// Global javascript

function addLoadEvent(func, prepend) {
	var oldonload = window.onload;
	if (typeof window.onload != 'function') {
		window.onload = func;
	} else if (prepend) {
		window.onload = function() {
			func();
			if (oldonload) oldonload();
		}
	} else {
		window.onload = function() {
				if (oldonload) oldonload();
				func();
		}
	}
}

$j(document).ready(function() {
	// Formerly known as globalOnLoad
	var support_message = "Please contact support via the " +
		"<a href='http://support.virtualsoftware.net' target='_blank'>web site</a> " +
		"or call <span class='nowrap'>(888) 874-1118 x2.</span>";
	var support_message_plain = "Please contact support via " +
		"http://support.virtualsoftware.net " +
		"or call (888) 874-1118 x2.";
	DocumentData = $j.extend({}, window.DocumentData, {
		userAgent: navigator.userAgent.toLowerCase(),
		support_message: support_message,
		support_message_plain: support_message_plain,
		// Formats used by date.js ParseExact
		dateFormat: "M/d/yyyy",
		dateFormats: ["M/d/yyyy", "M/d/yy"],
		timeFormat: "H:mmtt",
		dateTimeFormat: "M/d/yy H:mmtt",
		fxRateDecimalDigits: 4
	});


	// IE 5.5 fixes
	if ($j.browser.msie && $j.browser.version == 5.5) {
		// IE 5.5 includes the right scroll bar within the body boundaries
		document.body.style.margin = "0 20px 0 0";
	}

	/*
	var hps = $j('#header_pin_link');
	if (hps && (browser == "Explorer" && version >= 7 || browser == "Firefox" && version >= 1.5
	|| browser == "Netscape" && version >= 7.2 || browser == "Safari" && version >= 3)) {
	// Pin header if necessary
	headerPin(-1);
	hps.show();
	}*/
	//stripetable function will be run at each page level. some page has hidden table row so this would casue problem
	//stripeTables();
	styleInputs();

	// Focus on first so-enabled element
	$j('.acceptInitialFocus:first').focus();

	// Delay until other varaiables (i.e. DocumentData) have been defined at time zero
	setTimeout(globalPageInit, 50);

	// Global beforeonload event
	window.onbeforeunload = function() {
		/* TODO re-enable after bug fix.
		When adding new expense report, and submitting, dirty flag is still set on submit and somehow this
		popup appears even though we're submitting and not exiting the page. 
		
		var dirty = false;
		$j(document).find('form').each(function() {
		if (isFormDirty(this))
		dirty = true;
		});
		if (dirty) {
		return "The current page contains modified data.";
		}*/
		return; // No return value prevents default browser close confirmation
	};
	//enable all AutoComplete fields
	bindAutoCompletes();
});

function bindAutoCompletes(elem) {
	//if elem is null, it will automatically pick the body
	$j('.autoComplete', elem).each(function() {
		AutoComplete.init($j(this));
	});
}

function stripeTables(tableElems) {

	if (!tableElems) tableElems = $j('table.striped');
	// Remove in case row was previously striped
	var stripes = ['striped_even', 'striped_odd'];
	tableElems.each(function() {
		var bodyElems = $j(this).find('tbody');
		var next_stripe = 1;	// Start over every table, not every body
		bodyElems.each(function() {
			var trElem = $j(this);
			$j(this).find('tr.striped').each(function(idx) {
				var trElem = $j(this);
				if (trElem.css('display') != 'none') {
					if (trElem.hasClass('striped_new_row')) {
						next_stripe = next_stripe == 0 ? 1 : 0;
					}
					trElem.removeClass('striped_even striped_odd');
					trElem.addClass(stripes[next_stripe]);
				}
			});
		});
	});
}

// Easy calendar setup which uses previous input field, not set up until icon is clicked

