HTML Typer

by soulwire

HTML

<section id="content"></section>

CSS

html, body {
    background: #f2f2f2;
}

#content {
    background: #fff;
    font-size: 18px;
    padding: 20px;
    margin: 0 auto;    
    width: 80%;
}

#content strong {
    font-weight: 600;
}

#content em {
    font-style: italic;
}

#content li {
    list-style-type: square;
    margin-left: 20px;
}

.highlight {
    background-color: #fff885;
}

JavaScript

jQuery.fn.outerHTML = function(s) { return (s) ? this.before(s).remove() : jQuery("<p>").append(this.eq(0).clone()).html();}

var regex = {
  tags: /(<\w[^>]+>)([^\<]+)(<\/[^>]+>)/,
  index: /\{\/?(\d+)\}/,
  open: /\{(\d+)\}/,
  shut: /\{\/(\d+)\}/
};
    
var tags = [];
var queue = [];

var $container = $('#content');

function parse(content) {
    // Recursively parse and replace the content
    var result = regex.tags.exec(content);
    while(result) {
      // Get the start and end of the string
      var before = content.substr(0, result.index);
      var after = content.substr(result.index + result[0].length);
      // Create the main content
      var insert = '{n}' + result[2] + '{/n}';
      insert = insert.replace(/(\{\/?)n(\})/g, '$1' + tags.length + '$2');
      // Insert it between the rest of the content
      content = before + insert + after;
      // Store the tags we've replaced
      tags.push(result[1] + result[3]);
      // Find the next result
      result = regex.tags.exec(content);
      // Rest the regex
      regex.tags.lastIndex = 0;
    }
    
    // Strip into queue
    queue.push(' ');
    queue = queue.concat( content.match(/\{?\/?.\}?/g) );
}

var $tags = [];
var $tag = null;

function type() {
    
    if(queue.length > 0) {
        var char = queue.shift();
      
        if(regex.index.test(char)) {
          
          // If we're opening a tag
          if(regex.open.test(char)) {
            
            var index = +char.match(regex.index)[1];
            var $tag = $(tags[index]);
            $container.append($tag);
            $container = $tag;
          } else {
            // Close the tag and go up one level
            $container = $container.parent();
          }
          // We've done nothing, so step forward
          type();
        } else {
          $container.append(char);
        }
    }
}

parse('Lorem <span class="highlight"><a href="#">ipsum</a> dolor <a href="#">sit <strong>amet</strong></a>,...