Skip to content

Commit

Permalink
✨ Add binding for amp-date-picker min attribute (#19035)
Browse files Browse the repository at this point in the history
* Add binding for amp-date-picker min attribute

* Clarify getDefaultMinDate behavior and remove extra moment call
  • Loading branch information
cvializ authored Oct 30, 2018
1 parent 299b0ab commit 36fd394
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 59 deletions.
13 changes: 13 additions & 0 deletions examples/date-picker.amp.html
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,19 @@ <h3>Start and End Today</h3>
<button on="tap: trp.clear">Clear</button>
<amp-date-picker id="trp" type="range" layout="fixed-height" height="360"></amp-date-picker>

<h2>amp-bind</h2>
<h3>min</h3>
<amp-state id="min"><script type="application/json">"2018-10-10"</script></amp-state>
<div><span [text]="min">2018-10-10</span></div>
<label>min: <input on="change:AMP.setState({min: event.value})" value="2018-10-10"></label>
<amp-date-picker mode="static" layout="fixed-height" height="360" min="2018-10-10" [min]="min"></amp-date-picker>

<h3>max</h3>
<amp-state id="max"><script type="application/json">"2018-10-10"</script></amp-state>
<div><span [text]="max">2018-10-10</span></div>
<label>max: <input on="change:AMP.setState({max: event.value})" value="2018-10-10"></label>
<amp-date-picker mode="static" layout="fixed-height" height="360" max="2018-10-10" [max]="max"></amp-date-picker>

<div class="spacer"></div>
</body>
</html>
4 changes: 4 additions & 0 deletions extensions/amp-bind/0.1/bind-validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ function createElementRules_() {
'AMP-CAROUSEL': {
'slide': null,
},
'AMP-DATE-PICKER': {
'max': null,
'min': null,
},
'AMP-GOOGLE-DOCUMENT-EMBED': {
'src': null,
'title': null,
Expand Down
11 changes: 11 additions & 0 deletions extensions/amp-bind/amp-bind.md
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,17 @@ Only binding to the following components and attributes are allowed:
<td><code>[slide]</code><sup>*</sup></td>
<td>Changes the currently displayed slide index. <a href="https://ampbyexample.com/advanced/image_galleries_with_amp-carousel/#linking-carousels-with-amp-bind">See an example</a>.</td>
</tr>
<tr>
<td><code>&lt;amp-date-picker&gt;</code></td>
<td>
<code>[min]</code><br>
<code>[max]</code>
</td>
<td>
Sets the earliest selectable date<br>
Sets the latest selectable date
</td>
</tr>
<tr>
<td><code>&lt;amp-google-document-embed&gt;</code></td>
<td><code>[src]</code><br><code>[title]</code></td>
Expand Down
26 changes: 24 additions & 2 deletions extensions/amp-date-picker/0.1/amp-date-picker.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,6 @@ const TAG = 'amp-date-picker';
const DATE_SEPARATOR = ' ';

const attributesToForward = [
'max',
'min',
'month-format',
'number-of-months',
'minimum-nights',
Expand Down Expand Up @@ -481,6 +479,23 @@ export class AmpDatePicker extends AMP.BaseElement {
});
}

/** @override */
mutatedAttributesCallback(mutations) {
const newState = map();

const min = mutations['min'];
if (min !== undefined) {
newState['min'] = min;
}

const max = mutations['max'];
if (max !== undefined) {
newState['max'] = max;
}

this.setState_(newState);
}

/** @override */
layoutCallback() {
const srcAttributesPromise = this.setupSrcAttributes_();
Expand Down Expand Up @@ -743,13 +758,18 @@ export class AmpDatePicker extends AMP.BaseElement {
this.endDateField_.value = this.getFormattedDate_(endDate);
}

const max = element.getAttribute('max') || '';
const min = element.getAttribute('min') || '';

return map({
date,
endDate,
focused: this.mode_ == DatePickerMode.STATIC,
focusedInput: this.ReactDatesConstants_.START_DATE,
isFocused: false,
isOpen: this.mode_ == DatePickerMode.STATIC,
max,
min,
startDate,
});
}
Expand Down Expand Up @@ -1676,6 +1696,8 @@ export class AmpDatePicker extends AMP.BaseElement {
// in the month.
this.reactRender_(
this.react_.createElement(Picker, Object.assign({}, {
min: props.min,
max: props.max,
date: props.date,
startDate: props.startDate,
endDate: props.endDate,
Expand Down
77 changes: 47 additions & 30 deletions extensions/amp-date-picker/0.1/date-picker-common.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,17 @@ export function withDatePickerCommon(WrappedComponent) {
const moment = requireExternal('moment');

/**
* @param {!moment} max
* @return {!moment}
* If `max` is null, the default minimum date is the current date.
* If `max` is a Moment date and earlier than the current date, then
* there is no default minimum date. If `max` is later than the current date,
* then the default minimum date is the current date.
* @param {?moment} max
* @return {?moment}
*/
function getDefaultMinDate(max) {
const today = moment();
if (max) {
return !isInclusivelyAfterDay(today, moment(max)) ? today : '';
return !isInclusivelyAfterDay(today, max) ? today : null;
} else {
return today;
}
Expand All @@ -52,8 +56,8 @@ export function withDatePickerCommon(WrappedComponent) {
* @return {boolean}
*/
function isOutsideRange(min, max, date) {
const maxInclusive = max && moment(max);
const minInclusive = min && moment(min);
const maxInclusive = max ? moment(max) : null;
const minInclusive = min ? moment(min) : getDefaultMinDate(maxInclusive);
if (!maxInclusive && !minInclusive) {
return false;
} else if (!minInclusive) {
Expand All @@ -65,6 +69,18 @@ export function withDatePickerCommon(WrappedComponent) {
}
}

/**
* @param {!./dates-list.DatesList} list
* @param {!moment} day
* @return {boolean}
*/
function datesListContains(list, day) {
if (!list) {
return false;
}
return list.contains(day);
}

const defaultProps = map({
blocked: null,
highlighted: null,
Expand All @@ -81,12 +97,16 @@ export function withDatePickerCommon(WrappedComponent) {
constructor(props) {
super(props);

/** @private @const */
this.min_ = this.props.min || getDefaultMinDate(this.props.max);
const {
blocked,
highlighted,
min,
max,
} = props;

this.isDayBlocked = this.isDayBlocked.bind(this);
this.isDayHighlighted = this.isDayHighlighted.bind(this);
this.isOutsideRange = this.isOutsideRange.bind(this);
this.isDayBlocked = datesListContains.bind(null, blocked);
this.isDayHighlighted = datesListContains.bind(null, highlighted);
this.isOutsideRange = isOutsideRange.bind(null, min, max);
}

/** @override */
Expand All @@ -96,28 +116,25 @@ export function withDatePickerCommon(WrappedComponent) {
}
}

/**
* @param {!moment} day
* @return {boolean}
*/
isDayBlocked(day) {
return this.props.blocked.contains(day);
}
/** @override */
componentWillReceiveProps(nextProps) {
const {
max,
min,
blocked,
highlighted,
} = nextProps;
if (min != this.props.min || max != this.props.max) {
this.isOutsideRange = isOutsideRange.bind(null, min, max);
}

/**
* @param {!moment} day
* @return {boolean}
*/
isDayHighlighted(day) {
return this.props.highlighted.contains(day);
}
if (blocked != this.props.blocked) {
this.isDayBlocked = datesListContains.bind(null, blocked);
}

/**
* @param {!moment} day
* @return {boolean}
*/
isOutsideRange(day) {
return isOutsideRange(this.min_, this.props.max, day);
if (highlighted != this.props.highlighted) {
this.isDayHighlighted = datesListContains.bind(null, highlighted);
}
}

/** @override */
Expand Down
3 changes: 2 additions & 1 deletion extensions/amp-date-picker/0.1/test/test-amp-date-picker.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,8 @@ describes.realWin('amp-date-picker', {
});

describe('src templates', () => {
it('should parse RRULE and date templates', () => {
it('should parse RRULE and date templates', function() {
this.timeout(4000);
const template = createDateTemplate('{{val}}', {
dates: '2018-01-01',
id: 'srcTemplate',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@
<amp-date-picker mode="overlay" touch-keyboard-editable input-selector="#a4">
<input id="a4">
</amp-date-picker>
<!-- Valid: amp-date-picker with max and min binding -->
<amp-date-picker [min]="min" [max]="max" layout="fixed-height" height="360">
</amp-date-picker>

<!-- Invalid: single amp-date-picker with start-input-selector -->
<amp-date-picker type="single" mode="static" start-input-selector="#x3" layout="fixed-height" height="360">
Expand Down
Loading

0 comments on commit 36fd394

Please sign in to comment.