datetime.js 36KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. var __extends = (this && this.__extends) || (function () {
  2. var extendStatics = Object.setPrototypeOf ||
  3. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  4. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  5. return function (d, b) {
  6. extendStatics(d, b);
  7. function __() { this.constructor = d; }
  8. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  9. };
  10. })();
  11. var __assign = (this && this.__assign) || Object.assign || function(t) {
  12. for (var s, i = 1, n = arguments.length; i < n; i++) {
  13. s = arguments[i];
  14. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
  15. t[p] = s[p];
  16. }
  17. return t;
  18. };
  19. (function (factory) {
  20. if (typeof module === "object" && typeof module.exports === "object") {
  21. var v = factory(require, exports);
  22. if (v !== undefined) module.exports = v;
  23. }
  24. else if (typeof define === "function" && define.amd) {
  25. define(["require", "exports", "@angular/core", "@angular/forms", "../../config/config", "../picker/picker-controller", "../../util/form", "../../util/base-input", "../item/item", "../../util/util", "../../util/datetime-util"], factory);
  26. }
  27. })(function (require, exports) {
  28. "use strict";
  29. Object.defineProperty(exports, "__esModule", { value: true });
  30. var core_1 = require("@angular/core");
  31. var forms_1 = require("@angular/forms");
  32. var config_1 = require("../../config/config");
  33. var picker_controller_1 = require("../picker/picker-controller");
  34. var form_1 = require("../../util/form");
  35. var base_input_1 = require("../../util/base-input");
  36. var item_1 = require("../item/item");
  37. var util_1 = require("../../util/util");
  38. var datetime_util_1 = require("../../util/datetime-util");
  39. /**
  40. * @name DateTime
  41. * @description
  42. * The DateTime component is used to present an interface which makes it easy for
  43. * users to select dates and times. Tapping on `<ion-datetime>` will display a picker
  44. * interface that slides up from the bottom of the page. The picker then displays
  45. * scrollable columns that can be used to individually select years, months, days,
  46. * hours and minute values. The DateTime component is similar to the native
  47. * `<input type="datetime-local">` element, however, Ionic's DateTime component makes
  48. * it easy to display the date and time in a preferred format, and manage the datetime
  49. * values.
  50. *
  51. * ```html
  52. * <ion-item>
  53. * <ion-label>Date</ion-label>
  54. * <ion-datetime displayFormat="MM/DD/YYYY" [(ngModel)]="myDate"></ion-datetime>
  55. * </ion-item>
  56. * ```
  57. *
  58. *
  59. * ## Display and Picker Formats
  60. *
  61. * The DateTime component displays the values in two places: in the `<ion-datetime>`
  62. * component, and in the interface that is presented from the bottom of the screen.
  63. * The following chart lists all of the formats that can be used.
  64. *
  65. * | Format | Description | Example |
  66. * |---------|--------------------------------|-------------------------|
  67. * | `YYYY` | Year, 4 digits | `2018` |
  68. * | `YY` | Year, 2 digits | `18` |
  69. * | `M` | Month | `1` ... `12` |
  70. * | `MM` | Month, leading zero | `01` ... `12` |
  71. * | `MMM` | Month, short name | `Jan` |
  72. * | `MMMM` | Month, full name | `January` |
  73. * | `D` | Day | `1` ... `31` |
  74. * | `DD` | Day, leading zero | `01` ... `31` |
  75. * | `DDD` | Day, short name | `Fri` |
  76. * | `DDDD` | Day, full name | `Friday` |
  77. * | `H` | Hour, 24-hour | `0` ... `23` |
  78. * | `HH` | Hour, 24-hour, leading zero | `00` ... `23` |
  79. * | `h` | Hour, 12-hour | `1` ... `12` |
  80. * | `hh` | Hour, 12-hour, leading zero | `01` ... `12` |
  81. * | `a` | 12-hour time period, lowercase | `am` `pm` |
  82. * | `A` | 12-hour time period, uppercase | `AM` `PM` |
  83. * | `m` | Minute | `1` ... `59` |
  84. * | `mm` | Minute, leading zero | `01` ... `59` |
  85. * | `s` | Second | `1` ... `59` |
  86. * | `ss` | Second, leading zero | `01` ... `59` |
  87. * | `Z` | UTC Timezone Offset | `Z or +HH:mm or -HH:mm` |
  88. *
  89. * **Important**: See the [Month Names and Day of the Week Names](#month-names-and-day-of-the-week-names)
  90. * section below on how to use different names for the month and day.
  91. *
  92. * ### Display Format
  93. *
  94. * The `displayFormat` input property specifies how a datetime's value should be
  95. * printed, as formatted text, within the `ion-datetime` component.
  96. *
  97. * In the following example, the display in the `<ion-datetime>` will use the
  98. * month's short name, the numerical day with a leading zero, a comma and the
  99. * four-digit year. In addition to the date, it will display the time with the hours
  100. * in the 24-hour format and the minutes. Any character can be used as a separator.
  101. * An example display using this format is: `Jun 17, 2005 11:06`.
  102. *
  103. * ```html
  104. * <ion-item>
  105. * <ion-label>Date</ion-label>
  106. * <ion-datetime displayFormat="MMM DD, YYYY HH:mm" [(ngModel)]="myDate"></ion-datetime>
  107. * </ion-item>
  108. * ```
  109. *
  110. * ### Picker Format
  111. *
  112. * The `pickerFormat` input property determines which columns should be shown in the
  113. * interface, the order of the columns, and which format to use within each column.
  114. * If the `pickerFormat` input is not provided then it will default to the `displayFormat`.
  115. *
  116. * In the following example, the display in the `<ion-datetime>` will use the
  117. * `MM/YYYY` format, such as `06/2020`. However, the picker interface
  118. * will display two columns with the month's long name, and the four-digit year.
  119. *
  120. * ```html
  121. * <ion-item>
  122. * <ion-label>Date</ion-label>
  123. * <ion-datetime displayFormat="MM/YYYY" pickerFormat="MMMM YYYY" [(ngModel)]="myDate"></ion-datetime>
  124. * </ion-item>
  125. * ```
  126. *
  127. * ### Datetime Data
  128. *
  129. * Historically, handling datetime values within JavaScript, or even within HTML
  130. * inputs, has always been a challenge. Specifically, JavaScript's `Date` object is
  131. * notoriously difficult to correctly parse apart datetime strings or to format
  132. * datetime values. Even worse is how different browsers and JavaScript versions
  133. * parse various datetime strings differently, especially per locale.
  134. *
  135. * But no worries, all is not lost! Ionic's datetime input has been designed so
  136. * developers can avoid the common pitfalls, allowing developers to easily format
  137. * datetime values within the input, and give the user a simple datetime picker for a
  138. * great user experience.
  139. *
  140. * ##### ISO 8601 Datetime Format: YYYY-MM-DDTHH:mmZ
  141. *
  142. * Ionic uses the [ISO 8601 datetime format](https://www.w3.org/TR/NOTE-datetime)
  143. * for its value. The value is simply a string, rather than using JavaScript's `Date`
  144. * object. Additionally, when using the ISO datetime format, it makes it easier
  145. * to serialize and pass within JSON objects, and sending databases a standardized
  146. * format which it can be easily parsed if need be.
  147. *
  148. * To create an ISO datetime string for the current date and time, e.g. use `const currentDate = (new Date()).toISOString();`.
  149. *
  150. * An ISO format can be used as a simple year, or just the hour and minute, or get more
  151. * detailed down to the millisecond and timezone. Any of the ISO formats below can be used,
  152. * and after a user selects a new value, Ionic will continue to use the same ISO format
  153. * which datetime value was originally given as.
  154. *
  155. * | Description | Format | Datetime Value Example |
  156. * |----------------------|------------------------|------------------------------|
  157. * | Year | YYYY | 1994 |
  158. * | Year and Month | YYYY-MM | 1994-12 |
  159. * | Complete Date | YYYY-MM-DD | 1994-12-15 |
  160. * | Date and Time | YYYY-MM-DDTHH:mm | 1994-12-15T13:47 |
  161. * | UTC Timezone | YYYY-MM-DDTHH:mm:ssTZD | 1994-12-15T13:47:20.789Z |
  162. * | Timezone Offset | YYYY-MM-DDTHH:mm:ssTZD | 1994-12-15T13:47:20.789+5:00 |
  163. * | Hour and Minute | HH:mm | 13:47 |
  164. * | Hour, Minute, Second | HH:mm:ss | 13:47:20 |
  165. *
  166. * Note that the year is always four-digits, milliseconds (if it's added) is always
  167. * three-digits, and all others are always two-digits. So the number representing
  168. * January always has a leading zero, such as `01`. Additionally, the hour is always
  169. * in the 24-hour format, so `00` is `12am` on a 12-hour clock, `13` means `1pm`,
  170. * and `23` means `11pm`.
  171. *
  172. * It's also important to note that neither the `displayFormat` or `pickerFormat` can
  173. * set the datetime value's output, which is the value that is set by the component's
  174. * `ngModel`. The format's are merely for displaying the value as text and the picker's
  175. * interface, but the datetime's value is always persisted as a valid ISO 8601 datetime
  176. * string.
  177. *
  178. *
  179. * ## Min and Max Datetimes
  180. *
  181. * Dates are infinite in either direction, so for a user's selection there should be at
  182. * least some form of restricting the dates that can be selected. By default, the maximum
  183. * date is to the end of the current year, and the minimum date is from the beginning
  184. * of the year that was 100 years ago.
  185. *
  186. * To customize the minimum and maximum datetime values, the `min` and `max` component
  187. * inputs can be provided which may make more sense for the app's use-case, rather
  188. * than the default of the last 100 years. Following the same IS0 8601 format listed
  189. * in the table above, each component can restrict which dates can be selected by the
  190. * user. Below is an example of restricting the date selection between the beginning
  191. * of 2016, and October 31st of 2020:
  192. *
  193. * ```html
  194. * <ion-item>
  195. * <ion-label>Date</ion-label>
  196. * <ion-datetime displayFormat="MMMM YYYY" min="2016" max="2020-10-31" [(ngModel)]="myDate">
  197. * </ion-datetime>
  198. * </ion-item>
  199. * ```
  200. *
  201. *
  202. * ## Month Names and Day of the Week Names
  203. *
  204. * At this time, there is no one-size-fits-all standard to automatically choose the correct
  205. * language/spelling for a month name, or day of the week name, depending on the language
  206. * or locale. Good news is that there is an
  207. * [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat)
  208. * standard which *most* browsers have adopted. However, at this time the standard has not
  209. * been fully implemented by all popular browsers so Ionic is unavailable to take advantage
  210. * of it *yet*. Additionally, Angular also provides an internationalization service, but it
  211. * is still under heavy development so Ionic does not depend on it at this time.
  212. *
  213. * All things considered, the by far easiest solution is to just provide an array of names
  214. * if the app needs to use names other than the default English version of month and day
  215. * names. The month names and day names can be either configured at the app level, or
  216. * individual `ion-datetime` level.
  217. *
  218. * ### App Config Level
  219. *
  220. * ```ts
  221. * //app.module.ts
  222. * @NgModule({
  223. * ...,
  224. * imports: [
  225. * IonicModule.forRoot(MyApp, {
  226. * monthNames: ['janeiro', 'fevereiro', 'mar\u00e7o', ... ],
  227. * monthShortNames: ['jan', 'fev', 'mar', ... ],
  228. * dayNames: ['domingo', 'segunda-feira', 'ter\u00e7a-feira', ... ],
  229. * dayShortNames: ['dom', 'seg', 'ter', ... ],
  230. * })
  231. * ],
  232. * ...
  233. * })
  234. * ```
  235. *
  236. * ### Component Input Level
  237. *
  238. * ```html
  239. * <ion-item>
  240. * <ion-label>Período</ion-label>
  241. * <ion-datetime displayFormat="DDDD MMM D, YYYY" [(ngModel)]="myDate"
  242. * monthNames="janeiro, fevereiro, mar\u00e7o, ..."
  243. * monthShortNames="jan, fev, mar, ..."
  244. * dayNames="domingo, segunda-feira, ter\u00e7a-feira, ..."
  245. * dayShortNames="dom, seg, ter, ..."></ion-datetime>
  246. * </ion-item>
  247. * ```
  248. *
  249. *
  250. * ### Advanced Datetime Validation and Manipulation
  251. *
  252. * The datetime picker provides the simplicity of selecting an exact format, and persists
  253. * the datetime values as a string using the standardized
  254. * [ISO 8601 datetime format](https://www.w3.org/TR/NOTE-datetime).
  255. * However, it's important to note that `ion-datetime` does not attempt to solve all
  256. * situtations when validating and manipulating datetime values. If datetime values need
  257. * to be parsed from a certain format, or manipulated (such as adding 5 days to a date,
  258. * subtracting 30 minutes, etc.), or even formatting data to a specific locale, then we highly
  259. * recommend using [moment.js](http://momentjs.com/) to "Parse, validate, manipulate, and
  260. * display dates in JavaScript". [Moment.js](http://momentjs.com/) has quickly become
  261. * our goto standard when dealing with datetimes within JavaScript, but Ionic does not
  262. * prepackage this dependency since most apps will not require it, and its locale
  263. * configuration should be decided by the end-developer.
  264. *
  265. *
  266. * @usage
  267. * ```html
  268. * <ion-item>
  269. * <ion-label>Date</ion-label>
  270. * <ion-datetime displayFormat="MM/DD/YYYY" [(ngModel)]="myDate">
  271. * </ion-datetime>
  272. * </ion-item>
  273. * ```
  274. *
  275. *
  276. * @demo /docs/demos/src/datetime/
  277. */
  278. var DateTime = (function (_super) {
  279. __extends(DateTime, _super);
  280. function DateTime(form, config, elementRef, renderer, item, _pickerCtrl) {
  281. var _this = _super.call(this, config, elementRef, renderer, 'datetime', {}, form, item, null) || this;
  282. _this._pickerCtrl = _pickerCtrl;
  283. _this._text = '';
  284. _this._locale = {};
  285. /**
  286. * @input {string} The text to display on the picker's cancel button. Default: `Cancel`.
  287. */
  288. _this.cancelText = 'Cancel';
  289. /**
  290. * @input {string} The text to display on the picker's "Done" button. Default: `Done`.
  291. */
  292. _this.doneText = 'Done';
  293. /**
  294. * @input {any} Any additional options that the picker interface can accept.
  295. * See the [Picker API docs](../../picker/Picker) for the picker options.
  296. */
  297. _this.pickerOptions = {};
  298. /**
  299. * @input {string} The text to display when there's no date selected yet.
  300. * Using lowercase to match the input attribute
  301. */
  302. _this.placeholder = '';
  303. /**
  304. * @output {any} Emitted when the datetime selection was cancelled.
  305. */
  306. _this.ionCancel = new core_1.EventEmitter();
  307. return _this;
  308. }
  309. /**
  310. * @hidden
  311. */
  312. DateTime.prototype.ngAfterContentInit = function () {
  313. var _this = this;
  314. // first see if locale names were provided in the inputs
  315. // then check to see if they're in the config
  316. // if neither were provided then it will use default English names
  317. ['monthNames', 'monthShortNames', 'dayNames', 'dayShortNames'].forEach(function (type) {
  318. _this._locale[type] = convertToArrayOfStrings(util_1.isPresent(_this[type]) ? _this[type] : _this._config.get(type), type);
  319. });
  320. this._initialize();
  321. };
  322. /**
  323. * @hidden
  324. */
  325. DateTime.prototype._inputNormalize = function (val) {
  326. datetime_util_1.updateDate(this._value, val);
  327. return this._value;
  328. };
  329. /**
  330. * @hidden
  331. */
  332. DateTime.prototype._inputUpdated = function () {
  333. _super.prototype._inputUpdated.call(this);
  334. this.updateText();
  335. };
  336. /**
  337. * @hidden
  338. */
  339. DateTime.prototype._inputShouldChange = function () {
  340. return true;
  341. };
  342. /**
  343. * TODO: REMOVE THIS
  344. * @hidden
  345. */
  346. DateTime.prototype._inputChangeEvent = function () {
  347. return this.value;
  348. };
  349. /**
  350. * @hidden
  351. */
  352. DateTime.prototype._inputNgModelEvent = function () {
  353. return datetime_util_1.convertDataToISO(this.value);
  354. };
  355. DateTime.prototype._click = function (ev) {
  356. ev.preventDefault();
  357. ev.stopPropagation();
  358. this.open();
  359. };
  360. DateTime.prototype._keyup = function () {
  361. this.open();
  362. };
  363. /**
  364. * @hidden
  365. */
  366. DateTime.prototype.open = function () {
  367. var _this = this;
  368. if (this.isFocus() || this._disabled) {
  369. return;
  370. }
  371. (void 0) /* console.debug */;
  372. // the user may have assigned some options specifically for the picker
  373. var pickerOptions = __assign({}, this.pickerOptions);
  374. // Add a cancel and done button by default to the picker
  375. var defaultButtons = [{
  376. text: this.cancelText,
  377. role: 'cancel',
  378. handler: function () { return _this.ionCancel.emit(_this); }
  379. }, {
  380. text: this.doneText,
  381. handler: function (data) { return _this.value = data; },
  382. }];
  383. pickerOptions.buttons = (pickerOptions.buttons || []).concat(defaultButtons);
  384. // Configure picker under the hood
  385. var picker = this._picker = this._pickerCtrl.create(pickerOptions);
  386. picker.ionChange.subscribe(function () {
  387. _this.validate();
  388. picker.refresh();
  389. });
  390. // Update picker status before presenting
  391. this.generate();
  392. this.validate();
  393. // Present picker
  394. this._fireFocus();
  395. picker.present(pickerOptions);
  396. picker.onDidDismiss(function () {
  397. _this._fireBlur();
  398. });
  399. };
  400. /**
  401. * @hidden
  402. */
  403. DateTime.prototype.generate = function () {
  404. var _this = this;
  405. var picker = this._picker;
  406. // if a picker format wasn't provided, then fallback
  407. // to use the display format
  408. var template = this.pickerFormat || this.displayFormat || DEFAULT_FORMAT;
  409. if (util_1.isPresent(template)) {
  410. // make sure we've got up to date sizing information
  411. this.calcMinMax();
  412. // does not support selecting by day name
  413. // automaticallly remove any day name formats
  414. template = template.replace('DDDD', '{~}').replace('DDD', '{~}');
  415. if (template.indexOf('D') === -1) {
  416. // there is not a day in the template
  417. // replace the day name with a numeric one if it exists
  418. template = template.replace('{~}', 'D');
  419. }
  420. // make sure no day name replacer is left in the string
  421. template = template.replace(/{~}/g, '');
  422. // parse apart the given template into an array of "formats"
  423. datetime_util_1.parseTemplate(template).forEach(function (format) {
  424. // loop through each format in the template
  425. // create a new picker column to build up with data
  426. var key = datetime_util_1.convertFormatToKey(format);
  427. var values;
  428. // first see if they have exact values to use for this input
  429. if (util_1.isPresent(_this[key + 'Values'])) {
  430. // user provide exact values for this date part
  431. values = convertToArrayOfNumbers(_this[key + 'Values'], key);
  432. }
  433. else {
  434. // use the default date part values
  435. values = datetime_util_1.dateValueRange(format, _this._min, _this._max);
  436. }
  437. var column = {
  438. name: key,
  439. selectedIndex: 0,
  440. options: values.map(function (val) {
  441. return {
  442. value: val,
  443. text: datetime_util_1.renderTextFormat(format, val, null, _this._locale),
  444. };
  445. })
  446. };
  447. // cool, we've loaded up the columns with options
  448. // preselect the option for this column
  449. var optValue = datetime_util_1.getValueFromFormat(_this.getValueOrDefault(), format);
  450. var selectedIndex = column.options.findIndex(function (opt) { return opt.value === optValue; });
  451. if (selectedIndex >= 0) {
  452. // set the select index for this column's options
  453. column.selectedIndex = selectedIndex;
  454. }
  455. // add our newly created column to the picker
  456. picker.addColumn(column);
  457. });
  458. // Normalize min/max
  459. var min_1 = this._min;
  460. var max_1 = this._max;
  461. var columns_1 = this._picker.getColumns();
  462. ['month', 'day', 'hour', 'minute']
  463. .filter(function (name) { return !columns_1.find(function (column) { return column.name === name; }); })
  464. .forEach(function (name) {
  465. min_1[name] = 0;
  466. max_1[name] = 0;
  467. });
  468. this.divyColumns();
  469. }
  470. };
  471. /**
  472. * @hidden
  473. */
  474. DateTime.prototype.validateColumn = function (name, index, min, max, lowerBounds, upperBounds) {
  475. (void 0) /* assert */;
  476. (void 0) /* assert */;
  477. var column = this._picker.getColumn(name);
  478. if (!column) {
  479. return 0;
  480. }
  481. var lb = lowerBounds.slice();
  482. var ub = upperBounds.slice();
  483. var options = column.options;
  484. var indexMin = options.length - 1;
  485. var indexMax = 0;
  486. for (var i = 0; i < options.length; i++) {
  487. var opt = options[i];
  488. var value = opt.value;
  489. lb[index] = opt.value;
  490. ub[index] = opt.value;
  491. var disabled = opt.disabled = (value < lowerBounds[index] ||
  492. value > upperBounds[index] ||
  493. datetime_util_1.dateSortValue(ub[0], ub[1], ub[2], ub[3], ub[4]) < min ||
  494. datetime_util_1.dateSortValue(lb[0], lb[1], lb[2], lb[3], lb[4]) > max);
  495. if (!disabled) {
  496. indexMin = Math.min(indexMin, i);
  497. indexMax = Math.max(indexMax, i);
  498. }
  499. }
  500. var selectedIndex = column.selectedIndex = util_1.clamp(indexMin, column.selectedIndex, indexMax);
  501. opt = column.options[selectedIndex];
  502. if (opt) {
  503. return opt.value;
  504. }
  505. return 0;
  506. };
  507. /**
  508. * @private
  509. */
  510. DateTime.prototype.validate = function () {
  511. var today = new Date();
  512. var minCompareVal = datetime_util_1.dateDataSortValue(this._min);
  513. var maxCompareVal = datetime_util_1.dateDataSortValue(this._max);
  514. var yearCol = this._picker.getColumn('year');
  515. (void 0) /* assert */;
  516. var selectedYear = today.getFullYear();
  517. if (yearCol) {
  518. // default to the first value if the current year doesn't exist in the options
  519. if (!yearCol.options.find(function (col) { return col.value === today.getFullYear(); })) {
  520. selectedYear = yearCol.options[0].value;
  521. }
  522. var yearOpt = yearCol.options[yearCol.selectedIndex];
  523. if (yearOpt) {
  524. // they have a selected year value
  525. selectedYear = yearOpt.value;
  526. }
  527. }
  528. var selectedMonth = this.validateColumn('month', 1, minCompareVal, maxCompareVal, [selectedYear, 0, 0, 0, 0], [selectedYear, 12, 31, 23, 59]);
  529. var numDaysInMonth = datetime_util_1.daysInMonth(selectedMonth, selectedYear);
  530. var selectedDay = this.validateColumn('day', 2, minCompareVal, maxCompareVal, [selectedYear, selectedMonth, 0, 0, 0], [selectedYear, selectedMonth, numDaysInMonth, 23, 59]);
  531. var selectedHour = this.validateColumn('hour', 3, minCompareVal, maxCompareVal, [selectedYear, selectedMonth, selectedDay, 0, 0], [selectedYear, selectedMonth, selectedDay, 23, 59]);
  532. this.validateColumn('minute', 4, minCompareVal, maxCompareVal, [selectedYear, selectedMonth, selectedDay, selectedHour, 0], [selectedYear, selectedMonth, selectedDay, selectedHour, 59]);
  533. };
  534. /**
  535. * @hidden
  536. */
  537. DateTime.prototype.divyColumns = function () {
  538. var pickerColumns = this._picker.getColumns();
  539. var columnsWidth = [];
  540. var col;
  541. var width;
  542. for (var i = 0; i < pickerColumns.length; i++) {
  543. col = pickerColumns[i];
  544. columnsWidth.push(0);
  545. for (var j = 0; j < col.options.length; j++) {
  546. width = col.options[j].text.length;
  547. if (width > columnsWidth[i]) {
  548. columnsWidth[i] = width;
  549. }
  550. }
  551. }
  552. if (columnsWidth.length === 2) {
  553. width = Math.max(columnsWidth[0], columnsWidth[1]);
  554. pickerColumns[0].align = 'right';
  555. pickerColumns[1].align = 'left';
  556. pickerColumns[0].optionsWidth = pickerColumns[1].optionsWidth = width * 17 + "px";
  557. }
  558. else if (columnsWidth.length === 3) {
  559. width = Math.max(columnsWidth[0], columnsWidth[2]);
  560. pickerColumns[0].align = 'right';
  561. pickerColumns[1].columnWidth = columnsWidth[1] * 17 + "px";
  562. pickerColumns[0].optionsWidth = pickerColumns[2].optionsWidth = width * 17 + "px";
  563. pickerColumns[2].align = 'left';
  564. }
  565. };
  566. /**
  567. * @hidden
  568. */
  569. DateTime.prototype.updateText = function () {
  570. // create the text of the formatted data
  571. var template = this.displayFormat || this.pickerFormat || DEFAULT_FORMAT;
  572. this._text = datetime_util_1.renderDateTime(template, this.getValue(), this._locale);
  573. };
  574. /**
  575. * @hidden
  576. */
  577. DateTime.prototype.getValue = function () {
  578. return this._value;
  579. };
  580. /**
  581. * @hidden
  582. */
  583. DateTime.prototype.getValueOrDefault = function () {
  584. if (this.hasValue()) {
  585. return this._value;
  586. }
  587. var initialDateString = this.getDefaultValueDateString();
  588. var _default = {};
  589. datetime_util_1.updateDate(_default, initialDateString);
  590. return _default;
  591. };
  592. /**
  593. * Get the default value as a date string
  594. * @hidden
  595. */
  596. DateTime.prototype.getDefaultValueDateString = function () {
  597. if (this.initialValue) {
  598. return this.initialValue;
  599. }
  600. var nowString = (new Date).toISOString();
  601. if (this.max) {
  602. var now = datetime_util_1.parseDate(nowString);
  603. var max = datetime_util_1.parseDate(this.max);
  604. var v = void 0;
  605. for (var i in max) {
  606. v = max[i];
  607. if (v === null) {
  608. max[i] = now[i];
  609. }
  610. }
  611. var diff = datetime_util_1.compareDates(now, max);
  612. // If max is before current time, return max
  613. if (diff > 0) {
  614. return this.max;
  615. }
  616. }
  617. return nowString;
  618. };
  619. /**
  620. * @hidden
  621. */
  622. DateTime.prototype.hasValue = function () {
  623. var val = this._value;
  624. return util_1.isPresent(val)
  625. && util_1.isObject(val)
  626. && Object.keys(val).length > 0;
  627. };
  628. /**
  629. * @hidden
  630. */
  631. DateTime.prototype.calcMinMax = function (now) {
  632. var todaysYear = (now || new Date()).getFullYear();
  633. if (util_1.isPresent(this.yearValues)) {
  634. var years = convertToArrayOfNumbers(this.yearValues, 'year');
  635. if (util_1.isBlank(this.min)) {
  636. this.min = Math.min.apply(Math, years);
  637. }
  638. if (util_1.isBlank(this.max)) {
  639. this.max = Math.max.apply(Math, years);
  640. }
  641. }
  642. else {
  643. if (util_1.isBlank(this.min)) {
  644. this.min = (todaysYear - 100).toString();
  645. }
  646. if (util_1.isBlank(this.max)) {
  647. this.max = todaysYear.toString();
  648. }
  649. }
  650. var min = this._min = datetime_util_1.parseDate(this.min);
  651. var max = this._max = datetime_util_1.parseDate(this.max);
  652. min.year = min.year || todaysYear;
  653. max.year = max.year || todaysYear;
  654. min.month = min.month || 1;
  655. max.month = max.month || 12;
  656. min.day = min.day || 1;
  657. max.day = max.day || 31;
  658. min.hour = min.hour || 0;
  659. max.hour = max.hour || 23;
  660. min.minute = min.minute || 0;
  661. max.minute = max.minute || 59;
  662. min.second = min.second || 0;
  663. max.second = max.second || 59;
  664. // Ensure min/max constraits
  665. if (min.year > max.year) {
  666. console.error('min.year > max.year');
  667. min.year = max.year - 100;
  668. }
  669. if (min.year === max.year) {
  670. if (min.month > max.month) {
  671. console.error('min.month > max.month');
  672. min.month = 1;
  673. }
  674. else if (min.month === max.month && min.day > max.day) {
  675. console.error('min.day > max.day');
  676. min.day = 1;
  677. }
  678. }
  679. };
  680. DateTime.decorators = [
  681. { type: core_1.Component, args: [{
  682. selector: 'ion-datetime',
  683. template: '<div *ngIf="!_text" class="datetime-text datetime-placeholder">{{placeholder}}</div>' +
  684. '<div *ngIf="_text" class="datetime-text">{{_text}}</div>' +
  685. '<button aria-haspopup="true" ' +
  686. 'type="button" ' +
  687. '[id]="id" ' +
  688. 'ion-button="item-cover" ' +
  689. '[attr.aria-labelledby]="_labelId" ' +
  690. '[attr.aria-disabled]="_disabled" ' +
  691. 'class="item-cover">' +
  692. '</button>',
  693. host: {
  694. '[class.datetime-disabled]': '_disabled'
  695. },
  696. providers: [{ provide: forms_1.NG_VALUE_ACCESSOR, useExisting: DateTime, multi: true }],
  697. encapsulation: core_1.ViewEncapsulation.None,
  698. },] },
  699. ];
  700. /** @nocollapse */
  701. DateTime.ctorParameters = function () { return [
  702. { type: form_1.Form, },
  703. { type: config_1.Config, },
  704. { type: core_1.ElementRef, },
  705. { type: core_1.Renderer, },
  706. { type: item_1.Item, decorators: [{ type: core_1.Optional },] },
  707. { type: picker_controller_1.PickerController, decorators: [{ type: core_1.Optional },] },
  708. ]; };
  709. DateTime.propDecorators = {
  710. 'min': [{ type: core_1.Input },],
  711. 'max': [{ type: core_1.Input },],
  712. 'displayFormat': [{ type: core_1.Input },],
  713. 'initialValue': [{ type: core_1.Input },],
  714. 'pickerFormat': [{ type: core_1.Input },],
  715. 'cancelText': [{ type: core_1.Input },],
  716. 'doneText': [{ type: core_1.Input },],
  717. 'yearValues': [{ type: core_1.Input },],
  718. 'monthValues': [{ type: core_1.Input },],
  719. 'dayValues': [{ type: core_1.Input },],
  720. 'hourValues': [{ type: core_1.Input },],
  721. 'minuteValues': [{ type: core_1.Input },],
  722. 'monthNames': [{ type: core_1.Input },],
  723. 'monthShortNames': [{ type: core_1.Input },],
  724. 'dayNames': [{ type: core_1.Input },],
  725. 'dayShortNames': [{ type: core_1.Input },],
  726. 'pickerOptions': [{ type: core_1.Input },],
  727. 'placeholder': [{ type: core_1.Input },],
  728. 'ionCancel': [{ type: core_1.Output },],
  729. '_click': [{ type: core_1.HostListener, args: ['click', ['$event'],] },],
  730. '_keyup': [{ type: core_1.HostListener, args: ['keyup.space',] },],
  731. };
  732. return DateTime;
  733. }(base_input_1.BaseInput));
  734. exports.DateTime = DateTime;
  735. /**
  736. * @hidden
  737. * Use to convert a string of comma separated numbers or
  738. * an array of numbers, and clean up any user input
  739. */
  740. function convertToArrayOfNumbers(input, type) {
  741. if (util_1.isString(input)) {
  742. // convert the string to an array of strings
  743. // auto remove any whitespace and [] characters
  744. input = input.replace(/\[|\]|\s/g, '').split(',');
  745. }
  746. var values;
  747. if (util_1.isArray(input)) {
  748. // ensure each value is an actual number in the returned array
  749. values = input
  750. .map(function (num) { return parseInt(num, 10); })
  751. .filter(isFinite);
  752. }
  753. if (!values || !values.length) {
  754. console.warn("Invalid \"" + type + "Values\". Must be an array of numbers, or a comma separated string of numbers.");
  755. }
  756. return values;
  757. }
  758. /**
  759. * @hidden
  760. * Use to convert a string of comma separated strings or
  761. * an array of strings, and clean up any user input
  762. */
  763. function convertToArrayOfStrings(input, type) {
  764. if (util_1.isPresent(input)) {
  765. if (util_1.isString(input)) {
  766. // convert the string to an array of strings
  767. // auto remove any [] characters
  768. input = input.replace(/\[|\]/g, '').split(',');
  769. }
  770. var values;
  771. if (util_1.isArray(input)) {
  772. // trim up each string value
  773. values = input.map(function (val) { return val.trim(); });
  774. }
  775. if (!values || !values.length) {
  776. console.warn("Invalid \"" + type + "Names\". Must be an array of strings, or a comma separated string.");
  777. }
  778. return values;
  779. }
  780. }
  781. var DEFAULT_FORMAT = 'MMM D, YYYY';
  782. });
  783. //# sourceMappingURL=datetime.js.map