util-dom/lib/index.js

"use strict";
/**
 * @module util-dom
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.getNearestSelectorPath = exports.isSelectorElementPresent = exports.insertStyle = exports.injectScript = exports.insertLink = exports.isDynamicClass = exports.isDynamicId = void 0;
/**
 * @file All dom related utilities
 */
const util_promise_1 = require("@softvar/util-promise");
/**
 * Checks wthether the input value matches the dynamic id criteria
 * @since 0.0.2
 * @param {string} identifier - input value
 * @example
 * // returns true
 * isDynamicId('myDiv-aaa_1234');
 * @returns {boolean}
 */
function isDynamicId(identifier) {
    // xyz_2535 xyz-35353 xyz3536
    // xyz_252a xyz-3536af
    const reDynamicId1 = /[a-z]+[_-][0-9a-f_-]{2,}/gi;
    // abcd22
    const reDynamicId2 = /[0-9a-f]{5,}/gi;
    return reDynamicId1.test(identifier) || reDynamicId2.test(identifier);
}
exports.isDynamicId = isDynamicId;
/**
 * Checks wthether the input value matches the dynamic id criteria
 * @since 0.0.2
 * @param {string} identifier - input value
 * @example
 * // return true
 * isDynamicClass('myDiv-aaa_1234');
 * @returns {boolean}
 */
function isDynamicClass(identifier) {
    // wrapper-6_3547
    const reDynamicClass1 = /[a-z]+[_-][0-9_-]{4,}/gi;
    return reDynamicClass1.test(identifier);
}
exports.isDynamicClass = isDynamicClass;
/**
 * Insert link tag to the document at the specified position
 * @since 0.0.5
 * @param {string} href
 * @param {string} [position=head] where link tag needs to be appended
 * @example
 * // return Promise
 * insertLink('https://example.example').then(() => console.log(`Appended`))
 *
 * // returns Promise
 * insertLink('https://example.example', 'body').then(() => console.log(`Appended`))
 * @returns {Promise}
 */
exports.insertLink = (href, position = 'head') => {
    var _a;
    const d = new util_promise_1.deferred();
    const link = document.createElement('link');
    link.href = href;
    link.rel = 'stylesheet';
    link.onload = () => {
        d.resolve();
    };
    link.onerror = () => {
        d.reject();
    };
    (_a = document.getElementsByTagName(position)[0]) === null || _a === void 0 ? void 0 : _a.appendChild(link);
    return d.promise;
};
/**
 * inject Script tag to the document at the specified position
 * @since 0.0.5
 * @param {string} src
 * @param {string} [position=head] where Script tag needs to be appended
 * @param {object} [config={}] configuration options
 * @param {object} [config.html] innerHTML of the script tag if src is not provided
 * @param {object} [config.id=StringiedRandomNumber] id of the script tag
 * @example
 * // return Promise
 * injectScript('https://example.example'. 'body').then(src => console.log(`Appended ${src}`))
 *
 * // returns Promise
 * injectScript('https://example.example', '#my-elm-id').then(src => console.log(`Appended ${src}`))
 * // returns Promise
 * injectScript(null, '#my-elm-id', {html: `<a href="">Example</a>`}).then(src => console.log(`Appended ${src}`))
 * @returns {Promise}
 */
exports.injectScript = (src, targetElem, config = { id: Math.random().toString() }) => {
    var _a;
    const d = new util_promise_1.deferred();
    const domElm = document.createElement('script');
    domElm.type = 'text/javascript';
    domElm.id = config.id;
    if (src) {
        domElm.src = src;
        domElm.onload = () => {
            d.resolve(src);
        };
        domElm.onerror = () => {
            d.reject(src);
        };
    }
    else if (config.html) {
        domElm.innerHTML = config.html;
        d.resolve(config.html);
    }
    if (document.querySelector(targetElem)) {
        (_a = document.querySelector(targetElem)) === null || _a === void 0 ? void 0 : _a.appendChild(domElm);
    }
    else {
        document.body.appendChild(domElm);
    }
    return d.promise;
};
/**
 * Insert style tag to the document at the specified position
 * @since 0.0.5
 * @param {string} content
 * @param {string} [position=head] where style tag needs to be appended
 * @example
 * // return Promise
 * insertStyle(`a{color:red;}`).then(() => console.log(`Appended`))
 *
 * // returns Promise
 * insertStyle(`a{color:red;}`, 'body').then(() => console.log(`Appended`))
 * @returns {Promise}
 */
exports.insertStyle = (content, position = 'head') => {
    var _a;
    const d = new util_promise_1.deferred();
    const style = document.createElement('style');
    style.innerHTML = content;
    style.onload = () => {
        d.resolve();
    };
    style.onerror = () => {
        d.reject();
    };
    (_a = document.getElementsByTagName(position)[0]) === null || _a === void 0 ? void 0 : _a.appendChild(style);
    return d.promise;
};
/**
 * Checks if the element having the specified path exists
 * @since 0.0.5
 * @param {string} path selector of an element
 * @example
 * // returns true
 * isSelectorElementPresent('body');
 * // returns false
 * isSelectorElementPresent('unknown-selector');
 * @returns {boolean}
 */
function isSelectorElementPresent(path) {
    try {
        return document.querySelectorAll(path).length === 1;
    }
    catch (e) {
        return false;
    }
}
exports.isSelectorElementPresent = isSelectorElementPresent;
/**
 * Gives the nearest(shorter) selector path for the specified Node element
 * @param {*} node - HTML Node
 * @example
 * // returns my-id
 * getNearestSelectorPath(document.querySelector('#my-id'));
 * // returns '.flex-column.mb-2.mb-md-0.mr-0.pr-md-4 > h5:nth-of-type(1)'
 * getNearestSelectorPath($0); // some arbitary DOM element
 * @returns {string} nearest/short selector path
 */
function getNearestSelectorPath(node) {
    if (!node) {
        return '';
    }
    const nodeName = node.nodeName.toLowerCase();
    if (nodeName === 'body' || nodeName === 'head' || nodeName === 'html') {
        return nodeName;
    }
    // do not use ids for elements that do not get rendered
    const id = node.getAttribute('id');
    if (id &&
        !/base|link|meta|style|iframe|script|noscript/gi.test(node.nodeName) &&
        !isDynamicId(id) &&
        isSelectorElementPresent('#' + id)) {
        return `#${id}`;
    }
    if (node.hasAttribute('class')) {
        const classNames = node.getAttribute('class').split(/\s+/);
        for (const className of classNames) {
            if (isSelectorElementPresent('.' + className) && !isDynamicClass(className)) {
                return `.${className}`;
            }
        }
        for (const className of classNames) {
            if (isSelectorElementPresent('.' + className) && !isDynamicClass(className)) {
                return `${nodeName}.${className}`;
            }
        }
        if (classNames.length && isSelectorElementPresent('.' + classNames.join('.')) && !isDynamicClass(classNames.join('.'))) {
            return `.${classNames.join('.')}`;
        }
    }
    const parentPath = getNearestSelectorPath(node.parentNode);
    let index = 0;
    for (let iterator = node; iterator; iterator = iterator.previousSibling) {
        if (node.nodeName === iterator.nodeName) {
            index++;
        }
    }
    return `${parentPath} > ${nodeName}:nth-of-type(${index})`;
}
exports.getNearestSelectorPath = getNearestSelectorPath;
//# sourceMappingURL=index.js.map