﻿/*
 * Dropdown Library
 * 
 * Author: Alex Tseng
 *
 * LastUpdate: 2009.11.1
 */

(function(){

var $D = Dropdown = {

	initialize: function(options){

		options = {

			handle: options.handle,

			element: options.element,

			customPanel: options.customPanel,

			tagName: options.tagName || 'div',

			className: options.className || 'active',

			hiddenField: options.hiddenField || null,

			useEffect: options.useEffect || false,

			fps: options.fps || '25',

			unit: options.unit || 'px',

			duration: options.duration || '500',

			property: options.property || null,

			transition: options.transition || 'slide',

			callback: options.callback || function(){}
		};

		this.options = options;

		this.handle = this.id(options.handle);

		this.element = this.id(options.element);

		this.customPanel = this.id(options.customPanel);

		if (!this.handle) this.handle = this.element;

		if (!this.element || !this.customPanel) return;

		this.build();
	},

	id: function(elem){
		return document.getElementById(elem);
	},

	tag: function(name, root) {
		return (root || document).getElementsByTagName(name);
	},

	show: function(elem){
		elem.style.display = 'block';
	},

	hide: function(elem){
		var curDisplay = this.getStyle(elem, 'display');
		if (curDisplay != 'none')
			elem.$oldDisplay = curDisplay;
		elem.style.display = 'none';
	},

	toggle: function(elem) {
		return this[this.isDisplayed(elem) ? 'hide' : 'show'](elem);
	},

	create: function(elem){
		return document.createElementNS ? document.createElementNS('http://www.w3.org/1999/xhtml', elem) : document.createElement(elem);
	},

	text: function(elem){
		var t = '';
		elem = elem.childNodes || elem;
		for(var i=0;i<elem.length;i++) {
			t += elem[i].nodeType != 1 ? elem[i].nodeValue : this.text(elem[i].childNodes);
		}
		return t.trim();
	},

	getStyle: function(e, name){
		if (e.style[name])
			return e.style[name];
		else if (e.currentStyle)
			return e.currentStyle[name];
		else if (document.defaultView && document.defaultView.getComputedStyle) {
			name = name.replace(/([A-Z])/g, "-$1");
			name = name.toLowerCase();
			var s = document.defaultView.getComputedStyle(e, " ");
			return s && s.getPropertyValue(name);
		} else
			return null;
	},

	setStyle: function(e, name, value){
		return e.style[name] = value;
	},

	isDisplayed: function(elem){
		return this.getStyle(elem, 'display') != 'none';
	},

	addEvent: function(element, eventType, handle){
		return document.addEventListener ? element.addEventListener(eventType, handle, false) : element.attachEvent('on' + eventType, handle);
	},

	removeEvent: function(element, eventType, handle){
		return document.removeEventListener ? element.removeEventListener(eventType, handle, false) : element.detachEvent('on' + eventType, handle);
	},

	stopPropagation: function(e){
		return (e && e.stopPropagation) ? e.stopPropagation() : window.event.cancelBubble = true;
	},

	hasClass: function(elem, className){
		 return elem.className.contains(className, ' ');
	},

	addClass: function(elem, className){
		if (!this.hasClass(elem, className)) elem.className = (elem.className + ' ' + className).clean();
	},

	removeClass: function(elem, className){
		elem.className = elem.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1');
		if (!elem.className) elem.removeAttribute('class');
	},

	showToggle: function(){
		var el = this.customPanel, hd = this.handle, self = this;

		this.addEvent(hd, 'click', function(e) {
			self.stopPropagation(e);
			self.toggle(el);
		});
	},

	slideToggle: function(){

		var el = this.customPanel, hd = this.handle, self = this;

		var h, el_h = el.offsetHeight, hd_h = 0;

		var unit = this.options.unit;

		var step = Math.round(1000 / this.options.fps) || 20;

		var duration = Math.round(this.options.duration / step);

		if ( this.getStyle(el, 'overflow') !== 'hidden' )
			this.setStyle(el, 'overflow', 'hidden');

		if ( !this.isDisplayed(el) ) {
			this.show(el);
			el_h = el.offsetHeight;
			this.hide(el);
			this.setStyle(el, 'height', 0);
		}

		var height = el_h - hd_h;

		var handle = function() {

			if ( !self.isDisplayed(el) && self.getStyle(el, 'height').toInt() !== 0 ) {
				el.style.height = 0;
				height = - height;
			}

			self.show(el);

			if ( el.offsetHeight - 2 === hd_h ) {
				h = hd_h;
				height = - height;
			} else {
				h = el_h;
				height = Math.abs(height);
			}

			for (var i=1;i<=step;i++) {
				(function() {
					var pos = i;
					setTimeout(function() {
						el.style.height = (h - (height * pos / step)) + unit;
						if (pos === step && el.offsetHeight - 2 === hd_h) self.hide(el);
					}, pos * duration);
				})();
			}
		}

		hd.onclick = function() {
			handle();
		}
	},

	build: function(){

		var self = this;

		var input = this.id(this.options.hiddenField);

		var elements = this.tag(this.options.tagName, this.customPanel);

		this.options.useEffect ? this.slideToggle() : this.showToggle();

		if ( !input ) {
			input = this.create('input');
			input.setAttribute('type', 'hidden');
			input.setAttribute('id', this.options.hiddenField);
			input.setAttribute('name', this.options.hiddenField);
			this.element.parentNode.appendChild(input);
		}

		for (var i = 0, l = elements.length; i < l; i++) {
			elements[i].onclick = function(i){
				for (var j = 0, l = elements.length; j < l; j++) {
					var elem = elements[j];
					self.removeClass(elem, self.options.className);
					if (this === elem) {
						input.setAttribute('value', j);
						self.addClass(this, self.options.className);
					}
				}
				self.hide(self.customPanel);
				self.element.innerHTML = self.text(this);
			}
		}

		this.addEvent(document.body, 'click', function(e) {
			self.stopPropagation(e);
			self.hide(self.customPanel);
		});
	}

};

String.prototype.trim = function(){
	return this.replace(/^\s+|\s+$/g, '');
};

String.prototype.clean = function(){
	return this.replace(/\s+/g, ' ').trim();
};

String.prototype.contains = function(string, separator){
	return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1;
};

String.prototype.toInt = function(base){
	return parseInt(this, base || 10);
};

String.prototype.stripScripts = function(){
	var scripts = '';
	return this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){
		scripts += arguments[1] + '\n';
		return '';
	});
};

String.prototype.cleanHTML = function(){
	return this.replace(/<[^>]*>/g, '');
};

String.prototype.escapeHTML = function(){
	return this.replace(/&/g,'&amp;').replace(/>/g,'&gt;').replace(/</g,'&lt;').replace(/"/g,'&quot;').replace(/'/g,'&#39;');
};

})();