1 if(!dojo._hasResource["dojox.grid.Grid"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2 dojo._hasResource["dojox.grid.Grid"] = true;
3 dojo.provide("dojox.grid.Grid");
4 dojo.require("dojox.grid.VirtualGrid");
5 dojo.require("dojox.grid._data.model");
6 dojo.require("dojox.grid._data.editors");
7 dojo.require("dojox.grid._data.dijitEditors");
10 // we are at the wrong location!
12 dojo.declare('dojox.Grid', dojox.VirtualGrid, {
14 // A grid widget with virtual scrolling, cell editing, complex rows,
15 // sorting, fixed columns, sizeable columns, etc.
17 // Grid is a subclass of VirtualGrid, providing binding to a data
20 // define the grid structure:
21 // | var structure = [ // array of view objects
22 // | { cells: [// array of rows, a row is an array of cells
23 // | [ { name: "Alpha", width: 6 },
24 // | { name: "Beta" },
25 // | { name: "Gamma", get: formatFunction }
30 // define a grid data model
31 // | var model = new dojox.grid.data.table(null, data);
33 // | <div id="grid" model="model" structure="structure"
34 // | dojoType="dojox.VirtualGrid"></div>
38 // string or object grid data model
39 model: 'dojox.grid.data.Table',
42 postCreate: function(){
46 m = dojo.getObject(m);
48 this.model = (dojo.isFunction(m)) ? new m() : m;
49 this._setModel(this.model);
51 this.inherited(arguments);
56 this.inherited(arguments);
60 _structureChanged: function() {
61 this.indexCellFields();
62 this.inherited(arguments);
66 _setModel: function(inModel){
67 // if(!inModel){ return; }
70 this.model.observer(this);
72 this.indexCellFields();
76 setModel: function(inModel){
78 // Set the grid's data model
80 // Model object, usually an instance of a dojox.grid.data.Model
83 this.model.notObserver(this);
85 this._setModel(inModel);
89 get: function(inRowIndex){
90 // summary: data socket (called in cell's context)
91 return this.grid.model.getDatum(inRowIndex, this.fieldIndex);
94 // model modifications
95 modelAllChange: function(){
96 this.rowCount = (this.model ? this.model.getRowCount() : 0);
97 this.updateRowCount(this.rowCount);
100 modelRowChange: function(inData, inRowIndex){
101 this.updateRow(inRowIndex);
104 modelDatumChange: function(inDatum, inRowIndex, inFieldIndex){
105 this.updateRow(inRowIndex);
108 modelFieldsChange: function() {
109 this.indexCellFields();
114 modelInsertion: function(inRowIndex){
115 this.updateRowCount(this.model.getRowCount());
119 modelRemoval: function(inKeys){
120 this.updateRowCount(this.model.getRowCount());
124 getCellName: function(inCell){
125 var v = this.model.fields.values, i = inCell.fieldIndex;
126 return i>=0 && i<v.length && v[i].name || this.inherited(arguments);
129 indexCellFields: function(){
130 var cells = this.layout.cells;
131 for(var i=0, c; cells && (c=cells[i]); i++){
132 if(dojo.isString(c.field)){
133 c.fieldIndex = this.model.fields.indexOf(c.field);
141 // Re-render the grid, getting new data from the model
143 this.model.measure();
147 canSort: function(inSortInfo){
148 var f = this.getSortField(inSortInfo);
149 // 0 is not a valid sort field
150 return f && this.model.canSort(f);
153 getSortField: function(inSortInfo){
155 // Retrieves the model field on which to sort data.
156 // inSortInfo: Integer
157 // 1-based grid column index; positive if sort is ascending, otherwise negative
158 var c = this.getCell(this.getSortIndex(inSortInfo));
159 // we expect c.fieldIndex == -1 for non model fields
160 // that yields a getSortField value of 0, which can be detected as invalid
161 return (c.fieldIndex+1) * (this.sortInfo > 0 ? 1 : -1);
166 this.model.sort(this.getSortField());
170 addRow: function(inRowData, inIndex){
172 var i = inIndex || -1;
174 i = this.selection.getFirstSelected() || 0;
179 this.model.insert(inRowData, i);
180 this.model.beginModifyRow(i);
182 // FIXME: add to edit
183 for(var j=0, c; ((c=this.getCell(j)) && !c.editor); j++){}
185 this.edit.setEditCell(c, i);
186 this.focus.setFocusCell(c, i);
188 this.focus.setFocusCell(this.getCell(0), i);
192 removeSelectedRows: function(){
194 var s = this.selection.getSelected();
196 this.model.remove(s);
197 this.selection.clear();
203 canEdit: function(inCell, inRowIndex){
205 // Determines if a given cell may be edited
208 // inRowIndex: Integer
211 // True if given cell may be edited
212 return (this.model.canModify ? this.model.canModify(inRowIndex) : true);
215 doStartEdit: function(inCell, inRowIndex){
216 this.model.beginModifyRow(inRowIndex);
217 this.onStartEdit(inCell, inRowIndex);
220 doApplyCellEdit: function(inValue, inRowIndex, inFieldIndex){
221 this.model.setDatum(inValue, inRowIndex, inFieldIndex);
222 this.onApplyCellEdit(inValue, inRowIndex, inFieldIndex);
225 doCancelEdit: function(inRowIndex){
226 this.model.cancelModifyRow(inRowIndex);
227 this.onCancelEdit.apply(this, arguments);
230 doApplyEdit: function(inRowIndex){
231 this.model.endModifyRow(inRowIndex);
232 this.onApplyEdit(inRowIndex);
235 styleRowState: function(inRow){
236 // summary: Perform row styling
237 if(this.model.getState){
238 var states=this.model.getState(inRow.index), c='';
239 for(var i=0, ss=["inflight", "error", "inserting"], s; s=ss[i]; i++){
241 c = ' dojoxGrid-row-' + s;
245 inRow.customClasses += c;
249 onStyleRow: function(inRow){
250 this.styleRowState(inRow);
251 this.inherited(arguments);
256 dojox.Grid.markupFactory = function(props, node, ctor){
257 // handle setting up a data model for a store if one
258 // isn't provided. There are some caveats:
259 // * we only really handle dojo.data sources well. They're the future
260 // so it's no big deal, but it's something to be aware of.
261 // * I'm pretty sure that colgroup introspection is missing some of
262 // the available settable properties.
263 // * No handling of cell formatting and content getting is done
265 var widthFromAttr = function(n){
266 var w = d.attr(n, "width")||"auto";
267 if((w != "auto")&&(w.substr(-2) != "em")){
268 w = parseInt(w)+"px";
272 if(!props.model && d.hasAttr(node, "store")){
273 // if a model isn't specified and we point to a store, assume
274 // we're also folding the definition for a model up into the
275 // inline ctor for the Grid. This will then take properties
276 // like "query", "rowsPerPage", and "clientSort" from the grid
278 var mNode = node.cloneNode(false);
281 "dojoType": d.attr(node, "dataModelClass") || "dojox.grid.data.DojoData"
283 props.model = d.parser.instantiate([mNode])[0];
285 // if(!props.model){ console.debug("no model!"); }
286 // if a structure isn't referenced, do we have enough
287 // data to try to build one automatically?
288 if( !props.structure &&
289 node.nodeName.toLowerCase() == "table"){
291 // try to discover a structure
292 props.structure = d.query("> colgroup", node).map(function(cg){
293 var sv = d.attr(cg, "span");
295 noscroll: (d.attr(cg, "noscroll") == "true") ? true : false,
296 __span: (!!sv ? parseInt(sv) : 1),
299 if(d.hasAttr(cg, "width")){
300 v.width = widthFromAttr(cg);
302 return v; // for vendetta
304 if(!props.structure.length){
305 props.structure.push({
307 cells: [] // catch-all view
310 // check to see if we're gonna have more than one view
312 // for each tr in our th, create a row of cells
313 d.query("thead > tr", node).forEach(function(tr, tr_idx){
318 d.query("> th", tr).map(function(th){
319 // what view will this cell go into?
322 // to prevent extraneous iteration, we start counters over
323 // for each row, incrementing over the surface area of the
324 // structure that colgroup processing generates and
325 // creating cell objects for each <th> to place into those
326 // cell groups. There's a lot of state-keepking logic
327 // here, but it is what it has to be.
328 if(!cView){ // current view book keeping
330 cView = props.structure[0];
331 }else if(cellCount >= (lastViewIdx+cView.__span)){
333 // move to allocating things into the next view
334 lastViewIdx += cView.__span;
336 cView = props.structure[viewIdx];
339 // actually define the cell from what markup hands us
341 name: d.trim(d.attr(th, "name")||th.innerHTML),
342 field: d.trim(d.attr(th, "field")||""),
343 colSpan: parseInt(d.attr(th, "colspan")||1)
345 cellCount += cell.colSpan;
346 cell.field = cell.field||cell.name;
347 cell.width = widthFromAttr(th);
348 if(!cView.cells[tr_idx]){
349 cView.cells[tr_idx] = [];
351 cView.cells[tr_idx].push(cell);
354 // console.debug(dojo.toJson(props.structure, true));
356 return new dojox.Grid(props, node);
360 // alias us to the right location
361 dojox.grid.Grid = dojox.Grid;