fomantic-ui 2.9.1-beta.2 → 2.9.1-beta.20

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 (339) hide show
  1. package/.eslintrc.js +110 -0
  2. package/.github/workflows/ci.yml +14 -4
  3. package/.stylelintrc.js +46 -0
  4. package/dist/components/accordion.css +19 -26
  5. package/dist/components/accordion.js +568 -595
  6. package/dist/components/accordion.min.css +1 -1
  7. package/dist/components/accordion.min.js +2 -2
  8. package/dist/components/ad.css +31 -41
  9. package/dist/components/ad.min.css +1 -1
  10. package/dist/components/api.js +1161 -1179
  11. package/dist/components/api.min.js +2 -2
  12. package/dist/components/breadcrumb.css +1 -1
  13. package/dist/components/breadcrumb.min.css +1 -1
  14. package/dist/components/button.css +71 -106
  15. package/dist/components/button.min.css +1 -1
  16. package/dist/components/calendar.css +18 -16
  17. package/dist/components/calendar.js +1895 -1809
  18. package/dist/components/calendar.min.css +2 -2
  19. package/dist/components/calendar.min.js +2 -2
  20. package/dist/components/card.css +83 -115
  21. package/dist/components/card.min.css +1 -1
  22. package/dist/components/checkbox.css +47 -64
  23. package/dist/components/checkbox.js +842 -841
  24. package/dist/components/checkbox.min.css +1 -1
  25. package/dist/components/checkbox.min.js +2 -2
  26. package/dist/components/comment.css +37 -51
  27. package/dist/components/comment.min.css +1 -1
  28. package/dist/components/container.css +6 -5
  29. package/dist/components/container.min.css +2 -2
  30. package/dist/components/dimmer.css +31 -41
  31. package/dist/components/dimmer.js +708 -737
  32. package/dist/components/dimmer.min.css +1 -1
  33. package/dist/components/dimmer.min.js +2 -2
  34. package/dist/components/divider.css +32 -44
  35. package/dist/components/divider.min.css +1 -1
  36. package/dist/components/dropdown.css +129 -166
  37. package/dist/components/dropdown.js +4161 -4234
  38. package/dist/components/dropdown.min.css +2 -2
  39. package/dist/components/dropdown.min.js +2 -2
  40. package/dist/components/embed.css +13 -19
  41. package/dist/components/embed.js +651 -675
  42. package/dist/components/embed.min.css +1 -1
  43. package/dist/components/embed.min.js +2 -2
  44. package/dist/components/emoji.css +7 -6
  45. package/dist/components/feed.css +24 -32
  46. package/dist/components/feed.min.css +1 -1
  47. package/dist/components/flag.css +5 -3
  48. package/dist/components/flag.min.css +1 -1
  49. package/dist/components/flyout.css +44 -58
  50. package/dist/components/flyout.js +1464 -1465
  51. package/dist/components/flyout.min.css +2 -2
  52. package/dist/components/flyout.min.js +2 -2
  53. package/dist/components/form.css +85 -111
  54. package/dist/components/form.js +1979 -2004
  55. package/dist/components/form.min.css +1 -1
  56. package/dist/components/form.min.js +2 -2
  57. package/dist/components/grid.css +70 -96
  58. package/dist/components/grid.min.css +1 -1
  59. package/dist/components/header.css +47 -65
  60. package/dist/components/header.min.css +1 -1
  61. package/dist/components/icon.css +45 -66
  62. package/dist/components/icon.min.css +2 -2
  63. package/dist/components/image.css +32 -42
  64. package/dist/components/image.min.css +1 -1
  65. package/dist/components/input.css +182 -65
  66. package/dist/components/input.min.css +2 -2
  67. package/dist/components/item.css +55 -77
  68. package/dist/components/item.min.css +1 -1
  69. package/dist/components/label.css +68 -91
  70. package/dist/components/label.min.css +2 -2
  71. package/dist/components/list.css +44 -59
  72. package/dist/components/list.min.css +1 -1
  73. package/dist/components/loader.css +16 -22
  74. package/dist/components/loader.min.css +1 -1
  75. package/dist/components/menu.css +126 -186
  76. package/dist/components/message.css +25 -35
  77. package/dist/components/message.min.css +1 -1
  78. package/dist/components/modal.css +39 -40
  79. package/dist/components/modal.js +1491 -1485
  80. package/dist/components/modal.min.css +2 -2
  81. package/dist/components/modal.min.js +2 -2
  82. package/dist/components/nag.css +21 -28
  83. package/dist/components/nag.js +518 -526
  84. package/dist/components/nag.min.css +2 -2
  85. package/dist/components/nag.min.js +2 -2
  86. package/dist/components/placeholder.css +10 -12
  87. package/dist/components/placeholder.min.css +1 -1
  88. package/dist/components/popup.css +352 -59
  89. package/dist/components/popup.js +1437 -1456
  90. package/dist/components/popup.min.css +2 -2
  91. package/dist/components/popup.min.js +2 -2
  92. package/dist/components/progress.css +29 -39
  93. package/dist/components/progress.js +969 -997
  94. package/dist/components/progress.min.css +1 -1
  95. package/dist/components/progress.min.js +2 -2
  96. package/dist/components/rail.css +15 -20
  97. package/dist/components/rail.min.css +1 -1
  98. package/dist/components/rating.css +9 -13
  99. package/dist/components/rating.js +505 -523
  100. package/dist/components/rating.min.css +1 -1
  101. package/dist/components/rating.min.js +2 -2
  102. package/dist/components/reset.css +1 -1
  103. package/dist/components/reset.min.css +1 -1
  104. package/dist/components/reveal.css +19 -26
  105. package/dist/components/reveal.min.css +1 -1
  106. package/dist/components/search.css +43 -58
  107. package/dist/components/search.js +1498 -1534
  108. package/dist/components/search.min.css +2 -2
  109. package/dist/components/search.min.js +2 -2
  110. package/dist/components/segment.css +64 -83
  111. package/dist/components/segment.min.css +2 -2
  112. package/dist/components/shape.css +10 -14
  113. package/dist/components/shape.js +792 -809
  114. package/dist/components/shape.min.css +1 -1
  115. package/dist/components/shape.min.js +2 -2
  116. package/dist/components/sidebar.css +43 -58
  117. package/dist/components/sidebar.js +1071 -1098
  118. package/dist/components/sidebar.min.css +2 -2
  119. package/dist/components/sidebar.min.js +2 -2
  120. package/dist/components/site.css +5 -5
  121. package/dist/components/site.js +462 -476
  122. package/dist/components/site.min.css +1 -1
  123. package/dist/components/site.min.js +2 -2
  124. package/dist/components/slider.css +27 -37
  125. package/dist/components/slider.js +1287 -1306
  126. package/dist/components/slider.min.js +2 -2
  127. package/dist/components/state.js +639 -657
  128. package/dist/components/state.min.js +2 -2
  129. package/dist/components/statistic.css +32 -41
  130. package/dist/components/statistic.min.css +2 -2
  131. package/dist/components/step.css +26 -35
  132. package/dist/components/step.min.css +1 -1
  133. package/dist/components/sticky.css +1 -1
  134. package/dist/components/sticky.js +857 -902
  135. package/dist/components/sticky.min.css +1 -1
  136. package/dist/components/sticky.min.js +2 -2
  137. package/dist/components/tab.css +6 -8
  138. package/dist/components/tab.js +922 -963
  139. package/dist/components/tab.min.css +1 -1
  140. package/dist/components/tab.min.js +2 -2
  141. package/dist/components/table.css +93 -119
  142. package/dist/components/table.min.css +2 -2
  143. package/dist/components/text.css +1 -1
  144. package/dist/components/text.min.css +1 -1
  145. package/dist/components/toast.css +4 -6
  146. package/dist/components/toast.js +886 -887
  147. package/dist/components/toast.min.css +1 -1
  148. package/dist/components/toast.min.js +2 -2
  149. package/dist/components/transition.css +150 -3
  150. package/dist/components/transition.js +1041 -1077
  151. package/dist/components/transition.min.css +2 -2
  152. package/dist/components/transition.min.js +2 -2
  153. package/dist/components/visibility.js +1220 -1244
  154. package/dist/components/visibility.min.js +2 -2
  155. package/dist/semantic.css +2529 -1778
  156. package/dist/semantic.js +28928 -29383
  157. package/dist/semantic.min.css +2 -2
  158. package/dist/semantic.min.js +2 -2
  159. package/dist/themes/default/assets/fonts/Lato-Bold.woff +0 -0
  160. package/dist/themes/default/assets/fonts/Lato-Bold.woff2 +0 -0
  161. package/dist/themes/default/assets/fonts/Lato-BoldItalic.woff +0 -0
  162. package/dist/themes/default/assets/fonts/Lato-BoldItalic.woff2 +0 -0
  163. package/dist/themes/default/assets/fonts/Lato-Italic.woff +0 -0
  164. package/dist/themes/default/assets/fonts/Lato-Italic.woff2 +0 -0
  165. package/dist/themes/default/assets/fonts/Lato-Regular.woff +0 -0
  166. package/dist/themes/default/assets/fonts/Lato-Regular.woff2 +0 -0
  167. package/dist/themes/default/assets/fonts/LatoLatin-Bold.woff +0 -0
  168. package/dist/themes/default/assets/fonts/LatoLatin-Bold.woff2 +0 -0
  169. package/dist/themes/default/assets/fonts/LatoLatin-BoldItalic.woff +0 -0
  170. package/dist/themes/default/assets/fonts/LatoLatin-BoldItalic.woff2 +0 -0
  171. package/dist/themes/default/assets/fonts/LatoLatin-Italic.woff +0 -0
  172. package/dist/themes/default/assets/fonts/LatoLatin-Italic.woff2 +0 -0
  173. package/dist/themes/default/assets/fonts/LatoLatin-Regular.woff +0 -0
  174. package/dist/themes/default/assets/fonts/LatoLatin-Regular.woff2 +0 -0
  175. package/examples/assets/show-examples.js +13 -13
  176. package/gulpfile.js +9 -10
  177. package/package.json +13 -8
  178. package/scripts/nightly-version.js +81 -75
  179. package/src/definitions/behaviors/api.js +1162 -1180
  180. package/src/definitions/behaviors/form.js +1978 -2003
  181. package/src/definitions/behaviors/state.js +645 -663
  182. package/src/definitions/behaviors/visibility.js +1219 -1243
  183. package/src/definitions/collections/breadcrumb.less +41 -44
  184. package/src/definitions/collections/form.less +869 -879
  185. package/src/definitions/collections/grid.less +1690 -1695
  186. package/src/definitions/collections/menu.less +1493 -1503
  187. package/src/definitions/collections/message.less +292 -295
  188. package/src/definitions/collections/table.less +1616 -1620
  189. package/src/definitions/elements/button.less +1721 -1743
  190. package/src/definitions/elements/container.less +209 -209
  191. package/src/definitions/elements/divider.less +205 -206
  192. package/src/definitions/elements/emoji.less +38 -44
  193. package/src/definitions/elements/flag.less +44 -46
  194. package/src/definitions/elements/header.less +337 -345
  195. package/src/definitions/elements/icon.less +516 -443
  196. package/src/definitions/elements/image.less +221 -225
  197. package/src/definitions/elements/input.less +663 -659
  198. package/src/definitions/elements/label.less +803 -793
  199. package/src/definitions/elements/list.less +809 -809
  200. package/src/definitions/elements/loader.less +272 -266
  201. package/src/definitions/elements/placeholder.less +171 -168
  202. package/src/definitions/elements/rail.less +91 -91
  203. package/src/definitions/elements/reveal.less +192 -196
  204. package/src/definitions/elements/segment.less +743 -746
  205. package/src/definitions/elements/step.less +425 -433
  206. package/src/definitions/elements/text.less +32 -34
  207. package/src/definitions/globals/reset.less +9 -6
  208. package/src/definitions/globals/site.js +461 -475
  209. package/src/definitions/globals/site.less +106 -108
  210. package/src/definitions/modules/accordion.js +567 -594
  211. package/src/definitions/modules/accordion.less +242 -246
  212. package/src/definitions/modules/calendar.js +1894 -1808
  213. package/src/definitions/modules/calendar.less +98 -95
  214. package/src/definitions/modules/checkbox.js +841 -840
  215. package/src/definitions/modules/checkbox.less +536 -542
  216. package/src/definitions/modules/dimmer.js +707 -736
  217. package/src/definitions/modules/dimmer.less +300 -297
  218. package/src/definitions/modules/dropdown.js +4160 -4233
  219. package/src/definitions/modules/dropdown.less +1577 -1589
  220. package/src/definitions/modules/embed.js +650 -674
  221. package/src/definitions/modules/embed.less +81 -82
  222. package/src/definitions/modules/flyout.js +1463 -1464
  223. package/src/definitions/modules/flyout.less +445 -451
  224. package/src/definitions/modules/modal.js +1490 -1484
  225. package/src/definitions/modules/modal.less +459 -459
  226. package/src/definitions/modules/nag.js +517 -525
  227. package/src/definitions/modules/nag.less +134 -138
  228. package/src/definitions/modules/popup.js +1436 -1455
  229. package/src/definitions/modules/popup.less +742 -687
  230. package/src/definitions/modules/progress.js +968 -996
  231. package/src/definitions/modules/progress.less +521 -494
  232. package/src/definitions/modules/rating.js +504 -522
  233. package/src/definitions/modules/rating.less +94 -101
  234. package/src/definitions/modules/search.js +1497 -1533
  235. package/src/definitions/modules/search.less +375 -382
  236. package/src/definitions/modules/shape.js +791 -808
  237. package/src/definitions/modules/shape.less +71 -76
  238. package/src/definitions/modules/sidebar.js +1070 -1097
  239. package/src/definitions/modules/sidebar.less +463 -472
  240. package/src/definitions/modules/slider.js +1286 -1305
  241. package/src/definitions/modules/slider.less +307 -308
  242. package/src/definitions/modules/sticky.js +873 -918
  243. package/src/definitions/modules/sticky.less +21 -23
  244. package/src/definitions/modules/tab.js +921 -962
  245. package/src/definitions/modules/tab.less +51 -52
  246. package/src/definitions/modules/toast.js +885 -886
  247. package/src/definitions/modules/toast.less +584 -586
  248. package/src/definitions/modules/transition.js +1040 -1076
  249. package/src/definitions/modules/transition.less +62 -28
  250. package/src/definitions/views/ad.less +206 -206
  251. package/src/definitions/views/card.less +968 -970
  252. package/src/definitions/views/comment.less +190 -198
  253. package/src/definitions/views/feed.less +220 -224
  254. package/src/definitions/views/item.less +436 -446
  255. package/src/definitions/views/statistic.less +271 -277
  256. package/src/theme.less +29 -32
  257. package/src/themes/default/assets/fonts/Lato-Bold.woff +0 -0
  258. package/src/themes/default/assets/fonts/Lato-Bold.woff2 +0 -0
  259. package/src/themes/default/assets/fonts/Lato-BoldItalic.woff +0 -0
  260. package/src/themes/default/assets/fonts/Lato-BoldItalic.woff2 +0 -0
  261. package/src/themes/default/assets/fonts/Lato-Italic.woff +0 -0
  262. package/src/themes/default/assets/fonts/Lato-Italic.woff2 +0 -0
  263. package/src/themes/default/assets/fonts/Lato-Regular.woff +0 -0
  264. package/src/themes/default/assets/fonts/Lato-Regular.woff2 +0 -0
  265. package/src/themes/default/assets/fonts/LatoLatin-Bold.woff +0 -0
  266. package/src/themes/default/assets/fonts/LatoLatin-Bold.woff2 +0 -0
  267. package/src/themes/default/assets/fonts/LatoLatin-BoldItalic.woff +0 -0
  268. package/src/themes/default/assets/fonts/LatoLatin-BoldItalic.woff2 +0 -0
  269. package/src/themes/default/assets/fonts/LatoLatin-Italic.woff +0 -0
  270. package/src/themes/default/assets/fonts/LatoLatin-Italic.woff2 +0 -0
  271. package/src/themes/default/assets/fonts/LatoLatin-Regular.woff +0 -0
  272. package/src/themes/default/assets/fonts/LatoLatin-Regular.woff2 +0 -0
  273. package/src/themes/default/elements/container.variables +0 -7
  274. package/src/themes/default/elements/icon.variables +18 -0
  275. package/src/themes/default/elements/segment.variables +0 -7
  276. package/src/themes/default/globals/colors.less +589 -589
  277. package/src/themes/default/globals/site.variables +8 -0
  278. package/src/themes/default/globals/variation.variables +13 -1
  279. package/src/themes/default/modules/calendar.variables +2 -0
  280. package/src/themes/default/modules/nag.variables +1 -1
  281. package/src/themes/default/modules/popup.variables +2 -0
  282. package/src/themes/default/modules/transition.variables +8 -1
  283. package/tasks/admin/components/create.js +274 -276
  284. package/tasks/admin/components/init.js +123 -130
  285. package/tasks/admin/components/update.js +149 -157
  286. package/tasks/admin/distributions/create.js +184 -187
  287. package/tasks/admin/distributions/init.js +123 -130
  288. package/tasks/admin/distributions/update.js +145 -152
  289. package/tasks/admin/publish.js +5 -7
  290. package/tasks/admin/register.js +36 -38
  291. package/tasks/admin/release.js +8 -10
  292. package/tasks/build/assets.js +42 -39
  293. package/tasks/build/css.js +225 -216
  294. package/tasks/build/javascript.js +118 -113
  295. package/tasks/build.js +10 -10
  296. package/tasks/check-install.js +14 -16
  297. package/tasks/clean.js +5 -5
  298. package/tasks/collections/admin.js +34 -36
  299. package/tasks/collections/build.js +18 -20
  300. package/tasks/collections/docs.js +9 -11
  301. package/tasks/collections/install.js +9 -11
  302. package/tasks/collections/rtl.js +9 -11
  303. package/tasks/collections/various.js +8 -10
  304. package/tasks/config/admin/github.js +17 -17
  305. package/tasks/config/admin/oauth.example.js +4 -4
  306. package/tasks/config/admin/release.js +98 -98
  307. package/tasks/config/admin/templates/component-package.js +9 -10
  308. package/tasks/config/admin/templates/css-package.js +18 -20
  309. package/tasks/config/admin/templates/less-package.js +11 -13
  310. package/tasks/config/defaults.js +116 -114
  311. package/tasks/config/docs.js +23 -23
  312. package/tasks/config/npm/gulpfile.js +8 -9
  313. package/tasks/config/project/config.js +127 -134
  314. package/tasks/config/project/install.js +715 -713
  315. package/tasks/config/project/release.js +32 -38
  316. package/tasks/config/tasks.js +165 -156
  317. package/tasks/config/user.js +23 -26
  318. package/tasks/docs/build.js +97 -95
  319. package/tasks/docs/metadata.js +90 -96
  320. package/tasks/docs/serve.js +80 -81
  321. package/tasks/install.js +370 -378
  322. package/tasks/rtl/build.js +2 -2
  323. package/tasks/rtl/watch.js +2 -2
  324. package/tasks/version.js +4 -4
  325. package/tasks/watch.js +28 -30
  326. package/test/meteor/assets.js +10 -13
  327. package/test/meteor/fonts.js +12 -13
  328. package/test/modules/accordion.spec.js +6 -8
  329. package/test/modules/checkbox.spec.js +5 -7
  330. package/test/modules/dropdown.spec.js +5 -7
  331. package/test/modules/modal.spec.js +6 -8
  332. package/test/modules/module.spec.js +158 -178
  333. package/test/modules/popup.spec.js +5 -7
  334. package/test/modules/search.spec.js +5 -7
  335. package/test/modules/shape.spec.js +5 -7
  336. package/test/modules/sidebar.spec.js +5 -7
  337. package/test/modules/tab.spec.js +6 -8
  338. package/test/modules/transition.spec.js +5 -7
  339. package/test/modules/video.spec.js +5 -7
@@ -8,1883 +8,1969 @@
8
8
  *
9
9
  */
10
10
 
