_EditManager.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. define("dojox/grid/_EditManager", [
  2. "dojo/_base/lang",
  3. "dojo/_base/array",
  4. "dojo/_base/declare",
  5. "dojo/_base/connect",
  6. "dojo/_base/sniff",
  7. "./util"
  8. ], function(lang, array, declare, connect, has, util){
  9. return declare("dojox.grid._EditManager", null, {
  10. // summary:
  11. // Controls grid cell editing process. Owned by grid and used internally for editing.
  12. constructor: function(inGrid){
  13. // inGrid: dojox.Grid
  14. // The dojox.Grid this editor should be attached to
  15. this.grid = inGrid;
  16. if(has("ie")){
  17. this.connections = [connect.connect(document.body, "onfocus", lang.hitch(this, "_boomerangFocus"))];
  18. }else{
  19. this.connections = [connect.connect(this.grid, 'onBlur', this, 'apply')];
  20. }
  21. },
  22. info: {},
  23. destroy: function(){
  24. array.forEach(this.connections, connect.disconnect);
  25. },
  26. cellFocus: function(inCell, inRowIndex){
  27. // summary:
  28. // Invoke editing when cell is focused
  29. // inCell: cell object
  30. // Grid cell object
  31. // inRowIndex: Integer
  32. // Grid row index
  33. if(this.grid.singleClickEdit || this.isEditRow(inRowIndex)){
  34. // if same row or quick editing, edit
  35. this.setEditCell(inCell, inRowIndex);
  36. }else{
  37. // otherwise, apply any pending row edits
  38. this.apply();
  39. }
  40. // if dynamic or static editing...
  41. if(this.isEditing() || (inCell && inCell.editable && inCell.alwaysEditing)){
  42. // let the editor focus itself as needed
  43. this._focusEditor(inCell, inRowIndex);
  44. }
  45. },
  46. rowClick: function(e){
  47. if(this.isEditing() && !this.isEditRow(e.rowIndex)){
  48. this.apply();
  49. }
  50. },
  51. styleRow: function(inRow){
  52. if(inRow.index == this.info.rowIndex){
  53. inRow.customClasses += ' dojoxGridRowEditing';
  54. }
  55. },
  56. dispatchEvent: function(e){
  57. var c = e.cell, ed = (c && c["editable"]) ? c : 0;
  58. return ed && ed.dispatchEvent(e.dispatch, e);
  59. },
  60. // Editing
  61. isEditing: function(){
  62. // summary:
  63. // Indicates editing state of the grid.
  64. // returns: Boolean
  65. // True if grid is actively editing
  66. return this.info.rowIndex !== undefined;
  67. },
  68. isEditCell: function(inRowIndex, inCellIndex){
  69. // summary:
  70. // Indicates if the given cell is being edited.
  71. // inRowIndex: Integer
  72. // Grid row index
  73. // inCellIndex: Integer
  74. // Grid cell index
  75. // returns: Boolean
  76. // True if given cell is being edited
  77. return (this.info.rowIndex === inRowIndex) && (this.info.cell.index == inCellIndex);
  78. },
  79. isEditRow: function(inRowIndex){
  80. // summary:
  81. // Indicates if the given row is being edited.
  82. // inRowIndex: Integer
  83. // Grid row index
  84. // returns: Boolean
  85. // True if given row is being edited
  86. return this.info.rowIndex === inRowIndex;
  87. },
  88. setEditCell: function(inCell, inRowIndex){
  89. // summary:
  90. // Set the given cell to be edited
  91. // inRowIndex: Integer
  92. // Grid row index
  93. // inCell: Object
  94. // Grid cell object
  95. if(!this.isEditCell(inRowIndex, inCell.index) && this.grid.canEdit && this.grid.canEdit(inCell, inRowIndex)){
  96. this.start(inCell, inRowIndex, this.isEditRow(inRowIndex) || inCell.editable);
  97. }
  98. },
  99. _focusEditor: function(inCell, inRowIndex){
  100. util.fire(inCell, "focus", [inRowIndex]);
  101. },
  102. focusEditor: function(){
  103. if(this.isEditing()){
  104. this._focusEditor(this.info.cell, this.info.rowIndex);
  105. }
  106. },
  107. // implement fix for focus boomerang effect on IE
  108. _boomerangWindow: 500,
  109. _shouldCatchBoomerang: function(){
  110. return this._catchBoomerang > new Date().getTime();
  111. },
  112. _boomerangFocus: function(){
  113. //console.log("_boomerangFocus");
  114. if(this._shouldCatchBoomerang()){
  115. // make sure we don't utterly lose focus
  116. this.grid.focus.focusGrid();
  117. // let the editor focus itself as needed
  118. this.focusEditor();
  119. // only catch once
  120. this._catchBoomerang = 0;
  121. }
  122. },
  123. _doCatchBoomerang: function(){
  124. // give ourselves a few ms to boomerang IE focus effects
  125. if(has("ie")){this._catchBoomerang = new Date().getTime() + this._boomerangWindow;}
  126. },
  127. // end boomerang fix API
  128. start: function(inCell, inRowIndex, inEditing){
  129. if(!this._isValidInput()){
  130. return;
  131. }
  132. if(has("ie") < 9 && this.grid._autoHeight){
  133. this._avoidUpdate();//workaround for #11101
  134. }
  135. this.grid.beginUpdate();
  136. this.editorApply();
  137. if(this.isEditing() && !this.isEditRow(inRowIndex)){
  138. this.applyRowEdit();
  139. this.grid.updateRow(inRowIndex);
  140. }
  141. if(inEditing){
  142. this.info = { cell: inCell, rowIndex: inRowIndex };
  143. this.grid.doStartEdit(inCell, inRowIndex);
  144. this.grid.updateRow(inRowIndex);
  145. }else{
  146. this.info = {};
  147. }
  148. this.grid.endUpdate();
  149. // make sure we don't utterly lose focus
  150. this.grid.focus.focusGrid();
  151. // let the editor focus itself as needed
  152. this._focusEditor(inCell, inRowIndex);
  153. // give ourselves a few ms to boomerang IE focus effects
  154. this._doCatchBoomerang();
  155. },
  156. _editorDo: function(inMethod){
  157. var c = this.info.cell;
  158. //c && c.editor && c.editor[inMethod](c, this.info.rowIndex);
  159. if(c && c.editable){
  160. c[inMethod](this.info.rowIndex);
  161. }
  162. },
  163. editorApply: function(){
  164. this._editorDo("apply");
  165. },
  166. editorCancel: function(){
  167. this._editorDo("cancel");
  168. },
  169. applyCellEdit: function(inValue, inCell, inRowIndex){
  170. if(this.grid.canEdit(inCell, inRowIndex)){
  171. this.grid.doApplyCellEdit(inValue, inRowIndex, inCell.field);
  172. }
  173. },
  174. applyRowEdit: function(){
  175. this.grid.doApplyEdit(this.info.rowIndex, this.info.cell.field);
  176. },
  177. apply: function(){
  178. // summary:
  179. // Apply a grid edit
  180. if(this.isEditing() && this._isValidInput()){
  181. this.grid.beginUpdate();
  182. this.editorApply();
  183. this.applyRowEdit();
  184. this.info = {};
  185. this.grid.endUpdate();
  186. this.grid.focus.focusGrid();
  187. this._doCatchBoomerang();
  188. }
  189. },
  190. cancel: function(){
  191. // summary:
  192. // Cancel a grid edit
  193. if(this.isEditing()){
  194. this.grid.beginUpdate();
  195. this.editorCancel();
  196. this.info = {};
  197. this.grid.endUpdate();
  198. this.grid.focus.focusGrid();
  199. this._doCatchBoomerang();
  200. }
  201. },
  202. save: function(inRowIndex, inView){
  203. // summary:
  204. // Save the grid editing state
  205. // inRowIndex: Integer
  206. // Grid row index
  207. // inView: Object
  208. // Grid view
  209. var c = this.info.cell;
  210. if(this.isEditRow(inRowIndex) && (!inView || c.view==inView) && c.editable){
  211. c.save(c, this.info.rowIndex);
  212. }
  213. },
  214. restore: function(inView, inRowIndex){
  215. // summary:
  216. // Restores the grid editing state
  217. // inRowIndex: Integer
  218. // Grid row index
  219. // inView: Object
  220. // Grid view
  221. var c = this.info.cell;
  222. if(this.isEditRow(inRowIndex) && c.view == inView && c.editable){
  223. c.restore(this.info.rowIndex);
  224. }
  225. },
  226. _isValidInput: function(){
  227. var w = (this.info.cell || {}).widget;
  228. if(!w || !w.isValid){
  229. //no validation needed
  230. return true;
  231. }
  232. w.focused = true;
  233. return w.isValid(true);
  234. },
  235. _avoidUpdate: function(){
  236. // Use a flag to temporarily skip grid.update() so that dijit.form.Form.resize()
  237. // or similar containers will not result into a deadlock(see #11101)
  238. var self = this;
  239. self._noUpdate = true;
  240. if(self._avoidUpdateHandler){
  241. clearTimeout(self._avoidUpdateHandler);
  242. }
  243. self._avoidUpdateHandler = setTimeout(function(){
  244. self._noUpdate = false;
  245. }, 100);
  246. }
  247. });
  248. });