4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
13 * @class Roo.grid.Grid
14 * @extends Roo.util.Observable
15 * This class represents the primary interface of a component based grid control.
16 * <br><br>Usage:<pre><code>
17 var grid = new Roo.grid.Grid("my-container-id", {
20 selModel: mySelectionModel,
21 autoSizeColumns: true,
22 monitorWindowResize: false,
28 * <b>Common Problems:</b><br/>
29 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
30 * element will correct this<br/>
31 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
32 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
33 * are unpredictable.<br/>
34 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
35 * grid to calculate dimensions/offsets.<br/>
37 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
38 * The container MUST have some type of size defined for the grid to fill. The container will be
39 * automatically set to position relative if it isn't already.
40 * @param {Object} config A config object that sets properties on this grid.
42 Roo.grid.Grid = function(container, config){
43 // initialize the container
44 this.container = Roo.get(container);
45 this.container.update("");
46 this.container.setStyle("overflow", "hidden");
47 this.container.addClass('x-grid-container');
49 this.id = this.container.id;
51 Roo.apply(this, config);
52 // check and correct shorthanded configs
54 this.dataSource = this.ds;
58 this.colModel = this.cm;
62 this.selModel = this.sm;
67 this.selModel = Roo.factory(this.selModel, Roo.grid);
68 this.sm = this.selModel;
69 this.sm.xmodule = this.xmodule || false;
71 if (typeof(this.colModel.config) == 'undefined') {
72 this.colModel = new Roo.grid.ColumnModel(this.colModel);
73 this.cm = this.colModel;
74 this.cm.xmodule = this.xmodule || false;
76 if (this.dataSource) {
77 this.dataSource= Roo.factory(this.dataSource, Roo.data);
78 this.ds = this.dataSource;
79 this.ds.xmodule = this.xmodule || false;
86 this.container.setWidth(this.width);
90 this.container.setHeight(this.height);
97 * The raw click event for the entire grid.
98 * @param {Roo.EventObject} e
103 * The raw dblclick event for the entire grid.
104 * @param {Roo.EventObject} e
109 * The raw contextmenu event for the entire grid.
110 * @param {Roo.EventObject} e
112 "contextmenu" : true,
115 * The raw mousedown event for the entire grid.
116 * @param {Roo.EventObject} e
121 * The raw mouseup event for the entire grid.
122 * @param {Roo.EventObject} e
127 * The raw mouseover event for the entire grid.
128 * @param {Roo.EventObject} e
133 * The raw mouseout event for the entire grid.
134 * @param {Roo.EventObject} e
139 * The raw keypress event for the entire grid.
140 * @param {Roo.EventObject} e
145 * The raw keydown event for the entire grid.
146 * @param {Roo.EventObject} e
154 * Fires when a cell is clicked
156 * @param {Number} rowIndex
157 * @param {Number} columnIndex
158 * @param {Roo.EventObject} e
162 * @event celldblclick
163 * Fires when a cell is double clicked
165 * @param {Number} rowIndex
166 * @param {Number} columnIndex
167 * @param {Roo.EventObject} e
169 "celldblclick" : true,
172 * Fires when a row is clicked
174 * @param {Number} rowIndex
175 * @param {Roo.EventObject} e
180 * Fires when a row is double clicked
182 * @param {Number} rowIndex
183 * @param {Roo.EventObject} e
185 "rowdblclick" : true,
188 * Fires when a header is clicked
190 * @param {Number} columnIndex
191 * @param {Roo.EventObject} e
193 "headerclick" : true,
195 * @event headerdblclick
196 * Fires when a header cell is double clicked
198 * @param {Number} columnIndex
199 * @param {Roo.EventObject} e
201 "headerdblclick" : true,
203 * @event rowcontextmenu
204 * Fires when a row is right clicked
206 * @param {Number} rowIndex
207 * @param {Roo.EventObject} e
209 "rowcontextmenu" : true,
211 * @event cellcontextmenu
212 * Fires when a cell is right clicked
214 * @param {Number} rowIndex
215 * @param {Number} cellIndex
216 * @param {Roo.EventObject} e
218 "cellcontextmenu" : true,
220 * @event headercontextmenu
221 * Fires when a header is right clicked
223 * @param {Number} columnIndex
224 * @param {Roo.EventObject} e
226 "headercontextmenu" : true,
229 * Fires when the body element is scrolled
230 * @param {Number} scrollLeft
231 * @param {Number} scrollTop
235 * @event columnresize
236 * Fires when the user resizes a column
237 * @param {Number} columnIndex
238 * @param {Number} newSize
240 "columnresize" : true,
243 * Fires when the user moves a column
244 * @param {Number} oldIndex
245 * @param {Number} newIndex
250 * Fires when row(s) start being dragged
252 * @param {Roo.GridDD} dd The drag drop object
253 * @param {event} e The raw browser event
258 * Fires when a drag operation is complete
260 * @param {Roo.GridDD} dd The drag drop object
261 * @param {event} e The raw browser event
266 * Fires when dragged row(s) are dropped on a valid DD target
268 * @param {Roo.GridDD} dd The drag drop object
269 * @param {String} targetId The target drag drop object
270 * @param {event} e The raw browser event
275 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
277 * @param {Roo.GridDD} dd The drag drop object
278 * @param {String} targetId The target drag drop object
279 * @param {event} e The raw browser event
284 * Fires when the dragged row(s) first cross another DD target while being dragged
286 * @param {Roo.GridDD} dd The drag drop object
287 * @param {String} targetId The target drag drop object
288 * @param {event} e The raw browser event
293 * Fires when the dragged row(s) leave another DD target while being dragged
295 * @param {Roo.GridDD} dd The drag drop object
296 * @param {String} targetId The target drag drop object
297 * @param {event} e The raw browser event
302 * Fires when a row is rendered, so you can change add a style to it.
303 * @param {GridView} gridview The grid view
304 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
310 * Fires when the grid is rendered
316 Roo.grid.Grid.superclass.constructor.call(this);
318 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
321 * @cfg {Roo.grid.AbstractSelectionModel} sm The selection Model (default = Roo.grid.RowSelectionModel)
324 * @cfg {Roo.grid.GridView} view The view that renders the grid (default = Roo.grid.GridView)
327 * @cfg {Roo.grid.ColumnModel} cm[] The columns of the grid
330 * @cfg {Roo.data.Store} ds The data store for the grid
333 * @cfg {Roo.Toolbar} toolbar a toolbar for buttons etc.
336 * @cfg {String} ddGroup - drag drop group.
339 * @cfg {String} dragGroup - drag group (?? not sure if needed.)
343 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
348 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
349 * <b>on initial render.</b> It is more efficient to explicitly size the columns
350 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
352 autoSizeColumns : false,
355 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
357 autoSizeHeaders : true,
360 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
362 monitorWindowResize : true,
365 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
366 * rows measured to get a columns size. Default is 0 (all rows).
368 maxRowsToMeasure : 0,
371 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
373 trackMouseOver : true,
376 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
379 * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
383 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
385 enableDragDrop : false,
388 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
390 enableColumnMove : true,
393 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
395 enableColumnHide : true,
398 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
400 enableRowHeightSync : false,
403 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
408 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
413 * @cfg {String} autoExpandColumn The id (or dataIndex) of a column in this grid that should expand to fill unused space. This id can not be 0. Default is false.
415 autoExpandColumn : false,
418 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
424 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
426 autoExpandMax : 1000,
429 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
434 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
438 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
442 * @cfg {boolean} sortColMenu Sort the column order menu when it shows (usefull for long lists..) default false
450 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
451 * of a fixed width. Default is false.
454 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
459 * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
460 * %0 is replaced with the number of selected rows.
462 ddText : "{0} selected row{1}",
466 * Called once after all setup has been completed and the grid is ready to be rendered.
467 * @return {Roo.grid.Grid} this
471 var c = this.container;
472 // try to detect autoHeight/width mode
473 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
474 this.autoHeight = true;
476 var view = this.getView();
479 c.on("click", this.onClick, this);
480 c.on("dblclick", this.onDblClick, this);
481 c.on("contextmenu", this.onContextMenu, this);
482 c.on("keydown", this.onKeyDown, this);
484 c.on("touchstart", this.onTouchStart, this);
487 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
489 this.getSelectionModel().init(this);
494 this.loadMask = new Roo.LoadMask(this.container,
495 Roo.apply({store:this.dataSource}, this.loadMask));
499 if (this.toolbar && this.toolbar.xtype) {
500 this.toolbar.container = this.getView().getHeaderPanel(true);
501 this.toolbar = new Roo.Toolbar(this.toolbar);
503 if (this.footer && this.footer.xtype) {
504 this.footer.dataSource = this.getDataSource();
505 this.footer.container = this.getView().getFooterPanel(true);
506 this.footer = Roo.factory(this.footer, Roo);
508 if (this.dropTarget && this.dropTarget.xtype) {
509 delete this.dropTarget.xtype;
510 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
514 this.rendered = true;
515 this.fireEvent('render', this);
520 * Reconfigures the grid to use a different Store and Column Model.
521 * The View will be bound to the new objects and refreshed.
522 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
523 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
525 reconfigure : function(dataSource, colModel){
527 this.loadMask.destroy();
528 this.loadMask = new Roo.LoadMask(this.container,
529 Roo.apply({store:dataSource}, this.loadMask));
531 this.view.bind(dataSource, colModel);
532 this.dataSource = dataSource;
533 this.colModel = colModel;
534 this.view.refresh(true);
538 * Add's a column, default at the end..
540 * @param {int} position to add (default end)
541 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
543 addColumns : function(pos, ar)
546 for (var i =0;i< ar.length;i++) {
548 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
549 this.cm.lookup[cfg.id] = cfg;
553 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
554 pos = this.cm.config.length; //this.cm.config.push(cfg);
556 pos = Math.max(0,pos);
559 this.cm.config.splice.apply(this.cm.config, ar);
563 this.view.generateRules(this.cm);
564 this.view.refresh(true);
572 onKeyDown : function(e){
573 this.fireEvent("keydown", e);
578 * @param {Boolean} removeEl True to remove the element
580 destroy : function(removeEl, keepListeners){
582 this.loadMask.destroy();
584 var c = this.container;
585 c.removeAllListeners();
587 this.colModel.purgeListeners();
589 this.purgeListeners();
592 if(removeEl === true){
598 processEvent : function(name, e){
599 // does this fire select???
600 //Roo.log('grid:processEvent ' + name);
602 if (name != 'touchstart' ) {
603 this.fireEvent(name, e);
606 var t = e.getTarget();
608 var header = v.findHeaderIndex(t);
609 if(header !== false){
610 var ename = name == 'touchstart' ? 'click' : name;
612 this.fireEvent("header" + ename, this, header, e);
614 var row = v.findRowIndex(t);
615 var cell = v.findCellIndex(t);
616 if (name == 'touchstart') {
617 // first touch is always a click.
618 // hopefull this happens after selection is updated.?
621 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
622 var cs = this.selModel.getSelectedCell();
623 if (row == cs[0] && cell == cs[1]){
627 if (typeof(this.selModel.getSelections) != 'undefined') {
628 var cs = this.selModel.getSelections();
629 var ds = this.dataSource;
630 if (cs.length == 1 && ds.getAt(row) == cs[0]){
641 this.fireEvent("row" + name, this, row, e);
643 this.fireEvent("cell" + name, this, row, cell, e);
650 onClick : function(e){
651 this.processEvent("click", e);
654 onTouchStart : function(e){
655 this.processEvent("touchstart", e);
659 onContextMenu : function(e, t){
660 this.processEvent("contextmenu", e);
664 onDblClick : function(e){
665 this.processEvent("dblclick", e);
669 walkCells : function(row, col, step, fn, scope){
670 var cm = this.colModel, clen = cm.getColumnCount();
671 var ds = this.dataSource, rlen = ds.getCount(), first = true;
683 if(fn.call(scope || this, row, col, cm) === true){
701 if(fn.call(scope || this, row, col, cm) === true){
713 getSelections : function(){
714 return this.selModel.getSelections();
718 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
719 * but if manual update is required this method will initiate it.
721 autoSize : function(){
724 if(this.view.adjustForScroll){
725 this.view.adjustForScroll();
731 * Returns the grid's underlying element.
732 * @return {Element} The element
734 getGridEl : function(){
735 return this.container;
738 // private for compatibility, overridden by editor grid
739 stopEditing : function(){},
742 * Returns the grid's SelectionModel.
743 * @return {SelectionModel}
745 getSelectionModel : function(){
747 this.selModel = new Roo.grid.RowSelectionModel();
749 return this.selModel;
753 * Returns the grid's DataSource.
754 * @return {DataSource}
756 getDataSource : function(){
757 return this.dataSource;
761 * Returns the grid's ColumnModel.
762 * @return {ColumnModel}
764 getColumnModel : function(){
765 return this.colModel;
769 * Returns the grid's GridView object.
772 getView : function(){
774 this.view = new Roo.grid.GridView(this.viewConfig);
775 this.relayEvents(this.view, [
776 "beforerowremoved", "beforerowsinserted",
777 "beforerefresh", "rowremoved",
778 "rowsinserted", "rowupdated" ,"refresh"
784 * Called to get grid's drag proxy text, by default returns this.ddText.
785 * Override this to put something different in the dragged text.
788 getDragDropText : function(){
789 var count = this.selModel.getCount();
790 return String.format(this.ddText, count, count == 1 ? '' : 's');