/** * @class Ext.ListView * @extends Ext.DataView *

Ext.ListView is a fast and light-weight implentation of a * {@link Ext.grid.GridPanel Grid} like view with the following characteristics:

*
*

Example usage:

*

// consume JSON of this form:
{
   "images":[
      {
         "name":"dance_fever.jpg",
         "size":2067,
         "lastmod":1236974993000,
         "url":"images\/thumbs\/dance_fever.jpg"
      },
      {
         "name":"zack_sink.jpg",
         "size":2303,
         "lastmod":1236974993000,
         "url":"images\/thumbs\/zack_sink.jpg"
      }
   ]
} 
var store = new Ext.data.JsonStore({
    url: 'get-images.php',
    root: 'images',
    fields: [
        'name', 'url',
        {name:'size', type: 'float'},
        {name:'lastmod', type:'date', dateFormat:'timestamp'}
    ]
});
store.load();

var listView = new Ext.ListView({
    store: store,
    multiSelect: true,
    emptyText: 'No images to display',
    reserveScrollOffset: true,
    columns: [{
        header: 'File',
        width: .5,
        dataIndex: 'name'
    },{
        header: 'Last Modified',
        width: .35, 
        dataIndex: 'lastmod',
        tpl: '{lastmod:date("m-d h:i a")}'
    },{
        header: 'Size',
        dataIndex: 'size',
        tpl: '{size:fileSize}', // format using Ext.util.Format.fileSize()
        align: 'right'
    }]
});

// put it in a Panel so it looks pretty
var panel = new Ext.Panel({
    id:'images-view',
    width:425,
    height:250,
    collapsible:true,
    layout:'fit',
    title:'Simple ListView (0 items selected)',
    items: listView
});
panel.render(document.body);

// little bit of feedback
listView.on('selectionchange', function(view, nodes){
    var l = nodes.length;
    var s = l != 1 ? 's' : '';
    panel.setTitle('Simple ListView ('+l+' item'+s+' selected)');
});
 * 
* @constructor * @param {Object} config * @xtype listview */ Ext.ListView = Ext.extend(Ext.DataView, {
/** * Set this property to true to disable the header click handler disabling sort * (defaults to false). * @type Boolean * @property disableHeaders */
/** * @cfg {Boolean} hideHeaders * true to hide the {@link #internalTpl header row} (defaults to false so * the {@link #internalTpl header row} will be shown). */
/** * @cfg {String} itemSelector * Defaults to 'dl' to work with the preconfigured {@link Ext.DataView#tpl tpl}. * This setting specifies the CSS selector (e.g. div.some-class or span:first-child) * that will be used to determine what nodes the ListView will be working with. */ itemSelector: 'dl',
/** * @cfg {String} selectedClass The CSS class applied to a selected row (defaults to * 'x-list-selected'). An example overriding the default styling:

    .x-list-selected {background-color: yellow;}
    
* @type String */ selectedClass:'x-list-selected',
/** * @cfg {String} overClass The CSS class applied when over a row (defaults to * 'x-list-over'). An example overriding the default styling:

    .x-list-over {background-color: orange;}
    
* @type String */ overClass:'x-list-over',
/** * @cfg {Boolean} reserveScrollOffset * By default will defer accounting for the configured {@link #scrollOffset} * for 10 milliseconds. Specify true to account for the configured * {@link #scrollOffset} immediately. */
/** * @cfg {Number} scrollOffset The amount of space to reserve for the scrollbar (defaults to * 19 pixels) */ scrollOffset : 19,
/** * @cfg {Boolean/Object} columnResize * Specify true or specify a configuration object for {@link Ext.ListView.ColumnResizer} * to enable the columns to be resizable (defaults to true). */ columnResize: true,
/** * @cfg {Array} columns An array of column configuration objects, for example: *

{
    align: 'right',
    dataIndex: 'size',
    header: 'Size',
    tpl: '{size:fileSize}',
    width: .35
}
     * 
* Acceptable properties for each column configuration object are: *
*/
/** * @cfg {Boolean/Object} columnSort * Specify true or specify a configuration object for {@link Ext.ListView.Sorter} * to enable the columns to be sortable (defaults to true). */ columnSort: true,
/** * @cfg {String/Array} internalTpl * The template to be used for the header row. See {@link #tpl} for more details. */ initComponent : function(){ if(this.columnResize){ this.colResizer = new Ext.ListView.ColumnResizer(this.colResizer); this.colResizer.init(this); } if(this.columnSort){ this.colSorter = new Ext.ListView.Sorter(this.columnSort); this.colSorter.init(this); } if(!this.internalTpl){ this.internalTpl = new Ext.XTemplate( '
', '', '
', '{header}', '
', '
', '
', '
', '
', '
' ); } if(!this.tpl){ this.tpl = new Ext.XTemplate( '', '
', '', '
', '{[values.tpl.apply(parent)]}', '
', '
', '
', '
', '
' ); }; var cs = this.columns, allocatedWidth = 0, colsWithWidth = 0, len = cs.length; for(var i = 0; i < len; i++){ var c = cs[i]; if(!c.tpl){ c.tpl = new Ext.XTemplate('{' + c.dataIndex + '}'); }else if(Ext.isString(c.tpl)){ c.tpl = new Ext.XTemplate(c.tpl); } c.align = c.align || 'left'; if(Ext.isNumber(c.width)){ c.width *= 100; allocatedWidth += c.width; colsWithWidth++; } } // auto calculate missing column widths if(colsWithWidth < len){ var remaining = len - colsWithWidth; if(allocatedWidth < 100){ var perCol = ((100-allocatedWidth) / remaining); for(var j = 0; j < len; j++){ var c = cs[j]; if(!Ext.isNumber(c.width)){ c.width = perCol; } } } } Ext.ListView.superclass.initComponent.call(this); }, onRender : function(){ Ext.ListView.superclass.onRender.apply(this, arguments); this.internalTpl.overwrite(this.el, {columns: this.columns}); this.innerBody = Ext.get(this.el.dom.childNodes[1].firstChild); this.innerHd = Ext.get(this.el.dom.firstChild.firstChild); if(this.hideHeaders){ this.el.dom.firstChild.style.display = 'none'; } }, getTemplateTarget : function(){ return this.innerBody; },
/** *

Function which can be overridden which returns the data object passed to this * view's {@link #tpl template} to render the whole ListView. The returned object * shall contain the following properties:

*
* @param {Array} records An Array of {@link Ext.data.Record}s to be rendered into the DataView. * @param {Number} startIndex the index number of the Record being prepared for rendering. * @return {Object} A data object containing properties to be processed by a repeating * XTemplate as described above. */ collectData : function(){ var rs = Ext.ListView.superclass.collectData.apply(this, arguments); return { columns: this.columns, rows: rs } }, verifyInternalSize : function(){ if(this.lastSize){ this.onResize(this.lastSize.width, this.lastSize.height); } }, // private onResize : function(w, h){ var bd = this.innerBody.dom; var hd = this.innerHd.dom if(!bd){ return; } var bdp = bd.parentNode; if(Ext.isNumber(w)){ var sw = w - this.scrollOffset; if(this.reserveScrollOffset || ((bdp.offsetWidth - bdp.clientWidth) > 10)){ bd.style.width = sw + 'px'; hd.style.width = sw + 'px'; }else{ bd.style.width = w + 'px'; hd.style.width = w + 'px'; setTimeout(function(){ if((bdp.offsetWidth - bdp.clientWidth) > 10){ bd.style.width = sw + 'px'; hd.style.width = sw + 'px'; } }, 10); } } if(Ext.isNumber(h == 'number')){ bdp.style.height = (h - hd.parentNode.offsetHeight) + 'px'; } }, updateIndexes : function(){ Ext.ListView.superclass.updateIndexes.apply(this, arguments); this.verifyInternalSize(); }, findHeaderIndex : function(hd){ hd = hd.dom || hd; var pn = hd.parentNode, cs = pn.parentNode.childNodes; for(var i = 0, c; c = cs[i]; i++){ if(c == pn){ return i; } } return -1; }, setHdWidths : function(){ var els = this.innerHd.dom.getElementsByTagName('div'); for(var i = 0, cs = this.columns, len = cs.length; i < len; i++){ els[i].style.width = cs[i].width + '%'; } } }); Ext.reg('listview', Ext.ListView);