/* encoding: UTF-8 */
// This is a standalone Javascript module that traverses the DOM in it's entirety
// and wraps any vowels characters it finds in a `<span class="vowel">` element.
//
// Documentation & Updates available at:
// http://minar.stillingar.is/js/vowels/test.htm
// Hugsmiðjan ehf. (Dec. 2006)


// Usage: Place the following line of code *anywhere* in the HTML code of your page:
// <script src="[path-to-your-script-folder]/vowels.js"></script>

var wrapVowelChars = function(_block)
{
  var _nodeList = _block.childNodes;
  if (!_nodeList) { return; }

  var w = wrapVowelChars;

  // Reverse-loop over the `_nodeList`
  var i = _nodeList.length;
  while (i--)
  {
    var _node = _nodeList[i];

    switch (_node.nodeType)
    {
      case 3: // TEXT_NODE
        var _buffer = "";
        var _chars = _node.nodeValue;
        var _vowelElm = null;
        // walk the characters in the (text)`_node`
        for (var c=0, _char; (_char = _chars.charAt(c)); c++)
        {
          if (!(_vowelElm = w._vowelElmCache[_char])) // not a vowel!
          {
            // push it into the `_buffer`
            _buffer += _char;
          }
          else // is a vowel!
          {
            // flush the `_buffer`
            if (_buffer.length)
            {
              _block.insertBefore(document.createTextNode(_buffer), _node);
              _buffer = "";
            }
            // insert the vowel `<span>`
            _block.insertBefore(_vowelElm.cloneNode(1), _node);
          }
        }
        // flush the leftover `_buffer`
        if (_buffer.length)
        {
          _block.insertBefore(document.createTextNode(_buffer), _node);
        }
        // remove the old (text)`_node`
        _block.removeChild(_node);
        break;
      case 1: // ELEMENT_NODE
        // make sure the `_node.tagName` is not in `_forbiddenTagNames`
        if (!w._forbiddenTagNames[_node.tagName.toLowerCase()] &&
            (_node.className != w.vowelTagClass))
        {
          // recurse
          w(_node);
        }
        break;
    }
    // end of `childNodes` loop.
  }
};

(function(){
  var w = wrapVowelChars;

  // Configuration
  w.vowelTag   = "span";
  w.vowelTagClass = "vowel";
  w.vowelChars = "aeiouyæöáéíóúýøâàäåêèëîìïôòûùüÿ"; // This list is bound to grow over time.
  // Feel free to contact us at <stillingar@hugsmidjan.is> with suggestions for vowels.

  // `<textarea>` and `<option>` elements contain plain text
  // but may *not*  contain `<span>` or other HTML elements.
  w._forbiddenTagNames = {
    "textarea" : 1,
    "option"   : 1,
    "script"   : 1,
    "style"    : 1
  };
  w._vowelElmCache = {};


  w._run = function()
  {
    var _vowelChars = w.vowelChars.split("");
    for (var c=0, _char; (_char = _vowelChars[c]); c++)
    {
      var _vElm = document.createElement(w.vowelTag);
      _vElm.className = w.vowelTagClass;
      _vElm.innerHTML = _char;
      w._vowelElmCache[_char] = _vElm;
   
      var _vElmUpper = _vElm.cloneNode(1);
      _vElmUpper.innerHTML = _char.toUpperCase();
      w._vowelElmCache[_char.toUpperCase()] = _vElmUpper;
    }

    // use `wrapVowelCharBlocks` if it's present
    // else default to `document.body`
    var _blocks = window.wrapVowelCharBlocks || [document.body];

    // loop through the `_blocks` array
    // (usually there's just one item, but this feature is nice to have)
    for (var bi=0,bl=_blocks.length; bi<bl; bi++)
    {
      var _block = _blocks[bi];
      // Sugar: allow String values, do `document.getElementById` lookup
      if (typeof(_block)=="string")
      {
        _block = document.getElementById(_block);
      }
      if (_block)
      {
        // take the `_block` offline (and leave `_standInElm` in its place)
        var _standInElm = document.createElement(_block.tagName);
        var _parent = _block.parentNode;
        _parent.insertBefore(_standInElm, _block.nextSibling);
        _parent.removeChild(_block);

        // recursively search `_block` for vowels and wrap them in.
        wrapVowelChars(_block);

        // put `_block` back online
        _parent.insertBefore(_block, _standInElm);
        _parent.removeChild(_standInElm);
      }
    }
  };

  // Searches `document.body` for vowel-elements and zaps them!
  // (i.e. returns the HTML back to its original form.)
  w.reset = function(_block)
  {
    _block = _block || document.body;
    var _candidates = _block.getElementsByTagName(wrapVowelChars.vowelTag);
    var i = _candidates.length;
    while (i--)
    {
      var _elm = _candidates[i];
      if (_elm.className == wrapVowelChars.vowelTagClass)
      {
        _elm.parentNode.insertBefore(_elm.firstChild, _elm);
        _elm.parentNode.removeChild(_elm);
      }
    }
  };


  // Now let's run wrapVowelChars() on window.onload
  var wn = window,
      f = w._run;

  if (wn.addEventListener) // w3c standard
  {
    wn.addEventListener("load", f, false);
  }
  else if (wn.attachEvent) // MSIE
  {
    wn.attachEvent("onload", f);
  }
  else // others
  {
    if (wn.onload)
    {
      var _oldOnload = wn.onload;
      wn.onload = function(){ _oldOnload(); f(); };
    }
    else
    {
      wn.onload = f;
    }
  }

})();

