UNPKG

ares-ide

Version:

A browser-based code editor and UI designer for Enyo 2 projects

439 lines (371 loc) 11.7 kB
/** * Flex Layout * Supports Webkit, Mozilla, IE8+ * @author Lex Podgorny <lex.podgorny@lge.com> */ enyo.kind({ name : 'enyo.FlexLayout', kind : 'Layout', layoutClass : 'enyo-flex-layout', flexSpacing : 0, flexBias : null, flexStretch : null, defaultSpacing : 0, defaultFlex : 10, defaultBias : 'row', defaultStretch : true, /******************** PRIVATE *********************/ _nReflow : 0, // Reflow counter _nResponseCondition : 0, // Predicate function. Returns true if oControl has FlexLayout _hasFlexLayout: function(oControl) { return ( oControl.layout && oControl.layout instanceof enyo.FlexLayout ); }, // Returns flex value assigned to oControl _getFlex: function(oControl) { var nFit = this._getFit(oControl); if (nFit) { return nFit; } if (typeof oControl.flex == 'undefined' || oControl.flex === false) { return 0; } if (oControl.flex === true) { return this.defaultFlex; } return oControl.flex; }, // Returns fit value assigned to oControl _getFit: function(oControl) { if (typeof oControl.fit == 'undefined' || oControl.fit === false) { return 0; } if (oControl.fit === true) { return this.defaultFlex; } return oControl.fit; }, // Returns spacing value assigned to container of this layout _getSpacing: function() { if (typeof this.container.flexSpacing == 'undefined' || this.container.flexSpacing === false) { return this.defaultSpacing; } return parseInt(this.container.flexSpacing, 10); }, _getStretch: function() { if (typeof this.container.noStretch != 'undefined') { return !this.container.noStretch; } if (typeof this.container.flexStretch == 'undefined') { return this.defaultStretch; } return !!this.container.flexStretch; }, _getBias: function() { if (typeof this.container.flexBias == 'undefined' || !this.container.flexBias) { return this.defaultBias; } return this.container.flexBias; }, // Predicate function. Returns true if oControl.flexOrient is "column" _isColumn: function(oControl) { if (typeof oControl.flexOrient == 'undefined' || oControl.flexOrient != 'column' && oControl.flexOrient != 'row') { return this.flexBias == 'column'; } return oControl.flexOrient == 'column'; }, // Returns 0 if container width has NOT crossed flexResponseWidth // Otherwise returns 1 if flexResponseWidth has been crossed while increasing width, // and -1 while decreasing _getResponseFlag: function(oBounds) { var nResponseWidth = this.container.flexResponseWidth, nNewResponseCondition = 0; if (typeof nResponseWidth != 'undefined' && nResponseWidth > 0) { if (oBounds.content.width < nResponseWidth) { nNewResponseCondition = -1; } else { nNewResponseCondition = 1; } } if (this._nResponseCondition > nNewResponseCondition) { this._nResponseCondition = nNewResponseCondition; return -1; } else if (this._nResponseCondition < nNewResponseCondition) { this._nResponseCondition = nNewResponseCondition; return 1; } return 0; }, // Returns response strategy kind object as specified in oControl.flexResponse, otherwise null _getResponseStrategy: function(oControl) { if (typeof oControl.flexResponse != 'undefined') { if (typeof enyo.FlexLayout.ResponseStrategy[oControl.flexResponse] != 'undefined') { return enyo.FlexLayout.ResponseStrategy[oControl.flexResponse]; } } return null; }, // Walks children and triggers their response strategies if specified _setResponseValues: function(oBounds) { var oControl, oStrategy, nResponseFlag = this._getResponseFlag(oBounds), nChildren = this.container.children.length, n = 0; if (nResponseFlag !== 0) { for (;n<nChildren; n++) { oControl = this.container.children[n]; oStrategy = this._getResponseStrategy(oControl); if (oStrategy) { oStrategy.respond(oControl, nResponseFlag > 0); } } } }, // Renders values set to aMetrics arrray by collectMetrics() // Calculates and renders coordinates of children _renderMetrics: function(aMetrics, oStylesContainer) { var n = 0, nX = 0, nY = 0, bInSecondary = false, // bBiasCols ? bInRows : bInCols bBiasCols = (this.flexBias == 'column'), o; for (;n<aMetrics.length; n++) { o = aMetrics[n]; if (o.isColumn) { if (bBiasCols) { if (bInSecondary) { bInSecondary = false; nY = 0; nX += aMetrics[n-1].width + this.flexSpacing; } } else { if (!bInSecondary) { bInSecondary = true; nX = 0; } } o.styles.setBoxLeft(nX, oStylesContainer); o.styles.setBoxTop (nY, oStylesContainer); if (o.flex > 0) { nX += o.width + this.flexSpacing; } else { nX += o.styles.box.width + this.flexSpacing; } } else { if (bBiasCols) { if (!bInSecondary) { bInSecondary = true; nY = 0; } } else { if (bInSecondary) { bInSecondary = false; nX = 0; nY += aMetrics[n-1].height + this.flexSpacing; } } o.styles.setBoxLeft(nX, oStylesContainer); o.styles.setBoxTop (nY, oStylesContainer); if (o.flex > 0) { nY += o.height + this.flexSpacing; } else { nY += o.styles.box.height + this.flexSpacing; } } if (o.width) { o.styles.setBoxWidth (o.width); } if (o.height) { o.styles.setBoxHeight(o.height); } // o.styles.setPosition('absolute'); o.styles.commit(); } }, // Makes a pass through children and gathers their sizes // Calculates sizes of flexible controls in row/column groups // Sets values to metrics array for subsequent rendering _collectMetrics: function(aChildren, oBounds) { var oThis = this, oControl, oStyles, nChildren = aChildren.length, n = 0, oMetrics = {}, aMetrics = [], nFlexHeight = 0, nRemainingHeight = oBounds.content.height, nFlexRows = 0, nRows = 0, nFlexWidth = 0, nRemainingWidth = oBounds.content.width, nFlexCols = 0, nCols = 0, bInSecondary = false, // bBiasCols ? bInRows : bInCols bColumn = false, bBiasCols = (this.flexBias == 'column'); function _beginSecondaryGroup() { if (!bInSecondary) { bInSecondary = true; if (bBiasCols) { nRemainingHeight = oBounds.content.height; nFlexRows = 0; nRows = 0; nCols ++; nFlexCols ++; } else { nRemainingWidth = oBounds.content.width; nFlexCols = 0; nCols = 0; nRows ++; nFlexRows ++; } } } function _endSecondaryGroup() { if (bInSecondary) { bInSecondary = false; var n1 = n - 1; if (bBiasCols) { nFlexHeight = Math.round((nRemainingHeight - oThis.flexSpacing * (nRows - 1))/(nFlexRows ? nFlexRows : 1)); while (aMetrics[n1] && !aMetrics[n1].isColumn) { if (aMetrics[n1].flex > 0) { aMetrics[n1].height = nFlexHeight; } n1 --; } } else { nFlexWidth = Math.round((nRemainingWidth - oThis.flexSpacing * (nCols - 1))/(nFlexCols ? nFlexCols : 1)); while (aMetrics[n1] && aMetrics[n1].isColumn) { if (aMetrics[n1].flex > 0) { aMetrics[n1].width = nFlexWidth; } n1 --; } } } } for (;n<nChildren; n++) { oControl = aChildren[n]; oStyles = new enyo.Styles(oControl); bColumn = this._isColumn(oControl); oMetrics ={ control : oControl, flex : this._getFlex(oControl), styles : oStyles, width : null, height : null, isColumn : bColumn }; if (bColumn) { if (bBiasCols) { _endSecondaryGroup(); if (this.flexStretch) { oMetrics.height = oBounds.content.height; } } else { _beginSecondaryGroup(); } nCols ++; if (oMetrics.flex > 0) { nFlexCols ++; } else { nRemainingWidth -= oStyles.box.width; } } else { if (bBiasCols) { _beginSecondaryGroup(); } else { _endSecondaryGroup(); if (this.flexStretch) { oMetrics.width = oBounds.content.width; } } nRows ++; if (oMetrics.flex > 0) { nFlexRows ++; } else { nRemainingHeight -= oStyles.box.height; } } aMetrics.push(oMetrics); } _endSecondaryGroup(); if (bBiasCols) { nFlexWidth = Math.round((nRemainingWidth - this.flexSpacing * (nCols - 1))/nFlexCols); for (n=0; n<aMetrics.length; n++) { if (!aMetrics[n].isColumn && this.flexStretch || aMetrics[n].flex > 0) { aMetrics[n].width = nFlexWidth; } } } else { nFlexHeight = Math.round((nRemainingHeight - this.flexSpacing * (nRows - 1))/nFlexRows); for (n=0; n<aMetrics.length; n++) { if (aMetrics[n].isColumn && this.flexStretch || aMetrics[n].flex > 0) { aMetrics[n].height = nFlexHeight; } } } return aMetrics; }, // Returns clone array of children that have been ordered accordingly // to their flexOrder _getOrderedChildren: function() { var n = 0, oControl, aChildren = enyo.cloneArray(this.container.children), nChildren = aChildren.length; for (;n<nChildren; n++) { oControl = aChildren[n]; if (typeof oControl.flexOrder != 'undefined' && oControl._flexMoved != this._nReflow) { aChildren.splice(n, 1); aChildren.splice(oControl.flexOrder, 0, oControl); oControl._flexMoved = this._nReflow; n --; } } return aChildren; }, // Applies enyo.ContentLayout to children that are designated // with flex:"content" _applyContentLayouts: function() { var n = 0, oControl; for (;n<this.container.children.length; n++) { oControl = this.container.children[n]; if (oControl.flex == 'content') { oControl.setLayoutKind('enyo.ContentLayout'); } } }, // Runs once and initializes all that needs to be initialized // Calls function that applies enyo.ContentLayout to children _initialize : function(oStylesContainer) { if (this._nReflow > 0) { return; } this._nReflow = 1; this._applyContentLayouts(); }, /******************** PUBLIC *********************/ // Main reflow function, re-renders sizes and positions of children reflow: enyo.inherit(function(sup) { return function() { sup.apply(this, arguments); // var now = enyo.now(); this.flexSpacing = this._getSpacing(); this.flexBias = this._getBias(); this.flexStretch = this._getStretch(); this.container.addClass('enyo-flex-layout-relative'); var oStylesContainer = new enyo.Styles(this.container); enyo.Styles.setStyles(this.container, { 'min-height' : oStylesContainer.content.height + 'px' }); this.container.removeClass('enyo-flex-layout-relative'); this._initialize(oStylesContainer); this._setResponseValues(oStylesContainer); var aChildren = this._getOrderedChildren(), aMetrics = this._collectMetrics(aChildren, oStylesContainer); this._renderMetrics(aMetrics, oStylesContainer); this._nReflow ++; this.container.bubble('onReflow', {layout: this}); // enyo.log(this.container.name, enyo.now() - now); }; }) }); enyo.kind({ name : 'enyo.HFlexLayout', kind : 'enyo.FlexLayout', defaultBias : 'column' }); enyo.kind({ name : 'enyo.VFlexLayout', kind : 'enyo.FlexLayout', defaultBias : 'row' }); enyo.kind({ name : 'enyo.FlexBox', kind : enyo.Control, layoutKind : 'FlexLayout' });