flatpickr_rails 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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;