UNPKG

jsf.js_next_gen

Version:

A next generation typescript reimplementation of jsf.js

1,358 lines (1,345 loc) 378 kB
/******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ({ /***/ "./node_modules/mona-dish/src/main/typescript/AssocArray.ts": /*!******************************************************************!*\ !*** ./node_modules/mona-dish/src/main/typescript/AssocArray.ts ***! \******************************************************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { /*! * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to you under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.deepEqual = exports.shallowMerge = exports.simpleShallowMerge = exports.deepCopy = exports.buildPath = exports.resolve = exports.appendIf = exports.assignIf = exports.append = exports.assign = void 0; const Es2019Array_1 = __webpack_require__(/*! ./Es2019Array */ "./node_modules/mona-dish/src/main/typescript/Es2019Array.ts"); /** * A nop as assign functionality (aka ignore assign) */ class IgnoreAssign { constructor(parent) { this.parent = parent; } set value(value) { } get value() { return this.parent; } } ; /** * uses the known pattern from config * assign(target, key1, key2, key3).value = value; * @param target * @param keys */ function assign(target, ...accessPath) { if (accessPath.length < 1) { return new IgnoreAssign(target); } const lastPathItem = buildPath(target, ...accessPath); let assigner = new (class { set value(value) { lastPathItem.target[lastPathItem.key] = value; } get value() { return lastPathItem.target[lastPathItem.key]; } })(); return assigner; } exports.assign = assign; function append(target, ...accessPath) { if (accessPath.length < 1) { return new IgnoreAssign(target); } const lastPathItem = buildPath(target, ...accessPath); let appender = new (class { set value(value) { if (!Array.isArray(value)) { value = [value]; } if (!lastPathItem.target[lastPathItem.key]) { lastPathItem.target[lastPathItem.key] = value; } else { if (!Array.isArray(lastPathItem.target[lastPathItem.key])) { lastPathItem.target[lastPathItem.key] = [lastPathItem.target[lastPathItem.key]]; } lastPathItem.target[lastPathItem.key].push(...value); } } })(); return appender; } exports.append = append; /** * uses the known pattern from config * assign(target, key1, key2, key3).value = value; * @param target * @param keys */ function assignIf(condition, target, ...accessPath) { if ((!condition) || accessPath.length < 1) { return new IgnoreAssign(target); } return assign(target, ...accessPath); } exports.assignIf = assignIf; /** * uses the known pattern from config * assign(target, key1, key2, key3).value = value; * @param target * @param keys */ function appendIf(condition, target, ...accessPath) { if ((!condition) || accessPath.length < 1) { return new IgnoreAssign(target); } return append(target, ...accessPath); } exports.appendIf = appendIf; function resolve(target, ...accessPath) { let ret = null; accessPath = flattenAccessPath(accessPath); let currPtr = target; for (let cnt = 0; cnt < accessPath.length; cnt++) { let accessKeyIndex = accessPath[cnt]; accessKeyIndex = arrayIndex(accessKeyIndex) != -1 ? arrayIndex(accessKeyIndex) : accessKeyIndex; currPtr = currPtr === null || currPtr === void 0 ? void 0 : currPtr[accessKeyIndex]; if ('undefined' == typeof currPtr) { return null; } ret = currPtr; } return currPtr; } exports.resolve = resolve; function keyVal(key) { let start = key.indexOf("["); if (start >= 0) { return key.substring(0, start); } else { return key; } } function arrayIndex(key) { let start = key.indexOf("["); let end = key.indexOf("]"); if (start >= 0 && end > 0 && start < end) { return parseInt(key.substring(start + 1, end)); } else { return -1; } } function isArrayPos(currKey, arrPos) { return currKey === "" && arrPos >= 0; } function isNoArray(arrPos) { return arrPos == -1; } function alloc(arr, length, defaultVal = {}) { let toAdd = []; toAdd.length = length; toAdd[length - 1] = defaultVal; arr.push(...toAdd); } function flattenAccessPath(accessPath) { return new Es2019Array_1.Es2019Array(...accessPath).flatMap(path => path.split("[")) .map(path => path.indexOf("]") != -1 ? "[" + path : path) .filter(path => path != ""); } /** * builds up a path, only done if no data is present! * @param target * @param accessPath * @returns the last assignable entry */ function buildPath(target, ...accessPath) { accessPath = flattenAccessPath(accessPath); //we now have a pattern of having the array accessors always in separate items let parentPtr = target; let parKeyArrPos = null; let currKey = null; let arrPos = -1; for (let cnt = 0; cnt < accessPath.length; cnt++) { currKey = keyVal(accessPath[cnt]); arrPos = arrayIndex(accessPath[cnt]); //it now is either key or arrPos if (arrPos != -1) { //case root(array)[5] -> root must be array and allocate 5 elements //case root.item[5] root.item must be array and of 5 elements if (!Array.isArray(parentPtr)) { throw Error("Associative array referenced as index array in path reference"); } //we need to look ahead for proper allocation //not end reached let nextArrPos = -1; if (cnt < accessPath.length - 1) { nextArrPos = arrayIndex(accessPath[cnt + 1]); } let dataPresent = 'undefined' != typeof (parentPtr === null || parentPtr === void 0 ? void 0 : parentPtr[arrPos]); //no data present check here is needed, because alloc only reserves if not present alloc(parentPtr, arrPos + 1, nextArrPos != -1 ? [] : {}); parKeyArrPos = arrPos; //we now go to the reserved element if (cnt == accessPath.length - 1) { parentPtr[arrPos] = (dataPresent) ? parentPtr[arrPos] : null; } else { parentPtr = parentPtr[arrPos]; } } else { if (Array.isArray(parentPtr)) { throw Error("Index array referenced as associative array in path reference"); } //again look ahead whether the next value is an array or assoc array let nextArrPos = -1; if (cnt < accessPath.length - 1) { nextArrPos = arrayIndex(accessPath[cnt + 1]); } parKeyArrPos = currKey; let dataPresent = 'undefined' != typeof (parentPtr === null || parentPtr === void 0 ? void 0 : parentPtr[currKey]); if (cnt == accessPath.length - 1) { if (!dataPresent) { parentPtr[currKey] = null; } } else { if (!dataPresent) { parentPtr[currKey] = nextArrPos == -1 ? {} : []; } parentPtr = parentPtr[currKey]; } } } return { target: parentPtr, key: parKeyArrPos }; } exports.buildPath = buildPath; function deepCopy(fromAssoc) { return JSON.parse(JSON.stringify(fromAssoc)); } exports.deepCopy = deepCopy; /** * simple left to right merge * * @param assocArrays */ function simpleShallowMerge(...assocArrays) { return shallowMerge(true, false, ...assocArrays); } exports.simpleShallowMerge = simpleShallowMerge; function _appendWithOverwrite(withAppend, target, key, arr, toAssign) { if (!withAppend) { target[key] = arr[key]; } else { //overwrite means in this case, no double entries! //we do not a deep compare for now a single value compare suffices if ('undefined' == typeof (target === null || target === void 0 ? void 0 : target[key])) { target[key] = toAssign; } else if (!Array.isArray(target[key])) { let oldVal = target[key]; let newVals = []; //TODO maybe deep deep compare here, but on the other hand it is //shallow toAssign.forEach(item => { if (oldVal != item) { newVals.push(item); } }); target[key] = new Es2019Array_1.Es2019Array(...[]); target[key].push(oldVal); target[key].push(...newVals); } else { let oldVal = target[key]; let newVals = []; //TODO deep compare here toAssign.forEach(item => { if (oldVal.indexOf(item) == -1) { newVals.push(item); } }); target[key].push(...newVals); } } } function _appendWithoutOverwrite(withAppend, target, key, arr, toAssign) { if (!withAppend) { return; } else { //overwrite means in this case, no double entries! //we do not a deep compare for now a single value compare suffices if ('undefined' == typeof (target === null || target === void 0 ? void 0 : target[key])) { target[key] = toAssign; } else if (!Array.isArray(target[key])) { let oldVal = target[key]; target[key] = new Es2019Array_1.Es2019Array(...[]); target[key].push(oldVal); target[key].push(...toAssign); } else { target[key].push(...toAssign); } } } /** * Shallow merge as in config, but on raw associative arrays * * @param overwrite overwrite existing keys, if they exist with their subtrees * @param withAppend if a key exist append the values or drop them * Combination overwrite withappend filters doubles out of merged arrays * @param assocArrays array of assoc arres reduced right to left */ function shallowMerge(overwrite = true, withAppend = false, ...assocArrays) { let target = {}; new Es2019Array_1.Es2019Array(...assocArrays).map(arr => { return { arr, keys: Object.keys(arr) }; }).forEach(({ arr, keys }) => { keys.forEach(key => { let toAssign = arr[key]; if (!Array.isArray(toAssign) && withAppend) { toAssign = new Es2019Array_1.Es2019Array(...[toAssign]); } if (overwrite || !(target === null || target === void 0 ? void 0 : target[key])) { _appendWithOverwrite(withAppend, target, key, arr, toAssign); } else if (!overwrite && (target === null || target === void 0 ? void 0 : target[key])) { _appendWithoutOverwrite(withAppend, target, key, arr, toAssign); } }); }); return target; } exports.shallowMerge = shallowMerge; //TODO test this, slightly altered from https://medium.com/@pancemarko/deep-equality-in-javascript-determining-if-two-objects-are-equal-bf98cf47e934 //he overlooked some optimizations and a shortcut at typeof! function deepEqual(obj1, obj2) { if (obj1 == obj2) { return false; } if (typeof obj1 != typeof obj2) { return false; } if (Array.isArray(obj1) && Array.isArray(obj2)) { if (obj1.length != obj2.length) { return; } //arrays must be equal, order as well, there is no way around it //this is the major limitation we have return obj1.every((item, cnt) => deepEqual(item, obj2[cnt])); } //string number and other primitives are filtered out here if ("object" == typeof obj1 && "object" == typeof obj2) { let keys1 = Object.keys(obj1); let keys2 = Object.keys(obj2); if (keys1.length != keys2.length) { return false; } return keys1.every(key => keys2.indexOf(key) != -1) && keys1.every(key => deepEqual(obj1[key], obj2[key])); } return false; //done here no match found } exports.deepEqual = deepEqual; /***/ }), /***/ "./node_modules/mona-dish/src/main/typescript/Config.ts": /*!**************************************************************!*\ !*** ./node_modules/mona-dish/src/main/typescript/Config.ts ***! \**************************************************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Config = exports.CONFIG_ANY = exports.CONFIG_VALUE = void 0; const Es2019Array_1 = __webpack_require__(/*! ./Es2019Array */ "./node_modules/mona-dish/src/main/typescript/Es2019Array.ts"); const Monad_1 = __webpack_require__(/*! ./Monad */ "./node_modules/mona-dish/src/main/typescript/Monad.ts"); const Lang_1 = __webpack_require__(/*! ./Lang */ "./node_modules/mona-dish/src/main/typescript/Lang.ts"); var objAssign = Lang_1.Lang.objAssign; const AssocArray_1 = __webpack_require__(/*! ./AssocArray */ "./node_modules/mona-dish/src/main/typescript/AssocArray.ts"); /** * specialized value embedder * for our Configuration */ class ConfigEntry extends Monad_1.ValueEmbedder { constructor(rootElem, key, arrPos) { super(rootElem, key); this.arrPos = arrPos !== null && arrPos !== void 0 ? arrPos : -1; } get value() { if (this.key == "" && this.arrPos >= 0) { return this._value[this.arrPos]; } else if (this.key && this.arrPos >= 0) { return this._value[this.key][this.arrPos]; } return this._value[this.key]; } set value(val) { if (this.key == "" && this.arrPos >= 0) { this._value[this.arrPos] = val; return; } else if (this.key && this.arrPos >= 0) { this._value[this.key][this.arrPos] = val; return; } this._value[this.key] = val; } } /*default value for absent*/ ConfigEntry.absent = ConfigEntry.fromNullable(null); exports.CONFIG_VALUE = "__END_POINT__"; exports.CONFIG_ANY = "__ANY_POINT__"; /** * Config, basically an optional wrapper for a json structure * (not Side - effect free, since we can alter the internal config state * without generating a new config), not sure if we should make it side - effect free * since this would swallow a lot of performance and ram */ class Config extends Monad_1.Optional { constructor(root, configDef) { super(root); this.configDef = configDef; } /** * shallow copy getter, copies only the first level, references the deeper nodes * in a shared manner */ get shallowCopy() { return this.shallowCopy$(); } shallowCopy$() { let ret = new Config({}); ret.shallowMerge(this.value); return ret; } /** * deep copy, copies all config nodes */ get deepCopy() { return this.deepCopy$(); } deepCopy$() { return new Config(objAssign({}, this.value)); } /** * creates a config from an initial value or null * @param value */ static fromNullable(value) { return new Config(value); } /** * simple merge for the root configs */ shallowMerge(other, overwrite = true, withAppend = false) { //shallow merge must be mutable so we have to remap let newThis = (0, AssocArray_1.shallowMerge)(overwrite, withAppend, this.value, other.value); if (Array.isArray(this._value)) { this._value.length = 0; this._value.push(...newThis); } else { Object.getOwnPropertyNames(this._value).forEach(key => delete this._value[key]); Object.getOwnPropertyNames(newThis).forEach(key => this._value[key] = newThis[key]); } } /** * assigns a single value as array, or appends it * to an existing value mapping a single value to array * * * usage myConfig.append("foobaz").value = "newValue" * myConfig.append("foobaz").value = "newValue2" * * resulting in myConfig.foobaz == ["newValue, newValue2"] * * @param {string[]} accessPath */ append(...accessPath) { return (0, AssocArray_1.append)(this._value, ...accessPath); } /** * appends to an existing entry (or extends into an array and appends) * if the condition is met * @param {boolean} condition * @param {string[]} accessPath */ appendIf(condition, ...accessPath) { return (0, AssocArray_1.appendIf)(condition, this._value, ...accessPath); } /** * assigns a new value on the given access path * @param accessPath */ assign(...accessPath) { return (0, AssocArray_1.assign)(this.value, ...accessPath); } /** * assign a value if the condition is set to true, otherwise skip it * * @param condition the condition, the access accessPath into the config * @param accessPath */ assignIf(condition, ...accessPath) { return (0, AssocArray_1.assignIf)(condition, this._value, ...accessPath); } /** * get if the access path is present (get is reserved as getter with a default, on the current path) * TODO will be renamed to something more meaningful and deprecated, the name is ambiguous * @param accessPath the access path */ getIf(...accessPath) { this.assertAccessPath(...accessPath); return this.getClass().fromNullable((0, AssocArray_1.resolve)(this.value, ...accessPath)); } /** * gets the current node and if none is present returns a config with a default value * @param defaultVal */ get(defaultVal) { return this.getClass().fromNullable(super.get(defaultVal).value); } //empties the current config entry delete(key) { if (key in this.value) { delete this.value[key]; } return this; } /** * converts the entire config into a json object */ toJson() { return JSON.stringify(this.value); } getClass() { return Config; } setVal(val) { this._value = val; } /** * asserts the access path for a semi typed access * @param accessPath * @private */ assertAccessPath(...accessPath) { var _a, _b, _c, _d, _e, _f, _g, _h, _j; accessPath = this.preprocessKeys(...accessPath); if (!this.configDef) { //untyped return; } const ERR_ACCESS_PATH = "Access Path to config invalid"; let currAccessPos = Monad_1.Optional.fromNullable(Object.keys(this.configDef).map(key => { let ret = {}; ret[key] = this.configDef[key]; return ret; })); for (let cnt = 0; cnt < accessPath.length; cnt++) { let currKey = this.keyVal(accessPath[cnt]); let arrPos = this.arrayIndex(accessPath[cnt]); //key index if (this.isArray(arrPos)) { if (currKey != "") { currAccessPos = Array.isArray(currAccessPos.value) ? Monad_1.Optional.fromNullable((_b = (_a = new Es2019Array_1.Es2019Array(...currAccessPos.value) .find(item => { var _a; return !!((_a = item === null || item === void 0 ? void 0 : item[currKey]) !== null && _a !== void 0 ? _a : false); })) === null || _a === void 0 ? void 0 : _a[currKey]) === null || _b === void 0 ? void 0 : _b[arrPos]) : Monad_1.Optional.fromNullable((_e = (_d = (_c = currAccessPos.value) === null || _c === void 0 ? void 0 : _c[currKey]) === null || _d === void 0 ? void 0 : _d[arrPos]) !== null && _e !== void 0 ? _e : null); } else { currAccessPos = (Array.isArray(currAccessPos.value)) ? Monad_1.Optional.fromNullable((_f = currAccessPos.value) === null || _f === void 0 ? void 0 : _f[arrPos]) : Monad_1.Optional.absent; } //we noe store either the current array or the filtered look ahead to go further } else { //we now have an array and go further with a singular key currAccessPos = (Array.isArray(currAccessPos.value)) ? Monad_1.Optional.fromNullable((_g = new Es2019Array_1.Es2019Array(...currAccessPos.value) .find(item => { var _a; return !!((_a = item === null || item === void 0 ? void 0 : item[currKey]) !== null && _a !== void 0 ? _a : false); })) === null || _g === void 0 ? void 0 : _g[currKey]) : Monad_1.Optional.fromNullable((_j = (_h = currAccessPos.value) === null || _h === void 0 ? void 0 : _h[currKey]) !== null && _j !== void 0 ? _j : null); } if (!currAccessPos.isPresent()) { throw Error(ERR_ACCESS_PATH); } if (currAccessPos.value == exports.CONFIG_ANY) { return; } } } isNoArray(arrPos) { return arrPos == -1; } isArray(arrPos) { return !this.isNoArray(arrPos); } } exports.Config = Config; /***/ }), /***/ "./node_modules/mona-dish/src/main/typescript/DomQuery.ts": /*!****************************************************************!*\ !*** ./node_modules/mona-dish/src/main/typescript/DomQuery.ts ***! \****************************************************************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { /*! * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to you under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http:// www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DQ$ = exports.DQ = exports.DomQueryCollector = exports.DomQuery = exports.Style = exports.ElementAttribute = void 0; const Monad_1 = __webpack_require__(/*! ./Monad */ "./node_modules/mona-dish/src/main/typescript/Monad.ts"); const SourcesCollectors_1 = __webpack_require__(/*! ./SourcesCollectors */ "./node_modules/mona-dish/src/main/typescript/SourcesCollectors.ts"); const Lang_1 = __webpack_require__(/*! ./Lang */ "./node_modules/mona-dish/src/main/typescript/Lang.ts"); const Global_1 = __webpack_require__(/*! ./Global */ "./node_modules/mona-dish/src/main/typescript/Global.ts"); const Es2019Array_1 = __webpack_require__(/*! ./Es2019Array */ "./node_modules/mona-dish/src/main/typescript/Es2019Array.ts"); var trim = Lang_1.Lang.trim; var isString = Lang_1.Lang.isString; var eqi = Lang_1.Lang.equalsIgnoreCase; var objToArray = Lang_1.Lang.objToArray; const AssocArray_1 = __webpack_require__(/*! ./AssocArray */ "./node_modules/mona-dish/src/main/typescript/AssocArray.ts"); class NonceValueEmbedder extends Monad_1.ValueEmbedder { constructor(rootElems) { super(rootElems === null || rootElems === void 0 ? void 0 : rootElems[0], "nonce"); this.rootElems = rootElems; } isAbsent() { const value = this.value; return 'undefined' == typeof value || '' == value; } get value() { var _a, _b, _c, _d, _e; return (_c = (_b = (_a = this === null || this === void 0 ? void 0 : this.rootElems) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.nonce) !== null && _c !== void 0 ? _c : (_e = (_d = this === null || this === void 0 ? void 0 : this.rootElems) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.getAttribute("nonce"); } set value(newVal) { var _a; if (!((_a = this === null || this === void 0 ? void 0 : this.rootElems) === null || _a === void 0 ? void 0 : _a.length)) { return; } this.rootElems.forEach((rootElem) => { if ("undefined" != typeof (rootElem === null || rootElem === void 0 ? void 0 : rootElem.nonce)) { rootElem.nonce = newVal; } else { rootElem.setAttribute("nonce", newVal); } }); } } /** * * // - submit checkboxes and radio inputs only if checked if ((tagName != "select" && elemType != "button" && elemType != "reset" && elemType != "submit" && elemType != "image") && ((elemType != "checkbox" && elemType != "radio" */ var ALLOWED_SUBMITTABLE_ELEMENTS; (function (ALLOWED_SUBMITTABLE_ELEMENTS) { ALLOWED_SUBMITTABLE_ELEMENTS["SELECT"] = "select"; ALLOWED_SUBMITTABLE_ELEMENTS["BUTTON"] = "button"; ALLOWED_SUBMITTABLE_ELEMENTS["SUBMIT"] = "submit"; ALLOWED_SUBMITTABLE_ELEMENTS["RESET"] = "reset"; ALLOWED_SUBMITTABLE_ELEMENTS["IMAGE"] = "image"; ALLOWED_SUBMITTABLE_ELEMENTS["RADIO"] = "radio"; ALLOWED_SUBMITTABLE_ELEMENTS["CHECKBOX"] = "checkbox"; })(ALLOWED_SUBMITTABLE_ELEMENTS || (ALLOWED_SUBMITTABLE_ELEMENTS = {})); /** * helper to fix a common problem that a system has to wait, until a certain condition is reached. * Depending on the browser this uses either the Mutation Observer or a semi compatible interval as fallback. * @param root the root DomQuery element to start from * @param condition the condition lambda to be fulfilled * @param options options for the search */ function waitUntilDom(root, condition, options = { attributes: true, childList: true, subtree: true, timeout: 500, interval: 100 }) { return new Promise((success, error) => { let observer = null; const MUT_ERROR = new Error("Mutation observer timeout"); // we do the same but for now ignore the options on the dom query // we cannot use absent here, because the condition might search for an absent element function findElement(root, condition) { let found = null; if (!!condition(root)) { return root; } if (options.childList) { found = (condition(root)) ? root : root.childNodes.filter(item => condition(item)).first().value.value; } else if (options.subtree) { found = (condition(root)) ? root : root.querySelectorAll(" * ").filter(item => condition(item)).first().value.value; } else { found = (condition(root)) ? root : null; } return found; } let foundElement = root; if (!!(foundElement = findElement(foundElement, condition))) { success(new DomQuery(foundElement)); return; } if ('undefined' != typeof MutationObserver) { const mutTimeout = setTimeout(() => { observer.disconnect(); return error(MUT_ERROR); }, options.timeout); const callback = (mutationList) => { const found = new DomQuery(mutationList.map((mut) => mut.target)).filter(item => condition(item)).first(); if (found.isPresent()) { clearTimeout(mutTimeout); observer.disconnect(); success(new DomQuery(found || root)); } }; observer = new MutationObserver(callback); // browsers might ignore it, but we cannot break the api in the case // hence no timeout is passed let observableOpts = Object.assign({}, options); delete observableOpts.timeout; root.eachElem(item => { observer.observe(item, observableOpts); }); } else { // fallback for legacy browsers without mutation observer let interval = setInterval(() => { let found = findElement(root, condition); if (!!found) { if (timeout) { clearTimeout(timeout); clearInterval(interval); interval = null; } success(new DomQuery(found || root)); } }, options.interval); let timeout = setTimeout(() => { if (interval) { clearInterval(interval); error(MUT_ERROR); } }, options.timeout); } }); } class ElementAttribute extends Monad_1.ValueEmbedder { constructor(element, name, defaultVal = null) { super(element, name); this.element = element; this.name = name; this.defaultVal = defaultVal; } get value() { let val = this.element.get(0).orElse(...[]).values; if (!val.length) { return this.defaultVal; } return val[0].getAttribute(this.name); } set value(value) { let val = this.element.get(0).orElse(...[]).values; for (let cnt = 0; cnt < val.length; cnt++) { val[cnt].setAttribute(this.name, value); } val[0].setAttribute(this.name, value); } getClass() { return ElementAttribute; } static fromNullable(value, valueKey = "value") { return new ElementAttribute(value, valueKey); } } exports.ElementAttribute = ElementAttribute; class Style extends Monad_1.ValueEmbedder { constructor(element, name, defaultVal = null) { super(element, name); this.element = element; this.name = name; this.defaultVal = defaultVal; } get value() { let val = this.element.values; if (!val.length) { return this.defaultVal; } return val[0].style[this.name]; } set value(value) { let val = this.element.values; for (let cnt = 0; cnt < val.length; cnt++) { val[cnt].style[this.name] = value; } } getClass() { return ElementAttribute; } static fromNullable(value, valueKey = "value") { return new ElementAttribute(value, valueKey); } } exports.Style = Style; /** * small helper for the specialized jsf case * @constructor */ const DEFAULT_WHITELIST = () => { return true; }; /** * Monadic DomNode representation, ala jquery * This is a thin wrapper over querySelectorAll * to get slim monadic support * to reduce implementation code on the users side. * This is vital for frameworks which want to rely on * plain dom but still do not want to lose * the reduced code footprint of querying dom trees and traversing * by using functional patterns. * * Also, a few convenience methods are added to reduce * the code footprint of standard dom processing * operations like eval * * in most older systems * Note parts of this code still stem from the Dom.js I have written 10 years * ago, those parts look a bit ancient and will be replaced over time. * */ class DomQuery { constructor(...rootNode) { this.rootNode = []; this.pos = -1; // because we can stream from an array stream directly into the dom query this._limits = -1; if (Monad_1.Optional.fromNullable(rootNode).isAbsent() || !rootNode.length) { return; } else { // we need to flatten out the arrays for (let cnt = 0; cnt < rootNode.length; cnt++) { if (!rootNode[cnt]) { // we skip possible null entries which can happen in // certain corner conditions due to the constructor re-wrapping single elements into arrays. } else if (isString(rootNode[cnt])) { let foundElement = DomQuery.querySelectorAll(rootNode[cnt]); if (!foundElement.isAbsent()) { rootNode.push(...foundElement.values); } } else if (rootNode[cnt] instanceof DomQuery) { this.rootNode.push(...rootNode[cnt].values); } else { this.rootNode.push(rootNode[cnt]); } } } } /** * returns the first element */ get value() { return this.getAsElem(0); } get values() { return this.allElems(); } get global() { return Global_1._global$; } get stream() { throw Error("Not implemented, include Stream.ts for this to work"); } get lazyStream() { throw Error("Not implemented, include Stream.ts for this to work"); } /** * returns the id of the first element */ get id() { return new ElementAttribute(this.get(0), "id"); } /** * length of the entire query set */ get length() { return this.rootNode.length; } /** * convenience method for tagName */ get tagName() { return this.getAsElem(0).getIf("tagName"); } /** * convenience method for nodeName */ get nodeName() { return this.getAsElem(0).getIf("nodeName"); } isTag(tagName) { return !this.isAbsent() && (this.nodeName.orElse("__none___") .value.toLowerCase() == tagName.toLowerCase() || this.tagName.orElse("__none___") .value.toLowerCase() == tagName.toLowerCase()); } /** * convenience property for type * * returns null in case of no type existing otherwise * the type of the first element */ get type() { return this.getAsElem(0).getIf("type"); } /** * convenience property for name * * returns null in case of no type existing otherwise * the name of the first element */ get name() { return new Monad_1.ValueEmbedder(this.getAsElem(0).value, "name"); } /** * convenience property for value * * returns null in case of no type existing otherwise * the value of the first element */ get inputValue() { if (this.getAsElem(0).getIf("value").isPresent()) { return new Monad_1.ValueEmbedder(this.getAsElem(0).value); } else { return Monad_1.ValueEmbedder.absent; } } get val() { return this.inputValue.value; } set val(value) { this.inputValue.value = value; } get nodeId() { return this.id.value; } set nodeId(value) { this.id.value = value; } get checked() { return new Es2019Array_1.Es2019Array(...this.values).every(el => !!el.checked); } set checked(newChecked) { this.eachElem(el => el.checked = newChecked); } get elements() { // a simple querySelectorAll should suffice return this.querySelectorAll("input, checkbox, select, textarea, fieldset"); } get deepElements() { let elemStr = "input, select, textarea, checkbox, fieldset"; return this.querySelectorAllDeep(elemStr); } /** * a deep search which treats the single isolated shadow dom areas * separately and runs the query on each shadow dom * @param queryStr */ querySelectorAllDeep(queryStr) { let found = []; let queryRes = this.querySelectorAll(queryStr); if (queryRes.length) { found.push(queryRes); } let shadowRoots = this.querySelectorAll("*").shadowRoot; if (shadowRoots.length) { let shadowRes = shadowRoots.querySelectorAllDeep(queryStr); if (shadowRes.length) { found.push(shadowRes); } } return new DomQuery(...found); } /** * disabled flag */ get disabled() { return this.attr("disabled").isPresent(); } set disabled(disabled) { // this.attr("disabled").value = disabled + ""; if (!disabled) { this.removeAttribute("disabled"); } else { this.attr("disabled").value = "disabled"; } } removeAttribute(name) { this.eachElem(item => item.removeAttribute(name)); } get childNodes() { let childNodeArr = []; this.eachElem((item) => { childNodeArr = childNodeArr.concat(objToArray(item.childNodes)); }); return new DomQuery(...childNodeArr); } get asArray() { // filter not supported by IE11 let items = new Es2019Array_1.Es2019Array(...this.rootNode).filter(item => { return item != null; }).map(item => { return DomQuery.byId(item); }); return items; } get offsetWidth() { return new Es2019Array_1.Es2019Array(...this.rootNode) .filter(item => item != null) .map(elem => elem.offsetWidth) .reduce((accumulate, incoming) => accumulate + incoming, 0); } get offsetHeight() { return new Es2019Array_1.Es2019Array(...this.rootNode) .filter(item => item != null) .map(elem => elem.offsetHeight) .reduce((accumulate, incoming) => accumulate + incoming, 0); } get offsetLeft() { return new Es2019Array_1.Es2019Array(...this.rootNode) .filter(item => item != null) .map(elem => elem.offsetLeft) .reduce((accumulate, incoming) => accumulate + incoming, 0); } get offsetTop() { return new Es2019Array_1.Es2019Array(this.rootNode) .filter(item => item != null) .map(elem => elem.offsetTop) .reduce((accumulate, incoming) => accumulate + incoming, 0); } get asNodeArray() { return new Es2019Array_1.Es2019Array(...this.rootNode.filter(item => item != null)); } get nonce() { return new NonceValueEmbedder(this.rootNode); } static querySelectorAllDeep(selector) { return new DomQuery(document).querySelectorAllDeep(selector); } /** * easy query selector all producer * * @param selector the selector * @returns a results dom query object */ static querySelectorAll(selector) { if (selector.indexOf("/shadow/") != -1) { return new DomQuery(document)._querySelectorAllDeep(selector); } else { return new DomQuery(document)._querySelectorAll(selector); } } /** * byId producer * * @param selector id * @param deep true if you want to go into shadow areas * @return a DomQuery containing the found elements */ static byId(selector, deep = false) { if (isString(selector)) { return (!deep) ? new DomQuery(document).byId(selector) : new DomQuery(document).byIdDeep(selector); } else { return new DomQuery(selector); } } /** * byTagName producer * * @param selector name * @return a DomQuery containing the found elements */ static byTagName(selector) { if (isString(selector)) { return new DomQuery(document).byTagName(selector); } else { return new DomQuery(selector); } } static globalEval(code, nonce) { return new DomQuery(document).globalEval(code, nonce); } static globalEvalSticky(code, nonce) { return new DomQuery(document).globalEvalSticky(code, nonce); } /** * builds the ie nodes properly in a placeholder * and bypasses a non script insert bug that way * @param markup the markup code to be executed from */ static fromMarkup(markup) { // https:// developer.mozilla.org/de/docs/Web/API/DOMParser license creative commons const doc = document.implementation.createHTMLDocument(""); markup = trim(markup); let lowerMarkup = markup.toLowerCase(); if (lowerMarkup.search(/<!doctype[^\w\-]+/gi) != -1 || lowerMarkup.search(/<html[^\w\-]+/gi) != -1 || lowerMarkup.search(/<head[^\w\-]+/gi) != -1 || lowerMarkup.search(/<body[^\w\-]+/gi) != -1) { doc.documentElement.innerHTML = markup; return new DomQuery(doc.documentElement); } else { let startsWithTag = function (str, tagName) { let tag1 = ["<", tagName, ">"].join(""); let tag2 = ["<", tagName, " "].join(""); return (str.indexOf(tag1) == 0) || (str.indexOf(tag2) == 0); }; let dummyPlaceHolder = new DomQuery(document.createElement("div")); // table needs special treatment due to the browsers auto creation if (startsWithTag(lowerMarkup, "thead") || startsWithTag(lowerMarkup, "tbody")) { dummyPlaceHolder.html(`<table>${markup}</table>`); return dummyPlaceHolder.querySelectorAll("table").get(0).childNodes.detach(); } else if (startsWithTag(lowerMarkup, "tfoot")) { dummyPlaceHolder.html(`<table><thead></thead><tbody><tbody${markup}</table>`); return dummyPlaceHolder.querySelectorAll("table").get(2).childNodes.detach(); } else if (startsWithTag(lowerMarkup, "tr")) { dummyPlaceHolder.html(`<table><tbody>${markup}</tbody></table>`); return dummyPlaceHolder.querySelectorAll("tbody").get(0).childNodes.detach(); } else if (startsWithTag(lowerMarkup, "td")) { dummyPlaceHolder.html(`<table><tbody><tr>${markup}</tr></tbody></table>`); return dummyPlaceHolder.querySelectorAll("tr").get(0).childNodes.detach(); } dummyPlaceHolder.html(markup); return dummyPlaceHolder.childNodes.detach(); } } /** * returns the nth element as DomQuery * from the internal elements * note if you try to reach a non-existing element position * you will get back an absent entry * * @param index the nth index */ get(index) { return (index < this.rootNode.length) ? new DomQuery(this.rootNode[index]) : DomQuery.absent; } /** * returns the nth element as optional of an Element object * @param index the number from the index * @param defaults the default value if the index is overrun default Optional\.absent */ getAsElem(index, defaults = Monad_1.Optional.absent) { return (index < this.rootNode.length) ? Monad_1.Optional.fromNullable(this.rootNode[index]) : defaults; } /** * returns the files from a given element * @param index */ filesFromElem(index) { var _a; return (index < this.rootNode.length) ? ((_a = this.rootNode[index]) === null || _a === void 0 ? void 0 : _a.files) ? this.rootNode[index].files : [] : []; } /** * returns the value array< of all elements */ allElems() { return this.rootNode; } /** * absent no values reached? */ isAbsent() { return this.length == 0; } /** * should make the code clearer * note if you pass a function * this refers to the active DomQuery object */ isPresent(presentRunnable) { let absent = this.isAbsent(); if (!absent && presentRunnable) { presentRunnable.call(this, this); } return !absent; } /** * should make the code clearer * note if you pass a function * this refers to the active DomQuery object * * * @param presentRunnable */ ifPresentLazy(presentRunnable = function () { }) { this.isPresent.call(this, presentRunnable); return this; } /** * remove all affected nodes from this query object from the dom tree */ delete() { this.eachElem((node) => { if (node.parentNode) { node.parentNode.removeChild(node); } }); } querySelectorAll(selector) { // We could merge both methods, but for now this is more readable if (selector.indexOf("/shadow/") != -1) { return this._querySelectorAllDeep(selector); } else { return this._querySelectorAll(selector); } } closest(selector) { // We could merge both methods, but for now this is more readable if (selector.indexOf("/shadow/") != -1) { return this._closestDeep(selector); } else { return this._closest(selector); } } /** * core byId method * @param id the id to search for * @param includeRoot also match the root element? */ byId(id, includeRoot) { let res = []; if (includeRoot) { res = res.concat(...new Es2019Array_1.Es2019Array(...((this === null || this === void 0 ? void 0 : this.rootNode) || [])) .filter(((item) => id == item.id)) .map(item => new DomQuery(item))); } // for some strange kind of reason the # selector fails // on hidden elements we use the attributes match selector // that works res = res.concat(this.querySelectorAll(`[id="${id}"]`)); return new DomQuery(...res); } byIdDeep(id, includeRoot) { let res = []; if (includeRoot) { res = res.concat(new Es2019Array_1.Es2019Array(...((this === null || this === void 0 ? void 0 : this.rootNode) || [])) .filter(item => id == item.id) .map(item => new DomQuery(item))); } let subItems = this.querySelectorAllDeep(`[id="${id}"]`); if (subItems.length) { res.push(subItems); } return new DomQuery(...res); } /** * same as byId just for the tag name * @param tagName the tag-name to search for * @param includeRoot shall the root element be part of this search * @param deep do we also want to go into shadow dom areas */ byTagName(tagName, includeRoot, deep) { var _a; let res = []; if (includeRoot) { res = new Es2019Array_1.Es2019Array(...((_a = this === null || this === void 0 ? void 0 : this.rootNode) !== null && _a !== void 0 ? _a : [])) .filter(element => (element === null || element === void 0 ? void 0 : element.tagName) == tagName) .reduce((reduction, item) => reduction.concat([item]), res); } (deep) ? res.push(this.querySelectorAllDeep(tagName)) : res.push(this.querySelectorAll(tagName)); return new DomQuery(...res); } /** * attr accessor, usage myQuery.attr("class").value = "bla" * or let value myQuery.attr("class").value * @param attr the attribute to set * @param defaultValue the default value in case nothing is presented (defaults to null) */ attr(attr, defaultValue = null) { return new ElementAttribute(this, attr, defaultValue); } style(cssProperty, defaultValue = null) { return new Style(this, cssProperty, defaultValue); } /** * Checks for an existing class in the class attributes * * @param clazz the class to search for */ hasClass(clazz) { let hasIt = false; this.eachElem(node => { hasIt = node.classList.contains(clazz); if (hasIt) { return false; } }); return hasIt; } /** * append