/*---------------------------------------------------------------------------------------------
 *  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 './actionbar.css';
import * as platform from '../../../common/platform';
import * as nls from '../../../../nls';
import { Disposable, dispose } from '../../../common/lifecycle';
import { SelectBox } from '../selectBox/selectBox';
import { Action, ActionRunner } from '../../../common/actions';
import * as DOM from '../../dom';
import * as types from '../../../common/types';
import { EventType, Gesture } from '../../touch';
import { StandardKeyboardEvent } from '../../keyboardEvent';
import { Emitter } from '../../../common/event';
import { DataTransfers } from '../../dnd';
import { isFirefox } from '../../browser';
var BaseActionViewItem = /** @class */ (function (_super) {
    __extends(BaseActionViewItem, _super);
    function BaseActionViewItem(context, action, options) {
        var _this = _super.call(this) || this;
        _this.options = options;
        _this._context = context || _this;
        _this._action = action;
        if (action instanceof Action) {
            _this._register(action.onDidChange(function (event) {
                if (!_this.element) {
                    // we have not been rendered yet, so there
                    // is no point in updating the UI
                    return;
                }
                _this.handleActionChangeEvent(event);
            }));
        }
        return _this;
    }
    BaseActionViewItem.prototype.handleActionChangeEvent = function (event) {
        if (event.enabled !== undefined) {
            this.updateEnabled();
        }
        if (event.checked !== undefined) {
            this.updateChecked();
        }
        if (event.class !== undefined) {
            this.updateClass();
        }
        if (event.label !== undefined) {
            this.updateLabel();
            this.updateTooltip();
        }
        if (event.tooltip !== undefined) {
            this.updateTooltip();
        }
    };
    Object.defineProperty(BaseActionViewItem.prototype, "actionRunner", {
        get: function () {
            if (!this._actionRunner) {
                this._actionRunner = this._register(new ActionRunner());
            }
            return this._actionRunner;
        },
        set: function (actionRunner) {
            this._actionRunner = actionRunner;
        },
        enumerable: true,
        configurable: true
    });
    BaseActionViewItem.prototype.getAction = function () {
        return this._action;
    };
    BaseActionViewItem.prototype.isEnabled = function () {
        return this._action.enabled;
    };
    BaseActionViewItem.prototype.setActionContext = function (newContext) {
        this._context = newContext;
    };
    BaseActionViewItem.prototype.render = function (container) {
        var _this = this;
        var element = this.element = container;
        this._register(Gesture.addTarget(container));
        var enableDragging = this.options && this.options.draggable;
        if (enableDragging) {
            container.draggable = true;
            if (isFirefox) {
                // Firefox: requires to set a text data transfer to get going
                this._register(DOM.addDisposableListener(container, DOM.EventType.DRAG_START, function (e) { var _a; return (_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.setData(DataTransfers.TEXT, _this._action.label); }));
            }
        }
        this._register(DOM.addDisposableListener(element, EventType.Tap, function (e) { return _this.onClick(e); }));
        this._register(DOM.addDisposableListener(element, DOM.EventType.MOUSE_DOWN, function (e) {
            if (!enableDragging) {
                DOM.EventHelper.stop(e, true); // do not run when dragging is on because that would disable it
            }
            if (_this._action.enabled && e.button === 0) {
                DOM.addClass(element, 'active');
            }
        }));
        this._register(DOM.addDisposableListener(element, DOM.EventType.CLICK, function (e) {
            DOM.EventHelper.stop(e, true);
            // See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard
            // > Writing to the clipboard
            // > You can use the "cut" and "copy" commands without any special
            // permission if you are using them in a short-lived event handler
            // for a user action (for example, a click handler).
            // => to get the Copy and Paste context menu actions working on Firefox,
            // there should be no timeout here
            if (_this.options && _this.options.isMenu) {
                _this.onClick(e);
            }
            else {
                platform.setImmediate(function () { return _this.onClick(e); });
            }
        }));
        this._register(DOM.addDisposableListener(element, DOM.EventType.DBLCLICK, function (e) {
            DOM.EventHelper.stop(e, true);
        }));
        [DOM.EventType.MOUSE_UP, DOM.EventType.MOUSE_OUT].forEach(function (event) {
            _this._register(DOM.addDisposableListener(element, event, function (e) {
                DOM.EventHelper.stop(e);
                DOM.removeClass(element, 'active');
            }));
        });
    };
    BaseActionViewItem.prototype.onClick = function (event) {
        DOM.EventHelper.stop(event, true);
        var context;
        if (types.isUndefinedOrNull(this._context)) {
            context = event;
        }
        else {
            context = this._context;
            if (types.isObject(context)) {
                context.event = event;
            }
        }
        this.actionRunner.run(this._action, context);
    };
    BaseActionViewItem.prototype.focus = function () {
        if (this.element) {
            this.element.focus();
            DOM.addClass(this.element, 'focused');
        }
    };
    BaseActionViewItem.prototype.blur = function () {
        if (this.element) {
            this.element.blur();
            DOM.removeClass(this.element, 'focused');
        }
    };
    BaseActionViewItem.prototype.updateEnabled = function () {
        // implement in subclass
    };
    BaseActionViewItem.prototype.updateLabel = function () {
        // implement in subclass
    };
    BaseActionViewItem.prototype.updateTooltip = function () {
        // implement in subclass
    };
    BaseActionViewItem.prototype.updateClass = function () {
        // implement in subclass
    };
    BaseActionViewItem.prototype.updateChecked = function () {
        // implement in subclass
    };
    BaseActionViewItem.prototype.dispose = function () {
        if (this.element) {
            DOM.removeNode(this.element);
            this.element = undefined;
        }
        _super.prototype.dispose.call(this);
    };
    return BaseActionViewItem;
}(Disposable));
export { BaseActionViewItem };
var Separator = /** @class */ (function (_super) {
    __extends(Separator, _super);
    function Separator(label) {
        var _this = _super.call(this, Separator.ID, label, label ? 'separator text' : 'separator') || this;
        _this.checked = false;
        _this.enabled = false;
        return _this;
    }
    Separator.ID = 'vs.actions.separator';
    return Separator;
}(Action));
export { Separator };
var ActionViewItem = /** @class */ (function (_super) {
    __extends(ActionViewItem, _super);
    function ActionViewItem(context, action, options) {
        if (options === void 0) { options = {}; }
        var _this = _super.call(this, context, action, options) || this;
        _this.options = options;
        _this.options.icon = options.icon !== undefined ? options.icon : false;
        _this.options.label = options.label !== undefined ? options.label : true;
        _this.cssClass = '';
        return _this;
    }
    ActionViewItem.prototype.render = function (container) {
        _super.prototype.render.call(this, container);
        if (this.element) {
            this.label = DOM.append(this.element, DOM.$('a.action-label'));
        }
        if (this.label) {
            if (this._action.id === Separator.ID) {
                this.label.setAttribute('role', 'presentation'); // A separator is a presentation item
            }
            else {
                if (this.options.isMenu) {
                    this.label.setAttribute('role', 'menuitem');
                }
                else {
                    this.label.setAttribute('role', 'button');
                }
            }
        }
        if (this.options.label && this.options.keybinding && this.element) {
            DOM.append(this.element, DOM.$('span.keybinding')).textContent = this.options.keybinding;
        }
        this.updateClass();
        this.updateLabel();
        this.updateTooltip();
        this.updateEnabled();
        this.updateChecked();
    };
    ActionViewItem.prototype.focus = function () {
        _super.prototype.focus.call(this);
        if (this.label) {
            this.label.focus();
        }
    };
    ActionViewItem.prototype.updateLabel = function () {
        if (this.options.label && this.label) {
            this.label.textContent = this.getAction().label;
        }
    };
    ActionViewItem.prototype.updateTooltip = function () {
        var title = null;
        if (this.getAction().tooltip) {
            title = this.getAction().tooltip;
        }
        else if (!this.options.label && this.getAction().label && this.options.icon) {
            title = this.getAction().label;
            if (this.options.keybinding) {
                title = nls.localize({ key: 'titleLabel', comment: ['action title', 'action keybinding'] }, "{0} ({1})", title, this.options.keybinding);
            }
        }
        if (title && this.label) {
            this.label.title = title;
        }
    };
    ActionViewItem.prototype.updateClass = function () {
        if (this.cssClass && this.label) {
            DOM.removeClasses(this.label, this.cssClass);
        }
        if (this.options.icon) {
            this.cssClass = this.getAction().class;
            if (this.label) {
                DOM.addClass(this.label, 'codicon');
                if (this.cssClass) {
                    DOM.addClasses(this.label, this.cssClass);
                }
            }
            this.updateEnabled();
        }
        else {
            if (this.label) {
                DOM.removeClass(this.label, 'codicon');
            }
        }
    };
    ActionViewItem.prototype.updateEnabled = function () {
        if (this.getAction().enabled) {
            if (this.label) {
                this.label.removeAttribute('aria-disabled');
                DOM.removeClass(this.label, 'disabled');
                this.label.tabIndex = 0;
            }
            if (this.element) {
                DOM.removeClass(this.element, 'disabled');
            }
        }
        else {
            if (this.label) {
                this.label.setAttribute('aria-disabled', 'true');
                DOM.addClass(this.label, 'disabled');
                DOM.removeTabIndexAndUpdateFocus(this.label);
            }
            if (this.element) {
                DOM.addClass(this.element, 'disabled');
            }
        }
    };
    ActionViewItem.prototype.updateChecked = function () {
        if (this.label) {
            if (this.getAction().checked) {
                DOM.addClass(this.label, 'checked');
            }
            else {
                DOM.removeClass(this.label, 'checked');
            }
        }
    };
    return ActionViewItem;
}(BaseActionViewItem));
export { ActionViewItem };
var defaultOptions = {
    orientation: 0 /* HORIZONTAL */,
    context: null,
    triggerKeys: {
        keys: [3 /* Enter */, 10 /* Space */],
        keyDown: false
    }
};
var ActionBar = /** @class */ (function (_super) {
    __extends(ActionBar, _super);
    function ActionBar(container, options) {
        if (options === void 0) { options = defaultOptions; }
        var _this = _super.call(this) || this;
        _this._onDidBlur = _this._register(new Emitter());
        _this.onDidBlur = _this._onDidBlur.event;
        _this._onDidCancel = _this._register(new Emitter());
        _this.onDidCancel = _this._onDidCancel.event;
        _this._onDidRun = _this._register(new Emitter());
        _this.onDidRun = _this._onDidRun.event;
        _this._onDidBeforeRun = _this._register(new Emitter());
        _this.onDidBeforeRun = _this._onDidBeforeRun.event;
        _this.options = options;
        _this._context = options.context;
        if (!_this.options.triggerKeys) {
            _this.options.triggerKeys = defaultOptions.triggerKeys;
        }
        if (_this.options.actionRunner) {
            _this._actionRunner = _this.options.actionRunner;
        }
        else {
            _this._actionRunner = new ActionRunner();
            _this._register(_this._actionRunner);
        }
        _this._register(_this._actionRunner.onDidRun(function (e) { return _this._onDidRun.fire(e); }));
        _this._register(_this._actionRunner.onDidBeforeRun(function (e) { return _this._onDidBeforeRun.fire(e); }));
        _this.viewItems = [];
        _this.focusedItem = undefined;
        _this.domNode = document.createElement('div');
        _this.domNode.className = 'monaco-action-bar';
        if (options.animated !== false) {
            DOM.addClass(_this.domNode, 'animated');
        }
        var previousKey;
        var nextKey;
        switch (_this.options.orientation) {
            case 0 /* HORIZONTAL */:
                previousKey = 15 /* LeftArrow */;
                nextKey = 17 /* RightArrow */;
                break;
            case 1 /* HORIZONTAL_REVERSE */:
                previousKey = 17 /* RightArrow */;
                nextKey = 15 /* LeftArrow */;
                _this.domNode.className += ' reverse';
                break;
            case 2 /* VERTICAL */:
                previousKey = 16 /* UpArrow */;
                nextKey = 18 /* DownArrow */;
                _this.domNode.className += ' vertical';
                break;
            case 3 /* VERTICAL_REVERSE */:
                previousKey = 18 /* DownArrow */;
                nextKey = 16 /* UpArrow */;
                _this.domNode.className += ' vertical reverse';
                break;
        }
        _this._register(DOM.addDisposableListener(_this.domNode, DOM.EventType.KEY_DOWN, function (e) {
            var event = new StandardKeyboardEvent(e);
            var eventHandled = true;
            if (event.equals(previousKey)) {
                _this.focusPrevious();
            }
            else if (event.equals(nextKey)) {
                _this.focusNext();
            }
            else if (event.equals(9 /* Escape */)) {
                _this.cancel();
            }
            else if (_this.isTriggerKeyEvent(event)) {
                // Staying out of the else branch even if not triggered
                if (_this.options.triggerKeys && _this.options.triggerKeys.keyDown) {
                    _this.doTrigger(event);
                }
            }
            else {
                eventHandled = false;
            }
            if (eventHandled) {
                event.preventDefault();
                event.stopPropagation();
            }
        }));
        _this._register(DOM.addDisposableListener(_this.domNode, DOM.EventType.KEY_UP, function (e) {
            var event = new StandardKeyboardEvent(e);
            // Run action on Enter/Space
            if (_this.isTriggerKeyEvent(event)) {
                if (_this.options.triggerKeys && !_this.options.triggerKeys.keyDown) {
                    _this.doTrigger(event);
                }
                event.preventDefault();
                event.stopPropagation();
            }
            // Recompute focused item
            else if (event.equals(2 /* Tab */) || event.equals(1024 /* Shift */ | 2 /* Tab */)) {
                _this.updateFocusedItem();
            }
        }));
        _this.focusTracker = _this._register(DOM.trackFocus(_this.domNode));
        _this._register(_this.focusTracker.onDidBlur(function () {
            if (document.activeElement === _this.domNode || !DOM.isAncestor(document.activeElement, _this.domNode)) {
                _this._onDidBlur.fire();
                _this.focusedItem = undefined;
            }
        }));
        _this._register(_this.focusTracker.onDidFocus(function () { return _this.updateFocusedItem(); }));
        _this.actionsList = document.createElement('ul');
        _this.actionsList.className = 'actions-container';
        _this.actionsList.setAttribute('role', 'toolbar');
        if (_this.options.ariaLabel) {
            _this.actionsList.setAttribute('aria-label', _this.options.ariaLabel);
        }
        _this.domNode.appendChild(_this.actionsList);
        container.appendChild(_this.domNode);
        return _this;
    }
    ActionBar.prototype.setAriaLabel = function (label) {
        if (label) {
            this.actionsList.setAttribute('aria-label', label);
        }
        else {
            this.actionsList.removeAttribute('aria-label');
        }
    };
    ActionBar.prototype.isTriggerKeyEvent = function (event) {
        var ret = false;
        if (this.options.triggerKeys) {
            this.options.triggerKeys.keys.forEach(function (keyCode) {
                ret = ret || event.equals(keyCode);
            });
        }
        return ret;
    };
    ActionBar.prototype.updateFocusedItem = function () {
        for (var i = 0; i < this.actionsList.children.length; i++) {
            var elem = this.actionsList.children[i];
            if (DOM.isAncestor(document.activeElement, elem)) {
                this.focusedItem = i;
                break;
            }
        }
    };
    Object.defineProperty(ActionBar.prototype, "context", {
        get: function () {
            return this._context;
        },
        set: function (context) {
            this._context = context;
            this.viewItems.forEach(function (i) { return i.setActionContext(context); });
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(ActionBar.prototype, "actionRunner", {
        get: function () {
            return this._actionRunner;
        },
        set: function (actionRunner) {
            if (actionRunner) {
                this._actionRunner = actionRunner;
                this.viewItems.forEach(function (item) { return item.actionRunner = actionRunner; });
            }
        },
        enumerable: true,
        configurable: true
    });
    ActionBar.prototype.getContainer = function () {
        return this.domNode;
    };
    ActionBar.prototype.push = function (arg, options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        var actions = Array.isArray(arg) ? arg : [arg];
        var index = types.isNumber(options.index) ? options.index : null;
        actions.forEach(function (action) {
            var actionViewItemElement = document.createElement('li');
            actionViewItemElement.className = 'action-item';
            actionViewItemElement.setAttribute('role', 'presentation');
            // Prevent native context menu on actions
            _this._register(DOM.addDisposableListener(actionViewItemElement, DOM.EventType.CONTEXT_MENU, function (e) {
                e.preventDefault();
                e.stopPropagation();
            }));
            var item;
            if (_this.options.actionViewItemProvider) {
                item = _this.options.actionViewItemProvider(action);
            }
            if (!item) {
                item = new ActionViewItem(_this.context, action, options);
            }
            item.actionRunner = _this._actionRunner;
            item.setActionContext(_this.context);
            item.render(actionViewItemElement);
            if (index === null || index < 0 || index >= _this.actionsList.children.length) {
                _this.actionsList.appendChild(actionViewItemElement);
                _this.viewItems.push(item);
            }
            else {
                _this.actionsList.insertBefore(actionViewItemElement, _this.actionsList.children[index]);
                _this.viewItems.splice(index, 0, item);
                index++;
            }
        });
    };
    ActionBar.prototype.getWidth = function (index) {
        if (index >= 0 && index < this.actionsList.children.length) {
            var item = this.actionsList.children.item(index);
            if (item) {
                return item.clientWidth;
            }
        }
        return 0;
    };
    ActionBar.prototype.getHeight = function (index) {
        if (index >= 0 && index < this.actionsList.children.length) {
            var item = this.actionsList.children.item(index);
            if (item) {
                return item.clientHeight;
            }
        }
        return 0;
    };
    ActionBar.prototype.pull = function (index) {
        if (index >= 0 && index < this.viewItems.length) {
            this.actionsList.removeChild(this.actionsList.childNodes[index]);
            dispose(this.viewItems.splice(index, 1));
        }
    };
    ActionBar.prototype.clear = function () {
        this.viewItems = dispose(this.viewItems);
        DOM.clearNode(this.actionsList);
    };
    ActionBar.prototype.length = function () {
        return this.viewItems.length;
    };
    ActionBar.prototype.isEmpty = function () {
        return this.viewItems.length === 0;
    };
    ActionBar.prototype.focus = function (arg) {
        var selectFirst = false;
        var index = undefined;
        if (arg === undefined) {
            selectFirst = true;
        }
        else if (typeof arg === 'number') {
            index = arg;
        }
        else if (typeof arg === 'boolean') {
            selectFirst = arg;
        }
        if (selectFirst && typeof this.focusedItem === 'undefined') {
            // Focus the first enabled item
            this.focusedItem = this.viewItems.length - 1;
            this.focusNext();
        }
        else {
            if (index !== undefined) {
                this.focusedItem = index;
            }
            this.updateFocus();
        }
    };
    ActionBar.prototype.focusNext = function () {
        if (typeof this.focusedItem === 'undefined') {
            this.focusedItem = this.viewItems.length - 1;
        }
        var startIndex = this.focusedItem;
        var item;
        do {
            this.focusedItem = (this.focusedItem + 1) % this.viewItems.length;
            item = this.viewItems[this.focusedItem];
        } while (this.focusedItem !== startIndex && !item.isEnabled());
        if (this.focusedItem === startIndex && !item.isEnabled()) {
            this.focusedItem = undefined;
        }
        this.updateFocus();
    };
    ActionBar.prototype.focusPrevious = function () {
        if (typeof this.focusedItem === 'undefined') {
            this.focusedItem = 0;
        }
        var startIndex = this.focusedItem;
        var item;
        do {
            this.focusedItem = this.focusedItem - 1;
            if (this.focusedItem < 0) {
                this.focusedItem = this.viewItems.length - 1;
            }
            item = this.viewItems[this.focusedItem];
        } while (this.focusedItem !== startIndex && !item.isEnabled());
        if (this.focusedItem === startIndex && !item.isEnabled()) {
            this.focusedItem = undefined;
        }
        this.updateFocus(true);
    };
    ActionBar.prototype.updateFocus = function (fromRight, preventScroll) {
        if (typeof this.focusedItem === 'undefined') {
            this.actionsList.focus({ preventScroll: preventScroll });
        }
        for (var i = 0; i < this.viewItems.length; i++) {
            var item = this.viewItems[i];
            var actionViewItem = item;
            if (i === this.focusedItem) {
                if (types.isFunction(actionViewItem.isEnabled)) {
                    if (actionViewItem.isEnabled() && types.isFunction(actionViewItem.focus)) {
                        actionViewItem.focus(fromRight);
                    }
                    else {
                        this.actionsList.focus({ preventScroll: preventScroll });
                    }
                }
            }
            else {
                if (types.isFunction(actionViewItem.blur)) {
                    actionViewItem.blur();
                }
            }
        }
    };
    ActionBar.prototype.doTrigger = function (event) {
        if (typeof this.focusedItem === 'undefined') {
            return; //nothing to focus
        }
        // trigger action
        var actionViewItem = this.viewItems[this.focusedItem];
        if (actionViewItem instanceof BaseActionViewItem) {
            var context = (actionViewItem._context === null || actionViewItem._context === undefined) ? event : actionViewItem._context;
            this.run(actionViewItem._action, context);
        }
    };
    ActionBar.prototype.cancel = function () {
        if (document.activeElement instanceof HTMLElement) {
            document.activeElement.blur(); // remove focus from focused action
        }
        this._onDidCancel.fire();
    };
    ActionBar.prototype.run = function (action, context) {
        return this._actionRunner.run(action, context);
    };
    ActionBar.prototype.dispose = function () {
        dispose(this.viewItems);
        this.viewItems = [];
        DOM.removeNode(this.getContainer());
        _super.prototype.dispose.call(this);
    };
    return ActionBar;
}(Disposable));
export { ActionBar };
var SelectActionViewItem = /** @class */ (function (_super) {
    __extends(SelectActionViewItem, _super);
    function SelectActionViewItem(ctx, action, options, selected, contextViewProvider, selectBoxOptions) {
        var _this = _super.call(this, ctx, action) || this;
        _this.selectBox = new SelectBox(options, selected, contextViewProvider, undefined, selectBoxOptions);
        _this._register(_this.selectBox);
        _this.registerListeners();
        return _this;
    }
    SelectActionViewItem.prototype.setOptions = function (options, selected) {
        this.selectBox.setOptions(options, selected);
    };
    SelectActionViewItem.prototype.select = function (index) {
        this.selectBox.select(index);
    };
    SelectActionViewItem.prototype.registerListeners = function () {
        var _this = this;
        this._register(this.selectBox.onDidSelect(function (e) {
            _this.actionRunner.run(_this._action, _this.getActionContext(e.selected, e.index));
        }));
    };
    SelectActionViewItem.prototype.getActionContext = function (option, index) {
        return option;
    };
    SelectActionViewItem.prototype.focus = function () {
        if (this.selectBox) {
            this.selectBox.focus();
        }
    };
    SelectActionViewItem.prototype.blur = function () {
        if (this.selectBox) {
            this.selectBox.blur();
        }
    };
    SelectActionViewItem.prototype.render = function (container) {
        this.selectBox.render(container);
    };
    return SelectActionViewItem;
}(BaseActionViewItem));
export { SelectActionViewItem };