function calendarSetup(trigger, params) {
	function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };

	if (typeof params == 'undefined') params = {};
	
	var input = $j(trigger).prev('input');
	var firstDay = 0;
	if (window.calDOW != null && window.calDOW >= 0 && window.calDOW <= 6)
		firstDay = window.calDOW;

	// Internal params
	param_default("open_now", true);

	// Params from calendar.js
	param_default("inputField", input[0]);
	param_default("inputField2", null); // backup date field to check when input_id is empty
	param_default("button", trigger);
	param_default("ifFormat", "%m/%d/%Y");
	param_default("align", "Tr");
	param_default("firstDay", firstDay);
	param_default("cache", true);
	param_default("weekNumbers", false);
	param_default("electric", false); // Update date only when closed
	
	Calendar.setup(params);

	if (params.open_now) trigger.onclick();
}

// Update body rows: line numbers and css classes through table
// Table rows alternate between odd/even classes
// If a line_number span exists on the line, it is incremented beginning with 1
// elem: a table or an element within a table

function tableUpdateLines(elem) {
	// Note: body may be split up into pieces due to repeated headers
	elem = $j(elem);
	var tableElem;
	if (elem.is('table')) tableElem = elem;
	else tableElem = elem.parents('table:first');
	var trElems = tableElem.children('tbody').children('tr');
	stripeTables(tableElem);
	trElems.each(function(idx) {
		var line_number = $j(this).find('.line_number');
		if (line_number[0]) line_number[0].innerHTML = idx + 1;
	});
}

// models: array of model rows (tr's)
// dest: tr before which new rows will be inserted (optional)

function raddRow(models, dest, options) 
{
	if (!options) options = {};
	options.setFocus = typeof(options.setFocus) == 'boolean' ? options.setFocus : true;

	// A single element within models may have a field with class 'raddRowLineNumber'
	//   visible or hidden, which contains a line number to increment

	var newNodes = $j(models).clone();
	if (!dest) dest = $j($j(models)[0]);
	$j(newNodes).removeClass('raddRowModel');
	dest.before(newNodes);

	var selected = false;
	$j(newNodes).each(function() {
		var elem = $j(this);
		// Append the index to the ID fields of newNodes
		//this.id += index;

		elem.show();
		if (options.setFocus) {
			elem.find('input, select').each(function() {
				if (selected) return;
				elem = $j(this);
				// Make the newNode appear, and make the first input selected
				if (elem[0].type != 'hidden' && elem[0].disabled != true &&
						!elem.hasClass('raddRowFocusSkip') && elem.css('display') != 'none') {
					selected = true;
					elem.focus();
					if (elem[0].type == 'text') elem.select();
				}
			});
		}
	});

	// Update the number field in the model
	var tempModel = $j(models).find('.raddRowLineNumber');
	tempModel.html(parseInt(tempModel.html())+1);

//	var tableElems = $j(newNodes).parents('table.striped');
//	stripeTables(tableElems);
	bindAutoCompletes(newNodes);
	return newNodes;
}

function displayFlash(message, options) {

	if (quickadd_displayFlash(message, options))
		return;
	
	var flash_box = $j('#flash_box');
	if (flash_box.length == 0) {
		var title = 'Error';
		if (options && options.header)
			title = options.header;
		modalAlert(title, message, { cssClass: 'message_box attention' });
		return;
	}
	
	var message_box = flash_box.is('.message_box') ? flash_box : $j('.message_box', flash_box);
	var flash_message = $j('#flash_message');
	$j.modal.close(); // In case one is open
	if (!flash_box[0] || !flash_message[0]) {
		modalQuery("Notice", message, null, [
			{cssClass: 'ok', text: 'Ok', onclick: function() { $j.modal.close();}}
		]);
		return;
	}
	flash_box.hide();
	message_box.removeClass('info attention error success icon_32_info icon_32_attention icon_32_error icon_32_success');
	if (options && options.cssClass) {
		//flash_box.addClass('message_box ' + options.cssClass);
		message_box.addClass(options.cssClass);
		if (options.cssClass.match(/info/)) 			message_box.addClass('icon_32_info');
		else if (options.cssClass.match(/attention/)) 	message_box.addClass('icon_32_attention');
		else if (options.cssClass.match(/error/)) 		message_box.addClass('icon_32_error');
		else if (options.cssClass.match(/success/)) 	message_box.addClass('icon_32_success');
	}
	flash_message.html('');
	if (options && options.header)
		flash_message.html("<h1>" + options.header + "</h1>");
	flash_message.append(message);

	// Clear title bar message, in case something's there from before
	$j('#message').html('');
	flash_box.show();
	
	if ($j.isFunction(window.pngfix)) {
		pngfix(flash_box); // IE6 only
	}
	
	$j.scrollTo({top: 0, left: 0}, {
		duration: 200,
		onAfter: function() {
			Effects.highlight(flash_box);
		}
	});
}

