flatpickr_rails 1.0.0 → 1.1.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +1 -1
  4. data/lib/flatpickr_rails/version.rb +1 -1
  5. data/vendor/assets/javascripts/flatpickr.js +1408 -701
  6. data/vendor/assets/stylesheets/flatpickr.css +842 -7
  7. data/vendor/assets/stylesheets/flatpickr/airbnb.css +926 -0
  8. data/vendor/assets/stylesheets/flatpickr/airbnb.rtl.css +946 -0
  9. data/vendor/assets/stylesheets/flatpickr/base16_flat.rtl.css +869 -0
  10. data/vendor/assets/stylesheets/flatpickr/confetti.css +859 -0
  11. data/vendor/assets/stylesheets/flatpickr/confetti.rtl.css +883 -0
  12. data/vendor/assets/stylesheets/flatpickr/dark.css +848 -0
  13. data/vendor/assets/stylesheets/flatpickr/dark.rtl.css +869 -0
  14. data/vendor/assets/stylesheets/flatpickr/flatpickr.css +848 -0
  15. data/vendor/assets/stylesheets/flatpickr/light.css +862 -0
  16. data/vendor/assets/stylesheets/flatpickr/material_blue.css +859 -0
  17. data/vendor/assets/stylesheets/flatpickr/material_blue.rtl.css +883 -0
  18. data/vendor/assets/stylesheets/flatpickr/material_green.css +859 -0
  19. data/vendor/assets/stylesheets/flatpickr/material_green.rtl.css +883 -0
  20. data/vendor/assets/stylesheets/flatpickr/material_orange.css +859 -0
  21. data/vendor/assets/stylesheets/flatpickr/material_orange.rtl.css +883 -0
  22. data/vendor/assets/stylesheets/flatpickr/material_red.css +859 -0
  23. data/vendor/assets/stylesheets/flatpickr/material_red.rtl.css +883 -0
  24. metadata +19 -19
  25. data/vendor/assets/stylesheets/flatpickr.airbnb.css +0 -13
  26. data/vendor/assets/stylesheets/flatpickr.airbnb.rtl.css +0 -13
  27. data/vendor/assets/stylesheets/flatpickr.base16_flat.css +0 -13
  28. data/vendor/assets/stylesheets/flatpickr.base16_flat.rtl.css +0 -13
  29. data/vendor/assets/stylesheets/flatpickr.confetti.css +0 -13
  30. data/vendor/assets/stylesheets/flatpickr.confetti.rtl.css +0 -13
  31. data/vendor/assets/stylesheets/flatpickr.dark.css +0 -13
  32. data/vendor/assets/stylesheets/flatpickr.dark.rtl.css +0 -13
  33. data/vendor/assets/stylesheets/flatpickr.material_blue.css +0 -13
  34. data/vendor/assets/stylesheets/flatpickr.material_blue.rtl.css +0 -13
  35. data/vendor/assets/stylesheets/flatpickr.material_green.css +0 -13
  36. data/vendor/assets/stylesheets/flatpickr.material_green.rtl.css +0 -13
  37. data/vendor/assets/stylesheets/flatpickr.material_orange.css +0 -13
  38. data/vendor/assets/stylesheets/flatpickr.material_orange.rtl.css +0 -13
  39. data/vendor/assets/stylesheets/flatpickr.material_red.css +0 -13
  40. data/vendor/assets/stylesheets/flatpickr.material_red.rtl.css +0 -13
  41. data/vendor/assets/stylesheets/flatpickr.rtl.css +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 50f7b3b2de24cbdca4152f52970c2a3fb94d304e
4
- data.tar.gz: d6e87b110359eb61ea4605964db9c28215231a77
3
+ metadata.gz: e11cbf708ff2af51f285a15e791c78e1e523de9f
4
+ data.tar.gz: 97b804c5b3a95be9e256f8e39621bdb4e351d581
5
5
  SHA512:
6
- metadata.gz: 17aac1145148b860f308425813ce64cba79fc4a04958580b7eea1a542711170cf70faa91ac5536d286a4c79f6ae9fb3dfd39c4804abd41c4fa3851259fa3f436
7
- data.tar.gz: 932fb54899722e893911e91098db410e37412ff1b345d039043f8a5d89564f37481d39df5f73be57cf5d89c42d69b74ffcd5c5718518acbb32a3ec05db60e923
6
+ metadata.gz: e677124185b2cf2b4775eb4bd150b7606f7a138cb17b3a9a3d6d596f14c5637a404133f64e8082b043fc560ca80a7243084c6c0d78732da2f94292af38590c12
7
+ data.tar.gz: d862fe33f8ba2ed4772d2e9dbae6dbdf2551afc27462056ac2dca9d0cb313c9acc3ead84ba2eda4b66420c5ad4d40670c642d1d9b5054a8ba65f020ea3981832
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ *.gem
data/README.md CHANGED
@@ -33,7 +33,7 @@ Add this line to app/assets/stylesheets/application.css
33
33
  To use one of the themes, add:
34
34
 
35
35
  ```css
36
- *= require flatpickr.material_red
36
+ *= require flatpickr/material_red
37
37
  ```
38
38
 
39
39
  Available themes are: airbnb, base16_flat, confetti, dark, material_blue, material_green, material_orange, material_red.
@@ -1,3 +1,3 @@
1
1
  module FlatpickrRails
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -2,72 +2,81 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument
2
2
 
3
3
  var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
4
4
 
