ngx-bootstrap-timepicker.js 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078
  1. import { Injectable, forwardRef, EventEmitter, Component, ChangeDetectionStrategy, ViewEncapsulation, ChangeDetectorRef, Input, Output, NgModule } from '@angular/core';
  2. import { NG_VALUE_ACCESSOR } from '@angular/forms';
  3. import { BehaviorSubject } from 'rxjs';
  4. import { MiniStore, MiniState } from 'ngx-bootstrap/mini-ngrx';
  5. import { CommonModule } from '@angular/common';
  6. /**
  7. * @fileoverview added by tsickle
  8. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  9. */
  10. class TimepickerActions {
  11. /**
  12. * @param {?} value
  13. * @return {?}
  14. */
  15. writeValue(value) {
  16. return {
  17. type: TimepickerActions.WRITE_VALUE,
  18. payload: value
  19. };
  20. }
  21. /**
  22. * @param {?} event
  23. * @return {?}
  24. */
  25. changeHours(event) {
  26. return {
  27. type: TimepickerActions.CHANGE_HOURS,
  28. payload: event
  29. };
  30. }
  31. /**
  32. * @param {?} event
  33. * @return {?}
  34. */
  35. changeMinutes(event) {
  36. return {
  37. type: TimepickerActions.CHANGE_MINUTES,
  38. payload: event
  39. };
  40. }
  41. /**
  42. * @param {?} event
  43. * @return {?}
  44. */
  45. changeSeconds(event) {
  46. return {
  47. type: TimepickerActions.CHANGE_SECONDS,
  48. payload: event
  49. };
  50. }
  51. /**
  52. * @param {?} value
  53. * @return {?}
  54. */
  55. setTime(value) {
  56. return {
  57. type: TimepickerActions.SET_TIME_UNIT,
  58. payload: value
  59. };
  60. }
  61. /**
  62. * @param {?} value
  63. * @return {?}
  64. */
  65. updateControls(value) {
  66. return {
  67. type: TimepickerActions.UPDATE_CONTROLS,
  68. payload: value
  69. };
  70. }
  71. }
  72. TimepickerActions.WRITE_VALUE = '[timepicker] write value from ng model';
  73. TimepickerActions.CHANGE_HOURS = '[timepicker] change hours';
  74. TimepickerActions.CHANGE_MINUTES = '[timepicker] change minutes';
  75. TimepickerActions.CHANGE_SECONDS = '[timepicker] change seconds';
  76. TimepickerActions.SET_TIME_UNIT = '[timepicker] set time unit';
  77. TimepickerActions.UPDATE_CONTROLS = '[timepicker] update controls';
  78. TimepickerActions.decorators = [
  79. { type: Injectable }
  80. ];
  81. /**
  82. * @fileoverview added by tsickle
  83. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  84. */
  85. /** @type {?} */
  86. const dex = 10;
  87. /** @type {?} */
  88. const hoursPerDay = 24;
  89. /** @type {?} */
  90. const hoursPerDayHalf = 12;
  91. /** @type {?} */
  92. const minutesPerHour = 60;
  93. /** @type {?} */
  94. const secondsPerMinute = 60;
  95. /**
  96. * @param {?=} value
  97. * @return {?}
  98. */
  99. function isValidDate(value) {
  100. if (!value) {
  101. return false;
  102. }
  103. if (value instanceof Date && isNaN(value.getHours())) {
  104. return false;
  105. }
  106. if (typeof value === 'string') {
  107. return isValidDate(new Date(value));
  108. }
  109. return true;
  110. }
  111. /**
  112. * @param {?} controls
  113. * @param {?} newDate
  114. * @return {?}
  115. */
  116. function isValidLimit(controls, newDate) {
  117. if (controls.min && newDate < controls.min) {
  118. return false;
  119. }
  120. if (controls.max && newDate > controls.max) {
  121. return false;
  122. }
  123. return true;
  124. }
  125. /**
  126. * @param {?} value
  127. * @return {?}
  128. */
  129. function toNumber(value) {
  130. if (typeof value === 'number') {
  131. return value;
  132. }
  133. return parseInt(value, dex);
  134. }
  135. /**
  136. * @param {?} value
  137. * @param {?=} isPM
  138. * @return {?}
  139. */
  140. function parseHours(value, isPM = false) {
  141. /** @type {?} */
  142. const hour = toNumber(value);
  143. if (isNaN(hour) ||
  144. hour < 0 ||
  145. hour > (isPM ? hoursPerDayHalf : hoursPerDay)) {
  146. return NaN;
  147. }
  148. return hour;
  149. }
  150. /**
  151. * @param {?} value
  152. * @return {?}
  153. */
  154. function parseMinutes(value) {
  155. /** @type {?} */
  156. const minute = toNumber(value);
  157. if (isNaN(minute) || minute < 0 || minute > minutesPerHour) {
  158. return NaN;
  159. }
  160. return minute;
  161. }
  162. /**
  163. * @param {?} value
  164. * @return {?}
  165. */
  166. function parseSeconds(value) {
  167. /** @type {?} */
  168. const seconds = toNumber(value);
  169. if (isNaN(seconds) || seconds < 0 || seconds > secondsPerMinute) {
  170. return NaN;
  171. }
  172. return seconds;
  173. }
  174. /**
  175. * @param {?} value
  176. * @return {?}
  177. */
  178. function parseTime(value) {
  179. if (typeof value === 'string') {
  180. return new Date(value);
  181. }
  182. return value;
  183. }
  184. /**
  185. * @param {?} value
  186. * @param {?} diff
  187. * @return {?}
  188. */
  189. function changeTime(value, diff) {
  190. if (!value) {
  191. return changeTime(createDate(new Date(), 0, 0, 0), diff);
  192. }
  193. /** @type {?} */
  194. let hour = value.getHours();
  195. /** @type {?} */
  196. let minutes = value.getMinutes();
  197. /** @type {?} */
  198. let seconds = value.getSeconds();
  199. if (diff.hour) {
  200. hour = (hour + toNumber(diff.hour)) % hoursPerDay;
  201. if (hour < 0) {
  202. hour += hoursPerDay;
  203. }
  204. }
  205. if (diff.minute) {
  206. minutes = minutes + toNumber(diff.minute);
  207. }
  208. if (diff.seconds) {
  209. seconds = seconds + toNumber(diff.seconds);
  210. }
  211. return createDate(value, hour, minutes, seconds);
  212. }
  213. /**
  214. * @param {?} value
  215. * @param {?} opts
  216. * @return {?}
  217. */
  218. function setTime(value, opts) {
  219. /** @type {?} */
  220. let hour = parseHours(opts.hour);
  221. /** @type {?} */
  222. const minute = parseMinutes(opts.minute);
  223. /** @type {?} */
  224. const seconds = parseSeconds(opts.seconds) || 0;
  225. if (opts.isPM && hour !== 12) {
  226. hour += hoursPerDayHalf;
  227. }
  228. if (!value) {
  229. if (!isNaN(hour) && !isNaN(minute)) {
  230. return createDate(new Date(), hour, minute, seconds);
  231. }
  232. return value;
  233. }
  234. if (isNaN(hour) || isNaN(minute)) {
  235. return value;
  236. }
  237. return createDate(value, hour, minute, seconds);
  238. }
  239. /**
  240. * @param {?} value
  241. * @param {?} hours
  242. * @param {?} minutes
  243. * @param {?} seconds
  244. * @return {?}
  245. */
  246. function createDate(value, hours, minutes, seconds) {
  247. return new Date(value.getFullYear(), value.getMonth(), value.getDate(), hours, minutes, seconds, value.getMilliseconds());
  248. }
  249. /**
  250. * @param {?} value
  251. * @return {?}
  252. */
  253. function padNumber(value) {
  254. /** @type {?} */
  255. const _value = value.toString();
  256. if (_value.length > 1) {
  257. return _value;
  258. }
  259. return `0${_value}`;
  260. }
  261. /**
  262. * @param {?} hours
  263. * @param {?} isPM
  264. * @return {?}
  265. */
  266. function isHourInputValid(hours, isPM) {
  267. return !isNaN(parseHours(hours, isPM));
  268. }
  269. /**
  270. * @param {?} minutes
  271. * @return {?}
  272. */
  273. function isMinuteInputValid(minutes) {
  274. return !isNaN(parseMinutes(minutes));
  275. }
  276. /**
  277. * @param {?} seconds
  278. * @return {?}
  279. */
  280. function isSecondInputValid(seconds) {
  281. return !isNaN(parseSeconds(seconds));
  282. }
  283. /**
  284. * @param {?} diff
  285. * @param {?} max
  286. * @param {?} min
  287. * @return {?}
  288. */
  289. function isInputLimitValid(diff, max, min) {
  290. /** @type {?} */
  291. const newDate = setTime(new Date(), diff);
  292. if (max && newDate > max) {
  293. return false;
  294. }
  295. if (min && newDate < min) {
  296. return false;
  297. }
  298. return true;
  299. }
  300. /**
  301. * @param {?} hours
  302. * @param {?=} minutes
  303. * @param {?=} seconds
  304. * @param {?=} isPM
  305. * @return {?}
  306. */
  307. function isInputValid(hours, minutes = '0', seconds = '0', isPM) {
  308. return isHourInputValid(hours, isPM)
  309. && isMinuteInputValid(minutes)
  310. && isSecondInputValid(seconds);
  311. }
  312. /**
  313. * @fileoverview added by tsickle
  314. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  315. */
  316. /**
  317. * @param {?} state
  318. * @param {?=} event
  319. * @return {?}
  320. */
  321. function canChangeValue(state, event) {
  322. if (state.readonlyInput || state.disabled) {
  323. return false;
  324. }
  325. if (event) {
  326. if (event.source === 'wheel' && !state.mousewheel) {
  327. return false;
  328. }
  329. if (event.source === 'key' && !state.arrowkeys) {
  330. return false;
  331. }
  332. }
  333. return true;
  334. }
  335. /**
  336. * @param {?} event
  337. * @param {?} controls
  338. * @return {?}
  339. */
  340. function canChangeHours(event, controls) {
  341. if (!event.step) {
  342. return false;
  343. }
  344. if (event.step > 0 && !controls.canIncrementHours) {
  345. return false;
  346. }
  347. if (event.step < 0 && !controls.canDecrementHours) {
  348. return false;
  349. }
  350. return true;
  351. }
  352. /**
  353. * @param {?} event
  354. * @param {?} controls
  355. * @return {?}
  356. */
  357. function canChangeMinutes(event, controls) {
  358. if (!event.step) {
  359. return false;
  360. }
  361. if (event.step > 0 && !controls.canIncrementMinutes) {
  362. return false;
  363. }
  364. if (event.step < 0 && !controls.canDecrementMinutes) {
  365. return false;
  366. }
  367. return true;
  368. }
  369. /**
  370. * @param {?} event
  371. * @param {?} controls
  372. * @return {?}
  373. */
  374. function canChangeSeconds(event, controls) {
  375. if (!event.step) {
  376. return false;
  377. }
  378. if (event.step > 0 && !controls.canIncrementSeconds) {
  379. return false;
  380. }
  381. if (event.step < 0 && !controls.canDecrementSeconds) {
  382. return false;
  383. }
  384. return true;
  385. }
  386. /**
  387. * @param {?} state
  388. * @return {?}
  389. */
  390. function getControlsValue(state) {
  391. const { hourStep, minuteStep, secondsStep, readonlyInput, disabled, mousewheel, arrowkeys, showSpinners, showMeridian, showSeconds, meridians, min, max } = state;
  392. return {
  393. hourStep,
  394. minuteStep,
  395. secondsStep,
  396. readonlyInput,
  397. disabled,
  398. mousewheel,
  399. arrowkeys,
  400. showSpinners,
  401. showMeridian,
  402. showSeconds,
  403. meridians,
  404. min,
  405. max
  406. };
  407. }
  408. /**
  409. * @param {?} value
  410. * @param {?} state
  411. * @return {?}
  412. */
  413. function timepickerControls(value, state) {
  414. /** @type {?} */
  415. const hoursPerDayHalf = 12;
  416. const { min, max, hourStep, minuteStep, secondsStep, showSeconds } = state;
  417. /** @type {?} */
  418. const res = {
  419. canIncrementHours: true,
  420. canIncrementMinutes: true,
  421. canIncrementSeconds: true,
  422. canDecrementHours: true,
  423. canDecrementMinutes: true,
  424. canDecrementSeconds: true,
  425. canToggleMeridian: true
  426. };
  427. if (!value) {
  428. return res;
  429. }
  430. // compare dates
  431. if (max) {
  432. /** @type {?} */
  433. const _newHour = changeTime(value, { hour: hourStep });
  434. res.canIncrementHours = max > _newHour;
  435. if (!res.canIncrementHours) {
  436. /** @type {?} */
  437. const _newMinutes = changeTime(value, { minute: minuteStep });
  438. res.canIncrementMinutes = showSeconds
  439. ? max > _newMinutes
  440. : max >= _newMinutes;
  441. }
  442. if (!res.canIncrementMinutes) {
  443. /** @type {?} */
  444. const _newSeconds = changeTime(value, { seconds: secondsStep });
  445. res.canIncrementSeconds = max >= _newSeconds;
  446. }
  447. if (value.getHours() < hoursPerDayHalf) {
  448. res.canToggleMeridian = changeTime(value, { hour: hoursPerDayHalf }) < max;
  449. }
  450. }
  451. if (min) {
  452. /** @type {?} */
  453. const _newHour = changeTime(value, { hour: -hourStep });
  454. res.canDecrementHours = min < _newHour;
  455. if (!res.canDecrementHours) {
  456. /** @type {?} */
  457. const _newMinutes = changeTime(value, { minute: -minuteStep });
  458. res.canDecrementMinutes = showSeconds
  459. ? min < _newMinutes
  460. : min <= _newMinutes;
  461. }
  462. if (!res.canDecrementMinutes) {
  463. /** @type {?} */
  464. const _newSeconds = changeTime(value, { seconds: -secondsStep });
  465. res.canDecrementSeconds = min <= _newSeconds;
  466. }
  467. if (value.getHours() >= hoursPerDayHalf) {
  468. res.canToggleMeridian = changeTime(value, { hour: -hoursPerDayHalf }) > min;
  469. }
  470. }
  471. return res;
  472. }
  473. /**
  474. * @fileoverview added by tsickle
  475. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  476. */
  477. /**
  478. * Provides default configuration values for timepicker
  479. */
  480. class TimepickerConfig {
  481. constructor() {
  482. /**
  483. * hours change step
  484. */
  485. this.hourStep = 1;
  486. /**
  487. * hours change step
  488. */
  489. this.minuteStep = 5;
  490. /**
  491. * seconds changes step
  492. */
  493. this.secondsStep = 10;
  494. /**
  495. * if true works in 12H mode and displays AM/PM. If false works in 24H mode and hides AM/PM
  496. */
  497. this.showMeridian = true;
  498. /**
  499. * meridian labels based on locale
  500. */
  501. this.meridians = ['AM', 'PM'];
  502. /**
  503. * if true hours and minutes fields will be readonly
  504. */
  505. this.readonlyInput = false;
  506. /**
  507. * if true hours and minutes fields will be disabled
  508. */
  509. this.disabled = false;
  510. /**
  511. * if true scroll inside hours and minutes inputs will change time
  512. */
  513. this.mousewheel = true;
  514. /**
  515. * if true the values of hours and minutes can be changed using the up/down arrow keys on the keyboard
  516. */
  517. this.arrowkeys = true;
  518. /**
  519. * if true spinner arrows above and below the inputs will be shown
  520. */
  521. this.showSpinners = true;
  522. /**
  523. * show seconds in timepicker
  524. */
  525. this.showSeconds = false;
  526. /**
  527. * show minutes in timepicker
  528. */
  529. this.showMinutes = true;
  530. /**
  531. * placeholder for hours field in timepicker
  532. */
  533. this.hoursPlaceholder = 'HH';
  534. /**
  535. * placeholder for minutes field in timepicker
  536. */
  537. this.minutesPlaceholder = 'MM';
  538. /**
  539. * placeholder for seconds field in timepicker
  540. */
  541. this.secondsPlaceholder = 'SS';
  542. }
  543. }
  544. TimepickerConfig.decorators = [
  545. { type: Injectable }
  546. ];
  547. /**
  548. * @fileoverview added by tsickle
  549. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  550. */
  551. /** @type {?} */
  552. const initialState = {
  553. value: null,
  554. config: new TimepickerConfig(),
  555. controls: {
  556. canIncrementHours: true,
  557. canIncrementMinutes: true,
  558. canIncrementSeconds: true,
  559. canDecrementHours: true,
  560. canDecrementMinutes: true,
  561. canDecrementSeconds: true,
  562. canToggleMeridian: true
  563. }
  564. };
  565. // tslint:disable-next-line:cyclomatic-complexity
  566. /**
  567. * @param {?=} state
  568. * @param {?=} action
  569. * @return {?}
  570. */
  571. function timepickerReducer(state = initialState, action) {
  572. switch (action.type) {
  573. case TimepickerActions.WRITE_VALUE: {
  574. return Object.assign({}, state, { value: action.payload });
  575. }
  576. case TimepickerActions.CHANGE_HOURS: {
  577. if (!canChangeValue(state.config, action.payload) ||
  578. !canChangeHours(action.payload, state.controls)) {
  579. return state;
  580. }
  581. /** @type {?} */
  582. const _newTime = changeTime(state.value, { hour: action.payload.step });
  583. if ((state.config.max || state.config.min) && !isValidLimit(state.config, _newTime)) {
  584. return state;
  585. }
  586. return Object.assign({}, state, { value: _newTime });
  587. }
  588. case TimepickerActions.CHANGE_MINUTES: {
  589. if (!canChangeValue(state.config, action.payload) ||
  590. !canChangeMinutes(action.payload, state.controls)) {
  591. return state;
  592. }
  593. /** @type {?} */
  594. const _newTime = changeTime(state.value, { minute: action.payload.step });
  595. if ((state.config.max || state.config.min) && !isValidLimit(state.config, _newTime)) {
  596. return state;
  597. }
  598. return Object.assign({}, state, { value: _newTime });
  599. }
  600. case TimepickerActions.CHANGE_SECONDS: {
  601. if (!canChangeValue(state.config, action.payload) ||
  602. !canChangeSeconds(action.payload, state.controls)) {
  603. return state;
  604. }
  605. /** @type {?} */
  606. const _newTime = changeTime(state.value, {
  607. seconds: action.payload.step
  608. });
  609. if ((state.config.max || state.config.min) && !isValidLimit(state.config, _newTime)) {
  610. return state;
  611. }
  612. return Object.assign({}, state, { value: _newTime });
  613. }
  614. case TimepickerActions.SET_TIME_UNIT: {
  615. if (!canChangeValue(state.config)) {
  616. return state;
  617. }
  618. /** @type {?} */
  619. const _newTime = setTime(state.value, action.payload);
  620. return Object.assign({}, state, { value: _newTime });
  621. }
  622. case TimepickerActions.UPDATE_CONTROLS: {
  623. /** @type {?} */
  624. const _newControlsState = timepickerControls(state.value, action.payload);
  625. /** @type {?} */
  626. const _newState = {
  627. value: state.value,
  628. config: action.payload,
  629. controls: _newControlsState
  630. };
  631. if (state.config.showMeridian !== _newState.config.showMeridian) {
  632. if (state.value) {
  633. _newState.value = new Date(state.value);
  634. }
  635. }
  636. return Object.assign({}, state, _newState);
  637. }
  638. default:
  639. return state;
  640. }
  641. }
  642. /**
  643. * @fileoverview added by tsickle
  644. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  645. */
  646. class TimepickerStore extends MiniStore {
  647. constructor() {
  648. /** @type {?} */
  649. const _dispatcher = new BehaviorSubject({
  650. type: '[mini-ngrx] dispatcher init'
  651. });
  652. /** @type {?} */
  653. const state = new MiniState(initialState, _dispatcher, timepickerReducer);
  654. super(_dispatcher, timepickerReducer, state);
  655. }
  656. }
  657. TimepickerStore.decorators = [
  658. { type: Injectable }
  659. ];
  660. /** @nocollapse */
  661. TimepickerStore.ctorParameters = () => [];
  662. /**
  663. * @fileoverview added by tsickle
  664. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  665. */
  666. /** @type {?} */
  667. const TIMEPICKER_CONTROL_VALUE_ACCESSOR = {
  668. provide: NG_VALUE_ACCESSOR,
  669. /* tslint:disable-next-line: no-use-before-declare */
  670. useExisting: forwardRef((/**
  671. * @return {?}
  672. */
  673. () => TimepickerComponent)),
  674. multi: true
  675. };
  676. class TimepickerComponent {
  677. /**
  678. * @param {?} _config
  679. * @param {?} _cd
  680. * @param {?} _store
  681. * @param {?} _timepickerActions
  682. */
  683. constructor(_config, _cd, _store, _timepickerActions) {
  684. this._cd = _cd;
  685. this._store = _store;
  686. this._timepickerActions = _timepickerActions;
  687. /**
  688. * emits true if value is a valid date
  689. */
  690. this.isValid = new EventEmitter();
  691. // min\max validation for input fields
  692. this.invalidHours = false;
  693. this.invalidMinutes = false;
  694. this.invalidSeconds = false;
  695. // control value accessor methods
  696. // tslint:disable-next-line:no-any
  697. this.onChange = Function.prototype;
  698. // tslint:disable-next-line:no-any
  699. this.onTouched = Function.prototype;
  700. Object.assign(this, _config);
  701. this.timepickerSub = _store
  702. .select((/**
  703. * @param {?} state
  704. * @return {?}
  705. */
  706. state => state.value))
  707. .subscribe((/**
  708. * @param {?} value
  709. * @return {?}
  710. */
  711. (value) => {
  712. // update UI values if date changed
  713. this._renderTime(value);
  714. this.onChange(value);
  715. this._store.dispatch(this._timepickerActions.updateControls(getControlsValue(this)));
  716. }));
  717. _store
  718. .select((/**
  719. * @param {?} state
  720. * @return {?}
  721. */
  722. state => state.controls))
  723. .subscribe((/**
  724. * @param {?} controlsState
  725. * @return {?}
  726. */
  727. (controlsState) => {
  728. this.isValid.emit(isInputValid(this.hours, this.minutes, this.seconds, this.isPM()));
  729. Object.assign(this, controlsState);
  730. _cd.markForCheck();
  731. }));
  732. }
  733. /**
  734. * @deprecated - please use `isEditable` instead
  735. * @return {?}
  736. */
  737. get isSpinnersVisible() {
  738. return this.showSpinners && !this.readonlyInput;
  739. }
  740. /**
  741. * @return {?}
  742. */
  743. get isEditable() {
  744. return !(this.readonlyInput || this.disabled);
  745. }
  746. /**
  747. * @return {?}
  748. */
  749. resetValidation() {
  750. this.invalidHours = false;
  751. this.invalidMinutes = false;
  752. this.invalidSeconds = false;
  753. }
  754. /**
  755. * @return {?}
  756. */
  757. isPM() {
  758. return this.showMeridian && this.meridian === this.meridians[1];
  759. }
  760. /**
  761. * @param {?} $event
  762. * @return {?}
  763. */
  764. prevDef($event) {
  765. $event.preventDefault();
  766. }
  767. /**
  768. * @param {?} $event
  769. * @return {?}
  770. */
  771. wheelSign($event) {
  772. return Math.sign($event.deltaY) * -1;
  773. }
  774. /**
  775. * @param {?} changes
  776. * @return {?}
  777. */
  778. ngOnChanges(changes) {
  779. this._store.dispatch(this._timepickerActions.updateControls(getControlsValue(this)));
  780. }
  781. /**
  782. * @param {?} step
  783. * @param {?=} source
  784. * @return {?}
  785. */
  786. changeHours(step, source = '') {
  787. this.resetValidation();
  788. this._store.dispatch(this._timepickerActions.changeHours({ step, source }));
  789. }
  790. /**
  791. * @param {?} step
  792. * @param {?=} source
  793. * @return {?}
  794. */
  795. changeMinutes(step, source = '') {
  796. this.resetValidation();
  797. this._store.dispatch(this._timepickerActions.changeMinutes({ step, source }));
  798. }
  799. /**
  800. * @param {?} step
  801. * @param {?=} source
  802. * @return {?}
  803. */
  804. changeSeconds(step, source = '') {
  805. this.resetValidation();
  806. this._store.dispatch(this._timepickerActions.changeSeconds({ step, source }));
  807. }
  808. /**
  809. * @param {?} hours
  810. * @return {?}
  811. */
  812. updateHours(hours) {
  813. this.resetValidation();
  814. this.hours = hours;
  815. /** @type {?} */
  816. const isValid = isHourInputValid(this.hours, this.isPM()) && this.isValidLimit();
  817. if (!isValid) {
  818. this.invalidHours = true;
  819. this.isValid.emit(false);
  820. this.onChange(null);
  821. return;
  822. }
  823. this._updateTime();
  824. }
  825. /**
  826. * @param {?} minutes
  827. * @return {?}
  828. */
  829. updateMinutes(minutes) {
  830. this.resetValidation();
  831. this.minutes = minutes;
  832. /** @type {?} */
  833. const isValid = isMinuteInputValid(this.minutes) && this.isValidLimit();
  834. if (!isValid) {
  835. this.invalidMinutes = true;
  836. this.isValid.emit(false);
  837. this.onChange(null);
  838. return;
  839. }
  840. this._updateTime();
  841. }
  842. /**
  843. * @param {?} seconds
  844. * @return {?}
  845. */
  846. updateSeconds(seconds) {
  847. this.resetValidation();
  848. this.seconds = seconds;
  849. /** @type {?} */
  850. const isValid = isSecondInputValid(this.seconds) && this.isValidLimit();
  851. if (!isValid) {
  852. this.invalidSeconds = true;
  853. this.isValid.emit(false);
  854. this.onChange(null);
  855. return;
  856. }
  857. this._updateTime();
  858. }
  859. /**
  860. * @return {?}
  861. */
  862. isValidLimit() {
  863. return isInputLimitValid({
  864. hour: this.hours,
  865. minute: this.minutes,
  866. seconds: this.seconds,
  867. isPM: this.isPM()
  868. }, this.max, this.min);
  869. }
  870. /**
  871. * @return {?}
  872. */
  873. _updateTime() {
  874. /** @type {?} */
  875. const _seconds = this.showSeconds ? this.seconds : void 0;
  876. /** @type {?} */
  877. const _minutes = this.showMinutes ? this.minutes : void 0;
  878. if (!isInputValid(this.hours, _minutes, _seconds, this.isPM())) {
  879. this.isValid.emit(false);
  880. this.onChange(null);
  881. return;
  882. }
  883. this._store.dispatch(this._timepickerActions.setTime({
  884. hour: this.hours,
  885. minute: this.minutes,
  886. seconds: this.seconds,
  887. isPM: this.isPM()
  888. }));
  889. }
  890. /**
  891. * @return {?}
  892. */
  893. toggleMeridian() {
  894. if (!this.showMeridian || !this.isEditable) {
  895. return;
  896. }
  897. /** @type {?} */
  898. const _hoursPerDayHalf = 12;
  899. this._store.dispatch(this._timepickerActions.changeHours({
  900. step: _hoursPerDayHalf,
  901. source: ''
  902. }));
  903. }
  904. /**
  905. * Write a new value to the element.
  906. * @param {?} obj
  907. * @return {?}
  908. */
  909. writeValue(obj) {
  910. if (isValidDate(obj)) {
  911. this._store.dispatch(this._timepickerActions.writeValue(parseTime(obj)));
  912. }
  913. else if (obj == null) {
  914. this._store.dispatch(this._timepickerActions.writeValue(null));
  915. }
  916. }
  917. /**
  918. * Set the function to be called when the control receives a change event.
  919. * @param {?} fn
  920. * @return {?}
  921. */
  922. // tslint:disable-next-line:no-any
  923. registerOnChange(fn) {
  924. this.onChange = fn;
  925. }
  926. /**
  927. * Set the function to be called when the control receives a touch event.
  928. * @param {?} fn
  929. * @return {?}
  930. */
  931. registerOnTouched(fn) {
  932. this.onTouched = fn;
  933. }
  934. /**
  935. * This function is called when the control status changes to or from "disabled".
  936. * Depending on the value, it will enable or disable the appropriate DOM element.
  937. *
  938. * @param {?} isDisabled
  939. * @return {?}
  940. */
  941. setDisabledState(isDisabled) {
  942. this.disabled = isDisabled;
  943. this._cd.markForCheck();
  944. }
  945. /**
  946. * @return {?}
  947. */
  948. ngOnDestroy() {
  949. this.timepickerSub.unsubscribe();
  950. }
  951. /**
  952. * @private
  953. * @param {?} value
  954. * @return {?}
  955. */
  956. _renderTime(value) {
  957. if (!isValidDate(value)) {
  958. this.hours = '';
  959. this.minutes = '';
  960. this.seconds = '';
  961. this.meridian = this.meridians[0];
  962. return;
  963. }
  964. /** @type {?} */
  965. const _value = parseTime(value);
  966. /** @type {?} */
  967. const _hoursPerDayHalf = 12;
  968. /** @type {?} */
  969. let _hours = _value.getHours();
  970. if (this.showMeridian) {
  971. this.meridian = this.meridians[_hours >= _hoursPerDayHalf ? 1 : 0];
  972. _hours = _hours % _hoursPerDayHalf;
  973. // should be 12 PM, not 00 PM
  974. if (_hours === 0) {
  975. _hours = _hoursPerDayHalf;
  976. }
  977. }
  978. this.hours = padNumber(_hours);
  979. this.minutes = padNumber(_value.getMinutes());
  980. this.seconds = padNumber(_value.getUTCSeconds());
  981. }
  982. }
  983. TimepickerComponent.decorators = [
  984. { type: Component, args: [{
  985. selector: 'timepicker',
  986. changeDetection: ChangeDetectionStrategy.OnPush,
  987. providers: [TIMEPICKER_CONTROL_VALUE_ACCESSOR, TimepickerStore],
  988. template: "<table>\n <tbody>\n <tr class=\"text-center\" [hidden]=\"!showSpinners\">\n <!-- increment hours button-->\n <td>\n <a class=\"btn btn-link\" [class.disabled]=\"!canIncrementHours || !isEditable\"\n (click)=\"changeHours(hourStep)\"\n ><span class=\"bs-chevron bs-chevron-up\"></span></a>\n </td>\n <!-- divider -->\n <td *ngIf=\"showMinutes\">&nbsp;&nbsp;&nbsp;</td>\n <!-- increment minutes button -->\n <td *ngIf=\"showMinutes\">\n <a class=\"btn btn-link\" [class.disabled]=\"!canIncrementMinutes || !isEditable\"\n (click)=\"changeMinutes(minuteStep)\"\n ><span class=\"bs-chevron bs-chevron-up\"></span></a>\n </td>\n <!-- divider -->\n <td *ngIf=\"showSeconds\">&nbsp;</td>\n <!-- increment seconds button -->\n <td *ngIf=\"showSeconds\">\n <a class=\"btn btn-link\" [class.disabled]=\"!canIncrementSeconds || !isEditable\"\n (click)=\"changeSeconds(secondsStep)\">\n <span class=\"bs-chevron bs-chevron-up\"></span>\n </a>\n </td>\n <!-- space between -->\n <td *ngIf=\"showMeridian\">&nbsp;&nbsp;&nbsp;</td>\n <!-- meridian placeholder-->\n <td *ngIf=\"showMeridian\"></td>\n </tr>\n <tr>\n <!-- hours -->\n <td class=\"form-group\" [class.has-error]=\"invalidHours\">\n <input type=\"text\" [class.is-invalid]=\"invalidHours\"\n class=\"form-control text-center bs-timepicker-field\"\n [placeholder]=\"hoursPlaceholder\"\n maxlength=\"2\"\n [readonly]=\"readonlyInput\"\n [disabled]=\"disabled\"\n [value]=\"hours\"\n (wheel)=\"prevDef($event);changeHours(hourStep * wheelSign($event), 'wheel')\"\n (keydown.ArrowUp)=\"changeHours(hourStep, 'key')\"\n (keydown.ArrowDown)=\"changeHours(-hourStep, 'key')\"\n (change)=\"updateHours($event.target.value)\"></td>\n <!-- divider -->\n <td *ngIf=\"showMinutes\">&nbsp;:&nbsp;</td>\n <!-- minutes -->\n <td class=\"form-group\" *ngIf=\"showMinutes\" [class.has-error]=\"invalidMinutes\">\n <input type=\"text\" [class.is-invalid]=\"invalidMinutes\"\n class=\"form-control text-center bs-timepicker-field\"\n [placeholder]=\"minutesPlaceholder\"\n maxlength=\"2\"\n [readonly]=\"readonlyInput\"\n [disabled]=\"disabled\"\n [value]=\"minutes\"\n (wheel)=\"prevDef($event);changeMinutes(minuteStep * wheelSign($event), 'wheel')\"\n (keydown.ArrowUp)=\"changeMinutes(minuteStep, 'key')\"\n (keydown.ArrowDown)=\"changeMinutes(-minuteStep, 'key')\"\n (change)=\"updateMinutes($event.target.value)\">\n </td>\n <!-- divider -->\n <td *ngIf=\"showSeconds\">&nbsp;:&nbsp;</td>\n <!-- seconds -->\n <td class=\"form-group\" *ngIf=\"showSeconds\" [class.has-error]=\"invalidSeconds\">\n <input type=\"text\" [class.is-invalid]=\"invalidSeconds\"\n class=\"form-control text-center bs-timepicker-field\"\n [placeholder]=\"secondsPlaceholder\"\n maxlength=\"2\"\n [readonly]=\"readonlyInput\"\n [disabled]=\"disabled\"\n [value]=\"seconds\"\n (wheel)=\"prevDef($event);changeSeconds(secondsStep * wheelSign($event), 'wheel')\"\n (keydown.ArrowUp)=\"changeSeconds(secondsStep, 'key')\"\n (keydown.ArrowDown)=\"changeSeconds(-secondsStep, 'key')\"\n (change)=\"updateSeconds($event.target.value)\">\n </td>\n <!-- space between -->\n <td *ngIf=\"showMeridian\">&nbsp;&nbsp;&nbsp;</td>\n <!-- meridian -->\n <td *ngIf=\"showMeridian\">\n <button type=\"button\" class=\"btn btn-default text-center\"\n [disabled]=\"!isEditable || !canToggleMeridian\"\n [class.disabled]=\"!isEditable || !canToggleMeridian\"\n (click)=\"toggleMeridian()\"\n >{{ meridian }}\n </button>\n </td>\n </tr>\n <tr class=\"text-center\" [hidden]=\"!showSpinners\">\n <!-- decrement hours button-->\n <td>\n <a class=\"btn btn-link\" [class.disabled]=\"!canDecrementHours || !isEditable\"\n (click)=\"changeHours(-hourStep)\">\n <span class=\"bs-chevron bs-chevron-down\"></span>\n </a>\n </td>\n <!-- divider -->\n <td *ngIf=\"showMinutes\">&nbsp;&nbsp;&nbsp;</td>\n <!-- decrement minutes button-->\n <td *ngIf=\"showMinutes\">\n <a class=\"btn btn-link\" [class.disabled]=\"!canDecrementMinutes || !isEditable\"\n (click)=\"changeMinutes(-minuteStep)\">\n <span class=\"bs-chevron bs-chevron-down\"></span>\n </a>\n </td>\n <!-- divider -->\n <td *ngIf=\"showSeconds\">&nbsp;</td>\n <!-- decrement seconds button-->\n <td *ngIf=\"showSeconds\">\n <a class=\"btn btn-link\" [class.disabled]=\"!canDecrementSeconds || !isEditable\"\n (click)=\"changeSeconds(-secondsStep)\">\n <span class=\"bs-chevron bs-chevron-down\"></span>\n </a>\n </td>\n <!-- space between -->\n <td *ngIf=\"showMeridian\">&nbsp;&nbsp;&nbsp;</td>\n <!-- meridian placeholder-->\n <td *ngIf=\"showMeridian\"></td>\n </tr>\n </tbody>\n</table>\n",
  989. encapsulation: ViewEncapsulation.None,
  990. styles: [`
  991. .bs-chevron {
  992. border-style: solid;
  993. display: block;
  994. width: 9px;
  995. height: 9px;
  996. position: relative;
  997. border-width: 3px 0px 0 3px;
  998. }
  999. .bs-chevron-up {
  1000. -webkit-transform: rotate(45deg);
  1001. transform: rotate(45deg);
  1002. top: 2px;
  1003. }
  1004. .bs-chevron-down {
  1005. -webkit-transform: rotate(-135deg);
  1006. transform: rotate(-135deg);
  1007. top: -2px;
  1008. }
  1009. .bs-timepicker-field {
  1010. width: 50px;
  1011. padding: .375rem .55rem;
  1012. }
  1013. `]
  1014. }] }
  1015. ];
  1016. /** @nocollapse */
  1017. TimepickerComponent.ctorParameters = () => [
  1018. { type: TimepickerConfig },
  1019. { type: ChangeDetectorRef },
  1020. { type: TimepickerStore },
  1021. { type: TimepickerActions }
  1022. ];
  1023. TimepickerComponent.propDecorators = {
  1024. hourStep: [{ type: Input }],
  1025. minuteStep: [{ type: Input }],
  1026. secondsStep: [{ type: Input }],
  1027. readonlyInput: [{ type: Input }],
  1028. disabled: [{ type: Input }],
  1029. mousewheel: [{ type: Input }],
  1030. arrowkeys: [{ type: Input }],
  1031. showSpinners: [{ type: Input }],
  1032. showMeridian: [{ type: Input }],
  1033. showMinutes: [{ type: Input }],
  1034. showSeconds: [{ type: Input }],
  1035. meridians: [{ type: Input }],
  1036. min: [{ type: Input }],
  1037. max: [{ type: Input }],
  1038. hoursPlaceholder: [{ type: Input }],
  1039. minutesPlaceholder: [{ type: Input }],
  1040. secondsPlaceholder: [{ type: Input }],
  1041. isValid: [{ type: Output }]
  1042. };
  1043. /**
  1044. * @fileoverview added by tsickle
  1045. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  1046. */
  1047. class TimepickerModule {
  1048. /**
  1049. * @return {?}
  1050. */
  1051. static forRoot() {
  1052. return {
  1053. ngModule: TimepickerModule,
  1054. providers: [TimepickerConfig, TimepickerActions, TimepickerStore]
  1055. };
  1056. }
  1057. }
  1058. TimepickerModule.decorators = [
  1059. { type: NgModule, args: [{
  1060. imports: [CommonModule],
  1061. declarations: [TimepickerComponent],
  1062. exports: [TimepickerComponent]
  1063. },] }
  1064. ];
  1065. export { TimepickerActions, TimepickerComponent, TimepickerConfig, TimepickerModule, TimepickerStore, TIMEPICKER_CONTROL_VALUE_ACCESSOR as ɵa };
  1066. //# sourceMappingURL=ngx-bootstrap-timepicker.js.map