diff --git a/web_app/css/external/jquery-ui-timepicker-addon.css b/web_app/css/external/jquery-ui-timepicker-addon.css
deleted file mode 100644
index 2d9e031..0000000
--- a/web_app/css/external/jquery-ui-timepicker-addon.css
+++ /dev/null
@@ -1,27 +0,0 @@
-.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }
-.ui-timepicker-div dl { text-align: left; }
-.ui-timepicker-div dl dt { float: left; clear:left; padding: 0 0 0 5px; }
-.ui-timepicker-div dl dd { margin: 0 10px 10px 40%; }
-.ui-timepicker-div td { font-size: 90%; }
-.ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; }
-.ui-timepicker-div .ui_tpicker_unit_hide{ display: none; }
-
-.ui-timepicker-rtl{ direction: rtl; }
-.ui-timepicker-rtl dl { text-align: right; padding: 0 5px 0 0; }
-.ui-timepicker-rtl dl dt{ float: right; clear: right; }
-.ui-timepicker-rtl dl dd { margin: 0 40% 10px 10px; }
-
-/* Shortened version style */
-.ui-timepicker-div.ui-timepicker-oneLine { padding-right: 2px; }
-.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_time,
-.ui-timepicker-div.ui-timepicker-oneLine dt { display: none; }
-.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_time_label { display: block; padding-top: 2px; }
-.ui-timepicker-div.ui-timepicker-oneLine dl { text-align: right; }
-.ui-timepicker-div.ui-timepicker-oneLine dl dd,
-.ui-timepicker-div.ui-timepicker-oneLine dl dd > div { display:inline-block; margin:0; }
-.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_minute:before,
-.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_second:before { content:':'; display:inline-block; }
-.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_millisec:before,
-.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_microsec:before { content:'.'; display:inline-block; }
-.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_unit_hide,
-.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_unit_hide:before{ display: none; }
\ No newline at end of file
diff --git a/web_app/css/external/jquery.timepicker.css b/web_app/css/external/jquery.timepicker.css
new file mode 100644
index 0000000..cd75f13
--- /dev/null
+++ b/web_app/css/external/jquery.timepicker.css
@@ -0,0 +1,72 @@
+.ui-timepicker-wrapper {
+ overflow-y: auto;
+ height: 150px;
+ width: 6.5em;
+ background: #fff;
+ border: 1px solid #ddd;
+ -webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);
+ -moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);
+ box-shadow:0 5px 10px rgba(0,0,0,0.2);
+ outline: none;
+ z-index: 10001;
+ margin: 0;
+}
+
+.ui-timepicker-wrapper.ui-timepicker-with-duration {
+ width: 13em;
+}
+
+.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-30,
+.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-60 {
+ width: 11em;
+}
+
+.ui-timepicker-list {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.ui-timepicker-duration {
+ margin-left: 5px; color: #888;
+}
+
+.ui-timepicker-list:hover .ui-timepicker-duration {
+ color: #888;
+}
+
+.ui-timepicker-list li {
+ padding: 3px 0 3px 5px;
+ cursor: pointer;
+ white-space: nowrap;
+ color: #000;
+ list-style: none;
+ margin: 0;
+}
+
+.ui-timepicker-list:hover .ui-timepicker-selected {
+ background: #fff; color: #000;
+}
+
+li.ui-timepicker-selected,
+.ui-timepicker-list li:hover,
+.ui-timepicker-list .ui-timepicker-selected:hover {
+ background: #1980EC; color: #fff;
+}
+
+li.ui-timepicker-selected .ui-timepicker-duration,
+.ui-timepicker-list li:hover .ui-timepicker-duration {
+ color: #ccc;
+}
+
+.ui-timepicker-list li.ui-timepicker-disabled,
+.ui-timepicker-list li.ui-timepicker-disabled:hover,
+.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled {
+ color: #888;
+ cursor: default;
+}
+
+.ui-timepicker-list li.ui-timepicker-disabled:hover,
+.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled {
+ background: #f2f2f2;
+}
diff --git a/web_app/js/external/jquery-ui-timepicker-addon.js b/web_app/js/external/jquery-ui-timepicker-addon.js
deleted file mode 100644
index a9bc63e..0000000
--- a/web_app/js/external/jquery-ui-timepicker-addon.js
+++ /dev/null
@@ -1,2251 +0,0 @@
-/*
- * jQuery Timepicker Addon
- * By: Trent Richardson [http://trentrichardson.com]
- *
- * Copyright 2013 Trent Richardson
- * You may use this project under MIT license.
- * http://trentrichardson.com/Impromptu/MIT-LICENSE.txt
- */
-
-(function (factory) {
- if (typeof define === 'function' && define.amd) {
- define(['jquery', 'jquery.ui'], factory);
- } else {
- factory(jQuery);
- }
-}(function ($) {
-
- /*
- * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded"
- */
- $.ui.timepicker = $.ui.timepicker || {};
- if ($.ui.timepicker.version) {
- return;
- }
-
- /*
- * Extend jQueryUI, get it started with our version number
- */
- $.extend($.ui, {
- timepicker: {
- version: "@@version"
- }
- });
-
- /*
- * Timepicker manager.
- * Use the singleton instance of this class, $.timepicker, to interact with the time picker.
- * Settings for (groups of) time pickers are maintained in an instance object,
- * allowing multiple different settings on the same page.
- */
- var Timepicker = function () {
- this.regional = []; // Available regional settings, indexed by language code
- this.regional[''] = { // Default regional settings
- currentText: 'Now',
- closeText: 'Done',
- amNames: ['AM', 'A'],
- pmNames: ['PM', 'P'],
- timeFormat: 'HH:mm',
- timeSuffix: '',
- timeOnlyTitle: 'Choose Time',
- timeText: 'Time',
- hourText: 'Hour',
- minuteText: 'Minute',
- secondText: 'Second',
- millisecText: 'Millisecond',
- microsecText: 'Microsecond',
- timezoneText: 'Time Zone',
- isRTL: false
- };
- this._defaults = { // Global defaults for all the datetime picker instances
- showButtonPanel: true,
- timeOnly: false,
- timeOnlyShowDate: false,
- showHour: null,
- showMinute: null,
- showSecond: null,
- showMillisec: null,
- showMicrosec: null,
- showTimezone: null,
- showTime: true,
- stepHour: 1,
- stepMinute: 1,
- stepSecond: 1,
- stepMillisec: 1,
- stepMicrosec: 1,
- hour: 0,
- minute: 0,
- second: 0,
- millisec: 0,
- microsec: 0,
- timezone: null,
- hourMin: 0,
- minuteMin: 0,
- secondMin: 0,
- millisecMin: 0,
- microsecMin: 0,
- hourMax: 23,
- minuteMax: 59,
- secondMax: 59,
- millisecMax: 999,
- microsecMax: 999,
- minDateTime: null,
- maxDateTime: null,
- maxTime: null,
- minTime: null,
- onSelect: null,
- hourGrid: 0,
- minuteGrid: 0,
- secondGrid: 0,
- millisecGrid: 0,
- microsecGrid: 0,
- alwaysSetTime: true,
- separator: ' ',
- altFieldTimeOnly: true,
- altTimeFormat: null,
- altSeparator: null,
- altTimeSuffix: null,
- altRedirectFocus: true,
- pickerTimeFormat: null,
- pickerTimeSuffix: null,
- showTimepicker: true,
- timezoneList: null,
- addSliderAccess: false,
- sliderAccessArgs: null,
- controlType: 'slider',
- oneLine: false,
- defaultValue: null,
- parse: 'strict',
- afterInject: null
- };
- $.extend(this._defaults, this.regional['']);
- };
-
- $.extend(Timepicker.prototype, {
- $input: null,
- $altInput: null,
- $timeObj: null,
- inst: null,
- hour_slider: null,
- minute_slider: null,
- second_slider: null,
- millisec_slider: null,
- microsec_slider: null,
- timezone_select: null,
- maxTime: null,
- minTime: null,
- hour: 0,
- minute: 0,
- second: 0,
- millisec: 0,
- microsec: 0,
- timezone: null,
- hourMinOriginal: null,
- minuteMinOriginal: null,
- secondMinOriginal: null,
- millisecMinOriginal: null,
- microsecMinOriginal: null,
- hourMaxOriginal: null,
- minuteMaxOriginal: null,
- secondMaxOriginal: null,
- millisecMaxOriginal: null,
- microsecMaxOriginal: null,
- ampm: '',
- formattedDate: '',
- formattedTime: '',
- formattedDateTime: '',
- timezoneList: null,
- units: ['hour', 'minute', 'second', 'millisec', 'microsec'],
- support: {},
- control: null,
-
- /*
- * Override the default settings for all instances of the time picker.
- * @param {Object} settings object - the new settings to use as defaults (anonymous object)
- * @return {Object} the manager object
- */
- setDefaults: function (settings) {
- extendRemove(this._defaults, settings || {});
- return this;
- },
-
- /*
- * Create a new Timepicker instance
- */
- _newInst: function ($input, opts) {
- var tp_inst = new Timepicker(),
- inlineSettings = {},
- fns = {},
- overrides, i;
-
- for (var attrName in this._defaults) {
- if (this._defaults.hasOwnProperty(attrName)) {
- var attrValue = $input.attr('time:' + attrName);
- if (attrValue) {
- try {
- inlineSettings[attrName] = eval(attrValue);
- } catch (err) {
- inlineSettings[attrName] = attrValue;
- }
- }
- }
- }
-
- overrides = {
- beforeShow: function (input, dp_inst) {
- if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) {
- return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst);
- }
- },
- onChangeMonthYear: function (year, month, dp_inst) {
- // Update the time as well : this prevents the time from disappearing from the $input field.
- // tp_inst._updateDateTime(dp_inst);
- if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) {
- tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);
- }
- },
- onClose: function (dateText, dp_inst) {
- if (tp_inst.timeDefined === true && $input.val() !== '') {
- tp_inst._updateDateTime(dp_inst);
- }
- if ($.isFunction(tp_inst._defaults.evnts.onClose)) {
- tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst);
- }
- }
- };
- for (i in overrides) {
- if (overrides.hasOwnProperty(i)) {
- fns[i] = opts[i] || this._defaults[i] || null;
- }
- }
-
- tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, opts, overrides, {
- evnts: fns,
- timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
- });
- tp_inst.amNames = $.map(tp_inst._defaults.amNames, function (val) {
- return val.toUpperCase();
- });
- tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function (val) {
- return val.toUpperCase();
- });
-
- // detect which units are supported
- tp_inst.support = detectSupport(
- tp_inst._defaults.timeFormat +
- (tp_inst._defaults.pickerTimeFormat ? tp_inst._defaults.pickerTimeFormat : '') +
- (tp_inst._defaults.altTimeFormat ? tp_inst._defaults.altTimeFormat : ''));
-
- // controlType is string - key to our this._controls
- if (typeof(tp_inst._defaults.controlType) === 'string') {
- if (tp_inst._defaults.controlType === 'slider' && typeof($.ui.slider) === 'undefined') {
- tp_inst._defaults.controlType = 'select';
- }
- tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType];
- }
- // controlType is an object and must implement create, options, value methods
- else {
- tp_inst.control = tp_inst._defaults.controlType;
- }
-
- // prep the timezone options
- var timezoneList = [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270, -240, -210, -180, -120, -60,
- 0, 60, 120, 180, 210, 240, 270, 300, 330, 345, 360, 390, 420, 480, 525, 540, 570, 600, 630, 660, 690, 720, 765, 780, 840];
- if (tp_inst._defaults.timezoneList !== null) {
- timezoneList = tp_inst._defaults.timezoneList;
- }
- var tzl = timezoneList.length, tzi = 0, tzv = null;
- if (tzl > 0 && typeof timezoneList[0] !== 'object') {
- for (; tzi < tzl; tzi++) {
- tzv = timezoneList[tzi];
- timezoneList[tzi] = { value: tzv, label: $.timepicker.timezoneOffsetString(tzv, tp_inst.support.iso8601) };
- }
- }
- tp_inst._defaults.timezoneList = timezoneList;
-
- // set the default units
- tp_inst.timezone = tp_inst._defaults.timezone !== null ? $.timepicker.timezoneOffsetNumber(tp_inst._defaults.timezone) :
- ((new Date()).getTimezoneOffset() * -1);
- tp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin ? tp_inst._defaults.hourMin :
- tp_inst._defaults.hour > tp_inst._defaults.hourMax ? tp_inst._defaults.hourMax : tp_inst._defaults.hour;
- tp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin ? tp_inst._defaults.minuteMin :
- tp_inst._defaults.minute > tp_inst._defaults.minuteMax ? tp_inst._defaults.minuteMax : tp_inst._defaults.minute;
- tp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin ? tp_inst._defaults.secondMin :
- tp_inst._defaults.second > tp_inst._defaults.secondMax ? tp_inst._defaults.secondMax : tp_inst._defaults.second;
- tp_inst.millisec = tp_inst._defaults.millisec < tp_inst._defaults.millisecMin ? tp_inst._defaults.millisecMin :
- tp_inst._defaults.millisec > tp_inst._defaults.millisecMax ? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec;
- tp_inst.microsec = tp_inst._defaults.microsec < tp_inst._defaults.microsecMin ? tp_inst._defaults.microsecMin :
- tp_inst._defaults.microsec > tp_inst._defaults.microsecMax ? tp_inst._defaults.microsecMax : tp_inst._defaults.microsec;
- tp_inst.ampm = '';
- tp_inst.$input = $input;
-
- if (tp_inst._defaults.altField) {
- tp_inst.$altInput = $(tp_inst._defaults.altField);
- if (tp_inst._defaults.altRedirectFocus === true) {
- tp_inst.$altInput.css({
- cursor: 'pointer'
- }).focus(function () {
- $input.trigger("focus");
- });
- }
- }
-
- if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) {
- tp_inst._defaults.minDate = new Date();
- }
- if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) {
- tp_inst._defaults.maxDate = new Date();
- }
-
- // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
- if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) {
- tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
- }
- if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) {
- tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
- }
- if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) {
- tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
- }
- if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) {
- tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
- }
- tp_inst.$input.bind('focus', function () {
- tp_inst._onFocus();
- });
-
- return tp_inst;
- },
-
- /*
- * add our sliders to the calendar
- */
- _addTimePicker: function (dp_inst) {
- var currDT = $.trim((this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val());
-
- this.timeDefined = this._parseTime(currDT);
- this._limitMinMaxDateTime(dp_inst, false);
- this._injectTimePicker();
- this._afterInject();
- },
-
- /*
- * parse the time string from input value or _setTime
- */
- _parseTime: function (timeString, withDate) {
- if (!this.inst) {
- this.inst = $.datepicker._getInst(this.$input[0]);
- }
-
- if (withDate || !this._defaults.timeOnly) {
- var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
- try {
- var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);
- if (!parseRes.timeObj) {
- return false;
- }
- $.extend(this, parseRes.timeObj);
- } catch (err) {
- $.timepicker.log("Error parsing the date/time string: " + err +
- "\ndate/time string = " + timeString +
- "\ntimeFormat = " + this._defaults.timeFormat +
- "\ndateFormat = " + dp_dateFormat);
- return false;
- }
- return true;
- } else {
- var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);
- if (!timeObj) {
- return false;
- }
- $.extend(this, timeObj);
- return true;
- }
- },
-
- /*
- * Handle callback option after injecting timepicker
- */
- _afterInject: function() {
- var o = this.inst.settings;
- if ($.isFunction(o.afterInject)) {
- o.afterInject.call(this);
- }
- },
-
- /*
- * generate and inject html for timepicker into ui datepicker
- */
- _injectTimePicker: function () {
- var $dp = this.inst.dpDiv,
- o = this.inst.settings,
- tp_inst = this,
- litem = '',
- uitem = '',
- show = null,
- max = {},
- gridSize = {},
- size = null,
- i = 0,
- l = 0;
-
- // Prevent displaying twice
- if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) {
- var noDisplay = ' ui_tpicker_unit_hide',
- html = '
' + '- ' + o.timeText + '
' +
- '';
-
- // Create the markup
- for (i = 0, l = this.units.length; i < l; i++) {
- litem = this.units[i];
- uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
- show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
-
- // Added by Peter Medeiros:
- // - Figure out what the hour/minute/second max should be based on the step values.
- // - Example: if stepMinute is 15, then minMax is 45.
- max[litem] = parseInt((o[litem + 'Max'] - ((o[litem + 'Max'] - o[litem + 'Min']) % o['step' + uitem])), 10);
- gridSize[litem] = 0;
-
- html += '- ' + o[litem + 'Text'] + '
' +
- '- ';
-
- if (show && o[litem + 'Grid'] > 0) {
- html += '
';
-
- if (litem === 'hour') {
- for (var h = o[litem + 'Min']; h <= max[litem]; h += parseInt(o[litem + 'Grid'], 10)) {
- gridSize[litem]++;
- var tmph = $.datepicker.formatTime(this.support.ampm ? 'hht' : 'HH', {hour: h}, o);
- html += '' + tmph + ' | ';
- }
- }
- else {
- for (var m = o[litem + 'Min']; m <= max[litem]; m += parseInt(o[litem + 'Grid'], 10)) {
- gridSize[litem]++;
- html += '' + ((m < 10) ? '0' : '') + m + ' | ';
- }
- }
-
- html += '
';
- }
- html += ' ';
- }
-
- // Timezone
- var showTz = o.showTimezone !== null ? o.showTimezone : this.support.timezone;
- html += '- ' + o.timezoneText + '
';
- html += '';
-
- // Create the elements from string
- html += '
';
- var $tp = $(html);
-
- // if we only want time picker...
- if (o.timeOnly === true) {
- $tp.prepend('');
- $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
- }
-
- // add sliders, adjust grids, add events
- for (i = 0, l = tp_inst.units.length; i < l; i++) {
- litem = tp_inst.units[i];
- uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
- show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
-
- // add the slider
- tp_inst[litem + '_slider'] = tp_inst.control.create(tp_inst, $tp.find('.ui_tpicker_' + litem + '_slider'), litem, tp_inst[litem], o[litem + 'Min'], max[litem], o['step' + uitem]);
-
- // adjust the grid and add click event
- if (show && o[litem + 'Grid'] > 0) {
- size = 100 * gridSize[litem] * o[litem + 'Grid'] / (max[litem] - o[litem + 'Min']);
- $tp.find('.ui_tpicker_' + litem + ' table').css({
- width: size + "%",
- marginLeft: o.isRTL ? '0' : ((size / (-2 * gridSize[litem])) + "%"),
- marginRight: o.isRTL ? ((size / (-2 * gridSize[litem])) + "%") : '0',
- borderCollapse: 'collapse'
- }).find("td").click(function (e) {
- var $t = $(this),
- h = $t.html(),
- n = parseInt(h.replace(/[^0-9]/g), 10),
- ap = h.replace(/[^apm]/ig),
- f = $t.data('for'); // loses scope, so we use data-for
-
- if (f === 'hour') {
- if (ap.indexOf('p') !== -1 && n < 12) {
- n += 12;
- }
- else {
- if (ap.indexOf('a') !== -1 && n === 12) {
- n = 0;
- }
- }
- }
-
- tp_inst.control.value(tp_inst, tp_inst[f + '_slider'], litem, n);
-
- tp_inst._onTimeChange();
- tp_inst._onSelectHandler();
- }).css({
- cursor: 'pointer',
- width: (100 / gridSize[litem]) + '%',
- textAlign: 'center',
- overflow: 'hidden'
- });
- } // end if grid > 0
- } // end for loop
-
- // Add timezone options
- this.timezone_select = $tp.find('.ui_tpicker_timezone').append('').find("select");
- $.fn.append.apply(this.timezone_select,
- $.map(o.timezoneList, function (val, idx) {
- return $("").val(typeof val === "object" ? val.value : val).text(typeof val === "object" ? val.label : val);
- }));
- if (typeof(this.timezone) !== "undefined" && this.timezone !== null && this.timezone !== "") {
- var local_timezone = (new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12)).getTimezoneOffset() * -1;
- if (local_timezone === this.timezone) {
- selectLocalTimezone(tp_inst);
- } else {
- this.timezone_select.val(this.timezone);
- }
- } else {
- if (typeof(this.hour) !== "undefined" && this.hour !== null && this.hour !== "") {
- this.timezone_select.val(o.timezone);
- } else {
- selectLocalTimezone(tp_inst);
- }
- }
- this.timezone_select.change(function () {
- tp_inst._onTimeChange();
- tp_inst._onSelectHandler();
- tp_inst._afterInject();
- });
- // End timezone options
-
- // inject timepicker into datepicker
- var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
- if ($buttonPanel.length) {
- $buttonPanel.before($tp);
- } else {
- $dp.append($tp);
- }
-
- this.$timeObj = $tp.find('.ui_tpicker_time');
-
- if (this.inst !== null) {
- var timeDefined = this.timeDefined;
- this._onTimeChange();
- this.timeDefined = timeDefined;
- }
-
- // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
- if (this._defaults.addSliderAccess) {
- var sliderAccessArgs = this._defaults.sliderAccessArgs,
- rtl = this._defaults.isRTL;
- sliderAccessArgs.isRTL = rtl;
-
- setTimeout(function () { // fix for inline mode
- if ($tp.find('.ui-slider-access').length === 0) {
- $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);
-
- // fix any grids since sliders are shorter
- var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);
- if (sliderAccessWidth) {
- $tp.find('table:visible').each(function () {
- var $g = $(this),
- oldWidth = $g.outerWidth(),
- oldMarginLeft = $g.css(rtl ? 'marginRight' : 'marginLeft').toString().replace('%', ''),
- newWidth = oldWidth - sliderAccessWidth,
- newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%',
- css = { width: newWidth, marginRight: 0, marginLeft: 0 };
- css[rtl ? 'marginRight' : 'marginLeft'] = newMarginLeft;
- $g.css(css);
- });
- }
- }
- }, 10);
- }
- // end slideAccess integration
-
- tp_inst._limitMinMaxDateTime(this.inst, true);
- }
- },
-
- /*
- * This function tries to limit the ability to go outside the
- * min/max date range
- */
- _limitMinMaxDateTime: function (dp_inst, adjustSliders) {
- var o = this._defaults,
- dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);
-
- if (!this._defaults.showTimepicker) {
- return;
- } // No time so nothing to check here
-
- if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) {
- var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),
- minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
-
- if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null || this.microsecMinOriginal === null) {
- this.hourMinOriginal = o.hourMin;
- this.minuteMinOriginal = o.minuteMin;
- this.secondMinOriginal = o.secondMin;
- this.millisecMinOriginal = o.millisecMin;
- this.microsecMinOriginal = o.microsecMin;
- }
-
- if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() === dp_date.getTime()) {
- this._defaults.hourMin = minDateTime.getHours();
- if (this.hour <= this._defaults.hourMin) {
- this.hour = this._defaults.hourMin;
- this._defaults.minuteMin = minDateTime.getMinutes();
- if (this.minute <= this._defaults.minuteMin) {
- this.minute = this._defaults.minuteMin;
- this._defaults.secondMin = minDateTime.getSeconds();
- if (this.second <= this._defaults.secondMin) {
- this.second = this._defaults.secondMin;
- this._defaults.millisecMin = minDateTime.getMilliseconds();
- if (this.millisec <= this._defaults.millisecMin) {
- this.millisec = this._defaults.millisecMin;
- this._defaults.microsecMin = minDateTime.getMicroseconds();
- } else {
- if (this.microsec < this._defaults.microsecMin) {
- this.microsec = this._defaults.microsecMin;
- }
- this._defaults.microsecMin = this.microsecMinOriginal;
- }
- } else {
- this._defaults.millisecMin = this.millisecMinOriginal;
- this._defaults.microsecMin = this.microsecMinOriginal;
- }
- } else {
- this._defaults.secondMin = this.secondMinOriginal;
- this._defaults.millisecMin = this.millisecMinOriginal;
- this._defaults.microsecMin = this.microsecMinOriginal;
- }
- } else {
- this._defaults.minuteMin = this.minuteMinOriginal;
- this._defaults.secondMin = this.secondMinOriginal;
- this._defaults.millisecMin = this.millisecMinOriginal;
- this._defaults.microsecMin = this.microsecMinOriginal;
- }
- } else {
- this._defaults.hourMin = this.hourMinOriginal;
- this._defaults.minuteMin = this.minuteMinOriginal;
- this._defaults.secondMin = this.secondMinOriginal;
- this._defaults.millisecMin = this.millisecMinOriginal;
- this._defaults.microsecMin = this.microsecMinOriginal;
- }
- }
-
- if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) {
- var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),
- maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
-
- if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null || this.millisecMaxOriginal === null) {
- this.hourMaxOriginal = o.hourMax;
- this.minuteMaxOriginal = o.minuteMax;
- this.secondMaxOriginal = o.secondMax;
- this.millisecMaxOriginal = o.millisecMax;
- this.microsecMaxOriginal = o.microsecMax;
- }
-
- if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() === dp_date.getTime()) {
- this._defaults.hourMax = maxDateTime.getHours();
- if (this.hour >= this._defaults.hourMax) {
- this.hour = this._defaults.hourMax;
- this._defaults.minuteMax = maxDateTime.getMinutes();
- if (this.minute >= this._defaults.minuteMax) {
- this.minute = this._defaults.minuteMax;
- this._defaults.secondMax = maxDateTime.getSeconds();
- if (this.second >= this._defaults.secondMax) {
- this.second = this._defaults.secondMax;
- this._defaults.millisecMax = maxDateTime.getMilliseconds();
- if (this.millisec >= this._defaults.millisecMax) {
- this.millisec = this._defaults.millisecMax;
- this._defaults.microsecMax = maxDateTime.getMicroseconds();
- } else {
- if (this.microsec > this._defaults.microsecMax) {
- this.microsec = this._defaults.microsecMax;
- }
- this._defaults.microsecMax = this.microsecMaxOriginal;
- }
- } else {
- this._defaults.millisecMax = this.millisecMaxOriginal;
- this._defaults.microsecMax = this.microsecMaxOriginal;
- }
- } else {
- this._defaults.secondMax = this.secondMaxOriginal;
- this._defaults.millisecMax = this.millisecMaxOriginal;
- this._defaults.microsecMax = this.microsecMaxOriginal;
- }
- } else {
- this._defaults.minuteMax = this.minuteMaxOriginal;
- this._defaults.secondMax = this.secondMaxOriginal;
- this._defaults.millisecMax = this.millisecMaxOriginal;
- this._defaults.microsecMax = this.microsecMaxOriginal;
- }
- } else {
- this._defaults.hourMax = this.hourMaxOriginal;
- this._defaults.minuteMax = this.minuteMaxOriginal;
- this._defaults.secondMax = this.secondMaxOriginal;
- this._defaults.millisecMax = this.millisecMaxOriginal;
- this._defaults.microsecMax = this.microsecMaxOriginal;
- }
- }
-
- if (dp_inst.settings.minTime!==null) {
- var tempMinTime=new Date("01/01/1970 " + dp_inst.settings.minTime);
- if (this.hourtempMaxTime.getHours()) {
- this.hour=this._defaults.hourMax=tempMaxTime.getHours();
- this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();
- } else if (this.hour===tempMaxTime.getHours() && this.minute>tempMaxTime.getMinutes()) {
- this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();
- } else {
- if (this._defaults.hourMax>tempMaxTime.getHours()) {
- this._defaults.hourMax=tempMaxTime.getHours();
- this._defaults.minuteMax=tempMaxTime.getMinutes();
- } else if (this._defaults.hourMax===tempMaxTime.getHours()===this.hour && this._defaults.minuteMax>tempMaxTime.getMinutes()) {
- this._defaults.minuteMax=tempMaxTime.getMinutes();
- } else {
- this._defaults.minuteMax=59;
- }
- }
- }
-
- if (adjustSliders !== undefined && adjustSliders === true) {
- var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10),
- minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10),
- secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10),
- millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10),
- microsecMax = parseInt((this._defaults.microsecMax - ((this._defaults.microsecMax - this._defaults.microsecMin) % this._defaults.stepMicrosec)), 10);
-
- if (this.hour_slider) {
- this.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax, step: this._defaults.stepHour });
- this.control.value(this, this.hour_slider, 'hour', this.hour - (this.hour % this._defaults.stepHour));
- }
- if (this.minute_slider) {
- this.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax, step: this._defaults.stepMinute });
- this.control.value(this, this.minute_slider, 'minute', this.minute - (this.minute % this._defaults.stepMinute));
- }
- if (this.second_slider) {
- this.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax, step: this._defaults.stepSecond });
- this.control.value(this, this.second_slider, 'second', this.second - (this.second % this._defaults.stepSecond));
- }
- if (this.millisec_slider) {
- this.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax, step: this._defaults.stepMillisec });
- this.control.value(this, this.millisec_slider, 'millisec', this.millisec - (this.millisec % this._defaults.stepMillisec));
- }
- if (this.microsec_slider) {
- this.control.options(this, this.microsec_slider, 'microsec', { min: this._defaults.microsecMin, max: microsecMax, step: this._defaults.stepMicrosec });
- this.control.value(this, this.microsec_slider, 'microsec', this.microsec - (this.microsec % this._defaults.stepMicrosec));
- }
- }
-
- },
-
- /*
- * when a slider moves, set the internal time...
- * on time change is also called when the time is updated in the text field
- */
- _onTimeChange: function () {
- if (!this._defaults.showTimepicker) {
- return;
- }
- var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false,
- minute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false,
- second = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false,
- millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false,
- microsec = (this.microsec_slider) ? this.control.value(this, this.microsec_slider, 'microsec') : false,
- timezone = (this.timezone_select) ? this.timezone_select.val() : false,
- o = this._defaults,
- pickerTimeFormat = o.pickerTimeFormat || o.timeFormat,
- pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;
-
- if (typeof(hour) === 'object') {
- hour = false;
- }
- if (typeof(minute) === 'object') {
- minute = false;
- }
- if (typeof(second) === 'object') {
- second = false;
- }
- if (typeof(millisec) === 'object') {
- millisec = false;
- }
- if (typeof(microsec) === 'object') {
- microsec = false;
- }
- if (typeof(timezone) === 'object') {
- timezone = false;
- }
-
- if (hour !== false) {
- hour = parseInt(hour, 10);
- }
- if (minute !== false) {
- minute = parseInt(minute, 10);
- }
- if (second !== false) {
- second = parseInt(second, 10);
- }
- if (millisec !== false) {
- millisec = parseInt(millisec, 10);
- }
- if (microsec !== false) {
- microsec = parseInt(microsec, 10);
- }
- if (timezone !== false) {
- timezone = timezone.toString();
- }
-
- var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];
-
- // If the update was done in the input field, the input field should not be updated.
- // If the update was done using the sliders, update the input field.
- var hasChanged = (
- hour !== parseInt(this.hour,10) || // sliders should all be numeric
- minute !== parseInt(this.minute,10) ||
- second !== parseInt(this.second,10) ||
- millisec !== parseInt(this.millisec,10) ||
- microsec !== parseInt(this.microsec,10) ||
- (this.ampm.length > 0 && (hour < 12) !== ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1)) ||
- (this.timezone !== null && timezone !== this.timezone.toString()) // could be numeric or "EST" format, so use toString()
- );
-
- if (hasChanged) {
-
- if (hour !== false) {
- this.hour = hour;
- }
- if (minute !== false) {
- this.minute = minute;
- }
- if (second !== false) {
- this.second = second;
- }
- if (millisec !== false) {
- this.millisec = millisec;
- }
- if (microsec !== false) {
- this.microsec = microsec;
- }
- if (timezone !== false) {
- this.timezone = timezone;
- }
-
- if (!this.inst) {
- this.inst = $.datepicker._getInst(this.$input[0]);
- }
-
- this._limitMinMaxDateTime(this.inst, true);
- }
- if (this.support.ampm) {
- this.ampm = ampm;
- }
-
- // Updates the time within the timepicker
- this.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o);
- if (this.$timeObj) {
- if (pickerTimeFormat === o.timeFormat) {
- this.$timeObj.text(this.formattedTime + pickerTimeSuffix);
- }
- else {
- this.$timeObj.text($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix);
- }
- }
-
- this.timeDefined = true;
- if (hasChanged) {
- this._updateDateTime();
- //this.$input.focus(); // may automatically open the picker on setDate
- }
- },
-
- /*
- * call custom onSelect.
- * bind to sliders slidestop, and grid click.
- */
- _onSelectHandler: function () {
- var onSelect = this._defaults.onSelect || this.inst.settings.onSelect;
- var inputEl = this.$input ? this.$input[0] : null;
- if (onSelect && inputEl) {
- onSelect.apply(inputEl, [this.formattedDateTime, this]);
- }
- },
-
- /*
- * update our input with the new date time..
- */
- _updateDateTime: function (dp_inst) {
- dp_inst = this.inst || dp_inst;
- var dtTmp = (dp_inst.currentYear > 0?
- new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay) :
- new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
- dt = $.datepicker._daylightSavingAdjust(dtTmp),
- //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
- //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay)),
- dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
- formatCfg = $.datepicker._getFormatConfig(dp_inst),
- timeAvailable = dt !== null && this.timeDefined;
- this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);
- var formattedDateTime = this.formattedDate;
-
- // if a slider was changed but datepicker doesn't have a value yet, set it
- if (dp_inst.lastVal === "") {
- dp_inst.currentYear = dp_inst.selectedYear;
- dp_inst.currentMonth = dp_inst.selectedMonth;
- dp_inst.currentDay = dp_inst.selectedDay;
- }
-
- /*
- * remove following lines to force every changes in date picker to change the input value
- * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker.
- * If the user manually empty the value in the input field, the date picker will never change selected value.
- */
- //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {
- // return;
- //}
-
- if (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === false) {
- formattedDateTime = this.formattedTime;
- } else if ((this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) || (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === true)) {
- formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;
- }
-
- this.formattedDateTime = formattedDateTime;
-
- if (!this._defaults.showTimepicker) {
- this.$input.val(this.formattedDate);
- } else if (this.$altInput && this._defaults.timeOnly === false && this._defaults.altFieldTimeOnly === true) {
- this.$altInput.val(this.formattedTime);
- this.$input.val(this.formattedDate);
- } else if (this.$altInput) {
- this.$input.val(formattedDateTime);
- var altFormattedDateTime = '',
- altSeparator = this._defaults.altSeparator !== null ? this._defaults.altSeparator : this._defaults.separator,
- altTimeSuffix = this._defaults.altTimeSuffix !== null ? this._defaults.altTimeSuffix : this._defaults.timeSuffix;
-
- if (!this._defaults.timeOnly) {
- if (this._defaults.altFormat) {
- altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg);
- }
- else {
- altFormattedDateTime = this.formattedDate;
- }
-
- if (altFormattedDateTime) {
- altFormattedDateTime += altSeparator;
- }
- }
-
- if (this._defaults.altTimeFormat !== null) {
- altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix;
- }
- else {
- altFormattedDateTime += this.formattedTime + altTimeSuffix;
- }
- this.$altInput.val(altFormattedDateTime);
- } else {
- this.$input.val(formattedDateTime);
- }
-
- this.$input.trigger("change");
- },
-
- _onFocus: function () {
- if (!this.$input.val() && this._defaults.defaultValue) {
- this.$input.val(this._defaults.defaultValue);
- var inst = $.datepicker._getInst(this.$input.get(0)),
- tp_inst = $.datepicker._get(inst, 'timepicker');
- if (tp_inst) {
- if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {
- try {
- $.datepicker._updateDatepicker(inst);
- } catch (err) {
- $.timepicker.log(err);
- }
- }
- }
- }
- },
-
- /*
- * Small abstraction to control types
- * We can add more, just be sure to follow the pattern: create, options, value
- */
- _controls: {
- // slider methods
- slider: {
- create: function (tp_inst, obj, unit, val, min, max, step) {
- var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60
- return obj.prop('slide', null).slider({
- orientation: "horizontal",
- value: rtl ? val * -1 : val,
- min: rtl ? max * -1 : min,
- max: rtl ? min * -1 : max,
- step: step,
- slide: function (event, ui) {
- tp_inst.control.value(tp_inst, $(this), unit, rtl ? ui.value * -1 : ui.value);
- tp_inst._onTimeChange();
- },
- stop: function (event, ui) {
- tp_inst._onSelectHandler();
- }
- });
- },
- options: function (tp_inst, obj, unit, opts, val) {
- if (tp_inst._defaults.isRTL) {
- if (typeof(opts) === 'string') {
- if (opts === 'min' || opts === 'max') {
- if (val !== undefined) {
- return obj.slider(opts, val * -1);
- }
- return Math.abs(obj.slider(opts));
- }
- return obj.slider(opts);
- }
- var min = opts.min,
- max = opts.max;
- opts.min = opts.max = null;
- if (min !== undefined) {
- opts.max = min * -1;
- }
- if (max !== undefined) {
- opts.min = max * -1;
- }
- return obj.slider(opts);
- }
- if (typeof(opts) === 'string' && val !== undefined) {
- return obj.slider(opts, val);
- }
- return obj.slider(opts);
- },
- value: function (tp_inst, obj, unit, val) {
- if (tp_inst._defaults.isRTL) {
- if (val !== undefined) {
- return obj.slider('value', val * -1);
- }
- return Math.abs(obj.slider('value'));
- }
- if (val !== undefined) {
- return obj.slider('value', val);
- }
- return obj.slider('value');
- }
- },
- // select methods
- select: {
- create: function (tp_inst, obj, unit, val, min, max, step) {
- var sel = '';
-
- obj.children('select').remove();
-
- $(sel).appendTo(obj).change(function (e) {
- tp_inst._onTimeChange();
- tp_inst._onSelectHandler();
- tp_inst._afterInject();
- });
-
- return obj;
- },
- options: function (tp_inst, obj, unit, opts, val) {
- var o = {},
- $t = obj.children('select');
- if (typeof(opts) === 'string') {
- if (val === undefined) {
- return $t.data(opts);
- }
- o[opts] = val;
- }
- else { o = opts; }
- return tp_inst.control.create(tp_inst, obj, $t.data('unit'), $t.val(), o.min>=0 ? o.min : $t.data('min'), o.max || $t.data('max'), o.step || $t.data('step'));
- },
- value: function (tp_inst, obj, unit, val) {
- var $t = obj.children('select');
- if (val !== undefined) {
- return $t.val(val);
- }
- return $t.val();
- }
- }
- } // end _controls
-
- });
-
- $.fn.extend({
- /*
- * shorthand just to use timepicker.
- */
- timepicker: function (o) {
- o = o || {};
- var tmp_args = Array.prototype.slice.call(arguments);
-
- if (typeof o === 'object') {
- tmp_args[0] = $.extend(o, {
- timeOnly: true
- });
- }
-
- return $(this).each(function () {
- $.fn.datetimepicker.apply($(this), tmp_args);
- });
- },
-
- /*
- * extend timepicker to datepicker
- */
- datetimepicker: function (o) {
- o = o || {};
- var tmp_args = arguments;
-
- if (typeof(o) === 'string') {
- if (o === 'getDate' || (o === 'option' && tmp_args.length === 2 && typeof (tmp_args[1]) === 'string')) {
- return $.fn.datepicker.apply($(this[0]), tmp_args);
- } else {
- return this.each(function () {
- var $t = $(this);
- $t.datepicker.apply($t, tmp_args);
- });
- }
- } else {
- return this.each(function () {
- var $t = $(this);
- $t.datepicker($.timepicker._newInst($t, o)._defaults);
- });
- }
- }
- });
-
- /*
- * Public Utility to parse date and time
- */
- $.datepicker.parseDateTime = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
- var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings);
- if (parseRes.timeObj) {
- var t = parseRes.timeObj;
- parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec);
- parseRes.date.setMicroseconds(t.microsec);
- }
-
- return parseRes.date;
- };
-
- /*
- * Public utility to parse time
- */
- $.datepicker.parseTime = function (timeFormat, timeString, options) {
- var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {}),
- iso8601 = (timeFormat.replace(/\'.*?\'/g, '').indexOf('Z') !== -1);
-
- // Strict parse requires the timeString to match the timeFormat exactly
- var strictParse = function (f, s, o) {
-
- // pattern for standard and localized AM/PM markers
- var getPatternAmpm = function (amNames, pmNames) {
- var markers = [];
- if (amNames) {
- $.merge(markers, amNames);
- }
- if (pmNames) {
- $.merge(markers, pmNames);
- }
- markers = $.map(markers, function (val) {
- return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&');
- });
- return '(' + markers.join('|') + ')?';
- };
-
- // figure out position of time elements.. cause js cant do named captures
- var getFormatPositions = function (timeFormat) {
- var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|c{1}|t{1,2}|z|'.*?')/g),
- orders = {
- h: -1,
- m: -1,
- s: -1,
- l: -1,
- c: -1,
- t: -1,
- z: -1
- };
-
- if (finds) {
- for (var i = 0; i < finds.length; i++) {
- if (orders[finds[i].toString().charAt(0)] === -1) {
- orders[finds[i].toString().charAt(0)] = i + 1;
- }
- }
- }
- return orders;
- };
-
- var regstr = '^' + f.toString()
- .replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {
- var ml = match.length;
- switch (match.charAt(0).toLowerCase()) {
- case 'h':
- return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
- case 'm':
- return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
- case 's':
- return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
- case 'l':
- return '(\\d?\\d?\\d)';
- case 'c':
- return '(\\d?\\d?\\d)';
- case 'z':
- return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?';
- case 't':
- return getPatternAmpm(o.amNames, o.pmNames);
- default: // literal escaped in quotes
- return '(' + match.replace(/\'/g, "").replace(/(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g, function (m) { return "\\" + m; }) + ')?';
- }
- })
- .replace(/\s/g, '\\s?') +
- o.timeSuffix + '$',
- order = getFormatPositions(f),
- ampm = '',
- treg;
-
- treg = s.match(new RegExp(regstr, 'i'));
-
- var resTime = {
- hour: 0,
- minute: 0,
- second: 0,
- millisec: 0,
- microsec: 0
- };
-
- if (treg) {
- if (order.t !== -1) {
- if (treg[order.t] === undefined || treg[order.t].length === 0) {
- ampm = '';
- resTime.ampm = '';
- } else {
- ampm = $.inArray(treg[order.t].toUpperCase(), $.map(o.amNames, function (x,i) { return x.toUpperCase(); })) !== -1 ? 'AM' : 'PM';
- resTime.ampm = o[ampm === 'AM' ? 'amNames' : 'pmNames'][0];
- }
- }
-
- if (order.h !== -1) {
- if (ampm === 'AM' && treg[order.h] === '12') {
- resTime.hour = 0; // 12am = 0 hour
- } else {
- if (ampm === 'PM' && treg[order.h] !== '12') {
- resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12
- } else {
- resTime.hour = Number(treg[order.h]);
- }
- }
- }
-
- if (order.m !== -1) {
- resTime.minute = Number(treg[order.m]);
- }
- if (order.s !== -1) {
- resTime.second = Number(treg[order.s]);
- }
- if (order.l !== -1) {
- resTime.millisec = Number(treg[order.l]);
- }
- if (order.c !== -1) {
- resTime.microsec = Number(treg[order.c]);
- }
- if (order.z !== -1 && treg[order.z] !== undefined) {
- resTime.timezone = $.timepicker.timezoneOffsetNumber(treg[order.z]);
- }
-
-
- return resTime;
- }
- return false;
- };// end strictParse
-
- // First try JS Date, if that fails, use strictParse
- var looseParse = function (f, s, o) {
- try {
- var d = new Date('2012-01-01 ' + s);
- if (isNaN(d.getTime())) {
- d = new Date('2012-01-01T' + s);
- if (isNaN(d.getTime())) {
- d = new Date('01/01/2012 ' + s);
- if (isNaN(d.getTime())) {
- throw "Unable to parse time with native Date: " + s;
- }
- }
- }
-
- return {
- hour: d.getHours(),
- minute: d.getMinutes(),
- second: d.getSeconds(),
- millisec: d.getMilliseconds(),
- microsec: d.getMicroseconds(),
- timezone: d.getTimezoneOffset() * -1
- };
- }
- catch (err) {
- try {
- return strictParse(f, s, o);
- }
- catch (err2) {
- $.timepicker.log("Unable to parse \ntimeString: " + s + "\ntimeFormat: " + f);
- }
- }
- return false;
- }; // end looseParse
-
- if (typeof o.parse === "function") {
- return o.parse(timeFormat, timeString, o);
- }
- if (o.parse === 'loose') {
- return looseParse(timeFormat, timeString, o);
- }
- return strictParse(timeFormat, timeString, o);
- };
-
- /**
- * Public utility to format the time
- * @param {string} format format of the time
- * @param {Object} time Object not a Date for timezones
- * @param {Object} [options] essentially the regional[].. amNames, pmNames, ampm
- * @returns {string} the formatted time
- */
- $.datepicker.formatTime = function (format, time, options) {
- options = options || {};
- options = $.extend({}, $.timepicker._defaults, options);
- time = $.extend({
- hour: 0,
- minute: 0,
- second: 0,
- millisec: 0,
- microsec: 0,
- timezone: null
- }, time);
-
- var tmptime = format,
- ampmName = options.amNames[0],
- hour = parseInt(time.hour, 10);
-
- if (hour > 11) {
- ampmName = options.pmNames[0];
- }
-
- tmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {
- switch (match) {
- case 'HH':
- return ('0' + hour).slice(-2);
- case 'H':
- return hour;
- case 'hh':
- return ('0' + convert24to12(hour)).slice(-2);
- case 'h':
- return convert24to12(hour);
- case 'mm':
- return ('0' + time.minute).slice(-2);
- case 'm':
- return time.minute;
- case 'ss':
- return ('0' + time.second).slice(-2);
- case 's':
- return time.second;
- case 'l':
- return ('00' + time.millisec).slice(-3);
- case 'c':
- return ('00' + time.microsec).slice(-3);
- case 'z':
- return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, false);
- case 'Z':
- return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, true);
- case 'T':
- return ampmName.charAt(0).toUpperCase();
- case 'TT':
- return ampmName.toUpperCase();
- case 't':
- return ampmName.charAt(0).toLowerCase();
- case 'tt':
- return ampmName.toLowerCase();
- default:
- return match.replace(/'/g, "");
- }
- });
-
- return tmptime;
- };
-
- /*
- * the bad hack :/ override datepicker so it doesn't close on select
- // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
- */
- $.datepicker._base_selectDate = $.datepicker._selectDate;
- $.datepicker._selectDate = function (id, dateStr) {
- var inst = this._getInst($(id)[0]),
- tp_inst = this._get(inst, 'timepicker'),
- was_inline;
-
- if (tp_inst && inst.settings.showTimepicker) {
- tp_inst._limitMinMaxDateTime(inst, true);
- was_inline = inst.inline;
- inst.inline = inst.stay_open = true;
- //This way the onSelect handler called from calendarpicker get the full dateTime
- this._base_selectDate(id, dateStr);
- inst.inline = was_inline;
- inst.stay_open = false;
- this._notifyChange(inst);
- this._updateDatepicker(inst);
- } else {
- this._base_selectDate(id, dateStr);
- }
- };
-
- /*
- * second bad hack :/ override datepicker so it triggers an event when changing the input field
- * and does not redraw the datepicker on every selectDate event
- */
- $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
- $.datepicker._updateDatepicker = function (inst) {
-
- // don't popup the datepicker if there is another instance already opened
- var input = inst.input[0];
- if ($.datepicker._curInst && $.datepicker._curInst !== inst && $.datepicker._datepickerShowing && $.datepicker._lastInput !== input) {
- return;
- }
-
- if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
-
- this._base_updateDatepicker(inst);
-
- // Reload the time control when changing something in the input text field.
- var tp_inst = this._get(inst, 'timepicker');
- if (tp_inst) {
- tp_inst._addTimePicker(inst);
- }
- }
- };
-
- /*
- * third bad hack :/ override datepicker so it allows spaces and colon in the input field
- */
- $.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
- $.datepicker._doKeyPress = function (event) {
- var inst = $.datepicker._getInst(event.target),
- tp_inst = $.datepicker._get(inst, 'timepicker');
-
- if (tp_inst) {
- if ($.datepicker._get(inst, 'constrainInput')) {
- var ampm = tp_inst.support.ampm,
- tz = tp_inst._defaults.showTimezone !== null ? tp_inst._defaults.showTimezone : tp_inst.support.timezone,
- dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
- datetimeChars = tp_inst._defaults.timeFormat.toString()
- .replace(/[hms]/g, '')
- .replace(/TT/g, ampm ? 'APM' : '')
- .replace(/Tt/g, ampm ? 'AaPpMm' : '')
- .replace(/tT/g, ampm ? 'AaPpMm' : '')
- .replace(/T/g, ampm ? 'AP' : '')
- .replace(/tt/g, ampm ? 'apm' : '')
- .replace(/t/g, ampm ? 'ap' : '') +
- " " + tp_inst._defaults.separator +
- tp_inst._defaults.timeSuffix +
- (tz ? tp_inst._defaults.timezoneList.join('') : '') +
- (tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) +
- dateChars,
- chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
- return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);
- }
- }
-
- return $.datepicker._base_doKeyPress(event);
- };
-
- /*
- * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField
- * Update any alternate field to synchronise with the main field.
- */
- $.datepicker._base_updateAlternate = $.datepicker._updateAlternate;
- $.datepicker._updateAlternate = function (inst) {
- var tp_inst = this._get(inst, 'timepicker');
- if (tp_inst) {
- var altField = tp_inst._defaults.altField;
- if (altField) { // update alternate field too
- var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat,
- date = this._getDate(inst),
- formatCfg = $.datepicker._getFormatConfig(inst),
- altFormattedDateTime = '',
- altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator,
- altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix,
- altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat;
-
- altFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix;
- if (!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly && date !== null) {
- if (tp_inst._defaults.altFormat) {
- altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, date, formatCfg) + altSeparator + altFormattedDateTime;
- }
- else {
- altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime;
- }
- }
- $(altField).val( inst.input.val() ? altFormattedDateTime : "");
- }
- }
- else {
- $.datepicker._base_updateAlternate(inst);
- }
- };
-
- /*
- * Override key up event to sync manual input changes.
- */
- $.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
- $.datepicker._doKeyUp = function (event) {
- var inst = $.datepicker._getInst(event.target),
- tp_inst = $.datepicker._get(inst, 'timepicker');
-
- if (tp_inst) {
- if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {
- try {
- $.datepicker._updateDatepicker(inst);
- } catch (err) {
- $.timepicker.log(err);
- }
- }
- }
-
- return $.datepicker._base_doKeyUp(event);
- };
-
- /*
- * override "Today" button to also grab the time.
- */
- $.datepicker._base_gotoToday = $.datepicker._gotoToday;
- $.datepicker._gotoToday = function (id) {
- var inst = this._getInst($(id)[0]),
- $dp = inst.dpDiv;
- var tp_inst = this._get(inst, 'timepicker');
- selectLocalTimezone(tp_inst);
- var now = new Date();
- this._setTime(inst, now);
- this._setDate(inst, now);
- this._base_gotoToday(id);
- };
-
- /*
- * Disable & enable the Time in the datetimepicker
- */
- $.datepicker._disableTimepickerDatepicker = function (target) {
- var inst = this._getInst(target);
- if (!inst) {
- return;
- }
-
- var tp_inst = this._get(inst, 'timepicker');
- $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
- if (tp_inst) {
- inst.settings.showTimepicker = false;
- tp_inst._defaults.showTimepicker = false;
- tp_inst._updateDateTime(inst);
- }
- };
-
- $.datepicker._enableTimepickerDatepicker = function (target) {
- var inst = this._getInst(target);
- if (!inst) {
- return;
- }
-
- var tp_inst = this._get(inst, 'timepicker');
- $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
- if (tp_inst) {
- inst.settings.showTimepicker = true;
- tp_inst._defaults.showTimepicker = true;
- tp_inst._addTimePicker(inst); // Could be disabled on page load
- tp_inst._updateDateTime(inst);
- }
- };
-
- /*
- * Create our own set time function
- */
- $.datepicker._setTime = function (inst, date) {
- var tp_inst = this._get(inst, 'timepicker');
- if (tp_inst) {
- var defaults = tp_inst._defaults;
-
- // calling _setTime with no date sets time to defaults
- tp_inst.hour = date ? date.getHours() : defaults.hour;
- tp_inst.minute = date ? date.getMinutes() : defaults.minute;
- tp_inst.second = date ? date.getSeconds() : defaults.second;
- tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec;
- tp_inst.microsec = date ? date.getMicroseconds() : defaults.microsec;
-
- //check if within min/max times..
- tp_inst._limitMinMaxDateTime(inst, true);
-
- tp_inst._onTimeChange();
- tp_inst._updateDateTime(inst);
- }
- };
-
- /*
- * Create new public method to set only time, callable as $().datepicker('setTime', date)
- */
- $.datepicker._setTimeDatepicker = function (target, date, withDate) {
- var inst = this._getInst(target);
- if (!inst) {
- return;
- }
-
- var tp_inst = this._get(inst, 'timepicker');
-
- if (tp_inst) {
- this._setDateFromField(inst);
- var tp_date;
- if (date) {
- if (typeof date === "string") {
- tp_inst._parseTime(date, withDate);
- tp_date = new Date();
- tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
- tp_date.setMicroseconds(tp_inst.microsec);
- } else {
- tp_date = new Date(date.getTime());
- tp_date.setMicroseconds(date.getMicroseconds());
- }
- if (tp_date.toString() === 'Invalid Date') {
- tp_date = undefined;
- }
- this._setTime(inst, tp_date);
- }
- }
-
- };
-
- /*
- * override setDate() to allow setting time too within Date object
- */
- $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
- $.datepicker._setDateDatepicker = function (target, _date) {
- var inst = this._getInst(target);
- var date = _date;
- if (!inst) {
- return;
- }
-
- if (typeof(_date) === 'string') {
- date = new Date(_date);
- if (!date.getTime()) {
- this._base_setDateDatepicker.apply(this, arguments);
- date = $(target).datepicker('getDate');
- }
- }
-
- var tp_inst = this._get(inst, 'timepicker');
- var tp_date;
- if (date instanceof Date) {
- tp_date = new Date(date.getTime());
- tp_date.setMicroseconds(date.getMicroseconds());
- } else {
- tp_date = date;
- }
-
- // This is important if you are using the timezone option, javascript's Date
- // object will only return the timezone offset for the current locale, so we
- // adjust it accordingly. If not using timezone option this won't matter..
- // If a timezone is different in tp, keep the timezone as is
- if (tp_inst && tp_date) {
- // look out for DST if tz wasn't specified
- if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {
- tp_inst.timezone = tp_date.getTimezoneOffset() * -1;
- }
- date = $.timepicker.timezoneAdjust(date, tp_inst.timezone);
- tp_date = $.timepicker.timezoneAdjust(tp_date, tp_inst.timezone);
- }
-
- this._updateDatepicker(inst);
- this._base_setDateDatepicker.apply(this, arguments);
- this._setTimeDatepicker(target, tp_date, true);
- };
-
- /*
- * override getDate() to allow getting time too within Date object
- */
- $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
- $.datepicker._getDateDatepicker = function (target, noDefault) {
- var inst = this._getInst(target);
- if (!inst) {
- return;
- }
-
- var tp_inst = this._get(inst, 'timepicker');
-
- if (tp_inst) {
- // if it hasn't yet been defined, grab from field
- if (inst.lastVal === undefined) {
- this._setDateFromField(inst, noDefault);
- }
-
- var date = this._getDate(inst);
- var currDT = $.trim((tp_inst.$altInput && tp_inst._defaults.altFieldTimeOnly) ? tp_inst.$input.val() + ' ' + tp_inst.$altInput.val() : tp_inst.$input.val());
- if (date && tp_inst._parseTime(currDT, !inst.settings.timeOnly)) {
- date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
- date.setMicroseconds(tp_inst.microsec);
-
- // This is important if you are using the timezone option, javascript's Date
- // object will only return the timezone offset for the current locale, so we
- // adjust it accordingly. If not using timezone option this won't matter..
- if (tp_inst.timezone != null) {
- // look out for DST if tz wasn't specified
- if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {
- tp_inst.timezone = date.getTimezoneOffset() * -1;
- }
- date = $.timepicker.timezoneAdjust(date, tp_inst.timezone);
- }
- }
- return date;
- }
- return this._base_getDateDatepicker(target, noDefault);
- };
-
- /*
- * override parseDate() because UI 1.8.14 throws an error about "Extra characters"
- * An option in datapicker to ignore extra format characters would be nicer.
- */
- $.datepicker._base_parseDate = $.datepicker.parseDate;
- $.datepicker.parseDate = function (format, value, settings) {
- var date;
- try {
- date = this._base_parseDate(format, value, settings);
- } catch (err) {
- // Hack! The error message ends with a colon, a space, and
- // the "extra" characters. We rely on that instead of
- // attempting to perfectly reproduce the parsing algorithm.
- if (err.indexOf(":") >= 0) {
- date = this._base_parseDate(format, value.substring(0, value.length - (err.length - err.indexOf(':') - 2)), settings);
- $.timepicker.log("Error parsing the date string: " + err + "\ndate string = " + value + "\ndate format = " + format);
- } else {
- throw err;
- }
- }
- return date;
- };
-
- /*
- * override formatDate to set date with time to the input
- */
- $.datepicker._base_formatDate = $.datepicker._formatDate;
- $.datepicker._formatDate = function (inst, day, month, year) {
- var tp_inst = this._get(inst, 'timepicker');
- if (tp_inst) {
- tp_inst._updateDateTime(inst);
- return tp_inst.$input.val();
- }
- return this._base_formatDate(inst);
- };
-
- /*
- * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
- */
- $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
- $.datepicker._optionDatepicker = function (target, name, value) {
- var inst = this._getInst(target),
- name_clone;
- if (!inst) {
- return null;
- }
-
- var tp_inst = this._get(inst, 'timepicker');
- if (tp_inst) {
- var min = null,
- max = null,
- onselect = null,
- overrides = tp_inst._defaults.evnts,
- fns = {},
- prop,
- ret,
- oldVal,
- $target;
- if (typeof name === 'string') { // if min/max was set with the string
- if (name === 'minDate' || name === 'minDateTime') {
- min = value;
- } else if (name === 'maxDate' || name === 'maxDateTime') {
- max = value;
- } else if (name === 'onSelect') {
- onselect = value;
- } else if (overrides.hasOwnProperty(name)) {
- if (typeof (value) === 'undefined') {
- return overrides[name];
- }
- fns[name] = value;
- name_clone = {}; //empty results in exiting function after overrides updated
- }
- } else if (typeof name === 'object') { //if min/max was set with the JSON
- if (name.minDate) {
- min = name.minDate;
- } else if (name.minDateTime) {
- min = name.minDateTime;
- } else if (name.maxDate) {
- max = name.maxDate;
- } else if (name.maxDateTime) {
- max = name.maxDateTime;
- }
- for (prop in overrides) {
- if (overrides.hasOwnProperty(prop) && name[prop]) {
- fns[prop] = name[prop];
- }
- }
- }
- for (prop in fns) {
- if (fns.hasOwnProperty(prop)) {
- overrides[prop] = fns[prop];
- if (!name_clone) { name_clone = $.extend({}, name); }
- delete name_clone[prop];
- }
- }
- if (name_clone && isEmptyObject(name_clone)) { return; }
- if (min) { //if min was set
- if (min === 0) {
- min = new Date();
- } else {
- min = new Date(min);
- }
- tp_inst._defaults.minDate = min;
- tp_inst._defaults.minDateTime = min;
- } else if (max) { //if max was set
- if (max === 0) {
- max = new Date();
- } else {
- max = new Date(max);
- }
- tp_inst._defaults.maxDate = max;
- tp_inst._defaults.maxDateTime = max;
- } else if (onselect) {
- tp_inst._defaults.onSelect = onselect;
- }
-
- // Datepicker will override our date when we call _base_optionDatepicker when
- // calling minDate/maxDate, so we will first grab the value, call
- // _base_optionDatepicker, then set our value back.
- if(min || max){
- $target = $(target);
- oldVal = $target.datetimepicker('getDate');
- ret = this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
- $target.datetimepicker('setDate', oldVal);
- return ret;
- }
- }
- if (value === undefined) {
- return this._base_optionDatepicker.call($.datepicker, target, name);
- }
- return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
- };
-
- /*
- * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,
- * it will return false for all objects
- */
- var isEmptyObject = function (obj) {
- var prop;
- for (prop in obj) {
- if (obj.hasOwnProperty(prop)) {
- return false;
- }
- }
- return true;
- };
-
- /*
- * jQuery extend now ignores nulls!
- */
- var extendRemove = function (target, props) {
- $.extend(target, props);
- for (var name in props) {
- if (props[name] === null || props[name] === undefined) {
- target[name] = props[name];
- }
- }
- return target;
- };
-
- /*
- * Determine by the time format which units are supported
- * Returns an object of booleans for each unit
- */
- var detectSupport = function (timeFormat) {
- var tf = timeFormat.replace(/'.*?'/g, '').toLowerCase(), // removes literals
- isIn = function (f, t) { // does the format contain the token?
- return f.indexOf(t) !== -1 ? true : false;
- };
- return {
- hour: isIn(tf, 'h'),
- minute: isIn(tf, 'm'),
- second: isIn(tf, 's'),
- millisec: isIn(tf, 'l'),
- microsec: isIn(tf, 'c'),
- timezone: isIn(tf, 'z'),
- ampm: isIn(tf, 't') && isIn(timeFormat, 'h'),
- iso8601: isIn(timeFormat, 'Z')
- };
- };
-
- /*
- * Converts 24 hour format into 12 hour
- * Returns 12 hour without leading 0
- */
- var convert24to12 = function (hour) {
- hour %= 12;
-
- if (hour === 0) {
- hour = 12;
- }
-
- return String(hour);
- };
-
- var computeEffectiveSetting = function (settings, property) {
- return settings && settings[property] ? settings[property] : $.timepicker._defaults[property];
- };
-
- /*
- * Splits datetime string into date and time substrings.
- * Throws exception when date can't be parsed
- * Returns {dateString: dateString, timeString: timeString}
- */
- var splitDateTime = function (dateTimeString, timeSettings) {
- // The idea is to get the number separator occurrences in datetime and the time format requested (since time has
- // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.
- var separator = computeEffectiveSetting(timeSettings, 'separator'),
- format = computeEffectiveSetting(timeSettings, 'timeFormat'),
- timeParts = format.split(separator), // how many occurrences of separator may be in our format?
- timePartsLen = timeParts.length,
- allParts = dateTimeString.split(separator),
- allPartsLen = allParts.length;
-
- if (allPartsLen > 1) {
- return {
- dateString: allParts.splice(0, allPartsLen - timePartsLen).join(separator),
- timeString: allParts.splice(0, timePartsLen).join(separator)
- };
- }
-
- return {
- dateString: dateTimeString,
- timeString: ''
- };
- };
-
- /*
- * Internal function to parse datetime interval
- * Returns: {date: Date, timeObj: Object}, where
- * date - parsed date without time (type Date)
- * timeObj = {hour: , minute: , second: , millisec: , microsec: } - parsed time. Optional
- */
- var parseDateTimeInternal = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
- var date,
- parts,
- parsedTime;
-
- parts = splitDateTime(dateTimeString, timeSettings);
- date = $.datepicker._base_parseDate(dateFormat, parts.dateString, dateSettings);
-
- if (parts.timeString === '') {
- return {
- date: date
- };
- }
-
- parsedTime = $.datepicker.parseTime(timeFormat, parts.timeString, timeSettings);
-
- if (!parsedTime) {
- throw 'Wrong time format';
- }
-
- return {
- date: date,
- timeObj: parsedTime
- };
- };
-
- /*
- * Internal function to set timezone_select to the local timezone
- */
- var selectLocalTimezone = function (tp_inst, date) {
- if (tp_inst && tp_inst.timezone_select) {
- var now = date || new Date();
- tp_inst.timezone_select.val(-now.getTimezoneOffset());
- }
- };
-
- /*
- * Create a Singleton Instance
- */
- $.timepicker = new Timepicker();
-
- /**
- * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)
- * @param {number} tzMinutes if not a number, less than -720 (-1200), or greater than 840 (+1400) this value is returned
- * @param {boolean} iso8601 if true formats in accordance to iso8601 "+12:45"
- * @return {string}
- */
- $.timepicker.timezoneOffsetString = function (tzMinutes, iso8601) {
- if (isNaN(tzMinutes) || tzMinutes > 840 || tzMinutes < -720) {
- return tzMinutes;
- }
-
- var off = tzMinutes,
- minutes = off % 60,
- hours = (off - minutes) / 60,
- iso = iso8601 ? ':' : '',
- tz = (off >= 0 ? '+' : '-') + ('0' + Math.abs(hours)).slice(-2) + iso + ('0' + Math.abs(minutes)).slice(-2);
-
- if (tz === '+00:00') {
- return 'Z';
- }
- return tz;
- };
-
- /**
- * Get the number in minutes that represents a timezone string
- * @param {string} tzString formatted like "+0500", "-1245", "Z"
- * @return {number} the offset minutes or the original string if it doesn't match expectations
- */
- $.timepicker.timezoneOffsetNumber = function (tzString) {
- var normalized = tzString.toString().replace(':', ''); // excuse any iso8601, end up with "+1245"
-
- if (normalized.toUpperCase() === 'Z') { // if iso8601 with Z, its 0 minute offset
- return 0;
- }
-
- if (!/^(\-|\+)\d{4}$/.test(normalized)) { // possibly a user defined tz, so just give it back
- return tzString;
- }
-
- return ((normalized.substr(0, 1) === '-' ? -1 : 1) * // plus or minus
- ((parseInt(normalized.substr(1, 2), 10) * 60) + // hours (converted to minutes)
- parseInt(normalized.substr(3, 2), 10))); // minutes
- };
-
- /**
- * No way to set timezone in js Date, so we must adjust the minutes to compensate. (think setDate, getDate)
- * @param {Date} date
- * @param {string} toTimezone formatted like "+0500", "-1245"
- * @return {Date}
- */
- $.timepicker.timezoneAdjust = function (date, toTimezone) {
- var toTz = $.timepicker.timezoneOffsetNumber(toTimezone);
- if (!isNaN(toTz)) {
- date.setMinutes(date.getMinutes() + -date.getTimezoneOffset() - toTz);
- }
- return date;
- };
-
- /**
- * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to
- * enforce date range limits.
- * n.b. The input value must be correctly formatted (reformatting is not supported)
- * @param {Element} startTime
- * @param {Element} endTime
- * @param {Object} options Options for the timepicker() call
- * @return {jQuery}
- */
- $.timepicker.timeRange = function (startTime, endTime, options) {
- return $.timepicker.handleRange('timepicker', startTime, endTime, options);
- };
-
- /**
- * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to
- * enforce date range limits.
- * @param {Element} startTime
- * @param {Element} endTime
- * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
- * a boolean value that can be used to reformat the input values to the `dateFormat`.
- * @param {string} method Can be used to specify the type of picker to be added
- * @return {jQuery}
- */
- $.timepicker.datetimeRange = function (startTime, endTime, options) {
- $.timepicker.handleRange('datetimepicker', startTime, endTime, options);
- };
-
- /**
- * Calls `datepicker` on the `startTime` and `endTime` elements, and configures them to
- * enforce date range limits.
- * @param {Element} startTime
- * @param {Element} endTime
- * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
- * a boolean value that can be used to reformat the input values to the `dateFormat`.
- * @return {jQuery}
- */
- $.timepicker.dateRange = function (startTime, endTime, options) {
- $.timepicker.handleRange('datepicker', startTime, endTime, options);
- };
-
- /**
- * Calls `method` on the `startTime` and `endTime` elements, and configures them to
- * enforce date range limits.
- * @param {string} method Can be used to specify the type of picker to be added
- * @param {Element} startTime
- * @param {Element} endTime
- * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
- * a boolean value that can be used to reformat the input values to the `dateFormat`.
- * @return {jQuery}
- */
- $.timepicker.handleRange = function (method, startTime, endTime, options) {
- options = $.extend({}, {
- minInterval: 0, // min allowed interval in milliseconds
- maxInterval: 0, // max allowed interval in milliseconds
- start: {}, // options for start picker
- end: {} // options for end picker
- }, options);
-
- // for the mean time this fixes an issue with calling getDate with timepicker()
- var timeOnly = false;
- if(method === 'timepicker'){
- timeOnly = true;
- method = 'datetimepicker';
- }
-
- function checkDates(changed, other) {
- var startdt = startTime[method]('getDate'),
- enddt = endTime[method]('getDate'),
- changeddt = changed[method]('getDate');
-
- if (startdt !== null) {
- var minDate = new Date(startdt.getTime()),
- maxDate = new Date(startdt.getTime());
-
- minDate.setMilliseconds(minDate.getMilliseconds() + options.minInterval);
- maxDate.setMilliseconds(maxDate.getMilliseconds() + options.maxInterval);
-
- if (options.minInterval > 0 && minDate > enddt) { // minInterval check
- endTime[method]('setDate', minDate);
- }
- else if (options.maxInterval > 0 && maxDate < enddt) { // max interval check
- endTime[method]('setDate', maxDate);
- }
- else if (startdt > enddt) {
- other[method]('setDate', changeddt);
- }
- }
- }
-
- function selected(changed, other, option) {
- if (!changed.val()) {
- return;
- }
- var date = changed[method].call(changed, 'getDate');
- if (date !== null && options.minInterval > 0) {
- if (option === 'minDate') {
- date.setMilliseconds(date.getMilliseconds() + options.minInterval);
- }
- if (option === 'maxDate') {
- date.setMilliseconds(date.getMilliseconds() - options.minInterval);
- }
- }
-
- if (date.getTime) {
- other[method].call(other, 'option', option, date);
- }
- }
-
- $.fn[method].call(startTime, $.extend({
- timeOnly: timeOnly,
- onClose: function (dateText, inst) {
- checkDates($(this), endTime);
- },
- onSelect: function (selectedDateTime) {
- selected($(this), endTime, 'minDate');
- }
- }, options, options.start));
- $.fn[method].call(endTime, $.extend({
- timeOnly: timeOnly,
- onClose: function (dateText, inst) {
- checkDates($(this), startTime);
- },
- onSelect: function (selectedDateTime) {
- selected($(this), startTime, 'maxDate');
- }
- }, options, options.end));
-
- checkDates(startTime, endTime);
-
- selected(startTime, endTime, 'minDate');
- selected(endTime, startTime, 'maxDate');
-
- return $([startTime.get(0), endTime.get(0)]);
- };
-
- /**
- * Log error or data to the console during error or debugging
- * @param {Object} err pass any type object to log to the console during error or debugging
- * @return {void}
- */
- $.timepicker.log = function () {
- if (window.console) {
- window.console.log.apply(window.console, Array.prototype.slice.call(arguments));
- }
- };
-
- /*
- * Add util object to allow access to private methods for testability.
- */
- $.timepicker._util = {
- _extendRemove: extendRemove,
- _isEmptyObject: isEmptyObject,
- _convert24to12: convert24to12,
- _detectSupport: detectSupport,
- _selectLocalTimezone: selectLocalTimezone,
- _computeEffectiveSetting: computeEffectiveSetting,
- _splitDateTime: splitDateTime,
- _parseDateTimeInternal: parseDateTimeInternal
- };
-
- /*
- * Microsecond support
- */
- if (!Date.prototype.getMicroseconds) {
- Date.prototype.microseconds = 0;
- Date.prototype.getMicroseconds = function () { return this.microseconds; };
- Date.prototype.setMicroseconds = function (m) {
- this.setMilliseconds(this.getMilliseconds() + Math.floor(m / 1000));
- this.microseconds = m % 1000;
- return this;
- };
- }
-
- /*
- * Keep up with the version
- */
- $.timepicker.version = "@@version";
-
-}));
diff --git a/web_app/js/external/jquery.keypad.package-2.0.1.zip b/web_app/js/external/jquery.keypad.package-2.0.1.zip
deleted file mode 100644
index 913a4da..0000000
Binary files a/web_app/js/external/jquery.keypad.package-2.0.1.zip and /dev/null differ
diff --git a/web_app/js/external/jquery.timepicker.js b/web_app/js/external/jquery.timepicker.js
new file mode 100644
index 0000000..1861978
--- /dev/null
+++ b/web_app/js/external/jquery.timepicker.js
@@ -0,0 +1,1195 @@
+/*!
+ * jquery-timepicker v1.8.2 - A jQuery timepicker plugin inspired by Google Calendar. It supports both mouse and keyboard navigation.
+ * Copyright (c) 2015 Jon Thornton - http://jonthornton.github.com/jquery-timepicker/
+ * License: MIT
+ */
+
+
+(function (factory) {
+ if (typeof exports === "object" && exports &&
+ typeof module === "object" && module && module.exports === exports) {
+ // Browserify. Attach to jQuery module.
+ factory(require("jquery"));
+ } else if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['jquery'], factory);
+ } else {
+ // Browser globals
+ factory(jQuery);
+ }
+}(function ($) {
+ var _baseDate = _generateBaseDate();
+ var _ONE_DAY = 86400;
+ var _lang = {
+ am: 'am',
+ pm: 'pm',
+ AM: 'AM',
+ PM: 'PM',
+ decimal: '.',
+ mins: 'mins',
+ hr: 'hr',
+ hrs: 'hrs'
+ };
+
+ var methods = {
+ init: function(options)
+ {
+ return this.each(function()
+ {
+ var self = $(this);
+
+ // pick up settings from data attributes
+ var attributeOptions = [];
+ for (var key in $.fn.timepicker.defaults) {
+ if (self.data(key)) {
+ attributeOptions[key] = self.data(key);
+ }
+ }
+
+ var settings = $.extend({}, $.fn.timepicker.defaults, attributeOptions, options);
+
+ if (settings.lang) {
+ _lang = $.extend(_lang, settings.lang);
+ }
+
+ settings = _parseSettings(settings);
+ self.data('timepicker-settings', settings);
+ self.addClass('ui-timepicker-input');
+
+ if (settings.useSelect) {
+ _render(self);
+ } else {
+ self.prop('autocomplete', 'off');
+ if (settings.showOn) {
+ for (i in settings.showOn) {
+ self.on(settings.showOn[i]+'.timepicker', methods.show);
+ }
+ }
+ self.on('change.timepicker', _formatValue);
+ self.on('keydown.timepicker', _keydownhandler);
+ self.on('keyup.timepicker', _keyuphandler);
+ if (settings.disableTextInput) {
+ self.on('keypress.timepicker', function(e) { e.preventDefault(); });
+ }
+
+ _formatValue.call(self.get(0));
+ }
+ });
+ },
+
+ show: function(e)
+ {
+ var self = $(this);
+ var settings = self.data('timepicker-settings');
+
+ if (e) {
+ e.preventDefault();
+ }
+
+ if (settings.useSelect) {
+ self.data('timepicker-list').focus();
+ return;
+ }
+
+ if (_hideKeyboard(self)) {
+ // block the keyboard on mobile devices
+ self.blur();
+ }
+
+ var list = self.data('timepicker-list');
+
+ // check if input is readonly
+ // if (self.prop('readonly')) {
+ // return;
+ // }
+
+ // check if list needs to be rendered
+ if (!list || list.length === 0 || typeof settings.durationTime === 'function') {
+ _render(self);
+ list = self.data('timepicker-list');
+ }
+
+ if (_isVisible(list)) {
+ return;
+ }
+
+ self.data('ui-timepicker-value', self.val());
+ _setSelected(self, list);
+
+ // make sure other pickers are hidden
+ methods.hide();
+
+ // position the dropdown relative to the input
+ list.show();
+ var listOffset = {};
+
+ if (settings.orientation.match(/r/)) {
+ // right-align the dropdown
+ listOffset.left = self.offset().left + self.outerWidth() - list.outerWidth() + parseInt(list.css('marginLeft').replace('px', ''), 10);
+ } else {
+ // left-align the dropdown
+ listOffset.left = self.offset().left + parseInt(list.css('marginLeft').replace('px', ''), 10);
+ }
+
+ var verticalOrientation;
+ if (settings.orientation.match(/t/)) {
+ verticalOrientation = 't';
+ } else if (settings.orientation.match(/b/)) {
+ verticalOrientation = 'b';
+ } else if ((self.offset().top + self.outerHeight(true) + list.outerHeight()) > $(window).height() + $(window).scrollTop()) {
+ verticalOrientation = 't';
+ } else {
+ verticalOrientation = 'b';
+ }
+
+ if (verticalOrientation == 't') {
+ // position the dropdown on top
+ list.addClass('ui-timepicker-positioned-top');
+ listOffset.top = self.offset().top - list.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10);
+ } else {
+ // put it under the input
+ list.removeClass('ui-timepicker-positioned-top');
+ listOffset.top = self.offset().top + self.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10);
+ }
+
+ list.offset(listOffset);
+
+ // position scrolling
+ var selected = list.find('.ui-timepicker-selected');
+
+ if (!selected.length) {
+ if (_getTimeValue(self)) {
+ selected = _findRow(self, list, _time2int(_getTimeValue(self)));
+ } else if (settings.scrollDefault) {
+ selected = _findRow(self, list, settings.scrollDefault());
+ }
+ }
+
+ if (selected && selected.length) {
+ var topOffset = list.scrollTop() + selected.position().top - selected.outerHeight();
+ list.scrollTop(topOffset);
+ } else {
+ list.scrollTop(0);
+ }
+
+ // prevent scroll propagation
+ if(settings.stopScrollPropagation) {
+ $(document).on('wheel.ui-timepicker', '.ui-timepicker-wrapper', function(e){
+ e.preventDefault();
+ var currentScroll = $(this).scrollTop();
+ $(this).scrollTop(currentScroll + e.originalEvent.deltaY);
+ });
+ }
+
+ // attach close handlers
+ $(document).on('touchstart.ui-timepicker mousedown.ui-timepicker', _closeHandler);
+ $(window).on('resize.ui-timepicker', _closeHandler);
+ if (settings.closeOnWindowScroll) {
+ $(document).on('scroll.ui-timepicker', _closeHandler);
+ }
+
+ self.trigger('showTimepicker');
+
+ return this;
+ },
+
+ hide: function(e)
+ {
+ var self = $(this);
+ var settings = self.data('timepicker-settings');
+
+ if (settings && settings.useSelect) {
+ self.blur();
+ }
+
+ $('.ui-timepicker-wrapper').each(function() {
+ var list = $(this);
+ if (!_isVisible(list)) {
+ return;
+ }
+
+ var self = list.data('timepicker-input');
+ var settings = self.data('timepicker-settings');
+
+ if (settings && settings.selectOnBlur) {
+ _selectValue(self);
+ }
+
+ list.hide();
+ self.trigger('hideTimepicker');
+ });
+
+ return this;
+ },
+
+ option: function(key, value)
+ {
+ return this.each(function(){
+ var self = $(this);
+ var settings = self.data('timepicker-settings');
+ var list = self.data('timepicker-list');
+
+ if (typeof key == 'object') {
+ settings = $.extend(settings, key);
+
+ } else if (typeof key == 'string' && typeof value != 'undefined') {
+ settings[key] = value;
+
+ } else if (typeof key == 'string') {
+ return settings[key];
+ }
+
+ settings = _parseSettings(settings);
+
+ self.data('timepicker-settings', settings);
+
+ if (list) {
+ list.remove();
+ self.data('timepicker-list', false);
+ }
+
+ if (settings.useSelect) {
+ _render(self);
+ }
+ });
+ },
+
+ getSecondsFromMidnight: function()
+ {
+ return _time2int(_getTimeValue(this));
+ },
+
+ getTime: function(relative_date)
+ {
+ var self = this;
+
+ var time_string = _getTimeValue(self);
+ if (!time_string) {
+ return null;
+ }
+
+ var offset = _time2int(time_string);
+ if (offset === null) {
+ return null;
+ }
+
+ if (!relative_date) {
+ relative_date = new Date();
+ }
+
+ // construct a Date with today's date, and offset's time
+ var time = new Date(relative_date);
+ time.setHours(offset / 3600);
+ time.setMinutes(offset % 3600 / 60);
+ time.setSeconds(offset % 60);
+ time.setMilliseconds(0);
+
+ return time;
+ },
+
+ setTime: function(value)
+ {
+ var self = this;
+ var settings = self.data('timepicker-settings');
+
+ if (settings.forceRoundTime) {
+ var prettyTime = _roundAndFormatTime(_time2int(value), settings)
+ } else {
+ var prettyTime = _int2time(_time2int(value), settings);
+ }
+
+ if (value && prettyTime === null && settings.noneOption) {
+ prettyTime = value;
+ }
+
+ _setTimeValue(self, prettyTime);
+ if (self.data('timepicker-list')) {
+ _setSelected(self, self.data('timepicker-list'));
+ }
+
+ return this;
+ },
+
+ remove: function()
+ {
+ var self = this;
+
+ // check if this element is a timepicker
+ if (!self.hasClass('ui-timepicker-input')) {
+ return;
+ }
+
+ var settings = self.data('timepicker-settings');
+ self.removeAttr('autocomplete', 'off');
+ self.removeClass('ui-timepicker-input');
+ self.removeData('timepicker-settings');
+ self.off('.timepicker');
+
+ // timepicker-list won't be present unless the user has interacted with this timepicker
+ if (self.data('timepicker-list')) {
+ self.data('timepicker-list').remove();
+ }
+
+ if (settings.useSelect) {
+ self.show();
+ }
+
+ self.removeData('timepicker-list');
+
+ return this;
+ }
+ };
+
+ // private methods
+
+ function _isVisible(elem)
+ {
+ var el = elem[0];
+ return el.offsetWidth > 0 && el.offsetHeight > 0;
+ }
+
+ function _parseSettings(settings)
+ {
+ if (settings.minTime) {
+ settings.minTime = _time2int(settings.minTime);
+ }
+
+ if (settings.maxTime) {
+ settings.maxTime = _time2int(settings.maxTime);
+ }
+
+ if (settings.durationTime && typeof settings.durationTime !== 'function') {
+ settings.durationTime = _time2int(settings.durationTime);
+ }
+
+ if (settings.scrollDefault == 'now') {
+ settings.scrollDefault = function() {
+ return settings.roundingFunction(_time2int(new Date()), settings);
+ }
+ } else if (settings.scrollDefault && typeof settings.scrollDefault != 'function') {
+ var val = settings.scrollDefault;
+ settings.scrollDefault = function() {
+ return settings.roundingFunction(_time2int(val), settings);
+ }
+ } else if (settings.minTime) {
+ settings.scrollDefault = function() {
+ return settings.roundingFunction(settings.minTime, settings);
+ }
+ }
+
+ if ($.type(settings.timeFormat) === "string" && settings.timeFormat.match(/[gh]/)) {
+ settings._twelveHourTime = true;
+ }
+
+ if (settings.showOnFocus === false && settings.showOn.indexOf('focus') != -1) {
+ settings.showOn.splice(settings.showOn.indexOf('focus'), 1);
+ }
+
+ if (settings.disableTimeRanges.length > 0) {
+ // convert string times to integers
+ for (var i in settings.disableTimeRanges) {
+ settings.disableTimeRanges[i] = [
+ _time2int(settings.disableTimeRanges[i][0]),
+ _time2int(settings.disableTimeRanges[i][1])
+ ];
+ }
+
+ // sort by starting time
+ settings.disableTimeRanges = settings.disableTimeRanges.sort(function(a, b){
+ return a[0] - b[0];
+ });
+
+ // merge any overlapping ranges
+ for (var i = settings.disableTimeRanges.length-1; i > 0; i--) {
+ if (settings.disableTimeRanges[i][0] <= settings.disableTimeRanges[i-1][1]) {
+ settings.disableTimeRanges[i-1] = [
+ Math.min(settings.disableTimeRanges[i][0], settings.disableTimeRanges[i-1][0]),
+ Math.max(settings.disableTimeRanges[i][1], settings.disableTimeRanges[i-1][1])
+ ];
+ settings.disableTimeRanges.splice(i, 1);
+ }
+ }
+ }
+
+ return settings;
+ }
+
+ function _render(self)
+ {
+ var settings = self.data('timepicker-settings');
+ var list = self.data('timepicker-list');
+
+ if (list && list.length) {
+ list.remove();
+ self.data('timepicker-list', false);
+ }
+
+ if (settings.useSelect) {
+ list = $('', { 'class': 'ui-timepicker-select' });
+ var wrapped_list = list;
+ } else {
+ list = $('', { 'class': 'ui-timepicker-list' });
+
+ var wrapped_list = $('', { 'class': 'ui-timepicker-wrapper', 'tabindex': -1 });
+ wrapped_list.css({'display':'none', 'position': 'absolute' }).append(list);
+ }
+
+ if (settings.noneOption) {
+ if (settings.noneOption === true) {
+ settings.noneOption = (settings.useSelect) ? 'Time...' : 'None';
+ }
+
+ if ($.isArray(settings.noneOption)) {
+ for (var i in settings.noneOption) {
+ if (parseInt(i, 10) == i){
+ var noneElement = _generateNoneElement(settings.noneOption[i], settings.useSelect);
+ list.append(noneElement);
+ }
+ }
+ } else {
+ var noneElement = _generateNoneElement(settings.noneOption, settings.useSelect);
+ list.append(noneElement);
+ }
+ }
+
+ if (settings.className) {
+ wrapped_list.addClass(settings.className);
+ }
+
+ if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
+ var stepval = typeof settings.step == 'function' ? 'function' : settings.step;
+ wrapped_list.addClass('ui-timepicker-with-duration');
+ wrapped_list.addClass('ui-timepicker-step-'+settings.step);
+ }
+
+ var durStart = settings.minTime;
+ if (typeof settings.durationTime === 'function') {
+ durStart = _time2int(settings.durationTime());
+ } else if (settings.durationTime !== null) {
+ durStart = settings.durationTime;
+ }
+ var start = (settings.minTime !== null) ? settings.minTime : 0;
+ var end = (settings.maxTime !== null) ? settings.maxTime : (start + _ONE_DAY - 1);
+
+ if (end < start) {
+ // make sure the end time is greater than start time, otherwise there will be no list to show
+ end += _ONE_DAY;
+ }
+
+ if (end === _ONE_DAY-1 && $.type(settings.timeFormat) === "string" && settings.show2400) {
+ // show a 24:00 option when using military time
+ end = _ONE_DAY;
+ }
+
+ var dr = settings.disableTimeRanges;
+ var drCur = 0;
+ var drLen = dr.length;
+
+ var stepFunc = settings.step;
+ if (typeof stepFunc != 'function') {
+ stepFunc = function() {
+ return settings.step;
+ }
+ }
+
+ for (var i=start, j=0; i <= end; j++, i += stepFunc(j)*60) {
+ var timeInt = i;
+ var timeString = _int2time(timeInt, settings);
+
+ if (settings.useSelect) {
+ var row = $('', { 'value': timeString });
+ row.text(timeString);
+ } else {
+ var row = $('');
+ row.data('time', (timeInt <= 86400 ? timeInt : timeInt % 86400));
+ row.text(timeString);
+ }
+
+ if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
+ var durationString = _int2duration(i - durStart, settings.step);
+ if (settings.useSelect) {
+ row.text(row.text()+' ('+durationString+')');
+ } else {
+ var duration = $('', { 'class': 'ui-timepicker-duration' });
+ duration.text(' ('+durationString+')');
+ row.append(duration);
+ }
+ }
+
+ if (drCur < drLen) {
+ if (timeInt >= dr[drCur][1]) {
+ drCur += 1;
+ }
+
+ if (dr[drCur] && timeInt >= dr[drCur][0] && timeInt < dr[drCur][1]) {
+ if (settings.useSelect) {
+ row.prop('disabled', true);
+ } else {
+ row.addClass('ui-timepicker-disabled');
+ }
+ }
+ }
+
+ list.append(row);
+ }
+
+ wrapped_list.data('timepicker-input', self);
+ self.data('timepicker-list', wrapped_list);
+
+ if (settings.useSelect) {
+ if (self.val()) {
+ list.val(_roundAndFormatTime(_time2int(self.val()), settings));
+ }
+
+ list.on('focus', function(){
+ $(this).data('timepicker-input').trigger('showTimepicker');
+ });
+ list.on('blur', function(){
+ $(this).data('timepicker-input').trigger('hideTimepicker');
+ });
+ list.on('change', function(){
+ _setTimeValue(self, $(this).val(), 'select');
+ });
+
+ _setTimeValue(self, list.val(), 'initial');
+ self.hide().after(list);
+ } else {
+ var appendTo = settings.appendTo;
+ if (typeof appendTo === 'string') {
+ appendTo = $(appendTo);
+ } else if (typeof appendTo === 'function') {
+ appendTo = appendTo(self);
+ }
+ appendTo.append(wrapped_list);
+ _setSelected(self, list);
+
+ list.on('mousedown', 'li', function(e) {
+
+ // hack: temporarily disable the focus handler
+ // to deal with the fact that IE fires 'focus'
+ // events asynchronously
+ self.off('focus.timepicker');
+ self.on('focus.timepicker-ie-hack', function(){
+ self.off('focus.timepicker-ie-hack');
+ self.on('focus.timepicker', methods.show);
+ });
+
+ if (!_hideKeyboard(self)) {
+ self[0].focus();
+ }
+
+ // make sure only the clicked row is selected
+ list.find('li').removeClass('ui-timepicker-selected');
+ $(this).addClass('ui-timepicker-selected');
+
+ if (_selectValue(self)) {
+ self.trigger('hideTimepicker');
+
+ list.on('mouseup.timepicker', 'li', function(e) {
+ list.off('mouseup.timepicker');
+ wrapped_list.hide();
+ });
+ }
+ });
+ }
+ }
+
+ function _generateNoneElement(optionValue, useSelect)
+ {
+ var label, className, value;
+
+ if (typeof optionValue == 'object') {
+ label = optionValue.label;
+ className = optionValue.className;
+ value = optionValue.value;
+ } else if (typeof optionValue == 'string') {
+ label = optionValue;
+ } else {
+ $.error('Invalid noneOption value');
+ }
+
+ if (useSelect) {
+ return $('', {
+ 'value': value,
+ 'class': className,
+ 'text': label
+ });
+ } else {
+ return $('', {
+ 'class': className,
+ 'text': label
+ }).data('time', value);
+ }
+ }
+
+ function _roundAndFormatTime(seconds, settings)
+ {
+ seconds = settings.roundingFunction(seconds, settings);
+ if (seconds !== null) {
+ return _int2time(seconds, settings);
+ }
+ }
+
+ function _generateBaseDate()
+ {
+ return new Date(1970, 1, 1, 0, 0, 0);
+ }
+
+ // event handler to decide whether to close timepicker
+ function _closeHandler(e)
+ {
+ var target = $(e.target);
+ var input = target.closest('.ui-timepicker-input');
+ if (input.length === 0 && target.closest('.ui-timepicker-wrapper').length === 0) {
+ methods.hide();
+ $(document).unbind('.ui-timepicker');
+ $(window).unbind('.ui-timepicker');
+ }
+ }
+
+ function _hideKeyboard(self)
+ {
+ var settings = self.data('timepicker-settings');
+ return ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && settings.disableTouchKeyboard);
+ }
+
+ function _findRow(self, list, value)
+ {
+ if (!value && value !== 0) {
+ return false;
+ }
+
+ var settings = self.data('timepicker-settings');
+ var out = false;
+ var value = settings.roundingFunction(value, settings);
+
+ // loop through the menu items
+ list.find('li').each(function(i, obj) {
+ var jObj = $(obj);
+ if (typeof jObj.data('time') != 'number') {
+ return;
+ }
+
+ if (jObj.data('time') == value) {
+ out = jObj;
+ return false;
+ }
+ });
+
+ return out;
+ }
+
+ function _setSelected(self, list)
+ {
+ list.find('li').removeClass('ui-timepicker-selected');
+
+ var timeValue = _time2int(_getTimeValue(self), self.data('timepicker-settings'));
+ if (timeValue === null) {
+ return;
+ }
+
+ var selected = _findRow(self, list, timeValue);
+ if (selected) {
+
+ var topDelta = selected.offset().top - list.offset().top;
+
+ if (topDelta + selected.outerHeight() > list.outerHeight() || topDelta < 0) {
+ list.scrollTop(list.scrollTop() + selected.position().top - selected.outerHeight());
+ }
+
+ selected.addClass('ui-timepicker-selected');
+ }
+ }
+
+
+ function _formatValue(e, origin)
+ {
+ if (this.value === '' || origin == 'timepicker') {
+ return;
+ }
+
+ var self = $(this);
+
+ if (self.is(':focus') && (!e || e.type != 'change')) {
+ return;
+ }
+
+ var settings = self.data('timepicker-settings');
+ var seconds = _time2int(this.value, settings);
+
+ if (seconds === null) {
+ self.trigger('timeFormatError');
+ return;
+ }
+
+ var rangeError = false;
+ // check that the time in within bounds
+ if (settings.minTime !== null && seconds < settings.minTime) {
+ rangeError = true;
+ } else if (settings.maxTime !== null && seconds > settings.maxTime) {
+ rangeError = true;
+ }
+
+ // check that time isn't within disabled time ranges
+ $.each(settings.disableTimeRanges, function(){
+ if (seconds >= this[0] && seconds < this[1]) {
+ rangeError = true;
+ return false;
+ }
+ });
+
+ if (settings.forceRoundTime) {
+ seconds = settings.roundingFunction(seconds, settings);
+ }
+
+ var prettyTime = _int2time(seconds, settings);
+
+ if (rangeError) {
+ if (_setTimeValue(self, prettyTime, 'error')) {
+ self.trigger('timeRangeError');
+ }
+ } else {
+ _setTimeValue(self, prettyTime);
+ }
+ }
+
+ function _getTimeValue(self)
+ {
+ if (self.is('input')) {
+ return self.val();
+ } else {
+ // use the element's data attributes to store values
+ return self.data('ui-timepicker-value');
+ }
+ }
+
+ function _setTimeValue(self, value, source)
+ {
+ if (self.is('input')) {
+ self.val(value);
+
+ var settings = self.data('timepicker-settings');
+ if (settings.useSelect && source != 'select' && source != 'initial') {
+ self.data('timepicker-list').val(_roundAndFormatTime(_time2int(value), settings));
+ }
+ }
+
+ if (self.data('ui-timepicker-value') != value) {
+ self.data('ui-timepicker-value', value);
+ if (source == 'select') {
+ self.trigger('selectTime').trigger('changeTime').trigger('change', 'timepicker');
+ } else if (source != 'error') {
+ self.trigger('changeTime');
+ }
+
+ return true;
+ } else {
+ self.trigger('selectTime');
+ return false;
+ }
+ }
+
+ /*
+ * Keyboard navigation via arrow keys
+ */
+ function _keydownhandler(e)
+ {
+ var self = $(this);
+ var list = self.data('timepicker-list');
+
+ if (!list || !_isVisible(list)) {
+ if (e.keyCode == 40) {
+ // show the list!
+ methods.show.call(self.get(0));
+ list = self.data('timepicker-list');
+ if (!_hideKeyboard(self)) {
+ self.focus();
+ }
+ } else {
+ return true;
+ }
+ }
+
+ switch (e.keyCode) {
+
+ case 13: // return
+ if (_selectValue(self)) {
+ methods.hide.apply(this);
+ }
+
+ e.preventDefault();
+ return false;
+
+ case 38: // up
+ var selected = list.find('.ui-timepicker-selected');
+
+ if (!selected.length) {
+ list.find('li').each(function(i, obj) {
+ if ($(obj).position().top > 0) {
+ selected = $(obj);
+ return false;
+ }
+ });
+ selected.addClass('ui-timepicker-selected');
+
+ } else if (!selected.is(':first-child')) {
+ selected.removeClass('ui-timepicker-selected');
+ selected.prev().addClass('ui-timepicker-selected');
+
+ if (selected.prev().position().top < selected.outerHeight()) {
+ list.scrollTop(list.scrollTop() - selected.outerHeight());
+ }
+ }
+
+ return false;
+
+ case 40: // down
+ selected = list.find('.ui-timepicker-selected');
+
+ if (selected.length === 0) {
+ list.find('li').each(function(i, obj) {
+ if ($(obj).position().top > 0) {
+ selected = $(obj);
+ return false;
+ }
+ });
+
+ selected.addClass('ui-timepicker-selected');
+ } else if (!selected.is(':last-child')) {
+ selected.removeClass('ui-timepicker-selected');
+ selected.next().addClass('ui-timepicker-selected');
+
+ if (selected.next().position().top + 2*selected.outerHeight() > list.outerHeight()) {
+ list.scrollTop(list.scrollTop() + selected.outerHeight());
+ }
+ }
+
+ return false;
+
+ case 27: // escape
+ list.find('li').removeClass('ui-timepicker-selected');
+ methods.hide();
+ break;
+
+ case 9: //tab
+ methods.hide();
+ break;
+
+ default:
+ return true;
+ }
+ }
+
+ /*
+ * Time typeahead
+ */
+ function _keyuphandler(e)
+ {
+ var self = $(this);
+ var list = self.data('timepicker-list');
+ var settings = self.data('timepicker-settings');
+
+ if (!list || !_isVisible(list) || settings.disableTextInput) {
+ return true;
+ }
+
+ switch (e.keyCode) {
+
+ case 96: // numpad numerals
+ case 97:
+ case 98:
+ case 99:
+ case 100:
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 48: // numerals
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ case 55:
+ case 56:
+ case 57:
+ case 65: // a
+ case 77: // m
+ case 80: // p
+ case 186: // colon
+ case 8: // backspace
+ case 46: // delete
+ if (settings.typeaheadHighlight) {
+ _setSelected(self, list);
+ } else {
+ list.hide();
+ }
+ break;
+ }
+ }
+
+ function _selectValue(self)
+ {
+ var settings = self.data('timepicker-settings');
+ var list = self.data('timepicker-list');
+ var timeValue = null;
+
+ var cursor = list.find('.ui-timepicker-selected');
+
+ if (cursor.hasClass('ui-timepicker-disabled')) {
+ return false;
+ }
+
+ if (cursor.length) {
+ // selected value found
+ timeValue = cursor.data('time');
+ }
+
+ if (timeValue !== null) {
+ if (typeof timeValue != 'string') {
+ timeValue = _int2time(timeValue, settings);
+ }
+
+ _setTimeValue(self, timeValue, 'select');
+ }
+
+ return true;
+ }
+
+ function _int2duration(seconds, step)
+ {
+ seconds = Math.abs(seconds);
+ var minutes = Math.round(seconds/60),
+ duration = [],
+ hours, mins;
+
+ if (minutes < 60) {
+ // Only show (x mins) under 1 hour
+ duration = [minutes, _lang.mins];
+ } else {
+ hours = Math.floor(minutes/60);
+ mins = minutes%60;
+
+ // Show decimal notation (eg: 1.5 hrs) for 30 minute steps
+ if (step == 30 && mins == 30) {
+ hours += _lang.decimal + 5;
+ }
+
+ duration.push(hours);
+ duration.push(hours == 1 ? _lang.hr : _lang.hrs);
+
+ // Show remainder minutes notation (eg: 1 hr 15 mins) for non-30 minute steps
+ // and only if there are remainder minutes to show
+ if (step != 30 && mins) {
+ duration.push(mins);
+ duration.push(_lang.mins);
+ }
+ }
+
+ return duration.join(' ');
+ }
+
+ function _int2time(seconds, settings)
+ {
+ if (seconds === null) {
+ return null;
+ }
+
+ var time = new Date(_baseDate.valueOf() + (seconds*1000));
+
+ if (isNaN(time.getTime())) {
+ return null;
+ }
+
+ if ($.type(settings.timeFormat) === "function") {
+ return settings.timeFormat(time);
+ }
+
+ var output = '';
+ var hour, code;
+ for (var i=0; i 11) ? _lang.pm : _lang.am;
+ break;
+
+ case 'A':
+ output += (time.getHours() > 11) ? _lang.PM : _lang.AM;
+ break;
+
+ case 'g':
+ hour = time.getHours() % 12;
+ output += (hour === 0) ? '12' : hour;
+ break;
+
+ case 'G':
+ hour = time.getHours();
+ if (seconds === _ONE_DAY) hour = 24;
+ output += hour;
+ break;
+
+ case 'h':
+ hour = time.getHours() % 12;
+
+ if (hour !== 0 && hour < 10) {
+ hour = '0'+hour;
+ }
+
+ output += (hour === 0) ? '12' : hour;
+ break;
+
+ case 'H':
+ hour = time.getHours();
+ if (seconds === _ONE_DAY) hour = 24;
+ output += (hour > 9) ? hour : '0'+hour;
+ break;
+
+ case 'i':
+ var minutes = time.getMinutes();
+ output += (minutes > 9) ? minutes : '0'+minutes;
+ break;
+
+ case 's':
+ seconds = time.getSeconds();
+ output += (seconds > 9) ? seconds : '0'+seconds;
+ break;
+
+ case '\\':
+ // escape character; add the next character and skip ahead
+ i++;
+ output += settings.timeFormat.charAt(i);
+ break;
+
+ default:
+ output += code;
+ }
+ }
+
+ return output;
+ }
+
+ function _time2int(timeString, settings)
+ {
+ if (timeString === '') return null;
+ if (!timeString || timeString+0 == timeString) return timeString;
+
+ if (typeof(timeString) == 'object') {
+ return timeString.getHours()*3600 + timeString.getMinutes()*60 + timeString.getSeconds();
+ }
+
+ timeString = timeString.toLowerCase().replace(/[\s\.]/g, '');
+
+ // if the last character is an "a" or "p", add the "m"
+ if (timeString.slice(-1) == 'a' || timeString.slice(-1) == 'p') {
+ timeString += 'm';
+ }
+
+ var ampmRegex = '(' +
+ _lang.am.replace('.', '')+'|' +
+ _lang.pm.replace('.', '')+'|' +
+ _lang.AM.replace('.', '')+'|' +
+ _lang.PM.replace('.', '')+')?';
+
+ // try to parse time input
+ var pattern = new RegExp('^'+ampmRegex+'([0-2]?[0-9])\\W?([0-5][0-9])?\\W?([0-5][0-9])?'+ampmRegex+'$');
+
+ var time = timeString.match(pattern);
+ if (!time) {
+ return null;
+ }
+
+ var hour = parseInt(time[2]*1, 10);
+ var ampm = time[1] || time[5];
+ var hours = hour;
+
+ if (hour <= 12 && ampm) {
+ var isPm = (ampm == _lang.pm || ampm == _lang.PM);
+
+ if (hour == 12) {
+ hours = isPm ? 12 : 0;
+ } else {
+ hours = (hour + (isPm ? 12 : 0));
+ }
+ }
+
+ var minutes = ( time[3]*1 || 0 );
+ var seconds = ( time[4]*1 || 0 );
+ var timeInt = hours*3600 + minutes*60 + seconds;
+
+ // if no am/pm provided, intelligently guess based on the scrollDefault
+ if (hour < 12 && !ampm && settings && settings._twelveHourTime && settings.scrollDefault) {
+ var delta = timeInt - settings.scrollDefault();
+ if (delta < 0 && delta >= _ONE_DAY / -2) {
+ timeInt = (timeInt + (_ONE_DAY / 2)) % _ONE_DAY;
+ }
+ }
+
+ return timeInt;
+ }
+
+ function _pad2(n) {
+ return ("0" + n).slice(-2);
+ }
+
+ // Plugin entry
+ $.fn.timepicker = function(method)
+ {
+ if (!this.length) return this;
+ if (methods[method]) {
+ // check if this element is a timepicker
+ if (!this.hasClass('ui-timepicker-input')) {
+ return this;
+ }
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+ }
+ else if(typeof method === "object" || !method) { return methods.init.apply(this, arguments); }
+ else { $.error("Method "+ method + " does not exist on jQuery.timepicker"); }
+ };
+ // Global defaults
+ $.fn.timepicker.defaults = {
+ className: null,
+ minTime: null,
+ maxTime: null,
+ durationTime: null,
+ step: 30,
+ showDuration: false,
+ showOnFocus: true,
+ showOn: ['click', 'focus'],
+ timeFormat: 'g:ia',
+ scrollDefault: null,
+ selectOnBlur: false,
+ disableTextInput: false,
+ disableTouchKeyboard: false,
+ forceRoundTime: false,
+ roundingFunction: function(seconds, settings) {
+ if (seconds === null) {
+ return null;
+ } else {
+ var offset = seconds % (settings.step*60); // step is in minutes
+
+ if (offset >= settings.step*30) {
+ // if offset is larger than a half step, round up
+ seconds += (settings.step*60) - offset;
+ } else {
+ // round down
+ seconds -= offset;
+ }
+
+ return seconds;
+ }
+ },
+ appendTo: 'body',
+ orientation: 'l',
+ disableTimeRanges: [],
+ closeOnWindowScroll: false,
+ typeaheadHighlight: true,
+ noneOption: false,
+ show2400: false,
+ stopScrollPropagation: false
+ };
+}));
diff --git a/web_app/js/external/jquery.timepicker.min.js b/web_app/js/external/jquery.timepicker.min.js
new file mode 100644
index 0000000..eedd332
--- /dev/null
+++ b/web_app/js/external/jquery.timepicker.min.js
@@ -0,0 +1,7 @@
+/*!
+ * jquery-timepicker v1.8.2 - A jQuery timepicker plugin inspired by Google Calendar. It supports both mouse and keyboard navigation.
+ * Copyright (c) 2015 Jon Thornton - http://jonthornton.github.com/jquery-timepicker/
+ * License: MIT
+ */
+
+!function(a){"object"==typeof exports&&exports&&"object"==typeof module&&module&&module.exports===exports?a(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery)}(function(a){function b(a){var b=a[0];return b.offsetWidth>0&&b.offsetHeight>0}function c(b){if(b.minTime&&(b.minTime=u(b.minTime)),b.maxTime&&(b.maxTime=u(b.maxTime)),b.durationTime&&"function"!=typeof b.durationTime&&(b.durationTime=u(b.durationTime)),"now"==b.scrollDefault)b.scrollDefault=function(){return b.roundingFunction(u(new Date),b)};else if(b.scrollDefault&&"function"!=typeof b.scrollDefault){var c=b.scrollDefault;b.scrollDefault=function(){return b.roundingFunction(u(c),b)}}else b.minTime&&(b.scrollDefault=function(){return b.roundingFunction(b.minTime,b)});if("string"===a.type(b.timeFormat)&&b.timeFormat.match(/[gh]/)&&(b._twelveHourTime=!0),b.showOnFocus===!1&&-1!=b.showOn.indexOf("focus")&&b.showOn.splice(b.showOn.indexOf("focus"),1),b.disableTimeRanges.length>0){for(var d in b.disableTimeRanges)b.disableTimeRanges[d]=[u(b.disableTimeRanges[d][0]),u(b.disableTimeRanges[d][1])];b.disableTimeRanges=b.disableTimeRanges.sort(function(a,b){return a[0]-b[0]});for(var d=b.disableTimeRanges.length-1;d>0;d--)b.disableTimeRanges[d][0]<=b.disableTimeRanges[d-1][1]&&(b.disableTimeRanges[d-1]=[Math.min(b.disableTimeRanges[d][0],b.disableTimeRanges[d-1][0]),Math.max(b.disableTimeRanges[d][1],b.disableTimeRanges[d-1][1])],b.disableTimeRanges.splice(d,1))}return b}function d(b){var c=b.data("timepicker-settings"),d=b.data("timepicker-list");if(d&&d.length&&(d.remove(),b.data("timepicker-list",!1)),c.useSelect){d=a("",{"class":"ui-timepicker-select"});var g=d}else{d=a("",{"class":"ui-timepicker-list"});var g=a("",{"class":"ui-timepicker-wrapper",tabindex:-1});g.css({display:"none",position:"absolute"}).append(d)}if(c.noneOption)if(c.noneOption===!0&&(c.noneOption=c.useSelect?"Time...":"None"),a.isArray(c.noneOption)){for(var h in c.noneOption)if(parseInt(h,10)==h){var i=e(c.noneOption[h],c.useSelect);d.append(i)}}else{var i=e(c.noneOption,c.useSelect);d.append(i)}if(c.className&&g.addClass(c.className),(null!==c.minTime||null!==c.durationTime)&&c.showDuration){"function"==typeof c.step?"function":c.step;g.addClass("ui-timepicker-with-duration"),g.addClass("ui-timepicker-step-"+c.step)}var k=c.minTime;"function"==typeof c.durationTime?k=u(c.durationTime()):null!==c.durationTime&&(k=c.durationTime);var m=null!==c.minTime?c.minTime:0,n=null!==c.maxTime?c.maxTime:m+w-1;m>n&&(n+=w),n===w-1&&"string"===a.type(c.timeFormat)&&c.show2400&&(n=w);var p=c.disableTimeRanges,q=0,v=p.length,x=c.step;"function"!=typeof x&&(x=function(){return c.step});for(var h=m,z=0;n>=h;z++,h+=60*x(z)){var A=h,B=t(A,c);if(c.useSelect){var C=a("",{value:B});C.text(B)}else{var C=a("");C.data("time",86400>=A?A:A%86400),C.text(B)}if((null!==c.minTime||null!==c.durationTime)&&c.showDuration){var D=s(h-k,c.step);if(c.useSelect)C.text(C.text()+" ("+D+")");else{var E=a("",{"class":"ui-timepicker-duration"});E.text(" ("+D+")"),C.append(E)}}v>q&&(A>=p[q][1]&&(q+=1),p[q]&&A>=p[q][0]&&A",{value:f,"class":e,text:d}):a("",{"class":e,text:d}).data("time",f)}function f(a,b){return a=b.roundingFunction(a,b),null!==a?t(a,b):void 0}function g(){return new Date(1970,1,1,0,0,0)}function h(b){var c=a(b.target),d=c.closest(".ui-timepicker-input");0===d.length&&0===c.closest(".ui-timepicker-wrapper").length&&(y.hide(),a(document).unbind(".ui-timepicker"),a(window).unbind(".ui-timepicker"))}function j(a){var b=a.data("timepicker-settings");return(window.navigator.msMaxTouchPoints||"ontouchstart"in document)&&b.disableTouchKeyboard}function k(b,c,d){if(!d&&0!==d)return!1;var e=b.data("timepicker-settings"),f=!1,d=e.roundingFunction(d,e);return c.find("li").each(function(b,c){var e=a(c);if("number"==typeof e.data("time"))return e.data("time")==d?(f=e,!1):void 0}),f}function l(a,b){b.find("li").removeClass("ui-timepicker-selected");var c=u(n(a),a.data("timepicker-settings"));if(null!==c){var d=k(a,b,c);if(d){var e=d.offset().top-b.offset().top;(e+d.outerHeight()>b.outerHeight()||0>e)&&b.scrollTop(b.scrollTop()+d.position().top-d.outerHeight()),d.addClass("ui-timepicker-selected")}}}function m(b,c){if(""!==this.value&&"timepicker"!=c){var d=a(this);if(!d.is(":focus")||b&&"change"==b.type){var e=d.data("timepicker-settings"),f=u(this.value,e);if(null===f)return void d.trigger("timeFormatError");var g=!1;null!==e.minTime&&fe.maxTime&&(g=!0),a.each(e.disableTimeRanges,function(){return f>=this[0]&&f0?(f=a(c),!1):void 0}),f.addClass("ui-timepicker-selected")),!1;case 40:return f=e.find(".ui-timepicker-selected"),0===f.length?(e.find("li").each(function(b,c){return a(c).position().top>0?(f=a(c),!1):void 0}),f.addClass("ui-timepicker-selected")):f.is(":last-child")||(f.removeClass("ui-timepicker-selected"),f.next().addClass("ui-timepicker-selected"),f.next().position().top+2*f.outerHeight()>e.outerHeight()&&e.scrollTop(e.scrollTop()+f.outerHeight())),!1;case 27:e.find("li").removeClass("ui-timepicker-selected"),y.hide();break;case 9:y.hide();break;default:return!0}}function q(c){var d=a(this),e=d.data("timepicker-list"),f=d.data("timepicker-settings");if(!e||!b(e)||f.disableTextInput)return!0;switch(c.keyCode){case 96:case 97:case 98:case 99:case 100:case 101:case 102:case 103:case 104:case 105:case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:case 65:case 77:case 80:case 186:case 8:case 46:f.typeaheadHighlight?l(d,e):e.hide()}}function r(a){var b=a.data("timepicker-settings"),c=a.data("timepicker-list"),d=null,e=c.find(".ui-timepicker-selected");return e.hasClass("ui-timepicker-disabled")?!1:(e.length&&(d=e.data("time")),null!==d&&("string"!=typeof d&&(d=t(d,b)),o(a,d,"select")),!0)}function s(a,b){a=Math.abs(a);var c,d,e=Math.round(a/60),f=[];return 60>e?f=[e,x.mins]:(c=Math.floor(e/60),d=e%60,30==b&&30==d&&(c+=x.decimal+5),f.push(c),f.push(1==c?x.hr:x.hrs),30!=b&&d&&(f.push(d),f.push(x.mins))),f.join(" ")}function t(b,c){if(null===b)return null;var d=new Date(v.valueOf()+1e3*b);if(isNaN(d.getTime()))return null;if("function"===a.type(c.timeFormat))return c.timeFormat(d);for(var e,f,g="",h=0;h11?x.pm:x.am;break;case"A":g+=d.getHours()>11?x.PM:x.AM;break;case"g":e=d.getHours()%12,g+=0===e?"12":e;break;case"G":e=d.getHours(),b===w&&(e=24),g+=e;break;case"h":e=d.getHours()%12,0!==e&&10>e&&(e="0"+e),g+=0===e?"12":e;break;case"H":e=d.getHours(),b===w&&(e=24),g+=e>9?e:"0"+e;break;case"i":var i=d.getMinutes();g+=i>9?i:"0"+i;break;case"s":b=d.getSeconds(),g+=b>9?b:"0"+b;break;case"\\":h++,g+=c.timeFormat.charAt(h);break;default:g+=f}return g}function u(a,b){if(""===a)return null;if(!a||a+0==a)return a;if("object"==typeof a)return 3600*a.getHours()+60*a.getMinutes()+a.getSeconds();a=a.toLowerCase().replace(/[\s\.]/g,""),("a"==a.slice(-1)||"p"==a.slice(-1))&&(a+="m");var c="("+x.am.replace(".","")+"|"+x.pm.replace(".","")+"|"+x.AM.replace(".","")+"|"+x.PM.replace(".","")+")?",d=new RegExp("^"+c+"([0-2]?[0-9])\\W?([0-5][0-9])?\\W?([0-5][0-9])?"+c+"$"),e=a.match(d);if(!e)return null;var f=parseInt(1*e[2],10),g=e[1]||e[5],h=f;if(12>=f&&g){var i=g==x.pm||g==x.PM;h=12==f?i?12:0:f+(i?12:0)}var j=1*e[3]||0,k=1*e[4]||0,l=3600*h+60*j+k;if(12>f&&!g&&b&&b._twelveHourTime&&b.scrollDefault){var m=l-b.scrollDefault();0>m&&m>=w/-2&&(l=(l+w/2)%w)}return l}var v=g(),w=86400,x={am:"am",pm:"pm",AM:"AM",PM:"PM",decimal:".",mins:"mins",hr:"hr",hrs:"hrs"},y={init:function(b){return this.each(function(){var e=a(this),f=[];for(var g in a.fn.timepicker.defaults)e.data(g)&&(f[g]=e.data(g));var h=a.extend({},a.fn.timepicker.defaults,f,b);if(h.lang&&(x=a.extend(x,h.lang)),h=c(h),e.data("timepicker-settings",h),e.addClass("ui-timepicker-input"),h.useSelect)d(e);else{if(e.prop("autocomplete","off"),h.showOn)for(i in h.showOn)e.on(h.showOn[i]+".timepicker",y.show);e.on("change.timepicker",m),e.on("keydown.timepicker",p),e.on("keyup.timepicker",q),h.disableTextInput&&e.on("keypress.timepicker",function(a){a.preventDefault()}),m.call(e.get(0))}})},show:function(c){var e=a(this),f=e.data("timepicker-settings");if(c&&c.preventDefault(),f.useSelect)return void e.data("timepicker-list").focus();j(e)&&e.blur();var g=e.data("timepicker-list");if(!e.prop("readonly")&&(g&&0!==g.length&&"function"!=typeof f.durationTime||(d(e),g=e.data("timepicker-list")),!b(g))){e.data("ui-timepicker-value",e.val()),l(e,g),y.hide(),g.show();var i={};f.orientation.match(/r/)?i.left=e.offset().left+e.outerWidth()-g.outerWidth()+parseInt(g.css("marginLeft").replace("px",""),10):i.left=e.offset().left+parseInt(g.css("marginLeft").replace("px",""),10);var m;m=f.orientation.match(/t/)?"t":f.orientation.match(/b/)?"b":e.offset().top+e.outerHeight(!0)+g.outerHeight()>a(window).height()+a(window).scrollTop()?"t":"b","t"==m?(g.addClass("ui-timepicker-positioned-top"),i.top=e.offset().top-g.outerHeight()+parseInt(g.css("marginTop").replace("px",""),10)):(g.removeClass("ui-timepicker-positioned-top"),i.top=e.offset().top+e.outerHeight()+parseInt(g.css("marginTop").replace("px",""),10)),g.offset(i);var o=g.find(".ui-timepicker-selected");if(o.length||(n(e)?o=k(e,g,u(n(e))):f.scrollDefault&&(o=k(e,g,f.scrollDefault()))),o&&o.length){var p=g.scrollTop()+o.position().top-o.outerHeight();g.scrollTop(p)}else g.scrollTop(0);return f.stopScrollPropagation&&a(document).on("wheel.ui-timepicker",".ui-timepicker-wrapper",function(b){b.preventDefault();var c=a(this).scrollTop();a(this).scrollTop(c+b.originalEvent.deltaY)}),a(document).on("touchstart.ui-timepicker mousedown.ui-timepicker",h),a(window).on("resize.ui-timepicker",h),f.closeOnWindowScroll&&a(document).on("scroll.ui-timepicker",h),e.trigger("showTimepicker"),this}},hide:function(c){var d=a(this),e=d.data("timepicker-settings");return e&&e.useSelect&&d.blur(),a(".ui-timepicker-wrapper").each(function(){var c=a(this);if(b(c)){var d=c.data("timepicker-input"),e=d.data("timepicker-settings");e&&e.selectOnBlur&&r(d),c.hide(),d.trigger("hideTimepicker")}}),this},option:function(b,e){return this.each(function(){var f=a(this),g=f.data("timepicker-settings"),h=f.data("timepicker-list");if("object"==typeof b)g=a.extend(g,b);else if("string"==typeof b&&"undefined"!=typeof e)g[b]=e;else if("string"==typeof b)return g[b];g=c(g),f.data("timepicker-settings",g),h&&(h.remove(),f.data("timepicker-list",!1)),g.useSelect&&d(f)})},getSecondsFromMidnight:function(){return u(n(this))},getTime:function(a){var b=this,c=n(b);if(!c)return null;var d=u(c);if(null===d)return null;a||(a=new Date);var e=new Date(a);return e.setHours(d/3600),e.setMinutes(d%3600/60),e.setSeconds(d%60),e.setMilliseconds(0),e},setTime:function(a){var b=this,c=b.data("timepicker-settings");if(c.forceRoundTime)var d=f(u(a),c);else var d=t(u(a),c);return a&&null===d&&c.noneOption&&(d=a),o(b,d),b.data("timepicker-list")&&l(b,b.data("timepicker-list")),this},remove:function(){var a=this;if(a.hasClass("ui-timepicker-input")){var b=a.data("timepicker-settings");return a.removeAttr("autocomplete","off"),a.removeClass("ui-timepicker-input"),a.removeData("timepicker-settings"),a.off(".timepicker"),a.data("timepicker-list")&&a.data("timepicker-list").remove(),b.useSelect&&a.show(),a.removeData("timepicker-list"),this}}};a.fn.timepicker=function(b){return this.length?y[b]?this.hasClass("ui-timepicker-input")?y[b].apply(this,Array.prototype.slice.call(arguments,1)):this:"object"!=typeof b&&b?void a.error("Method "+b+" does not exist on jQuery.timepicker"):y.init.apply(this,arguments):this},a.fn.timepicker.defaults={className:null,minTime:null,maxTime:null,durationTime:null,step:30,showDuration:!1,showOnFocus:!0,showOn:["click","focus"],timeFormat:"g:ia",scrollDefault:null,selectOnBlur:!1,disableTextInput:!1,disableTouchKeyboard:!1,forceRoundTime:!1,roundingFunction:function(a,b){if(null===a)return null;var c=a%(60*b.step);return c>=30*b.step?a+=60*b.step-c:a-=c,a},appendTo:"body",orientation:"l",disableTimeRanges:[],closeOnWindowScroll:!1,typeaheadHighlight:!0,noneOption:!1,show2400:!1,stopScrollPropagation:!1}});
\ No newline at end of file
diff --git a/web_app/js/sif_tools.js b/web_app/js/sif_tools.js
index bb164d7..a93326f 100644
--- a/web_app/js/sif_tools.js
+++ b/web_app/js/sif_tools.js
@@ -82,7 +82,8 @@ function setup_ui_elements()
// set up date/time pickers
$( "#gem_desired_date" ).datepicker();
$( "#event_end_date" ).datepicker();
- $( "#event_end_time" ).timepicker();
+ // $( "#event_end_time" ).timepicker();
+ $('#event_end_time').timepicker({ 'timeFormat': 'H:i', 'disableTextInput': true });
// set up buttons
["calculate-rank", "reset-rank", "calculate-gems", "reset-gems", "calculate-card", "reset-card", "start-stop-timer", "clear-timer"].forEach(function(entry) {
diff --git a/web_app/sif_tools.html b/web_app/sif_tools.html
index 7c9a396..f04c472 100644
--- a/web_app/sif_tools.html
+++ b/web_app/sif_tools.html
@@ -6,14 +6,14 @@
SIF Tools
-
-
+
+
-
-
+
+
-
+