/public/javascripts/dojo/release/dojo/dojox/grid/compat/Grid.js

http://enginey.googlecode.com/ · JavaScript · 378 lines · 233 code · 44 blank · 101 comment · 38 complexity · ab358c8020a315ac104ff772ee318460 MD5 · raw file

  1. /*
  2. Copyright (c) 2004-2008, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.grid.compat.Grid"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.grid.compat.Grid"] = true;
  8. dojo.provide("dojox.grid.compat.Grid");
  9. dojo.require("dojox.grid.compat.VirtualGrid");
  10. dojo.require("dojox.grid.compat._data.model");
  11. dojo.require("dojox.grid.compat._data.editors");
  12. dojo.require("dojox.grid.compat._data.dijitEditors");
  13. // FIXME:
  14. // we are at the wrong location!
  15. dojo.declare('dojox.Grid', dojox.VirtualGrid, {
  16. // summary:
  17. // A grid widget with virtual scrolling, cell editing, complex rows,
  18. // sorting, fixed columns, sizeable columns, etc.
  19. // description:
  20. // Grid is a subclass of VirtualGrid, providing binding to a data
  21. // store.
  22. // example:
  23. // define the grid structure:
  24. // | var structure = [ // array of view objects
  25. // | { cells: [// array of rows, a row is an array of cells
  26. // | [ { name: "Alpha", width: 6 },
  27. // | { name: "Beta" },
  28. // | { name: "Gamma", get: formatFunction }
  29. // | ]
  30. // | ]}
  31. // | ];
  32. //
  33. // define a grid data model
  34. // | var model = new dojox.grid.data.table(null, data);
  35. // |
  36. // | <div id="grid" model="model" structure="structure"
  37. // | dojoType="dojox.VirtualGrid"></div>
  38. //
  39. // model:
  40. // string or object grid data model
  41. model: 'dojox.grid.data.Table',
  42. // life cycle
  43. postCreate: function(){
  44. if(this.model){
  45. var m = this.model;
  46. if(dojo.isString(m)){
  47. m = dojo.getObject(m);
  48. }
  49. this.model = (dojo.isFunction(m)) ? new m() : m;
  50. this._setModel(this.model);
  51. }
  52. this.inherited(arguments);
  53. },
  54. destroy: function(){
  55. this.setModel(null);
  56. this.inherited(arguments);
  57. },
  58. // structure
  59. _structureChanged: function() {
  60. this.indexCellFields();
  61. this.inherited(arguments);
  62. },
  63. // model
  64. _setModel: function(inModel){
  65. // if(!inModel){ return; }
  66. this.model = inModel;
  67. if(this.model){
  68. this.model.observer(this);
  69. this.model.measure();
  70. this.indexCellFields();
  71. }
  72. },
  73. setModel: function(inModel){
  74. // summary:
  75. // Set the grid's data model
  76. // inModel: Object
  77. // Model object, usually an instance of a dojox.grid.data.Model
  78. // subclass
  79. if(this.model){
  80. this.model.notObserver(this);
  81. }
  82. this._setModel(inModel);
  83. },
  84. get: function(inRowIndex){
  85. // summary: data socket (called in cell's context)
  86. return this.grid.model.getDatum(inRowIndex, this.fieldIndex);
  87. },
  88. // model modifications
  89. modelAllChange: function(){
  90. this.rowCount = (this.model ? this.model.getRowCount() : 0);
  91. this.updateRowCount(this.rowCount);
  92. },
  93. modelBeginUpdate: function(){
  94. this.beginUpdate();
  95. },
  96. modelEndUpdate: function(){
  97. this.endUpdate();
  98. },
  99. modelRowChange: function(inData, inRowIndex){
  100. this.updateRow(inRowIndex);
  101. },
  102. modelDatumChange: function(inDatum, inRowIndex, inFieldIndex){
  103. this.updateRow(inRowIndex);
  104. },
  105. modelFieldsChange: function() {
  106. this.indexCellFields();
  107. this.render();
  108. },
  109. // model insertion
  110. modelInsertion: function(inRowIndex){
  111. this.updateRowCount(this.model.getRowCount());
  112. },
  113. // model removal
  114. modelRemoval: function(inKeys){
  115. this.updateRowCount(this.model.getRowCount());
  116. },
  117. // cells
  118. getCellName: function(inCell){
  119. var v = this.model.fields.values, i = inCell.fieldIndex;
  120. return i>=0 && i<v.length && v[i].name || this.inherited(arguments);
  121. },
  122. indexCellFields: function(){
  123. var cells = this.layout.cells;
  124. for(var i=0, c; cells && (c=cells[i]); i++){
  125. if(dojo.isString(c.field)){
  126. c.fieldIndex = this.model.fields.indexOf(c.field);
  127. }
  128. }
  129. },
  130. // utility
  131. refresh: function(){
  132. // summary:
  133. // Re-render the grid, getting new data from the model
  134. this.edit.cancel();
  135. this.model.measure();
  136. },
  137. // sorting
  138. canSort: function(inSortInfo){
  139. var f = this.getSortField(inSortInfo);
  140. // 0 is not a valid sort field
  141. return f && this.model.canSort(f);
  142. },
  143. getSortField: function(inSortInfo){
  144. // summary:
  145. // Retrieves the model field on which to sort data.
  146. // inSortInfo: Integer
  147. // 1-based grid column index; positive if sort is ascending, otherwise negative
  148. var c = this.getCell(this.getSortIndex(inSortInfo));
  149. // we expect c.fieldIndex == -1 for non model fields
  150. // that yields a getSortField value of 0, which can be detected as invalid
  151. return (c.fieldIndex+1) * (this.sortInfo > 0 ? 1 : -1);
  152. },
  153. sort: function(){
  154. this.edit.apply();
  155. this.model.sort(this.getSortField());
  156. },
  157. // row editing
  158. addRow: function(inRowData, inIndex){
  159. this.edit.apply();
  160. var i = inIndex || -1;
  161. if(i<0){
  162. i = this.selection.getFirstSelected() || 0;
  163. }
  164. if(i<0){
  165. i = 0;
  166. }
  167. this.model.insert(inRowData, i);
  168. this.model.beginModifyRow(i);
  169. // begin editing row
  170. // FIXME: add to edit
  171. for(var j=0, c; ((c=this.getCell(j)) && !c.editor); j++){}
  172. if(c&&c.editor){
  173. this.edit.setEditCell(c, i);
  174. this.focus.setFocusCell(c, i);
  175. }else{
  176. this.focus.setFocusCell(this.getCell(0), i);
  177. }
  178. },
  179. removeSelectedRows: function(){
  180. this.edit.apply();
  181. var s = this.selection.getSelected();
  182. if(s.length){
  183. this.model.remove(s);
  184. this.selection.clear();
  185. }
  186. },
  187. //: protected
  188. // editing
  189. canEdit: function(inCell, inRowIndex){
  190. // summary:
  191. // Determines if a given cell may be edited
  192. // inCell: Object
  193. // A grid cell
  194. // inRowIndex: Integer
  195. // Grid row index
  196. // returns: Boolean
  197. // True if given cell may be edited
  198. return (this.model.canModify ? this.model.canModify(inRowIndex) : true);
  199. },
  200. doStartEdit: function(inCell, inRowIndex){
  201. this.model.beginModifyRow(inRowIndex);
  202. this.onStartEdit(inCell, inRowIndex);
  203. },
  204. doApplyCellEdit: function(inValue, inRowIndex, inFieldIndex){
  205. this.model.setDatum(inValue, inRowIndex, inFieldIndex);
  206. this.onApplyCellEdit(inValue, inRowIndex, inFieldIndex);
  207. },
  208. doCancelEdit: function(inRowIndex){
  209. this.model.cancelModifyRow(inRowIndex);
  210. this.onCancelEdit.apply(this, arguments);
  211. },
  212. doApplyEdit: function(inRowIndex){
  213. this.model.endModifyRow(inRowIndex);
  214. this.onApplyEdit(inRowIndex);
  215. },
  216. styleRowState: function(inRow){
  217. // summary: Perform row styling
  218. if(this.model.getState){
  219. var states=this.model.getState(inRow.index), c='';
  220. for(var i=0, ss=["inflight", "error", "inserting"], s; s=ss[i]; i++){
  221. if(states[s]){
  222. c = ' dojoxGrid-row-' + s;
  223. break;
  224. }
  225. }
  226. inRow.customClasses += c;
  227. }
  228. },
  229. onStyleRow: function(inRow){
  230. this.styleRowState(inRow);
  231. this.inherited(arguments);
  232. }
  233. });
  234. dojox.Grid.markupFactory = function(props, node, ctor){
  235. // handle setting up a data model for a store if one
  236. // isn't provided. There are some caveats:
  237. // * we only really handle dojo.data sources well. They're the future
  238. // so it's no big deal, but it's something to be aware of.
  239. // * I'm pretty sure that colgroup introspection is missing some of
  240. // the available settable properties.
  241. // * No handling of cell formatting and content getting is done
  242. var d = dojo;
  243. var widthFromAttr = function(n){
  244. var w = d.attr(n, "width")||"auto";
  245. if((w != "auto")&&(w.substr(-2) != "em")){
  246. w = parseInt(w)+"px";
  247. }
  248. return w;
  249. }
  250. if(!props.model && d.hasAttr(node, "store")){
  251. // if a model isn't specified and we point to a store, assume
  252. // we're also folding the definition for a model up into the
  253. // inline ctor for the Grid. This will then take properties
  254. // like "query", "rowsPerPage", and "clientSort" from the grid
  255. // definition.
  256. var mNode = node.cloneNode(false);
  257. d.attr(mNode, {
  258. "jsId": null,
  259. "dojoType": d.attr(node, "dataModelClass") || "dojox.grid.data.DojoData"
  260. });
  261. props.model = d.parser.instantiate([mNode])[0];
  262. }
  263. // if(!props.model){ console.debug("no model!"); }
  264. // if a structure isn't referenced, do we have enough
  265. // data to try to build one automatically?
  266. if( !props.structure &&
  267. node.nodeName.toLowerCase() == "table"){
  268. // try to discover a structure
  269. props.structure = d.query("> colgroup", node).map(function(cg){
  270. var sv = d.attr(cg, "span");
  271. var v = {
  272. noscroll: (d.attr(cg, "noscroll") == "true") ? true : false,
  273. __span: (!!sv ? parseInt(sv) : 1),
  274. cells: []
  275. };
  276. if(d.hasAttr(cg, "width")){
  277. v.width = widthFromAttr(cg);
  278. }
  279. return v; // for vendetta
  280. });
  281. if(!props.structure.length){
  282. props.structure.push({
  283. __span: Infinity,
  284. cells: [] // catch-all view
  285. });
  286. }
  287. // check to see if we're gonna have more than one view
  288. // for each tr in our th, create a row of cells
  289. d.query("thead > tr", node).forEach(function(tr, tr_idx){
  290. var cellCount = 0;
  291. var viewIdx = 0;
  292. var lastViewIdx;
  293. var cView = null;
  294. d.query("> th", tr).map(function(th){
  295. // what view will this cell go into?
  296. // NOTE:
  297. // to prevent extraneous iteration, we start counters over
  298. // for each row, incrementing over the surface area of the
  299. // structure that colgroup processing generates and
  300. // creating cell objects for each <th> to place into those
  301. // cell groups. There's a lot of state-keepking logic
  302. // here, but it is what it has to be.
  303. if(!cView){ // current view book keeping
  304. lastViewIdx = 0;
  305. cView = props.structure[0];
  306. }else if(cellCount >= (lastViewIdx+cView.__span)){
  307. viewIdx++;
  308. // move to allocating things into the next view
  309. lastViewIdx += cView.__span;
  310. lastView = cView;
  311. cView = props.structure[viewIdx];
  312. }
  313. // actually define the cell from what markup hands us
  314. var cell = {
  315. name: d.trim(d.attr(th, "name")||th.innerHTML),
  316. field: d.trim(d.attr(th, "field")||""),
  317. colSpan: parseInt(d.attr(th, "colspan")||1)
  318. };
  319. cellCount += cell.colSpan;
  320. cell.field = cell.field||cell.name;
  321. cell.width = widthFromAttr(th);
  322. if(!cView.cells[tr_idx]){
  323. cView.cells[tr_idx] = [];
  324. }
  325. cView.cells[tr_idx].push(cell);
  326. });
  327. });
  328. // console.debug(dojo.toJson(props.structure, true));
  329. }
  330. return new dojox.Grid(props, node);
  331. }
  332. // alias us to the right location
  333. dojox.grid.Grid = dojox.Grid;
  334. }