UNPKG

monaco-editor

Version:
601 lines (600 loc) • 24.2 kB
/*--------------------------------------------------------------------------------------------- * 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.js'; import * as nls from '../../../../nls.js'; import { Disposable, dispose } from '../../../common/lifecycle.js'; import { Action, ActionRunner } from '../../../common/actions.js'; import * as DOM from '../../dom.js'; import * as types from '../../../common/types.js'; import { EventType, Gesture } from '../../touch.js'; import { StandardKeyboardEvent } from '../../keyboardEvent.js'; import { Emitter } from '../../../common/event.js'; var BaseActionItem = /** @class */ (function (_super) { __extends(BaseActionItem, _super); function BaseActionItem(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; } BaseActionItem.prototype.handleActionChangeEvent = function (event) { if (event.enabled !== void 0) { this.updateEnabled(); } if (event.checked !== void 0) { this.updateChecked(); } if (event.class !== void 0) { this.updateClass(); } if (event.label !== void 0) { this.updateLabel(); this.updateTooltip(); } if (event.tooltip !== void 0) { this.updateTooltip(); } }; Object.defineProperty(BaseActionItem.prototype, "actionRunner", { get: function () { return this._actionRunner; }, set: function (actionRunner) { this._actionRunner = actionRunner; }, enumerable: true, configurable: true }); BaseActionItem.prototype.getAction = function () { return this._action; }; BaseActionItem.prototype.isEnabled = function () { return this._action.enabled; }; BaseActionItem.prototype.setActionContext = function (newContext) { this._context = newContext; }; BaseActionItem.prototype.render = function (container) { var _this = this; this.element = container; Gesture.addTarget(container); var enableDragging = this.options && this.options.draggable; if (enableDragging) { container.draggable = true; } this._register(DOM.addDisposableListener(this.element, EventType.Tap, function (e) { return _this.onClick(e); })); this._register(DOM.addDisposableListener(this.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 } var mouseEvent = e; if (_this._action.enabled && mouseEvent.button === 0) { DOM.addClass(_this.element, 'active'); } })); this._register(DOM.addDisposableListener(this.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(this.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(_this.element, event, function (e) { DOM.EventHelper.stop(e); DOM.removeClass(_this.element, 'active'); })); }); }; BaseActionItem.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); }; BaseActionItem.prototype.focus = function () { if (this.element) { this.element.focus(); DOM.addClass(this.element, 'focused'); } }; BaseActionItem.prototype.blur = function () { if (this.element) { this.element.blur(); DOM.removeClass(this.element, 'focused'); } }; BaseActionItem.prototype.updateEnabled = function () { // implement in subclass }; BaseActionItem.prototype.updateLabel = function () { // implement in subclass }; BaseActionItem.prototype.updateTooltip = function () { // implement in subclass }; BaseActionItem.prototype.updateClass = function () { // implement in subclass }; BaseActionItem.prototype.updateChecked = function () { // implement in subclass }; BaseActionItem.prototype.dispose = function () { if (this.element) { DOM.removeNode(this.element); this.element = null; } _super.prototype.dispose.call(this); }; return BaseActionItem; }(Disposable)); export { BaseActionItem }; 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.radio = false; _this.enabled = false; return _this; } Separator.ID = 'vs.actions.separator'; return Separator; }(Action)); export { Separator }; var ActionItem = /** @class */ (function (_super) { __extends(ActionItem, _super); function ActionItem(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; } ActionItem.prototype.render = function (container) { _super.prototype.render.call(this, container); this.label = DOM.append(this.element, DOM.$('a.action-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) { DOM.append(this.element, DOM.$('span.keybinding')).textContent = this.options.keybinding; } this.updateClass(); this.updateLabel(); this.updateTooltip(); this.updateEnabled(); this.updateChecked(); }; ActionItem.prototype.focus = function () { _super.prototype.focus.call(this); this.label.focus(); }; ActionItem.prototype.updateLabel = function () { if (this.options.label) { this.label.textContent = this.getAction().label; } }; ActionItem.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.title = title; } }; ActionItem.prototype.updateClass = function () { if (this.cssClass) { DOM.removeClasses(this.label, this.cssClass); } if (this.options.icon) { this.cssClass = this.getAction().class; DOM.addClass(this.label, 'icon'); if (this.cssClass) { DOM.addClasses(this.label, this.cssClass); } this.updateEnabled(); } else { DOM.removeClass(this.label, 'icon'); } }; ActionItem.prototype.updateEnabled = function () { if (this.getAction().enabled) { this.label.removeAttribute('aria-disabled'); DOM.removeClass(this.element, 'disabled'); DOM.removeClass(this.label, 'disabled'); this.label.tabIndex = 0; } else { this.label.setAttribute('aria-disabled', 'true'); DOM.addClass(this.element, 'disabled'); DOM.addClass(this.label, 'disabled'); DOM.removeTabIndexAndUpdateFocus(this.label); } }; ActionItem.prototype.updateChecked = function () { if (this.getAction().checked) { DOM.addClass(this.label, 'checked'); } else { DOM.removeClass(this.label, 'checked'); } }; return ActionItem; }(BaseActionItem)); export { ActionItem }; 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._onDidCancel = _this._register(new Emitter()); _this._onDidRun = _this._register(new Emitter()); _this._onDidBeforeRun = _this._register(new Emitter()); _this.options = options; _this._context = options.context; _this._actionRunner = _this.options.actionRunner; if (!_this.options.triggerKeys) { _this.options.triggerKeys = defaultOptions.triggerKeys; } if (!_this._actionRunner) { _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.items = []; _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.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; } Object.defineProperty(ActionBar.prototype, "onDidBlur", { get: function () { return this._onDidBlur.event; }, enumerable: true, configurable: true }); Object.defineProperty(ActionBar.prototype, "onDidCancel", { get: function () { return this._onDidCancel.event; }, enumerable: true, configurable: true }); Object.defineProperty(ActionBar.prototype, "onDidRun", { get: function () { return this._onDidRun.event; }, enumerable: true, configurable: true }); Object.defineProperty(ActionBar.prototype, "onDidBeforeRun", { get: function () { return this._onDidBeforeRun.event; }, enumerable: true, configurable: true }); 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.items.forEach(function (i) { return i.setActionContext(context); }); }, 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 actionItemElement = document.createElement('li'); actionItemElement.className = 'action-item'; actionItemElement.setAttribute('role', 'presentation'); // Prevent native context menu on actions _this._register(DOM.addDisposableListener(actionItemElement, DOM.EventType.CONTEXT_MENU, function (e) { e.preventDefault(); e.stopPropagation(); })); var item = null; if (_this.options.actionItemProvider) { item = _this.options.actionItemProvider(action); } if (!item) { item = new ActionItem(_this.context, action, options); } item.actionRunner = _this._actionRunner; item.setActionContext(_this.context); item.render(actionItemElement); if (index === null || index < 0 || index >= _this.actionsList.children.length) { _this.actionsList.appendChild(actionItemElement); _this.items.push(item); } else { _this.actionsList.insertBefore(actionItemElement, _this.actionsList.children[index]); _this.items.splice(index, 0, item); index++; } }); }; ActionBar.prototype.clear = function () { this.items = dispose(this.items); DOM.clearNode(this.actionsList); }; ActionBar.prototype.isEmpty = function () { return this.items.length === 0; }; ActionBar.prototype.focus = function (selectFirst) { if (selectFirst && typeof this.focusedItem === 'undefined') { // Focus the first enabled item this.focusedItem = this.items.length - 1; this.focusNext(); } else { this.updateFocus(); } }; ActionBar.prototype.focusNext = function () { if (typeof this.focusedItem === 'undefined') { this.focusedItem = this.items.length - 1; } var startIndex = this.focusedItem; var item; do { this.focusedItem = (this.focusedItem + 1) % this.items.length; item = this.items[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.items.length - 1; } item = this.items[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) { if (typeof this.focusedItem === 'undefined') { this.actionsList.focus(); } for (var i = 0; i < this.items.length; i++) { var item = this.items[i]; var actionItem = item; if (i === this.focusedItem) { if (types.isFunction(actionItem.isEnabled)) { if (actionItem.isEnabled() && types.isFunction(actionItem.focus)) { actionItem.focus(fromRight); } else { this.actionsList.focus(); } } } else { if (types.isFunction(actionItem.blur)) { actionItem.blur(); } } } }; ActionBar.prototype.doTrigger = function (event) { if (typeof this.focusedItem === 'undefined') { return; //nothing to focus } // trigger action var actionItem = this.items[this.focusedItem]; if (actionItem instanceof BaseActionItem) { var context_1 = (actionItem._context === null || actionItem._context === undefined) ? event : actionItem._context; this.run(actionItem._action, context_1); } }; 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 () { if (this.items !== null) { dispose(this.items); } this.items = null; DOM.removeNode(this.getContainer()); _super.prototype.dispose.call(this); }; return ActionBar; }(Disposable)); export { ActionBar };