UNPKG

dockview-core

Version:

Zero dependency layout manager supporting tabs, groups, grids and splitviews for vanilla TypeScript

995 lines 154 kB
"use strict"; 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 (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DockviewComponent = void 0; var gridview_1 = require("../gridview/gridview"); var droptarget_1 = require("../dnd/droptarget"); var backend_1 = require("../dnd/backend"); var array_1 = require("../array"); var dockviewPanel_1 = require("./dockviewPanel"); var lifecycle_1 = require("../lifecycle"); var events_1 = require("../events"); var watermark_1 = require("./components/watermark/watermark"); var math_1 = require("../math"); var deserializer_1 = require("./deserializer"); var options_1 = require("./options"); var baseComponentGridview_1 = require("../gridview/baseComponentGridview"); var component_api_1 = require("../api/component.api"); var splitview_1 = require("../splitview/splitview"); var dockviewGroupPanelModel_1 = require("./dockviewGroupPanelModel"); var events_2 = require("./events"); var dockviewGroupPanel_1 = require("./dockviewGroupPanel"); var dockviewPanelModel_1 = require("./dockviewPanelModel"); var dataTransfer_1 = require("../dnd/dataTransfer"); var overlay_1 = require("../overlay/overlay"); var dom_1 = require("../dom"); var dockviewFloatingGroupPanel_1 = require("./dockviewFloatingGroupPanel"); var constants_1 = require("../constants"); var overlayRenderContainer_1 = require("../overlay/overlayRenderContainer"); var popoutWindow_1 = require("../popoutWindow"); var strictEventsSequencing_1 = require("./strictEventsSequencing"); var popupService_1 = require("./components/popupService"); var contextMenu_1 = require("./contextMenu"); var dropTargetAnchorContainer_1 = require("../dnd/dropTargetAnchorContainer"); var theme_1 = require("./theme"); var dockviewShell_1 = require("./dockviewShell"); var tabGroupAccent_1 = require("./tabGroupAccent"); var DEFAULT_ROOT_OVERLAY_MODEL = { activationSize: { type: 'pixels', value: 10 }, size: { type: 'pixels', value: 20 }, }; function buildTabGroupColorPalette(options) { var _a; var entries = (_a = options.tabGroupColors) !== null && _a !== void 0 ? _a : tabGroupAccent_1.DEFAULT_TAB_GROUP_COLORS; var enabled = options.tabGroupAccent !== 'off'; return new tabGroupAccent_1.TabGroupColorPalette(entries, enabled); } function moveGroupWithoutDestroying(options) { var activePanel = options.from.activePanel; var panels = __spreadArray([], __read(options.from.panels), false).map(function (panel) { var removedPanel = options.from.model.removePanel(panel); options.from.model.renderContainer.detatch(panel); return removedPanel; }); panels.forEach(function (panel) { options.to.model.openPanel(panel, { skipSetActive: activePanel !== panel, skipSetGroupActive: true, }); }); } var DockviewComponent = /** @class */ (function (_super) { __extends(DockviewComponent, _super); function DockviewComponent(container, options) { var _a, _b, _c, _d, _e, _f, _g; var _this = _super.call(this, container, { proportionalLayout: true, orientation: splitview_1.Orientation.HORIZONTAL, styles: options.hideBorders ? { separatorBorder: 'transparent' } : undefined, disableAutoResizing: options.disableAutoResizing, locked: options.locked, margin: (_b = (_a = options.theme) === null || _a === void 0 ? void 0 : _a.gap) !== null && _b !== void 0 ? _b : 0, className: options.className, }) || this; _this.nextGroupId = (0, math_1.sequentialNumberGenerator)(); _this._deserializer = new deserializer_1.DefaultDockviewDeserialzier(_this); _this._watermark = null; _this._popoutPopupServices = new Map(); _this._onWillDragPanel = new events_1.Emitter(); _this.onWillDragPanel = _this._onWillDragPanel.event; _this._onWillDragGroup = new events_1.Emitter(); _this.onWillDragGroup = _this._onWillDragGroup.event; _this._onDidDrop = new events_1.Emitter(); _this.onDidDrop = _this._onDidDrop.event; _this._onWillDrop = new events_1.Emitter(); _this.onWillDrop = _this._onWillDrop.event; _this._onWillShowOverlay = new events_1.Emitter(); _this.onWillShowOverlay = _this._onWillShowOverlay.event; _this._onUnhandledDragOverEvent = new events_1.Emitter(); _this.onUnhandledDragOverEvent = _this._onUnhandledDragOverEvent.event; _this._onDidRemovePanel = new events_1.Emitter(); _this.onDidRemovePanel = _this._onDidRemovePanel.event; _this._onDidAddPanel = new events_1.Emitter(); _this.onDidAddPanel = _this._onDidAddPanel.event; _this._onDidPopoutGroupSizeChange = new events_1.Emitter(); _this.onDidPopoutGroupSizeChange = _this._onDidPopoutGroupSizeChange.event; _this._onDidPopoutGroupPositionChange = new events_1.Emitter(); _this.onDidPopoutGroupPositionChange = _this._onDidPopoutGroupPositionChange.event; _this._onDidOpenPopoutWindowFail = new events_1.Emitter(); _this.onDidOpenPopoutWindowFail = _this._onDidOpenPopoutWindowFail.event; _this._onDidLayoutFromJSON = new events_1.Emitter(); _this.onDidLayoutFromJSON = _this._onDidLayoutFromJSON.event; _this._onDidActivePanelChange = new events_1.Emitter({ replay: true }); _this.onDidActivePanelChange = _this._onDidActivePanelChange.event; _this._onDidMovePanel = new events_1.Emitter(); _this.onDidMovePanel = _this._onDidMovePanel.event; _this._onDidCreateTabGroup = new events_1.Emitter(); _this.onDidCreateTabGroup = _this._onDidCreateTabGroup.event; _this._onDidDestroyTabGroup = new events_1.Emitter(); _this.onDidDestroyTabGroup = _this._onDidDestroyTabGroup.event; _this._onDidAddPanelToTabGroup = new events_1.Emitter(); _this.onDidAddPanelToTabGroup = _this._onDidAddPanelToTabGroup.event; _this._onDidRemovePanelFromTabGroup = new events_1.Emitter(); _this.onDidRemovePanelFromTabGroup = _this._onDidRemovePanelFromTabGroup.event; _this._onDidTabGroupChange = new events_1.Emitter(); _this.onDidTabGroupChange = _this._onDidTabGroupChange.event; _this._onDidTabGroupCollapsedChange = new events_1.Emitter(); _this.onDidTabGroupCollapsedChange = _this._onDidTabGroupCollapsedChange.event; _this._onDidMaximizedGroupChange = new events_1.Emitter(); _this.onDidMaximizedGroupChange = _this._onDidMaximizedGroupChange.event; _this._inShellLayout = false; _this._edgeGroups = new Map(); _this._edgeGroupDisposables = new Map(); _this._floatingGroups = []; _this._popoutGroups = []; _this._popoutRestorationPromise = Promise.resolve(); _this._popoutRestorationCleanups = new Set(); _this._onDidRemoveGroup = new events_1.Emitter(); _this.onDidRemoveGroup = _this._onDidRemoveGroup.event; _this._onDidAddGroup = new events_1.Emitter(); _this.onDidAddGroup = _this._onDidAddGroup.event; _this._onDidOptionsChange = new events_1.Emitter(); _this.onDidOptionsChange = _this._onDidOptionsChange.event; _this._onDidActiveGroupChange = new events_1.Emitter(); _this.onDidActiveGroupChange = _this._onDidActiveGroupChange.event; _this._moving = false; _this._options = options; _this._tabGroupColorPalette = buildTabGroupColorPalette(options); _this.popupService = new popupService_1.PopupService(_this.element); _this.contextMenuController = new contextMenu_1.ContextMenuController(_this); _this._api = new component_api_1.DockviewApi(_this); // The shell always wraps the dockview element so edge groups can be // added at any time via addEdgeGroup() without re-parenting the DOM. _this.disableResizing = true; container.removeChild(_this.element); _this._shellManager = new dockviewShell_1.ShellManager(container, _this.element, function (w, h) { return _this._layoutFromShell(w, h); }, (_d = (_c = options.theme) === null || _c === void 0 ? void 0 : _c.gap) !== null && _d !== void 0 ? _d : 0, (_e = options.theme) === null || _e === void 0 ? void 0 : _e.edgeGroupCollapsedSize); // The shell wraps the dockview element, so move the popup anchor // into the shell so overflow dropdowns in edge groups position correctly _this.popupService.updateRoot(_this._shellManager.element); _this._shellThemeClassnames = new dom_1.Classnames(_this._shellManager.element); // Anchor the overlay container to the shell element so that edge groups // (which live outside this.element in the shell layout) are covered when // dndOverlayMounting is 'absolute'. _this.rootDropTargetContainer = new dropTargetAnchorContainer_1.DropTargetAnchorContainer(_this._shellManager.element, { disabled: true }); _this.overlayRenderContainer = new overlayRenderContainer_1.OverlayRenderContainer(_this._shellManager.element, _this); // Hosted in the shell (not inside `.dv-dockview`) so floating overlays // share a stacking context with `dv-render-overlay` panels; sized to // mirror the gridview rect so saved positions remain valid. _this._floatingOverlayHost = document.createElement('div'); _this._floatingOverlayHost.className = 'dv-floating-overlay-host'; _this._shellManager.element.appendChild(_this._floatingOverlayHost); var rootCanDisplayOverlay = function (event, position) { var data = (0, dataTransfer_1.getPanelData)(); if (data) { if (data.viewId !== _this.id) { return false; } if (position === 'center') { // center drop target is only allowed if there are no panels in the grid // floating panels are allowed return _this.gridview.length === 0; } return true; } if (position === 'center' && _this.gridview.length !== 0) { /** * for external events only show the four-corner drag overlays, disable * the center position so that external drag events can fall through to the group * and panel drop target handlers */ return false; } var firedEvent = new options_1.DockviewUnhandledDragOverEvent(event, 'edge', position, dataTransfer_1.getPanelData); _this._onUnhandledDragOverEvent.fire(firedEvent); return firedEvent.isAccepted; }; _this._rootDropTarget = backend_1.html5Backend.createDropTarget(_this.element, { className: 'dv-drop-target-edge', canDisplayOverlay: rootCanDisplayOverlay, acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'], overlayModel: (_f = options.rootOverlayModel) !== null && _f !== void 0 ? _f : DEFAULT_ROOT_OVERLAY_MODEL, getOverrideTarget: function () { var _a; return (_a = _this.rootDropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; }, }); _this._rootPointerDropTarget = backend_1.pointerBackend.createDropTarget(_this.element, { className: 'dv-drop-target-edge', canDisplayOverlay: rootCanDisplayOverlay, acceptedTargetZones: [ 'top', 'bottom', 'left', 'right', 'center', ], overlayModel: (_g = options.rootOverlayModel) !== null && _g !== void 0 ? _g : DEFAULT_ROOT_OVERLAY_MODEL, getOverrideTarget: function () { var _a; return (_a = _this.rootDropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; }, }); _this.updateDropTargetModel(options); (0, dom_1.toggleClass)(_this.gridview.element, 'dv-dockview', true); (0, dom_1.toggleClass)(_this.element, 'dv-debug', !!options.debug); _this.updateTheme(); _this.updateWatermark(); if (options.debug) { _this.addDisposables(new strictEventsSequencing_1.StrictEventsSequencing(_this)); } _this.addDisposables(_this.rootDropTargetContainer, _this.overlayRenderContainer, _this._onWillDragPanel, _this._onWillDragGroup, _this._onWillShowOverlay, _this._onDidActivePanelChange, _this._onDidAddPanel, _this._onDidRemovePanel, _this._onDidLayoutFromJSON, _this._onDidDrop, _this._onWillDrop, _this._onDidMovePanel, _this._onDidMovePanel.event(function () { /** * Update overlay positions after DOM layout completes to prevent 0×0 dimensions. * With defaultRenderer="always" this results in panel content not showing after move operations. * Debounced to avoid multiple calls when moving groups with multiple panels. */ _this.debouncedUpdateAllPositions(); }), _this._onDidAddGroup, _this._onDidRemoveGroup, _this._onDidActiveGroupChange, _this._onUnhandledDragOverEvent, _this._onDidMaximizedGroupChange, _this._onDidOptionsChange, _this._onDidPopoutGroupSizeChange, _this._onDidPopoutGroupPositionChange, _this._onDidOpenPopoutWindowFail, _this._onDidCreateTabGroup, _this._onDidDestroyTabGroup, _this._onDidAddPanelToTabGroup, _this._onDidRemovePanelFromTabGroup, _this._onDidTabGroupChange, _this._onDidTabGroupCollapsedChange, _this.onDidViewVisibilityChangeMicroTaskQueue(function () { _this.updateWatermark(); }), _this.onDidAdd(function (event) { if (!_this._moving) { _this._onDidAddGroup.fire(event); } }), _this.onDidRemove(function (event) { if (!_this._moving) { _this._onDidRemoveGroup.fire(event); } }), _this.onDidActiveChange(function (event) { if (!_this._moving) { _this._onDidActiveGroupChange.fire(event); } }), _this.onDidMaximizedChange(function (event) { _this._onDidMaximizedGroupChange.fire({ group: event.panel, isMaximized: event.isMaximized, }); }), events_1.Event.any(_this.onDidAdd, _this.onDidRemove)(function () { _this.updateWatermark(); }), events_1.Event.any(_this.onDidAddPanel, _this.onDidRemovePanel, _this.onDidAddGroup, _this.onDidRemove, _this.onDidRemoveGroup, _this.onDidMovePanel, _this.onDidActivePanelChange, _this.onDidPopoutGroupPositionChange, _this.onDidPopoutGroupSizeChange, _this.onDidCreateTabGroup, _this.onDidDestroyTabGroup, _this.onDidAddPanelToTabGroup, _this.onDidRemovePanelFromTabGroup, _this.onDidTabGroupChange, _this.onDidTabGroupCollapsedChange)(function () { _this._bufferOnDidLayoutChange.fire(); }), lifecycle_1.Disposable.from(function () { var e_1, _a, e_2, _b, e_3, _c, e_4, _d; var _e; try { // Cancel any pending popout-restoration timers scheduled by // fromJSON so they don't open new browser windows after // dispose, and resolve their promises so callers awaiting // popoutRestorationPromise don't hang. See issue #851. for (var _f = __values(__spreadArray([], __read(_this._popoutRestorationCleanups), false)), _g = _f.next(); !_g.done; _g = _f.next()) { var cleanup = _g.value; cleanup(); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_g && !_g.done && (_a = _f.return)) _a.call(_f); } finally { if (e_1) throw e_1.error; } } _this._popoutRestorationCleanups.clear(); try { // iterate over a copy of the array since .dispose() mutates the original array for (var _h = __values(__spreadArray([], __read(_this._floatingGroups), false)), _j = _h.next(); !_j.done; _j = _h.next()) { var group = _j.value; group.dispose(); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_j && !_j.done && (_b = _h.return)) _b.call(_h); } finally { if (e_2) throw e_2.error; } } try { // iterate over a copy of the array since .dispose() mutates the original array for (var _k = __values(__spreadArray([], __read(_this._popoutGroups), false)), _l = _k.next(); !_l.done; _l = _k.next()) { var group = _l.value; group.disposable.dispose(); } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (_l && !_l.done && (_c = _k.return)) _c.call(_k); } finally { if (e_3) throw e_3.error; } } (_e = _this._shellManager) === null || _e === void 0 ? void 0 : _e.dispose(); try { for (var _m = __values(_this._edgeGroupDisposables.values()), _o = _m.next(); !_o.done; _o = _m.next()) { var d = _o.value; d.dispose(); } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (_o && !_o.done && (_d = _m.return)) _d.call(_m); } finally { if (e_4) throw e_4.error; } } _this._edgeGroupDisposables.clear(); }), _this._rootDropTarget, _this._rootPointerDropTarget, events_1.Event.any(_this._rootDropTarget.onWillShowOverlay, _this._rootPointerDropTarget.onWillShowOverlay)(function (event) { if (_this.gridview.length > 0 && event.position === 'center') { // option only available when no panels in primary grid return; } _this._onWillShowOverlay.fire(new events_2.DockviewWillShowOverlayLocationEvent(event, { kind: 'edge', panel: undefined, api: _this._api, group: undefined, getData: dataTransfer_1.getPanelData, })); }), events_1.Event.any(_this._rootDropTarget.onDrop, _this._rootPointerDropTarget.onDrop)(function (event) { var _a; var willDropEvent = new dockviewGroupPanelModel_1.DockviewWillDropEvent({ nativeEvent: event.nativeEvent, position: event.position, panel: undefined, api: _this._api, group: undefined, getData: dataTransfer_1.getPanelData, kind: 'edge', }); _this._onWillDrop.fire(willDropEvent); if (willDropEvent.defaultPrevented) { return; } var data = (0, dataTransfer_1.getPanelData)(); if (data) { _this.moveGroupOrPanel({ from: { groupId: data.groupId, panelId: (_a = data.panelId) !== null && _a !== void 0 ? _a : undefined, }, to: { group: _this.orthogonalize(event.position), position: 'center', }, }); } else { _this._onDidDrop.fire(new dockviewGroupPanelModel_1.DockviewDidDropEvent({ nativeEvent: event.nativeEvent, position: event.position, panel: undefined, api: _this._api, group: undefined, getData: dataTransfer_1.getPanelData, })); } })); return _this; } Object.defineProperty(DockviewComponent.prototype, "orientation", { get: function () { return this.gridview.orientation; }, enumerable: false, configurable: true }); Object.defineProperty(DockviewComponent.prototype, "totalPanels", { get: function () { return this.panels.length; }, enumerable: false, configurable: true }); Object.defineProperty(DockviewComponent.prototype, "panels", { get: function () { return this.groups.flatMap(function (group) { return group.panels; }); }, enumerable: false, configurable: true }); Object.defineProperty(DockviewComponent.prototype, "options", { get: function () { return this._options; }, enumerable: false, configurable: true }); Object.defineProperty(DockviewComponent.prototype, "tabGroupColorPalette", { get: function () { return this._tabGroupColorPalette; }, enumerable: false, configurable: true }); Object.defineProperty(DockviewComponent.prototype, "activePanel", { get: function () { var activeGroup = this.activeGroup; if (!activeGroup) { return undefined; } return activeGroup.activePanel; }, enumerable: false, configurable: true }); Object.defineProperty(DockviewComponent.prototype, "renderer", { get: function () { var _a; return (_a = this.options.defaultRenderer) !== null && _a !== void 0 ? _a : 'onlyWhenVisible'; }, enumerable: false, configurable: true }); Object.defineProperty(DockviewComponent.prototype, "defaultHeaderPosition", { get: function () { var _a; return (_a = this.options.defaultHeaderPosition) !== null && _a !== void 0 ? _a : 'top'; }, enumerable: false, configurable: true }); Object.defineProperty(DockviewComponent.prototype, "api", { get: function () { return this._api; }, enumerable: false, configurable: true }); Object.defineProperty(DockviewComponent.prototype, "floatingGroups", { get: function () { return this._floatingGroups; }, enumerable: false, configurable: true }); Object.defineProperty(DockviewComponent.prototype, "popoutRestorationPromise", { /** * Promise that resolves when all popout groups from the last fromJSON call are restored. * Useful for tests that need to wait for delayed popout creation. */ get: function () { return this._popoutRestorationPromise; }, enumerable: false, configurable: true }); DockviewComponent.prototype.setVisible = function (panel, visible) { switch (panel.api.location.type) { case 'grid': _super.prototype.setVisible.call(this, panel, visible); break; case 'floating': { var item = this.floatingGroups.find(function (floatingGroup) { return floatingGroup.group === panel; }); if (item) { item.overlay.setVisible(visible); panel.api._onDidVisibilityChange.fire({ isVisible: visible, }); } break; } case 'popout': console.warn('dockview: You cannot hide a group that is in a popout window'); break; case 'edge': // Edge group visibility is managed via setEdgeGroupVisible break; } }; /** * Returns the {@link PopupService} that should host popovers (context * menus, tab overflow menus) for the given group. Popout groups have their * own service rooted in their popout window so the popover renders there * and dismisses on events from that window. */ DockviewComponent.prototype.getPopupServiceForGroup = function (group) { var _a; return (_a = this._popoutPopupServices.get(group.id)) !== null && _a !== void 0 ? _a : this.popupService; }; DockviewComponent.prototype.addPopoutGroup = function (itemToPopout, options) { var _this = this; var _a, _b, _c, _d, _e, _f; if (itemToPopout instanceof dockviewGroupPanel_1.DockviewGroupPanel && itemToPopout.model.location.type === 'edge') { // edge groups are permanent structural elements and cannot be popped out return Promise.resolve(false); } if (itemToPopout instanceof dockviewPanel_1.DockviewPanel && itemToPopout.group.size === 1) { return this.addPopoutGroup(itemToPopout.group, options); } var theme = (0, dom_1.getDockviewTheme)(this.gridview.element); var element = this.element; function getBox() { if (options === null || options === void 0 ? void 0 : options.position) { return options.position; } if (itemToPopout instanceof dockviewGroupPanel_1.DockviewGroupPanel) { return itemToPopout.element.getBoundingClientRect(); } if (itemToPopout.group) { return itemToPopout.group.element.getBoundingClientRect(); } return element.getBoundingClientRect(); } var box = getBox(); var groupId = (_b = (_a = options === null || options === void 0 ? void 0 : options.overridePopoutGroup) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : this.getNextGroupId(); var _window = new popoutWindow_1.PopoutWindow("".concat(this.id, "-").concat(groupId), // unique id theme !== null && theme !== void 0 ? theme : '', { url: (_e = (_c = options === null || options === void 0 ? void 0 : options.popoutUrl) !== null && _c !== void 0 ? _c : (_d = this.options) === null || _d === void 0 ? void 0 : _d.popoutUrl) !== null && _e !== void 0 ? _e : '/popout.html', left: window.screenX + box.left, top: window.screenY + box.top, width: box.width, height: box.height, onDidOpen: options === null || options === void 0 ? void 0 : options.onDidOpen, onWillClose: options === null || options === void 0 ? void 0 : options.onWillClose, nonce: (_f = this.options) === null || _f === void 0 ? void 0 : _f.nonce, }); var popoutWindowDisposable = new lifecycle_1.CompositeDisposable(_window, _window.onDidClose(function () { popoutWindowDisposable.dispose(); })); return _window .open() .then(function (popoutContainer) { var _a; if (_window.isDisposed) { return false; } var referenceGroup = (options === null || options === void 0 ? void 0 : options.referenceGroup) ? options.referenceGroup : itemToPopout instanceof dockviewPanel_1.DockviewPanel ? itemToPopout.group : itemToPopout; var referenceLocation = itemToPopout.api.location.type; /** * The group that is being added doesn't already exist within the DOM, the most likely occurrence * of this case is when being called from the `fromJSON(...)` method */ var isGroupAddedToDom = referenceGroup.element.parentElement !== null; var group; if (!isGroupAddedToDom) { group = referenceGroup; } else if (options === null || options === void 0 ? void 0 : options.overridePopoutGroup) { group = options.overridePopoutGroup; } else { group = _this.createGroup({ id: groupId }); if (popoutContainer) { _this._onDidAddGroup.fire(group); } } if (popoutContainer === null) { console.error('dockview: failed to create popout. perhaps you need to allow pop-ups for this website'); popoutWindowDisposable.dispose(); _this._onDidOpenPopoutWindowFail.fire(); // if the popout window was blocked, we need to move the group back to the reference group // and set it to visible _this.movingLock(function () { return moveGroupWithoutDestroying({ from: group, to: referenceGroup, }); }); if (!referenceGroup.api.isVisible) { referenceGroup.api.setVisible(true); } return false; } var gready = document.createElement('div'); gready.className = 'dv-overlay-render-container'; var overlayRenderContainer = new overlayRenderContainer_1.OverlayRenderContainer(gready, _this); group.model.renderContainer = overlayRenderContainer; group.layout(_window.window.innerWidth, _window.window.innerHeight); var floatingBox; if (!(options === null || options === void 0 ? void 0 : options.overridePopoutGroup) && isGroupAddedToDom) { if (itemToPopout instanceof dockviewPanel_1.DockviewPanel) { _this.movingLock(function () { var panel = referenceGroup.model.removePanel(itemToPopout); group.model.openPanel(panel); }); } else { _this.movingLock(function () { return moveGroupWithoutDestroying({ from: referenceGroup, to: group, }); }); switch (referenceLocation) { case 'grid': referenceGroup.api.setVisible(false); break; case 'floating': case 'popout': floatingBox = (_a = _this._floatingGroups .find(function (value) { return value.group.api.id === itemToPopout.api.id; })) === null || _a === void 0 ? void 0 : _a.overlay.toJSON(); _this.removeGroup(referenceGroup); break; } } } popoutContainer.classList.add('dv-dockview'); popoutContainer.style.overflow = 'hidden'; popoutContainer.appendChild(gready); popoutContainer.appendChild(group.element); var anchor = document.createElement('div'); var dropTargetContainer = new dropTargetAnchorContainer_1.DropTargetAnchorContainer(anchor, { disabled: _this.rootDropTargetContainer.disabled }); popoutContainer.appendChild(anchor); group.model.dropTargetContainer = dropTargetContainer; // Each popout group needs its own popover service so that // tab context menus, chip menus, and tab overflow menus // render in the popout window (not the main window) and // their pointerdown/keydown listeners fire on the right // window for outside-click and Escape dismissal. var popoutPopupService = new popupService_1.PopupService(popoutContainer, _window.window); _this._popoutPopupServices.set(group.id, popoutPopupService); popoutWindowDisposable.addDisposables(popoutPopupService, lifecycle_1.Disposable.from(function () { _this._popoutPopupServices.delete(group.id); })); group.model.location = { type: 'popout', getWindow: function () { return _window.window; }, popoutUrl: options === null || options === void 0 ? void 0 : options.popoutUrl, }; if (isGroupAddedToDom && itemToPopout.api.location.type === 'grid') { itemToPopout.api.setVisible(false); } _this.doSetGroupAndPanelActive(group); popoutWindowDisposable.addDisposables(group.api.onDidActiveChange(function (event) { var _a; if (event.isActive) { (_a = _window.window) === null || _a === void 0 ? void 0 : _a.focus(); } }), group.api.onWillFocus(function () { var _a; (_a = _window.window) === null || _a === void 0 ? void 0 : _a.focus(); })); var returnedGroup; var isValidReferenceGroup = isGroupAddedToDom && referenceGroup && _this.getPanel(referenceGroup.id); var value = { window: _window, popoutGroup: group, referenceGroup: isValidReferenceGroup ? referenceGroup.id : undefined, disposable: { dispose: function () { popoutWindowDisposable.dispose(); return returnedGroup; }, }, }; var _onDidWindowPositionChange = (0, dom_1.onDidWindowMoveEnd)(_window.window); popoutWindowDisposable.addDisposables(_onDidWindowPositionChange, (0, dom_1.onDidWindowResizeEnd)(_window.window, function () { _this._onDidPopoutGroupSizeChange.fire({ width: _window.window.innerWidth, height: _window.window.innerHeight, group: group, }); }), _onDidWindowPositionChange.event(function () { _this._onDidPopoutGroupPositionChange.fire({ screenX: _window.window.screenX, screenY: _window.window.screenX, group: group, }); }), /** * ResizeObserver seems slow here, I do not know why but we don't need it * since we can reply on the window resize event as we will occupy the full * window dimensions */ (0, events_1.addDisposableListener)(_window.window, 'resize', function () { group.layout(_window.window.innerWidth, _window.window.innerHeight); }), overlayRenderContainer, lifecycle_1.Disposable.from(function () { if (_this.isDisposed) { return; // cleanup may run after instance is disposed } if (isGroupAddedToDom && _this.getPanel(referenceGroup.id)) { _this.movingLock(function () { return moveGroupWithoutDestroying({ from: group, to: referenceGroup, }); }); if (!referenceGroup.api.isVisible) { referenceGroup.api.setVisible(true); } if (_this.getPanel(group.id)) { _this.doRemoveGroup(group, { skipPopoutAssociated: true, }); } } else if (_this.getPanel(group.id)) { group.model.renderContainer = _this.overlayRenderContainer; group.model.dropTargetContainer = _this.rootDropTargetContainer; returnedGroup = group; var alreadyRemoved = !_this._popoutGroups.find(function (p) { return p.popoutGroup === group; }); if (alreadyRemoved) { /** * If this popout group was explicitly removed then we shouldn't run the additional * steps. To tell if the running of this disposable is the result of this popout group * being explicitly removed we can check if this popout group is still referenced in * the `this._popoutGroups` list. */ return; } if (floatingBox) { _this.addFloatingGroup(group, { height: floatingBox.height, width: floatingBox.width, position: floatingBox, }); } else { _this.doRemoveGroup(group, { skipDispose: true, skipActive: true, skipPopoutReturn: true, }); group.model.location = { type: 'grid' }; _this.movingLock(function () { // suppress group add events since the group already exists _this.doAddGroup(group, [0]); }); } _this.doSetGroupAndPanelActive(group); } })); _this._popoutGroups.push(value); _this.updateWatermark(); return true; }) .catch(function (err) { console.error('dockview: failed to create popout.', err); return false; }); }; DockviewComponent.prototype.addFloatingGroup = function (item, options) { var _this = this; var _a, _b, _c, _d, _e, _f; if (item instanceof dockviewGroupPanel_1.DockviewGroupPanel && item.model.location.type === 'edge') { // edge groups are permanent structural elements and cannot be floated return; } var group; if (item instanceof dockviewPanel_1.DockviewPanel) { group = this.createGroup(); this._onDidAddGroup.fire(group); this.movingLock(function () { return _this.removePanel(item, { removeEmptyGroup: true, skipDispose: true, skipSetActiveGroup: true, }); }); this.movingLock(function () { return group.model.openPanel(item, { skipSetGroupActive: true }); }); } else { group = item; var popoutReferenceGroupId = (_a = this._popoutGroups.find(function (_) { return _.popoutGroup === group; })) === null || _a === void 0 ? void 0 : _a.referenceGroup; var popoutReferenceGroup_1 = popoutReferenceGroupId ? this.getPanel(popoutReferenceGroupId) : undefined; var skip = typeof (options === null || options === void 0 ? void 0 : options.skipRemoveGroup) === 'boolean' && options.skipRemoveGroup; if (!skip) { if (popoutReferenceGroup_1) { this.movingLock(function () { return moveGroupWithoutDestroying({ from: item, to: popoutReferenceGroup_1, }); }); this.doRemoveGroup(item, { skipPopoutReturn: true, skipPopoutAssociated: true, }); this.doRemoveGroup(popoutReferenceGroup_1, { skipDispose: true, }); group = popoutReferenceGroup_1; } else { this.doRemoveGroup(item, { skipDispose: true, skipPopoutReturn: true, skipPopoutAssociated: false, }); } } } function getAnchoredBox() { if (options === null || options === void 0 ? void 0 : options.position) { var result = {}; if ('left' in options.position) { result.left = Math.max(options.position.left, 0); } else if ('right' in options.position) { result.right = Math.max(options.position.right, 0); } else { result.left = constants_1.DEFAULT_FLOATING_GROUP_POSITION.left; } if ('top' in options.position) { result.top = Math.max(options.position.top, 0); } else if ('bottom' in options.position) { result.bottom = Math.max(options.position.bottom, 0); } else { result.top = constants_1.DEFAULT_FLOATING_GROUP_POSITION.top; } if (typeof options.width === 'number') { result.width = Math.max(options.width, 0); } else { result.width = constants_1.DEFAULT_FLOATING_GROUP_POSITION.width; } if (typeof options.height === 'number') { result.height = Math.max(options.height, 0); } else { result.height = constants_1.DEFAULT_FLOATING_GROUP_POSITION.height; } return result; } return { left: typeof (options === null || options === void 0 ? void 0 : options.x) === 'number' ? Math.max(options.x, 0) : constants_1.DEFAULT_FLOATING_GROUP_POSITION.left, top: typeof (options === null || options === void 0 ? void 0 : options.y) === 'number' ? Math.max(options.y, 0) : constants_1.DEFAULT_FLOATING_GROUP_POSITION.top, width: typeof (options === null || options === void 0 ? void 0 : options.width) === 'number' ? Math.max(options.width, 0) : constants_1.DEFAULT_FLOATING_GROUP_POSITION.width, height: typeof (options === null || options === void 0 ? void 0 : options.height) === 'number' ? Math.max(options.height, 0) : constants_1.DEFAULT_FLOATING_GROUP_POSITION.height, }; } var anchoredBox = getAnchoredBox(); var overlay = new overlay_1.Overlay(__assign(__assign({ container: (_b = this._floatingOverlayHost) !== null && _b !== void 0 ? _b : this.gridview.element, content: group.element }, anchoredBox), { minimumInViewportWidth: this.options.floatingGroupBounds === 'boundedWithinViewport' ? undefined : ((_d = (_c = this.options.floatingGroupBounds) === null || _c === void 0 ? void 0 : _c.minimumWidthWithinViewport) !== null && _d !== void 0 ? _d : constants_1.DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE), minimumInViewportHeight: this.options.floatingGroupBounds === 'boundedWithinViewport' ? undefined : ((_f = (_e = this.options.floatingGroupBounds) === null || _e === void 0 ? void 0 : _e.minimumHeightWithinViewport) !== null && _f !== void 0 ? _f : constants_1.DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE) })); var el = group.element.querySelector('.dv-void-container'); if (!el) { throw new Error('dockview: failed to find drag handle'); } overlay.setupDrag(el, { inDragMode: typeof (options === null || options === void 0 ? void 0 : options.inDragMode) === 'boolean' ? options.inDragMode : false, }); var floatingGroupPanel = new dockviewFloatingGroupPanel_1.DockviewFloatingGroupPanel(group, overlay); var disposable = new lifecycle_1.CompositeDisposable(group.api.onDidActiveChange(function (event) { if (event.isActive) { overlay.bringToFront(); } }), (function () { var lastWidth = -1; var lastHeight = -1; return (0, dom_1.watchElementResize)(group.element, function (entry) { var width = Math.round(entry.contentRect.width); var height = Math.round(entry.contentRect.height); if (width === lastWidth && height === lastHeight) { return; } lastWidth = width; lastHeight = height; group.layout(width, height); // let the group know it's size is changing so it can fire events to the panel }); })()); floatingGroupPanel.addDisposables(overlay.onDidChange(function () { // this is either a resize or a move // to inform the panels .layout(...) the group with it's current size // don't care about resize since the above watcher handles that group.layout(group.width, group.height); }), overlay.onDidChangeEnd(function () { _this._bufferOnDidLayoutChange.fire(); }), group.onDidChange(function (event) { overlay.setBounds({ height: event === null || event === void 0 ? void 0 : event.height, width: event === null || event === void 0 ? void 0 : event.width, }); }), { dispose: function () { disposable.dispose(); (0, array_1.remove)(_this._floatingGroups, floatingGroupPanel); group.model.location = { type: 'grid' }; _this.updateWatermark(); }, }); this._floatingGroups.push(floatingGroupPanel); group.model.location = { type: 'floating' }; if (!(options === null || options === void 0 ? void 0 : options.skipActiveGroup)) { this.doSetGroupAndPanelActive(group); } this.updateWatermark(); }; DockviewComponent.prototype.orthogonalize = function (position, options) { this.gridview.normalize(); switch (position) { case 'top': case 'bottom': if (this.gridview.orientation === splitview_1.Orientation.HORIZONTAL) { // we need to add to a vertical splitview but the current root is a horizontal splitview. // insert a vertical splitview at the root level and add the existing view as a child this.gridview.insertOrthogonalSplitviewAtRoot(); } break; case 'left': case 'right': if (this.gridview.orientation === splitview_1.Orientation.VERTICAL) { // we need to add to a horizontal splitview but the current root is a v