@theia/core
Version:
Theia is a cloud & desktop IDE framework implemented in TypeScript.
371 lines • 15.9 kB
JavaScript
// *****************************************************************************
// 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
;