novo-elements
Version:
1,419 lines (1,411 loc) • 545 kB
JavaScript
import { isDate, format, addDays, addWeeks, addMonths, startOfMinute, startOfDay, startOfWeek, startOfMonth, endOfDay, endOfWeek, endOfMonth, isSameDay, isSameMonth, isSameSecond, differenceInSeconds, differenceInCalendarDays, differenceInDays, isWithinInterval, getMonth, getYear, setMinutes, setHours, isBefore, isAfter, addMinutes, getDay, differenceInMinutes, addHours } from 'date-fns';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import * as i0 from '@angular/core';
import { TemplateRef, isDevMode, EventEmitter, Injectable } from '@angular/core';
var AppBridgeHandler;
(function (AppBridgeHandler) {
AppBridgeHandler[AppBridgeHandler["HTTP"] = 0] = "HTTP";
AppBridgeHandler[AppBridgeHandler["OPEN"] = 1] = "OPEN";
AppBridgeHandler[AppBridgeHandler["OPEN_LIST"] = 2] = "OPEN_LIST";
AppBridgeHandler[AppBridgeHandler["CLOSE"] = 3] = "CLOSE";
AppBridgeHandler[AppBridgeHandler["REFRESH"] = 4] = "REFRESH";
AppBridgeHandler[AppBridgeHandler["PIN"] = 5] = "PIN";
AppBridgeHandler[AppBridgeHandler["REGISTER"] = 6] = "REGISTER";
AppBridgeHandler[AppBridgeHandler["UPDATE"] = 7] = "UPDATE";
AppBridgeHandler[AppBridgeHandler["REQUEST_DATA"] = 8] = "REQUEST_DATA";
AppBridgeHandler[AppBridgeHandler["CALLBACK"] = 9] = "CALLBACK";
AppBridgeHandler[AppBridgeHandler["PING"] = 10] = "PING";
})(AppBridgeHandler || (AppBridgeHandler = {}));
const HTTP_VERBS = {
GET: 'get',
POST: 'post',
PUT: 'put',
DELETE: 'delete',
};
const MESSAGE_TYPES = {
REGISTER: 'register',
OPEN: 'open',
OPEN_LIST: 'openList',
CLOSE: 'close',
REFRESH: 'refresh',
PIN: 'pin',
PING: 'ping',
UPDATE: 'update',
HTTP_GET: 'httpGET',
HTTP_POST: 'httpPOST',
HTTP_PUT: 'httpPUT',
HTTP_DELETE: 'httpDELETE',
CUSTOM_EVENT: 'customEvent',
REQUEST_DATA: 'requestData',
CALLBACK: 'callback',
};
class AppBridgeService {
create(name) {
return new AppBridge(name);
}
}
class DevAppBridgeService {
constructor(http) {
this.http = http;
}
create(name, postRobotRef) {
return new DevAppBridge(name, this.http, postRobotRef);
}
}
// remove attributes unsafe for postrobot.send()
function cleanPacket(packet) {
if (packet && typeof packet === 'object' && 'source' in packet) {
delete packet.source;
}
}
class AppBridge {
// Type?
constructor(traceName = 'AppBridge', postRobotRef) {
this.id = `${Date.now()}`;
this._registeredFrames = [];
this._handlers = {};
this._tracing = false;
this._eventListeners = {};
this.traceName = traceName;
this.postRobot = postRobotRef || /* global */ postRobot;
if (this.postRobot) {
this.postRobot.CONFIG.LOG_LEVEL = 'error';
try {
this._setupHandlers();
}
catch (error) {
// No op
}
}
}
set tracing(tracing) {
this._tracing = tracing;
}
handle(type, handler) {
this._handlers[type] = handler;
}
_trace(eventType, event) {
if (this._tracing) {
console.info(`[${this.traceName || this.id}] "${eventType}"`, event);
}
}
_setupHandlers() {
// map an object for all handlers, so that we can run some other actions before each of them
const defaultMsgHandlers = {
// Register
[MESSAGE_TYPES.REGISTER]: async (event) => {
this._registeredFrames.push(event);
const windowName = await this.register(event.data);
return { windowName };
},
// Update
[MESSAGE_TYPES.UPDATE]: (event) => {
return this.update(event.data).then((success) => {
return { success };
});
},
// Open
[MESSAGE_TYPES.OPEN]: (event) => {
return this.open(event.data).then((success) => {
return { success };
});
},
[MESSAGE_TYPES.OPEN_LIST]: (event) => {
return this.openList(event.data).then((success) => {
return { success };
});
},
// Close
[MESSAGE_TYPES.CLOSE]: (event) => {
const index = this._registeredFrames.findIndex((frame) => frame.data.id === event.data.id);
if (index !== -1) {
this._registeredFrames.splice(index, 1);
}
return this.close(event.data).then(success => ({ success }));
},
// Refresh
[MESSAGE_TYPES.REFRESH]: (event) => {
return this.refresh(event.data).then((success) => {
return { success };
});
},
// PIN
[MESSAGE_TYPES.PIN]: (event) => {
return this.pin(event.data).then((success) => {
return { success };
});
},
// PING
[MESSAGE_TYPES.PING]: (event) => {
return this.httpGET('ping', undefined, event.data.origin).then((result) => {
return { data: result.data, error: result.error };
});
},
// REQUEST_DATA
[MESSAGE_TYPES.REQUEST_DATA]: (event) => {
return this.requestData(event.data).then((result) => {
return { data: result.data, error: result.error };
});
},
// CALLBACKS
[MESSAGE_TYPES.CALLBACK]: (event) => {
return this.callback(event.data).then((success) => {
return { success };
});
},
// HTTP-GET
[MESSAGE_TYPES.HTTP_GET]: (event) => {
return this.httpGET(event.data.relativeURL, undefined, event.data.origin).then((result) => {
return { data: result.data, error: result.error };
});
},
// HTTP-POST
[MESSAGE_TYPES.HTTP_POST]: (event) => {
return this.httpPOST(event.data.relativeURL, event.data.data, undefined, event.data.origin).then((result) => {
return { data: result.data, error: result.error };
});
},
// HTTP-PUT
[MESSAGE_TYPES.HTTP_PUT]: (event) => {
return this.httpPUT(event.data.relativeURL, event.data.data, undefined, event.data.origin).then((result) => {
return { data: result.data, error: result.error };
});
},
// HTTP-DELETE
[MESSAGE_TYPES.HTTP_DELETE]: (event) => {
return this.httpDELETE(event.data.relativeURL, undefined, event.data.origin).then((result) => {
return { data: result.data, error: result.error };
});
},
// Custom Events
[MESSAGE_TYPES.CUSTOM_EVENT]: async (event) => {
if (this._eventListeners[event.data.event]) {
this._eventListeners[event.data.event].forEach((listener) => {
listener(event.data.data);
});
}
if (this._registeredFrames.length > 0) {
cleanPacket(event.data);
this._registeredFrames.forEach((frame) => {
// TODO: Should this make sure it doesn't echo the custom event back to the author?
this.postRobot.send(frame.source, MESSAGE_TYPES.CUSTOM_EVENT, event.data);
});
}
},
};
Object.keys(defaultMsgHandlers).forEach(msgType => {
this.postRobot.on(msgType, event => {
this._trace(msgType, event);
const origin = Array.isArray(event.data.origin) ? event.data.origin : [];
if (event.origin !== this.windowOrigin()) {
origin.unshift(event.origin);
}
else if (origin.indexOf(event.data.originTraceName) === -1) {
origin.unshift(event.data.originTraceName);
}
if (event.data) {
// known gap - simple commands will not forward origin/source from subchild frames to parent
event.data.origin = origin;
event.data.source = event.source;
}
return defaultMsgHandlers[msgType](event);
});
});
}
windowOrigin() {
return window.location.origin;
}
handleMessage({ msgType, handler, packet, echoPacket, resolveEventData }) {
let returnPromise;
if (this._handlers[handler]) {
// Should be directly returning a promise. However, as a fallback, provide callback arguments
let callbackSuccess;
let callbackFail;
returnPromise = new Promise((s, f) => {
callbackSuccess = s;
callbackFail = f;
});
const handlerResult = this._handlers[handler](packet, callbackArg => {
if (callbackArg) {
callbackSuccess(true);
}
else {
callbackFail(false);
}
});
if (handlerResult && 'then' in handlerResult) {
returnPromise = handlerResult;
}
return returnPromise.then(result => true, () => false);
}
else {
return this.postRobot.sendToParent(msgType, echoPacket || packet);
}
}
/**
* Fires or responds to an open event
* @param packet any - packet of data to send with the open event
*/
open(packet) {
return new Promise((resolve, reject) => {
if (this._handlers[AppBridgeHandler.OPEN]) {
this._handlers[AppBridgeHandler.OPEN](packet, (success) => {
if (success) {
resolve(true);
}
else {
reject(false);
}
});
}
else {
cleanPacket(packet);
Object.assign(packet, { id: this.id, windowName: this.windowName });
this.postRobot
.sendToParent(MESSAGE_TYPES.OPEN, packet)
.then((event) => {
this._trace(`${MESSAGE_TYPES.OPEN} (callback)`, event);
if (event.data) {
resolve(true);
}
else {
reject(false);
}
})
.catch((err) => {
reject(false);
});
}
});
}
/**
* Fires or responds to an openList event
* @param packet any - packet of data to send with the open event
*/
openList(packet) {
return new Promise((resolve, reject) => {
if (this._handlers[AppBridgeHandler.OPEN_LIST]) {
this._handlers[AppBridgeHandler.OPEN_LIST](packet, (success) => {
if (success) {
resolve(true);
}
else {
reject(false);
}
});
}
else {
const openListPacket = {};
Object.assign(openListPacket, { type: 'List', entityType: packet.type, keywords: packet.keywords, criteria: packet.criteria });
this.postRobot
.sendToParent(MESSAGE_TYPES.OPEN_LIST, packet)
.then((event) => {
this._trace(`${MESSAGE_TYPES.OPEN_LIST} (callback)`, event);
if (event.data) {
resolve(true);
}
else {
reject(false);
}
})
.catch((err) => {
reject(false);
});
}
});
}
/**
* Fires or responds to an close event
* @param packet any - packet of data to send with the close event
*/
update(packet) {
return new Promise((resolve, reject) => {
if (this._handlers[AppBridgeHandler.UPDATE]) {
this._handlers[AppBridgeHandler.UPDATE](packet, (success) => {
if (success) {
resolve(true);
}
else {
reject(false);
}
});
}
else {
cleanPacket(packet);
Object.assign(packet, { id: this.id, windowName: this.windowName });
this.postRobot
.sendToParent(MESSAGE_TYPES.UPDATE, packet)
.then((event) => {
this._trace(`${MESSAGE_TYPES.UPDATE} (callback)`, event);
if (event.data) {
resolve(true);
}
else {
reject(false);
}
})
.catch((err) => {
reject(false);
});
}
});
}
/**
* Fires or responds to an close event
*/
close(packet) {
return new Promise((resolve, reject) => {
if (this._handlers[AppBridgeHandler.CLOSE]) {
this._handlers[AppBridgeHandler.CLOSE](packet, (success) => {
if (success) {
resolve(true);
}
else {
reject(false);
}
});
}
else {
if (packet) {
console.info('[AppBridge] - close(packet) is deprecated! Please just use close()!');
}
const realPacket = { id: this.id, windowName: this.windowName };
this.postRobot
.sendToParent(MESSAGE_TYPES.CLOSE, realPacket)
.then((event) => {
this._trace(`${MESSAGE_TYPES.CLOSE} (callback)`, event);
if (event.data) {
resolve(true);
}
else {
reject(false);
}
})
.catch((err) => {
reject(false);
});
}
});
}
/**
* Fires or responds to an close event
*/
refresh(packet) {
return new Promise((resolve, reject) => {
if (this._handlers[AppBridgeHandler.REFRESH]) {
this._handlers[AppBridgeHandler.REFRESH](packet, (success) => {
if (success) {
resolve(true);
}
else {
reject(false);
}
});
}
else {
if (packet) {
console.info('[AppBridge] - refresh(packet) is deprecated! Please just use refresh()!');
}
const realPacket = { id: this.id, windowName: this.windowName };
this.postRobot
.sendToParent(MESSAGE_TYPES.REFRESH, realPacket)
.then((event) => {
this._trace(`${MESSAGE_TYPES.REFRESH} (callback)`, event);
if (event.data) {
resolve(true);
}
else {
reject(false);
}
})
.catch((err) => {
reject(false);
});
}
});
}
ping() {
return new Promise((resolve, reject) => {
if (this._handlers[AppBridgeHandler.PING]) {
this._handlers[AppBridgeHandler.PING]({}, (data, error) => {
resolve({ data, error });
});
}
else {
this.postRobot
.sendToParent(MESSAGE_TYPES.PING, {})
.then((event) => {
resolve({ data: event.data.data, error: event.data.error });
})
.catch((err) => {
reject(null);
});
}
});
}
/**
* Fires or responds to a pin event
*/
pin(packet) {
return new Promise((resolve, reject) => {
if (this._handlers[AppBridgeHandler.PIN]) {
this._handlers[AppBridgeHandler.PIN](packet, (success) => {
if (success) {
resolve(true);
}
else {
reject(false);
}
});
}
else {
if (packet) {
console.info('[AppBridge] - pin(packet) is deprecated! Please just use pin()!');
}
const realPacket = { id: this.id, windowName: this.windowName };
this.postRobot
.sendToParent(MESSAGE_TYPES.PIN, realPacket)
.then((event) => {
this._trace(`${MESSAGE_TYPES.PIN} (callback)`, event);
if (event.data) {
resolve(true);
}
else {
reject(false);
}
})
.catch((err) => {
reject(false);
});
}
});
}
/**
* Fires or responds to a requestData event
* @param packet any - packet of data to send with the requestData event
*/
requestData(packet) {
return new Promise((resolve, reject) => {
if (this._handlers[AppBridgeHandler.REQUEST_DATA]) {
this._handlers[AppBridgeHandler.REQUEST_DATA](packet, (data) => {
if (data) {
resolve({ data });
}
else {
reject(false);
}
});
}
else {
cleanPacket(packet);
Object.assign(packet, { id: this.id, windowName: this.windowName });
this.postRobot
.sendToParent(MESSAGE_TYPES.REQUEST_DATA, packet)
.then((event) => {
this._trace(`${MESSAGE_TYPES.REQUEST_DATA} (callback)`, event);
if (event.data) {
resolve({ data: event.data.data });
}
else {
reject(false);
}
})
.catch((err) => {
reject(false);
});
}
});
}
/**
* Fires a generic callback command
* @param packet string - key: string, generic: boolean
*/
callback(packet) {
return new Promise((resolve, reject) => {
if (this._handlers[AppBridgeHandler.CALLBACK]) {
this._handlers[AppBridgeHandler.CALLBACK](packet, (success) => {
if (success) {
resolve(true);
}
else {
reject(false);
}
});
}
else {
cleanPacket(packet);
Object.assign(packet, { id: this.id, windowName: this.windowName });
this.postRobot
.sendToParent(MESSAGE_TYPES.CALLBACK, packet)
.then((event) => {
this._trace(`${MESSAGE_TYPES.CALLBACK} (callback)`, event);
if (event.data) {
resolve(true);
}
else {
reject(false);
}
})
.catch((err) => {
reject(false);
});
}
});
}
/**
* Fires or responds to an register event
* @param packet any - packet of data to send with the event
*/
register(packet = {}) {
return new Promise((resolve, reject) => {
if (this._handlers[AppBridgeHandler.REGISTER]) {
this._handlers[AppBridgeHandler.REGISTER](packet, (windowName) => {
if (windowName) {
resolve(windowName);
}
else {
resolve(null);
}
});
}
else {
cleanPacket(packet);
Object.assign(packet, { id: this.id });
this.postRobot
.sendToParent(MESSAGE_TYPES.REGISTER, packet)
.then((event) => {
this._trace(`${MESSAGE_TYPES.REGISTER} (callback)`, event);
if (event.data) {
this.windowName = event.data.windowName;
resolve(event.data.windowName);
}
else {
resolve(null);
}
})
.catch((err) => {
this._trace(`${MESSAGE_TYPES.REGISTER} - FAILED - (no parent)`, err);
reject(err);
});
}
});
}
/**
* Fires or responds to an HTTP_GET event
* @param relativeURL string - URL to fetch, relative to the mainframe URL
* @param timeout - how long to attempt the request before reporting an error
* @param originStack - the domain of the previous frame(s) the request originated from
*/
httpGET(relativeURL, timeout = 10000, originStack) {
return new Promise((resolve, reject) => {
if (this._handlers[AppBridgeHandler.HTTP]) {
this._handlers[AppBridgeHandler.HTTP]({ verb: HTTP_VERBS.GET, relativeURL, origin: originStack || [this.traceName] }, (data, error) => {
resolve({ data, error });
});
}
else {
this.postRobot
.sendToParent(MESSAGE_TYPES.HTTP_GET, { relativeURL, origin: originStack, originTraceName: this.traceName }, { timeout })
.then((event) => {
resolve({ data: event.data.data, error: event.data.error });
})
.catch((err) => {
reject(null);
});
}
});
}
/**
* Fires or responds to an HTTP_POST event
* @param relativeURL string - URL to fetch, relative to the mainframe URL
* @param postData any - packet of data to send with the event
* @param timeout - how long to attempt the request before reporting an error
* @param originStack - the domain of the previous frame(s) the request originated from
*/
httpPOST(relativeURL, postData, timeout = 10000, originStack) {
return new Promise((resolve, reject) => {
if (this._handlers[AppBridgeHandler.HTTP]) {
this._handlers[AppBridgeHandler.HTTP]({ verb: HTTP_VERBS.POST, relativeURL, data: postData, origin: originStack || [this.traceName] }, (data, error) => {
resolve({ data, error });
});
}
else {
this.postRobot
.sendToParent(MESSAGE_TYPES.HTTP_POST, { relativeURL, data: postData, origin: originStack, originTraceName: this.traceName }, { timeout })
.then((event) => {
resolve({ data: event.data.data, error: event.data.error });
})
.catch((err) => {
reject(null);
});
}
});
}
/**
* Fires or responds to an HTTP_PUT event
* @param relativeURL string - URL to fetch, relative to the mainframe URL
* @param packet any - packet of data to send with the event
* @param timeout - how long to attempt the request before reporting an error
* @param originStack - the domain of the previous frame(s) the request originated from
*/
httpPUT(relativeURL, putData, timeout = 10000, originStack) {
return new Promise((resolve, reject) => {
if (this._handlers[AppBridgeHandler.HTTP]) {
this._handlers[AppBridgeHandler.HTTP]({ verb: HTTP_VERBS.PUT, relativeURL, data: putData, origin: originStack || [this.traceName] }, (data, error) => {
resolve({ data, error });
});
}
else {
this.postRobot
.sendToParent(MESSAGE_TYPES.HTTP_PUT, { relativeURL, data: putData, origin: originStack, originTraceName: this.traceName }, { timeout })
.then((event) => {
resolve({ data: event.data.data, error: event.data.error });
})
.catch((err) => {
reject(null);
});
}
});
}
/**
* Fires or responds to an HTTP_DELETE event
* @param relativeURL string - URL to fetch, relative to the mainframe URL
* @param timeout - how long to attempt the request before reporting an error
* @param originStack - the domain of the previous frame(s) the request originated from
*/
httpDELETE(relativeURL, timeout = 10000, originStack) {
return new Promise((resolve, reject) => {
if (this._handlers[AppBridgeHandler.HTTP]) {
this._handlers[AppBridgeHandler.HTTP]({ verb: HTTP_VERBS.DELETE, relativeURL, origin: originStack || [this.traceName] }, (data, error) => {
resolve({ data, error });
});
}
else {
this.postRobot
.sendToParent(MESSAGE_TYPES.HTTP_DELETE, { relativeURL, origin: originStack, originTraceName: this.traceName }, { timeout })
.then((event) => {
resolve({ data: event.data.data, error: event.data.error });
})
.catch((err) => {
reject(null);
});
}
});
}
/**
* Fires a custom event to anywhere in the application
* @param event string - event name to fire
* @param data any - data to be sent along with the event
*/
fireEvent(event, data) {
return new Promise((resolve, reject) => {
this.postRobot
.sendToParent(MESSAGE_TYPES.CUSTOM_EVENT, { event, data })
.then((e) => {
resolve(e);
})
.catch((err) => {
reject(null);
});
});
}
/**
* Fires a custom event to all registered frames
* @param event string - event name to fire
* @param data any - data to be sent along with the event
*/
fireEventToChildren(event, data) {
if (this._registeredFrames.length > 0) {
this._registeredFrames.forEach((frame) => {
this.postRobot.send(frame.source, MESSAGE_TYPES.CUSTOM_EVENT, {
event,
eventType: event,
data,
});
});
}
}
/**
* Fires a custom event to specified frames
* @param source Window - specific iframe contentWindow
* @param event string - event name to fire
* @param data any - data to be sent along with the event
*/
fireEventToChild(source, event, data) {
if (source instanceof HTMLIFrameElement) {
source = source.contentWindow;
}
this.postRobot.send(source, MESSAGE_TYPES.CUSTOM_EVENT, { event, data });
}
/**
* Adds an event listener to a custom event
* @param event string - event name to listen to
* @param callback function - callback to be fired when an event is caught
*/
addEventListener(event, callback) {
if (!this._eventListeners[event]) {
this._eventListeners[event] = [];
}
this._eventListeners[event].push(callback);
}
}
class DevAppBridge extends AppBridge {
constructor(traceName = 'DevAppBridge', http, postRobotRef) {
super(traceName, postRobotRef);
this.http = http;
const cookie = this.getCookie('UlEncodedIdentity');
if (cookie && cookie.length) {
const identity = JSON.parse(decodeURIComponent(cookie));
const endpoints = identity.sessions.reduce((obj, session) => {
obj[session.name] = session.value.endpoint;
return obj;
}, {});
this.baseURL = endpoints.rest;
}
}
_setupHandlers() { }
/**
* Fires or responds to an HTTP_GET event
*/
httpGET(relativeURL) {
return this.http.get(`${this.baseURL}/${relativeURL}`, { withCredentials: true }).toPromise();
}
/**
* Fires or responds to an HTTP_POST event
*/
httpPOST(relativeURL, postData) {
return this.http.post(`${this.baseURL}/${relativeURL}`, postData, { withCredentials: true }).toPromise();
}
/**
* Fires or responds to an HTTP_PUT event
*/
httpPUT(relativeURL, putData) {
return this.http.put(`${this.baseURL}/${relativeURL}`, putData, { withCredentials: true }).toPromise();
}
/**
* Fires or responds to an HTTP_DELETE event
*/
httpDELETE(relativeURL) {
return this.http.delete(`${this.baseURL}/${relativeURL}`, { withCredentials: true }).toPromise();
}
getCookie(cname) {
if (document) {
const name = `${cname}=`;
const ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1);
}
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
}
return false;
}
}
class BaseRenderer {
constructor() {
this._data = {};
this._value = '';
this.meta = {};
}
get data() {
return this._data;
}
set data(d) {
this._data = d;
}
get value() {
return this._value;
}
set value(v) {
this._value = v;
}
}
/**
* Copyright © 2022 Sasha Koss
* https://www.npmjs.com/package/@date-fns/upgrade
**/
const tokensMap = {
// 'D MMMM': '',
// 'Do MMMM': '',
// 'DD MMMM': '',
M: 'L',
Mo: 'Mo',
MM: 'LL',
MMM: 'LLL',
MMMM: 'LLLL',
Q: 'q',
Qo: 'qo',
D: 'd',
Do: 'do',
DD: 'dd',
DDD: 'D',
DDDo: 'Do',
DDDD: 'DDD',
d: 'i',
do: 'io',
dd: 'iiiiii',
ddd: 'iii',
dddd: 'iiii',
A: 'a',
a: 'a',
aa: 'aaaa',
E: 'i',
W: 'I',
Wo: 'Io',
WW: 'II',
YY: 'yy',
YYYY: 'yyyy',
GG: 'RR',
GGGG: 'RRRR',
H: 'H',
HH: 'HH',
h: 'h',
hh: 'hh',
m: 'm',
mm: 'mm',
s: 's',
ss: 'ss',
S: 'S',
SS: 'SS',
SSS: 'SSS',
Z: 'xxx',
ZZ: 'xx',
X: 't',
x: 'T',
};
const v1tokens = Object.keys(tokensMap)
.sort()
.reverse();
const tokensRegExp = new RegExp('(\\[[^\\[]*\\])|(\\\\)?' + '(' + v1tokens.join('|') + '|.)', 'g');
function convertTokens(format) {
const tokensCaptures = format.match(tokensRegExp);
if (tokensCaptures) {
return tokensCaptures
.reduce((acc, tokenString, index) => {
const v2token = tokensMap[tokenString];
if (!v2token) {
const escapedCaptures = tokenString.match(/^\[(.+)\]$/);
if (escapedCaptures) {
acc.textBuffer.push(escapedCaptures[1]);
}
else {
acc.textBuffer.push(tokenString);
}
}
const endOfString = index === tokensCaptures.length - 1;
if (acc.textBuffer.length && (v2token || endOfString)) {
acc.formatBuffer.push(`'${acc.textBuffer.join('')}'`);
acc.textBuffer = [];
}
if (v2token)
acc.formatBuffer.push(v2token); // eslint-disable-line
return acc;
}, { formatBuffer: [], textBuffer: [] })
.formatBuffer.join('');
}
else {
return format;
}
}
/**
* Copyright © 2022 Sasha Koss
* https://www.npmjs.com/package/@date-fns/upgrade
**/
const MILLISECONDS_IN_HOUR = 3600000;
const MILLISECONDS_IN_MINUTE = 60000;
const DEFAULT_ADDITIONAL_DIGITS = 2;
const parseTokenDateTimeDelimeter = /[T ]/;
const parseTokenPlainTime = /:/;
// year tokens
const parseTokenYY = /^(\d{2})$/;
const parseTokensYYY = [
/^([+-]\d{2})$/, // 0 additional digits
/^([+-]\d{3})$/, // 1 additional digit
/^([+-]\d{4})$/, // 2 additional digits
];
const parseTokenYYYY = /^(\d{4})/;
const parseTokensYYYYY = [
/^([+-]\d{4})/, // 0 additional digits
/^([+-]\d{5})/, // 1 additional digit
/^([+-]\d{6})/, // 2 additional digits
];
// date tokens
const parseTokenMM = /^-(\d{2})$/;
const parseTokenDDD = /^-?(\d{3})$/;
const parseTokenMMDD = /^-?(\d{2})-?(\d{2})$/;
const parseTokenWww = /^-?W(\d{2})$/;
const parseTokenWwwD = /^-?W(\d{2})-?(\d{1})$/;
// time tokens
const parseTokenHH = /^(\d{2}([.,]\d*)?)$/;
const parseTokenHHMM = /^(\d{2}):?(\d{2}([.,]\d*)?)$/;
const parseTokenHHMMSS = /^(\d{2}):?(\d{2}):?(\d{2}([.,]\d*)?)$/;
// timezone tokens
const parseTokenTimezone = /([Z+-].*)$/;
const parseTokenTimezoneZ = /^(Z)$/;
const parseTokenTimezoneHH = /^([+-])(\d{2})$/;
const parseTokenTimezoneHHMM = /^([+-])(\d{2}):?(\d{2})$/;
function legacyParse(argument, options = {}) {
if (isDate(argument)) {
// Prevent the date to lose the milliseconds when passed to new Date() in IE10
return new Date(argument.getTime());
}
else if (typeof argument !== 'string') {
return new Date(argument);
}
const additionalDigits = options.additionalDigits == null
? DEFAULT_ADDITIONAL_DIGITS
: Number(options.additionalDigits);
const dateStrings = splitDateString(argument);
const parseYearResult = parseYear(dateStrings.date || '', additionalDigits);
const year = parseYearResult.year;
const restDateString = parseYearResult.restDateString;
const date = parseDate(restDateString || '', year);
if (date) {
const timestamp = date.getTime();
let time = 0;
let offset;
if (dateStrings.time) {
time = parseTime(dateStrings.time) || 0;
}
if (dateStrings.timezone) {
offset = parseTimezone(dateStrings.timezone) * MILLISECONDS_IN_MINUTE;
}
else {
const fullTime = timestamp + time;
const fullTimeDate = new Date(fullTime);
offset = getTimezoneOffsetInMilliseconds(fullTimeDate);
// Adjust time when it's coming from DST
const fullTimeDateNextDay = new Date(fullTime);
fullTimeDateNextDay.setDate(fullTimeDate.getDate() + 1);
const offsetDiff = getTimezoneOffsetInMilliseconds(fullTimeDateNextDay) -
getTimezoneOffsetInMilliseconds(fullTimeDate);
if (offsetDiff > 0) {
offset += offsetDiff;
}
}
return new Date(timestamp + time + offset);
}
else {
return new Date(argument);
}
}
function splitDateString(dateString) {
const array = dateString.split(parseTokenDateTimeDelimeter);
let timeString;
let date;
let time;
let timezone;
if (parseTokenPlainTime.test(array[0])) {
date = undefined;
timeString = array[0];
}
else {
date = array[0];
timeString = array[1];
}
if (timeString) {
const token = parseTokenTimezone.exec(timeString);
if (token) {
time = timeString.replace(token[1], '');
timezone = token[1];
}
else {
time = timeString;
}
}
return {
date,
time,
timezone,
};
}
function parseYear(dateString, additionalDigits) {
const parseTokenYYY = parseTokensYYY[additionalDigits];
const parseTokenYYYYY = parseTokensYYYYY[additionalDigits];
let token;
// YYYY or ±YYYYY
token = parseTokenYYYY.exec(dateString) || parseTokenYYYYY.exec(dateString);
if (token) {
const yearString = token[1];
return {
year: parseInt(yearString, 10),
restDateString: dateString.slice(yearString.length),
};
}
// YY or ±YYY
token = parseTokenYY.exec(dateString) || parseTokenYYY.exec(dateString);
if (token) {
const centuryString = token[1];
return {
year: parseInt(centuryString, 10) * 100,
restDateString: dateString.slice(centuryString.length),
};
}
// Invalid ISO-formatted year
return {
year: null,
};
}
function parseDate(dateString, year) {
// Invalid ISO-formatted year
if (year === null) {
return null;
}
let token;
let date;
let month;
let week;
// YYYY
if (dateString.length === 0) {
date = new Date(0);
date.setUTCFullYear(year);
return date;
}
// YYYY-MM
token = parseTokenMM.exec(dateString);
if (token) {
date = new Date(0);
month = parseInt(token[1], 10) - 1;
date.setUTCFullYear(year, month);
return date;
}
// YYYY-DDD or YYYYDDD
token = parseTokenDDD.exec(dateString);
if (token) {
date = new Date(0);
const dayOfYear = parseInt(token[1], 10);
date.setUTCFullYear(year, 0, dayOfYear);
return date;
}
// YYYY-MM-DD or YYYYMMDD
token = parseTokenMMDD.exec(dateString);
if (token) {
date = new Date(0);
month = parseInt(token[1], 10) - 1;
const day = parseInt(token[2], 10);
date.setUTCFullYear(year, month, day);
return date;
}
// YYYY-Www or YYYYWww
token = parseTokenWww.exec(dateString);
if (token) {
week = parseInt(token[1], 10) - 1;
return dayOfISOYear(year, week);
}
// YYYY-Www-D or YYYYWwwD
token = parseTokenWwwD.exec(dateString);
if (token) {
week = parseInt(token[1], 10) - 1;
const dayOfWeek = parseInt(token[2], 10) - 1;
return dayOfISOYear(year, week, dayOfWeek);
}
// Invalid ISO-formatted date
return null;
}
function parseTime(timeString) {
let token;
let hours;
let minutes;
// hh
token = parseTokenHH.exec(timeString);
if (token) {
hours = parseFloat(token[1].replace(',', '.'));
return (hours % 24) * MILLISECONDS_IN_HOUR;
}
// hh:mm or hhmm
token = parseTokenHHMM.exec(timeString);
if (token) {
hours = parseInt(token[1], 10);
minutes = parseFloat(token[2].replace(',', '.'));
return ((hours % 24) * MILLISECONDS_IN_HOUR + minutes * MILLISECONDS_IN_MINUTE);
}
// hh:mm:ss or hhmmss
token = parseTokenHHMMSS.exec(timeString);
if (token) {
hours = parseInt(token[1], 10);
minutes = parseInt(token[2], 10);
const seconds = parseFloat(token[3].replace(',', '.'));
return ((hours % 24) * MILLISECONDS_IN_HOUR +
minutes * MILLISECONDS_IN_MINUTE +
seconds * 1000);
}
// Invalid ISO-formatted time
return null;
}
function parseTimezone(timezoneString) {
let token;
let absoluteOffset;
// Z
token = parseTokenTimezoneZ.exec(timezoneString);
if (token) {
return 0;
}
// ±hh
token = parseTokenTimezoneHH.exec(timezoneString);
if (token) {
absoluteOffset = parseInt(token[2], 10) * 60;
return token[1] === '+' ? -absoluteOffset : absoluteOffset;
}
// ±hh:mm or ±hhmm
token = parseTokenTimezoneHHMM.exec(timezoneString);
if (token) {
absoluteOffset = parseInt(token[2], 10) * 60 + parseInt(token[3], 10);
return token[1] === '+' ? -absoluteOffset : absoluteOffset;
}
return 0;
}
function dayOfISOYear(isoYear, week = 0, day = 0) {
const date = new Date(0);
date.setUTCFullYear(isoYear, 0, 4);
const fourthOfJanuaryDay = date.getUTCDay() || 7;
const diff = week * 7 + day + 1 - fourthOfJanuaryDay;
date.setUTCDate(date.getUTCDate() + diff);
return date;
}
function getTimezoneOffsetInMilliseconds(dirtyDate) {
const date = new Date(dirtyDate.getTime());
const baseTimezoneOffset = date.getTimezoneOffset();
date.setSeconds(0, 0);
const millisecondsPartOfTimezoneOffset = date.getTime() % MILLISECONDS_IN_MINUTE;
return (baseTimezoneOffset * MILLISECONDS_IN_MINUTE +
millisecondsPartOfTimezoneOffset);
}
/**
* This DateUtil is a wrapper for calling new date-fns v2 functions with existing legacy
* v1 function calls without having to refactor too much code and potentially introduce
* breaking changes.
*
* The old calls generally called date-fns functions with loosely-typed date values, often
* of type DateLike (Date | string | number). This was a problem when upgrading to date-fns
* v2 since functions are now typed more strongly and no longer accept strings.
*
* If you are adding a new component/feature and looking here to add a new date-fns wrapper
* function, strongly consider not doing that and instead refactoring your code to not use
* DateLike, and calling the date-fns function(s) directly.
**/
class DateUtil {
static getDateFromAnyType(date) {
return legacyParse(date);
}
static getWeekDayFromNumber(weekDay) {
if (0 <= weekDay && weekDay <= 6) {
return weekDay;
}
else {
console.warn('Invalid weekDay value:', weekDay);
return 0;
}
}
static parse(date, options) {
if (options?.userDateFormat && typeof date === 'string' && date.trim()) {
date = this.rewireDatePositionsToMDY(date, options.userDateFormat);
delete options.userDateFormat;
}
return legacyParse(date, options);
}
static format(date, formatString) {
if (!date) {
return '';
}
date = this.getDateFromAnyType(date);
formatString = convertTokens(formatString);
return format(date, formatString);
}
static addDays(date, days) {
date = this.getDateFromAnyType(date);
return addDays(date, days);
}
static addWeeks(date, weeks) {
date = this.getDateFromAnyType(date);
return addWeeks(date, weeks);
}
static addMonths(date, months) {
date = this.getDateFromAnyType(date);
return addMonths(date, months);
}
static startOfMinute(date) {
date = this.getDateFromAnyType(date);
return startOfMinute(date);
}
static startOfDay(date) {
date = this.getDateFromAnyType(date);
return startOfDay(date);
}
static startOfWeek(date, options) {
date = this.getDateFromAnyType(date);
if (options?.weekStartsOn) {
options.weekStartsOn = this.getWeekDayFromNumber(options.weekStartsOn);
}
return startOfWeek(date, options);
}
static startOfMonth(date) {
date = this.getDateFromAnyType(date);
return startOfMonth(date);
}
static endOfDay(date) {
date = this.getDateFromAnyType(date);
return endOfDay(date);
}
static endOfWeek(date, options) {
date = this.getDateFromAnyType(date);
if (options?.weekStartsOn) {
options.weekStartsOn = this.getWeekDayFromNumber(options.weekStartsOn);
}
return endOfWeek(date, options);
}
static endOfMonth(date) {
date = this.getDateFromAnyType(date);
return endOfMonth(date);
}
static isSameDay(dateLeft, dateRight) {
dateLeft = this.getDateFromAnyType(dateLeft);
dateRight = this.getDateFromAnyType(dateRight);
return isSameDay(dateLeft, dateRight);
}
static isSameMonth(dateLeft, dateRight) {
dateLeft = this.getDateFromAnyType(dateLeft);
dateRight = this.getDateFromAnyType(dateRight);
return isSameMonth(dateLeft, dateRight);
}
static isSameSecond(dateLeft, dateRight) {
dateLeft = this.getDateFromAnyType(dateLeft);
dateRight = this.getDateFromAnyType(dateRight);
return isSameSecond(dateLeft, dateRight);
}
static differenceInSeconds(date, start) {
date = this.getDateFromAnyType(date);
start = this.getDateFromAnyType(start);
return differenceInSeconds(date, start);
}
static differenceInCalendarDays(date, start) {
date = this.getDateFromAnyType(date);
start = this.getDateFromAnyType(start);
return differenceInCalendarDays(date, start);
}
static differenceInDays(date, start) {
date = this.getDateFromAnyType(date);
start = this.getDateFromAnyType(start);
return differenceInDays(date, start);
}
static isWithinRange(date, start, end) {
date = this.getDateFromAnyType(date);
const interval = {
start: this.getDateFromAnyType(start),
end: this.getDateFromAnyType(end),
};
/**
* Need extra error handling here to retain backwards compatibility because the new
* isWithinInterval replacement function throws an error for Invalid Dates and Invalid
* Intervals instead of returning true or false.
**/
try {
return isWithinInterval(date, interval);
}
catch (e) {
console.warn(e.toString());
return false;
}
}
static getMonth(date) {
date = this.getDateFromAnyType(date);
return getMonth(date);
}
static getYear(date) {
date = this.getDateFromAnyType(date);
return getYear(date);
}
static setMinutes(date, minutes) {
date = this.getDateFromAnyType(date);
return setMinutes(date, minutes);
}
static setHours(date, hours) {
date = this.getDateFromAnyType(date);
return setHours(date, hours);
}
static isBefore(date, minDate) {
date = this.getDateFromAnyType(date);
return isBefore(date, minDate);
}
static isAfter(date, maxDate) {
date = this.getDateFromAnyType(date);
return isAfter(date, maxDate);
}
static rewireDatePositionsToMDY(dateStr, userDateFormat) {
userDateFormat = userDateFormat.toUpperCase();
if (userDateFormat === 'MM/DD/YYYY') {
return dateStr;
}
const separatorPattern = /[.\\/-]/;
// Creates an order, eg ['D', 'M', 'Y']
const separatorChar = separatorPattern.exec(userDateFormat)[0];
const tokenOrder = userDateFormat.split(separatorPattern).map(chars => chars[0]);
if (tokenOrder.length < 3) {
// Could not determine date token order from localized date format
return dateStr;
}
const tokenSourceOrder = ['M', 'D', 'Y'].map(token => tokenOrder.indexOf(token));
const dateTimeSplit = dateStr.split(', ');
const datePortions = dateTimeSplit[0].split(separatorPattern);
if (datePortions.length < 3) {
// Could not retrieve M/D/Y from localized date format
return dateStr;
}
let convertedDateStr = tokenSourceOrder.map(index => datePortions[index]).join(separatorChar);
if (dateTimeSplit.length > 1) {
convertedDateStr += ', ' + dateTimeSplit.slice(1).join(', ');
}
return convertedDateStr;
}
}
class DateRange {
constructor(
/** The start date of the range. */
start,
/** The end date of the range. */
end) {
this.start = start;
this.end = end;
}
}
/* eslint-disable no-invalid-this */
/**
* Copyright © 2018-2022 Ferdinand Prantl
* https://www.npmjs.com/package/timezone-support
**/
const formattingToken = /(\[[^[]*\])|([-:/.()\s]+)|(A|a|YYYY|YY?|MM?|DD?|d|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g;
const formatTokenFunctions = {};
const formatters = {};
function formatZonedTime(time, format) {
let formatter = formatters[format];
if (!formatter) {
formatter = formatters[format] = makeFormatter(format);
}
return formatter(time);
}
function makeFormatter(format) {
const array = format.match(formattingToken);
const { length } = array;
for (let i = 0; i < length; ++i) {
const token = array[i];
const formatter = formatTokenFunctions[token];
if (formatter) {
array[i] = formatter;
}
else {
array[i] = token.replace(/^\[|\]$/g, '');
}
}
return function (time) {
let output = '';
for (const token of array) {
output += typeof token === 'function' ? token.call(time) : token;
}
return output;
};
}
const addFormatToken = function (token, padded, property) {
const callback = typeof pr