buefy 0.9.9 → 0.9.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/CHANGELOG.md +1639 -1609
  2. package/dist/buefy.css +20 -2
  3. package/dist/buefy.esm.js +2227 -1869
  4. package/dist/buefy.esm.min.js +2 -2
  5. package/dist/buefy.js +2266 -1907
  6. package/dist/buefy.min.css +1 -1
  7. package/dist/buefy.min.js +2 -2
  8. package/dist/cjs/autocomplete.js +6 -6
  9. package/dist/cjs/breadcrumb.js +127 -0
  10. package/dist/cjs/button.js +6 -107
  11. package/dist/cjs/carousel.js +9 -7
  12. package/dist/cjs/checkbox.js +5 -5
  13. package/dist/cjs/{chunk-d33a8a78.js → chunk-114191ae.js} +3 -3
  14. package/dist/cjs/{chunk-dafdb70c.js → chunk-2062216d.js} +39 -3
  15. package/dist/cjs/{chunk-64efc596.js → chunk-2911aa4b.js} +20 -16
  16. package/dist/cjs/{chunk-96ab31c1.js → chunk-2ae50815.js} +7 -7
  17. package/dist/cjs/{chunk-c3032504.js → chunk-2c7de785.js} +3 -3
  18. package/dist/cjs/{chunk-50ff3a78.js → chunk-30670fac.js} +96 -15
  19. package/dist/cjs/{chunk-e57b3891.js → chunk-34949503.js} +2 -2
  20. package/dist/cjs/{chunk-0abd2223.js → chunk-3b43d77a.js} +2 -2
  21. package/dist/cjs/{chunk-dcdbe2e8.js → chunk-3cc5d9a6.js} +1 -1
  22. package/dist/cjs/{chunk-0b57168e.js → chunk-61023b09.js} +3 -3
  23. package/dist/cjs/chunk-6cb902f8.js +314 -0
  24. package/dist/cjs/{chunk-adb01a93.js → chunk-7da0c017.js} +26 -24
  25. package/dist/cjs/{chunk-60255743.js → chunk-9103eeda.js} +4 -0
  26. package/dist/cjs/{chunk-14c82365.js → chunk-92621ff7.js} +37 -0
  27. package/dist/cjs/{chunk-816cba7a.js → chunk-9e4cf4c5.js} +1 -1
  28. package/dist/cjs/{chunk-33b9d1cf.js → chunk-a11294f9.js} +27 -26
  29. package/dist/cjs/{chunk-430b5370.js → chunk-bfcad370.js} +25 -2
  30. package/dist/cjs/{chunk-cc470e7c.js → chunk-c6fbc7b4.js} +7 -7
  31. package/dist/cjs/{chunk-993f89de.js → chunk-c7b2aa4b.js} +5 -4
  32. package/dist/cjs/{chunk-6474e963.js → chunk-d0f8ea39.js} +9 -9
  33. package/dist/cjs/{chunk-3acb500b.js → chunk-d120e215.js} +2 -2
  34. package/dist/cjs/{chunk-f5baaa70.js → chunk-d54e40f6.js} +2 -1
  35. package/dist/cjs/{chunk-916a2858.js → chunk-f5106717.js} +4 -4
  36. package/dist/cjs/chunk-fe2f57ee.js +110 -0
  37. package/dist/cjs/{chunk-2571dc7c.js → chunk-fefd7b77.js} +0 -0
  38. package/dist/cjs/clockpicker.js +11 -11
  39. package/dist/cjs/config.js +2 -2
  40. package/dist/cjs/datepicker.js +12 -12
  41. package/dist/cjs/datetimepicker.js +22 -15
  42. package/dist/cjs/dialog.js +13 -11
  43. package/dist/cjs/dropdown.js +8 -8
  44. package/dist/cjs/field.js +5 -5
  45. package/dist/cjs/helpers.js +2 -3
  46. package/dist/cjs/icon.js +3 -3
  47. package/dist/cjs/image.js +6 -311
  48. package/dist/cjs/index.js +29 -23
  49. package/dist/cjs/input.js +5 -5
  50. package/dist/cjs/loading.js +6 -6
  51. package/dist/cjs/menu.js +3 -3
  52. package/dist/cjs/message.js +6 -6
  53. package/dist/cjs/modal.js +6 -6
  54. package/dist/cjs/navbar.js +16 -4
  55. package/dist/cjs/notification.js +23 -11
  56. package/dist/cjs/numberinput.js +9 -7
  57. package/dist/cjs/pagination.js +8 -8
  58. package/dist/cjs/progress.js +10 -6
  59. package/dist/cjs/radio.js +3 -3
  60. package/dist/cjs/rate.js +3 -3
  61. package/dist/cjs/select.js +7 -7
  62. package/dist/cjs/sidebar.js +2 -2
  63. package/dist/cjs/slider.js +4 -4
  64. package/dist/cjs/snackbar.js +5 -5
  65. package/dist/cjs/steps.js +8 -8
  66. package/dist/cjs/switch.js +1 -1
  67. package/dist/cjs/table.js +13 -13
  68. package/dist/cjs/tabs.js +8 -8
  69. package/dist/cjs/tag.js +3 -3
  70. package/dist/cjs/taginput.js +34 -22
  71. package/dist/cjs/timepicker.js +13 -13
  72. package/dist/cjs/toast.js +5 -5
  73. package/dist/cjs/tooltip.js +5 -5
  74. package/dist/cjs/upload.js +5 -5
  75. package/dist/components/autocomplete/index.js +98 -13
  76. package/dist/components/autocomplete/index.min.js +2 -2
  77. package/dist/components/breadcrumb/index.js +293 -0
  78. package/dist/components/breadcrumb/index.min.js +2 -0
  79. package/dist/components/button/index.js +5 -1
  80. package/dist/components/button/index.min.js +2 -2
  81. package/dist/components/carousel/index.js +348 -15
  82. package/dist/components/carousel/index.min.js +2 -2
  83. package/dist/components/checkbox/index.js +1 -1
  84. package/dist/components/checkbox/index.min.js +1 -1
  85. package/dist/components/clockpicker/index.js +54 -47
  86. package/dist/components/clockpicker/index.min.js +2 -2
  87. package/dist/components/collapse/index.js +1 -1
  88. package/dist/components/collapse/index.min.js +1 -1
  89. package/dist/components/datepicker/index.js +41 -32
  90. package/dist/components/datepicker/index.min.js +2 -2
  91. package/dist/components/datetimepicker/index.js +75 -58
  92. package/dist/components/datetimepicker/index.min.js +2 -2
  93. package/dist/components/dialog/index.js +126 -18
  94. package/dist/components/dialog/index.min.js +2 -2
  95. package/dist/components/dropdown/index.js +5 -1
  96. package/dist/components/dropdown/index.min.js +1 -1
  97. package/dist/components/field/index.js +29 -23
  98. package/dist/components/field/index.min.js +2 -2
  99. package/dist/components/icon/index.js +5 -1
  100. package/dist/components/icon/index.min.js +2 -2
  101. package/dist/components/image/index.js +463 -444
  102. package/dist/components/image/index.min.js +2 -2
  103. package/dist/components/input/index.js +5 -1
  104. package/dist/components/input/index.min.js +2 -2
  105. package/dist/components/loading/index.js +2 -2
  106. package/dist/components/loading/index.min.js +2 -2
  107. package/dist/components/menu/index.js +5 -1
  108. package/dist/components/menu/index.min.js +2 -2
  109. package/dist/components/message/index.js +43 -3
  110. package/dist/components/message/index.min.js +2 -2
  111. package/dist/components/modal/index.js +7 -2
  112. package/dist/components/modal/index.min.js +2 -2
  113. package/dist/components/navbar/index.js +16 -4
  114. package/dist/components/navbar/index.min.js +2 -2
  115. package/dist/components/notification/index.js +59 -6
  116. package/dist/components/notification/index.min.js +2 -2
  117. package/dist/components/numberinput/index.js +9 -3
  118. package/dist/components/numberinput/index.min.js +2 -2
  119. package/dist/components/pagination/index.js +5 -1
  120. package/dist/components/pagination/index.min.js +2 -2
  121. package/dist/components/progress/index.js +10 -2
  122. package/dist/components/progress/index.min.js +2 -2
  123. package/dist/components/radio/index.js +1 -1
  124. package/dist/components/radio/index.min.js +1 -1
  125. package/dist/components/rate/index.js +5 -1
  126. package/dist/components/rate/index.min.js +2 -2
  127. package/dist/components/select/index.js +5 -1
  128. package/dist/components/select/index.min.js +2 -2
  129. package/dist/components/sidebar/index.js +5 -1
  130. package/dist/components/sidebar/index.min.js +1 -1
  131. package/dist/components/skeleton/index.js +1 -1
  132. package/dist/components/skeleton/index.min.js +1 -1
  133. package/dist/components/slider/index.js +5 -1
  134. package/dist/components/slider/index.min.js +2 -2
  135. package/dist/components/snackbar/index.js +7 -2
  136. package/dist/components/snackbar/index.min.js +2 -2
  137. package/dist/components/steps/index.js +5 -1
  138. package/dist/components/steps/index.min.js +2 -2
  139. package/dist/components/switch/index.js +5 -1
  140. package/dist/components/switch/index.min.js +1 -1
  141. package/dist/components/table/index.js +6 -2
  142. package/dist/components/table/index.min.js +2 -2
  143. package/dist/components/tabs/index.js +5 -1
  144. package/dist/components/tabs/index.min.js +2 -2
  145. package/dist/components/tag/index.js +26 -3
  146. package/dist/components/tag/index.min.js +2 -2
  147. package/dist/components/taginput/index.js +185 -29
  148. package/dist/components/taginput/index.min.js +2 -2
  149. package/dist/components/timepicker/index.js +54 -47
  150. package/dist/components/timepicker/index.min.js +2 -2
  151. package/dist/components/toast/index.js +7 -2
  152. package/dist/components/toast/index.min.js +2 -2
  153. package/dist/components/tooltip/index.js +5 -1
  154. package/dist/components/tooltip/index.min.js +1 -1
  155. package/dist/components/upload/index.js +5 -1
  156. package/dist/components/upload/index.min.js +2 -2
  157. package/dist/esm/autocomplete.js +7 -7
  158. package/dist/esm/breadcrumb.js +122 -0
  159. package/dist/esm/button.js +6 -107
  160. package/dist/esm/carousel.js +7 -5
  161. package/dist/esm/{chunk-56040896.js → chunk-18e8b067.js} +3 -3
  162. package/dist/esm/{chunk-fa404a2c.js → chunk-21fc0948.js} +7 -7
  163. package/dist/esm/{chunk-f9299099.js → chunk-22e9f916.js} +19 -15
  164. package/dist/esm/{chunk-1fafdf15.js → chunk-2452e3d3.js} +37 -1
  165. package/dist/esm/{chunk-1297c2c9.js → chunk-29ca0df8.js} +1 -1
  166. package/dist/esm/{chunk-3c2169d7.js → chunk-2f2f0a74.js} +25 -2
  167. package/dist/esm/{chunk-cf72ce36.js → chunk-3773c62d.js} +2 -2
  168. package/dist/esm/{chunk-2c957994.js → chunk-4b67a181.js} +3 -3
  169. package/dist/esm/{chunk-45740cdc.js → chunk-6019fd7a.js} +96 -15
  170. package/dist/esm/chunk-71a547bc.js +312 -0
  171. package/dist/esm/{chunk-516e4877.js → chunk-75a5af93.js} +1 -1
  172. package/dist/esm/{chunk-4e380ee2.js → chunk-799e084d.js} +2 -1
  173. package/dist/esm/{chunk-37678809.js → chunk-83eb0d37.js} +3 -3
  174. package/dist/esm/{chunk-34c74085.js → chunk-8d0f95b8.js} +4 -4
  175. package/dist/esm/{chunk-652f2dad.js → chunk-8ed29c41.js} +4 -0
  176. package/dist/esm/{chunk-742a9694.js → chunk-9f7f7441.js} +3 -2
  177. package/dist/esm/{chunk-f160efb9.js → chunk-ae8ab23a.js} +4 -4
  178. package/dist/esm/{chunk-c3b09672.js → chunk-b07e3182.js} +26 -24
  179. package/dist/esm/{chunk-e36a4f2c.js → chunk-b0c0c6b0.js} +0 -0
  180. package/dist/esm/{chunk-ee935ae6.js → chunk-c9c58d0c.js} +1 -1
  181. package/dist/esm/{chunk-1d62828e.js → chunk-d7f92d97.js} +39 -3
  182. package/dist/esm/{chunk-7fd02ffe.js → chunk-d92f0cd9.js} +2 -2
  183. package/dist/esm/chunk-e7c9b2cb.js +108 -0
  184. package/dist/esm/{chunk-0e22ae0a.js → chunk-ece062a7.js} +27 -26
  185. package/dist/esm/clockpicker.js +9 -9
  186. package/dist/esm/config.js +2 -2
  187. package/dist/esm/datepicker.js +11 -11
  188. package/dist/esm/datetimepicker.js +21 -14
  189. package/dist/esm/dialog.js +10 -8
  190. package/dist/esm/dropdown.js +5 -5
  191. package/dist/esm/field.js +4 -4
  192. package/dist/esm/helpers.js +2 -3
  193. package/dist/esm/icon.js +4 -4
  194. package/dist/esm/image.js +6 -311
  195. package/dist/esm/index.js +106 -100
  196. package/dist/esm/input.js +6 -6
  197. package/dist/esm/loading.js +4 -4
  198. package/dist/esm/menu.js +3 -3
  199. package/dist/esm/message.js +5 -5
  200. package/dist/esm/modal.js +4 -4
  201. package/dist/esm/navbar.js +16 -4
  202. package/dist/esm/notification.js +22 -10
  203. package/dist/esm/numberinput.js +9 -7
  204. package/dist/esm/pagination.js +5 -5
  205. package/dist/esm/progress.js +8 -4
  206. package/dist/esm/rate.js +3 -3
  207. package/dist/esm/select.js +6 -6
  208. package/dist/esm/sidebar.js +2 -2
  209. package/dist/esm/slider.js +3 -3
  210. package/dist/esm/snackbar.js +4 -4
  211. package/dist/esm/steps.js +6 -6
  212. package/dist/esm/switch.js +1 -1
  213. package/dist/esm/table.js +9 -9
  214. package/dist/esm/tabs.js +6 -6
  215. package/dist/esm/tag.js +2 -2
  216. package/dist/esm/taginput.js +33 -21
  217. package/dist/esm/timepicker.js +12 -12
  218. package/dist/esm/toast.js +4 -4
  219. package/dist/esm/tooltip.js +4 -4
  220. package/dist/esm/upload.js +3 -3
  221. package/dist/vetur/attributes.json +95 -19
  222. package/dist/vetur/tags.json +37 -4
  223. package/package.json +2 -2
  224. package/src/components/autocomplete/Autocomplete.spec.js +70 -0
  225. package/src/components/autocomplete/Autocomplete.vue +93 -18
  226. package/src/components/breadcrumb/Breadcrumb.spec.js +63 -0
  227. package/src/components/breadcrumb/Breadcrumb.vue +43 -0
  228. package/src/components/breadcrumb/BreadcrumbItem.spec.js +25 -0
  229. package/src/components/breadcrumb/BreadcrumbItem.vue +33 -0
  230. package/src/components/breadcrumb/__snapshots__/Breadcrumb.spec.js.snap +7 -0
  231. package/src/components/breadcrumb/__snapshots__/BreadcrumbItem.spec.js.snap +7 -0
  232. package/src/components/breadcrumb/index.js +20 -0
  233. package/src/components/carousel/CarouselList.vue +3 -1
  234. package/src/components/carousel/__snapshots__/CarouselList.spec.js.snap +128 -8
  235. package/src/components/clockpicker/Clockpicker.vue +259 -259
  236. package/src/components/datepicker/Datepicker.vue +10 -6
  237. package/src/components/datetimepicker/Datetimepicker.vue +8 -1
  238. package/src/components/dialog/Dialog.vue +10 -10
  239. package/src/components/field/Field.vue +271 -270
  240. package/src/components/image/Image.spec.js +197 -183
  241. package/src/components/image/Image.vue +4 -2
  242. package/src/components/index.js +2 -0
  243. package/src/components/loading/Loading.vue +1 -1
  244. package/src/components/loading/__snapshots__/Loading.spec.js.snap +1 -1
  245. package/src/components/message/Message.vue +7 -1
  246. package/src/components/message/__snapshots__/Message.spec.js.snap +1 -0
  247. package/src/components/modal/Modal.vue +2 -0
  248. package/src/components/navbar/Navbar.vue +5 -1
  249. package/src/components/navbar/NavbarBurger.vue +1 -0
  250. package/src/components/navbar/NavbarDropdown.vue +8 -2
  251. package/src/components/navbar/__snapshots__/NavBar.spec.js.snap +11 -11
  252. package/src/components/navbar/__snapshots__/NavBarBurger.spec.js.snap +3 -0
  253. package/src/components/navbar/__snapshots__/NavbarDropdown.spec.js.snap +1 -1
  254. package/src/components/notification/Notification.vue +6 -0
  255. package/src/components/notification/NotificationNotice.vue +16 -3
  256. package/src/components/notification/__snapshots__/Notification.spec.js.snap +1 -0
  257. package/src/components/numberinput/Numberinput.spec.js +10 -0
  258. package/src/components/numberinput/Numberinput.vue +4 -2
  259. package/src/components/progress/Progress.vue +6 -2
  260. package/src/components/snackbar/Snackbar.vue +2 -0
  261. package/src/components/tag/Tag.vue +25 -2
  262. package/src/components/tag/__snapshots__/Tag.spec.js.snap +1 -1
  263. package/src/components/taginput/Taginput.spec.js +57 -1
  264. package/src/components/taginput/Taginput.vue +373 -364
  265. package/src/components/toast/Toast.vue +1 -1
  266. package/src/index.js +2 -0
  267. package/src/scss/buefy.scss +1 -0
  268. package/src/scss/components/_loading.scss +2 -1
  269. package/src/scss/components/_message.scss +3 -0
  270. package/src/scss/components/_notification.scss +8 -0
  271. package/src/scss/components/_progress.scss +8 -0
  272. package/src/utils/MessageMixin.js +32 -1
  273. package/src/utils/NoticeMixin.js +1 -0
  274. package/src/utils/TimepickerMixin.js +718 -716
  275. package/src/utils/config.js +4 -0
  276. package/src/utils/helpers.js +1 -2
  277. package/types/components.d.ts +5 -0
  278. package/src/components/navbar/__snapshots__/NavbarBurger.spec.js.snap +0 -3
