fomantic-ui 2.9.1-beta.17 → 2.9.1-beta.19

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