IndirectSelection.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  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.enhanced.plugins.IndirectSelection"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.grid.enhanced.plugins.IndirectSelection"] = true;
  8. dojo.provide("dojox.grid.enhanced.plugins.IndirectSelection");
  9. dojo.require('dojo.string');
  10. dojo.require("dojox.grid.cells.dijit");
  11. dojo.require("dojox.grid.enhanced._Plugin");
  12. dojo.declare("dojox.grid.enhanced.plugins.IndirectSelection", dojox.grid.enhanced._Plugin, {
  13. // summary:
  14. // A handy way for adding check boxe/radio button for rows, and selecting rows by swiping(or keyboard)
  15. // description:
  16. // For better rendering performance, div(images) are used to simulate radio button|check boxes
  17. //
  18. // example:
  19. // <div dojoType="dojox.grid.EnhancedGrid" plugins="{indirectSelection: true}" ...></div>
  20. // or <div dojoType="dojox.grid.EnhancedGrid" plugins="{indirectSelection: {name: 'xxx', width:'30px', styles:'text-align: center;'}}" ...></div>
  21. //name: String
  22. // Plugin name
  23. name: "indirectSelection",
  24. constructor: function(){
  25. //Hook layout.setStructure(), so that indirectSelection is always included
  26. var layout = this.grid.layout;
  27. this.connect(layout, 'setStructure', dojo.hitch(layout, this.addRowSelectCell, this.option));
  28. },
  29. addRowSelectCell: function(option){
  30. // summary:
  31. // Add indirectSelection cell(mapped to a column of radio button|check boxes)
  32. if(!this.grid.indirectSelection || this.grid.selectionMode == 'none'){
  33. return;
  34. }
  35. var rowSelectCellAdded = false, inValidFields = ['get', 'formatter', 'field', 'fields'],
  36. defaultCellDef = {type: dojox.grid.cells.MultipleRowSelector, name: '', width:'30px', styles:'text-align: center;'};
  37. if(option.headerSelector){ option.name = ''; }//mutual conflicting attrs
  38. if(this.grid.rowSelectCell){//remove the existed one
  39. this.grid.rowSelectCell.destroy();
  40. }
  41. dojo.forEach(this.structure, function(view){
  42. var cells = view.cells;
  43. if(cells && cells.length > 0 && !rowSelectCellAdded){
  44. var firstRow = cells[0];
  45. if(firstRow[0] && firstRow[0].isRowSelector){
  46. console.debug('addRowSelectCell() - row selector cells already added, return.');
  47. rowSelectCellAdded = true;
  48. return;
  49. }
  50. var selectDef, cellType = this.grid.selectionMode == 'single' ? dojox.grid.cells.SingleRowSelector : dojox.grid.cells.MultipleRowSelector;
  51. selectDef = dojo.mixin(defaultCellDef, option, {type: cellType, editable: false, notselectable: true, filterable: false, navigatable: true, nosort: true});
  52. dojo.forEach(inValidFields, function(field){//remove invalid fields
  53. if(field in selectDef){ delete selectDef[field]; }
  54. });
  55. if(cells.length > 1){ selectDef.rowSpan = cells.length; }//for complicate layout
  56. dojo.forEach(this.cells, function(cell, i){
  57. if(cell.index >= 0){
  58. cell.index += 1;
  59. //console.debug('cell '+ (cell.index - 1) + ' is updated to index ' + cell.index);
  60. }else{
  61. console.warn('Error:IndirectSelection.addRowSelectCell()- cell ' + i + ' has no index!');
  62. }
  63. });
  64. var rowSelectCell = this.addCellDef(0, 0, selectDef);
  65. rowSelectCell.index = 0;
  66. firstRow.unshift(rowSelectCell);
  67. this.cells.unshift(rowSelectCell);
  68. this.grid.rowSelectCell = rowSelectCell;
  69. rowSelectCellAdded = true;
  70. }
  71. }, this);
  72. this.cellCount = this.cells.length;
  73. },
  74. destroy: function(){
  75. this.grid.rowSelectCell.destroy();
  76. delete this.grid.rowSelectCell;
  77. this.inherited(arguments);
  78. }
  79. });
  80. dojo.declare("dojox.grid.cells.RowSelector", dojox.grid.cells._Widget, {
  81. // summary:
  82. // Common attributes & functions for row selectors(Radio|CheckBox)
  83. //inputType: String
  84. // Input type - Radio|CheckBox
  85. inputType: "",
  86. //map: Object
  87. // Cache div refs of radio|checkbox to avoid querying each time
  88. map: null,
  89. //disabledMap: Object
  90. // Cache index of disabled rows
  91. disabledMap: null,
  92. //isRowSelector: Boolean
  93. // Marker of indirectSelection cell(column)
  94. isRowSelector: true,
  95. //_connects: Array
  96. // List of all connections.
  97. _connects: null,
  98. //_subscribes: Array
  99. // List of all subscribes.
  100. _subscribes: null,
  101. //checkedText: String
  102. // Checked character for high contrast mode
  103. checkedText: '&#8730;',
  104. //unCheckedText: String
  105. // Unchecked character for high contrast mode
  106. unCheckedText: 'O',
  107. constructor: function(){
  108. this.map = {}; this.disabledMap = {}, this.disabledCount= 0;
  109. this._connects = []; this._subscribes = [];
  110. this.inA11YMode = dojo.hasClass(dojo.body(), "dijit_a11y");
  111. this.baseClass = "dojoxGridRowSelector dijitReset dijitInline dijit" + this.inputType;
  112. this.checkedClass = " dijit" + this.inputType + "Checked";
  113. this.disabledClass = " dijit" + this.inputType + "Disabled";
  114. this.checkedDisabledClass = " dijit" + this.inputType + "CheckedDisabled";
  115. this.statusTextClass = " dojoxGridRowSelectorStatusText";//a11y use
  116. this._connects.push(dojo.connect(this.grid, 'dokeyup', this, '_dokeyup'));
  117. this._connects.push(dojo.connect(this.grid.selection, 'onSelected', this, '_onSelected'));
  118. this._connects.push(dojo.connect(this.grid.selection, 'onDeselected', this, '_onDeselected'));
  119. this._connects.push(dojo.connect(this.grid.scroller, 'invalidatePageNode', this, '_pageDestroyed'));
  120. this._connects.push(dojo.connect(this.grid, 'onCellClick', this, '_onClick'));
  121. this._connects.push(dojo.connect(this.grid, 'updateRow', this, '_onUpdateRow'));
  122. },
  123. formatter: function(data, rowIndex){
  124. // summary:
  125. // Overwritten, see dojox.grid.cells._Widget
  126. var clazz = this.baseClass;
  127. var checked = this.getValue(rowIndex);
  128. var disabled = !!this.disabledMap[rowIndex];//normalize 'undefined'
  129. if(checked){
  130. clazz += this.checkedClass;
  131. if(disabled){ clazz += this.checkedDisabledClass; }
  132. }else if(disabled){
  133. clazz += this.disabledClass;
  134. }
  135. return ["<div tabindex = -1 ",
  136. "id = '" + this.grid.id + "_rowSelector_" + rowIndex + "' ",
  137. "name = '" + this.grid.id + "_rowSelector' class = '" + clazz + "' ",
  138. "role = 'presentation' aria-pressed = '" + checked + "' aria-disabled = '" + disabled +
  139. "' aria-label = '" + dojo.string.substitute(this.grid._nls["indirectSelection" + this.inputType], [rowIndex + 1]) + "'>",
  140. "<span class = '" + this.statusTextClass + "'>" + (checked ? this.checkedText : this.unCheckedText) + "</span>",
  141. "</div>"].join("");
  142. },
  143. setValue: function(rowIndex, inValue){
  144. // summary:
  145. // Overwritten, see dojox.grid.cells._Widget
  146. // Simply return, no action
  147. },
  148. getValue: function(rowIndex){
  149. // summary:
  150. // Overwritten, see dojox.grid.cells._Widget
  151. return this.grid.selection.isSelected(rowIndex);
  152. },
  153. toggleRow: function(index, value){
  154. // summary:
  155. // toggle checked | unchecked state for given row
  156. // index: Integer
  157. // Row index
  158. // value: Boolean
  159. // True - checked | False - unchecked
  160. this._nativeSelect(index, value);
  161. },
  162. setDisabled: function(index, disabled){
  163. // summary:
  164. // toggle disabled | enabled state for given row
  165. // idx: Integer
  166. // Row index
  167. // disabled: Boolean
  168. // True - disabled | False - enabled
  169. if(index < 0){ return; }
  170. this._toggleDisabledStyle(index, disabled);
  171. },
  172. disabled: function(index){
  173. // summary:
  174. // Check if one row is disabled
  175. return !!this.disabledMap[index];
  176. },
  177. _onClick: function(e){
  178. // summary:
  179. // When mouse click on the selector cell, select/deselect the row.
  180. if(e.cell === this){
  181. this._selectRow(e);
  182. }
  183. },
  184. _dokeyup: function(e){
  185. // summary:
  186. // Event handler for key up event
  187. // - from dojox.grid.enhanced._Events.dokeyup()
  188. // e: Event
  189. // Key up event
  190. if(e.cellIndex == this.index && e.rowIndex >= 0 && e.keyCode == dojo.keys.SPACE){
  191. this._selectRow(e);
  192. }
  193. },
  194. focus: function(rowIndex){
  195. // summary:
  196. // Set focus to given row
  197. // rowIndex: Integer
  198. // Target row
  199. var selector = this.map[rowIndex];
  200. if(selector){ selector.focus(); }
  201. },
  202. _focusEndingCell: function(rowIndex, cellIndex){
  203. // summary:
  204. // Set focus to the ending grid cell(rowIndex,cellIndex) when swipe selection finished
  205. // rowIndex: Integer
  206. // Row index
  207. // cellIndex: Integer
  208. // Column index
  209. var cell = this.grid.getCell(cellIndex);
  210. this.grid.focus.setFocusCell(cell, rowIndex);
  211. },
  212. _nativeSelect: function(index, value){
  213. // summary:
  214. // Use grid's native selection
  215. this.grid.selection[value ? 'select' : 'deselect'](index);
  216. },
  217. _onSelected: function(index){
  218. // summary:
  219. // Triggered when a row is selected
  220. this._toggleCheckedStyle(index, true);
  221. },
  222. _onDeselected: function(index){
  223. // summary:
  224. // Triggered when a row is deselected
  225. this._toggleCheckedStyle(index, false);
  226. },
  227. _onUpdateRow: function(index){
  228. // summary:
  229. // Clear cache when row is re-built.
  230. delete this.map[index];
  231. },
  232. _toggleCheckedStyle: function(index, value){
  233. // summary:
  234. // Change css styles for checked | unchecked
  235. var selector = this._getSelector(index);
  236. if(selector){
  237. dojo.toggleClass(selector, this.checkedClass, value);
  238. if(this.disabledMap[index]){
  239. dojo.toggleClass(selector, this.checkedDisabledClass, value);
  240. }
  241. dijit.setWaiState(selector, 'pressed', value);
  242. if(this.inA11YMode){
  243. dojo.attr(selector.firstChild, 'innerHTML', value ? this.checkedText : this.unCheckedText);
  244. }
  245. }
  246. },
  247. _toggleDisabledStyle: function(index, disabled){
  248. // summary:
  249. // Change css styles for disabled | enabled
  250. var selector = this._getSelector(index);
  251. if(selector){
  252. dojo.toggleClass(selector, this.disabledClass, disabled);
  253. if(this.getValue(index)){
  254. dojo.toggleClass(selector, this.checkedDisabledClass, disabled);
  255. }
  256. dijit.setWaiState(selector, 'disabled', disabled);
  257. }
  258. this.disabledMap[index] = disabled;
  259. if(index >= 0){
  260. this.disabledCount += disabled ? 1 : -1;
  261. }
  262. },
  263. _getSelector: function(index){
  264. // summary:
  265. // Find selector for given row caching it if 1st time found
  266. var selector = this.map[index];
  267. if(!selector){//use accurate query for better performance
  268. var rowNode = this.view.rowNodes[index];
  269. if(rowNode){
  270. selector = dojo.query('.dojoxGridRowSelector', rowNode)[0];
  271. if(selector){ this.map[index] = selector; }
  272. }
  273. }
  274. return selector;
  275. },
  276. _pageDestroyed: function(pageIndex){
  277. // summary:
  278. // Explicitly empty map cache when a page destroyed
  279. // See dojox.grid._Scroller.invalidatePageNode()
  280. // pageIndex: Integer
  281. // Index of destroyed page
  282. var rowsPerPage = this.grid.scroller.rowsPerPage;
  283. var start = pageIndex * rowsPerPage, end = start + rowsPerPage - 1;
  284. for(var i = start; i <= end; i++){
  285. if(!this.map[i]){continue;}
  286. dojo.destroy(this.map[i]);
  287. delete this.map[i];
  288. }
  289. //console.log("Page ",pageIndex, " destroyed, Map=",this.map);
  290. },
  291. destroy: function(){
  292. for(var i in this.map){
  293. dojo.destroy(this.map[i]);
  294. delete this.map[i];
  295. }
  296. for(i in this.disabledMap){ delete this.disabledMap[i]; }
  297. dojo.forEach(this._connects, dojo.disconnect);
  298. dojo.forEach(this._subscribes, dojo.unsubscribe);
  299. delete this._connects;
  300. delete this._subscribes;
  301. //console.log('Single(Multiple)RowSelector.destroy() executed!');
  302. }
  303. });
  304. dojo.declare("dojox.grid.cells.SingleRowSelector", dojox.grid.cells.RowSelector, {
  305. // summary:
  306. // IndirectSelection cell(column) for single selection mode, using styles of dijit.form.RadioButton
  307. inputType: "Radio",
  308. _selectRow: function(e){
  309. // summary:
  310. // Select the target row
  311. // e: Event
  312. // Event fired on the target row
  313. var index = e.rowIndex;
  314. if(this.disabledMap[index]){ return; }
  315. this._focusEndingCell(index, 0);
  316. this._nativeSelect(index, !this.grid.selection.selected[index]);
  317. }
  318. });
  319. dojo.declare("dojox.grid.cells.MultipleRowSelector", dojox.grid.cells.RowSelector, {
  320. // summary:
  321. // Indirect selection cell for multiple or extended mode, using dijit.form.CheckBox
  322. inputType: "CheckBox",
  323. //swipeStartRowIndex: Integer
  324. // Start row index for swipe selection
  325. swipeStartRowIndex: -1,
  326. //swipeMinRowIndex: Integer
  327. // Min row index for swipe selection
  328. swipeMinRowIndex: -1,
  329. //swipeMinRowIndex: Integer
  330. // Max row index for swipe selection
  331. swipeMaxRowIndex: -1,
  332. //toSelect: Boolean
  333. // new state for selection
  334. toSelect: false,
  335. //lastClickRowIdx: Integer
  336. // Row index for last click, used for range selection via Shift + click
  337. lastClickRowIdx: -1,
  338. //toggleAllTrigerred: Boolean
  339. // Whether toggle all has been triggered or not
  340. toggleAllTrigerred: false,
  341. unCheckedText: '&#9633;',
  342. constructor: function(){
  343. this._connects.push(dojo.connect(dojo.doc, 'onmouseup', this, '_domouseup'));
  344. this._connects.push(dojo.connect(this.grid, 'onRowMouseOver', this, '_onRowMouseOver'));
  345. this._connects.push(dojo.connect(this.grid.focus, 'move', this, '_swipeByKey'));
  346. this._connects.push(dojo.connect(this.grid, 'onCellMouseDown', this, '_onMouseDown'));
  347. if(this.headerSelector){//option set by user to add a select-all checkbox in column header
  348. this._connects.push(dojo.connect(this.grid.views, 'render', this, '_addHeaderSelector'));
  349. this._connects.push(dojo.connect(this.grid, 'onSelectionChanged', this, '_onSelectionChanged'));
  350. this._connects.push(dojo.connect(this.grid, 'onKeyDown', this, function(e){
  351. if(e.rowIndex == -1 && e.cellIndex == this.index && e.keyCode == dojo.keys.SPACE){
  352. this._toggletHeader();//TBD - a better way
  353. }
  354. }));
  355. }
  356. },
  357. toggleAllSelection:function(checked){
  358. // summary:
  359. // Toggle select all|deselect all
  360. // checked: Boolean
  361. // True - select all, False - deselect all
  362. var grid = this.grid, selection = grid.selection;
  363. if(checked){
  364. selection.selectRange(0, grid.rowCount-1);
  365. }else{
  366. selection.deselectAll();
  367. }
  368. this.toggleAllTrigerred = true;
  369. },
  370. _onMouseDown: function(e){
  371. if(e.cell == this){
  372. this._startSelection(e.rowIndex);
  373. dojo.stopEvent(e);
  374. }
  375. },
  376. _onRowMouseOver: function(e){
  377. // summary:
  378. // Event fired when mouse moves over a data row(outside of this column).
  379. // - from dojox.grid.enhanced._Events.onRowMouseOver()
  380. // e: Event
  381. // Decorated event object which contains reference to grid, cell, and rowIndex
  382. this._updateSelection(e, 0);
  383. },
  384. _domouseup: function(e){
  385. // summary:
  386. // Event handler for mouse up event - from dojo.doc.domouseup()
  387. // e: Event
  388. // Mouse up event
  389. if(dojo.isIE){
  390. this.view.content.decorateEvent(e);//TODO - why only e in IE hasn't been decorated?
  391. }
  392. var inSwipeSelection = e.cellIndex >= 0 && this.inSwipeSelection() && !this.grid.edit.isEditRow(e.rowIndex);
  393. if(inSwipeSelection){
  394. this._focusEndingCell(e.rowIndex, e.cellIndex);
  395. }
  396. this._finishSelect();
  397. },
  398. _dokeyup: function(e){
  399. // summary:
  400. // Event handler for key up event
  401. // - from dojox.grid.enhanced._Events.dokeyup()
  402. // e: Event
  403. // Key up event
  404. this.inherited(arguments);
  405. if(!e.shiftKey){
  406. this._finishSelect();
  407. }
  408. },
  409. _startSelection: function(rowIndex){
  410. // summary:
  411. // Initialize parameters to start a new swipe selection
  412. // rowIndex: Integer
  413. // Index of the start row
  414. this.swipeStartRowIndex = this.swipeMinRowIndex = this.swipeMaxRowIndex = rowIndex;
  415. this.toSelect = !this.getValue(rowIndex);
  416. },
  417. _updateSelection: function(e, delta){
  418. // summary:
  419. // Update row selections, fired during a swipe selection
  420. // e: Event
  421. // Event of the current row,
  422. // delta: Integer
  423. // Row index delta, used for swipe selection via Shift + Arrow key
  424. // 0: not via key, -1 : Shift + Up, 1 : Shift + Down
  425. if(!this.inSwipeSelection()){ return; }
  426. var byKey = delta !== 0;//whether via Shift + Arrow Key
  427. var currRow = e.rowIndex, deltaRow = currRow - this.swipeStartRowIndex + delta;
  428. if(deltaRow > 0 && this.swipeMaxRowIndex < currRow + delta){
  429. this.swipeMaxRowIndex = currRow + delta;
  430. }
  431. if(deltaRow < 0 && this.swipeMinRowIndex > currRow + delta){
  432. this.swipeMinRowIndex = currRow + delta;
  433. }
  434. var min = deltaRow > 0 ? this.swipeStartRowIndex : currRow + delta;
  435. var max = deltaRow > 0 ? currRow + delta : this.swipeStartRowIndex;
  436. for(var i = this.swipeMinRowIndex; i <= this.swipeMaxRowIndex; i++){
  437. if(this.disabledMap[i] || i < 0){ continue; }
  438. if(i >= min && i <= max){//deltaRow != 0 || this.toSelect
  439. this._nativeSelect(i, this.toSelect);
  440. }else if(!byKey){
  441. this._nativeSelect(i, !this.toSelect);
  442. }
  443. }
  444. },
  445. _swipeByKey: function(rowOffset, colOffset, e){
  446. // summary:
  447. // Update row selections, fired when Shift + Cursor is used for swipe selection
  448. // See dojox.grid.enhanced._Events.onKeyDown
  449. // e: Event
  450. // Event of the current row,
  451. // rowOffset: Integer
  452. // Row offset, used for swipe selection via Shift + Cursor
  453. // -1 : Shift + Up, 1 : Shift + Down
  454. if(!e || rowOffset === 0 || !e.shiftKey || e.cellIndex != this.index ||
  455. this.grid.focus.rowIndex < 0){ //TBD - e.rowIndex == 0 && delta == -1
  456. return;
  457. }
  458. var rowIndex = e.rowIndex;
  459. if(this.swipeStartRowIndex < 0){
  460. //A new swipe selection starts via Shift + Arrow key
  461. this.swipeStartRowIndex = rowIndex;
  462. if(rowOffset > 0){//Shift + Down
  463. this.swipeMaxRowIndex = rowIndex + rowOffset;
  464. this.swipeMinRowIndex = rowIndex;
  465. }else{//Shift + UP
  466. this.swipeMinRowIndex = rowIndex + rowOffset;
  467. this.swipeMaxRowIndex = rowIndex;
  468. }
  469. this.toSelect = this.getValue(rowIndex);
  470. }
  471. this._updateSelection(e, rowOffset);
  472. },
  473. _finishSelect: function(){
  474. // summary:
  475. // Reset parameters to end a swipe selection
  476. this.swipeStartRowIndex = -1;
  477. this.swipeMinRowIndex = -1;
  478. this.swipeMaxRowIndex = -1;
  479. this.toSelect = false;
  480. },
  481. inSwipeSelection: function(){
  482. // summary:
  483. // Check if during a swipe selection
  484. // return: Boolean
  485. // Whether in swipe selection
  486. return this.swipeStartRowIndex >= 0;
  487. },
  488. _nativeSelect: function(index, value){
  489. // summary:
  490. // Overwritten
  491. this.grid.selection[value ? 'addToSelection' : 'deselect'](index);
  492. },
  493. _selectRow: function(e){
  494. // summary:
  495. // Select the target row or range or rows
  496. // e: Event
  497. // Event fired on the target row
  498. var rowIndex = e.rowIndex;
  499. if(this.disabledMap[rowIndex]){ return; }
  500. dojo.stopEvent(e);
  501. this._focusEndingCell(rowIndex, 0);
  502. var delta = rowIndex - this.lastClickRowIdx;
  503. var newValue = !this.grid.selection.selected[rowIndex];
  504. if(this.lastClickRowIdx >= 0 && !e.ctrlKey && !e.altKey && e.shiftKey){
  505. var min = delta > 0 ? this.lastClickRowIdx : rowIndex;
  506. var max = delta > 0 ? rowIndex : this.lastClickRowIdx;
  507. for(var i = min; i >= 0 && i <= max; i++){
  508. this._nativeSelect(i, newValue);
  509. }
  510. }else{
  511. this._nativeSelect(rowIndex, newValue);
  512. }
  513. this.lastClickRowIdx = rowIndex;
  514. },
  515. getValue: function(rowIndex){
  516. // summary:
  517. // Overwritten
  518. if(rowIndex == -1){//header selector
  519. var g = this.grid;
  520. return g.rowCount > 0 && g.rowCount <= g.selection.getSelectedCount();
  521. }
  522. return this.inherited(arguments);
  523. },
  524. _addHeaderSelector: function(){
  525. // summary:
  526. // Add selector in column header for selecting|deselecting all
  527. var headerCellNode = this.view.getHeaderCellNode(this.index);
  528. if(!headerCellNode){ return; }
  529. dojo.empty(headerCellNode);
  530. var g = this.grid;
  531. var selector = headerCellNode.appendChild(dojo.create("div", {
  532. "tabindex": -1, "id": g.id + "_rowSelector_-1", "class": this.baseClass, "role": "presentation",
  533. "innerHTML": "<span class = '" + this.statusTextClass +
  534. "'></span><span style='height: 0; width: 0; overflow: hidden; display: block;'>" +
  535. g._nls["selectAll"] + "</span>"
  536. }));
  537. this.map[-1] = selector;
  538. var idx = this._headerSelectorConnectIdx;
  539. if(idx !== undefined){
  540. dojo.disconnect(this._connects[idx]);
  541. this._connects.splice(idx, 1);
  542. }
  543. this._headerSelectorConnectIdx = this._connects.length;
  544. this._connects.push(dojo.connect(selector, 'onclick', this, '_toggletHeader'));
  545. this._onSelectionChanged();
  546. },
  547. _toggletHeader: function(){
  548. // summary:
  549. // Toggle state for head selector
  550. if(!!this.disabledMap[-1]){ return; }
  551. this.grid._selectingRange = true;
  552. this.toggleAllSelection(!this.getValue(-1));
  553. this._onSelectionChanged();
  554. this.grid._selectingRange = false;
  555. },
  556. _onSelectionChanged: function(){
  557. // summary:
  558. // Update header selector anytime selection changed
  559. var g = this.grid;
  560. if(!this.map[-1] || g._selectingRange){ return; }
  561. this._toggleCheckedStyle(-1, this.getValue(-1));
  562. },
  563. _toggleDisabledStyle: function(index, disabled){
  564. // summary:
  565. // Overwritten
  566. this.inherited(arguments);
  567. if(this.headerSelector){
  568. var allDisabled = (this.grid.rowCount == this.disabledCount);
  569. if(allDisabled != !!this.disabledMap[-1]){//only if needed
  570. arguments[0] = -1;
  571. arguments[1] = allDisabled;
  572. this.inherited(arguments);
  573. }
  574. }
  575. }
  576. });
  577. dojox.grid.EnhancedGrid.registerPlugin(dojox.grid.enhanced.plugins.IndirectSelection/*name:'indirectSelection'*/, {"preInit": true});
  578. }