11
- ;(function ($, window, document, undefined) {
12
-
13
- 'use strict';
14
-
15
- $.isFunction = $.isFunction || function(obj) {
16
- return typeof obj === "function" && typeof obj.nodeType !== "number";
17
- };
18
-
19
- window = (typeof window != 'undefined' && window.Math == Math)
20
- ? window
21
- : (typeof self != 'undefined' && self.Math == Math)
22
- ? self
23
- : Function('return this')()
24
- ;
25
-
26
- $.fn.calendar = function(parameters) {
27
- var
28
- $allModules = $(this),
29
-
30
- moduleSelector = $allModules.selector || '',
31
-
32
- time = new Date().getTime(),
33
- performance = [],
34
-
35
- query = arguments[0],
36
- methodInvoked = (typeof query == 'string'),
37
- queryArguments = [].slice.call(arguments, 1),
38
- returnedValue,
39
- timeGapTable = {
40
- '5': {'row': 4, 'column': 3 },
41
- '10': {'row': 3, 'column': 2 },
42
- '15': {'row': 2, 'column': 2 },
43
- '20': {'row': 3, 'column': 1 },
44
- '30': {'row': 2, 'column': 1 }
45
- },
46
- numberText = ['','one','two','three','four','five','six','seven','eight']
47
- ;
48
-
49
- $allModules
50
- .each(function () {
51
- var
52
- settings = ( $.isPlainObject(parameters) )
53
- ? $.extend(true, {}, $.fn.calendar.settings, parameters)
54
- : $.extend({}, $.fn.calendar.settings),
55
-
56
- className = settings.className,
57
- namespace = settings.namespace,
58
- selector = settings.selector,
59
- formatter = settings.formatter,
60
- parser = settings.parser,
61
- metadata = settings.metadata,
62
- timeGap = timeGapTable[settings.minTimeGap],
63
- error = settings.error,
64
-
65
- eventNamespace = '.' + namespace,
66
- moduleNamespace = 'module-' + namespace,
67
-
68
- $module = $(this),
69
- $input = $module.find(selector.input),
70
- $container = $module.find(selector.popup),
71
- $activator = $module.find(selector.activator),
72
-
73
- element = this,
74
- instance = $module.data(moduleNamespace),
75
-
76
- isTouch,
77
- isTouchDown = false,
78
- isInverted = $module.hasClass(className.inverted),
79
- focusDateUsedForRange = false,
80
- selectionComplete = false,
81
- classObserver,
82
- module
83
- ;
84
-
85
- module = {
86
-
87
- initialize: function () {
88
- module.debug('Initializing calendar for', element, $module);
89
-
90
- isTouch = module.get.isTouch();
91
- module.setup.config();
92
- module.setup.popup();
93
- module.setup.inline();
94
- module.setup.input();
95
- module.setup.date();
96
- module.create.calendar();
97
-
98
- module.bind.events();
99
- module.observeChanges();
100
- module.instantiate();
101
- },
102
-
103
- instantiate: function () {
104
- module.verbose('Storing instance of calendar');
105
- instance = module;
106
- $module.data(moduleNamespace, instance);
107
- },
108
-
109
- destroy: function () {
110
- module.verbose('Destroying previous calendar for', element);
111
- $module.removeData(moduleNamespace);
112
- module.unbind.events();
113
- module.disconnect.classObserver();
114
- },
11
+ (function ($, window, document, undefined) {
12
+ 'use strict';
115
13
 
116
- setup: {
117
- config: function () {
118
- if (module.get.minDate() !== null) {
119
- module.set.minDate($module.data(metadata.minDate));
120
- }
121
- if (module.get.maxDate() !== null) {
122
- module.set.maxDate($module.data(metadata.maxDate));
123
- }
124
- module.setting('type', module.get.type());
125
- module.setting('on', settings.on || 'click');
126
- },
127
- popup: function () {
128
- if (settings.inline) {
129
- return;
130
- }
131
- if (!$activator.length) {
132
- $activator = $module.children().first();
133
- if (!$activator.length) {
134
- return;
135
- }
136
- }
137
- if ($.fn.popup === undefined) {
138
- module.error(error.popup);
139
- return;
140
- }
141
- if (!$container.length) {
142
- //prepend the popup element to the activator's parent so that it has less chance of messing with
143
- //the styling (eg input action button needs to be the last child to have correct border radius)
144
- var $activatorParent = $activator.parent(),
145
- domPositionFunction = $activatorParent.closest(selector.append).length !== 0 ? 'appendTo' : 'prependTo';
146
- $container = $('<div/>').addClass(className.popup)[domPositionFunction]($activatorParent);
147
- }
148
- $container.addClass(className.calendar);
149
- if(isInverted){
150
- $container.addClass(className.inverted);
151
- }
152
- var onVisible = function () {
153
- module.refreshTooltips();
154
- return settings.onVisible.apply($container, arguments);
155
- };
156
- var onHidden = function () {
157
- module.blur();
158
- return settings.onHidden.apply($container, arguments)
159
- }
160
- if (!$input.length) {
161
- //no input, $container has to handle focus/blur
162
- $container.attr('tabindex', '0');
163
- onVisible = function () {
164
- module.refreshTooltips();
165
- module.focus();
166
- return settings.onVisible.apply($container, arguments);
167
- };
168
- }
169
- var onShow = function () {
170
- //reset the focus date onShow
171
- module.set.focusDate(module.get.date());
172
- module.set.mode(module.get.validatedMode(settings.startMode));
173
- return settings.onShow.apply($container, arguments);
174
- };
175
- var on = module.setting('on');
176
- var options = $.extend({}, settings.popupOptions, {
177
- popup: $container,
178
- on: on,
179
- hoverable: on === 'hover',
180
- closable: on === 'click',
181
- onShow: onShow,
182
- onVisible: onVisible,
183
- onHide: settings.onHide,
184
- onHidden: onHidden
185
- });
186
- module.popup(options);
187
- },
188
- inline: function () {
189
- if ($activator.length && !settings.inline) {
190
- return;
191
- }
192
- settings.inline = true;
193
- $container = $('<div/>').addClass(className.calendar).appendTo($module);
194
- if (!$input.length) {
195
- $container.attr('tabindex', '0');
196
- }
197
- },
198
- input: function () {
199
- if (settings.touchReadonly && $input.length && isTouch) {
200
- $input.prop('readonly', true);
201
- }
202
- module.check.disabled();
203
- },
204
- date: function () {
205
- var date;
206
- if (settings.initialDate) {
207
- date = parser.date(settings.initialDate, settings);
208
- } else if ($module.data(metadata.date) !== undefined) {
209
- date = parser.date($module.data(metadata.date), settings);
210
- } else if ($input.length) {
211
- date = parser.date($input.val(), settings);
212
- }
213
- module.set.date(date, settings.formatInput, false);
214
- module.set.mode(module.get.mode(), false);
215
- }
216
- },
14
+ function isFunction(obj) {
15
+ return typeof obj === 'function' && typeof obj.nodeType !== 'number';
16
+ }
217
17
 
218
- trigger: {
219
- change: function() {
18
+ window = (typeof window != 'undefined' && window.Math == Math)
19
+ ? window
20
+ : globalThis;
21
+
22
+ $.fn.calendar = function (parameters) {
23
+ var
24
+ $allModules = $(this),
25
+ $document = $(document),
26
+
27
+ moduleSelector = $allModules.selector || '',
28
+
29
+ time = new Date().getTime(),
30
+ performance = [],
31
+
32
+ query = arguments[0],
33
+ methodInvoked = (typeof query == 'string'),
34
+ queryArguments = [].slice.call(arguments, 1),
35
+ returnedValue,
36
+ timeGapTable = {
37
+ 5: { row: 4, column: 3 },
38
+ 10: { row: 3, column: 2 },
39
+ 15: { row: 2, column: 2 },
40
+ 20: { row: 3, column: 1 },
41
+ 30: { row: 2, column: 1 },
42
+ },
43
+ numberText = ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight']
44
+ ;
45
+
46
+ $allModules.each(function () {
220
47
  var
221
- inputElement = $input[0]
48
+ settings = ($.isPlainObject(parameters))
49
+ ? $.extend(true, {}, $.fn.calendar.settings, parameters)
50
+ : $.extend({}, $.fn.calendar.settings),
51
+
52
+ className = settings.className,
53
+ namespace = settings.namespace,
54
+ selector = settings.selector,
55
+ formatter = settings.formatter,
56
+ parser = settings.parser,
57
+ metadata = settings.metadata,
58
+ timeGap = timeGapTable[settings.minTimeGap],
59
+ error = settings.error,
60
+
61
+ eventNamespace = '.' + namespace,
62
+ moduleNamespace = 'module-' + namespace,
63
+
64
+ $module = $(this),
65
+ $input = $module.find(selector.input),
66
+ $activator = $module.find(selector.activator),
67
+
68
+ element = this,
69
+ instance = $module.data(moduleNamespace),
70
+ $container = instance && instance.popupId ? $document.find('#' + instance.popupId) : $module.find(selector.popup),
71
+
72
+ isTouch,
73
+ isTouchDown = false,
74
+ isInverted = $module.hasClass(className.inverted),
75
+ focusDateUsedForRange = false,
76
+ selectionComplete = false,
77
+ classObserver,
78
+ module
222
79
  ;
223
- if(inputElement) {
224
- var events = document.createEvent('HTMLEvents');
225
- module.verbose('Triggering native change event');
226
- events.initEvent('change', true, false);
227
- inputElement.dispatchEvent(events);
228
- }
229
- }
230
- },
231
80
 
232
- create: {
233
- calendar: function () {
234
- var i, r, c, p, row, cell, pageGrid;
81
+ module = {
82
+
83
+ initialize: function () {
84
+ module.debug('Initializing calendar for', element, $module);
85
+
86
+ isTouch = module.get.isTouch();
87
+ module.setup.config();
88
+ module.setup.popup();
89
+ module.setup.inline();
90
+ module.setup.input();
91
+ module.setup.date();
92
+ module.create.calendar();
93
+
94
+ module.bind.events();
95
+ module.observeChanges();
96
+ module.instantiate();
97
+ },
98
+
99
+ instantiate: function () {
100
+ module.verbose('Storing instance of calendar');
101
+ instance = module;
102
+ $module.data(moduleNamespace, instance);
103
+ },
104
+
105
+ destroy: function () {
106
+ module.verbose('Destroying previous calendar for', element);
107
+ $module.removeData(moduleNamespace);
108
+ module.unbind.events();
109
+ module.disconnect.classObserver();
110
+ },
111
+
112
+ setup: {
113
+ config: function () {
114
+ if (module.get.minDate() !== null) {
115
+ module.set.minDate($module.data(metadata.minDate));
116
+ }
117
+ if (module.get.maxDate() !== null) {
118
+ module.set.maxDate($module.data(metadata.maxDate));
119
+ }
120
+ module.setting('type', module.get.type());
121
+ module.setting('on', settings.on || 'click');
122
+ },
123
+ popup: function () {
124
+ if (settings.inline) {
125
+ return;
126
+ }
127
+ if (!$activator.length) {
128
+ $activator = $module.children().first();
129
+ if (!$activator.length) {
130
+ return;
131
+ }
132
+ }
133
+ if ($.fn.popup === undefined) {
134
+ module.error(error.popup);
235
135
 
236
- var
237
- mode = module.get.mode(),
238
- today = new Date(),
239
- date = module.get.date(),
240
- focusDate = module.get.focusDate(),
241
- display = module.helper.dateInRange(focusDate || date || settings.initialDate || today)
242
- ;
136
+ return;
137
+ }
138
+ if (!$container.length) {
139
+ if (settings.context) {
140
+ module.popupId = namespace + '_popup_' + (Math.random().toString(16) + '000000000').slice(2, 10);
141
+ $container = $('<div/>', { id: module.popupId }).addClass(className.popup).appendTo($document.find(settings.context));
142
+ } else {
143
+ // prepend the popup element to the activator's parent so that it has less chance of messing with
144
+ // the styling (eg input action button needs to be the last child to have correct border radius)
145
+ var
146
+ $activatorParent = $activator.parent(),
147
+ domPositionFunction = $activatorParent.closest(selector.append).length !== 0 ? 'appendTo' : 'prependTo'
148
+ ;
149
+ $container = $('<div/>').addClass(className.popup)[domPositionFunction]($activatorParent);
150
+ }
151
+ }
152
+ $container.addClass(className.calendar);
153
+ if (isInverted) {
154
+ $container.addClass(className.inverted);
155
+ }
156
+ var onVisible = function () {
157
+ module.refreshTooltips();
158
+
159
+ return settings.onVisible.apply($container, arguments);
160
+ };
161
+ var onHidden = function () {
162
+ module.blur();
163
+
164
+ return settings.onHidden.apply($container, arguments);
165
+ };
166
+ if (!$input.length) {
167
+ // no input, $container has to handle focus/blur
168
+ $container.attr('tabindex', '0');
169
+ onVisible = function () {
170
+ module.refreshTooltips();
171
+ module.focus();
172
+
173
+ return settings.onVisible.apply($container, arguments);
174
+ };
175
+ }
176
+ var onShow = function () {
177
+ // reset the focus date onShow
178
+ module.set.focusDate(module.get.date());
179
+ module.set.mode(module.get.validatedMode(settings.startMode));
180
+
181
+ return settings.onShow.apply($container, arguments);
182
+ };
183
+ var on = module.setting('on');
184
+ var options = $.extend({}, settings.popupOptions, {
185
+ popup: $container,
186
+ movePopup: !settings.context,
187
+ on: on,
188
+ hoverable: on === 'hover',
189
+ closable: on === 'click',
190
+ onShow: onShow,
191
+ onVisible: onVisible,
192
+ onHide: settings.onHide,
193
+ onHidden: onHidden,
194
+ });
195
+ module.popup(options);
196
+ },
197
+ inline: function () {
198
+ if ($activator.length && !settings.inline) {
199
+ return;
200
+ }
201
+ settings.inline = true;
202
+ $container = $('<div/>').addClass(className.calendar).appendTo($module);
203
+ if (!$input.length) {
204
+ $container.attr('tabindex', '0');
205
+ }
206
+ },
207
+ input: function () {
208
+ if (settings.touchReadonly && $input.length && isTouch) {
209
+ $input.prop('readonly', true);
210
+ }
211
+ module.check.disabled();
212
+ },
213
+ date: function () {
214
+ var date;
215
+ if (settings.initialDate) {
216
+ date = parser.date(settings.initialDate, settings);
217
+ } else if ($module.data(metadata.date) !== undefined) {
218
+ date = parser.date($module.data(metadata.date), settings);
219
+ } else if ($input.length) {
220
+ date = parser.date($input.val(), settings);
221
+ }
222
+ module.set.date(date, settings.formatInput, false);
223
+ module.set.mode(module.get.mode(), false);
224
+ },
225
+ },
226
+
227
+ trigger: {
228
+ change: function () {
229
+ var
230
+ inputElement = $input[0]
231
+ ;
232
+ if (inputElement) {
233
+ var events = document.createEvent('HTMLEvents');
234
+ module.verbose('Triggering native change event');
235
+ events.initEvent('change', true, false);
236
+ inputElement.dispatchEvent(events);
237
+ }
238
+ },
239
+ },
240
+
241
+ create: {
242
+ calendar: function () {
243
+ var
244
+ i,
245
+ r,
246
+ c,
247
+ p,
248
+ row,
249
+ cell,
250
+ pageGrid
251
+ ;
252
+
253
+ var
254
+ mode = module.get.mode(),
255
+ today = new Date(),
256
+ date = module.get.date(),
257
+ focusDate = module.get.focusDate(),
258
+ display = module.helper.dateInRange(focusDate || date || settings.initialDate || today)
259
+ ;
260
+
261
+ if (!focusDate) {
262
+ focusDate = display;
263
+ module.set.focusDate(focusDate, false, false);
264
+ }
243
265
 
244
- if (!focusDate) {
245
- focusDate = display;
246
- module.set.focusDate(focusDate, false, false);
247
- }
266
+ var
267
+ isYear = mode === 'year',
268
+ isMonth = mode === 'month',
269
+ isDay = mode === 'day',
270
+ isHour = mode === 'hour',
271
+ isMinute = mode === 'minute',
272
+ isTimeOnly = settings.type === 'time'
273
+ ;
274
+
275
+ var multiMonth = Math.max(settings.multiMonth, 1);
276
+ var monthOffset = !isDay ? 0 : module.get.monthOffset();
277
+
278
+ var
279
+ minute = display.getMinutes(),
280
+ hour = display.getHours(),
281
+ day = display.getDate(),
282
+ startMonth = display.getMonth() + monthOffset,
283
+ year = display.getFullYear()
284
+ ;
285
+
286
+ var columns = isDay ? settings.showWeekNumbers ? 8 : 7 : isHour ? 4 : timeGap.column;
287
+ var rows = isDay || isHour ? 6 : timeGap.row;
288
+ var pages = isDay ? multiMonth : 1;
289
+
290
+ var container = $container;
291
+ var tooltipPosition = container.hasClass('left') ? 'right center' : 'left center';
292
+ container.empty();
293
+ if (pages > 1) {
294
+ pageGrid = $('<div/>').addClass(className.grid).appendTo(container);
295
+ }
248
296
 
249
- var
250
- isYear = mode === 'year',
251
- isMonth = mode === 'month',
252
- isDay = mode === 'day',
253
- isHour = mode === 'hour',
254
- isMinute = mode === 'minute',
255
- isTimeOnly = settings.type === 'time'
256
- ;
297
+ for (p = 0; p < pages; p++) {
298
+ if (pages > 1) {
299
+ var pageColumn = $('<div/>').addClass(className.column).appendTo(pageGrid);
300
+ container = pageColumn;
301
+ }
302
+
303
+ var month = startMonth + p;
304
+ var firstMonthDayColumn = (new Date(year, month, 1).getDay() - settings.firstDayOfWeek % 7 + 7) % 7;
305
+ if (!settings.constantHeight && isDay) {
306
+ var requiredCells = new Date(year, month + 1, 0).getDate() + firstMonthDayColumn;
307
+ rows = Math.ceil(requiredCells / 7);
308
+ }
309
+
310
+ var
311
+ yearChange = isYear ? 10 : isMonth ? 1 : 0,
312
+ monthChange = isDay ? 1 : 0,
313
+ dayChange = isHour || isMinute ? 1 : 0,
314
+ prevNextDay = isHour || isMinute ? day : 1,
315
+ prevDate = new Date(year - yearChange, month - monthChange, prevNextDay - dayChange, hour),
316
+ nextDate = new Date(year + yearChange, month + monthChange, prevNextDay + dayChange, hour),
317
+ prevLast = isYear
318
+ ? new Date(Math.ceil(year / 10) * 10 - 9, 0, 0)
319
+ : isMonth
320
+ ? new Date(year, 0, 0)
321
+ : isDay
322
+ ? new Date(year, month, 0)
323
+ : new Date(year, month, day, -1),
324
+ nextFirst = isYear
325
+ ? new Date(Math.ceil(year / 10) * 10 + 1, 0, 1)
326
+ : isMonth
327
+ ? new Date(year + 1, 0, 1)
328
+ : isDay
329
+ ? new Date(year, month + 1, 1)
330
+ : new Date(year, month, day + 1)
331
+ ;
332
+
333
+ var tempMode = mode;
334
+ if (isDay && settings.showWeekNumbers) {
335
+ tempMode += ' andweek';
336
+ }
337
+ var table = $('<table/>').addClass(className.table).addClass(tempMode).addClass(numberText[columns] + ' column').appendTo(container);
338
+ if (isInverted) {
339
+ table.addClass(className.inverted);
340
+ }
341
+ var textColumns = columns;
342
+ // no header for time-only mode
343
+ if (!isTimeOnly) {
344
+ var thead = $('<thead/>').appendTo(table);
345
+
346
+ row = $('<tr/>').appendTo(thead);
347
+ cell = $('<th/>').attr('colspan', '' + columns).appendTo(row);
348
+
349
+ var headerDate = isYear || isMonth
350
+ ? new Date(year, 0, 1)
351
+ : isDay
352
+ ? new Date(year, month, 1)
353
+ : new Date(year, month, day, hour, minute);
354
+ var headerText = $('<span/>').addClass(className.link).appendTo(cell);
355
+ headerText.text(module.helper.dateFormat(formatter[mode + 'Header'], headerDate));
356
+ var newMode = isMonth
357
+ ? (settings.disableYear ? 'day' : 'year')
358
+ : isDay
359
+ ? (settings.disableMonth ? 'year' : 'month')
360
+ : 'day';
361
+ headerText.data(metadata.mode, newMode);
362
+
363
+ if (p === 0) {
364
+ var prev = $('<span/>').addClass(className.prev).appendTo(cell);
365
+ prev.data(metadata.focusDate, prevDate);
366
+ prev.toggleClass(className.disabledCell, !module.helper.isDateInRange(prevLast, mode));
367
+ $('<i/>').addClass(className.prevIcon).appendTo(prev);
368
+ }
369
+
370
+ if (p === pages - 1) {
371
+ var next = $('<span/>').addClass(className.next).appendTo(cell);
372
+ next.data(metadata.focusDate, nextDate);
373
+ next.toggleClass(className.disabledCell, !module.helper.isDateInRange(nextFirst, mode));
374
+ $('<i/>').addClass(className.nextIcon).appendTo(next);
375
+ }
376
+ if (isDay) {
377
+ row = $('<tr/>').appendTo(thead);
378
+ if (settings.showWeekNumbers) {
379
+ cell = $('<th/>').appendTo(row);
380
+ cell.text(settings.text.weekNo);
381
+ cell.addClass(className.weekCell);
382
+ textColumns--;
383
+ }
384
+ for (i = 0; i < textColumns; i++) {
385
+ cell = $('<th/>').appendTo(row);
386
+ cell.text(formatter.dayColumnHeader((i + settings.firstDayOfWeek) % 7, settings));
387
+ }
388
+ }
389
+ }
390
+
391
+ var tbody = $('<tbody/>').appendTo(table);
392
+ i = isYear ? Math.ceil(year / 10) * 10 - 9 : isDay ? 1 - firstMonthDayColumn : 0;
393
+ for (r = 0; r < rows; r++) {
394
+ row = $('<tr/>').appendTo(tbody);
395
+ if (isDay && settings.showWeekNumbers) {
396
+ cell = $('<th/>').appendTo(row);
397
+ cell.text(module.get.weekOfYear(year, month, i + 1 - settings.firstDayOfWeek));
398
+ cell.addClass(className.weekCell);
399
+ }
400
+ for (c = 0; c < textColumns; c++, i++) {
401
+ var cellDate = isYear
402
+ ? new Date(i, month, 1, hour, minute)
403
+ : isMonth
404
+ ? new Date(year, i, 1, hour, minute)
405
+ : isDay
406
+ ? new Date(year, month, i, hour, minute)
407
+ : isHour
408
+ ? new Date(year, month, day, i)
409
+ : new Date(year, month, day, hour, i * settings.minTimeGap);
410
+ var cellText = isYear
411
+ ? i
412
+ : isMonth
413
+ ? settings.text.monthsShort[i]
414
+ : isDay
415
+ ? cellDate.getDate()
416
+ : module.helper.dateFormat(formatter.cellTime, cellDate);
417
+ cell = $('<td/>').addClass(className.cell).appendTo(row);
418
+ cell.text(cellText);
419
+ cell.data(metadata.date, cellDate);
420
+ var adjacent = isDay && cellDate.getMonth() !== ((month + 12) % 12);
421
+ var disabled = (!settings.selectAdjacentDays && adjacent) || !module.helper.isDateInRange(cellDate, mode) || settings.isDisabled(cellDate, mode) || module.helper.isDisabled(cellDate, mode) || !module.helper.isEnabled(cellDate, mode);
422
+ var eventDate;
423
+ if (disabled) {
424
+ var disabledDate = module.helper.findDayAsObject(cellDate, mode, settings.disabledDates);
425
+ if (disabledDate !== null && disabledDate[metadata.message]) {
426
+ cell.attr('data-tooltip', disabledDate[metadata.message]);
427
+ cell.attr('data-position', disabledDate[metadata.position] || tooltipPosition);
428
+ if (disabledDate[metadata.inverted] || (isInverted && disabledDate[metadata.inverted] === undefined)) {
429
+ cell.attr('data-inverted', '');
430
+ }
431
+ if (disabledDate[metadata.variation]) {
432
+ cell.attr('data-variation', disabledDate[metadata.variation]);
433
+ }
434
+ }
435
+ if (mode === 'hour') {
436
+ var disabledHour = module.helper.findHourAsObject(cellDate, mode, settings.disabledHours);
437
+ if (disabledHour !== null && disabledHour[metadata.message]) {
438
+ cell.attr('data-tooltip', disabledHour[metadata.message]);
439
+ cell.attr('data-position', disabledHour[metadata.position] || tooltipPosition);
440
+ if (disabledHour[metadata.inverted] || (isInverted && disabledHour[metadata.inverted] === undefined)) {
441
+ cell.attr('data-inverted', '');
442
+ }
443
+ if (disabledHour[metadata.variation]) {
444
+ cell.attr('data-variation', disabledHour[metadata.variation]);
445
+ }
446
+ }
447
+ }
448
+ } else {
449
+ eventDate = module.helper.findDayAsObject(cellDate, mode, settings.eventDates);
450
+ if (eventDate !== null) {
451
+ cell.addClass(eventDate[metadata.class] || settings.eventClass);
452
+ if (eventDate[metadata.message]) {
453
+ cell.attr('data-tooltip', eventDate[metadata.message]);
454
+ cell.attr('data-position', eventDate[metadata.position] || tooltipPosition);
455
+ if (eventDate[metadata.inverted] || (isInverted && eventDate[metadata.inverted] === undefined)) {
456
+ cell.attr('data-inverted', '');
457
+ }
458
+ if (eventDate[metadata.variation]) {
459
+ cell.attr('data-variation', eventDate[metadata.variation]);
460
+ }
461
+ }
462
+ }
463
+ }
464
+ var active = module.helper.dateEqual(cellDate, date, mode);
465
+ var isToday = module.helper.dateEqual(cellDate, today, mode);
466
+ cell.toggleClass(className.adjacentCell, adjacent && !eventDate);
467
+ cell.toggleClass(className.disabledCell, disabled);
468
+ cell.toggleClass(className.activeCell, active && !(adjacent && disabled));
469
+ if (!isHour && !isMinute) {
470
+ cell.toggleClass(className.todayCell, !adjacent && isToday);
471
+ }
472
+
473
+ // Allow for external modifications of each cell
474
+ var cellOptions = {
475
+ mode: mode,
476
+ adjacent: adjacent,
477
+ disabled: disabled,
478
+ active: active,
479
+ today: isToday,
480
+ };
481
+ formatter.cell(cell, cellDate, cellOptions);
482
+
483
+ if (module.helper.dateEqual(cellDate, focusDate, mode)) {
484
+ // ensure that the focus date is exactly equal to the cell date
485
+ // so that, if selected, the correct value is set
486
+ module.set.focusDate(cellDate, false, false);
487
+ }
488
+ }
489
+ }
490
+
491
+ if (settings.today) {
492
+ var todayRow = $('<tr/>').appendTo(tbody);
493
+ var todayButton = $('<td/>').attr('colspan', '' + columns).addClass(className.today).appendTo(todayRow);
494
+ todayButton.text(formatter.today(settings));
495
+ todayButton.data(metadata.date, today);
496
+ }
497
+
498
+ module.update.focus(false, table);
499
+
500
+ if (settings.inline) {
501
+ module.refreshTooltips();
502
+ }
503
+ }
504
+ },
505
+ },
506
+
507
+ update: {
508
+ focus: function (updateRange, container) {
509
+ container = container || $container;
510
+ var mode = module.get.mode();
511
+ var date = module.get.date();
512
+ var focusDate = module.get.focusDate();
513
+ var startDate = module.get.startDate();
514
+ var endDate = module.get.endDate();
515
+ var rangeDate = (updateRange ? focusDate : null) || date || (!isTouch ? focusDate : null);
516
+
517
+ container.find('td').each(function () {
518
+ var $cell = $(this);
519
+ var cellDate = $cell.data(metadata.date);
520
+ if (!cellDate) {
521
+ return;
522
+ }
523
+ var disabled = $cell.hasClass(className.disabledCell);
524
+ var active = $cell.hasClass(className.activeCell);
525
+ var adjacent = $cell.hasClass(className.adjacentCell);
526
+ var focused = module.helper.dateEqual(cellDate, focusDate, mode);
527
+ var inRange = !rangeDate
528
+ ? false
529
+ : ((!!startDate && module.helper.isDateInRange(cellDate, mode, startDate, rangeDate))
530
+ || (!!endDate && module.helper.isDateInRange(cellDate, mode, rangeDate, endDate)));
531
+ $cell.toggleClass(className.focusCell, focused && (!isTouch || isTouchDown) && (!adjacent || (settings.selectAdjacentDays && adjacent)) && !disabled);
532
+
533
+ if (module.helper.isTodayButton($cell)) {
534
+ return;
535
+ }
536
+ $cell.toggleClass(className.rangeCell, inRange && !active && !disabled);
537
+ });
538
+ },
539
+ },
540
+
541
+ refresh: function () {
542
+ module.create.calendar();
543
+ },
544
+
545
+ refreshTooltips: function () {
546
+ var winWidth = $(window).width();
547
+ $container.find('td[data-position]').each(function () {
548
+ var $cell = $(this);
549
+ var tooltipWidth = window.getComputedStyle($cell[0], '::after').width.replace(/[^0-9\.]/g, '');
550
+ var tooltipPosition = $cell.attr('data-position');
551
+ // use a fallback width of 250 (calendar width) for IE/Edge (which return "auto")
552
+ var calcPosition = (winWidth - $cell.width() - (parseInt(tooltipWidth, 10) || 250)) > $cell.offset().left ? 'right' : 'left';
553
+ if (tooltipPosition.indexOf(calcPosition) === -1) {
554
+ $cell.attr('data-position', tooltipPosition.replace(/(left|right)/, calcPosition));
555
+ }
556
+ });
557
+ },
558
+
559
+ bind: {
560
+ events: function () {
561
+ module.debug('Binding events');
562
+ $container.on('mousedown' + eventNamespace, module.event.mousedown);
563
+ $container.on('touchstart' + eventNamespace, module.event.mousedown);
564
+ $container.on('mouseup' + eventNamespace, module.event.mouseup);
565
+ $container.on('touchend' + eventNamespace, module.event.mouseup);
566
+ $container.on('mouseover' + eventNamespace, module.event.mouseover);
567
+ if ($input.length) {
568
+ $input.on('input' + eventNamespace, module.event.inputChange);
569
+ $input.on('focus' + eventNamespace, module.event.inputFocus);
570
+ $input.on('blur' + eventNamespace, module.event.inputBlur);
571
+ $input.on('keydown' + eventNamespace, module.event.keydown);
572
+ } else {
573
+ $container.on('keydown' + eventNamespace, module.event.keydown);
574
+ }
575
+ },
576
+ },
577
+
578
+ unbind: {
579
+ events: function () {
580
+ module.debug('Unbinding events');
581
+ $container.off(eventNamespace);
582
+ if ($input.length) {
583
+ $input.off(eventNamespace);
584
+ }
585
+ },
586
+ },
587
+
588
+ event: {
589
+ mouseover: function (event) {
590
+ var target = $(event.target);
591
+ var date = target.data(metadata.date);
592
+ var mousedown = event.buttons === 1;
593
+ if (date) {
594
+ module.set.focusDate(date, false, true, mousedown);
595
+ }
596
+ },
597
+ mousedown: function (event) {
598
+ if ($input.length) {
599
+ // prevent the mousedown on the calendar causing the input to lose focus
600
+ event.preventDefault();
601
+ }
602
+ isTouchDown = event.type.indexOf('touch') >= 0;
603
+ var target = $(event.target);
604
+ var date = target.data(metadata.date);
605
+ if (date) {
606
+ module.set.focusDate(date, false, true, true);
607
+ }
608
+ },
609
+ mouseup: function (event) {
610
+ // ensure input has focus so that it receives keydown events for calendar navigation
611
+ module.focus();
612
+ event.preventDefault();
613
+ event.stopPropagation();
614
+ isTouchDown = false;
615
+ var target = $(event.target);
616
+ if (target.hasClass('disabled')) {
617
+ return;
618
+ }
619
+ var parent = target.parent();
620
+ if (parent.data(metadata.date) || parent.data(metadata.focusDate) || parent.data(metadata.mode)) {
621
+ // clicked on a child element, switch to parent (used when clicking directly on prev/next <i> icon element)
622
+ target = parent;
623
+ }
624
+ var date = target.data(metadata.date);
625
+ var focusDate = target.data(metadata.focusDate);
626
+ var mode = target.data(metadata.mode);
627
+ if (date && settings.onSelect.call(element, date, module.get.mode()) !== false) {
628
+ var forceSet = target.hasClass(className.today);
629
+ module.selectDate(date, forceSet);
630
+ } else if (focusDate) {
631
+ module.set.focusDate(focusDate);
632
+ } else if (mode) {
633
+ module.set.mode(mode);
634
+ }
635
+ },
636
+ keydown: function (event) {
637
+ var keyCode = event.which;
638
+ if (keyCode === 9) {
639
+ // tab
640
+ module.popup('hide');
641
+ }
257
642
 
258
- var multiMonth = Math.max(settings.multiMonth, 1);
259
- var monthOffset = !isDay ? 0 : module.get.monthOffset();
643
+ if (module.popup('is visible')) {
644
+ var mode = module.get.mode();
645
+ if (keyCode === 37 || keyCode === 38 || keyCode === 39 || keyCode === 40) {
646
+ // arrow keys
647
+ var bigIncrement = mode === 'day' ? 7 : mode === 'hour' ? 4 : mode === 'minute' ? timeGap.column : 3;
648
+ var increment = keyCode === 37 ? -1 : keyCode === 38 ? -bigIncrement : keyCode == 39 ? 1 : bigIncrement;
649
+ increment *= mode === 'minute' ? settings.minTimeGap : 1;
650
+ var focusDate = module.get.focusDate() || module.get.date() || new Date();
651
+ var year = focusDate.getFullYear() + (mode === 'year' ? increment : 0);
652
+ var month = focusDate.getMonth() + (mode === 'month' ? increment : 0);
653
+ var day = focusDate.getDate() + (mode === 'day' ? increment : 0);
654
+ var hour = focusDate.getHours() + (mode === 'hour' ? increment : 0);
655
+ var minute = focusDate.getMinutes() + (mode === 'minute' ? increment : 0);
656
+ var newFocusDate = new Date(year, month, day, hour, minute);
657
+ if (settings.type === 'time') {
658
+ newFocusDate = module.helper.mergeDateTime(focusDate, newFocusDate);
659
+ }
660
+ if (module.helper.isDateInRange(newFocusDate, mode)) {
661
+ module.set.focusDate(newFocusDate);
662
+ }
663
+ } else if (keyCode === 13) {
664
+ // enter
665
+ var date = module.get.focusDate();
666
+ if (date && !settings.isDisabled(date, mode) && !module.helper.isDisabled(date, mode) && module.helper.isEnabled(date, mode)) {
667
+ if (settings.onSelect.call(element, date, module.get.mode()) !== false) {
668
+ module.selectDate(date);
669
+ }
670
+ }
671
+ // disable form submission:
672
+ event.preventDefault();
673
+ event.stopPropagation();
674
+ } else if (keyCode === 27) {
675
+ module.popup('hide');
676
+ event.stopPropagation();
677
+ }
678
+ }
260
679
 
261
- var
262
- minute = display.getMinutes(),
263
- hour = display.getHours(),
264
- day = display.getDate(),
265
- startMonth = display.getMonth() + monthOffset,
266
- year = display.getFullYear()
267
- ;
680
+ if (keyCode === 38 || keyCode === 40) {
681
+ // arrow-up || arrow-down
682
+ event.preventDefault(); // don't scroll
683
+ module.popup('show');
684
+ }
685
+ },
686
+ inputChange: function () {
687
+ var val = $input.val();
688
+ var date = parser.date(val, settings);
689
+ module.set.date(date, false);
690
+ },
691
+ inputFocus: function () {
692
+ $container.addClass(className.active);
693
+ },
694
+ inputBlur: function () {
695
+ $container.removeClass(className.active);
696
+ if (settings.formatInput) {
697
+ var date = module.get.date();
698
+ var text = module.helper.dateFormat(formatter[settings.type], date);
699
+ $input.val(text);
700
+ }
701
+ if (selectionComplete) {
702
+ module.trigger.change();
703
+ selectionComplete = false;
704
+ }
705
+ },
706
+ class: {
707
+ mutation: function (mutations) {
708
+ mutations.forEach(function (mutation) {
709
+ if (mutation.attributeName === 'class') {
710
+ module.check.disabled();
711
+ }
712
+ });
713
+ },
714
+ },
715
+ },
716
+
717
+ observeChanges: function () {
718
+ if ('MutationObserver' in window) {
719
+ classObserver = new MutationObserver(module.event.class.mutation);
720
+ module.debug('Setting up mutation observer', classObserver);
721
+ module.observe.class();
722
+ }
723
+ },
268
724
 
269
- var columns = isDay ? settings.showWeekNumbers ? 8 : 7 : isHour ? 4 : timeGap['column'];
270
- var rows = isDay || isHour ? 6 : timeGap['row'];
271
- var pages = isDay ? multiMonth : 1;
725
+ disconnect: {
726
+ classObserver: function () {
727
+ if ($input.length && classObserver) {
728
+ classObserver.disconnect();
729
+ }
730
+ },
731
+ },
732
+
733
+ observe: {
734
+ class: function () {
735
+ if ($input.length && classObserver) {
736
+ classObserver.observe($module[0], {
737
+ attributes: true,
738
+ });
739
+ }
740
+ },
741
+ },
742
+
743
+ is: {
744
+ disabled: function () {
745
+ return $module.hasClass(className.disabled);
746
+ },
747
+ },
748
+
749
+ check: {
750
+ disabled: function () {
751
+ $input.attr('tabindex', module.is.disabled() ? -1 : 0);
752
+ },
753
+ },
754
+
755
+ get: {
756
+ weekOfYear: function (weekYear, weekMonth, weekDay) {
757
+ // adapted from http://www.merlyn.demon.co.uk/weekcalc.htm
758
+ var ms1d = 864e5, // milliseconds in a day
759
+ ms7d = 7 * ms1d; // milliseconds in a week
760
+
761
+ return function () { // return a closure so constants get calculated only once
762
+ var DC3 = Date.UTC(weekYear, weekMonth, weekDay + 3) / ms1d, // an Absolute Day Number
763
+ AWN = Math.floor(DC3 / 7), // an Absolute Week Number
764
+ Wyr = new Date(AWN * ms7d).getUTCFullYear();
765
+
766
+ return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1;
767
+ }();
768
+ },
769
+ formattedDate: function (format, date) {
770
+ return module.helper.dateFormat(format || formatter[settings.type], date || module.get.date());
771
+ },
772
+ date: function () {
773
+ return module.helper.sanitiseDate($module.data(metadata.date)) || null;
774
+ },
775
+ inputDate: function () {
776
+ return $input.val();
777
+ },
778
+ focusDate: function () {
779
+ return $module.data(metadata.focusDate) || null;
780
+ },
781
+ startDate: function () {
782
+ var startModule = module.get.calendarModule(settings.startCalendar);
783
+
784
+ return (startModule ? startModule.get.date() : $module.data(metadata.startDate)) || null;
785
+ },
786
+ endDate: function () {
787
+ var endModule = module.get.calendarModule(settings.endCalendar);
788
+
789
+ return (endModule ? endModule.get.date() : $module.data(metadata.endDate)) || null;
790
+ },
791
+ minDate: function () {
792
+ return $module.data(metadata.minDate) || null;
793
+ },
794
+ maxDate: function () {
795
+ return $module.data(metadata.maxDate) || null;
796
+ },
797
+ monthOffset: function () {
798
+ return $module.data(metadata.monthOffset) || settings.monthOffset || 0;
799
+ },
800
+ mode: function () {
801
+ // only returns valid modes for the current settings
802
+ var mode = $module.data(metadata.mode) || settings.startMode;
803
+
804
+ return module.get.validatedMode(mode);
805
+ },
806
+ validatedMode: function (mode) {
807
+ var validModes = module.get.validModes();
808
+ if ($.inArray(mode, validModes) >= 0) {
809
+ return mode;
810
+ }
272
811
 
273
- var container = $container;
274
- var tooltipPosition = container.hasClass("left") ? "right center" : "left center";
275
- container.empty();
276
- if (pages > 1) {
277
- pageGrid = $('<div/>').addClass(className.grid).appendTo(container);
278
- }
812
+ return settings.type === 'time'
813
+ ? 'hour'
814
+ : settings.type === 'month'
815
+ ? 'month'
816
+ : settings.type === 'year' ? 'year' : 'day';
817
+ },
818
+ type: function () {
819
+ return $module.data(metadata.type) || settings.type;
820
+ },
821
+ validModes: function () {
822
+ var validModes = [];
823
+ if (settings.type !== 'time') {
824
+ if (!settings.disableYear || settings.type === 'year') {
825
+ validModes.push('year');
826
+ }
827
+ if (!(settings.disableMonth || settings.type === 'year') || settings.type === 'month') {
828
+ validModes.push('month');
829
+ }
830
+ if (settings.type.indexOf('date') >= 0) {
831
+ validModes.push('day');
832
+ }
833
+ }
834
+ if (settings.type.indexOf('time') >= 0) {
835
+ validModes.push('hour');
836
+ if (!settings.disableMinute) {
837
+ validModes.push('minute');
838
+ }
839
+ }
279
840
 
280
- for (p = 0; p < pages; p++) {
281
- if (pages > 1) {
282
- var pageColumn = $('<div/>').addClass(className.column).appendTo(pageGrid);
283
- container = pageColumn;
284
- }
285
-
286
- var month = startMonth + p;
287
- var firstMonthDayColumn = (new Date(year, month, 1).getDay() - settings.firstDayOfWeek % 7 + 7) % 7;
288
- if (!settings.constantHeight && isDay) {
289
- var requiredCells = new Date(year, month + 1, 0).getDate() + firstMonthDayColumn;
290
- rows = Math.ceil(requiredCells / 7);
291
- }
292
-
293
- var
294
- yearChange = isYear ? 10 : isMonth ? 1 : 0,
295
- monthChange = isDay ? 1 : 0,
296
- dayChange = isHour || isMinute ? 1 : 0,
297
- prevNextDay = isHour || isMinute ? day : 1,
298
- prevDate = new Date(year - yearChange, month - monthChange, prevNextDay - dayChange, hour),
299
- nextDate = new Date(year + yearChange, month + monthChange, prevNextDay + dayChange, hour),
300
- prevLast = isYear ? new Date(Math.ceil(year / 10) * 10 - 9, 0, 0) :
301
- isMonth ? new Date(year, 0, 0) : isDay ? new Date(year, month, 0) : new Date(year, month, day, -1),
302
- nextFirst = isYear ? new Date(Math.ceil(year / 10) * 10 + 1, 0, 1) :
303
- isMonth ? new Date(year + 1, 0, 1) : isDay ? new Date(year, month + 1, 1) : new Date(year, month, day + 1)
304
- ;
305
-
306
- var tempMode = mode;
307
- if (isDay && settings.showWeekNumbers){
308
- tempMode += ' andweek';
309
- }
310
- var table = $('<table/>').addClass(className.table).addClass(tempMode).addClass(numberText[columns] + ' column').appendTo(container);
311
- if(isInverted){
312
- table.addClass(className.inverted);
313
- }
314
- var textColumns = columns;
315
- //no header for time-only mode
316
- if (!isTimeOnly) {
317
- var thead = $('<thead/>').appendTo(table);
318
-
319
- row = $('<tr/>').appendTo(thead);
320
- cell = $('<th/>').attr('colspan', '' + columns).appendTo(row);
321
-
322
- var headerDate = isYear || isMonth ? new Date(year, 0, 1) :
323
- isDay ? new Date(year, month, 1) : new Date(year, month, day, hour, minute);
324
- var headerText = $('<span/>').addClass(className.link).appendTo(cell);
325
- headerText.text(module.helper.dateFormat(formatter[mode+'Header'], headerDate));
326
- var newMode = isMonth ? (settings.disableYear ? 'day' : 'year') :
327
- isDay ? (settings.disableMonth ? 'year' : 'month') : 'day';
328
- headerText.data(metadata.mode, newMode);
329
-
330
- if (p === 0) {
331
- var prev = $('<span/>').addClass(className.prev).appendTo(cell);
332
- prev.data(metadata.focusDate, prevDate);
333
- prev.toggleClass(className.disabledCell, !module.helper.isDateInRange(prevLast, mode));
334
- $('<i/>').addClass(className.prevIcon).appendTo(prev);
335
- }
841
+ return validModes;
842
+ },
843
+ isTouch: function () {
844
+ try {
845
+ document.createEvent('TouchEvent');
336
846
 
337
- if (p === pages - 1) {
338
- var next = $('<span/>').addClass(className.next).appendTo(cell);
339
- next.data(metadata.focusDate, nextDate);
340
- next.toggleClass(className.disabledCell, !module.helper.isDateInRange(nextFirst, mode));
341
- $('<i/>').addClass(className.nextIcon).appendTo(next);
342
- }
343
- if (isDay) {
344
- row = $('<tr/>').appendTo(thead);
345
- if(settings.showWeekNumbers) {
346
- cell = $('<th/>').appendTo(row);
347
- cell.text(settings.text.weekNo);
348
- cell.addClass(className.weekCell);
349
- textColumns--;
350
- }
351
- for (i = 0; i < textColumns; i++) {
352
- cell = $('<th/>').appendTo(row);
353
- cell.text(formatter.dayColumnHeader((i + settings.firstDayOfWeek) % 7, settings));
354
- }
355
- }
356
- }
357
-
358
- var tbody = $('<tbody/>').appendTo(table);
359
- i = isYear ? Math.ceil(year / 10) * 10 - 9 : isDay ? 1 - firstMonthDayColumn : 0;
360
- for (r = 0; r < rows; r++) {
361
- row = $('<tr/>').appendTo(tbody);
362
- if(isDay && settings.showWeekNumbers){
363
- cell = $('<th/>').appendTo(row);
364
- cell.text(module.get.weekOfYear(year,month,i+1-settings.firstDayOfWeek));
365
- cell.addClass(className.weekCell);
366
- }
367
- for (c = 0; c < textColumns; c++, i++) {
368
- var cellDate = isYear ? new Date(i, month, 1, hour, minute) :
369
- isMonth ? new Date(year, i, 1, hour, minute) : isDay ? new Date(year, month, i, hour, minute) :
370
- isHour ? new Date(year, month, day, i) : new Date(year, month, day, hour, i * settings.minTimeGap);
371
- var cellText = isYear ? i :
372
- isMonth ? settings.text.monthsShort[i] : isDay ? cellDate.getDate() :
373
- module.helper.dateFormat(formatter.cellTime,cellDate);
374
- cell = $('<td/>').addClass(className.cell).appendTo(row);
375
- cell.text(cellText);
376
- cell.data(metadata.date, cellDate);
377
- var adjacent = isDay && cellDate.getMonth() !== ((month + 12) % 12);
378
- var disabled = (!settings.selectAdjacentDays && adjacent) || !module.helper.isDateInRange(cellDate, mode) || settings.isDisabled(cellDate, mode) || module.helper.isDisabled(cellDate, mode) || !module.helper.isEnabled(cellDate, mode);
379
- var eventDate;
380
- if (disabled) {
381
- var disabledDate = module.helper.findDayAsObject(cellDate, mode, settings.disabledDates);
382
- if (disabledDate !== null && disabledDate[metadata.message]) {
383
- cell.attr("data-tooltip", disabledDate[metadata.message]);
384
- cell.attr("data-position", disabledDate[metadata.position] || tooltipPosition);
385
- if(disabledDate[metadata.inverted] || (isInverted && disabledDate[metadata.inverted] === undefined)) {
386
- cell.attr("data-inverted", '');
387
- }
388
- if(disabledDate[metadata.variation]) {
389
- cell.attr("data-variation", disabledDate[metadata.variation]);
390
- }
847
+ return true;
848
+ } catch (e) {
849
+ return false;
850
+ }
851
+ },
852
+ calendarModule: function (selector) {
853
+ if (!selector) {
854
+ return null;
855
+ }
856
+ if (!(selector instanceof $)) {
857
+ selector = $document.find(selector).first();
858
+ }
859
+
860
+ // assume range related calendars are using the same namespace
861
+ return selector.data(moduleNamespace);
862
+ },
863
+ },
864
+
865
+ set: {
866
+ date: function (date, updateInput, fireChange) {
867
+ updateInput = updateInput !== false;
868
+ fireChange = fireChange !== false;
869
+ date = module.helper.sanitiseDate(date);
870
+ date = module.helper.dateInRange(date);
871
+
872
+ var mode = module.get.mode();
873
+ var text = module.helper.dateFormat(formatter[settings.type], date);
874
+
875
+ if (fireChange && settings.onBeforeChange.call(element, date, text, mode) === false) {
876
+ return false;
877
+ }
878
+
879
+ module.set.focusDate(date);
880
+
881
+ if (settings.isDisabled(date, mode)) {
882
+ return false;
883
+ }
884
+
885
+ var endDate = module.get.endDate();
886
+ if (!!endDate && !!date && date > endDate) {
887
+ // selected date is greater than end date in range, so clear end date
888
+ module.set.endDate(undefined);
889
+ }
890
+ module.set.dataKeyValue(metadata.date, date);
891
+
892
+ if (updateInput && $input.length) {
893
+ $input.val(text);
894
+ }
895
+
896
+ if (fireChange) {
897
+ settings.onChange.call(element, date, text, mode);
898
+ }
899
+ },
900
+ startDate: function (date, refreshCalendar) {
901
+ date = module.helper.sanitiseDate(date);
902
+ var startModule = module.get.calendarModule(settings.startCalendar);
903
+ if (startModule) {
904
+ startModule.set.date(date);
905
+ }
906
+ module.set.dataKeyValue(metadata.startDate, date, refreshCalendar);
907
+ },
908
+ endDate: function (date, refreshCalendar) {
909
+ date = module.helper.sanitiseDate(date);
910
+ var endModule = module.get.calendarModule(settings.endCalendar);
911
+ if (endModule) {
912
+ endModule.set.date(date);
913
+ }
914
+ module.set.dataKeyValue(metadata.endDate, date, refreshCalendar);
915
+ },
916
+ focusDate: function (date, refreshCalendar, updateFocus, updateRange) {
917
+ date = module.helper.sanitiseDate(date);
918
+ date = module.helper.dateInRange(date);
919
+ var isDay = module.get.mode() === 'day';
920
+ var oldFocusDate = module.get.focusDate();
921
+ if (isDay && date && oldFocusDate) {
922
+ var yearDelta = date.getFullYear() - oldFocusDate.getFullYear();
923
+ var monthDelta = yearDelta * 12 + date.getMonth() - oldFocusDate.getMonth();
924
+ if (monthDelta) {
925
+ var monthOffset = module.get.monthOffset() - monthDelta;
926
+ module.set.monthOffset(monthOffset, false);
927
+ }
928
+ }
929
+ var changed = module.set.dataKeyValue(metadata.focusDate, date, !!date && refreshCalendar);
930
+ updateFocus = (updateFocus !== false && changed && refreshCalendar === false) || focusDateUsedForRange != updateRange;
931
+ focusDateUsedForRange = updateRange;
932
+ if (updateFocus) {
933
+ module.update.focus(updateRange);
934
+ }
935
+ },
936
+ minDate: function (date) {
937
+ date = module.helper.sanitiseDate(date);
938
+ if (settings.maxDate !== null && settings.maxDate <= date) {
939
+ module.verbose('Unable to set minDate variable bigger that maxDate variable', date, settings.maxDate);
940
+ } else {
941
+ module.setting('minDate', date);
942
+ module.set.dataKeyValue(metadata.minDate, date);
943
+ }
944
+ },
945
+ maxDate: function (date) {
946
+ date = module.helper.sanitiseDate(date);
947
+ if (settings.minDate !== null && settings.minDate >= date) {
948
+ module.verbose('Unable to set maxDate variable lower that minDate variable', date, settings.minDate);
949
+ } else {
950
+ module.setting('maxDate', date);
951
+ module.set.dataKeyValue(metadata.maxDate, date);
952
+ }
953
+ },
954
+ monthOffset: function (monthOffset, refreshCalendar) {
955
+ var multiMonth = Math.max(settings.multiMonth, 1);
956
+ monthOffset = Math.max(1 - multiMonth, Math.min(0, monthOffset));
957
+ module.set.dataKeyValue(metadata.monthOffset, monthOffset, refreshCalendar);
958
+ },
959
+ mode: function (mode, refreshCalendar) {
960
+ module.set.dataKeyValue(metadata.mode, mode, refreshCalendar);
961
+ },
962
+ dataKeyValue: function (key, value, refreshCalendar) {
963
+ var oldValue = $module.data(key);
964
+ var equal = oldValue === value || (oldValue <= value && oldValue >= value); // equality test for dates and string objects
965
+ if (value) {
966
+ $module.data(key, value);
967
+ } else {
968
+ $module.removeData(key);
969
+ }
970
+ refreshCalendar = refreshCalendar !== false && !equal;
971
+ if (refreshCalendar) {
972
+ module.refresh();
973
+ }
974
+
975
+ return !equal;
976
+ },
977
+ },
978
+
979
+ selectDate: function (date, forceSet) {
980
+ module.verbose('New date selection', date);
981
+ var mode = module.get.mode();
982
+ var complete = forceSet || mode === 'minute'
983
+ || (settings.disableMinute && mode === 'hour')
984
+ || (settings.type === 'date' && mode === 'day')
985
+ || (settings.type === 'month' && mode === 'month')
986
+ || (settings.type === 'year' && mode === 'year');
987
+ if (complete) {
988
+ var canceled = module.set.date(date) === false;
989
+ if (!canceled) {
990
+ selectionComplete = true;
991
+ if (settings.closable) {
992
+ module.popup('hide');
993
+ // if this is a range calendar, focus the container or input. This will open the popup from its event listeners.
994
+ var endModule = module.get.calendarModule(settings.endCalendar);
995
+ if (endModule) {
996
+ endModule.refresh();
997
+ if (endModule.setting('on') !== 'focus') {
998
+ endModule.popup('show');
999
+ }
1000
+ endModule.focus();
1001
+ }
1002
+ }
1003
+ }
1004
+ } else {
1005
+ var newMode = mode === 'year'
1006
+ ? (!settings.disableMonth ? 'month' : 'day')
1007
+ : mode === 'month'
1008
+ ? 'day'
1009
+ : mode === 'day' ? 'hour' : 'minute';
1010
+ module.set.mode(newMode);
1011
+ if (mode === 'hour' || (mode === 'day' && module.get.date())) {
1012
+ // the user has chosen enough to consider a valid date/time has been chosen
1013
+ module.set.date(date, true, false);
1014
+ } else {
1015
+ module.set.focusDate(date);
1016
+ }
391
1017
  }
392
- if (mode === 'hour') {
393
- var disabledHour = module.helper.findHourAsObject(cellDate, mode, settings.disabledHours);
394
- if (disabledHour !== null && disabledHour[metadata.message]) {
395
- cell.attr("data-tooltip", disabledHour[metadata.message]);
396
- cell.attr("data-position", disabledHour[metadata.position] || tooltipPosition);
397
- if(disabledHour[metadata.inverted] || (isInverted && disabledHour[metadata.inverted] === undefined)) {
398
- cell.attr("data-inverted", '');
399
- }
400
- if(disabledHour[metadata.variation]) {
401
- cell.attr("data-variation", disabledHour[metadata.variation]);
402
- }
403
- }
1018
+ },
1019
+
1020
+ changeDate: function (date) {
1021
+ module.set.date(date);
1022
+ },
1023
+
1024
+ clear: function () {
1025
+ module.set.date(undefined);
1026
+ },
1027
+
1028
+ popup: function () {
1029
+ return $activator.popup.apply($activator, arguments);
1030
+ },
1031
+
1032
+ focus: function () {
1033
+ if ($input.length) {
1034
+ $input.trigger('focus');
1035
+ } else {
1036
+ $container.trigger('focus');
404
1037
  }
405
- } else {
406
- eventDate = module.helper.findDayAsObject(cellDate, mode, settings.eventDates);
407
- if (eventDate !== null) {
408
- cell.addClass(eventDate[metadata.class] || settings.eventClass);
409
- if (eventDate[metadata.message]) {
410
- cell.attr("data-tooltip", eventDate[metadata.message]);
411
- cell.attr("data-position", eventDate[metadata.position] || tooltipPosition);
412
- if(eventDate[metadata.inverted] || (isInverted && eventDate[metadata.inverted] === undefined)) {
413
- cell.attr("data-inverted", '');
414
- }
415
- if(eventDate[metadata.variation]) {
416
- cell.attr("data-variation", eventDate[metadata.variation]);
417
- }
418
- }
1038
+ },
1039
+ blur: function () {
1040
+ if ($input.length) {
1041
+ $input.trigger('blur');
1042
+ } else {
1043
+ $container.trigger('blur');
419
1044
  }
420
- }
421
- var active = module.helper.dateEqual(cellDate, date, mode);
422
- var isToday = module.helper.dateEqual(cellDate, today, mode);
423
- cell.toggleClass(className.adjacentCell, adjacent && !eventDate);
424
- cell.toggleClass(className.disabledCell, disabled);
425
- cell.toggleClass(className.activeCell, active && !(adjacent && disabled));
426
- if (!isHour && !isMinute) {
427
- cell.toggleClass(className.todayCell, !adjacent && isToday);
428
- }
429
-
430
- // Allow for external modifications of each cell
431
- var cellOptions = {
432
- mode: mode,
433
- adjacent: adjacent,
434
- disabled: disabled,
435
- active: active,
436
- today: isToday
437
- };
438
- formatter.cell(cell, cellDate, cellOptions);
439
-
440
- if (module.helper.dateEqual(cellDate, focusDate, mode)) {
441
- //ensure that the focus date is exactly equal to the cell date
442
- //so that, if selected, the correct value is set
443
- module.set.focusDate(cellDate, false, false);
444
- }
445
- }
446
- }
1045
+ },
447
1046
 
448
- if (settings.today) {
449
- var todayRow = $('<tr/>').appendTo(tbody);
450
- var todayButton = $('<td/>').attr('colspan', '' + columns).addClass(className.today).appendTo(todayRow);
451
- todayButton.text(formatter.today(settings));
452
- todayButton.data(metadata.date, today);
453
- }
1047
+ helper: {
1048
+ dateFormat: function (format, date) {
1049
+ if (!(date instanceof Date)) {
1050
+ return '';
1051
+ }
1052
+ if (typeof format === 'function') {
1053
+ return format.call(module, date, settings);
1054
+ }
454
1055
 
455
- module.update.focus(false, table);
1056
+ var
1057
+ D = date.getDate(),
1058
+ M = date.getMonth(),
1059
+ Y = date.getFullYear(),
1060
+ d = date.getDay(),
1061
+ H = date.getHours(),
1062
+ m = date.getMinutes(),
1063
+ s = date.getSeconds(),
1064
+ w = module.get.weekOfYear(Y, M, D + 1 - settings.firstDayOfWeek),
1065
+ h = H % 12 || 12,
1066
+ a = H < 12 ? settings.text.am.toLowerCase() : settings.text.pm.toLowerCase(),
1067
+ tokens = {
1068
+ D: D,
1069
+ DD: ('0' + D).slice(-2),
1070
+ M: M + 1,
1071
+ MM: ('0' + (M + 1)).slice(-2),
1072
+ MMM: settings.text.monthsShort[M],
1073
+ MMMM: settings.text.months[M],
1074
+ Y: Y,
1075
+ YY: String(Y).slice(2),
1076
+ YYYY: Y,
1077
+ d: d,
1078
+ dd: settings.text.dayNamesShort[d].slice(0, 2),
1079
+ ddd: settings.text.dayNamesShort[d],
1080
+ dddd: settings.text.dayNames[d],
1081
+ h: h,
1082
+ hh: ('0' + h).slice(-2),
1083
+ H: H,
1084
+ HH: ('0' + H).slice(-2),
1085
+ m: m,
1086
+ mm: ('0' + m).slice(-2),
1087
+ s: s,
1088
+ ss: ('0' + s).slice(-2),
1089
+ a: a,
1090
+ A: a.toUpperCase(),
1091
+ S: ['th', 'st', 'nd', 'rd'][D % 10 > 3 ? 0 : (D % 100 - D % 10 !== 10) * D % 10],
1092
+ w: w,
1093
+ ww: ('0' + w).slice(-2),
1094
+ }
1095
+ ;
1096
+
1097
+ return format.replace(settings.regExp.token, function (match) {
1098
+ if (match in tokens) {
1099
+ return tokens[match];
1100
+ }
1101
+
1102
+ return match.slice(1, match.length - 1);
1103
+ });
1104
+ },
1105
+ isDisabled: function (date, mode) {
1106
+ return (mode === 'day' || mode === 'month' || mode === 'year' || mode === 'hour') && (((mode === 'day' && settings.disabledDaysOfWeek.indexOf(date.getDay()) !== -1) || settings.disabledDates.some(function (d) {
1107
+ if (typeof d === 'string') {
1108
+ d = module.helper.sanitiseDate(d);
1109
+ }
1110
+ if (d instanceof Date) {
1111
+ return module.helper.dateEqual(date, d, mode);
1112
+ }
1113
+ if (d !== null && typeof d === 'object') {
1114
+ if (d[metadata.year]) {
1115
+ if (typeof d[metadata.year] === 'number') {
1116
+ return date.getFullYear() == d[metadata.year];
1117
+ } else if (Array.isArray(d[metadata.year])) {
1118
+ return d[metadata.year].indexOf(date.getFullYear()) > -1;
1119
+ }
1120
+ } else if (d[metadata.month]) {
1121
+ if (typeof d[metadata.month] === 'number') {
1122
+ return date.getMonth() == d[metadata.month];
1123
+ } else if (Array.isArray(d[metadata.month])) {
1124
+ return d[metadata.month].indexOf(date.getMonth()) > -1;
1125
+ } else if (d[metadata.month] instanceof Date) {
1126
+ var sdate = module.helper.sanitiseDate(d[metadata.month]);
1127
+
1128
+ return (date.getMonth() == sdate.getMonth()) && (date.getFullYear() == sdate.getFullYear());
1129
+ }
1130
+ } else if (d[metadata.date] && mode === 'day') {
1131
+ if (d[metadata.date] instanceof Date) {
1132
+ return module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]), mode);
1133
+ } else if (Array.isArray(d[metadata.date])) {
1134
+ return d[metadata.date].some(function (idate) {
1135
+ return module.helper.dateEqual(date, idate, mode);
1136
+ });
1137
+ }
1138
+ }
1139
+ }
1140
+ })) || (mode === 'hour' && settings.disabledHours.some(function (d) {
1141
+ if (typeof d === 'string') {
1142
+ d = module.helper.sanitiseDate(d);
1143
+ }
1144
+ if (d instanceof Date) {
1145
+ return module.helper.dateEqual(date, d, mode);
1146
+ } else if (typeof d === 'number') {
1147
+ return date.getHours() === d;
1148
+ }
1149
+ if (d !== null && typeof d === 'object') {
1150
+ var blocked = true;
1151
+
1152
+ if (d[metadata.date]) {
1153
+ if (d[metadata.date] instanceof Date) {
1154
+ blocked = module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]));
1155
+ } else if (Array.isArray(d[metadata.date])) {
1156
+ return d[metadata.date].some(function (idate) {
1157
+ blocked = module.helper.dateEqual(date, idate, mode);
1158
+ });
1159
+ }
1160
+ }
1161
+
1162
+ if (d[metadata.days]) {
1163
+ if (typeof d[metadata.days] === 'number') {
1164
+ blocked = date.getDay() == d[metadata.days];
1165
+ } else if (Array.isArray(d[metadata.days])) {
1166
+ blocked = d[metadata.days].indexOf(date.getDay()) > -1;
1167
+ }
1168
+ }
1169
+
1170
+ if (d[metadata.hours]) {
1171
+ if (typeof d[metadata.hours] === 'number') {
1172
+ return blocked && date.getHours() == d[metadata.hours];
1173
+ } else if (Array.isArray(d[metadata.hours])) {
1174
+ return blocked && d[metadata.hours].indexOf(date.getHours()) > -1;
1175
+ }
1176
+ }
1177
+ }
1178
+ })));
1179
+ },
1180
+ isEnabled: function (date, mode) {
1181
+ if (mode === 'day') {
1182
+ return settings.enabledDates.length === 0 || settings.enabledDates.some(function (d) {
1183
+ if (typeof d === 'string') {
1184
+ d = module.helper.sanitiseDate(d);
1185
+ }
1186
+ if (d instanceof Date) {
1187
+ return module.helper.dateEqual(date, d, mode);
1188
+ }
1189
+ if (d !== null && typeof d === 'object' && d[metadata.date]) {
1190
+ return module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]), mode);
1191
+ }
1192
+ });
1193
+ } else {
1194
+ return true;
1195
+ }
1196
+ },
1197
+ findDayAsObject: function (date, mode, dates) {
1198
+ if (mode === 'day' || mode === 'month' || mode === 'year') {
1199
+ var d;
1200
+ for (var i = 0; i < dates.length; i++) {
1201
+ d = dates[i];
1202
+ if (typeof d === 'string') {
1203
+ d = module.helper.sanitiseDate(d);
1204
+ }
1205
+ if (d instanceof Date && module.helper.dateEqual(date, d, mode)) {
1206
+ var dateObject = {};
1207
+ dateObject[metadata.date] = d;
1208
+
1209
+ return dateObject;
1210
+ } else if (d !== null && typeof d === 'object') {
1211
+ if (d[metadata.year]) {
1212
+ if (typeof d[metadata.year] === 'number' && date.getFullYear() == d[metadata.year]) {
1213
+ return d;
1214
+ } else if (Array.isArray(d[metadata.year])) {
1215
+ if (d[metadata.year].indexOf(date.getFullYear()) > -1) {
1216
+ return d;
1217
+ }
1218
+ }
1219
+ } else if (d[metadata.month]) {
1220
+ if (typeof d[metadata.month] === 'number' && date.getMonth() == d[metadata.month]) {
1221
+ return d;
1222
+ } else if (Array.isArray(d[metadata.month])) {
1223
+ if (d[metadata.month].indexOf(date.getMonth()) > -1) {
1224
+ return d;
1225
+ }
1226
+ } else if (d[metadata.month] instanceof Date) {
1227
+ var sdate = module.helper.sanitiseDate(d[metadata.month]);
1228
+ if ((date.getMonth() == sdate.getMonth()) && (date.getFullYear() == sdate.getFullYear())) {
1229
+ return d;
1230
+ }
1231
+ }
1232
+ } else if (d[metadata.date] && mode === 'day') {
1233
+ if (d[metadata.date] instanceof Date && module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]), mode)) {
1234
+ return d;
1235
+ } else if (Array.isArray(d[metadata.date])) {
1236
+ if (d[metadata.date].some(function (idate) {
1237
+ return module.helper.dateEqual(date, idate, mode);
1238
+ })) {
1239
+ return d;
1240
+ }
1241
+ }
1242
+ }
1243
+ }
1244
+ }
1245
+ }
456
1246
 
457
- if(settings.inline){
458
- module.refreshTooltips();
459
- }
460
- }
461
- }
462
- },
1247
+ return null;
1248
+ },
1249
+ findHourAsObject: function (date, mode, hours) {
1250
+ if (mode === 'hour') {
1251
+ var d;
1252
+ var hourCheck = function (date, d) {
1253
+ if (d[metadata.hours]) {
1254
+ if (typeof d[metadata.hours] === 'number' && date.getHours() == d[metadata.hours]) {
1255
+ return d;
1256
+ } else if (Array.isArray(d[metadata.hours])) {
1257
+ if (d[metadata.hours].indexOf(date.getHours()) > -1) {
1258
+ return d;
1259
+ }
1260
+ }
1261
+ }
1262
+ };
1263
+ for (var i = 0; i < hours.length; i++) {
1264
+ d = hours[i];
1265
+ if (typeof d === 'number' && date.getHours() == d) {
1266
+ return null;
1267
+ } else if (d !== null && typeof d === 'object') {
1268
+ if (d[metadata.days] && hourCheck(date, d)) {
1269
+ if (typeof d[metadata.days] === 'number' && date.getDay() == d[metadata.days]) {
1270
+ return d;
1271
+ } else if (Array.isArray(d[metadata.days])) {
1272
+ if (d[metadata.days].indexOf(date.getDay()) > -1) {
1273
+ return d;
1274
+ }
1275
+ }
1276
+ } else if (d[metadata.date] && hourCheck(date, d)) {
1277
+ if (d[metadata.date] instanceof Date && module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]))) {
1278
+ return d;
1279
+ } else if (Array.isArray(d[metadata.date])) {
1280
+ if (d[metadata.date].some(function (idate) {
1281
+ return module.helper.dateEqual(date, idate, mode);
1282
+ })) {
1283
+ return d;
1284
+ }
1285
+ }
1286
+ } else if (hourCheck(date, d)) {
1287
+ return d;
1288
+ }
1289
+ }
1290
+ }
1291
+ }
463
1292
 
464
- update: {
465
- focus: function (updateRange, container) {
466
- container = container || $container;
467
- var mode = module.get.mode();
468
- var date = module.get.date();
469
- var focusDate = module.get.focusDate();
470
- var startDate = module.get.startDate();
471
- var endDate = module.get.endDate();
472
- var rangeDate = (updateRange ? focusDate : null) || date || (!isTouch ? focusDate : null);
473
-
474
- container.find('td').each(function () {
475
- var cell = $(this);
476
- var cellDate = cell.data(metadata.date);
477
- if (!cellDate) {
478
- return;
479
- }
480
- var disabled = cell.hasClass(className.disabledCell);
481
- var active = cell.hasClass(className.activeCell);
482
- var adjacent = cell.hasClass(className.adjacentCell);
483
- var focused = module.helper.dateEqual(cellDate, focusDate, mode);
484
- var inRange = !rangeDate ? false :
485
- ((!!startDate && module.helper.isDateInRange(cellDate, mode, startDate, rangeDate)) ||
486
- (!!endDate && module.helper.isDateInRange(cellDate, mode, rangeDate, endDate)));
487
- cell.toggleClass(className.focusCell, focused && (!isTouch || isTouchDown) && (!adjacent || (settings.selectAdjacentDays && adjacent)) && !disabled);
488
-
489
- if (module.helper.isTodayButton(cell)) {
490
- return;
491
- }
492
- cell.toggleClass(className.rangeCell, inRange && !active && !disabled);
493
- });
494
- }
495
- },
1293
+ return null;
1294
+ },
1295
+ sanitiseDate: function (date) {
1296
+ if (!(date instanceof Date)) {
1297
+ date = parser.date('' + date, settings);
1298
+ }
1299
+ if (!date || isNaN(date.getTime())) {
1300
+ return null;
1301
+ }
496
1302
 
497
- refresh: function () {
498
- module.create.calendar();
499
- },
1303
+ return date;
1304
+ },
1305
+ dateDiff: function (date1, date2, mode) {
1306
+ mode = mode || 'day';
1307
+ var isTimeOnly = settings.type === 'time';
1308
+ var isYear = mode === 'year';
1309
+ var isYearOrMonth = isYear || mode === 'month';
1310
+ var isMinute = mode === 'minute';
1311
+ var isHourOrMinute = isMinute || mode === 'hour';
1312
+ // only care about a minute accuracy of settings.minTimeGap
1313
+ date1 = new Date(
1314
+ isTimeOnly ? 2000 : date1.getFullYear(),
1315
+ isTimeOnly ? 0 : isYear ? 0 : date1.getMonth(),
1316
+ isTimeOnly ? 1 : isYearOrMonth ? 1 : date1.getDate(),
1317
+ !isHourOrMinute ? 0 : date1.getHours(),
1318
+ !isMinute ? 0 : settings.minTimeGap * Math.floor(date1.getMinutes() / settings.minTimeGap)
1319
+ );
1320
+ date2 = new Date(
1321
+ isTimeOnly ? 2000 : date2.getFullYear(),
1322
+ isTimeOnly ? 0 : isYear ? 0 : date2.getMonth(),
1323
+ isTimeOnly ? 1 : isYearOrMonth ? 1 : date2.getDate(),
1324
+ !isHourOrMinute ? 0 : date2.getHours(),
1325
+ !isMinute ? 0 : settings.minTimeGap * Math.floor(date2.getMinutes() / settings.minTimeGap)
1326
+ );
1327
+
1328
+ return date2.getTime() - date1.getTime();
1329
+ },
1330
+ dateEqual: function (date1, date2, mode) {
1331
+ return !!date1 && !!date2 && module.helper.dateDiff(date1, date2, mode) === 0;
1332
+ },
1333
+ isDateInRange: function (date, mode, minDate, maxDate) {
1334
+ if (!minDate && !maxDate) {
1335
+ var startDate = module.get.startDate();
1336
+ minDate = startDate && settings.minDate ? new Date(Math.max(startDate, settings.minDate)) : startDate || settings.minDate;
1337
+ maxDate = settings.maxDate;
1338
+ }
1339
+ minDate = minDate && new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate(), minDate.getHours(), settings.minTimeGap * Math.ceil(minDate.getMinutes() / settings.minTimeGap));
1340
+
1341
+ return !(!date
1342
+ || (minDate && module.helper.dateDiff(date, minDate, mode) > 0)
1343
+ || (maxDate && module.helper.dateDiff(maxDate, date, mode) > 0));
1344
+ },
1345
+ dateInRange: function (date, minDate, maxDate) {
1346
+ if (!minDate && !maxDate) {
1347
+ var startDate = module.get.startDate();
1348
+ minDate = startDate && settings.minDate ? new Date(Math.max(startDate, settings.minDate)) : startDate || settings.minDate;
1349
+ maxDate = settings.maxDate;
1350
+ }
1351
+ minDate = minDate && new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate(), minDate.getHours(), settings.minTimeGap * Math.ceil(minDate.getMinutes() / settings.minTimeGap));
1352
+ var isTimeOnly = settings.type === 'time';
1353
+
1354
+ return !date
1355
+ ? date
1356
+ : (minDate && module.helper.dateDiff(date, minDate, 'minute') > 0)
1357
+ ? (isTimeOnly ? module.helper.mergeDateTime(date, minDate) : minDate)
1358
+ : (maxDate && module.helper.dateDiff(maxDate, date, 'minute') > 0)
1359
+ ? (isTimeOnly ? module.helper.mergeDateTime(date, maxDate) : maxDate)
1360
+ : date;
1361
+ },
1362
+ mergeDateTime: function (date, time) {
1363
+ return (!date || !time)
1364
+ ? time
1365
+ : new Date(date.getFullYear(), date.getMonth(), date.getDate(), time.getHours(), time.getMinutes());
1366
+ },
1367
+ isTodayButton: function (element) {
1368
+ return element.text() === settings.text.today;
1369
+ },
1370
+ },
1371
+
1372
+ setting: function (name, value) {
1373
+ module.debug('Changing setting', name, value);
1374
+ if ($.isPlainObject(name)) {
1375
+ $.extend(true, settings, name);
1376
+ } else if (value !== undefined) {
1377
+ if ($.isPlainObject(settings[name])) {
1378
+ $.extend(true, settings[name], value);
1379
+ } else {
1380
+ settings[name] = value;
1381
+ }
1382
+ } else {
1383
+ return settings[name];
1384
+ }
1385
+ },
1386
+ internal: function (name, value) {
1387
+ if ($.isPlainObject(name)) {
1388
+ $.extend(true, module, name);
1389
+ } else if (value !== undefined) {
1390
+ module[name] = value;
1391
+ } else {
1392
+ return module[name];
1393
+ }
1394
+ },
1395
+ debug: function () {
1396
+ if (!settings.silent && settings.debug) {
1397
+ if (settings.performance) {
1398
+ module.performance.log(arguments);
1399
+ } else {
1400
+ module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
1401
+ module.debug.apply(console, arguments);
1402
+ }
1403
+ }
1404
+ },
1405
+ verbose: function () {
1406
+ if (!settings.silent && settings.verbose && settings.debug) {
1407
+ if (settings.performance) {
1408
+ module.performance.log(arguments);
1409
+ } else {
1410
+ module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
1411
+ module.verbose.apply(console, arguments);
1412
+ }
1413
+ }
1414
+ },
1415
+ error: function () {
1416
+ if (!settings.silent) {
1417
+ module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
1418
+ module.error.apply(console, arguments);
1419
+ }
1420
+ },
1421
+ performance: {
1422
+ log: function (message) {
1423
+ var
1424
+ currentTime,
1425
+ executionTime,
1426
+ previousTime
1427
+ ;
1428
+ if (settings.performance) {
1429
+ currentTime = new Date().getTime();
1430
+ previousTime = time || currentTime;
1431
+ executionTime = currentTime - previousTime;
1432
+ time = currentTime;
1433
+ performance.push({
1434
+ Name: message[0],
1435
+ Arguments: [].slice.call(message, 1) || '',
1436
+ Element: element,
1437
+ 'Execution Time': executionTime,
1438
+ });
1439
+ }
1440
+ clearTimeout(module.performance.timer);
1441
+ module.performance.timer = setTimeout(module.performance.display, 500);
1442
+ },
1443
+ display: function () {
1444
+ var
1445
+ title = settings.name + ':',
1446
+ totalTime = 0
1447
+ ;
1448
+ time = false;
1449
+ clearTimeout(module.performance.timer);
1450
+ $.each(performance, function (index, data) {
1451
+ totalTime += data['Execution Time'];
1452
+ });
1453
+ title += ' ' + totalTime + 'ms';
1454
+ if (moduleSelector) {
1455
+ title += ' \'' + moduleSelector + '\'';
1456
+ }
1457
+ if ((console.group !== undefined || console.table !== undefined) && performance.length > 0) {
1458
+ console.groupCollapsed(title);
1459
+ if (console.table) {
1460
+ console.table(performance);
1461
+ } else {
1462
+ $.each(performance, function (index, data) {
1463
+ console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
1464
+ });
1465
+ }
1466
+ console.groupEnd();
1467
+ }
1468
+ performance = [];
1469
+ },
1470
+ },
1471
+ invoke: function (query, passedArguments, context) {
1472
+ var
1473
+ object = instance,
1474
+ maxDepth,
1475
+ found,
1476
+ response
1477
+ ;
1478
+ passedArguments = passedArguments || queryArguments;
1479
+ context = context || element;
1480
+ if (typeof query == 'string' && object !== undefined) {
1481
+ query = query.split(/[\. ]/);
1482
+ maxDepth = query.length - 1;
1483
+ $.each(query, function (depth, value) {
1484
+ var camelCaseValue = (depth != maxDepth)
1485
+ ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
1486
+ : query
1487
+ ;
1488
+ if ($.isPlainObject(object[camelCaseValue]) && (depth != maxDepth)) {
1489
+ object = object[camelCaseValue];
1490
+ } else if (object[camelCaseValue] !== undefined) {
1491
+ found = object[camelCaseValue];
1492
+
1493
+ return false;
1494
+ } else if ($.isPlainObject(object[value]) && (depth != maxDepth)) {
1495
+ object = object[value];
1496
+ } else if (object[value] !== undefined) {
1497
+ found = object[value];
1498
+
1499
+ return false;
1500
+ } else {
1501
+ module.error(error.method, query);
1502
+
1503
+ return false;
1504
+ }
1505
+ });
1506
+ }
1507
+ if (isFunction(found)) {
1508
+ response = found.apply(context, passedArguments);
1509
+ } else if (found !== undefined) {
1510
+ response = found;
1511
+ }
1512
+ if (Array.isArray(returnedValue)) {
1513
+ returnedValue.push(response);
1514
+ } else if (returnedValue !== undefined) {
1515
+ returnedValue = [returnedValue, response];
1516
+ } else if (response !== undefined) {
1517
+ returnedValue = response;
1518
+ }
500
1519
 
501
- refreshTooltips: function() {
502
- var winWidth = $(window).width();
503
- $container.find('td[data-position]').each(function () {
504
- var cell = $(this);
505
- var tooltipWidth = window.getComputedStyle(cell[0], '::after').width.replace(/[^0-9\.]/g,'');
506
- var tooltipPosition = cell.attr('data-position');
507
- // use a fallback width of 250 (calendar width) for IE/Edge (which return "auto")
508
- var calcPosition = (winWidth - cell.width() - (parseInt(tooltipWidth,10) || 250)) > cell.offset().left ? 'right' : 'left';
509
- if(tooltipPosition.indexOf(calcPosition) === -1) {
510
- cell.attr('data-position',tooltipPosition.replace(/(left|right)/,calcPosition));
511
- }
512
- });
513
- },
1520
+ return found;
1521
+ },
1522
+ };
514
1523
 