function hideMessageBox(elem) {
	// Remove old classes and hide
	elem = elem ? $j(elem) : $j('.message_box_wrapper');
	elem.hide().removeClass('info attention error success icon_32_info icon_32_attention icon_32_error icon_32_success');
}


/*	Perform tasks when a new page is loaded normally, or reloaded with ajax. */

function globalPageInit() {
	// TODO: Only call setSessionTimeout when DocumentData is present?
	Login.setSessionTimeout();
	$j('.message_box_wrapper').not('.initialized').addClass('initialized').each(function() {
		var elem = $j(this);
		elem.find('.message_box_close').click(function() {
			hideMessageBox(elem);
		});
	});
	$j('.titlebar_message_box').not('.initialized').addClass('initialized').each(function() {
		var elem = $j(this);
		elem.find('.message_box_close').click(function() {
			elem.hide().removeClass('info attention error success');
		});
	});
}

/*	Stock effects for consistent product experience. */
// Effect is copied to registration.js. registration.html doesn't include global.js but still need simlar virtual effects. 
var Effects = {
	highlight: function(elem) {
		//$j(elem).effect("pulsate", { times: 2 }, 250);
		elem = $j(elem);
		if (elem.is('.highlightableBackground')) {
			// Highlight by animating background color
			elem.css('backgroundColor', null); // Remove explicit background color just in case
			var color = elem.css('backgroundColor'); // Should get class-imposed color
			setTimeout(function() {
				elem.animate({backgroundColor: '#ffff77'}, 400, 'swing', function() {
					elem.animate({backgroundColor: color}, 600, 'swing', function() {
						elem.animate({backgroundColor: '#ffff77'}, 400, 'swing', function() {
							setTimeout(function() {
								elem.animate({backgroundColor: color}, 1500, 'swing', function() {
									elem.css('backgroundColor', null); // Remove explicit style to allow normal css to rule
								});
							}, 2000);
						});
					});
				});
			}, 500);
		}
		// Note: Tried to animate borderColor on the highlightableBorder class, but for some reason it doesn't seem to work
	},
	show: function(elem, callback) {
		//$j(elem).show(effect, options, 400, callback);
		$j(elem).show();
		if ($j.isFunction(callback)) callback();
	},
	hide: function(elem, callback) {
		//$j(elem).hide(effect, options, 400, callback);
		$j(elem).hide();
		if ($j.isFunction(callback)) callback();
	},
	
	// For debug it is useful to disable fading functions. Breakpoints have a way of stopping animations
	disableFade: true,
	//FADE_SPEED: 200,
	FADE_SPEED: 3000,
	
	fadeIn: function(elem, options, callback) {
		options = $j.extend({}, options);
		if (Effects.disableFade || options.disableFade) {
			elem.show();
			if ($j.isFunction(callback))
				callback();
		} else {
			//elem.fadeIn(options.speed ? options.speed : Effects.FADE_SPEED, callback);
			elem.fadeIn(options.speed ? options.speed : Effects.FADE_SPEED, function() {
				//alert('fadeIn complete');
				if ($j.isFunction(callback)) 
					callback();
			});
		}
	},
	fadeOut: function(elem, options, callback) {
		options = $j.extend({}, options);
		if (Effects.disableFade || options.disableFade) {
			elem.hide();
			if ($j.isFunction(callback))
				callback();
		} else {
			//elem.fadeOut(options.speed ? options.speed : Effects.FADE_SPEED, callback);
			elem.fadeOut(options.speed ? options.speed : Effects.FADE_SPEED, function() {
				//alert('fadeOut complete');
				if ($j.isFunction(callback)) 
					callback();
			});
		}
	}
};

function isArray(obj) {
	 if (obj.constructor.toString().indexOf("Array") == -1)
		return false;
	 else
		return true;
}

/* setLocation is called from ajax response in order to direct browser to new web page,
	similiar to a redirect. */

