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