PageRenderTime 104ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/app/assets/javascripts/lib/jquery-ui-timepicker-addon.js

https://gitlab.com/sgruhier/railsfrance.org
JavaScript | 985 lines | 748 code | 116 blank | 121 comment | 222 complexity | d96491ab212664b101dd6b4a783f6ad8 MD5 | raw file
  1. /*
  2. * jQuery timepicker addon
  3. * By: Trent Richardson [http://trentrichardson.com]
  4. * Version 0.9.5
  5. * Last Modified: 05/25/2011
  6. *
  7. * Copyright 2011 Trent Richardson
  8. * Dual licensed under the MIT and GPL licenses.
  9. * http://trentrichardson.com/Impromptu/GPL-LICENSE.txt
  10. * http://trentrichardson.com/Impromptu/MIT-LICENSE.txt
  11. *
  12. * HERES THE CSS:
  13. * .ui-timepicker-div .ui-widget-header{ margin-bottom: 8px; }
  14. * .ui-timepicker-div dl{ text-align: left; }
  15. * .ui-timepicker-div dl dt{ height: 25px; }
  16. * .ui-timepicker-div dl dd{ margin: -25px 10px 10px 65px; }
  17. * .ui-timepicker-div td { font-size: 90%; }
  18. */
  19. (function($) {
  20. $.extend($.ui, { timepicker: { version: "0.9.5" } });
  21. /* Time picker manager.
  22. Use the singleton instance of this class, $.timepicker, to interact with the time picker.
  23. Settings for (groups of) time pickers are maintained in an instance object,
  24. allowing multiple different settings on the same page. */
  25. function Timepicker() {
  26. this.regional = []; // Available regional settings, indexed by language code
  27. this.regional[''] = { // Default regional settings
  28. currentText: 'Now',
  29. closeText: 'Done',
  30. ampm: false,
  31. timeFormat: 'hh:mm tt',
  32. timeOnlyTitle: 'Choose Time',
  33. timeText: 'Time',
  34. hourText: 'Hour',
  35. minuteText: 'Minute',
  36. secondText: 'Second',
  37. timezoneText: 'Time Zone'
  38. };
  39. this._defaults = { // Global defaults for all the datetime picker instances
  40. showButtonPanel: true,
  41. timeOnly: false,
  42. showHour: true,
  43. showMinute: true,
  44. showSecond: false,
  45. showTimezone: false,
  46. showTime: true,
  47. stepHour: 0.05,
  48. stepMinute: 0.05,
  49. stepSecond: 0.05,
  50. hour: 0,
  51. minute: 0,
  52. second: 0,
  53. timezone: '+0000',
  54. hourMin: 0,
  55. minuteMin: 0,
  56. secondMin: 0,
  57. hourMax: 23,
  58. minuteMax: 59,
  59. secondMax: 59,
  60. minDateTime: null,
  61. maxDateTime: null,
  62. hourGrid: 0,
  63. minuteGrid: 0,
  64. secondGrid: 0,
  65. alwaysSetTime: true,
  66. separator: ' ',
  67. altFieldTimeOnly: true,
  68. showTimepicker: true,
  69. timezoneList: ["-1100", "-1000", "-0900", "-0800", "-0700", "-0600",
  70. "-0500", "-0400", "-0300", "-0200", "-0100", "+0000",
  71. "+0100", "+0200", "+0300", "+0400", "+0500", "+0600",
  72. "+0700", "+0800", "+0900", "+1000", "+1100", "+1200"]
  73. };
  74. $.extend(this._defaults, this.regional['']);
  75. }
  76. $.extend(Timepicker.prototype, {
  77. $input: null,
  78. $altInput: null,
  79. $timeObj: null,
  80. inst: null,
  81. hour_slider: null,
  82. minute_slider: null,
  83. second_slider: null,
  84. timezone_select: null,
  85. hour: 0,
  86. minute: 0,
  87. second: 0,
  88. timezone: '+0000',
  89. hourMinOriginal: null,
  90. minuteMinOriginal: null,
  91. secondMinOriginal: null,
  92. hourMaxOriginal: null,
  93. minuteMaxOriginal: null,
  94. secondMaxOriginal: null,
  95. ampm: '',
  96. formattedDate: '',
  97. formattedTime: '',
  98. formattedDateTime: '',
  99. timezoneList: ["-1100", "-1000", "-0900", "-0800", "-0700", "-0600",
  100. "-0500", "-0400", "-0300", "-0200", "-0100", "+0000",
  101. "+0100", "+0200", "+0300", "+0400", "+0500", "+0600",
  102. "+0700", "+0800", "+0900", "+1000", "+1100", "+1200"],
  103. /* Override the default settings for all instances of the time picker.
  104. @param settings object - the new settings to use as defaults (anonymous object)
  105. @return the manager object */
  106. setDefaults: function(settings) {
  107. extendRemove(this._defaults, settings || {});
  108. return this;
  109. },
  110. //########################################################################
  111. // Create a new Timepicker instance
  112. //########################################################################
  113. _newInst: function($input, o) {
  114. var tp_inst = new Timepicker(),
  115. inlineSettings = {};
  116. for (var attrName in this._defaults) {
  117. var attrValue = $input.attr('time:' + attrName);
  118. if (attrValue) {
  119. try {
  120. inlineSettings[attrName] = eval(attrValue);
  121. } catch (err) {
  122. inlineSettings[attrName] = attrValue;
  123. }
  124. }
  125. }
  126. tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, o, {
  127. beforeShow: function(input, dp_inst) {
  128. if ($.isFunction(o.beforeShow))
  129. o.beforeShow(input, dp_inst, tp_inst);
  130. },
  131. onChangeMonthYear: function(year, month, dp_inst) {
  132. // Update the time as well : this prevents the time from disappearing from the $input field.
  133. tp_inst._updateDateTime(dp_inst);
  134. if ($.isFunction(o.onChangeMonthYear))
  135. o.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);
  136. },
  137. onClose: function(dateText, dp_inst) {
  138. if (tp_inst.timeDefined === true && $input.val() != '')
  139. tp_inst._updateDateTime(dp_inst);
  140. if ($.isFunction(o.onClose))
  141. o.onClose.call($input[0], dateText, dp_inst, tp_inst);
  142. },
  143. timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
  144. });
  145. tp_inst.hour = tp_inst._defaults.hour;
  146. tp_inst.minute = tp_inst._defaults.minute;
  147. tp_inst.second = tp_inst._defaults.second;
  148. tp_inst.ampm = '';
  149. tp_inst.$input = $input;
  150. if (o.altField)
  151. tp_inst.$altInput = $(o.altField)
  152. .css({ cursor: 'pointer' })
  153. .focus(function(){ $input.trigger("focus"); });
  154. // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
  155. if(tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date)
  156. tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
  157. if(tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date)
  158. tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
  159. if(tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date)
  160. tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
  161. if(tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date)
  162. tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
  163. return tp_inst;
  164. },
  165. //########################################################################
  166. // add our sliders to the calendar
  167. //########################################################################
  168. _addTimePicker: function(dp_inst) {
  169. var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ?
  170. this.$input.val() + ' ' + this.$altInput.val() :
  171. this.$input.val();
  172. this.timeDefined = this._parseTime(currDT);
  173. this._limitMinMaxDateTime(dp_inst, false);
  174. this._injectTimePicker();
  175. },
  176. //########################################################################
  177. // parse the time string from input value or _setTime
  178. //########################################################################
  179. _parseTime: function(timeString, withDate) {
  180. var regstr = this._defaults.timeFormat.toString()
  181. .replace(/h{1,2}/ig, '(\\d?\\d)')
  182. .replace(/m{1,2}/ig, '(\\d?\\d)')
  183. .replace(/s{1,2}/ig, '(\\d?\\d)')
  184. .replace(/t{1,2}/ig, '(am|pm|a|p)?')
  185. .replace(/z{1}/ig, '((\\+|-)\\d\\d\\d\\d)?')
  186. .replace(/\s/g, '\\s?') + '$',
  187. order = this._getFormatPositions(),
  188. treg;
  189. if (!this.inst) this.inst = $.datepicker._getInst(this.$input[0]);
  190. if (withDate || !this._defaults.timeOnly) {
  191. // the time should come after x number of characters and a space.
  192. // x = at least the length of text specified by the date format
  193. var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
  194. // escape special regex characters in the seperator
  195. var specials = new RegExp("[.*+?|()\\[\\]{}\\\\]", "g");
  196. regstr = '.{' + dp_dateFormat.length + ',}' + this._defaults.separator.replace(specials, "\\$&") + regstr;
  197. }
  198. treg = timeString.match(new RegExp(regstr, 'i'));
  199. if (treg) {
  200. if (order.t !== -1)
  201. this.ampm = ((treg[order.t] === undefined || treg[order.t].length === 0) ?
  202. '' :
  203. (treg[order.t].charAt(0).toUpperCase() == 'A') ? 'AM' : 'PM').toUpperCase();
  204. if (order.h !== -1) {
  205. if (this.ampm == 'AM' && treg[order.h] == '12')
  206. this.hour = 0; // 12am = 0 hour
  207. else if (this.ampm == 'PM' && treg[order.h] != '12')
  208. this.hour = (parseFloat(treg[order.h]) + 12).toFixed(0); // 12pm = 12 hour, any other pm = hour + 12
  209. else this.hour = Number(treg[order.h]);
  210. }
  211. if (order.m !== -1) this.minute = Number(treg[order.m]);
  212. if (order.s !== -1) this.second = Number(treg[order.s]);
  213. if (order.z !== -1) this.timezone = treg[order.z];
  214. return true;
  215. }
  216. return false;
  217. },
  218. //########################################################################
  219. // figure out position of time elements.. cause js cant do named captures
  220. //########################################################################
  221. _getFormatPositions: function() {
  222. var finds = this._defaults.timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|t{1,2}|z)/g),
  223. orders = { h: -1, m: -1, s: -1, t: -1, z: -1 };
  224. if (finds)
  225. for (var i = 0; i < finds.length; i++)
  226. if (orders[finds[i].toString().charAt(0)] == -1)
  227. orders[finds[i].toString().charAt(0)] = i + 1;
  228. return orders;
  229. },
  230. //########################################################################
  231. // generate and inject html for timepicker into ui datepicker
  232. //########################################################################
  233. _injectTimePicker: function() {
  234. var $dp = this.inst.dpDiv,
  235. o = this._defaults,
  236. tp_inst = this,
  237. // Added by Peter Medeiros:
  238. // - Figure out what the hour/minute/second max should be based on the step values.
  239. // - Example: if stepMinute is 15, then minMax is 45.
  240. hourMax = (o.hourMax - (o.hourMax % o.stepHour)).toFixed(0),
  241. minMax = (o.minuteMax - (o.minuteMax % o.stepMinute)).toFixed(0),
  242. secMax = (o.secondMax - (o.secondMax % o.stepSecond)).toFixed(0),
  243. dp_id = this.inst.id.toString().replace(/([^A-Za-z0-9_])/g, '');
  244. // Prevent displaying twice
  245. //if ($dp.find("div#ui-timepicker-div-"+ dp_id).length === 0) {
  246. if ($dp.find("div#ui-timepicker-div-"+ dp_id).length === 0 && o.showTimepicker) {
  247. var noDisplay = ' style="display:none;"',
  248. html = '<div class="ui-timepicker-div" id="ui-timepicker-div-' + dp_id + '"><dl>' +
  249. '<dt class="ui_tpicker_time_label" id="ui_tpicker_time_label_' + dp_id + '"' +
  250. ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' +
  251. '<dd class="ui_tpicker_time" id="ui_tpicker_time_' + dp_id + '"' +
  252. ((o.showTime) ? '' : noDisplay) + '></dd>' +
  253. '<dt class="ui_tpicker_hour_label" id="ui_tpicker_hour_label_' + dp_id + '"' +
  254. ((o.showHour) ? '' : noDisplay) + '>' + o.hourText + '</dt>',
  255. hourGridSize = 0,
  256. minuteGridSize = 0,
  257. secondGridSize = 0,
  258. size;
  259. if (o.showHour && o.hourGrid > 0) {
  260. html += '<dd class="ui_tpicker_hour">' +
  261. '<div id="ui_tpicker_hour_' + dp_id + '"' + ((o.showHour) ? '' : noDisplay) + '></div>' +
  262. '<div style="padding-left: 1px"><table><tr>';
  263. for (var h = o.hourMin; h < hourMax; h += o.hourGrid) {
  264. hourGridSize++;
  265. var tmph = (o.ampm && h > 12) ? h-12 : h;
  266. if (tmph < 10) tmph = '0' + tmph;
  267. if (o.ampm) {
  268. if (h == 0) tmph = 12 +'a';
  269. else if (h < 12) tmph += 'a';
  270. else tmph += 'p';
  271. }
  272. html += '<td>' + tmph + '</td>';
  273. }
  274. html += '</tr></table></div>' +
  275. '</dd>';
  276. } else html += '<dd class="ui_tpicker_hour" id="ui_tpicker_hour_' + dp_id + '"' +
  277. ((o.showHour) ? '' : noDisplay) + '></dd>';
  278. html += '<dt class="ui_tpicker_minute_label" id="ui_tpicker_minute_label_' + dp_id + '"' +
  279. ((o.showMinute) ? '' : noDisplay) + '>' + o.minuteText + '</dt>';
  280. if (o.showMinute && o.minuteGrid > 0) {
  281. html += '<dd class="ui_tpicker_minute ui_tpicker_minute_' + o.minuteGrid + '">' +
  282. '<div id="ui_tpicker_minute_' + dp_id + '"' +
  283. ((o.showMinute) ? '' : noDisplay) + '></div>' +
  284. '<div style="padding-left: 1px"><table><tr>';
  285. for (var m = o.minuteMin; m < minMax; m += o.minuteGrid) {
  286. minuteGridSize++;
  287. html += '<td>' + ((m < 10) ? '0' : '') + m + '</td>';
  288. }
  289. html += '</tr></table></div>' +
  290. '</dd>';
  291. } else html += '<dd class="ui_tpicker_minute" id="ui_tpicker_minute_' + dp_id + '"' +
  292. ((o.showMinute) ? '' : noDisplay) + '></dd>';
  293. html += '<dt class="ui_tpicker_second_label" id="ui_tpicker_second_label_' + dp_id + '"' +
  294. ((o.showSecond) ? '' : noDisplay) + '>' + o.secondText + '</dt>';
  295. if (o.showSecond && o.secondGrid > 0) {
  296. html += '<dd class="ui_tpicker_second ui_tpicker_second_' + o.secondGrid + '">' +
  297. '<div id="ui_tpicker_second_' + dp_id + '"' +
  298. ((o.showSecond) ? '' : noDisplay) + '></div>' +
  299. '<div style="padding-left: 1px"><table><tr>';
  300. for (var s = o.secondMin; s < secMax; s += o.secondGrid) {
  301. secondGridSize++;
  302. html += '<td>' + ((s < 10) ? '0' : '') + s + '</td>';
  303. }
  304. html += '</tr></table></div>' +
  305. '</dd>';
  306. } else html += '<dd class="ui_tpicker_second" id="ui_tpicker_second_' + dp_id + '"' +
  307. ((o.showSecond) ? '' : noDisplay) + '></dd>';
  308. html += '<dt class="ui_tpicker_timezone_label" id="ui_tpicker_timezone_label_' + dp_id + '"' +
  309. ((o.showTimezone) ? '' : noDisplay) + '>' + o.timezoneText + '</dt>';
  310. html += '<dd class="ui_tpicker_timezone" id="ui_tpicker_timezone_' + dp_id + '"' +
  311. ((o.showTimezone) ? '' : noDisplay) + '></dd>';
  312. html += '</dl></div>';
  313. $tp = $(html);
  314. // if we only want time picker...
  315. if (o.timeOnly === true) {
  316. $tp.prepend(
  317. '<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' +
  318. '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' +
  319. '</div>');
  320. $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
  321. }
  322. this.hour_slider = $tp.find('#ui_tpicker_hour_'+ dp_id).slider({
  323. orientation: "horizontal",
  324. value: this.hour,
  325. min: o.hourMin,
  326. max: hourMax,
  327. step: o.stepHour,
  328. slide: function(event, ui) {
  329. tp_inst.hour_slider.slider( "option", "value", ui.value);
  330. tp_inst._onTimeChange();
  331. }
  332. });
  333. // Updated by Peter Medeiros:
  334. // - Pass in Event and UI instance into slide function
  335. this.minute_slider = $tp.find('#ui_tpicker_minute_'+ dp_id).slider({
  336. orientation: "horizontal",
  337. value: this.minute,
  338. min: o.minuteMin,
  339. max: minMax,
  340. step: o.stepMinute,
  341. slide: function(event, ui) {
  342. // update the global minute slider instance value with the current slider value
  343. tp_inst.minute_slider.slider( "option", "value", ui.value);
  344. tp_inst._onTimeChange();
  345. }
  346. });
  347. this.second_slider = $tp.find('#ui_tpicker_second_'+ dp_id).slider({
  348. orientation: "horizontal",
  349. value: this.second,
  350. min: o.secondMin,
  351. max: secMax,
  352. step: o.stepSecond,
  353. slide: function(event, ui) {
  354. tp_inst.second_slider.slider( "option", "value", ui.value);
  355. tp_inst._onTimeChange();
  356. }
  357. });
  358. this.timezone_select = $tp.find('#ui_tpicker_timezone_'+ dp_id).append('<select></select>').find("select");
  359. $.fn.append.apply(this.timezone_select,
  360. $.map(o.timezoneList, function(val, idx) {
  361. return $("<option />")
  362. .val(typeof val == "object" ? val.value : val)
  363. .text(typeof val == "object" ? val.label : val);
  364. })
  365. );
  366. this.timezone_select.val((typeof this.timezone != "undefined" && this.timezone != null && this.timezone != "") ? this.timezone : o.timezone);
  367. this.timezone_select.change(function() {
  368. tp_inst._onTimeChange();
  369. });
  370. // Add grid functionality
  371. if (o.showHour && o.hourGrid > 0) {
  372. size = 100 * hourGridSize * o.hourGrid / (hourMax - o.hourMin);
  373. $tp.find(".ui_tpicker_hour table").css({
  374. width: size + "%",
  375. marginLeft: (size / (-2 * hourGridSize)) + "%",
  376. borderCollapse: 'collapse'
  377. }).find("td").each( function(index) {
  378. $(this).click(function() {
  379. var h = $(this).html();
  380. if(o.ampm) {
  381. var ap = h.substring(2).toLowerCase(),
  382. aph = parseInt(h.substring(0,2));
  383. if (ap == 'a') {
  384. if (aph == 12) h = 0;
  385. else h = aph;
  386. } else if (aph == 12) h = 12;
  387. else h = aph + 12;
  388. }
  389. tp_inst.hour_slider.slider("option", "value", h);
  390. tp_inst._onTimeChange();
  391. tp_inst._onSelectHandler();
  392. }).css({
  393. cursor: 'pointer',
  394. width: (100 / hourGridSize) + '%',
  395. textAlign: 'center',
  396. overflow: 'hidden'
  397. });
  398. });
  399. }
  400. if (o.showMinute && o.minuteGrid > 0) {
  401. size = 100 * minuteGridSize * o.minuteGrid / (minMax - o.minuteMin);
  402. $tp.find(".ui_tpicker_minute table").css({
  403. width: size + "%",
  404. marginLeft: (size / (-2 * minuteGridSize)) + "%",
  405. borderCollapse: 'collapse'
  406. }).find("td").each(function(index) {
  407. $(this).click(function() {
  408. tp_inst.minute_slider.slider("option", "value", $(this).html());
  409. tp_inst._onTimeChange();
  410. tp_inst._onSelectHandler();
  411. }).css({
  412. cursor: 'pointer',
  413. width: (100 / minuteGridSize) + '%',
  414. textAlign: 'center',
  415. overflow: 'hidden'
  416. });
  417. });
  418. }
  419. if (o.showSecond && o.secondGrid > 0) {
  420. $tp.find(".ui_tpicker_second table").css({
  421. width: size + "%",
  422. marginLeft: (size / (-2 * secondGridSize)) + "%",
  423. borderCollapse: 'collapse'
  424. }).find("td").each(function(index) {
  425. $(this).click(function() {
  426. tp_inst.second_slider.slider("option", "value", $(this).html());
  427. tp_inst._onTimeChange();
  428. tp_inst._onSelectHandler();
  429. }).css({
  430. cursor: 'pointer',
  431. width: (100 / secondGridSize) + '%',
  432. textAlign: 'center',
  433. overflow: 'hidden'
  434. });
  435. });
  436. }
  437. var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
  438. if ($buttonPanel.length) $buttonPanel.before($tp);
  439. else $dp.append($tp);
  440. this.$timeObj = $tp.find('#ui_tpicker_time_'+ dp_id);
  441. if (this.inst !== null) {
  442. var timeDefined = this.timeDefined;
  443. this._onTimeChange();
  444. this.timeDefined = timeDefined;
  445. }
  446. //Emulate datepicker onSelect behavior. Call on slidestop.
  447. var onSelectDelegate = function() {
  448. tp_inst._onSelectHandler();
  449. };
  450. this.hour_slider.bind('slidestop',onSelectDelegate);
  451. this.minute_slider.bind('slidestop',onSelectDelegate);
  452. this.second_slider.bind('slidestop',onSelectDelegate);
  453. }
  454. },
  455. //########################################################################
  456. // This function tries to limit the ability to go outside the
  457. // min/max date range
  458. //########################################################################
  459. _limitMinMaxDateTime: function(dp_inst, adjustSliders){
  460. var o = this._defaults,
  461. dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);
  462. if(!this._defaults.showTimepicker) return; // No time so nothing to check here
  463. if(this._defaults.minDateTime !== null && dp_date){
  464. var minDateTime = this._defaults.minDateTime,
  465. minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
  466. if(this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null){
  467. this.hourMinOriginal = o.hourMin;
  468. this.minuteMinOriginal = o.minuteMin;
  469. this.secondMinOriginal = o.secondMin;
  470. }
  471. if(dp_inst.settings.timeOnly || minDateTimeDate.getTime() == dp_date.getTime()) {
  472. this._defaults.hourMin = minDateTime.getHours();
  473. if (this.hour <= this._defaults.hourMin) {
  474. this.hour = this._defaults.hourMin;
  475. this._defaults.minuteMin = minDateTime.getMinutes();
  476. if (this.minute <= this._defaults.minuteMin) {
  477. this.minute = this._defaults.minuteMin;
  478. this._defaults.secondMin = minDateTime.getSeconds();
  479. } else {
  480. if(this.second < this._defaults.secondMin) this.second = this._defaults.secondMin;
  481. this._defaults.secondMin = this.secondMinOriginal;
  482. }
  483. } else {
  484. this._defaults.minuteMin = this.minuteMinOriginal;
  485. this._defaults.secondMin = this.secondMinOriginal;
  486. }
  487. }else{
  488. this._defaults.hourMin = this.hourMinOriginal;
  489. this._defaults.minuteMin = this.minuteMinOriginal;
  490. this._defaults.secondMin = this.secondMinOriginal;
  491. }
  492. }
  493. if(this._defaults.maxDateTime !== null && dp_date){
  494. var maxDateTime = this._defaults.maxDateTime,
  495. maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
  496. if(this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null){
  497. this.hourMaxOriginal = o.hourMax;
  498. this.minuteMaxOriginal = o.minuteMax;
  499. this.secondMaxOriginal = o.secondMax;
  500. }
  501. if(dp_inst.settings.timeOnly || maxDateTimeDate.getTime() == dp_date.getTime()){
  502. this._defaults.hourMax = maxDateTime.getHours();
  503. if (this.hour >= this._defaults.hourMax) {
  504. this.hour = this._defaults.hourMax;
  505. this._defaults.minuteMax = maxDateTime.getMinutes();
  506. if (this.minute >= this._defaults.minuteMax) {
  507. this.minute = this._defaults.minuteMax;
  508. this._defaults.secondMin = maxDateTime.getSeconds();
  509. } else {
  510. if(this.second > this._defaults.secondMax) this.second = this._defaults.secondMax;
  511. this._defaults.secondMax = this.secondMaxOriginal;
  512. }
  513. } else {
  514. this._defaults.minuteMax = this.minuteMaxOriginal;
  515. this._defaults.secondMax = this.secondMaxOriginal;
  516. }
  517. }else{
  518. this._defaults.hourMax = this.hourMaxOriginal;
  519. this._defaults.minuteMax = this.minuteMaxOriginal;
  520. this._defaults.secondMax = this.secondMaxOriginal;
  521. }
  522. }
  523. if(adjustSliders !== undefined && adjustSliders === true){
  524. this.hour_slider.slider("option", { min: this._defaults.hourMin, max: this._defaults.hourMax }).slider('value', this.hour);
  525. this.minute_slider.slider("option", { min: this._defaults.minuteMin, max: this._defaults.minuteMax }).slider('value', this.minute);
  526. this.second_slider.slider("option", { min: this._defaults.secondMin, max: this._defaults.secondMax }).slider('value', this.second);
  527. }
  528. },
  529. //########################################################################
  530. // when a slider moves, set the internal time...
  531. // on time change is also called when the time is updated in the text field
  532. //########################################################################
  533. _onTimeChange: function() {
  534. var hour = (this.hour_slider) ? this.hour_slider.slider('value') : false,
  535. minute = (this.minute_slider) ? this.minute_slider.slider('value') : false,
  536. second = (this.second_slider) ? this.second_slider.slider('value') : false,
  537. timezone = (this.timezone_select) ? this.timezone_select.val() : false;
  538. if (hour !== false) hour = parseInt(hour,10);
  539. if (minute !== false) minute = parseInt(minute,10);
  540. if (second !== false) second = parseInt(second,10);
  541. var ampm = (hour < 12) ? 'AM' : 'PM';
  542. // If the update was done in the input field, the input field should not be updated.
  543. // If the update was done using the sliders, update the input field.
  544. var hasChanged = (hour != this.hour || minute != this.minute || second != this.second || (this.ampm.length > 0 && this.ampm != ampm) || timezone != this.timezone);
  545. if (hasChanged) {
  546. if (hour !== false)this.hour = hour;
  547. if (minute !== false) this.minute = minute;
  548. if (second !== false) this.second = second;
  549. if (timezone !== false) this.timezone = timezone;
  550. this._limitMinMaxDateTime(this.inst, true);
  551. }
  552. if (this._defaults.ampm) this.ampm = ampm;
  553. this._formatTime();
  554. if (this.$timeObj) this.$timeObj.text(this.formattedTime);
  555. this.timeDefined = true;
  556. if (hasChanged) this._updateDateTime();
  557. },
  558. //########################################################################
  559. // call custom onSelect.
  560. // bind to sliders slidestop, and grid click.
  561. //########################################################################
  562. _onSelectHandler: function() {
  563. var onSelect = this._defaults['onSelect'];
  564. var inputEl = this.$input ? this.$input[0] : null;
  565. if (onSelect && inputEl) {
  566. onSelect.apply(inputEl, [this.formattedDateTime, this]);
  567. }
  568. },
  569. //########################################################################
  570. // format the time all pretty...
  571. //########################################################################
  572. _formatTime: function(time, format, ampm) {
  573. if (ampm == undefined) ampm = this._defaults.ampm;
  574. time = time || { hour: this.hour, minute: this.minute, second: this.second, ampm: this.ampm, timezone: this.timezone };
  575. var tmptime = format || this._defaults.timeFormat.toString();
  576. if (ampm) {
  577. var hour12 = ((time.ampm == 'AM') ? (time.hour) : (time.hour % 12));
  578. hour12 = (Number(hour12) === 0) ? 12 : hour12;
  579. tmptime = tmptime.toString()
  580. .replace(/hh/g, ((hour12 < 10) ? '0' : '') + hour12)
  581. .replace(/h/g, hour12)
  582. .replace(/mm/g, ((time.minute < 10) ? '0' : '') + time.minute)
  583. .replace(/m/g, time.minute)
  584. .replace(/ss/g, ((time.second < 10) ? '0' : '') + time.second)
  585. .replace(/s/g, time.second)
  586. .replace(/TT/g, time.ampm.toUpperCase())
  587. .replace(/Tt/g, time.ampm.toUpperCase())
  588. .replace(/tT/g, time.ampm.toLowerCase())
  589. .replace(/tt/g, time.ampm.toLowerCase())
  590. .replace(/T/g, time.ampm.charAt(0).toUpperCase())
  591. .replace(/t/g, time.ampm.charAt(0).toLowerCase())
  592. .replace(/z/g, time.timezone);
  593. } else {
  594. tmptime = tmptime.toString()
  595. .replace(/hh/g, ((time.hour < 10) ? '0' : '') + time.hour)
  596. .replace(/h/g, time.hour)
  597. .replace(/mm/g, ((time.minute < 10) ? '0' : '') + time.minute)
  598. .replace(/m/g, time.minute)
  599. .replace(/ss/g, ((time.second < 10) ? '0' : '') + time.second)
  600. .replace(/s/g, time.second)
  601. .replace(/z/g, time.timezone);
  602. tmptime = $.trim(tmptime.replace(/t/gi, ''));
  603. }
  604. if (arguments.length) return tmptime;
  605. else this.formattedTime = tmptime;
  606. },
  607. //########################################################################
  608. // update our input with the new date time..
  609. //########################################################################
  610. _updateDateTime: function(dp_inst) {
  611. dp_inst = this.inst || dp_inst,
  612. dt = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay),
  613. dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
  614. formatCfg = $.datepicker._getFormatConfig(dp_inst),
  615. timeAvailable = dt !== null && this.timeDefined;
  616. this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);
  617. var formattedDateTime = this.formattedDate;
  618. if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0))
  619. return;
  620. if (this._defaults.timeOnly === true) {
  621. formattedDateTime = this.formattedTime;
  622. } else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) {
  623. formattedDateTime += this._defaults.separator + this.formattedTime;
  624. }
  625. this.formattedDateTime = formattedDateTime;
  626. if(!this._defaults.showTimepicker) {
  627. this.$input.val(this.formattedDate);
  628. } else if (this.$altInput && this._defaults.altFieldTimeOnly === true) {
  629. this.$altInput.val(this.formattedTime);
  630. this.$input.val(this.formattedDate);
  631. } else if(this.$altInput) {
  632. this.$altInput.val(formattedDateTime);
  633. this.$input.val(formattedDateTime);
  634. } else {
  635. this.$input.val(formattedDateTime);
  636. }
  637. this.$input.trigger("change");
  638. }
  639. });
  640. $.fn.extend({
  641. //########################################################################
  642. // shorthand just to use timepicker..
  643. //########################################################################
  644. timepicker: function(o) {
  645. o = o || {};
  646. var tmp_args = arguments;
  647. if (typeof o == 'object') tmp_args[0] = $.extend(o, { timeOnly: true });
  648. return $(this).each(function() {
  649. $.fn.datetimepicker.apply($(this), tmp_args);
  650. });
  651. },
  652. //########################################################################
  653. // extend timepicker to datepicker
  654. //########################################################################
  655. datetimepicker: function(o) {
  656. o = o || {};
  657. var $input = this,
  658. tmp_args = arguments;
  659. if (typeof(o) == 'string'){
  660. if(o == 'getDate')
  661. return $.fn.datepicker.apply($(this[0]), tmp_args);
  662. else
  663. return this.each(function() {
  664. var $t = $(this);
  665. $t.datepicker.apply($t, tmp_args);
  666. });
  667. }
  668. else
  669. return this.each(function() {
  670. var $t = $(this);
  671. $t.datepicker($.timepicker._newInst($t, o)._defaults);
  672. });
  673. }
  674. });
  675. //########################################################################
  676. // the bad hack :/ override datepicker so it doesnt close on select
  677. // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
  678. //########################################################################
  679. $.datepicker._base_selectDate = $.datepicker._selectDate;
  680. $.datepicker._selectDate = function (id, dateStr) {
  681. var inst = this._getInst($(id)[0]),
  682. tp_inst = this._get(inst, 'timepicker');
  683. if (tp_inst) {
  684. tp_inst._limitMinMaxDateTime(inst, true);
  685. inst.inline = inst.stay_open = true;
  686. //This way the onSelect handler called from calendarpicker get the full dateTime
  687. this._base_selectDate(id, dateStr + tp_inst._defaults.separator + tp_inst.formattedTime);
  688. inst.inline = inst.stay_open = false;
  689. this._notifyChange(inst);
  690. this._updateDatepicker(inst);
  691. }
  692. else this._base_selectDate(id, dateStr);
  693. };
  694. //#############################################################################################
  695. // second bad hack :/ override datepicker so it triggers an event when changing the input field
  696. // and does not redraw the datepicker on every selectDate event
  697. //#############################################################################################
  698. $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
  699. $.datepicker._updateDatepicker = function(inst) {
  700. if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
  701. this._base_updateDatepicker(inst);
  702. // Reload the time control when changing something in the input text field.
  703. var tp_inst = this._get(inst, 'timepicker');
  704. if(tp_inst) tp_inst._addTimePicker(inst);
  705. }
  706. };
  707. //#######################################################################################
  708. // third bad hack :/ override datepicker so it allows spaces and colan in the input field
  709. //#######################################################################################
  710. $.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
  711. $.datepicker._doKeyPress = function(event) {
  712. var inst = $.datepicker._getInst(event.target),
  713. tp_inst = $.datepicker._get(inst, 'timepicker');
  714. if (tp_inst) {
  715. if ($.datepicker._get(inst, 'constrainInput')) {
  716. var ampm = tp_inst._defaults.ampm,
  717. datetimeChars = tp_inst._defaults.timeFormat.toString()
  718. .replace(/[hms]/g, '')
  719. .replace(/TT/g, ampm ? 'APM' : '')
  720. .replace(/Tt/g, ampm ? 'AaPpMm' : '')
  721. .replace(/tT/g, ampm ? 'AaPpMm' : '')
  722. .replace(/T/g, ampm ? 'AP' : '')
  723. .replace(/tt/g, ampm ? 'apm' : '')
  724. .replace(/t/g, ampm ? 'ap' : '') +
  725. " " +
  726. tp_inst._defaults.separator +
  727. $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
  728. chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
  729. return event.ctrlKey || (chr < ' ' || !datetimeChars || datetimeChars.indexOf(chr) > -1);
  730. }
  731. }
  732. return $.datepicker._base_doKeyPress(event);
  733. };
  734. //#######################################################################################
  735. // Override key up event to sync manual input changes.
  736. //#######################################################################################
  737. $.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
  738. $.datepicker._doKeyUp = function (event) {
  739. var inst = $.datepicker._getInst(event.target),
  740. tp_inst = $.datepicker._get(inst, 'timepicker');
  741. if (tp_inst) {
  742. if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) {
  743. try {
  744. $.datepicker._updateDatepicker(inst);
  745. }
  746. catch (err) {
  747. $.datepicker.log(err);
  748. }
  749. }
  750. }
  751. return $.datepicker._base_doKeyUp(event);
  752. };
  753. //#######################################################################################
  754. // override "Today" button to also grab the time.
  755. //#######################################################################################
  756. $.datepicker._base_gotoToday = $.datepicker._gotoToday;
  757. $.datepicker._gotoToday = function(id) {
  758. this._base_gotoToday(id);
  759. this._setTime(this._getInst($(id)[0]), new Date());
  760. };
  761. //#######################################################################################
  762. // Disable & enable the Time in the datetimepicker
  763. //#######################################################################################
  764. $.datepicker._disableTimepickerDatepicker = function(target, date, withDate) {
  765. var inst = this._getInst(target),
  766. tp_inst = this._get(inst, 'timepicker');
  767. $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
  768. if (tp_inst) {
  769. tp_inst._defaults.showTimepicker = false;
  770. tp_inst._updateDateTime(inst);
  771. }
  772. };
  773. $.datepicker._enableTimepickerDatepicker = function(target, date, withDate) {
  774. var inst = this._getInst(target),
  775. tp_inst = this._get(inst, 'timepicker');
  776. $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
  777. if (tp_inst) {
  778. tp_inst._defaults.showTimepicker = true;
  779. tp_inst._addTimePicker(inst); // Could be disabled on page load
  780. tp_inst._updateDateTime(inst);
  781. }
  782. };
  783. //#######################################################################################
  784. // Create our own set time function
  785. //#######################################################################################
  786. $.datepicker._setTime = function(inst, date) {
  787. var tp_inst = this._get(inst, 'timepicker');
  788. if (tp_inst) {
  789. var defaults = tp_inst._defaults,
  790. // calling _setTime with no date sets time to defaults
  791. hour = date ? date.getHours() : defaults.hour,
  792. minute = date ? date.getMinutes() : defaults.minute,
  793. second = date ? date.getSeconds() : defaults.second;
  794. //check if within min/max times..
  795. if ((hour < defaults.hourMin || hour > defaults.hourMax) || (minute < defaults.minuteMin || minute > defaults.minuteMax) || (second < defaults.secondMin || second > defaults.secondMax)) {
  796. hour = defaults.hourMin;
  797. minute = defaults.minuteMin;
  798. second = defaults.secondMin;
  799. }
  800. if (tp_inst.hour_slider) tp_inst.hour_slider.slider('value', hour);
  801. else tp_inst.hour = hour;
  802. if (tp_inst.minute_slider) tp_inst.minute_slider.slider('value', minute);
  803. else tp_inst.minute = minute;
  804. if (tp_inst.second_slider) tp_inst.second_slider.slider('value', second);
  805. else tp_inst.second = second;
  806. tp_inst._onTimeChange();
  807. tp_inst._updateDateTime(inst);
  808. }
  809. };
  810. //#######################################################################################
  811. // Create new public method to set only time, callable as $().datepicker('setTime', date)
  812. //#######################################################################################
  813. $.datepicker._setTimeDatepicker = function(target, date, withDate) {
  814. var inst = this._getInst(target),
  815. tp_inst = this._get(inst, 'timepicker');
  816. if (tp_inst) {
  817. this._setDateFromField(inst);
  818. var tp_date;
  819. if (date) {
  820. if (typeof date == "string") {
  821. tp_inst._parseTime(date, withDate);
  822. tp_date = new Date();
  823. tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second);
  824. }
  825. else tp_date = new Date(date.getTime());
  826. if (tp_date.toString() == 'Invalid Date') tp_date = undefined;
  827. this._setTime(inst, tp_date);
  828. }
  829. }
  830. };
  831. //#######################################################################################
  832. // override setDate() to allow setting time too within Date object
  833. //#######################################################################################
  834. $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
  835. $.datepicker._setDateDatepicker = function(target, date) {
  836. var inst = this._getInst(target),
  837. tp_date = (date instanceof Date) ? new Date(date.getTime()) : date;
  838. this._updateDatepicker(inst);
  839. this._base_setDateDatepicker.apply(this, arguments);
  840. this._setTimeDatepicker(target, tp_date, true);
  841. };
  842. //#######################################################################################
  843. // override getDate() to allow getting time too within Date object
  844. //#######################################################################################
  845. $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
  846. $.datepicker._getDateDatepicker = function(target, noDefault) {
  847. var inst = this._getInst(target),
  848. tp_inst = this._get(inst, 'timepicker');
  849. if (tp_inst) {
  850. this._setDateFromField(inst, noDefault);
  851. var date = this._getDate(inst);
  852. if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second);
  853. return date;
  854. }
  855. return this._base_getDateDatepicker(target, noDefault);
  856. };
  857. //#######################################################################################
  858. // jQuery extend now ignores nulls!
  859. //#######################################################################################
  860. function extendRemove(target, props) {
  861. $.extend(target, props);
  862. for (var name in props)
  863. if (props[name] === null || props[name] === undefined)
  864. target[name] = props[name];
  865. return target;
  866. }
  867. $.timepicker = new Timepicker(); // singleton instance
  868. $.timepicker.version = "0.9.5";
  869. })(jQuery);