-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
amp-date-picker: restore rrule support #28887
Changes from all commits
f7f256a
12157fb
ab1f9ef
0e3c738
b71cc3f
a47391b
872646b
dd2acf3
f2ee126
f8eb27f
170a468
94152c8
c1ee0d0
0eaeeb6
6445b0c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,16 +14,20 @@ | |
* limitations under the License. | ||
*/ | ||
|
||
import * as rrule from '../../../node_modules/rrule/dist/es5/rrule.min.js'; | ||
import {requireExternal} from '../../../src/module'; | ||
|
||
const rrulestr = rrule.default.rrulestr || rrule.rrulestr; // CC imports into .default, browserify flattens a layer. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Please move this into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it makes more sense where it is, considering ideally it would even be |
||
|
||
/** @enum {string} */ | ||
const DateType = { | ||
INVALID: 'invalid', | ||
RRULE: 'rrule', | ||
DATE: 'date', | ||
}; | ||
|
||
/** | ||
* A class which wraps a list of moment dates. | ||
* A class which wraps a list of moment dates or RRULE dates. | ||
*/ | ||
export class DatesList { | ||
/** | ||
|
@@ -38,6 +42,11 @@ export class DatesList { | |
/** @private @const */ | ||
this.moment_ = requireExternal('moment'); | ||
|
||
/** @private @const */ | ||
this.rrulestrs_ = dates | ||
.filter((d) => this.getDateType_(d) === DateType.RRULE) | ||
.map((d) => tryParseRrulestr(d)); | ||
|
||
/** @private @const */ | ||
this.dates_ = dates | ||
.filter((d) => this.getDateType_(d) == DateType.DATE) | ||
|
@@ -46,14 +55,14 @@ export class DatesList { | |
} | ||
|
||
/** | ||
* Determines if the given date is contained within the moment dates | ||
* Determines if the given date is contained within the RRULEs or moment dates | ||
* contained in the date list. | ||
* @param {!moment|string} date | ||
* @return {boolean} | ||
*/ | ||
contains(date) { | ||
const m = this.moment_(date); | ||
return this.matchesDate_(m); | ||
return this.matchesDate_(m) || this.matchesRrule_(m); | ||
} | ||
|
||
/** | ||
|
@@ -73,7 +82,17 @@ export class DatesList { | |
} | ||
} | ||
|
||
return firstDatesAfter.sort((a, b) => a.toDate() - b.toDate())[0]; | ||
const rruleDates = this.rrulestrs_ | ||
.map((rrule) => /** @type {RRule} */ (rrule).after(date)) | ||
.filter(Boolean) | ||
.map(normalizeRruleReturn); | ||
|
||
return firstDatesAfter.concat(rruleDates).sort((a, b) => { | ||
// toDate method does not exist for RRule dates. | ||
a = a.toDate ? a.toDate() : a; | ||
b = b.toDate ? b.toDate() : b; | ||
return a - b; | ||
})[0]; | ||
} | ||
|
||
/** | ||
|
@@ -87,7 +106,26 @@ export class DatesList { | |
} | ||
|
||
/** | ||
* Distinguish between moment dates. | ||
* Determines if any internal RRULE object matches the given date. | ||
* @param {!moment} date | ||
* @return {boolean} | ||
* @private | ||
*/ | ||
matchesRrule_(date) { | ||
const nextDate = date.clone().startOf('day').add(1, 'day').toDate(); | ||
return this.rrulestrs_.some((rrule) => { | ||
const rruleUTCDate = /** @type {RRule} */ (rrule).before(nextDate); | ||
if (!rruleUTCDate) { | ||
return false; | ||
} | ||
const rruleLocalDate = normalizeRruleReturn(rruleUTCDate); | ||
const rruleMoment = this.moment_(rruleLocalDate); | ||
return this.ReactDates_['isSameDay'](rruleMoment, date); | ||
}); | ||
} | ||
|
||
/** | ||
* Distinguish between RRULE dates and moment dates. | ||
* @param {!moment|string} date | ||
* @return {!DateType} | ||
* @private | ||
|
@@ -97,6 +135,42 @@ export class DatesList { | |
return DateType.DATE; | ||
} | ||
|
||
const dateStr = /** @type {string} */ (date); | ||
if (tryParseRrulestr(dateStr)) { | ||
return DateType.RRULE; | ||
} | ||
|
||
return DateType.INVALID; | ||
} | ||
} | ||
|
||
/** | ||
* RRULE returns dates as local time formatted at UTC, so the | ||
* Date.prototype.getUTC* methods must be used to create a new date object. | ||
* {@link https://github.com/jakubroztocil/rrule#important-use-utc-dates} | ||
* @param {!Date} rruleDate | ||
* @return {!Date} | ||
*/ | ||
function normalizeRruleReturn(rruleDate) { | ||
const year = rruleDate.getUTCFullYear(); | ||
const month = rruleDate.getUTCMonth(); | ||
const day = rruleDate.getUTCDate(); | ||
const hours = rruleDate.getUTCHours(); | ||
const minutes = rruleDate.getUTCMinutes(); | ||
const seconds = rruleDate.getUTCSeconds(); | ||
const ms = rruleDate.getUTCMilliseconds(); | ||
return new Date(year, month, day, hours, minutes, seconds, ms); | ||
} | ||
|
||
/** | ||
* Tries to parse a string into an RRULE object. | ||
* @param {string} str A string which represents a repeating date RRULE spec. | ||
* @return {?RRule} | ||
*/ | ||
function tryParseRrulestr(str) { | ||
try { | ||
return rrulestr(str, {}); | ||
} catch (e) { | ||
return null; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OMG, you got this to work!