/** * @license * Copyright (C) 2015 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. */ import '../gr-rest-api-interface/gr-rest-api-interface'; import '../../../styles/shared-styles'; import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners'; import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin'; import {PolymerElement} from '@polymer/polymer/polymer-element'; import {htmlTemplate} from './gr-date-formatter_html'; import {TooltipMixin} from '../../../mixins/gr-tooltip-mixin/gr-tooltip-mixin'; import {property, customElement} from '@polymer/decorators'; import { parseDate, fromNow, isValidDate, isWithinDay, isWithinHalfYear, formatDate, utcOffsetString, } from '../../../utils/date-util'; import {TimeFormat, DateFormat} from '../../../constants/constants'; import {assertNever} from '../../../utils/common-util'; import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api'; 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 }; const DateFormats = { STD: { short: 'MMM DD', // Aug 29 full: 'MMM DD, YYYY', // Aug 29, 1997 }, US: { short: 'MM/DD', // 08/29 full: 'MM/DD/YY', // 08/29/97 }, ISO: { short: 'MM-DD', // 08-29 full: 'YYYY-MM-DD', // 1997-08-29 }, EURO: { short: 'DD. MMM', // 29. Aug full: 'DD.MM.YYYY', // 29.08.1997 }, UK: { short: 'DD/MM', // 29/08 full: 'DD/MM/YYYY', // 29/08/1997 }, }; interface DateFormatPair { short: string; full: string; } declare global { interface HTMLElementTagNameMap { 'gr-date-formatter': GrDateFormatter; } } export interface GrDateFormatter { $: { restAPI: RestApiService & Element; }; } @customElement('gr-date-formatter') export class GrDateFormatter extends TooltipMixin( GestureEventListeners(LegacyElementMixin(PolymerElement)) ) { static get template() { return htmlTemplate; } @property({type: String, notify: true}) dateStr: string | null = null; @property({type: Boolean}) showDateAndTime = false; /** * When true, the detailed date appears in a GR-TOOLTIP rather than in the * native browser tooltip. */ @property({type: Boolean}) hasTooltip = false; /** * The title to be used as the native tooltip or by the tooltip behavior. */ @property({ type: String, reflectToAttribute: true, computed: '_computeFullDateStr(dateStr, _timeFormat, _dateFormat)', }) title = ''; /** @type {?{short: string, full: string}} */ @property({type: Object}) _dateFormat?: DateFormatPair; @property({type: String}) _timeFormat?: string; @property({type: Boolean}) _relative?: boolean; constructor() { super(); } /** @override */ attached() { super.attached(); this._loadPreferences(); } _getUtcOffsetString() { return utcOffsetString(); } _loadPreferences() { return this._getLoggedIn().then(loggedIn => { if (!loggedIn) { this._timeFormat = TimeFormats.TIME_24; this._dateFormat = DateFormats.STD; this._relative = false; return; } return Promise.all([this._loadTimeFormat(), this._loadRelative()]); }); } _loadTimeFormat() { return this._getPreferences().then(preferences => { if (!preferences) { throw Error('Preferences is not set'); } this._decideTimeFormat(preferences.time_format); this._decideDateFormat(preferences.date_format); }); } _decideTimeFormat(timeFormat: TimeFormat) { switch (timeFormat) { case TimeFormat.HHMM_12: this._timeFormat = TimeFormats.TIME_12; break; case TimeFormat.HHMM_24: this._timeFormat = TimeFormats.TIME_24; break; default: assertNever(timeFormat, `Invalid time format: ${timeFormat}`); } } _decideDateFormat(dateFormat: DateFormat) { switch (dateFormat) { case DateFormat.STD: this._dateFormat = DateFormats.STD; break; case DateFormat.US: this._dateFormat = DateFormats.US; break; case DateFormat.ISO: this._dateFormat = DateFormats.ISO; break; case DateFormat.EURO: this._dateFormat = DateFormats.EURO; break; case DateFormat.UK: this._dateFormat = DateFormats.UK; break; default: assertNever(dateFormat, `Invalid date format: ${dateFormat}`); } } _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(); } _computeDateStr( dateStr?: string, timeFormat?: string, dateFormat?: DateFormatPair, relative?: boolean, showDateAndTime?: boolean ) { if (!dateStr || !timeFormat || !dateFormat) { return ''; } const date = parseDate(dateStr); if (!isValidDate(date)) { return ''; } if (relative) { return fromNow(date); } const now = new Date(); let format = dateFormat.full; if (isWithinDay(now, date)) { format = timeFormat; } else { if (isWithinHalfYear(now, date)) { format = dateFormat.short; } if (this.showDateAndTime || showDateAndTime) { format = `${format} ${timeFormat}`; } } return formatDate(date, format); } _timeToSecondsFormat(timeFormat: string | undefined) { return timeFormat === TimeFormats.TIME_12 ? TimeFormats.TIME_12_WITH_SEC : TimeFormats.TIME_24_WITH_SEC; } _computeFullDateStr( dateStr?: string, timeFormat?: string, dateFormat?: DateFormatPair ) { // Polymer 2: check for undefined if ([dateStr, timeFormat].includes(undefined) || !dateFormat) { return undefined; } if (!dateStr) { return ''; } const date = parseDate(dateStr); if (!isValidDate(date)) { return ''; } let format = dateFormat.full + ', '; format += this._timeToSecondsFormat(timeFormat); return formatDate(date, format) + this._getUtcOffsetString(); } }