UNPKG

ng-split-areas

Version:

Splitting views in Angular horizontally / vertically with configurable size-restrictions

1,157 lines (1,154 loc) 79.1 kB
import { __decorate, __metadata } from 'tslib'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Directive, ElementRef, EventEmitter, HostBinding, HostListener, Input, NgModule, NgZone, Output, Renderer2, ViewChild } from '@angular/core'; import { CommonModule } from '@angular/common'; import { Subject } from 'rxjs'; import { debounceTime } from 'rxjs/operators'; /** * Calculation logic for area sizes */ var AreaSizeCalculation = /** @class */ (function () { function AreaSizeCalculation() { } /** * Modifies sizes of areas in the list by totalSize * * @param areas list of areas to be modified * @param sourceAreaIndex index of area that triggered modification (will not be modified [a second time]) * @param totalSize size to be added / subtracted to / from areas within the list * @param containerSizePixel size of the container in pixel * @param gutterSizePxPerVisibleComponent size of the gutter in pixel per visible component * @param direction direction of modification starting from sourceAreaIndex * @returns size left, that couldnt be added / subtracted to / from the areas within the list */ AreaSizeCalculation.modifyAreaSizes = function (areas, sourceAreaIndex, totalSize, containerSizePixel, gutterSizePxPerVisibleComponent, direction) { var result = totalSize; // if there is nothing to modify (-> totalSize is zero) if (result === 0) { // there's nothing to do return result; } // if the area-list is empty if (!areas || areas.length === 0) { // there's nothing to do return result; } // if there is only 1 area in the area list if (areas.length <= 1) { // there's nothing to do, because the list contains the source area only return result; } // modifying direction = to the right if (direction === 'right') { // sourceArea is rightmost area if (sourceAreaIndex + 1 === areas.length) { // there's nothing to do return result; } // iterate the area-list to the right (starting with the component next to sourceAreaIndex) for (var i = sourceAreaIndex + 1; i < areas.length; i++) { // area at current index var currentArea = areas[i]; // left space to be subtracted result = AreaSizeCalculation.modifyAreaSize(currentArea, result, containerSizePixel, gutterSizePxPerVisibleComponent); // if there is no space left to modify if (result === 0) { // stop iterating break; } } } else if (direction === 'left') { // modifying direction = to the left // sourceArea is leftmost area if (sourceAreaIndex === 0) { // there's nothing to do return result; } // iterate the area-list to the left (starting with the component next to sourceAreaIndex) for (var i = sourceAreaIndex - 1; i >= 0; i--) { // area at current index var currentArea = areas[i]; // left space to be subtracted result = AreaSizeCalculation.modifyAreaSize(currentArea, result, containerSizePixel, gutterSizePxPerVisibleComponent); // if there is no space left to modify if (result === 0) { // stop iterating break; } } } return result; }; /** * Modifies size of the area by given size * * @param area Area to be modified * @param sizeToBeModified Size to be added / subtracted to / from the area * @param containerSize Size of the container * @param gutterSizePxPerVisibleComponent gutter size in px per visible component * * @returns left size that couldn't be added / subtracted to / from * the area (through min / max restrictions) */ AreaSizeCalculation.modifyAreaSize = function (area, sizeToBeModified, containerSize, gutterSizePxPerVisibleComponent) { // size left to be modified var result = sizeToBeModified; // is current action a subtraction var isSubtract = sizeToBeModified < 0; // there's size to be taken away (subtraction if (isSubtract) { // adding size taken away from the area result += this.subtractSizeFromArea(area, Math.abs(sizeToBeModified), containerSize, gutterSizePxPerVisibleComponent); } else { // subtracting size taken away from the area result -= this.addSizeToArea(area, sizeToBeModified, containerSize, gutterSizePxPerVisibleComponent); } return result; }; /** * Subtracts size of the area by given size * * @param area Area to be subtracted it's size * @param sizeToBeSubtracted Size to be subtracted from the area * @param containerSize Size of the container * @param gutterSizePxPerVisibleComponent size of the gutter in px per visible component * @returns size that was subtracted */ AreaSizeCalculation.subtractSizeFromArea = function (area, sizeToBeSubtracted, containerSize, gutterSizePxPerVisibleComponent) { // size that was subtracted var result = 0; // if the areas size is already 0 if (area.size === 0) { // there's nothing to do return result; } // maximum size to be taken away from the area var maxSizeToBeTakenAway = area.size; // area has a minimum pixel restriction if (area.minSizePx) { // minimum size of area (in pcnt of container size) var minSizeInPcntOfCurrentContainer = Math.ceil(area.minSizePx + gutterSizePxPerVisibleComponent) / containerSize; // maximum size to be taken away from area = current-size - min-size maxSizeToBeTakenAway = area.size - minSizeInPcntOfCurrentContainer; } // if there is no size available to be taken away if (maxSizeToBeTakenAway <= 0) { // there's nothing to do return result; } // size to be actually taken away from the area var sizeToBeTakenAway = sizeToBeSubtracted; // if the size to be taken away is > than the max size that can be taken away if (sizeToBeTakenAway > maxSizeToBeTakenAway) { // size to be taken away = max sizeToBeTakenAway = maxSizeToBeTakenAway; } // subtract size from current area's size area.size -= sizeToBeTakenAway; // set the result to the size taken away; result = sizeToBeTakenAway; // return what was actually taken away from the area return result; }; /** * Adds size to the area by given size * * @param area Area to be added something to it's size * @param sizeToBeAdded Size to be added to the area * @param containerSize Size of the container * @param gutterSizePxPerVisibleComponent size of the gutter in px per visible component * @returns size that was subtracted */ AreaSizeCalculation.addSizeToArea = function (area, sizeToBeAdded, containerSize, gutterSizePxPerVisibleComponent) { // size that was added var result = 0; // if the areas size is 0 if (area.size === 0) { // there's nothing to do return result; } //maximum size to be added (default: Number.MAX_VALUE) var maxSizeToBeAdded = Number.MAX_VALUE; // area has a maximum pixel restriction if (area.maxSizePx) { // maximum size of area (in pcnt of container size) var maxSizePcnt = Math.ceil(area.maxSizePx + gutterSizePxPerVisibleComponent) / containerSize; // if area size is already greater or equal max-size if (area.size >= maxSizePcnt) { // we cannot add any space to this area maxSizeToBeAdded = 0; } else { // we can add the amount until the area reaches max size maxSizeToBeAdded = maxSizePcnt - area.size; } } // if there is no size available to be added if (maxSizeToBeAdded === 0) { // there's nothing to do return result; } // size to be actually added to the area var sizeToBeActuallyAdded = sizeToBeAdded; // if the size to be added is > than the max size that can be added if (sizeToBeActuallyAdded > maxSizeToBeAdded) { // size to be added = max sizeToBeAdded = maxSizeToBeAdded; } // add size to current area's size area.size += sizeToBeAdded; // set the result to the size added result = sizeToBeAdded; // return what was actually added to the area return result; }; /** * Calculates area sizes according to given IAreaSizeCalculationOptions */ AreaSizeCalculation.prototype.calculate = function (opts) { // if calculate was triggered by a drag-and-drop action if (opts.calculationSource && opts.calculationSource.isDragAndDrop) { // handle dragging this.handleDragAndDrop(opts); } else if (opts.calculationSource && opts.calculationSource.isWindowResize) { // handle window-resize this.handleWindowResize(opts); } else { // handle normal layout calculations this.handleNormalLayout(opts); } }; /** * Calculates area sizes when gutters are dragged * (according to given AreaDragAndDrop inside IAreaSizeCalculationOptions) */ AreaSizeCalculation.prototype.handleDragAndDrop = function (opts) { // area-drag-and-drop object inside calculationSource var areaDragAndDrop = opts.calculationSource; // put dragged areas from drag-and-drop into a 2 element list var draggedAreas = [areaDragAndDrop.areaA, areaDragAndDrop.areaB]; // calculate complete size in px of both dragged areas var draggedAreasSizePx = (areaDragAndDrop.areaA.size + areaDragAndDrop.areaB.size) * (opts.containerSizePx ? opts.containerSizePx : 0); // both areas are visible after drag (size > 0) and the gutter was moved from it's original position if (areaDragAndDrop.areaA.size > 0 && areaDragAndDrop.areaB.size > 0 && areaDragAndDrop.offsetPixel) { // both areas (left side and right side) have min size px configured if (areaDragAndDrop.areaA.minSizePx && areaDragAndDrop.areaB.minSizePx) { // sum of min-size of both areas var totalMinSizePx = areaDragAndDrop.areaA.minSizePx + areaDragAndDrop.areaB.minSizePx; // size in px that can be used by the components (=> without gutter size) var draggedAreasSizePxWithoutGutter = draggedAreasSizePx - (opts.gutterSizePx ? opts.gutterSizePx : 0); // both components won't fit into given size (because the sum of their min-sizes is > total available space) if (totalMinSizePx > draggedAreasSizePxWithoutGutter) { // gutter was moved left (-> offsetPixel = start - end = a positive number) if (areaDragAndDrop.offsetPixel > 0) { //left side wins areaDragAndDrop.areaA.size += areaDragAndDrop.areaB.size; //right side is reset to 0 areaDragAndDrop.areaB.size = 0; } else if (areaDragAndDrop.offsetPixel < 0) { // gutter was moved right (-> offsetPixel = start - end = a negative number) //right side wins areaDragAndDrop.areaB.size += areaDragAndDrop.areaA.size; //left side is reset to 0 areaDragAndDrop.areaA.size = 0; } } } } // check & fix min sizes of dragged areas this.checkAndFixSizePxRestrictions({ // use complete size in px of both dragged areas as containerSizePx containerSizePx: draggedAreasSizePx, // use dragged areas as list of displayed areas displayedAreas: draggedAreas, // copy gutter size of original options object, because it's the same for dragging areas gutterSizePx: opts.gutterSizePx }); }; /** * Calculates area sizes when the window:resize-event was triggered */ AreaSizeCalculation.prototype.handleWindowResize = function (opts) { this.checkAndFixSizePxRestrictions(opts); }; /** * Calculates area sizes for normal layouting (first display, area-list changes, ...) */ AreaSizeCalculation.prototype.handleNormalLayout = function (opts) { this.checkAndFixSizePxRestrictions(opts); }; AreaSizeCalculation.prototype.checkAndFixSizePxRestrictions = function (opts) { //check and fix min-sizes this.checkAndFixSizePxRestrictedAreas(opts, 'min'); //check and fix max-sizes this.checkAndFixSizePxRestrictedAreas(opts, 'max'); }; /** * Checks and fixes <split-area>-Components that have minSizePx / maxSizePx configured * * @throws E-00001 - area sizes could not be calculated fixing minSizePx / maxSizePx */ AreaSizeCalculation.prototype.checkAndFixSizePxRestrictedAreas = function (opts, restrictionProperty) { var _this = this; // if we have one or zero displayed area(s) if (opts.displayedAreas.length <= 1) { // there is nothing to check and fix return; } // size of the container in pixel (= available space in px) var containerSizePixel = opts.containerSizePx ? opts.containerSizePx : 0; // areas with a size > 0 var displayedAreasWithSizeGreaterZero = opts.displayedAreas.filter(function (a) { return a.size !== 0; }); // total size of all gutters in px var totalGutterSizePx = (opts.displayedAreas.length - 1) * (opts.gutterSizePx ? opts.gutterSizePx : 0); // size of the gutter in px per component var gutterSizePxPerVisibleComponent = displayedAreasWithSizeGreaterZero.length > 1 ? totalGutterSizePx / displayedAreasWithSizeGreaterZero.length : totalGutterSizePx; // iterate all displayed areas (with size > 0) displayedAreasWithSizeGreaterZero.forEach(function (area, index) { // new size of the current area (default: current size) var newAreaSize = area.size; //switch min-width / max-width calculation by parameter (restrictionProperty) switch (restrictionProperty) { case 'min': // if the (calculated) area size in pixels is smaller than its configured minSize if (area.size * containerSizePixel < Math.ceil(area.minSizePx + gutterSizePxPerVisibleComponent)) { // new size of the current area (-> min size in percent) = // it's configured min size in pixels / container size in pixels newAreaSize = Math.ceil(area.minSizePx + gutterSizePxPerVisibleComponent) / containerSizePixel; } break; case 'max': // if the (calculated) area size in pixels is greater than its configured maxSize if (area.size * containerSizePixel > Math.ceil(area.maxSizePx + gutterSizePxPerVisibleComponent)) { // new size of the current area (-> max size in percent) = // it's configured max size in pixels / container size in pixels newAreaSize = Math.ceil(area.maxSizePx + gutterSizePxPerVisibleComponent) / containerSizePixel; } break; } // if new size of the area differs from current size if (newAreaSize !== area.size) { // space that needs to be taken away / added from/to other areas var sizeDiffToBeModifiedOnOtherAreas = area.size - newAreaSize; // current area size = size respecting the minimum pixel size area.size = newAreaSize; if (sizeDiffToBeModifiedOnOtherAreas !== 0) { // remove/add space-diff from to/all available areas var diffAfterRemovingSpaceFromAreas = _this.addAvailableSpaceToAreas(displayedAreasWithSizeGreaterZero, index, sizeDiffToBeModifiedOnOtherAreas, containerSizePixel, gutterSizePxPerVisibleComponent); // if there is still space left after checking all areas if (diffAfterRemovingSpaceFromAreas !== 0) { // we add the diff to our current area to keep our layout consistent area.size += sizeDiffToBeModifiedOnOtherAreas; } } } }); }; /** * Modifies areas adding available space * * @param areas list of areas to be modified * @param sourceAreaIndex index of area that triggered modification (will not be modified [a second time]) * @param availableSpace size to be added / subtracted to / from areas within the list * @param containerSizePixel size of the container in pixel * @param gutterSizePxPerVisibleComponent size of the gutter in pixel per visible component * * @returns space left after adding/removing from/to all available areas */ AreaSizeCalculation.prototype.addAvailableSpaceToAreas = function (areas, sourceAreaIndex, availableSpace, containerSizePixel, gutterSizePxPerVisibleComponent) { // add/remove space from/to areas on the right side of source-area(-index) var result = AreaSizeCalculation.modifyAreaSizes(areas, sourceAreaIndex, availableSpace, containerSizePixel, gutterSizePxPerVisibleComponent, 'right'); // if there is still some space to be added/removed left after checking right side areas if (result !== 0) { // add/remove space from/to areas on the left side of source-area(-index) result = AreaSizeCalculation.modifyAreaSizes(areas, sourceAreaIndex, result, containerSizePixel, gutterSizePxPerVisibleComponent, 'left'); } return result; }; return AreaSizeCalculation; }()); /** * Handles and notifies size changes */ var Area = /** @class */ (function () { function Area(area) { this.sizeChanged = new EventEmitter(); if (!area) { return; } this._size = area.size; this.comp = area.comp; this.maxSizePx = area.maxSizePx; this.minSizePx = area.minSizePx; this.order = area.order; } Object.defineProperty(Area.prototype, "size", { get: function () { return this._size; }, set: function (value) { var previousValue = this._size; this._size = value; if (previousValue !== value) { this.sizeChanged.next(value); } }, enumerable: true, configurable: true }); return Area; }()); /** * angular-split * * Areas size are set in percentage of the split container. * Gutters size are set in pixels. * * So we set css 'flex-basis' property like this (where 0 <= area.size <= 1): * calc( { area.size * 100 }% - { area.size * nbGutter * gutterSize }px ); * * Examples with 3 visible areas and 2 gutters: * * | 10px 10px | * |---------------------[]---------------------[]------------------------------------| * | calc(20% - 4px) calc(20% - 4px) calc(60% - 12px) | * * * | 10px 10px | * |--------------------------[]--------------------------[]--------------------------| * | calc(33.33% - 6.667px) calc(33.33% - 6.667px) calc(33.33% - 6.667px) | * * * |10px 10px | * |[]----------------------------------------------------[]--------------------------| * |0 calc(66.66% - 13.333px) calc(33%% - 6.667px) | * * * 10px 10px | * |[][]------------------------------------------------------------------------------| * |0 0 calc(100% - 20px) | * */ var SplitComponent = /** @class */ (function () { function SplitComponent(ngZone, elRef, cdRef, renderer) { this.ngZone = ngZone; this.elRef = elRef; this.cdRef = cdRef; this.renderer = renderer; this._direction = 'horizontal'; //// this._useTransition = false; //// this._disabled = false; //// this._width = null; //// this._height = null; //// this._gutterSize = 11; //// this._gutterColor = ''; //// this._gutterImageH = ''; //// this._gutterImageV = ''; //// this._dir = 'ltr'; //// this.dragStart = new EventEmitter(false); this.dragProgress = new EventEmitter(false); this.dragEnd = new EventEmitter(false); this.gutterClick = new EventEmitter(false); /** * notifies size changes on an area */ this.currentSizeChange = new EventEmitter(); this.transitionEndInternal = new Subject(); this.transitionEnd = this.transitionEndInternal.asObservable().pipe(debounceTime(20)); this.defaultAreaSizeCalculation = new AreaSizeCalculation(); this.isViewInitialized = false; this.isDragging = false; this.draggingWithoutMove = false; this.currentGutterNum = 0; this.displayedAreas = []; this.hidedAreas = []; this.dragListeners = []; this.dragStartValues = { sizePixelContainer: 0, sizePixelA: 0, sizePixelB: 0, sizePercentA: 0, sizePercentB: 0, }; this.setMinSizeOnContainer = false; } Object.defineProperty(SplitComponent.prototype, "direction", { get: function () { return this._direction; }, set: function (v) { var _this = this; v = (v === 'vertical') ? 'vertical' : 'horizontal'; this._direction = v; this.displayedAreas.concat(this.hidedAreas).forEach(function (area) { area.comp.setStyleVisibleAndDir(area.comp.visible, _this.isDragging, _this.direction); }); this.build(false, false); }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "useTransition", { get: function () { return this._useTransition; }, set: function (v) { v = (typeof (v) === 'boolean') ? v : (v === 'false' ? false : true); this._useTransition = v; }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "disabled", { get: function () { return this._disabled; }, set: function (v) { v = (typeof (v) === 'boolean') ? v : (v === 'false' ? false : true); this._disabled = v; // Force repaint if modified from TS class (instead of the template) this.cdRef.markForCheck(); }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "width", { get: function () { return this._width; }, set: function (v) { v = Number(v); this._width = (!isNaN(v) && v > 0) ? v : null; this.build(false, false); }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "height", { get: function () { return this._height; }, set: function (v) { v = Number(v); this._height = (!isNaN(v) && v > 0) ? v : null; this.build(false, false); }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "gutterSize", { get: function () { return this._gutterSize; }, set: function (v) { v = Number(v); this._gutterSize = (!isNaN(v) && v > 0) ? v : 11; this.build(false, false); }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "gutterColor", { get: function () { return this._gutterColor; }, set: function (v) { this._gutterColor = (typeof v === 'string' && v !== '') ? v : ''; // Force repaint if modified from TS class (instead of the template) this.cdRef.markForCheck(); }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "gutterImageH", { get: function () { return this._gutterImageH; }, set: function (v) { this._gutterImageH = (typeof v === 'string' && v !== '') ? v : ''; // Force repaint if modified from TS class (instead of the template) this.cdRef.markForCheck(); }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "gutterImageV", { get: function () { return this._gutterImageV; }, set: function (v) { this._gutterImageV = (typeof v === 'string' && v !== '') ? v : ''; // Force repaint if modified from TS class (instead of the template) this.cdRef.markForCheck(); }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "dir", { get: function () { return this._dir; }, set: function (v) { v = (v === 'rtl') ? 'rtl' : 'ltr'; this._dir = v; }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "cssFlexdirection", { get: function () { return (this.direction === 'horizontal') ? 'row' : 'column'; }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "cssWidth", { get: function () { return this.width ? this.width + "px" : '100%'; }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "cssHeight", { get: function () { return this.height ? this.height + "px" : '100%'; }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "cssMinwidth", { get: function () { return (this.direction === 'horizontal') ? this.getNbGutters() * this.gutterSize + "px" : null; }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "cssMinheight", { get: function () { return (this.direction === 'vertical') ? this.getNbGutters() * this.gutterSize + "px" : null; }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "areaSizeCalculation", { get: function () { return this._areaSizeCalculation; }, set: function (v) { this._areaSizeCalculation = v; }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "areaSizeCalculationToBeUsed", { get: function () { return this.areaSizeCalculation ? this.areaSizeCalculation : this.defaultAreaSizeCalculation; }, enumerable: true, configurable: true }); SplitComponent.prototype.addArea = function (comp) { var _this = this; var newArea = new Area({ comp: comp, minSizePx: comp.minSizePx, maxSizePx: comp.maxSizePx, order: 0, size: 0 }); newArea.sizeChanged.subscribe(function (newSize) { return _this.fireSizeChanged(newArea, newSize * 100); }); if (comp.visible === true) { this.displayedAreas.push(newArea); } else { this.hidedAreas.push(newArea); } comp.setStyleVisibleAndDir(comp.visible, this.isDragging, this.direction); this.build(true, true); }; SplitComponent.prototype.removeArea = function (comp) { if (this.displayedAreas.some(function (a) { return a.comp === comp; })) { var area = this.displayedAreas.find(function (a) { return a.comp === comp; }); this.displayedAreas.splice(this.displayedAreas.indexOf(area), 1); this.build(true, true); } else if (this.hidedAreas.some(function (a) { return a.comp === comp; })) { var area = this.hidedAreas.find(function (a) { return a.comp === comp; }); this.hidedAreas.splice(this.hidedAreas.indexOf(area), 1); } }; SplitComponent.prototype.updateArea = function (comp, resetOrders, resetSizes) { // Only refresh if area is displayed (No need to check inside 'hidedAreas') var item = this.displayedAreas.find(function (a) { return a.comp === comp; }); if (item) { // use minSizePx of the component item.minSizePx = comp.minSizePx; // use maxSizePx of the component item.maxSizePx = comp.maxSizePx; this.build(resetOrders, resetSizes); } }; SplitComponent.prototype.showArea = function (comp) { var _a; var area = this.hidedAreas.find(function (a) { return a.comp === comp; }); if (area) { comp.setStyleVisibleAndDir(comp.visible, this.isDragging, this.direction); var areas = this.hidedAreas.splice(this.hidedAreas.indexOf(area), 1); (_a = this.displayedAreas).push.apply(_a, areas); this.build(true, true); } }; SplitComponent.prototype.hideArea = function (comp) { var _a; var area = this.displayedAreas.find(function (a) { return a.comp === comp; }); if (area) { comp.setStyleVisibleAndDir(comp.visible, this.isDragging, this.direction); var areas = this.displayedAreas.splice(this.displayedAreas.indexOf(area), 1); areas.forEach(function (currentArea) { currentArea.order = 0; currentArea.size = 0; }); (_a = this.hidedAreas).push.apply(_a, areas); this.build(true, true); } }; Object.defineProperty(SplitComponent.prototype, "containerMinWidth", { /** * Min-Width of the container */ get: function () { if (!this.setMinSizeOnContainer) return undefined; // if split direction is NOT vertical if (this.direction !== "horizontal") { // min-width is 0 (unset) return 0; } // return the sum of all area minSizes + gutter sizes return this.getMinSizeOfAllDisplayedComponentsPlusGutterSize(); }, enumerable: true, configurable: true }); Object.defineProperty(SplitComponent.prototype, "containerMinHeight", { /** * Min-Height of the container */ get: function () { if (!this.setMinSizeOnContainer) return undefined; // if split direction is NOT vertical if (this.direction !== "vertical") { // min-height is 0 (unset) return 0; } // return the sum of all area minSizes + gutter sizes return this.getMinSizeOfAllDisplayedComponentsPlusGutterSize(); }, enumerable: true, configurable: true }); SplitComponent.prototype.ngAfterViewInit = function () { this.isViewInitialized = true; }; /** * Sum of all area minSizes + gutter sizes */ SplitComponent.prototype.getMinSizeOfAllDisplayedComponentsPlusGutterSize = function () { if (!this.displayedAreas || this.displayedAreas.length === 0) { return 0; } return this.getMinSizeOfAllDisplayedComponents() + (this.gutterSize * (this.displayedAreas.length - 1)); }; /** * Sum of all area minSizes */ SplitComponent.prototype.getMinSizeOfAllDisplayedComponents = function () { if (!this.displayedAreas || this.displayedAreas.length === 0) { return 0; } var result = 0; this.displayedAreas.forEach(function (area) { if (area.minSizePx) { result += area.minSizePx; } }); return result; }; SplitComponent.prototype.getNbGutters = function () { return this.displayedAreas.length - 1; }; SplitComponent.prototype.build = function (resetOrders, resetSizes) { var _this = this; this.stopDragging(); // ¤ AREAS ORDER if (resetOrders === true) { // If user provided 'order' for each area, use it to sort them. if (this.displayedAreas.every(function (a) { return a.comp.order !== null; })) { this.displayedAreas.sort(function (a, b) { return a.comp.order - b.comp.order; }); } // Then set real order with multiples of 2, numbers between will be used by gutters. this.displayedAreas.forEach(function (area, i) { area.order = i * 2; area.comp.setStyleOrder(area.order); }); } // ¤ AREAS SIZE PERCENT if (resetSizes === true) { var totalUserSize = this.displayedAreas.reduce(function (total, s) { return s.comp.size ? total + s.comp.size : total; }, 0); // If user provided 'size' for each area and total == 1, use it. if (this.displayedAreas.every(function (a) { return a.comp.size !== null; }) && totalUserSize > .999 && totalUserSize < 1.001) { this.displayedAreas.forEach(function (area) { area.size = area.comp.size; }); } // Else set equal sizes for all areas. else { var size_1 = 1 / this.displayedAreas.length; this.displayedAreas.forEach(function (area) { area.size = size_1; }); } } // ¤ // If some real area sizes are less than gutterSize, // set them to zero and dispatch size to others. var percentToDispatch = 0; // Get container pixel size var containerSizePixel = this.containerSizePx; this.displayedAreas.forEach(function (area) { if (area.size * containerSizePixel < _this.gutterSize) { percentToDispatch += area.size; area.size = 0; } }); if (percentToDispatch > 0 && this.displayedAreas.length > 0) { var nbAreasNotZero = this.displayedAreas.filter(function (a) { return a.size !== 0; }).length; if (nbAreasNotZero > 0) { var percentToAdd_1 = percentToDispatch / nbAreasNotZero; this.displayedAreas.filter(function (a) { return a.size !== 0; }).forEach(function (area) { area.size += percentToAdd_1; }); } // All area sizes (container percentage) are less than guterSize, // It means containerSize < ngGutters * gutterSize else { this.displayedAreas[this.displayedAreas.length - 1].size = 1; } } // do the extra calculation this.areaSizeCalculationToBeUsed.calculate(this.createAreaSizeCalculationOptions()); this.refreshStyleSizes(); this.cdRef.markForCheck(); }; /** * Creates an AreaSizeCalculation-Object of currently set instance parameters */ SplitComponent.prototype.createAreaSizeCalculationOptions = function (calculationSource) { return { calculationSource: calculationSource, containerSizePx: this.containerSizePx, displayedAreas: this.displayedAreas, gutterSizePx: this.gutterSize }; }; Object.defineProperty(SplitComponent.prototype, "containerSizePx", { /** * Size of the container in pixels (corresponding to direction: height or width) */ get: function () { // Get container pixel size var result = this.getNbGutters() * this.gutterSize; if (this.direction === 'horizontal') { result = this.width ? this.width : this.elRef.nativeElement.offsetWidth; } else { result = this.height ? this.height : this.elRef.nativeElement.offsetHeight; } return result; }, enumerable: true, configurable: true }); SplitComponent.prototype.refreshStyleSizes = function () { var _this = this; var sumGutterSize = this.getNbGutters() * this.gutterSize; this.displayedAreas.forEach(function (area) { area.comp.setStyleFlexbasis("calc( " + area.size * 100 + "% - " + area.size * sumGutterSize + "px )", _this.isDragging); }); }; SplitComponent.prototype.startDragging = function (startEvent, gutterOrder, gutterNum) { var _this = this; startEvent.preventDefault(); // Place code here to allow '(gutterClick)' event even if '[disabled]="true"'. this.currentGutterNum = gutterNum; this.draggingWithoutMove = true; this.ngZone.runOutsideAngular(function () { _this.dragListeners.push(_this.renderer.listen('document', 'mouseup', function (e) { return _this.stopDragging(); })); _this.dragListeners.push(_this.renderer.listen('document', 'touchend', function (e) { return _this.stopDragging(); })); _this.dragListeners.push(_this.renderer.listen('document', 'touchcancel', function (e) { return _this.stopDragging(); })); }); if (this.disabled) { return; } var areaA = this.displayedAreas.find(function (a) { return a.order === gutterOrder - 1; }); var areaB = this.displayedAreas.find(function (a) { return a.order === gutterOrder + 1; }); if (!areaA || !areaB) { return; } var prop = (this.direction === 'horizontal') ? 'offsetWidth' : 'offsetHeight'; this.dragStartValues.sizePixelContainer = this.elRef.nativeElement[prop]; this.dragStartValues.sizePixelA = areaA.comp.getSizePixel(prop); this.dragStartValues.sizePixelB = areaB.comp.getSizePixel(prop); this.dragStartValues.sizePercentA = areaA.size; this.dragStartValues.sizePercentB = areaB.size; var start; if (startEvent instanceof MouseEvent) { start = { x: startEvent.screenX, y: startEvent.screenY, }; } else if (startEvent instanceof TouchEvent) { start = { x: startEvent.touches[0].screenX, y: startEvent.touches[0].screenY, }; } else { return; } this.ngZone.runOutsideAngular(function () { _this.dragListeners.push(_this.renderer.listen('document', 'mousemove', function (e) { return _this.dragEvent(e, start, areaA, areaB); })); _this.dragListeners.push(_this.renderer.listen('document', 'touchmove', function (e) { return _this.dragEvent(e, start, areaA, areaB); })); }); areaA.comp.lockEvents(); areaB.comp.lockEvents(); this.isDragging = true; this.notify('start'); }; SplitComponent.prototype.dragEvent = function (event, start, areaA, areaB) { if (!this.isDragging) { return; } var end; if (event instanceof MouseEvent) { end = { x: event.screenX, y: event.screenY, }; } else if (event instanceof TouchEvent) { end = { x: event.touches[0].screenX, y: event.touches[0].screenY, }; } else { return; } this.draggingWithoutMove = false; this.drag(start, end, areaA, areaB); }; SplitComponent.prototype.drag = function (start, end, areaA, areaB) { // ¤ AREAS SIZE PIXEL var offsetPixel = (this.direction === 'horizontal') ? (start.x - end.x) : (start.y - end.y); /* const devicePixelRatio = window.devicePixelRatio || 1; //doesn't work offsetPixel = offsetPixel / devicePixelRatio; //doesn't work */ if (this.dir === 'rtl') { offsetPixel = -offsetPixel; } var newSizePixelA = this.dragStartValues.sizePixelA - offsetPixel; var newSizePixelB = this.dragStartValues.sizePixelB + offsetPixel; if (newSizePixelA < this.gutterSize && newSizePixelB < this.gutterSize) { // WTF.. get out of here! return; } else if (newSizePixelA < this.gutterSize) { newSizePixelB += newSizePixelA; newSizePixelA = 0; } else if (newSizePixelB < this.gutterSize) { newSizePixelA += newSizePixelB; newSizePixelB = 0; } // ¤ AREAS SIZE PERCENT if (newSizePixelA === 0) { areaB.size += areaA.size; areaA.size = 0; } else if (newSizePixelB === 0) { areaA.size += areaB.size; areaB.size = 0; } else { // NEW_PERCENT = START_PERCENT / START_PIXEL * NEW_PIXEL; if (this.dragStartValues.sizePercentA === 0) { areaB.size = this.dragStartValues.sizePercentB / this.dragStartValues.sizePixelB * newSizePixelB; areaA.size = this.dragStartValues.sizePercentB - areaB.size; } else if (this.dragStartValues.sizePercentB === 0) { areaA.size = this.dragStartValues.sizePercentA / this.dragStartValues.sizePixelA * newSizePixelA; areaB.size = this.dragStartValues.sizePercentA - areaA.size; } else { areaA.size = this.dragStartValues.sizePercentA / this.dragStartValues.sizePixelA * newSizePixelA; areaB.size = (this.dragStartValues.sizePercentA + this.dragStartValues.sizePercentB) - areaA.size; } } this.areaSizeCalculationToBeUsed.calculate(this.createAreaSizeCalculationOptions({ areaA: areaA, areaB: areaB, isDragAndDrop: true, offsetPixel: offsetPixel })); this.refreshStyleSizes(); this.notify('progress'); }; SplitComponent.prototype.stopDragging = function () { if (this.isDragging === false && this.draggingWithoutMove === false) { return; } this.displayedAreas.forEach(function (area) { area.comp.unlockEvents(); }); while (this.dragListeners.length > 0) { var fct = this.dragListeners.pop(); if (fct) { fct(); } } if (this.draggingWithoutMove === true) { this.notify('click'); } else { this.notify('end'); } this.isDragging = false; this.draggingWithoutMove = false; //trigger resize-event - components can handle it and react to new sizes accordingly this.triggerWindowResize(); }; SplitComponent.prototype.notify = function (type) { var areasSize = this.displayedAreas.map(function (a) { return a.size * 100; }); switch (type) { case 'start': return this.dragStart.emit({ gutterNum: this.currentGutterNum, sizes: areasSize }); case 'progress': return this.dragProgress.emit({ gutterNum: this.currentGutterNum, sizes: areasSize }); case 'end': return this.dragEnd.emit({ gutterNum: this.currentGutterNum, sizes: areasSize }); case 'click': return this.gutterClick.emit({ gutterNum: this.currentGutterNum, sizes: areasSize }); case 'transitionEnd': return this.transitionEndInternal.next(areasSize); } }; /** * Moves the gutter to it's max position between two areas * * @param gutterOrderIndex Index of the gutter to be moved */ SplitComponent.prototype.moveGutterMax = function (gutterOrderIndex) { this.moveGutterToPosition(gutterOrderIndex, Number.MAX_VALUE); }; /** * Moves the gutter to it's min position between two areas * * @param gutterOrderIndex Index of the gutter to be moved */ SplitComponent.prototype.moveGutterMin = function (gutterOrderIndex) { this.moveGutterToPosition(gutterOrderIndex, 0); }; /** * Moves the gutter to given position in Pixels * * @param gutterOrderIndex Index of the gutter to be moved * @param positionInPx new gutter position in px * * @version 0.2.8 triggers Window-Resize */ SplitComponent.prototype.moveGutterToPosition = function (gutterOrderIndex, positionInPx) { // area on left side of the gutter var areaA = this.displayedAreas.find(function (a) { return a.order === gutterOrderIndex - 1; }); // area on right side of the gutter var areaB = this.displayedAreas.find(function (a) { return a.order === gutterOrderIndex + 1; }); // if one of both areas couldn't be found if (!areaA || !areaB) { // the gutter in between can't be moved return; } var sizePixelA = areaA.comp.getSizePixel((this.direction === 'horizontal') ? 'offsetWidth' : 'offsetHeight'); var sizePixelB = areaB.comp.getSizePixel((this.direction === 'horizontal') ? 'offsetWidth' : 'offsetHeight'); var totalSizePx = sizePixelA + sizePixelB; var totalSizePcnt = areaA.size + areaB.size; var newSizePixelA = sizePixelA; var newSizePixelB = sizePixelB; // sizing left side component and right side component takes available space (=== true) var isLeftSideSizing = positionInPx >= 0; //sizing left side component, if positionInPx is > 0 if (isLeftSideSizing) { // left side componen will be positionInPx or totalSizePx (if it is smaller than positionInPx) newSizePixelA = positionInPx < totalSizePx ? positionInPx : totalSizePx; // right side component will take space still available newSizePixelB = totalSizePx - newSizePixelA; } //sizing right side component, if positionInPx is < 0 else { // absolute size of required right side component width var absolutePositionInPx = Math.abs(positionInPx); // right side componen will be absolutePositionInPx or totalSizePx (if it is smaller than absolutePositionInPx) newSizePixelB = absolutePositionInPx < totalSizePx ? absolutePositionInPx : totalSizePx; // left side component will take space still available newSizePixelA = totalSizePx - newSizePixelB; } if (newSizePixelA < this.gutterSize && newSizePixelB < this.gutterSize) { // WTF.. get out of here! return; } else if (newSizePixelA < this.gutterSize) { newSizePixelB += newSizePixelA; newSizePixelA = 0; } else if (newSizePixelB < this.gutterSize) { newSizePixelA += newSizePixelB; newSizePixelB = 0; } areaA.size = newSizePixelA / totalSizePx * totalSizePcnt; areaB.size = newSizePixelB / totalSizePx * totalSizePcnt; var draggedAreas = []; // component sizes will be checked / corrected in given order // if gutter movement is negative (= sizing area B) if (!isLeftSideSizing) { // areaB size should be checked / fixed first and diff space will be taken from areaA draggedAreas = [areaB, areaA]; } else { // areaA size should be checked / fixed first and diff space will be taken from areaB draggedAreas = [areaA, areaB]; } //drag-offset in pixel = size of areaA in px before resizing - size o