@taiga-ui/cdk
Version:
Base library for creating Angular components and applications using Taiga UI principles regarding of actual visual appearance
117 lines (116 loc) • 5.86 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getStartOffsetOfAttribute = exports.hasElementAttribute = exports.findAttributeOnElementWithAttrs = exports.findAttributeOnElementWithTag = exports.findElementsWithAttributeOnTag = exports.findElementsWithAttribute = exports.findElementsWithDirective = exports.findElementsByTagNames = exports.findElementsByTagName = exports.findElementsInTemplateByFn = exports.findElementsByFn = void 0;
const parse5_1 = require("parse5");
function findElementsByFn(nodes, predicateFn) {
const elements = [];
const visitNodes = (nodes) => {
nodes.forEach((n) => {
const node = n;
if (node.childNodes) {
visitNodes(node.childNodes);
}
if (predicateFn(node)) {
elements.push(node);
}
});
};
visitNodes(nodes);
return elements;
}
exports.findElementsByFn = findElementsByFn;
function findElementsInTemplateByFn(html, predicateFn) {
// utf8 with BOM adds an extra character to the beginning of the string
if (html.charCodeAt(0) === 0xfeff) {
html = html.slice(1);
}
const document = (0, parse5_1.parseFragment)(html, { sourceCodeLocationInfo: true });
return findElementsByFn(document.childNodes, predicateFn);
}
exports.findElementsInTemplateByFn = findElementsInTemplateByFn;
function findElementsByTagName(html, tagName,
// eslint-disable-next-line no-restricted-syntax
filterFn = () => true) {
return findElementsInTemplateByFn(html, (el) => el.tagName === tagName && filterFn(el));
}
exports.findElementsByTagName = findElementsByTagName;
function findElementsByTagNames(html, tagNames) {
return findElementsInTemplateByFn(html, (el) => tagNames.includes(el.tagName));
}
exports.findElementsByTagNames = findElementsByTagNames;
/**
* Parses a HTML fragment and traverses all AST nodes in order find elements that
* include the specified directive as attribute or input.
*/
function findElementsWithDirective(html, attributeName) {
const lowercasedAttrName = attributeName.toLowerCase();
const inputName = `[${lowercasedAttrName}]`;
return findElementsInTemplateByFn(html, (el) => { var _a; return (_a = el.attrs) === null || _a === void 0 ? void 0 : _a.some(({ name }) => name === lowercasedAttrName || name === inputName); });
}
exports.findElementsWithDirective = findElementsWithDirective;
/**
* Parses a HTML fragment and traverses all AST nodes in order find elements that
* include the specified attribute.
*/
function findElementsWithAttribute(html, attributeName) {
return findElementsInTemplateByFn(html, (el) => { var _a; return (_a = el.attrs) === null || _a === void 0 ? void 0 : _a.some((attr) => attr.name === attributeName.toLowerCase()); });
}
exports.findElementsWithAttribute = findElementsWithAttribute;
/**
* Parses a HTML fragment and traverses all AST nodes in order find elements that include the specified attribute and tag name.
* @param html
* @param attributeName
*/
function findElementsWithAttributeOnTag(html, attributeNames, tagNames = [],
// eslint-disable-next-line no-restricted-syntax
filterFn = () => true) {
return findElementsInTemplateByFn(html, (el) => {
var _a;
return (!attributeNames.length ||
((_a = el.attrs) === null || _a === void 0 ? void 0 : _a.some((attr) => attributeNames.map((name) => name.toLowerCase()).includes(attr.name)))) &&
(tagNames.includes(el.tagName) ||
tagNames.includes('*') ||
!tagNames.length) &&
filterFn(el);
});
}
exports.findElementsWithAttributeOnTag = findElementsWithAttributeOnTag;
/**
* Finds elements with explicit tag names that also contain the specified attribute. Returns the
* attribute start offset based on the specified HTML.
*/
function findAttributeOnElementWithTag(html, name, tagNames,
// eslint-disable-next-line no-restricted-syntax
filterFn = () => true) {
return findElementsWithAttribute(html, name)
.filter((element) => (tagNames.includes(element.tagName) || tagNames.includes('*')) &&
filterFn(element))
.map((element) => getStartOffsetOfAttribute(element, name));
}
exports.findAttributeOnElementWithTag = findAttributeOnElementWithTag;
/**
* Finds elements that contain the given attribute and contain at least one of the other
* specified attributes. Returns the primary attribute's start offset based on the specified HTML.
*/
function findAttributeOnElementWithAttrs(html, name, attrs,
// eslint-disable-next-line no-restricted-syntax
filterFn = () => true) {
return findElementsWithAttribute(html, name)
.filter((element) => attrs.some((attr) => hasElementAttribute(element, attr)) &&
filterFn(element))
.map((element) => getStartOffsetOfAttribute(element, name));
}
exports.findAttributeOnElementWithAttrs = findAttributeOnElementWithAttrs;
/** Shorthand function that checks if the specified element contains the given attribute. */
function hasElementAttribute(element, attributeName) {
var _a;
const lowercasedAttrName = attributeName.toLowerCase();
return (_a = element.attrs) === null || _a === void 0 ? void 0 : _a.some((attr) => attr.name === lowercasedAttrName || attr.name === `[${lowercasedAttrName}]`);
}
exports.hasElementAttribute = hasElementAttribute;
/** Gets the start offset of the given attribute from a Parse5 element. */
function getStartOffsetOfAttribute(element, attributeName) {
var _a, _b, _c;
return (((_c = (_b = (_a = element.sourceCodeLocation) === null || _a === void 0 ? void 0 : _a.attrs) === null || _b === void 0 ? void 0 : _b[attributeName.toLowerCase()]) === null || _c === void 0 ? void 0 : _c.startOffset) || 0);
}
exports.getStartOffsetOfAttribute = getStartOffsetOfAttribute;