IndirectSelection.js 21 KB

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