diff --git a/application/logs/log-2018-01-27.php b/application/logs/log-2018-01-27.php new file mode 100644 index 00000000..240a0224 --- /dev/null +++ b/application/logs/log-2018-01-27.php @@ -0,0 +1,4 @@ + + +ERROR - 2018-01-27 12:50:02 --> Severity: Notice --> Undefined offset: 1 C:\5.6\xampp\htdocs\SIA\SIANEW\current\siddharth_application\application\views\dailyBatchCardListing.php 366 +ERROR - 2018-01-27 12:50:02 --> Severity: Notice --> Undefined offset: 1 C:\5.6\xampp\htdocs\SIA\SIANEW\current\siddharth_application\application\views\dailyBatchCardListing.php 366 diff --git a/application/views/dailyBatchCardListing.php b/application/views/dailyBatchCardListing.php index 5ff82689..7b783df8 100755 --- a/application/views/dailyBatchCardListing.php +++ b/application/views/dailyBatchCardListing.php @@ -235,6 +235,9 @@ td{ padding:3px;} +
diff --git a/application/views/dailybatchcard.php b/application/views/dailybatchcard.php index 91280274..73de1a16 100755 --- a/application/views/dailybatchcard.php +++ b/application/views/dailybatchcard.php @@ -111,7 +111,7 @@ foreach($emplist as $r)xyz
+ produces $.xyz and $.fn.xyz. */
+ _init: function() {
+ // Apply default localisations
+ $.extend(this.defaultOptions, (this.regionalOptions && this.regionalOptions['']) || {});
+ // Camel-case the name
+ var jqName = camelCase(this.name);
+ // Expose jQuery singleton manager
+ $[jqName] = this;
+ // Expose jQuery collection plugin
+ $.fn[jqName] = function(options) {
+ var otherArgs = Array.prototype.slice.call(arguments, 1);
+ if ($[jqName]._isNotChained(options, otherArgs)) {
+ return $[jqName][options].apply($[jqName], [this[0]].concat(otherArgs));
+ }
+ return this.each(function() {
+ if (typeof options === 'string') {
+ if (options[0] === '_' || !$[jqName][options]) {
+ throw 'Unknown method: ' + options;
+ }
+ $[jqName][options].apply($[jqName], [this].concat(otherArgs));
+ }
+ else {
+ $[jqName]._attach(this, options);
+ }
+ });
+ };
+ },
+
+ /** Set default values for all subsequent instances.
+ @param options {object} The new default options.
+ @example $.plugin.setDefauls({name: value}) */
+ setDefaults: function(options) {
+ $.extend(this.defaultOptions, options || {});
+ },
+
+ /** Determine whether a method is a getter and doesn't permit chaining.
+ @private
+ @param name {string} The method name.
+ @param otherArgs {any[]} Any other arguments for the method.
+ @return {boolean} True if this method is a getter, false otherwise. */
+ _isNotChained: function(name, otherArgs) {
+ if (name === 'option' && (otherArgs.length === 0 ||
+ (otherArgs.length === 1 && typeof otherArgs[0] === 'string'))) {
+ return true;
+ }
+ return $.inArray(name, this._getters) > -1;
+ },
+
+ /** Initialise an element. Called internally only.
+ Adds an instance object as data named for the plugin.
+ @param elem {Element} The element to enhance.
+ @param options {object} Overriding settings. */
+ _attach: function(elem, options) {
+ elem = $(elem);
+ if (elem.hasClass(this._getMarker())) {
+ return;
+ }
+ elem.addClass(this._getMarker());
+ options = $.extend({}, this.defaultOptions, this._getMetadata(elem), options || {});
+ var inst = $.extend({name: this.name, elem: elem, options: options},
+ this._instSettings(elem, options));
+ elem.data(this.name, inst); // Save instance against element
+ this._postAttach(elem, inst);
+ this.option(elem, options);
+ },
+
+ /** Retrieve additional instance settings.
+ Override this in a sub-class to provide extra settings.
+ @param elem {jQuery} The current jQuery element.
+ @param options {object} The instance options.
+ @return {object} Any extra instance values.
+ @example _instSettings: function(elem, options) {
+ return {nav: elem.find(options.navSelector)};
+ } */
+ _instSettings: function(elem, options) {
+ return {};
+ },
+
+ /** Plugin specific post initialisation.
+ Override this in a sub-class to perform extra activities.
+ @param elem {jQuery} The current jQuery element.
+ @param inst {object} The instance settings.
+ @example _postAttach: function(elem, inst) {
+ elem.on('click.' + this.name, function() {
+ ...
+ });
+ } */
+ _postAttach: function(elem, inst) {
+ },
+
+ /** Retrieve metadata configuration from the element.
+ Metadata is specified as an attribute:
+ data-<plugin name>="<setting name>: '<value>', ...".
+ Dates should be specified as strings in this format: 'new Date(y, m-1, d)'.
+ @private
+ @param elem {jQuery} The source element.
+ @return {object} The inline configuration or {}. */
+ _getMetadata: function(elem) {
+ try {
+ var data = elem.data(this.name.toLowerCase()) || '';
+ data = data.replace(/'/g, '"');
+ data = data.replace(/([a-zA-Z0-9]+):/g, function(match, group, i) {
+ var count = data.substring(0, i).match(/"/g); // Handle embedded ':'
+ return (!count || count.length % 2 === 0 ? '"' + group + '":' : group + ':');
+ });
+ data = $.parseJSON('{' + data + '}');
+ for (var name in data) { // Convert dates
+ var value = data[name];
+ if (typeof value === 'string' && value.match(/^new Date\((.*)\)$/)) {
+ data[name] = eval(value);
+ }
+ }
+ return data;
+ }
+ catch (e) {
+ return {};
+ }
+ },
+
+ /** Retrieve the instance data for element.
+ @param elem {Element} The source element.
+ @return {object} The instance data or {}. */
+ _getInst: function(elem) {
+ return $(elem).data(this.name) || {};
+ },
+
+ /** Retrieve or reconfigure the settings for a plugin.
+ @param elem {Element} The source element.
+ @param name {object|string} The collection of new option values or the name of a single option.
+ @param [value] {any} The value for a single named option.
+ @return {any|object} If retrieving a single value or all options.
+ @example $(selector).plugin('option', 'name', value)
+ $(selector).plugin('option', {name: value, ...})
+ var value = $(selector).plugin('option', 'name')
+ var options = $(selector).plugin('option') */
+ option: function(elem, name, value) {
+ elem = $(elem);
+ var inst = elem.data(this.name);
+ if (!name || (typeof name === 'string' && value == null)) {
+ var options = (inst || {}).options;
+ return (options && name ? options[name] : options);
+ }
+ if (!elem.hasClass(this._getMarker())) {
+ return;
+ }
+ var options = name || {};
+ if (typeof name === 'string') {
+ options = {};
+ options[name] = value;
+ }
+ this._optionsChanged(elem, inst, options);
+ $.extend(inst.options, options);
+ },
+
+ /** Plugin specific options processing.
+ Old value available in inst.options[name], new value in options[name].
+ Override this in a sub-class to perform extra activities.
+ @param elem {jQuery} The current jQuery element.
+ @param inst {object} The instance settings.
+ @param options {object} The new options.
+ @example _optionsChanged: function(elem, inst, options) {
+ if (options.name != inst.options.name) {
+ elem.removeClass(inst.options.name).addClass(options.name);
+ }
+ } */
+ _optionsChanged: function(elem, inst, options) {
+ },
+
+ /** Remove all trace of the plugin.
+ Override _preDestroy for plugin-specific processing.
+ @param elem {Element} The source element.
+ @example $(selector).plugin('destroy') */
+ destroy: function(elem) {
+ elem = $(elem);
+ if (!elem.hasClass(this._getMarker())) {
+ return;
+ }
+ this._preDestroy(elem, this._getInst(elem));
+ elem.removeData(this.name).removeClass(this._getMarker());
+ },
+
+ /** Plugin specific pre destruction.
+ Override this in a sub-class to perform extra activities and undo everything that was
+ done in the _postAttach or _optionsChanged functions.
+ @param elem {jQuery} The current jQuery element.
+ @param inst {object} The instance settings.
+ @example _preDestroy: function(elem, inst) {
+ elem.off('.' + this.name);
+ } */
+ _preDestroy: function(elem, inst) {
+ }
+ });
+
+ /** Convert names from hyphenated to camel-case.
+ @private
+ @param value {string} The original hyphenated name.
+ @return {string} The camel-case version. */
+ function camelCase(name) {
+ return name.replace(/-([a-z])/g, function(match, group) {
+ return group.toUpperCase();
+ });
+ }
+
+ /** Expose the plugin base.
+ @namespace "$.JQPlugin" */
+ $.JQPlugin = {
+
+ /** Create a new collection plugin.
+ @memberof "$.JQPlugin"
+ @param [superClass='JQPlugin'] {string} The name of the parent class to inherit from.
+ @param overrides {object} The property/function overrides for the new class.
+ @example $.JQPlugin.createPlugin({
+ name: 'tabs',
+ defaultOptions: {selectedClass: 'selected'},
+ _initSettings: function(elem, options) { return {...}; },
+ _postAttach: function(elem, inst) { ... }
+ }); */
+ createPlugin: function(superClass, overrides) {
+ if (typeof superClass === 'object') {
+ overrides = superClass;
+ superClass = 'JQPlugin';
+ }
+ superClass = camelCase(superClass);
+ var className = camelCase(overrides.name);
+ JQClass.classes[className] = JQClass.classes[superClass].extend(overrides);
+ new JQClass.classes[className]();
+ }
+ };
+
+})(jQuery);
\ No newline at end of file
diff --git a/assets/jquery.timeentry.js b/assets/jquery.timeentry.js
new file mode 100644
index 00000000..d48a6478
--- /dev/null
+++ b/assets/jquery.timeentry.js
@@ -0,0 +1,1059 @@
+/* http://keith-wood.name/timeEntry.html
+ Time entry for jQuery v2.0.1.
+ Written by Keith Wood (kbwood{at}iinet.com.au) June 2007.
+ Available under the MIT (https://github.com/jquery/jquery/blob/master/MIT-LICENSE.txt) license.
+ Please attribute the author if you use it. */
+
+(function($) { // Hide scope, no $ conflict
+
+ var pluginName = 'timeEntry';
+
+ /** Create the time entry plugin.
+ Sets an input field to add a spinner for time entry.
+The time can be entered via directly typing the value, + via the arrow keys, or via spinner buttons. + It is configurable to show 12 or 24-hour time, to show or hide seconds, + to enforce a minimum and/or maximum time, to change the spinner image, + and to constrain the time to steps, e.g. only on the quarter hours.
+Expects HTML like:
+<input type="text">+
Provide inline configuration like:
+<input type="text" data-timeEntry="name: 'value'">+ @module TimeEntry + @augments JQPlugin + @example $(selector).timeEntry() + $(selector).timeEntry({showSeconds: true, minTime: new Date(0, 0, 0, 12, 0, 0)}) */ + $.JQPlugin.createPlugin({ + + /** The name of the plugin. */ + name: pluginName, + + /** Time entry before show callback. + Triggered when the input field is focussed. + @callback beforeShowCallback + @param input {Element} The current input field. + @return {object} Any changes to the instance settings. + @example beforeShow: function(input) { + // Cross-populate minimum/maximum times for a range + return {minTime: (input.id === 'timeTo' ? + $('#timeFrom').timeEntry('getTime') : null), + maxTime: (input.id === 'timeFrom' ? + $('#timeTo').timeEntry('getTime') : null)}; + } */ + + /** Time entry before set time callback. + Triggered when the input field value is to be changed. + @callback beforeSetTimeCallback + @param current {string} The current time value entered. + @param newTime {string} The new time value to use. + @param minTime {Date} The minimum time value allowed. + @param maxTime {Date} The maximum time value allowed. + @return {Date} The actual time value to set. + @example beforeSetTime: function(oldTime, newTime, minTime, maxTime) { + var increment = (newTime - (oldTime || newTime)) > 0; + if (newTime.getMinutes() > 30) { // First half of hour only + newTime.setMinutes(increment ? 0 : 30); + newTime.setHours(newTime.getHours() + (increment ? 1 : 0)); + } + return newTime; + } */ + + /** Default settings for the plugin. + @property [appendText=''] {string} Display text following the input box, e.g. showing the format. + @property [showSeconds=false] {boolean}
true to show seconds as well,
+ false for hours/minutes only.
+ @property [unlimitedHours=false] {boolean} true to allow entry of more than 24 hours,
+ false to restrict to one day.
+ @property [timeSteps=[1,1,1]] {number[]} Steps for each of hours/minutes/seconds when incrementing/decrementing.
+ @property [initialField=null] {number} The field to highlight initially (0 = hours, 1 = minutes, ...),
+ or null for none.
+ @property [noSeparatorEntry=false] {boolean} true to move to next sub-field after two digits entry.
+ @property [tabToExit=false] {boolean} true for tab key to go to next element,
+ false for tab key to step through internal fields.
+ @property [useMouseWheel=true] {boolean} true to use mouse wheel for increment/decrement if possible,
+ false to never use it.
+ @property [defaultTime=null] {Date|number|string} The time to use if none has been set,
+ or null for now. Specify as a Date object, as a number of seconds
+ offset from now, or as a string of offsets from now, using 'H' for hours,
+ 'M' for minutes, 'S' for seconds.
+ @property [minTime=null] {Date|number|string|number[]} The earliest selectable time,
+ or null for no limit. See defaultTime for possible formats,
+ use array of hours, minutes, seconds for unlimitedHours.
+ @property [maxTime=null] {Date|number|string|number[]} The latest selectable time,
+ or null for no limit. See defaultTime for possible formats,
+ use array of hours, minutes, seconds for unlimitedHours.
+ @property [spinnerImage='spinnerDefault.png'] {string} The URL of the images to use for the time spinner -
+ seven images packed horizontally for normal, each button pressed
+ (centre, previous, next, increment, decrement), and disabled.
+ @property [spinnerSize=[20,20,8]] {number[]} The width and height of the spinner image,
+ and size of centre button for current time.
+ @property [spinnerBigImage=''] {string} The URL of the images to use for the expanded time spinner -
+ seven images packed horizontally for normal, each button pressed
+ (centre, previous, next, increment, decrement), and disabled.
+ @property [spinnerBigSize=[40,40,16]] {number[]} The width and height of the expanded spinner image,
+ and size of centre button for current time.
+ @property [spinnerIncDecOnly=false] {boolean} true for increment/decrement buttons only, false for all.
+ @property [spinnerRepeat=[500,250]] {number[]} Initial and subsequent waits in milliseconds
+ for repeats on the spinner buttons.
+ @property [beforeShow=null] {beforeShowCallback} Function that takes an input field and
+ returns a set of custom settings for the time entry.
+ @property [beforeSetTime=null] {beforeSetTimeCallback} Function that runs before updating the time,
+ takes the old and new times, and minimum and maximum times as parameters,
+ and returns an adjusted time if necessary.
+ @example {defaultTime: new Date(0, 0, 0, 8, 30, 0), minTime: -300, maxTime: '+2H +30M'} */
+ defaultOptions: {
+ appendText: '',
+ showSeconds: false,
+ unlimitedHours: false,
+ timeSteps: [1, 1, 1],
+ initialField: null,
+ noSeparatorEntry: false,
+ tabToExit: false,
+ useMouseWheel: true,
+ defaultTime: null,
+ minTime: null,
+ maxTime: null,
+ spinnerImage: 'spinnerDefault.png',
+ spinnerSize: [20, 20, 8],
+ spinnerBigImage: '',
+ spinnerBigSize: [40, 40, 16],
+ spinnerIncDecOnly: false,
+ spinnerRepeat: [500, 250],
+ beforeShow: null,
+ beforeSetTime: null
+ },
+
+ /** Localisations for the plugin.
+ Entries are objects indexed by the language code ('' being the default US/English).
+ Each object has the following attributes.
+ @property [show24Hours=false] {boolean} true to use 24 hour time, false for 12 hour (AM/PM).
+ @property [separator=':'] {string} The separator between time fields.
+ @property [ampmPrefix=''] {string} The separator before the AM/PM text.
+ @property [ampmNames=['AM','PM']] {string[]} Names of morning/evening markers.
+ @property [spinnerTexts=['Now','Previous field','Next field','Increment','Decrement']] {string[]}
+ The popup texts for the spinner image areas. */
+ regionalOptions: { // Available regional settings, indexed by language/country code
+ '': { // Default regional settings - English/US
+ show24Hours: false,
+ separator: ':',
+ ampmPrefix: '',
+ ampmNames: ['AM', 'PM'],
+ spinnerTexts: ['Now', 'Previous field', 'Next field', 'Increment', 'Decrement']
+ }
+ },
+
+ _getters: ['getOffset', 'getTime', 'isDisabled'],
+
+ _appendClass: pluginName + '-append', // Class name for the appended content
+ _controlClass: pluginName + '-control', // Class name for the date entry control
+ _expandClass: pluginName + '-expand', // Class name for the expanded spinner
+
+ _disabledInputs: [], // List of time inputs that have been disabled
+
+ _instSettings: function(elem, options) {
+ return {_field: 0, _selectedHour: 0, _selectedMinute: 0, _selectedSecond: 0};
+ },
+
+ _postAttach: function(elem, inst) {
+ elem.on('focus.' + inst.name, this._doFocus).
+ on('blur.' + inst.name, this._doBlur).
+ on('click.' + inst.name, this._doClick).
+ on('keydown.' + inst.name, this._doKeyDown).
+ on('keypress.' + inst.name, this._doKeyPress).
+ on('paste.' + inst.name, function(event) { // Check pastes
+ setTimeout(function() { plugin._parseTime(inst); }, 1);
+ });
+ },
+
+ _optionsChanged: function(elem, inst, options) {
+ var currentTime = this._extractTime(inst);
+ $.extend(inst.options, options);
+ inst.options.show24Hours = inst.options.show24Hours || inst.options.unlimitedHours;
+ inst._field = 0;
+ if (currentTime) {
+ this._setTime(inst, new Date(0, 0, 0, currentTime[0], currentTime[1], currentTime[2]));
+ }
+ // Remove stuff dependent on old settings
+ elem.next('span.' + this._appendClass).remove();
+ elem.parent().find('span.' + this._controlClass).remove();
+ if ($.fn.mousewheel) {
+ elem.unmousewheel();
+ }
+ // And re-add if requested
+ var spinner = (!inst.options.spinnerImage ? null :
+ $(''));
+ elem.after(inst.options.appendText ? '' +
+ inst.options.appendText + '' : '').after(spinner || '');
+ // Allow mouse wheel usage
+ if (inst.options.useMouseWheel && $.fn.mousewheel) {
+ elem.mousewheel(this._doMouseWheel);
+ }
+ if (spinner) {
+ spinner.mousedown(this._handleSpinner).mouseup(this._endSpinner).
+ mouseover(this._expandSpinner).mouseout(this._endSpinner).
+ mousemove(this._describeSpinner);
+ }
+ },
+
+ /** Enable a time entry input and any associated spinner.
+ @param elem {Element} The single input field.
+ @example $(selector).timeEntry('enable') */
+ enable: function(elem) {
+ this._enableDisable(elem, false);
+ },
+
+ /** Disable a time entry input and any associated spinner.
+ @param elem {Element} The single input field.
+ @example $(selector).timeEntry('disable') */
+ disable: function(elem) {
+ this._enableDisable(elem, true);
+ },
+
+ /** Enable or disable a time entry input and any associated spinner.
+ @private
+ @param elem {Element} The single input field.
+ @param disable {boolean} true to disable, false to enable. */
+ _enableDisable: function(elem, disable) {
+ var inst = this._getInst(elem);
+ if (!inst) {
+ return;
+ }
+ elem.disabled = disable;
+ if (elem.nextSibling && elem.nextSibling.nodeName.toLowerCase() === 'span') {
+ this._changeSpinner(inst, elem.nextSibling, (disable ? 5 : -1));
+ }
+ this._disabledInputs = $.map(this._disabledInputs,
+ function(value) { return (value === elem ? null : value); }); // Delete entry
+ if (disable) {
+ this._disabledInputs.push(elem);
+ }
+ },
+
+ /** Check whether an input field has been disabled.
+ @param elem {Element} The input field to check.
+ @return {boolean} true if this field has been disabled, false if it is enabled.
+ @example if ($(selector).dateEntry('isDisabled')) {...} */
+ isDisabled: function(elem) {
+ return $.inArray(elem, this._disabledInputs) > -1;
+ },
+
+ _preDestroy: function(elem, inst) {
+ elem = $(elem).off('.' + pluginName);
+ if ($.fn.mousewheel) {
+ elem.unmousewheel();
+ }
+ this._disabledInputs = $.map(this._disabledInputs,
+ function(value) { return (value === elem[0] ? null : value); }); // Delete entry
+ elem.siblings('.' + this._appendClass + ',.' + this._controlClass).remove();
+ },
+
+ /** Initialise the current time for a time entry input field.
+ @param elem {Element} The input field to update.
+ @param time {Date|number|string} The new time or offset or null to clear.
+ An actual time or offset in seconds from now or units and periods of offsets from now.
+ @example $(selector).timeEntry('setTime', new Date(0, 0, 0, 11, 22, 33))
+ $(selector).timeEntry('setTime', +300)
+ $(selector).timeEntry('setTime', '+1H +30M')
+ $(selector).timeEntry('setTime', null) */
+ setTime: function(elem, time) {
+ var inst = this._getInst(elem);
+ if (inst) {
+ if (time === null || time === '') {
+ $(elem).val('');
+ }
+ else {
+ this._setTime(inst, time ? ($.isArray(time) ? time :
+ (typeof time === 'object' ? new Date(time.getTime()) : time)) : null);
+ }
+ }
+ },
+
+ /** Retrieve the current time for a time entry input field.
+ @param elem {Element} The input field to update.
+ @return {Date} The current time or null if none.
+ @example var time = $(selector).timeEntry('getTime') */
+ getTime: function(elem) {
+ var inst = this._getInst(elem);
+ var currentTime = (inst ? this._extractTime(inst) : null);
+ return (!currentTime ? null :
+ new Date(0, 0, 0, currentTime[0], currentTime[1], currentTime[2]));
+ },
+
+ /** Retrieve the millisecond offset for the current time.
+ @param elem {Element} The input field to examine.
+ @return {number} The time as milliseconds offset or zero if none.
+ @example var offset = $(selector).timeEntry('getOffset') */
+ getOffset: function(elem) {
+ var inst = this._getInst(elem);
+ var currentTime = (inst ? this._extractTime(inst) : null);
+ return (!currentTime ? 0 :
+ (currentTime[0] * 3600 + currentTime[1] * 60 + currentTime[2]) * 1000);
+ },
+
+ /** Initialise date entry.
+ @private
+ @param elem {Element|Event} The input field or the focus event. */
+ _doFocus: function(elem) {
+ var input = (elem.nodeName && elem.nodeName.toLowerCase() === 'input' ? elem : this);
+ if (plugin._lastInput === input || plugin.isDisabled(input)) {
+ plugin._focussed = false;
+ return;
+ }
+ var inst = plugin._getInst(input);
+ plugin._focussed = true;
+ plugin._lastInput = input;
+ plugin._blurredInput = null;
+ $.extend(inst.options, ($.isFunction(inst.options.beforeShow) ?
+ inst.options.beforeShow.apply(input, [input]) : {}));
+ plugin._parseTime(inst, elem.nodeName ? null : elem);
+ setTimeout(function() { plugin._showField(inst); }, 10);
+ },
+
+ /** Note that the field has been exited.
+ @private
+ @param event {Event} The blur event. */
+ _doBlur: function(event) {
+ plugin._blurredInput = plugin._lastInput;
+ plugin._lastInput = null;
+ },
+
+ /** Select appropriate field portion on click, if already in the field.
+ @private
+ @param event {Event} The click event. */
+ _doClick: function(event) {
+ var input = event.target;
+ var inst = plugin._getInst(input);
+ var prevField = inst._field;
+ if (!plugin._focussed) {
+ inst._field = plugin._getSelection(inst, input, event);
+ }
+ if (prevField !== inst._field) {
+ inst._lastChr = '';
+ }
+ plugin._showField(inst);
+ plugin._focussed = false;
+ },
+
+ /** Find the selected subfield within the control.
+ @private
+ @param inst {object} The current instance settings.
+ @param input {Element} The input control.
+ @param event {Event} The triggering event.
+ @return {number} The selected subfield. */
+ _getSelection: function(inst, input, event) {
+ var select = 0;
+ var fieldSizes = [inst.elem.val().split(inst.options.separator)[0].length, 2, 2];
+ if (input.selectionStart !== null) { // Use input select range
+ var end = 0;
+ for (var field = 0; field <= Math.max(1, inst._secondField, inst._ampmField); field++) {
+ end += (field !== inst._ampmField ? fieldSizes[field] + inst.options.separator.length :
+ inst.options.ampmPrefix.length + inst.options.ampmNames[0].length);
+ select = field;
+ if (input.selectionStart < end) {
+ break;
+ }
+ }
+ }
+ else if (input.createTextRange && event != null) { // 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
+ for (var field = 0; field <= Math.max(1, inst._secondField, inst._ampmField); field++) {
+ var end = (field !== inst._ampmField ? (field * fieldSize) + 2 :
+ (inst._ampmField * fieldSize) + inst.options.ampmPrefix.length +
+ inst.options.ampmNames[0].length);
+ range.collapse();
+ range.moveEnd('character', end);
+ select = field;
+ if (offsetX < range.boundingWidth) { // And compare
+ break;
+ }
+ }
+ }
+ return select;
+ },
+
+ /** Handle keystrokes in the field.
+ @private
+ @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 = plugin._getInst(event.target);
+ switch (event.keyCode) {
+ case 9: return (inst.options.tabToExit ? true : (event.shiftKey ?
+ // Move to previous time field, or out if at the beginning
+ plugin._changeField(inst, -1, true) :
+ // Move to next time field, or out if at the end
+ plugin._changeField(inst, +1, true)));
+ case 35: if (event.ctrlKey) { // Clear time on ctrl+end
+ plugin._setValue(inst, '');
+ }
+ else { // Last field on end
+ inst._field = Math.max(1, inst._secondField, inst._ampmField);
+ plugin._adjustField(inst, 0);
+ }
+ break;
+ case 36: if (event.ctrlKey) { // Current time on ctrl+home
+ plugin._setTime(inst);
+ }
+ else { // First field on home
+ inst._field = 0;
+ plugin._adjustField(inst, 0);
+ }
+ break;
+ case 37: plugin._changeField(inst, -1, false); break; // Previous field on left
+ case 38: plugin._adjustField(inst, +1); break; // Increment time field on up
+ case 39: plugin._changeField(inst, +1, false); break; // Next field on right
+ case 40: plugin._adjustField(inst, -1); break; // Decrement time field on down
+ case 46: plugin._setValue(inst, ''); break; // Clear time on delete
+ case 8: inst._lastChr = ''; // Fall through
+ default: return true;
+ }
+ return false;
+ },
+
+ /** Disallow unwanted characters.
+ @private
+ @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 = plugin._getInst(event.target);
+ plugin._handleKeyPress(inst, chr);
+ return false;
+ },
+
+ /** Update date based on keystroke entered.
+ @private
+ @param inst {object} The instance settings.
+ @param chr {string} The new character. */
+ _handleKeyPress: function(inst, chr) {
+ if (chr === inst.options.separator) {
+ this._changeField(inst, +1, false);
+ }
+ else if (chr >= '0' && chr <= '9') { // Allow direct entry of date
+ var key = parseInt(chr, 10);
+ var value = parseInt(inst._lastChr + chr, 10);
+ var hour = (inst._field !== 0 ? inst._selectedHour :
+ (inst.options.unlimitedHours ? value :
+ (inst.options.show24Hours ? (value < 24 ? value : key) :
+ (value >= 1 && value <= 12 ? value :
+ (key > 0 ? key : inst._selectedHour)) % 12 +
+ (inst._selectedHour >= 12 ? 12 : 0))));
+ var minute = (inst._field !== 1 ? inst._selectedMinute :
+ (value < 60 ? value : key));
+ var second = (inst._field !== inst._secondField ? inst._selectedSecond :
+ (value < 60 ? value : key));
+ var fields = this._constrainTime(inst, [hour, minute, second]);
+ this._setTime(inst, (inst.options.unlimitedHours ? fields :
+ new Date(0, 0, 0, fields[0], fields[1], fields[2])));
+ if (inst.options.noSeparatorEntry && inst._lastChr) {
+ this._changeField(inst, +1, false);
+ }
+ else {
+ inst._lastChr = (inst.options.unlimitedHours && inst._field === 0 ? inst._lastChr + chr : chr);
+ }
+ }
+ else if (!inst.options.show24Hours) { // Set am/pm based on first char of names
+ chr = chr.toLowerCase();
+ if ((chr === inst.options.ampmNames[0].substring(0, 1).toLowerCase() &&
+ inst._selectedHour >= 12) ||
+ (chr === inst.options.ampmNames[1].substring(0, 1).toLowerCase() &&
+ inst._selectedHour < 12)) {
+ var saveField = inst._field;
+ inst._field = inst._ampmField;
+ this._adjustField(inst, +1);
+ inst._field = saveField;
+ this._showField(inst);
+ }
+ }
+ },
+
+ /** Increment/decrement on mouse wheel activity.
+ @private
+ @param event {Event} The mouse wheel event.
+ @param delta {number} The amount of change. */
+ _doMouseWheel: function(event, delta) {
+ if (plugin.isDisabled(event.target)) {
+ return;
+ }
+ var inst = plugin._getInst(event.target);
+ inst.elem.focus();
+ if (!inst.elem.val()) {
+ plugin._parseTime(inst);
+ }
+ plugin._adjustField(inst, delta);
+ event.preventDefault();
+ },
+
+ /** Expand the spinner, if possible, to make it easier to use.
+ @private
+ @param event {Event} The mouse over event. */
+ _expandSpinner: function(event) {
+ var spinner = plugin._getSpinnerTarget(event);
+ var inst = plugin._getInst(plugin._getInput(spinner));
+ if (plugin.isDisabled(inst.elem[0])) {
+ return;
+ }
+ if (inst.options.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;
+ });
+ $('').
+ mousedown(plugin._handleSpinner).mouseup(plugin._endSpinner).
+ mouseout(plugin._endExpand).mousemove(plugin._describeSpinner).
+ insertAfter(spinner);
+ }
+ },
+
+ /** Locate the actual input field from the spinner.
+ @private
+ @param spinner {Element} The current spinner.
+ @return {Element} The corresponding input. */
+ _getInput: function(spinner) {
+ return $(spinner).siblings('.' + this._getMarker())[0];
+ },
+
+ /** Change the title based on position within the spinner.
+ @private
+ @param event {Event} The mouse move event. */
+ _describeSpinner: function(event) {
+ var spinner = plugin._getSpinnerTarget(event);
+ var inst = plugin._getInst(plugin._getInput(spinner));
+ spinner.title = inst.options.spinnerTexts[plugin._getSpinnerRegion(inst, event)];
+ },
+
+ /** Handle a click on the spinner.
+ @private
+ @param event {Event} The mouse click event. */
+ _handleSpinner: function(event) {
+ var spinner = plugin._getSpinnerTarget(event);
+ var input = plugin._getInput(spinner);
+ if (plugin.isDisabled(input)) {
+ return;
+ }
+ if (input === plugin._blurredInput) {
+ plugin._lastInput = input;
+ plugin._blurredInput = null;
+ }
+ var inst = plugin._getInst(input);
+ plugin._doFocus(input);
+ var region = plugin._getSpinnerRegion(inst, event);
+ plugin._changeSpinner(inst, spinner, region);
+ plugin._actionSpinner(inst, region);
+ plugin._timer = null;
+ plugin._handlingSpinner = true;
+ if (region >= 3 && inst.options.spinnerRepeat[0]) { // Repeat increment/decrement
+ plugin._timer = setTimeout(
+ function() { plugin._repeatSpinner(inst, region); },
+ inst.options.spinnerRepeat[0]);
+ $(spinner).one('mouseout', plugin._releaseSpinner).
+ one('mouseup', plugin._releaseSpinner);
+ }
+ },
+
+ /** Action a click on the spinner.
+ @private
+ @param inst {object} The instance settings.
+ @param region {number} The spinner "button". */
+ _actionSpinner: function(inst, region) {
+ if (!inst.elem.val()) {
+ plugin._parseTime(inst);
+ }
+ switch (region) {
+ case 0: this._setTime(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.
+ @private
+ @param inst {object} The instance settings.
+ @param region {number} The spinner "button". */
+ _repeatSpinner: function(inst, region) {
+ if (!plugin._timer) {
+ return;
+ }
+ plugin._lastInput = plugin._blurredInput;
+ this._actionSpinner(inst, region);
+ this._timer = setTimeout(
+ function() { plugin._repeatSpinner(inst, region); },
+ inst.options.spinnerRepeat[1]);
+ },
+
+ /** Stop a spinner repeat.
+ @private
+ @param event {Event} The mouse event. */
+ _releaseSpinner: function(event) {
+ clearTimeout(plugin._timer);
+ plugin._timer = null;
+ },
+
+ /** Tidy up after an expanded spinner.
+ @private
+ @param event {Event} The mouse event. */
+ _endExpand: function(event) {
+ plugin._timer = null;
+ var spinner = plugin._getSpinnerTarget(event);
+ var input = plugin._getInput(spinner);
+ var inst = plugin._getInst(input);
+ $(spinner).remove();
+ inst._expanded = false;
+ },
+
+ /** Tidy up after a spinner click.
+ @private
+ @param event {Event} The mouse event. */
+ _endSpinner: function(event) {
+ plugin._timer = null;
+ var spinner = plugin._getSpinnerTarget(event);
+ var input = plugin._getInput(spinner);
+ var inst = plugin._getInst(input);
+ if (!plugin.isDisabled(input)) {
+ plugin._changeSpinner(inst, spinner, -1);
+ }
+ if (plugin._handlingSpinner) {
+ plugin._lastInput = plugin._blurredInput;
+ }
+ if (plugin._lastInput && plugin._handlingSpinner) {
+ plugin._showField(inst);
+ }
+ plugin._handlingSpinner = false;
+ },
+
+ /** Retrieve the spinner from the event.
+ @private
+ @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.
+ @private
+ @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 = $(spinner).offset();
+ var scrolled = [document.documentElement.scrollLeft || document.body.scrollLeft,
+ document.documentElement.scrollTop || document.body.scrollTop];
+ var left = (inst.options.spinnerIncDecOnly ? 99 : event.clientX + scrolled[0] - pos.left);
+ var top = event.clientY + scrolled[1] - pos.top;
+ var spinnerSize = inst.options[inst._expanded ? 'spinnerBigSize' : 'spinnerSize'];
+ var right = (inst.options.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 the button clicked.
+ @private
+ @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) *
+ inst.options[inst._expanded ? 'spinnerBigSize' : 'spinnerSize'][0]) + 'px 0px');
+ },
+
+ /** Extract the time value from the input field, or default to now.
+ @private
+ @param inst {object} The instance settings.
+ @param event {Event} The triggering event or null. */
+ _parseTime: function(inst, event) {
+ var currentTime = this._extractTime(inst);
+ if (currentTime) {
+ inst._selectedHour = currentTime[0];
+ inst._selectedMinute = currentTime[1];
+ inst._selectedSecond = currentTime[2];
+ }
+ else {
+ var now = this._constrainTime(inst);
+ inst._selectedHour = now[0];
+ inst._selectedMinute = now[1];
+ inst._selectedSecond = (inst.options.showSeconds ? now[2] : 0);
+ }
+ inst._secondField = (inst.options.showSeconds ? 2 : -1);
+ inst._ampmField = (inst.options.show24Hours ? -1 : (inst.options.showSeconds ? 3 : 2));
+ inst._lastChr = '';
+ var postProcess = function() {
+ if (inst.elem.val() !== '') {
+ plugin._showTime(inst);
+ }
+ };
+ if (typeof inst.options.initialField === 'number') {
+ inst._field = Math.max(0, Math.min(
+ Math.max(1, inst._secondField, inst._ampmField), inst.options.initialField));
+ postProcess();
+ }
+ else {
+ setTimeout(function() {
+ inst._field = plugin._getSelection(inst, inst.elem[0], event);
+ postProcess();
+ }, 0);
+ }
+ },
+
+ /** Extract the time value from a string as an array of values, or default to null.
+ @private
+ @param value {string} The date text.
+ @param inst {object} The instance settings.
+ @return {number[]} The retrieved time components (hours, minutes, seconds) or
+ null if no value. */
+ _extractTime: function(inst, value) {
+ value = value || inst.elem.val();
+ var currentTime = value.split(inst.options.separator);
+ if (inst.options.separator === '' && value !== '') {
+ currentTime[0] = value.substring(0, 2);
+ currentTime[1] = value.substring(2, 4);
+ currentTime[2] = value.substring(4, 6);
+ }
+ if (currentTime.length >= 2) {
+ var isAM = !inst.options.show24Hours && (value.indexOf(inst.options.ampmNames[0]) > -1);
+ var isPM = !inst.options.show24Hours && (value.indexOf(inst.options.ampmNames[1]) > -1);
+ var hour = parseInt(currentTime[0], 10);
+ hour = (isNaN(hour) ? 0 : hour);
+ hour = ((isAM || isPM) && hour === 12 ? 0 : hour) + (isPM ? 12 : 0);
+ var minute = parseInt(currentTime[1], 10);
+ minute = (isNaN(minute) ? 0 : minute);
+ var second = (currentTime.length >= 3 ? parseInt(currentTime[2], 10) : 0);
+ second = (isNaN(second) || !inst.options.showSeconds ? 0 : second);
+ return this._constrainTime(inst, [hour, minute, second]);
+ }
+ return null;
+ },
+
+ /** Constrain the given/current time to the time steps.
+ @private
+ @param inst {object} The instance settings.
+ @param fields {number[]} The current time components (hours, minutes, seconds).
+ @return {number[]} The constrained time components (hours, minutes, seconds). */
+ _constrainTime: function(inst, fields) {
+ var specified = (fields !== null && fields !== undefined);
+ if (!specified) {
+ var now = this._determineTime(inst.options.defaultTime, inst) || new Date();
+ fields = [now.getHours(), now.getMinutes(), now.getSeconds()];
+ }
+ var reset = false;
+ for (var i = 0; i < inst.options.timeSteps.length; i++) {
+ if (reset) {
+ fields[i] = 0;
+ }
+ else if (inst.options.timeSteps[i] > 1) {
+ fields[i] = Math.round(fields[i] / inst.options.timeSteps[i]) *
+ inst.options.timeSteps[i];
+ reset = true;
+ }
+ }
+ return fields;
+ },
+
+ /** Set the selected time into the input field.
+ @private
+ @param inst {object} The instance settings. */
+ _showTime: function(inst) {
+ var currentTime = (inst.options.unlimitedHours ? inst._selectedHour :
+ this._formatNumber(inst.options.show24Hours ? inst._selectedHour :
+ ((inst._selectedHour + 11) % 12) + 1)) + inst.options.separator +
+ this._formatNumber(inst._selectedMinute) +
+ (inst.options.showSeconds ? inst.options.separator +
+ this._formatNumber(inst._selectedSecond) : '') +
+ (inst.options.show24Hours ? '' : inst.options.ampmPrefix +
+ inst.options.ampmNames[(inst._selectedHour < 12 ? 0 : 1)]);
+ this._setValue(inst, currentTime);
+ this._showField(inst);
+ },
+
+ /** Highlight the current date field.
+ @private
+ @param inst {object} The instance settings. */
+ _showField: function(inst) {
+ var input = inst.elem[0];
+ if (inst.elem.is(':hidden') || plugin._lastInput !== input) {
+ return;
+ }
+ var fieldSizes = [inst.elem.val().split(inst.options.separator)[0].length, 2, 2];
+ var start = 0;
+ var field = 0;
+ while (field < inst._field) {
+ start += fieldSizes[field] +
+ (field === Math.max(1, inst._secondField) ? 0 : inst.options.separator.length);
+ field++;
+ }
+ var end = start + (inst._field !== inst._ampmField ? fieldSizes[field] :
+ inst.options.ampmPrefix.length + inst.options.ampmNames[0].length);
+ 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.elem.val().length);
+ range.select();
+ }
+ if (!input.disabled) {
+ input.focus();
+ }
+ },
+
+ /** Ensure displayed single number has a leading zero.
+ @private
+ @param value {number} The 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.
+ @private
+ @param inst {object} The instance settings.
+ @param value {string} The new value. */
+ _setValue: function(inst, value) {
+ if (value !== inst.elem.val()) {
+ inst.elem.val(value).trigger('change');
+ }
+ },
+
+ /** Move to previous/next field, or out of field altogether if appropriate.
+ @private
+ @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 exiting the field, false if not. */
+ _changeField: function(inst, offset, moveOut) {
+ var atFirstLast = (inst.elem.val() === '' ||
+ inst._field === (offset === -1 ? 0 : Math.max(1, inst._secondField, inst._ampmField)));
+ if (!atFirstLast) {
+ inst._field += offset;
+ }
+ this._showField(inst);
+ inst._lastChr = '';
+ return (atFirstLast && moveOut);
+ },
+
+ /** Update the current field in the direction indicated.
+ @private
+ @param inst {object} The instance settings.
+ @param offset {number} The amount to change by. */
+ _adjustField: function(inst, offset) {
+ if (inst.elem.val() === '') {
+ offset = 0;
+ }
+ if (inst.options.unlimitedHours) {
+ this._setTime(inst, [inst._selectedHour + (inst._field === 0 ? offset * inst.options.timeSteps[0] : 0),
+ inst._selectedMinute + (inst._field === 1 ? offset * inst.options.timeSteps[1] : 0),
+ inst._selectedSecond + (inst._field === inst._secondField ? offset * inst.options.timeSteps[2] : 0)]);
+ }
+ else {
+ this._setTime(inst, new Date(0, 0, 0,
+ inst._selectedHour + (inst._field === 0 ? offset * inst.options.timeSteps[0] : 0) +
+ (inst._field === inst._ampmField ? offset * 12 : 0),
+ inst._selectedMinute + (inst._field === 1 ? offset * inst.options.timeSteps[1] : 0),
+ inst._selectedSecond + (inst._field === inst._secondField ? offset * inst.options.timeSteps[2] : 0)));
+ }
+ },
+
+ /** Check against minimum/maximum and display time.
+ @private
+ @param inst {object} The instance settings.
+ @param time {Date|number|string|number[]} The actual time or offset in seconds from now or
+ units and periods of offsets from now or numeric period values. */
+ _setTime: function(inst, time) {
+ if (inst.options.unlimitedHours && $.isArray(time)) {
+ var fields = time;
+ }
+ else {
+ time = this._determineTime(time, inst);
+ var fields = (time ? [time.getHours(), time.getMinutes(), time.getSeconds()] : null);
+ }
+ fields = this._constrainTime(inst, fields);
+ time = new Date(0, 0, 0, fields[0], fields[1], fields[2]);
+ // Normalise to base date
+ var time = this._normaliseTime(time);
+ var minTime = this._normaliseTime(this._determineTime(inst.options.minTime, inst));
+ var maxTime = this._normaliseTime(this._determineTime(inst.options.maxTime, inst));
+ // Ensure it is within the bounds set
+ if (inst.options.unlimitedHours) {
+ while (fields[2] < 0) {
+ fields[2] += 60;
+ fields[1]--;
+ }
+ while (fields[2] > 59) {
+ fields[2] -= 60;
+ fields[1]++;
+ }
+ while (fields[1] < 0) {
+ fields[1] += 60;
+ fields[0]--;
+ }
+ while (fields[1] > 59) {
+ fields[1] -= 60;
+ fields[0]++;
+ }
+ minTime = (inst.options.minTime != null && $.isArray(inst.options.minTime)) ?
+ inst.options.minTime : [0, 0, 0];
+ if (fields[0] < minTime[0]) {
+ fields = minTime.slice(0, 3);
+ }
+ else if (fields[0] === minTime[0]) {
+ if (fields[1] < minTime[1]) {
+ fields[1] = minTime[1];
+ fields[2] = minTime[2];
+ }
+ else if (fields[1] === minTime[1]) {
+ if (fields[2] < minTime[2]) {
+ fields[2] = minTime[2];
+ }
+ }
+ }
+ if (inst.options.maxTime != null && $.isArray(inst.options.maxTime)) {
+ if (fields[0] > inst.options.maxTime[0]) {
+ fields = inst.options.maxTime.slice(0, 3);
+ }
+ else if (fields[0] === inst.options.maxTime[0]) {
+ if (fields[1] > inst.options.maxTime[1]) {
+ fields[1] = inst.options.maxTime[1];
+ fields[2] = inst.options.maxTime[2];
+ }
+ else if (fields[1] === inst.options.maxTime[1]) {
+ if (fields[2] > inst.options.maxTime[2]) {
+ fields[2] = inst.options.maxTime[2];
+ }
+ }
+ }
+ }
+ }
+ else {
+ if (minTime && maxTime && minTime > maxTime) {
+ if (time < minTime && time > maxTime) {
+ time = (Math.abs(time - minTime) < Math.abs(time - maxTime) ? minTime : maxTime);
+ }
+ }
+ else {
+ time = (minTime && time < minTime ? minTime :
+ (maxTime && time > maxTime ? maxTime : time));
+ }
+ fields[0] = time.getHours();
+ fields[1] = time.getMinutes();
+ fields[2] = time.getSeconds();
+ }
+ // Perform further restrictions if required
+ if ($.isFunction(inst.options.beforeSetTime)) {
+ time = inst.options.beforeSetTime.apply(inst.elem[0],
+ [this.getTime(inst.elem[0]), time, minTime, maxTime]);
+ fields[0] = time.getHours();
+ fields[1] = time.getMinutes();
+ fields[2] = time.getSeconds();
+ }
+ inst._selectedHour = fields[0];
+ inst._selectedMinute = fields[1];
+ inst._selectedSecond = fields[2];
+ this._showTime(inst);
+ },
+
+ /** A time may be specified as an exact value or a relative one.
+ @private
+ @param setting {Date|number|string|number[]} The actual time or offset in seconds from now or
+ units and periods of offsets from now or numeric period values.
+ @param inst {object} The instance settings.
+ @return {Date} The calculated time. */
+ _determineTime: function(setting, inst) {
+ var offsetNumeric = function(offset) { // E.g. +300, -2
+ var time = new Date();
+ time.setTime(time.getTime() + offset * 1000);
+ return time;
+ };
+ var offsetString = function(offset) { // E.g. '+2m', '-4h', '+3h +30m' or '12:34:56PM'
+ var fields = plugin._extractTime(inst, offset); // Actual time?
+ var time = new Date();
+ var hour = (fields ? fields[0] : time.getHours());
+ var minute = (fields ? fields[1] : time.getMinutes());
+ var second = (fields ? fields[2] : time.getSeconds());
+ if (!fields) {
+ var pattern = /([+-]?[0-9]+)\s*(s|S|m|M|h|H)?/g;
+ var matches = pattern.exec(offset);
+ while (matches) {
+ switch (matches[2] || 's') {
+ case 's' : case 'S' :
+ second += parseInt(matches[1], 10); break;
+ case 'm' : case 'M' :
+ minute += parseInt(matches[1], 10); break;
+ case 'h' : case 'H' :
+ hour += parseInt(matches[1], 10); break;
+ }
+ matches = pattern.exec(offset);
+ }
+ }
+ time = new Date(0, 0, 10, hour, minute, second, 0);
+ if (/^!/.test(offset)) { // No wrapping
+ if (time.getDate() > 10) {
+ time = new Date(0, 0, 10, 23, 59, 59);
+ }
+ else if (time.getDate() < 10) {
+ time = new Date(0, 0, 10, 0, 0, 0);
+ }
+ }
+ return time;
+ };
+ var offsetArray = function(setting) {
+ return new Date(0, 0, 0, setting[0], setting[1] || 0, setting[2] || 0, 0);
+ };
+ return (setting ? (typeof setting === 'string' ? offsetString(setting) :
+ (typeof setting === 'number' ? offsetNumeric(setting) :
+ ($.isArray(setting) ? offsetArray(setting) : setting))) : null);
+ },
+
+ /** Normalise time object to a common date.
+ @private
+ @param time {Date} The original time.
+ @return {Date} The normalised time. */
+ _normaliseTime: function(time) {
+ if (!time) {
+ return null;
+ }
+ time.setFullYear(1900);
+ time.setMonth(0);
+ time.setDate(0);
+ return time;
+ }
+ });
+
+ var plugin = $.timeEntry;
+
+})(jQuery);