UNPKG

@binary-constructions/semantic-map

Version:

A markup wrapper for the Leaflet map API

101 lines (85 loc) 3.12 kB
const ELEMENT_PREFIX="semantic-map"; const ATTRIBUTE_PREFIX="data-semantic-map-"; /** * @typedef ASTNode * @type {object} * @property {Node} node The DOM node. * @property {string[]} classes The semantic-map classes of `node`. * @property {object} attributes A dictionary object with the * semantic-map attributes of `node`. The dictionary is indexed by * the attribute names with "data-semantic-map-" stripped. */ /** * @typedef AST * @type {object} * @property {ASTNode|undefined} self The current node. * @property {ASTNode[]|undefined} subs The list of sub nodes. */ /** * Turn `node` and its sub-nodes into an abstract syntax tree that * only contains information relevant for semantic-map. * @param {Node} node The DOM node for which to create the AST. * @returns {ASTNode} The `ASTNode` for `node`. * * This function works recursively. While sub-nodes are only included * in the returned AST if they have either semantic-map specific * classes or attributes (or both), the topmost node always refers to * the argument `node` itself and may have its `self` property be * `undefined`. */ function createAstInner(node, filter) { if (!filter(node)) { return undefined; } const classes = node.classList ? Array.from(node.classList).filter(c => c.startsWith(ELEMENT_PREFIX)) : []; const attributes = node.attributes ? Array.from(node.attributes).filter(a => a.name.startsWith(ATTRIBUTE_PREFIX)).reduce( (as, a) => { let value = node.getAttribute(a.name); if (value !== undefined) { value = value.trim(); if (value !== "") { as[a.name.slice(18)] = value; } else { console.warn("ignoring empty attribute '" + a.name + "'"); } } return as; }, {}) : {}; const subs = []; let sub_node = node.firstChild; while (sub_node) { const sub = createAstInner(sub_node, filter); if (sub) { if (sub.self) { subs.push(sub); } else if (sub.subs) { subs.push(...sub.subs); } } sub_node = sub_node.nextSibling; } return { self: (classes.length || Object.keys(attributes).length) ? { node, classes, attributes } : undefined, subs: subs.length ? subs : undefined }; } /** * Turn `node` and its sub-nodes into a list of abstract * syntax trees that only contains information relevant for * semantic-map. * @param {Node} node The DOM node for which to create the AST. * @param {} filter TODO: document * @returns {ASTNode[]|undefined} A list of all the `ASTNode`s * found for `node`, or `undefined` if none. * * Unlike `createAstInner()` the ASTs returned by this function only * contain nodes with `self` defined. */ export function createAst(node, filter) { const ast = createAstInner(node, filter); return ast.self ? [ ast ] : ast.subs; }