/**
* A dialog box letting the user select an item from a predefined list.
* <p>Part of the XUI module which, for now, has an undocumented API.
*/
export class ItemChooser extends Dialog {
static showChooser(title, items, initialText=null, options=null,
reference=null) {
return new Promise((resolve, reject) => {
let dialog = new ItemChooser(title, items, initialText, options,
resolve);
dialog.open("center", reference);
});
}
constructor(title, items, initialText, options, resolve) {
super({ movable: true, resizable: true,
title: title, closeable: true,
template: ItemChooser.TEMPLATE });
let pane = this.contentPane.firstElementChild;
let fieldPane = pane.firstElementChild;
let cancelButton = fieldPane.firstElementChild;
cancelButton.setAttribute("title", "Cancel");
cancelButton.textContent = StockIcon["cancel"];
cancelButton.onclick = this.cancelAction.bind(this);
let okButton = cancelButton.nextElementSibling;
okButton.setAttribute("title", "OK");
okButton.textContent = StockIcon["ok"];
okButton.onclick = this.okAction.bind(this);
this._field = fieldPane.lastElementChild;
this._list = pane.lastElementChild;
this._list.id = Util.uid();
this._field.setAttribute("for", this._list.id);
this._field.addEventListener("selectionaccepted",
this.onSelectionAccepted.bind(this));
// xui-autocomplete-field and xui-list cannot be configured until they
// are "connected".
this._items = items;
this._initialText = initialText;
this._options = options;
this._resolve = resolve;
}
open(position="center", reference=null) {
super.open(position, reference);
// Now that xui-autocomplete-field and xui-list are "connected",
// we can configure them.
this._field.autofocus = true;
if (this._options !== null) {
for (let opt in this._options) {
let val = this._options[opt];
switch (opt.toLowerCase()) {
case "completionkey":
this._field.completionKey = val;
break;
case "acceptmode":
this._field.acceptMode = val;
break;
case "singleclicktoaccept":
this._field.singleClickToAccept = val;
break;
case "lenienttextchecker":
this._field.lenientTextChecker = val;
break;
case "labelmaker":
this._list.labelMaker = val;
break;
case "htmlrenderer":
this._list.htmlRenderer = val;
break;
case "disabledchecker":
this._list.disabledChecker = val;
break;
case "columns":
{
let len = ItemChooser.countToLength(val);
if (len !== null) {
// Note that unlike the field width, the list
// width is "not flex".
this._field.style.width = len;
}
}
break;
case "rows":
{
let len = ItemChooser.countToLength(val);
if (len !== null) {
this._list.style.height = len;
}
}
break;
default:
console.warn(`ItemChooser: ignoring option "${opt}"`);
break;
}
}
}
this._list.setAll(this._items);
if (this._initialText !== null) {
this._field.text = this._initialText;
}
}
static countToLength(val, mult=1) {
let num = Number.parseInt(val);
if (Number.isNaN(num) || num <= 0) {
return null;
}
return String(mult * num) + "em";
}
onSelectionAccepted(event) {
this.close([ event.xuiAcceptedText,
event.xuiSelectedIndex, event.xuiSelectedItem ]);
}
dialogClosed(result) {
// Close button clicked ==> null result, which is just fine.
this._resolve(result);
}
cancelAction() {
this.close(null);
}
okAction() {
this._field.acceptSelection();
}
}
ItemChooser.TEMPLATE = document.createElement("template");
ItemChooser.TEMPLATE.innerHTML = `
<div class="xui-item-chooser-pane">
<div class="xui-itmchsr-field-pane">
<button type="button"
class="xui-control xui-small-icon xui-itmchsr-cancel"></button>
<button type="button"
class="xui-control xui-small-icon xui-dlg-default-button
xui-itmchsr-ok"></button>
<xui-autocomplete-field class="xui-itmchsr-field"></xui-autocomplete-field>
</div>
<xui-list class="xui-itmchsr-list"></xui-list>
</div>
`;