/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
import './quickopen.css';
import * as nls from '../../../../nls.js';
import * as platform from '../../../common/platform.js';
import * as types from '../../../common/types.js';
import { Filter, Renderer, DataSource, AccessibilityProvider } from './quickOpenViewer.js';
import { InputBox } from '../../../browser/ui/inputbox/inputBox.js';
import { Tree } from '../../tree/browser/treeImpl.js';
import { ProgressBar } from '../../../browser/ui/progressbar/progressbar.js';
import { StandardKeyboardEvent } from '../../../browser/keyboardEvent.js';
import { DefaultController } from '../../tree/browser/treeDefaults.js';
import * as DOM from '../../../browser/dom.js';
import { Disposable } from '../../../common/lifecycle.js';
import { Color } from '../../../common/color.js';
import { mixin } from '../../../common/objects.js';
import { StandardMouseEvent } from '../../../browser/mouseEvent.js';
var QuickOpenController = /** @class */ (function (_super) {
    __extends(QuickOpenController, _super);
    function QuickOpenController() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    QuickOpenController.prototype.onContextMenu = function (tree, element, event) {
        if (platform.isMacintosh) {
            return this.onLeftClick(tree, element, event); // https://github.com/Microsoft/vscode/issues/1011
        }
        return _super.prototype.onContextMenu.call(this, tree, element, event);
    };
    return QuickOpenController;
}(DefaultController));
export { QuickOpenController };
var defaultStyles = {
    background: Color.fromHex('#1E1E1E'),
    foreground: Color.fromHex('#CCCCCC'),
    pickerGroupForeground: Color.fromHex('#0097FB'),
    pickerGroupBorder: Color.fromHex('#3F3F46'),
    widgetShadow: Color.fromHex('#000000'),
    progressBarBackground: Color.fromHex('#0E70C0')
};
var DEFAULT_INPUT_ARIA_LABEL = nls.localize('quickOpenAriaLabel', "Quick picker. Type to narrow down results.");
var QuickOpenWidget = /** @class */ (function (_super) {
    __extends(QuickOpenWidget, _super);
    function QuickOpenWidget(container, callbacks, options) {
        var _this = _super.call(this) || this;
        _this.isDisposed = false;
        _this.container = container;
        _this.callbacks = callbacks;
        _this.options = options;
        _this.styles = options || Object.create(null);
        mixin(_this.styles, defaultStyles, false);
        _this.model = null;
        return _this;
    }
    QuickOpenWidget.prototype.getModel = function () {
        return this.model;
    };
    QuickOpenWidget.prototype.create = function () {
        var _this = this;
        // Container
        this.element = document.createElement('div');
        DOM.addClass(this.element, 'monaco-quick-open-widget');
        this.container.appendChild(this.element);
        this._register(DOM.addDisposableListener(this.element, DOM.EventType.CONTEXT_MENU, function (e) { return DOM.EventHelper.stop(e, true); })); // Do this to fix an issue on Mac where the menu goes into the way
        this._register(DOM.addDisposableListener(this.element, DOM.EventType.FOCUS, function (e) { return _this.gainingFocus(); }, true));
        this._register(DOM.addDisposableListener(this.element, DOM.EventType.BLUR, function (e) { return _this.loosingFocus(e); }, true));
        this._register(DOM.addDisposableListener(this.element, DOM.EventType.KEY_DOWN, function (e) {
            var keyboardEvent = new StandardKeyboardEvent(e);
            if (keyboardEvent.keyCode === 9 /* Escape */) {
                DOM.EventHelper.stop(e, true);
                _this.hide(2 /* CANCELED */);
            }
            else if (keyboardEvent.keyCode === 2 /* Tab */ && !keyboardEvent.altKey && !keyboardEvent.ctrlKey && !keyboardEvent.metaKey) {
                var stops = e.currentTarget.querySelectorAll('input, .monaco-tree, .monaco-tree-row.focused .action-label.icon');
                if (keyboardEvent.shiftKey && keyboardEvent.target === stops[0]) {
                    DOM.EventHelper.stop(e, true);
                    stops[stops.length - 1].focus();
                }
                else if (!keyboardEvent.shiftKey && keyboardEvent.target === stops[stops.length - 1]) {
                    DOM.EventHelper.stop(e, true);
                    stops[0].focus();
                }
            }
        }));
        // Progress Bar
        this.progressBar = this._register(new ProgressBar(this.element, { progressBarBackground: this.styles.progressBarBackground }));
        this.progressBar.hide();
        // Input Field
        this.inputContainer = document.createElement('div');
        DOM.addClass(this.inputContainer, 'quick-open-input');
        this.element.appendChild(this.inputContainer);
        this.inputBox = this._register(new InputBox(this.inputContainer, undefined, {
            placeholder: this.options.inputPlaceHolder || '',
            ariaLabel: DEFAULT_INPUT_ARIA_LABEL,
            inputBackground: this.styles.inputBackground,
            inputForeground: this.styles.inputForeground,
            inputBorder: this.styles.inputBorder,
            inputValidationInfoBackground: this.styles.inputValidationInfoBackground,
            inputValidationInfoForeground: this.styles.inputValidationInfoForeground,
            inputValidationInfoBorder: this.styles.inputValidationInfoBorder,
            inputValidationWarningBackground: this.styles.inputValidationWarningBackground,
            inputValidationWarningForeground: this.styles.inputValidationWarningForeground,
            inputValidationWarningBorder: this.styles.inputValidationWarningBorder,
            inputValidationErrorBackground: this.styles.inputValidationErrorBackground,
            inputValidationErrorForeground: this.styles.inputValidationErrorForeground,
            inputValidationErrorBorder: this.styles.inputValidationErrorBorder
        }));
        this.inputElement = this.inputBox.inputElement;
        this.inputElement.setAttribute('role', 'combobox');
        this.inputElement.setAttribute('aria-haspopup', 'false');
        this.inputElement.setAttribute('aria-autocomplete', 'list');
        this._register(DOM.addDisposableListener(this.inputBox.inputElement, DOM.EventType.INPUT, function (e) { return _this.onType(); }));
        this._register(DOM.addDisposableListener(this.inputBox.inputElement, DOM.EventType.KEY_DOWN, function (e) {
            var keyboardEvent = new StandardKeyboardEvent(e);
            var shouldOpenInBackground = _this.shouldOpenInBackground(keyboardEvent);
            // Do not handle Tab: It is used to navigate between elements without mouse
            if (keyboardEvent.keyCode === 2 /* Tab */) {
                return;
            }
            // Pass tree navigation keys to the tree but leave focus in input field
            else if (keyboardEvent.keyCode === 18 /* DownArrow */ || keyboardEvent.keyCode === 16 /* UpArrow */ || keyboardEvent.keyCode === 12 /* PageDown */ || keyboardEvent.keyCode === 11 /* PageUp */) {
                DOM.EventHelper.stop(e, true);
                _this.navigateInTree(keyboardEvent.keyCode, keyboardEvent.shiftKey);
                // Position cursor at the end of input to allow right arrow (open in background)
                // to function immediately unless the user has made a selection
                if (_this.inputBox.inputElement.selectionStart === _this.inputBox.inputElement.selectionEnd) {
                    _this.inputBox.inputElement.selectionStart = _this.inputBox.value.length;
                }
            }
            // Select element on Enter or on Arrow-Right if we are at the end of the input
            else if (keyboardEvent.keyCode === 3 /* Enter */ || shouldOpenInBackground) {
                DOM.EventHelper.stop(e, true);
                var focus_1 = _this.tree.getFocus();
                if (focus_1) {
                    _this.elementSelected(focus_1, e, shouldOpenInBackground ? 2 /* OPEN_IN_BACKGROUND */ : 1 /* OPEN */);
                }
            }
        }));
        // Result count for screen readers
        this.resultCount = document.createElement('div');
        DOM.addClass(this.resultCount, 'quick-open-result-count');
        this.resultCount.setAttribute('aria-live', 'polite');
        this.resultCount.setAttribute('aria-atomic', 'true');
        this.element.appendChild(this.resultCount);
        // Tree
        this.treeContainer = document.createElement('div');
        DOM.addClass(this.treeContainer, 'quick-open-tree');
        this.element.appendChild(this.treeContainer);
        var createTree = this.options.treeCreator || (function (container, config, opts) { return new Tree(container, config, opts); });
        this.tree = this._register(createTree(this.treeContainer, {
            dataSource: new DataSource(this),
            controller: new QuickOpenController({ clickBehavior: 1 /* ON_MOUSE_UP */, keyboardSupport: this.options.keyboardSupport }),
            renderer: (this.renderer = new Renderer(this, this.styles)),
            filter: new Filter(this),
            accessibilityProvider: new AccessibilityProvider(this)
        }, {
            twistiePixels: 11,
            indentPixels: 0,
            alwaysFocused: true,
            verticalScrollMode: 3 /* Visible */,
            horizontalScrollMode: 2 /* Hidden */,
            ariaLabel: nls.localize('treeAriaLabel', "Quick Picker"),
            keyboardSupport: this.options.keyboardSupport,
            preventRootFocus: false
        }));
        this.treeElement = this.tree.getHTMLElement();
        // Handle Focus and Selection event
        this._register(this.tree.onDidChangeFocus(function (event) {
            _this.elementFocused(event.focus, event);
        }));
        this._register(this.tree.onDidChangeSelection(function (event) {
            if (event.selection && event.selection.length > 0) {
                var mouseEvent = event.payload && event.payload.originalEvent instanceof StandardMouseEvent ? event.payload.originalEvent : undefined;
                var shouldOpenInBackground = mouseEvent ? _this.shouldOpenInBackground(mouseEvent) : false;
                _this.elementSelected(event.selection[0], event, shouldOpenInBackground ? 2 /* OPEN_IN_BACKGROUND */ : 1 /* OPEN */);
            }
        }));
        this._register(DOM.addDisposableListener(this.treeContainer, DOM.EventType.KEY_DOWN, function (e) {
            var keyboardEvent = new StandardKeyboardEvent(e);
            // Only handle when in quick navigation mode
            if (!_this.quickNavigateConfiguration) {
                return;
            }
            // Support keyboard navigation in quick navigation mode
            if (keyboardEvent.keyCode === 18 /* DownArrow */ || keyboardEvent.keyCode === 16 /* UpArrow */ || keyboardEvent.keyCode === 12 /* PageDown */ || keyboardEvent.keyCode === 11 /* PageUp */) {
                DOM.EventHelper.stop(e, true);
                _this.navigateInTree(keyboardEvent.keyCode);
            }
            // Support to open item with Enter still even in quick nav mode
            else if (keyboardEvent.keyCode === 3 /* Enter */) {
                DOM.EventHelper.stop(e, true);
                var focus_2 = _this.tree.getFocus();
                if (focus_2) {
                    _this.elementSelected(focus_2, e);
                }
            }
        }));
        this._register(DOM.addDisposableListener(this.treeContainer, DOM.EventType.KEY_UP, function (e) {
            var keyboardEvent = new StandardKeyboardEvent(e);
            var keyCode = keyboardEvent.keyCode;
            // Only handle when in quick navigation mode
            if (!_this.quickNavigateConfiguration) {
                return;
            }
            // Select element when keys are pressed that signal it
            var quickNavKeys = _this.quickNavigateConfiguration.keybindings;
            var wasTriggerKeyPressed = quickNavKeys.some(function (k) {
                var _a = k.getParts(), firstPart = _a[0], chordPart = _a[1];
                if (chordPart) {
                    return false;
                }
                if (firstPart.shiftKey && keyCode === 4 /* Shift */) {
                    if (keyboardEvent.ctrlKey || keyboardEvent.altKey || keyboardEvent.metaKey) {
                        return false; // this is an optimistic check for the shift key being used to navigate back in quick open
                    }
                    return true;
                }
                if (firstPart.altKey && keyCode === 6 /* Alt */) {
                    return true;
                }
                if (firstPart.ctrlKey && keyCode === 5 /* Ctrl */) {
                    return true;
                }
                if (firstPart.metaKey && keyCode === 57 /* Meta */) {
                    return true;
                }
                return false;
            });
            if (wasTriggerKeyPressed) {
                var focus_3 = _this.tree.getFocus();
                if (focus_3) {
                    _this.elementSelected(focus_3, e);
                }
            }
        }));
        // Support layout
        if (this.layoutDimensions) {
            this.layout(this.layoutDimensions);
        }
        this.applyStyles();
        // Allows focus to switch to next/previous entry after tab into an actionbar item
        this._register(DOM.addDisposableListener(this.treeContainer, DOM.EventType.KEY_DOWN, function (e) {
            var keyboardEvent = new StandardKeyboardEvent(e);
            // Only handle when not in quick navigation mode
            if (_this.quickNavigateConfiguration) {
                return;
            }
            if (keyboardEvent.keyCode === 18 /* DownArrow */ || keyboardEvent.keyCode === 16 /* UpArrow */ || keyboardEvent.keyCode === 12 /* PageDown */ || keyboardEvent.keyCode === 11 /* PageUp */) {
                DOM.EventHelper.stop(e, true);
                _this.navigateInTree(keyboardEvent.keyCode, keyboardEvent.shiftKey);
                _this.treeElement.focus();
            }
        }));
        return this.element;
    };
    QuickOpenWidget.prototype.style = function (styles) {
        this.styles = styles;
        this.applyStyles();
    };
    QuickOpenWidget.prototype.applyStyles = function () {
        if (this.element) {
            var foreground = this.styles.foreground ? this.styles.foreground.toString() : '';
            var background = this.styles.background ? this.styles.background.toString() : '';
            var borderColor = this.styles.borderColor ? this.styles.borderColor.toString() : '';
            var widgetShadow = this.styles.widgetShadow ? this.styles.widgetShadow.toString() : '';
            this.element.style.color = foreground;
            this.element.style.backgroundColor = background;
            this.element.style.borderColor = borderColor;
            this.element.style.borderWidth = borderColor ? '1px' : '';
            this.element.style.borderStyle = borderColor ? 'solid' : '';
            this.element.style.boxShadow = widgetShadow ? "0 5px 8px " + widgetShadow : '';
        }
        if (this.progressBar) {
            this.progressBar.style({
                progressBarBackground: this.styles.progressBarBackground
            });
        }
        if (this.inputBox) {
            this.inputBox.style({
                inputBackground: this.styles.inputBackground,
                inputForeground: this.styles.inputForeground,
                inputBorder: this.styles.inputBorder,
                inputValidationInfoBackground: this.styles.inputValidationInfoBackground,
                inputValidationInfoForeground: this.styles.inputValidationInfoForeground,
                inputValidationInfoBorder: this.styles.inputValidationInfoBorder,
                inputValidationWarningBackground: this.styles.inputValidationWarningBackground,
                inputValidationWarningForeground: this.styles.inputValidationWarningForeground,
                inputValidationWarningBorder: this.styles.inputValidationWarningBorder,
                inputValidationErrorBackground: this.styles.inputValidationErrorBackground,
                inputValidationErrorForeground: this.styles.inputValidationErrorForeground,
                inputValidationErrorBorder: this.styles.inputValidationErrorBorder
            });
        }
        if (this.tree && !this.options.treeCreator) {
            this.tree.style(this.styles);
        }
        if (this.renderer) {
            this.renderer.updateStyles(this.styles);
        }
    };
    QuickOpenWidget.prototype.shouldOpenInBackground = function (e) {
        // Keyboard
        if (e instanceof StandardKeyboardEvent) {
            if (e.keyCode !== 17 /* RightArrow */) {
                return false; // only for right arrow
            }
            if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
                return false; // no modifiers allowed
            }
            // validate the cursor is at the end of the input and there is no selection,
            // and if not prevent opening in the background such as the selection can be changed
            var element = this.inputBox.inputElement;
            return element.selectionEnd === this.inputBox.value.length && element.selectionStart === element.selectionEnd;
        }
        // Mouse
        return e.middleButton;
    };
    QuickOpenWidget.prototype.onType = function () {
        var value = this.inputBox.value;
        // Adjust help text as needed if present
        if (this.helpText) {
            if (value) {
                DOM.hide(this.helpText);
            }
            else {
                DOM.show(this.helpText);
            }
        }
        // Send to callbacks
        this.callbacks.onType(value);
    };
    QuickOpenWidget.prototype.navigateInTree = function (keyCode, isShift) {
        var model = this.tree.getInput();
        var entries = model ? model.entries : [];
        var oldFocus = this.tree.getFocus();
        // Normal Navigation
        switch (keyCode) {
            case 18 /* DownArrow */:
                this.tree.focusNext();
                break;
            case 16 /* UpArrow */:
                this.tree.focusPrevious();
                break;
            case 12 /* PageDown */:
                this.tree.focusNextPage();
                break;
            case 11 /* PageUp */:
                this.tree.focusPreviousPage();
                break;
            case 2 /* Tab */:
                if (isShift) {
                    this.tree.focusPrevious();
                }
                else {
                    this.tree.focusNext();
                }
                break;
        }
        var newFocus = this.tree.getFocus();
        // Support cycle-through navigation if focus did not change
        if (entries.length > 1 && oldFocus === newFocus) {
            // Up from no entry or first entry goes down to last
            if (keyCode === 16 /* UpArrow */ || (keyCode === 2 /* Tab */ && isShift)) {
                this.tree.focusLast();
            }
            // Down from last entry goes to up to first
            else if (keyCode === 18 /* DownArrow */ || keyCode === 2 /* Tab */ && !isShift) {
                this.tree.focusFirst();
            }
        }
        // Reveal
        newFocus = this.tree.getFocus();
        if (newFocus) {
            this.tree.reveal(newFocus);
        }
    };
    QuickOpenWidget.prototype.elementFocused = function (value, event) {
        if (!value || !this.isVisible()) {
            return;
        }
        // ARIA
        var arivaActiveDescendant = this.treeElement.getAttribute('aria-activedescendant');
        if (arivaActiveDescendant) {
            this.inputElement.setAttribute('aria-activedescendant', arivaActiveDescendant);
        }
        else {
            this.inputElement.removeAttribute('aria-activedescendant');
        }
        var context = { event: event, keymods: this.extractKeyMods(event), quickNavigateConfiguration: this.quickNavigateConfiguration };
        this.model.runner.run(value, 0 /* PREVIEW */, context);
    };
    QuickOpenWidget.prototype.elementSelected = function (value, event, preferredMode) {
        var hide = true;
        // Trigger open of element on selection
        if (this.isVisible()) {
            var mode = preferredMode || 1 /* OPEN */;
            var context = { event: event, keymods: this.extractKeyMods(event), quickNavigateConfiguration: this.quickNavigateConfiguration };
            hide = this.model.runner.run(value, mode, context);
        }
        // Hide if command was run successfully
        if (hide) {
            this.hide(0 /* ELEMENT_SELECTED */);
        }
    };
    QuickOpenWidget.prototype.extractKeyMods = function (event) {
        return {
            ctrlCmd: event && (event.ctrlKey || event.metaKey || (event.payload && event.payload.originalEvent && (event.payload.originalEvent.ctrlKey || event.payload.originalEvent.metaKey))),
            alt: event && (event.altKey || (event.payload && event.payload.originalEvent && event.payload.originalEvent.altKey))
        };
    };
    QuickOpenWidget.prototype.show = function (param, options) {
        this.visible = true;
        this.isLoosingFocus = false;
        this.quickNavigateConfiguration = options ? options.quickNavigateConfiguration : undefined;
        // Adjust UI for quick navigate mode
        if (this.quickNavigateConfiguration) {
            DOM.hide(this.inputContainer);
            DOM.show(this.element);
            this.tree.domFocus();
        }
        // Otherwise use normal UI
        else {
            DOM.show(this.inputContainer);
            DOM.show(this.element);
            this.inputBox.focus();
        }
        // Adjust Help text for IE
        if (this.helpText) {
            if (this.quickNavigateConfiguration || types.isString(param)) {
                DOM.hide(this.helpText);
            }
            else {
                DOM.show(this.helpText);
            }
        }
        // Show based on param
        if (types.isString(param)) {
            this.doShowWithPrefix(param);
        }
        else {
            if (options && options.value) {
                this.restoreLastInput(options.value);
            }
            this.doShowWithInput(param, options && options.autoFocus ? options.autoFocus : {});
        }
        // Respect selectAll option
        if (options && options.inputSelection && !this.quickNavigateConfiguration) {
            this.inputBox.select(options.inputSelection);
        }
        if (this.callbacks.onShow) {
            this.callbacks.onShow();
        }
    };
    QuickOpenWidget.prototype.restoreLastInput = function (lastInput) {
        this.inputBox.value = lastInput;
        this.inputBox.select();
        this.callbacks.onType(lastInput);
    };
    QuickOpenWidget.prototype.doShowWithPrefix = function (prefix) {
        this.inputBox.value = prefix;
        this.callbacks.onType(prefix);
    };
    QuickOpenWidget.prototype.doShowWithInput = function (input, autoFocus) {
        this.setInput(input, autoFocus);
    };
    QuickOpenWidget.prototype.setInputAndLayout = function (input, autoFocus) {
        var _this = this;
        this.treeContainer.style.height = this.getHeight(input) + "px";
        this.tree.setInput(null).then(function () {
            _this.model = input;
            // ARIA
            _this.inputElement.setAttribute('aria-haspopup', String(input && input.entries && input.entries.length > 0));
            return _this.tree.setInput(input);
        }).then(function () {
            // Indicate entries to tree
            _this.tree.layout();
            var entries = input ? input.entries.filter(function (e) { return _this.isElementVisible(input, e); }) : [];
            _this.updateResultCount(entries.length);
            // Handle auto focus
            if (entries.length) {
                _this.autoFocus(input, entries, autoFocus);
            }
        });
    };
    QuickOpenWidget.prototype.isElementVisible = function (input, e) {
        if (!input.filter) {
            return true;
        }
        return input.filter.isVisible(e);
    };
    QuickOpenWidget.prototype.autoFocus = function (input, entries, autoFocus) {
        if (autoFocus === void 0) { autoFocus = {}; }
        // First check for auto focus of prefix matches
        if (autoFocus.autoFocusPrefixMatch) {
            var caseSensitiveMatch = void 0;
            var caseInsensitiveMatch = void 0;
            var prefix = autoFocus.autoFocusPrefixMatch;
            var lowerCasePrefix = prefix.toLowerCase();
            for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
                var entry = entries_1[_i];
                var label = input.dataSource.getLabel(entry) || '';
                if (!caseSensitiveMatch && label.indexOf(prefix) === 0) {
                    caseSensitiveMatch = entry;
                }
                else if (!caseInsensitiveMatch && label.toLowerCase().indexOf(lowerCasePrefix) === 0) {
                    caseInsensitiveMatch = entry;
                }
                if (caseSensitiveMatch && caseInsensitiveMatch) {
                    break;
                }
            }
            var entryToFocus = caseSensitiveMatch || caseInsensitiveMatch;
            if (entryToFocus) {
                this.tree.setFocus(entryToFocus);
                this.tree.reveal(entryToFocus, 0.5);
                return;
            }
        }
        // Second check for auto focus of first entry
        if (autoFocus.autoFocusFirstEntry) {
            this.tree.focusFirst();
            this.tree.reveal(this.tree.getFocus());
        }
        // Third check for specific index option
        else if (typeof autoFocus.autoFocusIndex === 'number') {
            if (entries.length > autoFocus.autoFocusIndex) {
                this.tree.focusNth(autoFocus.autoFocusIndex);
                this.tree.reveal(this.tree.getFocus());
            }
        }
        // Check for auto focus of second entry
        else if (autoFocus.autoFocusSecondEntry) {
            if (entries.length > 1) {
                this.tree.focusNth(1);
            }
        }
        // Finally check for auto focus of last entry
        else if (autoFocus.autoFocusLastEntry) {
            if (entries.length > 1) {
                this.tree.focusLast();
                this.tree.reveal(this.tree.getFocus());
            }
        }
    };
    QuickOpenWidget.prototype.getHeight = function (input) {
        var _this = this;
        var renderer = input.renderer;
        if (!input) {
            var itemHeight = renderer.getHeight(null);
            return this.options.minItemsToShow ? this.options.minItemsToShow * itemHeight : 0;
        }
        var height = 0;
        var preferredItemsHeight;
        if (this.layoutDimensions && this.layoutDimensions.height) {
            preferredItemsHeight = (this.layoutDimensions.height - 50 /* subtract height of input field (30px) and some spacing (drop shadow) to fit */) * 0.4 /* max 40% of screen */;
        }
        if (!preferredItemsHeight || preferredItemsHeight > QuickOpenWidget.MAX_ITEMS_HEIGHT) {
            preferredItemsHeight = QuickOpenWidget.MAX_ITEMS_HEIGHT;
        }
        var entries = input.entries.filter(function (e) { return _this.isElementVisible(input, e); });
        var maxEntries = this.options.maxItemsToShow || entries.length;
        for (var i = 0; i < maxEntries && i < entries.length; i++) {
            var entryHeight = renderer.getHeight(entries[i]);
            if (height + entryHeight <= preferredItemsHeight) {
                height += entryHeight;
            }
            else {
                break;
            }
        }
        return height;
    };
    QuickOpenWidget.prototype.updateResultCount = function (count) {
        this.resultCount.textContent = nls.localize({ key: 'quickInput.visibleCount', comment: ['This tells the user how many items are shown in a list of items to select from. The items can be anything. Currently not visible, but read by screen readers.'] }, "{0} Results", count);
    };
    QuickOpenWidget.prototype.hide = function (reason) {
        if (!this.isVisible()) {
            return;
        }
        this.visible = false;
        DOM.hide(this.element);
        this.element.blur();
        // Clear input field and clear tree
        this.inputBox.value = '';
        this.tree.setInput(null);
        // ARIA
        this.inputElement.setAttribute('aria-haspopup', 'false');
        // Reset Tree Height
        this.treeContainer.style.height = (this.options.minItemsToShow ? this.options.minItemsToShow * 22 : 0) + "px";
        // Clear any running Progress
        this.progressBar.stop().hide();
        // Clear Focus
        if (this.tree.isDOMFocused()) {
            this.tree.domBlur();
        }
        else if (this.inputBox.hasFocus()) {
            this.inputBox.blur();
        }
        // Callbacks
        if (reason === 0 /* ELEMENT_SELECTED */) {
            this.callbacks.onOk();
        }
        else {
            this.callbacks.onCancel();
        }
        if (this.callbacks.onHide) {
            this.callbacks.onHide(reason);
        }
    };
    QuickOpenWidget.prototype.setInput = function (input, autoFocus, ariaLabel) {
        if (!this.isVisible()) {
            return;
        }
        // If the input changes, indicate this to the tree
        if (!!this.getInput()) {
            this.onInputChanging();
        }
        // Adapt tree height to entries and apply input
        this.setInputAndLayout(input, autoFocus);
        // Apply ARIA
        if (this.inputBox) {
            this.inputBox.setAriaLabel(ariaLabel || DEFAULT_INPUT_ARIA_LABEL);
        }
    };
    QuickOpenWidget.prototype.onInputChanging = function () {
        var _this = this;
        if (this.inputChangingTimeoutHandle) {
            clearTimeout(this.inputChangingTimeoutHandle);
            this.inputChangingTimeoutHandle = null;
        }
        // when the input is changing in quick open, we indicate this as CSS class to the widget
        // for a certain timeout. this helps reducing some hectic UI updates when input changes quickly
        DOM.addClass(this.element, 'content-changing');
        this.inputChangingTimeoutHandle = setTimeout(function () {
            DOM.removeClass(_this.element, 'content-changing');
        }, 500);
    };
    QuickOpenWidget.prototype.getInput = function () {
        return this.tree.getInput();
    };
    QuickOpenWidget.prototype.isVisible = function () {
        return this.visible;
    };
    QuickOpenWidget.prototype.layout = function (dimension) {
        this.layoutDimensions = dimension;
        // Apply to quick open width (height is dynamic by number of items to show)
        var quickOpenWidth = Math.min(this.layoutDimensions.width * 0.62 /* golden cut */, QuickOpenWidget.MAX_WIDTH);
        if (this.element) {
            // quick open
            this.element.style.width = quickOpenWidth + "px";
            this.element.style.marginLeft = "-" + quickOpenWidth / 2 + "px";
            // input field
            this.inputContainer.style.width = quickOpenWidth - 12 + "px";
        }
    };
    QuickOpenWidget.prototype.gainingFocus = function () {
        this.isLoosingFocus = false;
    };
    QuickOpenWidget.prototype.loosingFocus = function (e) {
        var _this = this;
        if (!this.isVisible()) {
            return;
        }
        var relatedTarget = e.relatedTarget;
        if (!this.quickNavigateConfiguration && DOM.isAncestor(relatedTarget, this.element)) {
            return; // user clicked somewhere into quick open widget, do not close thereby
        }
        this.isLoosingFocus = true;
        setTimeout(function () {
            if (!_this.isLoosingFocus || _this.isDisposed) {
                return;
            }
            var veto = _this.callbacks.onFocusLost && _this.callbacks.onFocusLost();
            if (!veto) {
                _this.hide(1 /* FOCUS_LOST */);
            }
        }, 0);
    };
    QuickOpenWidget.prototype.dispose = function () {
        _super.prototype.dispose.call(this);
        this.isDisposed = true;
    };
    QuickOpenWidget.MAX_WIDTH = 600; // Max total width of quick open widget
    QuickOpenWidget.MAX_ITEMS_HEIGHT = 20 * 22; // Max height of item list below input field
    return QuickOpenWidget;
}(Disposable));
export { QuickOpenWidget };
