UNPKG

@matthewp/linkedom

Version:

A triple-linked lists based DOM implementation

107 lines (88 loc) 2.36 kB
'use strict'; // https://dom.spec.whatwg.org/#concept-live-range const {END, NEXT, PREV, START} = require('../shared/symbols.js'); const {getEnd, setAdjacent} = require('../shared/utils.js'); const deleteContents = ({[START]: start, [END]: end}, fragment = null) => { setAdjacent(start[PREV], end[NEXT]); do { const after = getEnd(start); const next = after === end ? after : after[NEXT]; if (fragment) fragment.insertBefore(start, fragment[END]); else start.remove(); start = next; } while (start !== end); }; /** * @implements globalThis.Range */ class Range { constructor() { this[START] = null; this[END] = null; this.commonAncestorContainer = null; } /* TODO: this is more complicated than it looks setStart(node, offset) { this[START] = node.childNodes[offset]; } setEnd(node, offset) { this[END] = getEnd(node.childNodes[offset]); } //*/ insertNode(newNode) { this[END].parentNode.insertBefore(newNode, this[START]); } selectNode(node) { this[START] = node; this[END] = getEnd(node); } surroundContents(parentNode) { parentNode.replaceChildren(this.extractContents()); } setStartBefore(node) { this[START] = node; } setStartAfter(node) { this[START] = node.nextSibling; } setEndBefore(node) { this[END] = getEnd(node.previousSibling); } setEndAfter(node) { this[END] = getEnd(node); } cloneContents() { let {[START]: start, [END]: end} = this; const fragment = start.ownerDocument.createDocumentFragment(); while (start !== end) { fragment.insertBefore(start.cloneNode(true), fragment[END]); start = getEnd(start); if (start !== end) start = start[NEXT]; } return fragment; } deleteContents() { deleteContents(this); } extractContents() { const fragment = this[START].ownerDocument.createDocumentFragment(); deleteContents(this, fragment); return fragment; } createContextualFragment(html) { const template = this.commonAncestorContainer.createElement('template'); template.innerHTML = html; this.selectNode(template.content); return template.content; } cloneRange() { const range = new Range; range[START] = this[START]; range[END] = this[END]; return range; } } exports.Range = Range