timepicker 1.14.1 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,603 @@
1
+ import Timepicker from "./timepicker/index.js";
2
+ import renderHtml from "./timepicker/render.js";
3
+ import { DEFAULT_SETTINGS } from "./timepicker/defaults.js";
4
+ import { EVENT_DEFAULTS } from "./timepicker/constants.js";
5
+
6
+ (function (factory) {
7
+ if (
8
+ typeof exports === "object" &&
9
+ exports &&
10
+ typeof module === "object" &&
11
+ module &&
12
+ module.exports === exports
13
+ ) {
14
+ // Browserify. Attach to jQuery module.
15
+ factory(require("jquery"));
16
+ } else if (typeof define === "function" && define.amd) {
17
+ // AMD. Register as an anonymous module.
18
+ define(["jquery"], factory);
19
+ } else {
20
+ // Browser globals
21
+ factory(jQuery);
22
+ }
23
+ })(function ($) {
24
+ var _lang = {};
25
+
26
+ var methods = {
27
+ init: function (options) {
28
+ return this.each(function () {
29
+ var self = $(this);
30
+
31
+ const tp = new Timepicker(this, options);
32
+ const settings = tp.settings;
33
+ _lang = settings.lang;
34
+
35
+ this.timepickerObj = tp;
36
+ self.addClass("ui-timepicker-input");
37
+
38
+ if (settings.useSelect) {
39
+ _render(self);
40
+ } else {
41
+ self.prop("autocomplete", "off");
42
+ if (settings.showOn) {
43
+ for (var i in settings.showOn) {
44
+ self.on(settings.showOn[i] + ".timepicker", methods.show);
45
+ }
46
+ }
47
+ self.on("change.timepicker", tp._handleFormatValue);
48
+ self.on("keydown.timepicker", _keydownhandler);
49
+ self.on("keyup.timepicker", tp._handleKeyUp);
50
+ if (settings.disableTextInput) {
51
+ self.on("keydown.timepicker", tp._disableTextInputHandler);
52
+ }
53
+ self.on("cut.timepicker", tp._handleKeyUp);
54
+ self.on("paste.timepicker", tp._handleKeyUp);
55
+
56
+ tp._formatValue(null, "initial");
57
+ }
58
+ });
59
+ },
60
+
61
+ show: function (e) {
62
+ var self = $(this);
63
+ var tp = self[0].timepickerObj;
64
+ var settings = tp.settings;
65
+
66
+ if (e) {
67
+ e.preventDefault();
68
+ }
69
+
70
+ if (settings.useSelect) {
71
+ tp.list.trigger("focus");
72
+ return;
73
+ }
74
+
75
+ if (tp._hideKeyboard()) {
76
+ // block the keyboard on mobile devices
77
+ self.trigger("blur");
78
+ }
79
+
80
+ var list = tp.list;
81
+
82
+ // check if input is readonly
83
+ if (self.prop("readonly")) {
84
+ return;
85
+ }
86
+
87
+ // check if list needs to be rendered
88
+ _render(self);
89
+ list = tp.list;
90
+
91
+ if (Timepicker.isVisible(list)) {
92
+ return;
93
+ }
94
+
95
+ if (self.is("input")) {
96
+ tp.selectedValue = self.val();
97
+ }
98
+
99
+ tp._setSelected();
100
+
101
+ // make sure other pickers are hidden
102
+ Timepicker.hideAll();
103
+
104
+ if (typeof settings.listWidth == "number") {
105
+ list.width(self.outerWidth() * settings.listWidth);
106
+ }
107
+
108
+ // position the dropdown relative to the input
109
+ list.show();
110
+ var listOffset = {};
111
+
112
+ if (settings.orientation.match(/r/)) {
113
+ // right-align the dropdown
114
+ listOffset.left =
115
+ self.offset().left +
116
+ self.outerWidth() -
117
+ list.outerWidth() +
118
+ parseInt(list.css("marginLeft").replace("px", ""), 10);
119
+ } else if (settings.orientation.match(/l/)) {
120
+ // left-align the dropdown
121
+ listOffset.left =
122
+ self.offset().left +
123
+ parseInt(list.css("marginLeft").replace("px", ""), 10);
124
+ } else if (settings.orientation.match(/c/)) {
125
+ // center-align the dropdown
126
+ listOffset.left =
127
+ self.offset().left +
128
+ (self.outerWidth() - list.outerWidth()) / 2 +
129
+ parseInt(list.css("marginLeft").replace("px", ""), 10);
130
+ }
131
+
132
+ var verticalOrientation;
133
+ if (settings.orientation.match(/t/)) {
134
+ verticalOrientation = "t";
135
+ } else if (settings.orientation.match(/b/)) {
136
+ verticalOrientation = "b";
137
+ } else if (
138
+ self.offset().top + self.outerHeight(true) + list.outerHeight() >
139
+ $(window).height() + $(window).scrollTop()
140
+ ) {
141
+ verticalOrientation = "t";
142
+ } else {
143
+ verticalOrientation = "b";
144
+ }
145
+
146
+ if (verticalOrientation == "t") {
147
+ // position the dropdown on top
148
+ list.addClass("ui-timepicker-positioned-top");
149
+ listOffset.top =
150
+ self.offset().top -
151
+ list.outerHeight() +
152
+ parseInt(list.css("marginTop").replace("px", ""), 10);
153
+ } else {
154
+ // put it under the input
155
+ list.removeClass("ui-timepicker-positioned-top");
156
+ listOffset.top =
157
+ self.offset().top +
158
+ self.outerHeight() +
159
+ parseInt(list.css("marginTop").replace("px", ""), 10);
160
+ }
161
+
162
+ list.offset(listOffset);
163
+
164
+ // position scrolling
165
+ var selected = list.find(".ui-timepicker-selected");
166
+
167
+ if (!selected.length) {
168
+ var timeInt = tp.anytime2int(tp._getTimeValue());
169
+ if (timeInt !== null) {
170
+ selected = $(tp._findRow(timeInt));
171
+ } else if (settings.scrollDefault()) {
172
+ selected = $(tp._findRow(settings.scrollDefault()));
173
+ }
174
+ }
175
+
176
+ // if not found or disabled, intelligently find first selectable element
177
+ if (!selected.length || selected.hasClass("ui-timepicker-disabled")) {
178
+ selected = list.find("li:not(.ui-timepicker-disabled):first");
179
+ }
180
+
181
+ if (selected && selected.length) {
182
+ var topOffset =
183
+ list.scrollTop() + selected.position().top - selected.outerHeight();
184
+ list.scrollTop(topOffset);
185
+ } else {
186
+ list.scrollTop(0);
187
+ }
188
+
189
+ // prevent scroll propagation
190
+ if (settings.stopScrollPropagation) {
191
+ $(document).on(
192
+ "wheel.ui-timepicker",
193
+ ".ui-timepicker-wrapper",
194
+ function (e) {
195
+ e.preventDefault();
196
+ var currentScroll = $(this).scrollTop();
197
+ $(this).scrollTop(currentScroll + e.originalEvent.deltaY);
198
+ }
199
+ );
200
+ }
201
+
202
+ // attach close handlers
203
+ $(document).on("mousedown.ui-timepicker", _closeHandler);
204
+ window.addEventListener("resize", _closeHandler);
205
+ if (settings.closeOnScroll) {
206
+ $(settings.closeOnScroll).on("scroll.ui-timepicker", _closeHandler);
207
+ }
208
+
209
+ self.trigger("showTimepicker");
210
+
211
+ return this;
212
+ },
213
+
214
+ hide: function (e) {
215
+ var tp = this[0].timepickerObj;
216
+
217
+ if (tp) {
218
+ tp.hideMe();
219
+ }
220
+
221
+ Timepicker.hideAll();
222
+ return this;
223
+ },
224
+
225
+ option: function (key, value) {
226
+ if (typeof key == "string" && typeof value == "undefined") {
227
+ var tp = this[0].timepickerObj;
228
+ return tp.settings[key];
229
+ }
230
+
231
+ return this.each(function () {
232
+ var self = $(this);
233
+ var tp = self[0].timepickerObj;
234
+ var settings = tp.settings;
235
+ var list = tp.list;
236
+
237
+ if (typeof key == "object") {
238
+ settings = $.extend(settings, key);
239
+ } else if (typeof key == "string") {
240
+ settings[key] = value;
241
+ }
242
+
243
+ settings = tp.parseSettings(settings);
244
+ tp.settings = settings;
245
+
246
+ tp._formatValue({ type: "change" }, "initial");
247
+
248
+ if (list) {
249
+ list.remove();
250
+ tp.list = null;
251
+ }
252
+
253
+ if (settings.useSelect) {
254
+ _render(self);
255
+ }
256
+ });
257
+ },
258
+
259
+ getSecondsFromMidnight: function () {
260
+ var tp = this[0].timepickerObj;
261
+ return tp.anytime2int(tp._getTimeValue());
262
+ },
263
+
264
+ getTime: function (relative_date) {
265
+ var tp = this[0].timepickerObj;
266
+
267
+ var time_string = tp._getTimeValue();
268
+ if (!time_string) {
269
+ return null;
270
+ }
271
+
272
+ var offset = tp.anytime2int(time_string);
273
+ if (offset === null) {
274
+ return null;
275
+ }
276
+
277
+ if (!relative_date) {
278
+ relative_date = new Date();
279
+ }
280
+
281
+ // construct a Date from relative date, and offset's time
282
+ var time = new Date(relative_date);
283
+ time.setHours(offset / 3600);
284
+ time.setMinutes((offset % 3600) / 60);
285
+ time.setSeconds(offset % 60);
286
+ time.setMilliseconds(0);
287
+
288
+ return time;
289
+ },
290
+
291
+ isVisible: function () {
292
+ var tp = this[0].timepickerObj;
293
+ return !!(tp && tp.list && Timepicker.isVisible(tp.list));
294
+ },
295
+
296
+ setTime: function (value) {
297
+ var tp = this[0].timepickerObj;
298
+ var settings = tp.settings;
299
+ var seconds = tp.anytime2int(value);
300
+
301
+ if (tp._isTimeRangeError(seconds, settings)) {
302
+ const timeRangeErrorEvent = new CustomEvent(
303
+ "timeRangeError",
304
+ EVENT_DEFAULTS
305
+ );
306
+ tp.targetEl.dispatchEvent(timeRangeErrorEvent);
307
+ }
308
+
309
+ if (settings.forceRoundTime) {
310
+ var prettyTime = tp._roundAndFormatTime(seconds);
311
+ } else {
312
+ var prettyTime = tp._int2time(seconds);
313
+ }
314
+
315
+ if (value && prettyTime === null && settings.noneOption) {
316
+ prettyTime = value;
317
+ }
318
+
319
+ tp._setTimeValue(prettyTime, "initial");
320
+ tp._formatValue({ type: "change" }, "initial");
321
+
322
+ if (tp && tp.list) {
323
+ tp._setSelected();
324
+ }
325
+
326
+ return this;
327
+ },
328
+
329
+ remove: function () {
330
+ var self = this;
331
+
332
+ // check if this element is a timepicker
333
+ if (!self.hasClass("ui-timepicker-input")) {
334
+ return;
335
+ }
336
+
337
+ var tp = self[0].timepickerObj;
338
+ var settings = tp.settings;
339
+
340
+ self.removeAttr("autocomplete", "off");
341
+ self.removeClass("ui-timepicker-input");
342
+ self.removeData("timepicker-obj");
343
+ self.off(".timepicker");
344
+
345
+ // timepicker-list won't be present unless the user has interacted with this timepicker
346
+ if (tp.list) {
347
+ tp.list.remove();
348
+ }
349
+
350
+ if (settings.useSelect) {
351
+ self.show();
352
+ }
353
+
354
+ if (tp.requiredMoved) {
355
+ self.prop("required", true);
356
+ }
357
+
358
+ tp.list = null;
359
+
360
+ return this;
361
+ }
362
+ };
363
+
364
+ // private methods
365
+
366
+ function _render(self) {
367
+ var tp = self[0].timepickerObj;
368
+ var list = tp.list;
369
+ var settings = tp.settings;
370
+
371
+ if (list && list.length) {
372
+ list.remove();
373
+ tp.list = null;
374
+ }
375
+
376
+ const wrapped_list = $(renderHtml(tp));
377
+ if (settings.useSelect) {
378
+ list = wrapped_list;
379
+ } else {
380
+ list = wrapped_list.children("ul");
381
+ }
382
+
383
+ wrapped_list.data("timepicker-input", self);
384
+ tp.list = wrapped_list;
385
+
386
+ if (settings.useSelect) {
387
+ if (self.val()) {
388
+ list.val(
389
+ settings.roundingFunction(tp.anytime2int(self.val()), settings)
390
+ );
391
+ } else {
392
+ // don't let the browser default to the first time; this selects a
393
+ // noneOption with an empty value, or nothing if there isn't one
394
+ list.val("");
395
+ }
396
+
397
+ list.on("focus", function () {
398
+ $(this).data("timepicker-input").trigger("showTimepicker");
399
+ });
400
+ list.on("blur", function () {
401
+ $(this).data("timepicker-input").trigger("hideTimepicker");
402
+ });
403
+ // time options hold seconds; noneOption values pass through as-is
404
+ const selectedTime = function () {
405
+ const value = list.val();
406
+ const seconds = parseInt(value);
407
+ return isNaN(seconds) ? value : tp._int2time(seconds);
408
+ };
409
+
410
+ list.on("change", function () {
411
+ tp._setTimeValue(selectedTime(), "select");
412
+ });
413
+
414
+ // the input gets hidden, and a hidden required field blocks
415
+ // submission without showing an error, so the select takes it over
416
+ if (self.prop("required")) {
417
+ tp.requiredMoved = true;
418
+ self.prop("required", false);
419
+ }
420
+ list.prop("required", !!tp.requiredMoved);
421
+
422
+ // a value that isn't in the list leaves the select blank; keep the
423
+ // input's value instead of overwriting it with nothing
424
+ const initialTime = list.val() === null ? self.val() : selectedTime();
425
+ tp._setTimeValue(initialTime, "initial");
426
+ self.hide().after(list);
427
+ } else {
428
+ var appendTo = settings.appendTo;
429
+ if (typeof appendTo === "string") {
430
+ appendTo = $(appendTo);
431
+ } else if (typeof appendTo === "function") {
432
+ appendTo = appendTo(self);
433
+ }
434
+ appendTo.append(wrapped_list);
435
+ tp._setSelected();
436
+
437
+ list.on("mousedown click", "li", function (e) {
438
+ // hack: temporarily disable the focus handler
439
+ // to deal with the fact that IE fires 'focus'
440
+ // events asynchronously
441
+ self.off("focus.timepicker");
442
+ self.on("focus.timepicker-ie-hack", function () {
443
+ self.off("focus.timepicker-ie-hack");
444
+ self.on("focus.timepicker", methods.show);
445
+ });
446
+
447
+ if (!tp._hideKeyboard()) {
448
+ self[0].focus();
449
+ }
450
+
451
+ // make sure only the clicked row is selected
452
+ list.find("li").removeClass("ui-timepicker-selected");
453
+ $(this).addClass("ui-timepicker-selected");
454
+
455
+ if (tp._selectValue()) {
456
+ self.trigger("hideTimepicker");
457
+
458
+ list.on("mouseup.timepicker click.timepicker", "li", function (e) {
459
+ list.off("mouseup.timepicker click.timepicker");
460
+ wrapped_list.hide();
461
+ });
462
+ }
463
+ });
464
+ }
465
+ }
466
+
467
+ // event handler to decide whether to close timepicker
468
+ function _closeHandler(e) {
469
+ if (e.type == "focus" && e.target == window) {
470
+ // mobile Chrome fires focus events against window for some reason
471
+ return;
472
+ }
473
+
474
+ var target = $(e.target);
475
+
476
+ if (
477
+ target.closest(".ui-timepicker-input").length ||
478
+ target.closest(".ui-timepicker-wrapper").length
479
+ ) {
480
+ // active timepicker was focused. ignore
481
+ return;
482
+ }
483
+
484
+ Timepicker.hideAll();
485
+ $(document).off(".ui-timepicker");
486
+ $(window).off(".ui-timepicker");
487
+ }
488
+
489
+ /*
490
+ * Keyboard navigation via arrow keys
491
+ */
492
+ function _keydownhandler(e) {
493
+ var self = $(this);
494
+ var tp = self[0].timepickerObj;
495
+ var list = tp.list;
496
+
497
+ if (!list || !Timepicker.isVisible(list)) {
498
+ if (e.keyCode == 40) {
499
+ // show the list!
500
+ methods.show.call(self.get(0));
501
+ list = tp.list;
502
+ if (!tp._hideKeyboard()) {
503
+ self.trigger("focus");
504
+ }
505
+ } else {
506
+ return true;
507
+ }
508
+ }
509
+
510
+ switch (e.keyCode) {
511
+ case 13: // return
512
+ if (tp._selectValue()) {
513
+ tp._formatValue({ type: "change" });
514
+ tp.hideMe();
515
+ }
516
+
517
+ e.preventDefault();
518
+ return false;
519
+
520
+ case 38: // up
521
+ var selected = list.find(".ui-timepicker-selected");
522
+
523
+ if (!selected.length) {
524
+ list.find("li").each(function (i, obj) {
525
+ if ($(obj).position().top > 0) {
526
+ selected = $(obj);
527
+ return false;
528
+ }
529
+ });
530
+ selected.addClass("ui-timepicker-selected");
531
+ } else if (!selected.is(":first-child")) {
532
+ selected.removeClass("ui-timepicker-selected");
533
+ selected.prev().addClass("ui-timepicker-selected");
534
+
535
+ if (selected.prev().position().top < selected.outerHeight()) {
536
+ list.scrollTop(list.scrollTop() - selected.outerHeight());
537
+ }
538
+ }
539
+
540
+ return false;
541
+
542
+ case 40: // down
543
+ selected = list.find(".ui-timepicker-selected");
544
+
545
+ if (selected.length === 0) {
546
+ list.find("li").each(function (i, obj) {
547
+ if ($(obj).position().top > 0) {
548
+ selected = $(obj);
549
+ return false;
550
+ }
551
+ });
552
+
553
+ selected.addClass("ui-timepicker-selected");
554
+ } else if (!selected.is(":last-child")) {
555
+ selected.removeClass("ui-timepicker-selected");
556
+ selected.next().addClass("ui-timepicker-selected");
557
+
558
+ if (
559
+ selected.next().position().top + 2 * selected.outerHeight() >
560
+ list.outerHeight()
561
+ ) {
562
+ list.scrollTop(list.scrollTop() + selected.outerHeight());
563
+ }
564
+ }
565
+
566
+ return false;
567
+
568
+ case 27: // escape
569
+ list.find("li").removeClass("ui-timepicker-selected");
570
+ tp.hideMe();
571
+ break;
572
+
573
+ case 9: //tab
574
+ tp.hideMe();
575
+ break;
576
+
577
+ default:
578
+ return true;
579
+ }
580
+ }
581
+
582
+ // Plugin entry
583
+ $.fn.timepicker = function (method) {
584
+ if (!this.length) return this;
585
+ if (methods[method]) {
586
+ // check if this element is a timepicker
587
+ if (!this.hasClass("ui-timepicker-input")) {
588
+ return this;
589
+ }
590
+ return methods[method].apply(
591
+ this,
592
+ Array.prototype.slice.call(arguments, 1)
593
+ );
594
+ } else if (typeof method === "object" || !method) {
595
+ return methods.init.apply(this, arguments);
596
+ } else {
597
+ $.error("Method " + method + " does not exist on jQuery.timepicker");
598
+ }
599
+ };
600
+
601
+ // Default plugin options.
602
+ $.fn.timepicker.defaults = DEFAULT_SETTINGS;
603
+ });