bootstrap-datetimepicker.js 43 KB

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