5
- /*! flatpickr v2.2.3, @license MIT */
6
- function Flatpickr(element, config) {
5
+ /*! flatpickr v3.0.5-1, @license MIT */
6
+ function FlatpickrInstance(element, config) {
7
7
  var self = this;
8
8
 
9
- function init() {
10
- if (element._flatpickr) destroy(element._flatpickr);
11
-
12
- element._flatpickr = self;
9
+ self._ = {};
10
+ self._.afterDayAnim = afterDayAnim;
11
+ self._bind = bind;
12
+ self._compareDates = compareDates;
13
+ self._setHoursFromDate = setHoursFromDate;
14
+ self.changeMonth = changeMonth;
15
+ self.changeYear = changeYear;
16
+ self.clear = clear;
17
+ self.close = close;
18
+ self._createElement = createElement;
19
+ self.destroy = destroy;
20
+ self.isEnabled = isEnabled;
21
+ self.jumpToDate = jumpToDate;
22
+ self.open = open;
23
+ self.redraw = redraw;
24
+ self.set = set;
25
+ self.setDate = setDate;
26
+ self.toggle = toggle;
13
27
 
14
- self.element = element;
28
+ function init() {
29
+ self.element = self.input = element;
15
30
  self.instanceConfig = config || {};
31
+ self.parseDate = FlatpickrInstance.prototype.parseDate.bind(self);
32
+ self.formatDate = FlatpickrInstance.prototype.formatDate.bind(self);
16
33
 
17
34
  setupFormats();
18
-
19
35
  parseConfig();
20
36
  setupLocale();
21
37
  setupInputs();
22
38
  setupDates();
23
-
24
39
  setupHelperFunctions();
25
40
 
26
- self.isOpen = self.config.inline;
27
- self.changeMonth = changeMonth;
28
- self.clear = clear;
29
- self.close = close;
30
- self.destroy = destroy;
31
- self.formatDate = formatDate;
32
- self.jumpToDate = jumpToDate;
33
- self.open = open;
34
- self.parseDate = parseDate;
35
- self.redraw = redraw;
36
- self.set = set;
37
- self.setDate = setDate;
38
- self.toggle = toggle;
39
-
40
- self.isMobile = !self.config.disableMobile && !self.config.inline && self.config.mode === "single" && !self.config.disable.length && !self.config.enable.length && /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
41
-
42
- if (!self.isMobile) build();
41
+ self.isOpen = false;
43
42
 
44
- bind();
43
+ self.isMobile = !self.config.disableMobile && !self.config.inline && self.config.mode === "single" && !self.config.disable.length && !self.config.enable.length && !self.config.weekNumbers && /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
45
44
 
46
- self.minDateHasTime = self.config.minDate && (self.config.minDate.getHours() || self.config.minDate.getMinutes() || self.config.minDate.getSeconds());
45
+ if (!self.isMobile) build();
47
46
 
48
- self.maxDateHasTime = self.config.maxDate && (self.config.maxDate.getHours() || self.config.maxDate.getMinutes() || self.config.maxDate.getSeconds());
47
+ bindEvents();
49
48
 
50
- if (!self.isMobile) {
51
- Object.defineProperty(self, "dateIsPicked", {
52
- set: function set(bool) {
53
- if (bool) return self.calendarContainer.classList.add("dateIsPicked");
54
- self.calendarContainer.classList.remove("dateIsPicked");
55
- }
56
- });
49
+ if (self.selectedDates.length || self.config.noCalendar) {
50
+ if (self.config.enableTime) {
51
+ setHoursFromDate(self.config.noCalendar ? self.latestSelectedDateObj || self.config.minDate : null);
52
+ }
53
+ updateValue();
57
54
  }
58
55
 
59
- self.dateIsPicked = self.selectedDates.length > 0 || self.config.noCalendar;
56
+ self.showTimeInput = self.selectedDates.length > 0 || self.config.noCalendar;
60
57
 
61
- if (self.selectedDates.length) {
62
- if (self.config.enableTime) setHoursFromDate();
63
- updateValue();
58
+ if (self.config.weekNumbers) {
59
+ self.calendarContainer.style.width = self.daysContainer.offsetWidth + self.weekWrapper.offsetWidth + "px";
64
60
  }
65
61
 
66
- if (self.config.weekNumbers) self.calendarContainer.style.width = self.days.offsetWidth + self.weekWrapper.offsetWidth + 2 + "px";
62
+ if (!self.isMobile) positionCalendar();
67
63
 
68
64
  triggerEvent("Ready");
69
65
  }
70
66
 
67
+ /**
68
+ * Binds a function to the current flatpickr instance
69
+ * @param {Function} fn the function
70
+ * @return {Function} the function bound to the instance
71
+ */
72
+ function bindToInstance(fn) {
73
+ return fn.bind(self);
74
+ }
75
+
76
+ /**
77
+ * The handler for all events targeting the time inputs
78
+ * @param {Event} e the event - "input", "wheel", "increment", etc
79
+ */
71
80
  function updateTime(e) {
72
81
  if (self.config.noCalendar && !self.selectedDates.length)
73
82
  // picking time only
@@ -77,23 +86,36 @@ function Flatpickr(element, config) {
77
86
 
78
87
  if (!self.selectedDates.length) return;
79
88
 
80
- setHoursFromInputs();
81
- updateValue();
89
+ if (!self.minDateHasTime || e.type !== "input" || e.target.value.length >= 2) {
90
+ setHoursFromInputs();
91
+ updateValue();
92
+ } else {
93
+ setTimeout(function () {
94
+ setHoursFromInputs();
95
+ updateValue();
96
+ }, 1000);
97
+ }
82
98
  }
83
99
 
100
+ /**
101
+ * Syncs the selected date object time with user's time input
102
+ */
84
103
  function setHoursFromInputs() {
85
104
  if (!self.config.enableTime) return;
86
105
 
87
- var hours = parseInt(self.hourElement.value, 10) || 0,
88
- minutes = parseInt(self.minuteElement.value, 10) || 0,
89
- seconds = self.config.enableSeconds ? parseInt(self.secondElement.value, 10) || 0 : 0;
106
+ var hours = (parseInt(self.hourElement.value, 10) || 0) % (self.amPM ? 12 : 24),
107
+ minutes = (parseInt(self.minuteElement.value, 10) || 0) % 60,
108
+ seconds = self.config.enableSeconds ? (parseInt(self.secondElement.value, 10) || 0) % 60 : 0;
109
+
110
+ if (self.amPM !== undefined) hours = hours % 12 + 12 * (self.amPM.textContent === "PM");
90
111
 
91
- if (self.amPM) hours = hours % 12 + 12 * (self.amPM.innerHTML === "PM");
112
+ if (self.minDateHasTime && compareDates(self.latestSelectedDateObj, self.config.minDate) === 0) {
92
113
 
93
- if (self.minDateHasTime && compareDates(latestSelectedDateObj(), self.config.minDate) === 0) {
94
114
  hours = Math.max(hours, self.config.minDate.getHours());
95
115
  if (hours === self.config.minDate.getHours()) minutes = Math.max(minutes, self.config.minDate.getMinutes());
96
- } else if (self.maxDateHasTime && compareDates(latestSelectedDateObj(), self.config.maxDate) === 0) {
116
+ }
117
+
118
+ if (self.maxDateHasTime && compareDates(self.latestSelectedDateObj, self.config.maxDate) === 0) {
97
119
  hours = Math.min(hours, self.config.maxDate.getHours());
98
120
  if (hours === self.config.maxDate.getHours()) minutes = Math.min(minutes, self.config.maxDate.getMinutes());
99
121
  }
@@ -101,15 +123,28 @@ function Flatpickr(element, config) {
101
123
  setHours(hours, minutes, seconds);
102
124
  }
103
125
 
126
+ /**
127
+ * Syncs time input values with a date
128
+ * @param {Date} dateObj the date to sync with
129
+ */
104
130
  function setHoursFromDate(dateObj) {
105
- var date = dateObj || latestSelectedDateObj();
131
+ var date = dateObj || self.latestSelectedDateObj;
106
132
 
107
133
  if (date) setHours(date.getHours(), date.getMinutes(), date.getSeconds());
108
134
  }
109
135
 
136
+ /**
137
+ * Sets the hours, minutes, and optionally seconds
138
+ * of the latest selected date object and the
139
+ * corresponding time inputs
140
+ * @param {Number} hours the hour. whether its military
141
+ * or am-pm gets inferred from config
142
+ * @param {Number} minutes the minutes
143
+ * @param {Number} seconds the seconds (optional)
144
+ */
110
145
  function setHours(hours, minutes, seconds) {
111
146
  if (self.selectedDates.length) {
112
- self.selectedDates[self.selectedDates.length - 1].setHours(hours % 24, minutes, seconds || 0, 0);
147
+ self.latestSelectedDateObj.setHours(hours % 24, minutes, seconds || 0, 0);
113
148
  }
114
149
 
115
150
  if (!self.config.enableTime || self.isMobile) return;
@@ -118,129 +153,239 @@ function Flatpickr(element, config) {
118
153
 
119
154
  self.minuteElement.value = self.pad(minutes);
120
155
 
121
- if (!self.config.time_24hr && self.selectedDates.length) self.amPM.textContent = latestSelectedDateObj().getHours() >= 12 ? "PM" : "AM";
156
+ if (!self.config.time_24hr) self.amPM.textContent = hours >= 12 ? "PM" : "AM";
122
157
 
123
- if (self.config.enableSeconds) self.secondElement.value = self.pad(seconds);
158
+ if (self.config.enableSeconds === true) self.secondElement.value = self.pad(seconds);
124
159
  }
125
160
 
126
- function bind() {
127
- if (self.config.wrap) {
128
- ["open", "close", "toggle", "clear"].forEach(function (el) {
129
- try {
130
- self.element.querySelector("[data-" + el + "]").addEventListener("click", self[el]);
131
- } catch (e) {
132
- //
133
- }
134
- });
161
+ /**
162
+ * Handles the year input and incrementing events
163
+ * @param {Event} event the keyup or increment event
164
+ */
165
+ function onYearInput(event) {
166
+ var year = event.target.value;
167
+ if (event.delta) year = (parseInt(year) + event.delta).toString();
168
+
169
+ if (year.length === 4 || event.key === "Enter") {
170
+ self.currentYearElement.blur();
171
+ if (!/[^\d]/.test(year)) changeYear(year);
135
172
  }
173
+ }
174
+
175
+ /**
176
+ * Essentially addEventListener + tracking
177
+ * @param {Element} element the element to addEventListener to
178
+ * @param {String} event the event name
179
+ * @param {Function} handler the event handler
180
+ */
181
+ function bind(element, event, handler) {
182
+ if (event instanceof Array) return event.forEach(function (ev) {
183
+ return bind(element, ev, handler);
184
+ });
185
+
186
+ if (element instanceof Array) return element.forEach(function (el) {
187
+ return bind(el, event, handler);
188
+ });
189
+
190
+ element.addEventListener(event, handler);
191
+ self._handlers.push({ element: element, event: event, handler: handler });
192
+ }
136
193
 
137
- if ("createEvent" in document) {
138
- self.changeEvent = document.createEvent("HTMLEvents");
139
- self.changeEvent.initEvent("change", false, true);
194
+ /**
195
+ * A mousedown handler which mimics click.
196
+ * Minimizes latency, since we don't need to wait for mouseup in most cases.
197
+ * Also, avoids handling right clicks.
198
+ *
199
+ * @param {Function} handler the event handler
200
+ */
201
+ function onClick(handler) {
202
+ return function (evt) {
203
+ return evt.which === 1 && handler(evt);
204
+ };
205
+ }
206
+
207
+ /**
208
+ * Adds all the necessary event listeners
209
+ */
210
+ function bindEvents() {
211
+ self._handlers = [];
212
+ self._animationLoop = [];
213
+ if (self.config.wrap) {
214
+ ["open", "close", "toggle", "clear"].forEach(function (evt) {
215
+ Array.prototype.forEach.call(self.element.querySelectorAll("[data-" + evt + "]"), function (el) {
216
+ return bind(el, "mousedown", onClick(self[evt]));
217
+ });
218
+ });
140
219
  }
141
220
 
142
221
  if (self.isMobile) return setupMobile();
143
222
 
144
223
  self.debouncedResize = debounce(onResize, 50);
145
224
  self.triggerChange = function () {
146
- return triggerEvent("Change");
225
+ triggerEvent("Change");
147
226
  };
148
- self.debouncedChange = debounce(self.triggerChange, 1000);
227
+ self.debouncedChange = debounce(self.triggerChange, 300);
228
+
229
+ if (self.config.mode === "range" && self.daysContainer) bind(self.daysContainer, "mouseover", function (e) {
230
+ return onMouseOver(e.target);
231
+ });
149
232
 
150
- if (self.config.mode === "range") self.days.addEventListener("mouseover", onMouseOver);
233
+ bind(window.document.body, "keydown", onKeyDown);
151
234
 
152
- document.addEventListener("keydown", onKeyDown);
153
- window.addEventListener("resize", self.debouncedResize);
235
+ if (!self.config.static) bind(self._input, "keydown", onKeyDown);
154
236
 
155
- var clickEvent = typeof window.ontouchstart !== "undefined" ? "touchstart" : "click";
237
+ if (!self.config.inline && !self.config.static) bind(window, "resize", self.debouncedResize);
156
238
 
157
- document.addEventListener(clickEvent, documentClick);
158
- document.addEventListener("blur", documentClick);
239
+ if (window.ontouchstart !== undefined) bind(window.document, "touchstart", documentClick);
159
240
 
160
- if (self.config.clickOpens) (self.altInput || self.input).addEventListener("focus", open);
241
+ bind(window.document, "mousedown", onClick(documentClick));
242
+ bind(self._input, "blur", documentClick);
161
243
 
162
- if (!self.config.noCalendar) {
163
- self.prevMonthNav.addEventListener("click", function () {
164
- return changeMonth(-1);
165
- });
166
- self.nextMonthNav.addEventListener("click", function () {
167
- return changeMonth(1);
168
- });
244
+ if (self.config.clickOpens === true) {
245
+ bind(self._input, "focus", self.open);
246
+ bind(self._input, "mousedown", onClick(self.open));
247
+ }
169
248
 
170
- self.currentYearElement.addEventListener("wheel", function (e) {
171
- return debounce(yearScroll(e), 50);
172
- });
173
- self.currentYearElement.addEventListener("focus", function () {
174
- self.currentYearElement.select();
249
+ if (!self.config.noCalendar) {
250
+ self.monthNav.addEventListener("wheel", function (e) {
251
+ return e.preventDefault();
175
252
  });
253
+ bind(self.monthNav, "wheel", debounce(onMonthNavScroll, 10));
254
+ bind(self.monthNav, "mousedown", onClick(onMonthNavClick));
176
255
 
177
- self.currentYearElement.addEventListener("input", function (event) {
178
- if (event.target.value.length === 4) {
179
- self.currentYearElement.blur();
180
- handleYearChange(event.target.value);
181
- event.target.value = self.currentYear;
182
- }
183
- });
256
+ bind(self.monthNav, ["keyup", "increment"], onYearInput);
257
+ bind(self.daysContainer, "mousedown", onClick(selectDate));
184
258
 
185
- self.days.addEventListener("click", selectDate);
259
+ if (self.config.animate) {
260
+ bind(self.daysContainer, ["webkitAnimationEnd", "animationend"], animateDays);
261
+ bind(self.monthNav, ["webkitAnimationEnd", "animationend"], animateMonths);
262
+ }
186
263
  }
187
264
 
188
265
  if (self.config.enableTime) {
189
- self.timeContainer.addEventListener("wheel", function (e) {
190
- return debounce(updateTime(e), 5);
191
- });
192
- self.timeContainer.addEventListener("input", updateTime);
266
+ var selText = function selText(e) {
267
+ return e.target.select();
268
+ };
269
+ bind(self.timeContainer, ["wheel", "input", "increment"], updateTime);
270
+ bind(self.timeContainer, "mousedown", onClick(timeIncrement));
193
271
 
194
- self.timeContainer.addEventListener("wheel", self.debouncedChange);
195
- self.timeContainer.addEventListener("input", self.triggerChange);
272
+ bind(self.timeContainer, ["wheel", "increment"], self.debouncedChange);
273
+ bind(self.timeContainer, "input", self.triggerChange);
196
274
 
197
- self.hourElement.addEventListener("focus", function () {
198
- self.hourElement.select();
199
- });
200
- self.minuteElement.addEventListener("focus", function () {
201
- self.minuteElement.select();
202
- });
275
+ bind([self.hourElement, self.minuteElement], "focus", selText);
203
276
 
204
- if (self.secondElement) {
205
- self.secondElement.addEventListener("focus", function () {
206
- self.secondElement.select();
207
- });
208
- }
277
+ if (self.secondElement !== undefined) bind(self.secondElement, "focus", function () {
278
+ return self.secondElement.select();
279
+ });
209
280
 
210
- if (self.amPM) {
211
- self.amPM.addEventListener("click", function (e) {
281
+ if (self.amPM !== undefined) {
282
+ bind(self.amPM, "mousedown", onClick(function (e) {
212
283
  updateTime(e);
213
284
  self.triggerChange(e);
214
- });
285
+ }));
286
+ }
287
+ }
288
+ }
289
+
290
+ function processPostDayAnimation() {
291
+ for (var i = self._animationLoop.length; i--;) {
292
+ self._animationLoop[i]();
293
+ self._animationLoop.splice(i, 1);
294
+ }
295
+ }
296
+
297
+ /**
298
+ * Removes the day container that slided out of view
299
+ * @param {Event} e the animation event
300
+ */
301
+ function animateDays(e) {
302
+ if (self.daysContainer.childNodes.length > 1) {
303
+ switch (e.animationName) {
304
+ case "fpSlideLeft":
305
+ self.daysContainer.lastChild.classList.remove("slideLeftNew");
306
+ self.daysContainer.removeChild(self.daysContainer.firstChild);
307
+ self.days = self.daysContainer.firstChild;
308
+ processPostDayAnimation();
309
+
310
+ break;
311
+
312
+ case "fpSlideRight":
313
+ self.daysContainer.firstChild.classList.remove("slideRightNew");
314
+ self.daysContainer.removeChild(self.daysContainer.lastChild);
315
+ self.days = self.daysContainer.firstChild;
316
+ processPostDayAnimation();
317
+
318
+ break;
319
+
320
+ default:
321
+ break;
215
322
  }
216
323
  }
217
324
  }
218
325
 
326
+ /**
327
+ * Removes the month element that animated out of view
328
+ * @param {Event} e the animation event
329
+ */
330
+ function animateMonths(e) {
331
+ switch (e.animationName) {
332
+ case "fpSlideLeftNew":
333
+ case "fpSlideRightNew":
334
+ self.navigationCurrentMonth.classList.remove("slideLeftNew");
335
+ self.navigationCurrentMonth.classList.remove("slideRightNew");
336
+ var nav = self.navigationCurrentMonth;
337
+
338
+ while (nav.nextSibling && /curr/.test(nav.nextSibling.className)) {
339
+ self.monthNav.removeChild(nav.nextSibling);
340
+ }while (nav.previousSibling && /curr/.test(nav.previousSibling.className)) {
341
+ self.monthNav.removeChild(nav.previousSibling);
342
+ }self.oldCurMonth = null;
343
+ break;
344
+ }
345
+ }
346
+
347
+ /**
348
+ * Set the calendar view to a particular date.
349
+ * @param {Date} jumpDate the date to set the view to
350
+ */
219
351
  function jumpToDate(jumpDate) {
220
- jumpDate = jumpDate ? parseDate(jumpDate) : latestSelectedDateObj() || (self.config.minDate > self.now ? self.config.minDate : self.now);
352
+ jumpDate = jumpDate ? self.parseDate(jumpDate) : self.latestSelectedDateObj || (self.config.minDate > self.now ? self.config.minDate : self.config.maxDate && self.config.maxDate < self.now ? self.config.maxDate : self.now);
221
353
 
222
354
  try {
223
355
  self.currentYear = jumpDate.getFullYear();
224
356
  self.currentMonth = jumpDate.getMonth();
225
357
  } catch (e) {
358
+ /* istanbul ignore next */
226
359
  console.error(e.stack);
360
+ /* istanbul ignore next */
227
361
  console.warn("Invalid date supplied: " + jumpDate);
228
362
  }
229
363
 
230
364
  self.redraw();
231
365
  }
232
366
 
233
- function incrementNumInput(e, delta) {
234
- var input = e.target.parentNode.childNodes[0];
235
- input.value = parseInt(input.value, 10) + delta * (input.step || 1);
367
+ /**
368
+ * The up/down arrow handler for time inputs
369
+ * @param {Event} e the click event
370
+ */
371
+ function timeIncrement(e) {
372
+ if (~e.target.className.indexOf("arrow")) incrementNumInput(e, e.target.classList.contains("arrowUp") ? 1 : -1);
373
+ }
236
374
 
237
- try {
238
- input.dispatchEvent(new Event("input", { "bubbles": true }));
239
- } catch (e) {
240
- var ev = document.createEvent("CustomEvent");
241
- ev.initCustomEvent("input", true, true, {});
242
- input.dispatchEvent(ev);
243
- }
375
+ /**
376
+ * Increments/decrements the value of input associ-
377
+ * ated with the up/down arrow by dispatching an
378
+ * "increment" event on the input.
379
+ *
380
+ * @param {Event} e the click event
381
+ * @param {Number} delta the diff (usually 1 or -1)
382
+ * @param {Element} inputElem the input element
383
+ */
384
+ function incrementNumInput(e, delta, inputElem) {
385
+ var input = inputElem || e.target.parentNode.childNodes[0];
386
+ var event = createEvent("increment");
387
+ event.delta = delta;
388
+ input.dispatchEvent(event);
244
389
  }
245
390
 
246
391
  function createNumberInput(inputClassName) {
@@ -250,23 +395,19 @@ function Flatpickr(element, config) {
250
395
  arrowDown = createElement("span", "arrowDown");
251
396
 
252
397
  numInput.type = "text";
398
+ numInput.pattern = "\\d*";
399
+
253
400
  wrapper.appendChild(numInput);
254
401
  wrapper.appendChild(arrowUp);
255
402
  wrapper.appendChild(arrowDown);
256
403
 
257
- arrowUp.addEventListener("click", function (e) {
258
- return incrementNumInput(e, 1);
259
- });
260
- arrowDown.addEventListener("click", function (e) {
261
- return incrementNumInput(e, -1);
262
- });
263
404
  return wrapper;
264
405
  }
265
406
 
266
407
  function build() {
267
- var fragment = document.createDocumentFragment();
408
+ var fragment = window.document.createDocumentFragment();
268
409
  self.calendarContainer = createElement("div", "flatpickr-calendar");
269
- self.numInputType = navigator.userAgent.indexOf("MSIE 9.0") > 0 ? "text" : "number";
410
+ self.calendarContainer.tabIndex = -1;
270
411
 
271
412
  if (!self.config.noCalendar) {
272
413
  fragment.appendChild(buildMonthNav());
@@ -276,42 +417,73 @@ function Flatpickr(element, config) {
276
417
 
277
418
  self.rContainer = createElement("div", "flatpickr-rContainer");
278
419
  self.rContainer.appendChild(buildWeekdays());
279
- self.rContainer.appendChild(buildDays());
420
+
421
+ if (!self.daysContainer) {
422
+ self.daysContainer = createElement("div", "flatpickr-days");
423
+ self.daysContainer.tabIndex = -1;
424
+ }
425
+
426
+ buildDays();
427
+ self.rContainer.appendChild(self.daysContainer);
428
+
280
429
  self.innerContainer.appendChild(self.rContainer);
281
430
  fragment.appendChild(self.innerContainer);
282
431
  }
283
432
 
284
433
  if (self.config.enableTime) fragment.appendChild(buildTime());
285
434
 
435
+ toggleClass(self.calendarContainer, "rangeMode", self.config.mode === "range");
436
+ toggleClass(self.calendarContainer, "animate", self.config.animate);
437
+
286
438
  self.calendarContainer.appendChild(fragment);
287
439
 
440
+ var customAppend = self.config.appendTo && self.config.appendTo.nodeType;
441
+
288
442
  if (self.config.inline || self.config.static) {
289
443
  self.calendarContainer.classList.add(self.config.inline ? "inline" : "static");
290
- positionCalendar();
291
444
 
292
- if (self.config.appendTo && self.config.appendTo.nodeType) self.config.appendTo.appendChild(self.calendarContainer);else {
293
- self.element.parentNode.insertBefore(self.calendarContainer, (self.altInput || self.input).nextSibling);
445
+ if (self.config.inline && !customAppend) {
446
+ return self.element.parentNode.insertBefore(self.calendarContainer, self._input.nextSibling);
447
+ }
448
+
449
+ if (self.config.static) {
450
+ var wrapper = createElement("div", "flatpickr-wrapper");
451
+ self.element.parentNode.insertBefore(wrapper, self.element);
452
+ wrapper.appendChild(self.element);
453
+
454
+ if (self.altInput) wrapper.appendChild(self.altInput);
455
+
456
+ wrapper.appendChild(self.calendarContainer);
457
+ return;
294
458
  }
295
- } else document.body.appendChild(self.calendarContainer);
459
+ }
460
+
461
+ (customAppend ? self.config.appendTo : window.document.body).appendChild(self.calendarContainer);
296
462
  }
297
463
 
298
- function createDay(className, date, dayNumber) {
299
- var dateIsEnabled = isEnabled(date),
464
+ function createDay(className, date, dayNumber, i) {
465
+ var dateIsEnabled = isEnabled(date, true),
300
466
  dayElement = createElement("span", "flatpickr-day " + className, date.getDate());
301
467
 
302
468
  dayElement.dateObj = date;
469
+ dayElement.$i = i;
470
+ dayElement.setAttribute("aria-label", self.formatDate(date, self.config.ariaDateFormat));
303
471
 
304
- if (compareDates(date, self.now) === 0) dayElement.classList.add("today");
472
+ if (compareDates(date, self.now) === 0) {
473
+ self.todayDateElem = dayElement;
474
+ dayElement.classList.add("today");
475
+ }
305
476
 
306
477
  if (dateIsEnabled) {
307
- dayElement.tabIndex = 0;
308
-
478
+ dayElement.tabIndex = -1;
309
479
  if (isDateSelected(date)) {
310
480
  dayElement.classList.add("selected");
311
-
481
+ self.selectedDateElem = dayElement;
312
482
  if (self.config.mode === "range") {
313
- dayElement.classList.add(compareDates(date, self.selectedDates[0]) === 0 ? "startRange" : "endRange");
314
- } else self.selectedDateElem = dayElement;
483
+ toggleClass(dayElement, "startRange", compareDates(date, self.selectedDates[0]) === 0);
484
+
485
+ toggleClass(dayElement, "endRange", compareDates(date, self.selectedDates[1]) === 0);
486
+ }
315
487
  }
316
488
  } else {
317
489
  dayElement.classList.add("disabled");
@@ -333,58 +505,109 @@ function Flatpickr(element, config) {
333
505
  return dayElement;
334
506
  }
335
507
 
336
- function buildDays() {
337
- if (!self.days) {
338
- self.days = createElement("div", "flatpickr-days");
339
- self.days.tabIndex = -1;
508
+ function focusOnDay(currentIndex, offset) {
509
+ var newIndex = currentIndex + offset || 0,
510
+ targetNode = currentIndex !== undefined ? self.days.childNodes[newIndex] : self.selectedDateElem || self.todayDateElem || self.days.childNodes[0],
511
+ focus = function focus() {
512
+ targetNode = targetNode || self.days.childNodes[newIndex];
513
+ targetNode.focus();
514
+
515
+ if (self.config.mode === "range") onMouseOver(targetNode);
516
+ };
517
+
518
+ if (targetNode === undefined && offset !== 0) {
519
+ if (offset > 0) {
520
+ self.changeMonth(1);
521
+ newIndex = newIndex % 42;
522
+ } else if (offset < 0) {
523
+ self.changeMonth(-1);
524
+ newIndex += 42;
525
+ }
526
+
527
+ return afterDayAnim(focus);
340
528
  }
341
529
 
342
- self.firstOfMonth = (new Date(self.currentYear, self.currentMonth, 1).getDay() - self.l10n.firstDayOfWeek + 7) % 7;
530
+ focus();
531
+ }
532
+
533
+ function afterDayAnim(fn) {
534
+ if (self.config.animate === true) return self._animationLoop.push(fn);
535
+ fn();
536
+ }
537
+
538
+ function buildDays(delta) {
539
+ var firstOfMonth = (new Date(self.currentYear, self.currentMonth, 1).getDay() - self.l10n.firstDayOfWeek + 7) % 7,
540
+ isRangeMode = self.config.mode === "range";
343
541
 
344
542
  self.prevMonthDays = self.utils.getDaysinMonth((self.currentMonth - 1 + 12) % 12);
543
+ self.selectedDateElem = undefined;
544
+ self.todayDateElem = undefined;
345
545
 
346
546
  var daysInMonth = self.utils.getDaysinMonth(),
347
- days = document.createDocumentFragment();
547
+ days = window.document.createDocumentFragment();
348
548
 
349
- var dayNumber = self.prevMonthDays + 1 - self.firstOfMonth;
549
+ var dayNumber = self.prevMonthDays + 1 - firstOfMonth,
550
+ dayIndex = 0;
350
551
 
351
- if (self.config.weekNumbers) self.weekNumbers.innerHTML = "";
552
+ if (self.config.weekNumbers && self.weekNumbers.firstChild) self.weekNumbers.textContent = "";
352
553
 
353
- if (self.config.mode === "range") {
554
+ if (isRangeMode) {
354
555
  // const dateLimits = self.config.enable.length || self.config.disable.length || self.config.mixDate || self.config.maxDate;
355
556
  self.minRangeDate = new Date(self.currentYear, self.currentMonth - 1, dayNumber);
356
- self.maxRangeDate = new Date(self.currentYear, self.currentMonth + 1, (42 - self.firstOfMonth) % daysInMonth);
557
+ self.maxRangeDate = new Date(self.currentYear, self.currentMonth + 1, (42 - firstOfMonth) % daysInMonth);
357
558
  }
358
559
 
359
- self.days.innerHTML = "";
360
-
361
560
  // prepend days from the ending of previous month
362
- for (var i = 0; dayNumber <= self.prevMonthDays; i++, dayNumber++) {
363
- days.appendChild(createDay("prevMonthDay", new Date(self.currentYear, self.currentMonth - 1, dayNumber), dayNumber));
561
+ for (; dayNumber <= self.prevMonthDays; dayNumber++, dayIndex++) {
562
+ days.appendChild(createDay("prevMonthDay", new Date(self.currentYear, self.currentMonth - 1, dayNumber), dayNumber, dayIndex));
364
563
  }
365
564
 
366
565
  // Start at 1 since there is no 0th day
367
- for (dayNumber = 1; dayNumber <= daysInMonth; dayNumber++) {
368
- days.appendChild(createDay("", new Date(self.currentYear, self.currentMonth, dayNumber), dayNumber));
566
+ for (dayNumber = 1; dayNumber <= daysInMonth; dayNumber++, dayIndex++) {
567
+ days.appendChild(createDay("", new Date(self.currentYear, self.currentMonth, dayNumber), dayNumber, dayIndex));
369
568
  }
370
569
 
371
570
  // append days from the next month
372
- for (var dayNum = daysInMonth + 1; dayNum <= 42 - self.firstOfMonth; dayNum++) {
373
- days.appendChild(createDay("nextMonthDay", new Date(self.currentYear, self.currentMonth + 1, dayNum % daysInMonth), dayNum));
571
+ for (var dayNum = daysInMonth + 1; dayNum <= 42 - firstOfMonth; dayNum++, dayIndex++) {
572
+ days.appendChild(createDay("nextMonthDay", new Date(self.currentYear, self.currentMonth + 1, dayNum % daysInMonth), dayNum, dayIndex));
374
573
  }
375
574
 
376
- self.days.appendChild(days);
377
- return self.days;
575
+ if (isRangeMode && self.selectedDates.length === 1 && days.childNodes[0]) {
576
+ self._hidePrevMonthArrow = self._hidePrevMonthArrow || self.minRangeDate > days.childNodes[0].dateObj;
577
+
578
+ self._hideNextMonthArrow = self._hideNextMonthArrow || self.maxRangeDate < new Date(self.currentYear, self.currentMonth + 1, 1);
579
+ } else updateNavigationCurrentMonth();
580
+
581
+ var dayContainer = createElement("div", "dayContainer");
582
+ dayContainer.appendChild(days);
583
+
584
+ if (!self.config.animate || delta === undefined) clearNode(self.daysContainer);else {
585
+ while (self.daysContainer.childNodes.length > 1) {
586
+ self.daysContainer.removeChild(self.daysContainer.firstChild);
587
+ }
588
+ }
589
+
590
+ if (delta >= 0) self.daysContainer.appendChild(dayContainer);else self.daysContainer.insertBefore(dayContainer, self.daysContainer.firstChild);
591
+
592
+ self.days = self.daysContainer.firstChild;
593
+ return self.daysContainer;
594
+ }
595
+
596
+ function clearNode(node) {
597
+ while (node.firstChild) {
598
+ node.removeChild(node.firstChild);
599
+ }
378
600
  }
379
601
 
380
602
  function buildMonthNav() {
381
- var monthNavFragment = document.createDocumentFragment();
603
+ var monthNavFragment = window.document.createDocumentFragment();
382
604
  self.monthNav = createElement("div", "flatpickr-month");
383
605
 
384
606
  self.prevMonthNav = createElement("span", "flatpickr-prev-month");
385
607
  self.prevMonthNav.innerHTML = self.config.prevArrow;
386
608
 
387
609
  self.currentMonthElement = createElement("span", "cur-month");
610
+ self.currentMonthElement.title = self.l10n.scrollTitle;
388
611
 
389
612
  var yearInput = createNumberInput("cur-year");
390
613
  self.currentYearElement = yearInput.childNodes[0];
@@ -410,6 +633,26 @@ function Flatpickr(element, config) {
410
633
  monthNavFragment.appendChild(self.nextMonthNav);
411
634
  self.monthNav.appendChild(monthNavFragment);
412
635
 
636
+ Object.defineProperty(self, "_hidePrevMonthArrow", {
637
+ get: function get() {
638
+ return this.__hidePrevMonthArrow;
639
+ },
640
+ set: function set(bool) {
641
+ if (this.__hidePrevMonthArrow !== bool) self.prevMonthNav.style.display = bool ? "none" : "block";
642
+ this.__hidePrevMonthArrow = bool;
643
+ }
644
+ });
645
+
646
+ Object.defineProperty(self, "_hideNextMonthArrow", {
647
+ get: function get() {
648
+ return this.__hideNextMonthArrow;
649
+ },
650
+ set: function set(bool) {
651
+ if (this.__hideNextMonthArrow !== bool) self.nextMonthNav.style.display = bool ? "none" : "block";
652
+ this.__hideNextMonthArrow = bool;
653
+ }
654
+ });
655
+
413
656
  updateNavigationCurrentMonth();
414
657
 
415
658
  return self.monthNav;
@@ -417,6 +660,7 @@ function Flatpickr(element, config) {
417
660
 
418
661
  function buildTime() {
419
662
  self.calendarContainer.classList.add("hasTime");
663
+ if (self.config.noCalendar) self.calendarContainer.classList.add("noCalendar");
420
664
  self.timeContainer = createElement("div", "flatpickr-time");
421
665
  self.timeContainer.tabIndex = -1;
422
666
  var separator = createElement("span", "flatpickr-time-separator", ":");
@@ -427,12 +671,11 @@ function Flatpickr(element, config) {
427
671
  var minuteInput = createNumberInput("flatpickr-minute");
428
672
  self.minuteElement = minuteInput.childNodes[0];
429
673
 
430
- self.hourElement.tabIndex = self.minuteElement.tabIndex = 0;
431
- self.hourElement.pattern = self.minuteElement.pattern = "\d*";
674
+ self.hourElement.tabIndex = self.minuteElement.tabIndex = -1;
432
675
 
433
- self.hourElement.value = self.pad(latestSelectedDateObj() ? latestSelectedDateObj().getHours() : self.config.defaultHour);
676
+ self.hourElement.value = self.pad(self.latestSelectedDateObj ? self.latestSelectedDateObj.getHours() : self.config.defaultHour);
434
677
 
435
- self.minuteElement.value = self.pad(latestSelectedDateObj() ? latestSelectedDateObj().getMinutes() : self.config.defaultMinute);
678
+ self.minuteElement.value = self.pad(self.latestSelectedDateObj ? self.latestSelectedDateObj.getMinutes() : self.config.defaultMinute);
436
679
 
437
680
  self.hourElement.step = self.config.hourIncrement;
438
681
  self.minuteElement.step = self.config.minuteIncrement;
@@ -457,8 +700,7 @@ function Flatpickr(element, config) {
457
700
  var secondInput = createNumberInput("flatpickr-second");
458
701
  self.secondElement = secondInput.childNodes[0];
459
702
 
460
- self.secondElement.pattern = self.hourElement.pattern;
461
- self.secondElement.value = latestSelectedDateObj() ? self.pad(latestSelectedDateObj().getSeconds()) : "00";
703
+ self.secondElement.value = self.latestSelectedDateObj ? self.pad(self.latestSelectedDateObj.getSeconds()) : "00";
462
704
 
463
705
  self.secondElement.step = self.minuteElement.step;
464
706
  self.secondElement.min = self.minuteElement.min;
@@ -472,7 +714,7 @@ function Flatpickr(element, config) {
472
714
  // add self.amPM if appropriate
473
715
  self.amPM = createElement("span", "flatpickr-am-pm", ["AM", "PM"][self.hourElement.value > 11 | 0]);
474
716
  self.amPM.title = self.l10n.toggleTitle;
475
- self.amPM.tabIndex = 0;
717
+ self.amPM.tabIndex = -1;
476
718
  self.timeContainer.appendChild(self.amPM);
477
719
  }
478
720
 
@@ -494,6 +736,7 @@ function Flatpickr(element, config) {
494
736
  return self.weekdayContainer;
495
737
  }
496
738
 
739
+ /* istanbul ignore next */
497
740
  function buildWeeks() {
498
741
  self.calendarContainer.classList.add("hasWeeks");
499
742
  self.weekWrapper = createElement("div", "flatpickr-weekwrapper");
@@ -504,21 +747,76 @@ function Flatpickr(element, config) {
504
747
  return self.weekWrapper;
505
748
  }
506
749
 
507
- function changeMonth(value, is_offset) {
508
- self.currentMonth = typeof is_offset === "undefined" || is_offset ? self.currentMonth + value : value;
750
+ function changeMonth(value, is_offset, animate) {
751
+ is_offset = is_offset === undefined || is_offset;
752
+ var delta = is_offset ? value : value - self.currentMonth;
753
+ var skipAnimations = !self.config.animate || animate === false;
509
754
 
510
- handleYearChange();
511
- updateNavigationCurrentMonth();
512
- buildDays();
755
+ if (delta < 0 && self._hidePrevMonthArrow || delta > 0 && self._hideNextMonthArrow) return;
756
+
757
+ self.currentMonth += delta;
758
+
759
+ if (self.currentMonth < 0 || self.currentMonth > 11) {
760
+ self.currentYear += self.currentMonth > 11 ? 1 : -1;
761
+ self.currentMonth = (self.currentMonth + 12) % 12;
762
+
763
+ triggerEvent("YearChange");
764
+ }
765
+
766
+ buildDays(!skipAnimations ? delta : undefined);
767
+
768
+ if (skipAnimations) {
769
+ triggerEvent("MonthChange");
770
+ return updateNavigationCurrentMonth();
771
+ }
772
+
773
+ // remove possible remnants from clicking too fast
774
+ var nav = self.navigationCurrentMonth;
775
+ if (delta < 0) {
776
+ while (nav.nextSibling && /curr/.test(nav.nextSibling.className)) {
777
+ self.monthNav.removeChild(nav.nextSibling);
778
+ }
779
+ } else if (delta > 0) {
780
+ while (nav.previousSibling && /curr/.test(nav.previousSibling.className)) {
781
+ self.monthNav.removeChild(nav.previousSibling);
782
+ }
783
+ }
784
+
785
+ self.oldCurMonth = self.navigationCurrentMonth;
786
+
787
+ self.navigationCurrentMonth = self.monthNav.insertBefore(self.oldCurMonth.cloneNode(true), delta > 0 ? self.oldCurMonth.nextSibling : self.oldCurMonth);
788
+
789
+ if (delta > 0) {
790
+ self.daysContainer.firstChild.classList.add("slideLeft");
791
+ self.daysContainer.lastChild.classList.add("slideLeftNew");
792
+
793
+ self.oldCurMonth.classList.add("slideLeft");
794
+ self.navigationCurrentMonth.classList.add("slideLeftNew");
795
+ } else if (delta < 0) {
796
+ self.daysContainer.firstChild.classList.add("slideRightNew");
797
+ self.daysContainer.lastChild.classList.add("slideRight");
513
798
 
514
- if (!self.config.noCalendar) self.days.focus();
799
+ self.oldCurMonth.classList.add("slideRight");
800
+ self.navigationCurrentMonth.classList.add("slideRightNew");
801
+ }
802
+
803
+ self.currentMonthElement = self.navigationCurrentMonth.firstChild;
804
+ self.currentYearElement = self.navigationCurrentMonth.lastChild.childNodes[0];
805
+
806
+ updateNavigationCurrentMonth();
807
+ self.oldCurMonth.firstChild.textContent = self.utils.monthToStr(self.currentMonth - delta);
515
808
 
516
809
  triggerEvent("MonthChange");
517
- }
518
810
 
519
- function clear() {
520
- var triggerChangeEvent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
811
+ if (document.activeElement && document.activeElement.$i) {
812
+ var index = document.activeElement.$i;
813
+ afterDayAnim(function () {
814
+ focusOnDay(index, 0);
815
+ });
816
+ }
817
+ }
521
818
 
819
+ function clear(triggerChangeEvent) {
522
820
  self.input.value = "";
523
821
 
524
822
  if (self.altInput) self.altInput.value = "";
@@ -526,7 +824,8 @@ function Flatpickr(element, config) {
526
824
  if (self.mobileInput) self.mobileInput.value = "";
527
825
 
528
826
  self.selectedDates = [];
529
- self.dateIsPicked = false;
827
+ self.latestSelectedDateObj = undefined;
828
+ self.showTimeInput = false;
530
829
 
531
830
  self.redraw();
532
831
 
@@ -540,91 +839,97 @@ function Flatpickr(element, config) {
540
839
 
541
840
  if (!self.isMobile) {
542
841
  self.calendarContainer.classList.remove("open");
543
- (self.altInput || self.input).classList.remove("active");
842
+ self._input.classList.remove("active");
544
843
  }
545
844
 
546
845
  triggerEvent("Close");
547
846
  }
548
847
 
549
- function destroy(instance) {
550
- instance = instance || self;
551
- instance.clear(false);
848
+ function destroy() {
849
+ if (self.config !== undefined) triggerEvent("Destroy");
552
850
 
553
- document.removeEventListener("keydown", onKeyDown);
554
- window.removeEventListener("resize", instance.debouncedResize);
851
+ for (var i = self._handlers.length; i--;) {
852
+ var h = self._handlers[i];
853
+ h.element.removeEventListener(h.event, h.handler);
854
+ }
855
+
856
+ self._handlers = [];
555
857
 
556
- document.removeEventListener("click", documentClick);
557
- document.removeEventListener("blur", documentClick);
858
+ if (self.mobileInput) {
859
+ if (self.mobileInput.parentNode) self.mobileInput.parentNode.removeChild(self.mobileInput);
860
+ self.mobileInput = null;
861
+ } else if (self.calendarContainer && self.calendarContainer.parentNode) self.calendarContainer.parentNode.removeChild(self.calendarContainer);
558
862
 
559
- if (instance.isMobile && instance.mobileInput && instance.mobileInput.parentNode) instance.mobileInput.parentNode.removeChild(instance.mobileInput);else if (instance.calendarContainer && instance.calendarContainer.parentNode) instance.calendarContainer.parentNode.removeChild(instance.calendarContainer);
863
+ if (self.altInput) {
864
+ self.input.type = "text";
865
+ if (self.altInput.parentNode) self.altInput.parentNode.removeChild(self.altInput);
866
+ delete self.altInput;
867
+ }
560
868
 
561
- if (instance.altInput) {
562
- instance.input.type = "text";
563
- if (instance.altInput.parentNode) instance.altInput.parentNode.removeChild(instance.altInput);
869
+ if (self.input) {
870
+ self.input.type = self.input._type;
871
+ self.input.classList.remove("flatpickr-input");
872
+ self.input.removeAttribute("readonly");
873
+ self.input.value = "";
564
874
  }
565
875
 
566
- instance.input.classList.remove("flatpickr-input");
567
- instance.input.removeEventListener("focus", open);
568
- instance.input.removeAttribute("readonly");
876
+ ["_showTimeInput", "latestSelectedDateObj", "_hideNextMonthArrow", "_hidePrevMonthArrow", "__hideNextMonthArrow", "__hidePrevMonthArrow", "isMobile", "isOpen", "selectedDateElem", "minDateHasTime", "maxDateHasTime", "days", "daysContainer", "_input", "_positionElement", "innerContainer", "rContainer", "monthNav", "todayDateElem", "calendarContainer", "weekdayContainer", "prevMonthNav", "nextMonthNav", "currentMonthElement", "currentYearElement", "navigationCurrentMonth", "selectedDateElem", "config"].forEach(function (k) {
877
+ return delete self[k];
878
+ });
569
879
  }
570
880
 
571
881
  function isCalendarElem(elem) {
572
- var e = elem;
573
- while (e) {
574
- if (/flatpickr-day|flatpickr-calendar/.test(e.className)) return true;
575
- e = e.parentNode;
576
- }
882
+ if (self.config.appendTo && self.config.appendTo.contains(elem)) return true;
577
883
 
578
- return false;
884
+ return self.calendarContainer.contains(elem);
579
885
  }
580
886
 
581
887
  function documentClick(e) {
582
- var isInput = self.element.contains(e.target) || e.target === self.input || e.target === self.altInput;
888
+ if (self.isOpen && !self.config.inline) {
889
+ var isCalendarElement = isCalendarElem(e.target);
890
+ var isInput = e.target === self.input || e.target === self.altInput || self.element.contains(e.target) ||
891
+ // web components
892
+ e.path && e.path.indexOf && (~e.path.indexOf(self.input) || ~e.path.indexOf(self.altInput));
583
893
 
584
- if (self.isOpen && !isCalendarElem(e.target) && !isInput) {
585
- self.close();
894
+ var lostFocus = e.type === "blur" ? isInput && e.relatedTarget && !isCalendarElem(e.relatedTarget) : !isInput && !isCalendarElement;
586
895
 
587
- if (self.config.mode === "range" && self.selectedDates.length === 1) {
588
- self.clear();
589
- self.redraw();
896
+ if (lostFocus && self.config.ignoredFocusElements.indexOf(e.target) === -1) {
897
+ self.close();
898
+
899
+ if (self.config.mode === "range" && self.selectedDates.length === 1) {
900
+ self.clear(false);
901
+ self.redraw();
902
+ }
590
903
  }
591
904
  }
592
905
  }
593
906
 
594
- function formatDate(frmt, dateObj) {
595
- if (self.config.formatDate) return self.config.formatDate(frmt, dateObj);
907
+ function changeYear(newYear) {
908
+ if (!newYear || self.currentYearElement.min && newYear < self.currentYearElement.min || self.currentYearElement.max && newYear > self.currentYearElement.max) return;
596
909
 
597
- var chars = frmt.split("");
598
- return chars.map(function (c, i) {
599
- return self.formats[c] && chars[i - 1] !== "\\" ? self.formats[c](dateObj) : c !== "\\" ? c : "";
600
- }).join("");
601
- }
910
+ var newYearNum = parseInt(newYear, 10),
911
+ isNewYear = self.currentYear !== newYearNum;
602
912
 
603
- function handleYearChange(newYear) {
604
- if (self.currentMonth < 0 || self.currentMonth > 11) {
605
- self.currentYear += self.currentMonth % 11;
606
- self.currentMonth = (self.currentMonth + 12) % 12;
607
- triggerEvent("YearChange");
608
- } else if (newYear && (!self.currentYearElement.min || newYear >= self.currentYearElement.min) && (!self.currentYearElement.max || newYear <= self.currentYearElement.max)) {
609
- self.currentYear = parseInt(newYear, 10) || self.currentYear;
913
+ self.currentYear = newYearNum || self.currentYear;
610
914
 
611
- if (self.config.maxDate && self.currentYear === self.config.maxDate.getFullYear()) {
612
- self.currentMonth = Math.min(self.config.maxDate.getMonth(), self.currentMonth);
613
- } else if (self.config.minDate && self.currentYear === self.config.minDate.getFullYear()) {
614
- self.currentMonth = Math.max(self.config.minDate.getMonth(), self.currentMonth);
615
- }
915
+ if (self.config.maxDate && self.currentYear === self.config.maxDate.getFullYear()) {
916
+ self.currentMonth = Math.min(self.config.maxDate.getMonth(), self.currentMonth);
917
+ } else if (self.config.minDate && self.currentYear === self.config.minDate.getFullYear()) {
918
+ self.currentMonth = Math.max(self.config.minDate.getMonth(), self.currentMonth);
919
+ }
616
920
 
921
+ if (isNewYear) {
617
922
  self.redraw();
618
923
  triggerEvent("YearChange");
619
924
  }
620
925
  }
621
926
 
622
- function isEnabled(dateToCheck) {
623
- if (self.config.minDate && compareDates(dateToCheck, self.config.minDate) < 0 || self.config.maxDate && compareDates(dateToCheck, self.config.maxDate) > 0) return false;
927
+ function isEnabled(date, timeless) {
928
+ if (self.config.minDate && compareDates(date, self.config.minDate, timeless !== undefined ? timeless : !self.minDateHasTime) < 0 || self.config.maxDate && compareDates(date, self.config.maxDate, timeless !== undefined ? timeless : !self.maxDateHasTime) > 0) return false;
624
929
 
625
930
  if (!self.config.enable.length && !self.config.disable.length) return true;
626
931
 
627
- dateToCheck = parseDate(dateToCheck, true); // timeless
932
+ var dateToCheck = self.parseDate(date, null, true); // timeless
628
933
 
629
934
  var bool = self.config.enable.length > 0,
630
935
  array = bool ? self.config.enable : self.config.disable;
@@ -633,68 +938,116 @@ function Flatpickr(element, config) {
633
938
  d = array[i];
634
939
 
635
940
  if (d instanceof Function && d(dateToCheck)) // disabled by function
636
- return bool;else if ((d instanceof Date || typeof d === "string") && parseDate(d, true).getTime() === dateToCheck.getTime())
941
+ return bool;else if (d instanceof Date && d.getTime() === dateToCheck.getTime())
942
+ // disabled by date
943
+ return bool;else if (typeof d === "string" && self.parseDate(d, null, true).getTime() === dateToCheck.getTime())
637
944
  // disabled by date string
638
945
  return bool;else if ( // disabled by range
639
- (typeof d === "undefined" ? "undefined" : _typeof(d)) === "object" && d.from && d.to && dateToCheck >= parseDate(d.from) && dateToCheck <= parseDate(d.to)) return bool;
946
+ (typeof d === "undefined" ? "undefined" : _typeof(d)) === "object" && d.from && d.to && dateToCheck >= d.from && dateToCheck <= d.to) return bool;
640
947
  }
641
948
 
642
949
  return !bool;
643
950
  }
644
951
 
645
952
  function onKeyDown(e) {
646
- if (self.isOpen) {
647
- switch (e.which) {
648
- case 13:
649
- if (self.timeContainer && self.timeContainer.contains(e.target)) updateValue();else selectDate(e);
953
+ var isInput = e.target === self._input;
954
+ var calendarElem = isCalendarElem(e.target);
955
+ var allowInput = self.config.allowInput;
956
+ var allowKeydown = self.isOpen && (!allowInput || !isInput);
957
+ var allowInlineKeydown = self.config.inline && isInput && !allowInput;
958
+
959
+ if (e.key === "Enter" && allowInput && isInput) {
960
+ self.setDate(self._input.value, true, e.target === self.altInput ? self.config.altFormat : self.config.dateFormat);
961
+ return e.target.blur();
962
+ } else if (calendarElem || allowKeydown || allowInlineKeydown) {
963
+ var isTimeObj = self.timeContainer && self.timeContainer.contains(e.target);
964
+ switch (e.key) {
965
+ case "Enter":
966
+ if (isTimeObj) updateValue();else selectDate(e);
650
967
 
651
968
  break;
652
969
 
653
- case 27:
970
+ case "Escape":
654
971
  // escape
655
- self.clear();
656
- self.redraw();
972
+ e.preventDefault();
657
973
  self.close();
658
974
  break;
659
975
 
660
- case 37:
661
- if (e.target !== self.input & e.target !== self.altInput) changeMonth(-1);
976
+ case "ArrowLeft":
977
+ case "ArrowRight":
978
+ if (!isTimeObj) {
979
+ e.preventDefault();
980
+
981
+ if (self.daysContainer) {
982
+ var _delta = e.key === "ArrowRight" ? 1 : -1;
983
+
984
+ if (!e.ctrlKey) focusOnDay(e.target.$i, _delta);else changeMonth(_delta, true);
985
+ } else if (self.config.enableTime && !isTimeObj) self.hourElement.focus();
986
+ }
987
+
662
988
  break;
663
989
 
664
- case 38:
990
+ case "ArrowUp":
991
+ case "ArrowDown":
665
992
  e.preventDefault();
666
-
667
- if (self.timeContainer && self.timeContainer.contains(e.target)) updateTime(e);else {
668
- self.currentYear++;
669
- self.redraw();
993
+ var delta = e.key === "ArrowDown" ? 1 : -1;
994
+
995
+ if (self.daysContainer) {
996
+ if (e.ctrlKey) {
997
+ changeYear(self.currentYear - delta);
998
+ focusOnDay(e.target.$i, 0);
999
+ } else if (!isTimeObj) focusOnDay(e.target.$i, delta * 7);
1000
+ } else if (self.config.enableTime) {
1001
+ if (!isTimeObj) self.hourElement.focus();
1002
+ updateTime(e);
670
1003
  }
671
1004
 
672
1005
  break;
673
1006
 
674
- case 39:
675
- if (e.target !== self.input & e.target !== self.altInput) changeMonth(1);
1007
+ case "Tab":
1008
+ if (e.target === self.hourElement) {
1009
+ e.preventDefault();
1010
+ self.minuteElement.select();
1011
+ } else if (e.target === self.minuteElement && (self.secondElement || self.amPM)) {
1012
+ e.preventDefault();
1013
+ (self.secondElement || self.amPM).focus();
1014
+ } else if (e.target === self.secondElement) {
1015
+ e.preventDefault();
1016
+ self.amPM.focus();
1017
+ }
1018
+
676
1019
  break;
677
1020
 
678
- case 40:
679
- e.preventDefault();
680
- if (self.timeContainer && self.timeContainer.contains(e.target)) updateTime(e);else {
681
- self.currentYear--;
682
- self.redraw();
1021
+ case "a":
1022
+ if (e.target === self.amPM) {
1023
+ self.amPM.textContent = "AM";
1024
+ setHoursFromInputs();
1025
+ updateValue();
683
1026
  }
1027
+ break;
684
1028
 
1029
+ case "p":
1030
+ if (e.target === self.amPM) {
1031
+ self.amPM.textContent = "PM";
1032
+ setHoursFromInputs();
1033
+ updateValue();
1034
+ }
685
1035
  break;
686
1036
 
687
1037
  default:
688
1038
  break;
1039
+
689
1040
  }
1041
+
1042
+ triggerEvent("KeyDown", e);
690
1043
  }
691
1044
  }
692
1045
 
693
- function onMouseOver(e) {
694
- if (self.selectedDates.length !== 1 || !e.target.classList.contains("flatpickr-day")) return;
1046
+ function onMouseOver(elem) {
1047
+ if (self.selectedDates.length !== 1 || !elem.classList.contains("flatpickr-day")) return;
695
1048
 
696
- var hoverDate = e.target.dateObj,
697
- initialDate = parseDate(self.selectedDates[0], true),
1049
+ var hoverDate = elem.dateObj,
1050
+ initialDate = self.parseDate(self.selectedDates[0], null, true),
698
1051
  rangeStartDate = Math.min(hoverDate.getTime(), self.selectedDates[0].getTime()),
699
1052
  rangeEndDate = Math.max(hoverDate.getTime(), self.selectedDates[0].getTime()),
700
1053
  containsDisabled = false;
@@ -706,23 +1059,36 @@ function Flatpickr(element, config) {
706
1059
  }
707
1060
  }
708
1061
 
709
- for (var timestamp = self.days.childNodes[0].dateObj.getTime(), i = 0; i < 42; i++, timestamp += self.utils.duration.DAY) {
710
- var outOfRange = timestamp < self.minRangeDate.getTime() || timestamp > self.maxRangeDate.getTime();
1062
+ var _loop = function _loop(timestamp, i) {
1063
+ var outOfRange = timestamp < self.minRangeDate.getTime() || timestamp > self.maxRangeDate.getTime(),
1064
+ dayElem = self.days.childNodes[i];
711
1065
 
712
1066
  if (outOfRange) {
713
1067
  self.days.childNodes[i].classList.add("notAllowed");
714
- self.days.childNodes[i].classList.remove("inRange", "startRange", "endRange");
715
- continue;
716
- } else if (containsDisabled && !outOfRange) continue;
1068
+ ["inRange", "startRange", "endRange"].forEach(function (c) {
1069
+ dayElem.classList.remove(c);
1070
+ });
1071
+ return "continue";
1072
+ } else if (containsDisabled && !outOfRange) return "continue";
717
1073
 
718
- self.days.childNodes[i].classList.remove("startRange", "inRange", "endRange", "notAllowed");
1074
+ ["startRange", "inRange", "endRange", "notAllowed"].forEach(function (c) {
1075
+ dayElem.classList.remove(c);
1076
+ });
719
1077
 
720
1078
  var minRangeDate = Math.max(self.minRangeDate.getTime(), rangeStartDate),
721
1079
  maxRangeDate = Math.min(self.maxRangeDate.getTime(), rangeEndDate);
722
1080
 
723
- e.target.classList.add(hoverDate < self.selectedDates[0] ? "startRange" : "endRange");
1081
+ elem.classList.add(hoverDate < self.selectedDates[0] ? "startRange" : "endRange");
1082
+
1083
+ if (initialDate < hoverDate && timestamp === initialDate.getTime()) dayElem.classList.add("startRange");else if (initialDate > hoverDate && timestamp === initialDate.getTime()) dayElem.classList.add("endRange");
1084
+
1085
+ if (timestamp >= minRangeDate && timestamp <= maxRangeDate) dayElem.classList.add("inRange");
1086
+ };
1087
+
1088
+ for (var timestamp = self.days.childNodes[0].dateObj.getTime(), i = 0; i < 42; i++, timestamp += self.utils.duration.DAY) {
1089
+ var _ret = _loop(timestamp, i);
724
1090
 
725
- if (initialDate > hoverDate && timestamp === initialDate.getTime()) self.days.childNodes[i].classList.add("endRange");else if (initialDate < hoverDate && timestamp === initialDate.getTime()) self.days.childNodes[i].classList.add("startRange");else if (timestamp > minRangeDate && timestamp < maxRangeDate) self.days.childNodes[i].classList.add("inRange");
1091
+ if (_ret === "continue") continue;
726
1092
  }
727
1093
  }
728
1094
 
@@ -730,7 +1096,7 @@ function Flatpickr(element, config) {
730
1096
  if (self.isOpen && !self.config.static && !self.config.inline) positionCalendar();
731
1097
  }
732
1098
 
733
- function open(e) {
1099
+ function open(e, positionElement) {
734
1100
  if (self.isMobile) {
735
1101
  if (e) {
736
1102
  e.preventDefault();
@@ -743,155 +1109,166 @@ function Flatpickr(element, config) {
743
1109
 
744
1110
  triggerEvent("Open");
745
1111
  return;
746
- } else if (self.isOpen || (self.altInput || self.input).disabled || self.config.inline) return;
1112
+ }
1113
+
1114
+ if (self.isOpen || self._input.disabled || self.config.inline) return;
747
1115
 
1116
+ self.isOpen = true;
748
1117
  self.calendarContainer.classList.add("open");
1118
+ positionCalendar(positionElement);
1119
+ self._input.classList.add("active");
749
1120
 
750
- if (!self.config.static && !self.config.inline) positionCalendar();
1121
+ triggerEvent("Open");
1122
+ }
751
1123
 
752
- self.isOpen = true;
1124
+ function minMaxDateSetter(type) {
1125
+ return function (date) {
1126
+ var dateObj = self.config["_" + type + "Date"] = self.parseDate(date);
753
1127
 
754
- if (!self.config.allowInput) {
755
- (self.altInput || self.input).blur();
756
- (self.config.noCalendar ? self.timeContainer : self.selectedDateElem ? self.selectedDateElem : self.days).focus();
757
- }
1128
+ var inverseDateObj = self.config["_" + (type === "min" ? "max" : "min") + "Date"];
1129
+ var isValidDate = date && dateObj instanceof Date;
758
1130
 
759
- (self.altInput || self.input).classList.add("active");
760
- triggerEvent("Open");
1131
+ if (isValidDate) {
1132
+ self[type + "DateHasTime"] = dateObj.getHours() || dateObj.getMinutes() || dateObj.getSeconds();
1133
+ }
1134
+
1135
+ if (self.selectedDates) {
1136
+ self.selectedDates = self.selectedDates.filter(function (d) {
1137
+ return isEnabled(d);
1138
+ });
1139
+ if (!self.selectedDates.length && type === "min") setHoursFromDate(dateObj);
1140
+ updateValue();
1141
+ }
1142
+
1143
+ if (self.daysContainer) {
1144
+ redraw();
1145
+
1146
+ if (isValidDate) self.currentYearElement[type] = dateObj.getFullYear();else self.currentYearElement.removeAttribute(type);
1147
+
1148
+ self.currentYearElement.disabled = inverseDateObj && dateObj && inverseDateObj.getFullYear() === dateObj.getFullYear();
1149
+ }
1150
+ };
761
1151
  }
762
1152
 
763
1153
  function parseConfig() {
764
- var boolOpts = ["utc", "wrap", "weekNumbers", "allowInput", "clickOpens", "time_24hr", "enableTime", "noCalendar", "altInput", "shorthandCurrentMonth", "inline", "static", "enableSeconds", "disableMobile"];
765
- self.config = Object.create(Flatpickr.defaultConfig);
766
- var userConfig = _extends({}, self.instanceConfig, self.element.dataset || {});
1154
+ var boolOpts = ["wrap", "weekNumbers", "allowInput", "clickOpens", "time_24hr", "enableTime", "noCalendar", "altInput", "shorthandCurrentMonth", "inline", "static", "enableSeconds", "disableMobile"];
767
1155
 
768
- Object.defineProperty(self.config, "minDate", {
1156
+ var hooks = ["onChange", "onClose", "onDayCreate", "onDestroy", "onKeyDown", "onMonthChange", "onOpen", "onParseConfig", "onReady", "onValueUpdate", "onYearChange"];
1157
+
1158
+ self.config = Object.create(flatpickr.defaultConfig);
1159
+
1160
+ var userConfig = _extends({}, self.instanceConfig, JSON.parse(JSON.stringify(self.element.dataset || {})));
1161
+
1162
+ self.config.parseDate = userConfig.parseDate;
1163
+ self.config.formatDate = userConfig.formatDate;
1164
+
1165
+ Object.defineProperty(self.config, "enable", {
769
1166
  get: function get() {
770
- return this._minDate;
1167
+ return self.config._enable || [];
771
1168
  },
772
- set: function set(date) {
773
- this._minDate = parseDate(date);
1169
+ set: function set(dates) {
1170
+ return self.config._enable = parseDateRules(dates);
1171
+ }
1172
+ });
774
1173
 
775
- if (self.days) redraw();
1174
+ Object.defineProperty(self.config, "disable", {
1175
+ get: function get() {
1176
+ return self.config._disable || [];
1177
+ },
1178
+ set: function set(dates) {
1179
+ return self.config._disable = parseDateRules(dates);
1180
+ }
1181
+ });
776
1182
 
777
- if (!self.currentYearElement) return;
1183
+ _extends(self.config, userConfig);
778
1184
 
779
- if (date && this._minDate instanceof Date) {
780
- self.minDateHasTime = this._minDate.getHours() || this._minDate.getMinutes() || this._minDate.getSeconds();
1185
+ if (!userConfig.dateFormat && userConfig.enableTime) {
1186
+ self.config.dateFormat = self.config.noCalendar ? "H:i" + (self.config.enableSeconds ? ":S" : "") : flatpickr.defaultConfig.dateFormat + " H:i" + (self.config.enableSeconds ? ":S" : "");
1187
+ }
781
1188
 
782
- self.currentYearElement.min = this._minDate.getFullYear();
783
- } else self.currentYearElement.removeAttribute("min");
1189
+ if (userConfig.altInput && userConfig.enableTime && !userConfig.altFormat) {
1190
+ self.config.altFormat = self.config.noCalendar ? "h:i" + (self.config.enableSeconds ? ":S K" : " K") : flatpickr.defaultConfig.altFormat + (" h:i" + (self.config.enableSeconds ? ":S" : "") + " K");
1191
+ }
784
1192
 
785
- self.currentYearElement.disabled = this._maxDate && this._minDate && this._maxDate.getFullYear() === this._minDate.getFullYear();
786
- }
1193
+ Object.defineProperty(self.config, "minDate", {
1194
+ get: function get() {
1195
+ return this._minDate;
1196
+ },
1197
+ set: minMaxDateSetter("min")
787
1198
  });
788
1199
 
789
1200
  Object.defineProperty(self.config, "maxDate", {
790
1201
  get: function get() {
791
1202
  return this._maxDate;
792
1203
  },
793
- set: function set(date) {
794
- this._maxDate = parseDate(date);
795
- if (self.days) redraw();
796
-
797
- if (!self.currentYearElement) return;
798
-
799
- if (date && this._maxDate instanceof Date) {
800
- self.currentYearElement.max = this._maxDate.getFullYear();
801
- self.maxDateHasTime = this._maxDate.getHours() || this._maxDate.getMinutes() || this._maxDate.getSeconds();
802
- } else self.currentYearElement.removeAttribute("max");
803
-
804
- self.currentYearElement.disabled = this._maxDate && this._minDate && this._maxDate.getFullYear() === this._minDate.getFullYear();
805
- }
1204
+ set: minMaxDateSetter("max")
806
1205
  });
807
1206
 
808
- _extends(self.config, userConfig);
1207
+ self.config.minDate = userConfig.minDate;
1208
+ self.config.maxDate = userConfig.maxDate;
809
1209
 
810
1210
  for (var i = 0; i < boolOpts.length; i++) {
811
1211
  self.config[boolOpts[i]] = self.config[boolOpts[i]] === true || self.config[boolOpts[i]] === "true";
812
- }if (!userConfig.dateFormat && userConfig.enableTime) {
813
- self.config.dateFormat = self.config.noCalendar ? "H:i" + (self.config.enableSeconds ? ":S" : "") : Flatpickr.defaultConfig.dateFormat + " H:i" + (self.config.enableSeconds ? ":S" : "");
1212
+ }for (var _i = hooks.length; _i--;) {
1213
+ if (self.config[hooks[_i]] !== undefined) {
1214
+ self.config[hooks[_i]] = arrayify(self.config[hooks[_i]] || []).map(bindToInstance);
1215
+ }
814
1216
  }
815
1217
 
816
- if (userConfig.altInput && userConfig.enableTime && !userConfig.altFormat) {
817
- self.config.altFormat = self.config.noCalendar ? "h:i" + (self.config.enableSeconds ? ":S K" : " K") : Flatpickr.defaultConfig.altFormat + (" h:i" + (self.config.enableSeconds ? ":S" : "") + " K");
1218
+ for (var _i2 = 0; _i2 < self.config.plugins.length; _i2++) {
1219
+ var pluginConf = self.config.plugins[_i2](self) || {};
1220
+ for (var key in pluginConf) {
1221
+
1222
+ if (self.config[key] instanceof Array || ~hooks.indexOf(key)) {
1223
+ self.config[key] = arrayify(pluginConf[key]).map(bindToInstance).concat(self.config[key]);
1224
+ } else if (typeof userConfig[key] === "undefined") self.config[key] = pluginConf[key];
1225
+ }
818
1226
  }
1227
+
1228
+ triggerEvent("ParseConfig");
819
1229
  }
820
1230
 
821
1231
  function setupLocale() {
822
- if (_typeof(self.config.locale) !== "object" && typeof Flatpickr.l10ns[self.config.locale] === "undefined") console.warn("flatpickr: invalid locale " + self.config.locale);
1232
+ if (_typeof(self.config.locale) !== "object" && typeof flatpickr.l10ns[self.config.locale] === "undefined") console.warn("flatpickr: invalid locale " + self.config.locale);
823
1233
 
824
- self.l10n = _extends(Object.create(Flatpickr.l10ns.default), _typeof(self.config.locale) === "object" ? self.config.locale : self.config.locale !== "default" ? Flatpickr.l10ns[self.config.locale] || {} : {});
1234
+ self.l10n = _extends(Object.create(flatpickr.l10ns.default), _typeof(self.config.locale) === "object" ? self.config.locale : self.config.locale !== "default" ? flatpickr.l10ns[self.config.locale] || {} : {});
825
1235
  }
826
1236
 
827
- function parseDate(date) {
828
- var timeless = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
1237
+ function positionCalendar() {
1238
+ var positionElement = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : self._positionElement;
829
1239
 
830
- if (!date) return null;
1240
+ if (self.calendarContainer === undefined) return;
831
1241
 
832
- var dateTimeRegex = /(\d+)/g,
833
- timeRegex = /^(\d{1,2})[:\s](\d\d)?[:\s]?(\d\d)?\s?(a|p)?/i,
834
- timestamp = /^(\d+)$/g,
835
- date_orig = date;
1242
+ var calendarHeight = self.calendarContainer.offsetHeight,
1243
+ calendarWidth = self.calendarContainer.offsetWidth,
1244
+ configPos = self.config.position,
1245
+ inputBounds = positionElement.getBoundingClientRect(),
1246
+ distanceFromBottom = window.innerHeight - inputBounds.bottom,
1247
+ showOnTop = configPos === "above" || configPos !== "below" && distanceFromBottom < calendarHeight && inputBounds.top > calendarHeight;
836
1248
 
837
- if (date.toFixed) // timestamp
838
- date = new Date(date);else if (typeof date === "string") {
839
- date = date.trim();
1249
+ var top = window.pageYOffset + inputBounds.top + (!showOnTop ? positionElement.offsetHeight + 2 : -calendarHeight - 2);
840
1250
 
841
- if (date === "today") {
842
- date = new Date();
843
- timeless = true;
844
- } else if (self.config.parseDate) date = self.config.parseDate(date);else if (timeRegex.test(date)) {
845
- // time picker
846
- var m = date.match(timeRegex),
847
- hours = !m[4] ? m[1] // military time, no conversion needed
848
- : m[1] % 12 + (m[4].toLowerCase() === "p" ? 12 : 0); // am/pm
1251
+ toggleClass(self.calendarContainer, "arrowTop", !showOnTop);
1252
+ toggleClass(self.calendarContainer, "arrowBottom", showOnTop);
849
1253
 
850
- date = new Date();
851
- date.setHours(hours, m[2] || 0, m[3] || 0);
852
- } else if (/Z$/.test(date) || /GMT$/.test(date)) // datestrings w/ timezone
853
- date = new Date(date);else if (dateTimeRegex.test(date) && /^[0-9]/.test(date)) {
854
- var d = date.match(dateTimeRegex);
855
- date = new Date(d[0] + "/" + (d[1] || 1) + "/" + (d[2] || 1) + " " + (d[3] || 0) + ":" + (d[4] || 0) + ":" + (d[5] || 0));
856
- } else // fallback
857
- date = new Date(date);
858
- }
1254
+ if (self.config.inline) return;
859
1255
 
860
- if (!(date instanceof Date)) {
861
- console.warn("flatpickr: invalid date " + date_orig);
862
- console.info(self.element);
863
- return null;
864
- }
865
-
866
- if (self.config.utc && !date.fp_isUTC) date = date.fp_toUTC();
867
-
868
- if (timeless) date.setHours(0, 0, 0, 0);
869
-
870
- return date;
871
- }
1256
+ var left = window.pageXOffset + inputBounds.left;
1257
+ var right = window.document.body.offsetWidth - inputBounds.right;
1258
+ var rightMost = left + calendarWidth > window.document.body.offsetWidth;
872
1259
 
873
- function positionCalendar() {
874
- var calendarHeight = self.calendarContainer.offsetHeight,
875
- input = self.altInput || self.input,
876
- inputBounds = input.getBoundingClientRect(),
877
- distanceFromBottom = window.innerHeight - inputBounds.bottom + input.offsetHeight;
1260
+ toggleClass(self.calendarContainer, "rightMost", rightMost);
878
1261
 
879
- var top = void 0,
880
- left = window.pageXOffset + inputBounds.left;
1262
+ if (self.config.static) return;
881
1263
 
882
- if (distanceFromBottom < calendarHeight) {
883
- top = window.pageYOffset - calendarHeight + inputBounds.top - 2;
884
- self.calendarContainer.classList.remove("arrowTop");
885
- self.calendarContainer.classList.add("arrowBottom");
886
- } else {
887
- top = window.pageYOffset + input.offsetHeight + inputBounds.top + 2;
888
- self.calendarContainer.classList.remove("arrowBottom");
889
- self.calendarContainer.classList.add("arrowTop");
890
- }
1264
+ self.calendarContainer.style.top = top + "px";
891
1265
 
892
- if (!self.config.static && !self.config.inline) {
893
- self.calendarContainer.style.top = top + "px";
1266
+ if (!rightMost) {
894
1267
  self.calendarContainer.style.left = left + "px";
1268
+ self.calendarContainer.style.right = "auto";
1269
+ } else {
1270
+ self.calendarContainer.style.left = "auto";
1271
+ self.calendarContainer.style.right = right + "px";
895
1272
  }
896
1273
  }
897
1274
 
@@ -904,35 +1281,41 @@ function Flatpickr(element, config) {
904
1281
  }
905
1282
 
906
1283
  function selectDate(e) {
907
- if (self.config.allowInput && e.which === 13 && e.target === (self.altInput || self.input)) return self.setDate((self.altInput || self.input).value), e.target.blur();
1284
+ e.preventDefault();
1285
+ e.stopPropagation();
908
1286
 
909
1287
  if (!e.target.classList.contains("flatpickr-day") || e.target.classList.contains("disabled") || e.target.classList.contains("notAllowed")) return;
910
1288
 
911
- var selectedDate = e.target.dateObj;
912
- self.selectedDateElem = e.target;
1289
+ var selectedDate = self.latestSelectedDateObj = new Date(e.target.dateObj.getTime());
913
1290
 
914
- if (self.config.mode === "single") {
915
- self.selectedDates = [selectedDate];
1291
+ var shouldChangeMonth = selectedDate.getMonth() !== self.currentMonth && self.config.mode !== "range";
916
1292
 
917
- if (!self.config.enableTime) self.close();
918
- } else if (self.config.mode === "multiple") {
1293
+ self.selectedDateElem = e.target;
1294
+
1295
+ if (self.config.mode === "single") self.selectedDates = [selectedDate];else if (self.config.mode === "multiple") {
919
1296
  var selectedIndex = isDateSelected(selectedDate);
920
1297
  if (selectedIndex) self.selectedDates.splice(selectedIndex, 1);else self.selectedDates.push(selectedDate);
921
1298
  } else if (self.config.mode === "range") {
922
1299
  if (self.selectedDates.length === 2) self.clear();
923
1300
 
924
1301
  self.selectedDates.push(selectedDate);
925
- self.selectedDates.sort(function (a, b) {
1302
+
1303
+ // unless selecting same date twice, sort ascendingly
1304
+ if (compareDates(selectedDate, self.selectedDates[0], true) !== 0) self.selectedDates.sort(function (a, b) {
926
1305
  return a.getTime() - b.getTime();
927
1306
  });
928
1307
  }
929
1308
 
930
1309
  setHoursFromInputs();
931
1310
 
932
- if (selectedDate.getMonth() !== self.currentMonth && self.config.mode !== "range") {
1311
+ if (shouldChangeMonth) {
1312
+ var isNewYear = self.currentYear !== selectedDate.getFullYear();
933
1313
  self.currentYear = selectedDate.getFullYear();
934
1314
  self.currentMonth = selectedDate.getMonth();
935
- updateNavigationCurrentMonth();
1315
+
1316
+ if (isNewYear) triggerEvent("YearChange");
1317
+
1318
+ triggerEvent("MonthChange");
936
1319
  }
937
1320
 
938
1321
  buildDays();
@@ -941,55 +1324,65 @@ function Flatpickr(element, config) {
941
1324
 
942
1325
  updateValue();
943
1326
 
944
- setTimeout(function () {
945
- return self.dateIsPicked = true;
1327
+ if (self.config.enableTime) setTimeout(function () {
1328
+ return self.showTimeInput = true;
946
1329
  }, 50);
947
1330
 
948
- if (self.config.mode === "range" && self.selectedDates.length === 1) onMouseOver(e);
1331
+ if (self.config.mode === "range") {
1332
+ if (self.selectedDates.length === 1) {
1333
+ onMouseOver(e.target);
949
1334
 
950
- triggerEvent("Change");
951
- }
1335
+ self._hidePrevMonthArrow = self._hidePrevMonthArrow || self.minRangeDate > self.days.childNodes[0].dateObj;
952
1336
 
953
- function set(option, value) {
954
- self.config[option] = value;
955
- self.redraw();
956
- jumpToDate();
957
- }
1337
+ self._hideNextMonthArrow = self._hideNextMonthArrow || self.maxRangeDate < new Date(self.currentYear, self.currentMonth + 1, 1);
1338
+ } else updateNavigationCurrentMonth();
1339
+ }
958
1340
 
959
- function setDate(date, triggerChange) {
960
- if (!date) return self.clear();
1341
+ triggerEvent("Change");
961
1342
 
962
- self.selectedDates = (Array.isArray(date) ? date.map(parseDate) : [parseDate(date)]).filter(function (d) {
963
- return d instanceof Date && isEnabled(d);
1343
+ // maintain focus
1344
+ if (!shouldChangeMonth) focusOnDay(e.target.$i, 0);else afterDayAnim(function () {
1345
+ return self.selectedDateElem.focus();
964
1346
  });
965
- self.redraw();
966
- jumpToDate();
967
1347
 
968
- setHoursFromDate();
969
- updateValue();
1348
+ if (self.config.enableTime) setTimeout(function () {
1349
+ return self.hourElement.select();
1350
+ }, 451);
970
1351
 
971
- self.dateIsPicked = self.selectedDates.length > 0;
1352
+ if (self.config.closeOnSelect) {
1353
+ var single = self.config.mode === "single" && !self.config.enableTime;
1354
+ var range = self.config.mode === "range" && self.selectedDates.length === 2 && !self.config.enableTime;
972
1355
 
973
- if (triggerChange) triggerEvent("Change");
1356
+ if (single || range) self.close();
1357
+ }
974
1358
  }
975
1359
 
976
- function setupDates() {
977
- self.selectedDates = [];
978
- self.now = new Date();
979
- var inputDate = self.config.defaultDate || self.input.value;
1360
+ function set(option, value) {
1361
+ self.config[option] = value;
1362
+ self.redraw();
1363
+ jumpToDate();
1364
+ }
980
1365
 
981
- if (Array.isArray(inputDate)) self.selectedDates = inputDate.map(parseDate);else if (inputDate) {
1366
+ function setSelectedDate(inputDate, format) {
1367
+ if (inputDate instanceof Array) self.selectedDates = inputDate.map(function (d) {
1368
+ return self.parseDate(d, format);
1369
+ });else if (inputDate instanceof Date || !isNaN(inputDate)) self.selectedDates = [self.parseDate(inputDate, format)];else if (inputDate && inputDate.substring) {
982
1370
  switch (self.config.mode) {
983
1371
  case "single":
984
- self.selectedDates = [parseDate(inputDate)];
1372
+ self.selectedDates = [self.parseDate(inputDate, format)];
985
1373
  break;
986
1374
 
987
1375
  case "multiple":
988
- self.selectedDates = inputDate.split("; ").map(parseDate);
1376
+ self.selectedDates = inputDate.split("; ").map(function (date) {
1377
+ return self.parseDate(date, format);
1378
+ });
989
1379
  break;
990
1380
 
991
1381
  case "range":
992
- self.selectedDates = inputDate.split(self.l10n.rangeSeparator).map(parseDate);
1382
+ self.selectedDates = inputDate.split(self.l10n.rangeSeparator).map(function (date) {
1383
+ return self.parseDate(date, format);
1384
+ });
1385
+
993
1386
  break;
994
1387
 
995
1388
  default:
@@ -998,169 +1391,167 @@ function Flatpickr(element, config) {
998
1391
  }
999
1392
 
1000
1393
  self.selectedDates = self.selectedDates.filter(function (d) {
1001
- return d instanceof Date && d.getTime() && isEnabled(d);
1394
+ return d instanceof Date && isEnabled(d, false);
1002
1395
  });
1003
1396
 
1004
- var initialDate = self.selectedDates.length ? self.selectedDates[0] : self.config.minDate > self.now ? self.config.minDate : self.now;
1005
-
1006
- self.currentYear = initialDate.getFullYear();
1007
- self.currentMonth = initialDate.getMonth();
1397
+ self.selectedDates.sort(function (a, b) {
1398
+ return a.getTime() - b.getTime();
1399
+ });
1008
1400
  }
1009
1401
 
1010
- function setupHelperFunctions() {
1011
- self.utils = {
1012
- duration: {
1013
- DAY: 86400000
1014
- },
1015
- getDaysinMonth: function getDaysinMonth() {
1016
- var month = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : self.currentMonth;
1017
- var yr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : self.currentYear;
1402
+ function setDate(date, triggerChange, format) {
1403
+ if (date !== 0 && !date) return self.clear(triggerChange);
1018
1404
 
1019
- if (month === 1 && (yr % 4 === 0 && yr % 100 !== 0 || yr % 400 === 0)) return 29;
1020
- return self.l10n.daysInMonth[month];
1021
- },
1405
+ setSelectedDate(date, format);
1022
1406
 
1023
- monthToStr: function monthToStr(monthNumber) {
1024
- var short = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : self.config.shorthandCurrentMonth;
1025
- return self.l10n.months[(short ? "short" : "long") + "hand"][monthNumber];
1026
- }
1027
- };
1028
- }
1407
+ self.showTimeInput = self.selectedDates.length > 0;
1408
+ self.latestSelectedDateObj = self.selectedDates[0];
1029
1409
 
1030
- function setupFormats() {
1031
- self.formats = {
1032
- // weekday name, short, e.g. Thu
1033
- D: function D(date) {
1034
- return self.l10n.weekdays.shorthand[self.formats.w(date)];
1035
- },
1410
+ self.redraw();
1411
+ jumpToDate();
1036
1412
 
1037
- // full month name e.g. January
1038
- F: function F(date) {
1039
- return self.utils.monthToStr(self.formats.n(date) - 1, false);
1040
- },
1413
+ setHoursFromDate();
1414
+ updateValue(triggerChange);
1041
1415
 
1042
- // hours with leading zero e.g. 03
1043
- H: function H(date) {
1044
- return Flatpickr.prototype.pad(date.getHours());
1045
- },
1416
+ if (triggerChange) triggerEvent("Change");
1417
+ }
1046
1418
 
1047
- // day (1-30) with ordinal suffix e.g. 1st, 2nd
1048
- J: function J(date) {
1049
- return date.getDate() + self.l10n.ordinal(date.getDate());
1050
- },
1419
+ function parseDateRules(arr) {
1420
+ for (var i = arr.length; i--;) {
1421
+ if (typeof arr[i] === "string" || +arr[i]) arr[i] = self.parseDate(arr[i], null, true);else if (arr[i] && arr[i].from && arr[i].to) {
1422
+ arr[i].from = self.parseDate(arr[i].from);
1423
+ arr[i].to = self.parseDate(arr[i].to);
1424
+ }
1425
+ }
1051
1426
 
1052
- // AM/PM
1053
- K: function K(date) {
1054
- return date.getHours() > 11 ? "PM" : "AM";
1055
- },
1427
+ return arr.filter(function (x) {
1428
+ return x;
1429
+ }); // remove falsy values
1430
+ }
1056
1431
 
1057
- // shorthand month e.g. Jan, Sep, Oct, etc
1058
- M: function M(date) {
1059
- return self.utils.monthToStr(date.getMonth(), true);
1060
- },
1432
+ function setupDates() {
1433
+ self.selectedDates = [];
1434
+ self.now = new Date();
1061
1435
 
1062
- // seconds 00-59
1063
- S: function S(date) {
1064
- return Flatpickr.prototype.pad(date.getSeconds());
1065
- },
1436
+ var preloadedDate = self.config.defaultDate || self.input.value;
1437
+ if (preloadedDate) setSelectedDate(preloadedDate, self.config.dateFormat);
1066
1438
 
1067
- // unix timestamp
1068
- U: function U(date) {
1069
- return date.getTime() / 1000;
1070
- },
1439
+ var initialDate = self.selectedDates.length ? self.selectedDates[0] : self.config.minDate && self.config.minDate.getTime() > self.now ? self.config.minDate : self.config.maxDate && self.config.maxDate.getTime() < self.now ? self.config.maxDate : self.now;
1071
1440
 
1072
- // full year e.g. 2016
1073
- Y: function Y(date) {
1074
- return date.getFullYear();
1075
- },
1441
+ self.currentYear = initialDate.getFullYear();
1442
+ self.currentMonth = initialDate.getMonth();
1076
1443
 
1077
- // day in month, padded (01-30)
1078
- d: function d(date) {
1079
- return Flatpickr.prototype.pad(self.formats.j(date));
1080
- },
1444
+ if (self.selectedDates.length) self.latestSelectedDateObj = self.selectedDates[0];
1081
1445
 
1082
- // hour from 1-12 (am/pm)
1083
- h: function h(date) {
1084
- return date.getHours() % 12 ? date.getHours() % 12 : 12;
1085
- },
1446
+ self.minDateHasTime = self.config.minDate && (self.config.minDate.getHours() || self.config.minDate.getMinutes() || self.config.minDate.getSeconds());
1086
1447
 
1087
- // minutes, padded with leading zero e.g. 09
1088
- i: function i(date) {
1089
- return Flatpickr.prototype.pad(date.getMinutes());
1090
- },
1448
+ self.maxDateHasTime = self.config.maxDate && (self.config.maxDate.getHours() || self.config.maxDate.getMinutes() || self.config.maxDate.getSeconds());
1091
1449
 
1092
- // day in month (1-30)
1093
- j: function j(date) {
1094
- return date.getDate();
1450
+ Object.defineProperty(self, "latestSelectedDateObj", {
1451
+ get: function get() {
1452
+ return self._selectedDateObj || self.selectedDates[self.selectedDates.length - 1];
1095
1453
  },
1454
+ set: function set(date) {
1455
+ self._selectedDateObj = date;
1456
+ }
1457
+ });
1096
1458
 
1097
- // weekday name, full, e.g. Thursday
1098
- l: function l(date) {
1099
- return self.l10n.weekdays.longhand[self.formats.w(date)];
1100
- },
1459
+ if (!self.isMobile) {
1460
+ Object.defineProperty(self, "showTimeInput", {
1461
+ get: function get() {
1462
+ return self._showTimeInput;
1463
+ },
1464
+ set: function set(bool) {
1465
+ self._showTimeInput = bool;
1466
+ if (self.calendarContainer) toggleClass(self.calendarContainer, "showTimeInput", bool);
1467
+ positionCalendar();
1468
+ }
1469
+ });
1470
+ }
1471
+ }
1101
1472
 
1102
- // padded month number (01-12)
1103
- m: function m(date) {
1104
- return Flatpickr.prototype.pad(self.formats.n(date));
1473
+ function setupHelperFunctions() {
1474
+ self.utils = {
1475
+ duration: {
1476
+ DAY: 86400000
1105
1477
  },
1478
+ getDaysinMonth: function getDaysinMonth(month, yr) {
1479
+ month = typeof month === "undefined" ? self.currentMonth : month;
1106
1480
 
1107
- // the month number (1-12)
1108
- n: function n(date) {
1109
- return date.getMonth() + 1;
1110
- },
1481
+ yr = typeof yr === "undefined" ? self.currentYear : yr;
1111
1482
 
1112
- // seconds 0-59
1113
- s: function s(date) {
1114
- return date.getSeconds();
1115
- },
1483
+ if (month === 1 && (yr % 4 === 0 && yr % 100 !== 0 || yr % 400 === 0)) return 29;
1116
1484
 
1117
- // number of the day of the week
1118
- w: function w(date) {
1119
- return date.getDay();
1485
+ return self.l10n.daysInMonth[month];
1120
1486
  },
1487
+ monthToStr: function monthToStr(monthNumber, shorthand) {
1488
+ shorthand = typeof shorthand === "undefined" ? self.config.shorthandCurrentMonth : shorthand;
1121
1489
 
1122
- // last two digits of year e.g. 16 for 2016
1123
- y: function y(date) {
1124
- return String(self.formats.Y(date)).substring(2);
1490
+ return self.l10n.months[(shorthand ? "short" : "long") + "hand"][monthNumber];
1125
1491
  }
1126
1492
  };
1127
1493
  }
1128
1494
 
1495
+ /* istanbul ignore next */
1496
+ function setupFormats() {
1497
+ self.formats = Object.create(FlatpickrInstance.prototype.formats);
1498
+ ["D", "F", "J", "M", "W", "l"].forEach(function (f) {
1499
+ self.formats[f] = FlatpickrInstance.prototype.formats[f].bind(self);
1500
+ });
1501
+
1502
+ self.revFormat.F = FlatpickrInstance.prototype.revFormat.F.bind(self);
1503
+ self.revFormat.M = FlatpickrInstance.prototype.revFormat.M.bind(self);
1504
+ }
1505
+
1129
1506
  function setupInputs() {
1130
1507
  self.input = self.config.wrap ? self.element.querySelector("[data-input]") : self.element;
1131
1508
 
1509
+ /* istanbul ignore next */
1510
+ if (!self.input) return console.warn("Error: invalid input element specified", self.input);
1511
+
1512
+ self.input._type = self.input.type;
1513
+ self.input.type = "text";
1514
+
1132
1515
  self.input.classList.add("flatpickr-input");
1516
+ self._input = self.input;
1517
+
1133
1518
  if (self.config.altInput) {
1134
1519
  // replicate self.element
1135
- self.altInput = createElement(self.input.nodeName, self.config.altInputClass);
1520
+ self.altInput = createElement(self.input.nodeName, self.input.className + " " + self.config.altInputClass);
1521
+ self._input = self.altInput;
1136
1522
  self.altInput.placeholder = self.input.placeholder;
1523
+ self.altInput.disabled = self.input.disabled;
1524
+ self.altInput.required = self.input.required;
1137
1525
  self.altInput.type = "text";
1138
-
1139
1526
  self.input.type = "hidden";
1140
- if (self.input.parentNode) self.input.parentNode.insertBefore(self.altInput, self.input.nextSibling);
1527
+
1528
+ if (!self.config.static && self.input.parentNode) self.input.parentNode.insertBefore(self.altInput, self.input.nextSibling);
1141
1529
  }
1142
1530
 
1143
- if (!self.config.allowInput) (self.altInput || self.input).setAttribute("readonly", "readonly");
1531
+ if (!self.config.allowInput) self._input.setAttribute("readonly", "readonly");
1532
+
1533
+ self._positionElement = self.config.positionElement || self._input;
1144
1534
  }
1145
1535
 
1146
1536
  function setupMobile() {
1147
1537
  var inputType = self.config.enableTime ? self.config.noCalendar ? "time" : "datetime-local" : "date";
1148
1538
 
1149
- self.mobileInput = createElement("input", "flatpickr-input flatpickr-mobile");
1539
+ self.mobileInput = createElement("input", self.input.className + " flatpickr-mobile");
1150
1540
  self.mobileInput.step = "any";
1151
- self.mobileInput.tabIndex = -1;
1541
+ self.mobileInput.tabIndex = 1;
1152
1542
  self.mobileInput.type = inputType;
1153
1543
  self.mobileInput.disabled = self.input.disabled;
1544
+ self.mobileInput.placeholder = self.input.placeholder;
1154
1545
 
1155
1546
  self.mobileFormatStr = inputType === "datetime-local" ? "Y-m-d\\TH:i:S" : inputType === "date" ? "Y-m-d" : "H:i:S";
1156
1547
 
1157
1548
  if (self.selectedDates.length) {
1158
- self.mobileInput.defaultValue = self.mobileInput.value = formatDate(self.mobileFormatStr, self.selectedDates[0]);
1549
+ self.mobileInput.defaultValue = self.mobileInput.value = self.formatDate(self.selectedDates[0], self.mobileFormatStr);
1159
1550
  }
1160
1551
 
1161
- if (self.config.minDate) self.mobileInput.min = formatDate("Y-m-d", self.config.minDate);
1552
+ if (self.config.minDate) self.mobileInput.min = self.formatDate(self.config.minDate, "Y-m-d");
1162
1553
 
1163
- if (self.config.maxDate) self.mobileInput.max = formatDate("Y-m-d", self.config.maxDate);
1554
+ if (self.config.maxDate) self.mobileInput.max = self.formatDate(self.config.maxDate, "Y-m-d");
1164
1555
 
1165
1556
  self.input.type = "hidden";
1166
1557
  if (self.config.altInput) self.altInput.type = "hidden";
@@ -1172,42 +1563,45 @@ function Flatpickr(element, config) {
1172
1563
  }
1173
1564
 
1174
1565
  self.mobileInput.addEventListener("change", function (e) {
1175
- self.setDate(e.target.value);
1566
+ self.setDate(e.target.value, false, self.mobileFormatStr);
1176
1567
  triggerEvent("Change");
1177
1568
  triggerEvent("Close");
1178
1569
  });
1179
1570
  }
1180
1571
 
1181
1572
  function toggle() {
1182
- if (self.isOpen) self.close();else self.open();
1573
+ if (self.isOpen) return self.close();
1574
+ self.open();
1183
1575
  }
1184
1576
 
1185
1577
  function triggerEvent(event, data) {
1186
- if (self.config["on" + event]) {
1187
- var hooks = Array.isArray(self.config["on" + event]) ? self.config["on" + event] : [self.config["on" + event]];
1578
+ var hooks = self.config["on" + event];
1188
1579
 
1189
- for (var i = 0; i < hooks.length; i++) {
1580
+ if (hooks !== undefined && hooks.length > 0) {
1581
+ for (var i = 0; hooks[i] && i < hooks.length; i++) {
1190
1582
  hooks[i](self.selectedDates, self.input.value, self, data);
1191
1583
  }
1192
1584
  }
1193
1585
 
1194
1586
  if (event === "Change") {
1195
- try {
1196
- self.input.dispatchEvent(new Event("change", { "bubbles": true }));
1587
+ self.input.dispatchEvent(createEvent("change"));
1197
1588
 
1198
- // many front-end frameworks bind to the input event
1199
- self.input.dispatchEvent(new Event("input", { "bubbles": true }));
1200
- } catch (e) {
1201
- if ("createEvent" in document) return self.input.dispatchEvent(self.changeEvent);
1202
-
1203
- self.input.fireEvent("onchange");
1204
- }
1589
+ // many front-end frameworks bind to the input event
1590
+ self.input.dispatchEvent(createEvent("input"));
1205
1591
  }
1206
1592
  }
1207
1593
 
1208
- function latestSelectedDateObj() {
1209
- if (self.selectedDates.length) return self.selectedDates[self.selectedDates.length - 1];
1210
- return null;
1594
+ /**
1595
+ * Creates an Event, normalized across browsers
1596
+ * @param {String} name the event name, e.g. "click"
1597
+ * @return {Event} the created event
1598
+ */
1599
+ function createEvent(name) {
1600
+ if (self._supportsEvents) return new Event(name, { bubbles: true });
1601
+
1602
+ self._[name + "Event"] = document.createEvent("Event");
1603
+ self._[name + "Event"].initEvent(name, true, true);
1604
+ return self._[name + "Event"];
1211
1605
  }
1212
1606
 
1213
1607
  function isDateSelected(date) {
@@ -1229,130 +1623,506 @@ function Flatpickr(element, config) {
1229
1623
  self.currentMonthElement.textContent = self.utils.monthToStr(self.currentMonth) + " ";
1230
1624
  self.currentYearElement.value = self.currentYear;
1231
1625
 
1232
- if (self.config.minDate) {
1233
- var hidePrevMonthArrow = self.currentYear === self.config.minDate.getFullYear() ? (self.currentMonth + 11) % 12 < self.config.minDate.getMonth() : self.currentYear < self.config.minDate.getFullYear();
1234
-
1235
- self.prevMonthNav.style.display = hidePrevMonthArrow ? "none" : "block";
1236
- } else self.prevMonthNav.style.display = "block";
1237
-
1238
- if (self.config.maxDate) {
1239
- var hideNextMonthArrow = self.currentYear === self.config.maxDate.getFullYear() ? self.currentMonth + 1 > self.config.maxDate.getMonth() : self.currentYear > self.config.maxDate.getFullYear();
1626
+ self._hidePrevMonthArrow = self.config.minDate && (self.currentYear === self.config.minDate.getFullYear() ? self.currentMonth <= self.config.minDate.getMonth() : self.currentYear < self.config.minDate.getFullYear());
1240
1627
 
1241
- self.nextMonthNav.style.display = hideNextMonthArrow ? "none" : "block";
1242
- } else self.nextMonthNav.style.display = "block";
1628
+ self._hideNextMonthArrow = self.config.maxDate && (self.currentYear === self.config.maxDate.getFullYear() ? self.currentMonth + 1 > self.config.maxDate.getMonth() : self.currentYear > self.config.maxDate.getFullYear());
1243
1629
  }
1244
1630
 
1245
- function updateValue() {
1246
- if (!self.selectedDates.length) return self.clear();
1631
+ /**
1632
+ * Updates the values of inputs associated with the calendar
1633
+ * @return {void}
1634
+ */
1635
+ function updateValue(triggerChange) {
1636
+ if (!self.selectedDates.length) return self.clear(triggerChange);
1247
1637
 
1248
1638
  if (self.isMobile) {
1249
- self.mobileInput.value = self.selectedDates.length ? formatDate(self.mobileFormatStr, latestSelectedDateObj()) : "";
1639
+ self.mobileInput.value = self.selectedDates.length ? self.formatDate(self.latestSelectedDateObj, self.mobileFormatStr) : "";
1250
1640
  }
1251
1641
 
1252
1642
  var joinChar = self.config.mode !== "range" ? "; " : self.l10n.rangeSeparator;
1253
1643
 
1254
1644
  self.input.value = self.selectedDates.map(function (dObj) {
1255
- return formatDate(self.config.dateFormat, dObj);
1645
+ return self.formatDate(dObj, self.config.dateFormat);
1256
1646
  }).join(joinChar);
1257
1647
 
1258
1648
  if (self.config.altInput) {
1259
1649
  self.altInput.value = self.selectedDates.map(function (dObj) {
1260
- return formatDate(self.config.altFormat, dObj);
1650
+ return self.formatDate(dObj, self.config.altFormat);
1261
1651
  }).join(joinChar);
1262
1652
  }
1263
1653
 
1264
- triggerEvent("ValueUpdate");
1654
+ if (triggerChange !== false) triggerEvent("ValueUpdate");
1265
1655
  }
1266
1656
 
1267
- function yearScroll(e) {
1657
+ function mouseDelta(e) {
1658
+ return Math.max(-1, Math.min(1, e.wheelDelta || -e.deltaY));
1659
+ }
1660
+
1661
+ function onMonthNavScroll(e) {
1268
1662
  e.preventDefault();
1663
+ var isYear = self.currentYearElement.parentNode.contains(e.target);
1664
+
1665
+ if (e.target === self.currentMonthElement || isYear) {
1269
1666
 
1270
- var delta = Math.max(-1, Math.min(1, e.wheelDelta || -e.deltaY)),
1271
- newYear = parseInt(e.target.value, 10) + delta;
1667
+ var delta = mouseDelta(e);
1272
1668
 
1273
- handleYearChange(newYear);
1274
- e.target.value = self.currentYear;
1669
+ if (isYear) {
1670
+ changeYear(self.currentYear + delta);
1671
+ e.target.value = self.currentYear;
1672
+ } else self.changeMonth(delta, true, false);
1673
+ }
1275
1674
  }
1276
1675
 
1277
- function createElement(tag) {
1278
- var className = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
1279
- var content = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "";
1676
+ function onMonthNavClick(e) {
1677
+ var isPrevMonth = self.prevMonthNav.contains(e.target);
1678
+ var isNextMonth = self.nextMonthNav.contains(e.target);
1679
+
1680
+ if (isPrevMonth || isNextMonth) changeMonth(isPrevMonth ? -1 : 1);else if (e.target === self.currentYearElement) {
1681
+ e.preventDefault();
1682
+ self.currentYearElement.select();
1683
+ } else if (e.target.className === "arrowUp") self.changeYear(self.currentYear + 1);else if (e.target.className === "arrowDown") self.changeYear(self.currentYear - 1);
1684
+ }
1685
+
1686
+ /**
1687
+ * Creates an HTMLElement with given tag, class, and textual content
1688
+ * @param {String} tag the HTML tag
1689
+ * @param {String} className the new element's class name
1690
+ * @param {String} content The new element's text content
1691
+ * @return {HTMLElement} the created HTML element
1692
+ */
1693
+ function createElement(tag, className, content) {
1694
+ var e = window.document.createElement(tag);
1695
+ className = className || "";
1696
+ content = content || "";
1280
1697
 
1281
- var e = document.createElement(tag);
1282
1698
  e.className = className;
1283
1699
 
1284
- if (content) e.innerHTML = content;
1700
+ if (content !== undefined) e.textContent = content;
1285
1701
 
1286
1702
  return e;
1287
1703
  }
1288
1704
 
1705
+ function arrayify(obj) {
1706
+ if (obj instanceof Array) return obj;
1707
+ return [obj];
1708
+ }
1709
+
1710
+ function toggleClass(elem, className, bool) {
1711
+ if (bool) return elem.classList.add(className);
1712
+ elem.classList.remove(className);
1713
+ }
1714
+
1715
+ /* istanbul ignore next */
1289
1716
  function debounce(func, wait, immediate) {
1290
1717
  var timeout = void 0;
1291
1718
  return function () {
1292
- for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
1293
- args[_key] = arguments[_key];
1294
- }
1295
-
1296
- var context = this;
1297
- var later = function later() {
1719
+ var context = this,
1720
+ args = arguments;
1721
+ clearTimeout(timeout);
1722
+ timeout = setTimeout(function () {
1298
1723
  timeout = null;
1299
1724
  if (!immediate) func.apply(context, args);
1300
- };
1301
-
1302
- clearTimeout(timeout);
1303
- timeout = setTimeout(later, wait);
1725
+ }, wait);
1304
1726
  if (immediate && !timeout) func.apply(context, args);
1305
1727
  };
1306
1728
  }
1307
1729
 
1308
- function compareDates(date1, date2) {
1730
+ /**
1731
+ * Compute the difference in dates, measured in ms
1732
+ * @param {Date} date1
1733
+ * @param {Date} date2
1734
+ * @param {Boolean} timeless whether to reset times of both dates to 00:00
1735
+ * @return {Number} the difference in ms
1736
+ */
1737
+ function compareDates(date1, date2, timeless) {
1309
1738
  if (!(date1 instanceof Date) || !(date2 instanceof Date)) return false;
1310
1739
 
1311
- return new Date(date1.getTime()).setHours(0, 0, 0, 0) - new Date(date2.getTime()).setHours(0, 0, 0, 0);
1740
+ if (timeless !== false) {
1741
+ return new Date(date1.getTime()).setHours(0, 0, 0, 0) - new Date(date2.getTime()).setHours(0, 0, 0, 0);
1742
+ }
1743
+
1744
+ return date1.getTime() - date2.getTime();
1312
1745
  }
1313
1746
 
1314
1747
  function timeWrapper(e) {
1315
1748
  e.preventDefault();
1316
- if (e && ((e.target.value || e.target.textContent).length >= 2 || // typed two digits
1317
- e.type !== "keydown" && e.type !== "input" // scroll event
1318
- )) e.target.blur();
1749
+
1750
+ var isKeyDown = e.type === "keydown",
1751
+ isWheel = e.type === "wheel",
1752
+ isIncrement = e.type === "increment",
1753
+ input = e.target;
1319
1754
 
1320
1755
  if (self.amPM && e.target === self.amPM) return e.target.textContent = ["AM", "PM"][e.target.textContent === "AM" | 0];
1321
1756
 
1322
- var min = Number(e.target.min),
1323
- max = Number(e.target.max),
1324
- step = Number(e.target.step),
1325
- curValue = parseInt(e.target.value, 10),
1326
- delta = Math.max(-1, Math.min(1, e.wheelDelta || -e.deltaY));
1757
+ var min = Number(input.min),
1758
+ max = Number(input.max),
1759
+ step = Number(input.step),
1760
+ curValue = parseInt(input.value, 10),
1761
+ delta = e.delta || (!isKeyDown ? Math.max(-1, Math.min(1, e.wheelDelta || -e.deltaY)) || 0 : e.which === 38 ? 1 : -1);
1327
1762
 
1328
- var newValue = Number(curValue);
1763
+ var newValue = curValue + step * delta;
1329
1764
 
1330
- if (e.type === "wheel") newValue = curValue + step * delta;else if (e.type === "keydown") newValue = curValue + step * (e.which === 38 ? 1 : -1);
1765
+ if (typeof input.value !== "undefined" && input.value.length === 2) {
1766
+ var isHourElem = input === self.hourElement,
1767
+ isMinuteElem = input === self.minuteElement;
1331
1768
 
1332
- if (newValue < min) {
1333
- newValue = max + newValue + (e.target !== self.hourElement) + (e.target === self.hourElement && !self.amPM);
1334
- } else if (newValue > max) {
1335
- newValue = e.target === self.hourElement ? newValue - max - !self.amPM : min;
1336
- }
1769
+ if (newValue < min) {
1770
+ newValue = max + newValue + !isHourElem + (isHourElem && !self.amPM);
1337
1771
 
1338
- if (self.amPM && e.target === self.hourElement && (step === 1 ? newValue + curValue === 23 : Math.abs(newValue - curValue) > step)) self.amPM.textContent = self.amPM.innerHTML === "PM" ? "AM" : "PM";
1772
+ if (isMinuteElem) incrementNumInput(null, -1, self.hourElement);
1773
+ } else if (newValue > max) {
1774
+ newValue = input === self.hourElement ? newValue - max - !self.amPM : min;
1339
1775
 
1340
- e.target.value = self.pad(newValue);
1776
+ if (isMinuteElem) incrementNumInput(null, 1, self.hourElement);
1777
+ }
1778
+
1779
+ if (self.amPM && isHourElem && (step === 1 ? newValue + curValue === 23 : Math.abs(newValue - curValue) > step)) self.amPM.textContent = self.amPM.textContent === "PM" ? "AM" : "PM";
1780
+
1781
+ input.value = self.pad(newValue);
1782
+ }
1341
1783
  }
1342
1784
 
1343
1785
  init();
1344
1786
  return self;
1345
1787
  }
1346
1788
 
1347
- Flatpickr.defaultConfig = {
1789
+ FlatpickrInstance.prototype = {
1790
+ formats: {
1791
+ // get the date in UTC
1792
+ Z: function Z(date) {
1793
+ return date.toISOString();
1794
+ },
1795
+
1796
+ // weekday name, short, e.g. Thu
1797
+ D: function D(date) {
1798
+ return this.l10n.weekdays.shorthand[this.formats.w(date)];
1799
+ },
1800
+
1801
+ // full month name e.g. January
1802
+ F: function F(date) {
1803
+ return this.utils.monthToStr(this.formats.n(date) - 1, false);
1804
+ },
1805
+
1806
+ // padded hour 1-12
1807
+ G: function G(date) {
1808
+ return FlatpickrInstance.prototype.pad(FlatpickrInstance.prototype.formats.h(date));
1809
+ },
1810
+
1811
+ // hours with leading zero e.g. 03
1812
+ H: function H(date) {
1813
+ return FlatpickrInstance.prototype.pad(date.getHours());
1814
+ },
1815
+
1816
+ // day (1-30) with ordinal suffix e.g. 1st, 2nd
1817
+ J: function J(date) {
1818
+ return date.getDate() + this.l10n.ordinal(date.getDate());
1819
+ },
1820
+
1821
+ // AM/PM
1822
+ K: function K(date) {
1823
+ return date.getHours() > 11 ? "PM" : "AM";
1824
+ },
1825
+
1826
+ // shorthand month e.g. Jan, Sep, Oct, etc
1827
+ M: function M(date) {
1828
+ return this.utils.monthToStr(date.getMonth(), true);
1829
+ },
1830
+
1831
+ // seconds 00-59
1832
+ S: function S(date) {
1833
+ return FlatpickrInstance.prototype.pad(date.getSeconds());
1834
+ },
1835
+
1836
+ // unix timestamp
1837
+ U: function U(date) {
1838
+ return date.getTime() / 1000;
1839
+ },
1840
+
1841
+ W: function W(date) {
1842
+ return this.config.getWeek(date);
1843
+ },
1844
+
1845
+ // full year e.g. 2016
1846
+ Y: function Y(date) {
1847
+ return date.getFullYear();
1848
+ },
1849
+
1850
+ // day in month, padded (01-30)
1851
+ d: function d(date) {
1852
+ return FlatpickrInstance.prototype.pad(date.getDate());
1853
+ },
1854
+
1855
+ // hour from 1-12 (am/pm)
1856
+ h: function h(date) {
1857
+ return date.getHours() % 12 ? date.getHours() % 12 : 12;
1858
+ },
1859
+
1860
+ // minutes, padded with leading zero e.g. 09
1861
+ i: function i(date) {
1862
+ return FlatpickrInstance.prototype.pad(date.getMinutes());
1863
+ },
1864
+
1865
+ // day in month (1-30)
1866
+ j: function j(date) {
1867
+ return date.getDate();
1868
+ },
1869
+
1870
+ // weekday name, full, e.g. Thursday
1871
+ l: function l(date) {
1872
+ return this.l10n.weekdays.longhand[date.getDay()];
1873
+ },
1874
+
1875
+ // padded month number (01-12)
1876
+ m: function m(date) {
1877
+ return FlatpickrInstance.prototype.pad(date.getMonth() + 1);
1878
+ },
1879
+
1880
+ // the month number (1-12)
1881
+ n: function n(date) {
1882
+ return date.getMonth() + 1;
1883
+ },
1884
+
1885
+ // seconds 0-59
1886
+ s: function s(date) {
1887
+ return date.getSeconds();
1888
+ },
1889
+
1890
+ // number of the day of the week
1891
+ w: function w(date) {
1892
+ return date.getDay();
1893
+ },
1894
+
1895
+ // last two digits of year e.g. 16 for 2016
1896
+ y: function y(date) {
1897
+ return String(date.getFullYear()).substring(2);
1898
+ }
1899
+ },
1900
+
1901
+ /**
1902
+ * Formats a given Date object into a string based on supplied format
1903
+ * @param {Date} dateObj the date object
1904
+ * @param {String} frmt a string composed of formatting tokens e.g. "Y-m-d"
1905
+ * @return {String} The textual representation of the date e.g. 2017-02-03
1906
+ */
1907
+ formatDate: function formatDate(dateObj, frmt) {
1908
+ var _this = this;
1909
+
1910
+ if (this.config !== undefined && this.config.formatDate !== undefined) return this.config.formatDate(dateObj, frmt);
1911
+
1912
+ return frmt.split("").map(function (c, i, arr) {
1913
+ return _this.formats[c] && arr[i - 1] !== "\\" ? _this.formats[c](dateObj) : c !== "\\" ? c : "";
1914
+ }).join("");
1915
+ },
1916
+
1917
+
1918
+ revFormat: {
1919
+ D: function D() {},
1920
+ F: function F(dateObj, monthName) {
1921
+ dateObj.setMonth(this.l10n.months.longhand.indexOf(monthName));
1922
+ },
1923
+ G: function G(dateObj, hour) {
1924
+ dateObj.setHours(parseFloat(hour));
1925
+ },
1926
+ H: function H(dateObj, hour) {
1927
+ dateObj.setHours(parseFloat(hour));
1928
+ },
1929
+ J: function J(dateObj, day) {
1930
+ dateObj.setDate(parseFloat(day));
1931
+ },
1932
+ K: function K(dateObj, amPM) {
1933
+ var hours = dateObj.getHours();
1934
+
1935
+ if (hours !== 12) dateObj.setHours(hours % 12 + 12 * /pm/i.test(amPM));
1936
+ },
1937
+ M: function M(dateObj, shortMonth) {
1938
+ dateObj.setMonth(this.l10n.months.shorthand.indexOf(shortMonth));
1939
+ },
1940
+ S: function S(dateObj, seconds) {
1941
+ dateObj.setSeconds(seconds);
1942
+ },
1943
+ U: function U(dateObj, unixSeconds) {
1944
+ return new Date(parseFloat(unixSeconds) * 1000);
1945
+ },
1946
+
1947
+ W: function W(dateObj, weekNumber) {
1948
+ weekNumber = parseInt(weekNumber);
1949
+ return new Date(dateObj.getFullYear(), 0, 2 + (weekNumber - 1) * 7, 0, 0, 0, 0, 0);
1950
+ },
1951
+ Y: function Y(dateObj, year) {
1952
+ dateObj.setFullYear(year);
1953
+ },
1954
+ Z: function Z(dateObj, ISODate) {
1955
+ return new Date(ISODate);
1956
+ },
1957
+
1958
+ d: function d(dateObj, day) {
1959
+ dateObj.setDate(parseFloat(day));
1960
+ },
1961
+ h: function h(dateObj, hour) {
1962
+ dateObj.setHours(parseFloat(hour));
1963
+ },
1964
+ i: function i(dateObj, minutes) {
1965
+ dateObj.setMinutes(parseFloat(minutes));
1966
+ },
1967
+ j: function j(dateObj, day) {
1968
+ dateObj.setDate(parseFloat(day));
1969
+ },
1970
+ l: function l() {},
1971
+ m: function m(dateObj, month) {
1972
+ dateObj.setMonth(parseFloat(month) - 1);
1973
+ },
1974
+ n: function n(dateObj, month) {
1975
+ dateObj.setMonth(parseFloat(month) - 1);
1976
+ },
1977
+ s: function s(dateObj, seconds) {
1978
+ dateObj.setSeconds(parseFloat(seconds));
1979
+ },
1980
+ w: function w() {},
1981
+ y: function y(dateObj, year) {
1982
+ dateObj.setFullYear(2000 + parseFloat(year));
1983
+ }
1984
+ },
1985
+
1986
+ tokenRegex: {
1987
+ D: "(\\w+)",
1988
+ F: "(\\w+)",
1989
+ G: "(\\d\\d|\\d)",
1990
+ H: "(\\d\\d|\\d)",
1991
+ J: "(\\d\\d|\\d)\\w+",
1992
+ K: "(am|AM|Am|aM|pm|PM|Pm|pM)",
1993
+ M: "(\\w+)",
1994
+ S: "(\\d\\d|\\d)",
1995
+ U: "(.+)",
1996
+ W: "(\\d\\d|\\d)",
1997
+ Y: "(\\d{4})",
1998
+ Z: "(.+)",
1999
+ d: "(\\d\\d|\\d)",
2000
+ h: "(\\d\\d|\\d)",
2001
+ i: "(\\d\\d|\\d)",
2002
+ j: "(\\d\\d|\\d)",
2003
+ l: "(\\w+)",
2004
+ m: "(\\d\\d|\\d)",
2005
+ n: "(\\d\\d|\\d)",
2006
+ s: "(\\d\\d|\\d)",
2007
+ w: "(\\d\\d|\\d)",
2008
+ y: "(\\d{2})"
2009
+ },
2010
+
2011
+ pad: function pad(number) {
2012
+ return ("0" + number).slice(-2);
2013
+ },
2014
+
2015
+ /**
2016
+ * Parses a date(+time) string into a Date object
2017
+ * @param {String} date the date string, e.g. 2017-02-03 14:45
2018
+ * @param {String} givenFormat the date format, e.g. Y-m-d H:i
2019
+ * @param {Boolean} timeless whether to reset the time of Date object
2020
+ * @return {Date} the parsed Date object
2021
+ */
2022
+ parseDate: function parseDate(date, givenFormat, timeless) {
2023
+ if (date !== 0 && !date) return null;
2024
+
2025
+ var date_orig = date;
2026
+
2027
+ if (date instanceof Date) date = new Date(date.getTime()); // create a copy
2028
+
2029
+ else if (date.toFixed !== undefined) // timestamp
2030
+ date = new Date(date);else {
2031
+ // date string
2032
+ var format = givenFormat || (this.config || flatpickr.defaultConfig).dateFormat;
2033
+ date = String(date).trim();
2034
+
2035
+ if (date === "today") {
2036
+ date = new Date();
2037
+ timeless = true;
2038
+ } else if (/Z$/.test(date) || /GMT$/.test(date)) // datestrings w/ timezone
2039
+ date = new Date(date);else if (this.config && this.config.parseDate) date = this.config.parseDate(date, format);else {
2040
+ var parsedDate = !this.config || !this.config.noCalendar ? new Date(new Date().getFullYear(), 0, 1, 0, 0, 0, 0) : new Date(new Date().setHours(0, 0, 0, 0));
2041
+
2042
+ var matched = void 0;
2043
+
2044
+ for (var i = 0, matchIndex = 0, regexStr = ""; i < format.length; i++) {
2045
+ var token = format[i];
2046
+ var isBackSlash = token === "\\";
2047
+ var escaped = format[i - 1] === "\\" || isBackSlash;
2048
+
2049
+ if (this.tokenRegex[token] && !escaped) {
2050
+ regexStr += this.tokenRegex[token];
2051
+ var match = new RegExp(regexStr).exec(date);
2052
+ if (match && (matched = true)) {
2053
+ parsedDate = this.revFormat[token](parsedDate, match[++matchIndex]) || parsedDate;
2054
+ }
2055
+ } else if (!isBackSlash) regexStr += "."; // don't really care
2056
+ }
2057
+
2058
+ date = matched ? parsedDate : null;
2059
+ }
2060
+ }
2061
+
2062
+ /* istanbul ignore next */
2063
+ if (!(date instanceof Date)) {
2064
+ console.warn("flatpickr: invalid date " + date_orig);
2065
+ console.info(this.element);
2066
+ return null;
2067
+ }
2068
+
2069
+ if (timeless === true) date.setHours(0, 0, 0, 0);
2070
+
2071
+ return date;
2072
+ }
2073
+ };
2074
+
2075
+ /* istanbul ignore next */
2076
+ function _flatpickr(nodeList, config) {
2077
+ var nodes = Array.prototype.slice.call(nodeList); // static list
2078
+ var instances = [];
2079
+ for (var i = 0; i < nodes.length; i++) {
2080
+ try {
2081
+ if (nodes[i].getAttribute("data-fp-omit") !== null) continue;
2082
+
2083
+ if (nodes[i]._flatpickr) {
2084
+ nodes[i]._flatpickr.destroy();
2085
+ nodes[i]._flatpickr = null;
2086
+ }
2087
+
2088
+ nodes[i]._flatpickr = new FlatpickrInstance(nodes[i], config || {});
2089
+ instances.push(nodes[i]._flatpickr);
2090
+ } catch (e) {
2091
+ console.warn(e, e.stack);
2092
+ }
2093
+ }
2094
+
2095
+ return instances.length === 1 ? instances[0] : instances;
2096
+ }
2097
+
2098
+ /* istanbul ignore next */
2099
+ if (typeof HTMLElement !== "undefined") {
2100
+ // browser env
2101
+ HTMLCollection.prototype.flatpickr = NodeList.prototype.flatpickr = function (config) {
2102
+ return _flatpickr(this, config);
2103
+ };
2104
+
2105
+ HTMLElement.prototype.flatpickr = function (config) {
2106
+ return _flatpickr([this], config);
2107
+ };
2108
+ }
2109
+
2110
+ /* istanbul ignore next */
2111
+ function flatpickr(selector, config) {
2112
+ if (selector instanceof NodeList) return _flatpickr(selector, config);else if (!(selector instanceof HTMLElement)) return _flatpickr(window.document.querySelectorAll(selector), config);
1348
2113
 
2114
+ return _flatpickr([selector], config);
2115
+ }
2116
+
2117
+ /* istanbul ignore next */
2118
+ flatpickr.defaultConfig = FlatpickrInstance.defaultConfig = {
1349
2119
  mode: "single",
1350
2120
 
1351
- /* if true, dates will be parsed, formatted, and displayed in UTC.
1352
- preloading date strings w/ timezones is recommended but not necessary */
1353
- utc: false,
2121
+ position: "auto",
2122
+
2123
+ animate: window.navigator.userAgent.indexOf("MSIE") === -1,
1354
2124
 
1355
- // wrap: see https://chmln.github.io/flatpickr/#strap
2125
+ // wrap: see https://chmln.github.io/flatpickr/examples/#flatpickr-external-elements
1356
2126
  wrap: false,
1357
2127
 
1358
2128
  // enables week numbers
@@ -1367,6 +2137,12 @@ Flatpickr.defaultConfig = {
1367
2137
  */
1368
2138
  clickOpens: true,
1369
2139
 
2140
+ /*
2141
+ closes calendar after date selection,
2142
+ unless 'mode' is 'multiple' or enableTime is true
2143
+ */
2144
+ closeOnSelect: true,
2145
+
1370
2146
  // display time picker in 24 hour mode
1371
2147
  time_24hr: false,
1372
2148
 
@@ -1379,6 +2155,9 @@ Flatpickr.defaultConfig = {
1379
2155
  // more date format chars at https://chmln.github.io/flatpickr/#dateformat
1380
2156
  dateFormat: "Y-m-d",
1381
2157
 
2158
+ // date format used in aria-label for days
2159
+ ariaDateFormat: "F j, Y",
2160
+
1382
2161
  // altInput - see https://chmln.github.io/flatpickr/#altinput
1383
2162
  altInput: false,
1384
2163
 
@@ -1405,16 +2184,11 @@ Flatpickr.defaultConfig = {
1405
2184
 
1406
2185
  getWeek: function getWeek(givenDate) {
1407
2186
  var date = new Date(givenDate.getTime());
1408
- date.setHours(0, 0, 0, 0);
1409
-
1410
- // Thursday in current week decides the year.
1411
- date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
1412
- // January 4 is always in week 1.
1413
- var week1 = new Date(date.getFullYear(), 0, 4);
1414
- // Adjust to Thursday in week 1 and count number of weeks from date to week1.
1415
- return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7);
2187
+ var onejan = new Date(date.getFullYear(), 0, 1);
2188
+ return Math.ceil(((date - onejan) / 86400000 + onejan.getDay() + 1) / 7);
1416
2189
  },
1417
2190
 
2191
+
1418
2192
  // see https://chmln.github.io/flatpickr/#disable
1419
2193
  enable: [],
1420
2194
 
@@ -1429,7 +2203,7 @@ Flatpickr.defaultConfig = {
1429
2203
 
1430
2204
  // position calendar inside wrapper and next to the input element
1431
2205
  // leave at false unless you know what you"re doing
1432
- static: false,
2206
+ "static": false,
1433
2207
 
1434
2208
  // DOM node to append the calendar to in *static* mode
1435
2209
  appendTo: null,
@@ -1459,24 +2233,44 @@ Flatpickr.defaultConfig = {
1459
2233
  // default locale
1460
2234
  locale: "default",
1461
2235
 
2236
+ plugins: [],
2237
+
2238
+ ignoredFocusElements: [],
2239
+
2240
+ // called every time calendar is closed
2241
+ onClose: undefined, // function (dateObj, dateStr) {}
2242
+
1462
2243
  // onChange callback when user selects a date or time
1463
- onChange: null, // function (dateObj, dateStr) {}
2244
+ onChange: undefined, // function (dateObj, dateStr) {}
2245
+
2246
+ // called for every day element
2247
+ onDayCreate: undefined,
2248
+
2249
+ // called every time the month is changed
2250
+ onMonthChange: undefined,
1464
2251
 
1465
2252
  // called every time calendar is opened
1466
- onOpen: null, // function (dateObj, dateStr) {}
2253
+ onOpen: undefined, // function (dateObj, dateStr) {}
1467
2254
 
1468
- // called every time calendar is closed
1469
- onClose: null, // function (dateObj, dateStr) {}
2255
+ // called after the configuration has been parsed
2256
+ onParseConfig: undefined,
1470
2257
 
1471
2258
  // called after calendar is ready
1472
- onReady: null, // function (dateObj, dateStr) {}
2259
+ onReady: undefined, // function (dateObj, dateStr) {}
2260
+
2261
+ // called after input value updated
2262
+ onValueUpdate: undefined,
2263
+
2264
+ // called every time the year is changed
2265
+ onYearChange: undefined,
1473
2266
 
1474
- onValueUpdate: null,
2267
+ onKeyDown: undefined,
1475
2268
 
1476
- onDayCreate: null
2269
+ onDestroy: undefined
1477
2270
  };
1478
2271
 
1479
- Flatpickr.l10ns = {
2272
+ /* istanbul ignore next */
2273
+ flatpickr.l10ns = {
1480
2274
  en: {
1481
2275
  weekdays: {
1482
2276
  shorthand: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
@@ -1509,46 +2303,15 @@ Flatpickr.l10ns = {
1509
2303
  }
1510
2304
  };
1511
2305
 
1512
- Flatpickr.l10ns.default = Flatpickr.l10ns.en;
1513
-
1514
- Flatpickr.localize = function (l10n) {
1515
- return _extends(Flatpickr.l10ns.default, l10n || {});
2306
+ flatpickr.l10ns.default = Object.create(flatpickr.l10ns.en);
2307
+ flatpickr.localize = function (l10n) {
2308
+ return _extends(flatpickr.l10ns.default, l10n || {});
1516
2309
  };
1517
-
1518
- Flatpickr.prototype = {
1519
- pad: function pad(number) {
1520
- return ("0" + number).slice(-2);
1521
- }
2310
+ flatpickr.setDefaults = function (config) {
2311
+ return _extends(flatpickr.defaultConfig, config || {});
1522
2312
  };
1523
2313
 
1524
- function _flatpickr(nodeList, config) {
1525
- var instances = [];
1526
- for (var i = 0; i < nodeList.length; i++) {
1527
- try {
1528
- nodeList[i]._flatpickr = new Flatpickr(nodeList[i], config || {});
1529
- instances.push(nodeList[i]._flatpickr);
1530
- } catch (e) {
1531
- console.warn(e, e.stack);
1532
- }
1533
- }
1534
-
1535
- return instances.length === 1 ? instances[0] : instances;
1536
- }
1537
- if (typeof HTMLElement !== "undefined") {
1538
- // browser env
1539
- HTMLCollection.prototype.flatpickr = NodeList.prototype.flatpickr = function (config) {
1540
- return _flatpickr(this, config);
1541
- };
1542
-
1543
- HTMLElement.prototype.flatpickr = function (config) {
1544
- return _flatpickr([this], config);
1545
- };
1546
- }
1547
-
1548
- function flatpickr(selector, config) {
1549
- return _flatpickr(document.querySelectorAll(selector), config);
1550
- }
1551
-
2314
+ /* istanbul ignore next */
1552
2315
  if (typeof jQuery !== "undefined") {
1553
2316
  jQuery.fn.flatpickr = function (config) {
1554
2317
  return _flatpickr(this, config);
@@ -1559,60 +2322,4 @@ Date.prototype.fp_incr = function (days) {
1559
2322
  return new Date(this.getFullYear(), this.getMonth(), this.getDate() + parseInt(days, 10));
1560
2323
  };
1561
2324
 
1562
- Date.prototype.fp_isUTC = false;
1563
- Date.prototype.fp_toUTC = function () {
1564
- var newDate = new Date(this.getUTCFullYear(), this.getUTCMonth(), this.getUTCDate(), this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds());
1565
-
1566
- newDate.fp_isUTC = true;
1567
- return newDate;
1568
- };
1569
-
1570
- // IE9 classList polyfill
1571
- if (!("classList" in document.documentElement) && Object.defineProperty && typeof HTMLElement !== "undefined") {
1572
- Object.defineProperty(HTMLElement.prototype, "classList", {
1573
- get: function get() {
1574
- var self = this;
1575
- function update(fn) {
1576
- return function (value) {
1577
- var classes = self.className.split(/\s+/),
1578
- index = classes.indexOf(value);
1579
-
1580
- fn(classes, index, value);
1581
- self.className = classes.join(" ");
1582
- };
1583
- }
1584
-
1585
- var ret = {
1586
- add: update(function (classes, index, value) {
1587
- if (!~index) classes.push(value);
1588
- }),
1589
-
1590
- remove: update(function (classes, index) {
1591
- if (~index) classes.splice(index, 1);
1592
- }),
1593
-
1594
- toggle: update(function (classes, index, value) {
1595
- if (~index) classes.splice(index, 1);else classes.push(value);
1596
- }),
1597
-
1598
- contains: function contains(value) {
1599
- return !!~self.className.split(/\s+/).indexOf(value);
1600
- },
1601
-
1602
- item: function item(i) {
1603
- return self.className.split(/\s+/)[i] || null;
1604
- }
1605
- };
1606
-
1607
- Object.defineProperty(ret, "length", {
1608
- get: function get() {
1609
- return self.className.split(/\s+/).length;
1610
- }
1611
- });
1612
-
1613
- return ret;
1614
- }
1615
- });
1616
- }
1617
-
1618
- if (typeof module !== "undefined") module.exports = Flatpickr;
2325
+ if (typeof module !== "undefined") module.exports = flatpickr;