beyond-rails 0.0.139

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +7 -0
  2. data/src/font/icomoon.eot +0 -0
  3. data/src/font/icomoon.svg +125 -0
  4. data/src/font/icomoon.ttf +0 -0
  5. data/src/font/icomoon.woff +0 -0
  6. data/src/img/black-cat.svg +15 -0
  7. data/src/img/cart.svg +16 -0
  8. data/src/img/china-flag.svg +16 -0
  9. data/src/img/ecpay.svg +12 -0
  10. data/src/img/family-mart.svg +13 -0
  11. data/src/img/fb-messenger.svg +12 -0
  12. data/src/img/fb.svg +10 -0
  13. data/src/img/hct.svg +16 -0
  14. data/src/img/hi-life.svg +23 -0
  15. data/src/img/line.svg +14 -0
  16. data/src/img/ok-mart.svg +9 -0
  17. data/src/img/pelican.svg +33 -0
  18. data/src/img/seven-eleven.svg +13 -0
  19. data/src/img/smilepay.svg +13 -0
  20. data/src/img/taiwan-flag.svg +17 -0
  21. data/src/js/components/Alert.js +23 -0
  22. data/src/js/components/Autocomplete.js +110 -0
  23. data/src/js/components/AutocompleteMenu.js +88 -0
  24. data/src/js/components/Btn.js +41 -0
  25. data/src/js/components/Checkbox.js +24 -0
  26. data/src/js/components/DateInput.js +74 -0
  27. data/src/js/components/DateMenu.js +370 -0
  28. data/src/js/components/DateTimeRanger.js +436 -0
  29. data/src/js/components/Datepicker.js +250 -0
  30. data/src/js/components/DatepickerBtnArrow.js +18 -0
  31. data/src/js/components/Dropdown.js +137 -0
  32. data/src/js/components/Menu.js +43 -0
  33. data/src/js/components/Modal.js +76 -0
  34. data/src/js/components/Navbar.js +47 -0
  35. data/src/js/components/Radio.js +24 -0
  36. data/src/js/components/SearchDropdown.js +339 -0
  37. data/src/js/components/Sidebar.js +56 -0
  38. data/src/js/components/Tabbox.js +229 -0
  39. data/src/js/components/TimeInput.js +71 -0
  40. data/src/js/components/TimeMenu.js +117 -0
  41. data/src/js/components/Toast.js +47 -0
  42. data/src/js/components/ToastItem.js +62 -0
  43. data/src/js/components/Tooltip.js +94 -0
  44. data/src/js/consts/createdComponents.js +1 -0
  45. data/src/js/consts/index.js +5 -0
  46. data/src/js/helpers/bind.js +53 -0
  47. data/src/js/helpers/dateEq.js +5 -0
  48. data/src/js/helpers/dateGt.js +5 -0
  49. data/src/js/helpers/dateLt.js +5 -0
  50. data/src/js/helpers/docReady.js +10 -0
  51. data/src/js/helpers/getFloatedTargetPos.js +250 -0
  52. data/src/js/helpers/getKey.js +14 -0
  53. data/src/js/helpers/isTouchDevice.js +3 -0
  54. data/src/js/helpers/msToS.js +3 -0
  55. data/src/js/helpers/promisify.js +9 -0
  56. data/src/js/helpers/range.js +7 -0
  57. data/src/js/helpers/supportDom.js +46 -0
  58. data/src/js/helpers/toPixel.js +3 -0
  59. data/src/js/helpers/unbindAll.js +6 -0
  60. data/src/js/index.js +47 -0
  61. data/src/js/jquery/bindAlertFn.js +13 -0
  62. data/src/js/jquery/bindAutocompleteFn.js +13 -0
  63. data/src/js/jquery/bindBtnFn.js +17 -0
  64. data/src/js/jquery/bindCheckboxFn.js +13 -0
  65. data/src/js/jquery/bindDateTimeRangerFn.js +14 -0
  66. data/src/js/jquery/bindDatepickerFn.js +14 -0
  67. data/src/js/jquery/bindDropdownFn.js +14 -0
  68. data/src/js/jquery/bindMenuFn.js +13 -0
  69. data/src/js/jquery/bindModalFn.js +14 -0
  70. data/src/js/jquery/bindNavbarFn.js +13 -0
  71. data/src/js/jquery/bindRadioFn.js +13 -0
  72. data/src/js/jquery/bindSearchDropdownFn.js +14 -0
  73. data/src/js/jquery/bindSidebarFn.js +13 -0
  74. data/src/js/jquery/bindTabboxFn.js +13 -0
  75. data/src/js/jquery/bindToastFn.js +6 -0
  76. data/src/js/jquery/bindTooltipFn.js +13 -0
  77. data/src/js/jquery/index.js +52 -0
  78. data/src/js/polyfills/classList.js +263 -0
  79. data/src/js/polyfills/elementDataset.js +3 -0
  80. data/src/js/polyfills/nodeContains.js +17 -0
  81. data/src/js/polyfills/nodeHasAttribute.js +5 -0
  82. data/src/js/polyfills/nodeRemove.js +19 -0
  83. data/src/sass/_beyond-sprockets.scss +1 -0
  84. data/src/sass/_beyond.scss +50 -0
  85. data/src/sass/_main.scss +141 -0
  86. data/src/sass/abstracts/_mixins.scss +129 -0
  87. data/src/sass/abstracts/_placeholders.scss +43 -0
  88. data/src/sass/abstracts/_variables.scss +355 -0
  89. data/src/sass/base/_background.scss +10 -0
  90. data/src/sass/base/_typography.scss +183 -0
  91. data/src/sass/components/_alert.scss +50 -0
  92. data/src/sass/components/_autocomplete.scss +29 -0
  93. data/src/sass/components/_avatar.scss +28 -0
  94. data/src/sass/components/_badge.scss +29 -0
  95. data/src/sass/components/_breadcrumb.scss +17 -0
  96. data/src/sass/components/_btn-group.scss +19 -0
  97. data/src/sass/components/_btn.scss +172 -0
  98. data/src/sass/components/_card.scss +183 -0
  99. data/src/sass/components/_checkbox.scss +99 -0
  100. data/src/sass/components/_date-input.scss +28 -0
  101. data/src/sass/components/_date-menu.scss +85 -0
  102. data/src/sass/components/_date-time-ranger.scss +21 -0
  103. data/src/sass/components/_datepicker.scss +3 -0
  104. data/src/sass/components/_dropdown.scss +144 -0
  105. data/src/sass/components/_form.scss +383 -0
  106. data/src/sass/components/_icon.scss +371 -0
  107. data/src/sass/components/_input.scss +48 -0
  108. data/src/sass/components/_list.scss +23 -0
  109. data/src/sass/components/_modal.scss +72 -0
  110. data/src/sass/components/_nav.scss +75 -0
  111. data/src/sass/components/_navbar.scss +211 -0
  112. data/src/sass/components/_pagination.scss +64 -0
  113. data/src/sass/components/_radio.scss +71 -0
  114. data/src/sass/components/_search-dropdown.scss +28 -0
  115. data/src/sass/components/_select.scss +54 -0
  116. data/src/sass/components/_sidebar.scss +35 -0
  117. data/src/sass/components/_spinner.scss +79 -0
  118. data/src/sass/components/_tabbox.scss +83 -0
  119. data/src/sass/components/_table.scss +65 -0
  120. data/src/sass/components/_tag.scss +43 -0
  121. data/src/sass/components/_time-input.scss +28 -0
  122. data/src/sass/components/_time-menu.scss +24 -0
  123. data/src/sass/components/_toast.scss +51 -0
  124. data/src/sass/components/_tooltip.scss +10 -0
  125. data/src/sass/img/arrow-dropdown.svg +4 -0
  126. data/src/sass/img/arrow-select-ex.svg +18 -0
  127. data/src/sass/img/arrow-select.svg +18 -0
  128. data/src/sass/layout/_border-util.scss +36 -0
  129. data/src/sass/layout/_col.scss +90 -0
  130. data/src/sass/layout/_container.scss +44 -0
  131. data/src/sass/layout/_flex-util.scss +18 -0
  132. data/src/sass/layout/_offset-util.scss +20 -0
  133. data/src/sass/layout/_sizing-util.scss +14 -0
  134. data/src/sass/layout/_spacing-util.scss +9 -0
  135. data/src/sass/layout/_visibility-util.scss +25 -0
  136. data/src/sass/vendor/_normalize.scss +578 -0
  137. data/src/sass/vendor/_turbolink.scss +5 -0
  138. metadata +235 -0
