All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.resources.primefaces-extensions.timepicker.0-jquery.ui.timepicker.js Maven / Gradle / Ivy

There is a newer version: 14.0.7.1
Show newest version
/*
 * jQuery UI Timepicker
 * 
 * Version 0.3.3
 *
 * 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 = 'fgtimepicker',
        tpuuid = new Date().getTime();

    /* Time picker manager.
    Use the singleton instance of this class, $.fgtimepicker, 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 FGTimepicker() {
        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(FGTimepicker.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).on('keydown.timepicker', this._doKeyDown).on('keyup.timepicker', this._doKeyUp).on("setData.timepicker", function (event, key, value) { inst.settings[key] = value; }).on("getData.timepicker", function (event, key) { return this._get(inst, key); }); $.data(target, PROP_NAME, inst); }, /* Handle keystrokes. */ _doKeyDown: function (event) { var inst = $.fgtimepicker._getInst(event.target); var handled = true; inst._keyEvent = true; if ($.fgtimepicker._timepickerShowing) { switch (event.keyCode) { case 9: $.fgtimepicker._hideTimepicker(); handled = false; break; // hide on tab out case 13: $.fgtimepicker._updateSelectedValue(inst); $.fgtimepicker._hideTimepicker(); return false; // don't submit the form break; // select the value on enter case 27: $.fgtimepicker._hideTimepicker(); break; // hide on escape default: handled = false; } } else if (event.keyCode == 36 && event.ctrlKey) { // display the time picker on ctrl+home $.fgtimepicker._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 = $.fgtimepicker._getInst(event.target); $.fgtimepicker._setTimeFromField(inst); $.fgtimepicker._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.off('focus.timepicker', this._showTimepicker); input.off('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.on("focus.timepicker", this._showTimepicker); input.on("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).on("click.timepicker", function () { if ($.fgtimepicker._timepickerShowing && $.fgtimepicker._lastInput == input[0]) { $.fgtimepicker._hideTimepicker(); } else if (!inst.input.is(':disabled')) { $.fgtimepicker._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).on("setData.timepicker", function (event, key, value) { inst.settings[key] = value; }).on("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 = $.fgtimepicker._getInst(input); inst.tpDiv.css('zIndex', $.fgtimepicker._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 ($.fgtimepicker._isDisabledTimepicker(input) || $.fgtimepicker._lastInput == input) { return; } // already here // fix v 0.0.8 - close current timepicker before showing another one $.fgtimepicker._hideTimepicker(); var inst = $.fgtimepicker._getInst(input); if ($.fgtimepicker._curInst && $.fgtimepicker._curInst != inst) { $.fgtimepicker._curInst.tpDiv.stop(true, true); } var beforeShow = $.fgtimepicker._get(inst, 'beforeShow'); extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {})); inst.lastVal = null; $.fgtimepicker._lastInput = input; $.fgtimepicker._setTimeFromField(inst); // calculate default position if ($.fgtimepicker._inDialog) { input.value = ''; } // hide cursor if (!$.fgtimepicker._pos) { // position below input $.fgtimepicker._pos = $.fgtimepicker._findPos(input); $.fgtimepicker._pos[1] += input.offsetHeight; // add the height } var isFixed = false; $(input).parents().each(function () { isFixed |= $(this).css('position') == 'fixed'; return !isFixed; }); var offset = {left: $.fgtimepicker._pos[0], top: $.fgtimepicker._pos[1]}; $.fgtimepicker._pos = null; // determine sizing offscreen inst.tpDiv.css({position: 'absolute', display: 'block', top: '-1000px'}); $.fgtimepicker._updateTimepicker(inst); // position with the ui position utility, if loaded if ((!inst.inline) && (typeof $.ui.position == 'object')) { inst.tpDiv.css({left: '0px', top: '0px'}).position({ of: inst.input, my: $.fgtimepicker._get(inst, 'myPosition'), at: $.fgtimepicker._get(inst, 'atPosition'), collision: 'flipfit' }); var offset = inst.tpDiv.offset(); $.fgtimepicker._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 = $.fgtimepicker._checkOffset(inst, offset, isFixed); inst.tpDiv.css({ position: ($.fgtimepicker._inDialog && $.blockUI ? 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none', left: offset.left + 'px', top: offset.top + 'px' }); if (!inst.inline) { var showAnim = $.fgtimepicker._get(inst, 'showAnim'); var duration = $.fgtimepicker._get(inst, 'duration'); var postProcess = function () { $.fgtimepicker._timepickerShowing = true; var borders = $.fgtimepicker._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 $.fgtimepicker._adjustZIndex(input); //inst.tpDiv.css('zIndex', $.fgtimepicker._getZIndex(input) +1); if ($.effects && $.effects[showAnim]) { inst.tpDiv.show(showAnim, $.fgtimepicker._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(); } $.fgtimepicker._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 = $.fgtimepicker._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') .off() .on("click", {fromDoubleClick: false}, $.proxy($.fgtimepicker.selectMinutes, this)) .on("dblclick", {fromDoubleClick: true}, $.proxy($.fgtimepicker.selectMinutes, this)) .end() .find('.ui-timepicker-hour-cell') .off() .on("click", {fromDoubleClick: false}, $.proxy($.fgtimepicker.selectHours, this)) .on("dblclick", {fromDoubleClick: true}, $.proxy($.fgtimepicker.selectHours, this)) .end() .find('.ui-timepicker td a') .off() .on('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'); }) .on('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').on("click", function (e) { $.fgtimepicker.selectNow(e); }).end() .find('.ui-timepicker-deselect').on("click", function (e) { $.fgtimepicker.deselectTime(e); }).end() .find('.ui-timepicker-close').on("click", function (e) { $.fgtimepicker._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 += '
'; var btnClasses = 'ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only'; var btnSpan = ''; 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') .on("click", { fromDoubleClick:false }, $.proxy($.fgtimepicker.selectMinutes, this)) .on("dblclick", { fromDoubleClick:true }, $.proxy($.fgtimepicker.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) .off('focus.timepicker', this._showTimepicker) .off('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 (!$.fgtimepicker._curInst) { return; } var $target = $(event.target); if ($target[0].id != $.fgtimepicker._mainDivId && $target.parents('#' + $.fgtimepicker._mainDivId).length == 0 && !$target.hasClass($.fgtimepicker.markerClassName) && !$target.hasClass($.fgtimepicker._triggerClass) && $.fgtimepicker._timepickerShowing && !($.fgtimepicker._inDialog && $.blockUI)) $.fgtimepicker._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 () { $.fgtimepicker._tidyDialog(inst); this._curInst = null; }; if ($.effects && $.effects[showAnim]) { inst.tpDiv.hide(showAnim, $.fgtimepicker._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).off('.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; } } $.fgtimepicker._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({}, $.fgtimepicker._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 ($.fgtimepicker._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 || !isNaN(parseInt(maxTime.minute)) || !isNaN(parseInt(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)) { $.fgtimepicker._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 ($.fgtimepicker._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)) { $.fgtimepicker._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.fgtimepicker = function (options) { /* Initialise the time picker. */ if (!$.fgtimepicker.initialized) { $(document).on('mousedown.timepicker', $.fgtimepicker._checkExternalClick); $.fgtimepicker.initialized = true; } /* Append timepicker main container to body if not exist. */ if ($("#" + $.fgtimepicker._mainDivId).length === 0) { $('body').append($.fgtimepicker.tpDiv); } var otherArgs = Array.prototype.slice.call(arguments, 1); if (typeof options == 'string' && (options == 'getTime' || options == 'getTimeAsDate' || options == 'getHour' || options == 'getMinute')) return $.fgtimepicker['_' + options + 'Timepicker'].apply($.fgtimepicker, [this[0]].concat(otherArgs)); if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string') return $.fgtimepicker['_' + options + 'Timepicker'].apply($.fgtimepicker, [this[0]].concat(otherArgs)); return this.each(function () { typeof options == 'string' ? $.fgtimepicker['_' + options + 'Timepicker'].apply($.fgtimepicker, [this].concat(otherArgs)) : $.fgtimepicker._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; }; $.fgtimepicker = new FGTimepicker(); // singleton instance $.fgtimepicker.initialized = false; $.fgtimepicker.uuid = new Date().getTime(); $.fgtimepicker.version = "0.3.3"; // Workaround for #4055 // Add another global to avoid noConflict issues with inline event handlers window['TP_jQuery_' + tpuuid] = $; })(jQuery);




© 2015 - 2024 Weber Informatics LLC | Privacy Policy