UNPKG

flexlayout-react

Version:

A multi-tab docking layout manager

281 lines (236 loc) 7.95 kB
import { AttributeDefinitions } from "../AttributeDefinitions"; import { DockLocation } from "../DockLocation"; import { DropInfo } from "../DropInfo"; import { Orientation } from "../Orientation"; import { Rect } from "../Rect"; import { IDraggable } from "./IDraggable"; import { IJsonBorderNode, IJsonRowNode, IJsonTabNode, IJsonTabSetNode } from "./IJsonModel"; import { Model } from "./Model"; export abstract class Node { /** @internal */ protected model: Model; /** @internal */ protected attributes: Record<string, any>; /** @internal */ protected parent?: Node; /** @internal */ protected children: Node[]; /** @internal */ protected rect: Rect; /** @internal */ protected path: string; /** @internal */ protected listeners: Map<string, (params: any) => void>; /** @internal */ protected constructor(_model: Model) { this.model = _model; this.attributes = {}; this.children = []; this.rect = Rect.empty(); this.listeners = new Map(); this.path = ""; } getId() { let id = this.attributes.id; if (id !== undefined) { return id as string; } id = this.model.nextUniqueId(); this.setId(id); return id as string; } getModel() { return this.model; } getType() { return this.attributes.type as string; } getParent() { return this.parent; } getChildren() { return this.children; } getRect() { return this.rect; } getPath() { return this.path; } getOrientation(): Orientation { if (this.parent === undefined) { 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: string, callback: (params: any) => void) { this.listeners.set(event, callback); } removeEventListener(event: string) { this.listeners.delete(event); } abstract toJson(): IJsonRowNode | IJsonBorderNode | IJsonTabSetNode | IJsonTabNode | undefined; /** @internal */ setId(id: string) { this.attributes.id = id; } /** @internal */ fireEvent(event: string, params: any) { // console.log(this._type, " fireEvent " + event + " " + JSON.stringify(params)); if (this.listeners.has(event)) { this.listeners.get(event)!(params); } } /** @internal */ getAttr(name: string) { let val = this.attributes[name]; if (val === undefined) { const modelName = this.getAttributeDefinitions().getModelName(name); if (modelName !== undefined) { val = this.model.getAttribute(modelName); } } // console.log(name + "=" + val); return val; } /** @internal */ forEachNode(fn: (node: Node, level: number) => void, level: number) { fn(this, level); level++; for (const node of this.children) { node.forEachNode(fn, level); } } /** @internal */ setPaths(path: string) { let i = 0; for (const node of this.children) { let newPath = path; if (node.getType() === "row") { if (node.getOrientation() === Orientation.VERT) { newPath += "/c" + i; } else { 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: Node) { this.parent = parent; } /** @internal */ setRect(rect: Rect) { this.rect = rect; } /** @internal */ setPath(path: string) { this.path = path; } /** @internal */ setWeight(weight: number) { this.attributes.weight = weight; } /** @internal */ setSelected(index: number) { this.attributes.selected = index; } /** @internal */ findDropTargetNode(windowId: string, dragNode: Node & IDraggable, x: number, y: number): DropInfo | undefined { let rtn: DropInfo | undefined; if (this.rect.contains(x, y)) { if (this.model.getMaximizedTabset(windowId) !== undefined) { rtn = this.model.getMaximizedTabset(windowId)!.canDrop(dragNode, x, y); } else { rtn = this.canDrop(dragNode, x, y); if (rtn === undefined) { if (this.children.length !== 0) { for (const child of this.children) { rtn = child.findDropTargetNode(windowId, dragNode, x, y); if (rtn !== undefined) { break; } } } } } } return rtn; } /** @internal */ canDrop(dragNode: Node & IDraggable, x: number, y: number): DropInfo | undefined { return undefined; } /** @internal */ canDockInto(dragNode: Node & IDraggable, dropInfo: DropInfo | undefined): boolean { if (dropInfo != null) { if (dropInfo.location === DockLocation.CENTER && dropInfo.node.isEnableDrop() === false) { return false; } // prevent named tabset docking into another tabset, since this would lose the header if (dropInfo.location === DockLocation.CENTER && dragNode.getType() === "tabset" && dragNode.getName() !== undefined) { return false; } if (dropInfo.location !== DockLocation.CENTER && dropInfo.node.isEnableDivide() === false) { return false; } // finally check model callback to check if drop allowed if (this.model.getOnAllowDrop()) { return (this.model.getOnAllowDrop() as (dragNode: Node, dropInfo: DropInfo) => boolean)(dragNode, dropInfo); } } return true; } /** @internal */ removeChild(childNode: Node) { const pos = this.children.indexOf(childNode); if (pos !== -1) { this.children.splice(pos, 1); } return pos; } /** @internal */ addChild(childNode: Node, pos?: number) { 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(style?: Record<string, any>) { if (style == null) { style = {}; } return this.rect.styleWithPosition(style); } /** @internal */ isEnableDivide() { return true; } /** @internal */ toAttributeString() { return JSON.stringify(this.attributes, undefined, "\t"); } // implemented by subclasses /** @internal */ abstract updateAttrs(json: any): void; /** @internal */ abstract getAttributeDefinitions(): AttributeDefinitions; }