Basically, the code looks for certain emoticon characters (like :) or :|) and replace them with an emoji icon. It also does this for emoji keywords like (:blush: or :smirk:).

A better explanation is probably on the GitHub repo.

What areas of the code should I concentrate on improving, and if possible, how to improve them?

(function( global ) {
  var emojify = (function() {

// Get DOM as local variable for simplicity's sake
var document = global.window.document;

return {

 // This functions sets configuration options
  config: function(emoticons, people, nature, objects, places, symbols) {
    this.emoticons_enabled = typeof emoticons !== 'undefined' ? emoticons : true;
    this.people_enabled = typeof people !== 'undefined' ? people : true;
    this.nature_enabled = typeof nature !== 'undefined' ? nature : true;
    this.objects_enabled = typeof objects !== 'undefined' ? objects : true;
    this.places_enabled = typeof places !== 'undefined' ? places : true;
    this.symbols_enabled = typeof symbols !== 'undefined' ? symbols : true;

  // Helper function to find text within DOM
  findText: function(element, pattern, callback) {
    for (var childi = element.childNodes.length; childi-->0;) {
      var child = element.childNodes[childi];
      if (child.nodeType == 1) {

        // Get tag name and class attribute
        var tag = child.tagName.toLowerCase(), classname;
          classname = child.getAttribute('class').toLowerCase();

        // Hacky at the minute, needs to be fixed
        if (classname) {
           if (tag !== 'script' && tag !== 'style' && tag !== 'textarea' && classname !== 'no-emojify')
             this.findText(child, pattern, callback);
        } else {
           if (tag !== 'script' && tag !== 'style' && tag !== 'textarea')
             this.findText(child, pattern, callback);

      } else if (child.nodeType == 3) {
        var matches = [];
        if (typeof pattern === 'string') {
          console.error('Accepts regex only');
        } else {
          var match;
          while (match = pattern.exec(child.data))
        for (var i = matches.length; i-->0;)
          callback.call(window, child, matches[i]);
  // Main method
  run: function() {
    var emoticons = [
      [/:-*\)/g, 'emojify blush'],
      [/:-*o/gi, 'emojify scream'],
      [/(:|;)-*]/g, 'emojify smirk'],
      [/(:|;)-*d/gi, 'emojify smiley'],
      [/xd/gi, 'emojify stuck_out_tongue_closed_eyes'],
      [/:-*p/gi, 'emojify stuck_out_tongue_winking_eye'],
      [/:-*(\[|@)/g, 'emojify rage'],
      [/:-*\(/g, 'emojify disappointed'],
      [/:'-*\(/g, 'emojify sob'],
      [/:-*\*/g, 'emojify kissing_heart'],
      [/;-*\)/g, 'emojify wink'],
      [/:-*\//g, 'emojify pensive'],
      [/:-*s/gi, 'emojify confounded'],
      [/:-*\|/g, 'emojify flushed'],
      [/:-*\$/g, 'emojify relaxed'],
      [/:-*x/gi, 'emojify mask'],
      [/<3/g, 'emojify heart'],
      [/<\/3/g, 'emojify broken_heart']
    ], people = [
      [/:bowtie:/g, 'emojify bowtie'],
      [/:smile:/g, 'emojify smile'],
      // Lots more regex keys
    ], nature = [
      [/:sunny:/g, 'emojify sunny'],
      [/:umbrella:/g, 'emojify umbrella'],
      // Lots more regex keys
    ], objects = [
      [/:bamboo:/g, 'emojify bamboo'],
      [/:gift_heart:/g, 'emojify gift_heart'],
      // Lots more regex keys
    ], places = [
      [/:109:/g, 'emojify onezeronine'],
      [/:house:/g, 'emojify house'],
      // Lots more regex keys
    ], symbols = [
      [/:one:/g, 'emojify one'],
      [/:two:/g, 'emojify two'],
      // Lots more regex keys
    ], r;

    // Create array of selected icon sets
    var selected_sets = [];

    // Iterate through selected icon sets
    for (var index = 0; index < selected_sets.length; index++) {
      // Iterate through all regexes
      while (r = selected_sets[index].shift()) {
        // Find and replace matches with <div> tags
        this.findText(document.body, r[0], function(node, match) {
          var wrap = document.createElement('div');
          wrap.setAttribute('class', r[1]);
          node.nextSibling.nodeValue = node.nextSibling.nodeValue.substr(match[0].length, node.nextSibling.nodeValue.length);
          node.parentNode.insertBefore(wrap, node.nextSibling);

  global.emojify = emojify;

})( this );

here are few improvement area which i would suggest ,

  1. Current code select all emot element of a document and apply the icon on that , it should be section based or say it should be dependent upon library user (just like jquery does).

  2. child.nodeType == 1 is not a good practice better use an enum/ switch for better comparison.

  3. better use jquery/underscore to make it usable. jquery extension are easy to write and maintain.

section based means I can select dom elements like all div or all paragraph having emot class and then apply your function on that , just like this


this will select all element having emot class and needs to emotify.

Let me know if you have any more confusion.

  • \$\begingroup\$ Could you elaborate on that? I don't understand what you mean by section-based in 1. Also, I am looking to make this into a jQuery extension soon. \$\endgroup\$ – Hassan Khan Dec 26 '12 at 13:53
  • \$\begingroup\$ Oh right, I suppose that will be easier to do once I've made it into a jQuery extension then. What about 2? Should I make an enum of node types and switch between them? Also, do you have any good links for converting my module to a jQuery extension? \$\endgroup\$ – Hassan Khan Dec 27 '12 at 21:55
  • \$\begingroup\$ Point number 2 is not valid if you use plugin/extension for jQuery. docs.jquery.com/Plugins/Authoring , here is the jQuery plugin sample \$\endgroup\$ – Paritosh Dec 28 '12 at 3:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.