1. #1
    Sencha User
    Join Date
    Mar 2010
    Posts
    83
    Vote Rating
    -1
    daiei27 is an unknown quantity at this point

      0  

    Exclamation [3.x, 3.2.0] RowExpander plugin UPDATED - August 10, 2010

    [3.x, 3.2.0] RowExpander plugin UPDATED - August 10, 2010


    History
    August 10, 2010
    - Added toolbar handling as an example to destroyNestedExtCmp (code below is highlighted in red)
    - Also, if you use the Header for RowExpander extension, see post #10 below...
    April 5, 2010
    - Initial release
    --

    NOTE to all RowExpander plugin users:
    If you use Ext components within expanded rows and are not aware of the memory leak issue, CHECK FOR THEM!


    As a quick check, add this link to your page and keep checking the value as you expand/collapse various components.
    Code:
    <a href="javascript: alert(Ext.ComponentMgr.all.length)" style="color:gray; font-size:smaller">Check ExtJS resources</a>
    --
    This update was made to address that issue, starting from Mikhail's modified RowExpander and running ExtJS 3.2.0.

    I added support to clean up any type of Ext component. I mainly added the cleanup of Ext Panels which covered most of my stuff (charts, etc.), but made it extremely easy for you to add any specific component needs of your own.

    The previous code did not clean up multiple components at the same level so I modified it to cover that scenario.

    It appears to work well in my simple tests (a grid with rows containing multiple charts and multiple grids, with those containing multiple charts and panels in them).

    Cheers,
    Chris

    --
    Attached and posted here:
    Code:
    /*!
     * Ext JS Library 3.2.0
     * Copyright(c) 2006-2009 Ext JS, LLC
     * licensing@extjs.com
     * http://www.extjs.com/license
     * 
     * Modifications by Mykhail Stadnik <http://mikhailstadnik.com>:
     *  - Nesting grids support added
     * Modifications by Chris Newman
     *  - 04/05/2010
     *    - Added support for Ext components in general
     *    - Added support for multiple components at the same level
     *    - Memory-leak fix for Panel-related components
     *      - NOTE: see destroyNestedExtCmp below for adding your own component handling
     *  - 08/10/2010
     *    - As an example, added toolbar to destroyNestedExtCmp
     */
    Ext.ns( 'Ext.ux.grid');
    
    /**
     * @class Ext.ux.grid.RowExpander
     * @extends Ext.util.Observable
     * Plugin (ptype = 'rowexpander') that adds the ability to have a Column in a grid which enables
     * a second row body which expands/contracts.  The expand/contract behavior is configurable to react
     * on clicking of the column, double click of the row, and/or hitting enter while a row is selected.
     *
     * @ptype rowexpander
     */
    Ext.ux.grid.RowExpander = Ext.extend( Ext.util.Observable, {
    
        /**
         * @cfg {Boolean} expandOnEnter
         * <tt>true</tt> to toggle selected row(s) between expanded/collapsed when the enter
         * key is pressed (defaults to <tt>true</tt>).
         */
        expandOnEnter : true,
    
        /**
         * @cfg {Boolean} expandOnDblClick
         * <tt>true</tt> to toggle a row between expanded/collapsed when double clicked
         * (defaults to <tt>true</tt>).
         */
        expandOnDblClick : true,
    
        header           : '',
        width            : 20,
        sortable         : false,
        fixed            : true,
        menuDisabled     : true,
        dataIndex        : '',
        id               : 'expander',
        lazyRender       : true,
        enableCaching    : true,
        actAsTree        : false,
        treeLeafProperty : 'is_leaf',
        appendRowClass   : true,
    
        constructor: function( config){
            if (!config.id) {
                config.id = Ext.id();
            }
    
            Ext.apply( this, config);
    
            var css =
                '.x-' + this.id + '-grid3-row-collapsed .x-grid3-row-expander { background-position:0 0; }' +
                '.x-' + this.id + '-grid3-row-expanded .x-grid3-row-expander { background-position:-25px 0; }' +
                '.x-' + this.id + '-grid3-row-collapsed .x-grid3-row-body { display:none !important; }' +
                '.x-' + this.id + '-grid3-row-expanded .x-grid3-row-body { display:block !important; }' +
                '.x-grid-expander-leaf .x-grid3-row-expander { background: none; }'
            ;
    
            Ext.util.CSS.createStyleSheet( css, Ext.id());
    
            this.expanderClass     = 'x-grid3-row-expander';
            this.rowExpandedClass  = 'x-' + this.id + '-grid3-row-expanded';
            this.rowCollapsedClass = 'x-' + this.id + '-grid3-row-collapsed';
            this.leafClass         = 'x-grid-expander-leaf';
    
            this.addEvents({
                /**
                 * @event beforeexpand
                 * Fires before the row expands. Have the listener return false to prevent the row from expanding.
                 * @param {Object} this RowExpander object.
                 * @param {Object} Ext.data.Record Record for the selected row.
                 * @param {Object} body body element for the secondary row.
                 * @param {Number} rowIndex The current row index.
                 */
                beforeexpand: true,
                /**
                 * @event expand
                 * Fires after the row expands.
                 * @param {Object} this RowExpander object.
                 * @param {Object} Ext.data.Record Record for the selected row.
                 * @param {Object} body body element for the secondary row.
                 * @param {Number} rowIndex The current row index.
                 */
                expand: true,
                /**
                 * @event beforecollapse
                 * Fires before the row collapses. Have the listener return false to prevent the row from collapsing.
                 * @param {Object} this RowExpander object.
                 * @param {Object} Ext.data.Record Record for the selected row.
                 * @param {Object} body body element for the secondary row.
                 * @param {Number} rowIndex The current row index.
                 */
                beforecollapse: true,
                /**
                 * @event collapse
                 * Fires after the row collapses.
                 * @param {Object} this RowExpander object.
                 * @param {Object} Ext.data.Record Record for the selected row.
                 * @param {Object} body body element for the secondary row.
                 * @param {Number} rowIndex The current row index.
                 */
                collapse: true
            });
    
            Ext.ux.grid.RowExpander.superclass.constructor.call(this);
    
            if(this.tpl){
                if(typeof this.tpl == 'string'){
                    this.tpl = new Ext.Template(this.tpl);
                }
                this.tpl.compile();
            }
    
            this.state = {};
            this.bodyContent = {};
        },
    
        getRowClass : function(record, rowIndex, p, ds){
            p.cols = p.cols-1;
            var content = this.bodyContent[record.id];
            if(!content && !this.lazyRender){
                content = this.getBodyContent(record, rowIndex);
            }
            if(content){
                p.body = content;
            }
            var cssClass = this.state[record.id] ? this.rowExpandedClass : this.rowCollapsedClass;
            if (this.actAsTree && record.get( this.treeLeafProperty)) {
                cssClass = this.leafClass;
            }
            return cssClass;
        },
    
        init : function(grid){
            this.grid = grid;
    
            var view = grid.getView();
            view.getRowClass = this.getRowClass.createDelegate( this);
    
            view.enableRowBody = true;
    
            grid.on( 'render',        this.onRender,        this);
            grid.on( 'destroy',       this.onDestroy,       this);
    
            view.on( 'beforerefresh', this.onBeforeRefresh, this);
            view.on( 'refresh',       this.onRefresh,       this);
        },
    
        // @private
        onRender: function() {
            var grid = this.grid;
            var mainBody = grid.getView().mainBody;
            mainBody && mainBody.on( 'mousedown', this.onMouseDown, this, {delegate: '.' + this.expanderClass});
            if (this.expandOnEnter) {
                this.keyNav = new Ext.KeyNav(this.grid.getGridEl(), {
                    'enter' : this.onEnter,
                    scope: this
                });
            }
            if (this.expandOnDblClick) {
                grid.on('rowdblclick', this.onRowDblClick, this);
            }
            if (this.actAsTree) {
                /**
                 * Stop bubbling parent events 
                 */
                grid.getEl().swallowEvent([ 'mouseover', 'mouseout', 'mousedown', 'click', 'dblclick' ]);
            }
        },
    
        // @private
        onBeforeRefresh : function() {
            var rows = this.grid.getEl().select( '.' + this.rowExpandedClass);
            rows.each( function( row) {
                this.collapseRow( row.dom);
            }, this);
        },
    
        // @private
        onRefresh : function() {
            var rows = this.grid.getEl().select( '.' + this.rowExpandedClass);
            rows.each( function( row) {
                Ext.fly( row).replaceClass( this.rowExpandedClass, this.rowCollapsedClass);
            }, this);
        },
    
        // @private    
        onDestroy: function() {
            this.keyNav.disable();
            delete this.keyNav;
            var mainBody = this.grid.getView().mainBody;
            mainBody && mainBody.un( 'mousedown', this.onMouseDown, this);
        },
    
        // @private
        onRowDblClick: function( grid, rowIdx, e) {
            this.toggleRow(rowIdx);
        },
    
        onEnter: function( e) {
            var g = this.grid;
            var sm = g.getSelectionModel();
            var sels = sm.getSelections();
            for (var i = 0, len = sels.length; i < len; i++) {
                var rowIdx = g.getStore().indexOf(sels[i]);
                this.toggleRow(rowIdx);
            }
        },
    
        getBodyContent : function( record, index){
            if (!this.enableCaching) {
                return this.tpl.apply( record.data);
            }
            var content = this.bodyContent[record.id];
            if (!content){
                content = this.tpl.apply( record.data);
                this.bodyContent[record.id] = content;
            }
            return content;
        },
    
        onMouseDown : function(e, t){
            e.stopEvent();
            var row = e.getTarget( '.x-grid3-row');
            this.toggleRow(row);
        },
    
        renderer : function(v, p, record){
            p.cellAttr = 'rowspan="2"';
            return '<div class="' + this.expanderClass + '"> </div>';
        },
    
        beforeExpand : function(record, body, rowIndex){
            if(this.fireEvent('beforeexpand', this, record, body, rowIndex) !== false){
                if(this.tpl && this.lazyRender){
                    body.innerHTML = this.getBodyContent(record, rowIndex);
                }
                return true;
            }else{
                return false;
            }
        },
    
        toggleRow : function(row){
            if(typeof row == 'number'){
                row = this.grid.view.getRow(row);
            }
            if (Ext.fly(row).hasClass( this.leafClass)) {
                return ;
            }
            this[Ext.fly(row).hasClass( this.rowCollapsedClass) ? 'expandRow' : 'collapseRow'](row);
        },
    
        expandRow : function( row){
            if(typeof row == 'number'){
                row = this.grid.view.getRow( row);
            }
            if (Ext.fly(row).hasClass( this.leafClass)) {
                return ;
            }
            var record = this.grid.store.getAt( row.rowIndex);
            var body = Ext.DomQuery.selectNode( 'tr:nth(2) div.x-grid3-row-body', row);
            if (this.beforeExpand(record, body, row.rowIndex)){
                this.state[record.id] = true;
                Ext.fly( row).replaceClass( this.rowCollapsedClass, this.rowExpandedClass);
                this.fireEvent( 'expand', this, record, body, row.rowIndex);
            }
        },
    
        /**
         * Avoid memory leaks by destroying all nested grids recursively
         * - Added handling of multiple children and panels (for charts)
         * @param {Ext.Element} - grid element to destroy
         */
        destroyNestedExtCmp : function( gridRow) {
            var gridEl;
            var bSearch = 1;
            while (bSearch) {
                bSearch = 0;
                // Grids
                if (gridEl = gridRow.child('.x-grid-panel')) {
                    this.destroyNestedExtCmp( gridEl);
                    var grid = Ext.getCmp( gridEl.id);
                    if (grid && (grid != this.grid)) {
                        if (grid instanceof Ext.grid.EditorGridPanel) {
                            var cm = grid.getColumnModel();
                            for (var i = 0, s = cm.getColumnCount(); i < s; i++) {
                                for (var ii = 0, ss = grid.getStore().getCount(); ii < ss; ii++) {
                                    if (editor = cm.getCellEditor( i, ii)) {
                                        editor.destroy();
                                    }
                                }
                            }
                                cm.destroy();
                            }
                        grid.destroy();
                        bSearch = 1;
                    }
                }
                // Panels, toolbars, etc.
                // (x-panel covers many other components that come wrapped in panels, including charts)
                if ((gridEl = gridRow.child('.x-panel')) ||
                    (gridEl = gridRow.child('.x-toolbar')) ) {  // <-- Add simple ExtJS component here
                    var cmp = Ext.getCmp( gridEl.id); // Grab component
                    cmp.destroy(); // Destroy component
                    bSearch = 1; // Search for more
                }
                /**
                ***  ADD more complex ExtJS component handling requirements here!!!
                **/
            } ;// end while - Ext components are found
        },
    
        collapseRow : function( row){
            if (typeof row == 'number'){
                row = this.grid.view.getRow( row);
            }
            if (Ext.fly( row).hasClass( this.leafClass)) {
                return ;
            }
            var record = this.grid.store.getAt( row.rowIndex);
            var body = Ext.fly( row).child( 'tr:nth(1) div.x-grid3-row-body', true);
            if (this.fireEvent( 'beforecollapse', this, record, body, row.rowIndex) !== false) {
                this.destroyNestedExtCmp( Ext.get( row));
                if (record) this.state[record.id] = false;
                Ext.fly( row).replaceClass( this.rowExpandedClass, this.rowCollapsedClass);
                this.fireEvent( 'collapse', this, record, body, row.rowIndex);
            }
        }
    });
    
    Ext.preg( 'rowexpander', Ext.ux.grid.RowExpander);
    
    //backwards compatibility
    Ext.grid.RowExpander = Ext.ux.grid.RowExpander;
    Attached Files

  2. #2
    Sencha User
    Join Date
    Mar 2010
    Posts
    83
    Vote Rating
    -1
    daiei27 is an unknown quantity at this point

      0  

    Default


    Hmm.. looks like the view count on the zip file resets when I update it. Anyways...

    For those that downloaded, any issues/updates?

  3. #3
    Sencha User
    Join Date
    Nov 2007
    Posts
    294
    Vote Rating
    0
    Sesshomurai is on a distinguished road

      0  

    Default


    I'll try this when I get home. I use an old version. But one question I had was. How easy would it be to modify it so it can load content into the expanded section via some ajax call? Any tips before I start coding that?

    thanks and nice work.

  4. #4
    Ext User
    Join Date
    Jan 2010
    Posts
    20
    Vote Rating
    0
    lingz_public is on a distinguished road

      0  

    Default


    Thanks daiei, will check my expander...
    Just curious whether you are successful to put one gridpanel inside expander? The problem is that the internal gridpanel behaves wired, and also triger collapse of outside gridpanel.
    If you have a workable example for this, would be great!

  5. #5
    Sencha User
    Join Date
    Mar 2010
    Posts
    83
    Vote Rating
    -1
    daiei27 is an unknown quantity at this point

      0  

    Default


    Sorry. Somehow I missed these posts...

    Quote Originally Posted by Sesshomurai View Post
    I'll try this when I get home. I use an old version. But one question I had was. How easy would it be to modify it so it can load content into the expanded section via some ajax call? Any tips before I start coding that?

    thanks and nice work.
    I load some stuff via AJAX, but mostly it's taking advantage of the AJAX mechanisms of the stores linked to my nested grids. For your problem, sounds like you just have to make your own AJAX call in the listeners property.
    Code:
        var resultExpander = new xg.RowExpander({
            actAsTree        : true,
            treeLeafProperty : 'is_leaf',
            listeners        : {
                expand : function( expander, record, body, rowIndex) {
                    // YOUR AJAX FUNCTION HERE
                    showTcResults(record.data.id,record.data.testcase); // loads my nested grids
                }
            },
            tpl : new Ext.Template(
                '<div class="dropdown ux-row-expander-box">',
                '  <div style="color:red; font-weight:bold">What sort of result info you want here?</div><br />',
                '  <div class="heading">Result files</div>',
                '  <div class="body">{resultfiles}</div>',
                '  <div class="heading">Detailed results</div>',
                '  <div class="body" id="results_tc_{id}"></div>',
                '  <div class="body" id="results_tc_graph_{id}"></div>',
                '</div>'
            )
        }); // end resultExpander
    That's a snippet from my code to give you an idea of where to put it.

    Quote Originally Posted by lingz_public View Post
    Thanks daiei, will check my expander...
    Just curious whether you are successful to put one gridpanel inside expander? The problem is that the internal gridpanel behaves wired, and also triger collapse of outside gridpanel.
    If you have a workable example for this, would be great!
    Unfortunately I do not have a demo I can post online, but this does work. I needed (or I should say REALLY WANTED ) a gridpanel nested within a rowExpander. Mikhail had the closest thing to it with some minor issues. That's why I took his code and expanded on it to get rid of the remaining memory leaks (that I saw) and to allow things like charts and other types of panels.

  6. #6
    Sencha User
    Join Date
    Mar 2010
    Posts
    83
    Vote Rating
    -1
    daiei27 is an unknown quantity at this point

      0  

    Default


    I should mention I searched all over the place for this sort of functionality. RowPanelExpander appeared to be the closest thing, but it did not handle a lot of the nesting issues that Mikhail led the charge on sorting out. If anyone finds a better solution, I'd be more than happy to hear it!

    Patches and improvements for RowExpander plugin are also welcome!

  7. #7
    Sencha User
    Join Date
    Jan 2009
    Posts
    18
    Vote Rating
    0
    mjmonserrat is on a distinguished road

      0  

    Default


    How to add Form on RowExpander wherein the text boxes and the check boxes inside the form serves as the Row Editor?

  8. #8
    Ext User
    Join Date
    Dec 2009
    Posts
    18
    Vote Rating
    0
    cq.yangyu@gmail.com is on a distinguished road

      0  

    Default


    Is there a demo for us ?

  9. #9
    Sencha User
    Join Date
    Mar 2010
    Posts
    83
    Vote Rating
    -1
    daiei27 is an unknown quantity at this point

      0  

    Default


    Quote Originally Posted by mjmonserrat View Post
    How to add Form on RowExpander wherein the text boxes and the check boxes inside the form serves as the Row Editor?
    You can tackle that all sorts of ways. You could actually create some sort of custom form in the RowExpander and update your stores as users apply changes, but it sounds like you may just want a RowEditor sort of plugin?
    Quote Originally Posted by cq.yangyu@gmail.com View Post
    Is there a demo for us ?
    See post #5.

  10. #10
    Sencha User
    Join Date
    Mar 2010
    Posts
    83
    Vote Rating
    -1
    daiei27 is an unknown quantity at this point

      0  

    Default Header for RowExpander extension

    Header for RowExpander extension


    If you use the Header for RowExpander extension, I found a memory leak when you open a row, then expand all rows. On expansion, the row's objects appear to be recreated, but the previous ones not properly destroyed.

    Here's my code with the fix in red:
    Code:
    = new xg.RowExpander({
                header: '<div class="x-grid3-hd-row-expander" style="display:inline;padding-left:18px;margin-left: -1px;"> </div>',
                // Override init function to add on header click behavior
                init : xg.RowExpander.prototype.init.createSequence(function(grid) {
                    grid.on('render', function() {
                        // add on header click behavior
                        Ext.fly(grid.getView().innerHd).on('mousedown', this.onHdMouseDown, this);
                        grid.getStore().on('load', function() {
                            var hdEl = Ext.fly(grid.getView().innerHd).child('div.x-grid3-hd-expander');
                            if (hdEl && hdEl.hasClass('x-grid3-hd-expanded')) {
                                hdEl.replaceClass('x-grid3-hd-expanded', 'x-grid3-hd-collapsed');
                            }
                        }, this);
                    }, this);
                }),
                // process on header click event
                onHdMouseDown : function(e, t) {
                    if (t.className == 'x-grid3-hd-row-expander') {
                        e.stopEvent();
                        var hd = Ext.fly(t.parentNode);
                        var isChecked = hd.hasClass('x-grid3-hd-expanded');
                        if (isChecked) {
                            hd.replaceClass('x-grid3-hd-expanded', 'x-grid3-hd-collapsed');
                            this.collapseAll();
                        } else {
                            var mask = new Ext.LoadMask(this.grid.id);
                            mask.show();
                            hd.replaceClass('x-grid3-hd-collapsed', 'x-grid3-hd-expanded');
                            var thisVar = this;
                            function expandRows () {
                                thisVar.expandAll();
                                mask.hide();
                            }
                            setTimeout(expandRows, 100);
                        }
                    }
                },
                // Expand all rows
                expandAll : function() {
                    for (var i = 0; i < this.grid.getStore().getCount(); i++) {
                        this.collapseRow(i);// workaround to prevent memory leak from expanding an expanded row
                        this.expandRow(i);
                    }
                },
                // Collapse all rows
                collapseAll : function() {
                    for (var i = 0; i < this.grid.getStore().getCount(); i++) {
                        this.collapseRow(i);
                    }
                },
                // For DUT-DP table
                listeners : {
                    expand : function( expander, record, body, rowIndex) {
                        showSesToolbar(record.data.session);
                    }
                },
                tpl : new Ext.Template(
                    '<div class="dropdown">',
                    '  <div id="toolbar_{session}"></div><br />',
                    '</div>'
                )
            })
    Expansion took a while before adding the additional collapse anyways so I added a mask while it loads. If you find that useful, look for the code in blue.

film izle

hd film izle

film sitesi

takipci kazanma sitesi

takipci kazanma sitesi

güzel olan herşey

takipci alma sitesi

komik eğlenceli videolar