function setLocation(location) {
	// When we load the new page, the animated spinner gif will stop.
	// During loading, remove the background image and change the message.
	$j.modal.open("<div class='inProgress'>Loading...</div>", {close: false});
	window.location = location;
}

// Advanced styling of input controls
// Set up css classes for input fields to allow css highlight of focused element

function styleInputs(elem) {
	if (!elem) elem = $j(document);
	else elem = $j(elem);
	
	// Firefox for macintosh - adjust size of any file input fields
	// For some reason they are wider than other browsers or even in windows firefox
	if (DocumentData.userAgent.match(/macintosh.*firefox/))
		$j("input[type='file']").each(function() {
			$j(this).attr('size', $j(this).attr('size') - 8);
		});
	
	

//fix for multiselector problem with old webkit (safari 3.5 and earlier + chrome 1.0).	
//	elem.find("input, select, textarea").each(function() {
	elem.find("input").add(elem.find("select")).add(elem.find("textarea")).each(function() {
		var elem = $j(this);
		if (elem[0].tagName == 'INPUT' && elem[0].type != 'text' && elem[0].type != 'password' && elem[0].type != 'select') return;
		elem.addClass("input_idle");
		elem.focus(function(){
			elem.addClass("input_focus").removeClass("input_idle");
		});
		elem.blur(function(){
			$j(this).removeClass("input_focus").addClass("input_idle");
		});
    });
	
	// Context with focus-dependent display
	var contextFocuser = elem.find('.contextFocuser');
	if (contextFocuser.length != 0) {
		contextFocuser.each(function() {
			var elem = $j(this);
			var wrapper = elem.parents('.contextWrapper:first');
			elem.focus(function() {
				var offset = elem.offset();
				wrapper.addClass('contextWrapperHasFocus');
				var offset2 = elem.offset();
				if (!document.contextWrapper || document.contextWrapper != wrapper[0]) {
					// Need to retain -0.5 pixel marginTop, see global.css
					wrapper[0].marginTopOrig = wrapper.css('marginTop'); 
					wrapper.css({
						//opacity: 0.8,
						marginTop: offset.top - offset2.top,
						marginLeft: offset.left - offset2.left
					});
					if (wrapper[0].shadow) {
						wrapper[0].shadow.remove();
						wrapper[0].shadow = null;
					}
					var wrapperPos = wrapper.position();
					wrapper[0].shadow = $j('<div class="contextShadow"></div>').css({
							opacity: 0.3,
							width: wrapper.outerWidth(),
							height: wrapper.outerHeight(),
							top: wrapperPos.top + offset.top - offset2.top + 2,
							left: wrapperPos.left + offset.left - offset2.left + 2.5
						}).appendTo(wrapper.parent());
				}
				document.contextWrapper = wrapper[0];

			});
		});
	
		// Detect when an input with a different or no contextWrapper gains focus
		//fix for multiselector problem with old webkit (safari 3.5 and earlier + chrome 1.0).
		//		$j('input, select').focus(function() {
		$j('input').add($('select')).focus(function() {
			var wrapper = $j(this).parents('.contextWrapper:first')
			if (document.contextWrapper && (wrapper.length == 0 || document.contextWrapper != wrapper[0])) {
				oldWrapper = $j(document.contextWrapper);
				oldWrapper.removeClass('contextWrapperHasFocus')
					.css('marginTop', document.contextWrapper.marginTopOrig).css('marginLeft', 0);
				if (oldWrapper[0].shadow) {
					oldWrapper[0].shadow.remove();
					oldWrapper[0].shadow = null;
				}
				document.contextWrapper = null;
			}
		});
	}
	
	/*
	$j(elem).find('input.fill').each(function() {
		var parent = this.parentNode;
		if (parent.tagName != 'TD' && parent.tagName != 'TH') return;
		setToParentWidth(this);
	});
	*/
}

function setToParentWidth(elem) {
	$j(elem).width($j(elem.parentNode).width());
}

