Skip to content

Commit

Permalink
[amp-date-display] Moves localeOptions from json type to data-options-*.
Browse files Browse the repository at this point in the history
  • Loading branch information
jingfei committed May 25, 2021
1 parent 1923187 commit b7bcffb
Show file tree
Hide file tree
Showing 16 changed files with 159 additions and 113 deletions.
5 changes: 1 addition & 4 deletions examples/amp-date-display.amp.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,7 @@ <h2>Locales</h2>
en-GB: {{dayName}} {{day}} {{monthName}} {{year}}
</template>
</amp-date-display>
<amp-date-display datetime="now" locale="zh-TW" layout="fixed" width="360" height="20">
<script type="application/json">
{ "localeOptions": { "timeStyle": "short" } }
</script>
<amp-date-display datetime="now" locale="zh-TW" layout="fixed" width="360" height="20" data-options-time-style="short">
<template type="amp-mustache">
zh-TW: {{localeString}}
</template>
Expand Down
85 changes: 81 additions & 4 deletions extensions/amp-date-display/0.1/amp-date-display.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,39 @@ const DEFAULT_LOCALE = 'en';
/** @const {number} */
const DEFAULT_OFFSET_SECONDS = 0;

/** @const {!Array<string>} */
const SUPPORTED_LOCALE_OPTIONS_ATTRS = [
'date-style',
'time-style',
'calendar',
'day-period',
'numbering-system',
'locale-matcher',
'time-zone',
'hour12',
'hour-cycle',
'format-matcher',
'weekday',
'era',
'year',
'month',
'day',
'hour',
'minute',
'second',
'fractional-second-digits',
'time-zone-name',
];

/** @const {!Object<string, *>} */
const DEFAULT_DATETIME_OPTIONS = {
'year': 'numeric',
'month': 'short',
'day': 'numeric',
'hour': 'numeric',
'minute': 'numeric',
};

/** @typedef {{
year: number,
month: number,
Expand Down Expand Up @@ -66,6 +99,7 @@ let VariablesDef;
minuteTwoDigit: string,
secondTwoDigit: string,
dayPeriod: string,
localeString: string,
}} */
let EnhancedVariablesDef;

