# Source: Prompt.js

    /**
     * A prompt dialog box.
     * <p>Part of the XUI module which, for now, has an undocumented API.
     */
    export class Prompt extends Dialog {
        static showPrompt(title, prompt,
                          columns=40, initialValue=null,
                          valueList=null, inputValueChecker=null,
                          reference=null) {
            return Prompt.prompt({ title: title,
                                   prompt: prompt,
                                   columns: columns,
                                   initialValue: initialValue,
                                   valueList: valueList,
                                   inputValueChecker: inputValueChecker },
                                 reference);
        }

        static prompt(options, reference) {
            return new Promise((resolve, reject) => {
                let dialog = new Prompt(options, resolve);
                dialog.open("center", reference);
            });
        }

        constructor(options, resolve) {
            const opts = Object.assign({
                title: "???",
                prompt: "???",
                hint: null,
                columns: 40,
                initialValue: null,
                valueList: null,
                inputValueChecker: null
            }, options);

            super({ movable: true, title: opts.title, closeable: true,
                    template: Prompt.TEMPLATE,
                    buttons: [ { label: "Cancel", action: "cancelAction" },
                               { label: "OK", action: "okAction",
                                 default: true } ]});

            this._resolve = resolve;

            let pane = this.contentPane.firstElementChild;
            let icon = pane.firstElementChild;
            icon.textContent = StockIcon["question"];

            let form = pane.lastElementChild;
            let question = form.firstElementChild;
            question.innerHTML = Prompt.textToHTML(opts.prompt);

            this._input = question.nextElementSibling;
            if (opts.columns < 10) {
                opts.columns = 10;
            }
            this._input.size = opts.columns;

            let hint = form.lastElementChild;
            if (opts.hint) {
                hint.innerHTML = Prompt.textToHTML(opts.hint);
            } else {
                hint.style.display = "none";
            }

            if (opts.initialValue !== null) {
                this._input.value = opts.initialValue;
                this.selectInputValue();
            }

            this._input.autocomplete = "off";
            if (opts.valueList !== null && Array.isArray(opts.valueList) &&
                opts.valueList.length > 0) {
                let allValues = [];
                for (let value of opts.valueList) {
                    value = value.toString().trim();
                    if (value.length > 0) {
                        allValues.push(value);
                    }
                }

                if (allValues.length > 0) {
                    // valueList is assumed to have been sorted by client code.
                    // (This may be easily done using valueList.sort().)

                    let datalistId = Util.uid();
                    Util.appendDatalist(datalistId, allValues, form);
                    this._input.setAttribute("list", datalistId);
                }
            }

            this._checkInputValue = opts.inputValueChecker;

            this._input.addEventListener("keydown", (e) => {
                if (e.key === "Enter") {
                    Util.consumeEvent(e);

                    this.okAction();
                }
            });
        }

        static textToHTML(text) {
            if (text.startsWith("<html>")) {
                text = text.substring(6);
            } else {
                text = Util.escapeHTML(text);
                if (text.indexOf('\n') >= 0) {
                    text = text.replaceAll('\n', "<br>");
                }
            }
            return text;
        }

        dialogClosed(result) {
            // Close button clicked ==> null result, which is just fine.
            this._resolve(result);
        }

        cancelAction() {
            this.close(null);
        }

        okAction() {
            let inputValue = this.getInputValue();
            if (this._checkInputValue !== null) {
                // checkInputValue may or may not accept null.
                if (!this._checkInputValue(inputValue)) {
                    this.selectInputValue();
                    return;
                }
            }

            this.close(inputValue);
        }

        // -----------------------------------
        // Validation helpers
        // -----------------------------------

        getInputValue() {
            let result = this._input.value;
            if (result !== null && (result = result.trim()).length === 0) {
                result = null;
            }
            return result;
        }

        selectInputValue() {
            this._input.focus();
            this._input.select();
        }
    }

    Prompt.TEMPLATE = document.createElement("template");
    Prompt.TEMPLATE.innerHTML = `
    <div class="xui-prompt-pane">
      <div class="xui-prompt-icon"></div>
      <div class="xui-prompt-form">
        <div class="xui-prompt-question"></div>
        <input class="xui-prompt-input" type="text" spellcheck="false" />
        <div class="xui-prompt-hint"></div>
      </div>
    </div>
    `;