UNPKG

chrome-devtools-frontend

Version:
129 lines (113 loc) 4.43 kB
// Copyright 2020 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import * as Diff from '../../../../third_party/diff/diff.js'; import * as UI from '../../legacy.js'; import {Events as FilteredListWidgetEvents, FilteredListWidget, Provider} from './FilteredListWidget.js'; export interface QuickPickItem { label: string; description?: string; detail?: string; } export interface QuickPickOptions { placeHolder: string; matchOnDescription?: boolean; matchOnDetail?: boolean; } export class QuickPick { private constructor() { throw new ReferenceError('Instance type not implemented.'); } static show(items: QuickPickItem[], options: QuickPickOptions): Promise<QuickPickItem|void> { let canceledPromise = new Promise<void>(_r => {}); // Intentionally creates an unresolved promise const fulfilledPromise = new Promise<QuickPickItem>(resolve => { const provider = new QuickPickProvider(items, resolve, options.matchOnDescription ? 0.5 : 0, options.matchOnDetail ? 0.25 : 0); const widget = new FilteredListWidget(provider); widget.setHintElement(options.placeHolder); widget.setPromptTitle(options.placeHolder); widget.showAsDialog(options.placeHolder); canceledPromise = widget.once(FilteredListWidgetEvents.Hidden); widget.setQuery(''); }); return Promise.race([fulfilledPromise, canceledPromise]).then(values => { // If it was fulfilled, then `result` will have a value. // If it was canceled, then `result` will be undefined. // Either way, it has the value that we want. return values; }); } } class QuickPickProvider extends Provider { private readonly resolve: Function; private readonly items: QuickPickItem[]; private matchOnDescription: number; private matchOnDetail: number; constructor( items: QuickPickItem[], resolve: Function, matchOnDescription: number|undefined = 0.5, matchOnDetail: number|undefined = 0.25) { super(); this.resolve = resolve; this.items = items; this.matchOnDescription = matchOnDescription; this.matchOnDetail = matchOnDetail; } itemCount(): number { return this.items.length; } itemKeyAt(itemIndex: number): string { const item = this.items[itemIndex]; let key = item.label; if (this.matchOnDescription) { key += ' ' + item.description; } if (this.matchOnDetail) { key += ' ' + item.detail; } return key; } itemScoreAt(itemIndex: number, query: string): number { const item = this.items[itemIndex]; const test = query.toLowerCase(); let score = Diff.Diff.DiffWrapper.characterScore(test, item.label.toLowerCase()); if (this.matchOnDescription && item.description) { const descriptionScore = Diff.Diff.DiffWrapper.characterScore(test, item.description.toLowerCase()); score += descriptionScore * this.matchOnDescription; } if (this.matchOnDetail && item.detail) { const detailScore = Diff.Diff.DiffWrapper.characterScore(test, item.detail.toLowerCase()); score += detailScore * this.matchOnDetail; } return score; } renderItem(itemIndex: number, query: string, titleElement: Element, subtitleElement: Element): void { const item = this.items[itemIndex]; titleElement.removeChildren(); const labelElement = titleElement.createChild('span'); UI.UIUtils.createTextChild(labelElement, item.label); FilteredListWidget.highlightRanges(titleElement, query, true); if (item.description) { const descriptionElement = titleElement.createChild('span', 'quickpick-description'); UI.UIUtils.createTextChild(descriptionElement, item.description); if (this.matchOnDescription) { FilteredListWidget.highlightRanges(descriptionElement, query, true); } } if (item.detail) { UI.UIUtils.createTextChild(subtitleElement, item.detail); if (this.matchOnDetail) { FilteredListWidget.highlightRanges(subtitleElement, query, true); } } } renderAsTwoRows(): boolean { return this.items.some(i => Boolean(i.detail)); } selectItem(itemIndex: number|null, _promptValue: string): void { if (typeof itemIndex === 'number') { this.resolve(this.items[itemIndex]); return; } this.resolve(undefined); } }