PageSourceSearch

https://my.0-1.ir/includes/jscript/wickedpicker.js

js 0-1.ir collected 2026-10-07 17:39:15 UTC 24,002 bytes, 624 lines download raw bytes

1/**
2 * wickedpicker v0.4.1 - A simple jQuery timepicker.
3 * Copyright (c) 2015-2016 Eric Gagnon - http://github.com/wickedRidge/wickedpicker
4 * License: MIT
5 */
6
7(function ($, window, document) {
8
9    "use strict";
10
11    if (typeof String.prototype.endsWith != 'function') {
12        /*
13         * Checks if this string end ends with another string
14         *
15         * @param {string} the string to be checked
16         *
17         * @return {bool}
18         */
19        String.prototype.endsWith = function (string) {
20            return string.length > 0 && this.substring(this.length - string.length, this.length) === string;
21        }
22    }
23
24    /*
25     * Returns if the user agent is mobile
26     *
27     * @return {bool}
28     */
29    var isMobile = function () {
30        return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
31    };
32
33    var today = new Date();
34
35    var pluginName = "wickedpicker",
36        defaults = {
37            now: today.getHours() + ':' + today.getMinutes(),
38            twentyFour: false,
39            upArrow: 'wickedpicker__controls__control-up',
40            downArrow: 'wickedpicker__controls__control-down',
41            close: 'wickedpicker__close',
42            hoverState: 'hover-state',
43            title: 'Timepicker',
44            showSeconds: false,
45            timeSeparator: ' : ',
46            secondsInterval: 1,
47            minutesInterval: 1,
48            beforeShow: null,
49            afterShow: null,
50            show: null,
51            clearable: false,
52            closeOnClickOutside: true,
53            onClickOutside: function() {},
54        };
55
56    /*
57     * @param {object} The input object the timepicker is attached to.
58     * @param {object} The object containing options
59     */
60    function Wickedpicker(element, options) {
61        this.element = $(element);
62        this.options = $.extend({}, defaults, options);
63
64        this.element.addClass('hasWickedpicker');
65        this.element.attr('onkeypress', 'return false;');
66        this.element.attr('aria-showingpicker', 'false');
67        this.createPicker();
68        this.timepicker = $('.wickedpicker');
69        this.up = $('.' + this.options.upArrow.split(/\s+/).join('.'));
70        this.down = $('.' + this.options.downArrow.split(/\s+/).join('.'));
71        this.separator = $('.wickedpicker__controls__control--separator');
72        this.hoursElem = $('.wickedpicker__controls__control--hours');
73        this.minutesElem = $('.wickedpicker__controls__control--minutes');
74        this.secondsElem = $('.wickedpicker__controls__control--seconds');
75        this.meridiemElem = $('.wickedpicker__controls__control--meridiem');
76        this.close = $('.' + this.options.close.split(/\s+/).join('.'));
77
78        //Create a new Date object based on the default or passing in now value
79        var time = this.timeArrayFromString(this.options.now);
80        this.options.now = new Date(today.getFullYear(), today.getMonth(), today.getDate(), time[0], time[1], time[2]);
81        this.selectedHour = this.parseHours(this.options.now.getHours());
82        this.selectedMin = this.parseSecMin(this.options.now.getMinutes());
83        this.selectedSec = this.parseSecMin(this.options.now.getSeconds());
84        this.selectedMeridiem = this.parseMeridiem(this.options.now.getHours());
85        this.setHoverState();
86        this.attach(element);
87        this.setText(element);
88    }
89
90    $.extend(Wickedpicker.prototype, {
91
92        /*
93         * Show given input's timepicker
94         *
95         * @param {object} The input being clicked
96         */
97        showPicker: function (element) {
98            //If there is a beforeShow function, then call it with the input calling the timepicker and the
99            // timepicker itself
100            if (typeof this.options.beforeShow === 'function') {
101                this.options.beforeShow(element, this.timepicker);
102            }
103            var timepickerPos = $(element).offset();
104
105            $(element).attr({'aria-showingpicker': 'true', 'tabindex': -1});
106            this.setText(element);
107            this.showHideMeridiemControl();
108            if (this.getText(element) !== this.getTime()) {
109
110                // Check meridiem 
111                var text = this.getText(element);
112                var re = /\s[ap]m$/i;
113                var meridiem = re.test(text) ? text.substr(-2, 2) : null;
114                var inputTime = text.replace(re, '').split(this.options.timeSeparator);
115                var newTime = {};
116                newTime.hours = inputTime[0];
117                newTime.minutes = inputTime[1];
118                newTime.meridiem = meridiem;
119                if (this.options.showSeconds) {
120                    newTime.seconds = inputTime[2];
121                }
122                this.setTime(newTime);
123            }
124            this.timepicker.css({
125                'z-index': this.element.css('z-index') + 1,
126                position: 'absolute',
127                left: timepickerPos.left,
128                top: timepickerPos.top + $(element)[0].offsetHeight
129            }).show();
130            //If there is a show function, then call it with the input calling the timepicker and the
131            // timepicker itself
132            if (typeof this.options.show === 'function') {
133                this.options.show(element, this.timepicker);
134            }
135
136            this.handleTimeAdjustments(element);
137        },
138
139        /*
140         * Hides the timepicker that is currently shown if it is not part of the timepicker
141         *
142         * @param {Object} The DOM object being clicked on the page
143         * 
144         * BeinnLora: added trigger function to call on closing/hiding timepicker. 
145         */
146        hideTimepicker: function (element) {
147            this.timepicker.hide();
148            if (typeof this.options.afterShow === 'function') {
149                this.options.afterShow(element, this.timepicker);
150            }
151            var pickerHidden = {
152                start: function () {
153                    var setShowPickerFalse = $.Deferred();
154                    $('[aria-showingpicker="true"]').attr('aria-showingpicker', 'false');
155                    return setShowPickerFalse.promise();
156                }
157            };
158
159            function setTabIndex(index) {
160                setTimeout(function () {
161                    $('[aria-showingpicker="false"]').attr('tabindex', index);
162                }, 400);
163            }
164
165            pickerHidden.start().then(setTabIndex(0));
166        },
167
168        /*
169         * Create a new timepicker. A single timepicker per page
170         */
171        createPicker: function () {
172            if ($('.wickedpicker').length === 0) {
173                var picker = '<div class="wickedpicker"><p class="wickedpicker__title">' + this.options.title + '<span class="wickedpicker__close"></span></p><ul class="wickedpicker__controls"><li class="wickedpicker__controls__control"><span class="' + this.options.upArrow + '"></span><span class="wickedpicker__controls__control--hours" tabindex="-1">00</span><span class="' + this.options.downArrow + '"></span></li><li class="wickedpicker__controls__control--separator"><span class="wickedpicker__controls__control--separator-inner">:</span></li><li class="wickedpicker__controls__control"><span class="' + this.options.upArrow + '"></span><span class="wickedpicker__controls__control--minutes" tabindex="-1">00</span><span class="' + this.options.downArrow + '"></span></li>';
174                if (this.options.showSeconds) {
175                    picker += '<li class="wickedpicker__controls__control--separator"><span class="wickedpicker__controls__control--separator-inner">:</span></li><li class="wickedpicker__controls__control"><span class="' + this.options.upArrow + '"></span><span class="wickedpicker__controls__control--seconds" tabindex="-1">00</span><span class="' + this.options.downArrow + '"></span> </li>';
176                }
177                picker += '<li class="wickedpicker__controls__control"><span class="' + this.options.upArrow + '"></span><span class="wickedpicker__controls__control--meridiem" tabindex="-1">AM</span><span class="' + this.options.downArrow + '"></span></li></ul></div>';
178                $('body').append(picker);
179                this.attachKeyboardEvents();
180            }
181        },
182
183        /*
184         * Hides the meridiem control if this timepicker is a 24 hour clock
185         */
186        showHideMeridiemControl: function () {
187            if (this.options.twentyFour === false) {
188                $(this.meridiemElem).parent().show();
189            }
190            else {
191                $(this.meridiemElem).parent().hide();
192            }
193        },
194
195        /*
196         * Hides the seconds control if this timepicker has showSeconds set to true
197         */
198        showHideSecondsControl: function () {
199            if (this.options.showSeconds) {
200                $(this.secondsElem).parent().show();
201            }
202            else {
203                $(this.secondsElem).parent().hide();
204            }
205        },
206
207        /*
208         * Bind the click events to the input
209         *
210         * @param {object} The input element
211         */
212        attach: function (element) {
213            var self = this;
214
215            if (this.options.clearable) {
216                self.makePickerInputClearable(element);
217            }
218
219            $(element).attr('tabindex', 0);
220            $(element).on('click focus', function (event) {
221                //Prevent multiple firings
222                if ($(self.timepicker).is(':hidden')) {
223                  self.showPicker($(this));
224                  window.lastTimePickerControl = $(this); //Put the reference on this timepicker into global scope for unsing that in afterShow function
225                  $(self.hoursElem).focus();
226                }
227            });
228
229
230            //Handle click events for closing Wickedpicker
231            var clickHandler = function (event) { //TODO: Fix double firing
232                //Only fire the hide event when you have to
233                if ($(self.timepicker).is(':visible')) {
234                    //Clicking the X
235                    if ($(event.target).is(self.close)) {
236                      self.hideTimepicker(window.lastTimePickerControl);
237                    } else if ($(event.target).closest(self.timepicker).length || $(event.target).closest($('.hasWickedpicker')).length) { //Clicking the Wickedpicker or one of it's input
237s
238                      event.stopPropagation();
239                    } else {   //Everything else
240                      if (typeof self.options.onClickOutside === 'function') {
241                        self.options.onClickOutside();
242                      }
243                      else {
244                        console.warn("Type of onClickOutside must be a function");
245                      }
246
247                      if (!self.options.closeOnClickOutside) {
248                        return;
249                      }
250                      self.hideTimepicker(window.lastTimePickerControl);
251                    }
252                    window.lastTimePickerControl = null;
253                }
254            };
255            $(document).off('click', clickHandler).on('click', clickHandler);
256        },
257
258        /**
259         * Added keyboard functionality to improve usabil
260         */
261        attachKeyboardEvents: function () {
262            $(document).on('keydown', $.proxy(function (event) {
263                switch (event.keyCode) {
264                    case 9:
265                        if (event.target.className !== 'hasWickedpicker') {
266                            $(this.close).trigger('click');
267                        }
268                        break;
269                    case 27:
270                        $(this.close).trigger('click');
271                        break;
272                    case 37: //Left arrow
273                        if (event.target.className !== this.hoursElem[0].className) {
274                            $(event.target).parent().prevAll('li').not(this.separator.selector).first().children()[1].focus();
275                        } else {
276                            $(event.target).parent().siblings(':last').children()[1].focus();
277                        }
278                        break;
279                    case 39: //Right arrow
280                        if (event.target.className !== this.meridiemElem[0].className) {
281                            $(event.target).parent().nextAll('li').not(this.separator.selector).first().children()[1].focus();
282                        } else {
283                            $(event.target).parent().siblings(':first').children()[1].focus();
284                        }
285                        break;
286                    case 38: //Up arrow
287                        $(':focus').prev().trigger('click');
288                        break;
289                    case 40: //Down arrow
290                        $(':focus').next().trigger('click');
291                        break;
292                    default:
293                        break;
294                }
295            }, this));
296        },
297
298        /*
299         * Set the time on the timepicker
300         *
301         * @param {object} The date being set
302         */
303        setTime: function (time) {
304            this.setHours(time.hours);
305            this.setMinutes(time.minutes);
306            this.setMeridiem(time.meridiem);
307            if (this.options.showSeconds) {
308                this.setSeconds(time.seconds);
309            }
310        },
311
312        /*
313         * Get the time from the timepicker
314         */
315        getTime: function () {
316            return [this.formatTime(this.getHours(), this.getMinutes(), this.getMeridiem(), this.getSeconds())];
317        },
318
319        /*
320         * Set the timpicker's hour(s) value
321         *
322         * @param {string} hours
323         */
324        setHours: function (hours) {
325            var hour = new Date();
326            hour.setHours(hours);
327            var hoursText = this.parseHours(hour.getHours());
328            this.hoursElem.text(hoursText);
329            this.selectedHour = hoursText;
330        },
331
332        /*
333         * Get the hour(s) value from the timepicker
334         *
335         * @return {integer}
336         */
337        getHours: function () {
338            var hours = new Date();
339            hours.setHours(this.hoursElem.text());
340            return hours.getHours();
341        },
342
343        /*
344         * Returns the correct hour value based on the type of clock, 12 or 24 hour
345         *
346         * @param {integer} The hours value before parsing
347         *
348         * @return {string|integer}
349         */
350        parseHours: function (hours) {
351            return (this.options.twentyFour === false) ? ((hours + 11) % 12) + 1 : (hours < 10) ? '0' + hours : hours;
352        },
353
354        /*
355         * Sets the timpicker's minutes value
356         *
357         * @param {string} minutes
358         */
359        setMinutes: function (minutes) {
360            var minute = new Date();
361            minute.setMinutes(minutes);
362            var minutesText = minute.getMinutes();
363            var min = this.parseSecMin(minutesText);
364            this.minutesElem.text(min);
365            this.selectedMin = min;
366        },
367
368        /*
369         * Get the minutes value from the timepicker
370         *
371         * @return {integer}
372         */
373        getMinutes: function () {
374            var minutes = new Date();
375            minutes.setMinutes(this.minutesElem.text());
376            return minutes.getMinutes();
377        },
378
379
380        /*
381         * Return a human-readable minutes/seconds value
382         *
383         * @param {string} value seconds or minutes
384         *
385         * @return {string|integer}
386         */
387        parseSecMin: function (value) {
388            return ((value < 10) ? '0' : '') + value;
389        },
390
391        /*
392         * Set the timepicker's meridiem value, AM or PM
393         *
394         * @param {string} The new meridiem
395         */
396        setMeridiem: function (inputMeridiem) {
397            var newMeridiem = '';
398            if (inputMeridiem === undefined) {
399                var meridiem = this.getMeridiem();
400                newMeridiem = (meridiem === 'PM') ? 'AM' : 'PM';
401            } else {
402                newMeridiem = inputMeridiem;
403            }
404            this.meridiemElem.text(newMeridiem);
405            this.selectedMeridiem = newMeridiem;
406        },
407
408        /*
409         * Get the timepicker's meridiem value, AM or PM
410         *
411         * @return {string}
412         */
413        getMeridiem: function () {
414            return this.meridiemElem.text();
415        },
416
417        /*
418         * Set the timepicker's seconds value
419         *
420         * @param {string} seconds
421         */
422        setSeconds: function (seconds) {
423            var second = new Date();
424            second.setSeconds(seconds);
425            var secondsText = second.getSeconds();
426            var sec = this.parseSecMin(secondsText);
427            this.secondsElem.text(sec);
428            this.selectedSec = sec;
429        },
430
431        /*
432         * Get the timepicker's seconds value
433         *
434         * return {string}
435         */
436        getSeconds: function () {
437            var seconds = new Date();
438            seconds.setSeconds(this.secondsElem.text());
439            return seconds.getSeconds();
440        },
441
442        /*
443         * Get the correct meridiem based on the hours given
444         *
445         * @param {string|integer} hours
446         *
447         * @return {string}
448         */
449        parseMeridiem: function (hours) {
450            return (hours > 11) ? 'PM' : 'AM';
451        },
452
453        /*
454         * Handles time incrementing and decrementing and passes
455         * the operator, '+' or '-', the input to be set after the change
456         * and the current arrow clicked, to decipher if hours, ninutes, or meridiem.
457         *
458         * @param {object} The input element
459         */
460        handleTimeAdjustments: function (element) {
461            var timeOut = 0;
462            //Click and click and hold timepicker incrementer and decrementer
463            $(this.up).add(this.down).off('mousedown click touchstart').on('mousedown click', {
464                'Wickedpicker': this,
465                'input': element
466            }, function (event) {
467                if(event.which!=1) return false;
468                var operator = (this.className.indexOf('up') > -1) ? '+' : '-';
469                var passedData = event.data;
470                if (event.type == 'mousedown') {
471                    timeOut = setInterval($.proxy(function (args) {
472                        args.Wickedpicker.changeValue(operator, args.input, this);
473                    }, this, {'Wickedpicker': passedData.Wickedpicker, 'input': passedData.input}), 200);
474                } else {
475                    passedData.Wickedpicker.changeValue(operator, passedData.input, this);
476                }
477            }).bind('mouseup touchend', function () {
478                clearInterval(timeOut);
479            });
480        },
481
482        /*
483         * Change the timepicker's time base on what is clicked
484         *
485         * @param {string} The + or - operator
486         * @param {object} The timepicker's associated input to be set post change
487         * @param {object} The DOM arrow object clicked, determines if it is hours,
488         * minutes, or meridiem base on the operator and its siblings
489         */
490        changeValue: function (operator, input, clicked) {
491            var target = (operator === '+') ? clicked.nextSibling : clicked.previousSibling;
492            var targetClass = $(target).attr('class');
493            if (targetClass.endsWith('hours')) {
494                this.setHours(eval(this.getHours() + operator + 1));
495            } else if (targetClass.endsWith('minutes')) {
496                this.setMinutes(eval(this.getMinutes() + operator + this.options.minutesInterval));
497            } else if (targetClass.endsWith('seconds')) {
498                this.setSeconds(eval(this.getSeconds() + operator + this.options.secondsInterval));
499            } else {
500                this.setMeridiem();
501            }
502            this.setText(input);
503        },
504
505
506        /*
507         * Sets the give input's text to the current timepicker's time
508         *
509         * @param {object} The input element
510         */
511        setText: function (input) {
512            $(input).val(this.formatTime(this.selectedHour, this.selectedMin, this.selectedMeridiem, this.selectedSec)).change();
513        },
514
515        /*
516         * Get the given input's value
517         *
518         * @param {object} The input element
519         *
520         * @return {string}
521         */
522        getText: function (input) {
523            return $(input).val();
524        },
525
526        /*
527         * Returns the correct time format as a string
528         *
529         * @param {string} hour
530         * @param {string} minutes
531         * @param {string} meridiem
532         *
533         * @return {string}
534         */
535        formatTime: function (hour, min, meridiem, seconds) {
536            var formattedTime = hour + this.options.timeSeparator + min;
537            if (this.options.showSeconds) {
538                formattedTime += this.options.timeSeparator  + seconds;
539            }
540            if (this.options.twentyFour === false) {
541                formattedTime += ' ' + meridiem;
542            }
543            return formattedTime;
544        },
545
546        /**
547         *  Apply the hover class to the arrows and close icon fonts
548         */
549        setHoverState: function () {
550            var self = this;
551            if (!isMobile()) {
552                $(this.up).add(this.down).add(this.close).hover(function () {
553                    $(this).toggleClass(self.options.hoverState);
554                });
555            }
556        },
557
558        /**
559         * Wrapping the given input field with the clearable container
560         * , add a span that will contain the x, and bind the clear
561         * input event to the span
562         *
563         * @param input
564         */
565        makePickerInputClearable: function(input) {
566            $(input).wrap('<div class="clearable-picker"></div>').after('<span data-clear-picker>&times;</span>');
567
568            //When the x is clicked, clear its sibling input field
569            $('[data-clear-picker]').on('click', function(event) {
570               $(this).siblings('.hasWickedpicker').val('');
571            });
572        },
573
574        /**
575         * Convert the options time string format
576         * to an array
577         *
578         * returns => [hours, minutes, seconds]
579         *
580         * @param stringTime
581         * @returns {*}
582         */
583        timeArrayFromString: function (stringTime) {
584            if (stringTime.length) {
585                var time = stringTime.split(':');
586                time[2] = (time.length < 3) ? '00' : time[2];
587                return time;
588            }
589            return false;
590        },
591
592        //public functions
593        /*
594         * Returns the requested input element's value
595         */
596        _time: function () {
597            var inputValue = $(this.element).val();
598            return (inputValue === '') ? this.formatTime(this.selectedHour, this.selectedMin, this.selectedMeridiem, this.selectedSec) : inputValue;
599        },
600        _hide: function() {
601            this.hideTimepicker(this.element);
602        }
603    });
604
605    //optional index if multiple inputs share the same class
606    $.fn[pluginName] = function (options, index) {
607        if (!$.isFunction(Wickedpicker.prototype['_' + options])) {
608            return this.each(function () {
609                if (!$.data(this, "plugin_" + pluginName)) {
610                    $.data(this, "plugin_" + pluginName, new Wickedpicker(this, options));
611                }
612            });
613        }
614        else if ($(this).hasClass('hasWickedpicker')) {
615            if (index !== undefined) {
616                return $.data($(this)[index], 'plugin_' + pluginName)['_' + options]();
617            }
618            else {
619                return $.data($(this)[0], 'plugin_' + pluginName)['_' + options]();
620            }
621        }
622    };
623
624})(jQuery, window, document);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.