// Configure a show/hide: 1) based on the value of a checkbox, or 2) clicking a span/image, or 3) based on the value of a select
function configShowHide(element, target, showval) {
	var onchange = function() {

		if (this.type == 'checkbox') {				// Checkbox
			if (this.checked) $j(target).show();
			else $j(target).hide();
		} else if (this.type == 'select-one') {		// Select
			var val = getSelectedValue(this);
			if (val == showval && this.disabled == false) {
				$j(target).show();
			} else { 
				$j(target).hide();
			}
		} else {									// Span/image
			$j(target).toggle();
		}
	};
	$j(element).change(onchange).click(onchange).keydown(onchange).change();
}

// Configure a show/hide using expand up/down images
function configExpandShowHide(element, target) {
	var onchange = function() {
		$j(target).each(function() {
			// Dont use toggle, doesnt work always with TR
			if ($j(this).css('display') == 'none')
				$j(this).show();
			else
				$j(this).hide();
		});
		if($j(element).find('.icon_expand_up').css('display') == 'none') {
			$j('.icon_expand_up').show();
			$j('.icon_expand_down').hide();
		} else {
			$j('.icon_expand_up').hide();
			$j('.icon_expand_down').show();
		}

	};
	$j(element).click(onchange);
}

/*	Get the URL without the query string. */

function getBaseUrl() {
	var loc = document.location;
	var url = loc.protocol + '//' + loc.host + loc.pathname;
	return url;
}

/* Add a trim function for strings. */

String.prototype.trim = function () {
    return this.replace(/^\s*/, "").replace(/\s*$/, "");
}

function trim(value) {
	return value.trim();
}

String.prototype.sanitize = function() {
	return this.replace(/>/, "&gt;").replace(/</, "&lt;");
}

/*	Fatal error.
	Important: Using standard browser alert to ensure blocking such that no other dialog can mask the message. */

function alertFatalError(err) {
	// Close dialog in case one is open
	$j.modal.close({ afterClose: function() {
		var str;
		if (!err) {
			str = "Unregistered error.";
		}
		if (typeof (err) == 'string') {
			str = err;
		} else {
			var str = "Error: " + (err.name ? err.name : '') + "\n" +
				(err.message ? ("Message: " + err.message + "\n") : '') +
				(err.filename ? ("File: " + err.filename + "\n") : (err.fileName ? ("File: " + err.fileName + "\n") : '')) +
				(err.lineNumber ? ("Line Number: " + err.lineNumber + "\n") : '');
		}
		str += "\n\n" + DocumentData.support_message_plain;
		//modalAlert("Error", str, {cssClass: 'message_box error'});
		alert(str);
		var label = "";
		if (err.name) {
			label += err.name + "::";
		}
		if (err.message) {
			label += err.message;
		}
		eventTrack("Errors-JS", "Fatal", label, DocumentData ? DocumentData.loginCompany : "");
	}});
}

/*
// Track the element that has focus
$j(document).ready(function() {
	if (!document.activeElement) {
		document.activeElement = null;
		document.onkeyup = function(event) {
			document.activeElement = event.target;
		}
		document.onclick = document.onkeyup;
	}
});
*/

/* 	Capture all elick events so we can check for session state.
	While we'd like to use capture, we'll use bubbling mode to
	be compatible with IE. */
/*
$j(document).ready(function() {
	if (document.addEventListener) {
		document.addEventListener('click', globalOnClick, false);
	} else if (document.attachEvent) {
		// Microsoft IE
		document.attachEvent('onclick', globalOnClick)
	}
});

function globalOnClick() {
	//alert('global click');
}
*/


function eventTrack(category, action, label, value) {
	try {
		//error check for input strings.
		if (category == "")
			category = null;
		if (action == "")
			action = null;
		if (label == "")
			label = null;
		if (value == "")
			value = null;
		if (window.pageTracker)
			pageTracker._trackEvent(category, action, label, value);
	} catch (e) {}
}

/*	Make a float value, could be a float already, or a string, or blank. */

function makeFloat(value) {
	if (typeof(value) == 'string') {
		// Trim and remove commas and dollar signs
		value = value.trim().replace(/[\$,]/g, '');
		if (value == '') return 0;
		value = parseFloat(value);
	}
	return value;
}

/*	Display a float as a formatted string. 
	value: may be a float, integer, or string.
*/

