not really known
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

265 lines
7.7 KiB

  1. /**
  2. _enyo.FittableLayout_ provides the base positioning and boundary logic for
  3. the fittable layout strategy. The fittable layout strategy is based on
  4. laying out items in either a set of rows or a set of columns, with most of
  5. the items having natural size, but one item expanding to fill the remaining
  6. space. The item that expands is labeled with the attribute _fit: true_.
  7. For example, in the following kind, the second component fills the available
  8. space in the container between the first and third components.
  9. enyo.kind({
  10. kind: "FittableRows",
  11. components: [
  12. {content: "1"},
  13. {content: "2", fit:true},
  14. {content: "3"}
  15. ]
  16. });
  17. <a href="#enyo.FittableColumnsLayout">enyo.FittableColumnsLayout</a> and
  18. <a href="#enyo.FittableRowsLayout">enyo.FittableRowsLayout</a> (or their
  19. subkinds) are used for layout rather than _enyo.FittableLayout_ because they
  20. specify properties that _enyo.FittableLayout_ expects to be available when
  21. laying items out.
  22. */
  23. enyo.kind({
  24. name: "enyo.FittableLayout",
  25. kind: "Layout",
  26. //* @protected
  27. calcFitIndex: function() {
  28. for (var i=0, c$=this.container.children, c; c=c$[i]; i++) {
  29. if (c.fit && c.showing) {
  30. return i;
  31. }
  32. }
  33. },
  34. getFitControl: function() {
  35. var c$=this.container.children;
  36. var f = c$[this.fitIndex];
  37. if (!(f && f.fit && f.showing)) {
  38. this.fitIndex = this.calcFitIndex();
  39. f = c$[this.fitIndex];
  40. }
  41. return f;
  42. },
  43. getLastControl: function() {
  44. var c$=this.container.children;
  45. var i = c$.length-1;
  46. var c = c$[i];
  47. while ((c=c$[i]) && !c.showing) {
  48. i--;
  49. }
  50. return c;
  51. },
  52. _reflow: function(measure, cMeasure, mAttr, nAttr) {
  53. this.container.addRemoveClass("enyo-stretch", !this.container.noStretch);
  54. var f = this.getFitControl();
  55. // no sizing if nothing is fit.
  56. if (!f) {
  57. return;
  58. }
  59. //
  60. // determine container size, available space
  61. var s=0, a=0, b=0, p;
  62. var n = this.container.hasNode();
  63. // calculate available space
  64. if (n) {
  65. // measure 1
  66. p = enyo.FittableLayout.calcPaddingExtents(n);
  67. // measure 2
  68. s = n[cMeasure] - (p[mAttr] + p[nAttr]);
  69. //console.log("overall size", s);
  70. }
  71. //
  72. // calculate space above fitting control
  73. // measure 3
  74. var fb = f.getBounds();
  75. // offset - container padding.
  76. a = fb[mAttr] - ((p && p[mAttr]) || 0);
  77. //console.log("above", a);
  78. //
  79. // calculate space below fitting control
  80. var l = this.getLastControl();
  81. if (l) {
  82. // measure 4
  83. var mb = enyo.FittableLayout.getComputedStyleValue(l.hasNode(), "margin", nAttr) || 0;
  84. if (l != f) {
  85. // measure 5
  86. var lb = l.getBounds();
  87. // fit offset + size
  88. var bf = fb[mAttr] + fb[measure];
  89. // last offset + size + ending margin
  90. var bl = lb[mAttr] + lb[measure] + mb;
  91. // space below is bottom of last item - bottom of fit item.
  92. b = bl - bf;
  93. } else {
  94. b = mb;
  95. }
  96. }
  97. // calculate appropriate size for fit control
  98. var fs = s - (a + b);
  99. //console.log(f.id, fs);
  100. // note: must be border-box;
  101. f.applyStyle(measure, fs + "px");
  102. },
  103. //* @public
  104. /**
  105. Updates the layout to reflect any changes to contained components or the
  106. layout container.
  107. */
  108. reflow: function() {
  109. if (this.orient == "h") {
  110. this._reflow("width", "clientWidth", "left", "right");
  111. } else {
  112. this._reflow("height", "clientHeight", "top", "bottom");
  113. }
  114. },
  115. statics: {
  116. //* @protected
  117. _ieCssToPixelValue: function(inNode, inValue) {
  118. var v = inValue;
  119. // From the awesome hack by Dean Edwards
  120. // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
  121. var s = inNode.style;
  122. // store style and runtime style values
  123. var l = s.left;
  124. var rl = inNode.runtimeStyle && inNode.runtimeStyle.left;
  125. // then put current style in runtime style.
  126. if (rl) {
  127. inNode.runtimeStyle.left = inNode.currentStyle.left;
  128. }
  129. // apply given value and measure its pixel value
  130. s.left = v;
  131. v = s.pixelLeft;
  132. // finally restore previous state
  133. s.left = l;
  134. if (rl) {
  135. s.runtimeStyle.left = rl;
  136. }
  137. return v;
  138. },
  139. _pxMatch: /px/i,
  140. getComputedStyleValue: function(inNode, inProp, inBoundary, inComputedStyle) {
  141. var s = inComputedStyle || enyo.dom.getComputedStyle(inNode);
  142. if (s) {
  143. return parseInt(s.getPropertyValue(inProp + "-" + inBoundary));
  144. } else if (inNode && inNode.currentStyle) {
  145. var v = inNode.currentStyle[inProp + enyo.cap(inBoundary)];
  146. if (!v.match(this._pxMatch)) {
  147. v = this._ieCssToPixelValue(inNode, v);
  148. }
  149. return parseInt(v);
  150. }
  151. return 0;
  152. },
  153. //* Gets the boundaries of a node's margin or padding box.
  154. calcBoxExtents: function(inNode, inBox) {
  155. var s = enyo.dom.getComputedStyle(inNode);
  156. return {
  157. top: this.getComputedStyleValue(inNode, inBox, "top", s),
  158. right: this.getComputedStyleValue(inNode, inBox, "right", s),
  159. bottom: this.getComputedStyleValue(inNode, inBox, "bottom", s),
  160. left: this.getComputedStyleValue(inNode, inBox, "left", s)
  161. };
  162. },
  163. //* Gets the calculated padding of a node.
  164. calcPaddingExtents: function(inNode) {
  165. return this.calcBoxExtents(inNode, "padding");
  166. },
  167. //* Gets the calculated margin of a node.
  168. calcMarginExtents: function(inNode) {
  169. return this.calcBoxExtents(inNode, "margin");
  170. }
  171. }
  172. });
  173. /**
  174. _enyo.FittableColumnsLayout_ provides a container in which items are laid
  175. out in a set of vertical columns, with most of the items having natural
  176. size, but one expanding to fill the remaining space. The one that expands is
  177. labeled with the attribute _fit: true_.
  178. _enyo.FittableColumnsLayout_ is meant to be used as a value for the
  179. _layoutKind_ property of other kinds. _layoutKind_ provides a way to add
  180. layout behavior in a pluggable fashion while retaining the ability to use a
  181. specific base kind.
  182. For example, the following code will align three components as columns, with
  183. the second filling the available container space between the first and third.
  184. enyo.kind({
  185. kind: enyo.Control,
  186. layoutKind: "FittableColumnsLayout",
  187. components: [
  188. {content: "1"},
  189. {content: "2", fit:true},
  190. {content: "3"}
  191. ]
  192. });
  193. Alternatively, if a specific base kind is not needed, then instead of
  194. setting the _layoutKind_ attribute, you can set the base kind to
  195. <a href="#enyo.FittableColumns">enyo.FittableColumns</a>:
  196. enyo.kind({
  197. kind: "FittableColumns",
  198. components: [
  199. {content: "1"},
  200. {content: "2", fit:true},
  201. {content: "3"}
  202. ]
  203. });
  204. */
  205. enyo.kind({
  206. name: "enyo.FittableColumnsLayout",
  207. kind: "FittableLayout",
  208. orient: "h",
  209. layoutClass: "enyo-fittable-columns-layout"
  210. });
  211. /**
  212. _enyo.FittableRowsLayout_ provides a container in which items are laid out
  213. in a set of horizontal rows, with most of the items having natural size, but
  214. one expanding to fill the remaining space. The one that expands is labeled
  215. with the attribute _fit: true_.
  216. _enyo.FittableRowsLayout_ is meant to be used as a value for the
  217. _layoutKind_ property of other kinds. _layoutKind_ provides a way to add
  218. layout behavior in a pluggable fashion while retaining the ability to use a
  219. specific base kind.
  220. For example, the following code will align three components as rows, with
  221. the second filling the available container space between the first and third.
  222. enyo.kind({
  223. kind: enyo.Control,
  224. layoutKind: "FittableRowsLayout",
  225. components: [
  226. {content: "1"},
  227. {content: "2", fit:true},
  228. {content: "3"}
  229. ]
  230. });
  231. Alternatively, if a specific base kind is not needed, then instead of
  232. setting the _layoutKind_ attribute, you can set the base kind to
  233. <a href="#enyo.FittableRows">enyo.FittableRows</a>:
  234. enyo.kind({
  235. kind: "FittableRows",
  236. components: [
  237. {content: "1"},
  238. {content: "2", fit:true},
  239. {content: "3"}
  240. ]
  241. });
  242. */
  243. enyo.kind({
  244. name: "enyo.FittableRowsLayout",
  245. kind: "FittableLayout",
  246. layoutClass: "enyo-fittable-rows-layout",
  247. orient: "v"
  248. });