@tangential/core
Version:
Core types and support code for Tangential
1,157 lines (1,126 loc) • 42.9 kB
JavaScript
import * as i0 from '@angular/core';
import { EventEmitter, Injectable, Optional } from '@angular/core';
import { share, filter, map } from 'rxjs/operators';
import { filter as filter$1 } from 'rxjs';
class SelectionEntry {
constructor(value, selected = false, disabled = false) {
this.value = value;
this.selected = selected;
this.disabled = disabled;
}
}
class SelectionList {
constructor(initialValues = [], selectAll = false, keyField = '$key') {
this.keyField = keyField;
this.entries = initialValues.map((v) => {
return new SelectionEntry(v, selectAll);
});
}
asIndexMap() {
const indices = {};
this.entries.forEach((entry, index) => {
indices[entry.value[this.keyField]] = index;
});
return indices;
}
select(values) {
const map = this.asIndexMap();
values.forEach((value) => {
const index = map[value[this.keyField]];
if (index || index === 0) {
this.entries[index].selected = true;
}
});
}
disable(values) {
const map = this.asIndexMap();
values.forEach((value) => {
const index = map[value[this.keyField]];
if (index || index === 0) {
this.entries[index].disabled = true;
}
});
}
}
class ArrayUtils {
static peek(ary) {
let v = undefined;
if (ary && ary.length) {
v = ary[ary.length - 1];
}
return v;
}
}
class Guard {
static isString(value) {
return typeof value === 'string';
}
}
class CodedError extends Error {
constructor(message, code) {
super(message);
this.code = code;
}
}
class ObjMapUtil {
static fromKeyedEntityArray(values, keyField = '$key') {
values = values || [];
const m = {};
for (let i = 0; i < values.length; i++) {
m[values[i][keyField]] = values[i];
}
return m;
}
static toArray(map) {
return Object.keys(map).map((key) => {
return map[key];
});
}
static toKeyedEntityArray(map, keyField = '$key') {
return Object.keys(map).map((key) => {
const keyObj = {}; // semicolon actually required here.
keyObj[keyField] = key;
return Object.assign({}, map[key], keyObj);
});
}
static toTruthMap(map) {
const result = {};
Object.keys(map).forEach((key) => {
result[key] = true;
});
return result;
}
static addAll(map, mapB, noOverwrite = false) {
map = map || {};
mapB = mapB || {};
Object.keys(mapB).forEach((key) => {
if (noOverwrite && map[key] !== undefined) {
throw new Error(`Key already exists on map, cannot replace: ${key}.`);
}
map[key] = mapB[key];
});
return map;
}
static removeAll(map, mapB) {
Object.keys(mapB).forEach((key) => {
if (map[key] !== undefined) {
delete map[key];
}
});
}
/**
* Remove the child fields from the provided map.
* @param map
* @param fields {string[]}
* @returns {ObjMap<V>}
*/
static deleteValueFields(map, fields = ['$key']) {
map = map || {};
fields.forEach((fieldKey) => {
Object.keys(map).forEach((key) => {
delete map[key][fieldKey];
});
});
return map;
}
}
const ResolveVoid = undefined;
class ObjectUtil {
/**
* Null safe version of Object.keys.
* @param map
* @returns {string[]} The keys for the map, or an empty array if the argument provided is falsy.
*/
static keys(map) {
return Object.keys(map || {});
}
/**
* Provide a map of keys such that 'map[key]' provides a literal true value if the key is present, even if the value
* on the source map is falsy.
*/
static toTruthMap(ary) {
const map = {};
ary.forEach(value => map[value] = true);
return map;
}
/**
* Expand the map into an array of key-value pairs.
* @param {ObjMap<T extends object>} map
* @returns MapEntry<T>
*/
static entries(map) {
const ret = Object.keys(map || {}).map((key) => {
return { key: key, value: map[key] };
});
return ret;
}
/**
* Provide the values of the map.
* @param {ObjMap<T>} map
* @returns MapEntry<T>
*/
static values(map) {
return Object.keys(map || {}).map((key) => {
return map[key];
});
}
static isObject(value) {
return (typeof value === 'object' || value.constructor === Object);
}
static isFunction(value) {
return (typeof value === 'function' || value instanceof Function);
}
static isNullOrDefined(value) {
return value === null || value === undefined;
}
static exists(value) {
return value !== null && value !== undefined;
}
static assignDeep(target, ...sources) {
target = target || {};
const L = sources.length;
for (let i = 0; i < L; i++) {
const source = sources[i] || {};
Object.keys(source).forEach(key => {
const value = source[key];
if (value && ObjectUtil.isObject(value)) {
target[key] = ObjectUtil.assignDeep({}, target[key] || {}, value);
}
else {
target[key] = value;
}
});
}
return target;
}
static removeNullish(obj) {
const cleanObj = {};
Object.keys(obj).forEach((key) => {
const v = obj[key];
if (v !== null && v !== undefined) {
cleanObj[key] = v;
}
});
return cleanObj;
}
}
const cleanFirebaseMap = function (firebaseList, deep) {
const result = {};
Object.keys(firebaseList).forEach((key) => {
if (key[0] !== '$') {
if (deep && firebaseList[key] instanceof Object) {
result[key] = cleanFirebaseMap(firebaseList[key], true);
}
else {
result[key] = firebaseList[key];
}
}
});
return result;
};
const pathExists = (object, path) => {
const parts = path.split('\.');
let exists = true;
let obj = object;
for (let i = 0; i < parts.length; i++) {
obj = obj[parts[i]];
if (obj === undefined) {
exists = false;
break;
}
}
return exists;
};
const ensureExists = (object, path, value = true) => {
const parts = path.split('\.');
let obj = object;
for (let i = 0; i < parts.length - 1; i++) {
const key = parts[i];
if (obj[key] === undefined) {
obj[key] = {};
}
obj = obj[key];
}
const lastKey = parts[parts.length - 1];
if (obj[lastKey] === undefined) {
obj[lastKey] = value;
}
return obj[lastKey];
};
const removeIfExists = (object, path) => {
const parts = path.split('\.');
let obj = object;
let existed = true;
for (let i = 0; i < parts.length - 1; i++) {
obj = obj[parts[i]];
if (obj === undefined) {
existed = false;
break;
}
}
if (existed) {
const lastKey = parts[parts.length - 1];
existed = obj[lastKey] !== undefined;
if (existed) {
delete obj[lastKey];
}
}
return existed;
};
const safe = (fn) => {
try {
return fn();
}
catch (e) {
return null;
}
};
const eachKey = (objMap, fn) => {
Object.keys(objMap).forEach((key) => {
fn(objMap[key], key);
});
};
class JsonUtil {
static diff(left, right) {
const diff = {};
let keys = ObjectUtil.keys(left).concat(ObjectUtil.keys(right));
keys = ObjectUtil.keys(ObjectUtil.toTruthMap(keys));
keys.forEach(key => {
const leftVal = left[key];
const rightVal = right[key];
if (!JsonUtil.areEqual(leftVal, rightVal)) {
diff[key] = true;
}
});
return diff;
}
static areEqual(left, right) {
let areEqual;
if (left === right) {
areEqual = true;
}
else if (!left || !right) {
areEqual = false;
}
else if (ObjectUtil.isObject(left)) {
if (!ObjectUtil.isObject(right)) {
areEqual = false;
}
else {
areEqual = ObjectUtil.keys(JsonUtil.diff(left, right)).length === 0;
}
}
return areEqual || false;
}
static applyJsonToInstance(instance, json) {
const model = instance.getModel();
json = json || {};
ObjectUtil.keys(model).forEach((key) => {
instance[key] = this.determineValue(json[key], model[key]);
});
}
static determineValue(jsonValue, defaultValue) {
let value = null;
if (ObjectUtil.isNullOrDefined(jsonValue)) {
value = defaultValue;
}
else if (ObjectUtil.isObject(jsonValue)) {
value = ObjectUtil.assignDeep({}, defaultValue, jsonValue);
}
else {
value = jsonValue;
}
return value;
}
static instanceToJson(instance, withHiddenFields) {
const model = instance.getModel();
const json = {};
ObjectUtil.keys(model).forEach((key) => {
if (withHiddenFields || JsonUtil.isLegalFirebaseKey(key)) {
const value = instance[key];
json[key] = value;
if (value) {
if (ObjectUtil.isFunction(value['toJson'])) {
json[key] = value.toJson(withHiddenFields);
}
else if (ObjectUtil.isObject(value)) {
json[key] = JsonUtil.mapToJson(value, withHiddenFields || false);
}
}
}
});
return json;
}
static mapToJson(map, withHiddenFields) {
const json = {};
// @ts-ignore Typescript is confused by the return type of ObjectUtil.entries.
ObjectUtil.entries(map).forEach((entry) => {
let v = entry.value;
if (v && v['toJson'] && ObjectUtil.isFunction(v['toJson'])) {
v = v.toJson(withHiddenFields);
}
json[entry.key] = v;
});
return json;
}
static keyedArrayToJsonMap(array, withHiddenFields, keyField = '$key') {
const json = {};
array.forEach(entry => {
json[entry[keyField]] = entry.toJson(withHiddenFields);
});
return json;
}
/**
* @param obj
* @returns {T}
* @deprecated See FireBlanket.util.removeIllegalKey
*/
static removeIllegalFirebaseKeys(obj) {
const cleanObj = {};
Object.keys(obj).forEach((key) => {
const v = obj[key];
if (JsonUtil.isLegalFirebaseKey(v)) {
cleanObj[key] = v;
}
});
return cleanObj;
}
/**
* @param key
* @returns {boolean}
* @deprecated See FireBlanket.util.isLegalFirebaseKey
*/
static isLegalFirebaseKey(key) {
return key !== null && key !== undefined && !key.startsWith('$');
}
}
class ReactiveUtil {
static unSub(subscription) {
if (subscription) {
subscription.unsubscribe();
}
}
}
class StringUtil {
static firstUniqueByCounterSuffix(value, values, separatorChar = ' ') {
let result = value;
const map = {};
values.forEach(v => map[v] = true);
let idx = 1;
while (map[result]) {
result = value + separatorChar + idx++;
}
return result;
}
/**
* Split a string that ends with a number into its corresponding parts. Useful for name collisions, e.g.
* FooValue, FooValue-1, FooValue-2
* @param value
*/
static withoutNumericSuffix(value) {
let idx = value.length;
const suffixChars = [];
for (idx; idx--; idx > 0) {
if (StringUtil._baseTen[value.charAt(idx)] !== true) {
break;
}
suffixChars.unshift(value.charAt(idx));
}
const suffixValue = suffixChars.length ? Number.parseInt(suffixChars.join('')) : undefined;
const text = value.substring(0, idx);
return { text: text.trim(), suffix: suffixValue };
}
static incrementCounterSuffix(value) {
let result = value;
let suffixValue = 1;
const suffixChars = [];
let idx = value.length;
for (idx; idx--; idx > 0) {
if (StringUtil._baseTen[value.charAt(idx)] !== true) {
break;
}
suffixChars.unshift(value.charAt(idx));
}
if (suffixChars.length) {
try {
suffixValue = Number.parseInt(suffixChars.join(''));
result = value.substring(0, idx + 1);
}
catch (e) {
suffixValue = 1;
}
}
return result + (suffixValue + 1);
}
}
StringUtil._baseTen = [true, true, true, true, true, true, true, true, true, true];
class AppEnvironment {
constructor() {
this.firebase = {}; // Class is another "we'd use an interface if we could, but compiler deletes interfaces"
this.name = 'dev';
this.production = false;
this.suppressAds = false;
}
}
/**
* From https://gist.github.com/mikelehen/3596a30bd69384624c11, via Firebase blog at
* https://firebase.googleblog.com/2015/02/the-2120-ways-to-ensure-unique_68.html
* With minor tweaks for use with TypeScript
**/
/**
* Fancy ID generator that creates 20-character string identifiers with the following properties:
*
* 1. They're based on timestamp so that they sort *after* any existing ids.
* 2. They contain 72-bits of random data after the timestamp so that IDs won't collide with other clients' IDs.
* 3. They sort *lexicographically* (so the timestamp is converted to characters that will sort properly).
* 4. They're monotonically increasing. Even if you generate more than one in the same timestamp, the
* latter ones will sort after the former ones. We do this by using the previous random bits
* but "incrementing" them by 1 (only in the case of a timestamp collision).
*/
// Modeled after base64 web-safe chars, but ordered by ASCII.
const PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
// Timestamp of last push, used to prevent local collisions if you push twice in one ms.
let lastPushTime = 0;
// We generate 72-bits of randomness which get turned into 12 characters and appended to the
// timestamp to prevent collisions with other clients. We store the last characters we
// generated because in the event of a collision, we'll use those same characters except
// "incremented" by one.
const lastRandChars = [];
const generatePushID = function () {
let i;
let now = Date.now();
const duplicateTime = (now === lastPushTime);
lastPushTime = now;
const timeStampChars = new Array(8);
for (i = 7; i >= 0; i--) {
timeStampChars[i] = PUSH_CHARS.charAt(now % 64);
// NOTE: Can't use << here because javascript will convert to int and lose the upper bits.
now = Math.floor(now / 64);
}
if (now !== 0) {
throw new Error('We should have converted the entire timestamp.');
}
let id = timeStampChars.join('');
if (!duplicateTime) {
for (i = 0; i < 12; i++) {
lastRandChars[i] = Math.floor(Math.random() * 64);
}
}
else {
// If the timestamp hasn't changed since last push, use the same random number, except incremented by 1.
for (i = 11; i >= 0 && lastRandChars[i] === 63; i--) {
lastRandChars[i] = 0;
}
lastRandChars[i]++;
}
for (i = 0; i < 12; i++) {
id += PUSH_CHARS.charAt(lastRandChars[i]);
}
if (id.length !== 20) {
throw new Error('Length should be 20.');
}
return id;
};
const Intention = {
/**
* An action has been performed. For example, a user has been created, granted a permission, removed, etc.
*/
action: 'action',
/**
* A general event, typically used to communicate UI state across domains.
*/
event: 'event',
/**
* A BusMessage whose intent is to record a log message.
*/
log: 'log',
/**
* A BusMessage whose intent is to provide a message to the Visitor. It is up to the currently active UI to determine the best method
* of sharing the message payload.
*/
notification: 'notification',
/**
* A BusMessage that communicates that the current Visitor has requested than an action be performed. For example, clicked a button
* that is intended to result in a user being created, a permission being granted, etc.
*/
request: 'request',
};
class BusMessage {
/** @todo: 'intent' should probably be handled by static creation methods. */
constructor(source, intent, key) {
this.id = generatePushID();
this.source = source;
this.intent = intent || 'event'; // this should not be optional.
this.key = key || '_';
}
}
class MessageBus {
constructor() {
this.bus = new EventEmitter(false);
this.all = this.bus.pipe(share());
}
post(message) {
this.bus.next(message);
}
}
MessageBus.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: MessageBus, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
MessageBus.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: MessageBus });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: MessageBus, decorators: [{
type: Injectable
}], ctorParameters: function () { return []; } });
class LogMessage extends BusMessage {
constructor(level, context, ...message) {
super(LogMessage.SourceKey, 'log');
this.message = message;
this.context = context;
this.level = level;
}
}
LogMessage.SourceKey = "LogMessage";
const spaces$1 = ' ';
/**
*
*
*/
const LogLevels = {
NONE: 'NONE',
fatal: 'fatal',
error: 'error',
warn: 'warn',
info: 'info',
debug: 'debug',
trace: 'trace'
};
class LoggerConfiguration {
constructor() {
this.contextAsStringWidth = 30;
this.includeFullContext = false;
/**
* For temporarily shutting of logging, use NONE, but if you are shutting off logging for production, or because you're using
* another logging system, you should Provide a simpler logging class in your module configuration.
* @type {LogLevel}
*/
this.logLevel = 'trace';
}
}
const emptyFn = function (...x) { };
class Logger {
constructor(configuration) {
this.config = new LoggerConfiguration();
this.config = configuration || this.config;
this.applyLevel();
}
trace(context, ...message) {
this.log(new LogMessage('trace', context, ...message));
}
debug(context, ...message) {
this.log(new LogMessage('debug', context, ...message));
}
info(context, ...message) {
this.log(new LogMessage('info', context, ...message));
}
warn(context, ...message) {
this.log(new LogMessage('warn', context, ...message));
}
error(context, ...message) {
this.log(new LogMessage('error', context, ...message));
}
fatal(context, ...message) {
this.log(new LogMessage('fatal', context, ...message));
}
applyLevel() {
console.log('Logger', 'applyLevel', this.config);
/**
* This keeps noise off the system bus when running in production mode or with logging off.
* Yes, it's supposed to fall through, despite the evil nature.
*/
// @ts-ignore
// noinspection FallThroughInSwitchStatementJS
switch (this.config.logLevel) {
// @ts-ignore
case LogLevels.NONE:
this.fatal = emptyFn;
// @ts-ignore
case LogLevels.fatal:
this.error = emptyFn;
// @ts-ignore
case LogLevels.error:
this.warn = emptyFn;
// @ts-ignore
case LogLevels.warn:
this.info = emptyFn;
// @ts-ignore
case LogLevels.info:
this.debug = emptyFn;
// @ts-ignore
case LogLevels.debug:
this.trace = emptyFn;
// @ts-ignore
}
}
}
Logger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: Logger, deps: [{ token: LoggerConfiguration, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
Logger.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: Logger });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: Logger, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: LoggerConfiguration, decorators: [{
type: Optional
}] }]; } });
const spaces = ' ';
/**
* Singleton. Attempting to run two Logger instances will fail. And rightly so!
*/
class ConsoleLogger extends Logger {
constructor(configuration) {
super(configuration);
}
log(message) {
let args = [message.level + ':'];
let name = '';
if (message.context && !this.config.includeFullContext && message.context.constructor) {
name = message.context._proto_ ? message.context._proto_.name : message.context.constructor.name;
}
const padChars = this.config.contextAsStringWidth - name.length;
name = padChars > 0 ? name + spaces.substring(0, padChars) : name;
args.push(name + ' - ');
args = args.concat(message.message);
if (this.config.includeFullContext && message.context) {
args.push(message.context);
}
console.log.apply(console, args);
}
}
ConsoleLogger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: ConsoleLogger, deps: [{ token: LoggerConfiguration, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
ConsoleLogger.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: ConsoleLogger });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: ConsoleLogger, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: LoggerConfiguration, decorators: [{
type: Optional
}] }]; } });
class BusLoggerConfiguration extends LoggerConfiguration {
constructor() {
super(...arguments);
this.alsoLogToConsole = false;
}
}
BusLoggerConfiguration.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: BusLoggerConfiguration, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
BusLoggerConfiguration.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: BusLoggerConfiguration });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: BusLoggerConfiguration, decorators: [{
type: Injectable
}] });
/**
* Singleton. Attempting to run two Logger instances will fail. And rightly so!
*/
class BusLogger extends ConsoleLogger {
constructor(bus, configuration) {
super(configuration);
this.bus = bus;
this.config = new BusLoggerConfiguration();
console.log('BusLogger', 'constructor', configuration);
}
log(message) {
this.bus.post(message);
if (this.config.alsoLogToConsole) {
super.log(message);
}
}
}
BusLogger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: BusLogger, deps: [{ token: MessageBus }, { token: LoggerConfiguration, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
BusLogger.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: BusLogger });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: BusLogger, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: MessageBus }, { type: LoggerConfiguration, decorators: [{
type: Optional
}] }]; } });
class NavigationMessage extends BusMessage {
constructor(key, path, additionalMessage) {
super(NavigationMessage.SourceKey, 'notification', key);
this.path = path;
this.additionalMessage = additionalMessage;
}
static filter(bus) {
return bus.all.pipe(filter(m => m.source === NavigationMessage.SourceKey));
}
}
NavigationMessage.SourceKey = 'NavigationMessage';
class NavigationRequiresAuthenticationMessage extends NavigationMessage {
constructor(path) {
super(NavigationRequiresAuthenticationMessage.Key, path);
}
static post(bus, path) {
bus.post(new NavigationRequiresAuthenticationMessage(path));
}
}
NavigationRequiresAuthenticationMessage.Key = 'requiresAuthentication';
class NavigationRequiresRoleMessage extends NavigationMessage {
constructor(path, roleKey) {
super(NavigationRequiresRoleMessage.Key, path, 'Role Required: ' + roleKey);
this.roleKey = roleKey;
}
static post(bus, path, roleKey) {
bus.post(new NavigationRequiresRoleMessage(path, roleKey));
}
}
NavigationRequiresRoleMessage.Key = 'requiresRole';
class NavigationRequiresPermissionMessage extends NavigationMessage {
constructor(path, permissionKey) {
super(NavigationRequiresPermissionMessage.SubKey, path, 'Permission Required: ' + permissionKey);
this.permissionKey = permissionKey;
}
static post(bus, path, roleKey) {
bus.post(new NavigationRequiresPermissionMessage(path, roleKey));
}
}
NavigationRequiresPermissionMessage.SubKey = 'requiresPermission';
class AppMessage extends BusMessage {
constructor(intent, key) {
super(AppMessage.SourceKey, intent, key);
}
static filter(bus) {
return bus.all.pipe(filter$1(msg => msg.source === AppMessage.SourceKey));
}
static signOutRequest() {
return new AppMessage('request', AppMessage.SignOutRequest);
}
}
AppMessage.SourceKey = 'App';
AppMessage.SignOutRequest = 'signOutRequest';
const DefaultPageAnalytics = function () {
return {
events: {
load: true,
unload: true
}
};
};
class NgRouteUtil {
static fullPath(route) {
let pathAry = [];
route.pathFromRoot
.map(routeSegment => routeSegment.snapshot)
.map(routeSnap => {
return routeSnap;
})
.map(routeSnap => routeSnap.url)
.filter(segments => segments && segments.length > 0)
.forEach(segments => segments.forEach(segment => pathAry.push(segment.toString())));
let path = pathAry.join('/');
if (path && path.endsWith('/')) {
path = path.substring(0, path.length - 1);
}
return path;
}
static primaryLeaf(router) {
let c = router.routerState.root;
while (c.firstChild) {
c = c.firstChild;
}
return c;
}
static findDescendantByComponentKey(router, componentTypeKey) {
let c = router.routerState.root;
do {
if (c.component && c.component['Key'] == componentTypeKey) {
break;
}
c = c.firstChild;
} while (c);
return c;
}
/**
* Breadth first search of route to find the descendant where 'parent.children[x].component['Key'] === componentTypeKey'
* This requires that the Component have the static field 'Key' declared and set to a value.
* @param route
* @param componentTypeKey
* @returns {Route | null}
*/
static findDescendantRouteByComponentKey(route, componentTypeKey) {
let result = null;
if (route.children) {
for (let i = 0; i < route.children.length; i++) {
let child = route.children[i];
if (child.component && child.component['Key'] === componentTypeKey) {
result = child;
break;
}
}
if (!result) {
for (let i = 0; i < route.children.length; i++) {
result = NgRouteUtil.findDescendantRouteByComponentKey(route.children[i], componentTypeKey);
if (result) {
break;
}
}
}
}
return result;
}
/**
* Breadth first search of route to find the descendant where 'parent.children[x].path === path'
* @param route
* @param path
* @returns {Route | null}
*/
static findDescendantRouteByPath(route, path) {
let result = null;
if (route.children) {
for (let i = 0; i < route.children.length; i++) {
let child = route.children[i];
if (child.path === path) {
result = child;
break;
}
}
if (!result) {
for (let i = 0; i < route.children.length; i++) {
result = NgRouteUtil.findDescendantRouteByPath(route.children[i], path);
if (result) {
break;
}
}
}
}
return result;
}
}
const TimeUnitSort = (b, a) => {
return a.orderIndex - b.orderIndex;
};
const TimeUnits = {
day: {
unitKey: 'day',
fullLabel: 'Day',
label: 'day',
separatorSuffix: 'd ',
logicalMax: 7,
momentKey: 'd',
orderIndex: 40,
next: 'h',
previous: undefined
},
h: {
unitKey: 'h',
fullLabel: 'Hour',
label: 'hour',
separatorSuffix: ':',
logicalMax: 23,
momentKey: 'h',
orderIndex: 30,
next: 'min',
previous: 'day'
},
min: {
unitKey: 'min',
fullLabel: 'Minute',
label: 'min',
separatorSuffix: ':',
logicalMax: 59,
momentKey: 'm',
orderIndex: 20,
next: 's',
previous: 'h'
},
s: {
unitKey: 's',
fullLabel: 'Second',
label: 'sec',
separatorSuffix: '.',
logicalMax: 59,
momentKey: 's',
orderIndex: 10,
next: 'ms',
previous: 'min'
},
ms: {
unitKey: 'ms',
fullLabel: 'Millisecond',
label: 'ms',
separatorSuffix: '',
logicalMax: 999,
momentKey: 'ms',
orderIndex: 0,
next: undefined,
previous: 's'
},
};
const TimeUnitKeySort = (a, b) => {
return TimeUnits[b].orderIndex - TimeUnits[a].orderIndex;
};
class Hacks {
static materialDesignPlaceholderText(changeDetector) {
setTimeout(() => {
changeDetector.markForCheck();
}, 100);
}
}
class LocalizationUtil {
static browserLanguages() {
let languages;
if (navigator['languages']) {
languages = navigator['languages'];
}
else {
languages = [navigator.language];
}
return languages;
}
}
const adjectives = [
'Abrupt', 'Acidic', 'Adorable', 'Adventurous', 'Aggressive', 'Agitated', 'Alert', 'Aloof', 'Amiable', 'Amused',
'Annoyed', 'Antsy', 'Anxious', 'Appalling', 'Appetizing', 'Apprehensive', 'Arrogant', 'Astonishing', 'Attractive',
'Batty', 'Beefy', 'Bewildered', 'Biting', 'Bitter', 'Bland', 'Blushing', 'Bored', 'Brave', 'Bright', 'Broad', 'Bulky',
'Burly', 'Charming', 'Cheeky', 'Cheerful', 'Clean', 'Clear', 'Cloudy', 'Clueless', 'Clumsy', 'Colorful', 'Colossal',
'Combative', 'Comfortable', 'Confused', 'Contemplative', 'Convincing', 'Convoluted', 'Cooperative', 'Corny', 'Costly',
'Courageous', 'Crabby', 'Creepy', 'Crooked', 'Cumbersome', 'Cynical', 'Dangerous', 'Dashing', 'Deep', 'Defeated',
'Defiant', 'Delicious', 'Delightful', 'Depraved', 'Despicable', 'Determined', 'Dilapidated', 'Diminutive',
'Disgusted', 'Distinct', 'Distraught', 'Distressed', 'Disturbed', 'Dizzy', 'Drab', 'Drained', 'Dull', 'Eager',
'Ecstatic', 'Elated', 'Elegant', 'Embarrassed', 'Enchanting', 'Encouraging', 'Energetic', 'Enormous', 'Enthusiastic',
'Envious', 'Exasperated', 'Excited', 'Exhilarated', 'Extensive', 'Exuberant', 'Fancy', 'Fantastic', 'Fierce',
'Filthy', 'Flat', 'Floppy', 'Fluttering', 'Foolish', 'Frantic', 'Fresh', 'Friendly', 'Frothy', 'Frustrating', 'Funny',
'Fuzzy', 'Gaudy', 'Gentle', 'Giddy', 'Gigantic', 'Glamorous', 'Gleaming', 'Glorious', 'Gorgeous', 'Graceful',
'Gritty', 'Grubby', 'Grumpy', 'Handsome', 'Happy', 'Harebrained', 'Healthy', 'Helpful', 'Hollow', 'Homely', 'Huge',
'Icy', 'Ideal', 'Immense', 'Impressionable', 'Intrigued', 'Itchy', 'Jealous', 'Jittery', 'Jolly', 'Joyous', 'Juicy',
'Jumpy', 'Kind', 'Lackadaisical', 'Lazy', 'Little', 'Lively', 'Livid', 'Lonely', 'Loose', 'Lovely', 'Lucky',
'Ludicrous', 'Macho', 'Magnificent', 'Mammoth', 'Maniacal', 'Massive', 'Melancholy', 'Melted', 'Miniature', 'Minute',
'Mistaken', 'Misty', 'Moody', 'Muddy', 'Mysterious', 'Narrow', 'Naughty', 'Nervous', 'Nonchalant', 'Nonsensical',
'Nutritious', 'Nutty', 'Oblivious', 'Obnoxious', 'Odd', 'Old-fashioned', 'Outrageous', 'Perfect', 'Perplexed',
'Petite', 'Petty', 'Plain', 'Pleasant', 'Poised', 'Pompous', 'Precious', 'Prickly', 'Proud', 'Pungent', 'Puny',
'Quaint', 'Quizzical', 'Ratty', 'Reassured', 'Relieved', 'Responsive', 'Ripe', 'Robust', 'Rough', 'Round', 'Salty',
'Sarcastic', 'Scant', 'Scary', 'Scattered', 'Scrawny', 'Selfish', 'Shaggy', 'Shaky', 'Shallow', 'Sharp', 'Shiny',
'Short', 'Silky', 'Silly', 'Skinny', 'Slippery', 'Small', 'Smarmy', 'Smiling', 'Smoggy', 'Smooth', 'Smug', 'Soggy',
'Solid', 'Sore', 'Sour', 'Sparkling', 'Spicy', 'Splendid', 'Spotless', 'Square', 'Stale', 'Steady', 'Steep', 'Sticky',
'Stormy', 'Stout', 'Strange', 'Strong', 'Stunning', 'Substantial', 'Successful', 'Succulent', 'Superficial',
'Superior', 'Swanky', 'Sweet', 'Tart', 'Tasty', 'Teeny', 'Tender', 'Tense', 'Terrible', 'Testy', 'Thankful', 'Thick',
'Thoughtful', 'Thoughtless', 'Timely', 'Tricky', 'Trite', 'Pated', 'Uneven', 'Unsightly', 'Upset', 'Uptight', 'Vast',
'Vexed', 'Victorious', 'Virtuous', 'Vivacious', 'Vivid', 'Wacky', 'Whimsical', 'Whopping', 'Wicked', 'Witty',
'Wobbly', 'Wonderful', 'Worried', 'Yummy', 'Zany', 'Zealous', 'Zippy'
];
const nouns = [
'Aardvark', 'Aardwolf', 'Albatross', 'Alligator', 'Alpaca', 'Anaconda', 'Anglerfish', 'Ant', 'Anteater', 'Antelope',
'Antlion', 'Ape', 'Aphid', 'Armadillo', 'Asp', 'Baboon', 'Badger', 'Bandicoot', 'Barnacle', 'Barracuda', 'Basilisk',
'Bass', 'Bat', 'Bear', 'Beaver', 'Bedbug', 'Bee', 'Beetle', 'Bison', 'Blackbird', 'Boa', 'Bobcat', 'Bobolink',
'Bonobo', 'Booby', 'Bovid', 'Buffalo', 'Bug', 'Butterfly', 'Buzzard', 'Camel', 'Canid', 'Capybara', 'Cardinal',
'Caribou', 'Carp', 'Caterpillar', 'Catfish', 'Catshark', 'Centipede', 'Cephalopod', 'Chameleon', 'Cheetah',
'Chickadee', 'Chimpanzee', 'Chinchilla', 'Chipmunk', 'Cicada', 'Clam', 'Clownfish', 'Cobra', 'Cockroach', 'Cod',
'Condor', 'Constrictor', 'Coral', 'Cougar', 'Cow', 'Coyote', 'Coypu', 'Crab', 'Crane', 'Crawdad', 'Crayfish',
'Cricket', 'Crocodile', 'Crow', 'Cuckoo', 'Damselfly', 'Deer', 'Dingo', 'Dolphin', 'Dormouse', 'Dove', 'Dragon',
'Dragonfly', 'Eagle', 'Earthworm', 'Earwig', 'Echidna', 'Eel', 'Egret', 'Elephant', 'Elk', 'Emu', 'Ermine', 'Falcon',
'Ferret', 'Finch', 'Firefly', 'Fish', 'Flamingo', 'Flea', 'Fly', 'Flyingfish', 'Fowl', 'Fox', 'Fox', 'Frog',
'Gazelle', 'Gecko', 'Gerbil', 'Gibbon', 'Giraffe', 'Goldfish', 'Gopher', 'Gorilla', 'Grasshopper', 'Grouse',
'Guanaco', 'Gull', 'Guppy', 'Haddock', 'Halibut', 'Hamster', 'Hare', 'Harrier', 'Hawk', 'Hedgehog', 'Heron',
'Herring', 'Hippopotamus', 'Hookworm', 'Hornet', 'Hoverfly', 'Hummingbird', 'Hyena', 'Iguana', 'Impala', 'Insect',
'Jacana', 'Jackal', 'Jaguar', 'Jay', 'Jellyfish', 'Junglefowl', 'Kangaroo', 'Kingfisher', 'Kite', 'Kiwi', 'Koala',
'Koi', 'Krill', 'Ladybug', 'Lamprey', 'Landfowl', 'Lark', 'Leech', 'Lemming', 'Lemur', 'Leopard', 'Leopard',
'Leopard', 'Leopon', 'Limpet', 'Lion', 'Lizard', 'Llama', 'Lobster', 'Locust', 'Loon', 'Louse', 'Lungfish', 'Lynx',
'Macaw', 'Mackerel', 'Magpie', 'Mammal', 'Manatee', 'Mandrill', 'Marlin', 'Marmoset', 'Marmot', 'Marsupial', 'Marten',
'Mastodon', 'Meadowlark', 'Meerkat', 'Mink', 'Minnow', 'Mite', 'Mockingbird', 'Mole', 'Mollusk', 'Mongoose', 'Monkey',
'Moose', 'Mosquito', 'Moth', 'Mouse', 'Mule', 'Muskox', 'Narwhal', 'Needlefish', 'Newt', 'Nighthawk', 'Nightingale',
'Numbat', 'Ocelot', 'Octopus', 'Okapi', 'Olingo', 'Opossum', 'Orangutan', 'Orca', 'Oribi', 'Ostrich', 'Otter', 'Owl',
'Ox', 'Panda', 'Panther', 'Panther', 'Parakeet', 'Parrot', 'Parrotfish', 'Partridge', 'Peacock', 'Peafowl', 'Pelican',
'Penguin', 'Perch', 'Pheasant', 'Pig', 'Pike', 'Pinniped', 'Piranha', 'Planarian', 'Platypus', 'Pony', 'Porcupine',
'Porpoise', 'Possum', 'Prawn', 'Primate', 'Ptarmigan', 'Puffin', 'Puma', 'Python', 'Quail', 'Quelea', 'Quokka',
'Raccoon', 'Rat', 'Rattlesnake', 'Raven', 'Reindeer', 'Reptile', 'Rhinoceros', 'Roadrunner', 'Rodent', 'Rook',
'Rooster', 'Roundworm', 'Sailfish', 'Salamander', 'Salmon', 'Sawfish', 'Scallop', 'Scorpion', 'Seahorse', 'Shrew',
'Shrimp', 'Silkworm', 'Silverfish', 'Skink', 'Skunk', 'Sloth', 'Slug', 'Smelt', 'Snail', 'Snipe', 'Sole', 'Sparrow',
'Spider', 'Spoonbill', 'Squid', 'Squirrel', 'Starfish', 'Stingray', 'Stoat', 'Stork', 'Sturgeon', 'Swallow', 'Swan',
'Swift', 'Swordfish', 'Swordtail', 'Tahr', 'Takin', 'Tapir', 'Tarantula', 'Tarsier', 'Termite', 'Tern', 'Thrush',
'Tick', 'Tiger', 'Tiglon', 'Titi', 'Toad', 'Tortoise', 'Toucan', 'Trout', 'Tuna', 'Turtle', 'Tyrannosaurus', 'Urial',
'Vaquita', 'Vicuña', 'Viper', 'Voalavoanala', 'Vole', 'Vulture', 'Wallaby', 'Walrus', 'Warbler', 'Wasp', 'Waterbuck',
'Weasel', 'Whale', 'Whippet', 'Whitefish', 'Wildcat', 'Wildebeest', 'Wildfowl', 'Wolf', 'Wolf', 'Wolverine', 'Wombat',
'Woodchuck', 'Woodpecker', 'Worm', 'Wren', 'Xerinae', 'Yak', 'Zebra', 'Zebu', 'Zorilla',
];
class NameGenerator {
static generate() {
const aRand = Math.floor(NameGenerator.adjectivesLength * Math.random());
const nRand = Math.floor(NameGenerator.nounsLength * Math.random());
return adjectives[aRand] + ' ' + nouns[nRand];
}
}
NameGenerator.adjectivesLength = adjectives.length;
NameGenerator.nounsLength = nouns.length;
class NgUtil {
static data$(route) {
return route.data.pipe(map((data) => {
return NgUtil.collectFromRoute(route.snapshot, true);
}));
}
static data(route) {
return NgUtil.collectFromRoute(route, true);
}
static params(route) {
return NgUtil.collectFromRoute(route, false);
}
static collectFromRoute(route, data) {
const datas = [{}];
let child = route.root;
while (child) {
const what = data ? child.data : child.params;
datas.push(what || {});
child = child.firstChild;
}
// merge them all together...
return Object.assign.apply(Object, datas);
}
static params$(route) {
return route.params.pipe(map((params) => {
return NgUtil.collectFromRoute(route.snapshot, false);
}));
}
static routeLeaf(route) {
let child = route.root;
while (child.firstChild) {
child = child.firstChild;
}
return child;
}
static keylessUrl(route) {
return route.url ? route.url.split('/').map(segment => NgUtil.isFirebaseId(segment) ? ':key' : segment).join('/') : '';
}
/**
*
* @param key
* @returns {boolean}
* @deprecated See FireBlanket.util#isFirebaseGeneratedId
*/
static isFirebaseId(key) {
let isKey = false;
if (key && key.length === 20 && key.startsWith('-')) {
isKey = true;
}
return isKey;
}
}
class TransformUtil {
static firstExisting(...obj) {
let result;
for (let i = 0; i < obj.length; i++) {
if (ObjectUtil.exists(obj[i])) {
result = obj[i];
break;
}
}
return result;
}
}
/**
* Cannot implement 'OnInit' any longer; Angular inspects for that and requires a decorator.
*/
class Page {
constructor(bus) {
this.bus = bus;
this.routeInfo = {
page: {
title: this.constructor['name']
},
showAds: false
};
}
}
/*
* Public API Surface of core
*/
/**
* Generated bundle index. Do not edit.
*/
export { AppEnvironment, AppMessage, ArrayUtils, BusLogger, BusLoggerConfiguration, BusMessage, CodedError, ConsoleLogger, DefaultPageAnalytics, Guard, Hacks, Intention, JsonUtil, LocalizationUtil, LogLevels, LogMessage, Logger, LoggerConfiguration, MessageBus, NameGenerator, NavigationMessage, NavigationRequiresAuthenticationMessage, NavigationRequiresPermissionMessage, NavigationRequiresRoleMessage, NgRouteUtil, NgUtil, ObjMapUtil, ObjectUtil, Page, ReactiveUtil, ResolveVoid, SelectionEntry, SelectionList, StringUtil, TimeUnitKeySort, TimeUnitSort, TimeUnits, TransformUtil, cleanFirebaseMap, eachKey, ensureExists, generatePushID, pathExists, removeIfExists, safe };
//# sourceMappingURL=tangential-core.mjs.map