@@ -0,0 +1,436 @@
1
+ import endOfDay from 'date-fns/endOfDay'
2
+ import parse from 'date-fns/parse'
3
+ import set from 'date-fns/set'
4
+ import noop from 'lodash.noop'
5
+ import startOfDay from 'date-fns/startOfDay'
6
+ import getHours from 'date-fns/getHours'
7
+ import getMinutes from 'date-fns/getMinutes'
8
+ import getSeconds from 'date-fns/getSeconds'
9
+ import DateInput from './DateInput'
10
+ import TimeInput from './TimeInput'
11
+ import DateMenu from './DateMenu'
12
+ import TimeMenu from './TimeMenu'
13
+ import DatepickerBtnArrow from './DatepickerBtnArrow'
14
+ import dateGt from '../helpers/dateGt'
15
+ import dateLt from '../helpers/dateLt'
16
+ import supportDom from '../helpers/supportDom'
17
+ import dateToTimestamp from '@superlanding/datetotimestamp'
18
+ import timestampToDate from '@superlanding/timestamptodate'
19
+
20
+ @supportDom
21
+ export default class DateTimeRanger {
22
+
23
+ constructor(dom, options = {}) {
24
+ this.dom = dom
25
+ this.options = options
26
+ this.options.change = options.change || noop
27
+ this.options.useMouseOver = ('useMouseOver' in options) ?
28
+ options.useMouseOver : true
29
+
30
+ this.lastTriggered = null
31
+ this.nextDate = null
32
+ this.focused = false
33
+ this.inputDateStartSet = false
34
+ this.inputDateEndSet = false
35
+ this.init()
36
+ }
37
+
38
+ init() {
39
+ const { dom } = this
40
+ const { startAt, endAt } = this.options
41
+
42
+ this.startDate = startAt ? new Date(startAt * 1000) : startOfDay(new Date())
43
+ this.endDate = endAt ? new Date(endAt * 1000) : endOfDay(this.startDate)
44
+
45
+ this.currentDate = this.startDate
46
+
47
+ this.inputDateStart = new DateInput(
48
+ dom.querySelector('[data-date-start]'),
49
+ this.startDate,
50
+ this.options
51
+ )
52
+
53
+ this.inputTimeStart = new TimeInput(
54
+ dom.querySelector('[data-time-start]'),
55
+ this.startDate,
56
+ this.options
57
+ )
58
+
59
+ this.btnArrow = new DatepickerBtnArrow(
60
+ dom.querySelector('[data-btn-arrow]')
61
+ )
62
+
63
+ this.inputDateEnd = new DateInput(
64
+ dom.querySelector('[data-date-end]'),
65
+ this.endDate,
66
+ this.options
67
+ )
68
+
69
+ this.inputTimeEnd = new TimeInput(
70
+ dom.querySelector('[data-time-end]'),
71
+ this.endDate,
72
+ this.options
73
+ )
74
+
75
+ this.dateMenu = new DateMenu({
76
+ date: this.currentDate,
77
+ startDate: this.startDate,
78
+ endDate: this.endDate,
79
+ options: this.options
80
+ })
81
+ this.timeMenu = new TimeMenu()
82
+
83
+ this.addEvents()
84
+ }
85
+
86
+ setTimestamps(startAt, endAt) {
87
+ return this.setDates(
88
+ timestampToDate(startAt),
89
+ timestampToDate(endAt)
90
+ )
91
+ }
92
+
93
+ setDates(startDate, endDate) {
94
+ if (dateGt(startDate, endDate)) {
95
+ throw new Error('Start date cannot be greater than end date.')
96
+ }
97
+ this.startDate = startDate
98
+ this.endDate = endDate
99
+ this.inputDateStart.setDate(this.startDate)
100
+ this.inputTimeStart.setDate(this.startDate)
101
+ this.inputDateEnd.setDate(this.endDate)
102
+ this.inputTimeEnd.setDate(this.endDate)
103
+ }
104
+
105
+ clearInputStatus() {
106
+ this.inputDateStart.clearStatus()
107
+ this.inputTimeStart.clearStatus()
108
+ this.inputDateEnd.clearStatus()
109
+ this.inputTimeEnd.clearStatus()
110
+ }
111
+
112
+ clearTimeInputStatus() {
113
+ this.inputTimeStart.clearStatus()
114
+ this.inputTimeEnd.clearStatus()
115
+ }
116
+
117
+ handleDateInputFocus(input) {
118
+ this.focused = true
119
+ this.inputDateStartSet = false
120
+ this.inputDateEndSet = false
121
+ this.clearTimeInputStatus()
122
+ this.inputDateStart.setActive(true)
123
+ this.inputDateEnd.setActive(true)
124
+ this.dateMenu.setDate({
125
+ date: this.startDate,
126
+ startDate: this.startDate,
127
+ endDate: this.endDate
128
+ })
129
+ this.dateMenu.show(this.dom)
130
+ this.timeMenu.hide()
131
+ }
132
+
133
+ handleTimeInputFocus(input) {
134
+ this.focused = true
135
+ this.clearInputStatus()
136
+ input.setActive(true)
137
+ this.lastTriggered = input
138
+ this.dateMenu.hide()
139
+ this.timeMenu.show({
140
+ src: this.dom,
141
+ date: input.date,
142
+ step: parseInt(input.dom.dataset.step, 10) || 30
143
+ })
144
+ }
145
+
146
+ handleDateInputKeyUp({ event, input, date, isStart }) {
147
+
148
+ const res = parse(event.target.value, input.datePattern, date)
149
+ this.nextDate = null
150
+
151
+ if (res.toString() === 'Invalid Date') {
152
+ return input.setDanger(true)
153
+ }
154
+ if (isStart && dateGt(startOfDay(res), startOfDay(this.endDate))) {
155
+ return input.setDanger(true)
156
+ }
157
+ if ((! isStart) && dateLt(startOfDay(res), startOfDay(this.startDate))) {
158
+ return input.setDanger(true)
159
+ }
160
+ input.setDanger(false)
161
+ this.nextDate = res
162
+ }
163
+
164
+ handleTimeInputKeyUp({ event, input, date, isStart }) {
165
+ const res = parse(event.target.value, input.timePattern, date)
166
+ this.nextDate = null
167
+
168
+ if (res.toString() === 'Invalid Date') {
169
+ return input.setDanger(true)
170
+ }
171
+ if (isStart && dateGt(startOfDay(res), startOfDay(this.endDate))) {
172
+ return input.setDanger(true)
173
+ }
174
+ if ((! isStart) && dateLt(startOfDay(res), startOfDay(this.startDate))) {
175
+ return input.setDanger(true)
176
+ }
177
+ input.setDanger(false)
178
+ this.nextDate = res
179
+ }
180
+
181
+ handleDateInputBlur({ input, isStart }) {
182
+ const dateProp = isStart ? 'startDate' : 'endDate'
183
+ const oldDate = this[dateProp]
184
+ const { nextDate } = this
185
+
186
+ if (nextDate) {
187
+ this[dateProp] = nextDate
188
+ input.setDate(nextDate)
189
+ this.dateMenu.setDate({ [dateProp]: nextDate })
190
+ this.nextDate = null
191
+ }
192
+ else {
193
+ input.setDate(oldDate)
194
+ }
195
+ }
196
+
197
+ handleTimeInputBlur({ input, isStart }) {
198
+ const dateProp = isStart ? 'startDate' : 'endDate'
199
+ const oldDate = this[dateProp]
200
+ const { nextDate } = this
201
+
202
+ if (nextDate) {
203
+ this[dateProp] = nextDate
204
+ input.setDate(nextDate)
205
+ this.nextDate = null
206
+ }
207
+ else {
208
+ input.setDate(oldDate)
209
+ }
210
+ }
211
+
212
+ addDateInputEvents() {
213
+ this.inputDateStart.on('focus', () => this.handleDateInputFocus(this.inputDateStart))
214
+ this.inputDateStart.on('keyup', event => {
215
+ return this.handleDateInputKeyUp({
216
+ event,
217
+ input: this.inputDateStart,
218
+ date: this.startDate,
219
+ isStart: true
220
+ })
221
+ })
222
+ this.inputDateStart.on('blur', () => {
223
+ return this.handleDateInputBlur({
224
+ input: this.inputDateStart,
225
+ isStart: true
226
+ })
227
+ })
228
+
229
+ this.inputDateEnd.on('focus', () => this.handleDateInputFocus(this.inputDateEnd))
230
+ this.inputDateEnd.on('keyup', event => {
231
+ return this.handleDateInputKeyUp({
232
+ event,
233
+ input: this.inputDateEnd,
234
+ date: this.endDate,
235
+ isStart: false
236
+ })
237
+ })
238
+ this.inputDateEnd.on('blur', () => {
239
+ return this.handleDateInputBlur({
240
+ input: this.inputDateEnd,
241
+ isStart: false
242
+ })
243
+ })
244
+ }
245
+
246
+ addTimeInputEvents() {
247
+ this.inputTimeStart.on('focus', () => this.handleTimeInputFocus(this.inputTimeStart))
248
+ this.inputTimeStart.on('keyup', event => {
249
+ return this.handleTimeInputKeyUp({
250
+ event,
251
+ input: this.inputTimeStart,
252
+ date: this.startDate,
253
+ isStart: true
254
+ })
255
+ })
256
+ this.inputTimeStart.on('blur', event => {
257
+ return this.handleTimeInputBlur({
258
+ input: this.inputTimeStart,
259
+ isStart: true
260
+ })
261
+ })
262
+
263
+ this.inputTimeEnd.on('focus', () => this.handleTimeInputFocus(this.inputTimeEnd))
264
+ this.inputTimeEnd.on('keyup', event => {
265
+ return this.handleTimeInputKeyUp({
266
+ event,
267
+ input: this.inputTimeEnd,
268
+ date: this.startDate,
269
+ isStart: false
270
+ })
271
+ })
272
+ this.inputTimeEnd.on('blur', event => {
273
+ return this.handleTimeInputBlur({
274
+ input: this.inputTimeEnd,
275
+ isStart: false
276
+ })
277
+ })
278
+ }
279
+
280
+ switchDates() {
281
+ const oldStartDate = this.startDate
282
+ const oldEndDate = this.endDate;
283
+ [this.startDate, this.endDate] = [this.endDate, this.startDate]
284
+
285
+ // keeps the time
286
+ this.startDate = set(this.startDate, {
287
+ hours: getHours(oldStartDate),
288
+ minutes: getMinutes(oldStartDate),
289
+ seconds: getSeconds(oldStartDate)
290
+ })
291
+ this.endDate = set(this.endDate, {
292
+ hours: getHours(oldEndDate),
293
+ minutes: getMinutes(oldEndDate),
294
+ seconds: getSeconds(oldEndDate)
295
+ })
296
+ this.inputDateStart.setDate(this.startDate)
297
+ this.inputDateEnd.setDate(this.endDate)
298
+ }
299
+
300
+ emitChange() {
301
+ const { startDate, endDate } = this
302
+ this.options.change({
303
+ startDate,
304
+ endDate,
305
+ startAt: dateToTimestamp(startDate),
306
+ endAt: dateToTimestamp(endDate)
307
+ })
308
+ }
309
+
310
+ addMenuEvents() {
311
+ this.dateMenu.on('td-mouseover', (event, res) => {
312
+ if (this.dateMenu.startDate && (! this.dateMenu.endDate)) {
313
+ this.dateMenu.setHoveredCell(res)
314
+ }
315
+ })
316
+ this.dateMenu.on('td-click', (event, res) => {
317
+ event.stopPropagation()
318
+ event.preventDefault()
319
+
320
+ if (this.inputDateStartSet && this.inputDateEndSet) {
321
+ this.inputDateStartSet = false
322
+ this.inputDateEndSet = false
323
+ }
324
+
325
+ const { year, month, date } = res
326
+
327
+ if ((! this.inputDateStartSet) && (! this.inputDateEndSet)) {
328
+ this.dateMenu.setDate({ startDate: null, endDate: null })
329
+ const nextStartDate = set(this.startDate, { year, month, date })
330
+ this.startDate = nextStartDate
331
+ this.inputDateStart.setDate(nextStartDate)
332
+ this.inputDateStartSet = true
333
+ return this.dateMenu.setDate({
334
+ startDate: this.startDate
335
+ })
336
+ }
337
+
338
+ if (this.inputDateStartSet && (! this.inputDateEndSet)) {
339
+ this.endDate = set(this.endDate, { year, month, date })
340
+
341
+ // switch if next endDate is prior to startDate
342
+ if (dateLt(startOfDay(this.endDate), startOfDay(this.startDate))) {
343
+ this.switchDates()
344
+ }
345
+ this.inputDateStart.setDate(this.startDate)
346
+ this.inputDateEnd.setDate(this.endDate)
347
+
348
+ this.inputDateEndSet = true
349
+ this.dateMenu.setDate({
350
+ startDate: this.startDate,
351
+ endDate: this.endDate
352
+ })
353
+ return this.emitChange()
354
+ }
355
+ })
356
+
357
+ this.timeMenu.on('click', (event, res) => {
358
+ const nextDate = set(this.lastTriggered.date, { hours: res.hour, minutes: res.minute })
359
+ if (this.lastTriggered === this.inputTimeStart) {
360
+ this.startDate = nextDate
361
+ }
362
+ if (this.lastTriggered === this.inputTimeEnd) {
363
+ this.endDate = nextDate
364
+ }
365
+ this.lastTriggered.setDate(nextDate)
366
+ this.timeMenu.hide()
367
+ this.clearInputStatus()
368
+ this.emitChange()
369
+ })
370
+ }
371
+
372
+ addBtnArrowEvents() {
373
+ this.btnArrow.on('click', () => {
374
+ this.inputDateStart.focus()
375
+ this.handleDateInputFocus(this.inputDateStart)
376
+ })
377
+ }
378
+
379
+ addEvents() {
380
+
381
+ this.addDateInputEvents()
382
+ this.addTimeInputEvents()
383
+ this.addMenuEvents()
384
+ this.addBtnArrowEvents()
385
+
386
+ this.addEvent(document, 'click', event => {
387
+ const { dom, dateMenu, timeMenu } = this
388
+ const { target } = event
389
+ const dateMenuDom = dateMenu.dom
390
+ const timeMenuDom = timeMenu.dom
391
+
392
+ if (this.focused) {
393
+ this.focused = false
394
+ return
395
+ }
396
+ if ((! dateMenu.isVisible) && (! timeMenu.isVisible)) {
397
+ return
398
+ }
399
+ if (dom.contains(target)) {
400
+ return
401
+ }
402
+
403
+ if (dateMenuDom.contains(target)) {
404
+ return
405
+ }
406
+ if (dateMenuDom === target) {
407
+ return
408
+ }
409
+
410
+ if (timeMenuDom.contains(target)) {
411
+ return
412
+ }
413
+ if (timeMenuDom === target) {
414
+ return
415
+ }
416
+
417
+ this.clearInputStatus()
418
+
419
+ if (dateLt(startOfDay(this.endDate), startOfDay(this.startDate))) {
420
+ this.switchDates()
421
+ }
422
+ dateMenu.hide()
423
+ timeMenu.hide()
424
+ })
425
+ }
426
+
427
+ destroy() {
428
+ this.inputDateStart.destroy()
429
+ this.inputTimeStart.destroy()
430
+ this.inputDateEnd.destroy()
431
+ this.inputTimeEnd.destroy()
432
+ this.dateMenu.destroy()
433
+ this.timeMenu.destroy()
434
+ this.btnArrow.destroy()
435
+ }
436
+ }
@@ -0,0 +1,250 @@
1
+ import parse from 'date-fns/parse'
2
+ import set from 'date-fns/set'
3
+ import noop from 'lodash.noop'
4
+ import toDate from 'date-fns/toDate'
5
+ import DateInput from './DateInput'
6
+ import TimeInput from './TimeInput'
7
+ import DateMenu from './DateMenu'
8
+ import TimeMenu from './TimeMenu'
9
+ import supportDom from '../helpers/supportDom'
10
+ import { DEFAULT_TIMEZONE } from '../consts'
11
+ import dateToTimestamp from '@superlanding/datetotimestamp'
12
+ import timestampToDate from '@superlanding/timestamptodate'
13
+
14
+ @supportDom
15
+ export default class Datepicker {
16
+
17
+ constructor(dom, timestamp, options = {}) {
18
+ this.dom = dom
19
+ this.options = options
20
+ this.options.change = options.change || noop
21
+ this.tz = options.tz || DEFAULT_TIMEZONE
22
+
23
+ this.date = (timestamp === null) ? null : timestampToDate(timestamp)
24
+ this.menuDate = (timestamp === null) ? toDate(new Date()) : toDate(this.date)
25
+ this.focused = false
26
+ this.nextDate = null
27
+ this.init()
28
+ }
29
+
30
+ init() {
31
+ const { dom } = this
32
+ this.dateInput = new DateInput(
33
+ dom.querySelector('[data-date]'),
34
+ this.date,
35
+ this.options
36
+ )
37
+ this.dateMenu = new DateMenu({
38
+ date: this.menuDate,
39
+ options: Object.assign({}, this.options, { useSingleMenu: true })
40
+ })
41
+
42
+ const timeInput = dom.querySelector('[data-time]')
43
+ if (timeInput) {
44
+ this.timeInput = new TimeInput(
45
+ timeInput,
46
+ this.date,
47
+ this.options
48
+ )
49
+ this.timeMenu = new TimeMenu()
50
+ }
51
+ this.addEvents()
52
+ }
53
+
54
+ clearInputStatus() {
55
+ this.dateInput.clearStatus()
56
+ this.timeInput && this.timeInput.clearStatus()
57
+ }
58
+
59
+ handleDateInputFocus() {
60
+ this.focused = true
61
+ this.clearInputStatus()
62
+ this.dateInput.setActive(true)
63
+ this.dateMenu.setDate({ date: this.menuDate })
64
+ this.dateMenu.show(this.dom)
65
+ this.timeMenu && this.timeMenu.hide()
66
+ }
67
+
68
+ setTimestamp(timestamp) {
69
+ return this.setDate(timestampToDate(timestamp))
70
+ }
71
+
72
+ setDate(date) {
73
+ this.date = date
74
+ this.dateInput.setDate(date)
75
+ this.dateMenu.setDate({ startDate: date })
76
+ }
77
+
78
+ handleDateInputKeyUp(event) {
79
+ const { date, dateInput } = this
80
+ const { value } = event.target
81
+
82
+ if ((! dateInput.required) && (value === '')) {
83
+ this.date = null
84
+ this.nextDate = null
85
+ return
86
+ }
87
+
88
+ const res = parse(value, dateInput.datePattern, date)
89
+ this.nextDate = null
90
+ if (res.toString() === 'Invalid Date') {
91
+ return dateInput.setDanger(true)
92
+ }
93
+ dateInput.setDanger(false)
94
+ this.nextDate = res
95
+ }
96
+
97
+ handleDateInputBlur() {
98
+ const { nextDate, date, dateInput } = this
99
+
100
+ if (date === null) {
101
+ dateInput.setDate(null)
102
+ this.timeInput && this.timeInput.setDate(null)
103
+ }
104
+ else if (nextDate) {
105
+ this.date = nextDate
106
+ dateInput.setDate(nextDate)
107
+ this.dateMenu.setDate({ startDate: nextDate })
108
+ this.nextDate = null
109
+ }
110
+ else {
111
+ dateInput.setDate(date)
112
+ }
113
+ }
114
+
115
+ handleTimeInputFocus() {
116
+ const { timeInput } = this
117
+ this.focused = true
118
+ this.clearInputStatus()
119
+ timeInput.setActive(true)
120
+ this.dateMenu.hide()
121
+ this.timeMenu.show({ src: this.dom, date: timeInput.date })
122
+ }
123
+
124
+ handleTimeInputKeyUp(event) {
125
+ const { date, timeInput } = this
126
+ const { value } = event.target
127
+
128
+ if ((! timeInput.required) && (value === '')) {
129
+ this.nextDate = null
130
+ return
131
+ }
132
+ const res = parse(event.target.value, timeInput.timePattern, date)
133
+ this.nextDate = null
134
+
135
+ if (res.toString() === 'Invalid Date') {
136
+ return timeInput.setDanger(true)
137
+ }
138
+ timeInput.setDanger(false)
139
+ this.nextDate = res
140
+ }
141
+
142
+ handleTimeInputBlur() {
143
+ const { nextDate, date, timeInput } = this
144
+
145
+ if (nextDate) {
146
+ this.date = nextDate
147
+ timeInput.setDate(nextDate)
148
+ this.nextDate = null
149
+ }
150
+ else if (date) {
151
+ timeInput.setDate(date)
152
+ }
153
+ }
154
+
155
+ addDateInputEvents() {
156
+ this.dateInput.on('focus', () => this.handleDateInputFocus())
157
+ this.dateInput.on('keyup', event => this.handleDateInputKeyUp(event))
158
+ this.dateInput.on('blur', () => this.handleDateInputBlur())
159
+ }
160
+
161
+ addTimeInputEvents() {
162
+ this.timeInput.on('focus', () => this.handleTimeInputFocus())
163
+ this.timeInput.on('keyup', event => this.handleTimeInputKeyUp(event))
164
+ this.timeInput.on('blur', () => this.handleTimeInputBlur())
165
+ }
166
+
167
+ emitChange() {
168
+ const { date } = this
169
+ this.options.change({
170
+ date,
171
+ timestamp: dateToTimestamp(date)
172
+ })
173
+ }
174
+
175
+ addEvents() {
176
+
177
+ this.addDateInputEvents()
178
+
179
+ this.dateMenu.on('td-click', (event, res) => {
180
+ event.stopPropagation()
181
+ event.preventDefault()
182
+
183
+ const { year, month, date } = res
184
+ this.date = set(this.date || new Date(), { year, month, date })
185
+ this.dateInput.setDate(this.date)
186
+ this.dateMenu.setDate({ startDate: this.date })
187
+ this.dateInput.setActive(false)
188
+ this.dateMenu.hide()
189
+ this.emitChange()
190
+ })
191
+
192
+ if (this.timeInput) {
193
+ this.addTimeInputEvents()
194
+
195
+ this.timeMenu.on('click', (event, res) => {
196
+ if (this.date === null) {
197
+ this.date = set(new Date(), { hours: res.hour, minutes: res.minute })
198
+ this.dateInput.setDate(this.date)
199
+ }
200
+ else {
201
+ this.date = set(this.date, { hours: res.hour, minutes: res.minute })
202
+ }
203
+ this.timeInput.setDate(this.date)
204
+ this.timeMenu.hide()
205
+ this.clearInputStatus()
206
+ this.emitChange()
207
+ })
208
+ }
209
+
210
+ this.addEvent(document, 'click', event => {
211
+ const { dom, dateMenu, timeMenu } = this
212
+ const { target } = event
213
+ const dateMenuDom = dateMenu.dom
214
+ const timeMenuDom = timeMenu ? timeMenu.dom : null
215
+
216
+ if (this.focused) {
217
+ this.focused = false
218
+ return
219
+ }
220
+ if ((! dateMenu.isVisible) && (timeMenu && (! timeMenu.isVisible))) {
221
+ return
222
+ }
223
+ if (dom.contains(target)) {
224
+ return
225
+ }
226
+ if (dateMenuDom.contains(target)) {
227
+ return
228
+ }
229
+ if (dateMenuDom === target) {
230
+ return
231
+ }
232
+ if (timeMenuDom && timeMenuDom.contains(target)) {
233
+ return
234
+ }
235
+ if (timeMenuDom && (timeMenuDom === target)) {
236
+ return
237
+ }
238
+ this.clearInputStatus()
239
+ dateMenu.hide()
240
+ timeMenu && timeMenu.hide()
241
+ })
242
+ }
243
+
244
+ destroy() {
245
+ this.dateInput.destroy()
246
+ this.dateMenu.destroy()
247
+ this.timeInput && this.timeInput.destroy()
248
+ this.timeMenu && this.timeMenu.destroy()
249
+ }
250
+ }