@ministryofjustice/frontend 3.3.1 → 3.4.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/README.md +4 -10
- package/govuk-prototype-kit.config.json +5 -16
- package/moj/all.jquery.min.js +77 -3
- package/moj/all.js +2021 -1436
- package/moj/all.scss +2 -0
- package/moj/all.spec.js +15 -13
- package/moj/components/_all.scss +1 -0
- package/moj/components/action-bar/_action-bar.scss +4 -6
- package/moj/components/add-another/_add-another.scss +9 -7
- package/moj/components/add-another/add-another.js +90 -69
- package/moj/components/add-another/add-another.spec.js +165 -0
- package/moj/components/alert/README.md +0 -0
- package/moj/components/alert/_alert.scss +142 -0
- package/moj/components/alert/alert.js +247 -0
- package/moj/components/alert/alert.spec.helper.js +67 -0
- package/moj/components/alert/alert.spec.js +229 -0
- package/moj/components/alert/macro.njk +3 -0
- package/moj/components/alert/template.njk +83 -0
- package/moj/components/badge/_badge.scss +3 -4
- package/moj/components/banner/_banner.scss +5 -10
- package/moj/components/button-menu/_button-menu.scss +10 -9
- package/moj/components/button-menu/button-menu.js +139 -136
- package/moj/components/button-menu/button-menu.spec.js +295 -296
- package/moj/components/cookie-banner/_cookie-banner.scss +6 -5
- package/moj/components/currency-input/_currency-input.scss +4 -4
- package/moj/components/date-picker/README.md +14 -17
- package/moj/components/date-picker/_date-picker.scss +122 -106
- package/moj/components/date-picker/date-picker.js +473 -471
- package/moj/components/date-picker/date-picker.spec.js +971 -923
- package/moj/components/filter/README.md +1 -1
- package/moj/components/filter/_filter.scss +53 -75
- package/moj/components/filter-toggle-button/filter-toggle-button.js +71 -67
- package/moj/components/filter-toggle-button/filter-toggle-button.spec.js +203 -205
- package/moj/components/form-validator/form-validator.js +117 -109
- package/moj/components/header/_header.scss +17 -19
- package/moj/components/identity-bar/_identity-bar.scss +5 -5
- package/moj/components/interruption-card/_interruption-card.scss +2 -2
- package/moj/components/messages/_messages.scss +12 -19
- package/moj/components/multi-file-upload/README.md +1 -1
- package/moj/components/multi-file-upload/_multi-file-upload.scss +34 -30
- package/moj/components/multi-file-upload/multi-file-upload.js +188 -152
- package/moj/components/multi-file-upload/multi-file-upload.spec.js +510 -0
- package/moj/components/multi-select/_multi-select.scss +4 -3
- package/moj/components/multi-select/multi-select.js +55 -50
- package/moj/components/multi-select/multi-select.spec.js +72 -79
- package/moj/components/notification-badge/_notification-badge.scss +12 -12
- package/moj/components/organisation-switcher/_organisation-switcher.scss +1 -1
- package/moj/components/page-header-actions/_page-header-actions.scss +3 -2
- package/moj/components/pagination/_pagination.scss +26 -31
- package/moj/components/password-reveal/_password-reveal.scss +1 -2
- package/moj/components/password-reveal/password-reveal.js +22 -21
- package/moj/components/password-reveal/password-reveal.spec.js +39 -37
- package/moj/components/primary-navigation/_primary-navigation.scss +26 -29
- package/moj/components/progress-bar/_progress-bar.scss +21 -26
- package/moj/components/rich-text-editor/_rich-text-editor.scss +17 -16
- package/moj/components/rich-text-editor/rich-text-editor.js +117 -103
- package/moj/components/search/_search.scss +6 -4
- package/moj/components/search-toggle/search-toggle.js +29 -30
- package/moj/components/search-toggle/search-toggle.scss +21 -15
- package/moj/components/search-toggle/search-toggle.spec.js +65 -70
- package/moj/components/side-navigation/_side-navigation.scss +12 -21
- package/moj/components/sortable-table/_sortable-table.scss +25 -23
- package/moj/components/sortable-table/sortable-table.js +139 -117
- package/moj/components/sortable-table/sortable-table.spec.js +362 -0
- package/moj/components/sub-navigation/_sub-navigation.scss +24 -28
- package/moj/components/tag/_tag.scss +8 -9
- package/moj/components/task-list/_task-list.scss +8 -7
- package/moj/components/ticket-panel/_ticket-panel.scss +14 -6
- package/moj/components/timeline/_timeline.scss +18 -20
- package/moj/filters/all.js +28 -30
- package/moj/filters/prototype-kit-13-filters.js +2 -1
- package/moj/helpers/_all.scss +1 -0
- package/moj/helpers/_hidden.scss +1 -1
- package/moj/helpers/_links.scss +20 -0
- package/moj/helpers.js +160 -31
- package/moj/helpers.spec.js +235 -0
- package/moj/init.js +2 -2
- package/moj/moj-frontend.min.css +2 -2
- package/moj/moj-frontend.min.js +77 -3
- package/moj/namespace.js +2 -1
- package/moj/objects/_filter-layout.scss +11 -10
- package/moj/objects/_scrollable-pane.scss +11 -14
- package/moj/settings/_colours.scss +5 -0
- package/moj/settings/_measurements.scss +0 -2
- package/moj/utilities/_hidden.scss +3 -3
- package/moj/utilities/_width-container.scss +1 -1
- package/package.json +1 -1
|
@@ -2,234 +2,232 @@
|
|
|
2
2
|
* Datepicker config
|
|
3
3
|
*
|
|
4
4
|
* @typedef {object} DatepickerConfig
|
|
5
|
-
* @property {string}
|
|
6
|
-
* @property {string}
|
|
5
|
+
* @property {string} [excludedDates] - Dates that cannot be selected
|
|
6
|
+
* @property {string} [excludedDays] - Days that cannot be selected
|
|
7
7
|
* @property {boolean} [leadingZeroes] - Whether to add leading zeroes when populating the field
|
|
8
|
-
* @property {string}
|
|
9
|
-
* @property {string}
|
|
10
|
-
* @property {string}
|
|
8
|
+
* @property {string} [minDate] - The earliest available date
|
|
9
|
+
* @property {string} [maxDate] - The latest available date
|
|
10
|
+
* @property {string} [weekStartDay] - First day of the week in calendar view
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* @param {HTMLElement} $module - HTML element
|
|
15
15
|
* @param {DatepickerConfig} config - config object
|
|
16
|
-
* @
|
|
16
|
+
* @class
|
|
17
17
|
*/
|
|
18
18
|
function Datepicker($module, config = {}) {
|
|
19
19
|
if (!$module) {
|
|
20
|
-
return this
|
|
20
|
+
return this
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
const schema = Object.freeze({
|
|
24
24
|
properties: {
|
|
25
|
-
excludedDates: { type:
|
|
26
|
-
excludedDays: { type:
|
|
27
|
-
leadingZeros: { type:
|
|
28
|
-
maxDate: { type:
|
|
29
|
-
minDate: { type:
|
|
30
|
-
weekStartDay: { type:
|
|
31
|
-
}
|
|
32
|
-
})
|
|
25
|
+
excludedDates: { type: 'string' },
|
|
26
|
+
excludedDays: { type: 'string' },
|
|
27
|
+
leadingZeros: { type: 'string' },
|
|
28
|
+
maxDate: { type: 'string' },
|
|
29
|
+
minDate: { type: 'string' },
|
|
30
|
+
weekStartDay: { type: 'string' }
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
33
|
|
|
34
34
|
const defaults = {
|
|
35
35
|
leadingZeros: false,
|
|
36
|
-
weekStartDay:
|
|
37
|
-
}
|
|
36
|
+
weekStartDay: 'monday'
|
|
37
|
+
}
|
|
38
38
|
|
|
39
39
|
// data attributes override JS config, which overrides defaults
|
|
40
40
|
this.config = this.mergeConfigs(
|
|
41
41
|
defaults,
|
|
42
42
|
config,
|
|
43
|
-
this.parseDataset(schema, $module.dataset)
|
|
44
|
-
)
|
|
43
|
+
this.parseDataset(schema, $module.dataset)
|
|
44
|
+
)
|
|
45
45
|
|
|
46
46
|
this.dayLabels = [
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
]
|
|
47
|
+
'Monday',
|
|
48
|
+
'Tuesday',
|
|
49
|
+
'Wednesday',
|
|
50
|
+
'Thursday',
|
|
51
|
+
'Friday',
|
|
52
|
+
'Saturday',
|
|
53
|
+
'Sunday'
|
|
54
|
+
]
|
|
55
55
|
|
|
56
56
|
this.monthLabels = [
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
]
|
|
70
|
-
|
|
71
|
-
this.currentDate = new Date()
|
|
72
|
-
this.currentDate.setHours(0, 0, 0, 0)
|
|
73
|
-
this.calendarDays = []
|
|
74
|
-
this.excludedDates = []
|
|
75
|
-
this.excludedDays = []
|
|
76
|
-
|
|
77
|
-
this.buttonClass =
|
|
78
|
-
this.selectedDayButtonClass =
|
|
79
|
-
this.currentDayButtonClass =
|
|
80
|
-
this.todayButtonClass =
|
|
81
|
-
|
|
82
|
-
this.$module = $module
|
|
83
|
-
this.$input = $module.querySelector(
|
|
57
|
+
'January',
|
|
58
|
+
'February',
|
|
59
|
+
'March',
|
|
60
|
+
'April',
|
|
61
|
+
'May',
|
|
62
|
+
'June',
|
|
63
|
+
'July',
|
|
64
|
+
'August',
|
|
65
|
+
'September',
|
|
66
|
+
'October',
|
|
67
|
+
'November',
|
|
68
|
+
'December'
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
this.currentDate = new Date()
|
|
72
|
+
this.currentDate.setHours(0, 0, 0, 0)
|
|
73
|
+
this.calendarDays = []
|
|
74
|
+
this.excludedDates = []
|
|
75
|
+
this.excludedDays = []
|
|
76
|
+
|
|
77
|
+
this.buttonClass = 'moj-datepicker__button'
|
|
78
|
+
this.selectedDayButtonClass = 'moj-datepicker__button--selected'
|
|
79
|
+
this.currentDayButtonClass = 'moj-datepicker__button--current'
|
|
80
|
+
this.todayButtonClass = 'moj-datepicker__button--today'
|
|
81
|
+
|
|
82
|
+
this.$module = $module
|
|
83
|
+
this.$input = $module.querySelector('.moj-js-datepicker-input')
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
Datepicker.prototype.init = function () {
|
|
87
87
|
// Check that required elements are present
|
|
88
88
|
if (!this.$input) {
|
|
89
|
-
return
|
|
89
|
+
return
|
|
90
90
|
}
|
|
91
91
|
if (this.$module.dataset.initialized) {
|
|
92
|
-
return
|
|
92
|
+
return
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
this.setOptions()
|
|
96
|
-
this.initControls()
|
|
97
|
-
this.$module.setAttribute(
|
|
98
|
-
}
|
|
95
|
+
this.setOptions()
|
|
96
|
+
this.initControls()
|
|
97
|
+
this.$module.setAttribute('data-initialized', 'true')
|
|
98
|
+
}
|
|
99
99
|
|
|
100
100
|
Datepicker.prototype.initControls = function () {
|
|
101
|
-
this.id = `datepicker-${this.$input.id}
|
|
101
|
+
this.id = `datepicker-${this.$input.id}`
|
|
102
102
|
|
|
103
|
-
this.$dialog = this.createDialog()
|
|
104
|
-
this.createCalendarHeaders()
|
|
103
|
+
this.$dialog = this.createDialog()
|
|
104
|
+
this.createCalendarHeaders()
|
|
105
105
|
|
|
106
|
-
const $componentWrapper = document.createElement(
|
|
107
|
-
const $inputWrapper = document.createElement(
|
|
108
|
-
$componentWrapper.classList.add(
|
|
109
|
-
$inputWrapper.classList.add(
|
|
106
|
+
const $componentWrapper = document.createElement('div')
|
|
107
|
+
const $inputWrapper = document.createElement('div')
|
|
108
|
+
$componentWrapper.classList.add('moj-datepicker__wrapper')
|
|
109
|
+
$inputWrapper.classList.add('govuk-input__wrapper')
|
|
110
110
|
|
|
111
|
-
this.$input.parentNode.insertBefore($componentWrapper, this.$input)
|
|
112
|
-
$componentWrapper.appendChild($inputWrapper)
|
|
113
|
-
$inputWrapper.appendChild(this.$input)
|
|
111
|
+
this.$input.parentNode.insertBefore($componentWrapper, this.$input)
|
|
112
|
+
$componentWrapper.appendChild($inputWrapper)
|
|
113
|
+
$inputWrapper.appendChild(this.$input)
|
|
114
114
|
|
|
115
|
-
$inputWrapper.insertAdjacentHTML(
|
|
116
|
-
$componentWrapper.insertAdjacentElement(
|
|
115
|
+
$inputWrapper.insertAdjacentHTML('beforeend', this.toggleTemplate())
|
|
116
|
+
$componentWrapper.insertAdjacentElement('beforeend', this.$dialog)
|
|
117
117
|
|
|
118
|
-
this.$calendarButton = this.$module.querySelector(
|
|
119
|
-
".moj-js-datepicker-toggle",
|
|
120
|
-
);
|
|
118
|
+
this.$calendarButton = this.$module.querySelector('.moj-js-datepicker-toggle')
|
|
121
119
|
this.$dialogTitle = this.$dialog.querySelector(
|
|
122
|
-
|
|
123
|
-
)
|
|
120
|
+
'.moj-js-datepicker-month-year'
|
|
121
|
+
)
|
|
124
122
|
|
|
125
|
-
this.createCalendar()
|
|
123
|
+
this.createCalendar()
|
|
126
124
|
|
|
127
125
|
this.$prevMonthButton = this.$dialog.querySelector(
|
|
128
|
-
|
|
129
|
-
)
|
|
126
|
+
'.moj-js-datepicker-prev-month'
|
|
127
|
+
)
|
|
130
128
|
this.$prevYearButton = this.$dialog.querySelector(
|
|
131
|
-
|
|
132
|
-
)
|
|
129
|
+
'.moj-js-datepicker-prev-year'
|
|
130
|
+
)
|
|
133
131
|
this.$nextMonthButton = this.$dialog.querySelector(
|
|
134
|
-
|
|
135
|
-
)
|
|
132
|
+
'.moj-js-datepicker-next-month'
|
|
133
|
+
)
|
|
136
134
|
this.$nextYearButton = this.$dialog.querySelector(
|
|
137
|
-
|
|
138
|
-
)
|
|
139
|
-
this.$cancelButton = this.$dialog.querySelector(
|
|
140
|
-
this.$okButton = this.$dialog.querySelector(
|
|
135
|
+
'.moj-js-datepicker-next-year'
|
|
136
|
+
)
|
|
137
|
+
this.$cancelButton = this.$dialog.querySelector('.moj-js-datepicker-cancel')
|
|
138
|
+
this.$okButton = this.$dialog.querySelector('.moj-js-datepicker-ok')
|
|
141
139
|
|
|
142
140
|
// add event listeners
|
|
143
|
-
this.$prevMonthButton.addEventListener(
|
|
144
|
-
this.focusPreviousMonth(event, false)
|
|
145
|
-
)
|
|
146
|
-
this.$prevYearButton.addEventListener(
|
|
147
|
-
this.focusPreviousYear(event, false)
|
|
148
|
-
)
|
|
149
|
-
this.$nextMonthButton.addEventListener(
|
|
150
|
-
this.focusNextMonth(event, false)
|
|
151
|
-
)
|
|
152
|
-
this.$nextYearButton.addEventListener(
|
|
153
|
-
this.focusNextYear(event, false)
|
|
154
|
-
)
|
|
155
|
-
this.$cancelButton.addEventListener(
|
|
156
|
-
event.preventDefault()
|
|
157
|
-
this.closeDialog(event)
|
|
158
|
-
})
|
|
159
|
-
this.$okButton.addEventListener(
|
|
160
|
-
this.selectDate(this.currentDate)
|
|
161
|
-
})
|
|
141
|
+
this.$prevMonthButton.addEventListener('click', (event) =>
|
|
142
|
+
this.focusPreviousMonth(event, false)
|
|
143
|
+
)
|
|
144
|
+
this.$prevYearButton.addEventListener('click', (event) =>
|
|
145
|
+
this.focusPreviousYear(event, false)
|
|
146
|
+
)
|
|
147
|
+
this.$nextMonthButton.addEventListener('click', (event) =>
|
|
148
|
+
this.focusNextMonth(event, false)
|
|
149
|
+
)
|
|
150
|
+
this.$nextYearButton.addEventListener('click', (event) =>
|
|
151
|
+
this.focusNextYear(event, false)
|
|
152
|
+
)
|
|
153
|
+
this.$cancelButton.addEventListener('click', (event) => {
|
|
154
|
+
event.preventDefault()
|
|
155
|
+
this.closeDialog(event)
|
|
156
|
+
})
|
|
157
|
+
this.$okButton.addEventListener('click', () => {
|
|
158
|
+
this.selectDate(this.currentDate)
|
|
159
|
+
})
|
|
162
160
|
|
|
163
161
|
const dialogButtons = this.$dialog.querySelectorAll(
|
|
164
|
-
'button:not([disabled="true"])'
|
|
165
|
-
)
|
|
162
|
+
'button:not([disabled="true"])'
|
|
163
|
+
)
|
|
166
164
|
// eslint-disable-next-line prefer-destructuring
|
|
167
|
-
this.$firstButtonInDialog = dialogButtons[0]
|
|
168
|
-
this.$lastButtonInDialog = dialogButtons[dialogButtons.length - 1]
|
|
169
|
-
this.$firstButtonInDialog.addEventListener(
|
|
170
|
-
this.firstButtonKeydown(event)
|
|
171
|
-
)
|
|
172
|
-
this.$lastButtonInDialog.addEventListener(
|
|
173
|
-
this.lastButtonKeydown(event)
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
this.$calendarButton.addEventListener(
|
|
177
|
-
this.toggleDialog(event)
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
this.$dialog.addEventListener(
|
|
181
|
-
if (event.key ===
|
|
182
|
-
this.closeDialog()
|
|
183
|
-
event.preventDefault()
|
|
184
|
-
event.stopPropagation()
|
|
165
|
+
this.$firstButtonInDialog = dialogButtons[0]
|
|
166
|
+
this.$lastButtonInDialog = dialogButtons[dialogButtons.length - 1]
|
|
167
|
+
this.$firstButtonInDialog.addEventListener('keydown', (event) =>
|
|
168
|
+
this.firstButtonKeydown(event)
|
|
169
|
+
)
|
|
170
|
+
this.$lastButtonInDialog.addEventListener('keydown', (event) =>
|
|
171
|
+
this.lastButtonKeydown(event)
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
this.$calendarButton.addEventListener('click', (event) =>
|
|
175
|
+
this.toggleDialog(event)
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
this.$dialog.addEventListener('keydown', (event) => {
|
|
179
|
+
if (event.key === 'Escape') {
|
|
180
|
+
this.closeDialog()
|
|
181
|
+
event.preventDefault()
|
|
182
|
+
event.stopPropagation()
|
|
185
183
|
}
|
|
186
|
-
})
|
|
184
|
+
})
|
|
187
185
|
|
|
188
|
-
document.body.addEventListener(
|
|
189
|
-
this.backgroundClick(event)
|
|
190
|
-
)
|
|
186
|
+
document.body.addEventListener('mouseup', (event) =>
|
|
187
|
+
this.backgroundClick(event)
|
|
188
|
+
)
|
|
191
189
|
|
|
192
190
|
// populates calendar with initial dates, avoids Wave errors about null buttons
|
|
193
|
-
this.updateCalendar()
|
|
194
|
-
}
|
|
191
|
+
this.updateCalendar()
|
|
192
|
+
}
|
|
195
193
|
|
|
196
194
|
Datepicker.prototype.createDialog = function () {
|
|
197
|
-
const titleId = `datepicker-title-${this.$input.id}
|
|
198
|
-
const $dialog = document.createElement(
|
|
199
|
-
|
|
200
|
-
$dialog.id = this.id
|
|
201
|
-
$dialog.setAttribute(
|
|
202
|
-
$dialog.setAttribute(
|
|
203
|
-
$dialog.setAttribute(
|
|
204
|
-
$dialog.setAttribute(
|
|
205
|
-
$dialog.innerHTML = this.dialogTemplate(titleId)
|
|
206
|
-
$dialog.hidden = true
|
|
207
|
-
|
|
208
|
-
return $dialog
|
|
209
|
-
}
|
|
195
|
+
const titleId = `datepicker-title-${this.$input.id}`
|
|
196
|
+
const $dialog = document.createElement('div')
|
|
197
|
+
|
|
198
|
+
$dialog.id = this.id
|
|
199
|
+
$dialog.setAttribute('class', 'moj-datepicker__dialog')
|
|
200
|
+
$dialog.setAttribute('role', 'dialog')
|
|
201
|
+
$dialog.setAttribute('aria-modal', 'true')
|
|
202
|
+
$dialog.setAttribute('aria-labelledby', titleId)
|
|
203
|
+
$dialog.innerHTML = this.dialogTemplate(titleId)
|
|
204
|
+
$dialog.hidden = true
|
|
205
|
+
|
|
206
|
+
return $dialog
|
|
207
|
+
}
|
|
210
208
|
|
|
211
209
|
Datepicker.prototype.createCalendar = function () {
|
|
212
|
-
const $tbody = this.$dialog.querySelector(
|
|
213
|
-
let dayCount = 0
|
|
210
|
+
const $tbody = this.$dialog.querySelector('tbody')
|
|
211
|
+
let dayCount = 0
|
|
214
212
|
for (let i = 0; i < 6; i++) {
|
|
215
213
|
// create row
|
|
216
|
-
const $row = $tbody.insertRow(i)
|
|
214
|
+
const $row = $tbody.insertRow(i)
|
|
217
215
|
|
|
218
216
|
for (let j = 0; j < 7; j++) {
|
|
219
217
|
// create cell (day)
|
|
220
|
-
const $cell = document.createElement(
|
|
221
|
-
const $dateButton = document.createElement(
|
|
218
|
+
const $cell = document.createElement('td')
|
|
219
|
+
const $dateButton = document.createElement('button')
|
|
222
220
|
|
|
223
|
-
$cell.appendChild($dateButton)
|
|
224
|
-
$row.appendChild($cell)
|
|
221
|
+
$cell.appendChild($dateButton)
|
|
222
|
+
$row.appendChild($cell)
|
|
225
223
|
|
|
226
|
-
const calendarDay = new DSCalendarDay($dateButton, dayCount, i, j, this)
|
|
227
|
-
calendarDay.init()
|
|
228
|
-
this.calendarDays.push(calendarDay)
|
|
229
|
-
dayCount
|
|
224
|
+
const calendarDay = new DSCalendarDay($dateButton, dayCount, i, j, this)
|
|
225
|
+
calendarDay.init()
|
|
226
|
+
this.calendarDays.push(calendarDay)
|
|
227
|
+
dayCount++
|
|
230
228
|
}
|
|
231
229
|
}
|
|
232
|
-
}
|
|
230
|
+
}
|
|
233
231
|
|
|
234
232
|
Datepicker.prototype.toggleTemplate = function () {
|
|
235
233
|
return `<button class="moj-datepicker__toggle moj-js-datepicker-toggle" type="button" aria-haspopup="dialog" aria-controls="${this.id}" aria-expanded="false">
|
|
@@ -244,14 +242,14 @@ Datepicker.prototype.toggleTemplate = function () {
|
|
|
244
242
|
<rect x="3.66669" width="1.46667" height="5.13333" rx="0.733333" fill="currentColor"></rect>
|
|
245
243
|
<rect x="16.8667" width="1.46667" height="5.13333" rx="0.733333" fill="currentColor"></rect>
|
|
246
244
|
</svg>
|
|
247
|
-
</button
|
|
248
|
-
}
|
|
245
|
+
</button>`
|
|
246
|
+
}
|
|
249
247
|
|
|
250
248
|
/**
|
|
251
249
|
* HTML template for calendar dialog
|
|
252
250
|
*
|
|
253
251
|
* @param {string} [titleId] - Id attribute for dialog title
|
|
254
|
-
* @
|
|
252
|
+
* @returns {string}
|
|
255
253
|
*/
|
|
256
254
|
Datepicker.prototype.dialogTemplate = function (titleId) {
|
|
257
255
|
return `<div class="moj-datepicker__dialog-header">
|
|
@@ -303,213 +301,220 @@ Datepicker.prototype.dialogTemplate = function (titleId) {
|
|
|
303
301
|
<div class="govuk-button-group">
|
|
304
302
|
<button type="button" class="govuk-button moj-js-datepicker-ok">Select</button>
|
|
305
303
|
<button type="button" class="govuk-button govuk-button--secondary moj-js-datepicker-cancel">Close</button>
|
|
306
|
-
</div
|
|
307
|
-
}
|
|
304
|
+
</div>`
|
|
305
|
+
}
|
|
308
306
|
|
|
309
307
|
Datepicker.prototype.createCalendarHeaders = function () {
|
|
310
308
|
this.dayLabels.forEach((day) => {
|
|
311
|
-
const html = `<th scope="col"><span aria-hidden="true">${day.substring(0, 3)}</span><span class="govuk-visually-hidden">${day}</span></th
|
|
312
|
-
const $headerRow = this.$dialog.querySelector(
|
|
313
|
-
$headerRow.insertAdjacentHTML(
|
|
314
|
-
})
|
|
315
|
-
}
|
|
309
|
+
const html = `<th scope="col"><span aria-hidden="true">${day.substring(0, 3)}</span><span class="govuk-visually-hidden">${day}</span></th>`
|
|
310
|
+
const $headerRow = this.$dialog.querySelector('thead > tr')
|
|
311
|
+
$headerRow.insertAdjacentHTML('beforeend', html)
|
|
312
|
+
})
|
|
313
|
+
}
|
|
316
314
|
|
|
317
315
|
/**
|
|
318
316
|
* Pads given number with leading zeros
|
|
319
317
|
*
|
|
320
318
|
* @param {number} value - The value to be padded
|
|
321
319
|
* @param {number} length - The length in characters of the output
|
|
322
|
-
* @
|
|
320
|
+
* @returns {string}
|
|
323
321
|
*/
|
|
324
322
|
Datepicker.prototype.leadingZeros = function (value, length = 2) {
|
|
325
|
-
let ret = value.toString()
|
|
323
|
+
let ret = value.toString()
|
|
326
324
|
|
|
327
325
|
while (ret.length < length) {
|
|
328
|
-
ret = `0${ret}
|
|
326
|
+
ret = `0${ret}`
|
|
329
327
|
}
|
|
330
328
|
|
|
331
|
-
return ret
|
|
332
|
-
}
|
|
329
|
+
return ret
|
|
330
|
+
}
|
|
333
331
|
|
|
334
332
|
Datepicker.prototype.setOptions = function () {
|
|
335
|
-
this.setMinAndMaxDatesOnCalendar()
|
|
336
|
-
this.setExcludedDates()
|
|
337
|
-
this.setExcludedDays()
|
|
338
|
-
this.setLeadingZeros()
|
|
339
|
-
this.setWeekStartDay()
|
|
340
|
-
}
|
|
333
|
+
this.setMinAndMaxDatesOnCalendar()
|
|
334
|
+
this.setExcludedDates()
|
|
335
|
+
this.setExcludedDays()
|
|
336
|
+
this.setLeadingZeros()
|
|
337
|
+
this.setWeekStartDay()
|
|
338
|
+
}
|
|
341
339
|
|
|
342
340
|
Datepicker.prototype.setMinAndMaxDatesOnCalendar = function () {
|
|
343
341
|
if (this.config.minDate) {
|
|
344
|
-
this.minDate = this.formattedDateFromString(this.config.minDate, null)
|
|
342
|
+
this.minDate = this.formattedDateFromString(this.config.minDate, null)
|
|
345
343
|
if (this.minDate && this.currentDate < this.minDate) {
|
|
346
|
-
this.currentDate = this.minDate
|
|
344
|
+
this.currentDate = this.minDate
|
|
347
345
|
}
|
|
348
346
|
}
|
|
349
347
|
|
|
350
348
|
if (this.config.maxDate) {
|
|
351
|
-
this.maxDate = this.formattedDateFromString(this.config.maxDate, null)
|
|
349
|
+
this.maxDate = this.formattedDateFromString(this.config.maxDate, null)
|
|
352
350
|
if (this.maxDate && this.currentDate > this.maxDate) {
|
|
353
|
-
this.currentDate = this.maxDate
|
|
351
|
+
this.currentDate = this.maxDate
|
|
354
352
|
}
|
|
355
353
|
}
|
|
356
|
-
}
|
|
354
|
+
}
|
|
357
355
|
|
|
358
356
|
Datepicker.prototype.setExcludedDates = function () {
|
|
359
357
|
if (this.config.excludedDates) {
|
|
360
358
|
this.excludedDates = this.config.excludedDates
|
|
361
|
-
.replace(/\s+/,
|
|
362
|
-
.split(
|
|
359
|
+
.replace(/\s+/, ' ')
|
|
360
|
+
.split(' ')
|
|
363
361
|
.map((item) => {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
.split("-")
|
|
368
|
-
.map((d) => this.formattedDateFromString(d, null));
|
|
369
|
-
if (startDate && endDate) {
|
|
370
|
-
const date = new Date(startDate.getTime());
|
|
371
|
-
const dates = [];
|
|
372
|
-
while (date <= endDate) {
|
|
373
|
-
dates.push(new Date(date));
|
|
374
|
-
date.setDate(date.getDate() + 1);
|
|
375
|
-
}
|
|
376
|
-
return dates;
|
|
377
|
-
}
|
|
378
|
-
} else {
|
|
379
|
-
return this.formattedDateFromString(item, null);
|
|
380
|
-
}
|
|
362
|
+
return item.includes('-')
|
|
363
|
+
? this.parseDateRangeString(item)
|
|
364
|
+
: this.formattedDateFromString(item)
|
|
381
365
|
})
|
|
382
366
|
.flat()
|
|
383
|
-
.filter((item) => item)
|
|
367
|
+
.filter((item) => item)
|
|
384
368
|
}
|
|
385
|
-
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/*
|
|
372
|
+
* Parses a daterange string into an array of dates
|
|
373
|
+
* @param {String} datestring - A daterange string in the format "dd/mm/yyyy-dd/mm/yyyy"
|
|
374
|
+
* @returns {Date[]}
|
|
375
|
+
*/
|
|
376
|
+
Datepicker.prototype.parseDateRangeString = function (datestring) {
|
|
377
|
+
const dates = []
|
|
378
|
+
const [startDate, endDate] = datestring
|
|
379
|
+
.split('-')
|
|
380
|
+
.map((d) => this.formattedDateFromString(d, null))
|
|
381
|
+
|
|
382
|
+
if (startDate && endDate) {
|
|
383
|
+
const date = new Date(startDate.getTime())
|
|
384
|
+
/* eslint-disable no-unmodified-loop-condition */
|
|
385
|
+
while (date <= endDate) {
|
|
386
|
+
dates.push(new Date(date))
|
|
387
|
+
date.setDate(date.getDate() + 1)
|
|
388
|
+
}
|
|
389
|
+
/* eslint-enable no-unmodified-loop-condition */
|
|
390
|
+
}
|
|
391
|
+
return dates
|
|
392
|
+
}
|
|
386
393
|
|
|
387
394
|
Datepicker.prototype.setExcludedDays = function () {
|
|
388
395
|
if (this.config.excludedDays) {
|
|
389
396
|
// lowercase and arrange dayLabels to put indexOf sunday == 0 for comparison
|
|
390
397
|
// with getDay() function
|
|
391
|
-
|
|
392
|
-
if (this.config.weekStartDay ===
|
|
393
|
-
weekDays.unshift(weekDays.pop())
|
|
398
|
+
const weekDays = this.dayLabels.map((item) => item.toLowerCase())
|
|
399
|
+
if (this.config.weekStartDay === 'monday') {
|
|
400
|
+
weekDays.unshift(weekDays.pop())
|
|
394
401
|
}
|
|
395
402
|
|
|
396
403
|
this.excludedDays = this.config.excludedDays
|
|
397
|
-
.replace(/\s+/,
|
|
404
|
+
.replace(/\s+/, ' ')
|
|
398
405
|
.toLowerCase()
|
|
399
|
-
.split(
|
|
406
|
+
.split(' ')
|
|
400
407
|
.map((item) => weekDays.indexOf(item))
|
|
401
|
-
.filter((item) => item !== -1)
|
|
408
|
+
.filter((item) => item !== -1)
|
|
402
409
|
}
|
|
403
|
-
}
|
|
410
|
+
}
|
|
404
411
|
|
|
405
412
|
Datepicker.prototype.setLeadingZeros = function () {
|
|
406
|
-
if (typeof this.config.leadingZeros !==
|
|
407
|
-
if (this.config.leadingZeros.toLowerCase() ===
|
|
408
|
-
this.config.leadingZeros = true
|
|
409
|
-
return
|
|
413
|
+
if (typeof this.config.leadingZeros !== 'boolean') {
|
|
414
|
+
if (this.config.leadingZeros.toLowerCase() === 'true') {
|
|
415
|
+
this.config.leadingZeros = true
|
|
416
|
+
return
|
|
410
417
|
}
|
|
411
|
-
if (this.config.leadingZeros.toLowerCase() ===
|
|
412
|
-
this.config.leadingZeros = false
|
|
413
|
-
return;
|
|
418
|
+
if (this.config.leadingZeros.toLowerCase() === 'false') {
|
|
419
|
+
this.config.leadingZeros = false
|
|
414
420
|
}
|
|
415
421
|
}
|
|
416
|
-
}
|
|
422
|
+
}
|
|
417
423
|
|
|
418
424
|
Datepicker.prototype.setWeekStartDay = function () {
|
|
419
|
-
const weekStartDayParam = this.config.weekStartDay
|
|
420
|
-
if (weekStartDayParam
|
|
421
|
-
this.config.weekStartDay =
|
|
425
|
+
const weekStartDayParam = this.config.weekStartDay
|
|
426
|
+
if (weekStartDayParam && weekStartDayParam.toLowerCase() === 'sunday') {
|
|
427
|
+
this.config.weekStartDay = 'sunday'
|
|
422
428
|
// Rotate dayLabels array to put Sunday as the first item
|
|
423
|
-
this.dayLabels.unshift(this.dayLabels.pop())
|
|
429
|
+
this.dayLabels.unshift(this.dayLabels.pop())
|
|
424
430
|
} else {
|
|
425
|
-
this.config.weekStartDay =
|
|
431
|
+
this.config.weekStartDay = 'monday'
|
|
426
432
|
}
|
|
427
|
-
}
|
|
433
|
+
}
|
|
428
434
|
|
|
429
435
|
/**
|
|
430
436
|
* Determine if a date is selecteable
|
|
431
437
|
*
|
|
432
438
|
* @param {Date} date - the date to check
|
|
433
|
-
* @
|
|
434
|
-
*
|
|
439
|
+
* @returns {boolean}
|
|
435
440
|
*/
|
|
436
441
|
Datepicker.prototype.isExcludedDate = function (date) {
|
|
437
442
|
// This comparison does not work correctly - it will exclude the mindate itself
|
|
438
443
|
// see: https://github.com/ministryofjustice/moj-frontend/issues/923
|
|
439
444
|
if (this.minDate && this.minDate > date) {
|
|
440
|
-
return true
|
|
445
|
+
return true
|
|
441
446
|
}
|
|
442
447
|
|
|
443
448
|
// This comparison works as expected - the maxdate will not be excluded
|
|
444
449
|
if (this.maxDate && this.maxDate < date) {
|
|
445
|
-
return true
|
|
450
|
+
return true
|
|
446
451
|
}
|
|
447
452
|
|
|
448
453
|
for (const excludedDate of this.excludedDates) {
|
|
449
454
|
if (date.toDateString() === excludedDate.toDateString()) {
|
|
450
|
-
return true
|
|
455
|
+
return true
|
|
451
456
|
}
|
|
452
457
|
}
|
|
453
458
|
|
|
454
459
|
if (this.excludedDays.includes(date.getDay())) {
|
|
455
|
-
return true
|
|
460
|
+
return true
|
|
456
461
|
}
|
|
457
462
|
|
|
458
|
-
return false
|
|
459
|
-
}
|
|
463
|
+
return false
|
|
464
|
+
}
|
|
460
465
|
|
|
461
466
|
/**
|
|
462
467
|
* Get a Date object from a string
|
|
463
468
|
*
|
|
464
469
|
* @param {string} dateString - string in the format d/m/yyyy dd/mm/yyyy
|
|
465
470
|
* @param {Date} fallback - date object to return if formatting fails
|
|
466
|
-
* @
|
|
471
|
+
* @returns {Date}
|
|
467
472
|
*/
|
|
468
473
|
Datepicker.prototype.formattedDateFromString = function (
|
|
469
474
|
dateString,
|
|
470
|
-
fallback = new Date()
|
|
475
|
+
fallback = new Date()
|
|
471
476
|
) {
|
|
472
|
-
let formattedDate = null
|
|
477
|
+
let formattedDate = null
|
|
473
478
|
// Accepts d/m/yyyy and dd/mm/yyyy
|
|
474
|
-
const dateFormatPattern = /(\d{1,2})([-/,. ])(\d{1,2})\2(\d{4})
|
|
479
|
+
const dateFormatPattern = /(\d{1,2})([-/,. ])(\d{1,2})\2(\d{4})/
|
|
475
480
|
|
|
476
|
-
if (!dateFormatPattern.test(dateString)) return fallback
|
|
481
|
+
if (!dateFormatPattern.test(dateString)) return fallback
|
|
477
482
|
|
|
478
|
-
const match = dateString.match(dateFormatPattern)
|
|
479
|
-
const day = match[1]
|
|
480
|
-
const month = match[3]
|
|
481
|
-
const year = match[4]
|
|
483
|
+
const match = dateString.match(dateFormatPattern)
|
|
484
|
+
const day = match[1]
|
|
485
|
+
const month = match[3]
|
|
486
|
+
const year = match[4]
|
|
482
487
|
|
|
483
|
-
formattedDate = new Date(`${year}-${month}-${day}`)
|
|
488
|
+
formattedDate = new Date(`${year}-${month}-${day}`)
|
|
484
489
|
if (formattedDate instanceof Date && !isNaN(formattedDate)) {
|
|
485
|
-
return formattedDate
|
|
490
|
+
return formattedDate
|
|
486
491
|
}
|
|
487
|
-
return fallback
|
|
488
|
-
}
|
|
492
|
+
return fallback
|
|
493
|
+
}
|
|
489
494
|
|
|
490
495
|
/**
|
|
491
496
|
* Get a formatted date string from a Date object
|
|
492
497
|
*
|
|
493
498
|
* @param {Date} date - date to format to a string
|
|
494
|
-
* @
|
|
499
|
+
* @returns {string}
|
|
495
500
|
*/
|
|
496
501
|
Datepicker.prototype.formattedDateFromDate = function (date) {
|
|
497
502
|
if (this.config.leadingZeros) {
|
|
498
|
-
return `${this.leadingZeros(date.getDate())}/${this.leadingZeros(date.getMonth() + 1)}/${date.getFullYear()}
|
|
499
|
-
} else {
|
|
500
|
-
return `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`;
|
|
503
|
+
return `${this.leadingZeros(date.getDate())}/${this.leadingZeros(date.getMonth() + 1)}/${date.getFullYear()}`
|
|
501
504
|
}
|
|
502
|
-
|
|
505
|
+
|
|
506
|
+
return `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`
|
|
507
|
+
}
|
|
503
508
|
|
|
504
509
|
/**
|
|
505
510
|
* Get a human readable date in the format Monday 2 March 2024
|
|
506
511
|
*
|
|
507
|
-
* @param {Date} - date to format
|
|
508
|
-
* @
|
|
512
|
+
* @param {Date} date - date to format
|
|
513
|
+
* @returns {string}
|
|
509
514
|
*/
|
|
510
515
|
Datepicker.prototype.formattedDateHuman = function (date) {
|
|
511
|
-
return `${this.dayLabels[(date.getDay() + 6) % 7]} ${date.getDate()} ${this.monthLabels[date.getMonth()]} ${date.getFullYear()}
|
|
512
|
-
}
|
|
516
|
+
return `${this.dayLabels[(date.getDay() + 6) % 7]} ${date.getDate()} ${this.monthLabels[date.getMonth()]} ${date.getFullYear()}`
|
|
517
|
+
}
|
|
513
518
|
|
|
514
519
|
Datepicker.prototype.backgroundClick = function (event) {
|
|
515
520
|
if (
|
|
@@ -518,75 +523,75 @@ Datepicker.prototype.backgroundClick = function (event) {
|
|
|
518
523
|
!this.$input.contains(event.target) &&
|
|
519
524
|
!this.$calendarButton.contains(event.target)
|
|
520
525
|
) {
|
|
521
|
-
event.preventDefault()
|
|
522
|
-
this.closeDialog()
|
|
526
|
+
event.preventDefault()
|
|
527
|
+
this.closeDialog()
|
|
523
528
|
}
|
|
524
|
-
}
|
|
529
|
+
}
|
|
525
530
|
|
|
526
531
|
Datepicker.prototype.firstButtonKeydown = function (event) {
|
|
527
|
-
if (event.key ===
|
|
528
|
-
this.$lastButtonInDialog.focus()
|
|
529
|
-
event.preventDefault()
|
|
532
|
+
if (event.key === 'Tab' && event.shiftKey) {
|
|
533
|
+
this.$lastButtonInDialog.focus()
|
|
534
|
+
event.preventDefault()
|
|
530
535
|
}
|
|
531
|
-
}
|
|
536
|
+
}
|
|
532
537
|
|
|
533
538
|
Datepicker.prototype.lastButtonKeydown = function (event) {
|
|
534
|
-
if (event.key ===
|
|
535
|
-
this.$firstButtonInDialog.focus()
|
|
536
|
-
event.preventDefault()
|
|
539
|
+
if (event.key === 'Tab' && !event.shiftKey) {
|
|
540
|
+
this.$firstButtonInDialog.focus()
|
|
541
|
+
event.preventDefault()
|
|
537
542
|
}
|
|
538
|
-
}
|
|
543
|
+
}
|
|
539
544
|
|
|
540
545
|
// render calendar
|
|
541
546
|
Datepicker.prototype.updateCalendar = function () {
|
|
542
|
-
this.$dialogTitle.innerHTML = `${this.monthLabels[this.currentDate.getMonth()]} ${this.currentDate.getFullYear()}
|
|
547
|
+
this.$dialogTitle.innerHTML = `${this.monthLabels[this.currentDate.getMonth()]} ${this.currentDate.getFullYear()}`
|
|
543
548
|
|
|
544
|
-
const day = this.currentDate
|
|
545
|
-
const firstOfMonth = new Date(day.getFullYear(), day.getMonth(), 1)
|
|
546
|
-
let dayOfWeek
|
|
549
|
+
const day = this.currentDate
|
|
550
|
+
const firstOfMonth = new Date(day.getFullYear(), day.getMonth(), 1)
|
|
551
|
+
let dayOfWeek
|
|
547
552
|
|
|
548
|
-
if (this.config.weekStartDay ===
|
|
549
|
-
dayOfWeek = firstOfMonth.getDay() === 0 ? 6 : firstOfMonth.getDay() - 1
|
|
553
|
+
if (this.config.weekStartDay === 'monday') {
|
|
554
|
+
dayOfWeek = firstOfMonth.getDay() === 0 ? 6 : firstOfMonth.getDay() - 1 // Change logic to make Monday first day of week, i.e. 0
|
|
550
555
|
} else {
|
|
551
|
-
dayOfWeek = firstOfMonth.getDay()
|
|
556
|
+
dayOfWeek = firstOfMonth.getDay()
|
|
552
557
|
}
|
|
553
558
|
|
|
554
|
-
firstOfMonth.setDate(firstOfMonth.getDate() - dayOfWeek)
|
|
559
|
+
firstOfMonth.setDate(firstOfMonth.getDate() - dayOfWeek)
|
|
555
560
|
|
|
556
|
-
const thisDay = new Date(firstOfMonth)
|
|
561
|
+
const thisDay = new Date(firstOfMonth)
|
|
557
562
|
|
|
558
563
|
// loop through our days
|
|
559
564
|
for (let i = 0; i < this.calendarDays.length; i++) {
|
|
560
|
-
const hidden = thisDay.getMonth() !== day.getMonth()
|
|
561
|
-
const disabled = this.isExcludedDate(thisDay)
|
|
565
|
+
const hidden = thisDay.getMonth() !== day.getMonth()
|
|
566
|
+
const disabled = this.isExcludedDate(thisDay)
|
|
562
567
|
|
|
563
|
-
this.calendarDays[i].update(thisDay, hidden, disabled)
|
|
568
|
+
this.calendarDays[i].update(thisDay, hidden, disabled)
|
|
564
569
|
|
|
565
|
-
thisDay.setDate(thisDay.getDate() + 1)
|
|
570
|
+
thisDay.setDate(thisDay.getDate() + 1)
|
|
566
571
|
}
|
|
567
|
-
}
|
|
572
|
+
}
|
|
568
573
|
|
|
569
574
|
Datepicker.prototype.setCurrentDate = function (focus = true) {
|
|
570
|
-
const { currentDate } = this
|
|
575
|
+
const { currentDate } = this
|
|
571
576
|
this.calendarDays.forEach((calendarDay) => {
|
|
572
|
-
calendarDay.button.classList.add(
|
|
573
|
-
calendarDay.button.classList.add(
|
|
574
|
-
calendarDay.button.setAttribute(
|
|
575
|
-
calendarDay.button.classList.remove(this.selectedDayButtonClass)
|
|
576
|
-
const calendarDayDate = calendarDay.date
|
|
577
|
-
calendarDayDate.setHours(0, 0, 0, 0)
|
|
577
|
+
calendarDay.button.classList.add('moj-datepicker__button')
|
|
578
|
+
calendarDay.button.classList.add('moj-datepicker__calendar-day')
|
|
579
|
+
calendarDay.button.setAttribute('tabindex', -1)
|
|
580
|
+
calendarDay.button.classList.remove(this.selectedDayButtonClass)
|
|
581
|
+
const calendarDayDate = calendarDay.date
|
|
582
|
+
calendarDayDate.setHours(0, 0, 0, 0)
|
|
578
583
|
|
|
579
|
-
const today = new Date()
|
|
580
|
-
today.setHours(0, 0, 0, 0)
|
|
584
|
+
const today = new Date()
|
|
585
|
+
today.setHours(0, 0, 0, 0)
|
|
581
586
|
|
|
582
587
|
if (
|
|
583
588
|
calendarDayDate.getTime() ===
|
|
584
589
|
currentDate.getTime() /* && !calendarDay.button.disabled */
|
|
585
590
|
) {
|
|
586
591
|
if (focus) {
|
|
587
|
-
calendarDay.button.setAttribute(
|
|
588
|
-
calendarDay.button.focus()
|
|
589
|
-
calendarDay.button.classList.add(this.selectedDayButtonClass)
|
|
592
|
+
calendarDay.button.setAttribute('tabindex', 0)
|
|
593
|
+
calendarDay.button.focus()
|
|
594
|
+
calendarDay.button.classList.add(this.selectedDayButtonClass)
|
|
590
595
|
}
|
|
591
596
|
}
|
|
592
597
|
|
|
@@ -594,213 +599,210 @@ Datepicker.prototype.setCurrentDate = function (focus = true) {
|
|
|
594
599
|
this.inputDate &&
|
|
595
600
|
calendarDayDate.getTime() === this.inputDate.getTime()
|
|
596
601
|
) {
|
|
597
|
-
calendarDay.button.classList.add(this.currentDayButtonClass)
|
|
598
|
-
calendarDay.button.setAttribute(
|
|
602
|
+
calendarDay.button.classList.add(this.currentDayButtonClass)
|
|
603
|
+
calendarDay.button.setAttribute('aria-current', 'date')
|
|
599
604
|
} else {
|
|
600
|
-
calendarDay.button.classList.remove(this.currentDayButtonClass)
|
|
601
|
-
calendarDay.button.removeAttribute(
|
|
605
|
+
calendarDay.button.classList.remove(this.currentDayButtonClass)
|
|
606
|
+
calendarDay.button.removeAttribute('aria-current')
|
|
602
607
|
}
|
|
603
608
|
|
|
604
609
|
if (calendarDayDate.getTime() === today.getTime()) {
|
|
605
|
-
calendarDay.button.classList.add(this.todayButtonClass)
|
|
610
|
+
calendarDay.button.classList.add(this.todayButtonClass)
|
|
606
611
|
} else {
|
|
607
|
-
calendarDay.button.classList.remove(this.todayButtonClass)
|
|
612
|
+
calendarDay.button.classList.remove(this.todayButtonClass)
|
|
608
613
|
}
|
|
609
|
-
})
|
|
614
|
+
})
|
|
610
615
|
|
|
611
616
|
// if no date is tab-able, make the first non-disabled date tab-able
|
|
612
617
|
if (!focus) {
|
|
613
618
|
const enabledDays = this.calendarDays.filter((calendarDay) => {
|
|
614
619
|
return (
|
|
615
|
-
window.getComputedStyle(calendarDay.button).display ===
|
|
620
|
+
window.getComputedStyle(calendarDay.button).display === 'block' &&
|
|
616
621
|
!calendarDay.button.disabled
|
|
617
|
-
)
|
|
618
|
-
})
|
|
622
|
+
)
|
|
623
|
+
})
|
|
619
624
|
|
|
620
|
-
enabledDays[0].button.setAttribute(
|
|
625
|
+
enabledDays[0].button.setAttribute('tabindex', 0)
|
|
621
626
|
|
|
622
|
-
this.currentDate = enabledDays[0].date
|
|
627
|
+
this.currentDate = enabledDays[0].date
|
|
623
628
|
}
|
|
624
|
-
}
|
|
629
|
+
}
|
|
625
630
|
|
|
626
631
|
Datepicker.prototype.selectDate = function (date) {
|
|
627
632
|
if (this.isExcludedDate(date)) {
|
|
628
|
-
return
|
|
633
|
+
return
|
|
629
634
|
}
|
|
630
635
|
|
|
631
|
-
this.$calendarButton.querySelector(
|
|
632
|
-
`Choose date. Selected date is ${this.formattedDateHuman(date)}
|
|
633
|
-
this.$input.value = this.formattedDateFromDate(date)
|
|
636
|
+
this.$calendarButton.querySelector('span').innerText =
|
|
637
|
+
`Choose date. Selected date is ${this.formattedDateHuman(date)}`
|
|
638
|
+
this.$input.value = this.formattedDateFromDate(date)
|
|
634
639
|
|
|
635
|
-
const changeEvent = new Event(
|
|
636
|
-
this.$input.dispatchEvent(changeEvent)
|
|
640
|
+
const changeEvent = new Event('change', { bubbles: true, cancelable: true })
|
|
641
|
+
this.$input.dispatchEvent(changeEvent)
|
|
637
642
|
|
|
638
|
-
this.closeDialog()
|
|
639
|
-
}
|
|
643
|
+
this.closeDialog()
|
|
644
|
+
}
|
|
640
645
|
|
|
641
646
|
Datepicker.prototype.isOpen = function () {
|
|
642
|
-
return this.$dialog.classList.contains(
|
|
643
|
-
}
|
|
647
|
+
return this.$dialog.classList.contains('moj-datepicker__dialog--open')
|
|
648
|
+
}
|
|
644
649
|
|
|
645
650
|
Datepicker.prototype.toggleDialog = function (event) {
|
|
646
|
-
event.preventDefault()
|
|
651
|
+
event.preventDefault()
|
|
647
652
|
if (this.isOpen()) {
|
|
648
|
-
this.closeDialog()
|
|
653
|
+
this.closeDialog()
|
|
649
654
|
} else {
|
|
650
|
-
this.setMinAndMaxDatesOnCalendar()
|
|
651
|
-
this.openDialog()
|
|
655
|
+
this.setMinAndMaxDatesOnCalendar()
|
|
656
|
+
this.openDialog()
|
|
652
657
|
}
|
|
653
|
-
}
|
|
658
|
+
}
|
|
654
659
|
|
|
655
660
|
Datepicker.prototype.openDialog = function () {
|
|
656
|
-
this.$dialog.hidden = false
|
|
657
|
-
this.$dialog.classList.add(
|
|
658
|
-
this.$calendarButton.setAttribute(
|
|
661
|
+
this.$dialog.hidden = false
|
|
662
|
+
this.$dialog.classList.add('moj-datepicker__dialog--open')
|
|
663
|
+
this.$calendarButton.setAttribute('aria-expanded', 'true')
|
|
659
664
|
|
|
660
665
|
// position the dialog
|
|
661
666
|
// if input is wider than dialog pin it to the right
|
|
662
667
|
if (this.$input.offsetWidth > this.$dialog.offsetWidth) {
|
|
663
|
-
this.$dialog.style.right = `0px
|
|
668
|
+
this.$dialog.style.right = `0px`
|
|
664
669
|
}
|
|
665
|
-
this.$dialog.style.top = `${this.$input.offsetHeight + 3}px
|
|
670
|
+
this.$dialog.style.top = `${this.$input.offsetHeight + 3}px`
|
|
666
671
|
|
|
667
672
|
// get the date from the input element
|
|
668
|
-
this.inputDate = this.formattedDateFromString(this.$input.value)
|
|
669
|
-
this.currentDate = this.inputDate
|
|
670
|
-
this.currentDate.setHours(0, 0, 0, 0)
|
|
673
|
+
this.inputDate = this.formattedDateFromString(this.$input.value)
|
|
674
|
+
this.currentDate = this.inputDate
|
|
675
|
+
this.currentDate.setHours(0, 0, 0, 0)
|
|
671
676
|
|
|
672
|
-
this.updateCalendar()
|
|
673
|
-
this.setCurrentDate()
|
|
674
|
-
}
|
|
677
|
+
this.updateCalendar()
|
|
678
|
+
this.setCurrentDate()
|
|
679
|
+
}
|
|
675
680
|
|
|
676
681
|
Datepicker.prototype.closeDialog = function () {
|
|
677
|
-
this.$dialog.hidden = true
|
|
678
|
-
this.$dialog.classList.remove(
|
|
679
|
-
this.$calendarButton.setAttribute(
|
|
680
|
-
this.$calendarButton.focus()
|
|
681
|
-
}
|
|
682
|
+
this.$dialog.hidden = true
|
|
683
|
+
this.$dialog.classList.remove('moj-datepicker__dialog--open')
|
|
684
|
+
this.$calendarButton.setAttribute('aria-expanded', 'false')
|
|
685
|
+
this.$calendarButton.focus()
|
|
686
|
+
}
|
|
682
687
|
|
|
683
688
|
Datepicker.prototype.goToDate = function (date, focus) {
|
|
684
|
-
const current = this.currentDate
|
|
685
|
-
this.currentDate = date
|
|
689
|
+
const current = this.currentDate
|
|
690
|
+
this.currentDate = date
|
|
686
691
|
|
|
687
692
|
if (
|
|
688
693
|
current.getMonth() !== this.currentDate.getMonth() ||
|
|
689
694
|
current.getFullYear() !== this.currentDate.getFullYear()
|
|
690
695
|
) {
|
|
691
|
-
this.updateCalendar()
|
|
696
|
+
this.updateCalendar()
|
|
692
697
|
}
|
|
693
698
|
|
|
694
|
-
this.setCurrentDate(focus)
|
|
695
|
-
}
|
|
699
|
+
this.setCurrentDate(focus)
|
|
700
|
+
}
|
|
696
701
|
|
|
697
702
|
// day navigation
|
|
698
703
|
Datepicker.prototype.focusNextDay = function () {
|
|
699
|
-
const date = new Date(this.currentDate)
|
|
700
|
-
date.setDate(date.getDate() + 1)
|
|
701
|
-
this.goToDate(date)
|
|
702
|
-
}
|
|
704
|
+
const date = new Date(this.currentDate)
|
|
705
|
+
date.setDate(date.getDate() + 1)
|
|
706
|
+
this.goToDate(date)
|
|
707
|
+
}
|
|
703
708
|
|
|
704
709
|
Datepicker.prototype.focusPreviousDay = function () {
|
|
705
|
-
const date = new Date(this.currentDate)
|
|
706
|
-
date.setDate(date.getDate() - 1)
|
|
707
|
-
this.goToDate(date)
|
|
708
|
-
}
|
|
710
|
+
const date = new Date(this.currentDate)
|
|
711
|
+
date.setDate(date.getDate() - 1)
|
|
712
|
+
this.goToDate(date)
|
|
713
|
+
}
|
|
709
714
|
|
|
710
715
|
// week navigation
|
|
711
716
|
Datepicker.prototype.focusNextWeek = function () {
|
|
712
|
-
const date = new Date(this.currentDate)
|
|
713
|
-
date.setDate(date.getDate() + 7)
|
|
714
|
-
this.goToDate(date)
|
|
715
|
-
}
|
|
717
|
+
const date = new Date(this.currentDate)
|
|
718
|
+
date.setDate(date.getDate() + 7)
|
|
719
|
+
this.goToDate(date)
|
|
720
|
+
}
|
|
716
721
|
|
|
717
722
|
Datepicker.prototype.focusPreviousWeek = function () {
|
|
718
|
-
const date = new Date(this.currentDate)
|
|
719
|
-
date.setDate(date.getDate() - 7)
|
|
720
|
-
this.goToDate(date)
|
|
721
|
-
}
|
|
723
|
+
const date = new Date(this.currentDate)
|
|
724
|
+
date.setDate(date.getDate() - 7)
|
|
725
|
+
this.goToDate(date)
|
|
726
|
+
}
|
|
722
727
|
|
|
723
728
|
Datepicker.prototype.focusFirstDayOfWeek = function () {
|
|
724
|
-
const date = new Date(this.currentDate)
|
|
725
|
-
const firstDayOfWeekIndex = this.config.weekStartDay
|
|
726
|
-
const dayOfWeek = date.getDay()
|
|
729
|
+
const date = new Date(this.currentDate)
|
|
730
|
+
const firstDayOfWeekIndex = this.config.weekStartDay === 'sunday' ? 0 : 1
|
|
731
|
+
const dayOfWeek = date.getDay()
|
|
727
732
|
const diff =
|
|
728
733
|
dayOfWeek >= firstDayOfWeekIndex
|
|
729
734
|
? dayOfWeek - firstDayOfWeekIndex
|
|
730
|
-
: 6 - dayOfWeek
|
|
735
|
+
: 6 - dayOfWeek
|
|
731
736
|
|
|
732
|
-
date.setDate(date.getDate() - diff)
|
|
733
|
-
date.setHours(0, 0, 0, 0)
|
|
737
|
+
date.setDate(date.getDate() - diff)
|
|
738
|
+
date.setHours(0, 0, 0, 0)
|
|
734
739
|
|
|
735
|
-
this.goToDate(date)
|
|
736
|
-
}
|
|
740
|
+
this.goToDate(date)
|
|
741
|
+
}
|
|
737
742
|
|
|
738
743
|
Datepicker.prototype.focusLastDayOfWeek = function () {
|
|
739
|
-
const date = new Date(this.currentDate)
|
|
740
|
-
const lastDayOfWeekIndex = this.config.weekStartDay
|
|
741
|
-
const dayOfWeek = date.getDay()
|
|
744
|
+
const date = new Date(this.currentDate)
|
|
745
|
+
const lastDayOfWeekIndex = this.config.weekStartDay === 'sunday' ? 6 : 0
|
|
746
|
+
const dayOfWeek = date.getDay()
|
|
742
747
|
const diff =
|
|
743
748
|
dayOfWeek <= lastDayOfWeekIndex
|
|
744
749
|
? lastDayOfWeekIndex - dayOfWeek
|
|
745
|
-
: 7 - dayOfWeek
|
|
750
|
+
: 7 - dayOfWeek
|
|
746
751
|
|
|
747
|
-
date.setDate(date.getDate() + diff)
|
|
748
|
-
date.setHours(0, 0, 0, 0)
|
|
752
|
+
date.setDate(date.getDate() + diff)
|
|
753
|
+
date.setHours(0, 0, 0, 0)
|
|
749
754
|
|
|
750
|
-
this.goToDate(date)
|
|
751
|
-
}
|
|
755
|
+
this.goToDate(date)
|
|
756
|
+
}
|
|
752
757
|
|
|
753
758
|
// month navigation
|
|
754
759
|
Datepicker.prototype.focusNextMonth = function (event, focus = true) {
|
|
755
|
-
event.preventDefault()
|
|
756
|
-
const date = new Date(this.currentDate)
|
|
757
|
-
date.setMonth(date.getMonth() + 1, 1)
|
|
758
|
-
this.goToDate(date, focus)
|
|
759
|
-
}
|
|
760
|
+
event.preventDefault()
|
|
761
|
+
const date = new Date(this.currentDate)
|
|
762
|
+
date.setMonth(date.getMonth() + 1, 1)
|
|
763
|
+
this.goToDate(date, focus)
|
|
764
|
+
}
|
|
760
765
|
|
|
761
766
|
Datepicker.prototype.focusPreviousMonth = function (event, focus = true) {
|
|
762
|
-
event.preventDefault()
|
|
763
|
-
const date = new Date(this.currentDate)
|
|
764
|
-
date.setMonth(date.getMonth() - 1, 1)
|
|
765
|
-
this.goToDate(date, focus)
|
|
766
|
-
}
|
|
767
|
+
event.preventDefault()
|
|
768
|
+
const date = new Date(this.currentDate)
|
|
769
|
+
date.setMonth(date.getMonth() - 1, 1)
|
|
770
|
+
this.goToDate(date, focus)
|
|
771
|
+
}
|
|
767
772
|
|
|
768
773
|
// year navigation
|
|
769
774
|
Datepicker.prototype.focusNextYear = function (event, focus = true) {
|
|
770
|
-
event.preventDefault()
|
|
771
|
-
const date = new Date(this.currentDate)
|
|
772
|
-
date.setFullYear(date.getFullYear() + 1, date.getMonth(), 1)
|
|
773
|
-
this.goToDate(date, focus)
|
|
774
|
-
}
|
|
775
|
+
event.preventDefault()
|
|
776
|
+
const date = new Date(this.currentDate)
|
|
777
|
+
date.setFullYear(date.getFullYear() + 1, date.getMonth(), 1)
|
|
778
|
+
this.goToDate(date, focus)
|
|
779
|
+
}
|
|
775
780
|
|
|
776
781
|
Datepicker.prototype.focusPreviousYear = function (event, focus = true) {
|
|
777
|
-
event.preventDefault()
|
|
778
|
-
const date = new Date(this.currentDate)
|
|
779
|
-
date.setFullYear(date.getFullYear() - 1, date.getMonth(), 1)
|
|
780
|
-
this.goToDate(date, focus)
|
|
781
|
-
}
|
|
782
|
+
event.preventDefault()
|
|
783
|
+
const date = new Date(this.currentDate)
|
|
784
|
+
date.setFullYear(date.getFullYear() - 1, date.getMonth(), 1)
|
|
785
|
+
this.goToDate(date, focus)
|
|
786
|
+
}
|
|
782
787
|
|
|
783
788
|
/**
|
|
784
789
|
* Parse dataset
|
|
785
790
|
*
|
|
786
|
-
*
|
|
787
|
-
* optionally expanding nested `i18n.field`
|
|
788
|
-
*
|
|
789
|
-
* @param {{ schema: Schema }} Component - Component class
|
|
791
|
+
* @param {Schema} schema - Component class
|
|
790
792
|
* @param {DOMStringMap} dataset - HTML element dataset
|
|
791
|
-
* @returns {
|
|
793
|
+
* @returns {object} Normalised dataset
|
|
792
794
|
*/
|
|
793
795
|
Datepicker.prototype.parseDataset = function (schema, dataset) {
|
|
794
|
-
const parsed = {}
|
|
796
|
+
const parsed = {}
|
|
795
797
|
|
|
796
|
-
for (const [field,
|
|
798
|
+
for (const [field, ,] of Object.entries(schema.properties)) {
|
|
797
799
|
if (field in dataset) {
|
|
798
|
-
parsed[field] = dataset[field]
|
|
800
|
+
parsed[field] = dataset[field]
|
|
799
801
|
}
|
|
800
802
|
}
|
|
801
803
|
|
|
802
|
-
return parsed
|
|
803
|
-
}
|
|
804
|
+
return parsed
|
|
805
|
+
}
|
|
804
806
|
|
|
805
807
|
/**
|
|
806
808
|
* Config merging function
|
|
@@ -812,28 +814,28 @@ Datepicker.prototype.parseDataset = function (schema, dataset) {
|
|
|
812
814
|
* @returns {{ [key: string]: unknown }} A merged config object
|
|
813
815
|
*/
|
|
814
816
|
Datepicker.prototype.mergeConfigs = function (...configObjects) {
|
|
815
|
-
const formattedConfigObject = {}
|
|
817
|
+
const formattedConfigObject = {}
|
|
816
818
|
|
|
817
819
|
// Loop through each of the passed objects
|
|
818
820
|
for (const configObject of configObjects) {
|
|
819
821
|
for (const key of Object.keys(configObject)) {
|
|
820
|
-
const option = formattedConfigObject[key]
|
|
821
|
-
const override = configObject[key]
|
|
822
|
+
const option = formattedConfigObject[key]
|
|
823
|
+
const override = configObject[key]
|
|
822
824
|
|
|
823
825
|
// Push their keys one-by-one into formattedConfigObject. Any duplicate
|
|
824
826
|
// keys with object values will be merged, otherwise the new value will
|
|
825
827
|
// override the existing value.
|
|
826
|
-
if (typeof option ===
|
|
828
|
+
if (typeof option === 'object' && typeof override === 'object') {
|
|
827
829
|
// @ts-expect-error Index signature for type 'string' is missing
|
|
828
|
-
formattedConfigObject[key] = this.mergeConfigs(option, override)
|
|
830
|
+
formattedConfigObject[key] = this.mergeConfigs(option, override)
|
|
829
831
|
} else {
|
|
830
|
-
formattedConfigObject[key] = override
|
|
832
|
+
formattedConfigObject[key] = override
|
|
831
833
|
}
|
|
832
834
|
}
|
|
833
835
|
}
|
|
834
836
|
|
|
835
|
-
return formattedConfigObject
|
|
836
|
-
}
|
|
837
|
+
return formattedConfigObject
|
|
838
|
+
}
|
|
837
839
|
|
|
838
840
|
/**
|
|
839
841
|
*
|
|
@@ -842,22 +844,22 @@ Datepicker.prototype.mergeConfigs = function (...configObjects) {
|
|
|
842
844
|
* @param {number} row
|
|
843
845
|
* @param {number} column
|
|
844
846
|
* @param {Datepicker} picker
|
|
845
|
-
* @
|
|
847
|
+
* @class
|
|
846
848
|
*/
|
|
847
849
|
function DSCalendarDay(button, index, row, column, picker) {
|
|
848
|
-
this.index = index
|
|
849
|
-
this.row = row
|
|
850
|
-
this.column = column
|
|
851
|
-
this.button = button
|
|
852
|
-
this.picker = picker
|
|
850
|
+
this.index = index
|
|
851
|
+
this.row = row
|
|
852
|
+
this.column = column
|
|
853
|
+
this.button = button
|
|
854
|
+
this.picker = picker
|
|
853
855
|
|
|
854
|
-
this.date = new Date()
|
|
856
|
+
this.date = new Date()
|
|
855
857
|
}
|
|
856
858
|
|
|
857
859
|
DSCalendarDay.prototype.init = function () {
|
|
858
|
-
this.button.addEventListener(
|
|
859
|
-
this.button.addEventListener(
|
|
860
|
-
}
|
|
860
|
+
this.button.addEventListener('keydown', this.keyPress.bind(this))
|
|
861
|
+
this.button.addEventListener('click', this.click.bind(this))
|
|
862
|
+
}
|
|
861
863
|
|
|
862
864
|
/**
|
|
863
865
|
* @param {Date} day - the Date for the calendar day
|
|
@@ -865,84 +867,84 @@ DSCalendarDay.prototype.init = function () {
|
|
|
865
867
|
* @param {boolean} disabled - is the day selectable or excluded
|
|
866
868
|
*/
|
|
867
869
|
DSCalendarDay.prototype.update = function (day, hidden, disabled) {
|
|
868
|
-
|
|
869
|
-
let accessibleLabel = this.picker.formattedDateHuman(day)
|
|
870
|
+
const label = day.getDate()
|
|
871
|
+
let accessibleLabel = this.picker.formattedDateHuman(day)
|
|
870
872
|
|
|
871
873
|
if (disabled) {
|
|
872
|
-
this.button.setAttribute(
|
|
873
|
-
accessibleLabel =
|
|
874
|
+
this.button.setAttribute('aria-disabled', true)
|
|
875
|
+
accessibleLabel = `Excluded date, ${accessibleLabel}`
|
|
874
876
|
} else {
|
|
875
|
-
this.button.removeAttribute(
|
|
877
|
+
this.button.removeAttribute('aria-disabled')
|
|
876
878
|
}
|
|
877
879
|
|
|
878
880
|
if (hidden) {
|
|
879
|
-
this.button.style.display =
|
|
881
|
+
this.button.style.display = 'none'
|
|
880
882
|
} else {
|
|
881
|
-
this.button.style.display =
|
|
883
|
+
this.button.style.display = 'block'
|
|
882
884
|
}
|
|
883
885
|
this.button.setAttribute(
|
|
884
|
-
|
|
885
|
-
this.picker.formattedDateFromDate(day)
|
|
886
|
-
)
|
|
886
|
+
'data-testid',
|
|
887
|
+
this.picker.formattedDateFromDate(day)
|
|
888
|
+
)
|
|
887
889
|
|
|
888
|
-
this.button.innerHTML = `<span class="govuk-visually-hidden">${accessibleLabel}</span><span aria-hidden="true">${label}</span
|
|
889
|
-
this.date = new Date(day)
|
|
890
|
-
}
|
|
890
|
+
this.button.innerHTML = `<span class="govuk-visually-hidden">${accessibleLabel}</span><span aria-hidden="true">${label}</span>`
|
|
891
|
+
this.date = new Date(day)
|
|
892
|
+
}
|
|
891
893
|
|
|
892
894
|
DSCalendarDay.prototype.click = function (event) {
|
|
893
|
-
this.picker.goToDate(this.date)
|
|
894
|
-
this.picker.selectDate(this.date)
|
|
895
|
+
this.picker.goToDate(this.date)
|
|
896
|
+
this.picker.selectDate(this.date)
|
|
895
897
|
|
|
896
|
-
event.stopPropagation()
|
|
897
|
-
event.preventDefault()
|
|
898
|
-
}
|
|
898
|
+
event.stopPropagation()
|
|
899
|
+
event.preventDefault()
|
|
900
|
+
}
|
|
899
901
|
|
|
900
902
|
DSCalendarDay.prototype.keyPress = function (event) {
|
|
901
|
-
let calendarNavKey = true
|
|
903
|
+
let calendarNavKey = true
|
|
902
904
|
|
|
903
905
|
switch (event.key) {
|
|
904
|
-
case
|
|
905
|
-
this.picker.focusPreviousDay()
|
|
906
|
-
break
|
|
907
|
-
case
|
|
908
|
-
this.picker.focusNextDay()
|
|
909
|
-
break
|
|
910
|
-
case
|
|
911
|
-
this.picker.focusPreviousWeek()
|
|
912
|
-
break
|
|
913
|
-
case
|
|
914
|
-
this.picker.focusNextWeek()
|
|
915
|
-
break
|
|
916
|
-
case
|
|
917
|
-
this.picker.focusFirstDayOfWeek()
|
|
918
|
-
break
|
|
919
|
-
case
|
|
920
|
-
this.picker.focusLastDayOfWeek()
|
|
921
|
-
break
|
|
922
|
-
case
|
|
906
|
+
case 'ArrowLeft':
|
|
907
|
+
this.picker.focusPreviousDay()
|
|
908
|
+
break
|
|
909
|
+
case 'ArrowRight':
|
|
910
|
+
this.picker.focusNextDay()
|
|
911
|
+
break
|
|
912
|
+
case 'ArrowUp':
|
|
913
|
+
this.picker.focusPreviousWeek()
|
|
914
|
+
break
|
|
915
|
+
case 'ArrowDown':
|
|
916
|
+
this.picker.focusNextWeek()
|
|
917
|
+
break
|
|
918
|
+
case 'Home':
|
|
919
|
+
this.picker.focusFirstDayOfWeek()
|
|
920
|
+
break
|
|
921
|
+
case 'End':
|
|
922
|
+
this.picker.focusLastDayOfWeek()
|
|
923
|
+
break
|
|
924
|
+
case 'PageUp':
|
|
923
925
|
// eslint-disable-next-line no-unused-expressions
|
|
924
926
|
event.shiftKey
|
|
925
927
|
? this.picker.focusPreviousYear(event)
|
|
926
|
-
: this.picker.focusPreviousMonth(event)
|
|
927
|
-
break
|
|
928
|
-
case
|
|
928
|
+
: this.picker.focusPreviousMonth(event)
|
|
929
|
+
break
|
|
930
|
+
case 'PageDown':
|
|
929
931
|
// eslint-disable-next-line no-unused-expressions
|
|
930
932
|
event.shiftKey
|
|
931
933
|
? this.picker.focusNextYear(event)
|
|
932
|
-
: this.picker.focusNextMonth(event)
|
|
933
|
-
break
|
|
934
|
+
: this.picker.focusNextMonth(event)
|
|
935
|
+
break
|
|
934
936
|
default:
|
|
935
|
-
calendarNavKey = false
|
|
936
|
-
break
|
|
937
|
+
calendarNavKey = false
|
|
938
|
+
break
|
|
937
939
|
}
|
|
938
940
|
|
|
939
941
|
if (calendarNavKey) {
|
|
940
|
-
event.preventDefault()
|
|
941
|
-
event.stopPropagation()
|
|
942
|
+
event.preventDefault()
|
|
943
|
+
event.stopPropagation()
|
|
942
944
|
}
|
|
943
|
-
}
|
|
945
|
+
}
|
|
944
946
|
|
|
945
|
-
MOJFrontend.DatePicker = Datepicker
|
|
947
|
+
MOJFrontend.DatePicker = Datepicker
|
|
946
948
|
|
|
947
949
|
/**
|
|
948
950
|
* Schema for component config
|