Vlad Kurkin (b_vladi) wrote in changelog,
Vlad Kurkin
b_vladi
changelog

[livejournal] r20627: LJSUP-10472: Changing display of setting...

Committer: vkurkin
LJSUP-10472: Changing display of setting date/time with creating/editing post
A   trunk/htdocs/js/jquery/jquery.dateentry.js
A   trunk/htdocs/js/jquery/jquery.dateentry.min.js
U   trunk/htdocs/js/jquery/jquery.lj.entryDatePicker.js
Added: trunk/htdocs/js/jquery/jquery.dateentry.js
===================================================================
--- trunk/htdocs/js/jquery/jquery.dateentry.js	                        (rev 0)
+++ trunk/htdocs/js/jquery/jquery.dateentry.js	2011-11-25 13:36:04 UTC (rev 20627)
@@ -0,0 +1,984 @@
+/* http://keith-wood.name/dateEntry.html
+ Date entry for jQuery v1.0.6.
+ Written by Keith Wood (kbwood{at}iinet.com.au) March 2009.
+ Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and
+ MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses.
+ Please attribute the author if you use it. */
+
+/* Turn an input field into an entry point for a date value.
+ The date can be entered via directly typing the value,
+ via the arrow keys, or via spinner buttons.
+ It is configurable to reorder the fields, to enforce a minimum
+ and/or maximum date, and to change the spinner image.
+ Attach it with $('input selector').dateEntry(); for default settings,
+ or configure it with options like:
+ $('input selector').dateEntry(
+ {spinnerImage: 'spinnerSquare.png', spinnerSize: [20, 20, 0]}); */
+
+(function($) { // Hide scope, no $ conflict
+
+	/* DateEntry manager.
+	 Use the singleton instance of this class, $.dateEntry, to interact with the date
+	 entry functionality. Settings for fields are maintained in an instance object,
+	 allowing multiple different settings on the same page. */
+	function DateEntry() {
+		this._disabledInputs = []; // List of date inputs that have been disabled
+		this.regional = []; // Available regional settings, indexed by language code
+		this.regional[''] = { // Default regional settings
+			dateFormat: 'mdy/', // The format of the date text:
+			// first three fields in order ('y' for year, 'Y' for two-digit year,
+			// 'm' for month, 'n' for abbreviated month name, 'N' for full month name,
+			// 'd' for day, 'w' for abbreviated day name and number,
+			// 'W' for full day name and number), followed by separator(s) 
+			monthNames: ['January', 'February', 'March', 'April', 'May', 'June',
+				'July', 'August', 'September', 'October', 'November', 'December'], // Names of the months
+			monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
+				'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // Abbreviated names of the months
+			dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
+			// Names of the days
+			dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // Abbreviated names of the days
+			spinnerTexts: ['Today', 'Previous field', 'Next field', 'Increment', 'Decrement']
+			// The popup texts for the spinner image areas
+		};
+		this._defaults = {
+			appendText: '', // Display text following the input box, e.g. showing the format
+			initialField: 0, // The field to highlight initially
+			useMouseWheel: true, // True to use mouse wheel for increment/decrement if possible,
+			// false to never use it
+			defaultDate: null, // The date to use if none has been set, leave at null for now
+			minDate: null, // The earliest selectable date, or null for no limit
+			maxDate: null, // The latest selectable date, or null for no limit
+			spinnerImage: 'spinnerDefault.png', // The URL of the images to use for the date spinner
+			// Seven images packed horizontally for normal, each button pressed, and disabled
+			spinnerSize: [20, 20, 8], // The width and height of the spinner image,
+			// and size of centre button for current date
+			spinnerBigImage: '', // The URL of the images to use for the expanded date spinner
+			// Seven images packed horizontally for normal, each button pressed, and disabled
+			spinnerBigSize: [40, 40, 16], // The width and height of the expanded spinner image,
+			// and size of centre button for current date
+			spinnerIncDecOnly: false, // True for increment/decrement buttons only, false for all
+			spinnerRepeat: [500, 250], // Initial and subsequent waits in milliseconds
+			// for repeats on the spinner buttons
+			beforeShow: null, // Function that takes an input field and
+			// returns a set of custom settings for the date entry
+			altField: null, // Selector, element or jQuery object for an alternate field to keep synchronised
+			altFormat: null // A separate format for the alternate field
+		};
+		$.extend(this._defaults, this.regional['']);
+	}
+
+	var PROP_NAME = 'dateEntry';
+
+	$.extend(DateEntry.prototype, {
+		/* Class name added to elements to indicate already configured with date entry. */
+		markerClassName: 'hasDateEntry',
+
+		/* Override the default settings for all instances of the date entry.
+		 @param  options  (object) the new settings to use as defaults (anonymous object)
+		 @return  (DateEntry) this object */
+		setDefaults: function(options) {
+			extendRemove(this._defaults, options || {});
+			return this;
+		},
+
+		/* Attach the date entry handler to an input field.
+		 @param  target   (element) the field to attach to
+		 @param  options  (object) custom settings for this instance */
+		_connectDateEntry: function(target, options) {
+			var input = $(target);
+			if (input.hasClass(this.markerClassName)) {
+				return;
+			}
+			var inst = {};
+			inst.options = $.extend({}, options);
+			inst._selectedYear = 0; // The currently selected year
+			inst._selectedMonth = 0; // The currently selected month
+			inst._selectedDay = 0; // The currently selected day
+			inst._field = 0; // The selected subfield
+			inst.input = $(target); // The attached input field
+			$.data(target, PROP_NAME, inst);
+			var spinnerImage = this._get(inst, 'spinnerImage');
+			var spinnerText = this._get(inst, 'spinnerText');
+			var spinnerSize = this._get(inst, 'spinnerSize');
+			var appendText = this._get(inst, 'appendText');
+			var spinner = (!spinnerImage ? null : $('<span class="dateEntry_control" style="display: inline-block; ' + 'background: url(\'' + spinnerImage + '\') 0 0 no-repeat; ' + 'width: ' + spinnerSize[0] + 'px; height: ' + spinnerSize[1] + 'px;' + ($.browser.mozilla && $.browser.version < '1.9' ? // FF 2- (Win)
+				' padding-left: ' + spinnerSize[0] + 'px; padding-bottom: ' + (spinnerSize[1] - 18) + 'px;' : '') + '"></span>'));
+			input.wrap('<span class="dateEntry_wrap"></span>').after(appendText ? '<span class="dateEntry_append">' + appendText + '</span>' : '').after(spinner || '');
+			input.addClass(this.markerClassName).bind('focus.dateEntry', this._doFocus).bind('blur.dateEntry', this._doBlur).bind('click.dateEntry', this._doClick).bind('keydown.dateEntry', this._doKeyDown).bind('keypress.dateEntry', this._doKeyPress);
+			// Check pastes
+			if ($.browser.mozilla) {
+				input.bind('input.dateEntry', function(event) {
+					$.dateEntry._parseDate(inst);
+				});
+			}
+			if ($.browser.msie) {
+				input.bind('paste.dateEntry', function(event) {
+						setTimeout(function() {
+							$.dateEntry._parseDate(inst);
+						}, 1);
+					});
+			}
+			// Allow mouse wheel usage
+			if (this._get(inst, 'useMouseWheel') && $.fn.mousewheel) {
+				input.mousewheel(this._doMouseWheel);
+			}
+			if (spinner) {
+				spinner.mousedown(this._handleSpinner).mouseup(this._endSpinner).mouseover(this._expandSpinner).mouseout(this._endSpinner).mousemove(this._describeSpinner);
+			}
+		},
+
+		/* Enable a date entry input and any associated spinner.
+		 @param  input  (element) single input field */
+		_enableDateEntry: function(input) {
+			this._enableDisable(input, false);
+		},
+
+		/* Disable a date entry input and any associated spinner.
+		 @param  input  (element) single input field */
+		_disableDateEntry: function(input) {
+			this._enableDisable(input, true);
+		},
+
+		/* Enable or disable a date entry input and any associated spinner.
+		 @param  input    (element) single input field
+		 @param  disable  (boolean) true to disable, false to enable */
+		_enableDisable: function(input, disable) {
+			var inst = $.data(input, PROP_NAME);
+			if (!inst) {
+				return;
+			}
+			input.disabled = disable;
+			if (input.nextSibling && input.nextSibling.nodeName.toLowerCase() == 'span') {
+				$.dateEntry._changeSpinner(inst, input.nextSibling, (disable ? 5 : -1));
+			}
+			$.dateEntry._disabledInputs = $.map($.dateEntry._disabledInputs, function(value) {
+					return (value == input ? null : value);
+				}); // Delete entry
+			if (disable) {
+				$.dateEntry._disabledInputs.push(input);
+			}
+		},
+
+		/* Check whether an input field has been disabled.
+		 @param  input  (element) input field to check
+		 @return  (boolean) true if this field has been disabled, false if it is enabled */
+		_isDisabledDateEntry: function(input) {
+			return $.inArray(input, this._disabledInputs) > -1;
+		},
+
+		/* Reconfigure the settings for a date entry field.
+		 @param  input  (element) input field to change
+		 @param  name   (object) new settings to add or
+		 (string) the option name
+		 @param  value  (any, optional) the option value */
+		_changeDateEntry: function(input, name, value) {
+			var inst = $.data(input, PROP_NAME);
+			if (inst) {
+				var options = name;
+				if (typeof name == 'string') {
+					options = {};
+					options[name] = value;
+				}
+				var currentDate = this._extractDate(inst.input.val(), inst);
+				extendRemove(inst.options, options || {});
+				if (currentDate) {
+					this._setDate(inst, currentDate);
+				}
+			}
+			$.data(input, PROP_NAME, inst);
+		},
+
+		/* Remove the date entry functionality from an input.
+		 @param  input  (element) input field to affect */
+		_destroyDateEntry: function(input) {
+			$input = $(input);
+			if (!$input.hasClass(this.markerClassName)) {
+				return;
+			}
+			$input.removeClass(this.markerClassName).unbind('.dateEntry');
+			if ($.fn.mousewheel) {
+				$input.unmousewheel();
+			}
+			this._disabledInputs = $.map(this._disabledInputs, function(value) {
+					return (value == input ? null : value);
+				}); // Delete entry
+			$input.parent().replaceWith($input);
+			$.removeData(input, PROP_NAME);
+		},
+
+		/* Initialise the current date for a date entry input field.
+		 @param  input  (element) input field to update
+		 @param  date   (Date) the new date or null for now */
+		_setDateDateEntry: function(input, date) {
+			var inst = $.data(input, PROP_NAME);
+			if (inst) {
+				if (date === null || date === '') {
+					inst.input.val('');
+				} else {
+					this._setDate(inst, date ? (typeof date == 'object' ? new Date(date.getTime()) : date) : null);
+				}
+			}
+		},
+
+		/* Retrieve the current date for a date entry input field.
+		 @param  input  (element) input field to update
+		 @return  (Date) current date or null if none */
+		_getDateDateEntry: function(input) {
+			var inst = $.data(input, PROP_NAME);
+			return (inst ? this._extractDate(inst.input.val(), inst) : null);
+		},
+
+		/* Initialise date entry.
+		 @param  target  (element) the input field or
+		 (event) the focus event */
+		_doFocus: function(target) {
+			var input = (target.nodeName && target.nodeName.toLowerCase() == 'input' ? target : this);
+			if ($.dateEntry._lastInput == input || $.dateEntry._isDisabledDateEntry(input)) {
+				$.dateEntry._focussed = false;
+				return;
+			}
+			var inst = $.data(input, PROP_NAME);
+			$.dateEntry._focussed = true;
+			$.dateEntry._lastInput = input;
+			$.dateEntry._blurredInput = null;
+			var beforeShow = $.dateEntry._get(inst, 'beforeShow');
+			extendRemove(inst.options, (beforeShow ? beforeShow.apply(input, [input]) : {}));
+			$.data(input, PROP_NAME, inst);
+			$.dateEntry._parseDate(inst);
+			setTimeout(function() {
+				$.dateEntry._showField(inst);
+			}, 10);
+		},
+
+		/* Note that the field has been exited.
+		 @param  event  (event) the blur event */
+		_doBlur: function(event) {
+			$.dateEntry._blurredInput = $.dateEntry._lastInput;
+			$.dateEntry._lastInput = null;
+		},
+
+		/* Select appropriate field portion on click, if already in the field.
+		 @param  event  (event) the click event */
+		_doClick: function(event) {
+			var input = event.target;
+			var inst = $.data(input, PROP_NAME);
+			if (!$.dateEntry._focussed) {
+				var dateFormat = $.dateEntry._get(inst, 'dateFormat');
+				inst._field = 0;
+				if (input.selectionStart != null) { // Use input select range
+					var end = 0;
+					for (var field = 0; field < 3; field++) {
+						end += $.dateEntry._fieldLength(inst, field, dateFormat) + 1;
+						inst._field = field;
+						if (input.selectionStart < end) {
+							break;
+						}
+					}
+				} else if (input.createTextRange) { // Check against bounding boxes
+					var src = $(event.srcElement);
+					var range = input.createTextRange();
+					var convert = function(value) {
+						return {thin: 2, medium: 4, thick: 6}[value] || value;
+					};
+					var offsetX = event.clientX + document.documentElement.scrollLeft - (src.offset().left + parseInt(convert(src.css('border-left-width')), 10)) - range.offsetLeft; // Position - left edge - alignment
+					var end = 0;
+					for (var field = 0; field < 3; field++) {
+						end += $.dateEntry._fieldLength(inst, field, dateFormat) + 1;
+						range.collapse();
+						range.moveEnd('character', end);
+						inst._field = field;
+						if (offsetX < range.boundingWidth) { // And compare
+							break;
+						}
+					}
+				}
+			}
+			$.data(input, PROP_NAME, inst);
+			$.dateEntry._showField(inst);
+			$.dateEntry._focussed = false;
+		},
+
+		/* Handle keystrokes in the field.
+		 @param  event  (event) the keydown event
+		 @return  (boolean) true to continue, false to stop processing */
+		_doKeyDown: function(event) {
+			if (event.keyCode >= 48) { // >= '0'
+				return true;
+			}
+			var inst = $.data(event.target, PROP_NAME);
+			switch (event.keyCode) {
+				case 9:
+					return (event.shiftKey ? // Move to previous date field, or out if at the beginning
+						$.dateEntry._changeField(inst, -1, true) : // Move to next date field, or out if at the end
+						$.dateEntry._changeField(inst, +1, true));
+				case 35:
+					if (event.ctrlKey) { // Clear date on ctrl+end
+						$.dateEntry._setValue(inst, '');
+					} else { // Last field on end
+						inst._field = 2;
+						$.dateEntry._adjustField(inst, 0);
+					}
+					break;
+				case 36:
+					if (event.ctrlKey) { // Current date on ctrl+home
+						$.dateEntry._setDate(inst);
+					} else { // First field on home
+						inst._field = 0;
+						$.dateEntry._adjustField(inst, 0);
+					}
+					break;
+				case 37:
+					$.dateEntry._changeField(inst, -1, false);
+					break; // Previous field on left
+				case 38:
+					$.dateEntry._adjustField(inst, +1);
+					break; // Increment date field on up
+				case 39:
+					$.dateEntry._changeField(inst, +1, false);
+					break; // Next field on right
+				case 40:
+					$.dateEntry._adjustField(inst, -1);
+					break; // Decrement date field on down
+				case 46:
+					$.dateEntry._setValue(inst, '');
+					break; // Clear date on delete
+			}
+			return false;
+		},
+
+		/* Disallow unwanted characters.
+		 @param  event  (event) the keypress event
+		 @return  (boolean) true to continue, false to stop processing */
+		_doKeyPress: function(event) {
+			var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode);
+			if (chr < ' ') {
+				return true;
+			}
+			var inst = $.data(event.target, PROP_NAME);
+			$.dateEntry._handleKeyPress(inst, chr);
+			return false;
+		},
+
+		/* Increment/decrement on mouse wheel activity.
+		 @param  event  (event) the mouse wheel event
+		 @param  delta  (number) the amount of change */
+		_doMouseWheel: function(event, delta) {
+			if ($.dateEntry._isDisabledDateEntry(event.target)) {
+				return;
+			}
+			delta = ($.browser.opera ? -delta / Math.abs(delta) : ($.browser.safari ? delta / Math.abs(delta) : delta));
+			var inst = $.data(event.target, PROP_NAME);
+			inst.input.focus();
+			if (!inst.input.val()) {
+				$.dateEntry._parseDate(inst);
+			}
+			$.dateEntry._adjustField(inst, delta);
+			event.preventDefault();
+		},
+
+		/* Expand the spinner, if possible, to make it easier to use.
+		 @param  event  (event) the mouse over event */
+		_expandSpinner: function(event) {
+			var spinner = $.dateEntry._getSpinnerTarget(event);
+			var inst = $.data($.dateEntry._getInput(spinner), PROP_NAME);
+			if ($.dateEntry._isDisabledDateEntry(inst.input[0])) {
+				return;
+			}
+			var spinnerBigImage = $.dateEntry._get(inst, 'spinnerBigImage');
+			if (spinnerBigImage) {
+				inst._expanded = true;
+				var offset = $(spinner).offset();
+				var relative = null;
+				$(spinner).parents().each(function() {
+					var parent = $(this);
+					if (parent.css('position') == 'relative' || parent.css('position') == 'absolute') {
+						relative = parent.offset();
+					}
+					return !relative;
+				});
+				var spinnerSize = $.dateEntry._get(inst, 'spinnerSize');
+				var spinnerBigSize = $.dateEntry._get(inst, 'spinnerBigSize');
+				$('<div class="dateEntry_expand" style="position: absolute; left: ' + (offset.left - (spinnerBigSize[0] - spinnerSize[0]) / 2 - (relative ? relative.left : 0)) + 'px; top: ' + (offset.top - (spinnerBigSize[1] - spinnerSize[1]) / 2 - (relative ? relative.top : 0)) + 'px; width: ' + spinnerBigSize[0] + 'px; height: ' + spinnerBigSize[1] + 'px; background: transparent url(' + spinnerBigImage + ') no-repeat 0px 0px; z-index: 10;"></div>').mousedown($.dateEntry._handleSpinner).mouseup($.dateEntry._endSpinner).mouseout($.dateEntry._endExpand).mousemove($.dateEntry._describeSpinner).insertAfter(spinner);
+			}
+		},
+
+		/* Locate the actual input field from the spinner.
+		 @param  spinner  (element) the current spinner
+		 @return  (element) the corresponding input */
+		_getInput: function(spinner) {
+			return $(spinner).siblings('.' + $.dateEntry.markerClassName)[0];
+		},
+
+		/* Change the title based on position within the spinner.
+		 @param  event  (event) the mouse move event */
+		_describeSpinner: function(event) {
+			var spinner = $.dateEntry._getSpinnerTarget(event);
+			var inst = $.data($.dateEntry._getInput(spinner), PROP_NAME);
+			spinner.title = $.dateEntry._get(inst, 'spinnerTexts')
+				[$.dateEntry._getSpinnerRegion(inst, event)];
+		},
+
+		/* Handle a click on the spinner.
+		 @param  event  (event) the mouse click event */
+		_handleSpinner: function(event) {
+			var spinner = $.dateEntry._getSpinnerTarget(event);
+			var input = $.dateEntry._getInput(spinner);
+			if ($.dateEntry._isDisabledDateEntry(input)) {
+				return;
+			}
+			if (input == $.dateEntry._blurredInput) {
+				$.dateEntry._lastInput = input;
+				$.dateEntry._blurredInput = null;
+			}
+			var inst = $.data(input, PROP_NAME);
+			$.dateEntry._doFocus(input);
+			var region = $.dateEntry._getSpinnerRegion(inst, event);
+			$.dateEntry._changeSpinner(inst, spinner, region);
+			$.dateEntry._actionSpinner(inst, region);
+			$.dateEntry._timer = null;
+			$.dateEntry._handlingSpinner = true;
+			var spinnerRepeat = $.dateEntry._get(inst, 'spinnerRepeat');
+			if (region >= 3 && spinnerRepeat[0]) { // Repeat increment/decrement
+				$.dateEntry._timer = setTimeout(function() {
+						$.dateEntry._repeatSpinner(inst, region);
+					}, spinnerRepeat[0]);
+				$(spinner).one('mouseout', $.dateEntry._releaseSpinner).one('mouseup', $.dateEntry._releaseSpinner);
+			}
+		},
+
+		/* Action a click on the spinner.
+		 @param  inst    (object) the instance settings
+		 @param  region  (number) the spinner "button" */
+		_actionSpinner: function(inst, region) {
+			if (!inst.input.val()) {
+				$.dateEntry._parseDate(inst);
+			}
+			switch (region) {
+				case 0:
+					this._setDate(inst);
+					break;
+				case 1:
+					this._changeField(inst, -1, false);
+					break;
+				case 2:
+					this._changeField(inst, +1, false);
+					break;
+				case 3:
+					this._adjustField(inst, +1);
+					break;
+				case 4:
+					this._adjustField(inst, -1);
+					break;
+			}
+		},
+
+		/* Repeat a click on the spinner.
+		 @param  inst    (object) the instance settings
+		 @param  region  (number) the spinner "button" */
+		_repeatSpinner: function(inst, region) {
+			if (!$.dateEntry._timer) {
+				return;
+			}
+			$.dateEntry._lastInput = $.dateEntry._blurredInput;
+			this._actionSpinner(inst, region);
+			this._timer = setTimeout(function() {
+					$.dateEntry._repeatSpinner(inst, region);
+				}, this._get(inst, 'spinnerRepeat')[1]);
+		},
+
+		/* Stop a spinner repeat.
+		 @param  event  (event) the mouse event */
+		_releaseSpinner: function(event) {
+			clearTimeout($.dateEntry._timer);
+			$.dateEntry._timer = null;
+		},
+
+		/* Tidy up after an expanded spinner.
+		 @param  event  (event) the mouse event */
+		_endExpand: function(event) {
+			$.dateEntry._timer = null;
+			var spinner = $.dateEntry._getSpinnerTarget(event);
+			var input = $.dateEntry._getInput(spinner);
+			var inst = $.data(input, PROP_NAME);
+			$(spinner).remove();
+			inst._expanded = false;
+		},
+
+		/* Tidy up after a spinner click.
+		 @param  event  (event) the mouse event */
+		_endSpinner: function(event) {
+			$.dateEntry._timer = null;
+			var spinner = $.dateEntry._getSpinnerTarget(event);
+			var input = $.dateEntry._getInput(spinner);
+			var inst = $.data(input, PROP_NAME);
+			if (!$.dateEntry._isDisabledDateEntry(input)) {
+				$.dateEntry._changeSpinner(inst, spinner, -1);
+			}
+			if ($.dateEntry._handlingSpinner) {
+				$.dateEntry._lastInput = $.dateEntry._blurredInput;
+			}
+			if ($.dateEntry._lastInput && $.dateEntry._handlingSpinner) {
+				$.dateEntry._showField(inst);
+			}
+			$.dateEntry._handlingSpinner = false;
+		},
+
+		/* Retrieve the spinner from the event.
+		 @param  event  (event) the mouse click event
+		 @return  (element) the target field */
+		_getSpinnerTarget: function(event) {
+			return event.target || event.srcElement;
+		},
+
+		/* Determine which "button" within the spinner was clicked.
+		 @param  inst   (object) the instance settings
+		 @param  event  (event) the mouse event
+		 @return  (number) the spinner "button" number */
+		_getSpinnerRegion: function(inst, event) {
+			var spinner = this._getSpinnerTarget(event);
+			var pos = ($.browser.opera || $.browser.safari ? $.dateEntry._findPos(spinner) : $(spinner).offset());
+			var scrolled = ($.browser.safari ? $.dateEntry._findScroll(spinner) : [document.documentElement.scrollLeft || document.body.scrollLeft,
+				document.documentElement.scrollTop || document.body.scrollTop]);
+			var spinnerIncDecOnly = this._get(inst, 'spinnerIncDecOnly');
+			var left = (spinnerIncDecOnly ? 99 : event.clientX + scrolled[0] - pos.left - ($.browser.msie ? 2 : 0));
+			var top = event.clientY + scrolled[1] - pos.top - ($.browser.msie ? 2 : 0);
+			var spinnerSize = this._get(inst, (inst._expanded ? 'spinnerBigSize' : 'spinnerSize'));
+			var right = (spinnerIncDecOnly ? 99 : spinnerSize[0] - 1 - left);
+			var bottom = spinnerSize[1] - 1 - top;
+			if (spinnerSize[2] > 0 && Math.abs(left - right) <= spinnerSize[2] && Math.abs(top - bottom) <= spinnerSize[2]) {
+				return 0; // Centre button
+			}
+			var min = Math.min(left, top, right, bottom);
+			return (min == left ? 1 : (min == right ? 2 : (min == top ? 3 : 4))); // Nearest edge
+		},
+
+		/* Change the spinner image depending on button clicked.
+		 @param  inst     (object) the instance settings
+		 @param  spinner  (element) the spinner control
+		 @param  region   (number) the spinner "button" */
+		_changeSpinner: function(inst, spinner, region) {
+			$(spinner).css('background-position', '-' + ((region + 1) * this._get(inst, (inst._expanded ? 'spinnerBigSize' : 'spinnerSize'))[0]) + 'px 0px');
+		},
+
+		/* Find an object's position on the screen.
+		 @param  obj  (element) the control
+		 @return  (object) position as .left and .top */
+		_findPos: function(obj) {
+			var curLeft = curTop = 0;
+			if (obj.offsetParent) {
+				curLeft = obj.offsetLeft;
+				curTop = obj.offsetTop;
+				while (obj = obj.offsetParent) {
+					var origCurLeft = curLeft;
+					curLeft += obj.offsetLeft;
+					if (curLeft < 0) {
+						curLeft = origCurLeft;
+					}
+					curTop += obj.offsetTop;
+				}
+			}
+			return {left: curLeft, top: curTop};
+		},
+
+		/* Find an object's scroll offset on the screen.
+		 @param  obj  (element) the control
+		 @return  (number[]) offset as [left, top] */
+		_findScroll: function(obj) {
+			var isFixed = false;
+			$(obj).parents().each(function() {
+				isFixed |= $(this).css('position') == 'fixed';
+			});
+			if (isFixed) {
+				return [0, 0];
+			}
+			var scrollLeft = obj.scrollLeft;
+			var scrollTop = obj.scrollTop;
+			while (obj = obj.parentNode) {
+				scrollLeft += obj.scrollLeft || 0;
+				scrollTop += obj.scrollTop || 0;
+			}
+			return [scrollLeft, scrollTop];
+		},
+
+		/* Get a setting value, defaulting if necessary.
+		 @param  inst  (object) the instance settings
+		 @param  name  (string) the setting name
+		 @return  (any) the setting value */
+		_get: function(inst, name) {
+			return (inst.options[name] != null ? inst.options[name] : $.dateEntry._defaults[name]);
+		},
+
+		/* Extract the date value from the input field, or default to now.
+		 @param  inst  (object) the instance settings */
+		_parseDate: function(inst) {
+			var currentDate = this._extractDate(inst.input.val(), inst) || this._normaliseDate(this._determineDate(this._get(inst, 'defaultDate'), inst) || new Date());
+			inst._selectedYear = currentDate.getFullYear();
+			inst._selectedMonth = currentDate.getMonth();
+			inst._selectedDay = currentDate.getDate();
+			inst._lastChr = '';
+			inst._field = Math.max(0, Math.min(2, this._get(inst, 'initialField')));
+			if (inst.input.val() != '') {
+				this._showDate(inst);
+			}
+		},
+
+		/* Extract the date value from a string.
+		 @param  value  (string) the date text
+		 @param  inst   (object) the instance settings
+		 @return  (Date) the retrieved date or null if no value */
+		_extractDate: function(value, inst) {
+			var dateFormat = this._get(inst, 'dateFormat');
+			var values = value.split(new RegExp('[\\' + dateFormat.substr(-1).split('').join('\\') + ']'));
+			var year = inst._selectedYear;
+			var month = inst._selectedMonth + 1;
+			var day = inst._selectedDay;
+			for (var i = 0, l = values.length; i < l; i++) {
+				var num = parseInt(values[i], 10);
+				num = (isNaN(num) ? 0 : num);
+				var field = dateFormat.charAt(i);
+				switch (field) {
+					case 'y':
+						year = num;
+						break;
+					case 'Y':
+						year = (num % 100) + (new Date().getFullYear() - new Date().getFullYear() % 100);
+						break;
+					case 'm':
+						month = num;
+						break;
+					case 'n':
+					case 'N':
+						month = $.inArray(values[i], this._get(inst, (field == 'N' ? 'monthNames' : 'monthNamesShort'))) + 1;
+						break;
+					case 'w':
+					case 'W':
+						if (dateFormat.charAt(3) == ' ') {
+							values.splice(i, 1);
+							num = parseInt(values[i], 10);
+						} else {
+							num = parseInt(values[i].substr(this._get(inst, (field == 'W' ? 'dayNames' : 'dayNamesShort'))[0].length + 1), 10);
+						}
+						num = (isNaN(num) ? 0 : num); // Fall through
+					case 'd':
+						day = num;
+						break;
+				}
+			}
+
+			return new Date(year, month - 1, day, 12);
+		},
+
+		/* Set the selected date into the input field.
+		 @param  inst  (object) the instance settings */
+		_showDate: function(inst) {
+			this._setValue(inst, this._formatDate(inst, this._get(inst, 'dateFormat')));
+			this._showField(inst);
+		},
+
+		/* Format a date as requested.
+		 @param  inst    (object) the instance settings
+		 @param  format  (string) the date format to use
+		 @return  (string) the formatted date */
+		_formatDate: function(inst, format) {
+			var currentDate = '';
+			for (var i = 0, l = format.length - 1; i < l; i++) {
+				currentDate += (i == 0 ? '' : format.charAt(format.length - 1));
+				var field = format.charAt(i);
+				switch (field) {
+					case 'y':
+						currentDate += this._formatNumber(inst._selectedYear);
+						break;
+					case 'Y':
+						currentDate += this._formatNumber(inst._selectedYear % 100);
+						break;
+					case 'm':
+						currentDate += this._formatNumber(inst._selectedMonth + 1);
+						break;
+					case 'n':
+					case 'N':
+						currentDate += this._get(inst, (field == 'N' ? 'monthNames' : 'monthNamesShort'))[inst._selectedMonth];
+						break;
+					case 'd':
+						currentDate += this._formatNumber(inst._selectedDay);
+						break;
+					case 'w':
+					case 'W':
+						currentDate += this._get(inst, (field == 'W' ? 'dayNames' : 'dayNamesShort'))[
+							new Date(inst._selectedYear, inst._selectedMonth, inst._selectedDay, 12).getDay()] + ' ' + this._formatNumber(inst._selectedDay);
+						break;
+				}
+			}
+			return currentDate;
+		},
+
+		/* Highlight the current date field.
+		 @param  inst  (object) the instance settings */
+		_showField: function(inst) {
+			var input = inst.input[0];
+			if (inst.input.is(':hidden') || $.dateEntry._lastInput != input) {
+				return;
+			}
+			var dateFormat = this._get(inst, 'dateFormat');
+			var start = 0;
+			for (var i = 0; i < inst._field; i++) {
+				start += this._fieldLength(inst, i, dateFormat) + 1;
+			}
+			var end = start + this._fieldLength(inst, i, dateFormat);
+			if (input.setSelectionRange) { // Mozilla
+				input.setSelectionRange(start, end);
+			} else if (input.createTextRange) { // IE
+				var range = input.createTextRange();
+				range.moveStart('character', start);
+				range.moveEnd('character', end - inst.input.val().length);
+				range.select();
+			}
+			if (!input.disabled) {
+				input.focus();
+			}
+		},
+
+		/* Calculate the field length.
+		 @param  inst        (object) the instance settings
+		 @param  field       (number) the field number (0-2)
+		 @param  dateFormat  (string) the format for the date display
+		 @return  (number) the length of this subfield */
+		_fieldLength: function(inst, field, dateFormat) {
+			field = dateFormat.charAt(field);
+			switch (field) {
+				case 'y':
+					return 4;
+				case 'n':
+				case 'N':
+					return this._get(inst, (field == 'N' ? 'monthNames' : 'monthNamesShort'))
+						[inst._selectedMonth].length;
+				case 'w':
+				case 'W':
+					return this._get(inst, (field == 'W' ? 'dayNames' : 'dayNamesShort'))
+						[new Date(inst._selectedYear, inst._selectedMonth, inst._selectedDay, 12).getDay()].length + 3;
+				default:
+					return 2;
+			}
+		},
+
+		/* Ensure displayed single number has a leading zero.
+		 @param  value  (number) current value
+		 @return  (string) number with at least two digits */
+		_formatNumber: function(value) {
+			return (value < 10 ? '0' : '') + value;
+		},
+
+		/* Update the input field and notify listeners.
+		 @param  inst   (object) the instance settings
+		 @param  value  (string) the new value */
+		_setValue: function(inst, value) {
+			if (value != inst.input.val()) {
+				var altField = this._get(inst, 'altField');
+				if (altField) {
+					$(altField).val(!value ? '' : this._formatDate(inst, this._get(inst, 'altFormat') || this._get(inst, 'dateFormat')));
+				}
+				inst.input.val(value).trigger('change');
+			}
+		},
+
+		/* Move to previous/next field, or out of field altogether if appropriate.
+		 @param  inst     (object) the instance settings
+		 @param  offset   (number) the direction of change (-1, +1)
+		 @param  moveOut  (boolean) true if can move out of the field
+		 @return  (boolean) true if exitting the field, false if not */
+		_changeField: function(inst, offset, moveOut) {
+			var atFirstLast = (inst.input.val() == '' || inst._field == (offset == -1 ? 0 : 2));
+			if (!atFirstLast) {
+				inst._field += offset;
+			}
+			this._showField(inst);
+			inst._lastChr = '';
+			$.data(inst.input[0], PROP_NAME, inst);
+			return (atFirstLast && moveOut);
+		},
+
+		/* Update the current field in the direction indicated.
+		 @param  inst    (object) the instance settings
+		 @param  offset  (number) the amount to change by */
+		_adjustField: function(inst, offset) {
+			if (inst.input.val() == '') {
+				offset = 0;
+			}
+			var field = this._get(inst, 'dateFormat').charAt(inst._field);
+			var year = inst._selectedYear + (field == 'y' || field == 'Y' ? offset : 0);
+			var month = inst._selectedMonth + (field == 'm' || field == 'n' || field == 'N' ? offset : 0);
+			var day = (field == 'd' || field == 'w' || field == 'W' ? inst._selectedDay + offset : Math.min(inst._selectedDay, this._getDaysInMonth(year, month)));
+			this._setDate(inst, new Date(year, month, day, 12));
+		},
+
+		/* Find the number of days in a given month.
+		 @param  year   (number) the full year
+		 @param  month  (number) the month (0 to 11)
+		 @return  (number) the number of days in this month */
+		_getDaysInMonth: function(year, month) {
+			return new Date(year, month + 1, 0, 12).getDate();
+		},
+
+		/* Check against minimum/maximum and display date.
+		 @param  inst  (object) the instance settings
+		 @param  date  (Date) an actual date or
+		 (number) offset in days from now or
+		 (string) units and periods of offsets from now */
+		_setDate: function(inst, date) {
+			// Normalise to base time
+			date = this._normaliseDate(this._determineDate(date || this._get(inst, 'defaultDate'), inst) || new Date());
+			var minDate = this._normaliseDate(this._determineDate(this._get(inst, 'minDate'), inst));
+			var maxDate = this._normaliseDate(this._determineDate(this._get(inst, 'maxDate'), inst));
+			// Ensure it is within the bounds set
+			date = (minDate && date < minDate ? minDate : (maxDate && date > maxDate ? maxDate : date));
+			inst._selectedYear = date.getFullYear();
+			inst._selectedMonth = date.getMonth();
+			inst._selectedDay = date.getDate();
+			this._showDate(inst);
+			$.data(inst.input[0], PROP_NAME, inst);
+		},
+
+		/* A date may be specified as an exact value or a relative one.
+		 @param  setting  (Date) an actual date or
+		 (string) date in current format
+		 (number) offset in days from now or
+		 (string) units and periods of offsets from now
+		 @param  inst     (object) the instance settings
+		 @return  (Date) the calculated date */
+		_determineDate: function(setting, inst) {
+			var offsetNumeric = function(offset) { // E.g. +300, -2
+				var date = $.dateEntry._normaliseDate(new Date());
+				date.setDate(date.getDate() + offset);
+				return date;
+			};
+			var offsetString = function(offset) { // E.g. '+2m', '-1w', '+3m +10d'
+				var date = $.dateEntry._extractDate(offset, inst);
+				if (date) {
+					return date;
+				}
+				offset = offset.toLowerCase();
+				date = $.dateEntry._normaliseDate(new Date());
+				var year = date.getFullYear();
+				var month = date.getMonth();
+				var day = date.getDate();
+				var pattern = /([+-]?[0-9]+)\s*(d|w|m|y)?/g;
+				var matches = pattern.exec(offset);
+				while (matches) {
+					switch (matches[2] || 'd') {
+						case 'd':
+							day += parseInt(matches[1], 10);
+							break;
+						case 'w':
+							day += parseInt(matches[1], 10) * 7;
+							break;
+						case 'm':
+							month += parseInt(matches[1], 10);
+							break;
+						case 'y':
+							year += parseInt(matches[1], 10);
+							break;
+					}
+					matches = pattern.exec(offset);
+				}
+				return new Date(year, month, day, 12);
+			};
+			return (setting ? (typeof setting == 'string' ? offsetString(setting) : (typeof setting == 'number' ? offsetNumeric(setting) : setting)) : null);
+		},
+
+		/* Normalise date object to a common time.
+		 @param  date  (Date) the original date
+		 @return  (Date) the normalised date */
+		_normaliseDate: function(date) {
+			if (date) {
+				date.setHours(12, 0, 0, 0);
+			}
+			return date;
+		},
+
+		/* Update date based on keystroke entered.
+		 @param  inst  (object) the instance settings
+		 @param  chr   (ch) the new character */
+		_handleKeyPress: function(inst, chr) {
+			var dateFormat = this._get(inst, 'dateFormat');
+			if (dateFormat.substring(3).indexOf(chr) > -1) {
+				this._changeField(inst, +1, false);
+			} else if (chr >= '0' && chr <= '9') { // Allow direct entry of date
+				var field = dateFormat.charAt(inst._field);
+				var key = parseInt(chr, 10);
+				var value = parseInt((inst._lastChr || '') + chr, 10);
+				var year = (field != 'y' && field != 'Y' ? inst._selectedYear : value);
+				var month = (field != 'm' && field != 'n' && field != 'N' ? inst._selectedMonth + 1 : (value >= 1 && value <= 12 ? value : (key > 0 ? key : inst._selectedMonth + 1)));
+				var day = (field != 'd' && field != 'w' && field != 'W' ? inst._selectedDay : (value >= 1 && value <= this._getDaysInMonth(year, month - 1) ? value : (key > 0 ? key : inst._selectedDay)));
+				this._setDate(inst, new Date(year, month - 1, day, 12));
+				inst._lastChr = (field != 'y' ? '' : inst._lastChr.substr(Math.max(0, inst._lastChr.length - 2))) + chr;
+			} else { // Allow text entry by month name
+				var field = dateFormat.charAt(inst._field);
+				if (field == 'n' || field == 'N') {
+					inst._lastChr += chr.toLowerCase();
+					var names = this._get(inst, (field == 'n' ? 'monthNamesShort' : 'monthNames'));
+					var findMonth = function() {
+						for (var i = 0; i < names.length; i++) {
+							if (names[i].toLowerCase().substring(0, inst._lastChr.length) == inst._lastChr) {
+								return i;
+								break;
+							}
+						}
+						return -1;
+					};
+					var month = findMonth();
+					if (month == -1) {
+						inst._lastChr = chr.toLowerCase();
+						month = findMonth();
+					}
+					if (month == -1) {
+						inst._lastChr = '';
+					} else {
+						var year = inst._selectedYear;
+						var day = Math.min(inst._selectedDay, this._getDaysInMonth(year, month));
+						this._setDate(inst, new Date(year, month, day, 12));
+					}
+				}
+			}
+		}
+	});
+
+	/* jQuery extend now ignores nulls!
+	 @param  target  (object) the object to update
+	 @param  props   (object) the new settings
+	 @return  (object) the updated object */
+	function extendRemove(target, props) {
+		$.extend(target, props);
+		for (var name in props) {
+			if (props[name] == null) {
+				target[name] = null;
+			}
+		}
+		return target;
+	}
+
+	/* Attach the date entry functionality to a jQuery selection.
+	 @param  command  (string) the command to run (optional, default 'attach')
+	 @param  options  (object) the new settings to use for these countdown instances (optional)
+	 @return  (jQuery) for chaining further calls */
+	$.fn.dateEntry = function(options) {
+		var otherArgs = Array.prototype.slice.call(arguments, 1);
+		if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate')) {
+			return $.dateEntry['_' + options + 'DateEntry'].apply($.dateEntry, [this[0]].concat(otherArgs));
+		}
+		return this.each(function() {
+			var nodeName = this.nodeName.toLowerCase();
+			if (nodeName == 'input') {
+				if (typeof options == 'string') {
+					$.dateEntry['_' + options + 'DateEntry'].apply($.dateEntry, [this].concat(otherArgs));
+				} else {
+					// Check for settings on the control itself
+					var inlineSettings = ($.fn.metadata ? $(this).metadata() : {});
+					$.dateEntry._connectDateEntry(this, $.extend(inlineSettings, options));
+				}
+			}
+		});
+	};
+
+	/* Initialise the date entry functionality. */
+	$.dateEntry = new DateEntry(); // Singleton instance
+
+})(jQuery);

