// Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. import { Widget } from '@phosphor/widgets'; import { Dialog } from './dialog'; import { Styling } from './styling'; const INPUT_DIALOG_CLASS = 'jp-Input-Dialog'; /** * Create and show a input dialog for a number. * * @param options - The dialog setup options. * * @returns A promise that resolves with whether the dialog was accepted */ export function getNumber( options: InputDialog.INumberOptions ): Promise> { let dialog = new Dialog({ ...options, body: new InputNumberDialog(options) }); return dialog.launch(); } /** * Create and show a input dialog for a choice. * * @param options - The dialog setup options. * * @returns A promise that resolves with whether the dialog was accepted */ export function getItem( options: InputDialog.IItemOptions ): Promise> { let dialog = new Dialog({ ...options, body: new InputItemsDialog(options) }); return dialog.launch(); } /** * Create and show a input dialog for a text. * * @param options - The dialog setup options. * * @returns A promise that resolves with whether the dialog was accepted */ export function getText( options: InputDialog.ITextOptions ): Promise> { let dialog = new Dialog({ ...options, body: new InputTextDialog(options) }); return dialog.launch(); } export namespace InputDialog { export interface IOptions extends Partial< Pick< Dialog.IOptions, Exclude, 'body' | 'buttons' | 'defaultButton'> > > { /** * Label of the requested input */ label: string; } export interface INumberOptions extends IOptions { /** * Default value */ value?: number; } export interface IItemOptions extends IOptions { /** * List of choices */ items: Array; /** * Default choice * * If the list is editable a string with a default value can be provided * otherwise the index of the default choice should be given. */ current?: number | string; /** * Is the item editable? */ editable?: boolean; /** * Placeholder text for editable input */ placeholder?: string; } export interface ITextOptions extends IOptions { /** * Default input text */ text?: string; /** * Placeholder text */ placeholder?: string; } } /** * Base widget for input dialog body */ class InputDialog extends Widget implements Dialog.IBodyWidget { /** * InputDialog constructor * * @param label Input field label */ constructor(label: string) { super(); this.addClass(INPUT_DIALOG_CLASS); let labelElement = document.createElement('label'); labelElement.textContent = label; // Initialize the node this.node.appendChild(labelElement); } /** Input HTML node */ protected _input: HTMLInputElement; } /** * Widget body for input number dialog */ class InputNumberDialog extends InputDialog { /** * InputNumberDialog constructor * * @param options Constructor options */ constructor(options: InputDialog.INumberOptions) { super(options.label); this._input = document.createElement('input', {}); this._input.classList.add('jp-mod-styled'); this._input.type = 'number'; this._input.value = options.value ? options.value.toString() : '0'; // Initialize the node this.node.appendChild(this._input); } /** * Get the number specified by the user. */ getValue(): number { if (this._input.value) { return Number(this._input.value); } else { return Number.NaN; } } } /** * Widget body for input text dialog */ class InputTextDialog extends InputDialog { /** * InputTextDialog constructor * * @param options Constructor options */ constructor(options: InputDialog.ITextOptions) { super(options.label); this._input = document.createElement('input', {}); this._input.classList.add('jp-mod-styled'); this._input.type = 'text'; this._input.value = options.text ? options.text : ''; if (options.placeholder) { this._input.placeholder = options.placeholder; } // Initialize the node this.node.appendChild(this._input); } /** * Get the text specified by the user */ getValue(): string { return this._input.value; } } /** * Widget body for input list dialog */ class InputItemsDialog extends InputDialog { /** * InputItemsDialog constructor * * @param options Constructor options */ constructor(options: InputDialog.IItemOptions) { super(options.label); this._editable = options.editable || false; let current = options.current || 0; let defaultIndex: number; if (typeof current === 'number') { defaultIndex = Math.max(0, Math.min(current, options.items.length - 1)); current = ''; } this._list = document.createElement('select'); options.items.forEach((item, index) => { let option = document.createElement('option'); if (index === defaultIndex) { option.selected = true; current = item; } option.value = item; option.textContent = item; this._list.appendChild(option); }); if (options.editable) { /* Use of list and datalist */ let data = document.createElement('datalist'); data.id = 'input-dialog-items'; data.appendChild(this._list); this._input = document.createElement('input', {}); this._input.classList.add('jp-mod-styled'); this._input.type = 'list'; this._input.value = current; this._input.setAttribute('list', data.id); if (options.placeholder) { this._input.placeholder = options.placeholder; } this.node.appendChild(this._input); this.node.appendChild(data); } else { /* Use select directly */ this.node.appendChild(Styling.wrapSelect(this._list)); } } /** * Get the user choice */ getValue(): string { if (this._editable) { return this._input.value; } else { return this._list.value; } } private _list: HTMLSelectElement; private _editable: boolean; }