
// CalendarDateSelect version 1.15 - a prototype based date picker
// Questions, comments, bugs? - see the project page: http://code.google.com/p/calendardateselect
if (typeof Prototype == 'undefined') {
	alert("CalendarDateSelect Error: Prototype could not be found. Please make sure that your application's layout includes prototype.js (.g. <%= javascript_include_tag :defaults %>) *before* it includes calendar_date_select.js (.g. <%= calendar_date_select_includes %>).");
}
if (Prototype.Version < "1.6") {
	alert("Prototype 1.6.0 is required.  If using earlier version of prototype, please use calendar_date_select version 1.8.3");
}

Element.addMethods({
	purgeElement: function(el){
		el = $(el);
		if (!el) { return; }
		var garbageBin = $('IELeakGarbageBin');
		if (!garbageBin) {
			garbageBin = new Element('DIV', {
				id: 'IELeakGarbageBin'
			}).hide();
			document.body.appendChild(garbageBin);
		}
		el.stopObserving();
		el.descendants().invoke('stopObserving');
		garbageBin.insert(el);
		garbageBin.update('');
	}
});

var nil = null;

Date.one_day = 24 * 60 * 60 * 1000;
Date.weekdays = $w("S M T W T F S");
Date.first_day_of_week = 0;
Date.months = $w("January February March April May June July August September October November December");
Date.padded2 = function(hour){
	var padded2 = parseInt(hour, 10);
	if (hour < 10) {
		padded2 = "0" + padded2;
	}
	return padded2;
};
Date.prototype.getPaddedMinutes = function(){ return Date.padded2(this.getMinutes()); };
Date.prototype.getAMPMHour = function(){
	var hour = this.getHours();
	return (hour === 0) ? 12 : (hour > 12 ? hour - 12 : hour);
};
Date.prototype.getAMPM = function(){ return (this.getHours() < 12) ? "AM" : "PM"; };
Date.prototype.stripTime = function(){ return new Date(this.getFullYear(), this.getMonth(), this.getDate()); };
Date.prototype.daysDistance = function(compare_date){ return Math.round((compare_date - this) / Date.one_day); };
Date.prototype.toFormattedString = function(include_time){
	var hour, str;
	str = Date.months[this.getMonth()] + " " + this.getDate() + ", " + this.getFullYear();
	
	if (include_time) {
		hour = this.getHours();
		str += " " + this.getAMPMHour() + ":" + this.getPaddedMinutes() + " " + this.getAMPM();
	}
	return str;
};
Date.parseFormattedString = function(string){ return new Date(string); };
Math.floor_to_interval = function(n, i){ return Math.floor(n / i) * i; };
window.f_height = function(){ return ([window.innerHeight ? window.innerHeight : null, document.documentElement ? document.documentElement.clientHeight : null, document.body ? document.body.clientHeight : null].select(function(x){
	return x > 0;
}).first() ||
0); };
window.f_scrollTop = function(){ return ([window.pageYOffset ? window.pageYOffset : null, document.documentElement ? document.documentElement.scrollTop : null, document.body ? document.body.scrollTop : null].select(function(x){
	return x > 0;
}).first() ||
0); };

