bootstrap-datetimepicker.js 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306
  1. /**
  2. * @license
  3. * =========================================================
  4. * bootstrap-datetimepicker.js
  5. * http://www.eyecon.ro/bootstrap-datepicker
  6. * =========================================================
  7. * Copyright 2012 Stefan Petre
  8. *
  9. * Contributions:
  10. * - Andrew Rowls
  11. * - Thiago de Arruda
  12. *
  13. * Licensed under the Apache License, Version 2.0 (the "License");
  14. * you may not use this file except in compliance with the License.
  15. * You may obtain a copy of the License at
  16. *
  17. * http://www.apache.org/licenses/LICENSE-2.0
  18. *
  19. * Unless required by applicable law or agreed to in writing, software
  20. * distributed under the License is distributed on an "AS IS" BASIS,
  21. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  22. * See the License for the specific language governing permissions and
  23. * limitations under the License.
  24. * =========================================================
  25. */
  26. (function($) {
  27. // Picker object
  28. var smartPhone = (window.orientation != undefined);
  29. var DateTimePicker = function(element, options) {
  30. this.id = dpgId++;
  31. this.init(element, options);
  32. };
  33. var dateToDate = function(dt) {
  34. if (typeof dt === 'string') {
  35. return new Date(dt);
  36. }
  37. return dt;
  38. };
  39. DateTimePicker.prototype = {
  40. constructor: DateTimePicker,
  41. init: function(element, options) {
  42. dates = $.fn.datetimepicker.dates;
  43. var icon;
  44. if (!(options.pickTime || options.pickDate))
  45. throw new Error('Must choose at least one picker');
  46. this.options = options;
  47. this.$element = $(element);
  48. this.language = options.language in dates ? options.language : 'en'
  49. this.pickDate = options.pickDate;
  50. this.pickTime = options.pickTime;
  51. this.isInput = this.$element.is('input');
  52. this.component = false;
  53. this.showTimeFirst = options.showTimeFirst;
  54. if (this.$element.find('.input-append') || this.$element.find('.input-prepend'))
  55. this.component = this.$element.find('.add-on');
  56. this.format = options.format;
  57. if (!this.format) {
  58. if (this.isInput) this.format = this.$element.data('format');
  59. else this.format = this.$element.find('input').data('format');
  60. if (!this.format) this.format = 'MM/dd/yyyy';
  61. }
  62. this._compileFormat();
  63. if (this.component) {
  64. icon = this.component.find('i');
  65. }
  66. if (this.pickTime) {
  67. if (icon && icon.length) this.timeIcon = icon.data('time-icon');
  68. if (!this.timeIcon) this.timeIcon = 'icon-time';
  69. if (!this.dateIcon) this.dateIcon = 'icon-calendar';
  70. icon.addClass(this.timeIcon);
  71. }
  72. if (this.pickDate && (!this.showTimeFirst)) {
  73. if (icon && icon.length) this.dateIcon = icon.data('date-icon');
  74. if (!this.dateIcon) this.dateIcon = 'icon-calendar';
  75. icon.removeClass(this.timeIcon);
  76. icon.addClass(this.dateIcon);
  77. }
  78. this.widget = $(getTemplate(this.timeIcon, this.dateIcon, options.pickDate, options.pickTime, options.pick12HourFormat, options.pickSeconds, options.collapse, options.showTimeFirst)).appendTo('body');
  79. this.minViewMode = options.minViewMode||this.$element.data('date-minviewmode')||0;
  80. if (typeof this.minViewMode === 'string') {
  81. switch (this.minViewMode) {
  82. case 'months':
  83. this.minViewMode = 1;
  84. break;
  85. case 'years':
  86. this.minViewMode = 2;
  87. break;
  88. default:
  89. this.minViewMode = 0;
  90. break;
  91. }
  92. }
  93. this.viewMode = options.viewMode||this.$element.data('date-viewmode')||0;
  94. if (typeof this.viewMode === 'string') {
  95. switch (this.viewMode) {
  96. case 'months':
  97. this.viewMode = 1;
  98. break;
  99. case 'years':
  100. this.viewMode = 2;
  101. break;
  102. default:
  103. this.viewMode = 0;
  104. break;
  105. }
  106. }
  107. this.startViewMode = this.viewMode;
  108. this.weekStart = options.weekStart||this.$element.data('date-weekstart')||0;
  109. this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
  110. this.setStartDate(options.startDate || this.$element.data('date-startdate'));
  111. this.setEndDate(options.endDate || this.$element.data('date-enddate'));
  112. this.fillDow();
  113. this.fillMonths();
  114. this.fillHours();
  115. this.fillMinutes();
  116. this.fillSeconds();
  117. this.update();
  118. this.showMode();
  119. this._attachDatePickerEvents();
  120. },
  121. show: function(e) {
  122. this.widget.show();
  123. this.height = this.component ? this.component.outerHeight() : this.$element.outerHeight();
  124. this.place();
  125. this.$element.trigger({
  126. type: 'show',
  127. date: this._date
  128. });
  129. this._attachDatePickerGlobalEvents();
  130. if (e) {
  131. e.stopPropagation();
  132. e.preventDefault();
  133. }
  134. },
  135. disable: function(){
  136. this.$element.find('input').prop('disabled',true);
  137. this._detachDatePickerEvents();
  138. },
  139. enable: function(){
  140. this.$element.find('input').prop('disabled',false);
  141. this._attachDatePickerEvents();
  142. },
  143. hide: function() {
  144. // Ignore event if in the middle of a picker transition
  145. var collapse = this.widget.find('.collapse')
  146. for (var i = 0; i < collapse.length; i++) {
  147. var collapseData = collapse.eq(i).data('collapse');
  148. if (collapseData && collapseData.transitioning)
  149. return;
  150. }
  151. this.widget.hide();
  152. this.viewMode = this.startViewMode;
  153. this.showMode();
  154. this.set();
  155. this.$element.trigger({
  156. type: 'hide',
  157. date: this._date
  158. });
  159. this._detachDatePickerGlobalEvents();
  160. },
  161. set: function() {
  162. var formatted = '';
  163. if (!this._unset) formatted = this.formatDate(this._date);
  164. if (!this.isInput) {
  165. if (this.component){
  166. var input = this.$element.find('input');
  167. input.val(formatted);
  168. this._resetMaskPos(input);
  169. }
  170. this.$element.data('date', formatted);
  171. } else {
  172. this.$element.val(formatted);
  173. this._resetMaskPos(this.$element);
  174. }
  175. },
  176. setValue: function(newDate) {
  177. if (!newDate) {
  178. this._unset = true;
  179. } else {
  180. this._unset = false;
  181. }
  182. if (typeof newDate === 'string') {
  183. this._date = this.parseDate(newDate);
  184. } else if(newDate) {
  185. this._date = new Date(newDate);
  186. }
  187. this.set();
  188. this.viewDate = UTCDate(this._date.getUTCFullYear(), this._date.getUTCMonth(), 1, 0, 0, 0, 0);
  189. this.fillDate();
  190. this.fillTime();
  191. },
  192. getDate: function() {
  193. if (this._unset) return null;
  194. return new Date(this._date.valueOf());
  195. },
  196. setDate: function(date) {
  197. if (!date) this.setValue(null);
  198. else this.setValue(date.valueOf());
  199. },
  200. setStartDate: function(date) {
  201. if (date instanceof Date) {
  202. this.startDate = date;
  203. } else if (typeof date === 'string') {
  204. this.startDate = new UTCDate(date);
  205. if (! this.startDate.getUTCFullYear()) {
  206. this.startDate = -Infinity;
  207. }
  208. } else {
  209. this.startDate = -Infinity;
  210. }
  211. if (this.viewDate) {
  212. this.update();
  213. }
  214. },
  215. setEndDate: function(date) {
  216. if (date instanceof Date) {
  217. this.endDate = date;
  218. } else if (typeof date === 'string') {
  219. this.endDate = new UTCDate(date);
  220. if (! this.endDate.getUTCFullYear()) {
  221. this.endDate = Infinity;
  222. }
  223. } else {
  224. this.endDate = Infinity;
  225. }
  226. if (this.viewDate) {
  227. this.update();
  228. }
  229. },
  230. getLocalDate: function() {
  231. if (this._unset) return null;
  232. var d = this._date;
  233. return new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(),
  234. d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
  235. },
  236. setLocalDate: function(localDate) {
  237. if (!localDate) this.setValue(null);
  238. else
  239. this.setValue(Date.UTC(
  240. localDate.getFullYear(),
  241. localDate.getMonth(),
  242. localDate.getDate(),
  243. localDate.getHours(),
  244. localDate.getMinutes(),
  245. localDate.getSeconds(),
  246. localDate.getMilliseconds()));
  247. },
  248. place: function(){
  249. var position = 'absolute';
  250. var offset = this.component ? this.component.offset() : this.$element.offset();
  251. this.width = this.component ? this.component.outerWidth() : this.$element.outerWidth();
  252. offset.top = offset.top + this.height;
  253. var $window = $(window);
  254. if ( this.options.width != undefined ) {
  255. this.widget.width( this.options.width );
  256. }
  257. if ( this.options.orientation == 'left' ) {
  258. this.widget.addClass( 'left-oriented' );
  259. offset.left = offset.left - this.widget.width() + 20;
  260. }
  261. if (this._isInFixed()) {
  262. position = 'fixed';
  263. offset.top -= $window.scrollTop();
  264. offset.left -= $window.scrollLeft();
  265. }
  266. if ($window.width() < offset.left + this.widget.outerWidth()) {
  267. offset.right = $window.width() - offset.left - this.width;
  268. offset.left = 'auto';
  269. this.widget.addClass('pull-right');
  270. } else {
  271. offset.right = 'auto';
  272. this.widget.removeClass('pull-right');
  273. }
  274. this.widget.css({
  275. position: position,
  276. top: offset.top,
  277. left: offset.left,
  278. right: offset.right
  279. });
  280. },
  281. notifyChange: function(){
  282. this.$element.trigger({
  283. type: 'changeDate',
  284. date: this.getDate(),
  285. localDate: this.getLocalDate()
  286. });
  287. },
  288. update: function(newDate){
  289. var dateStr = newDate;
  290. if (!dateStr) {
  291. if (this.isInput) {
  292. dateStr = this.$element.val();
  293. } else {
  294. dateStr = this.$element.find('input').val();
  295. }
  296. if (dateStr) {
  297. this._date = this.parseDate(dateStr);
  298. }
  299. if (!this._date) {
  300. var tmp = new Date()
  301. this._date = UTCDate(tmp.getFullYear(),
  302. tmp.getMonth(),
  303. tmp.getDate(),
  304. tmp.getHours(),
  305. tmp.getMinutes(),
  306. tmp.getSeconds(),
  307. tmp.getMilliseconds())
  308. }
  309. }
  310. this.viewDate = UTCDate(this._date.getUTCFullYear(), this._date.getUTCMonth(), 1, 0, 0, 0, 0);
  311. this.fillDate();
  312. this.fillTime();
  313. },
  314. fillDow: function() {
  315. var dowCnt = this.weekStart;
  316. var html = $('<tr>');
  317. while (dowCnt < this.weekStart + 7) {
  318. html.append('<th class="dow">' + dates.daysMin[(dowCnt++) % 7] + '</th>');
  319. }
  320. this.widget.find('.datepicker-days thead').append(html);
  321. },
  322. fillMonths: function() {
  323. var html = '';
  324. var i = 0
  325. while (i < 12) {
  326. html += '<span class="month">' + dates.monthsShort[i++] + '</span>';
  327. }
  328. this.widget.find('.datepicker-months td').append(html);
  329. },
  330. fillDate: function() {
  331. var year = this.viewDate.getUTCFullYear();
  332. var month = this.viewDate.getUTCMonth();
  333. var currentDate = UTCDate(
  334. this._date.getUTCFullYear(),
  335. this._date.getUTCMonth(),
  336. this._date.getUTCDate(),
  337. 0, 0, 0, 0
  338. );
  339. var startYear = typeof this.startDate === 'object' ? this.startDate.getUTCFullYear() : -Infinity;
  340. var startMonth = typeof this.startDate === 'object' ? this.startDate.getUTCMonth() : -1;
  341. var endYear = typeof this.endDate === 'object' ? this.endDate.getUTCFullYear() : Infinity;
  342. var endMonth = typeof this.endDate === 'object' ? this.endDate.getUTCMonth() : 12;
  343. this.widget.find('.datepicker-days').find('.disabled').removeClass('disabled');
  344. this.widget.find('.datepicker-months').find('.disabled').removeClass('disabled');
  345. this.widget.find('.datepicker-years').find('.disabled').removeClass('disabled');
  346. this.widget.find('.datepicker-days th:eq(1)').text(
  347. dates.months[month] + ' ' + year);
  348. var prevMonth = UTCDate(year, month-1, 28, 0, 0, 0, 0);
  349. var day = DPGlobal.getDaysInMonth(
  350. prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
  351. prevMonth.setUTCDate(day);
  352. prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7) % 7);
  353. if ((year == startYear && month <= startMonth) || year < startYear) {
  354. this.widget.find('.datepicker-days th:eq(0)').addClass('disabled');
  355. }
  356. if ((year == endYear && month >= endMonth) || year > endYear) {
  357. this.widget.find('.datepicker-days th:eq(2)').addClass('disabled');
  358. }
  359. var nextMonth = new Date(prevMonth.valueOf());
  360. nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
  361. nextMonth = nextMonth.valueOf();
  362. var html = [];
  363. var row;
  364. var clsName;
  365. while (prevMonth.valueOf() < nextMonth) {
  366. if (prevMonth.getUTCDay() === this.weekStart) {
  367. row = $('<tr>');
  368. html.push(row);
  369. }
  370. clsName = '';
  371. if (prevMonth.getUTCFullYear() < year ||
  372. (prevMonth.getUTCFullYear() == year &&
  373. prevMonth.getUTCMonth() < month)) {
  374. clsName += ' old';
  375. } else if (prevMonth.getUTCFullYear() > year ||
  376. (prevMonth.getUTCFullYear() == year &&
  377. prevMonth.getUTCMonth() > month)) {
  378. clsName += ' new';
  379. }
  380. if (prevMonth.valueOf() === currentDate.valueOf()) {
  381. clsName += ' active';
  382. }
  383. if ((prevMonth.valueOf() + 86400000) <= this.startDate) {
  384. clsName += ' disabled';
  385. }
  386. if (prevMonth.valueOf() > this.endDate) {
  387. clsName += ' disabled';
  388. }
  389. row.append('<td class="day' + clsName + '">' + prevMonth.getUTCDate() + '</td>');
  390. prevMonth.setUTCDate(prevMonth.getUTCDate() + 1);
  391. }
  392. this.widget.find('.datepicker-days tbody').empty().append(html);
  393. var currentYear = this._date.getUTCFullYear();
  394. var months = this.widget.find('.datepicker-months').find(
  395. 'th:eq(1)').text(year).end().find('span').removeClass('active');
  396. if (currentYear === year) {
  397. months.eq(this._date.getUTCMonth()).addClass('active');
  398. }
  399. if (currentYear - 1 < startYear) {
  400. this.widget.find('.datepicker-months th:eq(0)').addClass('disabled');
  401. }
  402. if (currentYear + 1 > endYear) {
  403. this.widget.find('.datepicker-months th:eq(2)').addClass('disabled');
  404. }
  405. for (var i = 0; i < 12; i++) {
  406. if ((year == startYear && startMonth > i) || (year < startYear)) {
  407. $(months[i]).addClass('disabled');
  408. } else if ((year == endYear && endMonth < i) || (year > endYear)) {
  409. $(months[i]).addClass('disabled');
  410. }
  411. }
  412. html = '';
  413. year = parseInt(year/10, 10) * 10;
  414. var yearCont = this.widget.find('.datepicker-years').find(
  415. 'th:eq(1)').text(year + '-' + (year + 9)).end().find('td');
  416. this.widget.find('.datepicker-years').find('th').removeClass('disabled');
  417. if (startYear > year) {
  418. this.widget.find('.datepicker-years').find('th:eq(0)').addClass('disabled');
  419. }
  420. if (endYear < year+9) {
  421. this.widget.find('.datepicker-years').find('th:eq(2)').addClass('disabled');
  422. }
  423. year -= 1;
  424. for (var i = -1; i < 11; i++) {
  425. html += '<span class="year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + ((year < startYear || year > endYear) ? ' disabled' : '') + '">' + year + '</span>';
  426. year += 1;
  427. }
  428. yearCont.html(html);
  429. },
  430. fillHours: function() {
  431. var table = this.widget.find(
  432. '.timepicker .timepicker-hours table');
  433. table.parent().hide();
  434. var html = '';
  435. if (this.options.pick12HourFormat) {
  436. var current = 1;
  437. for (var i = 0; i < 3; i += 1) {
  438. html += '<tr>';
  439. for (var j = 0; j < 4; j += 1) {
  440. var c = current.toString();
  441. html += '<td class="hour">' + padLeft(c, 2, '0') + '</td>';
  442. current++;
  443. }
  444. html += '</tr>'
  445. }
  446. } else {
  447. var current = 0;
  448. for (var i = 0; i < 6; i += 1) {
  449. html += '<tr>';
  450. for (var j = 0; j < 4; j += 1) {
  451. var c = current.toString();
  452. html += '<td class="hour">' + padLeft(c, 2, '0') + '</td>';
  453. current++;
  454. }
  455. html += '</tr>'
  456. }
  457. }
  458. table.html(html);
  459. },
  460. fillMinutes: function() {
  461. var table = this.widget.find(
  462. '.timepicker .timepicker-minutes table');
  463. table.parent().hide();
  464. var html = '';
  465. var current = 0;
  466. for (var i = 0; i < 5; i++) {
  467. html += '<tr>';
  468. for (var j = 0; j < 4; j += 1) {
  469. var c = current.toString();
  470. html += '<td class="minute">' + padLeft(c, 2, '0') + '</td>';
  471. current += 3;
  472. }
  473. html += '</tr>';
  474. }
  475. table.html(html);
  476. },
  477. fillSeconds: function() {
  478. var table = this.widget.find(
  479. '.timepicker .timepicker-seconds table');
  480. table.parent().hide();
  481. var html = '';
  482. var current = 0;
  483. for (var i = 0; i < 5; i++) {
  484. html += '<tr>';
  485. for (var j = 0; j < 4; j += 1) {
  486. var c = current.toString();
  487. html += '<td class="second">' + padLeft(c, 2, '0') + '</td>';
  488. current += 3;
  489. }
  490. html += '</tr>';
  491. }
  492. table.html(html);
  493. },
  494. fillTime: function() {
  495. if (!this._date)
  496. return;
  497. var timeComponents = this.widget.find('.timepicker span[data-time-component]');
  498. var table = timeComponents.closest('table');
  499. var is12HourFormat = this.options.pick12HourFormat;
  500. var hour = this._date.getUTCHours();
  501. var period = 'AM';
  502. if (is12HourFormat) {
  503. if (hour >= 12) period = 'PM';
  504. if (hour === 0) hour = 12;
  505. else if (hour != 12) hour = hour % 12;
  506. this.widget.find(
  507. '.timepicker [data-action=togglePeriod]').text(period);
  508. }
  509. hour = padLeft(hour.toString(), 2, '0');
  510. var minute = padLeft(this._date.getUTCMinutes().toString(), 2, '0');
  511. var second = padLeft(this._date.getUTCSeconds().toString(), 2, '0');
  512. timeComponents.filter('[data-time-component=hours]').text(hour);
  513. timeComponents.filter('[data-time-component=minutes]').text(minute);
  514. timeComponents.filter('[data-time-component=seconds]').text(second);
  515. },
  516. click: function(e) {
  517. e.stopPropagation();
  518. e.preventDefault();
  519. this._unset = false;
  520. var target = $(e.target).closest('span, td, th');
  521. if (target.length === 1) {
  522. if (! target.is('.disabled')) {
  523. switch(target[0].nodeName.toLowerCase()) {
  524. case 'th':
  525. switch(target[0].className) {
  526. case 'switch':
  527. this.showMode(1);
  528. break;
  529. case 'prev':
  530. case 'next':
  531. var vd = this.viewDate;
  532. var navFnc = DPGlobal.modes[this.viewMode].navFnc;
  533. var step = DPGlobal.modes[this.viewMode].navStep;
  534. if (target[0].className === 'prev') step = step * -1;
  535. vd['set' + navFnc](vd['get' + navFnc]() + step);
  536. this.fillDate();
  537. this.set();
  538. break;
  539. }
  540. break;
  541. case 'span':
  542. if (target.is('.month')) {
  543. var month = target.parent().find('span').index(target);
  544. this.viewDate.setUTCMonth(month);
  545. } else {
  546. var year = parseInt(target.text(), 10) || 0;
  547. this.viewDate.setUTCFullYear(year);
  548. }
  549. if (this.viewMode !== 0) {
  550. this._date = UTCDate(
  551. this.viewDate.getUTCFullYear(),
  552. this.viewDate.getUTCMonth(),
  553. this.viewDate.getUTCDate(),
  554. this._date.getUTCHours(),
  555. this._date.getUTCMinutes(),
  556. this._date.getUTCSeconds(),
  557. this._date.getUTCMilliseconds()
  558. );
  559. this.notifyChange();
  560. }
  561. this.showMode(-1);
  562. this.fillDate();
  563. this.set();
  564. break;
  565. case 'td':
  566. if (target.is('.day')) {
  567. var day = parseInt(target.text(), 10) || 1;
  568. var month = this.viewDate.getUTCMonth();
  569. var year = this.viewDate.getUTCFullYear();
  570. if (target.is('.old')) {
  571. if (month === 0) {
  572. month = 11;
  573. year -= 1;
  574. } else {
  575. month -= 1;
  576. }
  577. } else if (target.is('.new')) {
  578. if (month == 11) {
  579. month = 0;
  580. year += 1;
  581. } else {
  582. month += 1;
  583. }
  584. }
  585. this._date = UTCDate(
  586. year, month, day,
  587. this._date.getUTCHours(),
  588. this._date.getUTCMinutes(),
  589. this._date.getUTCSeconds(),
  590. this._date.getUTCMilliseconds()
  591. );
  592. this.viewDate = UTCDate(
  593. year, month, Math.min(28, day) , 0, 0, 0, 0);
  594. this.fillDate();
  595. this.set();
  596. this.notifyChange();
  597. }
  598. break;
  599. }
  600. }
  601. }
  602. },
  603. actions: {
  604. incrementHours: function(e) {
  605. this._date.setUTCHours(this._date.getUTCHours() + 1);
  606. },
  607. incrementMinutes: function(e) {
  608. this._date.setUTCMinutes(this._date.getUTCMinutes() + 1);
  609. },
  610. incrementSeconds: function(e) {
  611. this._date.setUTCSeconds(this._date.getUTCSeconds() + 1);
  612. },
  613. decrementHours: function(e) {
  614. this._date.setUTCHours(this._date.getUTCHours() - 1);
  615. },
  616. decrementMinutes: function(e) {
  617. this._date.setUTCMinutes(this._date.getUTCMinutes() - 1);
  618. },
  619. decrementSeconds: function(e) {
  620. this._date.setUTCSeconds(this._date.getUTCSeconds() - 1);
  621. },
  622. togglePeriod: function(e) {
  623. var hour = this._date.getUTCHours();
  624. if (hour >= 12) hour -= 12;
  625. else hour += 12;
  626. this._date.setUTCHours(hour);
  627. },
  628. showPicker: function() {
  629. this.widget.find('.timepicker > div:not(.timepicker-picker)').hide();
  630. this.widget.find('.timepicker .timepicker-picker').show();
  631. },
  632. showHours: function() {
  633. this.widget.find('.timepicker .timepicker-picker').hide();
  634. this.widget.find('.timepicker .timepicker-hours').show();
  635. },
  636. showMinutes: function() {
  637. this.widget.find('.timepicker .timepicker-picker').hide();
  638. this.widget.find('.timepicker .timepicker-minutes').show();
  639. },
  640. showSeconds: function() {
  641. this.widget.find('.timepicker .timepicker-picker').hide();
  642. this.widget.find('.timepicker .timepicker-seconds').show();
  643. },
  644. selectHour: function(e) {
  645. var tgt = $(e.target);
  646. var value = parseInt(tgt.text(), 10);
  647. if (this.options.pick12HourFormat) {
  648. var current = this._date.getUTCHours();
  649. if (current >= 12) {
  650. if (value != 12) value = (value + 12) % 24;
  651. } else {
  652. if (value === 12) value = 0;
  653. else value = value % 12;
  654. }
  655. }
  656. this._date.setUTCHours(value);
  657. this.actions.showPicker.call(this);
  658. },
  659. selectMinute: function(e) {
  660. var tgt = $(e.target);
  661. var value = parseInt(tgt.text(), 10);
  662. this._date.setUTCMinutes(value);
  663. this.actions.showPicker.call(this);
  664. },
  665. selectSecond: function(e) {
  666. var tgt = $(e.target);
  667. var value = parseInt(tgt.text(), 10);
  668. this._date.setUTCSeconds(value);
  669. this.actions.showPicker.call(this);
  670. }
  671. },
  672. doAction: function(e) {
  673. e.stopPropagation();
  674. e.preventDefault();
  675. if (!this._date) this._date = UTCDate(1970, 0, 0, 0, 0, 0, 0);
  676. var action = $(e.currentTarget).data('action');
  677. var rv = this.actions[action].apply(this, arguments);
  678. this.set();
  679. this.fillTime();
  680. this.notifyChange();
  681. return rv;
  682. },
  683. stopEvent: function(e) {
  684. e.stopPropagation();
  685. e.preventDefault();
  686. },
  687. // part of the following code was taken from
  688. // http://cloud.github.com/downloads/digitalBush/jquery.maskedinput/jquery.maskedinput-1.3.js
  689. keydown: function(e) {
  690. var self = this, k = e.which, input = $(e.target);
  691. if (k == 8 || k == 46) {
  692. // backspace and delete cause the maskPosition
  693. // to be recalculated
  694. setTimeout(function() {
  695. self._resetMaskPos(input);
  696. });
  697. }
  698. },
  699. keypress: function(e) {
  700. var k = e.which;
  701. if (k == 8 || k == 46) {
  702. // For those browsers which will trigger
  703. // keypress on backspace/delete
  704. return;
  705. }
  706. var input = $(e.target);
  707. var c = String.fromCharCode(k);
  708. var val = input.val() || '';
  709. val += c;
  710. var mask = this._mask[this._maskPos];
  711. if (!mask) {
  712. return false;
  713. }
  714. if (mask.end != val.length) {
  715. return;
  716. }
  717. if (!mask.pattern.test(val.slice(mask.start))) {
  718. val = val.slice(0, val.length - 1);
  719. while ((mask = this._mask[this._maskPos]) && mask.character) {
  720. val += mask.character;
  721. // advance mask position past static
  722. // part
  723. this._maskPos++;
  724. }
  725. val += c;
  726. if (mask.end != val.length) {
  727. input.val(val);
  728. return false;
  729. } else {
  730. if (!mask.pattern.test(val.slice(mask.start))) {
  731. input.val(val.slice(0, mask.start));
  732. return false;
  733. } else {
  734. input.val(val);
  735. this._maskPos++;
  736. return false;
  737. }
  738. }
  739. } else {
  740. this._maskPos++;
  741. }
  742. },
  743. change: function(e) {
  744. var input = $(e.target);
  745. var val = input.val();
  746. if (this._formatPattern.test(val)) {
  747. this.update();
  748. this.setValue(this._date.getTime());
  749. this.notifyChange();
  750. this.set();
  751. } else if (val && val.trim()) {
  752. this.setValue(this._date.getTime());
  753. if (this._date) this.set();
  754. else input.val('');
  755. } else {
  756. if (this._date) {
  757. this.setValue(null);
  758. // unset the date when the input is
  759. // erased
  760. this.notifyChange();
  761. this._unset = true;
  762. }
  763. }
  764. this._resetMaskPos(input);
  765. },
  766. showMode: function(dir) {
  767. if (dir) {
  768. this.viewMode = Math.max(this.minViewMode, Math.min(
  769. 2, this.viewMode + dir));
  770. }
  771. this.widget.find('.datepicker > div').hide().filter(
  772. '.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
  773. },
  774. destroy: function() {
  775. this._detachDatePickerEvents();
  776. this._detachDatePickerGlobalEvents();
  777. this.widget.remove();
  778. this.$element.removeData('datetimepicker');
  779. this.component.removeData('datetimepicker');
  780. },
  781. formatDate: function(d) {
  782. return this.format.replace(formatReplacer, function(match) {
  783. var methodName, property, rv, len = match.length;
  784. if (match === 'ms')
  785. len = 1;
  786. property = dateFormatComponents[match].property
  787. if (property === 'Hours12') {
  788. rv = d.getUTCHours();
  789. if (rv === 0) rv = 12;
  790. else if (rv !== 12) rv = rv % 12;
  791. } else if (property === 'Period12') {
  792. if (d.getUTCHours() >= 12) return 'PM';
  793. else return 'AM';
  794. } else {
  795. methodName = 'get' + property;
  796. rv = d[methodName]();
  797. }
  798. if (methodName === 'getUTCMonth') rv = rv + 1;
  799. if (methodName === 'getUTCYear') rv = rv + 1900 - 2000;
  800. return padLeft(rv.toString(), len, '0');
  801. });
  802. },
  803. parseDate: function(str) {
  804. var match, i, property, methodName, value, parsed = {};
  805. if (!(match = this._formatPattern.exec(str)))
  806. return null;
  807. for (i = 1; i < match.length; i++) {
  808. property = this._propertiesByIndex[i];
  809. if (!property)
  810. continue;
  811. value = match[i];
  812. if (/^\d+$/.test(value))
  813. value = parseInt(value, 10);
  814. parsed[property] = value;
  815. }
  816. return this._finishParsingDate(parsed);
  817. },
  818. _resetMaskPos: function(input) {
  819. var val = input.val();
  820. for (var i = 0; i < this._mask.length; i++) {
  821. if (this._mask[i].end > val.length) {
  822. // If the mask has ended then jump to
  823. // the next
  824. this._maskPos = i;
  825. break;
  826. } else if (this._mask[i].end === val.length) {
  827. this._maskPos = i + 1;
  828. break;
  829. }
  830. }
  831. },
  832. _finishParsingDate: function(parsed) {
  833. var year, month, date, hours, minutes, seconds, milliseconds;
  834. year = parsed.UTCFullYear;
  835. if (parsed.UTCYear) year = 2000 + parsed.UTCYear;
  836. if (!year) year = 1970;
  837. if (parsed.UTCMonth) month = parsed.UTCMonth - 1;
  838. else month = 0;
  839. date = parsed.UTCDate || 1;
  840. hours = parsed.UTCHours || 0;
  841. minutes = parsed.UTCMinutes || 0;
  842. seconds = parsed.UTCSeconds || 0;
  843. milliseconds = parsed.UTCMilliseconds || 0;
  844. if (parsed.Hours12) {
  845. hours = parsed.Hours12;
  846. }
  847. if (parsed.Period12) {
  848. if (/pm/i.test(parsed.Period12)) {
  849. if (hours != 12) hours = (hours + 12) % 24;
  850. } else {
  851. hours = hours % 12;
  852. }
  853. }
  854. return UTCDate(year, month, date, hours, minutes, seconds, milliseconds);
  855. },
  856. _compileFormat: function () {
  857. var match, component, components = [], mask = [],
  858. str = this.format, propertiesByIndex = {}, i = 0, pos = 0;
  859. while (match = formatComponent.exec(str)) {
  860. component = match[0];
  861. if (component in dateFormatComponents) {
  862. i++;
  863. propertiesByIndex[i] = dateFormatComponents[component].property;
  864. components.push('\\s*' + dateFormatComponents[component].getPattern(
  865. this) + '\\s*');
  866. mask.push({
  867. pattern: new RegExp(dateFormatComponents[component].getPattern(
  868. this)),
  869. property: dateFormatComponents[component].property,
  870. start: pos,
  871. end: pos += component.length
  872. });
  873. }
  874. else {
  875. components.push(escapeRegExp(component));
  876. mask.push({
  877. pattern: new RegExp(escapeRegExp(component)),
  878. character: component,
  879. start: pos,
  880. end: ++pos
  881. });
  882. }
  883. str = str.slice(component.length);
  884. }
  885. this._mask = mask;
  886. this._maskPos = 0;
  887. this._formatPattern = new RegExp(
  888. '^\\s*' + components.join('') + '\\s*$');
  889. this._propertiesByIndex = propertiesByIndex;
  890. },
  891. _attachDatePickerEvents: function() {
  892. var self = this;
  893. // this handles date picker clicks
  894. this.widget.on('click', '.datepicker *', $.proxy(this.click, this));
  895. // this handles time picker clicks
  896. this.widget.on('click', '[data-action]', $.proxy(this.doAction, this));
  897. this.widget.on('mousedown', $.proxy(this.stopEvent, this));
  898. if (this.pickDate && this.pickTime) {
  899. this.widget.on('click.togglePicker', '.accordion-toggle', function(e) {
  900. e.stopPropagation();
  901. var $this = $(this);
  902. var $parent = $this.closest('ul');
  903. var expanded = $parent.find('.collapse.in');
  904. var closed = $parent.find('.collapse:not(.in)');
  905. if (expanded && expanded.length) {
  906. var collapseData = expanded.data('collapse');
  907. if (collapseData && collapseData.transitioning) return;
  908. expanded.collapse('hide');
  909. closed.collapse('show')
  910. $this.find('i').toggleClass(self.timeIcon + ' ' + self.dateIcon);
  911. self.$element.find('.add-on i').toggleClass(self.timeIcon + ' ' + self.dateIcon);
  912. }
  913. });
  914. }
  915. if (this.isInput) {
  916. this.$element.on({
  917. 'focus': $.proxy(this.show, this),
  918. 'change': $.proxy(this.change, this)
  919. });
  920. if (this.options.maskInput) {
  921. this.$element.on({
  922. 'keydown': $.proxy(this.keydown, this),
  923. 'keypress': $.proxy(this.keypress, this)
  924. });
  925. }
  926. } else {
  927. this.$element.on({
  928. 'change': $.proxy(this.change, this)
  929. }, 'input');
  930. if (this.options.maskInput) {
  931. this.$element.on({
  932. 'keydown': $.proxy(this.keydown, this),
  933. 'keypress': $.proxy(this.keypress, this)
  934. }, 'input');
  935. }
  936. if (this.component){
  937. this.component.on('click', $.proxy(this.show, this));
  938. } else {
  939. this.$element.on('click', $.proxy(this.show, this));
  940. }
  941. }
  942. },
  943. _attachDatePickerGlobalEvents: function() {
  944. $(window).on(
  945. 'resize.datetimepicker' + this.id, $.proxy(this.place, this));
  946. if (!this.isInput) {
  947. $(document).on(
  948. 'mousedown.datetimepicker' + this.id, $.proxy(this.hide, this));
  949. }
  950. },
  951. _detachDatePickerEvents: function() {
  952. this.widget.off('click', '.datepicker *', this.click);
  953. this.widget.off('click', '[data-action]');
  954. this.widget.off('mousedown', this.stopEvent);
  955. if (this.pickDate && this.pickTime) {
  956. this.widget.off('click.togglePicker');
  957. }
  958. if (this.isInput) {
  959. this.$element.off({
  960. 'focus': this.show,
  961. 'change': this.change
  962. });
  963. if (this.options.maskInput) {
  964. this.$element.off({
  965. 'keydown': this.keydown,
  966. 'keypress': this.keypress
  967. });
  968. }
  969. } else {
  970. this.$element.off({
  971. 'change': this.change
  972. }, 'input');
  973. if (this.options.maskInput) {
  974. this.$element.off({
  975. 'keydown': this.keydown,
  976. 'keypress': this.keypress
  977. }, 'input');
  978. }
  979. if (this.component){
  980. this.component.off('click', this.show);
  981. } else {
  982. this.$element.off('click', this.show);
  983. }
  984. }
  985. },
  986. _detachDatePickerGlobalEvents: function () {
  987. $(window).off('resize.datetimepicker' + this.id);
  988. if (!this.isInput) {
  989. $(document).off('mousedown.datetimepicker' + this.id);
  990. }
  991. },
  992. _isInFixed: function() {
  993. if (this.$element) {
  994. var parents = this.$element.parents();
  995. var inFixed = false;
  996. for (var i=0; i<parents.length; i++) {
  997. if ($(parents[i]).css('position') == 'fixed') {
  998. inFixed = true;
  999. break;
  1000. }
  1001. };
  1002. return inFixed;
  1003. } else {
  1004. return false;
  1005. }
  1006. }
  1007. };
  1008. $.fn.datetimepicker = function ( option, val ) {
  1009. return this.each(function () {
  1010. var $this = $(this),
  1011. data = $this.data('datetimepicker'),
  1012. options = typeof option === 'object' && option;
  1013. if (!data) {
  1014. $this.data('datetimepicker', (data = new DateTimePicker(
  1015. this, $.extend({}, $.fn.datetimepicker.defaults,options))));
  1016. }
  1017. if (typeof option === 'string') data[option](val);
  1018. });
  1019. };
  1020. $.fn.datetimepicker.defaults = {
  1021. maskInput: false,
  1022. pickDate: true,
  1023. pickTime: true,
  1024. pick12HourFormat: false,
  1025. pickSeconds: true,
  1026. startDate: -Infinity,
  1027. endDate: Infinity,
  1028. collapse: true,
  1029. showTimeFirst: false
  1030. };
  1031. $.fn.datetimepicker.Constructor = DateTimePicker;
  1032. var dpgId = 0;
  1033. var dates = $.fn.datetimepicker.dates = {
  1034. days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
  1035. "Friday", "Saturday", "Sunday"],
  1036. daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
  1037. daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
  1038. months: ["January", "February", "March", "April", "May", "June",
  1039. "July", "August", "September", "October", "November", "December"],
  1040. monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
  1041. "Aug", "Sep", "Oct", "Nov", "Dec"]
  1042. };
  1043. var dateFormatComponents = {
  1044. dd: {property: 'UTCDate', getPattern: function() { return '(0?[1-9]|[1-2][0-9]|3[0-1])\\b';}},
  1045. MM: {property: 'UTCMonth', getPattern: function() {return '(0?[1-9]|1[0-2])\\b';}},
  1046. yy: {property: 'UTCYear', getPattern: function() {return '(\\d{2})\\b'}},
  1047. yyyy: {property: 'UTCFullYear', getPattern: function() {return '(\\d{4})\\b';}},
  1048. hh: {property: 'UTCHours', getPattern: function() {return '(0?[0-9]|1[0-9]|2[0-3])\\b';}},
  1049. mm: {property: 'UTCMinutes', getPattern: function() {return '(0?[0-9]|[1-5][0-9])\\b';}},
  1050. ss: {property: 'UTCSeconds', getPattern: function() {return '(0?[0-9]|[1-5][0-9])\\b';}},
  1051. ms: {property: 'UTCMilliseconds', getPattern: function() {return '([0-9]{1,3})\\b';}},
  1052. HH: {property: 'Hours12', getPattern: function() {return '(0?[1-9]|1[0-2])\\b';}},
  1053. PP: {property: 'Period12', getPattern: function() {return '(AM|PM|am|pm|Am|aM|Pm|pM)\\b';}}
  1054. };
  1055. var keys = [];
  1056. for (var k in dateFormatComponents) keys.push(k);
  1057. keys[keys.length - 1] += '\\b';
  1058. keys.push('.');
  1059. var formatComponent = new RegExp(keys.join('\\b|'));
  1060. keys.pop();
  1061. var formatReplacer = new RegExp(keys.join('\\b|'), 'g');
  1062. function escapeRegExp(str) {
  1063. // http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
  1064. return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
  1065. }
  1066. function padLeft(s, l, c) {
  1067. if (l < s.length) return s;
  1068. else return Array(l - s.length + 1).join(c || ' ') + s;
  1069. }
  1070. function getTemplate(timeIcon, dateIcon, pickDate, pickTime, is12Hours, showSeconds, collapse, showTimeFirst) {
  1071. if (pickDate && pickTime) {
  1072. return (
  1073. '<div class="bootstrap-datetimepicker-widget dropdown-menu">' +
  1074. '<ul>' +
  1075. '<li' + (collapse ? ' class="collapse ' + (!showTimeFirst ? 'in' : '' ) + '"' : '') + '>' +
  1076. '<div class="datepicker">' +
  1077. DPGlobal.template +
  1078. '</div>' +
  1079. '</li>' +
  1080. '<li class="picker-switch accordion-toggle"><a><i class="' + (showTimeFirst ? dateIcon : timeIcon) + '"></i></a></li>' +
  1081. '<li' + (collapse ? ' class="collapse ' + (showTimeFirst ? 'in' : '' ) + '"' : '') + '>' +
  1082. '<div class="timepicker">' +
  1083. TPGlobal.getTemplate(is12Hours, showSeconds) +
  1084. '</div>' +
  1085. '</li>' +
  1086. '</ul>' +
  1087. '</div>'
  1088. );
  1089. } else if (pickTime) {
  1090. return (
  1091. '<div class="bootstrap-datetimepicker-widget dropdown-menu">' +
  1092. '<div class="timepicker">' +
  1093. TPGlobal.getTemplate(is12Hours, showSeconds) +
  1094. '</div>' +
  1095. '</div>'
  1096. );
  1097. } else {
  1098. return (
  1099. '<div class="bootstrap-datetimepicker-widget dropdown-menu">' +
  1100. '<div class="datepicker">' +
  1101. DPGlobal.template +
  1102. '</div>' +
  1103. '</div>'
  1104. );
  1105. }
  1106. }
  1107. function UTCDate() {
  1108. return new Date(Date.UTC.apply(Date, arguments));
  1109. }
  1110. var DPGlobal = {
  1111. modes: [
  1112. {
  1113. clsName: 'days',
  1114. navFnc: 'UTCMonth',
  1115. navStep: 1
  1116. },
  1117. {
  1118. clsName: 'months',
  1119. navFnc: 'UTCFullYear',
  1120. navStep: 1
  1121. },
  1122. {
  1123. clsName: 'years',
  1124. navFnc: 'UTCFullYear',
  1125. navStep: 10
  1126. }],
  1127. isLeapYear: function (year) {
  1128. return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0))
  1129. },
  1130. getDaysInMonth: function (year, month) {
  1131. return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
  1132. },
  1133. headTemplate:
  1134. '<thead>' +
  1135. '<tr>' +
  1136. '<th class="prev">&lsaquo;</th>' +
  1137. '<th colspan="5" class="switch"></th>' +
  1138. '<th class="next">&rsaquo;</th>' +
  1139. '</tr>' +
  1140. '</thead>',
  1141. contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>'
  1142. };
  1143. DPGlobal.template =
  1144. '<div class="datepicker-days">' +
  1145. '<table class="table-condensed">' +
  1146. DPGlobal.headTemplate +
  1147. '<tbody></tbody>' +
  1148. '</table>' +
  1149. '</div>' +
  1150. '<div class="datepicker-months">' +
  1151. '<table class="table-condensed">' +
  1152. DPGlobal.headTemplate +
  1153. DPGlobal.contTemplate+
  1154. '</table>'+
  1155. '</div>'+
  1156. '<div class="datepicker-years">'+
  1157. '<table class="table-condensed">'+
  1158. DPGlobal.headTemplate+
  1159. DPGlobal.contTemplate+
  1160. '</table>'+
  1161. '</div>';
  1162. var TPGlobal = {
  1163. hourTemplate: '<span data-action="showHours" data-time-component="hours" class="timepicker-hour"></span>',
  1164. minuteTemplate: '<span data-action="showMinutes" data-time-component="minutes" class="timepicker-minute"></span>',
  1165. secondTemplate: '<span data-action="showSeconds" data-time-component="seconds" class="timepicker-second"></span>'
  1166. };
  1167. TPGlobal.getTemplate = function(is12Hours, showSeconds) {
  1168. return (
  1169. '<div class="timepicker-picker">' +
  1170. '<table class="table-condensed"' +
  1171. (is12Hours ? ' data-hour-format="12"' : '') +
  1172. '>' +
  1173. '<tr>' +
  1174. '<td><a href="#" class="btn" data-action="incrementHours"><i class="icon-chevron-up"></i></a></td>' +
  1175. '<td class="separator"></td>' +
  1176. '<td><a href="#" class="btn" data-action="incrementMinutes"><i class="icon-chevron-up"></i></a></td>' +
  1177. (showSeconds ?
  1178. '<td class="separator"></td>' +
  1179. '<td><a href="#" class="btn" data-action="incrementSeconds"><i class="icon-chevron-up"></i></a></td>': '')+
  1180. (is12Hours ? '<td class="separator"></td>' : '') +
  1181. '</tr>' +
  1182. '<tr>' +
  1183. '<td>' + TPGlobal.hourTemplate + '</td> ' +
  1184. '<td class="separator">:</td>' +
  1185. '<td>' + TPGlobal.minuteTemplate + '</td> ' +
  1186. (showSeconds ?
  1187. '<td class="separator">:</td>' +
  1188. '<td>' + TPGlobal.secondTemplate + '</td>' : '') +
  1189. (is12Hours ?
  1190. '<td class="separator"></td>' +
  1191. '<td>' +
  1192. '<button type="button" class="btn btn-primary" data-action="togglePeriod"></button>' +
  1193. '</td>' : '') +
  1194. '</tr>' +
  1195. '<tr>' +
  1196. '<td><a href="#" class="btn" data-action="decrementHours"><i class="icon-chevron-down"></i></a></td>' +
  1197. '<td class="separator"></td>' +
  1198. '<td><a href="#" class="btn" data-action="decrementMinutes"><i class="icon-chevron-down"></i></a></td>' +
  1199. (showSeconds ?
  1200. '<td class="separator"></td>' +
  1201. '<td><a href="#" class="btn" data-action="decrementSeconds"><i class="icon-chevron-down"></i></a></td>': '') +
  1202. (is12Hours ? '<td class="separator"></td>' : '') +
  1203. '</tr>' +
  1204. '</table>' +
  1205. '</div>' +
  1206. '<div class="timepicker-hours" data-action="selectHour">' +
  1207. '<table class="table-condensed">' +
  1208. '</table>'+
  1209. '</div>'+
  1210. '<div class="timepicker-minutes" data-action="selectMinute">' +
  1211. '<table class="table-condensed">' +
  1212. '</table>'+
  1213. '</div>'+
  1214. (showSeconds ?
  1215. '<div class="timepicker-seconds" data-action="selectSecond">' +
  1216. '<table class="table-condensed">' +
  1217. '</table>'+
  1218. '</div>': '')
  1219. );
  1220. }
  1221. })(window.jQuery)