| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 | import { ElementType } from "domelementtype";import { Element, Text, Comment, CDATA, Document, ProcessingInstruction, } from "./node.js";export * from "./node.js";// Default optionsconst defaultOpts = {    withStartIndices: false,    withEndIndices: false,    xmlMode: false,};export class DomHandler {    /**     * @param callback Called once parsing has completed.     * @param options Settings for the handler.     * @param elementCB Callback whenever a tag is closed.     */    constructor(callback, options, elementCB) {        /** The elements of the DOM */        this.dom = [];        /** The root element for the DOM */        this.root = new Document(this.dom);        /** Indicated whether parsing has been completed. */        this.done = false;        /** Stack of open tags. */        this.tagStack = [this.root];        /** A data node that is still being written to. */        this.lastNode = null;        /** Reference to the parser instance. Used for location information. */        this.parser = null;        // Make it possible to skip arguments, for backwards-compatibility        if (typeof options === "function") {            elementCB = options;            options = defaultOpts;        }        if (typeof callback === "object") {            options = callback;            callback = undefined;        }        this.callback = callback !== null && callback !== void 0 ? callback : null;        this.options = options !== null && options !== void 0 ? options : defaultOpts;        this.elementCB = elementCB !== null && elementCB !== void 0 ? elementCB : null;    }    onparserinit(parser) {        this.parser = parser;    }    // Resets the handler back to starting state    onreset() {        this.dom = [];        this.root = new Document(this.dom);        this.done = false;        this.tagStack = [this.root];        this.lastNode = null;        this.parser = null;    }    // Signals the handler that parsing is done    onend() {        if (this.done)            return;        this.done = true;        this.parser = null;        this.handleCallback(null);    }    onerror(error) {        this.handleCallback(error);    }    onclosetag() {        this.lastNode = null;        const elem = this.tagStack.pop();        if (this.options.withEndIndices) {            elem.endIndex = this.parser.endIndex;        }        if (this.elementCB)            this.elementCB(elem);    }    onopentag(name, attribs) {        const type = this.options.xmlMode ? ElementType.Tag : undefined;        const element = new Element(name, attribs, undefined, type);        this.addNode(element);        this.tagStack.push(element);    }    ontext(data) {        const { lastNode } = this;        if (lastNode && lastNode.type === ElementType.Text) {            lastNode.data += data;            if (this.options.withEndIndices) {                lastNode.endIndex = this.parser.endIndex;            }        }        else {            const node = new Text(data);            this.addNode(node);            this.lastNode = node;        }    }    oncomment(data) {        if (this.lastNode && this.lastNode.type === ElementType.Comment) {            this.lastNode.data += data;            return;        }        const node = new Comment(data);        this.addNode(node);        this.lastNode = node;    }    oncommentend() {        this.lastNode = null;    }    oncdatastart() {        const text = new Text("");        const node = new CDATA([text]);        this.addNode(node);        text.parent = node;        this.lastNode = text;    }    oncdataend() {        this.lastNode = null;    }    onprocessinginstruction(name, data) {        const node = new ProcessingInstruction(name, data);        this.addNode(node);    }    handleCallback(error) {        if (typeof this.callback === "function") {            this.callback(error, this.dom);        }        else if (error) {            throw error;        }    }    addNode(node) {        const parent = this.tagStack[this.tagStack.length - 1];        const previousSibling = parent.children[parent.children.length - 1];        if (this.options.withStartIndices) {            node.startIndex = this.parser.startIndex;        }        if (this.options.withEndIndices) {            node.endIndex = this.parser.endIndex;        }        parent.children.push(node);        if (previousSibling) {            node.prev = previousSibling;            previousSibling.next = node;        }        node.parent = parent;        this.lastNode = null;    }}export default DomHandler;
 |