515
- bind: {
516
- events: function () {
517
- module.debug('Binding events');
518
- $container.on('mousedown' + eventNamespace, module.event.mousedown);
519
- $container.on('touchstart' + eventNamespace, module.event.mousedown);
520
- $container.on('mouseup' + eventNamespace, module.event.mouseup);
521
- $container.on('touchend' + eventNamespace, module.event.mouseup);
522
- $container.on('mouseover' + eventNamespace, module.event.mouseover);
523
- if ($input.length) {
524
- $input.on('input' + eventNamespace, module.event.inputChange);
525
- $input.on('focus' + eventNamespace, module.event.inputFocus);
526
- $input.on('blur' + eventNamespace, module.event.inputBlur);
527
- $input.on('keydown' + eventNamespace, module.event.keydown);
1524
+ if (methodInvoked) {
1525
+ if (instance === undefined) {
1526
+ module.initialize();
1527
+ }
1528
+ module.invoke(query);
528
1529
  } else {
529
- $container.on('keydown' + eventNamespace, module.event.keydown);
530
- }
531
- }
1530
+ if (instance !== undefined) {
1531
+ instance.invoke('destroy');
1532
+ }
1533
+ module.initialize();
1534
+ }
1535
+ });
1536
+
1537
+ return (returnedValue !== undefined)
1538
+ ? returnedValue
1539
+ : this;
1540
+ };
1541
+
1542
+ $.fn.calendar.settings = {
1543
+
1544
+ name: 'Calendar',
1545
+ namespace: 'calendar',
1546
+
1547
+ silent: false,
1548
+ debug: false,
1549
+ verbose: false,
1550
+ performance: true,
1551
+
1552
+ context: false,
1553
+
1554
+ type: 'datetime', // picker type, can be 'datetime', 'date', 'time', 'month', or 'year'
1555
+ firstDayOfWeek: 0, // day for first day column (0 = Sunday)
1556
+ constantHeight: true, // add rows to shorter months to keep day calendar height consistent (6 rows)
1557
+ today: false, // show a 'today/now' button at the bottom of the calendar
1558
+ closable: true, // close the popup after selecting a date/time
1559
+ monthFirst: true, // month before day when parsing date from text
1560
+ touchReadonly: true, // set input to readonly on touch devices
1561
+ inline: false, // create the calendar inline instead of inside a popup
1562
+ on: null, // when to show the popup (defaults to 'focus' for input, 'click' for others)
1563
+ initialDate: null, // date to display initially when no date is selected (null = now)
1564
+ startMode: false, // display mode to start in, can be 'year', 'month', 'day', 'hour', 'minute' (false = 'day')
1565
+ minDate: null, // minimum date/time that can be selected, dates/times before are disabled
1566
+ maxDate: null, // maximum date/time that can be selected, dates/times after are disabled
1567
+ disableYear: false, // disable year selection mode
1568
+ disableMonth: false, // disable month selection mode
1569
+ disableMinute: false, // disable minute selection mode
1570
+ formatInput: true, // format the input text upon input blur and module creation
1571
+ startCalendar: null, // jquery object or selector for another calendar that represents the start date of a date range
1572
+ endCalendar: null, // jquery object or selector for another calendar that represents the end date of a date range
1573
+ multiMonth: 1, // show multiple months when in 'day' mode
1574
+ monthOffset: 0, // position current month by offset when multimonth > 1
1575
+ minTimeGap: 5,
1576
+ showWeekNumbers: false, // show Number of Week at the very first column of a dayView
1577
+ disabledHours: [], // specific hour(s) which won't be selectable and contain additional information.
1578
+ disabledDates: [], // specific day(s) which won't be selectable and contain additional information.
1579
+ disabledDaysOfWeek: [], // day(s) which won't be selectable(s) (0 = Sunday)
1580
+ enabledDates: [], // specific day(s) which will be selectable, all other days will be disabled
1581
+ eventDates: [], // specific day(s) which will be shown in a different color and using tooltips
1582
+ centuryBreak: 60, // starting short year until 99 where it will be assumed to belong to the last century
1583
+ currentCentury: 2000, // century to be added to 2-digit years (00 to {centuryBreak}-1)
1584
+ selectAdjacentDays: false, // The calendar can show dates from adjacent month. These adjacent month dates can also be made selectable.
1585
+ // popup options ('popup', 'on', 'hoverable', and show/hide callbacks are overridden)
1586
+ popupOptions: {
1587
+ position: 'bottom left',
1588
+ lastResort: 'bottom left',
1589
+ prefer: 'opposite',
1590
+ observeChanges: false,
1591
+ hideOnScroll: false,
532
1592
  },
533
1593
 
534
- unbind: {
535
- events: function () {
536
- module.debug('Unbinding events');
537
- $container.off(eventNamespace);
538
- if ($input.length) {
539
- $input.off(eventNamespace);
540
- }
541
- }
1594
+ text: {
1595
+ days: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
1596
+ dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
1597
+ dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
1598
+ months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
1599
+ monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
1600
+ today: 'Today',
1601
+ now: 'Now',
1602
+ am: 'AM',
1603
+ pm: 'PM',
1604
+ weekNo: 'Week',
542
1605
  },
543
1606
 
544
- event: {
545
- mouseover: function (event) {
546
- var target = $(event.target);
547
- var date = target.data(metadata.date);
548
- var mousedown = event.buttons === 1;
549
- if (date) {
550
- module.set.focusDate(date, false, true, mousedown);
551
- }
552
- },
553
- mousedown: function (event) {
554
- if ($input.length) {
555
- //prevent the mousedown on the calendar causing the input to lose focus
556
- event.preventDefault();
557
- }
558
- isTouchDown = event.type.indexOf('touch') >= 0;
559
- var target = $(event.target);
560
- var date = target.data(metadata.date);
561
- if (date) {
562
- module.set.focusDate(date, false, true, true);
563
- }
564
- },
565
- mouseup: function (event) {
566
- //ensure input has focus so that it receives keydown events for calendar navigation
567
- module.focus();
568
- event.preventDefault();
569
- event.stopPropagation();
570
- isTouchDown = false;
571
- var target = $(event.target);
572
- if (target.hasClass("disabled")) {
573
- return;
574
- }
575
- var parent = target.parent();
576
- if (parent.data(metadata.date) || parent.data(metadata.focusDate) || parent.data(metadata.mode)) {
577
- //clicked on a child element, switch to parent (used when clicking directly on prev/next <i> icon element)
578
- target = parent;
579
- }
580
- var date = target.data(metadata.date);
581
- var focusDate = target.data(metadata.focusDate);
582
- var mode = target.data(metadata.mode);
583
- if (date && settings.onSelect.call(element, date, module.get.mode()) !== false) {
584
- var forceSet = target.hasClass(className.today);
585
- module.selectDate(date, forceSet);
586
- }
587
- else if (focusDate) {
588
- module.set.focusDate(focusDate);
589
- }
590
- else if (mode) {
591
- module.set.mode(mode);
592
- }
593
- },
594
- keydown: function (event) {
595
- var keyCode = event.which;
596
- if (keyCode === 9) {
597
- //tab
598
- module.popup('hide');
599
- }
1607
+ formatter: {
1608
+ yearHeader: function (date, settings) {
1609
+ var decadeYear = Math.ceil(date.getFullYear() / 10) * 10;
1610
+
1611
+ return (decadeYear - 9) + ' - ' + (decadeYear + 2);
1612
+ },
1613
+ monthHeader: 'YYYY',
1614
+ dayHeader: 'MMMM YYYY',
1615
+ hourHeader: 'MMMM D, YYYY',
1616
+ minuteHeader: 'MMMM D, YYYY',
1617
+ dayColumnHeader: function (day, settings) {
1618
+ return settings.text.days[day];
1619
+ },
1620
+ datetime: 'MMMM D, YYYY h:mm A',
1621
+ date: 'MMMM D, YYYY',
1622
+ time: 'h:mm A',
1623
+ cellTime: 'h:mm A',
1624
+ month: 'MMMM YYYY',
1625
+ year: 'YYYY',
1626
+ today: function (settings) {
1627
+ return settings.type === 'date' ? settings.text.today : settings.text.now;
1628
+ },
1629
+ cell: function (cell, date, cellOptions) {
1630
+ },
1631
+ },
600
1632
 
601
- if (module.popup('is visible')) {
602
- var mode = module.get.mode();
603
- if (keyCode === 37 || keyCode === 38 || keyCode === 39 || keyCode === 40) {
604
- //arrow keys
605
- var bigIncrement = mode === 'day' ? 7 : mode === 'hour' ? 4 : mode === 'minute' ? timeGap['column'] : 3;
606
- var increment = keyCode === 37 ? -1 : keyCode === 38 ? -bigIncrement : keyCode == 39 ? 1 : bigIncrement;
607
- increment *= mode === 'minute' ? settings.minTimeGap : 1;
608
- var focusDate = module.get.focusDate() || module.get.date() || new Date();
609
- var year = focusDate.getFullYear() + (mode === 'year' ? increment : 0);
610
- var month = focusDate.getMonth() + (mode === 'month' ? increment : 0);
611
- var day = focusDate.getDate() + (mode === 'day' ? increment : 0);
612
- var hour = focusDate.getHours() + (mode === 'hour' ? increment : 0);
613
- var minute = focusDate.getMinutes() + (mode === 'minute' ? increment : 0);
614
- var newFocusDate = new Date(year, month, day, hour, minute);
615
- if (settings.type === 'time') {
616
- newFocusDate = module.helper.mergeDateTime(focusDate, newFocusDate);
1633
+ parser: {
1634
+ date: function (text, settings) {
1635
+ if (text instanceof Date) {
1636
+ return text;
617
1637
  }
618
- if (module.helper.isDateInRange(newFocusDate, mode)) {
619
- module.set.focusDate(newFocusDate);
1638
+ if (!text) {
1639
+ return null;
620
1640
  }
621
- } else if (keyCode === 13) {
622
- //enter
623
- var date = module.get.focusDate();
624
- if (date && !settings.isDisabled(date, mode) && !module.helper.isDisabled(date, mode) && module.helper.isEnabled(date, mode)) {
625
- if (settings.onSelect.call(element, date, module.get.mode()) !== false) {
626
- module.selectDate(date);
627
- }
1641
+ text = String(text).trim().replace(/([.:\/\-])\s+/g, '$1').replace(/\s+([.:\/-])/g, '$1').replace(/\s+/g, ' ');
1642
+ if (text.length === 0) {
1643
+ return null;
628
1644
  }
629
- //disable form submission:
630
- event.preventDefault();
631
- event.stopPropagation();
632
- } else if (keyCode === 27) {
633
- module.popup('hide');
634
- event.stopPropagation();
635
- }
636
- }
637
-
638
- if (keyCode === 38 || keyCode === 40) {
639
- //arrow-up || arrow-down
640
- event.preventDefault(); //don't scroll
641
- module.popup('show');
642
- }
643
- },
644
- inputChange: function () {
645
- var val = $input.val();
646
- var date = parser.date(val, settings);
647
- module.set.date(date, false);
648
- },
649
- inputFocus: function () {
650
- $container.addClass(className.active);
651
- },
652
- inputBlur: function () {
653
- $container.removeClass(className.active);
654
- if (settings.formatInput) {
655
- var date = module.get.date();
656
- var text = module.helper.dateFormat(formatter[settings.type], date);
657
- $input.val(text);
658
- }
659
- if(selectionComplete){
660
- module.trigger.change();
661
- selectionComplete = false;
662
- }
663
- },
664
- class: {
665
- mutation: function(mutations) {
666
- mutations.forEach(function(mutation) {
667
- if(mutation.attributeName === "class") {
668
- module.check.disabled();
1645
+ if (text.match(/^[0-9]{4}[\/\-\.][0-9]{1,2}[\/\-\.][0-9]{1,2}$/)) {
1646
+ text = text.replace(/[\/\-\.]/g, '/') + ' 00:00:00';
669
1647
  }
670
- });
671
- }
672
- }
673
- },
1648
+ // Reverse date and month in some cases
1649
+ text = settings.monthFirst || !text.match(/^[0-9]{1,2}[\/\-\.]/) ? text : text.replace(/[\/\-\.]/g, '/').replace(/([0-9]+)\/([0-9]+)/, '$2/$1');
1650
+ var textDate = new Date(text);
1651
+ var numberOnly = text.match(/^[0-9]+$/) !== null;
1652
+ if (!numberOnly && !isNaN(textDate.getDate())) {
1653
+ return textDate;
1654
+ }
1655
+ text = text.toLowerCase();
674
1656
 
675
- observeChanges: function() {
676
- if('MutationObserver' in window) {
677
- classObserver = new MutationObserver(module.event.class.mutation);
678
- module.debug('Setting up mutation observer', classObserver);
679
- module.observe.class();
680
- }
681
- },
1657
+ var
1658
+ i,
1659
+ j,
1660
+ k
1661
+ ;
1662
+ var
1663
+ minute = -1,
1664
+ hour = -1,
1665
+ day = -1,
1666
+ month = -1,
1667
+ year = -1
1668
+ ;
1669
+ var isAm = undefined;
682
1670
 
683
- disconnect: {
684
- classObserver: function() {
685
- if($input.length && classObserver) {
686
- classObserver.disconnect();
687
- }
688
- }
689
- },
1671
+ var isTimeOnly = settings.type === 'time';
1672
+ var isDateOnly = settings.type.indexOf('time') < 0;
690
1673
 
691
- observe: {
692
- class: function() {
693
- if($input.length && classObserver) {
694
- classObserver.observe($module[0], {
695
- attributes : true
696
- });
697
- }
698
- }
699
- },
1674
+ var
1675
+ words = text.split(settings.regExp.dateWords),
1676
+ word
1677
+ ;
1678
+ var
1679
+ numbers = text.split(settings.regExp.dateNumbers),
1680
+ number
1681
+ ;
700
1682
 
701
- is: {
702
- disabled: function() {
703
- return $module.hasClass(className.disabled);
704
- }
705
- },
1683
+ var parts;
1684
+ var monthString;
1685
+
1686
+ if (!isDateOnly) {
1687
+ // am/pm
1688
+ isAm = $.inArray(settings.text.am.toLowerCase(), words) >= 0
1689
+ ? true
1690
+ : $.inArray(settings.text.pm.toLowerCase(), words) >= 0 ? false : undefined;
1691
+
1692
+ // time with ':'
1693
+ for (i = 0; i < numbers.length; i++) {
1694
+ number = numbers[i];
1695
+ if (number.indexOf(':') >= 0) {
1696
+ if (hour < 0 || minute < 0) {
1697
+ parts = number.split(':');
1698
+ for (k = 0; k < Math.min(2, parts.length); k++) {
1699
+ j = parseInt(parts[k]);
1700
+ if (isNaN(j)) {
1701
+ j = 0;
1702
+ }
1703
+ if (k === 0) {
1704
+ hour = j % 24;
1705
+ } else {
1706
+ minute = j % 60;
1707
+ }
1708
+ }
1709
+ }
1710
+ numbers.splice(i, 1);
1711
+ }
1712
+ }
1713
+ }
706
1714
 
707
- check: {
708
- disabled: function(){
709
- $input.attr('tabindex',module.is.disabled() ? -1 : 0);
710
- }
711
- },
1715
+ if (!isTimeOnly) {
1716
+ // textual month
1717
+ for (i = 0; i < words.length; i++) {
1718
+ word = words[i];
1719
+ if (word.length <= 0) {
1720
+ continue;
1721
+ }
1722
+ for (j = 0; j < settings.text.months.length; j++) {
1723
+ monthString = settings.text.months[j];
1724
+ monthString = monthString.substring(0, word.length).toLowerCase();
1725
+ if (monthString === word) {
1726
+ month = j + 1;
1727
+
1728
+ break;
1729
+ }
1730
+ }
1731
+ if (month >= 0) {
1732
+ break;
1733
+ }
1734
+ }
712
1735
 
713
- get: {
714
- weekOfYear: function(weekYear,weekMonth,weekDay) {
715
- // adapted from http://www.merlyn.demon.co.uk/weekcalc.htm
716
- var ms1d = 864e5, // milliseconds in a day
717
- ms7d = 7 * ms1d; // milliseconds in a week
718
-
719
- return function() { // return a closure so constants get calculated only once
720
- var DC3 = Date.UTC(weekYear, weekMonth, weekDay + 3) / ms1d, // an Absolute Day Number
721
- AWN = Math.floor(DC3 / 7), // an Absolute Week Number
722
- Wyr = new Date(AWN * ms7d).getUTCFullYear();
723
-
724
- return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1;
725
- }();
726
- },
727
- formattedDate: function(format, date) {
728
- return module.helper.dateFormat(format || formatter[settings.type], date || module.get.date());
729
- },
730
- date: function () {
731
- return module.helper.sanitiseDate($module.data(metadata.date)) || null;
732
- },
733
- inputDate: function() {
734
- return $input.val();
735
- },
736
- focusDate: function () {
737
- return $module.data(metadata.focusDate) || null;
738
- },
739
- startDate: function () {
740
- var startModule = module.get.calendarModule(settings.startCalendar);
741
- return (startModule ? startModule.get.date() : $module.data(metadata.startDate)) || null;
742
- },
743
- endDate: function () {
744
- var endModule = module.get.calendarModule(settings.endCalendar);
745
- return (endModule ? endModule.get.date() : $module.data(metadata.endDate)) || null;
746
- },
747
- minDate: function() {
748
- return $module.data(metadata.minDate) || null;
749
- },
750
- maxDate: function() {
751
- return $module.data(metadata.maxDate) || null;
752
- },
753
- monthOffset: function () {
754
- return $module.data(metadata.monthOffset) || settings.monthOffset || 0;
755
- },
756
- mode: function () {
757
- //only returns valid modes for the current settings
758
- var mode = $module.data(metadata.mode) || settings.startMode;
759
- return module.get.validatedMode(mode);
760
- },
761
- validatedMode: function(mode){
762
- var validModes = module.get.validModes();
763
- if ($.inArray(mode, validModes) >= 0) {
764
- return mode;
765
- }
766
- return settings.type === 'time' ? 'hour' :
767
- settings.type === 'month' ? 'month' :
768
- settings.type === 'year' ? 'year' : 'day';
769
- },
770
- type: function() {
771
- return $module.data(metadata.type) || settings.type;
772
- },
773
- validModes: function () {
774
- var validModes = [];
775
- if (settings.type !== 'time') {
776
- if (!settings.disableYear || settings.type === 'year') {
777
- validModes.push('year');
778
- }
779
- if (!(settings.disableMonth || settings.type === 'year') || settings.type === 'month') {
780
- validModes.push('month');
781
- }
782
- if (settings.type.indexOf('date') >= 0) {
783
- validModes.push('day');
784
- }
785
- }
786
- if (settings.type.indexOf('time') >= 0) {
787
- validModes.push('hour');
788
- if (!settings.disableMinute) {
789
- validModes.push('minute');
790
- }
791
- }
792
- return validModes;
793
- },
794
- isTouch: function () {
795
- try {
796
- document.createEvent('TouchEvent');
797
- return true;
798
- }
799
- catch (e) {
800
- return false;
801
- }
802
- },
803
- calendarModule: function (selector) {
804
- if (!selector) {
805
- return null;
806
- }
807
- if (!(selector instanceof $)) {
808
- selector = $(document).find(selector).first();
809
- }
810
- //assume range related calendars are using the same namespace
811
- return selector.data(moduleNamespace);
812
- }
813
- },
1736
+ // year > settings.centuryBreak
1737
+ for (i = 0; i < numbers.length; i++) {
1738
+ j = parseInt(numbers[i]);
1739
+ if (isNaN(j)) {
1740
+ continue;
1741
+ }
1742
+ if (j >= settings.centuryBreak && i === numbers.length - 1) {
1743
+ if (j <= 99) {
1744
+ j += settings.currentCentury - 100;
1745
+ }
1746
+ year = j;
1747
+ numbers.splice(i, 1);
1748
+
1749
+ break;
1750
+ }
1751
+ }
814
1752
 
815
- set: {
816
- date: function (date, updateInput, fireChange) {
817
- updateInput = updateInput !== false;
818
- fireChange = fireChange !== false;
819
- date = module.helper.sanitiseDate(date);
820
- date = module.helper.dateInRange(date);
1753
+ // numeric month
1754
+ if (month < 0) {
1755
+ for (i = 0; i < numbers.length; i++) {
1756
+ k = i > 1 || settings.monthFirst ? i : i === 1 ? 0 : 1;
1757
+ j = parseInt(numbers[k]);
1758
+ if (isNaN(j)) {
1759
+ continue;
1760
+ }
1761
+ if (1 <= j && j <= 12) {
1762
+ month = j;
1763
+ numbers.splice(k, 1);
1764
+
1765
+ break;
1766
+ }
1767
+ }
1768
+ }
821
1769
 
822
- var mode = module.get.mode();
823
- var text = module.helper.dateFormat(formatter[settings.type],date);
1770
+ // day
1771
+ for (i = 0; i < numbers.length; i++) {
1772
+ j = parseInt(numbers[i]);
1773
+ if (isNaN(j)) {
1774
+ continue;
1775
+ }
1776
+ if (1 <= j && j <= 31) {
1777
+ day = j;
1778
+ numbers.splice(i, 1);
824
1779
 
825
- if (fireChange && settings.onBeforeChange.call(element, date, text, mode) === false) {
826
- return false;
827
- }
1780
+ break;
1781
+ }
1782
+ }
828
1783
 
829
- module.set.focusDate(date);
1784
+ // year <= settings.centuryBreak
1785
+ if (year < 0) {
1786
+ for (i = numbers.length - 1; i >= 0; i--) {
1787
+ j = parseInt(numbers[i]);
1788
+ if (isNaN(j)) {
1789
+ continue;
1790
+ }
1791
+ if (j <= 99) {
1792
+ j += settings.currentCentury;
1793
+ }
1794
+ year = j;
1795
+ numbers.splice(i, 1);
1796
+
1797
+ break;
1798
+ }
1799
+ }
1800
+ }
830
1801
 
831
- if (settings.isDisabled(date, mode)) {
832
- return false;
833
- }
1802
+ if (!isDateOnly) {
1803
+ // hour
1804
+ if (hour < 0) {
1805
+ for (i = 0; i < numbers.length; i++) {
1806
+ j = parseInt(numbers[i]);
1807
+ if (isNaN(j)) {
1808
+ continue;
1809
+ }
1810
+ if (0 <= j && j <= 23) {
1811
+ hour = j;
1812
+ numbers.splice(i, 1);
1813
+
1814
+ break;
1815
+ }
1816
+ }
1817
+ }
834
1818
 
835
- var endDate = module.get.endDate();
836
- if (!!endDate && !!date && date > endDate) {
837
- //selected date is greater than end date in range, so clear end date
838
- module.set.endDate(undefined);
839
- }
840
- module.set.dataKeyValue(metadata.date, date);
1819
+ // minute
1820
+ if (minute < 0) {
1821
+ for (i = 0; i < numbers.length; i++) {
1822
+ j = parseInt(numbers[i]);
1823
+ if (isNaN(j)) {
1824
+ continue;
1825
+ }
1826
+ if (0 <= j && j <= 59) {
1827
+ minute = j;
1828
+ numbers.splice(i, 1);
1829
+
1830
+ break;
1831
+ }
1832
+ }
1833
+ }
1834
+ }
841
1835
 
842
- if (updateInput && $input.length) {
843
- $input.val(text);
844
- }
1836
+ if (minute < 0 && hour < 0 && day < 0 && month < 0 && year < 0) {
1837
+ return null;
1838
+ }
845
1839
 
846
- if (fireChange) {
847
- settings.onChange.call(element, date, text, mode);
848
- }
849
- },
850
- startDate: function (date, refreshCalendar) {
851
- date = module.helper.sanitiseDate(date);
852
- var startModule = module.get.calendarModule(settings.startCalendar);
853
- if (startModule) {
854
- startModule.set.date(date);
855
- }
856
- module.set.dataKeyValue(metadata.startDate, date, refreshCalendar);
857
- },
858
- endDate: function (date, refreshCalendar) {
859
- date = module.helper.sanitiseDate(date);
860
- var endModule = module.get.calendarModule(settings.endCalendar);
861
- if (endModule) {
862
- endModule.set.date(date);
863
- }
864
- module.set.dataKeyValue(metadata.endDate, date, refreshCalendar);
865
- },
866
- focusDate: function (date, refreshCalendar, updateFocus, updateRange) {
867
- date = module.helper.sanitiseDate(date);
868
- date = module.helper.dateInRange(date);
869
- var isDay = module.get.mode() === 'day';
870
- var oldFocusDate = module.get.focusDate();
871
- if (isDay && date && oldFocusDate) {
872
- var yearDelta = date.getFullYear() - oldFocusDate.getFullYear();
873
- var monthDelta = yearDelta * 12 + date.getMonth() - oldFocusDate.getMonth();
874
- if (monthDelta) {
875
- var monthOffset = module.get.monthOffset() - monthDelta;
876
- module.set.monthOffset(monthOffset, false);
877
- }
878
- }
879
- var changed = module.set.dataKeyValue(metadata.focusDate, date, !!date && refreshCalendar);
880
- updateFocus = (updateFocus !== false && changed && refreshCalendar === false) || focusDateUsedForRange != updateRange;
881
- focusDateUsedForRange = updateRange;
882
- if (updateFocus) {
883
- module.update.focus(updateRange);
884
- }
885
- },
886
- minDate: function (date) {
887
- date = module.helper.sanitiseDate(date);
888
- if (settings.maxDate !== null && settings.maxDate <= date) {
889
- module.verbose('Unable to set minDate variable bigger that maxDate variable', date, settings.maxDate);
890
- } else {
891
- module.setting('minDate', date);
892
- module.set.dataKeyValue(metadata.minDate, date);
893
- }
894
- },
895
- maxDate: function (date) {
896
- date = module.helper.sanitiseDate(date);
897
- if (settings.minDate !== null && settings.minDate >= date) {
898
- module.verbose('Unable to set maxDate variable lower that minDate variable', date, settings.minDate);
899
- } else {
900
- module.setting('maxDate', date);
901
- module.set.dataKeyValue(metadata.maxDate, date);
902
- }
903
- },
904
- monthOffset: function (monthOffset, refreshCalendar) {
905
- var multiMonth = Math.max(settings.multiMonth, 1);
906
- monthOffset = Math.max(1 - multiMonth, Math.min(0, monthOffset));
907
- module.set.dataKeyValue(metadata.monthOffset, monthOffset, refreshCalendar);
908
- },
909
- mode: function (mode, refreshCalendar) {
910
- module.set.dataKeyValue(metadata.mode, mode, refreshCalendar);
911
- },
912
- dataKeyValue: function (key, value, refreshCalendar) {
913
- var oldValue = $module.data(key);
914
- var equal = oldValue === value || (oldValue <= value && oldValue >= value); //equality test for dates and string objects
915
- if (value) {
916
- $module.data(key, value);
917
- } else {
918
- $module.removeData(key);
919
- }
920
- refreshCalendar = refreshCalendar !== false && !equal;
921
- if (refreshCalendar) {
922
- module.refresh();
923
- }
924
- return !equal;
925
- }
926
- },
1840
+ if (minute < 0) {
1841
+ minute = 0;
1842
+ }
1843
+ if (hour < 0) {
1844
+ hour = 0;
1845
+ }
1846
+ if (day < 0) {
1847
+ day = 1;
1848
+ }
1849
+ if (month < 0) {
1850
+ month = 1;
1851
+ }
1852
+ if (year < 0) {
1853
+ year = new Date().getFullYear();
1854
+ }
1855
+
1856
+ if (isAm !== undefined) {
1857
+ if (isAm) {
1858
+ if (hour === 12) {
1859
+ hour = 0;
1860
+ }
1861
+ } else if (hour < 12) {
1862
+ hour += 12;
1863
+ }
1864
+ }
927
1865
 
928
- selectDate: function (date, forceSet) {
929
- module.verbose('New date selection', date);
930
- var mode = module.get.mode();
931
- var complete = forceSet || mode === 'minute' ||
932
- (settings.disableMinute && mode === 'hour') ||
933
- (settings.type === 'date' && mode === 'day') ||
934
- (settings.type === 'month' && mode === 'month') ||
935
- (settings.type === 'year' && mode === 'year');
936
- if (complete) {
937
- var canceled = module.set.date(date) === false;
938
- if (!canceled) {
939
- selectionComplete = true;
940
- if(settings.closable) {
941
- module.popup('hide');
942
- //if this is a range calendar, focus the container or input. This will open the popup from its event listeners.
943
- var endModule = module.get.calendarModule(settings.endCalendar);
944
- if (endModule) {
945
- endModule.refresh();
946
- if (endModule.setting('on') !== 'focus') {
947
- endModule.popup('show');
948
- }
949
- endModule.focus();
1866
+ var date = new Date(year, month - 1, day, hour, minute);
1867
+ if (date.getMonth() !== month - 1 || date.getFullYear() !== year) {
1868
+ // month or year don't match up, switch to last day of the month
1869
+ date = new Date(year, month, 0, hour, minute);
950
1870
  }
951
- }
952
- }
953
- } else {
954
- var newMode = mode === 'year' ? (!settings.disableMonth ? 'month' : 'day') :
955
- mode === 'month' ? 'day' : mode === 'day' ? 'hour' : 'minute';
956
- module.set.mode(newMode);
957
- if (mode === 'hour' || (mode === 'day' && module.get.date())) {
958
- //the user has chosen enough to consider a valid date/time has been chosen
959
- module.set.date(date, true, false);
960
- } else {
961
- module.set.focusDate(date);
962
- }
963
- }
964
- },
965
1871
 
966
- changeDate: function (date) {
967
- module.set.date(date);
1872
+ return isNaN(date.getTime()) ? null : date;
1873
+ },
968
1874
  },
969
1875
 
970
- clear: function () {
971
- module.set.date(undefined);
1876
+ // callback before date is changed, return false to cancel the change
1877
+ onBeforeChange: function (date, text, mode) {
1878
+ return true;
972
1879
  },
973
1880
 
974
- popup: function () {
975
- return $activator.popup.apply($activator, arguments);
1881
+ // callback when date changes
1882
+ onChange: function (date, text, mode) {
976
1883
  },
977
1884
 
978
- focus: function () {
979
- if ($input.length) {
980
- $input.focus();
981
- } else {
982
- $container.focus();
983
- }
984
- },
985
- blur: function () {
986
- if ($input.length) {
987
- $input.blur();
988
- } else {
989
- $container.blur();
990
- }
1885
+ // callback before show animation, return false to prevent show
1886
+ onShow: function () {
991
1887
  },
992
1888
 
993
- helper: {
994
- dateFormat: function(format,date) {
995
- if (!(date instanceof Date)) {
996
- return '';
997
- }
998
- if(typeof format === 'function') {
999
- return format.call(module, date, settings);
1000
- }
1889
+ // callback after show animation
1890
+ onVisible: function () {
1891
+ },
1001
1892
 
1002
- var D = date.getDate(),
1003
- M = date.getMonth(),
1004
- Y = date.getFullYear(),
1005
- d = date.getDay(),
1006
- H = date.getHours(),
1007
- m = date.getMinutes(),
1008
- s = date.getSeconds(),
1009
- w = module.get.weekOfYear(Y,M,D+1-settings.firstDayOfWeek),
1010
- h = H % 12 || 12,
1011
- a = H < 12 ? settings.text.am.toLowerCase() : settings.text.pm.toLowerCase(),
1012
- tokens = {
1013
- D: D,
1014
- DD: ('0'+D).slice(-2),
1015
- M: M + 1,
1016
- MM: ('0'+(M+1)).slice(-2),
1017
- MMM: settings.text.monthsShort[M],
1018
- MMMM: settings.text.months[M],
1019
- Y: Y,
1020
- YY: String(Y).slice(2),
1021
- YYYY: Y,
1022
- d: d,
1023
- dd: settings.text.dayNamesShort[d].slice(0,2),
1024
- ddd: settings.text.dayNamesShort[d],
1025
- dddd: settings.text.dayNames[d],
1026
- h: h,
1027
- hh: ('0'+h).slice(-2),
1028
- H: H,
1029
- HH: ('0'+H).slice(-2),
1030
- m: m,
1031
- mm: ('0'+m).slice(-2),
1032
- s: s,
1033
- ss: ('0'+s).slice(-2),
1034
- a: a,
1035
- A: a.toUpperCase(),
1036
- S: ['th', 'st', 'nd', 'rd'][D % 10 > 3 ? 0 : (D % 100 - D % 10 !== 10) * D % 10],
1037
- w: w,
1038
- ww: ('0'+w).slice(-2)
1039
- }
1040
- ;
1041
- return format.replace(settings.regExp.token, function (match) {
1042
- if (match in tokens) {
1043
- return tokens[match];
1044
- }
1045
- return match.slice(1, match.length - 1);
1046
- });
1047
- },
1048
- isDisabled: function(date, mode) {
1049
- return (mode === 'day' || mode === 'month' || mode === 'year' || mode === 'hour') && (((mode === 'day' && settings.disabledDaysOfWeek.indexOf(date.getDay()) !== -1) || settings.disabledDates.some(function(d){
1050
- if(typeof d === 'string') {
1051
- d = module.helper.sanitiseDate(d);
1052
- }
1053
- if (d instanceof Date) {
1054
- return module.helper.dateEqual(date, d, mode);
1055
- }
1056
- if (d !== null && typeof d === 'object') {
1057
- if (d[metadata.year]) {
1058
- if (typeof d[metadata.year] === 'number') {
1059
- return date.getFullYear() == d[metadata.year];
1060
- } else if (Array.isArray(d[metadata.year])) {
1061
- return d[metadata.year].indexOf(date.getFullYear()) > -1;
1062
- }
1063
- } else if (d[metadata.month]) {
1064
- if (typeof d[metadata.month] === 'number') {
1065
- return date.getMonth() == d[metadata.month];
1066
- } else if (Array.isArray(d[metadata.month])) {
1067
- return d[metadata.month].indexOf(date.getMonth()) > -1;
1068
- } else if (d[metadata.month] instanceof Date) {
1069
- var sdate = module.helper.sanitiseDate(d[metadata.month]);
1070
- return (date.getMonth() == sdate.getMonth()) && (date.getFullYear() == sdate.getFullYear())
1071
- }
1072
- } else if (d[metadata.date] && mode === 'day') {
1073
- if (d[metadata.date] instanceof Date) {
1074
- return module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]), mode);
1075
- } else if (Array.isArray(d[metadata.date])) {
1076
- return d[metadata.date].some(function(idate) {
1077
- return module.helper.dateEqual(date, idate, mode);
1078
- });
1079
- }
1080
- }
1081
- }
1082
- })) || (mode === 'hour' && settings.disabledHours.some(function(d){
1083
- if (typeof d === 'string') {
1084
- d = module.helper.sanitiseDate(d);
1085
- }
1086
- if (d instanceof Date) {
1087
- return module.helper.dateEqual(date, d, mode);
1088
- } else if (typeof d === 'number') {
1089
- return date.getHours() === d;
1090
- }
1091
- if (d !== null && typeof d === 'object') {
1092
- var blocked = true;
1093
-
1094
- if (d[metadata.date]) {
1095
- if (d[metadata.date] instanceof Date) {
1096
- blocked = module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]));
1097
- } else if (Array.isArray(d[metadata.date])) {
1098
- return d[metadata.date].some(function(idate) {
1099
- blocked = module.helper.dateEqual(date, idate, mode);
1100
- });
1101
- }
1102
- }
1893
+ // callback before hide animation, return false to prevent hide
1894
+ onHide: function () {
1895
+ },
1103
1896
 
1104
- if (d[metadata.days]) {
1105
- if (typeof d[metadata.days] === 'number') {
1106
- blocked = date.getDay() == d[metadata.days];
1107
- } else if (Array.isArray(d[metadata.days])) {
1108
- blocked = d[metadata.days].indexOf(date.getDay()) > -1;
1109
- }
1110
- }
1897
+ // callback after hide animation
1898
+ onHidden: function () {
1899
+ },
1111
1900
 
1112
- if (d[metadata.hours]) {
1113
- if (typeof d[metadata.hours] === 'number') {
1114
- return blocked && date.getHours() == d[metadata.hours];
1115
- } else if (Array.isArray(d[metadata.hours])) {
1116
- return blocked && d[metadata.hours].indexOf(date.getHours()) > -1;
1117
- }
1118
- }
1119
- }
1120
- })));
1121
- },
1122
- isEnabled: function(date, mode) {
1123
- if (mode === 'day') {
1124
- return settings.enabledDates.length === 0 || settings.enabledDates.some(function(d){
1125
- if(typeof d === 'string') {
1126
- d = module.helper.sanitiseDate(d);
1127
- }
1128
- if (d instanceof Date) {
1129
- return module.helper.dateEqual(date, d, mode);
1130
- }
1131
- if (d !== null && typeof d === 'object' && d[metadata.date]) {
1132
- return module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]), mode);
1133
- }
1134
- });
1135
- } else {
1136
- return true;
1137
- }
1138
- },
1139
- findDayAsObject: function(date, mode, dates) {
1140
- if (mode === 'day' || mode === 'month' || mode === 'year') {
1141
- var d;
1142
- for (var i = 0; i < dates.length; i++) {
1143
- d = dates[i];
1144
- if(typeof d === 'string') {
1145
- d = module.helper.sanitiseDate(d);
1146
- }
1147
- if (d instanceof Date && module.helper.dateEqual(date, d, mode)) {
1148
- var dateObject = {};
1149
- dateObject[metadata.date] = d;
1150
- return dateObject;
1151
- }
1152
- else if (d !== null && typeof d === 'object') {
1153
- if (d[metadata.year]) {
1154
- if (typeof d[metadata.year] === 'number' && date.getFullYear() == d[metadata.year]) {
1155
- return d;
1156
- } else if (Array.isArray(d[metadata.year])) {
1157
- if (d[metadata.year].indexOf(date.getFullYear()) > -1) {
1158
- return d;
1159
- }
1160
- }
1161
- } else if (d[metadata.month]) {
1162
- if (typeof d[metadata.month] === 'number' && date.getMonth() == d[metadata.month]) {
1163
- return d;
1164
- } else if (Array.isArray(d[metadata.month])) {
1165
- if (d[metadata.month].indexOf(date.getMonth()) > -1) {
1166
- return d;
1167
- }
1168
- } else if (d[metadata.month] instanceof Date) {
1169
- var sdate = module.helper.sanitiseDate(d[metadata.month]);
1170
- if ((date.getMonth() == sdate.getMonth()) && (date.getFullYear() == sdate.getFullYear())) {
1171
- return d;
1172
- }
1173
- }
1174
- } else if (d[metadata.date] && mode === 'day') {
1175
- if (d[metadata.date] instanceof Date && module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]), mode)) {
1176
- return d;
1177
- } else if (Array.isArray(d[metadata.date])) {
1178
- if(d[metadata.date].some(function(idate) { return module.helper.dateEqual(date, idate, mode); })) {
1179
- return d;
1180
- }
1181
- }
1182
- }
1183
- }
1184
- }
1185
- }
1186
- return null;
1187
- },
1188
- findHourAsObject: function(date, mode, hours) {
1189
- if (mode === 'hour') {
1190
- var d;
1191
- var hourCheck = function(date, d) {
1192
- if (d[metadata.hours]) {
1193
- if (typeof d[metadata.hours] === 'number' && date.getHours() == d[metadata.hours]) {
1194
- return d;
1195
- } else if (Array.isArray(d[metadata.hours])) {
1196
- if (d[metadata.hours].indexOf(date.getHours()) > -1) {
1197
- return d;
1198
- }
1199
- }
1200
- }
1201
- }
1202
- for (var i = 0; i < hours.length; i++) {
1203
- d = hours[i];
1204
- if (typeof d === 'number' && date.getHours() == d) {
1205
- return null;
1206
- } else if (d !== null && typeof d === 'object') {
1207
- if (d[metadata.days] && hourCheck(date,d)) {
1208
- if (typeof d[metadata.days] === 'number' && date.getDay() == d[metadata.days]) {
1209
- return d;
1210
- } else if (Array.isArray(d[metadata.days])) {
1211
- if (d[metadata.days].indexOf(date.getDay()) > -1) {
1212
- return d;
1213
- }
1214
- }
1215
- } else if (d[metadata.date] && hourCheck(date,d)) {
1216
- if (d[metadata.date] instanceof Date && module.helper.dateEqual(date, module.helper.sanitiseDate(d[metadata.date]))) {
1217
- return d;
1218
- } else if (Array.isArray(d[metadata.date])) {
1219
- if (d[metadata.date].some(function(idate) { return module.helper.dateEqual(date, idate, mode); })) {
1220
- return d;
1221
- }
1222
- }
1223
- } else if (hourCheck(date,d)) {
1224
- return d;
1225
- }
1226
- }
1227
- }
1228
- }
1229
- return null;
1230
- },
1231
- sanitiseDate: function (date) {
1232
- if (!(date instanceof Date)) {
1233
- date = parser.date('' + date, settings);
1234
- }
1235
- if (!date || isNaN(date.getTime())) {
1236
- return null;
1237
- }
1238
- return date;
1239
- },
1240
- dateDiff: function (date1, date2, mode) {
1241
- mode = mode || 'day';
1242
- var isTimeOnly = settings.type === 'time';
1243
- var isYear = mode === 'year';
1244
- var isYearOrMonth = isYear || mode === 'month';
1245
- var isMinute = mode === 'minute';
1246
- var isHourOrMinute = isMinute || mode === 'hour';
1247
- //only care about a minute accuracy of settings.minTimeGap
1248
- date1 = new Date(
1249
- isTimeOnly ? 2000 : date1.getFullYear(),
1250
- isTimeOnly ? 0 : isYear ? 0 : date1.getMonth(),
1251
- isTimeOnly ? 1 : isYearOrMonth ? 1 : date1.getDate(),
1252
- !isHourOrMinute ? 0 : date1.getHours(),
1253
- !isMinute ? 0 : settings.minTimeGap * Math.floor(date1.getMinutes() / settings.minTimeGap));
1254
- date2 = new Date(
1255
- isTimeOnly ? 2000 : date2.getFullYear(),
1256
- isTimeOnly ? 0 : isYear ? 0 : date2.getMonth(),
1257
- isTimeOnly ? 1 : isYearOrMonth ? 1 : date2.getDate(),
1258
- !isHourOrMinute ? 0 : date2.getHours(),
1259
- !isMinute ? 0 : settings.minTimeGap * Math.floor(date2.getMinutes() / settings.minTimeGap));
1260
- return date2.getTime() - date1.getTime();
1261
- },
1262
- dateEqual: function (date1, date2, mode) {
1263
- return !!date1 && !!date2 && module.helper.dateDiff(date1, date2, mode) === 0;
1264
- },
1265
- isDateInRange: function (date, mode, minDate, maxDate) {
1266
- if (!minDate && !maxDate) {
1267
- var startDate = module.get.startDate();
1268
- minDate = startDate && settings.minDate ? new Date(Math.max(startDate, settings.minDate)) : startDate || settings.minDate;
1269
- maxDate = settings.maxDate;
1270
- }
1271
- minDate = minDate && new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate(), minDate.getHours(), settings.minTimeGap * Math.ceil(minDate.getMinutes() / settings.minTimeGap));
1272
- return !(!date ||
1273
- (minDate && module.helper.dateDiff(date, minDate, mode) > 0) ||
1274
- (maxDate && module.helper.dateDiff(maxDate, date, mode) > 0));
1275
- },
1276
- dateInRange: function (date, minDate, maxDate) {
1277
- if (!minDate && !maxDate) {
1278
- var startDate = module.get.startDate();
1279
- minDate = startDate && settings.minDate ? new Date(Math.max(startDate, settings.minDate)) : startDate || settings.minDate;
1280
- maxDate = settings.maxDate;
1281
- }
1282
- minDate = minDate && new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate(), minDate.getHours(), settings.minTimeGap * Math.ceil(minDate.getMinutes() / settings.minTimeGap));
1283
- var isTimeOnly = settings.type === 'time';
1284
- return !date ? date :
1285
- (minDate && module.helper.dateDiff(date, minDate, 'minute') > 0) ?
1286
- (isTimeOnly ? module.helper.mergeDateTime(date, minDate) : minDate) :
1287
- (maxDate && module.helper.dateDiff(maxDate, date, 'minute') > 0) ?
1288
- (isTimeOnly ? module.helper.mergeDateTime(date, maxDate) : maxDate) :
1289
- date;
1290
- },
1291
- mergeDateTime: function (date, time) {
1292
- return (!date || !time) ? time :
1293
- new Date(date.getFullYear(), date.getMonth(), date.getDate(), time.getHours(), time.getMinutes());
1294
- },
1295
- isTodayButton: function(element) {
1296
- return element.text() === settings.text.today;
1297
- }
1901
+ // callback before item is selected, return false to prevent selection
1902
+ onSelect: function (date, mode) {
1298
1903
  },