Added: trunk/htdocs/js/jquery/jquery.dateentry.min.js
===================================================================
--- trunk/htdocs/js/jquery/jquery.dateentry.min.js	                        (rev 0)
+++ trunk/htdocs/js/jquery/jquery.dateentry.min.js	2011-11-25 13:36:04 UTC (rev 20627)
@@ -0,0 +1,7 @@
+/* http://keith-wood.name/dateEntry.html
+   Date entry for jQuery v1.0.6.
+   Written by Keith Wood (kbwood{at}iinet.com.au) March 2009.
+   Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and
+   MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses.
+   Please attribute the author if you use it. */
+(function(b){function m(){this._disabledInputs=[];this.regional=[];this.regional[""]={dateFormat:"mdy/",monthNames:"January,February,March,April,May,June,July,August,September,October,November,December".split(","),monthNamesShort:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(","),dayNames:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(","),dayNamesShort:"Sun,Mon,Tue,Wed,Thu,Fri,Sat".split(","),spinnerTexts:["Today","Previous field","Next field","Increment","Decrement"]}; this._defaults={appendText:"",initialField:0,useMouseWheel:!0,defaultDate:null,minDate:null,maxDate:null,spinnerImage:"spinnerDefault.png",spinnerSize:[20,20,8],spinnerBigImage:"",spinnerBigSize:[40,40,16],spinnerIncDecOnly:!1,spinnerRepeat:[500,250],beforeShow:null,altField:null,altFormat:null};b.extend(this._defaults,this.regional[""])}function l(a,c){b.extend(a,c);for(var d in c)null==c[d]&&(a[d]=null);return a}b.extend(m.prototype,{markerClassName:"hasDateEntry",setDefaults:function(a){l(this._defaults, a||{});return this},_connectDateEntry:function(a,c){var d=b(a);if(!d.hasClass(this.markerClassName)){var e={};e.options=b.extend({},c);e._selectedYear=0;e._selectedMonth=0;e._selectedDay=0;e._field=0;e.input=b(a);b.data(a,"dateEntry",e);var f=this._get(e,"spinnerImage");this._get(e,"spinnerText");var g=this._get(e,"spinnerSize"),h=this._get(e,"appendText"),f=!f?null:b('<span class="dateEntry_control" style="display: inline-block; background: url(\''+f+"') 0 0 no-repeat; width: "+g[0]+"px; height: "+ g[1]+"px;"+(b.browser.mozilla&&"1.9">b.browser.version?" padding-left: "+g[0]+"px; padding-bottom: "+(g[1]-18)+"px;":"")+'"></span>');d.wrap('<span class="dateEntry_wrap"></span>').after(h?'<span class="dateEntry_append">'+h+"</span>":"").after(f||"");d.addClass(this.markerClassName).bind("focus.dateEntry",this._doFocus).bind("blur.dateEntry",this._doBlur).bind("click.dateEntry",this._doClick).bind("keydown.dateEntry",this._doKeyDown).bind("keypress.dateEntry",this._doKeyPress);b.browser.mozilla&& d.bind("input.dateEntry",function(){b.dateEntry._parseDate(e)});b.browser.msie&&d.bind("paste.dateEntry",function(){setTimeout(function(){b.dateEntry._parseDate(e)},1)});this._get(e,"useMouseWheel")&&b.fn.mousewheel&&d.mousewheel(this._doMouseWheel);f&&f.mousedown(this._handleSpinner).mouseup(this._endSpinner).mouseover(this._expandSpinner).mouseout(this._endSpinner).mousemove(this._describeSpinner)}},_enableDateEntry:function(a){this._enableDisable(a,!1)},_disableDateEntry:function(a){this._enableDisable(a, !0)},_enableDisable:function(a,c){var d=b.data(a,"dateEntry");if(d)a.disabled=c,a.nextSibling&&"span"==a.nextSibling.nodeName.toLowerCase()&&b.dateEntry._changeSpinner(d,a.nextSibling,c?5:-1),b.dateEntry._disabledInputs=b.map(b.dateEntry._disabledInputs,function(c){return c==a?null:c}),c&&b.dateEntry._disabledInputs.push(a)},_isDisabledDateEntry:function(a){return-1<b.inArray(a,this._disabledInputs)},_changeDateEntry:function(a,c,d){var e=b.data(a,"dateEntry");if(e){var f=c;"string"==typeof c&&(f= {},f[c]=d);c=this._extractDate(e.input.val(),e);l(e.options,f||{});c&&this._setDate(e,c)}b.data(a,"dateEntry",e)},_destroyDateEntry:function(a){$input=b(a);if($input.hasClass(this.markerClassName))$input.removeClass(this.markerClassName).unbind(".dateEntry"),b.fn.mousewheel&&$input.unmousewheel(),this._disabledInputs=b.map(this._disabledInputs,function(c){return c==a?null:c}),$input.parent().replaceWith($input),b.removeData(a,"dateEntry")},_setDateDateEntry:function(a,c){var d=b.data(a,"dateEntry"); d&&(null===c||""===c?d.input.val(""):this._setDate(d,c?"object"==typeof c?new Date(c.getTime()):c:null))},_getDateDateEntry:function(a){return(a=b.data(a,"dateEntry"))?this._extractDate(a.input.val(),a):null},_doFocus:function(a){a=a.nodeName&&"input"==a.nodeName.toLowerCase()?a:this;if(b.dateEntry._lastInput==a||b.dateEntry._isDisabledDateEntry(a))b.dateEntry._focussed=!1;else{var c=b.data(a,"dateEntry");b.dateEntry._focussed=!0;b.dateEntry._lastInput=a;b.dateEntry._blurredInput=null;var d=b.dateEntry._get(c, "beforeShow");l(c.options,d?d.apply(a,[a]):{});b.data(a,"dateEntry",c);b.dateEntry._parseDate(c);setTimeout(function(){b.dateEntry._showField(c)},10)}},_doBlur:function(){b.dateEntry._blurredInput=b.dateEntry._lastInput;b.dateEntry._lastInput=null},_doClick:function(a){var c=a.target,d=b.data(c,"dateEntry");if(!b.dateEntry._focussed){var e=b.dateEntry._get(d,"dateFormat");d._field=0;if(null!=c.selectionStart)for(var f=0,a=0;3>a&&!(f+=b.dateEntry._fieldLength(d,a,e)+1,d._field=a,c.selectionStart<f);a++); else if(c.createTextRange)for(var f=b(a.srcElement),g=c.createTextRange(),a=a.clientX+document.documentElement.scrollLeft,h=f.offset().left,i=parseInt,f=f.css("border-left-width"),h=a-(h+i({thin:2,medium:4,thick:6}[f]||f,10))-g.offsetLeft,a=f=0;3>a&&!(f+=b.dateEntry._fieldLength(d,a,e)+1,g.collapse(),g.moveEnd("character",f),d._field=a,h<g.boundingWidth);a++);}b.data(c,"dateEntry",d);b.dateEntry._showField(d);b.dateEntry._focussed=!1},_doKeyDown:function(a){if(48<=a.keyCode)return!0;var c=b.data(a.target, "dateEntry");switch(a.keyCode){case 9:return a.shiftKey?b.dateEntry._changeField(c,-1,!0):b.dateEntry._changeField(c,1,!0);case 35:a.ctrlKey?b.dateEntry._setValue(c,""):(c._field=2,b.dateEntry._adjustField(c,0));break;case 36:a.ctrlKey?b.dateEntry._setDate(c):(c._field=0,b.dateEntry._adjustField(c,0));break;case 37:b.dateEntry._changeField(c,-1,!1);break;case 38:b.dateEntry._adjustField(c,1);break;case 39:b.dateEntry._changeField(c,1,!1);break;case 40:b.dateEntry._adjustField(c,-1);break;case 46:b.dateEntry._setValue(c, "")}return!1},_doKeyPress:function(a){var c=String.fromCharCode(void 0==a.charCode?a.keyCode:a.charCode);if(" ">c)return!0;a=b.data(a.target,"dateEntry");b.dateEntry._handleKeyPress(a,c);return!1},_doMouseWheel:function(a,c){if(!b.dateEntry._isDisabledDateEntry(a.target)){var c=b.browser.opera?-c/Math.abs(c):b.browser.safari?c/Math.abs(c):c,d=b.data(a.target,"dateEntry");d.input.focus();d.input.val()||b.dateEntry._parseDate(d);b.dateEntry._adjustField(d,c);a.preventDefault()}},_expandSpinner:function(a){var a= b.dateEntry._getSpinnerTarget(a),c=b.data(b.dateEntry._getInput(a),"dateEntry");if(!b.dateEntry._isDisabledDateEntry(c.input[0])){var d=b.dateEntry._get(c,"spinnerBigImage");if(d){c._expanded=!0;var e=b(a).offset(),f=null;b(a).parents().each(function(){var a=b(this);if("relative"==a.css("position")||"absolute"==a.css("position"))f=a.offset();return!f});var g=b.dateEntry._get(c,"spinnerSize"),c=b.dateEntry._get(c,"spinnerBigSize");b('<div class="dateEntry_expand" style="position: absolute; left: '+ (e.left-(c[0]-g[0])/2-(f?f.left:0))+"px; top: "+(e.top-(c[1]-g[1])/2-(f?f.top:0))+"px; width: "+c[0]+"px; height: "+c[1]+"px; background: transparent url("+d+') no-repeat 0px 0px; z-index: 10;"></div>').mousedown(b.dateEntry._handleSpinner).mouseup(b.dateEntry._endSpinner).mouseout(b.dateEntry._endExpand).mousemove(b.dateEntry._describeSpinner).insertAfter(a)}}},_getInput:function(a){return b(a).siblings("."+b.dateEntry.markerClassName)[0]},_describeSpinner:function(a){var c=b.dateEntry._getSpinnerTarget(a), d=b.data(b.dateEntry._getInput(c),"dateEntry");c.title=b.dateEntry._get(d,"spinnerTexts")[b.dateEntry._getSpinnerRegion(d,a)]},_handleSpinner:function(a){var c=b.dateEntry._getSpinnerTarget(a),d=b.dateEntry._getInput(c);if(!b.dateEntry._isDisabledDateEntry(d)){if(d==b.dateEntry._blurredInput)b.dateEntry._lastInput=d,b.dateEntry._blurredInput=null;var e=b.data(d,"dateEntry");b.dateEntry._doFocus(d);var f=b.dateEntry._getSpinnerRegion(e,a);b.dateEntry._changeSpinner(e,c,f);b.dateEntry._actionSpinner(e, f);b.dateEntry._timer=null;b.dateEntry._handlingSpinner=!0;a=b.dateEntry._get(e,"spinnerRepeat");if(3<=f&&a[0])b.dateEntry._timer=setTimeout(function(){b.dateEntry._repeatSpinner(e,f)},a[0]),b(c).one("mouseout",b.dateEntry._releaseSpinner).one("mouseup",b.dateEntry._releaseSpinner)}},_actionSpinner:function(a,c){a.input.val()||b.dateEntry._parseDate(a);switch(c){case 0:this._setDate(a);break;case 1:this._changeField(a,-1,!1);break;case 2:this._changeField(a,1,!1);break;case 3:this._adjustField(a, 1);break;case 4:this._adjustField(a,-1)}},_repeatSpinner:function(a,c){if(b.dateEntry._timer)b.dateEntry._lastInput=b.dateEntry._blurredInput,this._actionSpinner(a,c),this._timer=setTimeout(function(){b.dateEntry._repeatSpinner(a,c)},this._get(a,"spinnerRepeat")[1])},_releaseSpinner:function(){clearTimeout(b.dateEntry._timer);b.dateEntry._timer=null},_endExpand:function(a){b.dateEntry._timer=null;var a=b.dateEntry._getSpinnerTarget(a),c=b.dateEntry._getInput(a),c=b.data(c,"dateEntry");b(a).remove(); c._expanded=!1},_endSpinner:function(a){b.dateEntry._timer=null;var a=b.dateEntry._getSpinnerTarget(a),c=b.dateEntry._getInput(a),d=b.data(c,"dateEntry");b.dateEntry._isDisabledDateEntry(c)||b.dateEntry._changeSpinner(d,a,-1);if(b.dateEntry._handlingSpinner)b.dateEntry._lastInput=b.dateEntry._blurredInput;b.dateEntry._lastInput&&b.dateEntry._handlingSpinner&&b.dateEntry._showField(d);b.dateEntry._handlingSpinner=!1},_getSpinnerTarget:function(a){return a.target||a.srcElement},_getSpinnerRegion:function(a, c){var d=this._getSpinnerTarget(c),e=b.browser.opera||b.browser.safari?b.dateEntry._findPos(d):b(d).offset(),f=b.browser.safari?b.dateEntry._findScroll(d):[document.documentElement.scrollLeft||document.body.scrollLeft,document.documentElement.scrollTop||document.body.scrollTop],g=this._get(a,"spinnerIncDecOnly"),d=g?99:c.clientX+f[0]-e.left-(b.browser.msie?2:0),e=c.clientY+f[1]-e.top-(b.browser.msie?2:0),f=this._get(a,a._expanded?"spinnerBigSize":"spinnerSize"),g=g?99:f[0]-1-d,h=f[1]-1-e;if(0<f[2]&& Math.abs(d-g)<=f[2]&&Math.abs(e-h)<=f[2])return 0;f=Math.min(d,e,g,h);return f==d?1:f==g?2:f==e?3:4},_changeSpinner:function(a,c,d){b(c).css("background-position","-"+(d+1)*this._get(a,a._expanded?"spinnerBigSize":"spinnerSize")[0]+"px 0px")},_findPos:function(a){var c=curTop=0;if(a.offsetParent){c=a.offsetLeft;for(curTop=a.offsetTop;a=a.offsetParent;){var b=c,c=c+a.offsetLeft;0>c&&(c=b);curTop+=a.offsetTop}}return{left:c,top:curTop}},_findScroll:function(a){var c=!1;b(a).parents().each(function(){c|= "fixed"==b(this).css("position")});if(c)return[0,0];for(var d=a.scrollLeft,e=a.scrollTop;a=a.parentNode;)d+=a.scrollLeft||0,e+=a.scrollTop||0;return[d,e]},_get:function(a,c){return null!=a.options[c]?a.options[c]:b.dateEntry._defaults[c]},_parseDate:function(a){var c=this._extractDate(a.input.val(),a)||this._normaliseDate(this._determineDate(this._get(a,"defaultDate"),a)||new Date);a._selectedYear=c.getFullYear();a._selectedMonth=c.getMonth();a._selectedDay=c.getDate();a._lastChr="";a._field=Math.max(0, Math.min(2,this._get(a,"initialField")));""!=a.input.val()&&this._showDate(a)},_extractDate:function(a,c){for(var d=this._get(c,"dateFormat"),e=a.split(RegExp("[\\"+d.substr(-1).split("").join("\\")+"]")),f=c._selectedYear,g=c._selectedMonth+1,h=c._selectedDay,i=0,k=e.length;i<k;i++){var j=parseInt(e[i],10),j=isNaN(j)?0:j,l=d.charAt(i);switch(l){case "y":f=j;break;case "Y":f=j%100+((new Date).getFullYear()-(new Date).getFullYear()%100);break;case "m":g=j;break;case "n":case "N":g=b.inArray(e[i],this._get(c, "N"==l?"monthNames":"monthNamesShort"))+1;break;case "w":case "W":" "==d.charAt(3)?(e.splice(i,1),j=parseInt(e[i],10)):j=parseInt(e[i].substr(this._get(c,"W"==l?"dayNames":"dayNamesShort")[0].length+1),10),j=isNaN(j)?0:j;case "d":h=j}}return new Date(f,g-1,h,12)},_showDate:function(a){this._setValue(a,this._formatDate(a,this._get(a,"dateFormat")));this._showField(a)},_formatDate:function(a,c){for(var b="",e=0,f=c.length-1;e<f;e++){var b=b+(0==e?"":c.charAt(c.length-1)),g=c.charAt(e);switch(g){case "y":b+= this._formatNumber(a._selectedYear);break;case "Y":b+=this._formatNumber(a._selectedYear%100);break;case "m":b+=this._formatNumber(a._selectedMonth+1);break;case "n":case "N":b+=this._get(a,"N"==g?"monthNames":"monthNamesShort")[a._selectedMonth];break;case "d":b+=this._formatNumber(a._selectedDay);break;case "w":case "W":b+=this._get(a,"W"==g?"dayNames":"dayNamesShort")[(new Date(a._selectedYear,a._selectedMonth,a._selectedDay,12)).getDay()]+" "+this._formatNumber(a._selectedDay)}}return b},_showField:function(a){var c= a.input[0];if(!(a.input.is(":hidden")||b.dateEntry._lastInput!=c)){for(var d=this._get(a,"dateFormat"),e=0,f=0;f<a._field;f++)e+=this._fieldLength(a,f,d)+1;d=e+this._fieldLength(a,f,d);c.setSelectionRange?c.setSelectionRange(e,d):c.createTextRange&&(f=c.createTextRange(),f.moveStart("character",e),f.moveEnd("character",d-a.input.val().length),f.select());c.disabled||c.focus()}},_fieldLength:function(a,b,d){b=d.charAt(b);switch(b){case "y":return 4;case "n":case "N":return this._get(a,"N"==b?"monthNames": "monthNamesShort")[a._selectedMonth].length;case "w":case "W":return this._get(a,"W"==b?"dayNames":"dayNamesShort")[(new Date(a._selectedYear,a._selectedMonth,a._selectedDay,12)).getDay()].length+3;default:return 2}},_formatNumber:function(a){return(10>a?"0":"")+a},_setValue:function(a,c){if(c!=a.input.val()){var d=this._get(a,"altField");d&&b(d).val(!c?"":this._formatDate(a,this._get(a,"altFormat")||this._get(a,"dateFormat")));a.input.val(c).trigger("change")}},_changeField:function(a,c,d){var e= ""==a.input.val()||a._field==(-1==c?0:2);e||(a._field+=c);this._showField(a);a._lastChr="";b.data(a.input[0],"dateEntry",a);return e&&d},_adjustField:function(a,b){""==a.input.val()&&(b=0);var d=this._get(a,"dateFormat").charAt(a._field),e=a._selectedYear+("y"==d||"Y"==d?b:0),f=a._selectedMonth+("m"==d||"n"==d||"N"==d?b:0),d="d"==d||"w"==d||"W"==d?a._selectedDay+b:Math.min(a._selectedDay,this._getDaysInMonth(e,f));this._setDate(a,new Date(e,f,d,12))},_getDaysInMonth:function(a,b){return(new Date(a, b+1,0,12)).getDate()},_setDate:function(a,c){var c=this._normaliseDate(this._determineDate(c||this._get(a,"defaultDate"),a)||new Date),d=this._normaliseDate(this._determineDate(this._get(a,"minDate"),a)),e=this._normaliseDate(this._determineDate(this._get(a,"maxDate"),a)),c=d&&c<d?d:e&&c>e?e:c;a._selectedYear=c.getFullYear();a._selectedMonth=c.getMonth();a._selectedDay=c.getDate();this._showDate(a);b.data(a.input[0],"dateEntry",a)},_determineDate:function(a,c){var d=function(a){var c=b.dateEntry._normaliseDate(new Date); c.setDate(c.getDate()+a);return c};return a?"string"==typeof a?function(a){var d=b.dateEntry._extractDate(a,c);if(d)return d;for(var a=a.toLowerCase(),d=b.dateEntry._normaliseDate(new Date),g=d.getFullYear(),h=d.getMonth(),d=d.getDate(),i=/([+-]?[0-9]+)\s*(d|w|m|y)?/g,k=i.exec(a);k;){switch(k[2]||"d"){case "d":d+=parseInt(k[1],10);break;case "w":d+=7*parseInt(k[1],10);break;case "m":h+=parseInt(k[1],10);break;case "y":g+=parseInt(k[1],10)}k=i.exec(a)}return new Date(g,h,d,12)}(a):"number"==typeof a? d(a):a:null},_normaliseDate:function(a){a&&a.setHours(12,0,0,0);return a},_handleKeyPress:function(a,b){var d=this._get(a,"dateFormat");if(-1<d.substring(3).indexOf(b))this._changeField(a,1,!1);else if("0"<=b&&"9">=b){var e=d.charAt(a._field),f=parseInt(b,10),g=parseInt((a._lastChr||"")+b,10),h="y"!=e&&"Y"!=e?a._selectedYear:g,d="m"!=e&&"n"!=e&&"N"!=e?a._selectedMonth+1:1<=g&&12>=g?g:0<f?f:a._selectedMonth+1,f="d"!=e&&"w"!=e&&"W"!=e?a._selectedDay:1<=g&&g<=this._getDaysInMonth(h,d-1)?g:0<f?f:a._selectedDay; this._setDate(a,new Date(h,d-1,f,12));a._lastChr=("y"!=e?"":a._lastChr.substr(Math.max(0,a._lastChr.length-2)))+b}else if(e=d.charAt(a._field),"n"==e||"N"==e){a._lastChr+=b.toLowerCase();var i=this._get(a,"n"==e?"monthNamesShort":"monthNames"),e=function(){for(var b=0;b<i.length;b++)if(i[b].toLowerCase().substring(0,a._lastChr.length)==a._lastChr)return b;return-1},d=e();if(-1==d)a._lastChr=b.toLowerCase(),d=e();-1==d?a._lastChr="":(h=a._selectedYear,f=Math.min(a._selectedDay,this._getDaysInMonth(h, d)),this._setDate(a,new Date(h,d,f,12)))}}});b.fn.dateEntry=function(a){var c=Array.prototype.slice.call(arguments,1);return"string"==typeof a&&("isDisabled"==a||"getDate"==a)?b.dateEntry["_"+a+"DateEntry"].apply(b.dateEntry,[this[0]].concat(c)):this.each(function(){if("input"==this.nodeName.toLowerCase())if("string"==typeof a)b.dateEntry["_"+a+"DateEntry"].apply(b.dateEntry,[this].concat(c));else{var d=b.fn.metadata?b(this).metadata():{};b.dateEntry._connectDateEntry(this,b.extend(d,a))}})};b.dateEntry= new m})(jQuery);
\ No newline at end of file

