UNPKG

golden-layout

Version:
408 lines 14.6 kB
import { ComponentItemConfig, ItemConfig } from '../config/config'; import { AssertError, UnexpectedNullError } from '../errors/internal-error'; import { EventEmitter } from '../utils/event-emitter'; import { LogicalZIndex, LogicalZIndexToDefaultMap } from '../utils/types'; import { deepExtend, setElementHeight, setElementWidth } from '../utils/utils'; /** @public */ export class ComponentContainer extends EventEmitter { /** @internal */ constructor( /** @internal */ _config, /** @internal */ _parent, /** @internal */ _layoutManager, /** @internal */ _element, /** @internal */ _updateItemConfigEvent, /** @internal */ _showEvent, /** @internal */ _hideEvent, /** @internal */ _focusEvent, /** @internal */ _blurEvent) { super(); this._config = _config; this._parent = _parent; this._layoutManager = _layoutManager; this._element = _element; this._updateItemConfigEvent = _updateItemConfigEvent; this._showEvent = _showEvent; this._hideEvent = _hideEvent; this._focusEvent = _focusEvent; this._blurEvent = _blurEvent; /** @internal */ this._stackMaximised = false; this._width = 0; this._height = 0; this._visible = true; this._isShownWithZeroDimensions = true; this._componentType = _config.componentType; this._isClosable = _config.isClosable; this._initialState = _config.componentState; this._state = this._initialState; this._boundComponent = this.layoutManager.bindComponent(this, _config); this.updateElementPositionPropertyFromBoundComponent(); } get width() { return this._width; } get height() { return this._height; } get parent() { return this._parent; } /** @internal @deprecated use {@link (ComponentContainer:class).componentType} */ get componentName() { return this._componentType; } get componentType() { return this._componentType; } get virtual() { return this._boundComponent.virtual; } get component() { return this._boundComponent.component; } get tab() { return this._tab; } get title() { return this._parent.title; } get layoutManager() { return this._layoutManager; } get isHidden() { return !this._visible; } get visible() { return this._visible; } get state() { return this._state; } /** Return the initial component state */ get initialState() { return this._initialState; } /** The inner DOM element where the container's content is intended to live in */ get element() { return this._element; } /** @internal */ destroy() { this.releaseComponent(); this.stateRequestEvent = undefined; this.emit('destroy'); } /** @deprecated use {@link (ComponentContainer:class).element } */ getElement() { return this._element; } /** * Hides the container's component item (and hence, the container) if not already hidden. * Emits hide event prior to hiding the container. */ hide() { this._hideEvent(); } /** * Shows the container's component item (and hence, the container) if not visible. * Emits show event prior to hiding the container. */ show() { this._showEvent(); } /** * Focus this component in Layout. */ focus(suppressEvent = false) { this._focusEvent(suppressEvent); } /** * Remove focus from this component in Layout. */ blur(suppressEvent = false) { this._blurEvent(suppressEvent); } /** * Set the size from within the container. Traverses up * the item tree until it finds a row or column element * and resizes its items accordingly. * * If this container isn't a descendant of a row or column * it returns false * @param width - The new width in pixel * @param height - The new height in pixel * * @returns resizeSuccesful * * @internal */ setSize(width, height) { let ancestorItem = this._parent; if (ancestorItem.isColumn || ancestorItem.isRow || ancestorItem.parent === null) { throw new AssertError('ICSSPRC', 'ComponentContainer cannot have RowColumn Parent'); } else { let ancestorChildItem; do { ancestorChildItem = ancestorItem; ancestorItem = ancestorItem.parent; } while (ancestorItem !== null && !ancestorItem.isColumn && !ancestorItem.isRow); if (ancestorItem === null) { // no Row or Column found return false; } else { // ancestorItem is Row or Column const direction = ancestorItem.isColumn ? 'height' : 'width'; const currentSize = this[direction]; if (currentSize === null) { throw new UnexpectedNullError('ICSSCS11194'); } else { const newSize = direction === 'height' ? height : width; const totalPixel = currentSize * (1 / (ancestorChildItem.size / 100)); const percentage = (newSize / totalPixel) * 100; const delta = (ancestorChildItem.size - percentage) / (ancestorItem.contentItems.length - 1); for (let i = 0; i < ancestorItem.contentItems.length; i++) { const ancestorItemContentItem = ancestorItem.contentItems[i]; if (ancestorItemContentItem === ancestorChildItem) { ancestorItemContentItem.size = percentage; } else { ancestorItemContentItem.size += delta; } } ancestorItem.updateSize(false); return true; } } } } /** * Closes the container if it is closable. Can be called by * both the component within at as well as the contentItem containing * it. Emits a close event before the container itself is closed. */ close() { if (this._isClosable) { this.emit('close'); this._parent.close(); } } /** Replaces component without affecting layout */ replaceComponent(itemConfig) { this.releaseComponent(); if (!ItemConfig.isComponent(itemConfig)) { throw new Error('ReplaceComponent not passed a component ItemConfig'); } else { const config = ComponentItemConfig.resolve(itemConfig, false); this._initialState = config.componentState; this._state = this._initialState; this._componentType = config.componentType; this._updateItemConfigEvent(config); this._boundComponent = this.layoutManager.bindComponent(this, config); this.updateElementPositionPropertyFromBoundComponent(); if (this._boundComponent.virtual) { if (this.virtualVisibilityChangeRequiredEvent !== undefined) { this.virtualVisibilityChangeRequiredEvent(this, this._visible); } if (this.virtualRectingRequiredEvent !== undefined) { this._layoutManager.fireBeforeVirtualRectingEvent(1); try { this.virtualRectingRequiredEvent(this, this._width, this._height); } finally { this._layoutManager.fireAfterVirtualRectingEvent(); } } this.setBaseLogicalZIndex(); } this.emit('stateChanged'); } } /** * Returns the initial component state or the latest passed in setState() * @returns state * @deprecated Use {@link (ComponentContainer:class).initialState} */ getState() { return this._state; } /** * Merges the provided state into the current one * @deprecated Use {@link (ComponentContainer:class).stateRequestEvent} */ extendState(state) { const extendedState = deepExtend(this._state, state); this.setState(extendedState); } /** * Sets the component state * @deprecated Use {@link (ComponentContainer:class).stateRequestEvent} */ setState(state) { this._state = state; this._parent.emitBaseBubblingEvent('stateChanged'); } /** * Set's the components title */ setTitle(title) { this._parent.setTitle(title); } /** @internal */ setTab(tab) { this._tab = tab; this.emit('tab', tab); } /** @internal */ setVisibility(value) { if (this._boundComponent.virtual) { if (this.virtualVisibilityChangeRequiredEvent !== undefined) { this.virtualVisibilityChangeRequiredEvent(this, value); } } if (value) { if (!this._visible) { this._visible = true; if (this._height === 0 && this._width === 0) { this._isShownWithZeroDimensions = true; } else { this._isShownWithZeroDimensions = false; this.setSizeToNodeSize(this._width, this._height, true); this.emitShow(); } } else { if (this._isShownWithZeroDimensions && (this._height !== 0 || this._width !== 0)) { this._isShownWithZeroDimensions = false; this.setSizeToNodeSize(this._width, this._height, true); this.emitShow(); } } } else { if (this._visible) { this._visible = false; this._isShownWithZeroDimensions = false; this.emitHide(); } } } setBaseLogicalZIndex() { this.setLogicalZIndex(LogicalZIndex.base); } setLogicalZIndex(logicalZIndex) { if (logicalZIndex !== this._logicalZIndex) { this._logicalZIndex = logicalZIndex; this.notifyVirtualZIndexChangeRequired(); } } /** * Set the container's size, but considered temporary (for dragging) * so don't emit any events. * @internal */ enterDragMode(width, height) { this._width = width; this._height = height; setElementWidth(this._element, width); setElementHeight(this._element, height); this.setLogicalZIndex(LogicalZIndex.drag); this.drag(); } /** @internal */ exitDragMode() { this.setBaseLogicalZIndex(); } /** @internal */ enterStackMaximised() { this._stackMaximised = true; this.setLogicalZIndex(LogicalZIndex.stackMaximised); } /** @internal */ exitStackMaximised() { this.setBaseLogicalZIndex(); this._stackMaximised = false; } /** @internal */ drag() { if (this._boundComponent.virtual) { if (this.virtualRectingRequiredEvent !== undefined) { this._layoutManager.fireBeforeVirtualRectingEvent(1); try { this.virtualRectingRequiredEvent(this, this._width, this._height); } finally { this._layoutManager.fireAfterVirtualRectingEvent(); } } } } /** * Sets the container's size. Called by the container's component item. * To instead set the size programmatically from within the component itself, * use the public setSize method * @param width - in px * @param height - in px * @param force - set even if no change * @internal */ setSizeToNodeSize(width, height, force) { if (width !== this._width || height !== this._height || force) { this._width = width; this._height = height; setElementWidth(this._element, width); setElementHeight(this._element, height); if (this._boundComponent.virtual) { this.addVirtualSizedContainerToLayoutManager(); } else { this.emit('resize'); this.checkShownFromZeroDimensions(); } } } /** @internal */ notifyVirtualRectingRequired() { if (this.virtualRectingRequiredEvent !== undefined) { this.virtualRectingRequiredEvent(this, this._width, this._height); this.emit('resize'); this.checkShownFromZeroDimensions(); } } /** @internal */ notifyVirtualZIndexChangeRequired() { if (this.virtualZIndexChangeRequiredEvent !== undefined) { const logicalZIndex = this._logicalZIndex; const defaultZIndex = LogicalZIndexToDefaultMap[logicalZIndex]; this.virtualZIndexChangeRequiredEvent(this, logicalZIndex, defaultZIndex); } } /** @internal */ updateElementPositionPropertyFromBoundComponent() { if (this._boundComponent.virtual) { this._element.style.position = 'static'; } else { this._element.style.position = ''; // set it back to attribute value } } /** @internal */ addVirtualSizedContainerToLayoutManager() { this._layoutManager.beginVirtualSizedContainerAdding(); try { this._layoutManager.addVirtualSizedContainer(this); } finally { this._layoutManager.endVirtualSizedContainerAdding(); } } /** @internal */ checkShownFromZeroDimensions() { if (this._isShownWithZeroDimensions && (this._height !== 0 || this._width !== 0)) { this._isShownWithZeroDimensions = false; this.emitShow(); } } /** @internal */ emitShow() { this.emit('shown'); this.emit('show'); } /** @internal */ emitHide() { this.emit('hide'); } /** @internal */ releaseComponent() { if (this._stackMaximised) { this.exitStackMaximised(); } this.emit('beforeComponentRelease', this._boundComponent.component); this.layoutManager.unbindComponent(this, this._boundComponent.virtual, this._boundComponent.component); } } //# sourceMappingURL=component-container.js.map