@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
JavaScript
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("&");
strParts.push(lastPart.substring(ampIndex + 1));
}
}
return strParts.join('');
}
function getAmpEntity(str, index) {
let substring4 = str.substring(index, index + 4).toLowerCase();
if (substring4 == "<")
return { entity: "<", length: 4 };
else if (substring4 == ">")
return { entity: ">", length: 4 };
let substring5 = str.substring(index, index + 5).toLowerCase();
if (substring5 == "&")
return { entity: "&", length: 5 };
let substring6 = str.substring(index, index + 6).toLowerCase();
if (substring6 == "'")
return { entity: "'", length: 6 };
if (substring6 == """)
return { entity: """, length: 6 };
let substring7 = str.substring(index, index + 7).toLowerCase();
if (substring7.match(/^&#[\\d]{4};$$/)) { // 
return { entity: substring7, length: 7 };
}
let substring8 = str.substring(index, index + 8);
if (substring8.toLowerCase().match(/^&#x[\\dabcdef]{4};$/)) // «
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