function formatFloat(value, options) {
	options = $j.extend({ 
		decimalDigits: 2,
		separateWholeDigits: true
	}, options);
	
	// First handle decimal digits
	var value2 = printf('%.' + options.decimalDigits + 'f', value);
	
	// Insert commas
	if (options.separateWholeDigits) {
		value2 += '';
		parts = value2.split('.');
		part1 = parts[0];
		part2 = parts.length > 1 ? '.' + parts[1] : '';
		var pattern = /(\d+)(\d{3})/;
		while (pattern.test(part1)) {
			part1 = part1.replace(pattern, '$1' + ',' + '$2');
		}
		value2 = part1 + part2;
	}
	return value2;
}

/*	Display a time as a formatted string.
	value: may be a float, integer, or string,
	  in either decimal or h:mm format. */

function formatTime(value) {
	var hrs, mins, value2;
	if (typeof(value) == 'string' && value.match(/^[0-9]*:[0-9]*$/)) {
		hrs = value.replace(/^([0-9]*):([0-9]*)$/, "$1");
		hrs = hrs ? parseInt(hrs) : 0;
		mins = value.replace(/^([0-9]*):([0-9]*)$/, "$2");
		value2 = hrs + ':' + mins;
	} else {
		value2 = formatFloat(value);
	}
	return value2;
}

/*	Determine if the value is a valid representation of time, in decimal
	or hours:minutes format. */

function isTime(value) {
	if (value.match(/^[0-9]{1,2}\:?[0-9]*\s*[aApP]?\.?[mM]?\.?$/)) return true;
	if (value.match(/^[0-9]{1,2}\.?[0-9]*\s*[aApP]?\.?[mM]?\.?$/)) return true;	// This should not be there for TIME just for HOURS
/*	if (value.match(/^[0-9]*:[0-9]{2}$/)) return true; */
/*	if (value.match(/^([0-9]*\.)?[0-9]+$/)) return true; */
	return false;
}

function isHour(value) {
	if (value.match(/^([0-9]*\.)?[0-9]+$/)) return true;
	if (value.match(/^([0-9]*\:)?[0-9]+$/)) return true;
	return false;
}
/*	Parse a string representing a time. Supports decimal (float) as well
	as hours/minutes (as H:MM) */

function parseTime(value) {
	var value2;
	if (value.trim() == '') {
		value2 = 0;
	} else if (value.match(/^[0-9]*:[0-9]*$/)) {
		var hrs = value.replace(/^([0-9]*):([0-9]*)$/, "$1");
		hrs = hrs ? parseInt(hrs) : 0;
		var mins = value.replace(/^([0-9]*):([0-9]*)$/, "$2");
		//mins = mins ? parseInt(mins) : 0;
		//value2 = hrs + mins / 60;
		value2 = hrs + minutesToFloat(mins);
	} else {
		value2 = parseFloat(value);
	}
	return value2;
}

/*	Set the focus of an element after a short delay, in case there's a pending
	event (such as a tab) that will change it.
	elem: the element to gain focus
	options.select: true to also select the element contents
*/

function setDelayedFocus(elem, options) {
	var delay = options ? options.delay || 50 : 50;
	setTimeout(function() {
		elem = $j(elem);
		elem.focus();
		if (options && !!options.select) elem.select();
	}, delay);
}

/*

	Options
		onOk: callback for clicking ok (close)

*/

function modalAlert(title, message, options) {
	options = $j.extend({
		cssClass: 'message_box attention ' + (options.cssClass ? options.cssClass : '')
	}, options);
	modalQuery(title, message, options, [{
		cssClass: 'ok',
		text: 'Ok',
		isDefault: true,
		onClick: function() {
			if ($j.isFunction(options.onOk))
				options.onOk();
			else
				$j.modal.close();
		}
	}]);
	var label = "";
	if (title) {
		label += title + "::";
	}
	if (message) {
		label += message;
	}
	eventTrack("Errors-JS", "Warning", label, DocumentData ? DocumentData.loginCompany : "");
}

function modalAlertWithSetFocus(title, message, focusElement) {
	modalAlert(title, message, {
		onOk: function() {
			$j.modal.close();
			setDelayedFocus(focusElement, { select: true });
		}
	});
}

