| /** |
| * @license |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| (function() { |
| 'use strict'; |
| |
| const Duration = { |
| HOUR: 1000 * 60 * 60, |
| DAY: 1000 * 60 * 60 * 24, |
| }; |
| |
| const TimeFormats = { |
| TIME_12: 'h:mm A', // 2:14 PM |
| TIME_12_WITH_SEC: 'h:mm:ss A', // 2:14:00 PM |
| TIME_24: 'HH:mm', // 14:14 |
| TIME_24_WITH_SEC: 'HH:mm:ss', // 14:14:00 |
| MONTH_DAY: 'MMM DD', // Aug 29 |
| MONTH_DAY_YEAR: 'MMM DD, YYYY', // Aug 29, 1997 |
| }; |
| |
| /** |
| * @appliesMixin Gerrit.TooltipMixin |
| * @extends Polymer.Element |
| */ |
| class GrDateFormatter extends Polymer.mixinBehaviors( [ |
| Gerrit.TooltipBehavior, |
| ], Polymer.GestureEventListeners( |
| Polymer.LegacyElementMixin( |
| Polymer.Element))) { |
| static get is() { return 'gr-date-formatter'; } |
| |
| static get properties() { |
| return { |
| dateStr: { |
| type: String, |
| value: null, |
| notify: true, |
| }, |
| showDateAndTime: { |
| type: Boolean, |
| value: false, |
| }, |
| |
| /** |
| * When true, the detailed date appears in a GR-TOOLTIP rather than in the |
| * native browser tooltip. |
| */ |
| hasTooltip: Boolean, |
| |
| /** |
| * The title to be used as the native tooltip or by the tooltip behavior. |
| */ |
| title: { |
| type: String, |
| reflectToAttribute: true, |
| computed: '_computeFullDateStr(dateStr, _timeFormat)', |
| }, |
| |
| _timeFormat: String, // No default value to prevent flickering. |
| _relative: Boolean, // No default value to prevent flickering. |
| }; |
| } |
| |
| /** @override */ |
| attached() { |
| super.attached(); |
| this._loadPreferences(); |
| } |
| |
| _getUtcOffsetString() { |
| return ' UTC' + moment().format('Z'); |
| } |
| |
| _loadPreferences() { |
| return this._getLoggedIn().then(loggedIn => { |
| if (!loggedIn) { |
| this._timeFormat = TimeFormats.TIME_24; |
| this._relative = false; |
| return; |
| } |
| return Promise.all([ |
| this._loadTimeFormat(), |
| this._loadRelative(), |
| ]); |
| }); |
| } |
| |
| _loadTimeFormat() { |
| return this._getPreferences().then(preferences => { |
| const timeFormat = preferences && preferences.time_format; |
| switch (timeFormat) { |
| case 'HHMM_12': |
| this._timeFormat = TimeFormats.TIME_12; |
| break; |
| case 'HHMM_24': |
| this._timeFormat = TimeFormats.TIME_24; |
| break; |
| default: |
| throw Error('Invalid time format: ' + timeFormat); |
| } |
| }); |
| } |
| |
| _loadRelative() { |
| return this._getPreferences().then(prefs => { |
| // prefs.relative_date_in_change_table is not set when false. |
| this._relative = !!(prefs && prefs.relative_date_in_change_table); |
| }); |
| } |
| |
| _getLoggedIn() { |
| return this.$.restAPI.getLoggedIn(); |
| } |
| |
| _getPreferences() { |
| return this.$.restAPI.getPreferences(); |
| } |
| |
| /** |
| * Return true if date is within 24 hours and on the same day. |
| */ |
| _isWithinDay(now, date) { |
| const diff = -date.diff(now); |
| return diff < Duration.DAY && date.day() === now.getDay(); |
| } |
| |
| /** |
| * Returns true if date is from one to six months. |
| */ |
| _isWithinHalfYear(now, date) { |
| const diff = -date.diff(now); |
| return (date.day() !== now.getDay() || diff >= Duration.DAY) && |
| diff < 180 * Duration.DAY; |
| } |
| |
| _computeDateStr(dateStr, timeFormat, relative, showDateAndTime) { |
| if (!dateStr) { return ''; } |
| const date = moment(util.parseDate(dateStr)); |
| if (!date.isValid()) { return ''; } |
| if (relative) { |
| const dateFromNow = date.fromNow(); |
| if (dateFromNow === 'a few seconds ago') { |
| return 'just now'; |
| } else { |
| return dateFromNow; |
| } |
| } |
| const now = new Date(); |
| let format = TimeFormats.MONTH_DAY_YEAR; |
| if (this._isWithinDay(now, date)) { |
| format = timeFormat; |
| } else { |
| if (this._isWithinHalfYear(now, date)) { |
| format = TimeFormats.MONTH_DAY; |
| } |
| if (this.showDateAndTime) { |
| format = `${format} ${timeFormat}`; |
| } |
| } |
| return date.format(format); |
| } |
| |
| _timeToSecondsFormat(timeFormat) { |
| return timeFormat === TimeFormats.TIME_12 ? |
| TimeFormats.TIME_12_WITH_SEC : |
| TimeFormats.TIME_24_WITH_SEC; |
| } |
| |
| _computeFullDateStr(dateStr, timeFormat) { |
| // Polymer 2: check for undefined |
| if ([ |
| dateStr, |
| timeFormat, |
| ].some(arg => arg === undefined)) { |
| return undefined; |
| } |
| |
| if (!dateStr) { return ''; } |
| const date = moment(util.parseDate(dateStr)); |
| if (!date.isValid()) { return ''; } |
| let format = TimeFormats.MONTH_DAY_YEAR + ', '; |
| format += this._timeToSecondsFormat(timeFormat); |
| return date.format(format) + this._getUtcOffsetString(); |
| } |
| } |
| |
| customElements.define(GrDateFormatter.is, GrDateFormatter); |
| })(); |