UNPKG

flexlayout-react

Version:

A multi-tab docking layout manager

1,433 lines (1,432 loc) 230 kB
/** * flexlayout-react * @version 0.8.18 */ var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); import { jsx, jsxs, Fragment } from "react/jsx-runtime"; import * as React from "react"; import { useRef, useEffect } from "react"; import { createPortal } from "react-dom"; import { createRoot } from "react-dom/client"; const _Orientation = class _Orientation { /** @internal */ constructor(name) { /** @internal */ __publicField(this, "_name"); this._name = name; } static flip(from) { if (from === _Orientation.HORZ) { return _Orientation.VERT; } else { return _Orientation.HORZ; } } getName() { return this._name; } toString() { return this._name; } }; __publicField(_Orientation, "HORZ", new _Orientation("horz")); __publicField(_Orientation, "VERT", new _Orientation("vert")); let Orientation = _Orientation; class Rect { constructor(x, y, width, height) { __publicField(this, "x"); __publicField(this, "y"); __publicField(this, "width"); __publicField(this, "height"); this.x = x; this.y = y; this.width = width; this.height = height; } static empty() { return new Rect(0, 0, 0, 0); } static fromJson(json) { return new Rect(json.x, json.y, json.width, json.height); } toJson() { return { x: this.x, y: this.y, width: this.width, height: this.height }; } snap(round) { this.x = Math.round(this.x / round) * round; this.y = Math.round(this.y / round) * round; this.width = Math.round(this.width / round) * round; this.height = Math.round(this.height / round) * round; } static getBoundingClientRect(element) { const { x, y, width, height } = element.getBoundingClientRect(); return new Rect(x, y, width, height); } static getContentRect(element) { const rect = element.getBoundingClientRect(); const style2 = window.getComputedStyle(element); const paddingLeft = parseFloat(style2.paddingLeft); const paddingRight = parseFloat(style2.paddingRight); const paddingTop = parseFloat(style2.paddingTop); const paddingBottom = parseFloat(style2.paddingBottom); const borderLeftWidth = parseFloat(style2.borderLeftWidth); const borderRightWidth = parseFloat(style2.borderRightWidth); const borderTopWidth = parseFloat(style2.borderTopWidth); const borderBottomWidth = parseFloat(style2.borderBottomWidth); const contentWidth = rect.width - borderLeftWidth - paddingLeft - paddingRight - borderRightWidth; const contentHeight = rect.height - borderTopWidth - paddingTop - paddingBottom - borderBottomWidth; return new Rect( rect.left + borderLeftWidth + paddingLeft, rect.top + borderTopWidth + paddingTop, contentWidth, contentHeight ); } static fromDomRect(domRect) { return new Rect(domRect.x, domRect.y, domRect.width, domRect.height); } relativeTo(r) { return new Rect(this.x - r.x, this.y - r.y, this.width, this.height); } clone() { return new Rect(this.x, this.y, this.width, this.height); } equals(rect) { return this.x === (rect == null ? void 0 : rect.x) && this.y === (rect == null ? void 0 : rect.y) && this.width === (rect == null ? void 0 : rect.width) && this.height === (rect == null ? void 0 : rect.height); } equalSize(rect) { return this.width === (rect == null ? void 0 : rect.width) && this.height === (rect == null ? void 0 : rect.height); } getBottom() { return this.y + this.height; } getRight() { return this.x + this.width; } get bottom() { return this.y + this.height; } get right() { return this.x + this.width; } getCenter() { return { x: this.x + this.width / 2, y: this.y + this.height / 2 }; } positionElement(element, position) { this.styleWithPosition(element.style, position); } styleWithPosition(style2, position = "absolute") { style2.left = this.x + "px"; style2.top = this.y + "px"; style2.width = Math.max(0, this.width) + "px"; style2.height = Math.max(0, this.height) + "px"; style2.position = position; return style2; } contains(x, y) { if (this.x <= x && x <= this.getRight() && this.y <= y && y <= this.getBottom()) { return true; } else { return false; } } removeInsets(insets) { return new Rect(this.x + insets.left, this.y + insets.top, Math.max(0, this.width - insets.left - insets.right), Math.max(0, this.height - insets.top - insets.bottom)); } centerInRect(outerRect) { this.x = (outerRect.width - this.width) / 2; this.y = (outerRect.height - this.height) / 2; } /** @internal */ _getSize(orientation) { let prefSize = this.width; if (orientation === Orientation.VERT) { prefSize = this.height; } return prefSize; } toString() { return "(Rect: x=" + this.x + ", y=" + this.y + ", width=" + this.width + ", height=" + this.height + ")"; } } const _DockLocation = class _DockLocation { /** @internal */ constructor(_name, _orientation, _indexPlus) { /** @internal */ __publicField(this, "name"); /** @internal */ __publicField(this, "orientation"); /** @internal */ __publicField(this, "indexPlus"); this.name = _name; this.orientation = _orientation; this.indexPlus = _indexPlus; _DockLocation.values.set(this.name, this); } /** @internal */ static getByName(name) { return _DockLocation.values.get(name); } /** @internal */ static getLocation(rect, x, y) { x = (x - rect.x) / rect.width; y = (y - rect.y) / rect.height; if (x >= 0.25 && x < 0.75 && y >= 0.25 && y < 0.75) { return _DockLocation.CENTER; } const bl = y >= x; const br = y >= 1 - x; if (bl) { return br ? _DockLocation.BOTTOM : _DockLocation.LEFT; } else { return br ? _DockLocation.RIGHT : _DockLocation.TOP; } } getName() { return this.name; } getOrientation() { return this.orientation; } /** @internal */ getDockRect(r) { if (this === _DockLocation.TOP) { return new Rect(r.x, r.y, r.width, r.height / 2); } else if (this === _DockLocation.BOTTOM) { return new Rect(r.x, r.getBottom() - r.height / 2, r.width, r.height / 2); } if (this === _DockLocation.LEFT) { return new Rect(r.x, r.y, r.width / 2, r.height); } else if (this === _DockLocation.RIGHT) { return new Rect(r.getRight() - r.width / 2, r.y, r.width / 2, r.height); } else { return r.clone(); } } /** @internal */ split(rect, size) { if (this === _DockLocation.TOP) { const r1 = new Rect(rect.x, rect.y, rect.width, size); const r2 = new Rect(rect.x, rect.y + size, rect.width, rect.height - size); return { start: r1, end: r2 }; } else if (this === _DockLocation.LEFT) { const r1 = new Rect(rect.x, rect.y, size, rect.height); const r2 = new Rect(rect.x + size, rect.y, rect.width - size, rect.height); return { start: r1, end: r2 }; } if (this === _DockLocation.RIGHT) { const r1 = new Rect(rect.getRight() - size, rect.y, size, rect.height); const r2 = new Rect(rect.x, rect.y, rect.width - size, rect.height); return { start: r1, end: r2 }; } else { const r1 = new Rect(rect.x, rect.getBottom() - size, rect.width, size); const r2 = new Rect(rect.x, rect.y, rect.width, rect.height - size); return { start: r1, end: r2 }; } } /** @internal */ reflect() { if (this === _DockLocation.TOP) { return _DockLocation.BOTTOM; } else if (this === _DockLocation.LEFT) { return _DockLocation.RIGHT; } if (this === _DockLocation.RIGHT) { return _DockLocation.LEFT; } else { return _DockLocation.TOP; } } toString() { return "(DockLocation: name=" + this.name + ", orientation=" + this.orientation + ")"; } }; __publicField(_DockLocation, "values", /* @__PURE__ */ new Map()); __publicField(_DockLocation, "TOP", new _DockLocation("top", Orientation.VERT, 0)); __publicField(_DockLocation, "BOTTOM", new _DockLocation("bottom", Orientation.VERT, 1)); __publicField(_DockLocation, "LEFT", new _DockLocation("left", Orientation.HORZ, 0)); __publicField(_DockLocation, "RIGHT", new _DockLocation("right", Orientation.HORZ, 1)); __publicField(_DockLocation, "CENTER", new _DockLocation("center", Orientation.VERT, 0)); let DockLocation = _DockLocation; var I18nLabel = /* @__PURE__ */ ((I18nLabel2) => { I18nLabel2["Close_Tab"] = "Close"; I18nLabel2["Close_Tabset"] = "Close tab set"; I18nLabel2["Active_Tabset"] = "Active tab set"; I18nLabel2["Move_Tabset"] = "Move tab set"; I18nLabel2["Move_Tabs"] = "Move tabs(?)"; I18nLabel2["Maximize"] = "Maximize tab set"; I18nLabel2["Restore"] = "Restore tab set"; I18nLabel2["Popout_Tab"] = "Popout selected tab"; I18nLabel2["Overflow_Menu_Tooltip"] = "Hidden tabs"; I18nLabel2["Error_rendering_component"] = "Error rendering component"; I18nLabel2["Error_rendering_component_retry"] = "Retry"; return I18nLabel2; })(I18nLabel || {}); var CLASSES = /* @__PURE__ */ ((CLASSES2) => { CLASSES2["FLEXLAYOUT__BORDER"] = "flexlayout__border"; CLASSES2["FLEXLAYOUT__BORDER_"] = "flexlayout__border_"; CLASSES2["FLEXLAYOUT__BORDER_TAB_CONTENTS"] = "flexlayout__border_tab_contents"; CLASSES2["FLEXLAYOUT__BORDER_BUTTON"] = "flexlayout__border_button"; CLASSES2["FLEXLAYOUT__BORDER_BUTTON_"] = "flexlayout__border_button_"; CLASSES2["FLEXLAYOUT__BORDER_BUTTON_CONTENT"] = "flexlayout__border_button_content"; CLASSES2["FLEXLAYOUT__BORDER_BUTTON_LEADING"] = "flexlayout__border_button_leading"; CLASSES2["FLEXLAYOUT__BORDER_BUTTON_TRAILING"] = "flexlayout__border_button_trailing"; CLASSES2["FLEXLAYOUT__BORDER_BUTTON__SELECTED"] = "flexlayout__border_button--selected"; CLASSES2["FLEXLAYOUT__BORDER_BUTTON__UNSELECTED"] = "flexlayout__border_button--unselected"; CLASSES2["FLEXLAYOUT__BORDER_TOOLBAR_BUTTON_OVERFLOW"] = "flexlayout__border_toolbar_button_overflow"; CLASSES2["FLEXLAYOUT__BORDER_TOOLBAR_BUTTON_OVERFLOW_"] = "flexlayout__border_toolbar_button_overflow_"; CLASSES2["FLEXLAYOUT__BORDER_INNER"] = "flexlayout__border_inner"; CLASSES2["FLEXLAYOUT__BORDER_INNER_"] = "flexlayout__border_inner_"; CLASSES2["FLEXLAYOUT__BORDER_INNER_TAB_CONTAINER"] = "flexlayout__border_inner_tab_container"; CLASSES2["FLEXLAYOUT__BORDER_INNER_TAB_CONTAINER_"] = "flexlayout__border_inner_tab_container_"; CLASSES2["FLEXLAYOUT__BORDER_TAB_DIVIDER"] = "flexlayout__border_tab_divider"; CLASSES2["FLEXLAYOUT__BORDER_LEADING"] = "flexlayout__border_leading"; CLASSES2["FLEXLAYOUT__BORDER_SIZER"] = "flexlayout__border_sizer"; CLASSES2["FLEXLAYOUT__BORDER_TOOLBAR"] = "flexlayout__border_toolbar"; CLASSES2["FLEXLAYOUT__BORDER_TOOLBAR_"] = "flexlayout__border_toolbar_"; CLASSES2["FLEXLAYOUT__BORDER_TOOLBAR_BUTTON"] = "flexlayout__border_toolbar_button"; CLASSES2["FLEXLAYOUT__BORDER_TOOLBAR_BUTTON_FLOAT"] = "flexlayout__border_toolbar_button-float"; CLASSES2["FLEXLAYOUT__DRAG_RECT"] = "flexlayout__drag_rect"; CLASSES2["FLEXLAYOUT__EDGE_RECT"] = "flexlayout__edge_rect"; CLASSES2["FLEXLAYOUT__EDGE_RECT_TOP"] = "flexlayout__edge_rect_top"; CLASSES2["FLEXLAYOUT__EDGE_RECT_LEFT"] = "flexlayout__edge_rect_left"; CLASSES2["FLEXLAYOUT__EDGE_RECT_BOTTOM"] = "flexlayout__edge_rect_bottom"; CLASSES2["FLEXLAYOUT__EDGE_RECT_RIGHT"] = "flexlayout__edge_rect_right"; CLASSES2["FLEXLAYOUT__ERROR_BOUNDARY_CONTAINER"] = "flexlayout__error_boundary_container"; CLASSES2["FLEXLAYOUT__ERROR_BOUNDARY_CONTENT"] = "flexlayout__error_boundary_content"; CLASSES2["FLEXLAYOUT__FLOATING_WINDOW_CONTENT"] = "flexlayout__floating_window_content"; CLASSES2["FLEXLAYOUT__LAYOUT"] = "flexlayout__layout"; CLASSES2["FLEXLAYOUT__LAYOUT_MOVEABLES"] = "flexlayout__layout_moveables"; CLASSES2["FLEXLAYOUT__LAYOUT_OVERLAY"] = "flexlayout__layout_overlay"; CLASSES2["FLEXLAYOUT__LAYOUT_TAB_STAMPS"] = "flexlayout__layout_tab_stamps"; CLASSES2["FLEXLAYOUT__LAYOUT_MAIN"] = "flexlayout__layout_main"; CLASSES2["FLEXLAYOUT__LAYOUT_BORDER_CONTAINER"] = "flexlayout__layout_border_container"; CLASSES2["FLEXLAYOUT__LAYOUT_BORDER_CONTAINER_INNER"] = "flexlayout__layout_border_container_inner"; CLASSES2["FLEXLAYOUT__OUTLINE_RECT"] = "flexlayout__outline_rect"; CLASSES2["FLEXLAYOUT__OUTLINE_RECT_EDGE"] = "flexlayout__outline_rect_edge"; CLASSES2["FLEXLAYOUT__SPLITTER"] = "flexlayout__splitter"; CLASSES2["FLEXLAYOUT__SPLITTER_EXTRA"] = "flexlayout__splitter_extra"; CLASSES2["FLEXLAYOUT__SPLITTER_"] = "flexlayout__splitter_"; CLASSES2["FLEXLAYOUT__SPLITTER_BORDER"] = "flexlayout__splitter_border"; CLASSES2["FLEXLAYOUT__SPLITTER_DRAG"] = "flexlayout__splitter_drag"; CLASSES2["FLEXLAYOUT__SPLITTER_HANDLE"] = "flexlayout__splitter_handle"; CLASSES2["FLEXLAYOUT__SPLITTER_HANDLE_HORZ"] = "flexlayout__splitter_handle_horz"; CLASSES2["FLEXLAYOUT__SPLITTER_HANDLE_VERT"] = "flexlayout__splitter_handle_vert"; CLASSES2["FLEXLAYOUT__ROW"] = "flexlayout__row"; CLASSES2["FLEXLAYOUT__TAB"] = "flexlayout__tab"; CLASSES2["FLEXLAYOUT__TAB_POSITION"] = "flexlayout__tab_position"; CLASSES2["FLEXLAYOUT__TAB_MOVEABLE"] = "flexlayout__tab_moveable"; CLASSES2["FLEXLAYOUT__TAB_OVERLAY"] = "flexlayout__tab_overlay"; CLASSES2["FLEXLAYOUT__TABSET"] = "flexlayout__tabset"; CLASSES2["FLEXLAYOUT__TABSET_CONTAINER"] = "flexlayout__tabset_container"; CLASSES2["FLEXLAYOUT__TABSET_HEADER"] = "flexlayout__tabset_header"; CLASSES2["FLEXLAYOUT__TABSET_HEADER_CONTENT"] = "flexlayout__tabset_header_content"; CLASSES2["FLEXLAYOUT__TABSET_MAXIMIZED"] = "flexlayout__tabset-maximized"; CLASSES2["FLEXLAYOUT__TABSET_SELECTED"] = "flexlayout__tabset-selected"; CLASSES2["FLEXLAYOUT__TABSET_TAB_DIVIDER"] = "flexlayout__tabset_tab_divider"; CLASSES2["FLEXLAYOUT__TABSET_CONTENT"] = "flexlayout__tabset_content"; CLASSES2["FLEXLAYOUT__TABSET_TABBAR_INNER"] = "flexlayout__tabset_tabbar_inner"; CLASSES2["FLEXLAYOUT__TABSET_TABBAR_INNER_"] = "flexlayout__tabset_tabbar_inner_"; CLASSES2["FLEXLAYOUT__TABSET_LEADING"] = "flexlayout__tabset_leading"; CLASSES2["FLEXLAYOUT__TABSET_TABBAR_INNER_TAB_CONTAINER"] = "flexlayout__tabset_tabbar_inner_tab_container"; CLASSES2["FLEXLAYOUT__TABSET_TABBAR_INNER_TAB_CONTAINER_"] = "flexlayout__tabset_tabbar_inner_tab_container_"; CLASSES2["FLEXLAYOUT__TABSET_TABBAR_OUTER"] = "flexlayout__tabset_tabbar_outer"; CLASSES2["FLEXLAYOUT__TABSET_TABBAR_OUTER_"] = "flexlayout__tabset_tabbar_outer_"; CLASSES2["FLEXLAYOUT__TAB_BORDER"] = "flexlayout__tab_border"; CLASSES2["FLEXLAYOUT__TAB_BORDER_"] = "flexlayout__tab_border_"; CLASSES2["FLEXLAYOUT__TAB_BUTTON"] = "flexlayout__tab_button"; CLASSES2["FLEXLAYOUT__TAB_BUTTON_STRETCH"] = "flexlayout__tab_button_stretch"; CLASSES2["FLEXLAYOUT__TAB_BUTTON_CONTENT"] = "flexlayout__tab_button_content"; CLASSES2["FLEXLAYOUT__TAB_BUTTON_LEADING"] = "flexlayout__tab_button_leading"; CLASSES2["FLEXLAYOUT__TAB_BUTTON_OVERFLOW"] = "flexlayout__tab_button_overflow"; CLASSES2["FLEXLAYOUT__TAB_BUTTON_OVERFLOW_COUNT"] = "flexlayout__tab_button_overflow_count"; CLASSES2["FLEXLAYOUT__TAB_BUTTON_TEXTBOX"] = "flexlayout__tab_button_textbox"; CLASSES2["FLEXLAYOUT__TAB_BUTTON_TRAILING"] = "flexlayout__tab_button_trailing"; CLASSES2["FLEXLAYOUT__TAB_BUTTON_STAMP"] = "flexlayout__tab_button_stamp"; CLASSES2["FLEXLAYOUT__TAB_TOOLBAR"] = "flexlayout__tab_toolbar"; CLASSES2["FLEXLAYOUT__TAB_TOOLBAR_BUTTON"] = "flexlayout__tab_toolbar_button"; CLASSES2["FLEXLAYOUT__TAB_TOOLBAR_ICON"] = "flexlayout__tab_toolbar_icon"; CLASSES2["FLEXLAYOUT__TAB_TOOLBAR_BUTTON_"] = "flexlayout__tab_toolbar_button-"; CLASSES2["FLEXLAYOUT__TAB_TOOLBAR_BUTTON_FLOAT"] = "flexlayout__tab_toolbar_button-float"; CLASSES2["FLEXLAYOUT__TAB_TOOLBAR_STICKY_BUTTONS_CONTAINER"] = "flexlayout__tab_toolbar_sticky_buttons_container"; CLASSES2["FLEXLAYOUT__TAB_TOOLBAR_BUTTON_CLOSE"] = "flexlayout__tab_toolbar_button-close"; CLASSES2["FLEXLAYOUT__POPUP_MENU_CONTAINER"] = "flexlayout__popup_menu_container"; CLASSES2["FLEXLAYOUT__POPUP_MENU_ITEM"] = "flexlayout__popup_menu_item"; CLASSES2["FLEXLAYOUT__POPUP_MENU_ITEM__SELECTED"] = "flexlayout__popup_menu_item--selected"; CLASSES2["FLEXLAYOUT__POPUP_MENU"] = "flexlayout__popup_menu"; CLASSES2["FLEXLAYOUT__MINI_SCROLLBAR"] = "flexlayout__mini_scrollbar"; CLASSES2["FLEXLAYOUT__MINI_SCROLLBAR_CONTAINER"] = "flexlayout__mini_scrollbar_container"; return CLASSES2; })(CLASSES || {}); class Action { constructor(type, data) { __publicField(this, "type"); __publicField(this, "data"); this.type = type; this.data = data; } } const _Actions = class _Actions { /** * Adds a tab node to the given tabset node * @param json the json for the new tab node e.g {type:"tab", component:"table"} * @param toNodeId the new tab node will be added to the tabset with this node id * @param location the location where the new tab will be added, one of the DockLocation enum values. * @param index for docking to the center this value is the index of the tab, use -1 to add to the end. * @param select (optional) whether to select the new tab, overriding autoSelectTab * @returns {Action} the action */ static addNode(json, toNodeId, location, index, select) { return new Action(_Actions.ADD_NODE, { json, toNode: toNodeId, location: location.getName(), index, select }); } /** * Moves a node (tab or tabset) from one location to another * @param fromNodeId the id of the node to move * @param toNodeId the id of the node to receive the moved node * @param location the location where the moved node will be added, one of the DockLocation enum values. * @param index for docking to the center this value is the index of the tab, use -1 to add to the end. * @param select (optional) whether to select the moved tab(s) in new tabset, overriding autoSelectTab * @returns {Action} the action */ static moveNode(fromNodeId, toNodeId, location, index, select) { return new Action(_Actions.MOVE_NODE, { fromNode: fromNodeId, toNode: toNodeId, location: location.getName(), index, select }); } /** * Deletes a tab node from the layout * @param tabNodeId the id of the tab node to delete * @returns {Action} the action */ static deleteTab(tabNodeId) { return new Action(_Actions.DELETE_TAB, { node: tabNodeId }); } /** * Deletes a tabset node and all it's child tab nodes from the layout * @param tabsetNodeId the id of the tabset node to delete * @returns {Action} the action */ static deleteTabset(tabsetNodeId) { return new Action(_Actions.DELETE_TABSET, { node: tabsetNodeId }); } /** * Change the given nodes tab text * @param tabNodeId the id of the node to rename * @param text the test of the tab * @returns {Action} the action */ static renameTab(tabNodeId, text) { return new Action(_Actions.RENAME_TAB, { node: tabNodeId, text }); } /** * Selects the given tab in its parent tabset * @param tabNodeId the id of the node to set selected * @returns {Action} the action */ static selectTab(tabNodeId) { return new Action(_Actions.SELECT_TAB, { tabNode: tabNodeId }); } /** * Set the given tabset node as the active tabset * @param tabsetNodeId the id of the tabset node to set as active * @returns {Action} the action */ static setActiveTabset(tabsetNodeId, windowId) { return new Action(_Actions.SET_ACTIVE_TABSET, { tabsetNode: tabsetNodeId, windowId }); } /** * Adjust the weights of a row, used when the splitter is moved * @param nodeId the row node whose childrens weights are being adjusted * @param weights an array of weights to be applied to the children * @returns {Action} the action */ static adjustWeights(nodeId, weights) { return new Action(_Actions.ADJUST_WEIGHTS, { nodeId, weights }); } static adjustBorderSplit(nodeId, pos) { return new Action(_Actions.ADJUST_BORDER_SPLIT, { node: nodeId, pos }); } /** * Maximizes the given tabset * @param tabsetNodeId the id of the tabset to maximize * @returns {Action} the action */ static maximizeToggle(tabsetNodeId, windowId) { return new Action(_Actions.MAXIMIZE_TOGGLE, { node: tabsetNodeId, windowId }); } /** * Updates the global model jsone attributes * @param attributes the json for the model attributes to update (merge into the existing attributes) * @returns {Action} the action */ static updateModelAttributes(attributes) { return new Action(_Actions.UPDATE_MODEL_ATTRIBUTES, { json: attributes }); } /** * Updates the given nodes json attributes * @param nodeId the id of the node to update * @param attributes the json attributes to update (merge with the existing attributes) * @returns {Action} the action */ static updateNodeAttributes(nodeId, attributes) { return new Action(_Actions.UPDATE_NODE_ATTRIBUTES, { node: nodeId, json: attributes }); } /** * Pops out the given tab node into a new browser window * @param nodeId the tab node to popout * @returns */ static popoutTab(nodeId) { return new Action(_Actions.POPOUT_TAB, { node: nodeId }); } /** * Pops out the given tab set node into a new browser window * @param nodeId the tab set node to popout * @returns */ static popoutTabset(nodeId) { return new Action(_Actions.POPOUT_TABSET, { node: nodeId }); } /** * Closes the popout window * @param windowId the id of the popout window to close * @returns */ static closeWindow(windowId) { return new Action(_Actions.CLOSE_WINDOW, { windowId }); } /** * Creates a new empty popout window with the given layout * @param layout the json layout for the new window * @param rect the window rectangle in screen coordinates * @returns */ static createWindow(layout, rect) { return new Action(_Actions.CREATE_WINDOW, { layout, rect }); } }; __publicField(_Actions, "ADD_NODE", "FlexLayout_AddNode"); __publicField(_Actions, "MOVE_NODE", "FlexLayout_MoveNode"); __publicField(_Actions, "DELETE_TAB", "FlexLayout_DeleteTab"); __publicField(_Actions, "DELETE_TABSET", "FlexLayout_DeleteTabset"); __publicField(_Actions, "RENAME_TAB", "FlexLayout_RenameTab"); __publicField(_Actions, "SELECT_TAB", "FlexLayout_SelectTab"); __publicField(_Actions, "SET_ACTIVE_TABSET", "FlexLayout_SetActiveTabset"); __publicField(_Actions, "ADJUST_WEIGHTS", "FlexLayout_AdjustWeights"); __publicField(_Actions, "ADJUST_BORDER_SPLIT", "FlexLayout_AdjustBorderSplit"); __publicField(_Actions, "MAXIMIZE_TOGGLE", "FlexLayout_MaximizeToggle"); __publicField(_Actions, "UPDATE_MODEL_ATTRIBUTES", "FlexLayout_UpdateModelAttributes"); __publicField(_Actions, "UPDATE_NODE_ATTRIBUTES", "FlexLayout_UpdateNodeAttributes"); __publicField(_Actions, "POPOUT_TAB", "FlexLayout_PopoutTab"); __publicField(_Actions, "POPOUT_TABSET", "FlexLayout_PopoutTabset"); __publicField(_Actions, "CLOSE_WINDOW", "FlexLayout_CloseWindow"); __publicField(_Actions, "CREATE_WINDOW", "FlexLayout_CreateWindow"); let Actions = _Actions; class Attribute { constructor(name, modelName, defaultValue, alwaysWriteJson) { __publicField(this, "name"); __publicField(this, "alias"); __publicField(this, "modelName"); __publicField(this, "pairedAttr"); __publicField(this, "pairedType"); __publicField(this, "defaultValue"); __publicField(this, "alwaysWriteJson"); __publicField(this, "type"); __publicField(this, "required"); __publicField(this, "fixed"); __publicField(this, "description"); this.name = name; this.alias = void 0; this.modelName = modelName; this.defaultValue = defaultValue; this.alwaysWriteJson = alwaysWriteJson; this.required = false; this.fixed = false; this.type = "any"; } setType(value) { this.type = value; return this; } setAlias(value) { this.alias = value; return this; } setDescription(value) { this.description = value; } setRequired() { this.required = true; return this; } setFixed() { this.fixed = true; return this; } // sets modelAttr for nodes, and nodeAttr for model setpairedAttr(value) { this.pairedAttr = value; } setPairedType(value) { this.pairedType = value; } } __publicField(Attribute, "NUMBER", "number"); __publicField(Attribute, "STRING", "string"); __publicField(Attribute, "BOOLEAN", "boolean"); class AttributeDefinitions { constructor() { __publicField(this, "attributes"); __publicField(this, "nameToAttribute"); this.attributes = []; this.nameToAttribute = /* @__PURE__ */ new Map(); } addWithAll(name, modelName, defaultValue, alwaysWriteJson) { const attr = new Attribute(name, modelName, defaultValue, alwaysWriteJson); this.attributes.push(attr); this.nameToAttribute.set(name, attr); return attr; } addInherited(name, modelName) { return this.addWithAll(name, modelName, void 0, false); } add(name, defaultValue, alwaysWriteJson) { return this.addWithAll(name, void 0, defaultValue, alwaysWriteJson); } getAttributes() { return this.attributes; } getModelName(name) { const conversion = this.nameToAttribute.get(name); if (conversion !== void 0) { return conversion.modelName; } return void 0; } toJson(jsonObj, obj) { for (const attr of this.attributes) { const fromValue = obj[attr.name]; if (attr.alwaysWriteJson || fromValue !== attr.defaultValue) { jsonObj[attr.name] = fromValue; } } } fromJson(jsonObj, obj) { for (const attr of this.attributes) { let fromValue = jsonObj[attr.name]; if (fromValue === void 0 && attr.alias) { fromValue = jsonObj[attr.alias]; } if (fromValue === void 0) { obj[attr.name] = attr.defaultValue; } else { obj[attr.name] = fromValue; } } } update(jsonObj, obj) { for (const attr of this.attributes) { if (Object.prototype.hasOwnProperty.call(jsonObj, attr.name)) { const fromValue = jsonObj[attr.name]; if (fromValue === void 0) { delete obj[attr.name]; } else { obj[attr.name] = fromValue; } } } } setDefaults(obj) { for (const attr of this.attributes) { obj[attr.name] = attr.defaultValue; } } pairAttributes(type, childAttributes) { for (const attr of childAttributes.attributes) { if (attr.modelName && this.nameToAttribute.has(attr.modelName)) { const pairedAttr = this.nameToAttribute.get(attr.modelName); pairedAttr.setpairedAttr(attr); attr.setpairedAttr(pairedAttr); pairedAttr.setPairedType(type); } } } toTypescriptInterface(name, parentAttributes) { var _a, _b; const lines = []; const sorted = this.attributes.sort((a, b) => a.name.localeCompare(b.name)); lines.push("export interface I" + name + "Attributes {"); for (let i = 0; i < sorted.length; i++) { const c = sorted[i]; let type = c.type; let defaultValue = void 0; let attr = c; let inherited = void 0; if (attr.defaultValue !== void 0) { defaultValue = attr.defaultValue; } else if (attr.modelName !== void 0 && parentAttributes !== void 0 && parentAttributes.nameToAttribute.get(attr.modelName) !== void 0) { inherited = attr.modelName; attr = parentAttributes.nameToAttribute.get(inherited); defaultValue = attr.defaultValue; type = attr.type; } const defValue = JSON.stringify(defaultValue); const required = attr.required ? "" : "?"; let sb = " /**\n "; if (c.description) { sb += c.description; } else if (c.pairedType && ((_a = c.pairedAttr) == null ? void 0 : _a.description)) { sb += `Value for ${c.pairedType} attribute ${c.pairedAttr.name} if not overridden`; sb += "\n\n "; sb += (_b = c.pairedAttr) == null ? void 0 : _b.description; } sb += "\n\n "; if (c.fixed) { sb += `Fixed value: ${defValue}`; } else if (inherited) { sb += `Default: inherited from Global attribute ${c.modelName} (default ${defValue})`; } else { sb += `Default: ${defValue}`; } sb += "\n */"; lines.push(sb); lines.push(" " + c.name + required + ": " + type + ";\n"); } lines.push("}"); return lines.join("\n"); } } class DropInfo { constructor(node, rect, location, index, className) { __publicField(this, "node"); __publicField(this, "rect"); __publicField(this, "location"); __publicField(this, "index"); __publicField(this, "className"); this.node = node; this.rect = rect; this.location = location; this.index = index; this.className = className; } } class BorderSet { /** @internal */ constructor(_model) { /** @internal */ __publicField(this, "borders"); /** @internal */ __publicField(this, "borderMap"); /** @internal */ __publicField(this, "layoutHorizontal"); this.borders = []; this.borderMap = /* @__PURE__ */ new Map(); this.layoutHorizontal = true; } /** @internal */ static fromJson(json, model) { const borderSet = new BorderSet(model); borderSet.borders = json.map((borderJson) => BorderNode.fromJson(borderJson, model)); for (const border of borderSet.borders) { borderSet.borderMap.set(border.getLocation(), border); } return borderSet; } toJson() { return this.borders.map((borderNode) => borderNode.toJson()); } /** @internal */ getLayoutHorizontal() { return this.layoutHorizontal; } /** @internal */ getBorders() { return this.borders; } /** @internal */ getBorderMap() { return this.borderMap; } /** @internal */ forEachNode(fn) { for (const borderNode of this.borders) { fn(borderNode, 0); for (const node of borderNode.getChildren()) { node.forEachNode(fn, 1); } } } /** @internal */ setPaths() { for (const borderNode of this.borders) { const path = "/border/" + borderNode.getLocation().getName(); borderNode.setPath(path); let i = 0; for (const node of borderNode.getChildren()) { node.setPath(path + "/t" + i); i++; } } } /** @internal */ findDropTargetNode(dragNode, x, y) { for (const border of this.borders) { if (border.isShowing()) { const dropInfo = border.canDrop(dragNode, x, y); if (dropInfo !== void 0) { return dropInfo; } } } return void 0; } } class Node { /** @internal */ constructor(_model) { /** @internal */ __publicField(this, "model"); /** @internal */ __publicField(this, "attributes"); /** @internal */ __publicField(this, "parent"); /** @internal */ __publicField(this, "children"); /** @internal */ __publicField(this, "rect"); /** @internal */ __publicField(this, "path"); /** @internal */ __publicField(this, "listeners"); this.model = _model; this.attributes = {}; this.children = []; this.rect = Rect.empty(); this.listeners = /* @__PURE__ */ new Map(); this.path = ""; } getId() { let id = this.attributes.id; if (id !== void 0) { return id; } id = this.model.nextUniqueId(); this.setId(id); return id; } getModel() { return this.model; } getType() { return this.attributes.type; } getParent() { return this.parent; } getChildren() { return this.children; } getRect() { return this.rect; } getPath() { return this.path; } getOrientation() { if (this.parent === void 0) { return this.model.isRootOrientationVertical() ? Orientation.VERT : Orientation.HORZ; } else { return Orientation.flip(this.parent.getOrientation()); } } // event can be: resize, visibility, maximize (on tabset), close setEventListener(event, callback) { this.listeners.set(event, callback); } removeEventListener(event) { this.listeners.delete(event); } /** @internal */ setId(id) { this.attributes.id = id; } /** @internal */ fireEvent(event, params) { if (this.listeners.has(event)) { this.listeners.get(event)(params); } } /** @internal */ getAttr(name) { let val = this.attributes[name]; if (val === void 0) { const modelName = this.getAttributeDefinitions().getModelName(name); if (modelName !== void 0) { val = this.model.getAttribute(modelName); } } return val; } /** @internal */ forEachNode(fn, level) { fn(this, level); level++; for (const node of this.children) { node.forEachNode(fn, level); } } /** @internal */ setPaths(path) { let i = 0; for (const node of this.children) { let newPath = path; if (node.getType() === "row") { newPath += "/r" + i; } else if (node.getType() === "tabset") { newPath += "/ts" + i; } else if (node.getType() === "tab") { newPath += "/t" + i; } node.path = newPath; node.setPaths(newPath); i++; } } /** @internal */ setParent(parent) { this.parent = parent; } /** @internal */ setRect(rect) { this.rect = rect; } /** @internal */ setPath(path) { this.path = path; } /** @internal */ setWeight(weight) { this.attributes.weight = weight; } /** @internal */ setSelected(index) { this.attributes.selected = index; } /** @internal */ findDropTargetNode(windowId, dragNode, x, y) { let rtn; if (this.rect.contains(x, y)) { if (this.model.getMaximizedTabset(windowId) !== void 0) { rtn = this.model.getMaximizedTabset(windowId).canDrop(dragNode, x, y); } else { rtn = this.canDrop(dragNode, x, y); if (rtn === void 0) { if (this.children.length !== 0) { for (const child of this.children) { rtn = child.findDropTargetNode(windowId, dragNode, x, y); if (rtn !== void 0) { break; } } } } } } return rtn; } /** @internal */ canDrop(dragNode, x, y) { return void 0; } /** @internal */ canDockInto(dragNode, dropInfo) { if (dropInfo != null) { if (dropInfo.location === DockLocation.CENTER && dropInfo.node.isEnableDrop() === false) { return false; } if (dropInfo.location === DockLocation.CENTER && dragNode.getType() === "tabset" && dragNode.getName() !== void 0) { return false; } if (dropInfo.location !== DockLocation.CENTER && dropInfo.node.isEnableDivide() === false) { return false; } if (this.model.getOnAllowDrop()) { return this.model.getOnAllowDrop()(dragNode, dropInfo); } } return true; } /** @internal */ removeChild(childNode) { const pos = this.children.indexOf(childNode); if (pos !== -1) { this.children.splice(pos, 1); } return pos; } /** @internal */ addChild(childNode, pos) { if (pos != null) { this.children.splice(pos, 0, childNode); } else { this.children.push(childNode); pos = this.children.length - 1; } childNode.parent = this; return pos; } /** @internal */ removeAll() { this.children = []; } /** @internal */ styleWithPosition(style2) { if (style2 == null) { style2 = {}; } return this.rect.styleWithPosition(style2); } /** @internal */ isEnableDivide() { return true; } /** @internal */ toAttributeString() { return JSON.stringify(this.attributes, void 0, " "); } } const _TabNode = class _TabNode extends Node { /** @internal */ constructor(model, json, addToModel = true) { super(model); /** @internal */ __publicField(this, "tabRect", Rect.empty()); /** @internal */ __publicField(this, "moveableElement"); /** @internal */ __publicField(this, "tabStamp"); /** @internal */ __publicField(this, "renderedName"); /** @internal */ __publicField(this, "extra"); /** @internal */ __publicField(this, "visible"); /** @internal */ __publicField(this, "rendered"); /** @internal */ __publicField(this, "scrollTop"); /** @internal */ __publicField(this, "scrollLeft"); this.extra = {}; this.moveableElement = null; this.tabStamp = null; this.rendered = false; this.visible = false; _TabNode.attributeDefinitions.fromJson(json, this.attributes); if (addToModel === true) { model.addNode(this); } } /** @internal */ static fromJson(json, model, addToModel = true) { const newLayoutNode = new _TabNode(model, json, addToModel); return newLayoutNode; } getName() { return this.getAttr("name"); } getHelpText() { return this.getAttr("helpText"); } getComponent() { return this.getAttr("component"); } getWindowId() { if (this.parent instanceof TabSetNode) { return this.parent.getWindowId(); } return Model.MAIN_WINDOW_ID; } getWindow() { const layoutWindow = this.model.getwindowsMap().get(this.getWindowId()); if (layoutWindow) { return layoutWindow.window; } return void 0; } /** * Returns the config attribute that can be used to store node specific data that * WILL be saved to the json. The config attribute should be changed via the action Actions.updateNodeAttributes rather * than directly, for example: * this.state.model.doAction( * FlexLayout.Actions.updateNodeAttributes(node.getId(), {config:myConfigObject})); */ getConfig() { return this.attributes.config; } /** * Returns an object that can be used to store transient node specific data that will * NOT be saved in the json. */ getExtraData() { return this.extra; } isPoppedOut() { return this.getWindowId() !== Model.MAIN_WINDOW_ID; } isSelected() { return this.getParent().getSelectedNode() === this; } getIcon() { return this.getAttr("icon"); } isEnableClose() { return this.getAttr("enableClose"); } getCloseType() { return this.getAttr("closeType"); } isEnablePopout() { return this.getAttr("enablePopout"); } isEnablePopoutIcon() { return this.getAttr("enablePopoutIcon"); } isEnablePopoutOverlay() { return this.getAttr("enablePopoutOverlay"); } isEnableDrag() { return this.getAttr("enableDrag"); } isEnableRename() { return this.getAttr("enableRename"); } isEnableWindowReMount() { return this.getAttr("enableWindowReMount"); } getClassName() { return this.getAttr("className"); } getContentClassName() { return this.getAttr("contentClassName"); } getTabSetClassName() { return this.getAttr("tabsetClassName"); } isEnableRenderOnDemand() { return this.getAttr("enableRenderOnDemand"); } getMinWidth() { return this.getAttr("minWidth"); } getMinHeight() { return this.getAttr("minHeight"); } getMaxWidth() { return this.getAttr("maxWidth"); } getMaxHeight() { return this.getAttr("maxHeight"); } isVisible() { return this.visible; } toJson() { const json = {}; _TabNode.attributeDefinitions.toJson(json, this.attributes); return json; } /** @internal */ saveScrollPosition() { if (this.moveableElement) { this.scrollLeft = this.moveableElement.scrollLeft; this.scrollTop = this.moveableElement.scrollTop; } } /** @internal */ restoreScrollPosition() { if (this.scrollTop) { requestAnimationFrame(() => { if (this.moveableElement) { if (this.scrollTop) { this.moveableElement.scrollTop = this.scrollTop; this.moveableElement.scrollLeft = this.scrollLeft; } } }); } } /** @internal */ setRect(rect) { if (!rect.equals(this.rect)) { this.fireEvent("resize", { rect }); this.rect = rect; } } /** @internal */ setVisible(visible) { if (visible !== this.visible) { this.visible = visible; this.fireEvent("visibility", { visible }); } } /** @internal */ getScrollTop() { return this.scrollTop; } /** @internal */ setScrollTop(scrollTop) { this.scrollTop = scrollTop; } /** @internal */ getScrollLeft() { return this.scrollLeft; } /** @internal */ setScrollLeft(scrollLeft) { this.scrollLeft = scrollLeft; } /** @internal */ isRendered() { return this.rendered; } /** @internal */ setRendered(rendered) { this.rendered = rendered; } /** @internal */ getTabRect() { return this.tabRect; } /** @internal */ setTabRect(rect) { this.tabRect = rect; } /** @internal */ getTabStamp() { return this.tabStamp; } /** @internal */ setTabStamp(stamp) { this.tabStamp = stamp; } /** @internal */ getMoveableElement() { return this.moveableElement; } /** @internal */ setMoveableElement(element) { this.moveableElement = element; } /** @internal */ setRenderedName(name) { this.renderedName = name; } /** @internal */ getNameForOverflowMenu() { const altName = this.getAttr("altName"); if (altName !== void 0) { return altName; } return this.renderedName; } /** @internal */ setName(name) { this.attributes.name = name; } /** @internal */ delete() { this.parent.remove(this); this.fireEvent("close", {}); } /** @internal */ updateAttrs(json) { _TabNode.attributeDefinitions.update(json, this.attributes); } /** @internal */ getAttributeDefinitions() { return _TabNode.attributeDefinitions; } /** @internal */ setBorderWidth(width) { this.attributes.borderWidth = width; } /** @internal */ setBorderHeight(height) { this.attributes.borderHeight = height; } /** @internal */ static getAttributeDefinitions() { return _TabNode.attributeDefinitions; } /** @internal */ static createAttributeDefinitions() { const attributeDefinitions = new AttributeDefinitions(); attributeDefinitions.add("type", _TabNode.TYPE, true).setType(Attribute.STRING).setFixed(); attributeDefinitions.add("id", void 0).setType(Attribute.STRING).setDescription( `the unique id of the tab, if left undefined a uuid will be assigned` ); attributeDefinitions.add("name", "[Unnamed Tab]").setType(Attribute.STRING).setDescription( `name of tab to be displayed in the tab button` ); attributeDefinitions.add("altName", void 0).setType(Attribute.STRING).setDescription( `if there is no name specifed then this value will be used in the overflow menu` ); attributeDefinitions.add("helpText", void 0).setType(Attribute.STRING).setDescription( `An optional help text for the tab to be displayed upon tab hover.` ); attributeDefinitions.add("component", void 0).setType(Attribute.STRING).setDescription( `string identifying which component to run (for factory)` ); attributeDefinitions.add("config", void 0).setType("any").setDescription( `a place to hold json config for the hosted component` ); attributeDefinitions.add("tabsetClassName", void 0).setType(Attribute.STRING).setDescription( `class applied to parent tabset when this is the only tab and it is stretched to fill the tabset` ); attributeDefinitions.add("enableWindowReMount", false).setType(Attribute.BOOLEAN).setDescription( `if enabled the tab will re-mount when popped out/in` ); attributeDefinitions.addInherited("enableClose", "tabEnableClose").setType(Attribute.BOOLEAN).setDescription( `allow user to close tab via close button` ); attributeDefinitions.addInherited("closeType", "tabCloseType").setType("ICloseType").setDescription( `see values in ICloseType` ); attributeDefinitions.addInherited("enableDrag", "tabEnableDrag").setType(Attribute.BOOLEAN).setDescription( `allow user to drag tab to new location` ); attributeDefinitions.addInherited("enableRename", "tabEnableRename").setType(Attribute.BOOLEAN).setDescription( `allow user to rename tabs by double clicking` ); attributeDefinitions.addInherited("className", "tabClassName").setType(Attribute.STRING).setDescription( `class applied to tab button` ); attributeDefinitions.addInherited("contentClassName", "tabContentClassName").setType(Attribute.STRING).setDescription( `class applied to tab content` ); attributeDefinitions.addInherited("icon", "tabIcon").setType(Attribute.STRING).setDescription( `the tab icon` ); attributeDefinitions.addInherited("enableRenderOnDemand", "tabEnableRenderOnDemand").setType(Attribute.BOOLEAN).setDescription( `whether to avoid rendering component until tab is visible` ); attributeDefinitions.addInherited("enablePopout", "tabEnablePopout").setType(Attribute.BOOLEAN).setAlias("enableFloat").setDescription( `enable popout (in popout capable browser)` ); attributeDefinitions.addInherited("enablePopoutIcon", "tabEnablePopoutIcon").setType(Attribute.BOOLEAN).setDescription( `whether to show the popout icon in the tabset header if this tab enables popouts` ); attributeDefinitions.addInherited("enablePopoutOverlay", "tabEnablePopoutOverlay").setType(Attribute.BOOLEAN).setDescription( `if this tab will not work correctly in a popout window when the main window is backgrounded (inactive) then enabling this option will gray out this tab` ); attributeDefinitions.addInherited("borderWidth", "tabBorderWidth").setType(Attribute.NUMBER).setDescription( `width when added to border, -1 will use border size` ); attributeDefinitions.addInherited("borderHeight", "tabBorderHeight").setType(Attribute.NUMBER).setDescription( `height when added to border, -1 will use border size` ); attributeDefinitions.addInherited("minWidth", "tabMinWidth").setType(Attribute.NUMBER).setDescription( `the min width of this tab` ); attributeDefinitions.addInherited("minHeight", "tabMinHeight").setType(Attribute.NUMBER).setDescription( `the min height of this tab` ); attributeDefinitions.addInherited("maxWidth", "tabMaxWidth").setType(Attribute.NUMBER).setDescription( `the max width of this tab` ); attributeDefinitions.addInherited("maxHeight", "tabMaxHeight").setType(Attribute.NUMBER).setDescription( `the max height of this tab` ); return attributeDefinitions; } }; __publicField(_TabNode, "TYPE", "tab"); /** @internal */ __publicField(_TabNode, "attributeDefinitions", _TabNode.createAttributeDefinitions()); let TabNode = _TabNode; function isDesktop() { const desktop = typeof window !== "undefined" && window.matchMedia && window.matchMedia("(hover: hover) and (pointer: fine)").matches; return desktop; } function getRenderStateEx(layout, node, iconAngle) { let leadingContent = void 0; const titleContent = node.getName(); const name = node.getName(); if (iconAngle === void 0) { iconAngle = 0; } if (leadingContent === void 0 && node.getIcon() !== void 0) { if (iconAngle !== 0) { leadingContent = /* @__PURE__ */ jsx("img", { style: { width: "1em", height: "1em", transform: "rotate(" + iconAngle + "deg)" }, src: node.getIcon(), alt: "leadingContent" }); } else { leadingContent = /* @__PURE__ */ jsx("img", { style: { width: "1em", height: "1em" }, src: node.getIcon(), alt: "leadingContent" }); } } const buttons = []; const renderState = { leading: leadingContent, content: titleContent, name, buttons }; layout.customizeTab(node, renderState); node.setRenderedName(renderState.name); return renderState; } function isAuxMouseEvent(event) { let auxEvent = false; if (event.nativeEvent instanceof MouseEvent) { if (event.nativeEvent.button !== 0 || event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) { auxEvent = true; } } return auxEvent; } function enablePointerOnIFrames(enable, currentDocument) { const iframes = [ ...getElementsByTagName("iframe", currentDocument), ...getElementsByTagName("webview", currentDocument) ]; for (const iframe of iframes) { iframe.style.pointerEvents = enable ? "auto" : "none"; } } function getElementsByTagName(tag, currentDocument) { return [...currentDocument.getElementsByTagName(tag)]; } function startDrag(doc, event, drag, dragEnd, dragCancel) { event.preventDefault(); const pointerMove = (ev) => { ev.preventDefault(); drag(ev.clientX, ev.clientY); }; const pointerCancel = (ev) => { ev.preventDefault(); dragCancel(); }; const pointerUp = () => { doc.removeEventListener("pointermove", pointerMove); doc.removeEventListener("pointerup", pointerUp); doc.removeEventListener("pointercancel", pointerCancel); dragEnd(); }; doc.addEventListener("pointermove", pointerMove); doc.addEventListener("pointerup", pointerUp); doc.addEventListener("pointercancel", pointerCancel); } function canDockToWindow(node) { if (node instanceof TabNode) { return node.isEnablePopout(); } else if (node instanceof TabSetNode) { for (const child of node.getChildren()) { if (child.isEnablePopout() === false) { return false;