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
alt
attribute. - 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);