UNPKG

flexlayout-react

Version:

A multi-tab docking layout manager

390 lines 16.5 kB
import { Attribute } from "../Attribute"; import { AttributeDefinitions } from "../AttributeDefinitions"; import { DockLocation } from "../DockLocation"; import { DropInfo } from "../DropInfo"; import { Orientation } from "../Orientation"; import { Rect } from "../Rect"; import { CLASSES } from "../Types"; import { Model } from "./Model"; import { Node } from "./Node"; import { TabNode } from "./TabNode"; import { adjustSelectedIndex } from "./Utils"; export class BorderNode extends Node { /** @internal */ static fromJson(json, model) { const location = DockLocation.getByName(json.location); const border = new BorderNode(location, json, model); if (json.children) { border.children = json.children.map((jsonChild) => { const child = TabNode.fromJson(jsonChild, model); child.setParent(border); return child; }); } return border; } /** @internal */ constructor(location, json, model) { super(model); /** @internal */ this.outerRect = Rect.empty(); /** @internal */ this.contentRect = Rect.empty(); /** @internal */ this.tabHeaderRect = Rect.empty(); this.location = location; this.attributes.id = `border_${location.getName()}`; BorderNode.attributeDefinitions.fromJson(json, this.attributes); model.addNode(this); } getLocation() { return this.location; } getClassName() { return this.getAttr("className"); } isHorizontal() { return this.location.orientation === Orientation.HORZ; } getSize() { const defaultSize = this.getAttr("size"); const selected = this.getSelected(); if (selected === -1) { return defaultSize; } else { const tabNode = this.children[selected]; const tabBorderSize = this.isHorizontal() ? tabNode.getAttr("borderWidth") : tabNode.getAttr("borderHeight"); if (tabBorderSize === -1) { return defaultSize; } else { return tabBorderSize; } } } getMinSize() { const selectedNode = this.getSelectedNode(); let min = this.getAttr("minSize"); if (selectedNode) { const nodeMin = this.isHorizontal() ? selectedNode.getMinWidth() : selectedNode.getMinHeight(); min = Math.max(min, nodeMin); } return min; } getMaxSize() { const selectedNode = this.getSelectedNode(); let max = this.getAttr("maxSize"); if (selectedNode) { const nodeMax = this.isHorizontal() ? selectedNode.getMaxWidth() : selectedNode.getMaxHeight(); max = Math.min(max, nodeMax); } return max; } getSelected() { return this.attributes.selected; } isAutoHide() { return this.getAttr("enableAutoHide"); } getSelectedNode() { if (this.getSelected() !== -1) { return this.children[this.getSelected()]; } return undefined; } getOrientation() { return this.location.getOrientation(); } /** * 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; } isMaximized() { return false; } isShowing() { return this.attributes.show; } toJson() { const json = {}; BorderNode.attributeDefinitions.toJson(json, this.attributes); json.location = this.location.getName(); json.children = this.children.map((child) => child.toJson()); return json; } /** @internal */ isAutoSelectTab(whenOpen) { if (whenOpen == null) { whenOpen = this.getSelected() !== -1; } if (whenOpen) { return this.getAttr("autoSelectTabWhenOpen"); } else { return this.getAttr("autoSelectTabWhenClosed"); } } isEnableTabScrollbar() { return this.getAttr("enableTabScrollbar"); } /** @internal */ setSelected(index) { this.attributes.selected = index; } /** @internal */ getTabHeaderRect() { return this.tabHeaderRect; } /** @internal */ setTabHeaderRect(r) { this.tabHeaderRect = r; } /** @internal */ getOuterRect() { return this.outerRect; } /** @internal */ setOuterRect(r) { this.outerRect = r; } /** @internal */ getRect() { return this.tabHeaderRect; } /** @internal */ getContentRect() { return this.contentRect; } /** @internal */ setContentRect(r) { this.contentRect = r; } /** @internal */ isEnableDrop() { return this.getAttr("enableDrop"); } /** @internal */ setSize(pos) { const selected = this.getSelected(); if (selected === -1) { this.attributes.size = pos; } else { const tabNode = this.children[selected]; const tabBorderSize = this.isHorizontal() ? tabNode.getAttr("borderWidth") : tabNode.getAttr("borderHeight"); if (tabBorderSize === -1) { this.attributes.size = pos; } else { if (this.isHorizontal()) { tabNode.setBorderWidth(pos); } else { tabNode.setBorderHeight(pos); } } } } /** @internal */ updateAttrs(json) { BorderNode.attributeDefinitions.update(json, this.attributes); } /** @internal */ remove(node) { const removedIndex = this.removeChild(node); if (this.getSelected() !== -1) { adjustSelectedIndex(this, removedIndex); } } /** @internal */ canDrop(dragNode, x, y) { if (!(dragNode instanceof TabNode)) { return undefined; } let dropInfo; const dockLocation = DockLocation.CENTER; if (this.tabHeaderRect.contains(x, y)) { if (this.location.orientation === Orientation.VERT) { if (this.children.length > 0) { let child = this.children[0]; let childRect = child.getTabRect(); const childY = childRect.y; const childHeight = childRect.height; let pos = this.tabHeaderRect.x; let childCenter = 0; for (let i = 0; i < this.children.length; i++) { child = this.children[i]; childRect = child.getTabRect(); childCenter = childRect.x + childRect.width / 2; if (x >= pos && x < childCenter) { const outlineRect = new Rect(childRect.x - 2, childY, 3, childHeight); dropInfo = new DropInfo(this, outlineRect, dockLocation, i, CLASSES.FLEXLAYOUT__OUTLINE_RECT); break; } pos = childCenter; } if (dropInfo == null) { const outlineRect = new Rect(childRect.getRight() - 2, childY, 3, childHeight); dropInfo = new DropInfo(this, outlineRect, dockLocation, this.children.length, CLASSES.FLEXLAYOUT__OUTLINE_RECT); } } else { const outlineRect = new Rect(this.tabHeaderRect.x + 1, this.tabHeaderRect.y + 2, 3, 18); dropInfo = new DropInfo(this, outlineRect, dockLocation, 0, CLASSES.FLEXLAYOUT__OUTLINE_RECT); } } else { if (this.children.length > 0) { let child = this.children[0]; let childRect = child.getTabRect(); const childX = childRect.x; const childWidth = childRect.width; let pos = this.tabHeaderRect.y; let childCenter = 0; for (let i = 0; i < this.children.length; i++) { child = this.children[i]; childRect = child.getTabRect(); childCenter = childRect.y + childRect.height / 2; if (y >= pos && y < childCenter) { const outlineRect = new Rect(childX, childRect.y - 2, childWidth, 3); dropInfo = new DropInfo(this, outlineRect, dockLocation, i, CLASSES.FLEXLAYOUT__OUTLINE_RECT); break; } pos = childCenter; } if (dropInfo == null) { const outlineRect = new Rect(childX, childRect.getBottom() - 2, childWidth, 3); dropInfo = new DropInfo(this, outlineRect, dockLocation, this.children.length, CLASSES.FLEXLAYOUT__OUTLINE_RECT); } } else { const outlineRect = new Rect(this.tabHeaderRect.x + 2, this.tabHeaderRect.y + 1, 18, 3); dropInfo = new DropInfo(this, outlineRect, dockLocation, 0, CLASSES.FLEXLAYOUT__OUTLINE_RECT); } } if (!dragNode.canDockInto(dragNode, dropInfo)) { return undefined; } } else if (this.getSelected() !== -1 && this.outerRect.contains(x, y)) { const outlineRect = this.outerRect; dropInfo = new DropInfo(this, outlineRect, dockLocation, -1, CLASSES.FLEXLAYOUT__OUTLINE_RECT); if (!dragNode.canDockInto(dragNode, dropInfo)) { return undefined; } } return dropInfo; } /** @internal */ drop(dragNode, location, index, select) { let fromIndex = 0; const dragParent = dragNode.getParent(); if (dragParent !== undefined) { fromIndex = dragParent.removeChild(dragNode); // if selected node in border is being docked into a different border then deselect border tabs if (dragParent !== this && dragParent instanceof BorderNode && dragParent.getSelected() === fromIndex) { dragParent.setSelected(-1); } else { adjustSelectedIndex(dragParent, fromIndex); } } // if dropping a tab back to same tabset and moving to forward position then reduce insertion index if (dragNode instanceof TabNode && dragParent === this && fromIndex < index && index > 0) { index--; } // simple_bundled dock to existing tabset let insertPos = index; if (insertPos === -1) { insertPos = this.children.length; } if (dragNode instanceof TabNode) { this.addChild(dragNode, insertPos); } if (select || (select !== false && this.isAutoSelectTab())) { this.setSelected(insertPos); } this.model.tidy(); } /** @internal */ getSplitterBounds(index, useMinSize = false) { const pBounds = [0, 0]; const minSize = useMinSize ? this.getMinSize() : 0; const maxSize = useMinSize ? this.getMaxSize() : 99999; const rootRow = this.model.getRoot(Model.MAIN_WINDOW_ID); const innerRect = rootRow.getRect(); const splitterSize = this.model.getSplitterSize(); if (this.location === DockLocation.TOP) { pBounds[0] = this.tabHeaderRect.getBottom() + minSize; const maxPos = this.tabHeaderRect.getBottom() + maxSize; pBounds[1] = Math.max(pBounds[0], innerRect.getBottom() - rootRow.getMinHeight() - splitterSize); pBounds[1] = Math.min(pBounds[1], maxPos); } else if (this.location === DockLocation.LEFT) { pBounds[0] = this.tabHeaderRect.getRight() + minSize; const maxPos = this.tabHeaderRect.getRight() + maxSize; pBounds[1] = Math.max(pBounds[0], innerRect.getRight() - rootRow.getMinWidth() - splitterSize); pBounds[1] = Math.min(pBounds[1], maxPos); } else if (this.location === DockLocation.BOTTOM) { pBounds[1] = this.tabHeaderRect.y - minSize - splitterSize; const maxPos = this.tabHeaderRect.y - maxSize - splitterSize; pBounds[0] = Math.min(pBounds[1], innerRect.y + rootRow.getMinHeight()); pBounds[0] = Math.max(pBounds[0], maxPos); } else if (this.location === DockLocation.RIGHT) { pBounds[1] = this.tabHeaderRect.x - minSize - splitterSize; const maxPos = this.tabHeaderRect.x - maxSize - splitterSize; pBounds[0] = Math.min(pBounds[1], innerRect.x + rootRow.getMinWidth()); pBounds[0] = Math.max(pBounds[0], maxPos); } return pBounds; } /** @internal */ calculateSplit(splitter, splitterPos) { const pBounds = this.getSplitterBounds(splitterPos); if (this.location === DockLocation.BOTTOM || this.location === DockLocation.RIGHT) { return Math.max(0, pBounds[1] - splitterPos); } else { return Math.max(0, splitterPos - pBounds[0]); } } /** @internal */ getAttributeDefinitions() { return BorderNode.attributeDefinitions; } /** @internal */ static getAttributeDefinitions() { return BorderNode.attributeDefinitions; } /** @internal */ static createAttributeDefinitions() { const attributeDefinitions = new AttributeDefinitions(); attributeDefinitions.add("type", BorderNode.TYPE, true).setType(Attribute.STRING).setFixed(); attributeDefinitions.add("selected", -1).setType(Attribute.NUMBER).setDescription(`index of selected/visible tab in border; -1 means no tab selected`); attributeDefinitions.add("show", true).setType(Attribute.BOOLEAN).setDescription(`show/hide this border`); attributeDefinitions.add("config", undefined).setType("any").setDescription(`a place to hold json config used in your own code`); attributeDefinitions.addInherited("enableDrop", "borderEnableDrop").setType(Attribute.BOOLEAN).setDescription(`whether tabs can be dropped into this border`); attributeDefinitions.addInherited("className", "borderClassName").setType(Attribute.STRING).setDescription(`class applied to tab button`); attributeDefinitions.addInherited("autoSelectTabWhenOpen", "borderAutoSelectTabWhenOpen").setType(Attribute.BOOLEAN).setDescription(`whether to select new/moved tabs in border when the border is already open`); attributeDefinitions.addInherited("autoSelectTabWhenClosed", "borderAutoSelectTabWhenClosed").setType(Attribute.BOOLEAN).setDescription(`whether to select new/moved tabs in border when the border is currently closed`); attributeDefinitions.addInherited("size", "borderSize").setType(Attribute.NUMBER).setDescription(`size of the tab area when selected`); attributeDefinitions.addInherited("minSize", "borderMinSize").setType(Attribute.NUMBER).setDescription(`the minimum size of the tab area`); attributeDefinitions.addInherited("maxSize", "borderMaxSize").setType(Attribute.NUMBER).setDescription(`the maximum size of the tab area`); attributeDefinitions.addInherited("enableAutoHide", "borderEnableAutoHide").setType(Attribute.BOOLEAN).setDescription(`hide border if it has zero tabs`); attributeDefinitions.addInherited("enableTabScrollbar", "borderEnableTabScrollbar").setType(Attribute.BOOLEAN).setDescription(`whether to show a mini scrollbar for the tabs`); return attributeDefinitions; } } BorderNode.TYPE = "border"; /** @internal */ BorderNode.attributeDefinitions = BorderNode.createAttributeDefinitions(); //# sourceMappingURL=BorderNode.js.map