@@ -1,716 +1,718 @@
1
- import FormElementMixin from './FormElementMixin'
2
- import { isMobile, matchWithGroups } from './helpers'
3
- import config from './config'
4
-
5
- const AM = 'AM'
6
- const PM = 'PM'
7
- const HOUR_FORMAT_24 = '24'
8
- const HOUR_FORMAT_12 = '12'
9
-
10
- const defaultTimeFormatter = (date, vm) => {
11
- return vm.dtf.format(date)
12
- }
13
-
14
- const defaultTimeParser = (timeString, vm) => {
15
- if (timeString) {
16
- let d = null
17
- if (vm.computedValue && !isNaN(vm.computedValue)) {
18
- d = new Date(vm.computedValue)
19
- } else {
20
- d = vm.timeCreator()
21
- d.setMilliseconds(0)
22
- }
23
-
24
- if (vm.dtf.formatToParts && typeof vm.dtf.formatToParts === 'function') {
25
- const formatRegex = vm.dtf
26
- .formatToParts(d).map((part) => {
27
- if (part.type === 'literal') {
28
- return part.value.replace(/ /g, '\\s?')
29
- } else if (part.type === 'dayPeriod') {
30
- return `((?!=<${part.type}>)(${vm.amString}|${vm.pmString}|${AM}|${PM}|${AM.toLowerCase()}|${PM.toLowerCase()})?)`
31
- }
32
- return `((?!=<${part.type}>)\\d+)`
33
- }).join('')
34
- const timeGroups = matchWithGroups(formatRegex, timeString)
35
-
36
- // We do a simple validation for the group.
37
- // If it is not valid, it will fallback to Date.parse below
38
- timeGroups.hour = timeGroups.hour ? parseInt(timeGroups.hour, 10) : null
39
- timeGroups.minute = timeGroups.minute ? parseInt(timeGroups.minute, 10) : null
40
- timeGroups.second = timeGroups.second ? parseInt(timeGroups.second, 10) : null
41
- if (
42
- timeGroups.hour &&
43
- timeGroups.hour >= 0 &&
44
- timeGroups.hour < 24 &&
45
- timeGroups.minute &&
46
- timeGroups.minute >= 0 &&
47
- timeGroups.minute < 59
48
- ) {
49
- if (timeGroups.dayPeriod &&
50
- (
51
- timeGroups.dayPeriod.toLowerCase() === vm.pmString.toLowerCase() ||
52
- timeGroups.dayPeriod.toLowerCase() === PM.toLowerCase()
53
- ) &&
54
- timeGroups.hour < 12) {
55
- timeGroups.hour += 12
56
- }
57
- d.setHours(timeGroups.hour)
58
- d.setMinutes(timeGroups.minute)
59
- d.setSeconds(timeGroups.second || 0)
60
- return d
61
- }
62
- }
63
-
64
- // Fallback if formatToParts is not supported or if we were not able to parse a valid date
65
- let am = false
66
- if (vm.hourFormat === HOUR_FORMAT_12) {
67
- const dateString12 = timeString.split(' ')
68
- timeString = dateString12[0]
69
- am = (dateString12[1] === vm.amString || dateString12[1] === AM)
70
- }
71
- const time = timeString.split(':')
72
- let hours = parseInt(time[0], 10)
73
- const minutes = parseInt(time[1], 10)
74
- const seconds = vm.enableSeconds ? parseInt(time[2], 10) : 0
75
- if (isNaN(hours) || hours < 0 || hours > 23 ||
76
- (vm.hourFormat === HOUR_FORMAT_12 && (hours < 1 || hours > 12)) ||
77
- isNaN(minutes) || minutes < 0 || minutes > 59) {
78
- return null
79
- }
80
- d.setSeconds(seconds)
81
- d.setMinutes(minutes)
82
- if (vm.hourFormat === HOUR_FORMAT_12) {
83
- if (am && hours === 12) {
84
- hours = 0
85
- } else if (!am && hours !== 12) {
86
- hours += 12
87
- }
88
- }
89
- d.setHours(hours)
90
- return new Date(d.getTime())
91
- }
92
- return null
93
- }
94
-
95
- export default {
96
- mixins: [FormElementMixin],
97
- inheritAttrs: false,
98
- props: {
99
- value: Date,
100
- inline: Boolean,
101
- minTime: Date,
102
- maxTime: Date,
103
- placeholder: String,
104
- editable: Boolean,
105
- disabled: Boolean,
106
- hourFormat: {
107
- type: String,
108
- validator: (value) => {
109
- return value === HOUR_FORMAT_24 || value === HOUR_FORMAT_12
110
- }
111
- },
112
- incrementHours: {
113
- type: Number,
114
- default: 1
115
- },
116
- incrementMinutes: {
117
- type: Number,
118
- default: 1
119
- },
120
- incrementSeconds: {
121
- type: Number,
122
- default: 1
123
- },
124
- timeFormatter: {
125
- type: Function,
126
- default: (date, vm) => {
127
- if (typeof config.defaultTimeFormatter === 'function') {
128
- return config.defaultTimeFormatter(date)
129
- } else {
130
- return defaultTimeFormatter(date, vm)
131
- }
132
- }
133
- },
134
- timeParser: {
135
- type: Function,
136
- default: (date, vm) => {
137
- if (typeof config.defaultTimeParser === 'function') {
138
- return config.defaultTimeParser(date)
139
- } else {
140
- return defaultTimeParser(date, vm)
141
- }
142
- }
143
- },
144
- mobileNative: {
145
- type: Boolean,
146
- default: () => config.defaultTimepickerMobileNative
147
- },
148
- timeCreator: {
149
- type: Function,
150
- default: () => {
151
- if (typeof config.defaultTimeCreator === 'function') {
152
- return config.defaultTimeCreator()
153
- } else {
154
- return new Date()
155
- }
156
- }
157
- },
158
- position: String,
159
- unselectableTimes: Array,
160
- openOnFocus: Boolean,
161
- enableSeconds: Boolean,
162
- defaultMinutes: Number,
163
- defaultSeconds: Number,
164
- focusable: {
165
- type: Boolean,
166
- default: true
167
- },
168
- tzOffset: {
169
- type: Number,
170
- default: 0
171
- },
172
- appendToBody: Boolean,
173
- resetOnMeridianChange: {
174
- type: Boolean,
175
- default: false
176
- }
177
- },
178
- data() {
179
- return {
180
- dateSelected: this.value,
181
- hoursSelected: null,
182
- minutesSelected: null,
183
- secondsSelected: null,
184
- meridienSelected: null,
185
- _elementRef: 'input',
186
- AM,
187
- PM,
188
- HOUR_FORMAT_24,
189
- HOUR_FORMAT_12
190
- }
191
- },
192
- computed: {
193
- computedValue: {
194
- get() {
195
- return this.dateSelected
196
- },
197
- set(value) {
198
- this.dateSelected = value
199
- this.$emit('input', this.dateSelected)
200
- }
201
- },
202
- localeOptions() {
203
- return new Intl.DateTimeFormat(this.locale, {
204
- hour: 'numeric',
205
- minute: 'numeric',
206
- second: this.enableSeconds ? 'numeric' : undefined
207
- }).resolvedOptions()
208
- },
209
- dtf() {
210
- return new Intl.DateTimeFormat(this.locale, {
211
- hour: this.localeOptions.hour || 'numeric',
212
- minute: this.localeOptions.minute || 'numeric',
213
- second: this.enableSeconds ? this.localeOptions.second || 'numeric' : undefined,
214
- hour12: !this.isHourFormat24
215
- })
216
- },
217
- newHourFormat() {
218
- return this.hourFormat || (this.localeOptions.hour12 ? HOUR_FORMAT_12 : HOUR_FORMAT_24)
219
- },
220
- sampleTime() {
221
- let d = this.timeCreator()
222
- d.setHours(10)
223
- d.setSeconds(0)
224
- d.setMinutes(0)
225
- d.setMilliseconds(0)
226
- return d
227
- },
228
- hourLiteral() {
229
- if (this.dtf.formatToParts && typeof this.dtf.formatToParts === 'function') {
230
- let d = this.sampleTime
231
- const parts = this.dtf.formatToParts(d)
232
- const literal = parts.find((part, idx) => (idx > 0 && parts[idx - 1].type === 'hour'))
233
- if (literal) {
234
- return literal.value
235
- }
236
- }
237
- return ':'
238
- },
239
- minuteLiteral() {
240
- if (this.dtf.formatToParts && typeof this.dtf.formatToParts === 'function') {
241
- let d = this.sampleTime
242
- const parts = this.dtf.formatToParts(d)
243
- const literal = parts.find((part, idx) => (idx > 0 && parts[idx - 1].type === 'minute'))
244
- if (literal) {
245
- return literal.value
246
- }
247
- }
248
- return ':'
249
- },
250
- secondLiteral() {
251
- if (this.dtf.formatToParts && typeof this.dtf.formatToParts === 'function') {
252
- let d = this.sampleTime
253
- const parts = this.dtf.formatToParts(d)
254
- const literal = parts.find((part, idx) => (idx > 0 && parts[idx - 1].type === 'second'))
255
- if (literal) {
256
- return literal.value
257
- }
258
- }
259
- },
260
- amString() {
261
- if (this.dtf.formatToParts && typeof this.dtf.formatToParts === 'function') {
262
- let d = this.sampleTime
263
- d.setHours(10)
264
- const dayPeriod = this.dtf.formatToParts(d).find((part) => part.type === 'dayPeriod')
265
- if (dayPeriod) {
266
- return dayPeriod.value
267
- }
268
- }
269
- return AM
270
- },
271
- pmString() {
272
- if (this.dtf.formatToParts && typeof this.dtf.formatToParts === 'function') {
273
- let d = this.sampleTime
274
- d.setHours(20)
275
- const dayPeriod = this.dtf.formatToParts(d).find((part) => part.type === 'dayPeriod')
276
- if (dayPeriod) {
277
- return dayPeriod.value
278
- }
279
- }
280
- return PM
281
- },
282
- hours() {
283
- if (!this.incrementHours || this.incrementHours < 1) throw new Error('Hour increment cannot be null or less than 1.')
284
- const hours = []
285
- const numberOfHours = this.isHourFormat24 ? 24 : 12
286
- for (let i = 0; i < numberOfHours; i += this.incrementHours) {
287
- let value = i
288
- let label = value
289
- if (!this.isHourFormat24) {
290
- value = (i + 1)
291
- label = value
292
- if (this.meridienSelected === this.amString) {
293
- if (value === 12) {
294
- value = 0
295
- }
296
- } else if (this.meridienSelected === this.pmString) {
297
- if (value !== 12) {
298
- value += 12
299
- }
300
- }
301
- }
302
- hours.push({
303
- label: this.formatNumber(label),
304
- value: value
305
- })
306
- }
307
- return hours
308
- },
309
-
310
- minutes() {
311
- if (!this.incrementMinutes || this.incrementMinutes < 1) throw new Error('Minute increment cannot be null or less than 1.')
312
- const minutes = []
313
- for (let i = 0; i < 60; i += this.incrementMinutes) {
314
- minutes.push({
315
- label: this.formatNumber(i, true),
316
- value: i
317
- })
318
- }
319
- return minutes
320
- },
321
-
322
- seconds() {
323
- if (!this.incrementSeconds || this.incrementSeconds < 1) throw new Error('Second increment cannot be null or less than 1.')
324
- const seconds = []
325
- for (let i = 0; i < 60; i += this.incrementSeconds) {
326
- seconds.push({
327
- label: this.formatNumber(i, true),
328
- value: i
329
- })
330
- }
331
- return seconds
332
- },
333
-
334
- meridiens() {
335
- return [this.amString, this.pmString]
336
- },
337
-
338
- isMobile() {
339
- return this.mobileNative && isMobile.any()
340
- },
341
-
342
- isHourFormat24() {
343
- return this.newHourFormat === HOUR_FORMAT_24
344
- }
345
- },
346
- watch: {
347
- hourFormat() {
348
- if (this.hoursSelected !== null) {
349
- this.meridienSelected = this.hoursSelected >= 12 ? this.pmString : this.amString
350
- }
351
- },
352
- locale() {
353
- // see updateInternalState default
354
- if (!this.value) {
355
- this.meridienSelected = this.amString
356
- }
357
- },
358
- /**
359
- * When v-model is changed:
360
- * 1. Update internal value.
361
- * 2. If it's invalid, validate again.
362
- */
363
- value: {
364
- handler(value) {
365
- this.updateInternalState(value)
366
- !this.isValid && this.$refs.input.checkHtml5Validity()
367
- },
368
- immediate: true
369
- }
370
- },
371
- methods: {
372
- onMeridienChange(value) {
373
- if (this.hoursSelected !== null && this.resetOnMeridianChange) {
374
- this.hoursSelected = null
375
- this.minutesSelected = null
376
- this.secondsSelected = null
377
- this.computedValue = null
378
- } else if (this.hoursSelected !== null) {
379
- if (value === this.pmString) {
380
- this.hoursSelected += 12
381
- } else if (value === this.amString) {
382
- this.hoursSelected -= 12
383
- }
384
- }
385
- this.updateDateSelected(
386
- this.hoursSelected,
387
- this.minutesSelected,
388
- this.enableSeconds ? this.secondsSelected : 0,
389
- value)
390
- },
391
-
392
- onHoursChange(value) {
393
- if (!this.minutesSelected && typeof this.defaultMinutes !== 'undefined') {
394
- this.minutesSelected = this.defaultMinutes
395
- }
396
- if (!this.secondsSelected && typeof this.defaultSeconds !== 'undefined') {
397
- this.secondsSelected = this.defaultSeconds
398
- }
399
- this.updateDateSelected(
400
- parseInt(value, 10),
401
- this.minutesSelected,
402
- this.enableSeconds ? this.secondsSelected : 0,
403
- this.meridienSelected
404
- )
405
- },
406
-
407
- onMinutesChange(value) {
408
- if (!this.secondsSelected && this.defaultSeconds) {
409
- this.secondsSelected = this.defaultSeconds
410
- }
411
- this.updateDateSelected(
412
- this.hoursSelected,
413
- parseInt(value, 10),
414
- this.enableSeconds ? this.secondsSelected : 0,
415
- this.meridienSelected
416
- )
417
- },
418
-
419
- onSecondsChange(value) {
420
- this.updateDateSelected(
421
- this.hoursSelected,
422
- this.minutesSelected,
423
- parseInt(value, 10),
424
- this.meridienSelected
425
- )
426
- },
427
-
428
- updateDateSelected(hours, minutes, seconds, meridiens) {
429
- if (hours != null && minutes != null &&
430
- ((!this.isHourFormat24 && meridiens !== null) || this.isHourFormat24)) {
431
- let time = null
432
- if (this.computedValue && !isNaN(this.computedValue)) {
433
- time = new Date(this.computedValue)
434
- } else {
435
- time = this.timeCreator()
436
- time.setMilliseconds(0)
437
- }
438
- time.setHours(hours)
439
- time.setMinutes(minutes)
440
- time.setSeconds(seconds)
441
- this.computedValue = new Date(time.getTime())
442
- }
443
- },
444
-
445
- updateInternalState(value) {
446
- if (value) {
447
- this.hoursSelected = value.getHours()
448
- this.minutesSelected = value.getMinutes()
449
- this.secondsSelected = value.getSeconds()
450
- this.meridienSelected = value.getHours() >= 12 ? this.pmString : this.amString
451
- } else {
452
- this.hoursSelected = null
453
- this.minutesSelected = null
454
- this.secondsSelected = null
455
- this.meridienSelected = this.amString
456
- }
457
- this.dateSelected = value
458
- },
459
-
460
- isHourDisabled(hour) {
461
- let disabled = false
462
- if (this.minTime) {
463
- const minHours = this.minTime.getHours()
464
- const noMinutesAvailable = this.minutes.every((minute) => {
465
- return this.isMinuteDisabledForHour(hour, minute.value)
466
- })
467
- disabled = hour < minHours || noMinutesAvailable
468
- }
469
- if (this.maxTime) {
470
- if (!disabled) {
471
- const maxHours = this.maxTime.getHours()
472
- disabled = hour > maxHours
473
- }
474
- }
475
- if (this.unselectableTimes) {
476
- if (!disabled) {
477
- const unselectable = this.unselectableTimes.filter((time) => {
478
- if (this.enableSeconds && this.secondsSelected !== null) {
479
- return time.getHours() === hour &&
480
- time.getMinutes() === this.minutesSelected &&
481
- time.getSeconds() === this.secondsSelected
482
- } else if (this.minutesSelected !== null) {
483
- return time.getHours() === hour &&
484
- time.getMinutes() === this.minutesSelected
485
- }
486
- return false
487
- })
488
- if (unselectable.length > 0) {
489
- disabled = true
490
- } else {
491
- disabled = this.minutes.every((minute) => {
492
- return this.unselectableTimes.filter((time) => {
493
- return time.getHours() === hour &&
494
- time.getMinutes() === minute.value
495
- }).length > 0
496
- })
497
- }
498
- }
499
- }
500
- return disabled
501
- },
502
-
503
- isMinuteDisabledForHour(hour, minute) {
504
- let disabled = false
505
- if (this.minTime) {
506
- const minHours = this.minTime.getHours()
507
- const minMinutes = this.minTime.getMinutes()
508
- disabled = hour === minHours && minute < minMinutes
509
- }
510
- if (this.maxTime) {
511
- if (!disabled) {
512
- const maxHours = this.maxTime.getHours()
513
- const maxMinutes = this.maxTime.getMinutes()
514
- disabled = hour === maxHours && minute > maxMinutes
515
- }
516
- }
517
-
518
- return disabled
519
- },
520
-
521
- isMinuteDisabled(minute) {
522
- let disabled = false
523
- if (this.hoursSelected !== null) {
524
- if (this.isHourDisabled(this.hoursSelected)) {
525
- disabled = true
526
- } else {
527
- disabled = this.isMinuteDisabledForHour(this.hoursSelected, minute)
528
- }
529
- if (this.unselectableTimes) {
530
- if (!disabled) {
531
- const unselectable = this.unselectableTimes.filter((time) => {
532
- if (this.enableSeconds && this.secondsSelected !== null) {
533
- return time.getHours() === this.hoursSelected &&
534
- time.getMinutes() === minute &&
535
- time.getSeconds() === this.secondsSelected
536
- } else {
537
- return time.getHours() === this.hoursSelected &&
538
- time.getMinutes() === minute
539
- }
540
- })
541
- disabled = unselectable.length > 0
542
- }
543
- }
544
- }
545
- return disabled
546
- },
547
-
548
- isSecondDisabled(second) {
549
- let disabled = false
550
- if (this.minutesSelected !== null) {
551
- if (this.isMinuteDisabled(this.minutesSelected)) {
552
- disabled = true
553
- } else {
554
- if (this.minTime) {
555
- const minHours = this.minTime.getHours()
556
- const minMinutes = this.minTime.getMinutes()
557
- const minSeconds = this.minTime.getSeconds()
558
- disabled = this.hoursSelected === minHours &&
559
- this.minutesSelected === minMinutes &&
560
- second < minSeconds
561
- }
562
- if (this.maxTime) {
563
- if (!disabled) {
564
- const maxHours = this.maxTime.getHours()
565
- const maxMinutes = this.maxTime.getMinutes()
566
- const maxSeconds = this.maxTime.getSeconds()
567
- disabled = this.hoursSelected === maxHours &&
568
- this.minutesSelected === maxMinutes &&
569
- second > maxSeconds
570
- }
571
- }
572
- }
573
- if (this.unselectableTimes) {
574
- if (!disabled) {
575
- const unselectable = this.unselectableTimes.filter((time) => {
576
- return time.getHours() === this.hoursSelected &&
577
- time.getMinutes() === this.minutesSelected &&
578
- time.getSeconds() === second
579
- })
580
- disabled = unselectable.length > 0
581
- }
582
- }
583
- }
584
- return disabled
585
- },
586
-
587
- /*
588
- * Parse string into date
589
- */
590
- onChange(value) {
591
- const date = this.timeParser(value, this)
592
- this.updateInternalState(date)
593
- if (date && !isNaN(date)) {
594
- this.computedValue = date
595
- } else {
596
- // Force refresh input value when not valid date
597
- this.computedValue = null
598
- this.$refs.input.newValue = this.computedValue
599
- }
600
- },
601
-
602
- /*
603
- * Toggle timepicker
604
- */
605
- toggle(active) {
606
- if (this.$refs.dropdown) {
607
- this.$refs.dropdown.isActive = typeof active === 'boolean'
608
- ? active
609
- : !this.$refs.dropdown.isActive
610
- }
611
- },
612
-
613
- /*
614
- * Close timepicker
615
- */
616
- close() {
617
- this.toggle(false)
618
- },
619
-
620
- /*
621
- * Call default onFocus method and show timepicker
622
- */
623
- handleOnFocus() {
624
- this.onFocus()
625
- if (this.openOnFocus) {
626
- this.toggle(true)
627
- }
628
- },
629
-
630
- /*
631
- * Format date into string 'HH-MM-SS'
632
- */
633
- formatHHMMSS(value) {
634
- const date = new Date(value)
635
- if (value && !isNaN(date)) {
636
- const hours = date.getHours()
637
- const minutes = date.getMinutes()
638
- const seconds = date.getSeconds()
639
- return this.formatNumber(hours, true) + ':' +
640
- this.formatNumber(minutes, true) + ':' +
641
- this.formatNumber(seconds, true)
642
- }
643
- return ''
644
- },
645
-
646
- /*
647
- * Parse time from string
648
- */
649
- onChangeNativePicker(event) {
650
- const date = event.target.value
651
- if (date) {
652
- let time = null
653
- if (this.computedValue && !isNaN(this.computedValue)) {
654
- time = new Date(this.computedValue)
655
- } else {
656
- time = new Date()
657
- time.setMilliseconds(0)
658
- }
659
- const t = date.split(':')
660
- time.setHours(parseInt(t[0], 10))
661
- time.setMinutes(parseInt(t[1], 10))
662
- time.setSeconds(t[2] ? parseInt(t[2], 10) : 0)
663
- this.computedValue = new Date(time.getTime())
664
- } else {
665
- this.computedValue = null
666
- }
667
- },
668
-
669
- formatNumber(value, prependZero) {
670
- return this.isHourFormat24 || prependZero
671
- ? this.pad(value)
672
- : value
673
- },
674
-
675
- pad(value) {
676
- return (value < 10 ? '0' : '') + value
677
- },
678
-
679
- /*
680
- * Format date into string
681
- */
682
- formatValue(date) {
683
- if (date && !isNaN(date)) {
684
- return this.timeFormatter(date, this)
685
- } else {
686
- return null
687
- }
688
- },
689
- /**
690
- * Keypress event that is bound to the document.
691
- */
692
- keyPress({ key }) {
693
- if (this.$refs.dropdown && this.$refs.dropdown.isActive && (key === 'Escape' || key === 'Esc')) {
694
- this.toggle(false)
695
- }
696
- },
697
- /**
698
- * Emit 'blur' event on dropdown is not active (closed)
699
- */
700
- onActiveChange(value) {
701
- if (!value) {
702
- this.onBlur()
703
- }
704
- }
705
- },
706
- created() {
707
- if (typeof window !== 'undefined') {
708
- document.addEventListener('keyup', this.keyPress)
709
- }
710
- },
711
- beforeDestroy() {
712
- if (typeof window !== 'undefined') {
713
- document.removeEventListener('keyup', this.keyPress)
714
- }
715
- }
716
- }
1
+ import FormElementMixin from './FormElementMixin'
2
+ import { isMobile, matchWithGroups } from './helpers'
3
+ import config from './config'
4
+
5
+ const AM = 'AM'
6
+ const PM = 'PM'
7
+ const HOUR_FORMAT_24 = '24'
8
+ const HOUR_FORMAT_12 = '12'
9
+
10
+ const defaultTimeFormatter = (date, vm) => {
11
+ return vm.dtf.format(date)
12
+ }
13
+
14
+ const defaultTimeParser = (timeString, vm) => {
15
+ if (timeString) {
16
+ let d = null
17
+ if (vm.computedValue && !isNaN(vm.computedValue)) {
18
+ d = new Date(vm.computedValue)
19
+ } else {
20
+ d = vm.timeCreator()
21
+ d.setMilliseconds(0)
22
+ }
23
+
24
+ if (vm.dtf.formatToParts && typeof vm.dtf.formatToParts === 'function') {
25
+ const formatRegex = vm.dtf
26
+ .formatToParts(d).map((part) => {
27
+ if (part.type === 'literal') {
28
+ return part.value.replace(/ /g, '\\s?')
29
+ } else if (part.type === 'dayPeriod') {
30
+ return `((?!=<${part.type}>)(${vm.amString}|${vm.pmString}|${AM}|${PM}|${AM.toLowerCase()}|${PM.toLowerCase()})?)`
31
+ }
32
+ return `((?!=<${part.type}>)\\d+)`
33
+ }).join('')
34
+ const timeGroups = matchWithGroups(formatRegex, timeString)
35
+
36
+ // We do a simple validation for the group.
37
+ // If it is not valid, it will fallback to Date.parse below
38
+ timeGroups.hour = timeGroups.hour ? parseInt(timeGroups.hour, 10) : null
39
+ timeGroups.minute = timeGroups.minute ? parseInt(timeGroups.minute, 10) : null
40
+ timeGroups.second = timeGroups.second ? parseInt(timeGroups.second, 10) : null
41
+ if (
42
+ timeGroups.hour &&
43
+ timeGroups.hour >= 0 &&
44
+ timeGroups.hour < 24 &&
45
+ timeGroups.minute &&
46
+ timeGroups.minute >= 0 &&
47
+ timeGroups.minute < 59
48
+ ) {
49
+ if (timeGroups.dayPeriod &&
50
+ (
51
+ timeGroups.dayPeriod.toLowerCase() === vm.pmString.toLowerCase() ||
52
+ timeGroups.dayPeriod.toLowerCase() === PM.toLowerCase()
53
+ ) &&
54
+ timeGroups.hour < 12) {
55
+ timeGroups.hour += 12
56
+ }
57
+ d.setHours(timeGroups.hour)
58
+ d.setMinutes(timeGroups.minute)
59
+ d.setSeconds(timeGroups.second || 0)
60
+ return d
61
+ }
62
+ }
63
+
64
+ // Fallback if formatToParts is not supported or if we were not able to parse a valid date
65
+ let am = false
66
+ if (vm.hourFormat === HOUR_FORMAT_12) {
67
+ const dateString12 = timeString.split(' ')
68
+ timeString = dateString12[0]
69
+ am = (dateString12[1] === vm.amString || dateString12[1] === AM)
70
+ }
71
+ const time = timeString.split(':')
72
+ let hours = parseInt(time[0], 10)
73
+ const minutes = parseInt(time[1], 10)
74
+ const seconds = vm.enableSeconds ? parseInt(time[2], 10) : 0
75
+ if (isNaN(hours) || hours < 0 || hours > 23 ||
76
+ (vm.hourFormat === HOUR_FORMAT_12 && (hours < 1 || hours > 12)) ||
77
+ isNaN(minutes) || minutes < 0 || minutes > 59) {
78
+ return null
79
+ }
80
+ d.setSeconds(seconds)
81
+ d.setMinutes(minutes)
82
+ if (vm.hourFormat === HOUR_FORMAT_12) {
83
+ if (am && hours === 12) {
84
+ hours = 0
85
+ } else if (!am && hours !== 12) {
86
+ hours += 12
87
+ }
88
+ }
89
+ d.setHours(hours)
90
+ return new Date(d.getTime())
91
+ }
92
+ return null
93
+ }
94
+
95
+ export default {
96
+ mixins: [FormElementMixin],
97
+ inheritAttrs: false,
98
+ props: {
99
+ value: Date,
100
+ inline: Boolean,
101
+ minTime: Date,
102
+ maxTime: Date,
103
+ placeholder: String,
104
+ editable: Boolean,
105
+ disabled: Boolean,
106
+ hourFormat: {
107
+ type: String,
108
+ validator: (value) => {
109
+ return value === HOUR_FORMAT_24 || value === HOUR_FORMAT_12
110
+ }
111
+ },
112
+ incrementHours: {
113
+ type: Number,
114
+ default: 1
115
+ },
116
+ incrementMinutes: {
117
+ type: Number,
118
+ default: 1
119
+ },
120
+ incrementSeconds: {
121
+ type: Number,
122
+ default: 1
123
+ },
124
+ timeFormatter: {
125
+ type: Function,
126
+ default: (date, vm) => {
127
+ if (typeof config.defaultTimeFormatter === 'function') {
128
+ return config.defaultTimeFormatter(date)
129
+ } else {
130
+ return defaultTimeFormatter(date, vm)
131
+ }
132
+ }
133
+ },
134
+ timeParser: {
135
+ type: Function,
136
+ default: (date, vm) => {
137
+ if (typeof config.defaultTimeParser === 'function') {
138
+ return config.defaultTimeParser(date)
139
+ } else {
140
+ return defaultTimeParser(date, vm)
141
+ }
142
+ }
143
+ },
144
+ mobileNative: {
145
+ type: Boolean,
146
+ default: () => config.defaultTimepickerMobileNative
147
+ },
148
+ timeCreator: {
149
+ type: Function,
150
+ default: () => {
151
+ if (typeof config.defaultTimeCreator === 'function') {
152
+ return config.defaultTimeCreator()
153
+ } else {
154
+ return new Date()
155
+ }
156
+ }
157
+ },
158
+ position: String,
159
+ unselectableTimes: Array,
160
+ openOnFocus: Boolean,
161
+ enableSeconds: Boolean,
162
+ defaultMinutes: Number,
163
+ defaultSeconds: Number,
164
+ focusable: {
165
+ type: Boolean,
166
+ default: true
167
+ },
168
+ tzOffset: {
169
+ type: Number,
170
+ default: 0
171
+ },
172
+ appendToBody: Boolean,
173
+ resetOnMeridianChange: {
174
+ type: Boolean,
175
+ default: false
176
+ }
177
+ },
178
+ data() {
179
+ return {
180
+ dateSelected: this.value,
181
+ hoursSelected: null,
182
+ minutesSelected: null,
183
+ secondsSelected: null,
184
+ meridienSelected: null,
185
+ _elementRef: 'input',
186
+ AM,
187
+ PM,
188
+ HOUR_FORMAT_24,
189
+ HOUR_FORMAT_12
190
+ }
191
+ },
192
+ computed: {
193
+ computedValue: {
194
+ get() {
195
+ return this.dateSelected
196
+ },
197
+ set(value) {
198
+ this.dateSelected = value
199
+ this.$emit('input', this.dateSelected)
200
+ }
201
+ },
202
+ localeOptions() {
203
+ return new Intl.DateTimeFormat(this.locale, {
204
+ hour: 'numeric',
205
+ minute: 'numeric',
206
+ second: this.enableSeconds ? 'numeric' : undefined
207
+ }).resolvedOptions()
208
+ },
209
+ dtf() {
210
+ return new Intl.DateTimeFormat(this.locale, {
211
+ hour: this.localeOptions.hour || 'numeric',
212
+ minute: this.localeOptions.minute || 'numeric',
213
+ second: this.enableSeconds ? this.localeOptions.second || 'numeric' : undefined,
214
+ // Fixes 12 hour display github.com/buefy/buefy/issues/3418
215
+ hourCycle: !this.isHourFormat24 ? 'h12' : 'h23'
216
+ })
217
+ },
218
+ newHourFormat() {
219
+ return this.hourFormat || (this.localeOptions.hour12 ? HOUR_FORMAT_12 : HOUR_FORMAT_24)
220
+ },
221
+ sampleTime() {
222
+ let d = this.timeCreator()
223
+ d.setHours(10)
224
+ d.setSeconds(0)
225
+ d.setMinutes(0)
226
+ d.setMilliseconds(0)
227
+ return d
228
+ },
229
+ hourLiteral() {
230
+ if (this.dtf.formatToParts && typeof this.dtf.formatToParts === 'function') {
231
+ let d = this.sampleTime
232
+ const parts = this.dtf.formatToParts(d)
233
+ const literal = parts.find((part, idx) => (idx > 0 && parts[idx - 1].type === 'hour'))
234
+ if (literal) {
235
+ return literal.value
236
+ }
237
+ }
238
+ return ':'
239
+ },
240
+ minuteLiteral() {
241
+ if (this.dtf.formatToParts && typeof this.dtf.formatToParts === 'function') {
242
+ let d = this.sampleTime
243
+ const parts = this.dtf.formatToParts(d)
244
+ const literal = parts.find((part, idx) => (idx > 0 && parts[idx - 1].type === 'minute'))
245
+ if (literal) {
246
+ return literal.value
247
+ }
248
+ }
249
+ return ':'
250
+ },
251
+ secondLiteral() {
252
+ if (this.dtf.formatToParts && typeof this.dtf.formatToParts === 'function') {
253
+ let d = this.sampleTime
254
+ const parts = this.dtf.formatToParts(d)
255
+ const literal = parts.find((part, idx) => (idx > 0 && parts[idx - 1].type === 'second'))
256
+ if (literal) {
257
+ return literal.value
258
+ }
259
+ }
260
+ },
261
+ amString() {
262
+ if (this.dtf.formatToParts && typeof this.dtf.formatToParts === 'function') {
263
+ let d = this.sampleTime
264
+ d.setHours(10)
265
+ const dayPeriod = this.dtf.formatToParts(d).find((part) => part.type === 'dayPeriod')
266
+ if (dayPeriod) {
267
+ return dayPeriod.value
268
+ }
269
+ }
270
+ return AM
271
+ },
272
+ pmString() {
273
+ if (this.dtf.formatToParts && typeof this.dtf.formatToParts === 'function') {
274
+ let d = this.sampleTime
275
+ d.setHours(20)
276
+ const dayPeriod = this.dtf.formatToParts(d).find((part) => part.type === 'dayPeriod')
277
+ if (dayPeriod) {
278
+ return dayPeriod.value
279
+ }
280
+ }
281
+ return PM
282
+ },
283
+ hours() {
284
+ if (!this.incrementHours || this.incrementHours < 1) throw new Error('Hour increment cannot be null or less than 1.')
285
+ const hours = []
286
+ const numberOfHours = this.isHourFormat24 ? 24 : 12
287
+ for (let i = 0; i < numberOfHours; i += this.incrementHours) {
288
+ let value = i
289
+ let label = value
290
+ if (!this.isHourFormat24) {
291
+ value = (i + 1)
292
+ label = value
293
+ if (this.meridienSelected === this.amString) {
294
+ if (value === 12) {
295
+ value = 0
296
+ }
297
+ } else if (this.meridienSelected === this.pmString) {
298
+ if (value !== 12) {
299
+ value += 12
300
+ }
301
+ }
302
+ }
303
+ hours.push({
304
+ label: this.formatNumber(label),
305
+ value: value
306
+ })
307
+ }
308
+ return hours
309
+ },
310
+
311
+ minutes() {
312
+ if (!this.incrementMinutes || this.incrementMinutes < 1) throw new Error('Minute increment cannot be null or less than 1.')
313
+ const minutes = []
314
+ for (let i = 0; i < 60; i += this.incrementMinutes) {
315
+ minutes.push({
316
+ label: this.formatNumber(i, true),
317
+ value: i
318
+ })
319
+ }
320
+ return minutes
321
+ },
322
+
323
+ seconds() {
324
+ if (!this.incrementSeconds || this.incrementSeconds < 1) throw new Error('Second increment cannot be null or less than 1.')
325
+ const seconds = []
326
+ for (let i = 0; i < 60; i += this.incrementSeconds) {
327
+ seconds.push({
328
+ label: this.formatNumber(i, true),
329
+ value: i
330
+ })
331
+ }
332
+ return seconds
333
+ },
334
+
335
+ meridiens() {
336
+ return [this.amString, this.pmString]
337
+ },
338
+
339
+ isMobile() {
340
+ return this.mobileNative && isMobile.any()
341
+ },
342
+
343
+ isHourFormat24() {
344
+ return this.newHourFormat === HOUR_FORMAT_24
345
+ }
346
+ },
347
+ watch: {
348
+ hourFormat() {
349
+ if (this.hoursSelected !== null) {
350
+ this.meridienSelected = this.hoursSelected >= 12 ? this.pmString : this.amString
351
+ }
352
+ },
353
+ locale() {
354
+ // see updateInternalState default
355
+ if (!this.value) {
356
+ this.meridienSelected = this.amString
357
+ }
358
+ },
359
+ /**
360
+ * When v-model is changed:
361
+ * 1. Update internal value.
362
+ * 2. If it's invalid, validate again.
363
+ */
364
+ value: {
365
+ handler(value) {
366
+ this.updateInternalState(value)
367
+ !this.isValid && this.$refs.input.checkHtml5Validity()
368
+ },
369
+ immediate: true
370
+ }
371
+ },
372
+ methods: {
373
+ onMeridienChange(value) {
374
+ if (this.hoursSelected !== null && this.resetOnMeridianChange) {
375
+ this.hoursSelected = null
376
+ this.minutesSelected = null
377
+ this.secondsSelected = null
378
+ this.computedValue = null
379
+ } else if (this.hoursSelected !== null) {
380
+ if (value === this.pmString) {
381
+ this.hoursSelected += 12
382
+ } else if (value === this.amString) {
383
+ this.hoursSelected -= 12
384
+ }
385
+ }
386
+ this.updateDateSelected(
387
+ this.hoursSelected,
388
+ this.minutesSelected,
389
+ this.enableSeconds ? this.secondsSelected : 0,
390
+ value)
391
+ },
392
+
393
+ onHoursChange(value) {
394
+ if (!this.minutesSelected && typeof this.defaultMinutes !== 'undefined') {
395
+ this.minutesSelected = this.defaultMinutes
396
+ }
397
+ if (!this.secondsSelected && typeof this.defaultSeconds !== 'undefined') {
398
+ this.secondsSelected = this.defaultSeconds
399
+ }
400
+ this.updateDateSelected(
401
+ parseInt(value, 10),
402
+ this.minutesSelected,
403
+ this.enableSeconds ? this.secondsSelected : 0,
404
+ this.meridienSelected
405
+ )
406
+ },
407
+
408
+ onMinutesChange(value) {
409
+ if (!this.secondsSelected && this.defaultSeconds) {
410
+ this.secondsSelected = this.defaultSeconds
411
+ }
412
+ this.updateDateSelected(
413
+ this.hoursSelected,
414
+ parseInt(value, 10),
415
+ this.enableSeconds ? this.secondsSelected : 0,
416
+ this.meridienSelected
417
+ )
418
+ },
419
+
420
+ onSecondsChange(value) {
421
+ this.updateDateSelected(
422
+ this.hoursSelected,
423
+ this.minutesSelected,
424
+ parseInt(value, 10),
425
+ this.meridienSelected
426
+ )
427
+ },
428
+
429
+ updateDateSelected(hours, minutes, seconds, meridiens) {
430
+ if (hours != null && minutes != null &&
431
+ ((!this.isHourFormat24 && meridiens !== null) || this.isHourFormat24)) {
432
+ let time = null
433
+ if (this.computedValue && !isNaN(this.computedValue)) {
434
+ time = new Date(this.computedValue)
435
+ } else {
436
+ time = this.timeCreator()
437
+ time.setMilliseconds(0)
438
+ }
439
+ time.setHours(hours)
440
+ time.setMinutes(minutes)
441
+ time.setSeconds(seconds)
442
+
443
+ if (!isNaN(time.getTime())) this.computedValue = new Date(time.getTime())
444
+ }
445
+ },
446
+
447
+ updateInternalState(value) {
448
+ if (value) {
449
+ this.hoursSelected = value.getHours()
450
+ this.minutesSelected = value.getMinutes()
451
+ this.secondsSelected = value.getSeconds()
452
+ this.meridienSelected = value.getHours() >= 12 ? this.pmString : this.amString
453
+ } else {
454
+ this.hoursSelected = null
455
+ this.minutesSelected = null
456
+ this.secondsSelected = null
457
+ this.meridienSelected = this.amString
458
+ }
459
+ this.dateSelected = value
460
+ },
461
+
462
+ isHourDisabled(hour) {
463
+ let disabled = false
464
+ if (this.minTime) {
465
+ const minHours = this.minTime.getHours()
466
+ const noMinutesAvailable = this.minutes.every((minute) => {
467
+ return this.isMinuteDisabledForHour(hour, minute.value)
468
+ })
469
+ disabled = hour < minHours || noMinutesAvailable
470
+ }
471
+ if (this.maxTime) {
472
+ if (!disabled) {
473
+ const maxHours = this.maxTime.getHours()
474
+ disabled = hour > maxHours
475
+ }
476
+ }
477
+ if (this.unselectableTimes) {
478
+ if (!disabled) {
479
+ const unselectable = this.unselectableTimes.filter((time) => {
480
+ if (this.enableSeconds && this.secondsSelected !== null) {
481
+ return time.getHours() === hour &&
482
+ time.getMinutes() === this.minutesSelected &&
483
+ time.getSeconds() === this.secondsSelected
484
+ } else if (this.minutesSelected !== null) {
485
+ return time.getHours() === hour &&
486
+ time.getMinutes() === this.minutesSelected
487
+ }
488
+ return false
489
+ })
490
+ if (unselectable.length > 0) {
491
+ disabled = true
492
+ } else {
493
+ disabled = this.minutes.every((minute) => {
494
+ return this.unselectableTimes.filter((time) => {
495
+ return time.getHours() === hour &&
496
+ time.getMinutes() === minute.value
497
+ }).length > 0
498
+ })
499
+ }
500
+ }
501
+ }
502
+ return disabled
503
+ },
504
+
505
+ isMinuteDisabledForHour(hour, minute) {
506
+ let disabled = false
507
+ if (this.minTime) {
508
+ const minHours = this.minTime.getHours()
509
+ const minMinutes = this.minTime.getMinutes()
510
+ disabled = hour === minHours && minute < minMinutes
511
+ }
512
+ if (this.maxTime) {
513
+ if (!disabled) {
514
+ const maxHours = this.maxTime.getHours()
515
+ const maxMinutes = this.maxTime.getMinutes()
516
+ disabled = hour === maxHours && minute > maxMinutes
517
+ }
518
+ }
519
+
520
+ return disabled
521
+ },
522
+
523
+ isMinuteDisabled(minute) {
524
+ let disabled = false
525
+ if (this.hoursSelected !== null) {
526
+ if (this.isHourDisabled(this.hoursSelected)) {
527
+ disabled = true
528
+ } else {
529
+ disabled = this.isMinuteDisabledForHour(this.hoursSelected, minute)
530
+ }
531
+ if (this.unselectableTimes) {
532
+ if (!disabled) {
533
+ const unselectable = this.unselectableTimes.filter((time) => {
534
+ if (this.enableSeconds && this.secondsSelected !== null) {
535
+ return time.getHours() === this.hoursSelected &&
536
+ time.getMinutes() === minute &&
537
+ time.getSeconds() === this.secondsSelected
538
+ } else {
539
+ return time.getHours() === this.hoursSelected &&
540
+ time.getMinutes() === minute
541
+ }
542
+ })
543
+ disabled = unselectable.length > 0
544
+ }
545
+ }
546
+ }
547
+ return disabled
548
+ },
549
+
550
+ isSecondDisabled(second) {
551
+ let disabled = false
552
+ if (this.minutesSelected !== null) {
553
+ if (this.isMinuteDisabled(this.minutesSelected)) {
554
+ disabled = true
555
+ } else {
556
+ if (this.minTime) {
557
+ const minHours = this.minTime.getHours()
558
+ const minMinutes = this.minTime.getMinutes()
559
+ const minSeconds = this.minTime.getSeconds()
560
+ disabled = this.hoursSelected === minHours &&
561
+ this.minutesSelected === minMinutes &&
562
+ second < minSeconds
563
+ }
564
+ if (this.maxTime) {
565
+ if (!disabled) {
566
+ const maxHours = this.maxTime.getHours()
567
+ const maxMinutes = this.maxTime.getMinutes()
568
+ const maxSeconds = this.maxTime.getSeconds()
569
+ disabled = this.hoursSelected === maxHours &&
570
+ this.minutesSelected === maxMinutes &&
571
+ second > maxSeconds
572
+ }
573
+ }
574
+ }
575
+ if (this.unselectableTimes) {
576
+ if (!disabled) {
577
+ const unselectable = this.unselectableTimes.filter((time) => {
578
+ return time.getHours() === this.hoursSelected &&
579
+ time.getMinutes() === this.minutesSelected &&
580
+ time.getSeconds() === second
581
+ })
582
+ disabled = unselectable.length > 0
583
+ }
584
+ }
585
+ }
586
+ return disabled
587
+ },
588
+
589
+ /*
590
+ * Parse string into date
591
+ */
592
+ onChange(value) {
593
+ const date = this.timeParser(value, this)
594
+ this.updateInternalState(date)
595
+ if (date && !isNaN(date)) {
596
+ this.computedValue = date
597
+ } else {
598
+ // Force refresh input value when not valid date
599
+ this.computedValue = null
600
+ this.$refs.input.newValue = this.computedValue
601
+ }
602
+ },
603
+
604
+ /*
605
+ * Toggle timepicker
606
+ */
607
+ toggle(active) {
608
+ if (this.$refs.dropdown) {
609
+ this.$refs.dropdown.isActive = typeof active === 'boolean'
610
+ ? active
611
+ : !this.$refs.dropdown.isActive
612
+ }
613
+ },
614
+
615
+ /*
616
+ * Close timepicker
617
+ */
618
+ close() {
619
+ this.toggle(false)
620
+ },
621
+
622
+ /*
623
+ * Call default onFocus method and show timepicker
624
+ */
625
+ handleOnFocus() {
626
+ this.onFocus()
627
+ if (this.openOnFocus) {
628
+ this.toggle(true)
629
+ }
630
+ },
631
+
632
+ /*
633
+ * Format date into string 'HH-MM-SS'
634
+ */
635
+ formatHHMMSS(value) {
636
+ const date = new Date(value)
637
+ if (value && !isNaN(date)) {
638
+ const hours = date.getHours()
639
+ const minutes = date.getMinutes()
640
+ const seconds = date.getSeconds()
641
+ return this.formatNumber(hours, true) + ':' +
642
+ this.formatNumber(minutes, true) + ':' +
643
+ this.formatNumber(seconds, true)
644
+ }
645
+ return ''
646
+ },
647
+
648
+ /*
649
+ * Parse time from string
650
+ */
651
+ onChangeNativePicker(event) {
652
+ const date = event.target.value
653
+ if (date) {
654
+ let time = null
655
+ if (this.computedValue && !isNaN(this.computedValue)) {
656
+ time = new Date(this.computedValue)
657
+ } else {
658
+ time = new Date()
659
+ time.setMilliseconds(0)
660
+ }
661
+ const t = date.split(':')
662
+ time.setHours(parseInt(t[0], 10))
663
+ time.setMinutes(parseInt(t[1], 10))
664
+ time.setSeconds(t[2] ? parseInt(t[2], 10) : 0)
665
+ this.computedValue = new Date(time.getTime())
666
+ } else {
667
+ this.computedValue = null
668
+ }
669
+ },
670
+
671
+ formatNumber(value, prependZero) {
672
+ return this.isHourFormat24 || prependZero
673
+ ? this.pad(value)
674
+ : value
675
+ },
676
+
677
+ pad(value) {
678
+ return (value < 10 ? '0' : '') + value
679
+ },
680
+
681
+ /*
682
+ * Format date into string
683
+ */
684
+ formatValue(date) {
685
+ if (date && !isNaN(date)) {
686
+ return this.timeFormatter(date, this)
687
+ } else {
688
+ return null
689
+ }
690
+ },
691
+ /**
692
+ * Keypress event that is bound to the document.
693
+ */
694
+ keyPress({ key }) {
695
+ if (this.$refs.dropdown && this.$refs.dropdown.isActive && (key === 'Escape' || key === 'Esc')) {
696
+ this.toggle(false)
697
+ }
698
+ },
699
+ /**
700
+ * Emit 'blur' event on dropdown is not active (closed)
701
+ */
702
+ onActiveChange(value) {
703
+ if (!value) {
704
+ this.onBlur()
705
+ }
706
+ }
707
+ },
708
+ created() {
709
+ if (typeof window !== 'undefined') {
710
+ document.addEventListener('keyup', this.keyPress)
711
+ }
712
+ },
713
+ beforeDestroy() {
714
+ if (typeof window !== 'undefined') {
715
+ document.removeEventListener('keyup', this.keyPress)
716
+ }
717
+ }
718
+ }