define(["require", "exports", "./domutil", "./selection-mode"], function (require, exports, domutil_1, selection_mode_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    // tslint:disable-next-line:no-http-string
    exports.CLIPBOARD_NS = "http://mangalamresearch.org/ns/wed/clipboard";
    /**
     * An internal clipboard for wed editors.
     *
     * Due to the limitations of the clipboard API, wed maintains an internal
     * clipboard which allows it to transfer data in a way meaningful to wed.
     */
    class Clipboard {
        constructor() {
            this.tree = new DOMParser().parseFromString("<div/>", "text/xml");
            this.top = this.tree.firstElementChild;
            this._mode = selection_mode_1.SelectionMode.SPAN;
        }
        /**
         * The clipboard switches selection mode on the basis of how data is added to
         * it, and the mode remains in effect until data is added in a way that
         * changes the mode.
         *
         * Note that this property is **independent** of what the GUI is showing to
         * the user. The property "remembers", so to speak, how the clipboard has been
         * used.
         */
        get mode() {
            return this._mode;
        }
        /**
         * Sets the selection mode of this clipboard.
         *
         * @param vale The new mode.
         */
        setMode(value) {
            if (value !== this._mode) {
                this.clear();
            }
            this._mode = value;
        }
        /**
         * Clear the clipboard.
         *
         * Note that this clears only the contents of this object. **IT DOES NOT
         * AFFECT THE BROWSER'S CLIPBOARD!**
         */
        clear() {
            // Empty the div.
            // tslint:disable-next-line:no-inner-html
            this.top.innerHTML = "";
        }
        /**
         * Puts a span of nodes into the clipboard. This method switches the clipboard
         * to the span mode.
         *
         * Note that the clipboard is cleared before adding the nodes.
         *
         * @param nodes The nodes to put. These nodes become property of the clipboard
         * after being added. If you want to keep the nodes in another document, clone
         * them first.
         */
        putSpan(span) {
            this.clear();
            this.setMode(selection_mode_1.SelectionMode.SPAN);
            if (typeof span === "string") {
                this.top.textContent = span;
            }
            else {
                const { tree, top } = this;
                for (const node of span) {
                    top.appendChild(tree.adoptNode(node));
                }
            }
        }
        /**
         * Check whether a node can be added to this clipboard's data. Clipboards
         * cannot contain heterogenous data. An attribute can be added only if the
         * clipboard is empty or contains attributes. Another type of node can be
         * added only if the clipboard does not contain attributes.
         *
         * @param node The node to check.
         *
         * @returns Whether the node can be added to this clipboard's data.
         */
        canAddUnit(node) {
            const { top } = this;
            return domutil_1.isAttr(node) ? (top.firstElementChild === null ||
                containsClipboardAttributeCollection(top)) :
                !containsClipboardAttributeCollection(top);
        }
        /**
         * Puts a DOM node in the clipboard. This method switches the clipboard to
         * unit mode.
         *
         * Note that the clipboard is cleared before adding the node.
         *
         * @param node The node to put. This node becomes property of the clipboard
         * after being added. If you want to keep it in another document, clone it
         * first.
         *
         * @param add Add to the clipboard, rather than replace the contents.
         */
        putUnit(node, add) {
            this.setMode(selection_mode_1.SelectionMode.UNIT);
            const { top } = this;
            if (domutil_1.isAttr(node)) {
                let collection;
                if (add && containsClipboardAttributeCollection(top)) {
                    collection = top.firstElementChild;
                }
                else {
                    // In order to record a collection of attributes, we set the tree to
                    // contain a single element on which we set the attributes we want to
                    // move around.
                    this.clear();
                    collection =
                        top.ownerDocument.createElementNS(exports.CLIPBOARD_NS, "wed:attributes");
                    top.appendChild(collection);
                }
                collection.setAttributeNode(node);
            }
            else {
                if (!add || containsClipboardAttributeCollection(top)) {
                    this.clear();
                }
                top.appendChild(this.tree.adoptNode(node));
            }
        }
        /**
         * Determines whether, in a paste operation, the tree that is stored in this
         * clipboard, serialized, is equal to some text.
         *
         * This can be used as an optimization to avoid parsing anew ``text`` if the
         * tree in the clipboard is already a parsed representation of that text.
         *
         * @param text The text to test against.
         */
        isSerializedTree(text) {
            return this.top.innerHTML === text;
        }
        /**
         * @returns A deep copy of the tree in this clipboard.
         */
        cloneTree() {
            return this.top.cloneNode(true);
        }
        /**
         * Set the DOM clipboard data to reflect what is stored in this wed-internal
         * clipboard. Note that any old data in the DOM clipboard data is cleared
         * before setting the new data.
         *
         * @param clipboardData The object to set.
         */
        setupDOMClipboardData(clipboardData) {
            const { top } = this;
            clipboardData.clearData();
            clipboardData.setData("text/plain", top.textContent);
            clipboardData.setData("text/xml", top.innerHTML);
        }
    }
    exports.Clipboard = Clipboard;
    /**
     * Check whether the element has a single child element which is a collection of
     * attributes.
     *
     * @param el The element to check.
     *
     * @returns Whether the element contains an attribute collection.
     */
    function containsClipboardAttributeCollection(el) {
        const first = el.firstElementChild;
        return el.childNodes.length === 1 && first !== null &&
            first.namespaceURI === exports.CLIPBOARD_NS && first.localName === "attributes";
    }
    exports.containsClipboardAttributeCollection = containsClipboardAttributeCollection;
});
//# sourceMappingURL=clipboard.js.map