/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Script: extensions.js
 * Contains MooTools Element, Event, Array, String, and Number extensions
 * 
 * Author: Tom Occhino
 * License: MIT-style license.
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Element Extensions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Element.extend({

  getID: function() {
    regex = /\d+/;
  	return regex.exec(this.id)[0];
  },
  
	visible: function(){
		return this.getStyle('display') == 'none' || this.getStyle('visibility') == 'hidden' ? false : true;
	},
	
	show: function(){
		return this.setStyle('display', '').setOpacity(1);
	},
	
	hide: function(collapse){
		return collapse ? this.setStyle('display', 'none') : this.setOpacity(0);
	},
	
	toggle: function(collapse){
		return this.visible() ? this.hide(collapse) : this.show();
	},
	
	appendHTML: function(html){
		return this.setHTML(this.innerHTML + html);
	},
	
	cleanWhitespace: function(){
		$A(this.childNodes).each(function(node){
			if ($type(node) == 'whitespace') this.removeChild(node);
		}, this);
		return this;
	},
	
	setValue: function(val) {
		switch(this.getTag()){
			case 'select':
				this.selectedIndex = -1;
				if (!val) break;
				if ($type(val) != 'array') val = [val];
				$each(this.options, function(opt){
					opt.selected = val.test($pick(opt.value, opt.text));
				});
				break;
			case 'input':
				if (['checkbox', 'radio'].test(this.type)) {
					this.checked = ($type(val) == 'array') ? val.test(this.value) : (val == this.value);
					break;
				}
				if (!['hidden', 'text', 'password'].test(this.type)) break;
			case 'textarea': this.value = $type(val) ? val : '';
		}
		return this;
	},
	
	disableSelection: function(){
		if (window.ie) this.onselectstart = function(){ return false };
		this.style.MozUserSelect = "none";
		return this;
	},
	
	getSiblings: function(){
		var children = this.getParent().getChildren();
		children.splice(children.indexOf(this), 1);
		return children;
	},
	
	getHeight: function(){
		return this.getCoordinates().height;
	},
	
	getWidth: function(){
		return this.getCoordinates().width;
	},
		
	getRelativePosition: function(){
		var el = this, left = 0, top = 0;
		do {
			left += el.offsetLeft || 0 - el.scrollLeft || 0;
			top += el.offsetTop || 0 - el.scrollTop || 0;
		} while ((el = el.offsetParent) && (el != document.body) && !el.style.position.contains('e'));
		return {'x': left, 'y': top};
	},
	
	// from Prototype
	
	insert: function(content, position) {
     position = (position || 'bottom').toLowerCase();
     var t = Element._insertionTranslations[position], range;

     if(content && content.ownerDocument === document) {
       t.insert(this, content);
       return this;
     }

     content = content.toString();

     range = this.ownerDocument.createRange();
     t.initializeRange(this, range);
     t.insert(this, range.createContextualFragment(content.stripScripts()));

     return this;
   }
	
});

// From prototype

Element._getContentFromAnonymousElement = function(tagName, html) {
  var div = new Element('div'); t = Element._insertionTranslations.tags[tagName]
  div.innerHTML = t[0] + html + t[1];
  t[2].times(function() { div = div.firstChild });
  return $A(div.childNodes);
};

if(!document.createRange || window.opera) {
  Element.extend({
    insert: function(content, position) {
      position = (position || 'bottom').toLowerCase();
      var t = Element._insertionTranslations, pos = t[position], tagName;
    
      if(content && content.ownerDocument === document) {
        pos.insert(this, content);
        return this;
      }

      content = content.toString();
      tagName = ((position == 'before' || position == 'after')
        ? this.parentNode : this).tagName.toUpperCase();
    
      if(t.tags[tagName]) {
        var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
        if(position == 'top' || position == 'after') fragments.reverse();
        fragments.each(pos.insert.pass(this));
      }
      else this.insertAdjacentHTML(pos.adjacency, content.stripScripts());
    
      return this;
    }
  });
}

Element._insertionTranslations = {
  before: {
    adjacency: 'beforeBegin',
    insert: function(element, node) {
      element.parentNode.insertBefore(node, element);
    },
    initializeRange: function(element, range) {
      range.setStartBefore(element);      
    }
  },
  top: {
    adjacency: 'afterBegin',
    insert: function(element, node) {
      element.insertBefore(node, element.firstChild);
    },
    initializeRange: function(element, range) {
      range.selectNodeContents(element);
      range.collapse(true);
    }
  },
  bottom: {
    adjacency: 'beforeEnd',
    insert: function(element, node) {
      element.appendChild(node);
    }
  },
  after: {
    adjacency: 'afterEnd',
    insert: function(element, node) {
      element.parentNode.insertBefore(node, element.nextSibling);
    },
    initializeRange: function(element, range) {
      range.setStartAfter(element);
    }
  },
  tags: {
    TABLE:  ['<table>',                '</table>',                   1],
    TBODY:  ['<table><tbody>',         '</tbody></table>',           2],
    TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],
    TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
    SELECT: ['<select>',               '</select>',                  1]
  }
};

(function(){
  this.bottom.initializeRange = this.top.initializeRange;
  $extend(this.tags, {
    THEAD: this.tags.TBODY,
    TFOOT: this.tags.TBODY,
    TH:    this.tags.TD
  });
}).call(Element._insertionTranslations);

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Element Event Extensions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Element.Events.extend({
	
	wheelup: {
		type: Element.Events.mousewheel.type,
		map: function(event){
			event = new Event(event);
			if (event.wheel >= 0) this.fireEvent('wheelup', event)
		}
	},
	
	wheeldown: {
		type: Element.Events.mousewheel.type,
		map: function(event){
			event = new Event(event);
			if (event.wheel <= 0) this.fireEvent('wheeldown', event)
		}
	}
	
});


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Array Extensions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Array.extend({
	
	flatten: function(){
		var item = this.shift();
		var flattened = arguments[0] ? arguments[0] : [];
		if(!item) return flattened;
		else if($type(item) == 'array') return item.merge(this).flatten(flattened);
		else {
			flattened.push(item);
			return this.flatten(flattened);
		}
	},
	
	subset: function(from, to) {
		var subset = [];
		for(var i = 0, j = to - from; i < j; i++) subset[i] = this[from + i];
		return subset;
	}
	
});


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Number Extensions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Number.extend({
	
	between: function(start, end){
		return this > Math.min(start, end) && this < Math.max(start, end);
	}
	
});


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * String Extensions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
String.extend({
	
	htmlEncode: function() {
		return this.
		replaceAll('&', '&amp;').
		replaceAll('"', '&quot;').
		replaceAll("'", '&#039;').
		replaceAll('<', '&lt;').
		replaceAll('>', '&gt;');
	},
	
	htmlDecode: function() {
		return this.
		replaceAll('&amp;', '&').
		replaceAll('&quot;', '"').
		replaceAll('&#039;', "'").
		replaceAll('&lt;', '<').
		replaceAll('&gt;', '>');
	},
	
	replaceAll: function(fval, rval, options) {
		return this.replace(new RegExp(fval, $pick(options, 'gi')), rval);
	},
	
	stripTags: function() {
    return this.replace(/<\/?[^>]+>/gi, '');
  },
	
	zeroPad: function(num){
		return new Array(num - this.length).join('0') + this;
	},
	
	stripScripts: function() {
	  script_regex = '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)';
    return this.replace(new RegExp(script_regex, 'img'), '');
  }
});

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Ajax extensions
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

$extend(Ajax.prototype.options, {evalScripts: true});
