UNPKG

@surface/custom-element

Version:

Provides support of directives and data binding on custom elements.

78 lines (77 loc) 2.56 kB
import { enumerateRange } from "../common.js"; import { disposeTree } from "../singletons.js"; const BLOCKS = Symbol("custom-element:block"); export default class Block { constructor() { this.disposed = false; this.start = document.createComment("#start"); this.end = document.createComment("#end"); this.start[BLOCKS] = new Set([this]); this.end[BLOCKS] = new Set([this]); } isAnchor(node) { return !!node[BLOCKS]; } optimize() { const hasNestedDirective = this.start.nextSibling && this.start.nextSibling != this.end && this.isAnchor(this.start.nextSibling) && this.end.previousSibling && this.end.previousSibling != this.start && this.isAnchor(this.end.previousSibling); if (hasNestedDirective) { const nextOpen = this.start.nextSibling; const previousClose = this.end.previousSibling; const open = this.start; const close = this.end; for (const block of open[BLOCKS].values()) { block.start = nextOpen; nextOpen[BLOCKS].add(block); } for (const block of close[BLOCKS].values()) { block.end = previousClose; previousClose[BLOCKS].add(block); } open.remove(); close.remove(); } } connect(node) { node.appendChild(this.start); node.appendChild(this.end); } clear() { for (const element of enumerateRange(this.start, this.end)) { element.remove(); disposeTree(element); } } dispose() { if (!this.disposed) { this.clear(); if (this.start[BLOCKS].size == 1) { this.start.remove(); } else { this.start[BLOCKS].delete(this); } if (this.end[BLOCKS].size == 1) { this.end.remove(); } else { this.end[BLOCKS].delete(this); } this.disposed = true; } } insertAt(parent, reference) { parent.replaceChild(this.end, reference); parent.insertBefore(this.start, this.end); } setContent(content, optimize = true) { this.end.parentNode.insertBefore(content, this.end); if (optimize) { this.optimize(); } } }