hydra-file-access 5.0.0.pre1

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 (169) hide show
  1. data/.gitignore +2 -0
  2. data/Rakefile +5 -0
  3. data/app/assets/images/hydra/powered_by_hydra.png +0 -0
  4. data/app/assets/images/hydra/search-button.png +0 -0
  5. data/app/assets/javascripts/date-picker/booking/index.html +368 -0
  6. data/app/assets/javascripts/date-picker/calendarHTML.txt +84 -0
  7. data/app/assets/javascripts/date-picker/css/datepicker.css +511 -0
  8. data/app/assets/javascripts/date-picker/css/demo.css +229 -0
  9. data/app/assets/javascripts/date-picker/index.html +798 -0
  10. data/app/assets/javascripts/date-picker/js/datepicker.js +2898 -0
  11. data/app/assets/javascripts/date-picker/js/datepicker.packed.js +1 -0
  12. data/app/assets/javascripts/date-picker/js/lang/ar.js +9 -0
  13. data/app/assets/javascripts/date-picker/js/lang/cs.js +9 -0
  14. data/app/assets/javascripts/date-picker/js/lang/da.js +10 -0
  15. data/app/assets/javascripts/date-picker/js/lang/de.js +10 -0
  16. data/app/assets/javascripts/date-picker/js/lang/en.js +9 -0
  17. data/app/assets/javascripts/date-picker/js/lang/eo.js +13 -0
  18. data/app/assets/javascripts/date-picker/js/lang/es.js +9 -0
  19. data/app/assets/javascripts/date-picker/js/lang/et.js +23 -0
  20. data/app/assets/javascripts/date-picker/js/lang/fi.js +7 -0
  21. data/app/assets/javascripts/date-picker/js/lang/fr.js +69 -0
  22. data/app/assets/javascripts/date-picker/js/lang/he.js +9 -0
  23. data/app/assets/javascripts/date-picker/js/lang/hu.js +9 -0
  24. data/app/assets/javascripts/date-picker/js/lang/id.js +9 -0
  25. data/app/assets/javascripts/date-picker/js/lang/it.js +11 -0
  26. data/app/assets/javascripts/date-picker/js/lang/kr.js +9 -0
  27. data/app/assets/javascripts/date-picker/js/lang/lt.js +8 -0
  28. data/app/assets/javascripts/date-picker/js/lang/lv.js +9 -0
  29. data/app/assets/javascripts/date-picker/js/lang/nl.js +9 -0
  30. data/app/assets/javascripts/date-picker/js/lang/no.js +9 -0
  31. data/app/assets/javascripts/date-picker/js/lang/pl.js +10 -0
  32. data/app/assets/javascripts/date-picker/js/lang/pt-br.js +11 -0
  33. data/app/assets/javascripts/date-picker/js/lang/pt.js +9 -0
  34. data/app/assets/javascripts/date-picker/js/lang/ru.js +11 -0
  35. data/app/assets/javascripts/date-picker/js/lang/se.js +9 -0
  36. data/app/assets/javascripts/date-picker/js/lang/si.js +9 -0
  37. data/app/assets/javascripts/date-picker/js/lang/tr.js +9 -0
  38. data/app/assets/javascripts/date-picker/language/index.html +240 -0
  39. data/app/assets/javascripts/date-picker/media/Thumbs.db +0 -0
  40. data/app/assets/javascripts/date-picker/media/backstripes.gif +0 -0
  41. data/app/assets/javascripts/date-picker/media/bg_header.jpg +0 -0
  42. data/app/assets/javascripts/date-picker/media/bullet1.gif +0 -0
  43. data/app/assets/javascripts/date-picker/media/bullet2.gif +0 -0
  44. data/app/assets/javascripts/date-picker/media/cal-grey.gif +0 -0
  45. data/app/assets/javascripts/date-picker/media/cal.gif +0 -0
  46. data/app/assets/javascripts/date-picker/media/gradient-e5e5e5-ffffff.gif +0 -0
  47. data/app/assets/javascripts/hydra/hydra-head.js +195 -0
  48. data/app/assets/javascripts/hydra/mediashelf.datepicker.js +39 -0
  49. data/app/assets/javascripts/hydra/mediashelf.placeholder.js +67 -0
  50. data/app/assets/javascripts/jquery.form.js +1076 -0
  51. data/app/assets/javascripts/jquery.ui.datepicker.js +1793 -0
  52. data/app/assets/javascripts/spin.min.js +2 -0
  53. data/app/assets/stylesheets/hydra/html_refactor.css +79 -0
  54. data/app/assets/stylesheets/hydra/hydrangea-split-button.css +18 -0
  55. data/app/assets/stylesheets/hydra/hydrangea.css +288 -0
  56. data/app/assets/stylesheets/hydra/ie-styles.css +149 -0
  57. data/app/assets/stylesheets/hydra/styles.css +946 -0
  58. data/app/assets/stylesheets/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  59. data/app/assets/stylesheets/redmond/images/ui-bg_flat_55_fbec88_40x100.png +0 -0
  60. data/app/assets/stylesheets/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png +0 -0
  61. data/app/assets/stylesheets/redmond/images/ui-bg_glass_85_dfeffc_1x400.png +0 -0
  62. data/app/assets/stylesheets/redmond/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  63. data/app/assets/stylesheets/redmond/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png +0 -0
  64. data/app/assets/stylesheets/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png +0 -0
  65. data/app/assets/stylesheets/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png +0 -0
  66. data/app/assets/stylesheets/redmond/images/ui-icons_217bc0_256x240.png +0 -0
  67. data/app/assets/stylesheets/redmond/images/ui-icons_2e83ff_256x240.png +0 -0
  68. data/app/assets/stylesheets/redmond/images/ui-icons_469bdd_256x240.png +0 -0
  69. data/app/assets/stylesheets/redmond/images/ui-icons_6da8d5_256x240.png +0 -0
  70. data/app/assets/stylesheets/redmond/images/ui-icons_cd0a0a_256x240.png +0 -0
  71. data/app/assets/stylesheets/redmond/images/ui-icons_d8e7f3_256x240.png +0 -0
  72. data/app/assets/stylesheets/redmond/images/ui-icons_f9bd01_256x240.png +0 -0
  73. data/app/assets/stylesheets/redmond/jquery-ui-1.8.5.custom.css +572 -0
  74. data/app/controllers/hydra/application_controller.rb +5 -0
  75. data/app/controllers/hydra/file_assets_controller.rb +3 -0
  76. data/app/helpers/application_helper.rb +3 -0
  77. data/app/helpers/hydra/application_helper_behavior.rb +8 -0
  78. data/app/helpers/hydra/hydra_helper_behavior.rb +70 -0
  79. data/app/helpers/hydra_helper.rb +4 -0
  80. data/app/models/file_asset.rb +5 -0
  81. data/app/models/uses_default_partials.rb +23 -0
  82. data/app/views/_add_assets_links.html.erb +14 -0
  83. data/app/views/_user_util_links.html.erb +24 -0
  84. data/app/views/generic_content_objects/_contributor_form.html.erb +11 -0
  85. data/app/views/generic_content_objects/_description_form.html.erb +7 -0
  86. data/app/views/generic_content_objects/_edit_description.html.erb +23 -0
  87. data/app/views/generic_content_objects/_new.html.erb +0 -0
  88. data/app/views/generic_content_objects/_show_description.html.erb +41 -0
  89. data/app/views/generic_contents/_edit.html.erb +10 -0
  90. data/app/views/generic_contents/_index.html.erb +21 -0
  91. data/app/views/generic_contents/_show.html.erb +6 -0
  92. data/app/views/generic_contents/_show_content.html.erb +7 -0
  93. data/app/views/generic_images/_edit.html.erb +36 -0
  94. data/app/views/generic_images/_index.html.erb +24 -0
  95. data/app/views/generic_images/_show.html.erb +13 -0
  96. data/app/views/generic_images/_show_all.html.erb +14 -0
  97. data/app/views/generic_images/_show_content.html.erb +7 -0
  98. data/app/views/hydra/file_assets/_asset_saved_flash.html.erb +2 -0
  99. data/app/views/hydra/file_assets/_deletable_result.html.erb +5 -0
  100. data/app/views/hydra/file_assets/_file_assets_form.html.erb +11 -0
  101. data/app/views/hydra/file_assets/_index.html.erb +29 -0
  102. data/app/views/hydra/file_assets/_new.html.erb +6 -0
  103. data/app/views/hydra/file_assets/_result.html.erb +11 -0
  104. data/app/views/hydra/file_assets/index.html.erb +5 -0
  105. data/app/views/hydra/permissions/_edit_person_permissions.html.erb +30 -0
  106. data/app/views/hydra/permissions/_index.html.erb +46 -0
  107. data/app/views/hydra/permissions/_new.html.erb +14 -0
  108. data/app/views/hydra/permissions/_permissions_form.html.erb +23 -0
  109. data/app/views/hydra/permissions/index.html.erb +1 -0
  110. data/app/views/hydra/permissions/new.html.erb +1 -0
  111. data/app/views/mods_assets/_additional_info_form.html.erb +44 -0
  112. data/app/views/mods_assets/_contributor_form.html.erb +14 -0
  113. data/app/views/mods_assets/_edit.html.erb +10 -0
  114. data/app/views/mods_assets/_edit_description.html.erb +73 -0
  115. data/app/views/mods_assets/_edit_journal.html.erb +57 -0
  116. data/app/views/mods_assets/_index.html.erb +1 -0
  117. data/app/views/mods_assets/_index_list.html.erb +37 -0
  118. data/app/views/mods_assets/_index_table.html.erb +7 -0
  119. data/app/views/mods_assets/_progress_box.html.erb +82 -0
  120. data/app/views/mods_assets/_publication_form.html.erb +13 -0
  121. data/app/views/mods_assets/_show.html.erb +39 -0
  122. data/app/views/mods_assets/_show_additional_info.html.erb +17 -0
  123. data/app/views/mods_assets/_show_contributors.html.erb +7 -0
  124. data/app/views/mods_assets/_show_description.html.erb +35 -0
  125. data/app/views/mods_assets/_show_file_assets.html.erb +22 -0
  126. data/app/views/mods_assets/_show_journal.html.erb +42 -0
  127. data/app/views/mods_assets/_show_permissions.html.erb +15 -0
  128. data/app/views/mods_assets/_show_publication.html.erb +8 -0
  129. data/app/views/shared/_delete_asset_confirmation.html.erb +17 -0
  130. data/config/jetty.yml +7 -0
  131. data/hydra-file-access.gemspec +39 -0
  132. data/lib/hydra-file-access.rb +15 -0
  133. data/lib/hydra/assets.rb +5 -0
  134. data/lib/hydra/assets_controller_helper.rb +122 -0
  135. data/lib/hydra/controller/assets_controller_behavior.rb +153 -0
  136. data/lib/hydra/controller/file_assets_behavior.rb +140 -0
  137. data/lib/hydra/file_access/engine.rb +12 -0
  138. data/lib/hydra/file_assets.rb +11 -0
  139. data/lib/hydra/submission_workflow.rb +139 -0
  140. data/lib/hydra/ui.rb +6 -0
  141. data/spec/.gitignore +1 -0
  142. data/spec/controllers/file_assets_controller_spec.rb +180 -0
  143. data/spec/fixtures/small_file.txt +1 -0
  144. data/spec/helpers/access_controls_evaluation_spec.rb +19 -0
  145. data/spec/helpers/assets_controller_helper_spec.rb +63 -0
  146. data/spec/helpers/file_assets_helper_spec.rb +116 -0
  147. data/spec/helpers/hydra_helper_spec.rb +21 -0
  148. data/spec/helpers/hydra_model_methods_spec.rb +88 -0
  149. data/spec/integration/file_asset_spec.rb +68 -0
  150. data/spec/lib/hydra_submission_workflow_spec.rb +141 -0
  151. data/spec/models/file_asset_spec.rb +25 -0
  152. data/spec/spec_helper.rb +27 -0
  153. data/spec/support/Gemfile +12 -0
  154. data/spec/support/app/models/generic_content.rb +26 -0
  155. data/spec/support/app/models/sample.rb +33 -0
  156. data/spec/support/app/models/solr_document.rb +5 -0
  157. data/spec/support/db/migrate/20111101221803_create_searches.rb +16 -0
  158. data/spec/support/lib/generators/test_app_generator.rb +39 -0
  159. data/spec/support/matchers/helper_matcher.rb +14 -0
  160. data/spec/support/matchers/solr_matchers.rb +60 -0
  161. data/spec/support/spec/factories/users.rb +11 -0
  162. data/spec/support/spec/fixtures/hydra_test_generic_content.foxml.xml +138 -0
  163. data/spec/support/spec/fixtures/hydrangea_fixture_file_asset1.foxml.xml +4946 -0
  164. data/spec/support/spec/fixtures/hydrangea_fixture_mods_article1.foxml.xml +234 -0
  165. data/spec/support/spec/fixtures/hydrangea_fixture_mods_article2.foxml.xml +177 -0
  166. data/spec/support/spec/fixtures/hydrangea_fixture_mods_article3.foxml.xml +170 -0
  167. data/spec/support/spec/fixtures/hydrangea_fixture_uploaded_svg1.foxml.xml +676 -0
  168. data/tasks/rspec.rake +55 -0
  169. metadata +516 -0
