CheckboxGroup.html 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>The source code</title>
  6. <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7. <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8. <style type="text/css">
  9. .highlight { display: block; background-color: #ddd; }
  10. </style>
  11. <script type="text/javascript">
  12. function highlight() {
  13. document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14. }
  15. </script>
  16. </head>
  17. <body onload="prettyPrint(); highlight();">
  18. <pre class="prettyprint lang-js"><span id='Ext-layout-container-CheckboxGroup'>/**
  19. </span> * This layout implements the column arrangement for {@link Ext.form.CheckboxGroup} and {@link Ext.form.RadioGroup}.
  20. * It groups the component's sub-items into columns based on the component's
  21. * {@link Ext.form.CheckboxGroup#columns columns} and {@link Ext.form.CheckboxGroup#vertical} config properties.
  22. */
  23. Ext.define('Ext.layout.container.CheckboxGroup', {
  24. extend: 'Ext.layout.container.Container',
  25. alias: ['layout.checkboxgroup'],
  26. <span id='Ext-layout-container-CheckboxGroup-cfg-autoFlex'> /**
  27. </span> * @cfg {Boolean} [autoFlex=true]
  28. * By default, CheckboxGroup allocates all available space to the configured columns meaning that
  29. * column are evenly spaced across the container.
  30. *
  31. * To have each column only be wide enough to fit the container Checkboxes (or Radios), set `autoFlex` to `false`
  32. */
  33. autoFlex: true,
  34. type: 'checkboxgroup',
  35. childEls: [
  36. 'innerCt'
  37. ],
  38. renderTpl: [
  39. '&lt;table id=&quot;{ownerId}-innerCt&quot; role=&quot;presentation&quot; style=&quot;{tableStyle}&quot;&gt;&lt;tbody&gt;&lt;tr&gt;',
  40. '&lt;tpl for=&quot;columns&quot;&gt;',
  41. '&lt;td class=&quot;{parent.colCls}&quot; valign=&quot;top&quot; style=&quot;{style}&quot;&gt;',
  42. '{% this.renderColumn(out,parent,xindex-1) %}',
  43. '&lt;/td&gt;',
  44. '&lt;/tpl&gt;',
  45. '&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;'
  46. ],
  47. lastOwnerItemsGeneration : null,
  48. beginLayout: function(ownerContext) {
  49. var me = this,
  50. columns,
  51. numCols,
  52. i, width, cwidth,
  53. totalFlex = 0, flexedCols = 0,
  54. autoFlex = me.autoFlex,
  55. innerCtStyle = me.innerCt.dom.style;
  56. me.callParent(arguments);
  57. columns = me.columnNodes;
  58. ownerContext.innerCtContext = ownerContext.getEl('innerCt', me);
  59. // The columns config may be an array of widths. Any value &lt; 1 is taken to be a fraction:
  60. if (!ownerContext.widthModel.shrinkWrap) {
  61. numCols = columns.length;
  62. // If columns is an array of numeric widths
  63. if (me.columnsArray) {
  64. // first calculate total flex
  65. for (i = 0; i &lt; numCols; i++) {
  66. width = me.owner.columns[i];
  67. if (width &lt; 1) {
  68. totalFlex += width;
  69. flexedCols++;
  70. }
  71. }
  72. // now apply widths
  73. for (i = 0; i &lt; numCols; i++) {
  74. width = me.owner.columns[i];
  75. if (width &lt; 1) {
  76. cwidth = ((width / totalFlex) * 100) + '%';
  77. } else {
  78. cwidth = width + 'px';
  79. }
  80. columns[i].style.width = cwidth;
  81. }
  82. }
  83. // Otherwise it's the *number* of columns, so distributed the widths evenly
  84. else {
  85. for (i = 0; i &lt; numCols; i++) {
  86. // autoFlex: true will automatically calculate % widths
  87. // autoFlex: false allows the table to decide (shrinkWrap, in effect)
  88. // on a per-column basis
  89. cwidth = autoFlex
  90. ? (1 / numCols * 100) + '%'
  91. : '';
  92. columns[i].style.width = cwidth;
  93. flexedCols++;
  94. }
  95. }
  96. // no flexed cols -- all widths are fixed
  97. if (!flexedCols) {
  98. innerCtStyle.tableLayout = 'fixed';
  99. innerCtStyle.width = '';
  100. // some flexed cols -- need to fix some
  101. } else if (flexedCols &lt; numCols) {
  102. innerCtStyle.tableLayout = 'fixed';
  103. innerCtStyle.width = '100%';
  104. // let the table decide
  105. } else {
  106. innerCtStyle.tableLayout = 'auto';
  107. // if autoFlex, fill available space, else compact down
  108. if (autoFlex) {
  109. innerCtStyle.width = '100%';
  110. } else {
  111. innerCtStyle.width = '';
  112. }
  113. }
  114. } else {
  115. innerCtStyle.tableLayout = 'auto';
  116. innerCtStyle.width = '';
  117. }
  118. },
  119. cacheElements: function () {
  120. var me = this;
  121. // Grab defined childEls
  122. me.callParent();
  123. me.rowEl = me.innerCt.down('tr');
  124. // Grab columns TDs
  125. me.columnNodes = me.rowEl.dom.childNodes;
  126. },
  127. /*
  128. * Just wait for the child items to all lay themselves out in the width we are configured
  129. * to make available to them. Then we can measure our height.
  130. */
  131. calculate: function(ownerContext) {
  132. var me = this,
  133. targetContext, widthShrinkWrap, heightShrinkWrap, shrinkWrap, table, targetPadding;
  134. // The columnNodes are widthed using their own width attributes, we just need to wait
  135. // for all children to have arranged themselves in that width, and then collect our height.
  136. if (!ownerContext.getDomProp('containerChildrenDone')) {
  137. me.done = false;
  138. } else {
  139. targetContext = ownerContext.innerCtContext;
  140. widthShrinkWrap = ownerContext.widthModel.shrinkWrap;
  141. heightShrinkWrap = ownerContext.heightModel.shrinkWrap;
  142. shrinkWrap = heightShrinkWrap || widthShrinkWrap;
  143. table = targetContext.el.dom;
  144. targetPadding = shrinkWrap &amp;&amp; targetContext.getPaddingInfo();
  145. if (widthShrinkWrap) {
  146. ownerContext.setContentWidth(table.offsetWidth + targetPadding.width, true);
  147. }
  148. if (heightShrinkWrap) {
  149. ownerContext.setContentHeight(table.offsetHeight + targetPadding.height, true);
  150. }
  151. }
  152. },
  153. doRenderColumn: function (out, renderData, columnIndex) {
  154. // Careful! This method is bolted on to the renderTpl so all we get for context is
  155. // the renderData! The &quot;this&quot; pointer is the renderTpl instance!
  156. var me = renderData.$layout,
  157. owner = me.owner,
  158. columnCount = renderData.columnCount,
  159. items = owner.items.items,
  160. itemCount = items.length,
  161. item, itemIndex, rowCount, increment, tree;
  162. // Example:
  163. // columnCount = 3
  164. // items.length = 10
  165. if (owner.vertical) {
  166. // 0 1 2
  167. // +---+---+---+
  168. // 0 | 0 | 4 | 8 |
  169. // +---+---+---+
  170. // 1 | 1 | 5 | 9 |
  171. // +---+---+---+
  172. // 2 | 2 | 6 | |
  173. // +---+---+---+
  174. // 3 | 3 | 7 | |
  175. // +---+---+---+
  176. rowCount = Math.ceil(itemCount / columnCount); // = 4
  177. itemIndex = columnIndex * rowCount;
  178. itemCount = Math.min(itemCount, itemIndex + rowCount);
  179. increment = 1;
  180. } else {
  181. // 0 1 2
  182. // +---+---+---+
  183. // 0 | 0 | 1 | 2 |
  184. // +---+---+---+
  185. // 1 | 3 | 4 | 5 |
  186. // +---+---+---+
  187. // 2 | 6 | 7 | 8 |
  188. // +---+---+---+
  189. // 3 | 9 | | |
  190. // +---+---+---+
  191. itemIndex = columnIndex;
  192. increment = columnCount;
  193. }
  194. for ( ; itemIndex &lt; itemCount; itemIndex += increment) {
  195. item = items[itemIndex];
  196. me.configureItem(item);
  197. tree = item.getRenderTree();
  198. Ext.DomHelper.generateMarkup(tree, out);
  199. }
  200. },
  201. <span id='Ext-layout-container-CheckboxGroup-method-getColumnCount'> /**
  202. </span> * Returns the number of columns in the checkbox group.
  203. * @private
  204. */
  205. getColumnCount: function() {
  206. var me = this,
  207. owner = me.owner,
  208. ownerColumns = owner.columns;
  209. // Our columns config is an array of numeric widths.
  210. // Calculate our total width
  211. if (me.columnsArray) {
  212. return ownerColumns.length;
  213. }
  214. if (Ext.isNumber(ownerColumns)) {
  215. return ownerColumns;
  216. }
  217. return owner.items.length;
  218. },
  219. getItemSizePolicy: function (item) {
  220. return this.autoSizePolicy;
  221. },
  222. getRenderData: function () {
  223. var me = this,
  224. data = me.callParent(),
  225. owner = me.owner,
  226. i, columns = me.getColumnCount(),
  227. width, column, cwidth,
  228. autoFlex = me.autoFlex,
  229. totalFlex = 0, flexedCols = 0;
  230. // calculate total flex
  231. if (me.columnsArray) {
  232. for (i=0; i &lt; columns; i++) {
  233. width = me.owner.columns[i];
  234. if (width &lt; 1) {
  235. totalFlex += width;
  236. flexedCols++;
  237. }
  238. }
  239. }
  240. data.colCls = owner.groupCls;
  241. data.columnCount = columns;
  242. data.columns = [];
  243. for (i = 0; i &lt; columns; i++) {
  244. column = (data.columns[i] = {});
  245. if (me.columnsArray) {
  246. width = me.owner.columns[i];
  247. if (width &lt; 1) {
  248. cwidth = ((width / totalFlex) * 100) + '%';
  249. } else {
  250. cwidth = width + 'px';
  251. }
  252. column.style = 'width:' + cwidth;
  253. } else {
  254. column.style = 'width:' + (1 / columns * 100) + '%';
  255. flexedCols++;
  256. }
  257. }
  258. // If the columns config was an array of column widths, allow table to auto width
  259. data.tableStyle =
  260. !flexedCols ? 'table-layout:fixed;' :
  261. (flexedCols &lt; columns) ? 'table-layout:fixed;width:100%' :
  262. (autoFlex) ? 'table-layout:auto;width:100%' : 'table-layout:auto;';
  263. return data;
  264. },
  265. initLayout: function () {
  266. var me = this,
  267. owner = me.owner;
  268. me.columnsArray = Ext.isArray(owner.columns);
  269. me.autoColumns = !owner.columns || owner.columns === 'auto';
  270. me.vertical = owner.vertical;
  271. me.callParent();
  272. },
  273. // Always valid. beginLayout ensures the encapsulating elements of all children are in the correct place
  274. isValidParent: function() {
  275. return true;
  276. },
  277. setupRenderTpl: function (renderTpl) {
  278. this.callParent(arguments);
  279. renderTpl.renderColumn = this.doRenderColumn;
  280. },
  281. renderChildren: function () {
  282. var me = this,
  283. generation = me.owner.items.generation;
  284. if (me.lastOwnerItemsGeneration !== generation) {
  285. me.lastOwnerItemsGeneration = generation;
  286. me.renderItems(me.getLayoutItems());
  287. }
  288. },
  289. <span id='Ext-layout-container-CheckboxGroup-method-renderItems'> /**
  290. </span> * Iterates over all passed items, ensuring they are rendered. If the items are already rendered,
  291. * also determines if the items are in the proper place in the dom.
  292. * @protected
  293. */
  294. renderItems : function(items) {
  295. var me = this,
  296. itemCount = items.length,
  297. i,
  298. item,
  299. rowCount,
  300. columnCount,
  301. rowIndex,
  302. columnIndex;
  303. if (itemCount) {
  304. Ext.suspendLayouts();
  305. if (me.autoColumns) {
  306. me.addMissingColumns(itemCount);
  307. }
  308. columnCount = me.columnNodes.length;
  309. rowCount = Math.ceil(itemCount / columnCount);
  310. for (i = 0; i &lt; itemCount; i++) {
  311. item = items[i];
  312. rowIndex = me.getRenderRowIndex(i, rowCount, columnCount);
  313. columnIndex = me.getRenderColumnIndex(i, rowCount, columnCount);
  314. if (!item.rendered) {
  315. me.renderItem(item, rowIndex, columnIndex);
  316. } else if (!me.isItemAtPosition(item, rowIndex, columnIndex)) {
  317. me.moveItem(item, rowIndex, columnIndex);
  318. }
  319. }
  320. if (me.autoColumns) {
  321. me.removeExceedingColumns(itemCount);
  322. }
  323. Ext.resumeLayouts(true);
  324. }
  325. },
  326. isItemAtPosition : function(item, rowIndex, columnIndex) {
  327. return item.el.dom === this.getNodeAt(rowIndex, columnIndex);
  328. },
  329. getRenderColumnIndex : function(itemIndex, rowCount, columnCount) {
  330. if (this.vertical) {
  331. return Math.floor(itemIndex / rowCount);
  332. } else {
  333. return itemIndex % columnCount;
  334. }
  335. },
  336. getRenderRowIndex : function(itemIndex, rowCount, columnCount) {
  337. var me = this;
  338. if (me.vertical) {
  339. return itemIndex % rowCount;
  340. } else {
  341. return Math.floor(itemIndex / columnCount);
  342. }
  343. },
  344. getNodeAt : function(rowIndex, columnIndex) {
  345. return this.columnNodes[columnIndex].childNodes[rowIndex];
  346. },
  347. addMissingColumns : function(itemsCount) {
  348. var me = this,
  349. existingColumnsCount = me.columnNodes.length,
  350. missingColumnsCount,
  351. row,
  352. cls,
  353. i;
  354. if (existingColumnsCount &lt; itemsCount) {
  355. missingColumnsCount = itemsCount - existingColumnsCount;
  356. row = me.rowEl;
  357. cls = me.owner.groupCls;
  358. for (i = 0; i &lt; missingColumnsCount; i++) {
  359. row.createChild({
  360. cls: cls,
  361. tag: 'td',
  362. vAlign: 'top'
  363. });
  364. }
  365. }
  366. },
  367. removeExceedingColumns : function(itemsCount) {
  368. var me = this,
  369. existingColumnsCount = me.columnNodes.length,
  370. exceedingColumnsCount,
  371. row,
  372. i;
  373. if (existingColumnsCount &gt; itemsCount) {
  374. exceedingColumnsCount = existingColumnsCount - itemsCount;
  375. row = me.rowEl;
  376. for (i = 0; i &lt; exceedingColumnsCount; i++) {
  377. row.last().remove();
  378. }
  379. }
  380. },
  381. <span id='Ext-layout-container-CheckboxGroup-method-renderItem'> /**
  382. </span> * Renders the given Component into the specified row and column
  383. * @param {Ext.Component} item The Component to render
  384. * @param {number} rowIndex row index
  385. * @param {number} columnIndex column index
  386. * @private
  387. */
  388. renderItem : function(item, rowIndex, columnIndex) {
  389. var me = this;
  390. me.configureItem(item);
  391. item.render(Ext.get(me.columnNodes[columnIndex]), rowIndex);
  392. me.afterRenderItem(item);
  393. },
  394. <span id='Ext-layout-container-CheckboxGroup-method-moveItem'> /**
  395. </span> * Moves the given already rendered Component to the specified row and column
  396. * @param {Ext.Component} item The Component to move
  397. * @param {number} rowIndex row index
  398. * @param {number} columnIndex column index
  399. * @private
  400. */
  401. moveItem : function(item, rowIndex, columnIndex) {
  402. var me = this,
  403. column = me.columnNodes[columnIndex],
  404. targetNode = column.childNodes[rowIndex];
  405. column.insertBefore(item.el.dom, targetNode || null);
  406. }
  407. });</pre>
  408. </body>
  409. </html>