Source: app/NewDocumentDialog.js

/**
 * Dialog displayed by the <b>New</b>|<b>New Local Document</b> menu item of 
 * {@link XMLEditorApp}.
 * <p>Just like {@link XMLEditorApp.newRemoteFile}, this class may be used 
 * independently from <code>XMLEditorApp</code>.
 */
export class NewDocumentDialog extends XUI.Dialog {
    static showDialog(xmlEditor) {
        return new Promise((resolve, reject) => { 
            let dialog = new NewDocumentDialog(xmlEditor, resolve);
            dialog.open("center", xmlEditor);
        });
    }
    
    constructor(xmlEditor, resolve) {
        super({ title: "New Document",
                movable: true, resizable: true, closeable: true,
                template: NewDocumentDialog.TEMPLATE,
                buttons: [ { label: "Cancel", action: "cancelAction" },
                           { label: "OK", action: "okAction",
                             default: true } ]});

        this._xmlEditor = xmlEditor;
        this._resolve = resolve;
        
        let content = this.contentPane.firstElementChild;
        this._lists = content.lastElementChild.lastElementChild;
        
        this._templateSelected = this.templateSelected.bind(this);
        this._templateAccepted = this.templateAccepted.bind(this);
        
        // ---

        this.initLists();
    }

    templateSelected(event) {
        XUI.Util.consumeEvent(event);

        let item = this._lists.querySelector(".xxe-newdoc-selected");
        if (item !== null) {
            item.classList.remove("xxe-newdoc-selected");
        }
        
        event.target.classList.add("xxe-newdoc-selected");
    }
    
    templateAccepted(event) {
        XUI.Util.consumeEvent(event);
                
        this.okAction();
    }
    
    initLists() {
        // No need to focus this._lists. It's not keyboard enabled.
        
        return this._xmlEditor.listDocumentTemplates()
            .then((templateLists) => {
                      this.setLists(templateLists);
                      return true;
                  },
                  (error) => {
                      XUI.Alert.showError(
                          `Cannot list document templates:\n${error}`,
                          this._xmlEditor);
                      return false;
                  });
    }
    
    setLists(templateLists) {
        XUI.Util.removeAllChildren(this._lists);
        for (let item of templateLists) {
            this.appendList(item, /*categories*/ null, this._lists);
        }
    }

    appendList(item, categories, parent) {
        if (typeof item === "string") {
            let div = document.createElement("div");
            div.setAttribute("class", "xxe-newdoc-template");
            if (categories !== null) {
                div.setAttribute("data-category", categories);
            }
            div.textContent = item;
            parent.appendChild(div);

            div.onclick = this._templateSelected;
            div.ondblclick = this._templateAccepted;
        } else { // Array.
            let category = item.shift();
            let expanded = false;
            if (category.startsWith('+')) {
                expanded = true;
            }
            // Otherwise, starts with '-'.
            category = category.substring(1);

            let details = document.createElement("details");
            details.setAttribute("class", "xxe-newdoc-category");
            if (expanded) {
                details.setAttribute("open", "open");
            }
            parent.appendChild(details);
            
            let summary = document.createElement("summary");
            summary.textContent = category;
            details.appendChild(summary);

            let categories2 = (categories === null)? category :
                (categories + "/" + category);
            for (let subitem of item) {
                this.appendList(subitem, categories2, details);
            }
        }
    }
    
    dialogClosed(result) {
        // Close button clicked ==> null result, which is just fine.
        this._resolve(result);
    }
    
    cancelAction() {
        this.close(null);
    }
    
    okAction() {
        let item = this._lists.querySelector(".xxe-newdoc-selected");
        if (item === null) {
            return;
        }
        let category = item.getAttribute("data-category");
        let template = item.textContent;
        
        this.close([category, template]);
    }
}

NewDocumentDialog.TEMPLATE = document.createElement("template");
NewDocumentDialog.TEMPLATE.innerHTML = `
<div class="xxe-newdoc-content">
  <div class="xxe-newdoc-icon xui-newDocument-32"></div>
  <div class="xxe-newdoc-pane">
    <div class="xxe-newdoc-label">Document templates:</div>
    <div class="xxe-newdoc-lists" tabindex="0"></div>
  </div>
</div>
`;