@taiga-ui/cdk
Version:
Base library for creating Angular components and applications using Taiga UI principles regarding of actual visual appearance
118 lines • 5.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.findElementsByFn = findElementsByFn;
exports.findElementsInTemplateByFn = findElementsInTemplateByFn;
exports.findElementsByTagName = findElementsByTagName;
exports.findElementsByTagNames = findElementsByTagNames;
exports.findElementsWithDirective = findElementsWithDirective;
exports.findElementsWithAttribute = findElementsWithAttribute;
exports.findElementsWithAttributeOnTag = findElementsWithAttributeOnTag;
exports.findAttributeOnElementWithTag = findAttributeOnElementWithTag;
exports.findAttributeOnElementWithAttrs = findAttributeOnElementWithAttrs;
exports.hasElementAttribute = hasElementAttribute;
exports.hasElementAttributeWithValue = hasElementAttributeWithValue;
exports.getStartOffsetOfAttribute = getStartOffsetOfAttribute;
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;
}
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);
}
function findElementsByTagName(html, tagName, filterFn = () => true) {
return findElementsInTemplateByFn(html, (el) => el.tagName === tagName && filterFn(el));
}
function findElementsByTagNames(html, tagNames) {
return findElementsInTemplateByFn(html, (el) => tagNames.includes(el.tagName));
}
/**
* 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); });
}
/**
* 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()); });
}
/**
* 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 = [], 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);
});
}
/**
* 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, filterFn = () => true) {
return findElementsWithAttribute(html, name)
.filter((element) => (tagNames.includes(element.tagName) || tagNames.includes('*')) &&
filterFn(element))
.map((element) => getStartOffsetOfAttribute(element, name));
}
/**
* 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, filterFn = () => true) {
return findElementsWithAttribute(html, name)
.filter((element) => attrs.some((attr) => hasElementAttribute(element, attr)) &&
filterFn(element))
.map((element) => getStartOffsetOfAttribute(element, name));
}
/** 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}]`);
}
function hasElementAttributeWithValue(element, attributeName, attributeValue) {
var _a;
const lowercasedAttrName = attributeName.toLowerCase();
const lowercasedValue = attributeValue.toLowerCase();
return (_a = element.attrs) === null || _a === void 0 ? void 0 : _a.some((attr) => (attr.name === lowercasedAttrName && attr.value === lowercasedValue) ||
(attr.name === `[${lowercasedAttrName}]` &&
(attr.value === `'${attributeValue}'` ||
attr.value === `"${attributeValue}"`)));
}
/** 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);
}
//# sourceMappingURL=elements.js.map