_translations = {
	"OK": "OK",
	"Now": "Now",
	"Today": "Today",
	"Clear": "Clear"
};
SelectBox = Class.create();
SelectBox.prototype = {
	initialize: function(parent_element, values, html_options, style_options, onchange){
		this.element = new Element('select', html_options).setStyle(style_options).observe('change', onchange);
		parent_element.insert(this.element);
		this.populate(values);
	},
	populate: function(values){
		this.element.update('');
		var pair;
		for (var i = 0, l = values.length; i < l; ++i) {
			pair = values[i];
			if (typeof(pair) != "object") {
				pair = [pair, pair];
			}
			this.element.insert(new Element("option", {
				value: pair[1]
			}).update(pair[0]));
		}
	},
	setValue: function(value){
		var matched = false;
		var e = this.element;
		for (var i = 0, l = e.options.length; i < l; ++i) {
			if (e.options[i].value == value.toString()) {
				e.selectedIndex = i;
				matched = true;
			}
		}
		return matched;
	},
	getValue: function(){ return $F(this.element); }
};
CalendarDateSelect = Class.create();
CalendarDateSelect.prototype = {
	initialize: function(target_element, options){
		this.target_element = $(target_element); // make sure it's an element, not a string
		if (!this.target_element) {
			alert("Target element " + target_element + " not found!");
			return false;
		}
		if (this.target_element.tagName != "INPUT") {
			this.target_element = this.target_element.down("INPUT");
		}
		
		this.target_element.calendar_date_select = this;
		this.last_click_at = 0;
		// initialize the date control
		this.options = $H({
			embedded: false,
			popup: nil,
			time: false,
			buttons: true,
			clear_button: true,
			year_range: 10,
			close_on_click: nil,
			minute_interval: 5,
			offsetLeft: 0,
			offsetTop: 0,
			IEoffsetLeft: 0,
			IEoffsetTop: 0,
			popup_by: this.target_element,
			month_year: "dropdowns",
			onchange: this.target_element.onchange,
			parentElement: document.body,
			valid_date_check: nil
		}).merge(options ||
		{});
		this.use_time = this.options.get("time");
		this.parseDate();
		this.callback("before_show");
		this.initCalendarDiv();
		if (!this.options.get("embedded")) {
			this.positionCalendarDiv();
			// set the click handler to check if a user has clicked away from the document
			Event.observe(document, "mousedown", this.closeIfClickedOut_handler = this.closeIfClickedOut.bindAsEventListener(this));
			Event.observe(document, "keypress", this.keyPress_handler = this.keyPress.bindAsEventListener(this));
		}
		this.callback("after_show");
	},
	positionCalendarDiv: function(){
		var above = false;
		var c_pos = this.calendar_div.cumulativeOffset(), c_left = c_pos[0], c_top = c_pos[1], c_dim = this.calendar_div.getDimensions(), c_height = c_dim.height, c_width = c_dim.width;
		var w_top = window.f_scrollTop(), w_height = window.f_height();
		var e_dim = $(this.options.get("popup_by")).cumulativeOffset(), e_top = e_dim[1], e_left = e_dim[0], e_height = $(this.options.get("popup_by")).getDimensions().height, e_bottom = e_top + e_height;
		var parentEl = $(this.options.get("parentElement"));
		var parent_pos = parentEl.cumulativeOffset();
		e_top -= parent_pos[1];
		e_left -= parent_pos[0];
		e_bottom = e_top + e_height;
		var tmpInt;
		if (Prototype.Browser.IE) {
			e_top += this.options.get("IEoffsetTop");
			e_left += this.options.get("IEoffsetLeft");
		}
		else {
			// Firefox we need to adjust position by borders
			tmpInt = parseInt(parentEl.getStyle('borderLeftWidth'), 10);
			if (!isNaN(tmpInt)) {
				e_left += tmpInt;
			}
			tmpInt = parseInt(parentEl.getStyle('borderTopWidth'), 10);
			if (!isNaN(tmpInt)) {
				e_top += tmpInt;
			}
			tmpInt = parseInt(this.calendar_div.getStyle('borderLeftWidth'), 10);
			if (!isNaN(tmpInt)) {
				e_left += tmpInt;
			}
			tmpInt = parseInt(this.calendar_div.getStyle('borderTopWidth'), 10);
			if (!isNaN(tmpInt)) {
				e_top += tmpInt;
			}
			// offsets
			e_top += this.options.get("offsetTop");
			e_left += this.options.get("offsetLeft");
		}
		
		if (((e_bottom + c_height) > (w_top + w_height)) && (e_bottom - c_height > w_top)) {
			above = true;
		}
		
		var left_px = e_left.toString() + "px", top_px = (above ? (e_top - c_height) : (e_top + e_height)).toString() + "px";
		
		this.calendar_div.style.left = left_px;
		this.calendar_div.style.top = top_px;
		
		this.calendar_div.setStyle({
			visibility: ""
		});
		
		// draw an iframe behind the calendar -- ugly hack to make IE 6 happy
		if (Prototype.Browser.IE) {
			this.iframe = new Element("iframe", {
				src: "javascript:false",
				className: "ie6_blocker"
			}).setStyle({
				left: left_px,
				top: top_px,
				height: c_height.toString() + "px",
				width: c_width.toString() + "px",
				border: "0px"
			});
			$(this.options.get('parentElement')).insert(this.iframe);
		}
	},
	initCalendarDiv: function(){
		var parent, style;
		if (this.options.get("embedded")) {
			parent = this.target_element.parentNode;
			style = {};
		}
		else {
			parent = this.options.get('parentElement');
			style = {
				position: "absolute",
				visibility: "hidden",
				left: 0,
				top: 0
			};
		}
		this.calendar_div = new Element('div', {
			className: "calendar_date_select"
		}).setStyle(style);
		$(parent).insert(this.calendar_div);
		
		// create the divs
		$w("top header body buttons footer bottom").each((function(name){
			this.calendar_div.insert((this[name + "_div"] = new Element('div', {
				className: 'cds_' + name
			}).setStyle({
				clear: 'left'
			})));
		}).bind(this));
		
		this.initHeaderDiv();
		this.initButtonsDiv();
		this.initCalendarGrid();
		this.updateFooter("&#160;");
		
		this.refresh();
		this.setUseTime(this.use_time);
	},
	initHeaderDiv: function(){
		var header_div = this.header_div;
		header_div.insert((this.close_button = new Element('a', {
			href: "#",
			className: "close"
		}).update("x").observe('click', this.close.bindAsEventListener(this))));
		header_div.insert((this.next_month_button = new Element('a', {
			href: "#",
			className: "next"
		}).update("&gt;").observe('click', (function(ev){
			ev.stop();
			this.navMonth(this.date.getMonth() + 1);
		}).bindAsEventListener(this))));
		header_div.insert((this.prev_month_button = new Element('a', {
			href: "#",
			className: "prev"
		}).update("&lt;").observe('click', (function(ev){
			ev.stop();
			this.navMonth(this.date.getMonth() - 1);
		}).bindAsEventListener(this))));
		
		if (this.options.get("month_year") == "dropdowns") {
			this.month_select = new SelectBox(header_div, $R(0, 11).map(function(m){
				return [Date.months[m], m];
			}), {
				className: "month"
			}, null, (function(){
				this.navMonth(this.month_select.getValue());
			}).bindAsEventListener(this));
			this.year_select = new SelectBox(header_div, [], {
				className: "year"
			}, null, (function(){
				this.navYear(this.year_select.getValue());
			}).bindAsEventListener(this));
			this.populateYearRange();
		}
		else {
			header_div.insert((this.month_year_label = new Element('span')));
		}
	},
	initCalendarGrid: function(){
		var body_div = this.body_div;
		this.calendar_day_grid = [];
		var days_table = new Element("table", {
			cellPadding: "0px",
			cellSpacing: "0px",
			width: "100%"
		});
		// make the weekdays!
		var weekdays_thead = new Element('thead');
		var weekdays_row = new Element('tr');
		weekdays_thead.insert(weekdays_row);
		Date.weekdays.each(function(weekday){
			weekdays_row.insert(new Element("th").update(weekday));
		});
		days_table.insert(weekdays_thead);
		var days_tbody = new Element("tbody");
		days_table.insert(days_tbody);
		// Make the days!
		this.fillDays(days_tbody);
		days_table.observe('mouseover', (function(ev){
			var el = ev.findElement('td');
			if (el && el.match('.calendarDateCell')) {
				this.dayHover(ev.findElement('td'));
			}
		}).bindAsEventListener(this)).observe('mouseout', (function(ev){
			var el = ev.findElement('td');
			if (el && el.match('.calendarDateCell')) {
				this.dayHoverOut(ev.findElement('td'));
			}
		}).bindAsEventListener(this)).observe('click', (function(ev){
			ev.stop();
			var el = ev.findElement('td');
			if (el && el.match('.calendarDateCell')) {
				this.updateSelectedDate(ev.findElement('td'), true);
			}
		}).bindAsEventListener(this));
		body_div.insert(days_table);
	},
	fillDays: function(days_tbody){
		var row_number = 0, weekday, days_row;
		for (var cell_index = 0; cell_index < 42; cell_index++) {
			weekday = (cell_index + Date.first_day_of_week) % 7;
			if (cell_index % 7 === 0) {
				days_row = new Element("tr", {
					className: 'row_' + row_number++
				});
				days_tbody.insert(days_row);
			}
			this.calendar_day_grid[cell_index] = new Element("td", {
				className: (weekday === 0) || (weekday == 6) ? "weekend calendarDateCell" : "calendarDateCell" //clear the class
			}).setStyle({
				cursor: "pointer"
			}).insert(new Element("div"));
			days_row.insert(this.calendar_day_grid[cell_index]);
		}
	},
	initButtonsDiv: function(){
		var buttons_div = this.buttons_div;
		if (this.options.get("time")) {
			var blank_time = $A(this.options.get("time") == "mixed" ? [[" - ", ""]] : []);
			buttons_div.insert(new Element("span", {
				className: "at_sign"
			}).update("@"));
			
			var t = new Date();
			this.hour_select = new SelectBox(buttons_div, blank_time.concat($R(0, 23).map(function(x){
				t.setHours(x);
				return $A([t.getAMPMHour() + " " + t.getAMPM(), x]);
			})), {
				className: "hour"
			}, null, (function(ev){
				this.updateSelectedDate({
					hour: $F(ev.element())
				});
			}).bindAsEventListener(this));
			buttons_div.insert(new Element("span", {
				className: "seperator"
			}).update(":"));
			this.minute_select = new SelectBox(buttons_div, blank_time.concat($R(0, 59).select((function(x){
				return (x % this.options.get('minute_interval') === 0);
			}).bind(this)).map(function(x){
				return $A([Date.padded2(x), x]);
			})), {
				className: "minute"
			}, null, (function(ev){
				this.updateSelectedDate({
					minute: $F(ev.element())
				});
			}).bindAsEventListener(this));
			
		}
		else if (!this.options.get("buttons")) {
			buttons_div.purgeElement();
		}
		
		if (this.options.get("buttons")) {
			buttons_div.insert(new Element('span').update("&#160;"));
			if (this.options.get("time") == "mixed" || !this.options.get("time")) {
				buttons_div.insert(new Element("a", {
					href: "#"
				}).update(_translations.Today).observe('click', (function(ev){
					ev.stop();
					this.today(false);
				}).bindAsEventListener(this)));
			}
			
			if (this.options.get("time") == "mixed") {
				buttons_div.insert(new Element('span', {
					className: "button_seperator"
				}).update("&#160;|&#160;"));
			}
			
			if (this.options.get("time")) {
				buttons_div.insert(new Element("a", {
					href: "#"
				}).update(_translations.Now).observe('click', (function(ev){
					ev.stop();
					this.today(true);
				}).bindAsEventListener(this)));
			}
			
			if (!this.options.get("embedded") && !this.closeOnClick()) {
				buttons_div.insert(new Element('span', {
					className: "button_seperator"
				}).update("&#160;|&#160;"));
				buttons_div.insert(new Element("a", {
					href: "#"
				}).update(_translations.OK).observe('click', (function(ev){
					ev.stop();
					this.close();
				}).bindAsEventListener(this)));
			}
			if (this.options.get('clear_button')) {
				buttons_div.insert(new Element('span', {
					className: "button_seperator"
				}).update("&#160;|&#160;"));
				buttons_div.insert(new Element("a", {
					href: "#"
				}).update(_translations.Clear).observe('click', (function(ev){
					ev.stop();
					this.clearDate();
					if (!this.options.get("embedded")) {
						this.close();
					}
				}).bindAsEventListener(this)));
			}
		}
	},
	refresh: function(){
		this.refreshMonthYear();
		this.refreshCalendarGrid();
		
		this.setSelectedClass();
		this.updateFooter();
	},
	refreshCalendarGrid: function(){
		this.beginning_date = new Date(this.date).stripTime();
		this.beginning_date.setDate(1);
		this.beginning_date.setHours(12); // Prevent daylight savings time boundaries from showing a duplicate day
		var pre_days = this.beginning_date.getDay(); // draw some days before the fact
		if (pre_days < 3) {
			pre_days += 7;
		}
		this.beginning_date.setDate(1 - pre_days + Date.first_day_of_week);
		
		var iterator = new Date(this.beginning_date);
		
		var today = new Date().stripTime();
		var this_month = this.date.getMonth();
		vdc = this.options.get("valid_date_check");
		for (var cell_index = 0; cell_index < 42; cell_index++) {
			day = iterator.getDate();
			month = iterator.getMonth();
			cell = this.calendar_day_grid[cell_index];
			Element.purgeElement(cell.childNodes[0]);
			cell.insert((div = new Element("div").update(day)));
			if (month != this_month) {
				div.className = "other";
			}
			cell.day = day;
			cell.month = month;
			cell.year = iterator.getFullYear();
			if (vdc) {
				if (vdc(iterator.stripTime())) {
					cell.removeClassName("disabled");
				}
				else {
					cell.addClassName("disabled");
				}
			}
			iterator.setDate(day + 1);
		}
		
		if (this.today_cell) {
			this.today_cell.removeClassName("today");
		}
		
		if ($R(0, 41).include(days_until = this.beginning_date.stripTime().daysDistance(today))) {
			this.today_cell = this.calendar_day_grid[days_until];
			this.today_cell.addClassName("today");
		}
	},
	refreshMonthYear: function(){
		var m = this.date.getMonth();
		var y = this.date.getFullYear();
		// set the month
		if (this.options.get("month_year") == "dropdowns") {
			this.month_select.setValue(m, false);
			
			var e = this.year_select.element;
			if (this.flexibleYearRange() && (!(this.year_select.setValue(y, false)) || e.selectedIndex <= 1 || e.selectedIndex >= e.options.length - 2)) {
				this.populateYearRange();
			}
			
			this.year_select.setValue(y);
			
		}
		else {
			this.month_year_label.update(Date.months[m] + " " + y.toString());
		}
	},
	populateYearRange: function(){
		this.year_select.populate(this.yearRange().toArray());
	},
	yearRange: function(){
		if (!this.flexibleYearRange()) { return $R(this.options.get("year_range")[0], this.options.get("year_range")[1]); }
		
		var y = this.date.getFullYear();
		return $R(y - this.options.get("year_range"), y + this.options.get("year_range"));
	},
	flexibleYearRange: function(){ return (typeof(this.options.get("year_range")) == "number"); },
	validYear: function(year){
		if (this.flexibleYearRange()) { return true; }
		else { return this.yearRange().include(year); }
	},
	dayHover: function(element){
		var hover_date = new Date(this.selected_date);
		hover_date.setYear(element.year);
		hover_date.setMonth(element.month);
		hover_date.setDate(element.day);
		this.updateFooter(hover_date.toFormattedString(this.use_time));
	},
	dayHoverOut: function(element){
		this.updateFooter();
	},
	clearSelectedClass: function(){
		if (this.selected_cell) {
			this.selected_cell.removeClassName("selected");
		}
	},
	setSelectedClass: function(){
		if (!this.selection_made) { return; }
		this.clearSelectedClass();
		if ($R(0, 42).include(days_until = this.beginning_date.stripTime().daysDistance(this.selected_date.stripTime()))) {
			this.selected_cell = this.calendar_day_grid[days_until];
			this.selected_cell.addClassName("selected");
		}
	},
	reparse: function(){
		this.parseDate();
		this.refresh();
	},
	dateString: function(){ return (this.selection_made) ? this.selected_date.toFormattedString(this.use_time) : "&#160;"; },
	parseDate: function(){
		var value = $F(this.target_element).strip();
		this.selection_made = (value !== "");
		this.date = value === "" ? NaN : Date.parseFormattedString(this.options.get("date") || value);
		if (isNaN(this.date)) {
			this.date = new Date();
		}
		if (!this.validYear(this.date.getFullYear())) {
			this.date.setYear((this.date.getFullYear() < this.yearRange().start) ? this.yearRange().start : this.yearRange().end);
		}
		this.selected_date = new Date(this.date);
		this.use_time = /[0-9]:[0-9]{2}/.exec(value) ? true : false;
		this.date.setDate(1);
	},
	updateFooter: function(text){
		if (!text) {
			text = this.dateString();
		}
		this.footer_div.update('');
		this.footer_div.insert(new Element("span").update(text));
	},
	clearDate: function(){
		if ((this.target_element.disabled || this.target_element.readOnly) && this.options.get("popup") != "force") { return false; }
		var last_value = this.target_element.value;
		this.target_element.value = "";
		this.clearSelectedClass();
		this.updateFooter('&#160;');
		if (last_value != this.target_element.value) {
			this.callback("onchange");
		}
	},
	updateSelectedDate: function(partsOrElement, via_click){
		var parts = $H(partsOrElement);
		if ((this.target_element.disabled || this.target_element.readOnly) && this.options.get("popup") != "force") { return false; }
		if (parts.get("day")) {
			var t_selected_date = this.selected_date, vdc = this.options.get("valid_date_check");
			for (var x = 0; x <= 3; x++) {
				t_selected_date.setDate(parts.get("day"));
			}
			t_selected_date.setYear(parts.get("year"));
			t_selected_date.setMonth(parts.get("month"));
			
			if (vdc && !vdc(t_selected_date.stripTime())) { return false; }
			this.selected_date = t_selected_date;
			this.selection_made = true;
		}
		
		if (!isNaN(parts.get("hour"))) {
			this.selected_date.setHours(parts.get("hour"));
		}
		if (!isNaN(parts.get("minute"))) {
			this.selected_date.setMinutes(Math.floor_to_interval(parts.get("minute"), this.options.get("minute_interval")));
		}
		if (parts.get("hour") === "" || parts.get("minute") === "") {
			this.setUseTime(false);
		}
		else if (!isNaN(parts.get("hour")) || !isNaN(parts.get("minute"))) {
			this.setUseTime(true);
		}
		
		this.updateFooter();
		this.setSelectedClass();
		
		if (this.selection_made) {
			this.updateValue();
		}
		if (this.closeOnClick()) {
			this.close();
		}
		if (via_click && !this.options.get("embedded")) {
			if ((new Date() - this.last_click_at) < 333) {
				this.close();
			}
			this.last_click_at = new Date();
		}
	},
	closeOnClick: function(){
		if (this.options.get("embedded")) { return false; }
		if (this.options.get("close_on_click") === nil) { return (this.options.get("time")) ? false : true; }
		else { return (this.options.get("close_on_click")); }
	},
	navMonth: function(month){
		(target_date = new Date(this.date)).setMonth(month);
		return (this.navTo(target_date));
	},
	navYear: function(year){
		(target_date = new Date(this.date)).setYear(year);
		return (this.navTo(target_date));
	},
	navTo: function(date){
		if (!this.validYear(date.getFullYear())) { return false; }
		this.date = date;
		this.date.setDate(1);
		this.refresh();
		this.callback("after_navigate", this.date);
		return true;
	},
	setUseTime: function(turn_on){
		this.use_time = this.options.get("time") && (this.options.get("time") == "mixed" ? turn_on : true); // force use_time to true if time==true && time!="mixed"
		if (this.use_time && this.selected_date) { // only set hour/minute if a date is already selected
			var minute = Math.floor_to_interval(this.selected_date.getMinutes(), this.options.get("minute_interval"));
			var hour = this.selected_date.getHours();
			
			this.hour_select.setValue(hour);
			this.minute_select.setValue(minute);
		}
		else if (this.options.get("time") == "mixed") {
			this.hour_select.setValue("");
			this.minute_select.setValue("");
		}
	},
	updateValue: function(){
		var last_value = this.target_element.value;
		this.target_element.value = this.dateString();
		if (last_value != this.target_element.value) {
			this.callback("onchange");
		}
	},
	today: function(now){
		var d = new Date();
		this.date = new Date();
		var o = $H({
			day: d.getDate(),
			month: d.getMonth(),
			year: d.getFullYear(),
			hour: d.getHours(),
			minute: d.getMinutes()
		});
		if (!now) {
			o = o.merge({
				hour: "",
				minute: ""
			});
		}
		this.updateSelectedDate(o, true);
		this.refresh();
	},
	close: function(ev){
		if (this.closed) { return false; }
		if (ev && ev.stop) {
			ev.stop();
		}
		this.callback("before_close");
		this.target_element.calendar_date_select = nil;
		Event.stopObserving(document, "mousedown", this.closeIfClickedOut_handler);
		Event.stopObserving(document, "keypress", this.keyPress_handler);
		this.calendar_div.purgeElement();
		this.closed = true;
		if (this.iframe) {
			this.iframe.purgeElement();
		}
		if (this.target_element.type != "hidden" && !this.target_element.disabled) {
			this.target_element.focus();
		}
		this.callback("after_close");
	},
	closeIfClickedOut: function(e){
		if (!$(Event.element(e)).descendantOf(this.calendar_div)) {
			this.close();
		}
	},
	keyPress: function(e){
		if (e.keyCode == Event.KEY_ESC) {
			this.close();
		}
	},
	callback: function(name, param){
		if (this.options.get(name)) {
			this.options.get(name).bind(this.target_element)(param);
		}
	}
};
