forked from SitePen/dgrid
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CellSelection.js
201 lines (188 loc) · 5.82 KB
/
CellSelection.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
define([
'dojo/_base/declare',
'dojo/aspect',
'dojo/dom-class',
'dojo/on',
'dojo/has',
'./Selection'
], function (declare, aspect, domClass, listen, has, Selection) {
return declare(Selection, {
// summary:
// Add cell level selection capabilities to a grid. The grid will have a selection property and
// fire "dgrid-select" and "dgrid-deselect" events.
// ensure we don't select when an individual cell is not identifiable
selectionDelegate: '.dgrid-cell',
_selectionTargetType: 'cells',
_select: function (cell, toCell, value) {
var i,
id;
if (typeof value === 'undefined') {
// default to true
value = true;
}
if (typeof cell !== 'object' || !('element' in cell)) {
cell = this.cell(cell);
}
else if (!cell.row) {
// Row object was passed instead of cell
if (value && typeof value === 'object') {
// value is a hash of true/false values
for (id in value) {
this._select(this.cell(cell.id, id), null, value[id]);
}
}
else {
// Select/deselect all columns in row
for (id in this.columns) {
this._select(this.cell(cell.id, id), null, value);
}
}
return;
}
if (this.allowSelect(cell)) {
var selection = this.selection,
rowId = cell.row.id,
previousRow = selection[rowId];
if (!cell.column) {
for (i in this.columns) {
this._select(this.cell(rowId, i), null, value);
}
return;
}
var previous = previousRow && previousRow[cell.column.id];
if (value === null) {
// indicates a toggle
value = !previous;
}
var element = cell.element;
previousRow = previousRow || {};
previousRow[cell.column.id] = value;
this.selection[rowId] = previousRow;
// Check for all-false objects to see if it can be deleted.
// This prevents build-up of unnecessary iterations later.
var hasSelected = false;
for (i in previousRow) {
if (previousRow[i] === true) {
hasSelected = true;
break;
}
}
if (!hasSelected) {
delete this.selection[rowId];
}
if (element) {
// add or remove classes as appropriate
if (value) {
domClass.add(element, 'dgrid-selected' +
(this.addUiClasses ? ' ui-state-active' : ''));
}
else {
domClass.remove(element, 'dgrid-selected ui-state-active');
}
}
/* jshint eqeqeq: false */
// This comparison could coerce if previous is undefined; TODO: rewrite
if (value != previous && element) {
this._selectionEventQueues[(value ? '' : 'de') + 'select'].push(cell);
}
if (toCell) {
if (!toCell.element) {
toCell = this.cell(toCell);
}
if (!toCell || !toCell.row) {
this._lastSelected = element;
console.warn('The selection range has been reset because the ' +
'beginning of the selection is no longer in the DOM. ' +
'If you are using OnDemandList, you may wish to increase ' +
'farOffRemoval to avoid this, but note that keeping more nodes ' +
'in the DOM may impact performance.');
return;
}
var toElement = toCell.element;
var fromElement = cell.element;
// Find if it is earlier or later in the DOM
var direction = this._determineSelectionDirection(fromElement, toElement);
if (!direction) {
// The original element was actually replaced
toCell = this.cell(
document.getElementById(toCell.row.element.id), toElement.columnId);
toElement = toCell && toCell.element;
direction = this._determineSelectionDirection(fromElement, toElement);
}
// now we determine which columns are in the range
var idFrom = cell.column.id,
idTo = toCell.column.id,
started,
columnIds = [];
for (id in this.columns) {
if (started) {
columnIds.push(id);
}
if (id === idFrom && (idFrom = columnIds) ||
id === idTo && (idTo = columnIds)) {
// Once found, mark it off so we don't hit it again
columnIds.push(id);
if (started || (idFrom == columnIds && id == idTo)) {
// We are done if we hit the last ID, or if the IDs are the same
break;
}
started = true;
}
}
// now we iterate over rows
var row = cell.row,
nextNode = row.element;
toElement = toCell.row.element;
do {
// looping through each row..
// and now loop through each column to be selected
for (i = 0; i < columnIds.length; i++) {
cell = this.cell(nextNode, columnIds[i]);
this._select(cell, null, value);
}
if (nextNode == toElement) {
break;
}
} while ((nextNode = cell.row.element[direction]));
}
}
},
_determineSelectionDirection: function () {
// Extend Selection to return next/previousSibling instead of down/up,
// given how CellSelection#_select is written
var result = this.inherited(arguments);
if (result === 'down') {
return 'nextSibling';
}
if (result === 'up') {
return 'previousSibling';
}
return result;
},
isSelected: function (object, columnId) {
// summary:
// Returns true if the indicated cell is selected.
if (typeof object === 'undefined' || object === null) {
return false;
}
if (!object.element) {
object = this.cell(object, columnId);
}
// First check whether the given cell is indicated in the selection hash;
// failing that, check if allSelected is true (testing against the
// allowSelect method if possible)
var rowId = object.row.id;
if (rowId in this.selection) {
return !!this.selection[rowId][object.column.id];
}
else {
return this.allSelected && (!object.row.data || this.allowSelect(object));
}
},
clearSelection: function (exceptId) {
// disable exceptId in cell selection, since it would require double parameters
exceptId = false;
this.inherited(arguments);
}
});
});