beyond-rails 0.0.139
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/src/font/icomoon.eot +0 -0
- data/src/font/icomoon.svg +125 -0
- data/src/font/icomoon.ttf +0 -0
- data/src/font/icomoon.woff +0 -0
- data/src/img/black-cat.svg +15 -0
- data/src/img/cart.svg +16 -0
- data/src/img/china-flag.svg +16 -0
- data/src/img/ecpay.svg +12 -0
- data/src/img/family-mart.svg +13 -0
- data/src/img/fb-messenger.svg +12 -0
- data/src/img/fb.svg +10 -0
- data/src/img/hct.svg +16 -0
- data/src/img/hi-life.svg +23 -0
- data/src/img/line.svg +14 -0
- data/src/img/ok-mart.svg +9 -0
- data/src/img/pelican.svg +33 -0
- data/src/img/seven-eleven.svg +13 -0
- data/src/img/smilepay.svg +13 -0
- data/src/img/taiwan-flag.svg +17 -0
- data/src/js/components/Alert.js +23 -0
- data/src/js/components/Autocomplete.js +110 -0
- data/src/js/components/AutocompleteMenu.js +88 -0
- data/src/js/components/Btn.js +41 -0
- data/src/js/components/Checkbox.js +24 -0
- data/src/js/components/DateInput.js +74 -0
- data/src/js/components/DateMenu.js +370 -0
- data/src/js/components/DateTimeRanger.js +436 -0
- data/src/js/components/Datepicker.js +250 -0
- data/src/js/components/DatepickerBtnArrow.js +18 -0
- data/src/js/components/Dropdown.js +137 -0
- data/src/js/components/Menu.js +43 -0
- data/src/js/components/Modal.js +76 -0
- data/src/js/components/Navbar.js +47 -0
- data/src/js/components/Radio.js +24 -0
- data/src/js/components/SearchDropdown.js +339 -0
- data/src/js/components/Sidebar.js +56 -0
- data/src/js/components/Tabbox.js +229 -0
- data/src/js/components/TimeInput.js +71 -0
- data/src/js/components/TimeMenu.js +117 -0
- data/src/js/components/Toast.js +47 -0
- data/src/js/components/ToastItem.js +62 -0
- data/src/js/components/Tooltip.js +94 -0
- data/src/js/consts/createdComponents.js +1 -0
- data/src/js/consts/index.js +5 -0
- data/src/js/helpers/bind.js +53 -0
- data/src/js/helpers/dateEq.js +5 -0
- data/src/js/helpers/dateGt.js +5 -0
- data/src/js/helpers/dateLt.js +5 -0
- data/src/js/helpers/docReady.js +10 -0
- data/src/js/helpers/getFloatedTargetPos.js +250 -0
- data/src/js/helpers/getKey.js +14 -0
- data/src/js/helpers/isTouchDevice.js +3 -0
- data/src/js/helpers/msToS.js +3 -0
- data/src/js/helpers/promisify.js +9 -0
- data/src/js/helpers/range.js +7 -0
- data/src/js/helpers/supportDom.js +46 -0
- data/src/js/helpers/toPixel.js +3 -0
- data/src/js/helpers/unbindAll.js +6 -0
- data/src/js/index.js +47 -0
- data/src/js/jquery/bindAlertFn.js +13 -0
- data/src/js/jquery/bindAutocompleteFn.js +13 -0
- data/src/js/jquery/bindBtnFn.js +17 -0
- data/src/js/jquery/bindCheckboxFn.js +13 -0
- data/src/js/jquery/bindDateTimeRangerFn.js +14 -0
- data/src/js/jquery/bindDatepickerFn.js +14 -0
- data/src/js/jquery/bindDropdownFn.js +14 -0
- data/src/js/jquery/bindMenuFn.js +13 -0
- data/src/js/jquery/bindModalFn.js +14 -0
- data/src/js/jquery/bindNavbarFn.js +13 -0
- data/src/js/jquery/bindRadioFn.js +13 -0
- data/src/js/jquery/bindSearchDropdownFn.js +14 -0
- data/src/js/jquery/bindSidebarFn.js +13 -0
- data/src/js/jquery/bindTabboxFn.js +13 -0
- data/src/js/jquery/bindToastFn.js +6 -0
- data/src/js/jquery/bindTooltipFn.js +13 -0
- data/src/js/jquery/index.js +52 -0
- data/src/js/polyfills/classList.js +263 -0
- data/src/js/polyfills/elementDataset.js +3 -0
- data/src/js/polyfills/nodeContains.js +17 -0
- data/src/js/polyfills/nodeHasAttribute.js +5 -0
- data/src/js/polyfills/nodeRemove.js +19 -0
- data/src/sass/_beyond-sprockets.scss +1 -0
- data/src/sass/_beyond.scss +50 -0
- data/src/sass/_main.scss +141 -0
- data/src/sass/abstracts/_mixins.scss +129 -0
- data/src/sass/abstracts/_placeholders.scss +43 -0
- data/src/sass/abstracts/_variables.scss +355 -0
- data/src/sass/base/_background.scss +10 -0
- data/src/sass/base/_typography.scss +183 -0
- data/src/sass/components/_alert.scss +50 -0
- data/src/sass/components/_autocomplete.scss +29 -0
- data/src/sass/components/_avatar.scss +28 -0
- data/src/sass/components/_badge.scss +29 -0
- data/src/sass/components/_breadcrumb.scss +17 -0
- data/src/sass/components/_btn-group.scss +19 -0
- data/src/sass/components/_btn.scss +172 -0
- data/src/sass/components/_card.scss +183 -0
- data/src/sass/components/_checkbox.scss +99 -0
- data/src/sass/components/_date-input.scss +28 -0
- data/src/sass/components/_date-menu.scss +85 -0
- data/src/sass/components/_date-time-ranger.scss +21 -0
- data/src/sass/components/_datepicker.scss +3 -0
- data/src/sass/components/_dropdown.scss +144 -0
- data/src/sass/components/_form.scss +383 -0
- data/src/sass/components/_icon.scss +371 -0
- data/src/sass/components/_input.scss +48 -0
- data/src/sass/components/_list.scss +23 -0
- data/src/sass/components/_modal.scss +72 -0
- data/src/sass/components/_nav.scss +75 -0
- data/src/sass/components/_navbar.scss +211 -0
- data/src/sass/components/_pagination.scss +64 -0
- data/src/sass/components/_radio.scss +71 -0
- data/src/sass/components/_search-dropdown.scss +28 -0
- data/src/sass/components/_select.scss +54 -0
- data/src/sass/components/_sidebar.scss +35 -0
- data/src/sass/components/_spinner.scss +79 -0
- data/src/sass/components/_tabbox.scss +83 -0
- data/src/sass/components/_table.scss +65 -0
- data/src/sass/components/_tag.scss +43 -0
- data/src/sass/components/_time-input.scss +28 -0
- data/src/sass/components/_time-menu.scss +24 -0
- data/src/sass/components/_toast.scss +51 -0
- data/src/sass/components/_tooltip.scss +10 -0
- data/src/sass/img/arrow-dropdown.svg +4 -0
- data/src/sass/img/arrow-select-ex.svg +18 -0
- data/src/sass/img/arrow-select.svg +18 -0
- data/src/sass/layout/_border-util.scss +36 -0
- data/src/sass/layout/_col.scss +90 -0
- data/src/sass/layout/_container.scss +44 -0
- data/src/sass/layout/_flex-util.scss +18 -0
- data/src/sass/layout/_offset-util.scss +20 -0
- data/src/sass/layout/_sizing-util.scss +14 -0
- data/src/sass/layout/_spacing-util.scss +9 -0
- data/src/sass/layout/_visibility-util.scss +25 -0
- data/src/sass/vendor/_normalize.scss +578 -0
- data/src/sass/vendor/_turbolink.scss +5 -0
- 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
|
+
}
|