diff options
author | Lionel LASKE <llaske@c2s.fr> | 2012-09-18 19:16:20 (GMT) |
---|---|---|
committer | Lionel LASKE <llaske@c2s.fr> | 2012-09-18 19:16:20 (GMT) |
commit | 816de0918c28461cc2d1e3457348fd5b6e11950f (patch) | |
tree | 667959b6e32d998a5bf4ae927ea59d88b71bfd44 /html/lib/layout/fittable/source/FittableLayout.js |
Initial version
Diffstat (limited to 'html/lib/layout/fittable/source/FittableLayout.js')
-rw-r--r-- | html/lib/layout/fittable/source/FittableLayout.js | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/html/lib/layout/fittable/source/FittableLayout.js b/html/lib/layout/fittable/source/FittableLayout.js new file mode 100644 index 0000000..6045e65 --- /dev/null +++ b/html/lib/layout/fittable/source/FittableLayout.js @@ -0,0 +1,265 @@ +/** + _enyo.FittableLayout_ provides the base positioning and boundary logic for + the fittable layout strategy. The fittable layout strategy is based on + laying out items in either a set of rows or a set of columns, with most of + the items having natural size, but one item expanding to fill the remaining + space. The item that expands is labeled with the attribute _fit: true_. + + For example, in the following kind, the second component fills the available + space in the container between the first and third components. + + enyo.kind({ + kind: "FittableRows", + components: [ + {content: "1"}, + {content: "2", fit:true}, + {content: "3"} + ] + }); + + <a href="#enyo.FittableColumnsLayout">enyo.FittableColumnsLayout</a> and + <a href="#enyo.FittableRowsLayout">enyo.FittableRowsLayout</a> (or their + subkinds) are used for layout rather than _enyo.FittableLayout_ because they + specify properties that _enyo.FittableLayout_ expects to be available when + laying items out. +*/ +enyo.kind({ + name: "enyo.FittableLayout", + kind: "Layout", + //* @protected + calcFitIndex: function() { + for (var i=0, c$=this.container.children, c; c=c$[i]; i++) { + if (c.fit && c.showing) { + return i; + } + } + }, + getFitControl: function() { + var c$=this.container.children; + var f = c$[this.fitIndex]; + if (!(f && f.fit && f.showing)) { + this.fitIndex = this.calcFitIndex(); + f = c$[this.fitIndex]; + } + return f; + }, + getLastControl: function() { + var c$=this.container.children; + var i = c$.length-1; + var c = c$[i]; + while ((c=c$[i]) && !c.showing) { + i--; + } + return c; + }, + _reflow: function(measure, cMeasure, mAttr, nAttr) { + this.container.addRemoveClass("enyo-stretch", !this.container.noStretch); + var f = this.getFitControl(); + // no sizing if nothing is fit. + if (!f) { + return; + } + // + // determine container size, available space + var s=0, a=0, b=0, p; + var n = this.container.hasNode(); + // calculate available space + if (n) { + // measure 1 + p = enyo.FittableLayout.calcPaddingExtents(n); + // measure 2 + s = n[cMeasure] - (p[mAttr] + p[nAttr]); + //console.log("overall size", s); + } + // + // calculate space above fitting control + // measure 3 + var fb = f.getBounds(); + // offset - container padding. + a = fb[mAttr] - ((p && p[mAttr]) || 0); + //console.log("above", a); + // + // calculate space below fitting control + var l = this.getLastControl(); + if (l) { + // measure 4 + var mb = enyo.FittableLayout.getComputedStyleValue(l.hasNode(), "margin", nAttr) || 0; + if (l != f) { + // measure 5 + var lb = l.getBounds(); + // fit offset + size + var bf = fb[mAttr] + fb[measure]; + // last offset + size + ending margin + var bl = lb[mAttr] + lb[measure] + mb; + // space below is bottom of last item - bottom of fit item. + b = bl - bf; + } else { + b = mb; + } + } + + // calculate appropriate size for fit control + var fs = s - (a + b); + //console.log(f.id, fs); + // note: must be border-box; + f.applyStyle(measure, fs + "px"); + }, + //* @public + /** + Updates the layout to reflect any changes to contained components or the + layout container. + */ + reflow: function() { + if (this.orient == "h") { + this._reflow("width", "clientWidth", "left", "right"); + } else { + this._reflow("height", "clientHeight", "top", "bottom"); + } + }, + statics: { + //* @protected + _ieCssToPixelValue: function(inNode, inValue) { + var v = inValue; + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + var s = inNode.style; + // store style and runtime style values + var l = s.left; + var rl = inNode.runtimeStyle && inNode.runtimeStyle.left; + // then put current style in runtime style. + if (rl) { + inNode.runtimeStyle.left = inNode.currentStyle.left; + } + // apply given value and measure its pixel value + s.left = v; + v = s.pixelLeft; + // finally restore previous state + s.left = l; + if (rl) { + s.runtimeStyle.left = rl; + } + return v; + }, + _pxMatch: /px/i, + getComputedStyleValue: function(inNode, inProp, inBoundary, inComputedStyle) { + var s = inComputedStyle || enyo.dom.getComputedStyle(inNode); + if (s) { + return parseInt(s.getPropertyValue(inProp + "-" + inBoundary)); + } else if (inNode && inNode.currentStyle) { + var v = inNode.currentStyle[inProp + enyo.cap(inBoundary)]; + if (!v.match(this._pxMatch)) { + v = this._ieCssToPixelValue(inNode, v); + } + return parseInt(v); + } + return 0; + }, + //* Gets the boundaries of a node's margin or padding box. + calcBoxExtents: function(inNode, inBox) { + var s = enyo.dom.getComputedStyle(inNode); + return { + top: this.getComputedStyleValue(inNode, inBox, "top", s), + right: this.getComputedStyleValue(inNode, inBox, "right", s), + bottom: this.getComputedStyleValue(inNode, inBox, "bottom", s), + left: this.getComputedStyleValue(inNode, inBox, "left", s) + }; + }, + //* Gets the calculated padding of a node. + calcPaddingExtents: function(inNode) { + return this.calcBoxExtents(inNode, "padding"); + }, + //* Gets the calculated margin of a node. + calcMarginExtents: function(inNode) { + return this.calcBoxExtents(inNode, "margin"); + } + } +}); + +/** + _enyo.FittableColumnsLayout_ provides a container in which items are laid + out in a set of vertical columns, with most of the items having natural + size, but one expanding to fill the remaining space. The one that expands is + labeled with the attribute _fit: true_. + + _enyo.FittableColumnsLayout_ is meant to be used as a value for the + _layoutKind_ property of other kinds. _layoutKind_ provides a way to add + layout behavior in a pluggable fashion while retaining the ability to use a + specific base kind. + + For example, the following code will align three components as columns, with + the second filling the available container space between the first and third. + + enyo.kind({ + kind: enyo.Control, + layoutKind: "FittableColumnsLayout", + components: [ + {content: "1"}, + {content: "2", fit:true}, + {content: "3"} + ] + }); + + Alternatively, if a specific base kind is not needed, then instead of + setting the _layoutKind_ attribute, you can set the base kind to + <a href="#enyo.FittableColumns">enyo.FittableColumns</a>: + + enyo.kind({ + kind: "FittableColumns", + components: [ + {content: "1"}, + {content: "2", fit:true}, + {content: "3"} + ] + }); +*/ +enyo.kind({ + name: "enyo.FittableColumnsLayout", + kind: "FittableLayout", + orient: "h", + layoutClass: "enyo-fittable-columns-layout" +}); + + +/** + _enyo.FittableRowsLayout_ provides a container in which items are laid out + in a set of horizontal rows, with most of the items having natural size, but + one expanding to fill the remaining space. The one that expands is labeled + with the attribute _fit: true_. + + _enyo.FittableRowsLayout_ is meant to be used as a value for the + _layoutKind_ property of other kinds. _layoutKind_ provides a way to add + layout behavior in a pluggable fashion while retaining the ability to use a + specific base kind. + + For example, the following code will align three components as rows, with + the second filling the available container space between the first and third. + + enyo.kind({ + kind: enyo.Control, + layoutKind: "FittableRowsLayout", + components: [ + {content: "1"}, + {content: "2", fit:true}, + {content: "3"} + ] + }); + + Alternatively, if a specific base kind is not needed, then instead of + setting the _layoutKind_ attribute, you can set the base kind to + <a href="#enyo.FittableRows">enyo.FittableRows</a>: + + enyo.kind({ + kind: "FittableRows", + components: [ + {content: "1"}, + {content: "2", fit:true}, + {content: "3"} + ] + }); +*/ +enyo.kind({ + name: "enyo.FittableRowsLayout", + kind: "FittableLayout", + layoutClass: "enyo-fittable-rows-layout", + orient: "v" +}); |