264 lines
7.2 KiB
JavaScript
264 lines
7.2 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
* Portions Copyright (C) Philipp Kewisch */
|
|
|
|
import Time from "./time.js";
|
|
import Duration from "./duration.js";
|
|
// needed for typescript type resolution
|
|
// eslint-disable-next-line no-unused-vars
|
|
import Property from "./property.js";
|
|
|
|
/**
|
|
* This lets typescript resolve our custom types in the
|
|
* generated d.ts files (jsdoc typedefs are converted to typescript types).
|
|
* Ignore prevents the typedefs from being documented more than once.
|
|
* @ignore
|
|
* @typedef {import("./types.js").jCalComponent} jCalComponent
|
|
* Imports the 'occurrenceDetails' type from the "types.js" module
|
|
*/
|
|
|
|
/**
|
|
* This class represents the "period" value type, with various calculation and manipulation methods.
|
|
*
|
|
* @memberof ICAL
|
|
*/
|
|
class Period {
|
|
/**
|
|
* Creates a new {@link ICAL.Period} instance from the passed string.
|
|
*
|
|
* @param {String} str The string to parse
|
|
* @param {Property} prop The property this period will be on
|
|
* @return {Period} The created period instance
|
|
*/
|
|
static fromString(str, prop) {
|
|
let parts = str.split('/');
|
|
|
|
if (parts.length !== 2) {
|
|
throw new Error(
|
|
'Invalid string value: "' + str + '" must contain a "/" char.'
|
|
);
|
|
}
|
|
|
|
let options = {
|
|
start: Time.fromDateTimeString(parts[0], prop)
|
|
};
|
|
|
|
let end = parts[1];
|
|
|
|
if (Duration.isValueString(end)) {
|
|
options.duration = Duration.fromString(end);
|
|
} else {
|
|
options.end = Time.fromDateTimeString(end, prop);
|
|
}
|
|
|
|
return new Period(options);
|
|
}
|
|
|
|
/**
|
|
* Creates a new {@link ICAL.Period} instance from the given data object.
|
|
* The passed data object cannot contain both and end date and a duration.
|
|
*
|
|
* @param {Object} aData An object with members of the period
|
|
* @param {Time=} aData.start The start of the period
|
|
* @param {Time=} aData.end The end of the period
|
|
* @param {Duration=} aData.duration The duration of the period
|
|
* @return {Period} The period instance
|
|
*/
|
|
static fromData(aData) {
|
|
return new Period(aData);
|
|
}
|
|
|
|
/**
|
|
* Returns a new period instance from the given jCal data array. The first
|
|
* member is always the start date string, the second member is either a
|
|
* duration or end date string.
|
|
*
|
|
* @param {jCalComponent} aData The jCal data array
|
|
* @param {Property} aProp The property this jCal data is on
|
|
* @param {Boolean} aLenient If true, data value can be both date and date-time
|
|
* @return {Period} The period instance
|
|
*/
|
|
static fromJSON(aData, aProp, aLenient) {
|
|
function fromDateOrDateTimeString(aValue, dateProp) {
|
|
if (aLenient) {
|
|
return Time.fromString(aValue, dateProp);
|
|
} else {
|
|
return Time.fromDateTimeString(aValue, dateProp);
|
|
}
|
|
}
|
|
|
|
if (Duration.isValueString(aData[1])) {
|
|
return Period.fromData({
|
|
start: fromDateOrDateTimeString(aData[0], aProp),
|
|
duration: Duration.fromString(aData[1])
|
|
});
|
|
} else {
|
|
return Period.fromData({
|
|
start: fromDateOrDateTimeString(aData[0], aProp),
|
|
end: fromDateOrDateTimeString(aData[1], aProp)
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates a new ICAL.Period instance. The passed data object cannot contain both and end date and
|
|
* a duration.
|
|
*
|
|
* @param {Object} aData An object with members of the period
|
|
* @param {Time=} aData.start The start of the period
|
|
* @param {Time=} aData.end The end of the period
|
|
* @param {Duration=} aData.duration The duration of the period
|
|
*/
|
|
constructor(aData) {
|
|
this.wrappedJSObject = this;
|
|
|
|
if (aData && 'start' in aData) {
|
|
if (aData.start && !(aData.start instanceof Time)) {
|
|
throw new TypeError('.start must be an instance of ICAL.Time');
|
|
}
|
|
this.start = aData.start;
|
|
}
|
|
|
|
if (aData && aData.end && aData.duration) {
|
|
throw new Error('cannot accept both end and duration');
|
|
}
|
|
|
|
if (aData && 'end' in aData) {
|
|
if (aData.end && !(aData.end instanceof Time)) {
|
|
throw new TypeError('.end must be an instance of ICAL.Time');
|
|
}
|
|
this.end = aData.end;
|
|
}
|
|
|
|
if (aData && 'duration' in aData) {
|
|
if (aData.duration && !(aData.duration instanceof Duration)) {
|
|
throw new TypeError('.duration must be an instance of ICAL.Duration');
|
|
}
|
|
this.duration = aData.duration;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* The start of the period
|
|
* @type {Time}
|
|
*/
|
|
start = null;
|
|
|
|
/**
|
|
* The end of the period
|
|
* @type {Time}
|
|
*/
|
|
end = null;
|
|
|
|
/**
|
|
* The duration of the period
|
|
* @type {Duration}
|
|
*/
|
|
duration = null;
|
|
|
|
/**
|
|
* The class identifier.
|
|
* @constant
|
|
* @type {String}
|
|
* @default "icalperiod"
|
|
*/
|
|
icalclass = "icalperiod";
|
|
|
|
/**
|
|
* The type name, to be used in the jCal object.
|
|
* @constant
|
|
* @type {String}
|
|
* @default "period"
|
|
*/
|
|
icaltype = "period";
|
|
|
|
/**
|
|
* Returns a clone of the duration object.
|
|
*
|
|
* @return {Period} The cloned object
|
|
*/
|
|
clone() {
|
|
return Period.fromData({
|
|
start: this.start ? this.start.clone() : null,
|
|
end: this.end ? this.end.clone() : null,
|
|
duration: this.duration ? this.duration.clone() : null
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Calculates the duration of the period, either directly or by subtracting
|
|
* start from end date.
|
|
*
|
|
* @return {Duration} The calculated duration
|
|
*/
|
|
getDuration() {
|
|
if (this.duration) {
|
|
return this.duration;
|
|
} else {
|
|
return this.end.subtractDate(this.start);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calculates the end date of the period, either directly or by adding
|
|
* duration to start date.
|
|
*
|
|
* @return {Time} The calculated end date
|
|
*/
|
|
getEnd() {
|
|
if (this.end) {
|
|
return this.end;
|
|
} else {
|
|
let end = this.start.clone();
|
|
end.addDuration(this.duration);
|
|
return end;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Compare this period with a date or other period. To maintain the logic where a.compare(b)
|
|
* returns 1 when a > b, this function will return 1 when the period is after the date, 0 when the
|
|
* date is within the period, and -1 when the period is before the date. When comparing two
|
|
* periods, as soon as they overlap in any way this will return 0.
|
|
*
|
|
* @param {Time|Period} dt The date or other period to compare with
|
|
*/
|
|
compare(dt) {
|
|
if (dt.compare(this.start) < 0) {
|
|
return 1;
|
|
} else if (dt.compare(this.getEnd()) > 0) {
|
|
return -1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The string representation of this period.
|
|
* @return {String}
|
|
*/
|
|
toString() {
|
|
return this.start + "/" + (this.end || this.duration);
|
|
}
|
|
|
|
/**
|
|
* The jCal representation of this period type.
|
|
* @return {Object}
|
|
*/
|
|
toJSON() {
|
|
return [this.start.toString(), (this.end || this.duration).toString()];
|
|
}
|
|
|
|
/**
|
|
* The iCalendar string representation of this period.
|
|
* @return {String}
|
|
*/
|
|
toICALString() {
|
|
return this.start.toICALString() + "/" +
|
|
(this.end || this.duration).toICALString();
|
|
}
|
|
}
|
|
export default Period;
|