function modalConfirm(title, message, options) {
	options = $j.extend({
		cssClass: 'message_box attention hasTitleBar ' + (options.cssClass ? options.cssClass : '')
	}, options);
	modalQuery(title, message, options, [{
		cssClass: 'ok',
		text: options.okText ? options.okText : 'Ok',
		isDefault: false,
		onClick: function() {
			if ($j.isFunction(options.onOk))
				options.onOk();
			else
				$j.modal.close();
		}
	}, {
		cssClass: 'cancel',
		text: options.cancelText ? options.cancelText : 'Cancel',
		isDefault: true,
		onClick: function() {
			if ($j.isFunction(options.onCancel))
				options.onCancel();
			else
				$j.modal.close();
		}
	}]);
}


/*	Replacement for alert and confirm dialogs.

	Example:
	modalQuery("Title", "Testing 123", options, [
		{cssClass: 'ok', text: 'Ok', onclick: function() { $j.modal.close(); }},
		{cssClass: 'cancel', text: 'Cancel', isDefault: true, onclick: function() {
			$j.modal.close();
			doSomething();
		}}
	]);
	
	Options
		cssClass: dialog class (error, attention, success, info). Add message_box in each case.

*/

function modalQuery(title, message, options, buttonsActions) {
	options = $j.extend({}, options);
	var buttons = '';
	$j.each(buttonsActions, function() {
		buttons += '<input type="button" class="' + this.cssClass + 
			(!!this.isDefault ? ' default" ' : '" ') +
			'value="' + this.text + '"/>';
	});
	var cssClass = options.cssClass ? options.cssClass : 'dialogAlert'; // default
	
	if (cssClass.match(/hasTitleBar/)) {
		title = '<div class="titleBar">' + title + '</div>';
	} else {
		title = '<h1>' + title + '</h1>';
	}
	var html = 
		'<div class="' + cssClass + '">' + title + 
			'<div class="marginedContents">' + message + '</div>' + 
			'<div class="buttons">' + buttons + '</div>' +
		'</div>';
		
	$j.modal.open(html, {
		close: false,
		maxWidth: 500,
		onShow: function(dialog) {
			dialog.data.find('.message').append(message);
			$j.each(buttonsActions, function() {
				var button = this;
				dialog.data.find('.' + button.cssClass).click(function() {
					button.onClick();
					return false;
				});
			});
			/*dialog.data.find('form:first').submit(function() {
				dialog.data.find('.isDefault:first').click();
				return false;
			});*/
		},
		afterVisible: function(dialog) {
			// Make sure the dialog has focus, item must be visible
			var focusElem = dialog.data.find('.default:first');
			if (focusElem.length == 0)
				focusElem = dialog.data.find('input:first');
			focusElem.focus();
		}
	});
}


/*	jQuery plugin example.

(function ($) {
	$.fn.vteModal = function(options) {

		var defaults = {
			onShow: function(dialog) {
				// Center the dialog
				dialog.container.css('marginLeft', -dialog.container.width() / 2);
				dialog.container.css('marginTop', -dialog.container.height() / 2);
			}
		};

		options = $.extend(defaults, options);
		return this.modal(options);
	};

})(jQuery);
*/

/*	Product defaults for jquery.contextmenu */

$j.contextMenu.defaults({
	trigger: 'click', // Left mouse button
	itemHoverStyle: {
      border: '1px solid #ccc',
      backgroundColor: '#d2e1ec'
    },
	menuStyle: {width: ''} // Auto width
});

//only count the event of input text
// 8 = backspace
// space we do care
// 46 del
// 48-90 = 0-9 and a-z
// 96-111 = numpad 0-9 and */+-.
// 186-222 = ;=,-./{\}'
//http://aspdotnetfaq.com/Faq/What-is-the-list-of-KeyCodes-for-JavaScript-KeyDown-KeyPress-and-KeyUp-events.aspx

function DataKeyPressed(keyCode) {

	if (keyCode == 8 || keyCode == 32 ||
		keyCode == 46 ||
		(keyCode >= 48 && keyCode <= 90) ||
		(keyCode >= 96 && keyCode <= 111) ||
		(keyCode >= 186 && keyCode <= 222)) 
	{
		return true;
	}
	return false;
}