UNPKG

@aurigma/design-atoms-model

Version:

Design Atoms is a part of Customer's Canvas SDK which allows for manipulating individual design elements through your code.

538 lines 20.1 kB
import { ArgumentException } from "../Exception"; import { Uuid } from "../Product/Uuid"; import { uniq, defaults } from "@aurigma/utils-js"; import Environment from "../Utils/Environment"; import { EqualsOfFloatNumbers } from "../Math/Common"; export { /** @deprecated use from @aurigma/utils-js */ intersection } from "@aurigma/utils-js"; export function mmToPoint(millimeters) { return millimeters * 2.83464567; } ; export function stringEquals(str1, str2, options) { let ignoreCase = false; if (options != null) ignoreCase = typeof options === "boolean" ? options : options.ignoreCase; str1 = ignoreCase ? str1.toLowerCase() : str1; str2 = ignoreCase ? str2.toLowerCase() : str2; return str1 === str2; } export function urlCombine(startUrl, ...urlParts) { let endUrl = urlParts.pop(); if (urlParts.length === 0 && endUrl === "") return startUrl; const separatorChar = "/"; endUrl = endUrl.replace(/^(\/|\s)+/g, ""); startUrl = startUrl.replace(/(\/|\s)+$/g, ""); if (urlParts.length === 0) { return startUrl + separatorChar + endUrl; } else { const trimedArgs = urlParts.map(arg => arg.replace(/^(\/|\s)+/g, "").replace(/(\/|\s)+$/g, "")); return [startUrl, trimedArgs, endUrl].flat().join(separatorChar); } } export function contains(str1, str2) { return str1 != null && str2 != null && str1.toLowerCase().indexOf(str2.toLowerCase()) !== -1; } ; export const equals = (obj1, obj2) => { if (obj1 == null && obj2 == null) return true; if ((obj1 == null && obj2 != null) || (obj1 != null && obj2 == null)) return false; const typeof1 = typeof obj1; const typeof2 = typeof obj2; if (typeof1 !== typeof2) return false; if (typeof1 === "string" || typeof1 === "boolean") return obj1 === obj2; if (typeof1 === "number") return EqualsOfFloatNumbers(obj1, obj2); if (Array.isArray(obj1) && Array.isArray(obj2)) { if (obj1.length !== obj2.length) return false; return arrayEquals(obj1, obj2); } let equalFunc; const obj1equalsReady = obj1; const obj2equalsReady = obj2; if (typeof obj1equalsReady.equals === "function" && typeof obj2equalsReady.equals === "function") { equalFunc = (obj1, obj2) => obj1.equals(obj2); } else { equalFunc = (obj1, obj2) => obj1 == obj2; } return equalFunc(obj1, obj2); }; /** @deprecated use arrayIsEquals from `@aurigma/utils-js/algorithms/array` */ export function arrayEquals(obj1, obj2) { if (obj1 == null && obj2 == null) return true; if (obj1 == null || obj2 == null) return false; if (obj1.length !== obj2.length) return false; return obj1.reduce((result, value, index) => { return result && equals(value, obj2[index]); }, true); } export function arrayReferenceEquals(obj1, obj2) { if ((obj1 === null || obj1 === void 0 ? void 0 : obj1.length) !== (obj2 === null || obj2 === void 0 ? void 0 : obj2.length)) return false; return obj1.reduce((result, value, index) => { return result && value == obj2[index]; }, true); } export function isNullOrEmptyOrWhiteSpace(str) { if (str == null) return true; return str.trim() === ""; } export function capitalize(word) { if (word == null || word.length === 0 || /[A-Z]/.test(word[0])) return word; return word[0].toUpperCase() + word.substr(1); } export function isValidXml(str, fixAmpsEnabled = true) { if (isNullOrEmptyOrWhiteSpace(str) || !str.startsWith("<")) return false; if (fixAmpsEnabled) str = fixAmps(str); const xmlDoc = new DOMParser().parseFromString(`<root>${str}</root>`, "application/xml"); return xmlDoc.querySelector("parsererror") == null; } function fixAmps(str) { if (isNullOrEmptyOrWhiteSpace(str) || !str.startsWith("<")) return str; const strParts = [str]; while (true) { let lastPart = strParts.pop(); let ampIndex = lastPart.indexOf(`&`); if (ampIndex === -1) { strParts.push(lastPart); break; } strParts.push(lastPart.substring(0, ampIndex)); let ampEntity = getAmpEntity(lastPart, ampIndex); if (ampEntity != null) { strParts.push(ampEntity.entity); strParts.push(lastPart.substring(ampIndex + ampEntity.length)); } else { strParts.push("&amp;"); strParts.push(lastPart.substring(ampIndex + 1)); } } return strParts.join(''); } function getAmpEntity(str, index) { let substring4 = str.substring(index, index + 4).toLowerCase(); if (substring4 == "&lt;") return { entity: "&lt;", length: 4 }; else if (substring4 == "&gt;") return { entity: "&gt;", length: 4 }; let substring5 = str.substring(index, index + 5).toLowerCase(); if (substring5 == "&amp;") return { entity: "&amp;", length: 5 }; let substring6 = str.substring(index, index + 6).toLowerCase(); if (substring6 == "&apos;") return { entity: "&apos;", length: 6 }; if (substring6 == "&quot;") return { entity: "&quot;", length: 6 }; let substring7 = str.substring(index, index + 7).toLowerCase(); if (substring7.match(/^&#[\\d]{4};$$/)) { // &#0023; return { entity: substring7, length: 7 }; } let substring8 = str.substring(index, index + 8); if (substring8.toLowerCase().match(/^&#x[\\dabcdef]{4};$/)) // &#x00AB; return { entity: substring8, length: 8 }; return null; } export function getTextFromXml(xmlFormattedText, replaceParagraphString = " ") { const domParser = new DOMParser(); xmlFormattedText = fixAmps(xmlFormattedText); const xmlObject = domParser.parseFromString(`<root>${xmlFormattedText}</root>`, "application/xml"); let parseError = xmlObject.querySelector("parsererror"); if (parseError == null) { for (let br of Array.from(xmlObject.querySelectorAll("br"))) br.textContent = replaceParagraphString; const paragraphArray = Array.from(xmlObject.querySelectorAll("p, li")); if (paragraphArray.length > 1) { const paragraphArrayWithoutLastElement = paragraphArray.filter(p => p != paragraphArray[paragraphArray.length - 1]); for (let el of paragraphArrayWithoutLastElement) { const spaceSpan = document.createElementNS("application/xml", "span"); spaceSpan.textContent = replaceParagraphString; el.appendChild(spaceSpan); } } return xmlObject.querySelector("root").textContent; } else { console.warn(`Bad value xmlObject`, xmlObject, parseError.innerHTML); return escapeXml(xmlFormattedText); } } export function unescapeXml(str) { const stringForParse = `<span>${str}</span>`; if (isValidXml(stringForParse, false)) { const xmlDoc = new DOMParser().parseFromString(stringForParse, "application/xml"); const span = xmlDoc.querySelector("span"); return span.textContent; } else { return str; } } export function escapeXml(str) { const xmlDoc = new DOMParser().parseFromString("<span></span>", "application/xml"); const span = xmlDoc.querySelector("span"); span.textContent = str; let escapedString = (new XMLSerializer()).serializeToString(xmlDoc); escapedString = escapedString.replace("<span>", "").replace("</span>", "").replace("<span/>", "").replace("<span />", ""); return escapedString; } export function stringFormat(str) { var args = Array.prototype.slice.call(arguments); args.splice(0, 1); return str.replace(/\{(\d+)\}/g, (m, n) => args[n]); } export function getCurrentLineInTextArea(element) { const textLines = element.value.split("\n"); const selectionStart = element.selectionStart; let lineInitialPosition = 0; for (let i = 0; i < textLines.length; i++) { if (lineInitialPosition + textLines[i].length >= selectionStart) { return textLines[i]; } lineInitialPosition += textLines[i].length + 1; } } /** @deprecated use native JS array flatten */ export function flatten(nestedCollec) { const flattentArray = []; if (nestedCollec instanceof Array) for (let innerArray of nestedCollec) flattentArray.push(...innerArray); return flattentArray; } export function createCssDataUri(css) { return `data:text/css,${encodeURI(css)}`; } //function and css class are from bootstrap library export function measureScrollbar() { var scrollDiv = document.createElement('div'); scrollDiv.className = 'modal-scrollbar-measure'; document.body.appendChild(scrollDiv); var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth; document.body.removeChild(scrollDiv); return scrollbarWidth; } export function getHiddenElemenHeight(el) { const hiddenElement = el.cloneNode(); document.body.appendChild(hiddenElement); const style = getComputedStyle(hiddenElement); const height = hiddenElement.offsetHeight + parseFloat(style.marginTop) + parseFloat(style.marginBottom); hiddenElement.remove(); return height; } ; /** * @param element Element contains twitter bootstrap dropdown * @param getFocusElement Function returns element to be focused after dropdown expand */ export function enableMoveDropDownFocus(element, getFocusElement) { element.querySelectorAll('[data-toggle="dropdown"]').forEach((element) => { element.parentElement.addEventListener("shown.bs.dropdown", () => { getFocusElement().focus(); }); }); } export function timeout(delay) { if (delay == null) delay = 0; return new Promise(resolve => setTimeout(resolve, delay)); } export const delay = timeout; const objectUniqueIdsMap = new Map(); export function getUniqueId(object) { if (object == null) return null; if (!objectUniqueIdsMap.has(object)) objectUniqueIdsMap.set(object, new Uuid().value); return objectUniqueIdsMap.get(object); } export function getFontNames(text) { const fontNames = []; text = fixAmps(text); if (isValidXml(text, false)) { try { if (text != null) walkNodes(text, ["span", "ol", "ul"], parseSizeableNode); } catch (ex) { console.error("Unexpected exception while parsing item text"); console.error(ex); } } return uniq(fontNames); //#region local funcs function parseSizeableNode(element) { const style = parseXmlStyle(element); if (style != null && style.has("font-name")) fontNames.push(style.get("font-name")); } function parseXmlStyle(element) { const styleAttr = element.attributes.getNamedItem("style"); if (styleAttr == null || styleAttr.value == null) return null; const nodeStyleParts = styleAttr.value.split(";"); const styleMap = new Map(); for (let stylePart of nodeStyleParts) { stylePart = stylePart.trim(); if (stylePart == null || stylePart === "") continue; const content = stylePart.split(":"); const key = content[0].trim(); const value = content[1].trim(); styleMap.set(key, value); } return styleMap; } function walkNodes(gmXml, nodeNames, parseNode) { const xmlDoc = new DOMParser().parseFromString(`<body>${gmXml}</body>`, "application/xml"); let filter = { acceptNode: (node) => { const nodeName = node.nodeName.toLowerCase(); return nodeNames.includes(nodeName) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; } }; if (Environment.IsIE()) filter = makeIeCompatible(filter); // @ts-ignore const walker = document.createTreeWalker(xmlDoc.childNodes[0], NodeFilter.SHOW_ELEMENT, filter, false); while (walker.nextNode()) { const node = walker.currentNode; parseNode(node); } function makeIeCompatible(filter) { // @ts-ignore return filter.acceptNode; } } //#endregion } export function assign(target, sources, options) { options = normalize(options); if (options.ignoreNull) { for (let i = 0; i < sources.length; i++) { const source = structuredClone(sources[i]); //$.extend ignores undefined in the source, but not null removeNulls(source); sources[i] = source; } } return options.deep ? deepExtend(target, ...sources) : Object.assign(target, ...sources); function deepExtend(target, ...sources) { let extendedObj = target; const sourceObj = [...sources]; var merge = function (obj) { for (var prop in obj) { if (obj.hasOwnProperty(prop)) { if (typeof obj[prop] === "object" && extendedObj[prop] != null) { if (typeof extendedObj[prop] === "object") extendedObj[prop] = deepExtend(extendedObj[prop], obj[prop]); else extendedObj = obj[prop]; } else { extendedObj[prop] = obj[prop]; } } } }; for (let i = 0; i < sourceObj.length; i++) { const obj = sourceObj[i]; merge(obj); } return extendedObj; } ; function normalize(op) { if (op == null) op = {}; defaults(op, { deep: false, ignoreNull: true }); return op; } function removeNulls(source) { for (let propName of Object.keys(source)) { const property = source[propName]; if (property === null) { if (source.hasOwnProperty(propName)) delete source[propName]; else source[propName] = undefined; } else if (typeof property === "object") { removeNulls(property); } } } } export function assignProperties(target, propObject) { return assign(target, [propObject], { deep: true }); } export function normalize(paramObject, def) { if (paramObject == null) paramObject = {}; defaults(paramObject, def); return paramObject; } export function toDashedStyle(camleCase) { return camleCase.replace(/([A-Z])/g, (segment) => `-${segment.toLowerCase()}`); } export function getStringEnumValue(enumObject, enumValue) { let propertyNames = Object.getOwnPropertyNames(enumObject); return propertyNames[propertyNames .map(i => enumObject[i].toString().toLowerCase()) .indexOf(enumValue.toLowerCase())]; } export function strToInt(str) { const value = parseInt(str); if (str == null || str === "" || isNaN(value) || !isFinite(value)) return null; return value; } export function localStorageEnabled() { const test = "test"; try { localStorage.setItem(test, test); localStorage.removeItem(test); return true; } catch (e) { return false; } } /** * @deprecated The method should not be used. User ImageUtils.getImageSizeByUrl from design-atoms module. */ export async function getImageSize(imageUrl) { const imgElement = await toImageElement(imageUrl); return { width: imgElement.width, height: imgElement.height }; function toImageElement(url) { return new Promise((resolve) => { const img = new Image(); img.crossOrigin = "anonymous"; img.src = url; img.onload = () => resolve(img); img.onerror = e => resolve(null); return img; }); } } export function stripForJson(obj, omitProperties) { if (omitProperties == null) omitProperties = []; else if (typeof omitProperties === "string") omitProperties = [omitProperties]; const objectKeys = new Set(); let currentObj = obj; while (currentObj && currentObj !== Object.prototype) { Object.getOwnPropertyNames(currentObj).forEach(k => objectKeys.add(k)); currentObj = Object.getPrototypeOf(currentObj); } const allowedKeys = Array.from(objectKeys).filter(key => { if (key === 'constructor') return false; for (let forbiddenPrefix of ["_", "$$"]) if (key.startsWith(forbiddenPrefix)) return false; if (omitProperties.some(p => p === key)) return false; if (typeof obj[key] === "function") return false; return true; }); return allowedKeys.reduce((strippedObject, currentKey) => { strippedObject[currentKey] = obj[currentKey]; return strippedObject; }, {}); } export function isFocused(element, { checkDocumentFocus = false } = {}) { const focused = document.activeElement === element; return focused && (checkDocumentFocus ? document.hasFocus() : true); } export function getExtension(fileName) { const nameParts = fileName.split("."); return nameParts.length > 1 ? nameParts[nameParts.length - 1] : ""; } export function getNameWithoutExtension(fileName) { return fileName.split(".")[0]; } export function applyNullableValue(actual, redefined) { return redefined != null ? redefined : actual; } export function applyUndefinedValue(actual, redefined) { return redefined !== undefined ? redefined : actual; } export function getLastPathSegment(path) { if (isNullOrEmptyOrWhiteSpace(path)) return path; if (!path.includes("/")) return path; const segments = path.split("/"); return segments[segments.length - 1]; } export function parsePercentOrPointValue(point, printAreaSize) { let result = null; if (typeof point === "string" && /%$/.test(point)) { const percent = Number(point.split(/%/)[0]); result = printAreaSize * percent / 100; } else { result = Number(point); } if (typeof result !== "number" || isNaN(result)) throw new ArgumentException(`'${point}' is not a number or percent string`); return result; } export function isString(value) { return Boolean(typeof value === "string" || value instanceof String); } export function isNumber(value) { return typeof value === "number"; } export function isEmpty(value) { if (value == null) { return true; } if (typeof value === 'object') { return Object.keys(value).length === 0; } if (typeof value === 'string' || Array.isArray(value)) { return value.length === 0; } return false; } export function isEqual(a, b) { if (a === b) return true; if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) { return false; } const aKeys = Object.keys(a); const bKeys = Object.keys(b); if (aKeys.length !== bKeys.length) return false; return aKeys.every(key => isEqual(a[key], b[key])); } export const isObject = (value) => value !== null && typeof value === 'object'; //# sourceMappingURL=Utils.js.map