/*! jQuery Timepicker Addon - v1.6.3 - 2016-04-20 * http://trentrichardson.com/examples/timepicker * Copyright (c) 2016 Trent Richardson; Licensed MIT */ ( 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: '1.6.3', }, } ); /* * 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 += ''; } } else { for ( var m = o[ litem + 'Min' ]; m <= max[ litem ]; m += parseInt( o[ litem + 'Grid' ], 10 ) ) { gridSize[ litem ]++; html += ''; } } html += '
' + tmph + '' + ( m < 10 ? '0' : '' ) + m + '
'; } 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( '
' + '
' + o.timeOnlyTitle + '
' + '
' ); $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]/gi ), 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 $( '