Expand Down Expand Up @@ -95,6 +129,9 @@ export class AmpDateDisplay extends AMP.BaseElement {
/** @private {string} */
this.locale_ = '';

/** @private {Object<string, *>} */
this.localeOptions_ = null;

/** @private {?../../../src/service/template-impl.Templates} */
this.templates_ = null;

Expand Down Expand Up @@ -129,6 +166,8 @@ export class AmpDateDisplay extends AMP.BaseElement {

this.locale_ = this.element.getAttribute('locale') || DEFAULT_LOCALE;

this.localeOptions_ = this.parseLocalOptionsAttrs_(this.element);

const data = /** @type {!JsonObject} */ (this.getDataForTemplate_());
this.templates_
.findAndRenderTemplate(this.element, data)
Expand All @@ -152,8 +191,8 @@ export class AmpDateDisplay extends AMP.BaseElement {
const date = new Date(epoch + offset);
const inUTC = this.displayIn_.toLowerCase() === 'utc';
const basicData = inUTC
? this.getVariablesInUTC_(date, this.locale_)
: this.getVariablesInLocal_(date, this.locale_);
? this.getVariablesInUTC_(date, this.locale_, this.localeOptions_)
: this.getVariablesInLocal_(date, this.locale_, this.localeOptions_);

return this.enhanceBasicVariables_(basicData);
}
Expand Down Expand Up @@ -185,13 +224,44 @@ export class AmpDateDisplay extends AMP.BaseElement {
return epoch;
}

/**
* @param {!Element} element
* @return {Object<string, *>|undefined}
* @private
*/
parseLocalOptionsAttrs_(element) {
const getCamelCase = (kebabCase) =>
kebabCase
.split('-')
.map((str, index) =>
index === 0 ? str : str[0].toUpperCase() + str.substring(1)
)
.join('');

const localeOptions = SUPPORTED_LOCALE_OPTIONS_ATTRS.filter((attr) =>
element.hasAttribute(`data-options-${attr}`)
);
if (localeOptions.length === 0) {
return undefined;
}

return localeOptions.reduce(
(options, attr) => ({
...options,
[getCamelCase(attr)]: element.getAttribute(`data-options-${attr}`),
}),
{}
);
}

/**
* @param {!Date} date
* @param {string} locale
* @param {?Object<string, *>} localeOptions
* @return {!VariablesDef}
* @private
*/
getVariablesInLocal_(date, locale) {
getVariablesInLocal_(date, locale, localeOptions = DEFAULT_DATETIME_OPTIONS) {
return {
year: date.getFullYear(),
month: date.getMonth() + 1,
Expand All @@ -208,16 +278,22 @@ export class AmpDateDisplay extends AMP.BaseElement {
minute: date.getMinutes(),
second: date.getSeconds(),
iso: date.toISOString(),
localeString: date.toLocaleString(locale, localeOptions),
};
}

/**
* @param {!Date} date
* @param {string} locale
* @param {?Object<string, *>} localeOptions
* @return {!VariablesDef}
* @private
*/
getVariablesInUTC_(date, locale) {
getVariablesInUTC_(date, locale, localeOptions = DEFAULT_DATETIME_OPTIONS) {
const localeOptionsInUTC = {
...localeOptions,
timeZone: 'UTC',
};
return {
year: date.getUTCFullYear(),
month: date.getUTCMonth() + 1,
Expand All @@ -242,6 +318,7 @@ export class AmpDateDisplay extends AMP.BaseElement {
minute: date.getUTCMinutes(),
second: date.getUTCSeconds(),
iso: date.toISOString(),
localeString: date.toLocaleString(locale, localeOptionsInUTC),
};
}

Expand Down
7 changes: 7 additions & 0 deletions extensions/amp-date-display/0.1/amp-date-display.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ This table lists the format you can specify in your Mustache template:
| secondTwoDigit | 00, 01, 02, ..., 58, 59 |
| year | 0, 1, 2, ..., 1999, 2000, 2001, etc. |
| yearTwoDigit | 00, 01, 02, ..., 17, 18, 19, ..., 98, 99 |
| localeString | A string with a language sensitive representation. |

## Attributes

Expand Down Expand Up @@ -115,6 +116,12 @@ date to UTC.
The `offset-seconds` attribute specifies an integer number of seconds to shift
the given date.

### data-options-\* (optional)

The `data-options-*` supports all the options under [Intl.DateTimeFormat.options](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#parameters)
parameter that specifies the formatting style to use for `localeString` format.
Valid attributes include: `data-options-date-style`, `data-options-time-style`, etc.

## Validation

See [amp-date-display rules](../validator-amp-date-display.protoascii) in the AMP validator specification.
27 changes: 27 additions & 0 deletions extensions/amp-date-display/0.1/test/test-amp-date-display.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ describes.realWin(
expect(data.second).to.equal(6);
expect(data.secondTwoDigit).to.equal('06');
expect(data.dayPeriod).to.equal('am');
expect(data.localeString).to.equal('Feb 3, 2001, 4:05 AM');
});

it('provides all variables in local and English (default)', async () => {
Expand Down Expand Up @@ -108,6 +109,7 @@ describes.realWin(
expect(data.second).to.equal(6);
expect(data.secondTwoDigit).to.equal('06');
expect(data.dayPeriod).to.equal('am');
expect(data.localeString).to.equal('Feb 3, 2001, 4:05 AM');
});

describe('correctly parses', () => {
Expand Down Expand Up @@ -206,5 +208,30 @@ describes.realWin(
expect(data.dayName).to.equal('sobota');
expect(data.dayNameShort).to.equal('so');
});

it('locale and data-options-time-style', async () => {
element.setAttribute('datetime', '2001-02-03T04:05:06.007Z');
element.setAttribute('display-in', 'UTC');
element.setAttribute('locale', 'zh-TW');
element.setAttribute('data-options-time-style', 'short');
await element.buildInternal();

const data = impl.getDataForTemplate_();

expect(data.localeString).to.equal('上午4:05');
});

it('locale, data-options-time-style, and data-options-date-style', async () => {
element.setAttribute('datetime', '2001-02-03T04:05:06.007Z');
element.setAttribute('display-in', 'UTC');
element.setAttribute('locale', 'zh-TW');
element.setAttribute('data-options-date-style', 'full');
element.setAttribute('data-options-time-style', 'medium');
await element.buildInternal();

const data = impl.getDataForTemplate_();

expect(data.localeString).to.equal('2001年2月3日 星期六 上午4:05:06');
});
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@
<amp-date-display datetime="2017-08-02T15:05:05.+04:00" layout="fixed" width="360" height="20">
<template type="amp-mustache">{{iso}}</template>
</amp-date-display>

<!-- valid, with data-options-time-style -->
<amp-date-display datetime="now" layout="fixed" width="360" height="20" data-options-time-style="short">
<template type="amp-mustache">{{localeString}}</template>
</amp-date-display>
</body>

</html>
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@ amp-date-display/0.1/test/validator-amp-date-display.html:168:2 The attribute 'd
amp-date-display/0.1/test/validator-amp-date-display.html:173:2 The attribute 'datetime' in tag 'amp-date-display' is set to the invalid value '2017-08-02T15:05:05.+04:00'. (see https://amp.dev/documentation/components/amp-date-display)
| <template type="amp-mustache">{{iso}}</template>
| </amp-date-display>
|
| <!-- valid, with data-options-time-style -->
| <amp-date-display datetime="now" layout="fixed" width="360" height="20" data-options-time-style="short">
| <template type="amp-mustache">{{localeString}}</template>
| </amp-date-display>
| </body>
|
| </html>
| </html>
11 changes: 0 additions & 11 deletions extensions/amp-date-display/1.0/amp-date-display.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import {BaseElement} from './base-element';
import {Services} from '../../../src/services';
import {childElementsByTag, isJsonScriptTag} from '../../../src/dom';
import {dev, userAssert} from '../../../src/log';
import {dict} from '../../../src/core/types/object';
import {isExperimentOn} from '../../../src/experiments';
Expand All @@ -36,16 +35,6 @@ class AmpDateDisplay extends BaseElement {
this.template_ = null;
}

/** @override */
buildCallback() {
super.buildCallback();
// Handle additional JSON
const scriptElement = childElementsByTag(this.element, 'SCRIPT')[0];
if (scriptElement && isJsonScriptTag(scriptElement)) {
this.element.setAttribute('json', scriptElement.textContent);
}
}

/** @override */
isLayoutSupported(layout) {
userAssert(
Expand Down
21 changes: 1 addition & 20 deletions extensions/amp-date-display/1.0/base-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import {DateDisplay} from './component';
import {PreactBaseElement} from '../../../src/preact/base-element';
import {parseDateAttrs as parseDateAttrsBase} from '../../../src/utils/date';
import {tryParseJson} from '../../../src/core/types/object/json';

export class BaseElement extends PreactBaseElement {}

Expand All @@ -32,10 +31,7 @@ BaseElement['props'] = {
},
'displayIn': {attr: 'display-in'},
'locale': {attr: 'locale'},
'additionalOptions': {
attrs: ['json'],
parseAttrs: parseJsonStr,
},
'localeOptions': {attrPrefix: 'data-options-'},
};

/** @override */
Expand All @@ -60,18 +56,3 @@ export function parseDateAttrs(element) {
'timestamp-seconds',
]);
}

/**
* @param {!Element} element
* @return {?JsonObject} May be extend to parse arrays.
* @throws {Error} Parsing fails error.
*/
function parseJsonStr(element) {
const jsonStr = element.getAttribute('json');
if (!jsonStr) {
return;
}
return tryParseJson(jsonStr, (error) => {
throw error;
});
}
11 changes: 2 additions & 9 deletions extensions/amp-date-display/1.0/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,6 @@ const DEFAULT_DATETIME_OPTIONS = {
'minute': 'numeric',
};

/** @const {!Object<string, *>} */
const DEFAULT_DATETIME_OPTIONS_UTC = {
...DEFAULT_DATETIME_OPTIONS,
timeZone: 'UTC',
};

/**
* @param {!JsonObject} data
* @return {string}
Expand Down Expand Up @@ -95,12 +89,11 @@ export function DateDisplay({
datetime,
displayIn = DEFAULT_DISPLAY_IN,
locale = DEFAULT_LOCALE,
additionalOptions = {},
localeOptions,
render = DEFAULT_RENDER,
...rest
}) {
const date = getDate(datetime);
const {localeOptions} = additionalOptions;
const data = useMemo(
() => getDataForTemplate(new Date(date), displayIn, locale, localeOptions),
[date, displayIn, locale, localeOptions]
Expand Down Expand Up @@ -214,7 +207,7 @@ function getVariablesInLocal(
function getVariablesInUTC(
date,
locale,
localeOptions = DEFAULT_DATETIME_OPTIONS_UTC
localeOptions = DEFAULT_DATETIME_OPTIONS
) {
const localeOptionsInUTC = {
...localeOptions,
Expand Down
2 changes: 1 addition & 1 deletion extensions/amp-date-display/1.0/component.type.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ var DateDisplayDef = {};
* datetime: (!Date|number|string),
* displayIn: (string|undefined),
* locale: (string|undefined),
* additionalOptions: (?Object<string, *>|undefined),
* localeOptions: (Object<string, *>),
* render: (?RendererFunctionType|undefined),
* }}
*/
Expand Down
Loading

0 comments on commit b7bcffb

Please sign in to comment.