Modified: trunk/htdocs/js/jquery/jquery.lj.entryDatePicker.js
===================================================================
--- trunk/htdocs/js/jquery/jquery.lj.entryDatePicker.js	2011-11-25 13:26:20 UTC (rev 20626)
+++ trunk/htdocs/js/jquery/jquery.lj.entryDatePicker.js	2011-11-25 13:36:04 UTC (rev 20627)
@@ -1,7 +1,7 @@
 /*!
  * LiveJournal datePicker for edit entries.
  *
- * Copyright 2011, dmitry.petrov@sup.com
+ * Copyright 2011, dmitry.petrov@sup.com & vkurkin@sup.com
  *
  * http://docs.jquery.com/UI
  * 
@@ -9,6 +9,9 @@
  *	jquery.ui.core.js
  *	jquery.ui.widget.js
  *	jquery.lj.basicWidget.js
+ *	jquery.lj.inlineCalendar.js
+ *	jquery.dateentry.js
+ *	jquery.timeentry.js
  *
  * @overview Widget represents a date picker on update.bml and editjournal.bml pages.
  *
@@ -16,13 +19,61 @@
  * reset Return widget to the initial state
  * 
  */
-(function($,window) {
+(function($, window) {
+	var listeners = {
+		onStartEdit: function(evt) {
+			evt.data._setState('edit');
+			evt.data._isCalendarOpen = true;
+			evt.preventDefault();
+		},
+		onChangeMonth: function(evt) {
+			var self = evt.data,
+				month = this.selectedIndex,
+				newDate = self.currentDate;
+
+			if (self._isEvent === false) {
+				return;
+			}
+
+			newDate.setMonth(month);
+			if(newDate.getMonth() != month) {
+				newDate = new Date(self.currentDate.getFullYear(), month + 1, 0, newDate.getHours(), newDate.getMinutes());
+			}
+
+			self._setEditDate(newDate);
+		},
+		onChangeTime: function(evt) {
+			var newDate = $(this).timeEntry('getTime'),
+				self = evt.data;
+
+			if (self._isEvent === false) {
+				return;
+			}
+			newDate.setFullYear(self.currentDate.getFullYear());
+			newDate.setMonth(self.currentDate.getMonth());
+			newDate.setDate(self.currentDate.getDate());
+			self._setEditDate(newDate);
+		},
+		onChangeDate: function(evt) {
+			var newDate = $(this).dateEntry('getDate'),
+				self = evt.data;
+
+			if (self._isEvent === false) {
+				return;
+			}
+			newDate.setHours(self.currentDate.getHours());
+			newDate.setMinutes(self.currentDate.getMinutes());
+			self._setEditDate(newDate);
+		}
+	};
+
 	$.widget('lj.entryDatePicker', jQuery.lj.basicWidget, {
 		options: {
 			state: 'default',
 			//when the widget is in inedit or infutureedit states, the timers are paused.
 			states: ['default', 'edit', 'inedit', 'infutureedit', 'future'],
-			updateDate: true,
+			monthNames: Site.ml_text['month.names.long'] || ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
+			updateDate: !Site.is_edit,
 			//if true, widget sets custom_time flag if user clicks on edit link. Otherwise it
 			//does so only on real time change from user.
 			disableOnEdit: false,
@@ -31,26 +82,26 @@
 				'edit': 'entrydate-changeit',
 				'inedit': 'entrydate-changeit',
 				'infutureedit': 'entrydate-until',
-				'future': 'entrydate-until',
+				'future': Site.hasOwnProperty('is_delayed_post') && Site.is_delayed_post === 0 ? 'entrydate-changeit' : 'entrydate-until',
 				'delayed': 'entrydate-delayed'
 			},
 			selectors: {
 				dateInputs: 'input, select',
-				calendar: '.wrap-calendar',
+				calendar: '.wrap-calendar .i-calendar',
 				editLink: '#currentdate-edit',
-				currentDate: '#currentdate-date'
-			},
-			//this input was located outside the widget markup
-			customTimeFlag: jQuery()
+				monthSelect: '#_mm',
+				dateString: '.entrydate-string'
+			}
 		},
 
 		_create: function() {
-			var self = this;
-			var states = this.options.states;
+			var self = this,
+				states = this.options.states,
+				state = states.length;
 
 			this._totalStateClassNames = '';
-			for (var i in states) if (states.hasOwnProperty(i)) {
-				this._totalStateClassNames += ' ' + this.options.classNames[states[i]];
+			while (state) {
+				this._totalStateClassNames += ' ' + this.options.classNames[states[--state]];
 			}
 
 			this._dateInputs = {};
@@ -60,19 +111,27 @@
 				}
 			});
 
-			this._currentDate = this.element.find(this.options.selectors.currentDate);
+			this._dateString = this.element.find(this.options.selectors.dateString);
+
 			$.lj.basicWidget.prototype._create.apply(this);
 
-			this._initialUpdateDate = this.options.updateDate;
-			//if delayed posts are disabled we should get old bejavior
-			this.options.disableOnEdit = !this.element.hasClass(this.options.classNames.delayed);
-			this._updateTimer = null;
-			this._bindControls();
+			if (this._initialUp...
 (truncated)
Tags: b_vladi, js, livejournal, vkurkin
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 0 comments