/* * Ext JS Library 1.0.1 * Copyright(c) 2006-2007, Ext JS, LLC. * licensing@extjs.com * * http://www.extjs.com/license */ /** * @class Ext.grid.Grid * @extends Ext.util.Observable * This class represents the primary interface of a component based grid control. *

Usage:

 var grid = new Ext.grid.Grid("my-container-id", {
     ds: myDataStore,
     cm: myColModel,
     selModel: mySelectionModel,
     autoSizeColumns: true,
     monitorWindowResize: false,
     trackMouseOver: true
 });
 // set any options
 grid.render();
 * 
* Common Problems:
* - Grid does not resize properly when going smaller: Setting overflow hidden on the container * element will correct this
* - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element * dimensions. The grid adapts to your container's size, if your container has no size defined then the results * are unpredictable.
* - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the * grid to calculate dimensions/offsets.
* @constructor * @param {String/HTMLElement/Ext.Element} container The element into which this grid will be rendered - * The container MUST have some type of size defined for the grid to fill. The container will be * automatically set to position relative if it isn't already. * @param {Object} config A config object that sets properties on this grid. */ Ext.grid.Grid = function(container, config){ // initialize the container this.container = Ext.get(container); this.container.update(""); this.container.setStyle("overflow", "hidden"); this.container.addClass('x-grid-container'); this.id = this.container.id; Ext.apply(this, config); // check and correct shorthanded configs if(this.ds){ this.dataSource = this.ds; delete this.ds; } if(this.cm){ this.colModel = this.cm; delete this.cm; } if(this.sm){ this.selModel = this.sm; delete this.sm; } if(this.width){ this.container.setWidth(this.width); } if(this.height){ this.container.setHeight(this.height); } /** @private */ this.addEvents({ // raw events /** * @event click * The raw click event for the entire grid. * @param {Ext.EventObject} e */ "click" : true, /** * @event dblclick * The raw dblclick event for the entire grid. * @param {Ext.EventObject} e */ "dblclick" : true, /** * @event contextmenu * The raw contextmenu event for the entire grid. * @param {Ext.EventObject} e */ "contextmenu" : true, /** * @event mousedown * The raw mousedown event for the entire grid. * @param {Ext.EventObject} e */ "mousedown" : true, /** * @event mouseup * The raw mouseup event for the entire grid. * @param {Ext.EventObject} e */ "mouseup" : true, /** * @event mouseover * The raw mouseover event for the entire grid. * @param {Ext.EventObject} e */ "mouseover" : true, /** * @event mouseout * The raw mouseout event for the entire grid. * @param {Ext.EventObject} e */ "mouseout" : true, /** * @event keypress * The raw keypress event for the entire grid. * @param {Ext.EventObject} e */ "keypress" : true, /** * @event keydown * The raw keydown event for the entire grid. * @param {Ext.EventObject} e */ "keydown" : true, // custom events /** * @event cellclick * Fires when a cell is clicked * @param {Grid} this * @param {Number} rowIndex * @param {Number} columnIndex * @param {Ext.EventObject} e */ "cellclick" : true, /** * @event celldblclick * Fires when a cell is double clicked * @param {Grid} this * @param {Number} rowIndex * @param {Number} columnIndex * @param {Ext.EventObject} e */ "celldblclick" : true, /** * @event rowclick * Fires when a row is clicked * @param {Grid} this * @param {Number} rowIndex * @param {Ext.EventObject} e */ "rowclick" : true, /** * @event rowdblclick * Fires when a row is double clicked * @param {Grid} this * @param {Number} rowIndex * @param {Ext.EventObject} e */ "rowdblclick" : true, /** * @event headerclick * Fires when a header is clicked * @param {Grid} this * @param {Number} columnIndex * @param {Ext.EventObject} e */ "headerclick" : true, /** * @event headerdblclick * Fires when a header cell is double clicked * @param {Grid} this * @param {Number} rowIndex * @param {Number} columnIndex * @param {Ext.EventObject} e */ "headerdblclick" : true, /** * @event rowcontextmenu * Fires when a row is right clicked * @param {Grid} this * @param {Number} rowIndex * @param {Ext.EventObject} e */ "rowcontextmenu" : true, /** * @event cellcontextmenu * Fires when a cell is right clicked * @param {Grid} this * @param {Number} rowIndex * @param {Number} cellIndex * @param {Ext.EventObject} e */ "cellcontextmenu" : true, /** * @event headercontextmenu * Fires when a header is right clicked * @param {Grid} this * @param {Number} columnIndex * @param {Ext.EventObject} e */ "headercontextmenu" : true, /** * @event bodyscroll * Fires when the body element is scrolled * @param {Number} scrollLeft * @param {Number} scrollTop */ "bodyscroll" : true, /** * @event columnresize * Fires when the user resizes a column * @param {Number} columnIndex * @param {Number} newSize */ "columnresize" : true, /** * @event columnmove * Fires when the user moves a column * @param {Number} oldIndex * @param {Number} newIndex */ "columnmove" : true, /** * @event startdrag * Fires when row(s) start being dragged * @param {Grid} this * @param {Ext.GridDD} dd The drag drop object * @param {event} e The raw browser event */ "startdrag" : true, /** * @event enddrag * Fires when a drag operation is complete * @param {Grid} this * @param {Ext.GridDD} dd The drag drop object * @param {event} e The raw browser event */ "enddrag" : true, /** * @event dragdrop * Fires when dragged row(s) are dropped on a valid DD target * @param {Grid} this * @param {Ext.GridDD} dd The drag drop object * @param {String} targetId The target drag drop object * @param {event} e The raw browser event */ "dragdrop" : true, /** * @event dragover * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over. * @param {Grid} this * @param {Ext.GridDD} dd The drag drop object * @param {String} targetId The target drag drop object * @param {event} e The raw browser event */ "dragover" : true, /** * @event dragenter * Fires when the dragged row(s) first cross another DD target while being dragged * @param {Grid} this * @param {Ext.GridDD} dd The drag drop object * @param {String} targetId The target drag drop object * @param {event} e The raw browser event */ "dragenter" : true, /** * @event dragout * Fires when the dragged row(s) leave another DD target while being dragged * @param {Grid} this * @param {Ext.GridDD} dd The drag drop object * @param {String} targetId The target drag drop object * @param {event} e The raw browser event */ "dragout" : true }); Ext.grid.Grid.superclass.constructor.call(this); }; Ext.extend(Ext.grid.Grid, Ext.util.Observable, { /** * @cfg {Number} The minimum width a column can be resized to. Defaults to 25. */ minColumnWidth : 25, /** * @cfg {Boolean} True to automatically resize the columns to fit their content * on initial render. It is more efficient to explicitly size the columns * through the ColumnModel's {@link Ext.grid.ColumnModel#width} config option. */ autoSizeColumns : false, /** * @cfg {Boolean} True to measure headers with column data when auto sizing columns. */ autoSizeHeaders : true, /** * @cfg {Boolean} True to autoSize the grid when the window resizes. Defaults to true. */ monitorWindowResize : true, /** * @cfg {Boolean} If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of * rows measured to get a columns size - defaults to 0 (all rows). */ maxRowsToMeasure : 0, /** * @cfg {Boolean} True to highlight rows when the mouse is over. Default is false. */ trackMouseOver : true, /** * @cfg {Boolean} True to enable drag and drop of rows. */ enableDragDrop : false, /** * @cfg {Boolean} True to enable drag and drop reorder of columns. */ enableColumnMove : true, /** * @cfg {Boolean} True to enable hiding of columns with the header context menu. */ enableColumnHide : true, /** * @cfg {Boolean} True to manually sync row heights across locked and not locked rows. */ enableRowHeightSync : false, /** * @cfg {Boolean} True to stripe the rows. Default is true. */ stripeRows : true, /** * @cfg {Boolean} True to fit the height of the grid container to the height of the data. Defaults to false. */ autoHeight : false, /** * @cfg {String} The id of a column in this grid that should expand to fill unused space. */ autoExpandColumn : false, /** * @cfg {Number} The minimum width the autoExpandColumn can have (if enabled). * defaults to 50. */ autoExpandMin : 50, /** * @cfg {Number} The maximum width the autoExpandColumn can have (if enabled). Defaults to 1000. */ autoExpandMax : 1000, /** * @cfg {Object} The {@link Ext.grid.GridView} used by the grid. This can be set before a call to render(). */ view : null, /** * @cfg {Object} A javascript RegExp defining tagNames * allowed to have text selection (Defaults to /INPUT|TEXTAREA|SELECT/i). */ allowTextSelectionPattern : /INPUT|TEXTAREA|SELECT/i, /** * @cfg {Object} An {@link Ext.LoadMask} config or true to mask the grid while loading (defaults to false). */ loadMask : false, // private rendered : false, /** * Sets the maximum height of the grid - ignored if autoHeight is not on. * @type Number */ /** * Called once after all setup has been completed and the grid is ready to be rendered. * @return {Ext.grid.Grid} this */ render : function(){ var c = this.container; // try to detect autoHeight/width mode if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){ this.autoHeight = true; } var view = this.getView(); view.init(this); c.on("click", this.onClick, this); c.on("dblclick", this.onDblClick, this); c.on("contextmenu", this.onContextMenu, this); c.on("keydown", this.onKeyDown, this); this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]); this.getSelectionModel().init(this); view.render(); if(this.loadMask){ this.loadMask = new Ext.LoadMask(this.container, Ext.apply({store:this.dataSource}, this.loadMask)); } this.rendered = true; return this; }, reconfigure : function(dataSource, colModel){ if(this.loadMask){ this.loadMask.destroy(); this.loadMask = new Ext.LoadMask(this.container, Ext.apply({store:dataSource}, this.loadMask)); } this.view.bind(dataSource, colModel); this.dataSource = dataSource; this.colModel = colModel; this.view.refresh(true); }, onKeyDown : function(e){ this.fireEvent("keydown", e); }, /** * Destroy this grid. * @param {Boolean} removeEl True to remove the element */ destroy : function(removeEl, keepListeners){ if(this.loadMask){ this.loadMask.destroy(); } var c = this.container; c.removeAllListeners(); this.view.destroy(); this.colModel.purgeListeners(); if(!keepListeners){ this.purgeListeners(); } c.update(""); if(removeEl === true){ c.remove(); } }, // private processEvent : function(name, e){ this.fireEvent(name, e); var t = e.getTarget(); var v = this.view; var header = v.findHeaderIndex(t); if(header !== false){ this.fireEvent("header" + name, this, header, e); }else{ var row = v.findRowIndex(t); var cell = v.findCellIndex(t); if(row !== false){ this.fireEvent("row" + name, this, row, e); if(cell !== false){ this.fireEvent("cell" + name, this, row, cell, e); } } } }, // private onClick : function(e){ this.processEvent("click", e); }, // private onContextMenu : function(e, t){ this.processEvent("contextmenu", e); }, // private onDblClick : function(e){ this.processEvent("dblclick", e); }, walkCells : function(row, col, step, fn, scope){ var cm = this.colModel, clen = cm.getColumnCount(); var ds = this.dataSource, rlen = ds.getCount(), first = true; if(step < 0){ if(col < 0){ row--; first = false; } while(row >= 0){ if(!first){ col = clen-1; } first = false; while(col >= 0){ if(fn.call(scope || this, row, col, cm) === true){ return [row, col]; } col--; } row--; } } else { if(col >= clen){ row++; first = false; } while(row < rlen){ if(!first){ col = 0; } first = false; while(col < clen){ if(fn.call(scope || this, row, col, cm) === true){ return [row, col]; } col++; } row++; } } return null; }, getSelections : function(){ return this.selModel.getSelections(); }, /** * Causes the grid to manually recalculate its dimensions. Generally this is done automatically, * but if manual update is required this method will initiate it. */ autoSize : function(){ if(this.rendered){ this.view.layout(); if(this.view.adjustForScroll){ this.view.adjustForScroll(); } } }, // private for compatibility, overridden by editor grid stopEditing : function(){}, /** * Returns the grid's SelectionModel. * @return {SelectionModel} */ getSelectionModel : function(){ if(!this.selModel){ this.selModel = new Ext.grid.RowSelectionModel(); } return this.selModel; }, /** * Returns the grid's DataSource. * @return {DataSource} */ getDataSource : function(){ return this.dataSource; }, /** * Returns the grid's ColumnModel. * @return {ColumnModel} */ getColumnModel : function(){ return this.colModel; }, /** * Returns the grid's GridView object. * @return {GridView} */ getView : function(){ if(!this.view){ this.view = new Ext.grid.GridView(); } return this.view; }, /** * Called to get grid's drag proxy text, by default returns this.ddText. * @return {String} */ getDragDropText : function(){ var count = this.selModel.getCount(); return String.format(this.ddText, count, count == 1 ? '' : 's'); } }); /** * Configures the text is the drag proxy (defaults to "%0 selected row(s)"). * %0 is replaced with the number of selected rows. * @type String */ Ext.grid.Grid.prototype.ddText = "{0} selected row{1}";