UNPKG

@theia/core

Version:

Theia is a cloud & desktop IDE framework implemented in TypeScript.

371 lines • 15.9 kB
"use strict"; // ***************************************************************************** // Copyright (C) 2017 TypeFox and others. // // This program and the accompanying materials are made available under the // terms of the Eclipse Public License v. 2.0 which is available at // http://www.eclipse.org/legal/epl-2.0. // // This Source Code may also be made available under the following Secondary // Licenses when the conditions for such availability set forth in the Eclipse // Public License v. 2.0 are satisfied: GNU General Public License, version 2 // with the GNU Classpath Exception which is available at // https://www.gnu.org/software/classpath/license.html. // // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 // ***************************************************************************** var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.togglePinned = exports.lock = exports.pin = exports.unpin = exports.isPinned = exports.waitForHidden = exports.waitForRevealed = exports.waitForClosed = exports.addClipboardListener = exports.addKeyListener = exports.addEventListener = exports.EventListenerObject = exports.createIconButton = exports.setEnabled = exports.BaseWidget = exports.UnsafeWidgetUtilities = exports.DEFAULT_SCROLL_OPTIONS = exports.LOCKED_CLASS = exports.PINNED_CLASS = exports.FOCUS_CLASS = exports.SELECTED_CLASS = exports.CODICON_LOADING_CLASSES = exports.BUSY_CLASS = exports.COLLAPSED_CLASS = exports.CODICON_TREE_ITEM_CLASSES = exports.EXPANSION_TOGGLE_CLASS = exports.DISABLED_CLASS = exports.codicon = exports.codiconArray = exports.ACTION_ITEM = void 0; /* eslint-disable @typescript-eslint/no-explicit-any */ const inversify_1 = require("inversify"); const widgets_1 = require("@phosphor/widgets"); const messaging_1 = require("@phosphor/messaging"); const common_1 = require("../../common"); const keys_1 = require("../keyboard/keys"); const perfect_scrollbar_1 = require("perfect-scrollbar"); (0, inversify_1.decorate)((0, inversify_1.injectable)(), widgets_1.Widget); (0, inversify_1.decorate)((0, inversify_1.unmanaged)(), widgets_1.Widget, 0); __exportStar(require("@phosphor/widgets"), exports); __exportStar(require("@phosphor/messaging"), exports); exports.ACTION_ITEM = 'action-label'; function codiconArray(name, actionItem = false) { const array = ['codicon', `codicon-${name}`]; if (actionItem) { array.push(exports.ACTION_ITEM); } return array; } exports.codiconArray = codiconArray; function codicon(name, actionItem = false) { return `codicon codicon-${name}${actionItem ? ` ${exports.ACTION_ITEM}` : ''}`; } exports.codicon = codicon; exports.DISABLED_CLASS = 'theia-mod-disabled'; exports.EXPANSION_TOGGLE_CLASS = 'theia-ExpansionToggle'; exports.CODICON_TREE_ITEM_CLASSES = codiconArray('chevron-down'); exports.COLLAPSED_CLASS = 'theia-mod-collapsed'; exports.BUSY_CLASS = 'theia-mod-busy'; exports.CODICON_LOADING_CLASSES = codiconArray('loading'); exports.SELECTED_CLASS = 'theia-mod-selected'; exports.FOCUS_CLASS = 'theia-mod-focus'; exports.PINNED_CLASS = 'theia-mod-pinned'; exports.LOCKED_CLASS = 'theia-mod-locked'; exports.DEFAULT_SCROLL_OPTIONS = { suppressScrollX: true, minScrollbarLength: 35, }; /** * At a number of places in the code, we have effectively reimplemented Phosphor's Widget.attach and Widget.detach, * but omitted the checks that Phosphor expects to be performed for those operations. That is a bad idea, because it * means that we are telling widgets that they are attached or detached when not all the conditions that should apply * do apply. We should explicitly mark those locations so that we know where we should go fix them later. */ var UnsafeWidgetUtilities; (function (UnsafeWidgetUtilities) { /** * Ordinarily, the following checks should be performed before detaching a widget: * It should not be the child of another widget * It should be attached and it should be a child of document.body */ function detach(widget) { messaging_1.MessageLoop.sendMessage(widget, widgets_1.Widget.Msg.BeforeDetach); widget.node.remove(); messaging_1.MessageLoop.sendMessage(widget, widgets_1.Widget.Msg.AfterDetach); } UnsafeWidgetUtilities.detach = detach; ; /** * @param ref The child of the host element to insert the widget before. * Ordinarily the following checks should be performed: * The widget should have no parent * The widget should not be attached, and its node should not be a child of document.body * The host should be a child of document.body * We often violate the last condition. */ // eslint-disable-next-line no-null/no-null function attach(widget, host, ref = null) { messaging_1.MessageLoop.sendMessage(widget, widgets_1.Widget.Msg.BeforeAttach); host.insertBefore(widget.node, ref); messaging_1.MessageLoop.sendMessage(widget, widgets_1.Widget.Msg.AfterAttach); } UnsafeWidgetUtilities.attach = attach; ; })(UnsafeWidgetUtilities = exports.UnsafeWidgetUtilities || (exports.UnsafeWidgetUtilities = {})); let BaseWidget = class BaseWidget extends widgets_1.Widget { constructor() { super(...arguments); this.onScrollYReachEndEmitter = new common_1.Emitter(); this.onScrollYReachEnd = this.onScrollYReachEndEmitter.event; this.onScrollUpEmitter = new common_1.Emitter(); this.onScrollUp = this.onScrollUpEmitter.event; this.onDidChangeVisibilityEmitter = new common_1.Emitter(); this.onDidChangeVisibility = this.onDidChangeVisibilityEmitter.event; this.onDidDisposeEmitter = new common_1.Emitter(); this.onDidDispose = this.onDidDisposeEmitter.event; this.toDispose = new common_1.DisposableCollection(this.onDidDisposeEmitter, common_1.Disposable.create(() => this.onDidDisposeEmitter.fire()), this.onScrollYReachEndEmitter, this.onScrollUpEmitter, this.onDidChangeVisibilityEmitter); this.toDisposeOnDetach = new common_1.DisposableCollection(); } dispose() { if (this.isDisposed) { return; } super.dispose(); this.toDispose.dispose(); } onCloseRequest(msg) { super.onCloseRequest(msg); this.dispose(); } onBeforeAttach(msg) { if (this.title.iconClass === '') { this.title.iconClass = 'no-icon'; } super.onBeforeAttach(msg); } onAfterDetach(msg) { if (this.title.iconClass === 'no-icon') { this.title.iconClass = ''; } super.onAfterDetach(msg); } onBeforeDetach(msg) { this.toDisposeOnDetach.dispose(); super.onBeforeDetach(msg); } onAfterAttach(msg) { super.onAfterAttach(msg); if (this.scrollOptions) { (async () => { const container = await this.getScrollContainer(); container.style.overflow = 'hidden'; this.scrollBar = new perfect_scrollbar_1.default(container, this.scrollOptions); this.disableScrollBarFocus(container); this.toDisposeOnDetach.push(addEventListener(container, 'ps-y-reach-end', () => { this.onScrollYReachEndEmitter.fire(undefined); })); this.toDisposeOnDetach.push(addEventListener(container, 'ps-scroll-up', () => { this.onScrollUpEmitter.fire(undefined); })); this.toDisposeOnDetach.push(common_1.Disposable.create(() => { if (this.scrollBar) { this.scrollBar.destroy(); this.scrollBar = undefined; } container.style.overflow = 'initial'; })); })(); } } getScrollContainer() { return this.node; } disableScrollBarFocus(scrollContainer) { for (const thumbs of [scrollContainer.getElementsByClassName('ps__thumb-x'), scrollContainer.getElementsByClassName('ps__thumb-y')]) { for (let i = 0; i < thumbs.length; i++) { const element = thumbs.item(i); if (element) { element.removeAttribute('tabIndex'); } } } } onUpdateRequest(msg) { super.onUpdateRequest(msg); if (this.scrollBar) { this.scrollBar.update(); } } addUpdateListener(element, type, useCapture) { this.addEventListener(element, type, e => { this.update(); e.preventDefault(); }, useCapture); } addEventListener(element, type, listener, useCapture) { this.toDisposeOnDetach.push(addEventListener(element, type, listener, useCapture)); } addKeyListener(element, keysOrKeyCodes, action, ...additionalEventTypes) { this.toDisposeOnDetach.push(addKeyListener(element, keysOrKeyCodes, action, ...additionalEventTypes)); } addClipboardListener(element, type, listener) { this.toDisposeOnDetach.push(addClipboardListener(element, type, listener)); } setFlag(flag) { super.setFlag(flag); if (flag === widgets_1.Widget.Flag.IsVisible) { this.onDidChangeVisibilityEmitter.fire(this.isVisible); } } clearFlag(flag) { super.clearFlag(flag); if (flag === widgets_1.Widget.Flag.IsVisible) { this.onDidChangeVisibilityEmitter.fire(this.isVisible); } } }; BaseWidget = __decorate([ (0, inversify_1.injectable)() ], BaseWidget); exports.BaseWidget = BaseWidget; function setEnabled(element, enabled) { element.classList.toggle(exports.DISABLED_CLASS, !enabled); element.tabIndex = enabled ? 0 : -1; } exports.setEnabled = setEnabled; function createIconButton(...classNames) { const icon = document.createElement('i'); icon.classList.add(...classNames); const button = document.createElement('span'); button.tabIndex = 0; button.appendChild(icon); return button; } exports.createIconButton = createIconButton; var EventListenerObject; (function (EventListenerObject) { function is(listener) { return (0, common_1.isObject)(listener) && 'handleEvent' in listener; } EventListenerObject.is = is; })(EventListenerObject = exports.EventListenerObject || (exports.EventListenerObject = {})); function addEventListener(element, type, listener, useCapture) { element.addEventListener(type, listener, useCapture); return common_1.Disposable.create(() => element.removeEventListener(type, listener, useCapture)); } exports.addEventListener = addEventListener; function addKeyListener(element, keysOrKeyCodes, action, ...additionalEventTypes) { const toDispose = new common_1.DisposableCollection(); const keyCodePredicate = (() => { if (typeof keysOrKeyCodes === 'function') { return keysOrKeyCodes; } else { return (actual) => keys_1.KeysOrKeyCodes.toKeyCodes(keysOrKeyCodes).some(k => k.equals(actual)); } })(); toDispose.push(addEventListener(element, 'keydown', e => { const kc = keys_1.KeyCode.createKeyCode(e); if (keyCodePredicate(kc)) { const result = action(e); if (typeof result !== 'boolean' || result) { e.stopPropagation(); e.preventDefault(); } } })); for (const type of additionalEventTypes) { toDispose.push(addEventListener(element, type, e => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const event = type['keydown']; const result = action(event); if (typeof result !== 'boolean' || result) { e.stopPropagation(); e.preventDefault(); } })); } return toDispose; } exports.addKeyListener = addKeyListener; function addClipboardListener(element, type, listener) { const documentListener = (e) => { const activeElement = document.activeElement; if (activeElement && element.contains(activeElement)) { if (EventListenerObject.is(listener)) { listener.handleEvent(e); } else { listener.bind(element)(e); } } }; document.addEventListener(type, documentListener); return common_1.Disposable.create(() => document.removeEventListener(type, documentListener)); } exports.addClipboardListener = addClipboardListener; /** * Resolves when the given widget is detached and hidden. */ function waitForClosed(widget) { return waitForVisible(widget, false, false); } exports.waitForClosed = waitForClosed; /** * Resolves when the given widget is attached and visible. */ function waitForRevealed(widget) { return waitForVisible(widget, true, true); } exports.waitForRevealed = waitForRevealed; /** * Resolves when the given widget is hidden regardless of attachment. */ function waitForHidden(widget) { return waitForVisible(widget, true); } exports.waitForHidden = waitForHidden; function waitForVisible(widget, visible, attached) { if ((typeof attached !== 'boolean' || widget.isAttached === attached) && (widget.isVisible === visible || (widget.node.style.visibility !== 'hidden') === visible)) { return new Promise(resolve => window.requestAnimationFrame(() => resolve())); } return new Promise(resolve => { const waitFor = () => window.requestAnimationFrame(() => { if ((typeof attached !== 'boolean' || widget.isAttached === attached) && (widget.isVisible === visible || (widget.node.style.visibility !== 'hidden') === visible)) { window.requestAnimationFrame(() => resolve()); } else { waitFor(); } }); waitFor(); }); } function isPinned(title) { const pinnedState = !title.closable && title.className.includes(exports.PINNED_CLASS); return pinnedState; } exports.isPinned = isPinned; function unpin(title) { title.closable = true; title.className = title.className.replace(exports.PINNED_CLASS, '').trim(); } exports.unpin = unpin; function pin(title) { title.closable = false; if (!title.className.includes(exports.PINNED_CLASS)) { title.className += ` ${exports.PINNED_CLASS}`; } } exports.pin = pin; function lock(title) { if (!title.className.includes(exports.LOCKED_CLASS)) { title.className += ` ${exports.LOCKED_CLASS}`; } } exports.lock = lock; function togglePinned(title) { if (title) { if (isPinned(title)) { unpin(title); } else { pin(title); } } } exports.togglePinned = togglePinned; //# sourceMappingURL=widget.js.map