Source: xxe/part/ClipboardTool.js

/**
 * {@link XMLEditor} part used to display the clipboard content.
 */
class ClipboardTool extends HTMLElement {
    constructor() {
        super();

        this._xmlEditor = null;
        this._source = null;
        this._sourcePopup = null;
        this._onSourcePopupClosed = this.onSourcePopupClosed.bind(this);
        this._plainTextTimeout = null;
    }

    // -----------------------------------------------------------------------
    // Custom element
    // -----------------------------------------------------------------------

    connectedCallback() {
        if (this.firstChild === null) {
            this._button = document.createElement("span");
            this._button.className = "xxe-tool-button xxe-clpbrd-tool-button";
            this._button.setAttribute("title", "Show Clipboard Content");
            this._button.textContent = XUI.StockIcon["clipboard"];
            this.appendChild(this._button);

            this._label = document.createElement("span");
            this._label.className = "xxe-clpbrd-tool-label";
            this.appendChild(this._label);
            
            let handler = this.onClick.bind(this);
            this._button.addEventListener("click", handler);
            this._button.addEventListener("contextmenu", handler);
            this._label.addEventListener("contextmenu", handler);
        }
        // Otherwise, already connected.
    }

    // -----------------------------------------------------------------------
    // Event handlers
    // -----------------------------------------------------------------------

    onClick(event) {
        XUI.Util.consumeEvent(event);
        
        if (this._sourcePopup === null) {
            this._sourcePopup = XUI.Dialogs.open({
                form: this.createSourcePopup(this._source), type: "popup",
                classes:
                "xui-control xui-dialog xxe-tool-popup xxe-clpbrd-tool-src",
                position: "stopmenu", reference: this
            });
            this._sourcePopup.addEventListener("dialogclosed",
                                               this._onSourcePopupClosed);
        } else {
            XUI.Dialogs.close(this._sourcePopup);
        }
    }

    createSourcePopup(source) {
        let pane = document.createElement("pre");
        pane.className =
            "xui-control xxe-tool-popup-list xxe-clpbrd-tool-src-pane";
        pane.style.width =
            String(this.parentElement.getBoundingClientRect().width / 2) + "px";
        
        pane.textContent = (source === null)? "" : source;
        
        return pane;
    }
    
    onSourcePopupClosed(event) {
        this._sourcePopup = null;
        
        if (this._xmlEditor !== null) {
            this._xmlEditor.documentView.requestFocus();
        }
    }
    
    onPaste(event) {
        XUI.Util.consumeEvent(event);
        
        if (this._xmlEditor !== null && this._xmlEditor.documentIsOpened) {
            const pasted = event.clipboardData.getData('text/plain');
            if (pasted !== null && pasted.length > 0) {
                // pasted.startsWith("<?xml") is OK here.
                this._xmlEditor.documentView.sendSetClipboard(pasted);
            }
        }
    }
    
    // -----------------------------------------------------------------------
    // Used by XMLEditor
    // -----------------------------------------------------------------------

    set xmlEditor(editor) {
        assertOrError(editor !== null);
        this._xmlEditor = editor;
        
        editor.clipboardIntegration.getLevel()
            .then((level) => {
                if (level < ClipboardIntegration.CAN_READ_WRITE) {
                    this._button.style.color =
                        (level < ClipboardIntegration.CAN_WRITE)?
                        "orange" : "#F4C430"; /*Saffron*/

                    let toolTip = this._button.getAttribute("title");
                    toolTip += `\n\n\
SYSTEM CLIPBOARD INTEGRATION NOT AVAILABLE\n\
in this browser, therefore this is just a clipboard\n\
which is private to this XML editor.\n\n\
You'll have to paste text (Ctrl-V; \u2318-V on the Mac)\n\
copied from outside this XML editor into the text field\n\
at right to update the content of this private clipboard.`;
                    this._button.setAttribute("title", toolTip);
                    
                    // Focusable but without tab navigation.
                    this._label.setAttribute("tabindex", "-1"); 
                    this._label.addEventListener("paste",
                                                 this.onPaste.bind(this));
                }
            });
    }

    clipboardUpdated(update) {
        if (update !== null) {
            if (!update.label) {
                this.updateLabel("", false, null);
            } else {
                this.updateLabel(update.label, update.inclusion, update.source);
            }
        } else {
            // Otherwise, editing context changed but clipboard not updated
            // OR the document being edited has just been opened or closed.
            
            if (!this._xmlEditor.documentIsOpened) {
                this.updateLabel("", false, null);
            }
        }
    }

    updateLabel(label, readOnly, source) {
        if (this._plainTextTimeout !== null) {
            clearTimeout(this._plainTextTimeout);
            this._plainTextTimeout = null;
        }

        let plainText = null;
        if (label === "#text" && (plainText = source.trim()).length > 0) {
            plainText = plainText.replaceAll(/\s+/g, ' ');
            plainText = XUI.Util.shortenText(plainText, 40);

            this._label.textContent = plainText;
            this._plainTextTimeout = setTimeout(() => {
                this._label.textContent = "#text";
            }, 1000 /*ms*/);
        } else {
            this._label.textContent = label;
        }
        
        if (readOnly) {
            this._label.classList.add("xxe-clpbrd-tool-label-ro");
        } else {
            this._label.classList.remove("xxe-clpbrd-tool-label-ro");
        }
        
        this._source = source;
    }
}

window.customElements.define("xxe-clipboard-tool", ClipboardTool);