UNPKG

@tko/provider.mustache

Version:

Interpolate text/node attributes {{ }}

77 lines (76 loc) 2.47 kB
"use strict"; // @tko/provider.mustache 🥊 4.0.0-beta1.6 ESM import { unwrap } from "@tko/observable"; import { Provider } from "@tko/provider"; import { parseInterpolation } from "./mustacheParser"; const DEFAULT_ATTRIBUTE_BINDING_MAP = { value: "value", checked: "checked", class: "css" }; export default class AttributeMustacheProvider extends Provider { get FOR_NODE_TYPES() { return [1]; } constructor(params = {}) { super(params); this.ATTRIBUTES_TO_SKIP = new Set(params.attributesToSkip || ["data-bind"]); this.ATTRIBUTES_BINDING_MAP = params.attributesBindingMap || DEFAULT_ATTRIBUTE_BINDING_MAP; } *attributesToInterpolate(attributes) { for (const attr of Array.from(attributes)) { if (this.ATTRIBUTES_TO_SKIP.has(attr.name)) { continue; } if (attr.specified && attr.value.includes("{{")) { yield attr; } } } nodeHasBindings(node) { return !this.attributesToInterpolate(node.attributes).next().done; } partsTogether(parts, context, node, ...valueToWrite) { if (parts.length > 1) { return parts.map((p) => unwrap(p.asAttr(context, this.globals, node))).join(""); } const part = parts[0].asAttr(context, this.globals); if (valueToWrite.length) { part(valueToWrite[0]); } return part; } attributeBinding(name, parts) { return [name, parts]; } *bindingParts(node, context) { for (const attr of this.attributesToInterpolate(node.attributes)) { const parts = Array.from(parseInterpolation(attr.value)); if (parts.length) { yield this.attributeBinding(attr.name, parts); } } } getPossibleDirectBinding(attrName) { const bindingName = this.ATTRIBUTES_BINDING_MAP[attrName]; return bindingName && this.bindingHandlers.get(attrName); } *bindingObjects(node, context) { for (const [attrName, parts] of this.bindingParts(node, context)) { const bindingForAttribute = this.getPossibleDirectBinding(attrName); const handler = bindingForAttribute ? attrName : `attr.${attrName}`; const accessorFn = bindingForAttribute ? (...v) => this.partsTogether(parts, context, node, ...v) : (...v) => ({ [attrName]: this.partsTogether(parts, context, node, ...v) }); node.removeAttribute(attrName); yield { [handler]: accessorFn }; } } getBindingAccessors(node, context) { return Object.assign({}, ...this.bindingObjects(node, context)); } }