From 0b01f598aeebb87974dab0c60fa57793c1a96c55 Mon Sep 17 00:00:00 2001 From: Naomi Date: Tue, 1 Apr 2014 15:59:06 -0400 Subject: [PATCH] CC-5765 : Fixing up history page to match UI/UX upgraded timepicker,removing bootstrap datepicker js. --- .../controllers/PlayouthistoryController.php | 2 + .../public/css/jquery.ui.timepicker.css | 57 + .../bootstrap-datetimepicker.js | 1306 -------------- .../js/timepicker/jquery.ui.timepicker.js | 1496 +++++++++++++++++ 4 files changed, 1555 insertions(+), 1306 deletions(-) create mode 100644 airtime_mvc/public/css/jquery.ui.timepicker.css delete mode 100644 airtime_mvc/public/js/bootstrap-datetime/bootstrap-datetimepicker.js create mode 100644 airtime_mvc/public/js/timepicker/jquery.ui.timepicker.js diff --git a/airtime_mvc/application/controllers/PlayouthistoryController.php b/airtime_mvc/application/controllers/PlayouthistoryController.php index 18de7d871..baf65944b 100644 --- a/airtime_mvc/application/controllers/PlayouthistoryController.php +++ b/airtime_mvc/application/controllers/PlayouthistoryController.php @@ -83,6 +83,7 @@ class PlayouthistoryController extends Zend_Controller_Action $this->view->date_form = $form; + $this->view->headScript()->appendFile($baseUrl.'js/timepicker/jquery.ui.timepicker.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'js/contextmenu/jquery.contextMenu.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'js/datatables/js/jquery.dataTables.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.pluginAPI.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); @@ -98,6 +99,7 @@ class PlayouthistoryController extends Zend_Controller_Action $this->view->headLink()->appendStylesheet($baseUrl.'css/playouthistory.css?'.$CC_CONFIG['airtime_version']); $this->view->headLink()->appendStylesheet($baseUrl.'css/history_styles.css?'.$CC_CONFIG['airtime_version']); $this->view->headLink()->appendStylesheet($baseUrl.'css/jquery.contextMenu.css?'.$CC_CONFIG['airtime_version']); + $this->view->headLink()->appendStylesheet($baseUrl.'css/jquery.ui.timepicker.css?'.$CC_CONFIG['airtime_version']); //set datatables columns for display of data. $historyService = new Application_Service_HistoryService(); diff --git a/airtime_mvc/public/css/jquery.ui.timepicker.css b/airtime_mvc/public/css/jquery.ui.timepicker.css new file mode 100644 index 000000000..b5930fb73 --- /dev/null +++ b/airtime_mvc/public/css/jquery.ui.timepicker.css @@ -0,0 +1,57 @@ +/* + * Timepicker stylesheet + * Highly inspired from datepicker + * FG - Nov 2010 - Web3R + * + * version 0.0.3 : Fixed some settings, more dynamic + * version 0.0.4 : Removed width:100% on tables + * version 0.1.1 : set width 0 on tables to fix an ie6 bug + */ + +.ui-timepicker-inline { display: inline; } + +#ui-timepicker-div { padding: 0.2em; } +.ui-timepicker-table { display: inline-table; width: 0; } +.ui-timepicker-table table { margin:0.15em 0 0 0; border-collapse: collapse; } + +.ui-timepicker-hours, .ui-timepicker-minutes { padding: 0.2em; } + +.ui-timepicker-table .ui-timepicker-title { line-height: 1.8em; text-align: center; } +.ui-timepicker-table td { padding: 0.1em; width: 2.2em; } +.ui-timepicker-table th.periods { padding: 0.1em; width: 2.2em; } + +/* span for disabled cells */ +.ui-timepicker-table td span { + display:block; + padding:0.2em 0.3em 0.2em 0.5em; + width: 1.2em; + + text-align:right; + text-decoration:none; +} +/* anchors for clickable cells */ +.ui-timepicker-table td a { + display:block; + padding:0.2em 0.3em 0.2em 0.5em; + width: 1.2em; + cursor: pointer; + text-align:right; + text-decoration:none; +} + + +/* buttons and button pane styling */ +.ui-timepicker .ui-timepicker-buttonpane { + background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; +} +.ui-timepicker .ui-timepicker-buttonpane button { margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +/* The close button */ +.ui-timepicker .ui-timepicker-close { float: right } + +/* the now button */ +.ui-timepicker .ui-timepicker-now { float: left; } + +/* the deselect button */ +.ui-timepicker .ui-timepicker-deselect { float: left; } + + diff --git a/airtime_mvc/public/js/bootstrap-datetime/bootstrap-datetimepicker.js b/airtime_mvc/public/js/bootstrap-datetime/bootstrap-datetimepicker.js deleted file mode 100644 index d26ecc7e1..000000000 --- a/airtime_mvc/public/js/bootstrap-datetime/bootstrap-datetimepicker.js +++ /dev/null @@ -1,1306 +0,0 @@ -/** - * @license - * ========================================================= - * bootstrap-datetimepicker.js - * http://www.eyecon.ro/bootstrap-datepicker - * ========================================================= - * Copyright 2012 Stefan Petre - * - * Contributions: - * - Andrew Rowls - * - Thiago de Arruda - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================= - */ - -(function($) { - - // Picker object - var smartPhone = (window.orientation != undefined); - var DateTimePicker = function(element, options) { - this.id = dpgId++; - this.init(element, options); - }; - - var dateToDate = function(dt) { - if (typeof dt === 'string') { - return new Date(dt); - } - return dt; - }; - - DateTimePicker.prototype = { - constructor: DateTimePicker, - - init: function(element, options) { - - dates = $.fn.datetimepicker.dates; - - var icon; - if (!(options.pickTime || options.pickDate)) - throw new Error('Must choose at least one picker'); - this.options = options; - this.$element = $(element); - this.language = options.language in dates ? options.language : 'en' - this.pickDate = options.pickDate; - this.pickTime = options.pickTime; - this.isInput = this.$element.is('input'); - this.component = false; - this.showTimeFirst = options.showTimeFirst; - if (this.$element.find('.input-append') || this.$element.find('.input-prepend')) - this.component = this.$element.find('.add-on'); - this.format = options.format; - if (!this.format) { - if (this.isInput) this.format = this.$element.data('format'); - else this.format = this.$element.find('input').data('format'); - if (!this.format) this.format = 'MM/dd/yyyy'; - } - this._compileFormat(); - if (this.component) { - icon = this.component.find('i'); - } - if (this.pickTime) { - if (icon && icon.length) this.timeIcon = icon.data('time-icon'); - if (!this.timeIcon) this.timeIcon = 'icon-time'; - if (!this.dateIcon) this.dateIcon = 'icon-calendar'; - icon.addClass(this.timeIcon); - } - if (this.pickDate && (!this.showTimeFirst)) { - if (icon && icon.length) this.dateIcon = icon.data('date-icon'); - if (!this.dateIcon) this.dateIcon = 'icon-calendar'; - icon.removeClass(this.timeIcon); - icon.addClass(this.dateIcon); - } - this.widget = $(getTemplate(this.timeIcon, this.dateIcon, options.pickDate, options.pickTime, options.pick12HourFormat, options.pickSeconds, options.collapse, options.showTimeFirst)).appendTo('body'); - this.minViewMode = options.minViewMode||this.$element.data('date-minviewmode')||0; - if (typeof this.minViewMode === 'string') { - switch (this.minViewMode) { - case 'months': - this.minViewMode = 1; - break; - case 'years': - this.minViewMode = 2; - break; - default: - this.minViewMode = 0; - break; - } - } - this.viewMode = options.viewMode||this.$element.data('date-viewmode')||0; - if (typeof this.viewMode === 'string') { - switch (this.viewMode) { - case 'months': - this.viewMode = 1; - break; - case 'years': - this.viewMode = 2; - break; - default: - this.viewMode = 0; - break; - } - } - this.startViewMode = this.viewMode; - this.weekStart = options.weekStart||this.$element.data('date-weekstart')||0; - this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1; - this.setStartDate(options.startDate || this.$element.data('date-startdate')); - this.setEndDate(options.endDate || this.$element.data('date-enddate')); - this.fillDow(); - this.fillMonths(); - this.fillHours(); - this.fillMinutes(); - this.fillSeconds(); - this.update(); - this.showMode(); - this._attachDatePickerEvents(); - }, - - show: function(e) { - this.widget.show(); - this.height = this.component ? this.component.outerHeight() : this.$element.outerHeight(); - this.place(); - this.$element.trigger({ - type: 'show', - date: this._date - }); - this._attachDatePickerGlobalEvents(); - if (e) { - e.stopPropagation(); - e.preventDefault(); - } - }, - - disable: function(){ - this.$element.find('input').prop('disabled',true); - this._detachDatePickerEvents(); - }, - enable: function(){ - this.$element.find('input').prop('disabled',false); - this._attachDatePickerEvents(); - }, - - hide: function() { - // Ignore event if in the middle of a picker transition - var collapse = this.widget.find('.collapse') - for (var i = 0; i < collapse.length; i++) { - var collapseData = collapse.eq(i).data('collapse'); - if (collapseData && collapseData.transitioning) - return; - } - this.widget.hide(); - this.viewMode = this.startViewMode; - this.showMode(); - this.set(); - this.$element.trigger({ - type: 'hide', - date: this._date - }); - this._detachDatePickerGlobalEvents(); - }, - - set: function() { - var formatted = ''; - if (!this._unset) formatted = this.formatDate(this._date); - if (!this.isInput) { - if (this.component){ - var input = this.$element.find('input'); - input.val(formatted); - this._resetMaskPos(input); - } - this.$element.data('date', formatted); - } else { - this.$element.val(formatted); - this._resetMaskPos(this.$element); - } - }, - - setValue: function(newDate) { - if (!newDate) { - this._unset = true; - } else { - this._unset = false; - } - if (typeof newDate === 'string') { - this._date = this.parseDate(newDate); - } else if(newDate) { - this._date = new Date(newDate); - } - this.set(); - this.viewDate = UTCDate(this._date.getUTCFullYear(), this._date.getUTCMonth(), 1, 0, 0, 0, 0); - this.fillDate(); - this.fillTime(); - }, - - getDate: function() { - if (this._unset) return null; - return new Date(this._date.valueOf()); - }, - - setDate: function(date) { - if (!date) this.setValue(null); - else this.setValue(date.valueOf()); - }, - - setStartDate: function(date) { - if (date instanceof Date) { - this.startDate = date; - } else if (typeof date === 'string') { - this.startDate = new UTCDate(date); - if (! this.startDate.getUTCFullYear()) { - this.startDate = -Infinity; - } - } else { - this.startDate = -Infinity; - } - if (this.viewDate) { - this.update(); - } - }, - - setEndDate: function(date) { - if (date instanceof Date) { - this.endDate = date; - } else if (typeof date === 'string') { - this.endDate = new UTCDate(date); - if (! this.endDate.getUTCFullYear()) { - this.endDate = Infinity; - } - } else { - this.endDate = Infinity; - } - if (this.viewDate) { - this.update(); - } - }, - - getLocalDate: function() { - if (this._unset) return null; - var d = this._date; - return new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), - d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()); - }, - - setLocalDate: function(localDate) { - if (!localDate) this.setValue(null); - else - this.setValue(Date.UTC( - localDate.getFullYear(), - localDate.getMonth(), - localDate.getDate(), - localDate.getHours(), - localDate.getMinutes(), - localDate.getSeconds(), - localDate.getMilliseconds())); - }, - - place: function(){ - var position = 'absolute'; - var offset = this.component ? this.component.offset() : this.$element.offset(); - this.width = this.component ? this.component.outerWidth() : this.$element.outerWidth(); - offset.top = offset.top + this.height; - - var $window = $(window); - - if ( this.options.width != undefined ) { - this.widget.width( this.options.width ); - } - - if ( this.options.orientation == 'left' ) { - this.widget.addClass( 'left-oriented' ); - offset.left = offset.left - this.widget.width() + 20; - } - - if (this._isInFixed()) { - position = 'fixed'; - offset.top -= $window.scrollTop(); - offset.left -= $window.scrollLeft(); - } - - if ($window.width() < offset.left + this.widget.outerWidth()) { - offset.right = $window.width() - offset.left - this.width; - offset.left = 'auto'; - this.widget.addClass('pull-right'); - } else { - offset.right = 'auto'; - this.widget.removeClass('pull-right'); - } - - this.widget.css({ - position: position, - top: offset.top, - left: offset.left, - right: offset.right - }); - }, - - notifyChange: function(){ - this.$element.trigger({ - type: 'changeDate', - date: this.getDate(), - localDate: this.getLocalDate() - }); - }, - - update: function(newDate){ - var dateStr = newDate; - if (!dateStr) { - if (this.isInput) { - dateStr = this.$element.val(); - } else { - dateStr = this.$element.find('input').val(); - } - if (dateStr) { - this._date = this.parseDate(dateStr); - } - if (!this._date) { - var tmp = new Date() - this._date = UTCDate(tmp.getFullYear(), - tmp.getMonth(), - tmp.getDate(), - tmp.getHours(), - tmp.getMinutes(), - tmp.getSeconds(), - tmp.getMilliseconds()) - } - } - this.viewDate = UTCDate(this._date.getUTCFullYear(), this._date.getUTCMonth(), 1, 0, 0, 0, 0); - this.fillDate(); - this.fillTime(); - }, - - fillDow: function() { - var dowCnt = this.weekStart; - var html = $(''); - while (dowCnt < this.weekStart + 7) { - html.append('' + dates.daysMin[(dowCnt++) % 7] + ''); - } - this.widget.find('.datepicker-days thead').append(html); - }, - - fillMonths: function() { - var html = ''; - var i = 0 - while (i < 12) { - html += '' + dates.monthsShort[i++] + ''; - } - this.widget.find('.datepicker-months td').append(html); - }, - - fillDate: function() { - var year = this.viewDate.getUTCFullYear(); - var month = this.viewDate.getUTCMonth(); - var currentDate = UTCDate( - this._date.getUTCFullYear(), - this._date.getUTCMonth(), - this._date.getUTCDate(), - 0, 0, 0, 0 - ); - var startYear = typeof this.startDate === 'object' ? this.startDate.getUTCFullYear() : -Infinity; - var startMonth = typeof this.startDate === 'object' ? this.startDate.getUTCMonth() : -1; - var endYear = typeof this.endDate === 'object' ? this.endDate.getUTCFullYear() : Infinity; - var endMonth = typeof this.endDate === 'object' ? this.endDate.getUTCMonth() : 12; - - this.widget.find('.datepicker-days').find('.disabled').removeClass('disabled'); - this.widget.find('.datepicker-months').find('.disabled').removeClass('disabled'); - this.widget.find('.datepicker-years').find('.disabled').removeClass('disabled'); - - this.widget.find('.datepicker-days th:eq(1)').text( - dates.months[month] + ' ' + year); - - var prevMonth = UTCDate(year, month-1, 28, 0, 0, 0, 0); - var day = DPGlobal.getDaysInMonth( - prevMonth.getUTCFullYear(), prevMonth.getUTCMonth()); - prevMonth.setUTCDate(day); - prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7) % 7); - if ((year == startYear && month <= startMonth) || year < startYear) { - this.widget.find('.datepicker-days th:eq(0)').addClass('disabled'); - } - if ((year == endYear && month >= endMonth) || year > endYear) { - this.widget.find('.datepicker-days th:eq(2)').addClass('disabled'); - } - - var nextMonth = new Date(prevMonth.valueOf()); - nextMonth.setUTCDate(nextMonth.getUTCDate() + 42); - nextMonth = nextMonth.valueOf(); - var html = []; - var row; - var clsName; - while (prevMonth.valueOf() < nextMonth) { - if (prevMonth.getUTCDay() === this.weekStart) { - row = $(''); - html.push(row); - } - clsName = ''; - if (prevMonth.getUTCFullYear() < year || - (prevMonth.getUTCFullYear() == year && - prevMonth.getUTCMonth() < month)) { - clsName += ' old'; - } else if (prevMonth.getUTCFullYear() > year || - (prevMonth.getUTCFullYear() == year && - prevMonth.getUTCMonth() > month)) { - clsName += ' new'; - } - if (prevMonth.valueOf() === currentDate.valueOf()) { - clsName += ' active'; - } - if ((prevMonth.valueOf() + 86400000) <= this.startDate) { - clsName += ' disabled'; - } - if (prevMonth.valueOf() > this.endDate) { - clsName += ' disabled'; - } - row.append('' + prevMonth.getUTCDate() + ''); - prevMonth.setUTCDate(prevMonth.getUTCDate() + 1); - } - this.widget.find('.datepicker-days tbody').empty().append(html); - var currentYear = this._date.getUTCFullYear(); - - var months = this.widget.find('.datepicker-months').find( - 'th:eq(1)').text(year).end().find('span').removeClass('active'); - if (currentYear === year) { - months.eq(this._date.getUTCMonth()).addClass('active'); - } - if (currentYear - 1 < startYear) { - this.widget.find('.datepicker-months th:eq(0)').addClass('disabled'); - } - if (currentYear + 1 > endYear) { - this.widget.find('.datepicker-months th:eq(2)').addClass('disabled'); - } - for (var i = 0; i < 12; i++) { - if ((year == startYear && startMonth > i) || (year < startYear)) { - $(months[i]).addClass('disabled'); - } else if ((year == endYear && endMonth < i) || (year > endYear)) { - $(months[i]).addClass('disabled'); - } - } - - html = ''; - year = parseInt(year/10, 10) * 10; - var yearCont = this.widget.find('.datepicker-years').find( - 'th:eq(1)').text(year + '-' + (year + 9)).end().find('td'); - this.widget.find('.datepicker-years').find('th').removeClass('disabled'); - if (startYear > year) { - this.widget.find('.datepicker-years').find('th:eq(0)').addClass('disabled'); - } - if (endYear < year+9) { - this.widget.find('.datepicker-years').find('th:eq(2)').addClass('disabled'); - } - year -= 1; - for (var i = -1; i < 11; i++) { - html += '' + year + ''; - year += 1; - } - yearCont.html(html); - }, - - fillHours: function() { - var table = this.widget.find( - '.timepicker .timepicker-hours table'); - table.parent().hide(); - var html = ''; - if (this.options.pick12HourFormat) { - var current = 1; - for (var i = 0; i < 3; i += 1) { - html += ''; - for (var j = 0; j < 4; j += 1) { - var c = current.toString(); - html += '' + padLeft(c, 2, '0') + ''; - current++; - } - html += '' - } - } else { - var current = 0; - for (var i = 0; i < 6; i += 1) { - html += ''; - for (var j = 0; j < 4; j += 1) { - var c = current.toString(); - html += '' + padLeft(c, 2, '0') + ''; - current++; - } - html += '' - } - } - table.html(html); - }, - - fillMinutes: function() { - var table = this.widget.find( - '.timepicker .timepicker-minutes table'); - table.parent().hide(); - var html = ''; - var current = 0; - for (var i = 0; i < 5; i++) { - html += ''; - for (var j = 0; j < 4; j += 1) { - var c = current.toString(); - html += '' + padLeft(c, 2, '0') + ''; - current += 3; - } - html += ''; - } - table.html(html); - }, - - fillSeconds: function() { - var table = this.widget.find( - '.timepicker .timepicker-seconds table'); - table.parent().hide(); - var html = ''; - var current = 0; - for (var i = 0; i < 5; i++) { - html += ''; - for (var j = 0; j < 4; j += 1) { - var c = current.toString(); - html += '' + padLeft(c, 2, '0') + ''; - current += 3; - } - html += ''; - } - table.html(html); - }, - - fillTime: function() { - if (!this._date) - return; - var timeComponents = this.widget.find('.timepicker span[data-time-component]'); - var table = timeComponents.closest('table'); - var is12HourFormat = this.options.pick12HourFormat; - var hour = this._date.getUTCHours(); - var period = 'AM'; - if (is12HourFormat) { - if (hour >= 12) period = 'PM'; - if (hour === 0) hour = 12; - else if (hour != 12) hour = hour % 12; - this.widget.find( - '.timepicker [data-action=togglePeriod]').text(period); - } - hour = padLeft(hour.toString(), 2, '0'); - var minute = padLeft(this._date.getUTCMinutes().toString(), 2, '0'); - var second = padLeft(this._date.getUTCSeconds().toString(), 2, '0'); - timeComponents.filter('[data-time-component=hours]').text(hour); - timeComponents.filter('[data-time-component=minutes]').text(minute); - timeComponents.filter('[data-time-component=seconds]').text(second); - }, - - click: function(e) { - e.stopPropagation(); - e.preventDefault(); - this._unset = false; - var target = $(e.target).closest('span, td, th'); - if (target.length === 1) { - if (! target.is('.disabled')) { - switch(target[0].nodeName.toLowerCase()) { - case 'th': - switch(target[0].className) { - case 'switch': - this.showMode(1); - break; - case 'prev': - case 'next': - var vd = this.viewDate; - var navFnc = DPGlobal.modes[this.viewMode].navFnc; - var step = DPGlobal.modes[this.viewMode].navStep; - if (target[0].className === 'prev') step = step * -1; - vd['set' + navFnc](vd['get' + navFnc]() + step); - this.fillDate(); - this.set(); - break; - } - break; - case 'span': - if (target.is('.month')) { - var month = target.parent().find('span').index(target); - this.viewDate.setUTCMonth(month); - } else { - var year = parseInt(target.text(), 10) || 0; - this.viewDate.setUTCFullYear(year); - } - if (this.viewMode !== 0) { - this._date = UTCDate( - this.viewDate.getUTCFullYear(), - this.viewDate.getUTCMonth(), - this.viewDate.getUTCDate(), - this._date.getUTCHours(), - this._date.getUTCMinutes(), - this._date.getUTCSeconds(), - this._date.getUTCMilliseconds() - ); - this.notifyChange(); - } - this.showMode(-1); - this.fillDate(); - this.set(); - break; - case 'td': - if (target.is('.day')) { - var day = parseInt(target.text(), 10) || 1; - var month = this.viewDate.getUTCMonth(); - var year = this.viewDate.getUTCFullYear(); - if (target.is('.old')) { - if (month === 0) { - month = 11; - year -= 1; - } else { - month -= 1; - } - } else if (target.is('.new')) { - if (month == 11) { - month = 0; - year += 1; - } else { - month += 1; - } - } - this._date = UTCDate( - year, month, day, - this._date.getUTCHours(), - this._date.getUTCMinutes(), - this._date.getUTCSeconds(), - this._date.getUTCMilliseconds() - ); - this.viewDate = UTCDate( - year, month, Math.min(28, day) , 0, 0, 0, 0); - this.fillDate(); - this.set(); - this.notifyChange(); - } - break; - } - } - } - }, - - actions: { - incrementHours: function(e) { - this._date.setUTCHours(this._date.getUTCHours() + 1); - }, - - incrementMinutes: function(e) { - this._date.setUTCMinutes(this._date.getUTCMinutes() + 1); - }, - - incrementSeconds: function(e) { - this._date.setUTCSeconds(this._date.getUTCSeconds() + 1); - }, - - decrementHours: function(e) { - this._date.setUTCHours(this._date.getUTCHours() - 1); - }, - - decrementMinutes: function(e) { - this._date.setUTCMinutes(this._date.getUTCMinutes() - 1); - }, - - decrementSeconds: function(e) { - this._date.setUTCSeconds(this._date.getUTCSeconds() - 1); - }, - - togglePeriod: function(e) { - var hour = this._date.getUTCHours(); - if (hour >= 12) hour -= 12; - else hour += 12; - this._date.setUTCHours(hour); - }, - - showPicker: function() { - this.widget.find('.timepicker > div:not(.timepicker-picker)').hide(); - this.widget.find('.timepicker .timepicker-picker').show(); - }, - - showHours: function() { - this.widget.find('.timepicker .timepicker-picker').hide(); - this.widget.find('.timepicker .timepicker-hours').show(); - }, - - showMinutes: function() { - this.widget.find('.timepicker .timepicker-picker').hide(); - this.widget.find('.timepicker .timepicker-minutes').show(); - }, - - showSeconds: function() { - this.widget.find('.timepicker .timepicker-picker').hide(); - this.widget.find('.timepicker .timepicker-seconds').show(); - }, - - selectHour: function(e) { - var tgt = $(e.target); - var value = parseInt(tgt.text(), 10); - if (this.options.pick12HourFormat) { - var current = this._date.getUTCHours(); - if (current >= 12) { - if (value != 12) value = (value + 12) % 24; - } else { - if (value === 12) value = 0; - else value = value % 12; - } - } - this._date.setUTCHours(value); - this.actions.showPicker.call(this); - }, - - selectMinute: function(e) { - var tgt = $(e.target); - var value = parseInt(tgt.text(), 10); - this._date.setUTCMinutes(value); - this.actions.showPicker.call(this); - }, - - selectSecond: function(e) { - var tgt = $(e.target); - var value = parseInt(tgt.text(), 10); - this._date.setUTCSeconds(value); - this.actions.showPicker.call(this); - } - }, - - doAction: function(e) { - e.stopPropagation(); - e.preventDefault(); - if (!this._date) this._date = UTCDate(1970, 0, 0, 0, 0, 0, 0); - var action = $(e.currentTarget).data('action'); - var rv = this.actions[action].apply(this, arguments); - this.set(); - this.fillTime(); - this.notifyChange(); - return rv; - }, - - stopEvent: function(e) { - e.stopPropagation(); - e.preventDefault(); - }, - - // part of the following code was taken from - // http://cloud.github.com/downloads/digitalBush/jquery.maskedinput/jquery.maskedinput-1.3.js - keydown: function(e) { - var self = this, k = e.which, input = $(e.target); - if (k == 8 || k == 46) { - // backspace and delete cause the maskPosition - // to be recalculated - setTimeout(function() { - self._resetMaskPos(input); - }); - } - }, - - keypress: function(e) { - var k = e.which; - if (k == 8 || k == 46) { - // For those browsers which will trigger - // keypress on backspace/delete - return; - } - var input = $(e.target); - var c = String.fromCharCode(k); - var val = input.val() || ''; - val += c; - var mask = this._mask[this._maskPos]; - if (!mask) { - return false; - } - if (mask.end != val.length) { - return; - } - if (!mask.pattern.test(val.slice(mask.start))) { - val = val.slice(0, val.length - 1); - while ((mask = this._mask[this._maskPos]) && mask.character) { - val += mask.character; - // advance mask position past static - // part - this._maskPos++; - } - val += c; - if (mask.end != val.length) { - input.val(val); - return false; - } else { - if (!mask.pattern.test(val.slice(mask.start))) { - input.val(val.slice(0, mask.start)); - return false; - } else { - input.val(val); - this._maskPos++; - return false; - } - } - } else { - this._maskPos++; - } - }, - - change: function(e) { - var input = $(e.target); - var val = input.val(); - if (this._formatPattern.test(val)) { - this.update(); - this.setValue(this._date.getTime()); - this.notifyChange(); - this.set(); - } else if (val && val.trim()) { - this.setValue(this._date.getTime()); - if (this._date) this.set(); - else input.val(''); - } else { - if (this._date) { - this.setValue(null); - // unset the date when the input is - // erased - this.notifyChange(); - this._unset = true; - } - } - this._resetMaskPos(input); - }, - - showMode: function(dir) { - if (dir) { - this.viewMode = Math.max(this.minViewMode, Math.min( - 2, this.viewMode + dir)); - } - this.widget.find('.datepicker > div').hide().filter( - '.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); - }, - - destroy: function() { - this._detachDatePickerEvents(); - this._detachDatePickerGlobalEvents(); - this.widget.remove(); - this.$element.removeData('datetimepicker'); - this.component.removeData('datetimepicker'); - }, - - formatDate: function(d) { - return this.format.replace(formatReplacer, function(match) { - var methodName, property, rv, len = match.length; - if (match === 'ms') - len = 1; - property = dateFormatComponents[match].property - if (property === 'Hours12') { - rv = d.getUTCHours(); - if (rv === 0) rv = 12; - else if (rv !== 12) rv = rv % 12; - } else if (property === 'Period12') { - if (d.getUTCHours() >= 12) return 'PM'; - else return 'AM'; - } else { - methodName = 'get' + property; - rv = d[methodName](); - } - if (methodName === 'getUTCMonth') rv = rv + 1; - if (methodName === 'getUTCYear') rv = rv + 1900 - 2000; - return padLeft(rv.toString(), len, '0'); - }); - }, - - parseDate: function(str) { - var match, i, property, methodName, value, parsed = {}; - if (!(match = this._formatPattern.exec(str))) - return null; - for (i = 1; i < match.length; i++) { - property = this._propertiesByIndex[i]; - if (!property) - continue; - value = match[i]; - if (/^\d+$/.test(value)) - value = parseInt(value, 10); - parsed[property] = value; - } - return this._finishParsingDate(parsed); - }, - - _resetMaskPos: function(input) { - var val = input.val(); - for (var i = 0; i < this._mask.length; i++) { - if (this._mask[i].end > val.length) { - // If the mask has ended then jump to - // the next - this._maskPos = i; - break; - } else if (this._mask[i].end === val.length) { - this._maskPos = i + 1; - break; - } - } - }, - - _finishParsingDate: function(parsed) { - var year, month, date, hours, minutes, seconds, milliseconds; - year = parsed.UTCFullYear; - if (parsed.UTCYear) year = 2000 + parsed.UTCYear; - if (!year) year = 1970; - if (parsed.UTCMonth) month = parsed.UTCMonth - 1; - else month = 0; - date = parsed.UTCDate || 1; - hours = parsed.UTCHours || 0; - minutes = parsed.UTCMinutes || 0; - seconds = parsed.UTCSeconds || 0; - milliseconds = parsed.UTCMilliseconds || 0; - if (parsed.Hours12) { - hours = parsed.Hours12; - } - if (parsed.Period12) { - if (/pm/i.test(parsed.Period12)) { - if (hours != 12) hours = (hours + 12) % 24; - } else { - hours = hours % 12; - } - } - return UTCDate(year, month, date, hours, minutes, seconds, milliseconds); - }, - - _compileFormat: function () { - var match, component, components = [], mask = [], - str = this.format, propertiesByIndex = {}, i = 0, pos = 0; - while (match = formatComponent.exec(str)) { - component = match[0]; - if (component in dateFormatComponents) { - i++; - propertiesByIndex[i] = dateFormatComponents[component].property; - components.push('\\s*' + dateFormatComponents[component].getPattern( - this) + '\\s*'); - mask.push({ - pattern: new RegExp(dateFormatComponents[component].getPattern( - this)), - property: dateFormatComponents[component].property, - start: pos, - end: pos += component.length - }); - } - else { - components.push(escapeRegExp(component)); - mask.push({ - pattern: new RegExp(escapeRegExp(component)), - character: component, - start: pos, - end: ++pos - }); - } - str = str.slice(component.length); - } - this._mask = mask; - this._maskPos = 0; - this._formatPattern = new RegExp( - '^\\s*' + components.join('') + '\\s*$'); - this._propertiesByIndex = propertiesByIndex; - }, - - _attachDatePickerEvents: function() { - var self = this; - // this handles date picker clicks - this.widget.on('click', '.datepicker *', $.proxy(this.click, this)); - // this handles time picker clicks - this.widget.on('click', '[data-action]', $.proxy(this.doAction, this)); - this.widget.on('mousedown', $.proxy(this.stopEvent, this)); - if (this.pickDate && this.pickTime) { - this.widget.on('click.togglePicker', '.accordion-toggle', function(e) { - e.stopPropagation(); - var $this = $(this); - var $parent = $this.closest('ul'); - var expanded = $parent.find('.collapse.in'); - var closed = $parent.find('.collapse:not(.in)'); - - if (expanded && expanded.length) { - var collapseData = expanded.data('collapse'); - if (collapseData && collapseData.transitioning) return; - expanded.collapse('hide'); - closed.collapse('show') - $this.find('i').toggleClass(self.timeIcon + ' ' + self.dateIcon); - self.$element.find('.add-on i').toggleClass(self.timeIcon + ' ' + self.dateIcon); - } - }); - } - if (this.isInput) { - this.$element.on({ - 'focus': $.proxy(this.show, this), - 'change': $.proxy(this.change, this) - }); - if (this.options.maskInput) { - this.$element.on({ - 'keydown': $.proxy(this.keydown, this), - 'keypress': $.proxy(this.keypress, this) - }); - } - } else { - this.$element.on({ - 'change': $.proxy(this.change, this) - }, 'input'); - if (this.options.maskInput) { - this.$element.on({ - 'keydown': $.proxy(this.keydown, this), - 'keypress': $.proxy(this.keypress, this) - }, 'input'); - } - if (this.component){ - this.component.on('click', $.proxy(this.show, this)); - } else { - this.$element.on('click', $.proxy(this.show, this)); - } - } - }, - - _attachDatePickerGlobalEvents: function() { - $(window).on( - 'resize.datetimepicker' + this.id, $.proxy(this.place, this)); - if (!this.isInput) { - $(document).on( - 'mousedown.datetimepicker' + this.id, $.proxy(this.hide, this)); - } - }, - - _detachDatePickerEvents: function() { - this.widget.off('click', '.datepicker *', this.click); - this.widget.off('click', '[data-action]'); - this.widget.off('mousedown', this.stopEvent); - if (this.pickDate && this.pickTime) { - this.widget.off('click.togglePicker'); - } - if (this.isInput) { - this.$element.off({ - 'focus': this.show, - 'change': this.change - }); - if (this.options.maskInput) { - this.$element.off({ - 'keydown': this.keydown, - 'keypress': this.keypress - }); - } - } else { - this.$element.off({ - 'change': this.change - }, 'input'); - if (this.options.maskInput) { - this.$element.off({ - 'keydown': this.keydown, - 'keypress': this.keypress - }, 'input'); - } - if (this.component){ - this.component.off('click', this.show); - } else { - this.$element.off('click', this.show); - } - } - }, - - _detachDatePickerGlobalEvents: function () { - $(window).off('resize.datetimepicker' + this.id); - if (!this.isInput) { - $(document).off('mousedown.datetimepicker' + this.id); - } - }, - - _isInFixed: function() { - if (this.$element) { - var parents = this.$element.parents(); - var inFixed = false; - for (var i=0; i' + - '' + - '' - ); - } else if (pickTime) { - return ( - '' - ); - } else { - return ( - '' - ); - } - } - - function UTCDate() { - return new Date(Date.UTC.apply(Date, arguments)); - } - - var DPGlobal = { - modes: [ - { - clsName: 'days', - navFnc: 'UTCMonth', - navStep: 1 - }, - { - clsName: 'months', - navFnc: 'UTCFullYear', - navStep: 1 - }, - { - clsName: 'years', - navFnc: 'UTCFullYear', - navStep: 10 - }], - isLeapYear: function (year) { - return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) - }, - getDaysInMonth: function (year, month) { - return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month] - }, - headTemplate: - '' + - '' + - '‹' + - '' + - '›' + - '' + - '', - contTemplate: '' - }; - DPGlobal.template = - '
' + - '' + - DPGlobal.headTemplate + - '' + - '
' + - '
' + - '
' + - '' + - DPGlobal.headTemplate + - DPGlobal.contTemplate+ - '
'+ - '
'+ - '
'+ - ''+ - DPGlobal.headTemplate+ - DPGlobal.contTemplate+ - '
'+ - '
'; - var TPGlobal = { - hourTemplate: '', - minuteTemplate: '', - secondTemplate: '' - }; - TPGlobal.getTemplate = function(is12Hours, showSeconds) { - return ( - '
' + - '' + - '' + - '' + - '' + - '' + - (showSeconds ? - '' + - '': '')+ - (is12Hours ? '' : '') + - '' + - '' + - ' ' + - '' + - ' ' + - (showSeconds ? - '' + - '' : '') + - (is12Hours ? - '' + - '' : '') + - '' + - '' + - '' + - '' + - '' + - (showSeconds ? - '' + - '': '') + - (is12Hours ? '' : '') + - '' + - '
' + TPGlobal.hourTemplate + ':' + TPGlobal.minuteTemplate + ':' + TPGlobal.secondTemplate + '' + - '' + - '
' + - '
' + - '
' + - '' + - '
'+ - '
'+ - '
' + - '' + - '
'+ - '
'+ - (showSeconds ? - '
' + - '' + - '
'+ - '
': '') - ); - } - - -})(window.jQuery) \ No newline at end of file diff --git a/airtime_mvc/public/js/timepicker/jquery.ui.timepicker.js b/airtime_mvc/public/js/timepicker/jquery.ui.timepicker.js new file mode 100644 index 000000000..d8a0cfb7f --- /dev/null +++ b/airtime_mvc/public/js/timepicker/jquery.ui.timepicker.js @@ -0,0 +1,1496 @@ +/* + * jQuery UI Timepicker + * + * Copyright 2010-2013, Francois Gelinas + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://fgelinas.com/code/timepicker + * + * Depends: + * jquery.ui.core.js + * jquery.ui.position.js (only if position settings are used) + * + * Change version 0.1.0 - moved the t-rex up here + * + ____ + ___ .-~. /_"-._ + `-._~-. / /_ "~o\ :Y + \ \ / : \~x. ` ') + ] Y / | Y< ~-.__j + / ! _.--~T : l l< /.-~ + / / ____.--~ . ` l /~\ \<|Y + / / .-~~" /| . ',-~\ \L| + / / / .^ \ Y~Y \.^>/l_ "--' + / Y .-"( . l__ j_j l_/ /~_.-~ . + Y l / \ ) ~~~." / `/"~ / \.__/l_ + | \ _.-" ~-{__ l : l._Z~-.___.--~ + | ~---~ / ~~"---\_ ' __[> + l . _.^ ___ _>-y~ + \ \ . .-~ .-~ ~>--" / + \ ~---" / ./ _.-' + "-.,_____.,_ _.--~\ _.-~ + ~~ ( _} -Row + `. ~( + ) \ + /,`--'~\--'~\ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ->T-Rex<- +*/ + +(function ($) { + + $.extend($.ui, { timepicker: { version: "0.3.3"} }); + + var PROP_NAME = 'timepicker', + tpuuid = new Date().getTime(); + + /* Time picker 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. */ + + function Timepicker() { + this.debug = true; // Change this to true to start debugging + this._curInst = null; // The current instance in use + this._disabledInputs = []; // List of time picker inputs that have been disabled + this._timepickerShowing = false; // True if the popup picker is showing , false if not + this._inDialog = false; // True if showing within a "dialog", false if not + this._dialogClass = 'ui-timepicker-dialog'; // The name of the dialog marker class + this._mainDivId = 'ui-timepicker-div'; // The ID of the main timepicker division + this._inlineClass = 'ui-timepicker-inline'; // The name of the inline marker class + this._currentClass = 'ui-timepicker-current'; // The name of the current hour / minutes marker class + this._dayOverClass = 'ui-timepicker-days-cell-over'; // The name of the day hover marker class + + this.regional = []; // Available regional settings, indexed by language code + this.regional[''] = { // Default regional settings + hourText: 'Hour', // Display text for hours section + minuteText: 'Minute', // Display text for minutes link + amPmText: ['AM', 'PM'], // Display text for AM PM + closeButtonText: 'Done', // Text for the confirmation button (ok button) + nowButtonText: 'Now', // Text for the now button + deselectButtonText: 'Deselect' // Text for the deselect button + }; + this._defaults = { // Global defaults for all the time picker instances + showOn: 'focus', // 'focus' for popup on focus, + // 'button' for trigger button, or 'both' for either (not yet implemented) + button: null, // 'button' element that will trigger the timepicker + showAnim: 'fadeIn', // Name of jQuery animation for popup + showOptions: {}, // Options for enhanced animations + appendText: '', // Display text following the input box, e.g. showing the format + + beforeShow: null, // Define a callback function executed before the timepicker is shown + onSelect: null, // Define a callback function when a hour / minutes is selected + onClose: null, // Define a callback function when the timepicker is closed + + timeSeparator: ':', // The character to use to separate hours and minutes. + periodSeparator: ' ', // The character to use to separate the time from the time period. + showPeriod: false, // Define whether or not to show AM/PM with selected time + showPeriodLabels: true, // Show the AM/PM labels on the left of the time picker + showLeadingZero: true, // Define whether or not to show a leading zero for hours < 10. [true/false] + showMinutesLeadingZero: true, // Define whether or not to show a leading zero for minutes < 10. + altField: '', // Selector for an alternate field to store selected time into + defaultTime: 'now', // Used as default time when input field is empty or for inline timePicker + // (set to 'now' for the current time, '' for no highlighted time) + myPosition: 'left top', // Position of the dialog relative to the input. + // see the position utility for more info : http://jqueryui.com/demos/position/ + atPosition: 'left bottom', // Position of the input element to match + // Note : if the position utility is not loaded, the timepicker will attach left top to left bottom + //NEW: 2011-02-03 + onHourShow: null, // callback for enabling / disabling on selectable hours ex : function(hour) { return true; } + onMinuteShow: null, // callback for enabling / disabling on time selection ex : function(hour,minute) { return true; } + + hours: { + starts: 0, // first displayed hour + ends: 23 // last displayed hour + }, + minutes: { + starts: 0, // first displayed minute + ends: 55, // last displayed minute + interval: 5, // interval of displayed minutes + manual: [] // optional extra manual entries for minutes + }, + rows: 4, // number of rows for the input tables, minimum 2, makes more sense if you use multiple of 2 + // 2011-08-05 0.2.4 + showHours: true, // display the hours section of the dialog + showMinutes: true, // display the minute section of the dialog + optionalMinutes: false, // optionally parse inputs of whole hours with minutes omitted + + // buttons + showCloseButton: false, // shows an OK button to confirm the edit + showNowButton: false, // Shows the 'now' button + showDeselectButton: false, // Shows the deselect time button + + maxTime: { + hour: null, + minute: null + }, + minTime: { + hour: null, + minute: null + } + + }; + $.extend(this._defaults, this.regional['']); + + this.tpDiv = $(''); + } + + $.extend(Timepicker.prototype, { + /* Class name added to elements to indicate already configured with a time picker. */ + markerClassName: 'hasTimepicker', + + /* Debug logging (if enabled). */ + log: function () { + if (this.debug) + console.log.apply('', arguments); + }, + + _widgetTimepicker: function () { + return this.tpDiv; + }, + + /* Override the default settings for all instances of the time picker. + @param settings object - the new settings to use as defaults (anonymous object) + @return the manager object */ + setDefaults: function (settings) { + extendRemove(this._defaults, settings || {}); + return this; + }, + + /* Attach the time picker to a jQuery selection. + @param target element - the target input field or division or span + @param settings object - the new settings to use for this time picker instance (anonymous) */ + _attachTimepicker: function (target, settings) { + // check for settings on the control itself - in namespace 'time:' + var inlineSettings = null; + for (var attrName in this._defaults) { + var attrValue = target.getAttribute('time:' + attrName); + if (attrValue) { + inlineSettings = inlineSettings || {}; + try { + inlineSettings[attrName] = eval(attrValue); + } catch (err) { + inlineSettings[attrName] = attrValue; + } + } + } + var nodeName = target.nodeName.toLowerCase(); + var inline = (nodeName == 'div' || nodeName == 'span'); + + if (!target.id) { + this.uuid += 1; + target.id = 'tp' + this.uuid; + } + var inst = this._newInst($(target), inline); + inst.settings = $.extend({}, settings || {}, inlineSettings || {}); + if (nodeName == 'input') { + this._connectTimepicker(target, inst); + // init inst.hours and inst.minutes from the input value + this._setTimeFromField(inst); + } else if (inline) { + this._inlineTimepicker(target, inst); + } + + + }, + + /* Create a new instance object. */ + _newInst: function (target, inline) { + var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars + return { + id: id, input: target, // associated target + inline: inline, // is timepicker inline or not : + tpDiv: (!inline ? this.tpDiv : // presentation div + $('
')) + }; + }, + + /* Attach the time picker to an input field. */ + _connectTimepicker: function (target, inst) { + var input = $(target); + inst.append = $([]); + inst.trigger = $([]); + if (input.hasClass(this.markerClassName)) { return; } + this._attachments(input, inst); + input.addClass(this.markerClassName). + keydown(this._doKeyDown). + keyup(this._doKeyUp). + bind("setData.timepicker", function (event, key, value) { + inst.settings[key] = value; + }). + bind("getData.timepicker", function (event, key) { + return this._get(inst, key); + }); + $.data(target, PROP_NAME, inst); + }, + + /* Handle keystrokes. */ + _doKeyDown: function (event) { + var inst = $.timepicker._getInst(event.target); + var handled = true; + inst._keyEvent = true; + if ($.timepicker._timepickerShowing) { + switch (event.keyCode) { + case 9: $.timepicker._hideTimepicker(); + handled = false; + break; // hide on tab out + case 13: + $.timepicker._updateSelectedValue(inst); + $.timepicker._hideTimepicker(); + + return false; // don't submit the form + break; // select the value on enter + case 27: $.timepicker._hideTimepicker(); + break; // hide on escape + default: handled = false; + } + } + else if (event.keyCode == 36 && event.ctrlKey) { // display the time picker on ctrl+home + $.timepicker._showTimepicker(this); + } + else { + handled = false; + } + if (handled) { + event.preventDefault(); + event.stopPropagation(); + } + }, + + /* Update selected time on keyUp */ + /* Added verion 0.0.5 */ + _doKeyUp: function (event) { + var inst = $.timepicker._getInst(event.target); + $.timepicker._setTimeFromField(inst); + $.timepicker._updateTimepicker(inst); + }, + + /* Make attachments based on settings. */ + _attachments: function (input, inst) { + var appendText = this._get(inst, 'appendText'); + var isRTL = this._get(inst, 'isRTL'); + if (inst.append) { inst.append.remove(); } + if (appendText) { + inst.append = $('' + appendText + ''); + input[isRTL ? 'before' : 'after'](inst.append); + } + input.unbind('focus.timepicker', this._showTimepicker); + input.unbind('click.timepicker', this._adjustZIndex); + + if (inst.trigger) { inst.trigger.remove(); } + + var showOn = this._get(inst, 'showOn'); + if (showOn == 'focus' || showOn == 'both') { // pop-up time picker when in the marked field + input.bind("focus.timepicker", this._showTimepicker); + input.bind("click.timepicker", this._adjustZIndex); + } + if (showOn == 'button' || showOn == 'both') { // pop-up time picker when 'button' element is clicked + var button = this._get(inst, 'button'); + + // Add button if button element is not set + if(button == null) { + button = $(''); + input.after(button); + } + + $(button).bind("click.timepicker", function () { + if ($.timepicker._timepickerShowing && $.timepicker._lastInput == input[0]) { + $.timepicker._hideTimepicker(); + } else if (!inst.input.is(':disabled')) { + $.timepicker._showTimepicker(input[0]); + } + return false; + }); + + } + }, + + + /* Attach an inline time picker to a div. */ + _inlineTimepicker: function(target, inst) { + var divSpan = $(target); + if (divSpan.hasClass(this.markerClassName)) + return; + divSpan.addClass(this.markerClassName).append(inst.tpDiv). + bind("setData.timepicker", function(event, key, value){ + inst.settings[key] = value; + }).bind("getData.timepicker", function(event, key){ + return this._get(inst, key); + }); + $.data(target, PROP_NAME, inst); + + this._setTimeFromField(inst); + this._updateTimepicker(inst); + inst.tpDiv.show(); + }, + + _adjustZIndex: function(input) { + input = input.target || input; + var inst = $.timepicker._getInst(input); + inst.tpDiv.css('zIndex', $.timepicker._getZIndex(input) +1); + }, + + /* Pop-up the time picker for a given input field. + @param input element - the input field attached to the time picker or + event - if triggered by focus */ + _showTimepicker: function (input) { + input = input.target || input; + if (input.nodeName.toLowerCase() != 'input') { input = $('input', input.parentNode)[0]; } // find from button/image trigger + + if ($.timepicker._isDisabledTimepicker(input) || $.timepicker._lastInput == input) { return; } // already here + + // fix v 0.0.8 - close current timepicker before showing another one + $.timepicker._hideTimepicker(); + + var inst = $.timepicker._getInst(input); + if ($.timepicker._curInst && $.timepicker._curInst != inst) { + $.timepicker._curInst.tpDiv.stop(true, true); + } + var beforeShow = $.timepicker._get(inst, 'beforeShow'); + extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {})); + inst.lastVal = null; + $.timepicker._lastInput = input; + + $.timepicker._setTimeFromField(inst); + + // calculate default position + if ($.timepicker._inDialog) { input.value = ''; } // hide cursor + if (!$.timepicker._pos) { // position below input + $.timepicker._pos = $.timepicker._findPos(input); + $.timepicker._pos[1] += input.offsetHeight; // add the height + } + var isFixed = false; + $(input).parents().each(function () { + isFixed |= $(this).css('position') == 'fixed'; + return !isFixed; + }); + + var offset = { left: $.timepicker._pos[0], top: $.timepicker._pos[1] }; + + $.timepicker._pos = null; + // determine sizing offscreen + inst.tpDiv.css({ position: 'absolute', display: 'block', top: '-1000px' }); + $.timepicker._updateTimepicker(inst); + + + // position with the ui position utility, if loaded + if ( ( ! inst.inline ) && ( typeof $.ui.position == 'object' ) ) { + inst.tpDiv.position({ + of: inst.input, + my: $.timepicker._get( inst, 'myPosition' ), + at: $.timepicker._get( inst, 'atPosition' ), + // offset: $( "#offset" ).val(), + // using: using, + collision: 'flip' + }); + var offset = inst.tpDiv.offset(); + $.timepicker._pos = [offset.top, offset.left]; + } + + + // reset clicked state + inst._hoursClicked = false; + inst._minutesClicked = false; + + // fix width for dynamic number of time pickers + // and adjust position before showing + offset = $.timepicker._checkOffset(inst, offset, isFixed); + inst.tpDiv.css({ position: ($.timepicker._inDialog && $.blockUI ? + 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none', + left: offset.left + 'px', top: offset.top + 'px' + }); + if ( ! inst.inline ) { + var showAnim = $.timepicker._get(inst, 'showAnim'); + var duration = $.timepicker._get(inst, 'duration'); + + var postProcess = function () { + $.timepicker._timepickerShowing = true; + var borders = $.timepicker._getBorders(inst.tpDiv); + inst.tpDiv.find('iframe.ui-timepicker-cover'). // IE6- only + css({ left: -borders[0], top: -borders[1], + width: inst.tpDiv.outerWidth(), height: inst.tpDiv.outerHeight() + }); + }; + + // Fixed the zIndex problem for real (I hope) - FG - v 0.2.9 + $.timepicker._adjustZIndex(input); + //inst.tpDiv.css('zIndex', $.timepicker._getZIndex(input) +1); + + if ($.effects && $.effects[showAnim]) { + inst.tpDiv.show(showAnim, $.timepicker._get(inst, 'showOptions'), duration, postProcess); + } + else { + inst.tpDiv.show((showAnim ? duration : null), postProcess); + } + if (!showAnim || !duration) { postProcess(); } + if (inst.input.is(':visible') && !inst.input.is(':disabled')) { inst.input.focus(); } + $.timepicker._curInst = inst; + } + }, + + // This is an enhanced copy of the zIndex function of UI core 1.8.?? For backward compatibility. + // Enhancement returns maximum zindex value discovered while traversing parent elements, + // rather than the first zindex value found. Ensures the timepicker popup will be in front, + // even in funky scenarios like non-jq dialog containers with large fixed zindex values and + // nested zindex-influenced elements of their own. + _getZIndex: function (target) { + var elem = $(target); + var maxValue = 0; + var position, value; + while (elem.length && elem[0] !== document) { + position = elem.css("position"); + if (position === "absolute" || position === "relative" || position === "fixed") { + value = parseInt(elem.css("zIndex"), 10); + if (!isNaN(value) && value !== 0) { + if (value > maxValue) { maxValue = value; } + } + } + elem = elem.parent(); + } + + return maxValue; + }, + + /* Refresh the time picker + @param target element - The target input field or inline container element. */ + _refreshTimepicker: function(target) { + var inst = this._getInst(target); + if (inst) { + this._updateTimepicker(inst); + } + }, + + + /* Generate the time picker content. */ + _updateTimepicker: function (inst) { + inst.tpDiv.empty().append(this._generateHTML(inst)); + this._rebindDialogEvents(inst); + + }, + + _rebindDialogEvents: function (inst) { + var borders = $.timepicker._getBorders(inst.tpDiv), + self = this; + inst.tpDiv + .find('iframe.ui-timepicker-cover') // IE6- only + .css({ left: -borders[0], top: -borders[1], + width: inst.tpDiv.outerWidth(), height: inst.tpDiv.outerHeight() + }) + .end() + // after the picker html is appended bind the click & double click events (faster in IE this way + // then letting the browser interpret the inline events) + // the binding for the minute cells also exists in _updateMinuteDisplay + .find('.ui-timepicker-minute-cell') + .unbind() + .bind("click", { fromDoubleClick:false }, $.proxy($.timepicker.selectMinutes, this)) + .bind("dblclick", { fromDoubleClick:true }, $.proxy($.timepicker.selectMinutes, this)) + .end() + .find('.ui-timepicker-hour-cell') + .unbind() + .bind("click", { fromDoubleClick:false }, $.proxy($.timepicker.selectHours, this)) + .bind("dblclick", { fromDoubleClick:true }, $.proxy($.timepicker.selectHours, this)) + .end() + .find('.ui-timepicker td a') + .unbind() + .bind('mouseout', function () { + $(this).removeClass('ui-state-hover'); + if (this.className.indexOf('ui-timepicker-prev') != -1) $(this).removeClass('ui-timepicker-prev-hover'); + if (this.className.indexOf('ui-timepicker-next') != -1) $(this).removeClass('ui-timepicker-next-hover'); + }) + .bind('mouseover', function () { + if ( ! self._isDisabledTimepicker(inst.inline ? inst.tpDiv.parent()[0] : inst.input[0])) { + $(this).parents('.ui-timepicker-calendar').find('a').removeClass('ui-state-hover'); + $(this).addClass('ui-state-hover'); + if (this.className.indexOf('ui-timepicker-prev') != -1) $(this).addClass('ui-timepicker-prev-hover'); + if (this.className.indexOf('ui-timepicker-next') != -1) $(this).addClass('ui-timepicker-next-hover'); + } + }) + .end() + .find('.' + this._dayOverClass + ' a') + .trigger('mouseover') + .end() + .find('.ui-timepicker-now').bind("click", function(e) { + $.timepicker.selectNow(e); + }).end() + .find('.ui-timepicker-deselect').bind("click",function(e) { + $.timepicker.deselectTime(e); + }).end() + .find('.ui-timepicker-close').bind("click",function(e) { + $.timepicker._hideTimepicker(); + }).end(); + }, + + /* Generate the HTML for the current state of the time picker. */ + _generateHTML: function (inst) { + + var h, m, row, col, html, hoursHtml, minutesHtml = '', + showPeriod = (this._get(inst, 'showPeriod') == true), + showPeriodLabels = (this._get(inst, 'showPeriodLabels') == true), + showLeadingZero = (this._get(inst, 'showLeadingZero') == true), + showHours = (this._get(inst, 'showHours') == true), + showMinutes = (this._get(inst, 'showMinutes') == true), + amPmText = this._get(inst, 'amPmText'), + rows = this._get(inst, 'rows'), + amRows = 0, + pmRows = 0, + amItems = 0, + pmItems = 0, + amFirstRow = 0, + pmFirstRow = 0, + hours = Array(), + hours_options = this._get(inst, 'hours'), + hoursPerRow = null, + hourCounter = 0, + hourLabel = this._get(inst, 'hourText'), + showCloseButton = this._get(inst, 'showCloseButton'), + closeButtonText = this._get(inst, 'closeButtonText'), + showNowButton = this._get(inst, 'showNowButton'), + nowButtonText = this._get(inst, 'nowButtonText'), + showDeselectButton = this._get(inst, 'showDeselectButton'), + deselectButtonText = this._get(inst, 'deselectButtonText'), + showButtonPanel = showCloseButton || showNowButton || showDeselectButton; + + + + // prepare all hours and minutes, makes it easier to distribute by rows + for (h = hours_options.starts; h <= hours_options.ends; h++) { + hours.push (h); + } + hoursPerRow = Math.ceil(hours.length / rows); // always round up + + if (showPeriodLabels) { + for (hourCounter = 0; hourCounter < hours.length; hourCounter++) { + if (hours[hourCounter] < 12) { + amItems++; + } + else { + pmItems++; + } + } + hourCounter = 0; + + amRows = Math.floor(amItems / hours.length * rows); + pmRows = Math.floor(pmItems / hours.length * rows); + + // assign the extra row to the period that is more densely populated + if (rows != amRows + pmRows) { + // Make sure: AM Has Items and either PM Does Not, AM has no rows yet, or AM is more dense + if (amItems && (!pmItems || !amRows || (pmRows && amItems / amRows >= pmItems / pmRows))) { + amRows++; + } else { + pmRows++; + } + } + amFirstRow = Math.min(amRows, 1); + pmFirstRow = amRows + 1; + + if (amRows == 0) { + hoursPerRow = Math.ceil(pmItems / pmRows); + } else if (pmRows == 0) { + hoursPerRow = Math.ceil(amItems / amRows); + } else { + hoursPerRow = Math.ceil(Math.max(amItems / amRows, pmItems / pmRows)); + } + } + + + html = ''; + + if (showHours) { + + html += ''; // Close the Hour td + } + + if (showMinutes) { + html += ''; + } + + html += ''; + + + if (showButtonPanel) { + var buttonPanel = ''; + } + html += '
' + + '
' + + hourLabel + + '
' + + ''; + + for (row = 1; row <= rows; row++) { + html += ''; + // AM + if (row == amFirstRow && showPeriodLabels) { + html += ''; + } + // PM + if (row == pmFirstRow && showPeriodLabels) { + html += ''; + } + for (col = 1; col <= hoursPerRow; col++) { + if (showPeriodLabels && row < pmFirstRow && hours[hourCounter] >= 12) { + html += this._generateHTMLHourCell(inst, undefined, showPeriod, showLeadingZero); + } else { + html += this._generateHTMLHourCell(inst, hours[hourCounter], showPeriod, showLeadingZero); + hourCounter++; + } + } + html += ''; + } + html += '
' + amPmText[0] + '' + amPmText[1] + '
' + // Close the hours cells table + '
'; + html += this._generateHTMLMinutes(inst); + html += '
'; + if (showNowButton) { + buttonPanel += ''; + } + if (showDeselectButton) { + buttonPanel += ''; + } + if (showCloseButton) { + buttonPanel += ''; + } + + html += buttonPanel + '
'; + + return html; + }, + + /* Special function that update the minutes selection in currently visible timepicker + * called on hour selection when onMinuteShow is defined */ + _updateMinuteDisplay: function (inst) { + var newHtml = this._generateHTMLMinutes(inst); + inst.tpDiv.find('td.ui-timepicker-minutes').html(newHtml); + this._rebindDialogEvents(inst); + // after the picker html is appended bind the click & double click events (faster in IE this way + // then letting the browser interpret the inline events) + // yes I know, duplicate code, sorry +/* .find('.ui-timepicker-minute-cell') + .bind("click", { fromDoubleClick:false }, $.proxy($.timepicker.selectMinutes, this)) + .bind("dblclick", { fromDoubleClick:true }, $.proxy($.timepicker.selectMinutes, this)); +*/ + + }, + + /* + * Generate the minutes table + * This is separated from the _generateHTML function because is can be called separately (when hours changes) + */ + _generateHTMLMinutes: function (inst) { + + var m, row, html = '', + rows = this._get(inst, 'rows'), + minutes = Array(), + minutes_options = this._get(inst, 'minutes'), + minutesPerRow = null, + minuteCounter = 0, + showMinutesLeadingZero = (this._get(inst, 'showMinutesLeadingZero') == true), + onMinuteShow = this._get(inst, 'onMinuteShow'), + minuteLabel = this._get(inst, 'minuteText'); + + if ( ! minutes_options.starts) { + minutes_options.starts = 0; + } + if ( ! minutes_options.ends) { + minutes_options.ends = 59; + } + if ( ! minutes_options.manual) { + minutes_options.manual = []; + } + for (m = minutes_options.starts; m <= minutes_options.ends; m += minutes_options.interval) { + minutes.push(m); + } + for (i = 0; i < minutes_options.manual.length;i++) { + var currMin = minutes_options.manual[i]; + + // Validate & filter duplicates of manual minute input + if (typeof currMin != 'number' || currMin < 0 || currMin > 59 || $.inArray(currMin, minutes) >= 0) { + continue; + } + minutes.push(currMin); + } + + // Sort to get correct order after adding manual minutes + // Use compare function to sort by number, instead of string (default) + minutes.sort(function(a, b) { + return a-b; + }); + + minutesPerRow = Math.round(minutes.length / rows + 0.49); // always round up + + /* + * The minutes table + */ + // if currently selected minute is not enabled, we have a problem and need to select a new minute. + if (onMinuteShow && + (onMinuteShow.apply((inst.input ? inst.input[0] : null), [inst.hours , inst.minutes]) == false) ) { + // loop minutes and select first available + for (minuteCounter = 0; minuteCounter < minutes.length; minuteCounter += 1) { + m = minutes[minuteCounter]; + if (onMinuteShow.apply((inst.input ? inst.input[0] : null), [inst.hours, m])) { + inst.minutes = m; + break; + } + } + } + + + + html += '
' + + minuteLabel + + '
' + + ''; + + minuteCounter = 0; + for (row = 1; row <= rows; row++) { + html += ''; + while (minuteCounter < row * minutesPerRow) { + var m = minutes[minuteCounter]; + var displayText = ''; + if (m !== undefined ) { + displayText = (m < 10) && showMinutesLeadingZero ? "0" + m.toString() : m.toString(); + } + html += this._generateHTMLMinuteCell(inst, m, displayText); + minuteCounter++; + } + html += ''; + } + + html += '
'; + + return html; + }, + + /* Generate the content of a "Hour" cell */ + _generateHTMLHourCell: function (inst, hour, showPeriod, showLeadingZero) { + + var displayHour = hour; + if ((hour > 12) && showPeriod) { + displayHour = hour - 12; + } + if ((displayHour == 0) && showPeriod) { + displayHour = 12; + } + if ((displayHour < 10) && showLeadingZero) { + displayHour = '0' + displayHour; + } + + var html = ""; + var enabled = true; + var onHourShow = this._get(inst, 'onHourShow'); //custom callback + var maxTime = this._get(inst, 'maxTime'); + var minTime = this._get(inst, 'minTime'); + + if (hour == undefined) { + html = ' '; + return html; + } + + if (onHourShow) { + enabled = onHourShow.apply((inst.input ? inst.input[0] : null), [hour]); + } + + if (enabled) { + if ( !isNaN(parseInt(maxTime.hour)) && hour > maxTime.hour ) enabled = false; + if ( !isNaN(parseInt(minTime.hour)) && hour < minTime.hour ) enabled = false; + } + + if (enabled) { + html = '' + + '' + + displayHour.toString() + + ''; + } + else { + html = + '' + + '' + + displayHour.toString() + + '' + + ''; + } + return html; + }, + + /* Generate the content of a "Hour" cell */ + _generateHTMLMinuteCell: function (inst, minute, displayText) { + var html = ""; + var enabled = true; + var hour = inst.hours; + var onMinuteShow = this._get(inst, 'onMinuteShow'); //custom callback + var maxTime = this._get(inst, 'maxTime'); + var minTime = this._get(inst, 'minTime'); + + if (onMinuteShow) { + //NEW: 2011-02-03 we should give the hour as a parameter as well! + enabled = onMinuteShow.apply((inst.input ? inst.input[0] : null), [inst.hours,minute]); //trigger callback + } + + if (minute == undefined) { + html = ' '; + return html; + } + + if (enabled && hour !== null) { + if ( !isNaN(parseInt(maxTime.hour)) && !isNaN(parseInt(maxTime.minute)) && hour >= maxTime.hour && minute > maxTime.minute ) enabled = false; + if ( !isNaN(parseInt(minTime.hour)) && !isNaN(parseInt(minTime.minute)) && hour <= minTime.hour && minute < minTime.minute ) enabled = false; + } + + if (enabled) { + html = '' + + '' + + displayText + + ''; + } + else { + + html = '' + + '' + + displayText + + '' + + ''; + } + return html; + }, + + + /* Detach a timepicker from its control. + @param target element - the target input field or division or span */ + _destroyTimepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + $.removeData(target, PROP_NAME); + if (nodeName == 'input') { + inst.append.remove(); + inst.trigger.remove(); + $target.removeClass(this.markerClassName) + .unbind('focus.timepicker', this._showTimepicker) + .unbind('click.timepicker', this._adjustZIndex); + } else if (nodeName == 'div' || nodeName == 'span') + $target.removeClass(this.markerClassName).empty(); + }, + + /* Enable the date picker to a jQuery selection. + @param target element - the target input field or division or span */ + _enableTimepicker: function(target) { + var $target = $(target), + target_id = $target.attr('id'), + inst = $.data(target, PROP_NAME); + + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + if (nodeName == 'input') { + target.disabled = false; + var button = this._get(inst, 'button'); + $(button).removeClass('ui-state-disabled').disabled = false; + inst.trigger.filter('button'). + each(function() { this.disabled = false; }).end(); + } + else if (nodeName == 'div' || nodeName == 'span') { + var inline = $target.children('.' + this._inlineClass); + inline.children().removeClass('ui-state-disabled'); + inline.find('button').each( + function() { this.disabled = false } + ) + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value == target_id ? null : value); }); // delete entry + }, + + /* Disable the time picker to a jQuery selection. + @param target element - the target input field or division or span */ + _disableTimepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + if (nodeName == 'input') { + var button = this._get(inst, 'button'); + + $(button).addClass('ui-state-disabled').disabled = true; + target.disabled = true; + + inst.trigger.filter('button'). + each(function() { this.disabled = true; }).end(); + + } + else if (nodeName == 'div' || nodeName == 'span') { + var inline = $target.children('.' + this._inlineClass); + inline.children().addClass('ui-state-disabled'); + inline.find('button').each( + function() { this.disabled = true } + ) + + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value == target ? null : value); }); // delete entry + this._disabledInputs[this._disabledInputs.length] = $target.attr('id'); + }, + + /* Is the first field in a jQuery collection disabled as a timepicker? + @param target_id element - the target input field or division or span + @return boolean - true if disabled, false if enabled */ + _isDisabledTimepicker: function (target_id) { + if ( ! target_id) { return false; } + for (var i = 0; i < this._disabledInputs.length; i++) { + if (this._disabledInputs[i] == target_id) { return true; } + } + return false; + }, + + /* Check positioning to remain on screen. */ + _checkOffset: function (inst, offset, isFixed) { + var tpWidth = inst.tpDiv.outerWidth(); + var tpHeight = inst.tpDiv.outerHeight(); + var inputWidth = inst.input ? inst.input.outerWidth() : 0; + var inputHeight = inst.input ? inst.input.outerHeight() : 0; + var viewWidth = document.documentElement.clientWidth + $(document).scrollLeft(); + var viewHeight = document.documentElement.clientHeight + $(document).scrollTop(); + + offset.left -= (this._get(inst, 'isRTL') ? (tpWidth - inputWidth) : 0); + offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0; + offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; + + // now check if timepicker is showing outside window viewport - move to a better place if so. + offset.left -= Math.min(offset.left, (offset.left + tpWidth > viewWidth && viewWidth > tpWidth) ? + Math.abs(offset.left + tpWidth - viewWidth) : 0); + offset.top -= Math.min(offset.top, (offset.top + tpHeight > viewHeight && viewHeight > tpHeight) ? + Math.abs(tpHeight + inputHeight) : 0); + + return offset; + }, + + /* Find an object's position on the screen. */ + _findPos: function (obj) { + var inst = this._getInst(obj); + var isRTL = this._get(inst, 'isRTL'); + while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) { + obj = obj[isRTL ? 'previousSibling' : 'nextSibling']; + } + var position = $(obj).offset(); + return [position.left, position.top]; + }, + + /* Retrieve the size of left and top borders for an element. + @param elem (jQuery object) the element of interest + @return (number[2]) the left and top borders */ + _getBorders: function (elem) { + var convert = function (value) { + return { thin: 1, medium: 2, thick: 3}[value] || value; + }; + return [parseFloat(convert(elem.css('border-left-width'))), + parseFloat(convert(elem.css('border-top-width')))]; + }, + + + /* Close time picker if clicked elsewhere. */ + _checkExternalClick: function (event) { + if (!$.timepicker._curInst) { return; } + var $target = $(event.target); + if ($target[0].id != $.timepicker._mainDivId && + $target.parents('#' + $.timepicker._mainDivId).length == 0 && + !$target.hasClass($.timepicker.markerClassName) && + !$target.hasClass($.timepicker._triggerClass) && + $.timepicker._timepickerShowing && !($.timepicker._inDialog && $.blockUI)) + $.timepicker._hideTimepicker(); + }, + + /* Hide the time picker from view. + @param input element - the input field attached to the time picker */ + _hideTimepicker: function (input) { + var inst = this._curInst; + if (!inst || (input && inst != $.data(input, PROP_NAME))) { return; } + if (this._timepickerShowing) { + var showAnim = this._get(inst, 'showAnim'); + var duration = this._get(inst, 'duration'); + var postProcess = function () { + $.timepicker._tidyDialog(inst); + this._curInst = null; + }; + if ($.effects && $.effects[showAnim]) { + inst.tpDiv.hide(showAnim, $.timepicker._get(inst, 'showOptions'), duration, postProcess); + } + else { + inst.tpDiv[(showAnim == 'slideDown' ? 'slideUp' : + (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess); + } + if (!showAnim) { postProcess(); } + + this._timepickerShowing = false; + + this._lastInput = null; + if (this._inDialog) { + this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' }); + if ($.blockUI) { + $.unblockUI(); + $('body').append(this.tpDiv); + } + } + this._inDialog = false; + + var onClose = this._get(inst, 'onClose'); + if (onClose) { + onClose.apply( + (inst.input ? inst.input[0] : null), + [(inst.input ? inst.input.val() : ''), inst]); // trigger custom callback + } + + } + }, + + + + /* Tidy up after a dialog display. */ + _tidyDialog: function (inst) { + inst.tpDiv.removeClass(this._dialogClass).unbind('.ui-timepicker'); + }, + + /* Retrieve the instance data for the target control. + @param target element - the target input field or division or span + @return object - the associated instance data + @throws error if a jQuery problem getting data */ + _getInst: function (target) { + try { + return $.data(target, PROP_NAME); + } + catch (err) { + throw 'Missing instance data for this timepicker'; + } + }, + + /* Get a setting value, defaulting if necessary. */ + _get: function (inst, name) { + return inst.settings[name] !== undefined ? + inst.settings[name] : this._defaults[name]; + }, + + /* Parse existing time and initialise time picker. */ + _setTimeFromField: function (inst) { + if (inst.input.val() == inst.lastVal) { return; } + var defaultTime = this._get(inst, 'defaultTime'); + + var timeToParse = defaultTime == 'now' ? this._getCurrentTimeRounded(inst) : defaultTime; + if ((inst.inline == false) && (inst.input.val() != '')) { timeToParse = inst.input.val() } + + if (timeToParse instanceof Date) { + inst.hours = timeToParse.getHours(); + inst.minutes = timeToParse.getMinutes(); + } else { + var timeVal = inst.lastVal = timeToParse; + if (timeToParse == '') { + inst.hours = -1; + inst.minutes = -1; + } else { + var time = this.parseTime(inst, timeVal); + inst.hours = time.hours; + inst.minutes = time.minutes; + } + } + + + $.timepicker._updateTimepicker(inst); + }, + + /* Update or retrieve the settings for an existing time picker. + @param target element - the target input field or division or span + @param name object - the new settings to update or + string - the name of the setting to change or retrieve, + when retrieving also 'all' for all instance settings or + 'defaults' for all global defaults + @param value any - the new value for the setting + (omit if above is an object or to retrieve a value) */ + _optionTimepicker: function(target, name, value) { + var inst = this._getInst(target); + if (arguments.length == 2 && typeof name == 'string') { + return (name == 'defaults' ? $.extend({}, $.timepicker._defaults) : + (inst ? (name == 'all' ? $.extend({}, inst.settings) : + this._get(inst, name)) : null)); + } + var settings = name || {}; + if (typeof name == 'string') { + settings = {}; + settings[name] = value; + } + if (inst) { + extendRemove(inst.settings, settings); + if (this._curInst == inst) { + this._hideTimepicker(); + this._updateTimepicker(inst); + } + if (inst.inline) { + this._updateTimepicker(inst); + } + } + }, + + + /* Set the time for a jQuery selection. + @param target element - the target input field or division or span + @param time String - the new time */ + _setTimeTimepicker: function(target, time) { + var inst = this._getInst(target); + if (inst) { + this._setTime(inst, time); + this._updateTimepicker(inst); + this._updateAlternate(inst, time); + } + }, + + /* Set the time directly. */ + _setTime: function(inst, time, noChange) { + var origHours = inst.hours; + var origMinutes = inst.minutes; + if (time instanceof Date) { + inst.hours = time.getHours(); + inst.minutes = time.getMinutes(); + } else { + var time = this.parseTime(inst, time); + inst.hours = time.hours; + inst.minutes = time.minutes; + } + + if ((origHours != inst.hours || origMinutes != inst.minutes) && !noChange) { + inst.input.trigger('change'); + } + this._updateTimepicker(inst); + this._updateSelectedValue(inst); + }, + + /* Return the current time, ready to be parsed, rounded to the closest minute by interval */ + _getCurrentTimeRounded: function (inst) { + var currentTime = new Date(), + currentMinutes = currentTime.getMinutes(), + minutes_options = this._get(inst, 'minutes'), + // round to closest interval + adjustedMinutes = Math.round(currentMinutes / minutes_options.interval) * minutes_options.interval; + currentTime.setMinutes(adjustedMinutes); + return currentTime; + }, + + /* + * Parse a time string into hours and minutes + */ + parseTime: function (inst, timeVal) { + var retVal = new Object(); + retVal.hours = -1; + retVal.minutes = -1; + + if(!timeVal) + return ''; + + var timeSeparator = this._get(inst, 'timeSeparator'), + amPmText = this._get(inst, 'amPmText'), + showHours = this._get(inst, 'showHours'), + showMinutes = this._get(inst, 'showMinutes'), + optionalMinutes = this._get(inst, 'optionalMinutes'), + showPeriod = (this._get(inst, 'showPeriod') == true), + p = timeVal.indexOf(timeSeparator); + + // check if time separator found + if (p != -1) { + retVal.hours = parseInt(timeVal.substr(0, p), 10); + retVal.minutes = parseInt(timeVal.substr(p + 1), 10); + } + // check for hours only + else if ( (showHours) && ( !showMinutes || optionalMinutes ) ) { + retVal.hours = parseInt(timeVal, 10); + } + // check for minutes only + else if ( ( ! showHours) && (showMinutes) ) { + retVal.minutes = parseInt(timeVal, 10); + } + + if (showHours) { + var timeValUpper = timeVal.toUpperCase(); + if ((retVal.hours < 12) && (showPeriod) && (timeValUpper.indexOf(amPmText[1].toUpperCase()) != -1)) { + retVal.hours += 12; + } + // fix for 12 AM + if ((retVal.hours == 12) && (showPeriod) && (timeValUpper.indexOf(amPmText[0].toUpperCase()) != -1)) { + retVal.hours = 0; + } + } + + return retVal; + }, + + selectNow: function(event) { + var id = $(event.target).attr("data-timepicker-instance-id"), + $target = $(id), + inst = this._getInst($target[0]); + //if (!inst || (input && inst != $.data(input, PROP_NAME))) { return; } + var currentTime = new Date(); + inst.hours = currentTime.getHours(); + inst.minutes = currentTime.getMinutes(); + this._updateSelectedValue(inst); + this._updateTimepicker(inst); + this._hideTimepicker(); + }, + + deselectTime: function(event) { + var id = $(event.target).attr("data-timepicker-instance-id"), + $target = $(id), + inst = this._getInst($target[0]); + inst.hours = -1; + inst.minutes = -1; + this._updateSelectedValue(inst); + this._hideTimepicker(); + }, + + + selectHours: function (event) { + var $td = $(event.currentTarget), + id = $td.attr("data-timepicker-instance-id"), + newHours = parseInt($td.attr("data-hour")), + fromDoubleClick = event.data.fromDoubleClick, + $target = $(id), + inst = this._getInst($target[0]), + showMinutes = (this._get(inst, 'showMinutes') == true); + + // don't select if disabled + if ( $.timepicker._isDisabledTimepicker($target.attr('id')) ) { return false } + + $td.parents('.ui-timepicker-hours:first').find('a').removeClass('ui-state-active'); + $td.children('a').addClass('ui-state-active'); + inst.hours = newHours; + + // added for onMinuteShow callback + var onMinuteShow = this._get(inst, 'onMinuteShow'), + maxTime = this._get(inst, 'maxTime'), + minTime = this._get(inst, 'minTime'); + if (onMinuteShow || maxTime.minute || minTime.minute) { + // this will trigger a callback on selected hour to make sure selected minute is allowed. + this._updateMinuteDisplay(inst); + } + + this._updateSelectedValue(inst); + + inst._hoursClicked = true; + if ((inst._minutesClicked) || (fromDoubleClick) || (showMinutes == false)) { + $.timepicker._hideTimepicker(); + } + // return false because if used inline, prevent the url to change to a hashtag + return false; + }, + + selectMinutes: function (event) { + var $td = $(event.currentTarget), + id = $td.attr("data-timepicker-instance-id"), + newMinutes = parseInt($td.attr("data-minute")), + fromDoubleClick = event.data.fromDoubleClick, + $target = $(id), + inst = this._getInst($target[0]), + showHours = (this._get(inst, 'showHours') == true); + + // don't select if disabled + if ( $.timepicker._isDisabledTimepicker($target.attr('id')) ) { return false } + + $td.parents('.ui-timepicker-minutes:first').find('a').removeClass('ui-state-active'); + $td.children('a').addClass('ui-state-active'); + + inst.minutes = newMinutes; + this._updateSelectedValue(inst); + + inst._minutesClicked = true; + if ((inst._hoursClicked) || (fromDoubleClick) || (showHours == false)) { + $.timepicker._hideTimepicker(); + // return false because if used inline, prevent the url to change to a hashtag + return false; + } + + // return false because if used inline, prevent the url to change to a hashtag + return false; + }, + + _updateSelectedValue: function (inst) { + var newTime = this._getParsedTime(inst); + if (inst.input) { + inst.input.val(newTime); + inst.input.trigger('change'); + } + var onSelect = this._get(inst, 'onSelect'); + if (onSelect) { onSelect.apply((inst.input ? inst.input[0] : null), [newTime, inst]); } // trigger custom callback + this._updateAlternate(inst, newTime); + return newTime; + }, + + /* this function process selected time and return it parsed according to instance options */ + _getParsedTime: function(inst) { + + if (inst.hours == -1 && inst.minutes == -1) { + return ''; + } + + // default to 0 AM if hours is not valid + if ((inst.hours < inst.hours.starts) || (inst.hours > inst.hours.ends )) { inst.hours = 0; } + // default to 0 minutes if minute is not valid + if ((inst.minutes < inst.minutes.starts) || (inst.minutes > inst.minutes.ends)) { inst.minutes = 0; } + + var period = "", + showPeriod = (this._get(inst, 'showPeriod') == true), + showLeadingZero = (this._get(inst, 'showLeadingZero') == true), + showHours = (this._get(inst, 'showHours') == true), + showMinutes = (this._get(inst, 'showMinutes') == true), + optionalMinutes = (this._get(inst, 'optionalMinutes') == true), + amPmText = this._get(inst, 'amPmText'), + selectedHours = inst.hours ? inst.hours : 0, + selectedMinutes = inst.minutes ? inst.minutes : 0, + displayHours = selectedHours ? selectedHours : 0, + parsedTime = ''; + + // fix some display problem when hours or minutes are not selected yet + if (displayHours == -1) { displayHours = 0 } + if (selectedMinutes == -1) { selectedMinutes = 0 } + + if (showPeriod) { + if (inst.hours == 0) { + displayHours = 12; + } + if (inst.hours < 12) { + period = amPmText[0]; + } + else { + period = amPmText[1]; + if (displayHours > 12) { + displayHours -= 12; + } + } + } + + var h = displayHours.toString(); + if (showLeadingZero && (displayHours < 10)) { h = '0' + h; } + + var m = selectedMinutes.toString(); + if (selectedMinutes < 10) { m = '0' + m; } + + if (showHours) { + parsedTime += h; + } + if (showHours && showMinutes && (!optionalMinutes || m != 0)) { + parsedTime += this._get(inst, 'timeSeparator'); + } + if (showMinutes && (!optionalMinutes || m != 0)) { + parsedTime += m; + } + if (showHours) { + if (period.length > 0) { parsedTime += this._get(inst, 'periodSeparator') + period; } + } + + return parsedTime; + }, + + /* Update any alternate field to synchronise with the main field. */ + _updateAlternate: function(inst, newTime) { + var altField = this._get(inst, 'altField'); + if (altField) { // update alternate field too + $(altField).each(function(i,e) { + $(e).val(newTime); + }); + } + }, + + _getTimeAsDateTimepicker: function(input) { + var inst = this._getInst(input); + if (inst.hours == -1 && inst.minutes == -1) { + return ''; + } + + // default to 0 AM if hours is not valid + if ((inst.hours < inst.hours.starts) || (inst.hours > inst.hours.ends )) { inst.hours = 0; } + // default to 0 minutes if minute is not valid + if ((inst.minutes < inst.minutes.starts) || (inst.minutes > inst.minutes.ends)) { inst.minutes = 0; } + + return new Date(0, 0, 0, inst.hours, inst.minutes, 0); + }, + /* This might look unused but it's called by the $.fn.timepicker function with param getTime */ + /* added v 0.2.3 - gitHub issue #5 - Thanks edanuff */ + _getTimeTimepicker : function(input) { + var inst = this._getInst(input); + return this._getParsedTime(inst); + }, + _getHourTimepicker: function(input) { + var inst = this._getInst(input); + if ( inst == undefined) { return -1; } + return inst.hours; + }, + _getMinuteTimepicker: function(input) { + var inst= this._getInst(input); + if ( inst == undefined) { return -1; } + return inst.minutes; + } + + }); + + + + /* Invoke the timepicker functionality. + @param options string - a command, optionally followed by additional parameters or + Object - settings for attaching new timepicker functionality + @return jQuery object */ + $.fn.timepicker = function (options) { + /* Initialise the time picker. */ + if (!$.timepicker.initialized) { + $(document).mousedown($.timepicker._checkExternalClick); + $.timepicker.initialized = true; + } + + /* Append timepicker main container to body if not exist. */ + if ($("#"+$.timepicker._mainDivId).length === 0) { + $('body').append($.timepicker.tpDiv); + } + + var otherArgs = Array.prototype.slice.call(arguments, 1); + if (typeof options == 'string' && (options == 'getTime' || options == 'getTimeAsDate' || options == 'getHour' || options == 'getMinute' )) + return $.timepicker['_' + options + 'Timepicker']. + apply($.timepicker, [this[0]].concat(otherArgs)); + if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string') + return $.timepicker['_' + options + 'Timepicker']. + apply($.timepicker, [this[0]].concat(otherArgs)); + return this.each(function () { + typeof options == 'string' ? + $.timepicker['_' + options + 'Timepicker']. + apply($.timepicker, [this].concat(otherArgs)) : + $.timepicker._attachTimepicker(this, options); + }); + }; + + /* jQuery extend now ignores nulls! */ + function extendRemove(target, props) { + $.extend(target, props); + for (var name in props) + if (props[name] == null || props[name] == undefined) + target[name] = props[name]; + return target; + }; + + $.timepicker = new Timepicker(); // singleton instance + $.timepicker.initialized = false; + $.timepicker.uuid = new Date().getTime(); + $.timepicker.version = "0.3.3"; + + // Workaround for #4055 + // Add another global to avoid noConflict issues with inline event handlers + window['TP_jQuery_' + tpuuid] = $; + +})(jQuery);