_base.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /*
  2. Copyright (c) 2004-2012, 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.cells._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.grid.cells._base"] = true;
  8. dojo.provide("dojox.grid.cells._base");
  9. dojo.require("dojox.grid.util");
  10. dojo.require("dijit._Widget");
  11. dojo.declare("dojox.grid._DeferredTextWidget", dijit._Widget, {
  12. deferred: null,
  13. _destroyOnRemove: true,
  14. postCreate: function(){
  15. if(this.deferred){
  16. this.deferred.addBoth(dojo.hitch(this, function(text){
  17. if(this.domNode){
  18. this.domNode.innerHTML = text;
  19. }
  20. }));
  21. }
  22. }
  23. });
  24. (function(){
  25. var focusSelectNode = function(inNode){
  26. try{
  27. dojox.grid.util.fire(inNode, "focus");
  28. dojox.grid.util.fire(inNode, "select");
  29. }catch(e){// IE sux bad
  30. }
  31. };
  32. var whenIdle = function(/*inContext, inMethod, args ...*/){
  33. setTimeout(dojo.hitch.apply(dojo, arguments), 0);
  34. };
  35. var dgc = dojox.grid.cells;
  36. dojo.declare("dojox.grid.cells._Base", null, {
  37. // summary:
  38. // Respresents a grid cell and contains information about column options and methods
  39. // for retrieving cell related information.
  40. // Each column in a grid layout has a cell object and most events and many methods
  41. // provide access to these objects.
  42. styles: '',
  43. classes: '',
  44. editable: false,
  45. alwaysEditing: false,
  46. formatter: null,
  47. defaultValue: '...',
  48. value: null,
  49. hidden: false,
  50. noresize: false,
  51. draggable: true,
  52. //private
  53. _valueProp: "value",
  54. _formatPending: false,
  55. constructor: function(inProps){
  56. this._props = inProps || {};
  57. dojo.mixin(this, inProps);
  58. if(this.draggable === undefined){
  59. this.draggable = true;
  60. }
  61. },
  62. _defaultFormat: function(inValue, callArgs){
  63. var s = this.grid.formatterScope || this;
  64. var f = this.formatter;
  65. if(f && s && typeof f == "string"){
  66. f = this.formatter = s[f];
  67. }
  68. var v = (inValue != this.defaultValue && f) ? f.apply(s, callArgs) : inValue;
  69. if(typeof v == "undefined"){
  70. return this.defaultValue;
  71. }
  72. if(v && v.addBoth){
  73. // Check if it's a deferred
  74. v = new dojox.grid._DeferredTextWidget({deferred: v},
  75. dojo.create("span", {innerHTML: this.defaultValue}));
  76. }
  77. if(v && v.declaredClass && v.startup){
  78. return "<div class='dojoxGridStubNode' linkWidget='" +
  79. v.id +
  80. "' cellIdx='" +
  81. this.index +
  82. "'>" +
  83. this.defaultValue +
  84. "</div>";
  85. }
  86. return v;
  87. },
  88. // data source
  89. format: function(inRowIndex, inItem){
  90. // summary:
  91. // provides the html for a given grid cell.
  92. // inRowIndex: int
  93. // grid row index
  94. // returns: html for a given grid cell
  95. var i = this.grid.edit.info;
  96. var d = this.get ? this.get(inRowIndex, inItem) : (this.value || this.defaultValue);
  97. if (d && d.replace && this.grid.escapeHTMLInData) {
  98. d = d.replace(/&/g, '&amp;').replace(/</g, '&lt;');
  99. }
  100. if (this.editable && (this.alwaysEditing || (i.rowIndex==inRowIndex && i.cell==this))) {
  101. return this.formatEditing(i.value ? i.value : d, inRowIndex);
  102. } else {
  103. return this._defaultFormat(d, [d, inRowIndex, this]);
  104. }
  105. },
  106. formatEditing: function(inDatum, inRowIndex){
  107. // summary:
  108. // formats the cell for editing
  109. // inDatum: anything
  110. // cell data to edit
  111. // inRowIndex: int
  112. // grid row index
  113. // returns: string of html to place in grid cell
  114. },
  115. // utility
  116. getNode: function(inRowIndex){
  117. // summary:
  118. // gets the dom node for a given grid cell.
  119. // inRowIndex: int
  120. // grid row index
  121. // returns: dom node for a given grid cell
  122. return this.view.getCellNode(inRowIndex, this.index);
  123. },
  124. getHeaderNode: function(){
  125. return this.view.getHeaderCellNode(this.index);
  126. },
  127. getEditNode: function(inRowIndex){
  128. return (this.getNode(inRowIndex) || 0).firstChild || 0;
  129. },
  130. canResize: function(){
  131. var uw = this.unitWidth;
  132. return uw && (uw!=='auto');
  133. },
  134. isFlex: function(){
  135. var uw = this.unitWidth;
  136. return uw && dojo.isString(uw) && (uw=='auto' || uw.slice(-1)=='%');
  137. },
  138. // edit support
  139. applyEdit: function(inValue, inRowIndex){
  140. this.grid.edit.applyCellEdit(inValue, this, inRowIndex);
  141. },
  142. cancelEdit: function(inRowIndex){
  143. this.grid.doCancelEdit(inRowIndex);
  144. },
  145. _onEditBlur: function(inRowIndex){
  146. if(this.grid.edit.isEditCell(inRowIndex, this.index)){
  147. //console.log('editor onblur', e);
  148. this.grid.edit.apply();
  149. }
  150. },
  151. registerOnBlur: function(inNode, inRowIndex){
  152. if(this.commitOnBlur){
  153. dojo.connect(inNode, "onblur", function(e){
  154. // hack: if editor still thinks this editor is current some ms after it blurs, assume we've focused away from grid
  155. setTimeout(dojo.hitch(this, "_onEditBlur", inRowIndex), 250);
  156. });
  157. }
  158. },
  159. //protected
  160. needFormatNode: function(inDatum, inRowIndex){
  161. this._formatPending = true;
  162. whenIdle(this, "_formatNode", inDatum, inRowIndex);
  163. },
  164. cancelFormatNode: function(){
  165. this._formatPending = false;
  166. },
  167. //private
  168. _formatNode: function(inDatum, inRowIndex){
  169. if(this._formatPending){
  170. this._formatPending = false;
  171. // make cell selectable
  172. if(!dojo.isIE){
  173. dojo.setSelectable(this.grid.domNode, true);
  174. }
  175. this.formatNode(this.getEditNode(inRowIndex), inDatum, inRowIndex);
  176. }
  177. },
  178. //protected
  179. formatNode: function(inNode, inDatum, inRowIndex){
  180. // summary:
  181. // format the editing dom node. Use when editor is a widget.
  182. // inNode: dom node
  183. // dom node for the editor
  184. // inDatum: anything
  185. // cell data to edit
  186. // inRowIndex: int
  187. // grid row index
  188. if(dojo.isIE){
  189. // IE sux bad
  190. whenIdle(this, "focus", inRowIndex, inNode);
  191. }else{
  192. this.focus(inRowIndex, inNode);
  193. }
  194. },
  195. dispatchEvent: function(m, e){
  196. if(m in this){
  197. return this[m](e);
  198. }
  199. },
  200. //public
  201. getValue: function(inRowIndex){
  202. // summary:
  203. // returns value entered into editor
  204. // inRowIndex: int
  205. // grid row index
  206. // returns:
  207. // value of editor
  208. return this.getEditNode(inRowIndex)[this._valueProp];
  209. },
  210. setValue: function(inRowIndex, inValue){
  211. // summary:
  212. // set the value of the grid editor
  213. // inRowIndex: int
  214. // grid row index
  215. // inValue: anything
  216. // value of editor
  217. var n = this.getEditNode(inRowIndex);
  218. if(n){
  219. n[this._valueProp] = inValue;
  220. }
  221. },
  222. focus: function(inRowIndex, inNode){
  223. // summary:
  224. // focus the grid editor
  225. // inRowIndex: int
  226. // grid row index
  227. // inNode: dom node
  228. // editor node
  229. focusSelectNode(inNode || this.getEditNode(inRowIndex));
  230. },
  231. save: function(inRowIndex){
  232. // summary:
  233. // save editor state
  234. // inRowIndex: int
  235. // grid row index
  236. this.value = this.value || this.getValue(inRowIndex);
  237. //console.log("save", this.value, inCell.index, inRowIndex);
  238. },
  239. restore: function(inRowIndex){
  240. // summary:
  241. // restore editor state
  242. // inRowIndex: int
  243. // grid row index
  244. this.setValue(inRowIndex, this.value);
  245. //console.log("restore", this.value, inCell.index, inRowIndex);
  246. },
  247. //protected
  248. _finish: function(inRowIndex){
  249. // summary:
  250. // called when editing is completed to clean up editor
  251. // inRowIndex: int
  252. // grid row index
  253. dojo.setSelectable(this.grid.domNode, false);
  254. this.cancelFormatNode();
  255. },
  256. //public
  257. apply: function(inRowIndex){
  258. // summary:
  259. // apply edit from cell editor
  260. // inRowIndex: int
  261. // grid row index
  262. this.applyEdit(this.getValue(inRowIndex), inRowIndex);
  263. this._finish(inRowIndex);
  264. },
  265. cancel: function(inRowIndex){
  266. // summary:
  267. // cancel cell edit
  268. // inRowIndex: int
  269. // grid row index
  270. this.cancelEdit(inRowIndex);
  271. this._finish(inRowIndex);
  272. }
  273. });
  274. dgc._Base.markupFactory = function(node, cellDef){
  275. var d = dojo;
  276. var formatter = d.trim(d.attr(node, "formatter")||"");
  277. if(formatter){
  278. cellDef.formatter = dojo.getObject(formatter)||formatter;
  279. }
  280. var get = d.trim(d.attr(node, "get")||"");
  281. if(get){
  282. cellDef.get = dojo.getObject(get);
  283. }
  284. var getBoolAttr = function(attr, cell, cellAttr){
  285. var value = d.trim(d.attr(node, attr)||"");
  286. if(value){ cell[cellAttr||attr] = !(value.toLowerCase()=="false"); }
  287. };
  288. getBoolAttr("sortDesc", cellDef);
  289. getBoolAttr("editable", cellDef);
  290. getBoolAttr("alwaysEditing", cellDef);
  291. getBoolAttr("noresize", cellDef);
  292. getBoolAttr("draggable", cellDef);
  293. var value = d.trim(d.attr(node, "loadingText")||d.attr(node, "defaultValue")||"");
  294. if(value){
  295. cellDef.defaultValue = value;
  296. }
  297. var getStrAttr = function(attr, cell, cellAttr){
  298. var value = d.trim(d.attr(node, attr)||"")||undefined;
  299. if(value){ cell[cellAttr||attr] = value; }
  300. };
  301. getStrAttr("styles", cellDef);
  302. getStrAttr("headerStyles", cellDef);
  303. getStrAttr("cellStyles", cellDef);
  304. getStrAttr("classes", cellDef);
  305. getStrAttr("headerClasses", cellDef);
  306. getStrAttr("cellClasses", cellDef);
  307. };
  308. dojo.declare("dojox.grid.cells.Cell", dgc._Base, {
  309. // summary
  310. // grid cell that provides a standard text input box upon editing
  311. constructor: function(){
  312. this.keyFilter = this.keyFilter;
  313. },
  314. // keyFilter: RegExp
  315. // optional regex for disallowing keypresses
  316. keyFilter: null,
  317. formatEditing: function(inDatum, inRowIndex){
  318. this.needFormatNode(inDatum, inRowIndex);
  319. if (inDatum && inDatum.replace) {
  320. // escape quotes to avoid XSS
  321. inDatum = inDatum.replace(/"/g, '&quot;')
  322. }
  323. return '<input class="dojoxGridInput" type="text" value="' + inDatum + '">';
  324. },
  325. formatNode: function(inNode, inDatum, inRowIndex){
  326. this.inherited(arguments);
  327. // FIXME: feels too specific for this interface
  328. this.registerOnBlur(inNode, inRowIndex);
  329. },
  330. doKey: function(e){
  331. if(this.keyFilter){
  332. var key = String.fromCharCode(e.charCode);
  333. if(key.search(this.keyFilter) == -1){
  334. dojo.stopEvent(e);
  335. }
  336. }
  337. },
  338. _finish: function(inRowIndex){
  339. this.inherited(arguments);
  340. var n = this.getEditNode(inRowIndex);
  341. try{
  342. dojox.grid.util.fire(n, "blur");
  343. }catch(e){}
  344. }
  345. });
  346. dgc.Cell.markupFactory = function(node, cellDef){
  347. dgc._Base.markupFactory(node, cellDef);
  348. var d = dojo;
  349. var keyFilter = d.trim(d.attr(node, "keyFilter")||"");
  350. if(keyFilter){
  351. cellDef.keyFilter = new RegExp(keyFilter);
  352. }
  353. };
  354. dojo.declare("dojox.grid.cells.RowIndex", dgc.Cell, {
  355. name: 'Row',
  356. postscript: function(){
  357. this.editable = false;
  358. },
  359. get: function(inRowIndex){
  360. return inRowIndex + 1;
  361. }
  362. });
  363. dgc.RowIndex.markupFactory = function(node, cellDef){
  364. dgc.Cell.markupFactory(node, cellDef);
  365. };
  366. dojo.declare("dojox.grid.cells.Select", dgc.Cell, {
  367. // summary:
  368. // grid cell that provides a standard select for editing
  369. // options: Array
  370. // text of each item
  371. options: null,
  372. // values: Array
  373. // value for each item
  374. values: null,
  375. // returnIndex: Integer
  376. // editor returns only the index of the selected option and not the value
  377. returnIndex: -1,
  378. constructor: function(inCell){
  379. this.values = this.values || this.options;
  380. },
  381. formatEditing: function(inDatum, inRowIndex){
  382. this.needFormatNode(inDatum, inRowIndex);
  383. var h = [ '<select class="dojoxGridSelect">' ];
  384. for (var i=0, o, v; ((o=this.options[i]) !== undefined)&&((v=this.values[i]) !== undefined); i++){
  385. v = v.replace ? v.replace(/&/g, '&amp;').replace(/</g, '&lt;') : v;
  386. o = o.replace ? o.replace(/&/g, '&amp;').replace(/</g, '&lt;') : o;
  387. h.push("<option", (inDatum==v ? ' selected' : ''), ' value="' + v + '"', ">", o, "</option>");
  388. }
  389. h.push('</select>');
  390. return h.join('');
  391. },
  392. getValue: function(inRowIndex){
  393. var n = this.getEditNode(inRowIndex);
  394. if(n){
  395. var i = n.selectedIndex, o = n.options[i];
  396. return this.returnIndex > -1 ? i : o.value || o.innerHTML;
  397. }
  398. }
  399. });
  400. dgc.Select.markupFactory = function(node, cell){
  401. dgc.Cell.markupFactory(node, cell);
  402. var d=dojo;
  403. var options = d.trim(d.attr(node, "options")||"");
  404. if(options){
  405. var o = options.split(',');
  406. if(o[0] != options){
  407. cell.options = o;
  408. }
  409. }
  410. var values = d.trim(d.attr(node, "values")||"");
  411. if(values){
  412. var v = values.split(',');
  413. if(v[0] != values){
  414. cell.values = v;
  415. }
  416. }
  417. };
  418. dojo.declare("dojox.grid.cells.AlwaysEdit", dgc.Cell, {
  419. // summary:
  420. // grid cell that is always in an editable state, regardless of grid editing state
  421. alwaysEditing: true,
  422. _formatNode: function(inDatum, inRowIndex){
  423. this.formatNode(this.getEditNode(inRowIndex), inDatum, inRowIndex);
  424. },
  425. applyStaticValue: function(inRowIndex){
  426. var e = this.grid.edit;
  427. e.applyCellEdit(this.getValue(inRowIndex), this, inRowIndex);
  428. e.start(this, inRowIndex, true);
  429. }
  430. });
  431. dgc.AlwaysEdit.markupFactory = function(node, cell){
  432. dgc.Cell.markupFactory(node, cell);
  433. };
  434. dojo.declare("dojox.grid.cells.Bool", dgc.AlwaysEdit, {
  435. // summary:
  436. // grid cell that provides a standard checkbox that is always on for editing
  437. _valueProp: "checked",
  438. formatEditing: function(inDatum, inRowIndex){
  439. return '<input class="dojoxGridInput" type="checkbox"' + (inDatum ? ' checked="checked"' : '') + ' style="width: auto" />';
  440. },
  441. doclick: function(e){
  442. if(e.target.tagName == 'INPUT'){
  443. this.applyStaticValue(e.rowIndex);
  444. }
  445. }
  446. });
  447. dgc.Bool.markupFactory = function(node, cell){
  448. dgc.AlwaysEdit.markupFactory(node, cell);
  449. };
  450. })();
  451. }