@@ -0,0 +1,2898 @@
1
+ /*
2
+ DatePicker v5.4 by frequency-decoder.com
3
+
4
+ Released under a creative commons Attribution-Share Alike 3.0 Unported license (http://creativecommons.org/licenses/by-sa/3.0/)
5
+
6
+ Please credit frequency-decoder in any derivative work - thanks.
7
+
8
+ You are free:
9
+
10
+ * to Share � to copy, distribute and transmit the work
11
+ * to Remix � to adapt the work
12
+
13
+ Under the following conditions:
14
+
15
+ * Attribution � You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).
16
+ * Share Alike � If you alter, transform, or build upon this work, you may distribute the resulting work only under the same, similar or a compatible license.
17
+ */
18
+
19
+ var datePickerController = (function datePickerController() {
20
+
21
+ var debug = false,
22
+ isOpera = Object.prototype.toString.call(window.opera) === "[object Opera]",
23
+ isMoz = /mozilla/.test( navigator.userAgent.toLowerCase() ) && !/(compatible|webkit)/.test( navigator.userAgent.toLowerCase() ),
24
+ languageInfo = parseUILanguage(),
25
+ datePickers = {},
26
+ uniqueId = 0,
27
+ weeksInYearCache = {},
28
+ localeImport = false,
29
+ nbsp = String.fromCharCode(160),
30
+ describedBy = "",
31
+ nodrag = false,
32
+ buttonTabIndex = true,
33
+ returnLocaleDate = false,
34
+ mouseWheel = true,
35
+ cellFormat = "d-sp-F-sp-Y",
36
+ titleFormat = "F-sp-d-cc-sp-Y",
37
+ formatParts = isOpera ? ["placeholder"] : ["placeholder", "sp-F-sp-Y"],
38
+ dividors = ["dt","sl","ds","cc","sp"],
39
+ dvParts = "dt|sl|ds|cc|sp",
40
+ dParts = "d|j",
41
+ mParts = "m|n|M|F",
42
+ yParts = "Y|y",
43
+ kbEvent = false,
44
+ bespokeTitles = {},
45
+ finalOpacity = 100,
46
+ validFmtRegExp = /^((sp|dt|sl|ds|cc)|([d|D|l|j|N|w|S|W|M|F|m|n|t|Y|y]))(-((sp|dt|sl|ds|cc)|([d|D|l|j|N|w|S|W|M|F|m|n|t|Y|y])))*$/,
47
+ rangeRegExp = /^((\d\d\d\d)(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01]))$/,
48
+ wcDateRegExp = /^(((\d\d\d\d)|(\*\*\*\*))((0[1-9]|1[012])|(\*\*))(0[1-9]|[12][0-9]|3[01]))$/;
49
+
50
+ (function() {
51
+ var scriptFiles = document.getElementsByTagName('script'),
52
+ scriptInner = String(scriptFiles[scriptFiles.length - 1].innerHTML).replace(/[\n\r\s\t]+/g, " ").replace(/^\s+/, "").replace(/\s+$/, ""),
53
+ json = parseJSON(scriptInner);
54
+
55
+ if(typeof json === "object" && !("err" in json)) {
56
+ affectJSON(json);
57
+ };
58
+
59
+ if(typeof(fdLocale) != "object") {
60
+ var head = document.getElementsByTagName("head")[0] || document.documentElement,
61
+ loc = scriptFiles[scriptFiles.length - 1].src.substr(0, scriptFiles[scriptFiles.length - 1].src.lastIndexOf("/")) + "/lang/",
62
+ script;
63
+
64
+ for(var i = 0; i < languageInfo.length; i++) {
65
+ script = document.createElement('script');
66
+ script.type = "text/javascript";
67
+ script.src = loc + languageInfo[i] + ".js";
68
+ script.charSet = "utf-8";
69
+
70
+ /*@cc_on
71
+ /*@if(@_win32)
72
+ var bases = document.getElementsByTagName('base');
73
+ if (bases.length && bases[0].childNodes.length) {
74
+ bases[0].appendChild(script);
75
+ } else {
76
+ document.getElementsByTagName('head')[0].appendChild(script);
77
+ };
78
+ bases = null;
79
+ @else @*/
80
+ head.appendChild(script);
81
+ /*@end
82
+ @*/
83
+ };
84
+ script = null;
85
+ } else {
86
+ returnLocaleDate = true;
87
+ };
88
+ })();
89
+
90
+ function parseUILanguage() {
91
+ var languageTag = document.getElementsByTagName('html')[0].getAttribute('lang') || document.getElementsByTagName('html')[0].getAttribute('xml:lang');
92
+
93
+ if(!languageTag) {
94
+ languageTag = "en";
95
+ } else {
96
+ languageTag = languageTag.toLowerCase();
97
+ };
98
+
99
+ return languageTag.search(/^([a-z]{2,3})-([a-z]{2})$/) != -1 ? [languageTag.match(/^([a-z]{2,3})-([a-z]{2})$/)[1], languageTag] : [languageTag];
100
+ };
101
+
102
+ function affectJSON(json) {
103
+ if(typeof json !== "object") { return; };
104
+ for(key in json) {
105
+ value = json[key];
106
+ switch(key.toLowerCase()) {
107
+ case "lang":
108
+ if(value.search(/^[a-z]{2,3}(-([a-z]{2}))?$/i) != -1) {
109
+ languageInfo = [value.toLowerCase()];
110
+ returnLocaleDate = true;
111
+ };
112
+ break;
113
+ case "nodrag":
114
+ nodrag = !!value;
115
+ break;
116
+ case "buttontabindex":
117
+ buttonTabIndex = !!value;
118
+ break;
119
+ case "mousewheel":
120
+ mouseWheel = !!value;
121
+ break;
122
+ case "cellformat":
123
+ if(typeof value == "string" && value.match(validFmtRegExp)) {
124
+ parseCellFormat(value);
125
+ };
126
+ break;
127
+ case "titleformat":
128
+ if(typeof value == "string" && value.match(validFmtRegExp)) {
129
+ titleFormat = value;
130
+ };
131
+ break;
132
+ case "describedby":
133
+ if(typeof value == "string") {
134
+ describedBy = value;
135
+ };
136
+ break;
137
+ case "finalopacity":
138
+ if(typeof value == 'number' && (+value > 20 && +value <= 100)) {
139
+ finalOpacity = parseInt(value, 10);
140
+ };
141
+ break;
142
+ case "bespoketitles":
143
+ bespokeTitles = {};
144
+ for(var dt in value) {
145
+ bespokeTitles[dt] = value[dt];
146
+ };
147
+ };
148
+ };
149
+ };
150
+
151
+ function parseCellFormat(value) {
152
+ if(isOpera) {
153
+ // Don't use hidden text for opera due to focus outline problems
154
+ formatParts = ["placeholder"];
155
+ cellFormat = "j-sp-F-sp-Y";
156
+ return;
157
+ };
158
+
159
+ // I'm sure this could be done with a regExp and a split in one line... seriously...
160
+ var parts = value.split("-"),
161
+ fullParts = [],
162
+ tmpParts = [],
163
+ part;
164
+
165
+ for(var pt = 0; pt < parts.length; pt++) {
166
+ part = parts[pt];
167
+ if(part == "j" || part == "d") {
168
+ if(tmpParts.length) {
169
+ fullParts.push(tmpParts.join("-"));
170
+ tmpParts = [];
171
+ };
172
+ fullParts.push("placeholder");
173
+ } else {
174
+ tmpParts.push(part);
175
+ };
176
+ };
177
+
178
+ if(tmpParts.length) {
179
+ fullParts.push(tmpParts.join("-"));
180
+ };
181
+
182
+ if(!fullParts.length || fullParts.length > 3) {
183
+ formatParts = ["placeholder", "sp-F-sp-Y"];
184
+ cellFormat = "j-sp-F-sp-Y";
185
+ return;
186
+ };
187
+
188
+ formatParts = fullParts;
189
+ cellFormat = value;
190
+ };
191
+
192
+ function pad(value, length) {
193
+ length = length || 2;
194
+ return "0000".substr(0,length - Math.min(String(value).length, length)) + value;
195
+ };
196
+
197
+ function addEvent(obj, type, fn) {
198
+ try {
199
+ if( obj.attachEvent ) {
200
+ obj["e"+type+fn] = fn;
201
+ obj[type+fn] = function(){obj["e"+type+fn]( window.event );};
202
+ obj.attachEvent( "on"+type, obj[type+fn] );
203
+ } else {
204
+ obj.addEventListener( type, fn, true );
205
+ };
206
+ } catch(err) {}
207
+ };
208
+
209
+ function removeEvent(obj, type, fn) {
210
+ try {
211
+ if( obj.detachEvent ) {
212
+ obj.detachEvent( "on"+type, obj[type+fn] );
213
+ obj[type+fn] = null;
214
+ } else {
215
+ obj.removeEventListener( type, fn, true );
216
+ };
217
+ } catch(err) {};
218
+ };
219
+
220
+ function stopEvent(e) {
221
+ e = e || document.parentWindow.event;
222
+ if(e.stopPropagation) {
223
+ e.stopPropagation();
224
+ e.preventDefault();
225
+ };
226
+ /*@cc_on
227
+ @if(@_win32)
228
+ e.cancelBubble = true;
229
+ e.returnValue = false;
230
+ @end
231
+ @*/
232
+ return false;
233
+ };
234
+
235
+ function parseJSON(str) {
236
+ // Check we have a String
237
+ if(typeof str !== 'string' || str == "") { return {}; };
238
+ try {
239
+ // Does a JSON (native or not) Object exist
240
+ if(typeof JSON === "object" && JSON.parse) {
241
+ return window.JSON.parse(str);
242
+ // Genious code taken from: http://kentbrewster.com/badges/
243
+ } else if(/lang|buttontabindex|mousewheel|cellformat|titleformat|nodrag|describedby/.test(str.toLowerCase())) {
244
+ var f = Function(['var document,top,self,window,parent,Number,Date,Object,Function,',
245
+ 'Array,String,Math,RegExp,Image,ActiveXObject;',
246
+ 'return (' , str.replace(/<\!--.+-->/gim,'').replace(/\bfunction\b/g,'function�') , ');'].join(''));
247
+ return f();
248
+ };
249
+ } catch (e) { };
250
+
251
+ if(debug) {
252
+ throw "Could not parse the JSON object";
253
+ };
254
+
255
+ return {"err":"Could not parse the JSON object"};
256
+ };
257
+
258
+ function setARIARole(element, role) {
259
+ if(element && element.tagName) {
260
+ element.setAttribute("role", role);
261
+ };
262
+ };
263
+
264
+ function setARIAProperty(element, property, value) {
265
+ if(element && element.tagName) {
266
+ element.setAttribute("aria-" + property, value);
267
+ };
268
+ };
269
+
270
+ // The datePicker object itself
271
+ function datePicker(options) {
272
+ this.dateSet = null;
273
+ this.timerSet = false;
274
+ this.visible = false;
275
+ this.fadeTimer = null;
276
+ this.timer = null;
277
+ this.yearInc = 0;
278
+ this.monthInc = 0;
279
+ this.dayInc = 0;
280
+ this.mx = 0;
281
+ this.my = 0;
282
+ this.x = 0;
283
+ this.y = 0;
284
+ this.created = false;
285
+ this.disabled = false;
286
+ this.opacity = 0;
287
+ this.opacityTo = 99;
288
+ this.inUpdate = false;
289
+ this.kbEventsAdded = false;
290
+ this.fullCreate = false;
291
+ this.selectedTD = null;
292
+ this.cursorTD = null;
293
+ this.cursorDate = options.cursorDate ? options.cursorDate : "",
294
+ this.date = options.cursorDate ? new Date(+options.cursorDate.substr(0,4), +options.cursorDate.substr(4,2) - 1, +options.cursorDate.substr(6,2)) : new Date();
295
+ this.defaults = {};
296
+ this.dynDisabledDates = {};
297
+ this.firstDayOfWeek = localeImport.firstDayOfWeek;
298
+ this.interval = new Date();
299
+ this.clickActivated = false;
300
+ this.noFocus = true;
301
+ this.kbEvent = false;
302
+ this.disabledDates = false;
303
+ this.enabledDates = false;
304
+ this.delayedUpdate = false;
305
+ this.bespokeTitles = {};
306
+
307
+ for(var thing in options) {
308
+ if(thing.search(/callbacks|formElements|formatMasks/) != -1) continue;
309
+ this[thing] = options[thing];
310
+ };
311
+
312
+ /*@cc_on
313
+ @if(@_win32)
314
+ this.iePopUp = null;
315
+ this.isIE7 = false;
316
+ @end
317
+ @*/
318
+
319
+ /*@cc_on
320
+ @if(@_jscript_version <= 5.7)
321
+ this.isIE7 = document.documentElement && typeof document.documentElement.style.maxHeight != "undefined";
322
+ @end
323
+ @*/
324
+
325
+ for(var i = 0, prop; prop = ["callbacks", "formElements", "formatMasks"][i]; i++) {
326
+ this[prop] = {};
327
+ for(var thing in options[prop]) {
328
+ this[prop][thing] = options[prop][thing];
329
+ };
330
+ };
331
+
332
+ // Adjust time to stop daylight savings madness on windows
333
+ this.date.setHours(5);
334
+
335
+ this.changeHandler = function() {
336
+ o.setDateFromInput();
337
+ o.callback("dateset", o.createCbArgObj());
338
+ };
339
+ this.createCbArgObj = function() {
340
+ return this.dateSet ? {"id":this.id,"date":this.dateSet,"dd":pad(this.date.getDate()),"mm":pad(this.date.getMonth() + 1),"yyyy":this.date.getFullYear()} : {"id":this.id,"date":null,"dd":null,"mm":null,"yyyy":null};
341
+ };
342
+ this.getScrollOffsets = function() {
343
+ if(typeof(window.pageYOffset) == 'number') {
344
+ //Netscape compliant
345
+ return [window.pageXOffset, window.pageYOffset];
346
+ } else if(document.body && (document.body.scrollLeft || document.body.scrollTop)) {
347
+ //DOM compliant
348
+ return [document.body.scrollLeft, document.body.scrollTop];
349
+ } else if(document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
350
+ //IE6 standards compliant mode
351
+ return [document.documentElement.scrollLeft, document.documentElement.scrollTop];
352
+ };
353
+ return [0,0];
354
+ };
355
+ this.reposition = function() {
356
+ if(!o.created || o.staticPos) { return; };
357
+
358
+ o.div.style.visibility = "hidden";
359
+ o.div.style.left = o.div.style.top = "0px";
360
+ o.div.style.display = "block";
361
+
362
+ var osh = o.div.offsetHeight,
363
+ osw = o.div.offsetWidth,
364
+ elem = document.getElementById('fd-but-' + o.id),
365
+ pos = o.truePosition(elem),
366
+ trueBody = (document.compatMode && document.compatMode!="BackCompat") ? document.documentElement : document.body,
367
+ sOffsets = o.getScrollOffsets(),
368
+ scrollTop = sOffsets[1],
369
+ scrollLeft = sOffsets[0],
370
+ fitsBottom = parseInt(trueBody.clientHeight+scrollTop) > parseInt(osh+pos[1]+elem.offsetHeight+2),
371
+ fitsTop = parseInt(pos[1]-(osh+elem.offsetHeight+2)) > parseInt(scrollTop);
372
+
373
+ o.div.style.visibility = "visible";
374
+
375
+ o.div.style.left = Number(parseInt(trueBody.clientWidth+scrollLeft) < parseInt(osw+pos[0]) ? Math.abs(parseInt((trueBody.clientWidth+scrollLeft) - osw)) : pos[0]) + "px";
376
+ o.div.style.top = (fitsBottom || !fitsTop) ? Math.abs(parseInt(pos[1] + elem.offsetHeight + 2)) + "px" : Math.abs(parseInt(pos[1] - (osh + 2))) + "px";
377
+ /*@cc_on
378
+ @if(@_jscript_version <= 5.7)
379
+ if(o.isIE7) return;
380
+ o.iePopUp.style.top = o.div.style.top;
381
+ o.iePopUp.style.left = o.div.style.left;
382
+ o.iePopUp.style.width = osw + "px";
383
+ o.iePopUp.style.height = (osh - 2) + "px";
384
+ @end
385
+ @*/
386
+ };
387
+ this.removeOldFocus = function() {
388
+ var td = document.getElementById(o.id + "-date-picker-hover");
389
+ if(td) {
390
+ try {
391
+ td.setAttribute(!/*@cc_on!@*/false ? "tabIndex" : "tabindex", "-1");
392
+ td.tabIndex = -1;
393
+ td.className = td.className.replace(/date-picker-hover/, "");
394
+ td.id = "";
395
+ td.onblur = null;
396
+ td.onfocus = null;
397
+ } catch(err) {};
398
+ };
399
+ };
400
+ this.addAccessibleDate = function() {
401
+ var td = document.getElementById(o.id + "-date-picker-hover");
402
+
403
+ if(td && !(td.getElementsByTagName("span").length)) {
404
+ var ymd = td.className.match(/cd-([\d]{4})([\d]{2})([\d]{2})/),
405
+ noS = (td.className.search(/date-picker-unused|out-of-range|day-disabled|no-selection|not-selectable/) != -1),
406
+ spn = document.createElement('span'),
407
+ spnC;
408
+
409
+ spn.className = "fd-screen-reader";;
410
+
411
+ while(td.firstChild) td.removeChild(td.firstChild);
412
+
413
+ if(noS) {
414
+ spnC = spn.cloneNode(false);
415
+ spnC.appendChild(document.createTextNode(getTitleTranslation(13)));
416
+ td.appendChild(spnC);
417
+ };
418
+
419
+ for(var pt = 0, part; part = formatParts[pt]; pt++) {
420
+ if(part == "placeholder") {
421
+ td.appendChild(document.createTextNode(+ymd[3]));
422
+ } else {
423
+ spnC = spn.cloneNode(false);
424
+ spnC.appendChild(document.createTextNode(printFormattedDate(new Date(ymd[1], +ymd[2]-1, ymd[3]), part, true)));
425
+ td.appendChild(spnC);
426
+ };
427
+ };
428
+ };
429
+ };
430
+ this.setNewFocus = function() {
431
+ var td = document.getElementById(o.id + "-date-picker-hover");
432
+ if(td) {
433
+ try {
434
+ td.setAttribute(!/*@cc_on!@*/false ? "tabIndex" : "tabindex", "0");
435
+ td.tabIndex = 0;
436
+
437
+ td.className = td.className.replace(/date-picker-hover/, "") + " date-picker-hover";
438
+ if(!this.clickActivated) {
439
+ td.onblur = o.onblur;
440
+ td.onfocus = o.onfocus;
441
+ };
442
+
443
+ if(!isOpera && !this.clickActivated) o.addAccessibleDate();
444
+
445
+ if(!this.noFocus && !this.clickActivated) {
446
+ setTimeout(function() { try { td.focus(); } catch(err) {}; }, 0);
447
+ };
448
+ } catch(err) { };
449
+ };
450
+ };
451
+ this.setCursorDate = function(yyyymmdd) {
452
+ if(String(yyyymmdd).search(/^([0-9]{8})$/) != -1) {
453
+ this.date = new Date(+yyyymmdd.substr(0,4), +yyyymmdd.substr(4,2) - 1, +yyyymmdd.substr(6,2));
454
+ this.cursorDate = yyyymmdd;
455
+
456
+ if(this.staticPos) {
457
+ this.updateTable();
458
+ };
459
+ };
460
+ };
461
+ this.updateTable = function(noCallback) {
462
+ if(!o || o.inUpdate || !o.created) return;
463
+
464
+ o.inUpdate = true;
465
+ o.removeOldFocus();
466
+
467
+ if(o.timerSet && !o.delayedUpdate) {
468
+ if(o.monthInc) {
469
+ var n = o.date.getDate(),
470
+ d = new Date(o.date);
471
+
472
+ d.setDate(2);
473
+ d.setMonth(d.getMonth() + o.monthInc * 1);
474
+ d.setDate(Math.min(n, daysInMonth(d.getMonth(),d.getFullYear())));
475
+
476
+ o.date = new Date(d);
477
+ } else {
478
+ o.date.setDate(Math.min(o.date.getDate()+o.dayInc, daysInMonth(o.date.getMonth()+o.monthInc,o.date.getFullYear()+o.yearInc)));
479
+ o.date.setMonth(o.date.getMonth() + o.monthInc);
480
+ o.date.setFullYear(o.date.getFullYear() + o.yearInc);
481
+ };
482
+ };
483
+
484
+ o.outOfRange();
485
+ if(!o.noToday) { o.disableTodayButton(); };
486
+ o.showHideButtons(o.date);
487
+
488
+ var cd = o.date.getDate(),
489
+ cm = o.date.getMonth(),
490
+ cy = o.date.getFullYear(),
491
+ cursorDate = (String(cy) + pad(cm+1) + pad(cd)),
492
+ tmpDate = new Date(cy, cm, 1);
493
+
494
+ tmpDate.setHours(5);
495
+
496
+ var dt, cName, td, i, currentDate, cellAdded, col, currentStub, abbr, bespokeRenderClass, spnC, dateSetD,
497
+ weekDayC = ( tmpDate.getDay() + 6 ) % 7,
498
+ firstColIndex = (((weekDayC - o.firstDayOfWeek) + 7 ) % 7) - 1,
499
+ dpm = daysInMonth(cm, cy),
500
+ today = new Date(),
501
+ stub = String(tmpDate.getFullYear()) + pad(tmpDate.getMonth()+1),
502
+ cellAdded = [4,4,4,4,4,4],
503
+ lm = new Date(cy, cm-1, 1),
504
+ nm = new Date(cy, cm+1, 1),
505
+ daySub = daysInMonth(lm.getMonth(), lm.getFullYear()),
506
+ stubN = String(nm.getFullYear()) + pad(nm.getMonth()+1),
507
+ stubP = String(lm.getFullYear()) + pad(lm.getMonth()+1),
508
+ weekDayN = (nm.getDay() + 6) % 7,
509
+ weekDayP = (lm.getDay() + 6) % 7,
510
+ today = today.getFullYear() + pad(today.getMonth()+1) + pad(today.getDate()),
511
+ spn = document.createElement('span');
512
+
513
+ o.firstDateShown = !o.constrainSelection && o.fillGrid && (0 - firstColIndex < 1) ? String(stubP) + (daySub + (0 - firstColIndex)) : stub + "01";
514
+ o.lastDateShown = !o.constrainSelection && o.fillGrid ? stubN + pad(41 - firstColIndex - dpm) : stub + String(dpm);
515
+ o.currentYYYYMM = stub;
516
+
517
+ bespokeRenderClass = o.callback("redraw", {id:o.id, dd:pad(cd), mm:pad(cm+1), yyyy:cy, firstDateDisplayed:o.firstDateShown, lastDateDisplayed:o.lastDateShown}) || {};
518
+ dts = o.getDates(cy, cm+1);
519
+
520
+ o.checkSelectedDate();
521
+
522
+ dateSetD = (o.dateSet != null) ? o.dateSet.getFullYear() + pad(o.dateSet.getMonth()+1) + pad(o.dateSet.getDate()) : false;
523
+ spn.className = "fd-screen-reader";
524
+
525
+ if(this.selectedTD != null) {
526
+ setARIAProperty(this.selectedTD, "selected", false);
527
+ this.selectedTD = null;
528
+ };
529
+
530
+ for(var curr = 0; curr < 42; curr++) {
531
+ row = Math.floor(curr / 7);
532
+ td = o.tds[curr];
533
+ spnC = spn.cloneNode(false);
534
+
535
+ while(td.firstChild) td.removeChild(td.firstChild);
536
+
537
+ if((curr > firstColIndex && curr <= (firstColIndex + dpm)) || o.fillGrid) {
538
+ currentStub = stub;
539
+ weekDay = weekDayC;
540
+ dt = curr - firstColIndex;
541
+ cName = [];
542
+ selectable = true;
543
+
544
+ if(dt < 1) {
545
+ dt = daySub + dt;
546
+ currentStub = stubP;
547
+ weekDay = weekDayP;
548
+ selectable = !o.constrainSelection;
549
+ cName.push("month-out");
550
+ } else if(dt > dpm) {
551
+ dt -= dpm;
552
+ currentStub = stubN;
553
+ weekDay = weekDayN;
554
+ selectable = !o.constrainSelection;
555
+ cName.push("month-out");
556
+ };
557
+
558
+ weekDay = ( weekDay + dt + 6 ) % 7;
559
+
560
+ cName.push("day-" + localeDefaults.dayAbbrs[weekDay].toLowerCase());
561
+
562
+ currentDate = currentStub + String(dt < 10 ? "0" : "") + dt;
563
+
564
+ if(o.rangeLow && +currentDate < +o.rangeLow || o.rangeHigh && +currentDate > +o.rangeHigh) {
565
+ td.className = "out-of-range";
566
+ td.title = "";
567
+ td.appendChild(document.createTextNode(dt));
568
+ if(o.showWeeks) { cellAdded[row] = Math.min(cellAdded[row], 2); };
569
+ } else {
570
+ if(selectable) {
571
+ td.title = titleFormat ? printFormattedDate(new Date(+String(currentStub).substr(0,4), +String(currentStub).substr(4, 2) - 1, +dt), titleFormat, true) : "";
572
+ cName.push("cd-" + currentDate + " yyyymm-" + currentStub + " mmdd-" + currentStub.substr(4,2) + pad(dt));
573
+ } else {
574
+ td.title = titleFormat ? getTitleTranslation(13) + " " + printFormattedDate(new Date(+String(currentStub).substr(0,4), +String(currentStub).substr(4, 2) - 1, +dt), titleFormat, true) : "";
575
+ cName.push("yyyymm-" + currentStub + " mmdd-" + currentStub.substr(4,2) + pad(dt) + " not-selectable");
576
+ };
577
+
578
+ if(currentDate == today) { cName.push("date-picker-today"); };
579
+
580
+ if(dateSetD == currentDate) {
581
+ cName.push("date-picker-selected-date");
582
+ setARIAProperty(td, "selected", "true");
583
+ this.selectedTD = td;
584
+ };
585
+
586
+ if(o.disabledDays[weekDay] || dts[currentDate] == 0) { cName.push("day-disabled"); if(titleFormat && selectable) { td.title = getTitleTranslation(13) + " " + td.title; }; }
587
+
588
+ if(currentDate in bespokeRenderClass) { cName.push(bespokeRenderClass[currentDate]); }
589
+
590
+ if(o.highlightDays[weekDay]) { cName.push("date-picker-highlight"); };
591
+
592
+ if(cursorDate == currentDate) {
593
+ td.id = o.id + "-date-picker-hover";
594
+ };
595
+
596
+ td.appendChild(document.createTextNode(dt));
597
+ td.className = cName.join(" ");
598
+
599
+ if(o.showWeeks) {
600
+ cellAdded[row] = Math.min(cName[0] == "month-out" ? 3 : 1, cellAdded[row]);
601
+ };
602
+ };
603
+ } else {
604
+ td.className = "date-picker-unused";
605
+ td.appendChild(document.createTextNode(nbsp));
606
+ td.title = "";
607
+ };
608
+
609
+ if(o.showWeeks && curr - (row * 7) == 6) {
610
+ while(o.wkThs[row].firstChild) o.wkThs[row].removeChild(o.wkThs[row].firstChild);
611
+ o.wkThs[row].appendChild(document.createTextNode(cellAdded[row] == 4 && !o.fillGrid ? nbsp : getWeekNumber(cy, cm, curr - firstColIndex - 6)));
612
+ o.wkThs[row].className = "date-picker-week-header" + (["",""," out-of-range"," month-out",""][cellAdded[row]]);
613
+ };
614
+ };
615
+
616
+ var span = o.titleBar.getElementsByTagName("span");
617
+ while(span[0].firstChild) span[0].removeChild(span[0].firstChild);
618
+ while(span[1].firstChild) span[1].removeChild(span[1].firstChild);
619
+ span[0].appendChild(document.createTextNode(getMonthTranslation(cm, false) + nbsp));
620
+ span[1].appendChild(document.createTextNode(cy));
621
+
622
+ if(o.timerSet) {
623
+ o.timerInc = 50 + Math.round(((o.timerInc - 50) / 1.8));
624
+ o.timer = window.setTimeout(o.updateTable, o.timerInc);
625
+ };
626
+
627
+ o.inUpdate = o.delayedUpdate = false;
628
+ o.setNewFocus();
629
+ };
630
+
631
+ this.destroy = function() {
632
+
633
+ if(document.getElementById("fd-but-" + this.id)) {
634
+ document.getElementById("fd-but-" + this.id).parentNode.removeChild(document.getElementById("fd-but-" + this.id));
635
+ };
636
+
637
+ if(!this.created) { return; };
638
+
639
+ // Cleanup for Internet Explorer
640
+ removeEvent(this.table, "mousedown", o.onmousedown);
641
+ removeEvent(this.table, "mouseover", o.onmouseover);
642
+ removeEvent(this.table, "mouseout", o.onmouseout);
643
+ removeEvent(document, "mousedown", o.onmousedown);
644
+ removeEvent(document, "mouseup", o.clearTimer);
645
+
646
+ if (window.addEventListener && !window.devicePixelRatio) {
647
+ try {
648
+ window.removeEventListener('DOMMouseScroll', this.onmousewheel, false);
649
+ } catch(err) {};
650
+ } else {
651
+ removeEvent(document, "mousewheel", this.onmousewheel);
652
+ removeEvent(window, "mousewheel", this.onmousewheel);
653
+ };
654
+ o.removeOnFocusEvents();
655
+ clearTimeout(o.fadeTimer);
656
+ clearTimeout(o.timer);
657
+
658
+ /*@cc_on
659
+ @if(@_jscript_version <= 5.7)
660
+ if(!o.staticPos && !o.isIE7) {
661
+ try {
662
+ o.iePopUp.parentNode.removeChild(o.iePopUp);
663
+ o.iePopUp = null;
664
+ } catch(err) {};
665
+ };
666
+ @end
667
+ @*/
668
+
669
+ if(this.div && this.div.parentNode) {
670
+ this.div.parentNode.removeChild(this.div);
671
+ };
672
+
673
+ o = null;
674
+ };
675
+ this.resizeInlineDiv = function() {
676
+ o.div.style.width = o.table.offsetWidth + "px";
677
+ o.div.style.height = o.table.offsetHeight + "px";
678
+ };
679
+ this.create = function() {
680
+
681
+ if(document.getElementById("fd-" + this.id)) return;
682
+
683
+ this.noFocus = true;
684
+
685
+ function createTH(details) {
686
+ var th = document.createElement('th');
687
+ if(details.thClassName) th.className = details.thClassName;
688
+ if(details.colspan) {
689
+ /*@cc_on
690
+ /*@if (@_win32)
691
+ th.setAttribute('colSpan',details.colspan);
692
+ @else @*/
693
+ th.setAttribute('colspan',details.colspan);
694
+ /*@end
695
+ @*/
696
+ };
697
+ /*@cc_on
698
+ /*@if (@_win32)
699
+ th.unselectable = "on";
700
+ /*@end@*/
701
+ return th;
702
+ };
703
+ function createThAndButton(tr, obj) {
704
+ for(var i = 0, details; details = obj[i]; i++) {
705
+ var th = createTH(details);
706
+ tr.appendChild(th);
707
+ var but = document.createElement('span');
708
+ but.className = details.className;
709
+ but.id = o.id + details.id;
710
+ but.appendChild(document.createTextNode(details.text || o.nbsp));
711
+ but.title = details.title || "";
712
+ /*@cc_on
713
+ /*@if(@_win32)
714
+ th.unselectable = but.unselectable = "on";
715
+ /*@end@*/
716
+ th.appendChild(but);
717
+ };
718
+ };
719
+
720
+ this.div = document.createElement('div');
721
+ this.div.id = "fd-" + this.id;
722
+ this.div.className = "datePicker";
723
+
724
+ // Attempt to hide the div from screen readers during content creation
725
+ this.div.style.visibility = "hidden";
726
+ this.div.style.display = "none";
727
+
728
+ // Set the ARIA describedby property if the required block available
729
+ if(this.describedBy && document.getElementById(this.describedBy)) {
730
+ setARIAProperty(this.div, "describedby", this.describedBy);
731
+ };
732
+
733
+ // Set the ARIA labelled property if the required label available
734
+ if(this.labelledBy) {
735
+ setARIAProperty(this.div, "labelledby", this.labelledBy.id);
736
+ };
737
+
738
+ var tr, row, col, tableHead, tableBody, tableFoot;
739
+
740
+ this.table = document.createElement('table');
741
+ this.table.className = "datePickerTable";
742
+ this.table.onmouseover = this.onmouseover;
743
+ this.table.onmouseout = this.onmouseout;
744
+ this.table.onclick = this.onclick;
745
+
746
+ if(this.staticPos) {
747
+ this.table.onmousedown = this.onmousedown;
748
+ };
749
+
750
+ this.div.appendChild(this.table);
751
+
752
+ var dragEnabledCN = !this.dragDisabled ? " drag-enabled" : "";
753
+
754
+ if(!this.staticPos) {
755
+ this.div.style.visibility = "hidden";
756
+ this.div.className += dragEnabledCN;
757
+ document.getElementsByTagName('body')[0].appendChild(this.div);
758
+
759
+ /*@cc_on
760
+ @if(@_jscript_version <= 5.7)
761
+
762
+ if(!this.isIE7) {
763
+ this.iePopUp = document.createElement('iframe');
764
+ this.iePopUp.src = "javascript:'<html></html>';";
765
+ this.iePopUp.setAttribute('className','iehack');
766
+ // Remove iFrame from tabIndex
767
+ this.iePopUp.setAttribute("tabIndex", -1);
768
+ // Hide it from ARIA aware technologies
769
+ setARIARole(this.iePopUp, "presentation");
770
+ setARIAProperty(this.iePopUp, "hidden", "true");
771
+ this.iePopUp.scrolling = "no";
772
+ this.iePopUp.frameBorder = "0";
773
+ this.iePopUp.name = this.iePopUp.id = this.id + "-iePopUpHack";
774
+ document.body.appendChild(this.iePopUp);
775
+ };
776
+
777
+ @end
778
+ @*/
779
+
780
+ // Aria "hidden" property for non active popup datepickers
781
+ setARIAProperty(this.div, "hidden", "true");
782
+ } else {
783
+ elem = document.getElementById(this.positioned ? this.positioned : this.id);
784
+ if(!elem) {
785
+ this.div = null;
786
+ if(debug) throw this.positioned ? "Could not locate a datePickers associated parent element with an id:" + this.positioned : "Could not locate a datePickers associated input with an id:" + this.id;
787
+ return;
788
+ };
789
+
790
+ this.div.className += " static-datepicker";
791
+
792
+ if(this.positioned) {
793
+ elem.appendChild(this.div);
794
+ } else {
795
+ elem.parentNode.insertBefore(this.div, elem.nextSibling);
796
+ };
797
+
798
+ if(this.hideInput) {
799
+ for(var elemID in this.formElements) {
800
+ elem = document.getElementById(elemID);
801
+ if(elem) {
802
+ elem.className += " fd-hidden-input";
803
+ };
804
+ };
805
+ };
806
+
807
+ setTimeout(this.resizeInlineDiv, 300);
808
+ };
809
+
810
+ // ARIA Grid role
811
+ setARIARole(this.div, "grid");
812
+
813
+ if(this.statusFormat) {
814
+ tableFoot = document.createElement('tfoot');
815
+ this.table.appendChild(tableFoot);
816
+ tr = document.createElement('tr');
817
+ tr.className = "date-picker-tfoot";
818
+ tableFoot.appendChild(tr);
819
+ this.statusBar = createTH({thClassName:"date-picker-statusbar" + dragEnabledCN, colspan:this.showWeeks ? 8 : 7});
820
+ tr.appendChild(this.statusBar);
821
+ this.updateStatus();
822
+ };
823
+
824
+ tableHead = document.createElement('thead');
825
+ this.table.appendChild(tableHead);
826
+
827
+ tr = document.createElement('tr');
828
+ setARIARole(tr, "presentation");
829
+
830
+ tableHead.appendChild(tr);
831
+
832
+ // Title Bar
833
+ this.titleBar = createTH({thClassName:"date-picker-title" + dragEnabledCN, colspan:this.showWeeks ? 8 : 7});
834
+
835
+ tr.appendChild(this.titleBar);
836
+ tr = null;
837
+
838
+ var span = document.createElement('span');
839
+ span.appendChild(document.createTextNode(nbsp));
840
+ span.className = "month-display" + dragEnabledCN;
841
+ this.titleBar.appendChild(span);
842
+
843
+ span = document.createElement('span');
844
+ span.appendChild(document.createTextNode(nbsp));
845
+ span.className = "year-display" + dragEnabledCN;
846
+ this.titleBar.appendChild(span);
847
+
848
+ span = null;
849
+
850
+ tr = document.createElement('tr');
851
+ setARIARole(tr, "presentation");
852
+ tableHead.appendChild(tr);
853
+
854
+ createThAndButton(tr, [
855
+ {className:"prev-but prev-year", id:"-prev-year-but", text:"\u00AB", title:getTitleTranslation(2) },
856
+ {className:"prev-but prev-month", id:"-prev-month-but", text:"\u2039", title:getTitleTranslation(0) },
857
+ {colspan:this.showWeeks ? 4 : 3, className:"today-but", id:"-today-but", text:getTitleTranslation(4)},
858
+ {className:"next-but next-month", id:"-next-month-but", text:"\u203A", title:getTitleTranslation(1)},
859
+ {className:"next-but next-year", id:"-next-year-but", text:"\u00BB", title:getTitleTranslation(3) }
860
+ ]);
861
+
862
+ tableBody = document.createElement('tbody');
863
+ this.table.appendChild(tableBody);
864
+
865
+ var colspanTotal = this.showWeeks ? 8 : 7,
866
+ colOffset = this.showWeeks ? 0 : -1,
867
+ but, abbr;
868
+
869
+ for(var rows = 0; rows < 7; rows++) {
870
+ row = document.createElement('tr');
871
+
872
+ if(rows != 0) {
873
+ // ARIA Grid role
874
+ setARIARole(row, "row");
875
+ tableBody.appendChild(row);
876
+ } else {
877
+ tableHead.appendChild(row);
878
+ };
879
+
880
+ for(var cols = 0; cols < colspanTotal; cols++) {
881
+ if(rows === 0 || (this.showWeeks && cols === 0)) {
882
+ col = document.createElement('th');
883
+ } else {
884
+ col = document.createElement('td');
885
+ setARIAProperty(col, "describedby", this.id + "-col-" + cols + (this.showWeeks ? " " + this.id + "-row-" + rows : ""));
886
+ setARIAProperty(col, "selected", "false");
887
+ };
888
+
889
+ /*@cc_on@*/
890
+ /*@if(@_win32)
891
+ col.unselectable = "on";
892
+ /*@end@*/
893
+
894
+ row.appendChild(col);
895
+ if((this.showWeeks && cols > 0 && rows > 0) || (!this.showWeeks && rows > 0)) {
896
+ setARIARole(col, "gridcell");
897
+ } else {
898
+ if(rows === 0 && cols > colOffset) {
899
+ col.className = "date-picker-day-header";
900
+ col.scope = "col";
901
+ setARIARole(col, "columnheader");
902
+ col.id = this.id + "-col-" + cols;
903
+ } else {
904
+ col.className = "date-picker-week-header";
905
+ col.scope = "row";
906
+ setARIARole(col, "rowheader");
907
+ col.id = this.id + "-row-" + rows;
908
+ };
909
+ };
910
+ };
911
+ };
912
+
913
+ col = row = null;
914
+
915
+ this.ths = this.table.getElementsByTagName('thead')[0].getElementsByTagName('tr')[2].getElementsByTagName('th');
916
+ for (var y = 0; y < colspanTotal; y++) {
917
+ if(y == 0 && this.showWeeks) {
918
+ this.ths[y].appendChild(document.createTextNode(getTitleTranslation(6)));
919
+ this.ths[y].title = getTitleTranslation(8);
920
+ continue;
921
+ };
922
+
923
+ if(y > (this.showWeeks ? 0 : -1)) {
924
+ but = document.createElement("span");
925
+ but.className = "fd-day-header";
926
+ /*@cc_on@*/
927
+ /*@if(@_win32)
928
+ but.unselectable = "on";
929
+ /*@end@*/
930
+ this.ths[y].appendChild(but);
931
+ };
932
+ };
933
+
934
+ but = null;
935
+
936
+ this.trs = this.table.getElementsByTagName('tbody')[0].getElementsByTagName('tr');
937
+ this.tds = this.table.getElementsByTagName('tbody')[0].getElementsByTagName('td');
938
+ this.butPrevYear = document.getElementById(this.id + "-prev-year-but");
939
+ this.butPrevMonth = document.getElementById(this.id + "-prev-month-but");
940
+ this.butToday = document.getElementById(this.id + "-today-but");
941
+ this.butNextYear = document.getElementById(this.id + "-next-year-but");
942
+ this.butNextMonth = document.getElementById(this.id + "-next-month-but");
943
+
944
+ if(this.noToday) {
945
+ this.butToday.style.display = "none";
946
+ };
947
+
948
+ if(this.showWeeks) {
949
+ this.wkThs = this.table.getElementsByTagName('tbody')[0].getElementsByTagName('th');
950
+ this.div.className += " weeks-displayed";
951
+ };
952
+
953
+ tableBody = tableHead = tr = createThAndButton = createTH = null;
954
+
955
+ if(this.rangeLow && this.rangeHigh && (this.rangeHigh - this.rangeLow < 7)) { this.equaliseDates(); };
956
+
957
+ this.updateTableHeaders();
958
+ this.created = true;
959
+ this.updateTable();
960
+
961
+ if(this.staticPos) {
962
+ this.visible = true;
963
+ this.opacity = this.opacityTo = this.finalOpacity;
964
+ this.div.style.visibility = "visible";
965
+ this.div.style.display = "block";
966
+ this.noFocus = true;
967
+ this.fade();
968
+ } else {
969
+ this.reposition();
970
+ this.div.style.visibility = "visible";
971
+ this.fade();
972
+ this.noFocus = true;
973
+ };
974
+
975
+ this.callback("domcreate", { "id":this.id });
976
+ };
977
+ this.fade = function() {
978
+ window.clearTimeout(o.fadeTimer);
979
+ o.fadeTimer = null;
980
+ var diff = Math.round(o.opacity + ((o.opacityTo - o.opacity) / 4));
981
+ o.setOpacity(diff);
982
+ if(Math.abs(o.opacityTo - diff) > 3 && !o.noFadeEffect) {
983
+ o.fadeTimer = window.setTimeout(o.fade, 50);
984
+ } else {
985
+ o.setOpacity(o.opacityTo);
986
+ if(o.opacityTo == 0) {
987
+ o.div.style.display = "none";
988
+ o.div.style.visibility = "hidden";
989
+ setARIAProperty(o.div, "hidden", "true");
990
+ o.visible = false;
991
+ } else {
992
+ setARIAProperty(o.div, "hidden", "false");
993
+ o.visible = true;
994
+ };
995
+ };
996
+ };
997
+ this.trackDrag = function(e) {
998
+ e = e || window.event;
999
+ var diffx = (e.pageX?e.pageX:e.clientX?e.clientX:e.x) - o.mx;
1000
+ var diffy = (e.pageY?e.pageY:e.clientY?e.clientY:e.Y) - o.my;
1001
+ o.div.style.left = Math.round(o.x + diffx) > 0 ? Math.round(o.x + diffx) + 'px' : "0px";
1002
+ o.div.style.top = Math.round(o.y + diffy) > 0 ? Math.round(o.y + diffy) + 'px' : "0px";
1003
+ /*@cc_on
1004
+ @if(@_jscript_version <= 5.7)
1005
+ if(o.staticPos || o.isIE7) return;
1006
+ o.iePopUp.style.top = o.div.style.top;
1007
+ o.iePopUp.style.left = o.div.style.left;
1008
+ @end
1009
+ @*/
1010
+ };
1011
+ this.stopDrag = function(e) {
1012
+ var b = document.getElementsByTagName("body")[0];
1013
+ b.className = b.className.replace(/fd-drag-active/g, "");
1014
+ removeEvent(document,'mousemove',o.trackDrag, false);
1015
+ removeEvent(document,'mouseup',o.stopDrag, false);
1016
+ o.div.style.zIndex = 9999;
1017
+ };
1018
+ this.onmousedown = function(e) {
1019
+ e = e || document.parentWindow.event;
1020
+ var el = e.target != null ? e.target : e.srcElement,
1021
+ origEl = el,
1022
+ hideDP = true,
1023
+ reg = new RegExp("^fd-(but-)?" + o.id + "$");
1024
+
1025
+ o.mouseDownElem = null;
1026
+
1027
+ // Are we within the wrapper div or the button
1028
+ while(el) {
1029
+ if(el.id && el.id.length && el.id.search(reg) != -1) {
1030
+ hideDP = false;
1031
+ break;
1032
+ };
1033
+ try { el = el.parentNode; } catch(err) { break; };
1034
+ };
1035
+
1036
+ // If not, then ...
1037
+ if(hideDP) {
1038
+ hideAll();
1039
+ return true;
1040
+ };
1041
+
1042
+ if((o.div.className + origEl.className).search('fd-disabled') != -1) { return true; };
1043
+
1044
+ // We check the mousedown events on the buttons
1045
+ if(origEl.id.search(new RegExp("^" + o.id + "(-prev-year-but|-prev-month-but|-next-month-but|-next-year-but)$")) != -1) {
1046
+
1047
+ o.mouseDownElem = origEl;
1048
+
1049
+ addEvent(document, "mouseup", o.clearTimer);
1050
+ addEvent(origEl, "mouseout", o.clearTimer);
1051
+
1052
+ var incs = {
1053
+ "-prev-year-but":[0,-1,0],
1054
+ "-prev-month-but":[0,0,-1],
1055
+ "-next-year-but":[0,1,0],
1056
+ "-next-month-but":[0,0,1]
1057
+ },
1058
+ check = origEl.id.replace(o.id, ""),
1059
+ dateYYYYMM = Number(o.date.getFullYear() + pad(o.date.getMonth()+1));
1060
+
1061
+ o.timerInc = 800;
1062
+ o.timerSet = true;
1063
+ o.dayInc = incs[check][0];
1064
+ o.yearInc = incs[check][1];
1065
+ o.monthInc = incs[check][2];
1066
+ o.accellerator = 1;
1067
+
1068
+ if(!(o.currentYYYYMM == dateYYYYMM)) {
1069
+ if((o.currentYYYYMM < dateYYYYMM && (o.yearInc == -1 || o.monthInc == -1)) || (o.currentYYYYMM > dateYYYYMM && (o.yearInc == 1 || o.monthInc == 1))) {
1070
+ o.delayedUpdate = false;
1071
+ o.timerInc = 1200;
1072
+ } else {
1073
+ o.delayedUpdate = true;
1074
+ o.timerInc = 800;
1075
+ };
1076
+ };
1077
+
1078
+ o.updateTable();
1079
+
1080
+ return stopEvent(e);
1081
+
1082
+ } else if(el.className.search("drag-enabled") != -1) {
1083
+ o.mx = e.pageX ? e.pageX : e.clientX ? e.clientX : e.x;
1084
+ o.my = e.pageY ? e.pageY : e.clientY ? e.clientY : e.Y;
1085
+ o.x = parseInt(o.div.style.left);
1086
+ o.y = parseInt(o.div.style.top);
1087
+ addEvent(document,'mousemove',o.trackDrag, false);
1088
+ addEvent(document,'mouseup',o.stopDrag, false);
1089
+ var b = document.getElementsByTagName("body")[0];
1090
+ b.className = b.className.replace(/fd-drag-active/g, "") + " fd-drag-active";
1091
+ o.div.style.zIndex = 10000;
1092
+
1093
+ return stopEvent(e);
1094
+ };
1095
+ return true;
1096
+ };
1097
+ this.onclick = function(e) {
1098
+ if(o.opacity != o.opacityTo || o.disabled) return stopEvent(e);
1099
+
1100
+ e = e || document.parentWindow.event;
1101
+ var el = e.target != null ? e.target : e.srcElement;
1102
+
1103
+ while(el.parentNode) {
1104
+ // Are we within a valid i.e. clickable TD node
1105
+ if(el.tagName && el.tagName.toLowerCase() == "td") {
1106
+
1107
+ if(el.className.search(/cd-([0-9]{8})/) == -1 || el.className.search(/date-picker-unused|out-of-range|day-disabled|no-selection|not-selectable/) != -1) return stopEvent(e);
1108
+
1109
+ var cellDate = el.className.match(/cd-([0-9]{8})/)[1];
1110
+ o.date = new Date(cellDate.substr(0,4),cellDate.substr(4,2)-1,cellDate.substr(6,2));
1111
+ o.dateSet = new Date(o.date);
1112
+ o.noFocus = true;
1113
+ o.callback("dateset", { "id":o.id, "date":o.dateSet, "dd":o.dateSet.getDate(), "mm":o.dateSet.getMonth() + 1, "yyyy":o.dateSet.getFullYear() });
1114
+ o.returnFormattedDate();
1115
+ o.hide();
1116
+
1117
+ o.stopTimer();
1118
+
1119
+ break;
1120
+ // Today button pressed
1121
+ } else if(el.id && el.id == o.id + "-today-but") {
1122
+ o.date = new Date();
1123
+ o.updateTable();
1124
+ o.stopTimer();
1125
+ break;
1126
+ // Day headers clicked, change the first day of the week
1127
+ } else if(el.className.search(/date-picker-day-header/) != -1) {
1128
+ var cnt = o.showWeeks ? -1 : 0,
1129
+ elem = el;
1130
+
1131
+ while(elem.previousSibling) {
1132
+ elem = elem.previousSibling;
1133
+ if(elem.tagName && elem.tagName.toLowerCase() == "th") cnt++;
1134
+ };
1135
+
1136
+ o.firstDayOfWeek = (o.firstDayOfWeek + cnt) % 7;
1137
+ o.updateTableHeaders();
1138
+ break;
1139
+ };
1140
+ try { el = el.parentNode; } catch(err) { break; };
1141
+ };
1142
+
1143
+ return stopEvent(e);
1144
+ };
1145
+
1146
+ this.show = function(autoFocus) {
1147
+ if(this.staticPos) { return; };
1148
+
1149
+ var elem, elemID;
1150
+ for(elemID in this.formElements) {
1151
+ elem = document.getElementById(this.id);
1152
+ if(!elem || (elem && elem.disabled)) { return; };
1153
+ };
1154
+
1155
+ this.noFocus = true;
1156
+
1157
+ // If the datepicker doesn't exist in the dom
1158
+ if(!this.created || !document.getElementById('fd-' + this.id)) {
1159
+ this.created = false;
1160
+ this.fullCreate = false;
1161
+ this.create();
1162
+ this.fullCreate = true;
1163
+ } else {
1164
+ this.setDateFromInput();
1165
+ this.reposition();
1166
+ };
1167
+
1168
+ this.noFocus = !!!autoFocus;
1169
+
1170
+ if(this.noFocus) {
1171
+ this.clickActivated = true;
1172
+ addEvent(document, "mousedown", this.onmousedown);
1173
+ if(mouseWheel) {
1174
+ if (window.addEventListener && !window.devicePixelRatio) window.addEventListener('DOMMouseScroll', this.onmousewheel, false);
1175
+ else {
1176
+ addEvent(document, "mousewheel", this.onmousewheel);
1177
+ addEvent(window, "mousewheel", this.onmousewheel);
1178
+ };
1179
+ };
1180
+ } else {
1181
+ this.clickActivated = false;
1182
+ };
1183
+
1184
+ this.opacityTo = this.finalOpacity;
1185
+ this.div.style.display = "block";
1186
+
1187
+ /*@cc_on
1188
+ @if(@_jscript_version <= 5.7)
1189
+ if(!o.isIE7) {
1190
+ this.iePopUp.style.width = this.div.offsetWidth + "px";
1191
+ this.iePopUp.style.height = this.div.offsetHeight + "px";
1192
+ this.iePopUp.style.display = "block";
1193
+ };
1194
+ @end
1195
+ @*/
1196
+
1197
+ this.setNewFocus();
1198
+ this.fade();
1199
+ var butt = document.getElementById('fd-but-' + this.id);
1200
+ if(butt) { butt.className = butt.className.replace("dp-button-active", "") + " dp-button-active"; };
1201
+ };
1202
+ this.hide = function() {
1203
+ if(!this.visible || !this.created || !document.getElementById('fd-' + this.id)) return;
1204
+
1205
+ this.kbEvent = false;
1206
+
1207
+ o.div.className = o.div.className.replace("datepicker-focus", "");
1208
+
1209
+ this.stopTimer();
1210
+ this.removeOnFocusEvents();
1211
+ this.clickActivated = false;
1212
+
1213
+ // Update status bar
1214
+ if(this.statusBar) { this.updateStatus(getTitleTranslation(9)); };
1215
+
1216
+ this.noFocus = true;
1217
+ this.setNewFocus();
1218
+
1219
+ if(this.staticPos) {
1220
+ return;
1221
+ };
1222
+
1223
+ var butt = document.getElementById('fd-but-' + this.id);
1224
+ if(butt) butt.className = butt.className.replace("dp-button-active", "");
1225
+
1226
+ removeEvent(document, "mousedown", this.onmousedown);
1227
+
1228
+ if(mouseWheel) {
1229
+ if (window.addEventListener && !window.devicePixelRatio) {
1230
+ try { window.removeEventListener('DOMMouseScroll', this.onmousewheel, false);} catch(err) {};
1231
+ } else {
1232
+ removeEvent(document, "mousewheel", this.onmousewheel);
1233
+ removeEvent(window, "mousewheel", this.onmousewheel);
1234
+ };
1235
+ };
1236
+
1237
+ /*@cc_on
1238
+ @if(@_jscript_version <= 5.7)
1239
+ if(!this.isIE7) { this.iePopUp.style.display = "none"; };
1240
+ @end
1241
+ @*/
1242
+
1243
+ this.opacityTo = 0;
1244
+ this.fade();
1245
+ };
1246
+ this.onblur = function(e) {
1247
+ o.hide();
1248
+ };
1249
+ this.onfocus = function(e) {
1250
+ o.noFocus = false;
1251
+ o.div.className = o.div.className.replace("datepicker-focus", "") + " datepicker-focus";
1252
+ o.addOnFocusEvents();
1253
+ };
1254
+ this.onmousewheel = function(e) {
1255
+ e = e || document.parentWindow.event;
1256
+ var delta = 0;
1257
+
1258
+ if (e.wheelDelta) {
1259
+ delta = e.wheelDelta/120;
1260
+ if (isOpera && window.opera.version() < 9.2) delta = -delta;
1261
+ } else if(e.detail) {
1262
+ delta = -e.detail/3;
1263
+ };
1264
+
1265
+ var n = o.date.getDate(),
1266
+ d = new Date(o.date),
1267
+ inc = delta > 0 ? 1 : -1;
1268
+
1269
+ d.setDate(2);
1270
+ d.setMonth(d.getMonth() + inc * 1);
1271
+ d.setDate(Math.min(n, daysInMonth(d.getMonth(),d.getFullYear())));
1272
+
1273
+ if(o.outOfRange(d)) { return stopEvent(e); };
1274
+
1275
+ o.date = new Date(d);
1276
+
1277
+ o.updateTable();
1278
+
1279
+ if(o.statusBar) { o.updateStatus(printFormattedDate(o.date, o.statusFormat, true)); };
1280
+
1281
+ return stopEvent(e);
1282
+ };
1283
+ this.onkeydown = function (e) {
1284
+ o.stopTimer();
1285
+ if(!o.visible) return false;
1286
+
1287
+ e = e || document.parentWindow.event;
1288
+ var kc = e.keyCode ? e.keyCode : e.charCode;
1289
+
1290
+ if( kc == 13 ) {
1291
+ // RETURN/ENTER: close & select the date
1292
+ var td = document.getElementById(o.id + "-date-picker-hover");
1293
+ if(!td || td.className.search(/cd-([0-9]{8})/) == -1 || td.className.search(/no-selection|out-of-range|day-disabled/) != -1) {
1294
+ return stopEvent(e);
1295
+ };
1296
+ o.dateSet = new Date(o.date);
1297
+ o.callback("dateset", o.createCbArgObj());
1298
+ o.returnFormattedDate();
1299
+ o.hide();
1300
+ return stopEvent(e);
1301
+ } else if(kc == 27) {
1302
+ // ESC: close, no date selection
1303
+ if(!o.staticPos) {
1304
+ o.hide();
1305
+ return stopEvent(e);
1306
+ };
1307
+ return true;
1308
+ } else if(kc == 32 || kc == 0) {
1309
+ // SPACE: goto today's date
1310
+ o.date = new Date();
1311
+ o.updateTable();
1312
+ return stopEvent(e);
1313
+ } else if(kc == 9) {
1314
+ // TAB: close, no date selection & focus on btton - popup only
1315
+ if(!o.staticPos) {
1316
+ return stopEvent(e);
1317
+ };
1318
+ return true;
1319
+ };
1320
+
1321
+ // Internet Explorer fires the keydown event faster than the JavaScript engine can
1322
+ // update the interface. The following attempts to fix this.
1323
+
1324
+ /*@cc_on
1325
+ @if(@_win32)
1326
+ if(new Date().getTime() - o.interval.getTime() < 50) { return stopEvent(e); };
1327
+ o.interval = new Date();
1328
+ @end
1329
+ @*/
1330
+
1331
+ if(isMoz) {
1332
+ if(new Date().getTime() - o.interval.getTime() < 50) { return stopEvent(e); };
1333
+ o.interval = new Date();
1334
+ };
1335
+
1336
+ if ((kc > 49 && kc < 56) || (kc > 97 && kc < 104)) {
1337
+ if(kc > 96) kc -= (96-48);
1338
+ kc -= 49;
1339
+ o.firstDayOfWeek = (o.firstDayOfWeek + kc) % 7;
1340
+ o.updateTableHeaders();
1341
+ return stopEvent(e);
1342
+ };
1343
+
1344
+ if ( kc < 33 || kc > 40 ) return true;
1345
+
1346
+ var d = new Date(o.date), tmp, cursorYYYYMM = o.date.getFullYear() + pad(o.date.getMonth()+1);
1347
+
1348
+ // HOME: Set date to first day of current month
1349
+ if(kc == 36) {
1350
+ d.setDate(1);
1351
+ // END: Set date to last day of current month
1352
+ } else if(kc == 35) {
1353
+ d.setDate(daysInMonth(d.getMonth(),d.getFullYear()));
1354
+ // PAGE UP & DOWN
1355
+ } else if ( kc == 33 || kc == 34) {
1356
+ var inc = (kc == 34) ? 1 : -1;
1357
+
1358
+ // CTRL + PAGE UP/DOWN: Moves to the same date in the previous/next year
1359
+ if(e.ctrlKey) {
1360
+ d.setFullYear(d.getFullYear() + inc * 1);
1361
+ // PAGE UP/DOWN: Moves to the same date in the previous/next month
1362
+ } else {
1363
+ var n = o.date.getDate();
1364
+
1365
+ d.setDate(2);
1366
+ d.setMonth(d.getMonth() + inc * 1);
1367
+ d.setDate(Math.min(n, daysInMonth(d.getMonth(),d.getFullYear())));
1368
+ };
1369
+ // LEFT ARROW
1370
+ } else if ( kc == 37 ) {
1371
+ d = new Date(o.date.getFullYear(), o.date.getMonth(), o.date.getDate() - 1);
1372
+ // RIGHT ARROW
1373
+ } else if ( kc == 39 || kc == 34) {
1374
+ d = new Date(o.date.getFullYear(), o.date.getMonth(), o.date.getDate() + 1 );
1375
+ // UP ARROW
1376
+ } else if ( kc == 38 ) {
1377
+ d = new Date(o.date.getFullYear(), o.date.getMonth(), o.date.getDate() - 7);
1378
+ // DOWN ARROW
1379
+ } else if ( kc == 40 ) {
1380
+ d = new Date(o.date.getFullYear(), o.date.getMonth(), o.date.getDate() + 7);
1381
+ };
1382
+
1383
+ if(o.outOfRange(d)) { return stopEvent(e); };
1384
+ o.date = d;
1385
+
1386
+ if(o.statusBar) {
1387
+ o.updateStatus(o.getBespokeTitle(o.date.getFullYear(),o.date.getMonth() + 1,o.date.getDate()) || printFormattedDate(o.date, o.statusFormat, true));
1388
+ };
1389
+
1390
+ var t = String(o.date.getFullYear()) + pad(o.date.getMonth()+1) + pad(o.date.getDate());
1391
+
1392
+ if(e.ctrlKey || (kc == 33 || kc == 34) || t < o.firstDateShown || t > o.lastDateShown) {
1393
+ o.updateTable();
1394
+ /*@cc_on
1395
+ @if(@_win32)
1396
+ o.interval = new Date();
1397
+ @end
1398
+ @*/
1399
+ } else {
1400
+ if(!o.noToday) { o.disableTodayButton(); };
1401
+ o.removeOldFocus();
1402
+
1403
+ for(var i = 0, td; td = o.tds[i]; i++) {
1404
+ if(td.className.search("cd-" + t) == -1) {
1405
+ continue;
1406
+ };
1407
+ o.showHideButtons(o.date);
1408
+ td.id = o.id + "-date-picker-hover";
1409
+ o.setNewFocus();
1410
+ break;
1411
+ };
1412
+ };
1413
+
1414
+ return stopEvent(e);
1415
+ };
1416
+ this.onmouseout = function(e) {
1417
+ e = e || document.parentWindow.event;
1418
+ var p = e.toElement || e.relatedTarget;
1419
+ while (p && p != this) try { p = p.parentNode } catch(e) { p = this; };
1420
+ if (p == this) return false;
1421
+ if(o.currentTR) {
1422
+ o.currentTR.className = "";
1423
+ o.currentTR = null;
1424
+ };
1425
+
1426
+ if(o.statusBar) {
1427
+ o.updateStatus(o.getBespokeTitle(o.date.getFullYear(),o.date.getMonth() + 1,o.date.getDate()) || printFormattedDate(o.date, o.statusFormat, true));
1428
+ };
1429
+ };
1430
+ this.onmouseover = function(e) {
1431
+ e = e || document.parentWindow.event;
1432
+ var el = e.target != null ? e.target : e.srcElement;
1433
+ while(el.nodeType != 1) { el = el.parentNode; };
1434
+
1435
+ if(!el || ! el.tagName) { return; };
1436
+
1437
+ var statusText = getTitleTranslation(9);
1438
+ switch (el.tagName.toLowerCase()) {
1439
+ case "td":
1440
+ if(el.className.search(/date-picker-unused|out-of-range/) != -1) {
1441
+ statusText = getTitleTranslation(9);
1442
+ } if(el.className.search(/cd-([0-9]{8})/) != -1) {
1443
+ o.stopTimer();
1444
+ var cellDate = el.className.match(/cd-([0-9]{8})/)[1];
1445
+
1446
+ o.removeOldFocus();
1447
+ el.id = o.id+"-date-picker-hover";
1448
+ o.setNewFocus();
1449
+
1450
+ o.date = new Date(+cellDate.substr(0,4),+cellDate.substr(4,2)-1,+cellDate.substr(6,2));
1451
+ if(!o.noToday) { o.disableTodayButton(); };
1452
+
1453
+ statusText = o.getBespokeTitle(+cellDate.substr(0,4),+cellDate.substr(4,2),+cellDate.substr(6,2)) || printFormattedDate(o.date, o.statusFormat, true);
1454
+ };
1455
+ break;
1456
+ case "th":
1457
+ if(!o.statusBar) { break; };
1458
+ if(el.className.search(/drag-enabled/) != -1) {
1459
+ statusText = getTitleTranslation(10);
1460
+ } else if(el.className.search(/date-picker-week-header/) != -1) {
1461
+ var txt = el.firstChild ? el.firstChild.nodeValue : "";
1462
+ statusText = txt.search(/^(\d+)$/) != -1 ? getTitleTranslation(7, [txt, txt < 3 && o.date.getMonth() == 11 ? getWeeksInYear(o.date.getFullYear()) + 1 : getWeeksInYear(o.date.getFullYear())]) : getTitleTranslation(9);
1463
+ };
1464
+ break;
1465
+ case "span":
1466
+ if(!o.statusBar) { break; };
1467
+ if(el.className.search(/drag-enabled/) != -1) {
1468
+ statusText = getTitleTranslation(10);
1469
+ } else if(el.className.search(/day-([0-6])/) != -1) {
1470
+ var day = el.className.match(/day-([0-6])/)[1];
1471
+ statusText = getTitleTranslation(11, [getDayTranslation(day, false)]);
1472
+ } else if(el.className.search(/prev-year/) != -1) {
1473
+ statusText = getTitleTranslation(2);
1474
+ } else if(el.className.search(/prev-month/) != -1) {
1475
+ statusText = getTitleTranslation(0);
1476
+ } else if(el.className.search(/next-year/) != -1) {
1477
+ statusText = getTitleTranslation(3);
1478
+ } else if(el.className.search(/next-month/) != -1) {
1479
+ statusText = getTitleTranslation(1);
1480
+ } else if(el.className.search(/today-but/) != -1 && el.className.search(/disabled/) == -1) {
1481
+ statusText = getTitleTranslation(12);
1482
+ };
1483
+ break;
1484
+ default:
1485
+ statusText = "";
1486
+ };
1487
+ while(el.parentNode) {
1488
+ el = el.parentNode;
1489
+ if(el.nodeType == 1 && el.tagName.toLowerCase() == "tr") {
1490
+ if(o.currentTR) {
1491
+ if(el == o.currentTR) break;
1492
+ o.currentTR.className = "";
1493
+ };
1494
+ el.className = "dp-row-highlight";
1495
+ o.currentTR = el;
1496
+ break;
1497
+ };
1498
+ };
1499
+ if(o.statusBar && statusText) { o.updateStatus(statusText); };
1500
+ };
1501
+ this.clearTimer = function() {
1502
+ o.stopTimer();
1503
+ o.timerInc = 800;
1504
+ o.yearInc = 0;
1505
+ o.monthInc = 0;
1506
+ o.dayInc = 0;
1507
+
1508
+ removeEvent(document, "mouseup", o.clearTimer);
1509
+ if(o.mouseDownElem != null) {
1510
+ removeEvent(o.mouseDownElem, "mouseout", o.clearTimer);
1511
+ };
1512
+ o.mouseDownElem = null;
1513
+ };
1514
+
1515
+ var o = this;
1516
+
1517
+ this.setDateFromInput();
1518
+
1519
+ if(this.staticPos) {
1520
+ this.create();
1521
+ } else {
1522
+ this.createButton();
1523
+ };
1524
+
1525
+ (function() {
1526
+ var elemID, elem;
1527
+
1528
+ for(elemID in o.formElements) {
1529
+ elem = document.getElementById(elemID);
1530
+ if(elem && elem.tagName && elem.tagName.search(/select|input/i) != -1) {
1531
+ addEvent(elem, "change", o.changeHandler);
1532
+ };
1533
+
1534
+ if(!elem || elem.disabled == true) {
1535
+ o.disableDatePicker();
1536
+ };
1537
+ };
1538
+ })();
1539
+
1540
+
1541
+ // We have fully created the datepicker...
1542
+ this.fullCreate = true;
1543
+
1544
+
1545
+ };
1546
+ datePicker.prototype.addButtonEvents = function(but) {
1547
+ function buttonEvent (e) {
1548
+ e = e || window.event;
1549
+
1550
+ var inpId = this.id.replace('fd-but-',''),
1551
+ dpVisible = isVisible(inpId),
1552
+ autoFocus = false,
1553
+ kbEvent = datePickers[inpId].kbEvent;
1554
+
1555
+ if(kbEvent) {
1556
+ datePickers[inpId].kbEvent = false;
1557
+ return;
1558
+ };
1559
+
1560
+ if(e.type == "keydown") {
1561
+ datePickers[inpId].kbEvent = true;
1562
+ var kc = e.keyCode != null ? e.keyCode : e.charCode;
1563
+ if(kc != 13) return true;
1564
+ if(dpVisible) {
1565
+ this.className = this.className.replace("dp-button-active", "");
1566
+ hideAll();
1567
+ return stopEvent(e);
1568
+ };
1569
+ autoFocus = true;
1570
+ } else {
1571
+ datePickers[inpId].kbEvent = false;
1572
+ };
1573
+
1574
+ this.className = this.className.replace("dp-button-active", "");
1575
+
1576
+ if(!dpVisible) {
1577
+ this.className += " dp-button-active";
1578
+ hideAll(inpId);
1579
+ showDatePicker(inpId, autoFocus);
1580
+ } else {
1581
+ hideAll();
1582
+ };
1583
+
1584
+ return stopEvent(e);
1585
+ };
1586
+
1587
+ but.onkeydown = buttonEvent;
1588
+ but.onclick = buttonEvent;
1589
+
1590
+ if(!buttonTabIndex || this.bespokeTabIndex === false) {
1591
+ but.setAttribute(!/*@cc_on!@*/false ? "tabIndex" : "tabindex", "-1");
1592
+ but.tabIndex = -1;
1593
+ but.onkeydown = null;
1594
+ removeEvent(but, "keydown", buttonEvent);
1595
+ } else {
1596
+ but.setAttribute(!/*@cc_on!@*/false ? "tabIndex" : "tabindex", this.bespokeTabIndex);
1597
+ but.tabIndex = this.bespokeTabIndex;
1598
+ };
1599
+ };
1600
+
1601
+ datePicker.prototype.createButton = function() {
1602
+
1603
+ if(this.staticPos || document.getElementById("fd-but-" + this.id)) { return; };
1604
+
1605
+ var inp = document.getElementById(this.id),
1606
+ span = document.createElement('span'),
1607
+ but = document.createElement('a');
1608
+
1609
+ but.href = "#" + this.id;
1610
+ but.className = "date-picker-control";
1611
+ but.title = getTitleTranslation(5);
1612
+ but.id = "fd-but-" + this.id;
1613
+
1614
+ span.appendChild(document.createTextNode(nbsp));
1615
+ but.appendChild(span);
1616
+
1617
+ span = document.createElement('span');
1618
+ span.className = "fd-screen-reader";
1619
+ span.appendChild(document.createTextNode(but.title));
1620
+ but.appendChild(span);
1621
+
1622
+ // Set the ARIA role to be "button"
1623
+ setARIARole(but, "button");
1624
+
1625
+ // Set a "haspopup" ARIA property - should this not be a list if ID's????
1626
+ setARIAProperty(but, "haspopup", true);
1627
+
1628
+ if(this.positioned && document.getElementById(this.positioned)) {
1629
+ document.getElementById(this.positioned).appendChild(but);
1630
+ } else {
1631
+ inp.parentNode.insertBefore(but, inp.nextSibling);
1632
+ };
1633
+
1634
+ this.addButtonEvents(but);
1635
+
1636
+ but = null;
1637
+
1638
+ this.callback("dombuttoncreate", {id:this.id});
1639
+ };
1640
+ datePicker.prototype.setBespokeTitles = function(titles) {
1641
+ this.bespokeTitles = titles;
1642
+ };
1643
+ datePicker.prototype.addBespokeTitles = function(titles) {
1644
+ for(var dt in titles) {
1645
+ this.bespokeTitles[dt] = titles[dt];
1646
+ };
1647
+ };
1648
+ datePicker.prototype.getBespokeTitle = function(y,m,d) {
1649
+ var dt, dtFull, yyyymmdd = y + String(pad(m)) + pad(d);
1650
+
1651
+ // Try this datepickers bespoke titles
1652
+ for(dt in this.bespokeTitles) {
1653
+ dtFull = dt.replace(/^(\*\*\*\*)/, y).replace(/^(\d\d\d\d)(\*\*)/, "$1"+ pad(m));
1654
+ if(dtFull == yyyymmdd) return this.bespokeTitles[dt];
1655
+ };
1656
+
1657
+ // Try the generic bespoke titles
1658
+ for(dt in bespokeTitles) {
1659
+ dtFull = dt.replace(/^(\*\*\*\*)/, y).replace(/^(\d\d\d\d)(\*\*)/, "$1"+ pad(m));
1660
+ if(dtFull == yyyymmdd) return bespokeTitles[dt];
1661
+ };
1662
+
1663
+ return false;
1664
+ };
1665
+ datePicker.prototype.returnSelectedDate = function() {
1666
+ return this.dateSet;
1667
+ };
1668
+ datePicker.prototype.setRangeLow = function(range) {
1669
+ this.rangeLow = (String(range).search(/^(\d\d\d\d)(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])$/) == -1) ? false : range;
1670
+ if(!this.inUpdate) this.setDateFromInput();
1671
+ };
1672
+ datePicker.prototype.setRangeHigh = function(range) {
1673
+ this.rangeHigh = (String(range).search(/^(\d\d\d\d)(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])$/) == -1) ? false : range;
1674
+ if(!this.inUpdate) this.setDateFromInput();
1675
+ };
1676
+ datePicker.prototype.setDisabledDays = function(dayArray) {
1677
+ if(!dayArray.length || dayArray.length != 7 || dayArray.join("").search(/^([0|1]{7})$/) == -1) {
1678
+ if(debug) {
1679
+ throw "Invalid values located when attempting to call setDisabledDays";
1680
+ };
1681
+ return false;
1682
+ };
1683
+ this.disabledDays = dayArray;
1684
+ if(!this.inUpdate) this.setDateFromInput();
1685
+ };
1686
+ datePicker.prototype.setDisabledDates = function(dateObj) {
1687
+ this.disabledDates = {};
1688
+ this.addDisabledDates(dateObj);
1689
+ };
1690
+ datePicker.prototype.setEnabledDates = function(dateObj) {
1691
+ this.enabledDates = {};
1692
+ this.addEnabledDates(dateObj);
1693
+ };
1694
+ datePicker.prototype.addDisabledDates = function(dateObj) {
1695
+ this.enabledDates = false;
1696
+ this.disabledDates = this.disabledDates || {};
1697
+
1698
+ var startD;
1699
+ for(startD in dateObj) {
1700
+ if((String(startD).search(wcDateRegExp) != -1 && dateObj[startD] == 1) || (String(startD).search(rangeRegExp) != -1 && String(dateObj[startD]).search(rangeRegExp) != -1)) {
1701
+ this.disabledDates[startD] = dateObj[startD];
1702
+ };
1703
+ };
1704
+
1705
+ if(!this.inUpdate) this.setDateFromInput();
1706
+ };
1707
+ datePicker.prototype.addEnabledDates = function(dateObj) {
1708
+ this.disabledDates = false;
1709
+ this.enabledDates = this.enabledDates || {};
1710
+
1711
+ var startD;
1712
+ for(startD in dateObj) {
1713
+ if((String(startD).search(wcDateRegExp) != -1 && dateObj[startD] == 1) || (String(startD).search(rangeRegExp) != -1 && String(dateObj[startD]).search(rangeRegExp) != -1)) {
1714
+ this.enabledDates[startD] = dateObj[startD];
1715
+ };
1716
+ };
1717
+
1718
+ if(!this.inUpdate) this.setDateFromInput();
1719
+ };
1720
+ datePicker.prototype.setSelectedDate = function(yyyymmdd) {
1721
+ if(String(yyyymmdd).search(wcDateRegExp) == -1) {
1722
+ return false;
1723
+ };
1724
+
1725
+ var match = yyyymmdd.match(rangeRegExp),
1726
+ dt = new Date(+match[2],+match[3]-1,+match[4]);
1727
+
1728
+ if(!dt || isNaN(dt) || !this.canDateBeSelected(dt)) {
1729
+ return false;
1730
+ };
1731
+
1732
+ this.dateSet = new Date(dt);
1733
+
1734
+ if(!this.inUpdate) this.updateTable();
1735
+
1736
+ this.callback("dateset", this.createCbArgObj());
1737
+ this.returnFormattedDate();
1738
+ };
1739
+ datePicker.prototype.checkSelectedDate = function() {
1740
+ if(this.dateSet && !this.canDateBeSelected(this.dateSet)) {
1741
+ this.dateSet = null;
1742
+ };
1743
+ if(!this.inUpdate) this.updateTable();
1744
+ };
1745
+ datePicker.prototype.addOnFocusEvents = function() {
1746
+ if(this.kbEventsAdded || this.noFocus) {
1747
+ return;
1748
+ };
1749
+
1750
+ addEvent(document, "keypress", this.onkeydown);
1751
+ addEvent(document, "mousedown", this.onmousedown);
1752
+
1753
+ /*@cc_on
1754
+ @if(@_win32)
1755
+ removeEvent(document, "keypress", this.onkeydown);
1756
+ addEvent(document, "keydown", this.onkeydown);
1757
+ @end
1758
+ @*/
1759
+ if(window.devicePixelRatio) {
1760
+ removeEvent(document, "keypress", this.onkeydown);
1761
+ addEvent(document, "keydown", this.onkeydown);
1762
+ };
1763
+ this.noFocus = false;
1764
+ this.kbEventsAdded = true;
1765
+ };
1766
+ datePicker.prototype.removeOnFocusEvents = function() {
1767
+
1768
+ if(!this.kbEventsAdded) { return; };
1769
+
1770
+ removeEvent(document, "keypress", this.onkeydown);
1771
+ removeEvent(document, "keydown", this.onkeydown);
1772
+ removeEvent(document, "mousedown", this.onmousedown);
1773
+
1774
+ this.kbEventsAdded = false;
1775
+ };
1776
+ datePicker.prototype.stopTimer = function() {
1777
+ this.timerSet = false;
1778
+ window.clearTimeout(this.timer);
1779
+ };
1780
+ datePicker.prototype.setOpacity = function(op) {
1781
+ this.div.style.opacity = op/100;
1782
+ this.div.style.filter = 'alpha(opacity=' + op + ')';
1783
+ this.opacity = op;
1784
+ };
1785
+ datePicker.prototype.getDates = function(y, m) {
1786
+ var dpm = daysInMonth(m - 1, y),
1787
+ obj = {},
1788
+ dds = this.getGenericDates(y, m, false),
1789
+ eds = this.getGenericDates(y, m, true),
1790
+ dts = y + pad(m);
1791
+
1792
+ for(var i = 1; i <= dpm; i++) {
1793
+ dt = dts + "" + pad(i);
1794
+
1795
+ if(dds) {
1796
+ obj[dt] = (dt in dds) ? 0 : 1;
1797
+ } else if(eds) {
1798
+ obj[dt] = (dt in eds) ? 1 : 0;
1799
+ } else {
1800
+ obj[dt] = 1;
1801
+ };
1802
+ };
1803
+
1804
+ return obj;
1805
+ };
1806
+ datePicker.prototype.getGenericDates = function(y, m, enabled) {
1807
+ var deDates = enabled ? this.enabledDates : this.disabledDates;
1808
+
1809
+ if(!deDates) {
1810
+ return false;
1811
+ };
1812
+
1813
+ m = pad(m);
1814
+
1815
+ var obj = {},
1816
+ lower = this.firstDateShown,
1817
+ upper = this.lastDateShown,
1818
+ dt1, dt2, rngLower, rngUpper;
1819
+
1820
+ if(!upper || !lower) {
1821
+ lower = this.firstDateShown = y + pad(m) + "01";
1822
+ upper = this.lastDateShown = y + pad(m) + pad(daysInMonth(m, y));
1823
+ };
1824
+
1825
+ for(dt in deDates) {
1826
+ dt1 = dt.replace(/^(\*\*\*\*)/, y).replace(/^(\d\d\d\d)(\*\*)/, "$1"+m);
1827
+ dt2 = deDates[dt];
1828
+
1829
+ if(dt2 == 1) {
1830
+ if(Number(dt1.substr(0,6)) >= +String(this.firstDateShown).substr(0,6)
1831
+ &&
1832
+ Number(dt1.substr(0,6)) <= +String(this.lastDateShown).substr(0,6)) {
1833
+ obj[dt1] = 1;
1834
+ };
1835
+ continue;
1836
+ };
1837
+
1838
+ // Range
1839
+ if(+String(this.firstDateShown).substr(0,6) >= Number(dt1.substr(0,6))
1840
+ &&
1841
+ +String(this.lastDateShown).substr(0,6) <= Number(dt2.substr(0,6))) {
1842
+ // Same month
1843
+ if(Number(dt1.substr(0,6)) == Number(dt2.substr(0,6))) {
1844
+ for(var i = dt1; i <= dt2; i++) {
1845
+ obj[i] = 1;
1846
+ };
1847
+ continue;
1848
+ };
1849
+
1850
+ // Different months but we only want this month
1851
+ rngLower = Number(dt1.substr(0,6)) == +String(this.firstDateShown).substr(0,6) ? dt1 : lower;
1852
+ rngUpper = Number(dt2.substr(0,6)) == +String(this.lastDateShown).substr(0,6) ? dt2 : upper;
1853
+ for(var i = +rngLower; i <= +rngUpper; i++) {
1854
+ obj[i] = 1;
1855
+ };
1856
+ };
1857
+ };
1858
+ return obj;
1859
+ };
1860
+ datePicker.prototype.truePosition = function(element) {
1861
+ var pos = this.cumulativeOffset(element);
1862
+ if(isOpera) { return pos; };
1863
+ var iebody = (document.compatMode && document.compatMode != "BackCompat")? document.documentElement : document.body,
1864
+ dsocleft = document.all ? iebody.scrollLeft : window.pageXOffset,
1865
+ dsoctop = document.all ? iebody.scrollTop : window.pageYOffset,
1866
+ posReal = this.realOffset(element);
1867
+ return [pos[0] - posReal[0] + dsocleft, pos[1] - posReal[1] + dsoctop];
1868
+ };
1869
+ datePicker.prototype.realOffset = function(element) {
1870
+ var t = 0, l = 0;
1871
+ do {
1872
+ t += element.scrollTop || 0;
1873
+ l += element.scrollLeft || 0;
1874
+ element = element.parentNode;
1875
+ } while(element);
1876
+ return [l, t];
1877
+ };
1878
+ datePicker.prototype.cumulativeOffset = function(element) {
1879
+ var t = 0, l = 0;
1880
+ do {
1881
+ t += element.offsetTop || 0;
1882
+ l += element.offsetLeft || 0;
1883
+ element = element.offsetParent;
1884
+ } while(element);
1885
+ return [l, t];
1886
+ };
1887
+ datePicker.prototype.equaliseDates = function() {
1888
+ var clearDayFound = false, tmpDate;
1889
+ for(var i = this.rangeLow; i <= this.rangeHigh; i++) {
1890
+ tmpDate = String(i);
1891
+ if(!this.disabledDays[new Date(tmpDate.substr(0,4), tmpDate.substr(6,2), tmpDate.substr(4,2)).getDay() - 1]) {
1892
+ clearDayFound = true;
1893
+ break;
1894
+ };
1895
+ };
1896
+ if(!clearDayFound) { this.disabledDays = [0,0,0,0,0,0,0] };
1897
+ };
1898
+ datePicker.prototype.outOfRange = function(tmpDate) {
1899
+
1900
+ if(!this.rangeLow && !this.rangeHigh) { return false; };
1901
+ var level = false;
1902
+ if(!tmpDate) {
1903
+ level = true;
1904
+ tmpDate = this.date;
1905
+ };
1906
+
1907
+ var d = pad(tmpDate.getDate()),
1908
+ m = pad(tmpDate.getMonth() + 1),
1909
+ y = tmpDate.getFullYear(),
1910
+ dt = String(y)+String(m)+String(d);
1911
+
1912
+ if(this.rangeLow && +dt < +this.rangeLow) {
1913
+ if(!level) { return true; };
1914
+ this.date = new Date(this.rangeLow.substr(0,4), this.rangeLow.substr(4,2)-1, this.rangeLow.substr(6,2), 5, 0, 0);
1915
+ return false;
1916
+ };
1917
+ if(this.rangeHigh && +dt > +this.rangeHigh) {
1918
+ if(!level) { return true; };
1919
+ this.date = new Date(this.rangeHigh.substr(0,4), this.rangeHigh.substr(4,2)-1, this.rangeHigh.substr(6,2), 5, 0, 0);
1920
+ };
1921
+ return false;
1922
+ };
1923
+ datePicker.prototype.canDateBeSelected = function(tmpDate) {
1924
+ if(!tmpDate) return false;
1925
+
1926
+ var d = pad(tmpDate.getDate()),
1927
+ m = pad(tmpDate.getMonth() + 1),
1928
+ y = tmpDate.getFullYear(),
1929
+ dt = String(y)+String(m)+String(d),
1930
+ dd = this.getDates(y, m),
1931
+ wd = tmpDate.getDay() == 0 ? 7 : tmpDate.getDay();
1932
+
1933
+ if((this.rangeLow && +dt < +this.rangeLow) || (this.rangeHigh && +dt > +this.rangeHigh) || (dd[dt] == 0) || this.disabledDays[wd-1]) {
1934
+ return false;
1935
+ };
1936
+
1937
+ return true;
1938
+ };
1939
+ datePicker.prototype.updateStatus = function(msg) {
1940
+ while(this.statusBar.firstChild) { this.statusBar.removeChild(this.statusBar.firstChild); };
1941
+
1942
+ if(msg && this.statusFormat.search(/-S|S-/) != -1 && msg.search(/([0-9]{1,2})(st|nd|rd|th)/) != -1) {
1943
+ msg = msg.replace(/([0-9]{1,2})(st|nd|rd|th)/, "$1<sup>$2</sup>").split(/<sup>|<\/sup>/);
1944
+ var dc = document.createDocumentFragment();
1945
+ for(var i = 0, nd; nd = msg[i]; i++) {
1946
+ if(/^(st|nd|rd|th)$/.test(nd)) {
1947
+ var sup = document.createElement("sup");
1948
+ sup.appendChild(document.createTextNode(nd));
1949
+ dc.appendChild(sup);
1950
+ } else {
1951
+ dc.appendChild(document.createTextNode(nd));
1952
+ };
1953
+ };
1954
+ this.statusBar.appendChild(dc);
1955
+ } else {
1956
+ this.statusBar.appendChild(document.createTextNode(msg ? msg : getTitleTranslation(9)));
1957
+ };
1958
+ };
1959
+ datePicker.prototype.setDateFromInput = function() {
1960
+ var origDateSet = this.dateSet,
1961
+ m = false,
1962
+ dt, elemID, elem, elemFmt, d, y, elemVal;
1963
+
1964
+ this.dateSet = null;
1965
+
1966
+ for(elemID in this.formElements) {
1967
+ elem = document.getElementById(elemID);
1968
+
1969
+ if(!elem) {
1970
+ return;
1971
+ };
1972
+
1973
+ elemVal = String(elem.value);
1974
+ elemFmt = this.formElements[elemID];
1975
+ dt = false;
1976
+
1977
+ if(!(elemVal == "")) {
1978
+ for(var i = 0, fmt; fmt = this.formatMasks[elemID][i]; i++) {
1979
+ dt = parseDateString(elemVal, fmt);
1980
+ if(dt) {
1981
+ break;
1982
+ };
1983
+ };
1984
+ };
1985
+
1986
+ if(dt) {
1987
+ if(elemFmt.search(new RegExp('[' + dParts + ']')) != -1) {
1988
+ //console.log("located d part " + elemFmt + " : " + dt.getDate());
1989
+ d = dt.getDate();
1990
+ };
1991
+ if(elemFmt.search(new RegExp('[' + mParts + ']')) != -1) {
1992
+ //console.log("located m part " + elemFmt + " : " + dt.getMonth());
1993
+ m = dt.getMonth();
1994
+ };
1995
+ if(elemFmt.search(new RegExp('[' + yParts + ']')) != -1) {
1996
+ //console.log("located y part " + elemFmt + " : " + dt.getFullYear());
1997
+ y = dt.getFullYear()
1998
+ };
1999
+ };
2000
+ };
2001
+
2002
+ dt = false;
2003
+
2004
+ if(d && !(m === false) && y) {
2005
+ if(+d > daysInMonth(+m, +y)) {
2006
+ d = daysInMonth(+m, +y);
2007
+ dt = false;
2008
+ } else {
2009
+ dt = new Date(+y, +m, +d);
2010
+ };
2011
+ };
2012
+
2013
+ if(!dt || isNaN(dt)) {
2014
+ var newDate = new Date(y || new Date().getFullYear(), !(m === false) ? m : new Date().getMonth(), 1);
2015
+ this.date = this.cursorDate ? new Date(+this.cursorDate.substr(0,4), +this.cursorDate.substr(4,2) - 1, +this.cursorDate.substr(6,2)) : new Date(newDate.getFullYear(), newDate.getMonth(), Math.min(+d || new Date().getDate(), daysInMonth(newDate.getMonth(), newDate.getFullYear())));
2016
+
2017
+ this.date.setHours(5);
2018
+ this.outOfRange();
2019
+ //this.callback("dateset", this.createCbArgObj());
2020
+ this.updateTable();
2021
+ return;
2022
+ };
2023
+
2024
+
2025
+ dt.setHours(5);
2026
+ this.date = new Date(dt);
2027
+ this.outOfRange();
2028
+
2029
+ if(dt.getTime() == this.date.getTime() && this.canDateBeSelected(this.date)) {
2030
+ this.dateSet = new Date(this.date);
2031
+ };
2032
+
2033
+ //this.callback("dateset", this.createCbArgObj());
2034
+ if(this.fullCreate) this.updateTable();
2035
+ this.returnFormattedDate(true);
2036
+ };
2037
+ datePicker.prototype.setSelectIndex = function(elem, indx) {
2038
+ for(var opt = elem.options.length-1; opt >= 0; opt--) {
2039
+ if(elem.options[opt].value == indx) {
2040
+ elem.selectedIndex = opt;
2041
+ return;
2042
+ };
2043
+ };
2044
+ };
2045
+ datePicker.prototype.returnFormattedDate = function(noFocus) {
2046
+ if(!this.dateSet) {
2047
+ return;
2048
+ };
2049
+
2050
+ var d = pad(this.dateSet.getDate()),
2051
+ m = pad(this.dateSet.getMonth() + 1),
2052
+ y = this.dateSet.getFullYear(),
2053
+ el = false,
2054
+ elemID, elem, elemFmt, fmtDate;
2055
+
2056
+ noFocus = !!noFocus;
2057
+
2058
+ for(elemID in this.formElements) {
2059
+ elem = document.getElementById(elemID);
2060
+
2061
+ if(!elem) return;
2062
+
2063
+ if(!el) el = elem;
2064
+
2065
+ elemFmt = this.formElements[elemID];
2066
+
2067
+ fmtDate = printFormattedDate(this.dateSet, elemFmt, returnLocaleDate);
2068
+ if(elem.tagName.toLowerCase() == "input") {
2069
+ elem.value = fmtDate;
2070
+ } else {
2071
+ this.setSelectIndex(elem, fmtDate);
2072
+ };
2073
+ };
2074
+
2075
+ if(this.staticPos) {
2076
+ this.noFocus = true;
2077
+ this.updateTable();
2078
+ this.noFocus = false;
2079
+ };
2080
+
2081
+ if(this.fullCreate) {
2082
+ if(el.type && el.type != "hidden" && !noFocus) { el.focus(); };
2083
+ };
2084
+ };
2085
+ datePicker.prototype.disableDatePicker = function() {
2086
+ if(this.disabled) return;
2087
+
2088
+ if(this.staticPos) {
2089
+ this.removeOnFocusEvents();
2090
+ this.removeOldFocus();
2091
+ this.noFocus = true;
2092
+ this.div.className = this.div.className.replace(/dp-disabled/, "") + " dp-disabled";
2093
+ this.table.onmouseover = this.table.onclick = this.table.onmouseout = this.table.onmousedown = null;
2094
+ removeEvent(document, "mousedown", this.onmousedown);
2095
+ removeEvent(document, "mouseup", this.clearTimer);
2096
+ } else {
2097
+ if(this.visible) this.hide();
2098
+ var but = document.getElementById("fd-but-" + this.id);
2099
+ if(but) {
2100
+ but.className = but.className.replace(/dp-disabled/, "") + " dp-disabled";
2101
+ // Set a "disabled" ARIA state
2102
+ setARIAProperty(but, "disabled", true);
2103
+ but.onkeydown = but.onclick = function() { return false; };
2104
+ but.setAttribute(!/*@cc_on!@*/false ? "tabIndex" : "tabindex", "-1");
2105
+ but.tabIndex = -1;
2106
+ };
2107
+ };
2108
+
2109
+ clearTimeout(this.timer);
2110
+ this.disabled = true;
2111
+ };
2112
+ datePicker.prototype.enableDatePicker = function() {
2113
+ if(!this.disabled) return;
2114
+
2115
+ if(this.staticPos) {
2116
+ this.removeOldFocus();
2117
+ this.noFocus = true;
2118
+ this.updateTable();
2119
+ this.div.className = this.div.className.replace(/dp-disabled/, "");
2120
+ this.disabled = false;
2121
+ this.table.onmouseover = this.onmouseover;
2122
+ this.table.onmouseout = this.onmouseout;
2123
+ this.table.onclick = this.onclick;
2124
+ this.table.onmousedown = this.onmousedown;
2125
+ } else {
2126
+ var but = document.getElementById("fd-but-" + this.id);
2127
+ if(but) {
2128
+ but.className = but.className.replace(/dp-disabled/, "");
2129
+ // Reset the "disabled" ARIA state
2130
+ setARIAProperty(but, "disabled", false);
2131
+ this.addButtonEvents(but);
2132
+ };
2133
+ };
2134
+
2135
+ this.disabled = false;
2136
+ };
2137
+ datePicker.prototype.disableTodayButton = function() {
2138
+ var today = new Date();
2139
+ this.butToday.className = this.butToday.className.replace("fd-disabled", "");
2140
+ if(this.outOfRange(today) || (this.date.getDate() == today.getDate() && this.date.getMonth() == today.getMonth() && this.date.getFullYear() == today.getFullYear())) {
2141
+ this.butToday.className += " fd-disabled";
2142
+ };
2143
+ };
2144
+ datePicker.prototype.updateTableHeaders = function() {
2145
+ var colspanTotal = this.showWeeks ? 8 : 7,
2146
+ colOffset = this.showWeeks ? 1 : 0,
2147
+ d, but;
2148
+
2149
+ for(var col = colOffset; col < colspanTotal; col++ ) {
2150
+ d = (this.firstDayOfWeek + (col - colOffset)) % 7;
2151
+ this.ths[col].title = getDayTranslation(d, false);
2152
+
2153
+ if(col > colOffset) {
2154
+ but = this.ths[col].getElementsByTagName("span")[0];
2155
+ while(but.firstChild) { but.removeChild(but.firstChild); };
2156
+ but.appendChild(document.createTextNode(getDayTranslation(d, true)));
2157
+ but.title = this.ths[col].title;
2158
+ but.className = but.className.replace(/day-([0-6])/, "") + " day-" + d;
2159
+ but = null;
2160
+ } else {
2161
+ while(this.ths[col].firstChild) { this.ths[col].removeChild(this.ths[col].firstChild); };
2162
+ this.ths[col].appendChild(document.createTextNode(getDayTranslation(d, true)));
2163
+ };
2164
+
2165
+ this.ths[col].className = this.ths[col].className.replace(/date-picker-highlight/g, "");
2166
+ if(this.highlightDays[d]) {
2167
+ this.ths[col].className += " date-picker-highlight";
2168
+ };
2169
+ };
2170
+
2171
+ if(this.created) { this.updateTable(); }
2172
+ };
2173
+ datePicker.prototype.callback = function(type, args) {
2174
+ if(!type || !(type in this.callbacks)) {
2175
+ return false;
2176
+ };
2177
+
2178
+ var ret = false;
2179
+ for(var func = 0; func < this.callbacks[type].length; func++) {
2180
+ ret = this.callbacks[type][func](args || this.id);
2181
+ };
2182
+ return ret;
2183
+ };
2184
+ datePicker.prototype.showHideButtons = function(tmpDate) {
2185
+ if(!this.butPrevYear) { return; };
2186
+
2187
+ var tdm = tmpDate.getMonth(),
2188
+ tdy = tmpDate.getFullYear();
2189
+
2190
+ if(this.outOfRange(new Date((tdy - 1), tdm, daysInMonth(+tdm, tdy-1)))) {
2191
+ if(this.butPrevYear.className.search(/fd-disabled/) == -1) {
2192
+ this.butPrevYear.className += " fd-disabled";
2193
+ };
2194
+ if(this.yearInc == -1) this.stopTimer();
2195
+ } else {
2196
+ this.butPrevYear.className = this.butPrevYear.className.replace(/fd-disabled/g, "");
2197
+ };
2198
+
2199
+ if(this.outOfRange(new Date(tdy, (+tdm - 1), daysInMonth(+tdm-1, tdy)))) {
2200
+ if(this.butPrevMonth.className.search(/fd-disabled/) == -1) {
2201
+ this.butPrevMonth.className += " fd-disabled";
2202
+ };
2203
+ if(this.monthInc == -1) this.stopTimer();
2204
+ } else {
2205
+ this.butPrevMonth.className = this.butPrevMonth.className.replace(/fd-disabled/g, "");
2206
+ };
2207
+
2208
+ if(this.outOfRange(new Date((tdy + 1), +tdm, 1))) {
2209
+ if(this.butNextYear.className.search(/fd-disabled/) == -1) {
2210
+ this.butNextYear.className += " fd-disabled";
2211
+ };
2212
+ if(this.yearInc == 1) this.stopTimer();
2213
+ } else {
2214
+ this.butNextYear.className = this.butNextYear.className.replace(/fd-disabled/g, "");
2215
+ };
2216
+
2217
+ if(this.outOfRange(new Date(tdy, +tdm + 1, 1))) {
2218
+ if(this.butNextMonth.className.search(/fd-disabled/) == -1) {
2219
+ this.butNextMonth.className += " fd-disabled";
2220
+ };
2221
+ if(this.monthInc == 1) this.stopTimer();
2222
+ } else {
2223
+ this.butNextMonth.className = this.butNextMonth.className.replace(/fd-disabled/g, "");
2224
+ };
2225
+ };
2226
+ var localeDefaults = {
2227
+ fullMonths:["January","February","March","April","May","June","July","August","September","October","November","December"],
2228
+ monthAbbrs:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],
2229
+ fullDays: ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],
2230
+ dayAbbrs: ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"],
2231
+ titles: ["Previous month","Next month","Previous year","Next year", "Today", "Show Calendar", "wk", "Week [[%0%]] of [[%1%]]", "Week", "Select a date", "Click \u0026 Drag to move", "Display \u201C[[%0%]]\u201D first", "Go to Today\u2019s date", "Disabled date :"],
2232
+ firstDayOfWeek:0,
2233
+ imported: false
2234
+ };
2235
+ var joinNodeLists = function() {
2236
+ if(!arguments.length) { return []; }
2237
+ var nodeList = [];
2238
+ for (var i = 0; i < arguments.length; i++) {
2239
+ for (var j = 0, item; item = arguments[i][j]; j++) {
2240
+ nodeList[nodeList.length] = item;
2241
+ };
2242
+ };
2243
+ return nodeList;
2244
+ };
2245
+ var cleanUp = function() {
2246
+ var dp, fe;
2247
+ for(dp in datePickers) {
2248
+ for(fe in datePickers[dp].formElements) {
2249
+ if(!document.getElementById(fe)) {
2250
+ datePickers[dp].destroy();
2251
+ datePickers[dp] = null;
2252
+ delete datePickers[dp];
2253
+ break;
2254
+ }
2255
+ };
2256
+ };
2257
+ };
2258
+ var hideAll = function(exception) {
2259
+ var dp;
2260
+ for(dp in datePickers) {
2261
+ if(!datePickers[dp].created || (exception && exception == datePickers[dp].id)) continue;
2262
+ datePickers[dp].hide();
2263
+ };
2264
+ };
2265
+ var hideDatePicker = function(inpID) {
2266
+ if(inpID in datePickers) {
2267
+ if(!datePickers[inpID].created || datePickers[inpID].staticPos) return;
2268
+ datePickers[inpID].hide();
2269
+ };
2270
+ };
2271
+ var showDatePicker = function(inpID, autoFocus) {
2272
+ if(!(inpID in datePickers)) return false;
2273
+
2274
+ datePickers[inpID].clickActivated = !!!autoFocus;
2275
+ datePickers[inpID].show(autoFocus);
2276
+ return true;
2277
+ };
2278
+ var destroy = function(e) {
2279
+ e = e || window.event;
2280
+
2281
+ // Don't remove datepickers if it's a pagehide/pagecache event (webkit et al)
2282
+ if(e.persisted) {
2283
+ return;
2284
+ };
2285
+
2286
+ for(dp in datePickers) {
2287
+ datePickers[dp].destroy();
2288
+ datePickers[dp] = null;
2289
+ delete datePickers[dp];
2290
+ };
2291
+ datePickers = null;
2292
+
2293
+ removeEvent(window, 'unload', datePickerController.destroy);
2294
+ };
2295
+ var destroySingleDatePicker = function(id) {
2296
+ if(id && (id in datePickers)) {
2297
+ datePickers[id].destroy();
2298
+ datePickers[id] = null;
2299
+ delete datePickers[id];
2300
+ };
2301
+ };
2302
+ var getTitleTranslation = function(num, replacements) {
2303
+ replacements = replacements || [];
2304
+ if(localeImport.titles.length > num) {
2305
+ var txt = localeImport.titles[num];
2306
+ if(replacements && replacements.length) {
2307
+ for(var i = 0; i < replacements.length; i++) {
2308
+ txt = txt.replace("[[%" + i + "%]]", replacements[i]);
2309
+ };
2310
+ };
2311
+ return txt.replace(/[[%(\d)%]]/g,"");
2312
+ };
2313
+ return "";
2314
+ };
2315
+ var getDayTranslation = function(day, abbreviation) {
2316
+ var titles = localeImport[abbreviation ? "dayAbbrs" : "fullDays"];
2317
+ return titles.length && titles.length > day ? titles[day] : "";
2318
+ };
2319
+ var getMonthTranslation = function(month, abbreviation) {
2320
+ var titles = localeImport[abbreviation ? "monthAbbrs" : "fullMonths"];
2321
+ return titles.length && titles.length > month ? titles[month] : "";
2322
+ };
2323
+ var daysInMonth = function(nMonth, nYear) {
2324
+ nMonth = (nMonth + 12) % 12;
2325
+ return (((0 == (nYear%4)) && ((0 != (nYear%100)) || (0 == (nYear%400)))) && nMonth == 1) ? 29: [31,28,31,30,31,30,31,31,30,31,30,31][nMonth];
2326
+ };
2327
+
2328
+ var getWeeksInYear = function(Y) {
2329
+ if(Y in weeksInYearCache) {
2330
+ return weeksInYearCache[Y];
2331
+ };
2332
+ var X1, X2, NW;
2333
+ with (X1 = new Date(Y, 0, 4)) {
2334
+ setDate(getDate() - (6 + getDay()) % 7);
2335
+ };
2336
+ with (X2 = new Date(Y, 11, 28)) {
2337
+ setDate(getDate() + (7 - getDay()) % 7);
2338
+ };
2339
+ weeksInYearCache[Y] = Math.round((X2 - X1) / 604800000);
2340
+ return weeksInYearCache[Y];
2341
+ };
2342
+
2343
+ var getWeekNumber = function(y,m,d) {
2344
+ var d = new Date(y, m, d, 0, 0, 0);
2345
+ var DoW = d.getDay();
2346
+ d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu
2347
+ var ms = d.valueOf(); // GMT
2348
+ d.setMonth(0);
2349
+ d.setDate(4); // Thu in Week 1
2350
+ return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
2351
+ };
2352
+
2353
+ var printFormattedDate = function(date, fmt, useImportedLocale) {
2354
+ if(!date || isNaN(date)) { return ""; };
2355
+
2356
+ var parts = fmt.split("-"),
2357
+ str = [],
2358
+ d = date.getDate(),
2359
+ D = date.getDay(),
2360
+ m = date.getMonth(),
2361
+ y = date.getFullYear(),
2362
+ flags = {
2363
+ "sp":" ",
2364
+ "dt":".",
2365
+ "sl":"/",
2366
+ "ds":"-",
2367
+ "cc":",",
2368
+ "d":pad(d),
2369
+ "D":useImportedLocale ? localeImport.dayAbbrs[D == 0 ? 6 : D - 1] : localeDefaults.dayAbbrs[D == 0 ? 6 : D - 1],
2370
+ "l":useImportedLocale ? localeImport.fullDays[D == 0 ? 6 : D - 1] : localeDefaults.fullDays[D == 0 ? 6 : D - 1],
2371
+ "j":d,
2372
+ "N":D == 0 ? 7 : D,
2373
+ "w":D,
2374
+ "W":getWeekNumber(y,m,d),
2375
+ "M":useImportedLocale ? localeImport.monthAbbrs[m] : localeDefaults.monthAbbrs[m],
2376
+ "F":useImportedLocale ? localeImport.fullMonths[m] : localeDefaults.fullMonths[m],
2377
+ "m":pad(m + 1),
2378
+ "n":m + 1,
2379
+ "t":daysInMonth(m, y),
2380
+ "y":String(y).substr(2,2),
2381
+ "Y":y,
2382
+ "S":["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
2383
+ };
2384
+
2385
+ for(var pt = 0, part; part = parts[pt]; pt++) {
2386
+ str.push(!(part in flags) ? "" : flags[part]);
2387
+ };
2388
+
2389
+ return str.join("");
2390
+ };
2391
+ var parseDateString = function(str, fmt) {
2392
+ var d = false,
2393
+ m = false,
2394
+ y = false,
2395
+ now = new Date(),
2396
+ parts = fmt.replace(/-sp(-sp)+/g, "-sp").split("-"),
2397
+ divds = { "dt":".","sl":"/","ds":"-","cc":"," },
2398
+ str = "" + str;
2399
+
2400
+ loopLabel:
2401
+ for(var pt = 0, part; part = parts[pt]; pt++) {
2402
+ if(str.length == 0) { return false; };
2403
+
2404
+ switch(part) {
2405
+ // Dividers - be easy on them all i.e. accept them all when parsing...
2406
+ case "sp":
2407
+ case "dt":
2408
+ case "sl":
2409
+ case "ds":
2410
+ case "cc":
2411
+ str = str.replace(/^(\s|\.|\/|,|-){1,}/, "");
2412
+ break;
2413
+ // DAY
2414
+ case "d": // Day of the month, 2 digits with leading zeros (01 - 31)
2415
+ case "j": // Day of the month without leading zeros (1 - 31)
2416
+ // Accept both when parsing
2417
+ if(str.search(/^(3[01]|[12][0-9]|0?[1-9])/) != -1) {
2418
+ d = +str.match(/^(3[01]|[12][0-9]|0?[1-9])/)[0];
2419
+ str = str.substr(str.match(/^(3[01]|[12][0-9]|0?[1-9])/)[0].length);
2420
+ break;
2421
+ } else {
2422
+ return "";
2423
+ };
2424
+ case "D": // A textual representation of a day, three letters (Mon - Sun)
2425
+ case "l": // A full textual representation of the day of the week (Monday - Sunday)
2426
+ // Accept English & imported locales and both modifiers
2427
+ l = localeDefaults.fullDays.concat(localeDefaults.dayAbbrs);
2428
+ if(localeImport.imported) {
2429
+ l = l.concat(localeImport.fullDays).concat(localeImport.dayAbbrs);
2430
+ };
2431
+
2432
+ for(var i = 0; i < l.length; i++) {
2433
+ if(new RegExp("^" + l[i], "i").test(str)) {
2434
+ str = str.substr(l[i].length);
2435
+ continue loopLabel;
2436
+ };
2437
+ };
2438
+
2439
+ break;
2440
+ case "N": // ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) 1 (for Monday) through 7 (for Sunday)
2441
+ case "w": // Numeric representation of the day of the week 0 (for Sunday) through 6 (for Saturday)
2442
+ if(str.search(part == "N" ? /^([1-7])/ : /^([0-6])/) != -1) {
2443
+ str = str.substr(1);
2444
+
2445
+ };
2446
+ break;
2447
+ case "S": // English ordinal suffix for the day of the month, 2 characters: st, nd, rd or th
2448
+ if(str.search(/^(st|nd|rd|th)/i) != -1) {
2449
+ str = str.substr(2);
2450
+ };
2451
+ break;
2452
+ // WEEK
2453
+ case "W": // ISO-8601 week number of year, weeks starting on Monday (added in PHP 4.1.0): 1 - 53
2454
+ if(str.search(/^([1-9]|[1234[0-9]|5[0-3])/) != -1) {
2455
+ str = str.substr(str.match(/^([1-9]|[1234[0-9]|5[0-3])/)[0].length);
2456
+ };
2457
+ break;
2458
+ // MONTH
2459
+ case "M": // A short textual representation of a month, three letters
2460
+ case "F": // A full textual representation of a month, such as January or March
2461
+ // Accept English & imported locales and both modifiers
2462
+ l = localeDefaults.fullMonths.concat(localeDefaults.monthAbbrs);
2463
+ if(localeImport.imported) {
2464
+ l = l.concat(localeImport.fullMonths).concat(localeImport.monthAbbrs);
2465
+ };
2466
+ for(var i = 0; i < l.length; i++) {
2467
+ if(str.search(new RegExp("^" + l[i],"i")) != -1) {
2468
+ str = str.substr(l[i].length);
2469
+ m = ((i + 12) % 12);
2470
+ continue loopLabel;
2471
+ };
2472
+ };
2473
+ return "";
2474
+ case "m": // Numeric representation of a month, with leading zeros
2475
+ case "n": // Numeric representation of a month, without leading zeros
2476
+ // Accept either when parsing
2477
+ l = /^(1[012]|0?[1-9])/;
2478
+ if(str.search(l) != -1) {
2479
+ m = +str.match(l)[0] - 1;
2480
+ str = str.substr(str.match(l)[0].length);
2481
+ break;
2482
+ } else {
2483
+ return "";
2484
+ };
2485
+ case "t": // Number of days in the given month: 28 through 31
2486
+ if(str.search(/2[89]|3[01]/) != -1) {
2487
+ str = str.substr(2);
2488
+ break;
2489
+ };
2490
+ break;
2491
+ // YEAR
2492
+ case "Y": // A full numeric representation of a year, 4 digits
2493
+ if(str.search(/^(\d{4})/) != -1) {
2494
+ y = str.substr(0,4);
2495
+ str = str.substr(4);
2496
+ break;
2497
+ } else {
2498
+ return "";
2499
+ };
2500
+ case "y": // A two digit representation of a year - be easy on four figure dates though
2501
+ if(str.search(/^(\d{4})/) != -1) {
2502
+ y = str.substr(0,4);
2503
+ str = str.substr(4);
2504
+ break;
2505
+ } else if(str.search(/^(0[0-9]|[1-9][0-9])/) != -1) {
2506
+ y = str.substr(0,2);
2507
+ y = +y < 50 ? '20' + "" + String(y) : '19' + "" + String(y);
2508
+ str = str.substr(2);
2509
+ break;
2510
+ } else return "";
2511
+
2512
+ default:
2513
+ return "";
2514
+ };
2515
+ };
2516
+
2517
+ if(!(str == "") || (d === false && m === false && y === false)) {
2518
+ return false;
2519
+ };
2520
+
2521
+ m = m === false ? 11 : m;
2522
+ y = y === false ? now.getFullYear() : y;
2523
+ d = d === false ? daysInMonth(+m, +y) : d;
2524
+
2525
+ if(d > daysInMonth(+m, +y)) {
2526
+ return false;
2527
+ };
2528
+
2529
+ var tmpDate = new Date(y,m,d);
2530
+
2531
+ return !tmpDate || isNaN(tmpDate) ? false : tmpDate;
2532
+ };
2533
+ var findLabelForElement = function(element) {
2534
+ var label;
2535
+ if(element.parentNode && element.parentNode.tagName.toLowerCase() == "label") lebel = element.parentNode;
2536
+ else {
2537
+ var labelList = document.getElementsByTagName('label');
2538
+ // loop through label array attempting to match each 'for' attribute to the id of the current element
2539
+ for(var lbl = 0; lbl < labelList.length; lbl++) {
2540
+ // Internet Explorer requires the htmlFor test
2541
+ if((labelList[lbl]['htmlFor'] && labelList[lbl]['htmlFor'] == element.id) || (labelList[lbl].getAttribute('for') == element.id)) {
2542
+ label = labelList[lbl];
2543
+ break;
2544
+ };
2545
+ };
2546
+ };
2547
+
2548
+ if(label && !label.id) { label.id = element.id + "_label"; };
2549
+ return label;
2550
+ };
2551
+ var updateLanguage = function() {
2552
+ if(typeof(window.fdLocale) == "object" ) {
2553
+ localeImport = {
2554
+ titles : fdLocale.titles,
2555
+ fullMonths : fdLocale.fullMonths,
2556
+ monthAbbrs : fdLocale.monthAbbrs,
2557
+ fullDays : fdLocale.fullDays,
2558
+ dayAbbrs : fdLocale.dayAbbrs,
2559
+ firstDayOfWeek : ("firstDayOfWeek" in fdLocale) ? fdLocale.firstDayOfWeek : 0,
2560
+ imported : true
2561
+ };
2562
+ } else if(!localeImport) {
2563
+ localeImport = localeDefaults;
2564
+ };
2565
+ };
2566
+ var loadLanguage = function() {
2567
+ updateLanguage();
2568
+ for(dp in datePickers) {
2569
+ if(!datePickers[dp].created) continue;
2570
+ datePickers[dp].updateTable();
2571
+ };
2572
+ };
2573
+ var checkElem = function(elem) {
2574
+ return !(!elem || !elem.tagName || !((elem.tagName.toLowerCase() == "input" && (elem.type == "text" || elem.type == "hidden")) || elem.tagName.toLowerCase() == "select"));
2575
+ };
2576
+ var addDatePicker = function(options) {
2577
+
2578
+ updateLanguage();
2579
+
2580
+ if(!options.formElements) {
2581
+ if(debug) throw "No form elements stipulated within initialisation parameters";
2582
+ return;
2583
+ };
2584
+
2585
+ options.id = (options.id && (options.id in options.formElements)) ? options.id : "";
2586
+ options.formatMasks = {};
2587
+
2588
+ var testParts = [dParts,mParts,yParts],
2589
+ partsFound = [0,0,0],
2590
+ tmpPartsFound,
2591
+ matchedPart,
2592
+ newParts,
2593
+ indParts,
2594
+ fmt,
2595
+ fmtBag,
2596
+ fmtParts,
2597
+ newFormats,
2598
+ myMin,
2599
+ myMax;
2600
+
2601
+ for(var elemID in options.formElements) {
2602
+ elem = document.getElementById(elemID);
2603
+
2604
+ if(!checkElem(elem)) {
2605
+ if(debug) throw "The element with and id of '" + elemID + "' is of the wrong type or does not exist within the DOM";
2606
+ return false;
2607
+ };
2608
+
2609
+ if(!options.id) options.id = elemID;
2610
+
2611
+ fmt = options.formElements[elemID];
2612
+
2613
+ if(!(fmt.match(validFmtRegExp))) {
2614
+ if(debug) throw "The element with and id of '" + elemID + "' has the following incorrect date format assigned to it: " + fmt;
2615
+ return false;
2616
+ };
2617
+
2618
+ fmtBag = [fmt];
2619
+
2620
+ if(options.dateFormats && (elemID in options.dateFormats) && options.dateFormats[elemID].length) {
2621
+ newFormats = [];
2622
+
2623
+ for(var f = 0, bDft; bDft = options.dateFormats[elemID][f]; f++) {
2624
+ if(!(bDft.match(validFmtRegExp))) {
2625
+ if(debug) throw "The element with and id of '" + elemID + "' has the following incorrect date format assigned to it within the dateFormats parameter: " + bDft;
2626
+ return false;
2627
+ };
2628
+
2629
+ newFormats.push(bDft);
2630
+ };
2631
+
2632
+ fmtBag = fmtBag.concat(newFormats);
2633
+ };
2634
+
2635
+ tmpPartsFound = [0,0,0];
2636
+
2637
+ for(var i = 0, testPart; testPart = testParts[i]; i++) {
2638
+ if(fmt.search(new RegExp('('+testPart+')')) != -1) {
2639
+ partsFound[i] = tmpPartsFound[i] = 1;
2640
+
2641
+ // Create the date format strings to check against later for text input elements
2642
+ if(elem.tagName.toLowerCase() == "input") {
2643
+ matchedPart = fmt.match(new RegExp('('+testPart+')'))[0];
2644
+ newParts = String(matchedPart + "|" + testPart.replace(new RegExp("(" + matchedPart + ")"), "")).replace("||", "|");
2645
+ indParts = newParts.split("|");
2646
+ newFormats = [];
2647
+
2648
+ for(var z = 0, bFmt; bFmt = fmtBag[z]; z++) {
2649
+ for(var x = 0, indPart; indPart = indParts[x]; x++) {
2650
+ if(indPart == matchedPart) continue;
2651
+ newFormats.push(bFmt.replace(new RegExp('(' + testPart + ')(-|$)', 'g'), indPart + "-").replace(/-$/, ""));
2652
+ };
2653
+ };
2654
+
2655
+ fmtBag = fmtBag.concat(newFormats);
2656
+ };
2657
+ };
2658
+ };
2659
+
2660
+ options.formatMasks[elemID] = fmtBag.concat();
2661
+
2662
+ if(elem.tagName.toLowerCase() == "select") {
2663
+ myMin = myMax = 0;
2664
+
2665
+ // If we have a selectList, then try to parse the higher and lower limits
2666
+ var selOptions = elem.options;
2667
+
2668
+ // Check the yyyymmdd
2669
+ if(tmpPartsFound[0] && tmpPartsFound[1] && tmpPartsFound[2]) {
2670
+ var yyyymmdd,
2671
+ cursorDate = false;
2672
+
2673
+ // Remove the disabledDates parameter
2674
+ if("disabledDates" in options) {
2675
+ delete(options.disabledDates);
2676
+ };
2677
+
2678
+ // Dynamically calculate the available "enabled" dates
2679
+ options.enabledDates = {};
2680
+
2681
+ for(i = 0; i < selOptions.length; i++) {
2682
+ for(var f = 0, fmt; fmt = fmtBag[f]; f++) {
2683
+ dt = parseDateString(selOptions[i].value, fmt /*options.formElements[elemID]*/);
2684
+ if(dt) {
2685
+ yyyymmdd = dt.getFullYear() + "" + pad(dt.getMonth()+1) + "" + pad(dt.getDate());
2686
+
2687
+ if(!cursorDate) cursorDate = yyyymmdd;
2688
+
2689
+ options.enabledDates[yyyymmdd] = 1;
2690
+
2691
+ if(!myMin || Number(yyyymmdd) < myMin) {
2692
+ myMin = yyyymmdd;
2693
+ };
2694
+
2695
+ if(!myMax || Number(yyyymmdd) > myMax) {
2696
+ myMax = yyyymmdd;
2697
+ };
2698
+
2699
+ break;
2700
+ };
2701
+ };
2702
+ };
2703
+
2704
+ // Automatically set cursor to first available date (if no bespoke cursorDate was set);
2705
+ if(!options.cursorDate && cursorDate) options.cursorDate = cursorDate;
2706
+
2707
+ } else if(tmpPartsFound[1] && tmpPartsFound[2]) {
2708
+ var yyyymm;
2709
+
2710
+ for(i = 0; i < selOptions.length; i++) {
2711
+ for(var f = 0, fmt; fmt = fmtBag[f]; f++) {
2712
+ dt = parseDateString(selOptions[i].value, fmt /*options.formElements[elemID]*/);
2713
+ if(dt) {
2714
+ yyyymm = dt.getFullYear() + "" + pad(dt.getMonth()+1);
2715
+
2716
+ if(!myMin || Number(yyyymm) < myMin) {
2717
+ myMin = yyyymm;
2718
+ };
2719
+
2720
+ if(!myMax || Number(yyyymm) > myMax) {
2721
+ myMax = yyyymm;
2722
+ };
2723
+
2724
+ break;
2725
+ };
2726
+ };
2727
+ };
2728
+
2729
+ // Round the min & max values to be used as rangeLow & rangeHigh
2730
+ myMin += "" + "01";
2731
+ myMax += "" + daysInMonth(+myMax.substr(4,2) - 1, +myMax.substr(0,4));
2732
+
2733
+ } else if(tmpPartsFound[2]) {
2734
+ var yyyy;
2735
+
2736
+ for(i = 0; i < selOptions.length; i++) {
2737
+ for(var f = 0, fmt; fmt = fmtBag[f]; f++) {
2738
+ dt = parseDateString(selOptions[i].value, fmt /*options.formElements[elemID]*/);
2739
+ if(dt) {
2740
+ yyyy = dt.getFullYear();
2741
+ if(!myMin || Number(yyyy) < myMin) {
2742
+ myMin = yyyy;
2743
+ };
2744
+
2745
+ if(!myMax || Number(yyyy) > myMax) {
2746
+ myMax = yyyy;
2747
+ };
2748
+
2749
+ break;
2750
+ };
2751
+ };
2752
+ };
2753
+
2754
+ // Round the min & max values to be used as rangeLow & rangeHigh
2755
+ myMin += "0101";
2756
+ myMax += "1231";
2757
+ };
2758
+
2759
+ if(myMin && (!options.rangeLow || (+options.rangeLow < +myMin))) options.rangeLow = myMin;
2760
+ if(myMax && (!options.rangeHigh || (+options.rangeHigh > +myMin))) options.rangeHigh = myMax;
2761
+ };
2762
+ };
2763
+
2764
+ if(!(partsFound[0] && partsFound[1] && partsFound[2])) {
2765
+ if(debug) throw "Could not find all of the required date parts for element: " + elem.id;
2766
+ return false;
2767
+ };
2768
+
2769
+ var opts = {
2770
+ formElements:options.formElements,
2771
+ // Form element id
2772
+ id:options.id,
2773
+ // Format masks
2774
+ formatMasks:options.formatMasks,
2775
+ // Non popup datepicker required
2776
+ staticPos:!!(options.staticPos),
2777
+ // Position static datepicker or popup datepicker's button
2778
+ positioned:options.positioned && document.getElementById(options.positioned) ? options.positioned : "",
2779
+ // Ranges stipulated in YYYYMMDD format
2780
+ rangeLow:options.rangeLow && String(options.rangeLow).search(rangeRegExp) != -1 ? options.rangeLow : "",
2781
+ rangeHigh:options.rangeHigh && String(options.rangeHigh).search(rangeRegExp) != -1 ? options.rangeHigh : "",
2782
+ // Status bar format
2783
+ statusFormat:options.statusFormat && String(options.statusFormat).search(validFmtRegExp) != -1 ? options.statusFormat : "",
2784
+ // No fade in/out effect
2785
+ noFadeEffect:!!(options.staticPos) ? true : !!(options.noFadeEffect),
2786
+ // No drag functionality
2787
+ dragDisabled:nodrag || !!(options.staticPos) ? true : !!(options.dragDisabled),
2788
+ // Bespoke tabindex for this datePicker (or it's activation button)
2789
+ bespokeTabIndex:options.bespokeTabindex && typeof options.bespokeTabindex == 'number' ? parseInt(options.bespokeTabindex, 10) : 0,
2790
+ // Bespoke titles
2791
+ bespokeTitles:options.bespokeTitles || {},
2792
+ // Final opacity
2793
+ finalOpacity:options.finalOpacity && typeof options.finalOpacity == 'number' && (options.finalOpacity > 20 && options.finalOpacity <= 100) ? parseInt(+options.finalOpacity, 10) : (!!(options.staticPos) ? 100 : finalOpacity),
2794
+ // Do we hide the form elements on datepicker creation
2795
+ hideInput:!!(options.hideInput),
2796
+ // Do we hide the "today" button
2797
+ noToday:!!(options.noTodayButton),
2798
+ // Do we show week numbers
2799
+ showWeeks:!!(options.showWeeks),
2800
+ // Do we fill the entire grid with dates
2801
+ fillGrid:!!(options.fillGrid),
2802
+ // Do we constrain selection of dates outside the current month
2803
+ constrainSelection:"constrainSelection" in options ? !!(options.constrainSelection) : true,
2804
+ // The date to set the initial cursor to
2805
+ cursorDate:options.cursorDate && String(options.cursorDate).search(rangeRegExp) != -1 ? options.cursorDate : "",
2806
+ // Locate label to set the ARIA labelled-by property
2807
+ labelledBy:findLabelForElement(elem),
2808
+ // Have we been passed a describedBy to set the ARIA decribed-by property...
2809
+ describedBy:(options.describedBy && document.getElementById(options.describedBy)) ? options.describedBy : describedBy && document.getElementById(describedBy) ? describedBy : "",
2810
+ // Callback functions
2811
+ callbacks:options.callbackFunctions ? options.callbackFunctions : {},
2812
+ // Days of the week to highlight (normally the weekend)
2813
+ highlightDays:options.highlightDays && options.highlightDays.length && options.highlightDays.length == 7 ? options.highlightDays : [0,0,0,0,0,1,1],
2814
+ // Days of the week to disable
2815
+ disabledDays:options.disabledDays && options.disabledDays.length && options.disabledDays.length == 7 ? options.disabledDays : [0,0,0,0,0,0,0]
2816
+ };
2817
+
2818
+ if(options.disabledDates) {
2819
+ if(options.enabledDates) delete(options.enabledDates);
2820
+ opts.disabledDates = {};
2821
+ var startD;
2822
+ for(startD in options.disabledDates) {
2823
+ if((String(startD).search(wcDateRegExp) != -1 && options.disabledDates[startD] == 1) || (String(startD).search(rangeRegExp) != -1 && String(options.disabledDates[startD]).search(rangeRegExp) != -1)) {
2824
+ opts.disabledDates[startD] = options.disabledDates[startD];
2825
+ };
2826
+ };
2827
+ } else if(options.enabledDates) {
2828
+ var startD;
2829
+ opts.enabledDates = {};
2830
+ for(startD in options.enabledDates) {
2831
+ if((String(startD).search(wcDateRegExp) != -1 && options.enabledDates[startD] == 1) || (String(startD).search(rangeRegExp) != -1 && String(options.enabledDates[startD]).search(rangeRegExp) != -1)) {
2832
+ opts.enabledDates[startD] = options.enabledDates[startD];
2833
+ };
2834
+ };
2835
+ };
2836
+
2837
+ datePickers[options.id] = new datePicker(opts);
2838
+ datePickers[options.id].callback("create", datePickers[options.id].createCbArgObj());
2839
+ };
2840
+
2841
+ // Used by the button to dictate whether to open or close the datePicker
2842
+ var isVisible = function(id) {
2843
+ return (!id || !(id in datePickers)) ? false : datePickers[id].visible;
2844
+ };
2845
+
2846
+ addEvent(window, 'unload', destroy);
2847
+
2848
+ return {
2849
+ // General event functions...
2850
+ addEvent: function(obj, type, fn) { return addEvent(obj, type, fn); },
2851
+ removeEvent: function(obj, type, fn) { return removeEvent(obj, type, fn); },
2852
+ stopEvent: function(e) { return stopEvent(e); },
2853
+ // Show a single popup datepicker
2854
+ show: function(inpID) { return showDatePicker(inpID, false); },
2855
+ // Hide a popup datepicker
2856
+ hide: function(inpID) { return hideDatePicker(inpID); },
2857
+ // Create a new datepicker
2858
+ createDatePicker: function(options) { addDatePicker(options); },
2859
+ // Destroy a datepicker (remove events and DOM nodes)
2860
+ destroyDatePicker: function(inpID) { destroySingleDatePicker(inpID); },
2861
+ // Check datePicker form elements exist, if not, destroy the datepicker
2862
+ cleanUp: function() { cleanUp(); },
2863
+ // Pretty print a date object according to the format passed in
2864
+ printFormattedDate: function(dt, fmt, useImportedLocale) { return printFormattedDate(dt, fmt, useImportedLocale); },
2865
+ // Update the internal date using the form element value
2866
+ setDateFromInput: function(inpID) { if(!inpID || !(inpID in datePickers)) return false; datePickers[inpID].setDateFromInput(); },
2867
+ // Set low and high date ranges
2868
+ setRangeLow: function(inpID, yyyymmdd) { if(!inpID || !(inpID in datePickers)) { return false; }; datePickers[inpID].setRangeLow(yyyymmdd); },
2869
+ setRangeHigh: function(inpID, yyyymmdd) { if(!inpID || !(inpID in datePickers)) { return false; }; datePickers[inpID].setRangeHigh(yyyymmdd); },
2870
+ // Set bespoke titles for a datepicker instance
2871
+ setBespokeTitles: function(inpID, titles) {if(!inpID || !(inpID in datePickers)) { return false; }; datePickers[inpID].setBespokeTitles(titles); },
2872
+ // Add bespoke titles for a datepicker instance
2873
+ addBespokeTitles: function(inpID, titles) {if(!inpID || !(inpID in datePickers)) { return false; }; datePickers[inpID].addBespokeTitles(titles); },
2874
+ // Attempt to parse a valid date from a date string using the passed in format
2875
+ parseDateString: function(str, format) { return parseDateString(str, format); },
2876
+ // Change global configuration parameters
2877
+ setGlobalVars: function(json) { affectJSON(json); },
2878
+ setSelectedDate: function(inpID, yyyymmdd) { if(!inpID || !(inpID in datePickers)) { return false; }; datePickers[inpID].setSelectedDate(yyyymmdd); },
2879
+ // Is the date valid for selection i.e. not outside ranges etc
2880
+ dateValidForSelection: function(inpID, dt) { if(!inpID || !(inpID in datePickers)) return false; return datePickers[inpID].canDateBeSelected(dt); },
2881
+ // Add disabled and enabled dates
2882
+ addDisabledDates: function(inpID, dts) { if(!inpID || !(inpID in datePickers)) return false; datePickers[inpID].addDisabledDates(dts); },
2883
+ setDisabledDates: function(inpID, dts) { if(!inpID || !(inpID in datePickers)) return false; datePickers[inpID].setDisabledDates(dts); },
2884
+ addEnabledDates: function(inpID, dts) { if(!inpID || !(inpID in datePickers)) return false; datePickers[inpID].addEnabledDates(dts); },
2885
+ setEnabledDates: function(inpID, dts) { if(!inpID || !(inpID in datePickers)) return false; datePickers[inpID].setEnabledDates(dts); },
2886
+ // Disable and enable the datepicker
2887
+ disable: function(inpID) { if(!inpID || !(inpID in datePickers)) return false; datePickers[inpID].disableDatePicker(); },
2888
+ enable: function(inpID) { if(!inpID || !(inpID in datePickers)) return false; datePickers[inpID].enableDatePicker(); },
2889
+ // Set the cursor date
2890
+ setCursorDate: function(inpID, yyyymmdd) { if(!inpID || !(inpID in datePickers)) return false; datePickers[inpID].setCursorDate(yyyymmdd); },
2891
+ // Whats the currently selected date
2892
+ getSelectedDate: function(inpID) { return (!inpID || !(inpID in datePickers)) ? false : datePickers[inpID].returnSelectedDate(); },
2893
+ // Attempt to update the language (causes a redraw of all datepickers on the page)
2894
+ loadLanguage: function() { loadLanguage(); },
2895
+ // Set the debug level i.e. throw errors or fail silently
2896
+ setDebug: function(dbg) { debug = !!(dbg); }
2897
+ };
2898
+ })();