| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664 |
- // jQuery TimePicker plugin - http://github.com/wvega/timepicker
- //
- // A jQuery plugin to enhance standard form input fields helping users to select
- // (or type) times.
- //
- // Copyright (c) 2010 Willington Vega <wvega@wvega.com>
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- // Define a cross-browser window.console.log method.
- // For IE and FF without Firebug, fallback to using an alert.
- //if (!window.console) {
- // var log = window.opera ? window.opera.postError : alert;
- // window.console = { log: function(str) { log(str) } };
- //}
- if(typeof jQuery != 'undefined') {
- (function($, undefined){
- function pad(str, ch, length) {
- return Array(length + 1 - str.length).join(ch) + str;
- }
- function normalize() {
- if (arguments.length == 1) {
- return new Date(1988, 7, 24, arguments[0].getHours(), arguments[0].getMinutes(), 00);
- } else if (arguments.length == 2) {
- return new Date(1988, 7, 24, arguments[0], arguments[1], 00);
- } else {
- return new Date(1988, 7, 24);
- }
- }
-
- $.TimePicker = function() {
- var widget = this;
- widget.ui = $('ul.ui-timepicker');
- if (widget.ui.length == 0) {
- widget.ui = $('<ul></ul>').addClass('ui-timepicker ui-timepicker-hidden')
- .addClass('ui-widget ui-widget-content ui-menu')
- .addClass('ui-corner-all ui-helper-hidden')
- .appendTo('body');
- if ($.fn.jquery >= '1.4.2') {
- widget.ui.delegate('a', 'mouseenter.timepicker', function(event) {
- // passing false instead of an instance object tells the function
- // to use the current instance
- widget.activate(false, $(this).parent());
- }).delegate('a', 'mouseleave.timepicker', function(event) {
- widget.deactivate(false);
- }).delegate('a', 'click.timepicker', function(event) {
- event.preventDefault();
- widget.select(false, $(this).parent());
- });
- }
- widget.ui.bind('click.timepicker, scroll.timepicker', function(event) {
- clearTimeout(widget.closing);
- });
- }
- };
- $.TimePicker.count = 0;
- $.TimePicker.instance = function() {
- if (!$.TimePicker._instance) {
- $.TimePicker._instance = new $.TimePicker();
- }
- return $.TimePicker._instance;
- }
- $.TimePicker.prototype = {
- // extracted from from jQuery UI Core
- // http://github,com/jquery/jquery-ui/blob/master/ui/jquery.ui.core.js
- keyCode: {
- ALT: 18,
- BLOQ_MAYUS: 20,
- CTRL: 17,
- DOWN: 40,
- END: 35,
- ENTER: 13,
- HOME: 36,
- LEFT: 37,
- NUMPAD_ENTER: 108,
- PAGE_DOWN: 34,
- PAGE_UP: 33,
- RIGHT: 39,
- SHIFT: 16,
- TAB: 9,
- UP: 38
- },
-
- _items: function(i, startTime) {
- var widget = this, ul = $('<ul></ul>'), item = null, time, end;
- if (startTime) {
- time = normalize(startTime);
- } else if (i.options.startTime) {
- time = normalize(i.options.startTime);
- } else {
- time = normalize(i.options.startHour, i.options.startMinutes)
- }
-
- end = new Date(time.getTime() + 24 * 60 * 60 * 1000);
- while(time < end) {
- if (widget._isValidTime(i, time)) {
- item = $('<li>').addClass('ui-menu-item').appendTo(ul);
- $('<a>').addClass('ui-corner-all').text($.fn.timepicker.formatTime(i.options.timeFormat, time)).appendTo(item);
- item.data('time-value', time);
- }
- time = new Date(time.getTime() + i.options.interval * 60 * 1000);
- }
- return ul.children();
- },
-
- _isValidTime: function(i, time) {
- var min = null, max = null;
- time = normalize(time);
- if (i.options.minTime !== null) {
- min = normalize(i.options.minTime);
- } else if (i.options.minHour !== null || i.options.minMinutes !== null) {
- min = normalize(i.options.minHour, i.options.minMinutes);
- }
- if (i.options.maxTime !== null) {
- max = normalize(i.options.maxTime)
- } else if (i.options.maxHour !== null || i.options.maxMinutes !== null) {
- max = normalize(i.options.maxHour, i.options.maxMinutes);
- }
- if (min !== null && max !== null) {
- return time >= min && time <= max;
- } else if (min !== null) {
- return time >= min;
- } else if (max !== null) {
- return time <= max;
- }
- return true;
- },
- _hasScroll: function() {
- return this.ui.height() < this.ui.attr('scrollHeight');
- },
- /**
- * TODO: Write me!
- *
- * @param i
- * @param direction
- * @param edge
- * */
- _move: function(i, direction, edge) {
- var widget = this;
- if (widget.closed()) {
- widget.open(i);
- }
- if (!widget.active) {
- widget.activate(i, widget.ui.children(edge));
- return;
- }
- var next = widget.active[direction + 'All']('.ui-menu-item').eq(0);
- if (next.length) {
- widget.activate(i, next);
- } else {
- widget.activate(i, widget.ui.children(edge));
- }
- },
- //
- // protected methods
- //
- register: function(node, options) {
- var widget = this, i = {};// timepicker instance object
- i.element = $(node);
-
- if (i.element.data('TimePicker')) {return;}
- i.element.data('TimePicker', i);
- i.options = $.metadata ? $.extend({}, options, i.element.metadata()) : options;
- i.widget = widget;
- i.selectedTime = $.fn.timepicker.parseTime(i.element.val());
- // proxy functions for the exposed api methods
- $.extend(i, {
- next: function() {return widget.next(i);},
- previous: function() {return widget.previous(i);},
- first: function() {return widget.first(i);},
- last: function() {return widget.last(i);},
- selected: function() {return widget.selected(i);},
- open: function() {return widget.open(i);},
- close: function(force) {return widget.close(i, force);},
- closed: function() {return widget.closed(i);},
- destroy: function() {return widget.destroy(i)},
- getTime: function() {return widget.getTime(i);},
- setTime: function(time) {return widget.setTime(i, time);}
- });
- i.element.bind('keydown.timepicker', function(event) {
- switch (event.which || event.keyCode) {
- case widget.keyCode.ENTER:
- case widget.keyCode.NUMPAD_ENTER:
- event.preventDefault();
- if (widget.closed()) {
- i.element.trigger('change.timepicker');
- } else {
- widget.select(i, widget.active);
- }
- break;
- case widget.keyCode.UP:
- i.previous();
- break;
- case widget.keyCode.DOWN:
- i.next();
- break;
- default:
- if (!widget.closed()) {
- i.close(true);
- }
- break;
- }
- }).bind('focus.timepicker', function(event) {
- i.open();
- }).bind('blur.timepicker', function(event) {
- i.close();
- }).bind('change.timepicker', function(event) {
- if (i.closed()) {
- i.setTime($.fn.timepicker.parseTime(i.element.val()));
- }
- });
- },
- select: function(i, item) {
- var widget = this, instance = i === false ? widget.instance : i;
- clearTimeout(widget.closing);
- widget.setTime(instance, $.fn.timepicker.parseTime(item.children('a').text()));
- widget.close(instance, true);
- },
- activate: function(i, item) {
- var widget = this, instance = i === false ? widget.instance : i;
-
- if (instance !== widget.instance) {
- return;
- } else {
- widget.deactivate();
- }
- if (widget._hasScroll()) {
- var offset = item.offset().top - widget.ui.offset().top,
- scroll = widget.ui.scrollTop(),
- height = widget.ui.height();
- if (offset < 0) {
- widget.ui.scrollTop(scroll + offset);
- } else if (offset >= height) {
- widget.ui.scrollTop(scroll + offset - height + item.height());
- }
- }
- widget.active = item.eq(0).children('a').addClass('ui-state-hover')
- .attr('id', 'ui-active-item')
- .end();
- },
- deactivate: function() {
- var widget = this;
- if (!widget.active) {return;}
- widget.active.children('a').removeClass('ui-state-hover').removeAttr('id');
- widget.active = null;
- },
- // option: function(key, value) {
- // var self = this;
- // // TODO: handle variable updates
- // if (arguments.length > 1) {
- // if (self.options.hasOwnProperty(key)) {
- // self.options[key] = value;
- // }
- // return self;
- // }
- // return self.options[key];
- // },
- /**
- * _activate, _deactivate, first, last, next, previous, _move and
- * _hasScroll were extracted from jQuery UI Menu
- * http://github,com/jquery/jquery-ui/blob/menu/ui/jquery.ui.menu.js
- */
- //
- // public methods
- //
- next: function(i) {
- if (this.closed() || this.instance === i) {
- this._move(i, 'next', '.ui-menu-item:first');
- }
- },
- previous: function(i) {
- if (this.closed() || this.instance === i) {
- this._move(i, 'prev', '.ui-menu-item:last');
- }
- },
- first: function(i) {
- if (this.instance === i) {
- return this.active && !this.active.prevAll('.ui-menu-item').length;
- }
- return false;
- },
- last: function(i) {
- if (this.instance === i) {
- return this.active && !this.active.nextAll('.ui-menu-item').length;
- }
- return false;
- },
- selected: function(i) {
- if (this.instance === i) {
- return this.active ? this.active : null;
- }
- return null;
- },
- open: function(i) {
- var widget = this, zindex;
- // if a date is already selected and options.dynamic is true,
- // arrange the items in the list so the first item is
- // cronologically right after the selected date.
- // TODO: set selectedTime
- if (!i.items || (i.options.dynamic && i.selectedTime)) {
- i.items = widget._items(i);
- }
- // remove old li elements but keep associated events, then append
- // the new li elements to the ul
- if (widget.instance !== i || (i.options.dynamic && i.selectedTime)) {
- // handle menu events when using jQuery versions previous to
- // 1.4.2 (thanks to Brian Link)
- // http://github.com/wvega/timepicker/issues#issue/4
- if ($.fn.jquery < '1.4.2') {
- widget.ui.children().remove();
- widget.ui.append(i.items);
- widget.ui.find('a').bind('mouseover.timepicker', function(event) {
- widget.activate(i, $(this).parent());
- }).bind('mouseout.timepicker', function(event) {
- widget.deactivate(i);
- }).bind('click.timepicker', function(event) {
- event.preventDefault();
- widget.select(i, $(this).parent());
- });
- } else {
- widget.ui.children().detach();
- widget.ui.append(i.items);
- }
- }
-
- // theme
- widget.ui.removeClass('ui-helper-hidden ui-timepicker-hidden ui-timepicker-standard ui-timepicker-corners').show();
- switch (i.options.theme) {
- case 'standard':
- widget.ui.addClass('ui-timepicker-standard');
- break;
- case 'standard-rounded-corners':
- widget.ui.addClass('ui-timepicker-standard ui-timepicker-corners');
- break;
- default:
- break;
- }
- // position
- // zindex = i.element.offsetParent().css('z-index'); zindex == 'auto' ? 'auto' : parseInt(zindex, 10) + 1
- widget.ui.css($.extend(i.element.offset(), {
- width: i.element.innerWidth(),
- zIndex: i.element.offsetParent().css('z-index')
- }));
- widget.ui.css('top', parseInt(widget.ui.css('top'), 10) + i.element.outerHeight());
- widget.instance = i;
- // try to match input field's current value with an item in the
- // dropdown
- if (i.selectedTime) {
- i.items.each(function() {
- var item = $(this), time;
- if ($.fn.jquery < '1.4.2') {
- time = $.fn.timepicker.parseTime(item.find('a').text());
- } else {
- time = item.data('time-value');
- }
- if (time.getTime() == i.selectedTime.getTime()) {
- widget.activate(i, item);
- return false;
- }
- return true;
- });
- } else {
- widget.deactivate(i);
- }
- // don't break the chain
- return i.element;
- },
- close: function(i, force) {
- var widget = this;
- if (widget.closed() || force) {
- clearTimeout(widget.closing);
- if (widget.instance === i) {
- widget.ui.scrollTop(0).addClass('ui-helper-hidden ui-timepicker-hidden').hide();
- widget.ui.children().removeClass('ui-state-hover');
- }
- } else {
- widget.closing = setTimeout(function() {
- widget.close(i, true);
- }, 150);
- }
- return i.element;
- },
- closed: function() {
- return this.ui.is(':hidden');
- },
- destroy: function(i) {
- var widget = this;
- widget.close(i, true);
- return i.element.unbind('.timepicker').data('TimePicker', null);
- },
- getTime: function(i) {
- return i.selectedTime ? i.selectedTime : null;
- },
- setTime: function(i, time) {
- var widget = this;
- if (time && time.getMinutes) {
- i.selectedTime = time;
- i.element.val($.fn.timepicker.formatTime(i.options.timeFormat, time));
- // custom change event and change callback
- i.element.trigger('time-change', [time]);
- if ($.isFunction(i.options.change)) {
- i.options.change.apply(i.element, [time]);
- }
- } else {
- i.selectedTime = null;
- }
- }
- };
- $.TimePicker.defaults = {
- timeFormat: 'hh:mm p',
- minHour: null,
- minMinutes: null,
- minTime: null,
- maxHour: null,
- maxMinutes: null,
- maxTime: null,
- startHour: null,
- startMinutes: null,
- startTime: null,
- interval: 30,
- dynamic: true,
- theme: 'standard',
- // callbacks
- change: function(time) {}
- };
- $.fn.timepicker = function(options) {
- // TODO: see if it works with previous versions
- if ($.fn.jquery < '1.3') {
- return this;
- }
-
- // Calling the constructor again returns a reference to a TimePicker object.
- if (this.length == 1 && this.data('TimePicker')) {
- return this.data('TimePicker');
- }
-
- var globals = $.extend({}, $.TimePicker.defaults, options);
-
- return this.each(function() {
- $.TimePicker.instance().register(this, globals);
- });
- };
-
- /**
- * TODO: documentation
- */
- $.fn.timepicker.formatTime = function(format, time) {
- var hours = time.getHours(),
- hours12 = hours % 12,
- minutes = time.getMinutes(),
- seconds = time.getSeconds(),
- replacements = {
- hh: pad((hours12 === 0 ? 12 : hours12).toString(), '0', 2),
- HH: pad(hours.toString(), '0', 2),
- mm: pad(minutes.toString(), '0', 2),
- ss: pad(seconds.toString(), '0', 2),
- h: (hours12 === 0 ? 12 : hours12),
- H: hours,
- m: minutes,
- s: seconds,
- p: hours > 11 ? 'PM' : 'AM'
- },
- str = format, k = '';
- for (k in replacements) {
- if (replacements.hasOwnProperty(k)) {
- str = str.replace(new RegExp(k,'g'), replacements[k]);
- }
- }
- return str;
- };
- /**
- * Convert a string representing a given time into a Date object.
- *
- * The Date object will have attributes others than hours, minutes and
- * seconds set to current local time values. The function will return
- * false if given string can't be converted.
- *
- * If there is an 'a' in the string we set am to true, if there is a 'p'
- * we set pm to true, if both are present only am is setted to true.
- *
- * All non-digit characters are removed from the string before trying to
- * parse the time.
- *
- * '' can't be converted and the function returns false.
- * '1' is converted to 01:00:00 am
- * '11' is converted to 11:00:00 am
- * '111' is converted to 01:11:00 am
- * '1111' is converted to 11:11:00 am
- * '11111' is converted to 01:11:11 am
- * '111111' is converted to 11:11:11 am
- *
- * Only the first six (or less) characters are considered.
- *
- * Special case:
- *
- * When hours is greater than 24 and the last digit is less or equal than 6, and minutes
- * and seconds are less or equal than 60, we append a trailing zero and
- * start parsing process again. Examples:
- *
- * '95' is treated as '950' and converted to 09:50:00 am
- * '46' is treated as '460' and converted to 05:00:00 am
- * '57' can't be converted and the function returns false.
- *
- * For a detailed list of supported formats check the unit tests at
- * http://github.com/wvega/timepicker/tree/master/tests/
- */
- $.fn.timepicker.parseTime = (function(str) {
- var patterns = [
- // 1, 12, 123, 1234, 12345, 123456
- [/^(\d+)$/, '$1'],
- // :1, :2, :3, :4 ... :9
- [/^:(\d)$/, '$10'],
- // :1, :12, :123, :1234 ...
- [/^:(\d+)/, '$1'],
- // 6:06, 5:59, 5:8
- [/^(\d):([7-9])$/, '0$10$2'],
- [/^(\d):(\d\d)$/, '$1$2'],
- [/^(\d):(\d{1,})$/, '0$1$20'],
- // 10:8, 10:10, 10:34
- [/^(\d\d):([7-9])$/, '$10$2'],
- [/^(\d\d):(\d)$/, '$1$20'],
- [/^(\d\d):(\d*)$/, '$1$2'],
- // 123:4, 1234:456
- [/^(\d{3,}):(\d)$/, '$10$2'],
- [/^(\d{3,}):(\d{2,})/, '$1$2'],
- //
- [/^(\d):(\d):(\d)$/, '0$10$20$3'],
- [/^(\d{1,2}):(\d):(\d\d)/, '$10$2$3']];
- return function(str) {
- var time = normalize(new Date()),
- am = false, pm = false, h = false, m = false, s = false, k = 0;
- str = str.toLowerCase();
- am = /a/.test(str);
- pm = am ? false : /p/.test(str);
- str = str.replace(/[^0-9:]/g, '').replace(/:+/g, ':');
- for (k in patterns) {
- if (patterns[k][0].test(str)) {
- str = str.replace(patterns[k][0], patterns[k][1]);
- break;
- }
- }
- str = str.replace(/:/g, '');
- if (str.length == 1) {
- h = str;
- } else if (str.length == 2) {
- h = str;
- } else if (str.length == 3 || str.length == 5) {
- h = str.substr(0, 1);
- m = str.substr(1, 2);
- s = str.substr(3, 2);
- } else if (str.length == 4 || str.length > 5) {
- h = str.substr(0, 2);
- m = str.substr(2, 2);
- s = str.substr(4, 2);
- }
- if (str.length > 0 && str.length < 5) {
- if (str.length < 3) {
- m = 0;
- }
- s = 0;
- }
- if (h === false || m === false || s === false) {
- return false;
- }
- h = parseInt(h, 10);m = parseInt(m, 10);s = parseInt(s, 10);
- if (am && h == 12) {
- h = 0;
- } else if (pm && h < 12) {
- h = h + 12;
- }
- if (h > 24 && (h % 10) <= 6 && m <= 60 && s <= 60) {
- return $.fn.timepicker.parseTime(str + '0' + (am ? 'a' : '') + (pm ? 'p' : ''));
- } else if (h <= 24 && m <= 60 && s <= 60) {
- time.setHours(h, m, s);
- return time;
- } else {
- return false;
- }
- };
- })();
- })(jQuery);
- }
|