1299
1904
 
1300
- setting: function (name, value) {
1301
- module.debug('Changing setting', name, value);
1302
- if ($.isPlainObject(name)) {
1303
- $.extend(true, settings, name);
1304
- }
1305
- else if (value !== undefined) {
1306
- if ($.isPlainObject(settings[name])) {
1307
- $.extend(true, settings[name], value);
1308
- }
1309
- else {
1310
- settings[name] = value;
1311
- }
1312
- }
1313
- else {
1314
- return settings[name];
1315
- }
1905
+ // is the given date disabled?
1906
+ isDisabled: function (date, mode) {
1907
+ return false;
1316
1908
  },
1317
- internal: function (name, value) {
1318
- if( $.isPlainObject(name) ) {
1319
- $.extend(true, module, name);
1320
- }
1321
- else if(value !== undefined) {
1322
- module[name] = value;
1323
- }
1324
- else {
1325
- return module[name];
1326
- }
1909
+
1910
+ selector: {
1911
+ popup: '.ui.popup',
1912
+ input: 'input',
1913
+ activator: 'input',
1914
+ append: '.inline.field,.inline.fields',
1327
1915
  },
1328
- debug: function () {
1329
- if (!settings.silent && settings.debug) {
1330
- if (settings.performance) {
1331
- module.performance.log(arguments);
1332
- }
1333
- else {
1334
- module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
1335
- module.debug.apply(console, arguments);
1336
- }
1337
- }
1916
+
1917
+ regExp: {
1918
+ dateWords: /[^A-Za-z\u00C0-\u024F]+/g,
1919
+ dateNumbers: /[^\d:]+/g,
1920
+ token: /d{1,4}|D{1,2}|M{1,4}|YY(?:YY)?|([Hhmsw])\1?|[SAaY]|"[^"]*"|'[^']*'/g,
1338
1921
  },
1339
- verbose: function () {
1340
- if (!settings.silent && settings.verbose && settings.debug) {
1341
- if (settings.performance) {
1342
- module.performance.log(arguments);
1343
- }
1344
- else {
1345
- module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
1346
- module.verbose.apply(console, arguments);
1347
- }
1348
- }
1922
+
1923
+ error: {
1924
+ popup: 'UI Popup, a required component is not included in this page',
1925
+ method: 'The method you called is not defined.',
1349
1926
  },
1350
- error: function () {
1351
- if (!settings.silent) {
1352
- module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
1353
- module.error.apply(console, arguments);
1354
- }
1927
+
1928
+ className: {
1929
+ calendar: 'calendar',
1930
+ active: 'active',
1931
+ popup: 'ui popup',
1932
+ grid: 'ui equal width grid',
1933
+ column: 'column',
1934
+ table: 'ui celled center aligned unstackable table',
1935
+ inverted: 'inverted',
1936
+ prev: 'prev link',
1937
+ next: 'next link',
1938
+ prevIcon: 'chevron left icon',
1939
+ nextIcon: 'chevron right icon',
1940
+ link: 'link',
1941
+ cell: 'link',
1942
+ disabledCell: 'disabled',
1943
+ weekCell: 'disabled',
1944
+ adjacentCell: 'adjacent',
1945
+ activeCell: 'active',
1946
+ rangeCell: 'range',
1947
+ focusCell: 'focus',
1948
+ todayCell: 'today',
1949
+ today: 'today link',
1950
+ disabled: 'disabled',
1355
1951
  },
1356
- performance: {
1357
- log: function (message) {
1358
- var
1359
- currentTime,
1360
- executionTime,
1361
- previousTime
1362
- ;
1363
- if (settings.performance) {
1364
- currentTime = new Date().getTime();
1365
- previousTime = time || currentTime;
1366
- executionTime = currentTime - previousTime;
1367
- time = currentTime;
1368
- performance.push({
1369
- 'Name': message[0],
1370
- 'Arguments': [].slice.call(message, 1) || '',
1371
- 'Element': element,
1372
- 'Execution Time': executionTime
1373
- });
1374
- }
1375
- clearTimeout(module.performance.timer);
1376
- module.performance.timer = setTimeout(module.performance.display, 500);
1377
- },
1378
- display: function () {
1379
- var
1380
- title = settings.name + ':',
1381
- totalTime = 0
1382
- ;
1383
- time = false;
1384
- clearTimeout(module.performance.timer);
1385
- $.each(performance, function (index, data) {
1386
- totalTime += data['Execution Time'];
1387
- });
1388
- title += ' ' + totalTime + 'ms';
1389
- if (moduleSelector) {
1390
- title += ' \'' + moduleSelector + '\'';
1391
- }
1392
- if ((console.group !== undefined || console.table !== undefined) && performance.length > 0) {
1393
- console.groupCollapsed(title);
1394
- if (console.table) {
1395
- console.table(performance);
1396
- }
1397
- else {
1398
- $.each(performance, function (index, data) {
1399
- console.log(data['Name'] + ': ' + data['Execution Time'] + 'ms');
1400
- });
1401
- }
1402
- console.groupEnd();
1403
- }
1404
- performance = [];
1405
- }
1952
+
1953
+ metadata: {
1954
+ date: 'date',
1955
+ focusDate: 'focusDate',
1956
+ startDate: 'startDate',
1957
+ endDate: 'endDate',
1958
+ minDate: 'minDate',
1959
+ maxDate: 'maxDate',
1960
+ mode: 'mode',
1961
+ type: 'type',
1962
+ monthOffset: 'monthOffset',
1963
+ message: 'message',
1964
+ class: 'class',
1965
+ inverted: 'inverted',
1966
+ variation: 'variation',
1967
+ position: 'position',
1968
+ month: 'month',
1969
+ year: 'year',
1970
+ hours: 'hours',
1971
+ days: 'days',
1406
1972
  },
1407
- invoke: function (query, passedArguments, context) {
1408
- var
1409
- object = instance,
1410
- maxDepth,
1411
- found,
1412
- response
1413
- ;
1414
- passedArguments = passedArguments || queryArguments;
1415
- context = context || element;
1416
- if (typeof query == 'string' && object !== undefined) {
1417
- query = query.split(/[\. ]/);
1418
- maxDepth = query.length - 1;
1419
- $.each(query, function (depth, value) {
1420
- var camelCaseValue = (depth != maxDepth)
1421
- ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
1422
- : query
1423
- ;
1424
- if ($.isPlainObject(object[camelCaseValue]) && (depth != maxDepth)) {
1425
- object = object[camelCaseValue];
1426
- }
1427
- else if (object[camelCaseValue] !== undefined) {
1428
- found = object[camelCaseValue];
1429
- return false;
1430
- }
1431
- else if ($.isPlainObject(object[value]) && (depth != maxDepth)) {
1432
- object = object[value];
1433
- }
1434
- else if (object[value] !== undefined) {
1435
- found = object[value];
1436
- return false;
1437
- }
1438
- else {
1439
- module.error(error.method, query);
1440
- return false;
1441
- }
1442
- });
1443
- }
1444
- if ($.isFunction(found)) {
1445
- response = found.apply(context, passedArguments);
1446
- }
1447
- else if (found !== undefined) {
1448
- response = found;
1449
- }
1450
- if (Array.isArray(returnedValue)) {
1451
- returnedValue.push(response);
1452
- }
1453
- else if (returnedValue !== undefined) {
1454
- returnedValue = [returnedValue, response];
1455
- }
1456
- else if (response !== undefined) {
1457
- returnedValue = response;
1458
- }
1459
- return found;
1460
- }
1461
- };
1462
-
1463
- if (methodInvoked) {
1464
- if (instance === undefined) {
1465
- module.initialize();
1466
- }
1467
- module.invoke(query);
1468
- }
1469
- else {
1470
- if (instance !== undefined) {
1471
- instance.invoke('destroy');
1472
- }
1473
- module.initialize();
1474
- }
1475
- })
1476
- ;
1477
- return (returnedValue !== undefined)
1478
- ? returnedValue
1479
- : this
1480
- ;
1481
- };
1482
-
1483
- $.fn.calendar.settings = {
1484
-
1485
- name : 'Calendar',
1486
- namespace : 'calendar',
1487
-
1488
- silent: false,
1489
- debug: false,
1490
- verbose: false,
1491
- performance: true,
1492
-
1493
- type : 'datetime', // picker type, can be 'datetime', 'date', 'time', 'month', or 'year'
1494
- firstDayOfWeek : 0, // day for first day column (0 = Sunday)
1495
- constantHeight : true, // add rows to shorter months to keep day calendar height consistent (6 rows)
1496
- today : false, // show a 'today/now' button at the bottom of the calendar
1497
- closable : true, // close the popup after selecting a date/time
1498
- monthFirst : true, // month before day when parsing date from text
1499
- touchReadonly : true, // set input to readonly on touch devices
1500
- inline : false, // create the calendar inline instead of inside a popup
1501
- on : null, // when to show the popup (defaults to 'focus' for input, 'click' for others)
1502
- initialDate : null, // date to display initially when no date is selected (null = now)
1503
- startMode : false, // display mode to start in, can be 'year', 'month', 'day', 'hour', 'minute' (false = 'day')
1504
- minDate : null, // minimum date/time that can be selected, dates/times before are disabled
1505
- maxDate : null, // maximum date/time that can be selected, dates/times after are disabled
1506
- disableYear : false, // disable year selection mode
1507
- disableMonth : false, // disable month selection mode
1508
- disableMinute : false, // disable minute selection mode
1509
- formatInput : true, // format the input text upon input blur and module creation
1510
- startCalendar : null, // jquery object or selector for another calendar that represents the start date of a date range
1511
- endCalendar : null, // jquery object or selector for another calendar that represents the end date of a date range
1512
- multiMonth : 1, // show multiple months when in 'day' mode
1513
- monthOffset : 0, // position current month by offset when multimonth > 1
1514
- minTimeGap : 5,
1515
- showWeekNumbers : false, // show Number of Week at the very first column of a dayView
1516
- disabledHours : [], // specific hour(s) which won't be selectable and contain additional information.
1517
- disabledDates : [], // specific day(s) which won't be selectable and contain additional information.
1518
- disabledDaysOfWeek : [], // day(s) which won't be selectable(s) (0 = Sunday)
1519
- enabledDates : [], // specific day(s) which will be selectable, all other days will be disabled
1520
- eventDates : [], // specific day(s) which will be shown in a different color and using tooltips
1521
- centuryBreak : 60, // starting short year until 99 where it will be assumed to belong to the last century
1522
- currentCentury : 2000, // century to be added to 2-digit years (00 to {centuryBreak}-1)
1523
- selectAdjacentDays : false, // The calendar can show dates from adjacent month. These adjacent month dates can also be made selectable.
1524
- // popup options ('popup', 'on', 'hoverable', and show/hide callbacks are overridden)
1525
- popupOptions: {
1526
- position: 'bottom left',
1527
- lastResort: 'bottom left',
1528
- prefer: 'opposite',
1529
- observeChanges: false,
1530
- hideOnScroll: false
1531
- },
1532
-
1533
- text: {
1534
- days: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
1535
- dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
1536
- dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
1537
- months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
1538
- monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
1539
- today: 'Today',
1540
- now: 'Now',
1541
- am: 'AM',
1542
- pm: 'PM',
1543
- weekNo: 'Week'
1544
- },
1545
-
1546
- formatter: {
1547
- yearHeader: function (date, settings) {
1548
- var decadeYear = Math.ceil(date.getFullYear() / 10) * 10;
1549
- return (decadeYear - 9) + ' - ' + (decadeYear + 2);
1550
- },
1551
- monthHeader: 'YYYY',
1552
- dayHeader: 'MMMM YYYY',
1553
- hourHeader: 'MMMM D, YYYY',
1554
- minuteHeader: 'MMMM D, YYYY',
1555
- dayColumnHeader: function (day, settings) {
1556
- return settings.text.days[day];
1557
- },
1558
- datetime: 'MMMM D, YYYY h:mm A',
1559
- date: 'MMMM D, YYYY',
1560
- time: 'h:mm A',
1561
- cellTime: 'h:mm A',
1562
- month: 'MMMM YYYY',
1563
- year: 'YYYY',
1564
- today: function (settings) {
1565
- return settings.type === 'date' ? settings.text.today : settings.text.now;
1566
- },
1567
- cell: function (cell, date, cellOptions) {
1568
- }
1569
- },
1570
-
1571
- parser: {
1572
- date: function (text, settings) {
1573
- if (text instanceof Date) {
1574
- return text;
1575
- }
1576
- if (!text) {
1577
- return null;
1578
- }
1579
- text = String(text).trim().replace(/([.:\/\-])\s+/g,'$1').replace(/\s+([.:\/-])/g,'$1').replace(/\s+/g,' ');
1580
- if (text.length === 0) {
1581
- return null;
1582
- }
1583
- if(text.match(/^[0-9]{4}[\/\-\.][0-9]{1,2}[\/\-\.][0-9]{1,2}$/)){
1584
- text = text.replace(/[\/\-\.]/g,'/') + ' 00:00:00';
1585
- }
1586
- // Reverse date and month in some cases
1587
- text = settings.monthFirst || !text.match(/^[0-9]{1,2}[\/\-\.]/) ? text : text.replace(/[\/\-\.]/g,'/').replace(/([0-9]+)\/([0-9]+)/,'$2/$1');
1588
- var textDate = new Date(text);
1589
- var numberOnly = text.match(/^[0-9]+$/) !== null;
1590
- if(!numberOnly && !isNaN(textDate.getDate())) {
1591
- return textDate;
1592
- }
1593
- text = text.toLowerCase();
1594
-
1595
- var i, j, k;
1596
- var minute = -1, hour = -1, day = -1, month = -1, year = -1;
1597
- var isAm = undefined;
1598
-
1599
- var isTimeOnly = settings.type === 'time';
1600
- var isDateOnly = settings.type.indexOf('time') < 0;
1601
-
1602
- var words = text.split(settings.regExp.dateWords), word;
1603
- var numbers = text.split(settings.regExp.dateNumbers), number;
1604
-
1605
- var parts;
1606
- var monthString;
1607
-
1608
- if (!isDateOnly) {
1609
- //am/pm
1610
- isAm = $.inArray(settings.text.am.toLowerCase(), words) >= 0 ? true :
1611
- $.inArray(settings.text.pm.toLowerCase(), words) >= 0 ? false : undefined;
1612
-
1613
- //time with ':'
1614
- for (i = 0; i < numbers.length; i++) {
1615
- number = numbers[i];
1616
- if (number.indexOf(':') >= 0) {
1617
- if (hour < 0 || minute < 0) {
1618
- parts = number.split(':');
1619
- for (k = 0; k < Math.min(2, parts.length); k++) {
1620
- j = parseInt(parts[k]);
1621
- if (isNaN(j)) {
1622
- j = 0;
1623
- }
1624
- if (k === 0) {
1625
- hour = j % 24;
1626
- } else {
1627
- minute = j % 60;
1628
- }
1629
- }
1630
- }
1631
- numbers.splice(i, 1);
1632
- }
1633
- }
1634
- }
1635
-
1636
- if (!isTimeOnly) {
1637
- //textual month
1638
- for (i = 0; i < words.length; i++) {
1639
- word = words[i];
1640
- if (word.length <= 0) {
1641
- continue;
1642
- }
1643
- for (j = 0; j < settings.text.months.length; j++) {
1644
- monthString = settings.text.months[j];
1645
- monthString = monthString.substring(0, word.length).toLowerCase();
1646
- if (monthString === word) {
1647
- month = j + 1;
1648
- break;
1649
- }
1650
- }
1651
- if (month >= 0) {
1652
- break;
1653
- }
1654
- }
1655
-
1656
- //year > settings.centuryBreak
1657
- for (i = 0; i < numbers.length; i++) {
1658
- j = parseInt(numbers[i]);
1659
- if (isNaN(j)) {
1660
- continue;
1661
- }
1662
- if (j >= settings.centuryBreak && i === numbers.length-1) {
1663
- if (j <= 99) {
1664
- j += settings.currentCentury - 100;
1665
- }
1666
- year = j;
1667
- numbers.splice(i, 1);
1668
- break;
1669
- }
1670
- }
1671
-
1672
- //numeric month
1673
- if (month < 0) {
1674
- for (i = 0; i < numbers.length; i++) {
1675
- k = i > 1 || settings.monthFirst ? i : i === 1 ? 0 : 1;
1676
- j = parseInt(numbers[k]);
1677
- if (isNaN(j)) {
1678
- continue;
1679
- }
1680
- if (1 <= j && j <= 12) {
1681
- month = j;
1682
- numbers.splice(k, 1);
1683
- break;
1684
- }
1685
- }
1686
- }
1687
-
1688
- //day
1689
- for (i = 0; i < numbers.length; i++) {
1690
- j = parseInt(numbers[i]);
1691
- if (isNaN(j)) {
1692
- continue;
1693
- }
1694
- if (1 <= j && j <= 31) {
1695
- day = j;
1696
- numbers.splice(i, 1);
1697
- break;
1698
- }
1699
- }
1700
-
1701
- //year <= settings.centuryBreak
1702
- if (year < 0) {
1703
- for (i = numbers.length - 1; i >= 0; i--) {
1704
- j = parseInt(numbers[i]);
1705
- if (isNaN(j)) {
1706
- continue;
1707
- }
1708
- if (j <= 99) {
1709
- j += settings.currentCentury;
1710
- }
1711
- year = j;
1712
- numbers.splice(i, 1);
1713
- break;
1714
- }
1715
- }
1716
- }
1717
-
1718
- if (!isDateOnly) {
1719
- //hour
1720
- if (hour < 0) {
1721
- for (i = 0; i < numbers.length; i++) {
1722
- j = parseInt(numbers[i]);
1723
- if (isNaN(j)) {
1724
- continue;
1725
- }
1726
- if (0 <= j && j <= 23) {
1727
- hour = j;
1728
- numbers.splice(i, 1);
1729
- break;
1730
- }
1731
- }
1732
- }
1733
-
1734
- //minute
1735
- if (minute < 0) {
1736
- for (i = 0; i < numbers.length; i++) {
1737
- j = parseInt(numbers[i]);
1738
- if (isNaN(j)) {
1739
- continue;
1740
- }
1741
- if (0 <= j && j <= 59) {
1742
- minute = j;
1743
- numbers.splice(i, 1);
1744
- break;
1745
- }
1746
- }
1747
- }
1748
- }
1749
-
1750
- if (minute < 0 && hour < 0 && day < 0 && month < 0 && year < 0) {
1751
- return null;
1752
- }
1753
-
1754
- if (minute < 0) {
1755
- minute = 0;
1756
- }
1757
- if (hour < 0) {
1758
- hour = 0;
1759
- }
1760
- if (day < 0) {
1761
- day = 1;
1762
- }
1763
- if (month < 0) {
1764
- month = 1;
1765
- }
1766
- if (year < 0) {
1767
- year = new Date().getFullYear();
1768
- }
1769
-
1770
- if (isAm !== undefined) {
1771
- if (isAm) {
1772
- if (hour === 12) {
1773
- hour = 0;
1774
- }
1775
- } else if (hour < 12) {
1776
- hour += 12;
1777
- }
1778
- }
1779
-
1780
- var date = new Date(year, month - 1, day, hour, minute);
1781
- if (date.getMonth() !== month - 1 || date.getFullYear() !== year) {
1782
- //month or year don't match up, switch to last day of the month
1783
- date = new Date(year, month, 0, hour, minute);
1784
- }
1785
- return isNaN(date.getTime()) ? null : date;
1786
- }
1787
- },
1788
-
1789
- // callback before date is changed, return false to cancel the change
1790
- onBeforeChange: function (date, text, mode) {
1791
- return true;
1792
- },
1793
-
1794
- // callback when date changes
1795
- onChange: function (date, text, mode) {
1796
- },
1797
-
1798
- // callback before show animation, return false to prevent show
1799
- onShow: function () {
1800
- },
1801
-
1802
- // callback after show animation
1803
- onVisible: function () {
1804
- },
1805
-
1806
- // callback before hide animation, return false to prevent hide
1807
- onHide: function () {
1808
- },
1809
-
1810
- // callback after hide animation
1811
- onHidden: function () {
1812
- },
1813
-
1814
- // callback before item is selected, return false to prevent selection
1815
- onSelect: function (date, mode) {
1816
- },
1817
-
1818
- // is the given date disabled?
1819
- isDisabled: function (date, mode) {
1820
- return false;
1821
- },
1822
-
1823
- selector: {
1824
- popup: '.ui.popup',
1825
- input: 'input',
1826
- activator: 'input',
1827
- append: '.inline.field,.inline.fields'
1828
- },
1829
-
1830
- regExp: {
1831
- dateWords: /[^A-Za-z\u00C0-\u024F]+/g,
1832
- dateNumbers: /[^\d:]+/g,
1833
- token: /d{1,4}|D{1,2}|M{1,4}|YY(?:YY)?|([Hhmsw])\1?|[SAaY]|"[^"]*"|'[^']*'/g
1834
- },
1835
-
1836
- error: {
1837
- popup: 'UI Popup, a required component is not included in this page',
1838
- method: 'The method you called is not defined.'
1839
- },
1840
-
1841
- className: {
1842
- calendar: 'calendar',
1843
- active: 'active',
1844
- popup: 'ui popup',
1845
- grid: 'ui equal width grid',
1846
- column: 'column',
1847
- table: 'ui celled center aligned unstackable table',
1848
- inverted: 'inverted',
1849
- prev: 'prev link',
1850
- next: 'next link',
1851
- prevIcon: 'chevron left icon',
1852
- nextIcon: 'chevron right icon',
1853
- link: 'link',
1854
- cell: 'link',
1855
- disabledCell: 'disabled',
1856
- weekCell: 'disabled',
1857
- adjacentCell: 'adjacent',
1858
- activeCell: 'active',
1859
- rangeCell: 'range',
1860
- focusCell: 'focus',
1861
- todayCell: 'today',
1862
- today: 'today link',
1863
- disabled: 'disabled'
1864
- },
1865
-
1866
- metadata: {
1867
- date: 'date',
1868
- focusDate: 'focusDate',
1869
- startDate: 'startDate',
1870
- endDate: 'endDate',
1871
- minDate: 'minDate',
1872
- maxDate: 'maxDate',
1873
- mode: 'mode',
1874
- type: 'type',
1875
- monthOffset: 'monthOffset',
1876
- message: 'message',
1877
- class: 'class',
1878
- inverted: 'inverted',
1879
- variation: 'variation',
1880
- position: 'position',
1881
- month: 'month',
1882
- year: 'year',
1883
- hours: 'hours',
1884
- days: 'days'
1885
- },
1886
-
1887
- eventClass: 'blue'
1888
- };
1889
1973
 
1974
+ eventClass: 'blue',
1975
+ };
1890
1976
  })(jQuery, window, document);