UNPKG

dockview

Version:

Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support

239 lines (238 loc) 9.65 kB
import { getRelativeLocation, getGridLocation, } from './gridview'; import { Position } from '../dnd/droptarget'; import { tail, sequenceEquals } from '../array'; import { CompositeDisposable } from '../lifecycle'; import { BaseGrid, GroupChangeKind, toTarget, } from './baseComponentGridview'; import { GridviewApi } from '../api/component.api'; import { createComponent } from '../panel/componentFactory'; export class GridviewComponent extends BaseGrid { constructor(element, options) { super(element, { proportionalLayout: options.proportionalLayout, orientation: options.orientation, styles: options.styles, }); this._options = options; if (!this.options.components) { this.options.components = {}; } if (!this.options.frameworkComponents) { this.options.frameworkComponents = {}; } } get orientation() { return this.gridview.orientation; } set orientation(value) { this.gridview.orientation = value; } get options() { return this._options; } get deserializer() { return this._deserializer; } set deserializer(value) { this._deserializer = value; } updateOptions(options) { const hasOrientationChanged = typeof options.orientation === 'string' && this.options.orientation !== options.orientation; this._options = Object.assign(Object.assign({}, this.options), options); if (hasOrientationChanged) { this.gridview.orientation = options.orientation; } this.layout(this.gridview.width, this.gridview.height, true); } removePanel(panel) { this.removeGroup(panel); } /** * Serialize the current state of the layout * * @returns A JSON respresentation of the layout */ toJSON() { var _a; const data = this.gridview.serialize(); return { grid: data, activePanel: (_a = this.activeGroup) === null || _a === void 0 ? void 0 : _a.id, }; } setVisible(panel, visible) { this.gridview.setViewVisible(getGridLocation(panel.element), visible); } setActive(panel) { this._groups.forEach((value, key) => { value.value.setActive(panel === value.value); }); } toggleVisibility(panel) { this.setVisible(panel, !this.isVisible(panel)); } focus() { var _a; (_a = this.activeGroup) === null || _a === void 0 ? void 0 : _a.focus(); } fromJSON(serializedGridview, deferComponentLayout) { const { grid, activePanel } = serializedGridview; this.gridview.clear(); this._groups.clear(); const queue = []; this.gridview.deserialize(grid, { fromJSON: (node) => { const { data } = node; const view = createComponent(data.id, data.component, this.options.components || {}, this.options.frameworkComponents || {}, this.options.frameworkComponentFactory ? { createComponent: this.options.frameworkComponentFactory .createComponent, } : undefined); queue.push(() => view.init({ params: data.params, minimumWidth: data.minimumWidth, maximumWidth: data.maximumWidth, minimumHeight: data.minimumHeight, maximumHeight: data.maximumHeight, priority: data.priority, snap: !!data.snap, containerApi: new GridviewApi(this), isVisible: node.visible, })); this.registerPanel(view); return view; }, }); this.layout(this.width, this.height, true); if (deferComponentLayout) { setTimeout(() => { queue.forEach((f) => f()); }, 0); } else { queue.forEach((f) => f()); } if (typeof activePanel === 'string') { const panel = this.getPanel(activePanel); if (panel) { this.doSetGroupActive(panel); } } this._onGridEvent.fire({ kind: GroupChangeKind.LAYOUT_FROM_JSON }); } movePanel(panel, options) { var _a; let relativeLocation; const removedPanel = this.gridview.remove(panel); const referenceGroup = (_a = this._groups.get(options.reference)) === null || _a === void 0 ? void 0 : _a.value; if (!referenceGroup) { throw new Error(`reference group ${options.reference} does not exist`); } const target = toTarget(options.direction); if (target === Position.Center) { throw new Error(`${target} not supported as an option`); } else { const location = getGridLocation(referenceGroup.element); relativeLocation = getRelativeLocation(this.gridview.orientation, location, target); } this.doAddGroup(removedPanel, relativeLocation, options.size); } addPanel(options) { var _a, _b; let relativeLocation = options.location || [0]; if ((_a = options.position) === null || _a === void 0 ? void 0 : _a.reference) { const referenceGroup = (_b = this._groups.get(options.position.reference)) === null || _b === void 0 ? void 0 : _b.value; if (!referenceGroup) { throw new Error(`reference group ${options.position.reference} does not exist`); } const target = toTarget(options.position.direction); if (target === Position.Center) { throw new Error(`${target} not supported as an option`); } else { const location = getGridLocation(referenceGroup.element); relativeLocation = getRelativeLocation(this.gridview.orientation, location, target); } } const view = createComponent(options.id, options.component, this.options.components || {}, this.options.frameworkComponents || {}, this.options.frameworkComponentFactory ? { createComponent: this.options.frameworkComponentFactory .createComponent, } : undefined); view.init({ params: options.params || {}, minimumWidth: options.minimumWidth, maximumWidth: options.maximumWidth, minimumHeight: options.minimumHeight, maximumHeight: options.maximumHeight, priority: options.priority, snap: !!options.snap, containerApi: new GridviewApi(this), isVisible: true, }); this.registerPanel(view); this.doAddGroup(view, relativeLocation, options.size); return { api: view.api }; } registerPanel(panel) { const disposable = new CompositeDisposable(panel.api.onDidFocusChange((event) => { if (!event.isFocused) { return; } this._groups.forEach((groupItem) => { const group = groupItem.value; if (group !== panel) { group.setActive(false); } else { group.setActive(true); } }); })); this._groups.set(panel.id, { value: panel, disposable, }); } moveGroup(referenceGroup, groupId, target) { const sourceGroup = this.getPanel(groupId); if (!sourceGroup) { throw new Error('invalid operation'); } const referenceLocation = getGridLocation(referenceGroup.element); const targetLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, target); const [targetParentLocation, to] = tail(targetLocation); const sourceLocation = getGridLocation(sourceGroup.element); const [sourceParentLocation, from] = tail(sourceLocation); if (sequenceEquals(sourceParentLocation, targetParentLocation)) { // special case when 'swapping' two views within same grid location // if a group has one tab - we are essentially moving the 'group' // which is equivalent to swapping two views in this case this.gridview.moveView(sourceParentLocation, from, to); return; } // source group will become empty so delete the group const targetGroup = this.doRemoveGroup(sourceGroup, { skipActive: true, skipDispose: true, }); // after deleting the group we need to re-evaulate the ref location const updatedReferenceLocation = getGridLocation(referenceGroup.element); const location = getRelativeLocation(this.gridview.orientation, updatedReferenceLocation, target); this.doAddGroup(targetGroup, location); } removeGroup(group) { super.removeGroup(group); const panel = this._groups.get(group.id); if (panel) { panel.disposable.dispose(); this._groups.delete(group.id); } } dispose() { super.dispose(); } }