Converting graphical smilies to text
Frownies came to be in response to a joke. Someone on the Greasemonkey mailing list announced that they had developed a user script to convert ASCII “smilies” like :-) to their graphical equivalents. Someone else responded, wondering how long it would take for someone to do the reverse:
convert graphical smilies back to text.
For the record, it took me about 20 minutes. Most of the time was spent researching publishing software that auto-generated graphical smilies, and compiling a comprehensive list of variations.
This script relies on the fact that most publishing software that generates graphical smilies puts the text equivalent in
the alt attribute of the <img> element. So really what this script does is replace images with their ALT text, if the ALT text matches one of a list of
pre-defined constants.
Example: frownies.user.js
// ==UserScript==
// @name Frownies
// @namespace http://diveintogreasemonkey.org/download/
// @description convert graphical smilies to their text equivalents
// @include *
// ==/UserScript==
var smilies, images, img, replacement;
smilies = [":)", ":-)" ":-(", ":(", ";-)", ";)", ":-D", ":D", ":-/",
":/", ":X", ":-X", ":\">", ":P", ":-P", ":O", ":-O", "X-(",
"X(", ":->", ":>", "B-)", "B)", ">:)", ":((", ":(((", ":-((",
":))", ":-))", ":-|", ":|", "O:-)", "O:)", ":-B", ":B", "=;",
"I)", "I-)", "|-)", "|)", ":-&", ":&", ":-$", ":$", "[-(", ":O)",
":@)", "3:-O", ":(|)", "@};-", "**==", "(~~)", "*-:)", "8-X",
"8X", "=:)", "<):)", ";;)", ":*", ":-*", ":S", ":-S", "/:)",
"/:-)", "8-|", "8|", "8-}", "8}", "(:|", "=P~", ":-?", ":?",
"#-O", "#O", "=D>", "~:>", "%%-", "~O)", ":-L", ":L", "[-O<",
"[O<", "@-)", "@)", "$-)", "$)", ">-)", ":-\"", ":^O", "B-(",
"B(", ":)>-", "[-X", "[X", "\\:D/", ">:D<", "(%)", "=((", "#:-S",
"#:S", "=))", "L-)", "L)", "<:-P", "<:P", ":-SS", ":SS", ":-W",
":W", ":-<", ":<", ">:P", ">:-P", ">:/", ";))", ":-@", "^:)^",
":-J", "(*)", ":GRIN:", ":-)", ":SMILE:", ":SAD:", ":EEK:",
":SHOCK:", ":???:", "8)", "8-)", ":COOL:", ":LOL:", ":MAD:",
":RAZZ:", ":OOPS:", ":CRY:", ":EVIL:", ":TWISTED:", ":ROLL:",
":WINK:", ":!:", ":?:", ":IDEA:", ":ARROW:", ":NEUTRAL:",
":MRGREEN:"];
images = document.evaluate(
'//img[@alt]',
document,
null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null);
for (var i = 0; i < images.snapshotLength; i++) {
img = images.snapshotItem(i);
alt = img.alt.toUpperCase();
for (var j in smilies) {
if (alt == smilies[j]) {
replacement = document.createTextNode(alt);
img.parentNode.replaceChild(replacement, img);
}
}
}The code breaks down into four steps:
- Define a list of smilies (as text strings).
- Find all the images on the page that contain an
altattribute. - For each image, check whether the ALT text matches any of the list of ASCII smilies.
- If it matches, replace the
<img>element with a text node that contains only the ASCII smily.
The first step simply defines a list, using Javascript's [ ] syntax.
smilies = [":)", ":-)" ":-(", ":(", ";-)", ";)", ":-D", ":D", ":-/",
":/", ":X", ":-X", ":\">", ":P", ":-P", ":O", ":-O", "X-(",
"X(", ":->", ":>", "B-)", "B)", ">:)", ":((", ":(((", ":-((",
":))", ":-))", ":-|", ":|", "O:-)", "O:)", ":-B", ":B", "=;",
"I)", "I-)", "|-)", "|)", ":-&", ":&", ":-$", ":$", "[-(", ":O)",
":@)", "3:-O", ":(|)", "@};-", "**==", "(~~)", "*-:)", "8-X",
"8X", "=:)", "<):)", ";;)", ":*", ":-*", ":S", ":-S", "/:)",
"/:-)", "8-|", "8|", "8-}", "8}", "(:|", "=P~", ":-?", ":?",
"#-O", "#O", "=D>", "~:>", "%%-", "~O)", ":-L", ":L", "[-O<",
"[O<", "@-)", "@)", "$-)", "$)", ">-)", ":-\"", ":^O", "B-(",
"B(", ":)>-", "[-X", "[X", "\\:D/", ">:D<", "(%)", "=((", "#:-S",
"#:S", "=))", "L-)", "L)", "<:-P", "<:P", ":-SS", ":SS", ":-W",
":W", ":-<", ":<", ">:P", ">:-P", ">:/", ";))", ":-@", "^:)^",
":-J", "(*)", ":GRIN:", ":-)", ":SMILE:", ":SAD:", ":EEK:",
":SHOCK:", ":???:", "8)", "8-)", ":COOL:", ":LOL:", ":MAD:",
":RAZZ:", ":OOPS:", ":CRY:", ":EVIL:", ":TWISTED:", ":ROLL:",
":WINK:", ":!:", ":?:", ":IDEA:", ":ARROW:", ":NEUTRAL:",
":MRGREEN:"];Next I search the page for all <img> elements with an alt attribute, using an XPath query. See Doing something for every element with a certain attribute for more details on XPath queries.
images = document.evaluate(
'//img[@alt]',
document,
null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null);Step 3 loops through all these <img> elements, and checks whether the alt attribute matches any of my defined smilies. Because some smilies contain letters, I use the toUpperCase() method to convert the alt attribute to uppercase before comparing.
for (var i = 0; i < images.snapshotLength; i++) {
img = images.snapshotItem(i);
alt = img.alt.toUpperCase())
for (var j in smilies) {
if (alt == smilies[j]) {
// ...
}
}
}Finally, I create a new text node with the text of the smily, and replace the existing <img> element. See Replacing an element with new content for more details.
replacement = document.createTextNode(alt);
img.parentNode.replaceChild(replacement, img);