kmaterialize 2.0.0 → 2.3.3-1.0.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.
- package/LICENSE +21 -21
- package/README.md +55 -91
- package/components/appbar/_navbar.old.scss +223 -0
- package/components/appbar/appbar.css +235 -0
- package/components/appbar/appbar.mjs +54 -0
- package/components/appbar/appbar.test.mjs +9 -0
- package/components/atomic/atomic.mjs +19 -0
- package/components/atomic/component.mjs +67 -0
- package/components/badge/_badges.scss +75 -0
- package/components/badge/badge.mjs +11 -0
- package/components/breadcrumb/_breadcrumb.scss +27 -0
- package/components/button/_buttons.scss +352 -0
- package/components/button/button.mjs +11 -0
- package/components/button/buttons.stories.ts +150 -0
- package/components/button/buttons.ts +282 -0
- package/components/button/examples.iso.js +18 -0
- package/components/button/fabSpec.js +65 -0
- package/components/button/test-button.mjs +16 -0
- package/components/card/_cards.scss +229 -0
- package/components/card/card.mjs +10 -0
- package/components/card/cards.ts +185 -0
- package/components/card/cardsSpec.js +269 -0
- package/components/carousel/_carousel.scss +93 -0
- package/components/carousel/_slider.scss +119 -0
- package/components/carousel/carousel.ts +693 -0
- package/components/carousel/carouselSpec.js +61 -0
- package/components/carousel/slider.ts +431 -0
- package/components/carousel/sliderSpec.js +99 -0
- package/components/checkbox/_checkboxes.scss +281 -0
- package/components/checkbox/checkbox.mdx +24 -0
- package/components/checkbox/checkbox.stories.ts +120 -0
- package/components/chip/chip.mjs +37 -0
- package/components/chip/chip.test.mjs +10 -0
- package/components/chip/chips.css +126 -0
- package/components/chip/chips.mdx +33 -0
- package/components/chip/chips.ts +440 -0
- package/components/chip/chipsSpec.js +165 -0
- package/components/chip/readme.md +323 -0
- package/components/collapsible/_collapsible.scss +82 -0
- package/components/collapsible/collapsible.ts +230 -0
- package/components/collapsible/collapsibleSpec.js +240 -0
- package/components/datepicker/_datepicker.scss +268 -0
- package/components/datepicker/datepicker.ts +1450 -0
- package/components/datepicker/datepickerSpec.js +162 -0
- package/components/dialog/_materialbox.scss +42 -0
- package/components/dialog/_modal.scss +79 -0
- package/components/dialog/materialbox.ts +446 -0
- package/components/dialog/materialboxSpec.js +37 -0
- package/components/dialog/modal.ts +111 -0
- package/components/dialog/modalSpec.js +83 -0
- package/components/dialog/readme.md +5 -0
- package/components/divider/readme.md +15 -0
- package/components/dropdown/_dropdown.scss +83 -0
- package/components/dropdown/dropdown.ts +653 -0
- package/components/dropdown/dropdownSpec.js +108 -0
- package/components/list/_collection.scss +114 -0
- package/components/list/_list.scss +6 -0
- package/components/list/list.mjs +58 -0
- package/components/list/list.test.mjs +16 -0
- package/components/loading/loading.mjs +26 -0
- package/components/loading/loading.test.mjs +10 -0
- package/components/navigation-bar/_old +582 -0
- package/components/navigation-bar/navigation-bar.mdx +20 -0
- package/components/navigation-bar/navigation-bar.stories.ts +39 -0
- package/components/navigation-drawer/_sidenav.scss +247 -0
- package/components/navigation-drawer/sidenav.ts +546 -0
- package/components/navigation-drawer/sidenavSpec.js +124 -0
- package/components/pagination/_pagination.scss +47 -0
- package/components/progress/_preloader.scss +416 -0
- package/components/radio-button/_radio-buttons.scss +112 -0
- package/components/radio-button/radio-buttons.mdx +28 -0
- package/components/radio-button/radio-buttons.stories.ts +51 -0
- package/components/search/autocomplete.ts +620 -0
- package/components/search/autocompleteSpec.js +321 -0
- package/components/slider/_range.scss +157 -0
- package/components/slider/range.ts +216 -0
- package/components/snackbar/_toast.scss +68 -0
- package/components/snackbar/toastSpec.js +132 -0
- package/components/snackbar/toasts.ts +312 -0
- package/components/switch/_switches.scss +121 -0
- package/components/tabs/_tabs.scss +171 -0
- package/components/tabs/tabs.mjs +31 -0
- package/components/tabs/tabs.ts +358 -0
- package/components/tabs/tabsSpec.js +180 -0
- package/components/textfield/_file-input.scss +41 -0
- package/components/textfield/_input-fields.scss +368 -0
- package/components/textfield/_select.scss +104 -0
- package/components/textfield/formfields.css +311 -0
- package/components/textfield/forms.ts +182 -0
- package/components/textfield/formsSpec.js +142 -0
- package/components/textfield/select.ts +472 -0
- package/components/textfield/selectSpec.js +390 -0
- package/components/textfield/textfield.mjs +29 -0
- package/components/textfield/textfield.test.mjs +10 -0
- package/components/timepicker/_timepicker.scss +362 -0
- package/components/timepicker/timepicker.ts +905 -0
- package/components/tooltip/_tooltip.scss +40 -0
- package/components/tooltip/tooltip.ts +380 -0
- package/components/tooltip/tooltipSpec.js +145 -0
- package/dist/css/materialize.colors.min.css +6 -0
- package/dist/css/materialize.css +7578 -6326
- package/dist/css/materialize.min.css +6 -13
- package/dist/css/materialize.min.css.map +1 -0
- package/dist/js/materialize.cjs.js +8410 -0
- package/dist/js/materialize.d.ts +2625 -0
- package/dist/js/materialize.js +8415 -12374
- package/dist/js/materialize.min.js +6 -6
- package/dist/js/materialize.mjs +8382 -0
- package/package.json +82 -47
- package/sass/_colors.scss +417 -0
- package/sass/_global.scss +490 -0
- package/sass/_grid.scss +172 -0
- package/sass/_table_of_contents.scss +28 -0
- package/sass/_tapTarget.scss +102 -0
- package/sass/_typography.scss +58 -0
- package/sass/_variables.scss +56 -0
- package/sass/materialize.scss +51 -0
- package/sass/mixins.module.scss +168 -0
- package/extras/noUiSlider/nouislider.css +0 -406
- package/extras/noUiSlider/nouislider.js +0 -2147
- package/extras/noUiSlider/nouislider.min.js +0 -1
- package/js/anime.min.js +0 -34
- package/js/autocomplete.js +0 -448
- package/js/buttons.js +0 -354
- package/js/cards.js +0 -40
- package/js/carousel.js +0 -717
- package/js/cash.js +0 -960
- package/js/characterCounter.js +0 -136
- package/js/chips.js +0 -481
- package/js/collapsible.js +0 -275
- package/js/component.js +0 -44
- package/js/datepicker.js +0 -975
- package/js/dropdown.js +0 -635
- package/js/forms.js +0 -275
- package/js/global.js +0 -444
- package/js/materialbox.js +0 -453
- package/js/modal.js +0 -382
- package/js/parallax.js +0 -138
- package/js/pushpin.js +0 -148
- package/js/range.js +0 -263
- package/js/scrollspy.js +0 -295
- package/js/select.js +0 -450
- package/js/sidenav.js +0 -580
- package/js/slider.js +0 -359
- package/js/tabs.js +0 -402
- package/js/tapTarget.js +0 -314
- package/js/timepicker.js +0 -647
- package/js/toasts.js +0 -310
- package/js/tooltip.js +0 -303
- package/js/waves.js +0 -335
|
@@ -0,0 +1,905 @@
|
|
|
1
|
+
import { Utils } from '../../src/utils';
|
|
2
|
+
import { Component, BaseOptions, InitElements, MElement, I18nOptions } from '../../src/component';
|
|
3
|
+
import { DockedDisplayPlugin } from '../../src/dockedDisplayPlugin';
|
|
4
|
+
import { ModalDisplayPlugin } from '../../src/modalDisplayPlugin';
|
|
5
|
+
|
|
6
|
+
export type Views = 'hours' | 'minutes';
|
|
7
|
+
|
|
8
|
+
export interface TimepickerOptions extends BaseOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Dial radius.
|
|
11
|
+
* @default 135
|
|
12
|
+
*/
|
|
13
|
+
dialRadius: number;
|
|
14
|
+
/**
|
|
15
|
+
* Outer radius.
|
|
16
|
+
* @default 105
|
|
17
|
+
*/
|
|
18
|
+
outerRadius: number;
|
|
19
|
+
/**
|
|
20
|
+
* Inner radius.
|
|
21
|
+
* @default 70
|
|
22
|
+
*/
|
|
23
|
+
innerRadius: number;
|
|
24
|
+
/**
|
|
25
|
+
* Tick radius.
|
|
26
|
+
* @default 20
|
|
27
|
+
*/
|
|
28
|
+
tickRadius: number;
|
|
29
|
+
/**
|
|
30
|
+
* Duration of the transition from/to the hours/minutes view.
|
|
31
|
+
* @default 350
|
|
32
|
+
*/
|
|
33
|
+
duration: number;
|
|
34
|
+
/**
|
|
35
|
+
* Specify a DOM element OR selector for a DOM element to render
|
|
36
|
+
* the time picker in, by default it will be placed before the input.
|
|
37
|
+
* @default null
|
|
38
|
+
*/
|
|
39
|
+
container: HTMLElement | string | null;
|
|
40
|
+
/**
|
|
41
|
+
* Show the clear button in the Timepicker.
|
|
42
|
+
* @default false
|
|
43
|
+
*/
|
|
44
|
+
showClearBtn: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Autosubmit timepicker selection to input field
|
|
47
|
+
* @default true
|
|
48
|
+
*/
|
|
49
|
+
// @todo this is only working on analog clock, should apply to hour/minute input fields and am/pm selector as well
|
|
50
|
+
autoSubmit: true;
|
|
51
|
+
/**
|
|
52
|
+
* Default time to set on the timepicker 'now' or '13:14'.
|
|
53
|
+
* @default 'now';
|
|
54
|
+
*/
|
|
55
|
+
defaultTime: string;
|
|
56
|
+
/**
|
|
57
|
+
* Millisecond offset from the defaultTime.
|
|
58
|
+
* @default 0
|
|
59
|
+
*/
|
|
60
|
+
fromNow: number;
|
|
61
|
+
/**
|
|
62
|
+
* Internationalization options.
|
|
63
|
+
*/
|
|
64
|
+
i18n: Partial<I18nOptions>;
|
|
65
|
+
/**
|
|
66
|
+
* Use 12 hour AM/PM clock instead of 24 hour clock.
|
|
67
|
+
* @default true
|
|
68
|
+
*/
|
|
69
|
+
twelveHour: boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Vibrate device when dragging clock hand.
|
|
72
|
+
* @default true
|
|
73
|
+
*/
|
|
74
|
+
vibrate: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Callback function when a time is selected.
|
|
77
|
+
* @default null
|
|
78
|
+
*/
|
|
79
|
+
onSelect: (hour: number, minute: number) => void;
|
|
80
|
+
/**
|
|
81
|
+
* Callback function for interaction with input field.
|
|
82
|
+
* @default null
|
|
83
|
+
*/
|
|
84
|
+
onInputInteraction: (() => void) | null;
|
|
85
|
+
/**
|
|
86
|
+
* Callback function for done.
|
|
87
|
+
* @default null
|
|
88
|
+
*/
|
|
89
|
+
onDone: (() => void) | null;
|
|
90
|
+
/**
|
|
91
|
+
* Callback function for cancel.
|
|
92
|
+
* @default null
|
|
93
|
+
*/
|
|
94
|
+
onCancel: (() => void) | null;
|
|
95
|
+
/**
|
|
96
|
+
* Display plugin
|
|
97
|
+
*/
|
|
98
|
+
displayPlugin: string;
|
|
99
|
+
/**
|
|
100
|
+
* Configurable display plugin options
|
|
101
|
+
*/
|
|
102
|
+
displayPluginOptions: object;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const _defaults: TimepickerOptions = {
|
|
106
|
+
dialRadius: 135,
|
|
107
|
+
outerRadius: 105,
|
|
108
|
+
innerRadius: 70,
|
|
109
|
+
tickRadius: 20,
|
|
110
|
+
duration: 350,
|
|
111
|
+
container: null,
|
|
112
|
+
defaultTime: 'now', // default time, 'now' or '13:14' e.g.
|
|
113
|
+
fromNow: 0, // Millisecond offset from the defaultTime
|
|
114
|
+
showClearBtn: false,
|
|
115
|
+
autoSubmit: true,
|
|
116
|
+
// internationalization
|
|
117
|
+
i18n: {
|
|
118
|
+
cancel: 'Cancel',
|
|
119
|
+
clear: 'Clear',
|
|
120
|
+
done: 'Ok'
|
|
121
|
+
},
|
|
122
|
+
twelveHour: true, // change to 12 hour AM/PM clock from 24 hour
|
|
123
|
+
vibrate: true, // vibrate the device when dragging clock hand
|
|
124
|
+
// Callbacks
|
|
125
|
+
onSelect: null,
|
|
126
|
+
onInputInteraction: null,
|
|
127
|
+
onDone: null,
|
|
128
|
+
onCancel: null,
|
|
129
|
+
displayPlugin: null,
|
|
130
|
+
displayPluginOptions: null
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
type Point = {
|
|
134
|
+
x: number;
|
|
135
|
+
y: number;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export class Timepicker extends Component<TimepickerOptions> {
|
|
139
|
+
declare el: HTMLInputElement;
|
|
140
|
+
id: string;
|
|
141
|
+
containerEl: HTMLElement;
|
|
142
|
+
plate: HTMLElement;
|
|
143
|
+
digitalClock: HTMLElement;
|
|
144
|
+
inputHours: HTMLInputElement;
|
|
145
|
+
inputMinutes: HTMLInputElement;
|
|
146
|
+
x0: number;
|
|
147
|
+
y0: number;
|
|
148
|
+
moved: boolean;
|
|
149
|
+
dx: number;
|
|
150
|
+
dy: number;
|
|
151
|
+
/**
|
|
152
|
+
* Current view on the timepicker.
|
|
153
|
+
* @default 'hours'
|
|
154
|
+
*/
|
|
155
|
+
currentView: Views;
|
|
156
|
+
hand: SVGElement;
|
|
157
|
+
minutesView: HTMLElement;
|
|
158
|
+
hours: number;
|
|
159
|
+
minutes: number;
|
|
160
|
+
/** The selected time. */
|
|
161
|
+
time: string;
|
|
162
|
+
/**
|
|
163
|
+
* If the time is AM or PM on twelve-hour clock.
|
|
164
|
+
* @default 'PM'
|
|
165
|
+
*/
|
|
166
|
+
amOrPm: 'AM' | 'PM';
|
|
167
|
+
static _template;
|
|
168
|
+
/** Vibrate device when dragging clock hand. */
|
|
169
|
+
vibrate: 'vibrate' | 'webkitVibrate' | null;
|
|
170
|
+
_canvas: HTMLElement;
|
|
171
|
+
hoursView: HTMLElement;
|
|
172
|
+
spanAmPm: HTMLSpanElement;
|
|
173
|
+
footer: HTMLElement;
|
|
174
|
+
private _amBtn: HTMLElement;
|
|
175
|
+
private _pmBtn: HTMLElement;
|
|
176
|
+
bg: Element;
|
|
177
|
+
bearing: Element;
|
|
178
|
+
g: Element;
|
|
179
|
+
toggleViewTimer: string | number | NodeJS.Timeout;
|
|
180
|
+
vibrateTimer: NodeJS.Timeout | number;
|
|
181
|
+
private displayPlugin: DockedDisplayPlugin | ModalDisplayPlugin;
|
|
182
|
+
|
|
183
|
+
constructor(el: HTMLInputElement, options: Partial<TimepickerOptions>) {
|
|
184
|
+
super(el, options, Timepicker);
|
|
185
|
+
this.el['M_Timepicker'] = this;
|
|
186
|
+
this.options = {
|
|
187
|
+
...Timepicker.defaults,
|
|
188
|
+
...options
|
|
189
|
+
};
|
|
190
|
+
this.id = Utils.guid();
|
|
191
|
+
this._insertHTMLIntoDOM();
|
|
192
|
+
this._setupVariables();
|
|
193
|
+
this._setupEventHandlers();
|
|
194
|
+
this._clockSetup();
|
|
195
|
+
if (this.options.displayPlugin) this._setupDisplayPlugin();
|
|
196
|
+
this._pickerSetup();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
static get defaults(): TimepickerOptions {
|
|
200
|
+
return _defaults;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Initializes instance of Timepicker.
|
|
205
|
+
* @param el HTML element.
|
|
206
|
+
* @param options Component options.
|
|
207
|
+
*/
|
|
208
|
+
static init(el: HTMLInputElement, options?: Partial<TimepickerOptions>): Timepicker;
|
|
209
|
+
/**
|
|
210
|
+
* Initializes instances of Timepicker.
|
|
211
|
+
* @param els HTML elements.
|
|
212
|
+
* @param options Component options.
|
|
213
|
+
*/
|
|
214
|
+
static init(
|
|
215
|
+
els: InitElements<HTMLInputElement | MElement>,
|
|
216
|
+
options?: Partial<TimepickerOptions>
|
|
217
|
+
): Timepicker[];
|
|
218
|
+
/**
|
|
219
|
+
* Initializes instances of Timepicker.
|
|
220
|
+
* @param els HTML elements.
|
|
221
|
+
* @param options Component options.
|
|
222
|
+
*/
|
|
223
|
+
static init(
|
|
224
|
+
els: HTMLInputElement | InitElements<HTMLInputElement | MElement>,
|
|
225
|
+
options: Partial<TimepickerOptions> = {}
|
|
226
|
+
): Timepicker | Timepicker[] {
|
|
227
|
+
return super.init(els, options, Timepicker);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
static _addLeadingZero(num: number) {
|
|
231
|
+
return (num < 10 ? '0' : '') + num;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
static _createSVGEl(name: string) {
|
|
235
|
+
const svgNS = 'http://www.w3.org/2000/svg';
|
|
236
|
+
return document.createElementNS(svgNS, name);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
static _Pos(e: TouchEvent | MouseEvent): Point {
|
|
240
|
+
if (e.type.startsWith('touch') && (e as TouchEvent).targetTouches.length >= 1) {
|
|
241
|
+
return {
|
|
242
|
+
x: (e as TouchEvent).targetTouches[0].clientX,
|
|
243
|
+
y: (e as TouchEvent).targetTouches[0].clientY
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
// mouse event
|
|
247
|
+
return { x: (e as MouseEvent).clientX, y: (e as MouseEvent).clientY };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
static getInstance(el: HTMLElement): Timepicker {
|
|
251
|
+
return el['M_Timepicker'];
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
destroy() {
|
|
255
|
+
this._removeEventHandlers();
|
|
256
|
+
this.containerEl.remove();
|
|
257
|
+
this.el['M_Timepicker'] = undefined;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
_setupEventHandlers() {
|
|
261
|
+
this.el.addEventListener('click', this._handleInputClick);
|
|
262
|
+
// @todo allow input field to fill values from input field when container/modal opens
|
|
263
|
+
this.el.addEventListener('keydown', this._handleInputKeydown);
|
|
264
|
+
this.plate.addEventListener('mousedown', this._handleClockClickStart);
|
|
265
|
+
this.plate.addEventListener('touchstart', this._handleClockClickStart);
|
|
266
|
+
this.digitalClock.addEventListener('keyup', this._inputFromTextField);
|
|
267
|
+
this.inputHours.addEventListener('focus', () => this.showView('hours'));
|
|
268
|
+
this.inputHours.addEventListener('focusout', () => this.formatHours());
|
|
269
|
+
this.inputMinutes.addEventListener('focus', () => this.showView('minutes'));
|
|
270
|
+
this.inputMinutes.addEventListener('focusout', () => this.formatMinutes());
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
_removeEventHandlers() {
|
|
274
|
+
this.el.removeEventListener('click', this._handleInputClick);
|
|
275
|
+
this.el.removeEventListener('keydown', this._handleInputKeydown);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
_handleInputClick = () => {
|
|
279
|
+
this.inputHours.focus();
|
|
280
|
+
if (typeof this.options.onInputInteraction === 'function')
|
|
281
|
+
this.options.onInputInteraction.call(this);
|
|
282
|
+
if (this.displayPlugin) this.displayPlugin.show();
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
_handleInputKeydown = (e: KeyboardEvent) => {
|
|
286
|
+
if (Utils.keys.ENTER.includes(e.key)) {
|
|
287
|
+
e.preventDefault();
|
|
288
|
+
this.inputHours.focus();
|
|
289
|
+
if (typeof this.options.onInputInteraction === 'function')
|
|
290
|
+
this.options.onInputInteraction.call(this);
|
|
291
|
+
if (this.displayPlugin) this.displayPlugin.show();
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
_handleTimeInputEnterKey = (e: KeyboardEvent) => {
|
|
296
|
+
if (Utils.keys.ENTER.includes(e.key)) {
|
|
297
|
+
e.preventDefault();
|
|
298
|
+
this._inputFromTextField();
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
_handleClockClickStart = (e) => {
|
|
303
|
+
e.preventDefault();
|
|
304
|
+
const clockPlateBR = this.plate.getBoundingClientRect();
|
|
305
|
+
const offset = { x: clockPlateBR.left, y: clockPlateBR.top };
|
|
306
|
+
|
|
307
|
+
this.x0 = offset.x + this.options.dialRadius;
|
|
308
|
+
this.y0 = offset.y + this.options.dialRadius;
|
|
309
|
+
this.moved = false;
|
|
310
|
+
const clickPos = Timepicker._Pos(e);
|
|
311
|
+
this.dx = clickPos.x - this.x0;
|
|
312
|
+
this.dy = clickPos.y - this.y0;
|
|
313
|
+
|
|
314
|
+
// Set clock hands
|
|
315
|
+
this.setHand(this.dx, this.dy, false);
|
|
316
|
+
// Mousemove on document
|
|
317
|
+
document.addEventListener('mousemove', this._handleDocumentClickMove);
|
|
318
|
+
document.addEventListener('touchmove', this._handleDocumentClickMove);
|
|
319
|
+
// Mouseup on document
|
|
320
|
+
document.addEventListener('mouseup', this._handleDocumentClickEnd);
|
|
321
|
+
document.addEventListener('touchend', this._handleDocumentClickEnd);
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
_handleDocumentClickMove = (e) => {
|
|
325
|
+
e.preventDefault();
|
|
326
|
+
const clickPos = Timepicker._Pos(e);
|
|
327
|
+
const x = clickPos.x - this.x0;
|
|
328
|
+
const y = clickPos.y - this.y0;
|
|
329
|
+
this.moved = true;
|
|
330
|
+
this.setHand(x, y, false);
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
_handleDocumentClickEnd = (e) => {
|
|
334
|
+
e.preventDefault();
|
|
335
|
+
document.removeEventListener('mouseup', this._handleDocumentClickEnd);
|
|
336
|
+
document.removeEventListener('touchend', this._handleDocumentClickEnd);
|
|
337
|
+
const clickPos = Timepicker._Pos(e);
|
|
338
|
+
const x = clickPos.x - this.x0;
|
|
339
|
+
const y = clickPos.y - this.y0;
|
|
340
|
+
if (this.moved && x === this.dx && y === this.dy) {
|
|
341
|
+
this.setHand(x, y);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (this.currentView === 'hours') {
|
|
345
|
+
this.inputMinutes.focus();
|
|
346
|
+
this.showView('minutes', this.options.duration / 2);
|
|
347
|
+
} else {
|
|
348
|
+
// this.minutesView.classList.add('timepicker-dial-out');
|
|
349
|
+
setTimeout(() => {
|
|
350
|
+
if (this.options.autoSubmit) this.done();
|
|
351
|
+
}, this.options.duration / 2);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (typeof this.options.onSelect === 'function') {
|
|
355
|
+
this.options.onSelect.call(this, this.hours, this.minutes);
|
|
356
|
+
}
|
|
357
|
+
// Unbind mousemove event
|
|
358
|
+
document.removeEventListener('mousemove', this._handleDocumentClickMove);
|
|
359
|
+
document.removeEventListener('touchmove', this._handleDocumentClickMove);
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
_insertHTMLIntoDOM() {
|
|
363
|
+
const template = document.createElement('template');
|
|
364
|
+
template.innerHTML = Timepicker._template.trim();
|
|
365
|
+
|
|
366
|
+
this.containerEl = <HTMLElement>template.content.firstChild;
|
|
367
|
+
this.containerEl.id = 'container-' + this.id;
|
|
368
|
+
|
|
369
|
+
// Append popover to input by default
|
|
370
|
+
const optEl = this.options.container;
|
|
371
|
+
const containerEl = optEl instanceof HTMLElement ? optEl : document.querySelector(optEl);
|
|
372
|
+
|
|
373
|
+
if (this.options.container && !!containerEl) {
|
|
374
|
+
containerEl.append(this.containerEl);
|
|
375
|
+
} else {
|
|
376
|
+
this.el.parentElement.appendChild(this.containerEl);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
_setupVariables() {
|
|
381
|
+
this.currentView = 'hours';
|
|
382
|
+
this.vibrate = navigator.vibrate
|
|
383
|
+
? 'vibrate'
|
|
384
|
+
: navigator['webkitVibrate']
|
|
385
|
+
? 'webkitVibrate'
|
|
386
|
+
: null;
|
|
387
|
+
this._canvas = this.containerEl.querySelector('.timepicker-canvas');
|
|
388
|
+
this.plate = this.containerEl.querySelector('.timepicker-plate');
|
|
389
|
+
this.digitalClock = this.containerEl.querySelector('.timepicker-display-column');
|
|
390
|
+
this.hoursView = this.containerEl.querySelector('.timepicker-hours');
|
|
391
|
+
this.minutesView = this.containerEl.querySelector('.timepicker-minutes');
|
|
392
|
+
this.inputHours = this.containerEl.querySelector('.timepicker-input-hours');
|
|
393
|
+
this.inputMinutes = this.containerEl.querySelector('.timepicker-input-minutes');
|
|
394
|
+
this.spanAmPm = this.containerEl.querySelector('.timepicker-span-am-pm');
|
|
395
|
+
this.footer = this.containerEl.querySelector('.timepicker-footer');
|
|
396
|
+
this.amOrPm = 'PM';
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/*private _createButton(text: string, visibility: string): HTMLButtonElement {
|
|
400
|
+
const button = document.createElement('button');
|
|
401
|
+
button.classList.add('btn', 'waves-effect', 'text');
|
|
402
|
+
button.style.visibility = visibility;
|
|
403
|
+
button.type = 'button';
|
|
404
|
+
button.tabIndex = -1;
|
|
405
|
+
button.innerText = text;
|
|
406
|
+
return button;
|
|
407
|
+
}*/
|
|
408
|
+
|
|
409
|
+
_pickerSetup() {
|
|
410
|
+
// clearButton.classList.add('timepicker-clear');
|
|
411
|
+
// clearButton.addEventListener('click', this.clear);
|
|
412
|
+
// this.footer.appendChild(clearButton);
|
|
413
|
+
if (this.options.showClearBtn) {
|
|
414
|
+
Utils.createButton(
|
|
415
|
+
this.footer,
|
|
416
|
+
this.options.i18n.clear,
|
|
417
|
+
['timepicker-clear'],
|
|
418
|
+
true,
|
|
419
|
+
this.clear
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (!this.options.autoSubmit) {
|
|
424
|
+
/*const confirmationBtnsContainer = document.createElement('div');
|
|
425
|
+
confirmationBtnsContainer.classList.add('confirmation-btns');
|
|
426
|
+
this.footer.append(confirmationBtnsContainer);
|
|
427
|
+
|
|
428
|
+
const cancelButton = this._createButton(this.options.i18n.cancel, '');
|
|
429
|
+
cancelButton.classList.add('timepicker-close');
|
|
430
|
+
cancelButton.addEventListener('click', this.close);
|
|
431
|
+
confirmationBtnsContainer.appendChild(cancelButton);
|
|
432
|
+
|
|
433
|
+
const doneButton = this._createButton(this.options.i18n.done, '');
|
|
434
|
+
doneButton.classList.add('timepicker-close');
|
|
435
|
+
//doneButton.addEventListener('click', this._finishSelection);
|
|
436
|
+
confirmationBtnsContainer.appendChild(doneButton);*/
|
|
437
|
+
Utils.createConfirmationContainer(
|
|
438
|
+
this.footer,
|
|
439
|
+
this.options.i18n.done,
|
|
440
|
+
this.options.i18n.cancel,
|
|
441
|
+
this.confirm,
|
|
442
|
+
this.cancel
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
this._updateTimeFromInput();
|
|
447
|
+
this.showView('hours');
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
private _setupDisplayPlugin() {
|
|
451
|
+
if (this.options.displayPlugin === 'docked')
|
|
452
|
+
this.displayPlugin = DockedDisplayPlugin.init(
|
|
453
|
+
this.el,
|
|
454
|
+
this.containerEl,
|
|
455
|
+
this.options.displayPluginOptions
|
|
456
|
+
);
|
|
457
|
+
if (this.options.displayPlugin === 'modal') {
|
|
458
|
+
this.displayPlugin = ModalDisplayPlugin.init(this.el, this.containerEl, {
|
|
459
|
+
...this.options.displayPluginOptions,
|
|
460
|
+
...{ classList: ['timepicker-modal'] }
|
|
461
|
+
});
|
|
462
|
+
this.footer.remove();
|
|
463
|
+
this.footer = this.displayPlugin.footer;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
_clockSetup() {
|
|
468
|
+
if (this.options.twelveHour) {
|
|
469
|
+
// AM Button
|
|
470
|
+
this._amBtn = document.createElement('div');
|
|
471
|
+
this._amBtn.classList.add('am-btn', 'btn');
|
|
472
|
+
this._amBtn.innerText = 'AM';
|
|
473
|
+
this._amBtn.tabIndex = 0;
|
|
474
|
+
this._amBtn.addEventListener('click', this._handleAmPmClick);
|
|
475
|
+
this._amBtn.addEventListener('keypress', this._handleAmPmKeypress);
|
|
476
|
+
this.spanAmPm.appendChild(this._amBtn);
|
|
477
|
+
// PM Button
|
|
478
|
+
this._pmBtn = document.createElement('div');
|
|
479
|
+
this._pmBtn.classList.add('pm-btn', 'btn');
|
|
480
|
+
this._pmBtn.innerText = 'PM';
|
|
481
|
+
this._pmBtn.tabIndex = 0;
|
|
482
|
+
this._pmBtn.addEventListener('click', this._handleAmPmClick);
|
|
483
|
+
this._pmBtn.addEventListener('keypress', this._handleAmPmKeypress);
|
|
484
|
+
this.spanAmPm.appendChild(this._pmBtn);
|
|
485
|
+
}
|
|
486
|
+
this._buildHoursView();
|
|
487
|
+
this._buildMinutesView();
|
|
488
|
+
this._buildSVGClock();
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
_buildSVGClock() {
|
|
492
|
+
// Draw clock hands and others
|
|
493
|
+
const dialRadius = this.options.dialRadius;
|
|
494
|
+
const tickRadius = this.options.tickRadius;
|
|
495
|
+
const diameter = dialRadius * 2;
|
|
496
|
+
const svg = Timepicker._createSVGEl('svg');
|
|
497
|
+
svg.setAttribute('class', 'timepicker-svg');
|
|
498
|
+
svg.setAttribute('width', diameter.toString());
|
|
499
|
+
svg.setAttribute('height', diameter.toString());
|
|
500
|
+
const g = Timepicker._createSVGEl('g');
|
|
501
|
+
g.setAttribute('transform', 'translate(' + dialRadius + ',' + dialRadius + ')');
|
|
502
|
+
const bearing = Timepicker._createSVGEl('circle');
|
|
503
|
+
bearing.setAttribute('class', 'timepicker-canvas-bearing');
|
|
504
|
+
bearing.setAttribute('cx', '0');
|
|
505
|
+
bearing.setAttribute('cy', '0');
|
|
506
|
+
bearing.setAttribute('r', '4');
|
|
507
|
+
const hand = Timepicker._createSVGEl('line');
|
|
508
|
+
hand.setAttribute('x1', '0');
|
|
509
|
+
hand.setAttribute('y1', '0');
|
|
510
|
+
const bg = Timepicker._createSVGEl('circle');
|
|
511
|
+
bg.setAttribute('class', 'timepicker-canvas-bg');
|
|
512
|
+
bg.setAttribute('r', tickRadius.toString());
|
|
513
|
+
g.appendChild(hand);
|
|
514
|
+
g.appendChild(bg);
|
|
515
|
+
g.appendChild(bearing);
|
|
516
|
+
svg.appendChild(g);
|
|
517
|
+
this._canvas.appendChild(svg);
|
|
518
|
+
this.hand = hand;
|
|
519
|
+
this.bg = bg;
|
|
520
|
+
this.bearing = bearing;
|
|
521
|
+
this.g = g;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
_buildHoursView() {
|
|
525
|
+
// const $tick = document.createElement('div');
|
|
526
|
+
// $tick.classList.add('timepicker-tick');
|
|
527
|
+
// Hours view
|
|
528
|
+
if (this.options.twelveHour) {
|
|
529
|
+
for (let i = 1; i < 13; i += 1) {
|
|
530
|
+
// const tick = <HTMLElement>$tick.cloneNode(true);
|
|
531
|
+
const radian = (i / 6) * Math.PI;
|
|
532
|
+
const radius = this.options.outerRadius;
|
|
533
|
+
this._buildHoursTick(i, radian, radius);
|
|
534
|
+
}
|
|
535
|
+
} else {
|
|
536
|
+
for (let i = 0; i < 24; i += 1) {
|
|
537
|
+
// const tick = <HTMLElement>$tick.cloneNode(true);
|
|
538
|
+
const radian = (i / 6) * Math.PI;
|
|
539
|
+
const inner = i > 0 && i < 13;
|
|
540
|
+
const radius = inner ? this.options.innerRadius : this.options.outerRadius;
|
|
541
|
+
this._buildHoursTick(i, radian, radius);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
_buildHoursTick(i: number, radian: number, radius: number) {
|
|
547
|
+
const tick = document.createElement('div');
|
|
548
|
+
tick.classList.add('timepicker-tick');
|
|
549
|
+
tick.style.left =
|
|
550
|
+
this.options.dialRadius + Math.sin(radian) * radius - this.options.tickRadius + 'px';
|
|
551
|
+
tick.style.top =
|
|
552
|
+
this.options.dialRadius - Math.cos(radian) * radius - this.options.tickRadius + 'px';
|
|
553
|
+
tick.innerHTML = i === 0 ? '00' : i.toString();
|
|
554
|
+
this.hoursView.appendChild(tick);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
_buildMinutesView() {
|
|
558
|
+
const _tick = document.createElement('div');
|
|
559
|
+
_tick.classList.add('timepicker-tick');
|
|
560
|
+
// Minutes view
|
|
561
|
+
for (let i = 0; i < 60; i += 5) {
|
|
562
|
+
const tick = <HTMLElement>_tick.cloneNode(true);
|
|
563
|
+
const radian = (i / 30) * Math.PI;
|
|
564
|
+
tick.style.left =
|
|
565
|
+
this.options.dialRadius +
|
|
566
|
+
Math.sin(radian) * this.options.outerRadius -
|
|
567
|
+
this.options.tickRadius +
|
|
568
|
+
'px';
|
|
569
|
+
tick.style.top =
|
|
570
|
+
this.options.dialRadius -
|
|
571
|
+
Math.cos(radian) * this.options.outerRadius -
|
|
572
|
+
this.options.tickRadius +
|
|
573
|
+
'px';
|
|
574
|
+
tick.innerHTML = Timepicker._addLeadingZero(i);
|
|
575
|
+
this.minutesView.appendChild(tick);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
_handleAmPmClick = (e: MouseEvent) => {
|
|
580
|
+
this._handleAmPmInteraction(<HTMLElement>e.target);
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
_handleAmPmKeypress = (e: KeyboardEvent) => {
|
|
584
|
+
if (Utils.keys.ENTER.includes(e.key)) {
|
|
585
|
+
this._handleAmPmInteraction(<HTMLElement>e.target);
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
_handleAmPmInteraction = (e: HTMLElement) => {
|
|
590
|
+
this.amOrPm = e.classList.contains('am-btn') ? 'AM' : 'PM';
|
|
591
|
+
this._updateAmPmView();
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
_updateAmPmView() {
|
|
595
|
+
if (this.options.twelveHour) {
|
|
596
|
+
if (this.amOrPm === 'PM') {
|
|
597
|
+
this._amBtn.classList.remove('filled');
|
|
598
|
+
this._pmBtn.classList.add('filled');
|
|
599
|
+
} else if (this.amOrPm === 'AM') {
|
|
600
|
+
this._amBtn.classList.add('filled');
|
|
601
|
+
this._pmBtn.classList.remove('filled');
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
_updateTimeFromInput() {
|
|
607
|
+
// Get the time
|
|
608
|
+
let value = ((this.el.value || this.options.defaultTime || '') + '').split(':');
|
|
609
|
+
if (this.options.twelveHour && !(typeof value[1] === 'undefined')) {
|
|
610
|
+
if (value[1].toUpperCase().indexOf('AM') > 0) {
|
|
611
|
+
this.amOrPm = 'AM';
|
|
612
|
+
} else {
|
|
613
|
+
this.amOrPm = 'PM';
|
|
614
|
+
}
|
|
615
|
+
value[1] = value[1].replace('AM', '').replace('PM', '');
|
|
616
|
+
}
|
|
617
|
+
if (value[0] === 'now') {
|
|
618
|
+
const now = new Date(+new Date() + this.options.fromNow);
|
|
619
|
+
value = [now.getHours().toString(), now.getMinutes().toString()];
|
|
620
|
+
if (this.options.twelveHour) {
|
|
621
|
+
this.amOrPm = parseInt(value[0]) >= 12 && parseInt(value[0]) < 24 ? 'PM' : 'AM';
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
this.hours = +value[0] || 0;
|
|
625
|
+
this.minutes = +value[1] || 0;
|
|
626
|
+
this.inputHours.value = Timepicker._addLeadingZero(this.hours);
|
|
627
|
+
this.inputMinutes.value = Timepicker._addLeadingZero(this.minutes);
|
|
628
|
+
|
|
629
|
+
this._updateAmPmView();
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Show hours or minutes view on timepicker.
|
|
634
|
+
* @param view The name of the view you want to switch to, 'hours' or 'minutes'.
|
|
635
|
+
* @param delay
|
|
636
|
+
*/
|
|
637
|
+
showView = (view: Views, delay: number = null) => {
|
|
638
|
+
if (view === 'minutes' && getComputedStyle(this.hoursView).visibility === 'visible') {
|
|
639
|
+
// raiseCallback(this.options.beforeHourSelect);
|
|
640
|
+
}
|
|
641
|
+
const isHours = view === 'hours',
|
|
642
|
+
nextView = isHours ? this.hoursView : this.minutesView,
|
|
643
|
+
hideView = isHours ? this.minutesView : this.hoursView;
|
|
644
|
+
this.currentView = view;
|
|
645
|
+
|
|
646
|
+
/*if (isHours) {
|
|
647
|
+
this.inputHours.classList.add('text-primary');
|
|
648
|
+
this.inputMinutes.classList.remove('text-primary');
|
|
649
|
+
} else {
|
|
650
|
+
this.inputHours.classList.remove('text-primary');
|
|
651
|
+
this.inputMinutes.classList.add('text-primary');
|
|
652
|
+
}*/
|
|
653
|
+
|
|
654
|
+
// Transition view
|
|
655
|
+
hideView.classList.add('timepicker-dial-out');
|
|
656
|
+
|
|
657
|
+
nextView.style.visibility = 'visible';
|
|
658
|
+
nextView.classList.remove('timepicker-dial-out');
|
|
659
|
+
|
|
660
|
+
// Reset clock hand
|
|
661
|
+
this.resetClock(delay);
|
|
662
|
+
// After transitions ended
|
|
663
|
+
clearTimeout(this.toggleViewTimer);
|
|
664
|
+
this.toggleViewTimer = setTimeout(() => {
|
|
665
|
+
hideView.style.visibility = 'hidden';
|
|
666
|
+
}, this.options.duration);
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
resetClock(delay) {
|
|
670
|
+
const view = this.currentView,
|
|
671
|
+
value = this[view],
|
|
672
|
+
isHours = view === 'hours',
|
|
673
|
+
unit = Math.PI / (isHours ? 6 : 30),
|
|
674
|
+
radian = value * unit,
|
|
675
|
+
radius =
|
|
676
|
+
isHours && value > 0 && value < 13 ? this.options.innerRadius : this.options.outerRadius,
|
|
677
|
+
x = Math.sin(radian) * radius,
|
|
678
|
+
y = -Math.cos(radian) * radius;
|
|
679
|
+
|
|
680
|
+
if (delay) {
|
|
681
|
+
this._canvas?.classList.add('timepicker-canvas-out');
|
|
682
|
+
setTimeout(() => {
|
|
683
|
+
this._canvas?.classList.remove('timepicker-canvas-out');
|
|
684
|
+
this.setHand(x, y);
|
|
685
|
+
}, delay);
|
|
686
|
+
} else {
|
|
687
|
+
this.setHand(x, y);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
_inputFromTextField = () => {
|
|
692
|
+
const isHours = this.currentView === 'hours';
|
|
693
|
+
if (isHours && this.inputHours.value !== '') {
|
|
694
|
+
const value = parseInt(this.inputHours.value);
|
|
695
|
+
if (value > 0 && value < (this.options.twelveHour ? 13 : 24)) {
|
|
696
|
+
this.hours = value;
|
|
697
|
+
} else {
|
|
698
|
+
this.setHoursDefault();
|
|
699
|
+
}
|
|
700
|
+
this.drawClockFromTimeInput(this.hours, isHours);
|
|
701
|
+
} else if (!isHours && this.inputMinutes.value !== '') {
|
|
702
|
+
const value = parseInt(this.inputMinutes.value);
|
|
703
|
+
if (value >= 0 && value < 60) {
|
|
704
|
+
this.minutes = value;
|
|
705
|
+
} else {
|
|
706
|
+
this.minutes = new Date().getMinutes();
|
|
707
|
+
this.inputMinutes.value = this.minutes.toString();
|
|
708
|
+
}
|
|
709
|
+
this.drawClockFromTimeInput(this.minutes, isHours);
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
drawClockFromTimeInput(value, isHours) {
|
|
714
|
+
const unit = Math.PI / (isHours ? 6 : 30);
|
|
715
|
+
const radian = value * unit;
|
|
716
|
+
let radius;
|
|
717
|
+
if (this.options.twelveHour) {
|
|
718
|
+
radius = this.options.outerRadius;
|
|
719
|
+
} else {
|
|
720
|
+
radius =
|
|
721
|
+
isHours && value > 0 && value < 13 ? this.options.innerRadius : this.options.outerRadius;
|
|
722
|
+
}
|
|
723
|
+
this.setClockAttributes(radian, radius);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
setHand(x, y, roundBy5: boolean = false) {
|
|
727
|
+
const isHours = this.currentView === 'hours',
|
|
728
|
+
unit = Math.PI / (isHours || roundBy5 ? 6 : 30),
|
|
729
|
+
z = Math.sqrt(x * x + y * y),
|
|
730
|
+
inner = isHours && z < (this.options.outerRadius + this.options.innerRadius) / 2;
|
|
731
|
+
let radian = Math.atan2(x, -y),
|
|
732
|
+
radius = inner ? this.options.innerRadius : this.options.outerRadius;
|
|
733
|
+
|
|
734
|
+
if (this.options.twelveHour) {
|
|
735
|
+
radius = this.options.outerRadius;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// Radian should in range [0, 2PI]
|
|
739
|
+
if (radian < 0) {
|
|
740
|
+
radian = Math.PI * 2 + radian;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
// Get the round value
|
|
744
|
+
let value = Math.round(radian / unit);
|
|
745
|
+
|
|
746
|
+
// Get the round radian
|
|
747
|
+
radian = value * unit;
|
|
748
|
+
|
|
749
|
+
// Correct the hours or minutes
|
|
750
|
+
if (this.options.twelveHour) {
|
|
751
|
+
if (isHours) {
|
|
752
|
+
if (value === 0) value = 12;
|
|
753
|
+
} else {
|
|
754
|
+
if (roundBy5) value *= 5;
|
|
755
|
+
if (value === 60) value = 0;
|
|
756
|
+
}
|
|
757
|
+
} else {
|
|
758
|
+
if (isHours) {
|
|
759
|
+
if (value === 12) {
|
|
760
|
+
value = 0;
|
|
761
|
+
}
|
|
762
|
+
value = inner ? (value === 0 ? 12 : value) : value === 0 ? 0 : value + 12;
|
|
763
|
+
} else {
|
|
764
|
+
if (roundBy5) {
|
|
765
|
+
value *= 5;
|
|
766
|
+
}
|
|
767
|
+
if (value === 60) {
|
|
768
|
+
value = 0;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// Once hours or minutes changed, vibrate the device
|
|
774
|
+
if (this[this.currentView] !== value) {
|
|
775
|
+
if (this.vibrate && this.options.vibrate) {
|
|
776
|
+
// Do not vibrate too frequently
|
|
777
|
+
if (!this.vibrateTimer) {
|
|
778
|
+
navigator[this.vibrate](10);
|
|
779
|
+
this.vibrateTimer = setTimeout(() => {
|
|
780
|
+
this.vibrateTimer = null;
|
|
781
|
+
}, 100);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
this[this.currentView] = value;
|
|
787
|
+
if (isHours) {
|
|
788
|
+
this.inputHours.value = Timepicker._addLeadingZero(value);
|
|
789
|
+
} else {
|
|
790
|
+
this.inputMinutes.value = Timepicker._addLeadingZero(value);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// Set clock hand and others' position
|
|
794
|
+
this.setClockAttributes(radian, radius);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
setClockAttributes(radian: number, radius: number) {
|
|
798
|
+
const cx1 = Math.sin(radian) * (radius - this.options.tickRadius),
|
|
799
|
+
cy1 = -Math.cos(radian) * (radius - this.options.tickRadius),
|
|
800
|
+
cx2 = Math.sin(radian) * radius,
|
|
801
|
+
cy2 = -Math.cos(radian) * radius;
|
|
802
|
+
this.hand.setAttribute('x2', cx1.toString());
|
|
803
|
+
this.hand.setAttribute('y2', cy1.toString());
|
|
804
|
+
this.bg.setAttribute('cx', cx2.toString());
|
|
805
|
+
this.bg.setAttribute('cy', cy2.toString());
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
formatHours() {
|
|
809
|
+
if (this.inputHours.value == '') this.setHoursDefault();
|
|
810
|
+
this.inputHours.value = Timepicker._addLeadingZero(Number(this.inputHours.value));
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
formatMinutes() {
|
|
814
|
+
if (this.inputMinutes.value == '') this.minutes = new Date().getMinutes();
|
|
815
|
+
this.inputMinutes.value = Timepicker._addLeadingZero(Number(this.inputMinutes.value));
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
setHoursDefault() {
|
|
819
|
+
this.hours = new Date().getHours();
|
|
820
|
+
this.inputHours.value = (this.hours % (this.options.twelveHour ? 12 : 24)).toString();
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
done = (clearValue = null) => {
|
|
824
|
+
// Set input value
|
|
825
|
+
const last = this.el.value;
|
|
826
|
+
let value = clearValue
|
|
827
|
+
? ''
|
|
828
|
+
: Timepicker._addLeadingZero(this.hours) + ':' + Timepicker._addLeadingZero(this.minutes);
|
|
829
|
+
this.time = value;
|
|
830
|
+
if (!clearValue && this.options.twelveHour) {
|
|
831
|
+
value = `${value} ${this.amOrPm}`;
|
|
832
|
+
}
|
|
833
|
+
this.el.value = value;
|
|
834
|
+
// Trigger change event
|
|
835
|
+
if (value !== last) {
|
|
836
|
+
this.el.dispatchEvent(
|
|
837
|
+
new Event('change', { bubbles: true, cancelable: true, composed: true })
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
};
|
|
841
|
+
|
|
842
|
+
confirm = () => {
|
|
843
|
+
this.done();
|
|
844
|
+
if (this.displayPlugin) this.displayPlugin.hide();
|
|
845
|
+
if (typeof this.options.onDone === 'function') this.options.onDone.call(this);
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
cancel = () => {
|
|
849
|
+
// not logical clearing the input field on cancel, since the end user might want to make use of the previously submitted value
|
|
850
|
+
// this.clear();
|
|
851
|
+
if (this.displayPlugin) this.displayPlugin.hide();
|
|
852
|
+
if (typeof this.options.onCancel === 'function') this.options.onCancel.call(this);
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
clear = () => {
|
|
856
|
+
// @todo should clear timepicker hour/minute input elems and reset analog clock, currently clears input el
|
|
857
|
+
this.done(true);
|
|
858
|
+
};
|
|
859
|
+
|
|
860
|
+
// deprecated
|
|
861
|
+
open() {
|
|
862
|
+
console.warn(
|
|
863
|
+
'Timepicker.close() is deprecated. Remove this method and wrap in modal yourself.'
|
|
864
|
+
);
|
|
865
|
+
return this;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
close() {
|
|
869
|
+
console.warn(
|
|
870
|
+
'Timepicker.close() is deprecated. Remove this method and wrap in modal yourself.'
|
|
871
|
+
);
|
|
872
|
+
return this;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
static {
|
|
876
|
+
Timepicker._template = `<div class="timepicker-container">
|
|
877
|
+
<div class="timepicker-digital-display">
|
|
878
|
+
<div class="timepicker-text-container">
|
|
879
|
+
<div class="timepicker-display-column timepicker-display-digital-clock">
|
|
880
|
+
<div class="timepicker-input-hours-wrapper">
|
|
881
|
+
<input type="text" maxlength="2" class="timepicker-input-hours text-primary" />
|
|
882
|
+
</div>
|
|
883
|
+
<div class="timepicker-input-divider-wrapper">
|
|
884
|
+
<span class="timepicker-input-divider">:</span>
|
|
885
|
+
</div>
|
|
886
|
+
<div class="timepicker-input-minutes-wrapper">
|
|
887
|
+
<input type="text" maxlength="2" class="timepicker-input-minutes" />
|
|
888
|
+
</div>
|
|
889
|
+
</div>
|
|
890
|
+
<div class="timepicker-display-column timepicker-display-am-pm">
|
|
891
|
+
<div class="timepicker-span-am-pm"></div>
|
|
892
|
+
</div>
|
|
893
|
+
</div>
|
|
894
|
+
</div>
|
|
895
|
+
<div class="timepicker-analog-display">
|
|
896
|
+
<div class="timepicker-plate">
|
|
897
|
+
<div class="timepicker-canvas"></div>
|
|
898
|
+
<div class="timepicker-dial timepicker-hours"></div>
|
|
899
|
+
<div class="timepicker-dial timepicker-minutes timepicker-dial-out"></div>
|
|
900
|
+
</div>
|
|
901
|
+
<div class="timepicker-footer"></div>
|
|
902
|
+
</div>
|
|
903
|
+
</div>`;
|
|
904
|
+
}
|
|
905
|
+
}
|