UNPKG

flexlayout-react-v7-react-19

Version:

A multi-tab docking layout manager

497 lines 21.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Model = void 0; const Attribute_1 = require("../Attribute"); const AttributeDefinitions_1 = require("../AttributeDefinitions"); const DockLocation_1 = require("../DockLocation"); const Orientation_1 = require("../Orientation"); const Rect_1 = require("../Rect"); const Actions_1 = require("./Actions"); const BorderNode_1 = require("./BorderNode"); const BorderSet_1 = require("./BorderSet"); const RowNode_1 = require("./RowNode"); const TabNode_1 = require("./TabNode"); const TabSetNode_1 = require("./TabSetNode"); const Utils_1 = require("./Utils"); /** * Class containing the Tree of Nodes used by the FlexLayout component */ class Model { /** * Loads the model from the given json object * @param json the json model to load * @returns {Model} a new Model object */ static fromJson(json) { const model = new Model(); Model._attributeDefinitions.fromJson(json.global, model._attributes); if (json.borders) { model._borders = BorderSet_1.BorderSet._fromJson(json.borders, model); } model._root = RowNode_1.RowNode._fromJson(json.layout, model); model._tidy(); // initial tidy of node tree return model; } /** @internal */ static _createAttributeDefinitions() { const attributeDefinitions = new AttributeDefinitions_1.AttributeDefinitions(); attributeDefinitions.add("legacyOverflowMenu", false).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("enableEdgeDock", true).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("rootOrientationVertical", false).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("marginInsets", { top: 0, right: 0, bottom: 0, left: 0 }) .setType("IInsets"); attributeDefinitions.add("enableUseVisibility", false).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("enableRotateBorderIcons", true).setType(Attribute_1.Attribute.BOOLEAN); // splitter attributeDefinitions.add("splitterSize", -1).setType(Attribute_1.Attribute.NUMBER); attributeDefinitions.add("splitterExtra", 0).setType(Attribute_1.Attribute.NUMBER); // tab attributeDefinitions.add("tabEnableClose", true).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("tabCloseType", 1).setType("ICloseType"); attributeDefinitions.add("tabEnableFloat", false).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("tabEnableDrag", true).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("tabEnableRename", true).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("tabContentClassName", undefined).setType(Attribute_1.Attribute.STRING); attributeDefinitions.add("tabClassName", undefined).setType(Attribute_1.Attribute.STRING); attributeDefinitions.add("tabIcon", undefined).setType(Attribute_1.Attribute.STRING); attributeDefinitions.add("tabEnableRenderOnDemand", true).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("tabDragSpeed", 0.3).setType(Attribute_1.Attribute.NUMBER); attributeDefinitions.add("tabBorderWidth", -1).setType(Attribute_1.Attribute.NUMBER); attributeDefinitions.add("tabBorderHeight", -1).setType(Attribute_1.Attribute.NUMBER); // tabset attributeDefinitions.add("tabSetEnableDeleteWhenEmpty", true).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("tabSetEnableDrop", true).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("tabSetEnableDrag", true).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("tabSetEnableDivide", true).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("tabSetEnableMaximize", true).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("tabSetEnableClose", false).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("tabSetEnableSingleTabStretch", false).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("tabSetAutoSelectTab", true).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("tabSetClassNameTabStrip", undefined).setType(Attribute_1.Attribute.STRING); attributeDefinitions.add("tabSetClassNameHeader", undefined).setType(Attribute_1.Attribute.STRING); attributeDefinitions.add("tabSetEnableTabStrip", true).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("tabSetHeaderHeight", 0).setType(Attribute_1.Attribute.NUMBER); attributeDefinitions.add("tabSetTabStripHeight", 0).setType(Attribute_1.Attribute.NUMBER); attributeDefinitions.add("tabSetMarginInsets", { top: 0, right: 0, bottom: 0, left: 0 }) .setType("IInsets"); attributeDefinitions.add("tabSetBorderInsets", { top: 0, right: 0, bottom: 0, left: 0 }) .setType("IInsets"); attributeDefinitions.add("tabSetTabLocation", "top").setType("ITabLocation"); attributeDefinitions.add("tabSetMinWidth", 0).setType(Attribute_1.Attribute.NUMBER); attributeDefinitions.add("tabSetMinHeight", 0).setType(Attribute_1.Attribute.NUMBER); // border attributeDefinitions.add("borderSize", 200).setType(Attribute_1.Attribute.NUMBER); attributeDefinitions.add("borderMinSize", 0).setType(Attribute_1.Attribute.NUMBER); attributeDefinitions.add("borderBarSize", 0).setType(Attribute_1.Attribute.NUMBER); attributeDefinitions.add("borderEnableDrop", true).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("borderAutoSelectTabWhenOpen", true).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("borderAutoSelectTabWhenClosed", false).setType(Attribute_1.Attribute.BOOLEAN); attributeDefinitions.add("borderClassName", undefined).setType(Attribute_1.Attribute.STRING); attributeDefinitions.add("borderEnableAutoHide", false).setType(Attribute_1.Attribute.BOOLEAN); return attributeDefinitions; } /** * 'private' constructor. Use the static method Model.fromJson(json) to create a model * @internal */ constructor() { /** @internal */ this._borderRects = { inner: Rect_1.Rect.empty(), outer: Rect_1.Rect.empty() }; this._attributes = {}; this._idMap = {}; this._borders = new BorderSet_1.BorderSet(this); this._pointerFine = true; this._showHiddenBorder = DockLocation_1.DockLocation.CENTER; } /** @internal */ _setChangeListener(listener) { this._changeListener = listener; } /** * Get the currently active tabset node */ getActiveTabset() { if (this._activeTabSet && this.getNodeById(this._activeTabSet.getId())) { return this._activeTabSet; } else { return undefined; } } /** @internal */ _getShowHiddenBorder() { return this._showHiddenBorder; } /** @internal */ _setShowHiddenBorder(location) { this._showHiddenBorder = location; } /** @internal */ _setActiveTabset(tabsetNode) { this._activeTabSet = tabsetNode; } /** * Get the currently maximized tabset node */ getMaximizedTabset() { return this._maximizedTabSet; } /** @internal */ _setMaximizedTabset(tabsetNode) { this._maximizedTabSet = tabsetNode; } /** * Gets the root RowNode of the model * @returns {RowNode} */ getRoot() { return this._root; } isRootOrientationVertical() { return this._attributes.rootOrientationVertical; } isUseVisibility() { return this._attributes.enableUseVisibility; } isEnableRotateBorderIcons() { return this._attributes.enableRotateBorderIcons; } /** * Gets the * @returns {BorderSet|*} */ getBorderSet() { return this._borders; } /** @internal */ _getOuterInnerRects() { return this._borderRects; } /** @internal */ _getPointerFine() { return this._pointerFine; } /** @internal */ _setPointerFine(pointerFine) { this._pointerFine = pointerFine; } /** * Visits all the nodes in the model and calls the given function for each * @param fn a function that takes visited node and a integer level as parameters */ visitNodes(fn) { this._borders._forEachNode(fn); this._root._forEachNode(fn, 0); } /** * Gets a node by its id * @param id the id to find */ getNodeById(id) { return this._idMap[id]; } /** * Finds the first/top left tab set of the given node. * @param node The top node you want to begin searching from, deafults to the root node * @returns The first Tab Set */ getFirstTabSet(node = this._root) { const child = node.getChildren()[0]; if (child instanceof TabSetNode_1.TabSetNode) { return child; } else { return this.getFirstTabSet(child); } } /** * Update the node tree by performing the given action, * Actions should be generated via static methods on the Actions class * @param action the action to perform * @returns added Node for Actions.addNode; undefined otherwise */ doAction(action) { let returnVal = undefined; // console.log(action); switch (action.type) { case Actions_1.Actions.ADD_NODE: { const newNode = new TabNode_1.TabNode(this, action.data.json, true); const toNode = this._idMap[action.data.toNode]; if (toNode instanceof TabSetNode_1.TabSetNode || toNode instanceof BorderNode_1.BorderNode || toNode instanceof RowNode_1.RowNode) { toNode.drop(newNode, DockLocation_1.DockLocation.getByName(action.data.location), action.data.index, action.data.select); returnVal = newNode; } break; } case Actions_1.Actions.MOVE_NODE: { const fromNode = this._idMap[action.data.fromNode]; if (fromNode instanceof TabNode_1.TabNode || fromNode instanceof TabSetNode_1.TabSetNode) { const toNode = this._idMap[action.data.toNode]; if (toNode instanceof TabSetNode_1.TabSetNode || toNode instanceof BorderNode_1.BorderNode || toNode instanceof RowNode_1.RowNode) { toNode.drop(fromNode, DockLocation_1.DockLocation.getByName(action.data.location), action.data.index, action.data.select); } } break; } case Actions_1.Actions.DELETE_TAB: { const node = this._idMap[action.data.node]; if (node instanceof TabNode_1.TabNode) { node._delete(); } break; } case Actions_1.Actions.DELETE_TABSET: { const node = this._idMap[action.data.node]; if (node instanceof TabSetNode_1.TabSetNode) { // first delete all child tabs that are closeable const children = [...node.getChildren()]; for (let i = 0; i < children.length; i++) { const child = children[i]; if (child.isEnableClose()) { child._delete(); } } if (node.getChildren().length === 0) { node._delete(); } this._tidy(); } break; } case Actions_1.Actions.FLOAT_TAB: { const node = this._idMap[action.data.node]; if (node instanceof TabNode_1.TabNode) { node._setFloating(true); (0, Utils_1.adjustSelectedIndexAfterFloat)(node); } break; } case Actions_1.Actions.UNFLOAT_TAB: { const node = this._idMap[action.data.node]; if (node instanceof TabNode_1.TabNode) { node._setFloating(false); (0, Utils_1.adjustSelectedIndexAfterDock)(node); } break; } case Actions_1.Actions.RENAME_TAB: { const node = this._idMap[action.data.node]; if (node instanceof TabNode_1.TabNode) { node._setName(action.data.text); } break; } case Actions_1.Actions.SELECT_TAB: { const tabNode = this._idMap[action.data.tabNode]; if (tabNode instanceof TabNode_1.TabNode) { const parent = tabNode.getParent(); const pos = parent.getChildren().indexOf(tabNode); if (parent instanceof BorderNode_1.BorderNode) { if (parent.getSelected() === pos) { parent._setSelected(-1); } else { parent._setSelected(pos); } } else if (parent instanceof TabSetNode_1.TabSetNode) { if (parent.getSelected() !== pos) { parent._setSelected(pos); } this._activeTabSet = parent; } } break; } case Actions_1.Actions.SET_ACTIVE_TABSET: { if (action.data.tabsetNode === undefined) { this._activeTabSet = undefined; } else { const tabsetNode = this._idMap[action.data.tabsetNode]; if (tabsetNode instanceof TabSetNode_1.TabSetNode) { this._activeTabSet = tabsetNode; } } break; } case Actions_1.Actions.ADJUST_SPLIT: { const node1 = this._idMap[action.data.node1]; const node2 = this._idMap[action.data.node2]; if ((node1 instanceof TabSetNode_1.TabSetNode || node1 instanceof RowNode_1.RowNode) && (node2 instanceof TabSetNode_1.TabSetNode || node2 instanceof RowNode_1.RowNode)) { this._adjustSplitSide(node1, action.data.weight1, action.data.pixelWidth1); this._adjustSplitSide(node2, action.data.weight2, action.data.pixelWidth2); } break; } case Actions_1.Actions.ADJUST_BORDER_SPLIT: { const node = this._idMap[action.data.node]; if (node instanceof BorderNode_1.BorderNode) { node._setSize(action.data.pos); } break; } case Actions_1.Actions.MAXIMIZE_TOGGLE: { const node = this._idMap[action.data.node]; if (node instanceof TabSetNode_1.TabSetNode) { if (node === this._maximizedTabSet) { this._maximizedTabSet = undefined; } else { this._maximizedTabSet = node; this._activeTabSet = node; } } break; } case Actions_1.Actions.UPDATE_MODEL_ATTRIBUTES: { this._updateAttrs(action.data.json); break; } case Actions_1.Actions.UPDATE_NODE_ATTRIBUTES: { const node = this._idMap[action.data.node]; node._updateAttrs(action.data.json); break; } default: break; } this._updateIdMap(); if (this._changeListener !== undefined) { this._changeListener(action); } return returnVal; } /** @internal */ _updateIdMap() { // regenerate idMap to stop it building up this._idMap = {}; this.visitNodes((node) => (this._idMap[node.getId()] = node)); // console.log(JSON.stringify(Object.keys(this._idMap))); } /** @internal */ _adjustSplitSide(node, weight, pixels) { node._setWeight(weight); if (node.getWidth() != null && node.getOrientation() === Orientation_1.Orientation.VERT) { node._updateAttrs({ width: pixels }); } else if (node.getHeight() != null && node.getOrientation() === Orientation_1.Orientation.HORZ) { node._updateAttrs({ height: pixels }); } } /** * Converts the model to a json object * @returns {IJsonModel} json object that represents this model */ toJson() { const global = {}; Model._attributeDefinitions.toJson(global, this._attributes); // save state of nodes this.visitNodes((node) => { node._fireEvent("save", undefined); }); return { global, borders: this._borders._toJson(), layout: this._root.toJson() }; } getSplitterSize() { let splitterSize = this._attributes.splitterSize; if (splitterSize === -1) { // use defaults splitterSize = this._pointerFine ? 8 : 12; // larger for mobile } return splitterSize; } isLegacyOverflowMenu() { return this._attributes.legacyOverflowMenu; } getSplitterExtra() { return this._attributes.splitterExtra; } isEnableEdgeDock() { return this._attributes.enableEdgeDock; } /** @internal */ _addNode(node) { const id = node.getId(); if (this._idMap[id] !== undefined) { throw new Error(`Error: each node must have a unique id, duplicate id:${node.getId()}`); } if (node.getType() !== "splitter") { this._idMap[id] = node; } } /** @internal */ _layout(rect, metrics) { var _a; // let start = Date.now(); this._borderRects = this._borders._layoutBorder({ outer: rect, inner: rect }, metrics); rect = this._borderRects.inner.removeInsets(this._getAttribute("marginInsets")); (_a = this._root) === null || _a === void 0 ? void 0 : _a.calcMinSize(); this._root._layout(rect, metrics); // console.log("layout time: " + (Date.now() - start)); return rect; } /** @internal */ _findDropTargetNode(dragNode, x, y) { let node = this._root._findDropTargetNode(dragNode, x, y); if (node === undefined) { node = this._borders._findDropTargetNode(dragNode, x, y); } return node; } /** @internal */ _tidy() { // console.log("before _tidy", this.toString()); this._root._tidy(); // console.log("after _tidy", this.toString()); } /** @internal */ _updateAttrs(json) { Model._attributeDefinitions.update(json, this._attributes); } /** @internal */ _nextUniqueId() { return '#' + (0, Utils_1.randomUUID)(); } /** @internal */ _getAttribute(name) { return this._attributes[name]; } /** * Sets a function to allow/deny dropping a node * @param onAllowDrop function that takes the drag node and DropInfo and returns true if the drop is allowed */ setOnAllowDrop(onAllowDrop) { this._onAllowDrop = onAllowDrop; } /** @internal */ _getOnAllowDrop() { return this._onAllowDrop; } /** * set callback called when a new TabSet is created. * The tabNode can be undefined if it's the auto created first tabset in the root row (when the last * tab is deleted, the root tabset can be recreated) * @param onCreateTabSet */ setOnCreateTabSet(onCreateTabSet) { this._onCreateTabSet = onCreateTabSet; } /** @internal */ _getOnCreateTabSet() { return this._onCreateTabSet; } static toTypescriptInterfaces() { console.log(Model._attributeDefinitions.toTypescriptInterface("Global", undefined)); console.log(RowNode_1.RowNode.getAttributeDefinitions().toTypescriptInterface("Row", Model._attributeDefinitions)); console.log(TabSetNode_1.TabSetNode.getAttributeDefinitions().toTypescriptInterface("TabSet", Model._attributeDefinitions)); console.log(TabNode_1.TabNode.getAttributeDefinitions().toTypescriptInterface("Tab", Model._attributeDefinitions)); console.log(BorderNode_1.BorderNode.getAttributeDefinitions().toTypescriptInterface("Border", Model._attributeDefinitions)); } toString() { return JSON.stringify(this.toJson()); } } exports.Model = Model; /** @internal */ Model._attributeDefinitions = Model._createAttributeDefinitions(); //# sourceMappingURL=Model.js.map