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);
|
}
|
});
|
});
|