| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432 | <!DOCTYPE html><html><head>  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  <title>The source code</title>  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>  <style type="text/css">    .highlight { display: block; background-color: #ddd; }  </style>  <script type="text/javascript">    function highlight() {      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";    }  </script></head><body onload="prettyPrint(); highlight();">  <pre class="prettyprint lang-js"><span id='Ext-layout-container-Table'>/**</span> * This layout allows you to easily render content into an HTML table. The total number of columns can be specified, and * rowspan and colspan can be used to create complex layouts within the table. This class is intended to be extended or * created via the `layout: {type: 'table'}` {@link Ext.container.Container#layout} config, and should generally not * need to be created directly via the new keyword. * * Note that when creating a layout via config, the layout-specific config properties must be passed in via the {@link * Ext.container.Container#layout} object which will then be applied internally to the layout. In the case of * TableLayout, the only valid layout config properties are {@link #columns} and {@link #tableAttrs}. However, the items * added to a TableLayout can supply the following table-specific config properties: * *   - **rowspan** Applied to the table cell containing the item. *   - **colspan** Applied to the table cell containing the item. *   - **cellId** An id applied to the table cell containing the item. *   - **cellCls** A CSS class name added to the table cell containing the item. * * The basic concept of building up a TableLayout is conceptually very similar to building up a standard HTML table. You * simply add each panel (or "cell") that you want to include along with any span attributes specified as the special * config properties of rowspan and colspan which work exactly like their HTML counterparts. Rather than explicitly * creating and nesting rows and columns as you would in HTML, you simply specify the total column count in the * layout config and start adding panels in their natural order from left to right, top to bottom. The layout will * automatically figure out, based on the column count, rowspans and colspans, how to position each panel within the * table. Just like with HTML tables, your rowspans and colspans must add up correctly in your overall layout or you'll * end up with missing and/or extra cells! Example usage: * *     @example *     Ext.create('Ext.panel.Panel', { *         title: 'Table Layout', *         width: 300, *         height: 150, *         layout: { *             type: 'table', *             // The total column count must be specified here *             columns: 3 *         }, *         defaults: { *             // applied to each contained panel *             bodyStyle: 'padding:20px' *         }, *         items: [{ *             html: 'Cell A content', *             rowspan: 2 *         },{ *             html: 'Cell B content', *             colspan: 2 *         },{ *             html: 'Cell C content', *             cellCls: 'highlight' *         },{ *             html: 'Cell D content' *         }], *         renderTo: Ext.getBody() *     }); */Ext.define('Ext.layout.container.Table', {    /* Begin Definitions */    alias: ['layout.table'],    extend: 'Ext.layout.container.Container',    alternateClassName: 'Ext.layout.TableLayout',    /* End Definitions */<span id='Ext-layout-container-Table-cfg-columns'>    /**</span>     * @cfg {Number} columns     * The total number of columns to create in the table for this layout. If not specified, all Components added to     * this layout will be rendered into a single row using one column per Component.     */    // private    monitorResize:false,    type: 'table',    clearEl: true, // Base class will not create it if already truthy. Not needed in tables.    targetCls: Ext.baseCSSPrefix + 'table-layout-ct',    tableCls: Ext.baseCSSPrefix + 'table-layout',    cellCls: Ext.baseCSSPrefix + 'table-layout-cell',<span id='Ext-layout-container-Table-cfg-tableAttrs'>    /**</span>     * @cfg {Object} tableAttrs     * An object containing properties which are added to the {@link Ext.DomHelper DomHelper} specification used to     * create the layout's `<table>` element. Example:     *     *     {     *         xtype: 'panel',     *         layout: {     *             type: 'table',     *             columns: 3,     *             tableAttrs: {     *                 style: {     *                     width: '100%'     *                 }     *             }     *         }     *     }     */    tableAttrs: null,<span id='Ext-layout-container-Table-cfg-trAttrs'>    /**</span>     * @cfg {Object} trAttrs     * An object containing properties which are added to the {@link Ext.DomHelper DomHelper} specification used to     * create the layout's `<tr>` elements.     */<span id='Ext-layout-container-Table-cfg-tdAttrs'>    /**</span>     * @cfg {Object} tdAttrs     * An object containing properties which are added to the {@link Ext.DomHelper DomHelper} specification used to     * create the layout's `<td>` elements.     */    itemSizePolicy: {        setsWidth: 0,        setsHeight: 0    },    getItemSizePolicy: function (item) {        return this.itemSizePolicy;    },    getLayoutItems: function() {        var me = this,            result = [],            items = me.callParent(),            item,            len = items.length, i;        for (i = 0; i < len; i++) {            item = items[i];            if (!item.hidden) {                result.push(item);            }        }        return result;    },<span id='Ext-layout-container-Table-method-renderChildren'>    /**</span>     * @private     * Iterates over all passed items, ensuring they are rendered in a cell in the proper     * location in the table structure.     */    renderChildren: function() {        var me = this,            items = me.getLayoutItems(),            tbody = me.owner.getTargetEl().child('table', true).tBodies[0],            rows = tbody.rows,            i = 0,            len = items.length,            cells, curCell, rowIdx, cellIdx, item, trEl, tdEl, itemCt;        // Calculate the correct cell structure for the current items        cells = me.calculateCells(items);        // Loop over each cell and compare to the current cells in the table, inserting/        // removing/moving cells as needed, and making sure each item is rendered into        // the correct cell.        for (; i < len; i++) {            curCell = cells[i];            rowIdx = curCell.rowIdx;            cellIdx = curCell.cellIdx;            item = items[i];            // If no row present, create and insert one            trEl = rows[rowIdx];            if (!trEl) {                trEl = tbody.insertRow(rowIdx);                if (me.trAttrs) {                    trEl.set(me.trAttrs);                }            }            // If no cell present, create and insert one            itemCt = tdEl = Ext.get(trEl.cells[cellIdx] || trEl.insertCell(cellIdx));            if (me.needsDivWrap()) { //create wrapper div if needed - see docs below                itemCt = tdEl.first() || tdEl.createChild({tag: 'div'});                itemCt.setWidth(null);            }            // Render or move the component into the cell            if (!item.rendered) {                me.renderItem(item, itemCt, 0);            }            else if (!me.isValidParent(item, itemCt, rowIdx, cellIdx, tbody)) {                me.moveItem(item, itemCt, 0);            }            // Set the cell properties            if (me.tdAttrs) {                tdEl.set(me.tdAttrs);            }            if (item.tdAttrs) {                tdEl.set(item.tdAttrs);            }            tdEl.set({                colSpan: item.colspan || 1,                rowSpan: item.rowspan || 1,                id: item.cellId || '',                cls: me.cellCls + ' ' + (item.cellCls || '')            });            // If at the end of a row, remove any extra cells            if (!cells[i + 1] || cells[i + 1].rowIdx !== rowIdx) {                cellIdx++;                while (trEl.cells[cellIdx]) {                    trEl.deleteCell(cellIdx);                }            }        }        // Delete any extra rows        rowIdx++;        while (tbody.rows[rowIdx]) {            tbody.deleteRow(rowIdx);        }    },    calculate: function (ownerContext) {        if (!ownerContext.hasDomProp('containerChildrenDone')) {            this.done = false;        } else {            var targetContext = ownerContext.targetContext,                widthShrinkWrap = ownerContext.widthModel.shrinkWrap,                heightShrinkWrap = ownerContext.heightModel.shrinkWrap,                shrinkWrap = heightShrinkWrap || widthShrinkWrap,                table = shrinkWrap && targetContext.el.child('table', true),                targetPadding = shrinkWrap && targetContext.getPaddingInfo();            if (widthShrinkWrap) {                ownerContext.setContentWidth(table.offsetWidth + targetPadding.width, true);            }            if (heightShrinkWrap) {                ownerContext.setContentHeight(table.offsetHeight + targetPadding.height, true);            }        }    },    finalizeLayout: function() {        if (this.needsDivWrap()) {            // set wrapper div width to match layed out item - see docs below            var items = this.getLayoutItems(),                i,                iLen  = items.length,                item;            for (i = 0; i < iLen; i++) {                item = items[i];                Ext.fly(item.el.dom.parentNode).setWidth(item.getWidth());            }        }        if (Ext.isIE6 || (Ext.isIEQuirks)) {            // Fixes an issue where the table won't paint            this.owner.getTargetEl().child('table').repaint();        }    },<span id='Ext-layout-container-Table-method-calculateCells'>    /**</span>     * @private     * Determine the row and cell indexes for each component, taking into consideration     * the number of columns and each item's configured colspan/rowspan values.     * @param {Array} items The layout components     * @return {Object[]} List of row and cell indexes for each of the components     */    calculateCells: function(items) {        var cells = [],            rowIdx = 0,            colIdx = 0,            cellIdx = 0,            totalCols = this.columns || Infinity,            rowspans = [], //rolling list of active rowspans for each column            i = 0, j,            len = items.length,            item;        for (; i < len; i++) {            item = items[i];            // Find the first available row/col slot not taken up by a spanning cell            while (colIdx >= totalCols || rowspans[colIdx] > 0) {                if (colIdx >= totalCols) {                    // move down to next row                    colIdx = 0;                    cellIdx = 0;                    rowIdx++;                    // decrement all rowspans                    for (j = 0; j < totalCols; j++) {                        if (rowspans[j] > 0) {                            rowspans[j]--;                        }                    }                } else {                    colIdx++;                }            }            // Add the cell info to the list            cells.push({                rowIdx: rowIdx,                cellIdx: cellIdx            });            // Increment            for (j = item.colspan || 1; j; --j) {                rowspans[colIdx] = item.rowspan || 1;                ++colIdx;            }            ++cellIdx;        }        return cells;    },    getRenderTree: function() {        var me = this,            items = me.getLayoutItems(),            cells,            rows = [],            result = Ext.apply({                tag: 'table',                role: 'presentation',                cls: me.tableCls,                cellspacing: 0,                cn: {                    tag: 'tbody',                    cn: rows                }            }, me.tableAttrs),            tdAttrs = me.tdAttrs,            needsDivWrap = me.needsDivWrap(),            i, len = items.length, item, curCell, tr, rowIdx, cellIdx, cell;        // Calculate the correct cell structure for the current items        cells = me.calculateCells(items);        for (i = 0; i < len; i++) {            item = items[i];                        curCell = cells[i];            rowIdx = curCell.rowIdx;            cellIdx = curCell.cellIdx;            // If no row present, create and insert one            tr = rows[rowIdx];            if (!tr) {                tr = rows[rowIdx] = {                    tag: 'tr',                    cn: []                };                if (me.trAttrs) {                    Ext.apply(tr, me.trAttrs);                }            }            // If no cell present, create and insert one            cell = tr.cn[cellIdx] = {                tag: 'td'            };            if (tdAttrs) {                Ext.apply(cell, tdAttrs);            }            Ext.apply(cell, {                colSpan: item.colspan || 1,                rowSpan: item.rowspan || 1,                id: item.cellId || '',                cls: me.cellCls + ' ' + (item.cellCls || '')            });            if (needsDivWrap) { //create wrapper div if needed - see docs below                cell = cell.cn = {                    tag: 'div'                };            }            me.configureItem(item);            // The DomHelper config of the item is the cell's sole child            cell.cn = item.getRenderTree();        }        return result;    },    isValidParent: function(item, target, rowIdx, cellIdx) {        var tbody,            correctCell,            table;        // If we were called with the 3 arg signature just check that the parent table of the item is within the render target        if (arguments.length === 3) {            table = item.el.up('table');            return table && table.dom.parentNode === target.dom;        }        tbody = this.owner.getTargetEl().child('table', true).tBodies[0];        correctCell = tbody.rows[rowIdx].cells[cellIdx];        return item.el.dom.parentNode === correctCell;    },<span id='Ext-layout-container-Table-method-needsDivWrap'>    /**</span>     * @private     * Opera 10.5 has a bug where if a table cell's child has box-sizing:border-box and padding, it     * will include that padding in the size of the cell, making it always larger than the     * shrink-wrapped size of its contents. To get around this we have to wrap the contents in a div     * and then set that div's width to match the item rendered within it afterLayout. This method     * determines whether we need the wrapper div; it currently does a straight UA sniff as this bug     * seems isolated to just Opera 10.5, but feature detection could be added here if needed.     */    needsDivWrap: function() {        return Ext.isOpera10_5;    }});</pre></body></html>
 |