summaryrefslogtreecommitdiff
path: root/js/dojo-1.7.2/dojox/grid/enhanced/plugins/Selector.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/dojo-1.7.2/dojox/grid/enhanced/plugins/Selector.js')
-rw-r--r--js/dojo-1.7.2/dojox/grid/enhanced/plugins/Selector.js1477
1 files changed, 1477 insertions, 0 deletions
diff --git a/js/dojo-1.7.2/dojox/grid/enhanced/plugins/Selector.js b/js/dojo-1.7.2/dojox/grid/enhanced/plugins/Selector.js
new file mode 100644
index 0000000..c9e2574
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/grid/enhanced/plugins/Selector.js
@@ -0,0 +1,1477 @@
+//>>built
+define("dojox/grid/enhanced/plugins/Selector", [
+ "dojo/_base/kernel",
+ "dojo/_base/lang",
+ "dojo/_base/declare",
+ "dojo/_base/array",
+ "dojo/_base/event",
+ "dojo/keys",
+ "dojo/query",
+ "dojo/_base/html",
+ "dojo/_base/window",
+ "dijit/focus",
+ "../../_RowSelector",
+ "../_Plugin",
+ "../../EnhancedGrid",
+ "../../cells/_base",
+ "./AutoScroll"
+], function(dojo, lang, declare, array, event, keys, query, html, win, dijitFocus, _RowSelector, _Plugin, EnhancedGrid){
+
+/*=====
+dojo.declare("__SelectItem", null,{
+ // summary:
+ // An abstract representation of an item.
+});
+dojo.declare("__SelectCellItem", __SelectItem,{
+ // summary:
+ // An abstract representation of a cell.
+
+ // row: Integer
+ // Row index of this cell
+ row: 0,
+
+ // col: Integer
+ // Column index of this cell
+ col: 0
+});
+dojo.declare("__SelectRowItem", __SelectItem,{
+ // summary:
+ // An abstract representation of a row.
+
+ // row: Integer
+ // Row index of this row
+ row: 0,
+
+ // except: Integer[]
+ // An array of column indexes of all the unselected cells in this row.
+ except: []
+});
+dojo.declare("__SelectColItem", __SelectItem,{
+ // summary:
+ // An abstract representation of a column.
+
+ // col: Integer
+ // Column index of this column
+ col: 0,
+
+ // except: Integer[]
+ // An array of row indexes of all the unselected cells in this column.
+ except: []
+});
+=====*/
+
+var DISABLED = 0, SINGLE = 1, MULTI = 2,
+ _theOther = { col: "row", row: "col" },
+ _inRange = function(type, value, start, end, halfClose){
+ if(type !== "cell"){
+ value = value[type];
+ start = start[type];
+ end = end[type];
+ if(typeof value !== "number" || typeof start !== "number" || typeof end !== "number"){
+ return false;
+ }
+ return halfClose ? ((value >= start && value < end) || (value > end && value <= start))
+ : ((value >= start && value <= end) || (value >= end && value <= start));
+ }else{
+ return _inRange("col", value, start, end, halfClose) && _inRange("row", value, start, end, halfClose);
+ }
+ },
+ _isEqual = function(type, v1, v2){
+ try{
+ if(v1 && v2){
+ switch(type){
+ case "col": case "row":
+ return v1[type] == v2[type] && typeof v1[type] == "number" &&
+ !(_theOther[type] in v1) && !(_theOther[type] in v2);
+ case "cell":
+ return v1.col == v2.col && v1.row == v2.row && typeof v1.col == "number" && typeof v1.row == "number";
+ }
+ }
+ }catch(e){}
+ return false;
+ },
+ _stopEvent = function(evt){
+ try{
+ if(evt && evt.preventDefault){
+ event.stop(evt);
+ }
+ }catch(e){}
+ },
+ _createItem = function(type, rowIndex, colIndex){
+ switch(type){
+ case "col":
+ return {
+ "col": typeof colIndex == "undefined" ? rowIndex : colIndex,
+ "except": []
+ };
+ case "row":
+ return {
+ "row": rowIndex,
+ "except": []
+ };
+ case "cell":
+ return {
+ "row": rowIndex,
+ "col": colIndex
+ };
+ }
+ return null;
+ };
+var Selector = declare("dojox.grid.enhanced.plugins.Selector", _Plugin, {
+ // summary:
+ // Provides standard extended selection for grid.
+ // Supports mouse/keyboard selection, multi-selection, and de-selection.
+ // Acceptable plugin parameters:
+ // The whole plugin parameter object is a config object passed to the setupConfig function.
+ //
+ // Acceptable cell parameters defined in layout:
+ // 1. notselectable: boolean
+ // Whether this column is (and all the cells in it are) selectable.
+
+ // name: String
+ // plugin name
+ name: "selector",
+
+ // noClear: Boolean
+ // Not to clear rows selected by IndirectSelection.
+/*
+ // _config: null,
+ // _enabled: true,
+ // _selecting: {
+ // row: false,
+ // col: false,
+ // cell: false
+ // },
+ // _selected: {
+ // row: [],
+ // col: [],
+ // cell: []
+ // },
+ // _startPoint: {},
+ // _currentPoint: {},
+ // _lastAnchorPoint: {},
+ // _lastEndPoint: {},
+ // _lastSelectedAnchorPoint: {},
+ // _lastSelectedEndPoint: {},
+ // _keyboardSelect: {
+ // row: 0,
+ // col: 0,
+ // cell: 0
+ // },
+ // _curType: null,
+ // _lastType: null,
+ // _usingKeyboard: false,
+ // _toSelect: true,
+*/
+
+ constructor: function(grid, args){
+ this.grid = grid;
+ this._config = {
+ row: MULTI,
+ col: MULTI,
+ cell: MULTI
+ };
+ this.noClear = args && args.noClear;
+ this.setupConfig(args);
+ if(grid.selectionMode === "single"){
+ this._config.row = SINGLE;
+ }
+ this._enabled = true;
+ this._selecting = {};
+ this._selected = {
+ "col": [],
+ "row": [],
+ "cell": []
+ };
+ this._startPoint = {};
+ this._currentPoint = {};
+ this._lastAnchorPoint = {};
+ this._lastEndPoint = {};
+ this._lastSelectedAnchorPoint = {};
+ this._lastSelectedEndPoint = {};
+ this._keyboardSelect = {};
+ this._lastType = null;
+ this._selectedRowModified = {};
+ this._hacks();
+ this._initEvents();
+ this._initAreas();
+ this._mixinGrid();
+ },
+ destroy: function(){
+ this.inherited(arguments);
+ },
+ //------------public--------------------
+ setupConfig: function(config){
+ // summary:
+ // Set selection mode for row/col/cell.
+ // config: Object
+ // An object with the following structure (all properties are optional):
+ // {
+ // //Default is "multi", all other values are same as "multi".
+ // row: false|"disabled"|"single",
+ // col: false|"disabled"|"single",
+ // cell: false|"disabled"|"single"
+ // }
+ if(!config || !lang.isObject(config)){
+ return;
+ }
+ var types = ["row", "col", "cell"];
+ for(var type in config){
+ if(array.indexOf(types, type) >= 0){
+ if(!config[type] || config[type] == "disabled"){
+ this._config[type] = DISABLED;
+ }else if(config[type] == "single"){
+ this._config[type] = SINGLE;
+ }else{
+ this._config[type] = MULTI;
+ }
+ }
+ }
+
+ //Have to set mode to default grid selection.
+ var mode = ["none","single","extended"][this._config.row];
+ this.grid.selection.setMode(mode);
+ },
+ isSelected: function(type, rowIndex, colIndex){
+ // summary:
+ // Check whether a location (a cell, a column or a row) is selected.
+ // tag:
+ // public
+ // type: String
+ // "row" or "col" or "cell"
+ // rowIndex: Integer
+ // If type is "row" or "cell", this is the row index.
+ // If type if "col", this is the column index.
+ // colIndex: Integer?
+ // Only valid when type is "cell"
+ // return: Boolean
+ // true if selected, false if not. If cell is covered by a selected column, it's selected.
+ return this._isSelected(type, _createItem(type, rowIndex, colIndex));
+ },
+ toggleSelect: function(type, rowIndex, colIndex){
+ this._startSelect(type, _createItem(type, rowIndex, colIndex), this._config[type] === MULTI, false, false, !this.isSelected(type, rowIndex, colIndex));
+ this._endSelect(type);
+ },
+ select: function(type, rowIndex, colIndex){
+ // summary:
+ // Select a location (a cell, a column or a row).
+ // tag:
+ // public
+ // type: String
+ // "row" or "col" or "cell"
+ // rowIndex: Integer
+ // If type is "row" or "cell", this is the row index.
+ // If type if "col", this is the column index.
+ // colIndex: Integer?
+ // Only valid when type is "cell"
+ if(!this.isSelected(type, rowIndex, colIndex)){
+ this.toggleSelect(type, rowIndex, colIndex);
+ }
+ },
+ deselect: function(type, rowIndex, colIndex){
+ if(this.isSelected(type, rowIndex, colIndex)){
+ this.toggleSelect(type, rowIndex, colIndex);
+ }
+ },
+ selectRange: function(type, start, end, toSelect){
+ // summary:
+ // Select a continuous range (a block of cells, a set of continuous columns or rows)
+ // tag:
+ // public
+ // type: String
+ // "row" or "col" or "cell"
+ // start: Integer | Object
+ // If type is "row" or "col", this is the index of the starting row or column.
+ // If type if "cell", this is the left-top cell of the range.
+ // end: Integer | Object
+ // If type is "row" or "col", this is the index of the ending row or column.
+ // If type if "cell", this is the right-bottom cell of the range.
+ this.grid._selectingRange = true;
+ var startPoint = type == "cell" ? _createItem(type, start.row, start.col) : _createItem(type, start),
+ endPoint = type == "cell" ? _createItem(type, end.row, end.col) : _createItem(type, end);
+ this._startSelect(type, startPoint, false, false, false, toSelect);
+ this._highlight(type, endPoint, toSelect === undefined ? true : toSelect);
+ this._endSelect(type);
+ this.grid._selectingRange = false;
+ },
+ clear: function(type){
+ // summary:
+ // Clear all selections.
+ // tag:
+ // public
+ // type: String?
+ // "row" or "col" or "cell". If omitted, clear all.
+ this._clearSelection(type || "all");
+ },
+ isSelecting: function(type){
+ // summary:
+ // Check whether the user is currently selecting something.
+ // tag:
+ // public
+ // type: String
+ // "row" or "col" or "cell"
+ // return: Boolean
+ // true if is selection, false otherwise.
+ if(typeof type == "undefined"){
+ return this._selecting.col || this._selecting.row || this._selecting.cell;
+ }
+ return this._selecting[type];
+ },
+ selectEnabled: function(toEnable){
+ // summary:
+ // Turn on/off this selection functionality if *toEnable* is provided.
+ // Check whether this selection functionality is enabled if nothing is passed in.
+ // tag:
+ // public
+ // toEnable: Boolean?
+ // To enable or not. Optional.
+ // return: Boolean | undefined
+ // Enabled or not.
+ if(typeof toEnable != "undefined" && !this.isSelecting()){
+ this._enabled = !!toEnable;
+ }
+ return this._enabled;
+ },
+ getSelected: function(type, includeExceptions){
+ // summary:
+ // Get an array of selected locations.
+ // tag:
+ // public
+ // type: String
+ // "row" or "col" or "cell"
+ // includeExceptions: Boolean
+ // Only meaningful for rows/columns. If true, all selected rows/cols, even they are partly selected, are all returned.
+ // return: __SelectItem[]
+ switch(type){
+ case "cell":
+ return array.map(this._selected[type], function(item){ return item; });
+ case "col": case "row":
+ return array.map(includeExceptions ? this._selected[type]
+ : array.filter(this._selected[type], function(item){
+ return item.except.length === 0;
+ }), function(item){
+ return includeExceptions ? item : item[type];
+ });
+ }
+ return [];
+ },
+ getSelectedCount: function(type, includeExceptions){
+ // summary:
+ // Get the number of selected items.
+ // tag:
+ // public
+ // type: String
+ // "row" or "col" or "cell"
+ // includeExceptions: Boolean
+ // Only meaningful for rows/columns. If true, all selected rows/cols, even they are partly selected, are all returned.
+ // return: Integer
+ // The number of selected items.
+ switch(type){
+ case "cell":
+ return this._selected[type].length;
+ case "col": case "row":
+ return (includeExceptions ? this._selected[type]
+ : array.filter(this._selected[type], function(item){
+ return item.except.length === 0;
+ })).length;
+ }
+ return 0;
+ },
+ getSelectedType: function(){
+ // summary:
+ // Get the type of selected items.
+ // tag:
+ // public
+ // return: String
+ // "row" or "col" or "cell", or any mix of these (separator is | ).
+ var s = this._selected;
+ return ["", "cell", "row", "row|cell",
+ "col", "col|cell", "col|row", "col|row|cell"
+ ][(!!s.cell.length) | (!!s.row.length << 1) | (!!s.col.length << 2)];
+ },
+ getLastSelectedRange: function(type){
+ // summary:
+ // Get last selected range of the given type.
+ // tag:
+ // public
+ // return: Object
+ // {start: __SelectItem, end: __SelectItem}
+ // return null if nothing is selected.
+ return this._lastAnchorPoint[type] ? {
+ "start": this._lastAnchorPoint[type],
+ "end": this._lastEndPoint[type]
+ } : null;
+ },
+
+ //--------------------------private----------------------------
+ _hacks: function(){
+ // summary:
+ // Complete the event system of grid, hack some grid functions to prevent default behavior.
+ var g = this.grid;
+ var doContentMouseUp = function(e){
+ if(e.cellNode){
+ g.onMouseUp(e);
+ }
+ g.onMouseUpRow(e);
+ };
+ var mouseUp = lang.hitch(g, "onMouseUp");
+ var mouseDown = lang.hitch(g, "onMouseDown");
+ var doRowSelectorFocus = function(e){
+ e.cellNode.style.border = "solid 1px";
+ };
+ array.forEach(g.views.views, function(view){
+ view.content.domouseup = doContentMouseUp;
+ view.header.domouseup = mouseUp;
+ if(view.declaredClass == "dojox.grid._RowSelector"){
+ view.domousedown = mouseDown;
+ view.domouseup = mouseUp;
+ view.dofocus = doRowSelectorFocus;
+ }
+ });
+ //Disable default selection.
+ g.selection.clickSelect = function(){};
+
+ this._oldDeselectAll = g.selection.deselectAll;
+ var _this = this;
+ g.selection.selectRange = function(from, to){
+ _this.selectRange("row", from, to, true);
+ if(g.selection.preserver){
+ g.selection.preserver._updateMapping(true, true, false, from, to);
+ }
+ g.selection.onChanged();
+ };
+ g.selection.deselectRange = function(from, to){
+ _this.selectRange("row", from, to, false);
+ if(g.selection.preserver){
+ g.selection.preserver._updateMapping(true, false, false, from, to);
+ }
+ g.selection.onChanged();
+ };
+ g.selection.deselectAll = function(){
+ g._selectingRange = true;
+ _this._oldDeselectAll.apply(g.selection, arguments);
+ _this._clearSelection("all");
+ g._selectingRange = false;
+ if(g.selection.preserver){
+ g.selection.preserver._updateMapping(true, false, true);
+ }
+ g.selection.onChanged();
+ };
+
+ var rowSelector = g.views.views[0];
+ //The default function re-write the whole className, so can not insert any other classes.
+ if(rowSelector instanceof _RowSelector){
+ rowSelector.doStyleRowNode = function(inRowIndex, inRowNode){
+ html.removeClass(inRowNode, "dojoxGridRow");
+ html.addClass(inRowNode, "dojoxGridRowbar");
+ html.addClass(inRowNode, "dojoxGridNonNormalizedCell");
+ html.toggleClass(inRowNode, "dojoxGridRowbarOver", g.rows.isOver(inRowIndex));
+ html.toggleClass(inRowNode, "dojoxGridRowbarSelected", !!g.selection.isSelected(inRowIndex));
+ };
+ }
+ this.connect(g, "updateRow", function(rowIndex){
+ array.forEach(g.layout.cells, function(cell){
+ if(this.isSelected("cell", rowIndex, cell.index)){
+ this._highlightNode(cell.getNode(rowIndex), true);
+ }
+ }, this);
+ });
+ },
+ _mixinGrid: function(){
+ // summary:
+ // Expose events to grid.
+ var g = this.grid;
+ g.setupSelectorConfig = lang.hitch(this, this.setupConfig);
+ g.onStartSelect = function(){};
+ g.onEndSelect = function(){};
+ g.onStartDeselect = function(){};
+ g.onEndDeselect = function(){};
+ g.onSelectCleared = function(){};
+ },
+ _initEvents: function(){
+ // summary:
+ // Connect events, create event handlers.
+ var g = this.grid,
+ _this = this,
+ dp = lang.partial,
+ starter = function(type, e){
+ if(type === "row"){
+ _this._isUsingRowSelector = true;
+ }
+ //only left mouse button can select.
+ if(_this.selectEnabled() && _this._config[type] && e.button != 2){
+ if(_this._keyboardSelect.col || _this._keyboardSelect.row || _this._keyboardSelect.cell){
+ _this._endSelect("all");
+ _this._keyboardSelect.col = _this._keyboardSelect.row = _this._keyboardSelect.cell = 0;
+ }
+ if(_this._usingKeyboard){
+ _this._usingKeyboard = false;
+ }
+ var target = _createItem(type, e.rowIndex, e.cell && e.cell.index);
+ _this._startSelect(type, target, e.ctrlKey, e.shiftKey);
+ }
+ },
+ ender = lang.hitch(this, "_endSelect");
+ this.connect(g, "onHeaderCellMouseDown", dp(starter, "col"));
+ this.connect(g, "onHeaderCellMouseUp", dp(ender, "col"));
+
+ this.connect(g, "onRowSelectorMouseDown", dp(starter, "row"));
+ this.connect(g, "onRowSelectorMouseUp", dp(ender, "row"));
+
+ this.connect(g, "onCellMouseDown", function(e){
+ if(e.cell && e.cell.isRowSelector){ return; }
+ if(g.singleClickEdit){
+ _this._singleClickEdit = true;
+ g.singleClickEdit = false;
+ }
+ starter(_this._config["cell"] == DISABLED ? "row" : "cell", e);
+ });
+ this.connect(g, "onCellMouseUp", function(e){
+ if(_this._singleClickEdit){
+ delete _this._singleClickEdit;
+ g.singleClickEdit = true;
+ }
+ ender("all", e);
+ });
+
+ this.connect(g, "onCellMouseOver", function(e){
+ if(_this._curType != "row" && _this._selecting[_this._curType] && _this._config[_this._curType] == MULTI){
+ _this._highlight("col", _createItem("col", e.cell.index), _this._toSelect);
+ if(!_this._keyboardSelect.cell){
+ _this._highlight("cell", _createItem("cell", e.rowIndex, e.cell.index), _this._toSelect);
+ }
+ }
+ });
+ this.connect(g, "onHeaderCellMouseOver", function(e){
+ if(_this._selecting.col && _this._config.col == MULTI){
+ _this._highlight("col", _createItem("col", e.cell.index), _this._toSelect);
+ }
+ });
+ this.connect(g, "onRowMouseOver", function(e){
+ if(_this._selecting.row && _this._config.row == MULTI){
+ _this._highlight("row", _createItem("row", e.rowIndex), _this._toSelect);
+ }
+ });
+
+ //When row order has changed in a unpredictable way (sorted or filtered), map the new rowindex.
+ this.connect(g, "onSelectedById", "_onSelectedById");
+
+ //When the grid refreshes, all those selected should still appear selected.
+ this.connect(g, "_onFetchComplete", function(){
+ //console.debug("refresh after buildPage:", g._notRefreshSelection);
+ if(!g._notRefreshSelection){
+ this._refreshSelected(true);
+ }
+ });
+
+ //Small scroll might not refresh the grid.
+ this.connect(g.scroller, "buildPage", function(){
+ //console.debug("refresh after buildPage:", g._notRefreshSelection);
+ if(!g._notRefreshSelection){
+ this._refreshSelected(true);
+ }
+ });
+
+ //Whenever the mouse is up, end selecting.
+ this.connect(win.doc, "onmouseup", dp(ender, "all"));
+
+ //If autoscroll is enabled, connect to it.
+ this.connect(g, "onEndAutoScroll", function(isVertical, isForward, view, target){
+ var selectCell = _this._selecting.cell,
+ type, current, dir = isForward ? 1 : -1;
+ if(isVertical && (selectCell || _this._selecting.row)){
+ type = selectCell ? "cell" : "row";
+ current = _this._currentPoint[type];
+ _this._highlight(type, _createItem(type, current.row + dir, current.col), _this._toSelect);
+ }else if(!isVertical && (selectCell || _this._selecting.col)){
+ type = selectCell ? "cell" : "col";
+ current = _this._currentPoint[type];
+ _this._highlight(type, _createItem(type, current.row, target), _this._toSelect);
+ }
+ });
+ //If the grid is changed, selection should be consistent.
+ this.subscribe("dojox/grid/rearrange/move/" + g.id, "_onInternalRearrange");
+ this.subscribe("dojox/grid/rearrange/copy/" + g.id, "_onInternalRearrange");
+ this.subscribe("dojox/grid/rearrange/change/" + g.id, "_onExternalChange");
+ this.subscribe("dojox/grid/rearrange/insert/" + g.id, "_onExternalChange");
+ this.subscribe("dojox/grid/rearrange/remove/" + g.id, "clear");
+
+ //have to also select when the grid's default select is used.
+ this.connect(g, "onSelected", function(rowIndex){
+ if(this._selectedRowModified && this._isUsingRowSelector){
+ delete this._selectedRowModified;
+ }else if(!this.grid._selectingRange){
+ this.select("row", rowIndex);
+ }
+ });
+ this.connect(g, "onDeselected", function(rowIndex){
+ if(this._selectedRowModified && this._isUsingRowSelector){
+ delete this._selectedRowModified;
+ }else if(!this.grid._selectingRange){
+ this.deselect("row", rowIndex);
+ }
+ });
+ },
+ _onSelectedById: function(id, newIndex, isSelected){
+ if(this.grid._noInternalMapping){
+ return;
+ }
+ var pointSet = [this._lastAnchorPoint.row, this._lastEndPoint.row,
+ this._lastSelectedAnchorPoint.row, this._lastSelectedEndPoint.row];
+ pointSet = pointSet.concat(this._selected.row);
+ var found = false;
+ array.forEach(pointSet, function(item){
+ if(item){
+ if(item.id === id){
+ found = true;
+ item.row = newIndex;
+ }else if(item.row === newIndex && item.id){
+ item.row = -1;
+ }
+ }
+ });
+ if(!found && isSelected){
+ array.some(this._selected.row, function(item){
+ if(item && !item.id && !item.except.length){
+ item.id = id;
+ item.row = newIndex;
+ return true;
+ }
+ return false;
+ });
+ }
+ found = false;
+ pointSet = [this._lastAnchorPoint.cell, this._lastEndPoint.cell,
+ this._lastSelectedAnchorPoint.cell, this._lastSelectedEndPoint.cell];
+ pointSet = pointSet.concat(this._selected.cell);
+ array.forEach(pointSet, function(item){
+ if(item){
+ if(item.id === id){
+ found = true;
+ item.row = newIndex;
+ }else if(item.row === newIndex && item.id){
+ item.row = -1;
+ }
+ }
+ });
+ },
+ onSetStore: function(){
+ this._clearSelection("all");
+ },
+ _onInternalRearrange: function(type, mapping){
+ try{
+ //The column can not refresh it self!
+ this._refresh("col", false);
+
+ array.forEach(this._selected.row, function(item){
+ array.forEach(this.grid.layout.cells, function(cell){
+ this._highlightNode(cell.getNode(item.row), false);
+ }, this);
+ }, this);
+ //The rowbar must be cleaned manually
+ query(".dojoxGridRowSelectorSelected").forEach(function(node){
+ html.removeClass(node, "dojoxGridRowSelectorSelected");
+ html.removeClass(node, "dojoxGridRowSelectorSelectedUp");
+ html.removeClass(node, "dojoxGridRowSelectorSelectedDown");
+ });
+
+ var cleanUp = function(item){
+ if(item){
+ delete item.converted;
+ }
+ },
+ pointSet = [this._lastAnchorPoint[type], this._lastEndPoint[type],
+ this._lastSelectedAnchorPoint[type], this._lastSelectedEndPoint[type]];
+
+ if(type === "cell"){
+ this.selectRange("cell", mapping.to.min, mapping.to.max);
+ var cells = this.grid.layout.cells;
+ array.forEach(pointSet, function(item){
+ if(item.converted){ return; }
+ for(var r = mapping.from.min.row, tr = mapping.to.min.row; r <= mapping.from.max.row; ++r, ++tr){
+ for(var c = mapping.from.min.col, tc = mapping.to.min.col; c <= mapping.from.max.col; ++c, ++tc){
+ while(cells[c].hidden){ ++c; }
+ while(cells[tc].hidden){ ++tc; }
+ if(item.row == r && item.col == c){
+ //console.log('mapping found: (', item.row, ",",item.col,") to (", tr, ",", tc,")");
+ item.row = tr;
+ item.col = tc;
+ item.converted = true;
+ return;
+ }
+ }
+ }
+ });
+ }else{
+ pointSet = this._selected.cell.concat(this._selected[type]).concat(pointSet).concat(
+ [this._lastAnchorPoint.cell, this._lastEndPoint.cell,
+ this._lastSelectedAnchorPoint.cell, this._lastSelectedEndPoint.cell]);
+ array.forEach(pointSet, function(item){
+ if(item && !item.converted){
+ var from = item[type];
+ if(from in mapping){
+ item[type] = mapping[from];
+ }
+ item.converted = true;
+ }
+ });
+ array.forEach(this._selected[_theOther[type]], function(item){
+ for(var i = 0, len = item.except.length; i < len; ++i){
+ var from = item.except[i];
+ if(from in mapping){
+ item.except[i] = mapping[from];
+ }
+ }
+ });
+ }
+
+ array.forEach(pointSet, cleanUp);
+
+ this._refreshSelected(true);
+ this._focusPoint(type, this._lastEndPoint);
+ }catch(e){
+ console.warn("Selector._onInternalRearrange() error",e);
+ }
+ },
+ _onExternalChange: function(type, target){
+ var start = type == "cell" ? target.min : target[0],
+ end = type == "cell" ? target.max : target[target.length - 1];
+ this.selectRange(type, start, end);
+ },
+ _refresh: function(type, toHighlight){
+ if(!this._keyboardSelect[type]){
+ array.forEach(this._selected[type], function(item){
+ this._highlightSingle(type, toHighlight, item, undefined, true);
+ }, this);
+ }
+ },
+ _refreshSelected: function(){
+ this._refresh("col", true);
+ this._refresh("row", true);
+ this._refresh("cell", true);
+ },
+ _initAreas: function(){
+ var g = this.grid, f = g.focus, _this = this,
+ keyboardSelectReady = 1, duringKeyboardSelect = 2,
+ onmove = function(type, createNewEnd, rowStep, colStep, evt){
+ //Keyboard swipe selection is SHIFT + Direction Keys.
+ var ks = _this._keyboardSelect;
+ //Tricky, rely on valid status not being 0.
+ if(evt.shiftKey && ks[type]){
+ if(ks[type] === keyboardSelectReady){
+ if(type === "cell"){
+ var item = _this._lastEndPoint[type];
+ if(f.cell != g.layout.cells[item.col + colStep] || f.rowIndex != item.row + rowStep){
+ ks[type] = 0;
+ return;
+ }
+ }
+ //If selecting is not started, start it
+ _this._startSelect(type, _this._lastAnchorPoint[type], true, false, true);
+ _this._highlight(type, _this._lastEndPoint[type], _this._toSelect);
+ ks[type] = duringKeyboardSelect;
+ }
+ //Highlight to the new end point.
+ var newEnd = createNewEnd(type, rowStep, colStep, evt);
+ if(_this._isValid(type, newEnd, g)){
+ _this._highlight(type, newEnd, _this._toSelect);
+ }
+ _stopEvent(evt);
+ }
+ },
+ onkeydown = function(type, getTarget, evt, isBubble){
+ if(isBubble && _this.selectEnabled() && _this._config[type] != DISABLED){
+ switch(evt.keyCode){
+ case keys.SPACE:
+ //Keyboard single point selection is SPACE.
+ _this._startSelect(type, getTarget(), evt.ctrlKey, evt.shiftKey);
+ _this._endSelect(type);
+ break;
+ case keys.SHIFT:
+ //Keyboard swipe selection starts with SHIFT.
+ if(_this._config[type] == MULTI && _this._isValid(type, _this._lastAnchorPoint[type], g)){
+ //End last selection if any.
+ _this._endSelect(type);
+ _this._keyboardSelect[type] = keyboardSelectReady;
+ _this._usingKeyboard = true;
+ }
+ }
+ }
+ },
+ onkeyup = function(type, evt, isBubble){
+ if(isBubble && evt.keyCode == keys.SHIFT && _this._keyboardSelect[type]){
+ _this._endSelect(type);
+ _this._keyboardSelect[type] = 0;
+ }
+ };
+ //TODO: this area "rowHeader" should be put outside, same level as header/content.
+ if(g.views.views[0] instanceof _RowSelector){
+ this._lastFocusedRowBarIdx = 0;
+ f.addArea({
+ name:"rowHeader",
+ onFocus: function(evt, step){
+ var view = g.views.views[0];
+ if(view instanceof _RowSelector){
+ var rowBarNode = view.getCellNode(_this._lastFocusedRowBarIdx, 0);
+ if(rowBarNode){
+ html.toggleClass(rowBarNode, f.focusClass, false);
+ }
+ //evt might not be real event, it may be a mock object instead.
+ if(evt && "rowIndex" in evt){
+ if(evt.rowIndex >= 0){
+ _this._lastFocusedRowBarIdx = evt.rowIndex;
+ }else if(!_this._lastFocusedRowBarIdx){
+ _this._lastFocusedRowBarIdx = 0;
+ }
+ }
+ rowBarNode = view.getCellNode(_this._lastFocusedRowBarIdx, 0);
+ if(rowBarNode){
+ dijitFocus.focus(rowBarNode);
+ html.toggleClass(rowBarNode, f.focusClass, true);
+ }
+ f.rowIndex = _this._lastFocusedRowBarIdx;
+ _stopEvent(evt);
+ return true;
+ }
+ return false;
+ },
+ onBlur: function(evt, step){
+ var view = g.views.views[0];
+ if(view instanceof _RowSelector){
+ var rowBarNode = view.getCellNode(_this._lastFocusedRowBarIdx, 0);
+ if(rowBarNode){
+ html.toggleClass(rowBarNode, f.focusClass, false);
+ }
+ _stopEvent(evt);
+ }
+ return true;
+ },
+ onMove: function(rowStep, colStep, evt){
+ var view = g.views.views[0];
+ if(rowStep && view instanceof _RowSelector){
+ var next = _this._lastFocusedRowBarIdx + rowStep;
+ if(next >= 0 && next < g.rowCount){
+ //TODO: these logic require a better Scroller.
+ _stopEvent(evt);
+ var rowBarNode = view.getCellNode(_this._lastFocusedRowBarIdx, 0);
+ html.toggleClass(rowBarNode, f.focusClass, false);
+ //If the row is not fetched, fetch it.
+ var sc = g.scroller;
+ var lastPageRow = sc.getLastPageRow(sc.page);
+ var rc = g.rowCount - 1, row = Math.min(rc, next);
+ if(next > lastPageRow){
+ g.setScrollTop(g.scrollTop + sc.findScrollTop(row) - sc.findScrollTop(_this._lastFocusedRowBarIdx));
+ }
+ //Now we have fetched the row.
+ rowBarNode = view.getCellNode(next, 0);
+ dijitFocus.focus(rowBarNode);
+ html.toggleClass(rowBarNode, f.focusClass, true);
+ _this._lastFocusedRowBarIdx = next;
+ //If the row is out of view, scroll to it.
+ f.cell = rowBarNode;
+ f.cell.view = view;
+ f.cell.getNode = function(index){
+ return f.cell;
+ };
+ f.rowIndex = _this._lastFocusedRowBarIdx;
+ f.scrollIntoView();
+ f.cell = null;
+ }
+ }
+ }
+ });
+ f.placeArea("rowHeader","before","content");
+ }
+ //Support keyboard selection.
+ f.addArea({
+ name:"cellselect",
+ onMove: lang.partial(onmove, "cell", function(type, rowStep, colStep, evt){
+ var current = _this._currentPoint[type];
+ return _createItem("cell", current.row + rowStep, current.col + colStep);
+ }),
+ onKeyDown: lang.partial(onkeydown, "cell", function(){
+ return _createItem("cell", f.rowIndex, f.cell.index);
+ }),
+ onKeyUp: lang.partial(onkeyup, "cell")
+ });
+ f.placeArea("cellselect","below","content");
+ f.addArea({
+ name:"colselect",
+ onMove: lang.partial(onmove, "col", function(type, rowStep, colStep, evt){
+ var current = _this._currentPoint[type];
+ return _createItem("col", current.col + colStep);
+ }),
+ onKeyDown: lang.partial(onkeydown, "col", function(){
+ return _createItem("col", f.getHeaderIndex());
+ }),
+ onKeyUp: lang.partial(onkeyup, "col")
+ });
+ f.placeArea("colselect","below","header");
+ f.addArea({
+ name:"rowselect",
+ onMove: lang.partial(onmove, "row", function(type, rowStep, colStep, evt){
+ return _createItem("row", f.rowIndex);
+ }),
+ onKeyDown: lang.partial(onkeydown, "row", function(){
+ return _createItem("row", f.rowIndex);
+ }),
+ onKeyUp: lang.partial(onkeyup, "row")
+ });
+ f.placeArea("rowselect","below","rowHeader");
+ },
+ _clearSelection: function(type, reservedItem){
+ // summary:
+ // Clear selection for given type and fire events, but retain the highlight for *reservedItem*,
+ // thus avoid "flashing".
+ // tag:
+ // private
+ // type: String
+ // "row", "col", or "cell
+ // reservedItem: __SelectItem
+ // The item to retain highlight.
+ if(type == "all"){
+ this._clearSelection("cell", reservedItem);
+ this._clearSelection("col", reservedItem);
+ this._clearSelection("row", reservedItem);
+ return;
+ }
+ this._isUsingRowSelector = true;
+ array.forEach(this._selected[type], function(item){
+ if(!_isEqual(type, reservedItem, item)){
+ this._highlightSingle(type, false, item);
+ }
+ }, this);
+ this._blurPoint(type, this._currentPoint);
+ this._selecting[type] = false;
+ this._startPoint[type] = this._currentPoint[type] = null;
+ this._selected[type] = [];
+
+ //Have to also deselect default grid selection.
+ if(type == "row" && !this.grid._selectingRange){
+ this._oldDeselectAll.call(this.grid.selection);
+ this.grid.selection._selectedById = {};
+ }
+
+ //Fire events.
+ this.grid.onEndDeselect(type, null, null, this._selected);
+ this.grid.onSelectCleared(type);
+ },
+ _startSelect: function(type, start, extending, isRange, mandatarySelect, toSelect){
+ // summary:
+ // Start selection, setup start point and current point, fire events.
+ // tag:
+ // private
+ // type: String
+ // "row", "col", or "cell"
+ // extending: Boolean
+ // Whether this is a multi selection
+ // isRange: Boolean
+ // Whether this is a range selection (i.e. select from the last end point to this point)
+ // start: __SelectItem
+ // The start point
+ // mandatarySelect: Boolean
+ // If true, toSelect will be same as the original selection status.
+ if(!this._isValid(type, start)){
+ return;
+ }
+ var lastIsSelected = this._isSelected(type, this._lastEndPoint[type]),
+ isSelected = this._isSelected(type, start);
+
+ if(this.noClear && !extending){
+ this._toSelect = toSelect === undefined ? true : toSelect;
+ }else{
+ //If we are modifying the selection using keyboard, retain the old status.
+ this._toSelect = mandatarySelect ? isSelected : !isSelected;
+ }
+
+ //If CTRL is not pressed or it's SINGLE mode, this is a brand new selection.
+ if(!extending || (!isSelected && this._config[type] == SINGLE)){
+ this._clearSelection("col", start);
+ this._clearSelection("cell", start);
+ if(!this.noClear || (type === 'row' && this._config[type] == SINGLE)){
+ this._clearSelection('row', start);
+ }
+ this._toSelect = toSelect === undefined ? true : toSelect;
+ }
+
+ this._selecting[type] = true;
+ this._currentPoint[type] = null;
+
+ //We're holding SHIFT while clicking, it's a Click-Range selection.
+ if(isRange && this._lastType == type && lastIsSelected == this._toSelect && this._config[type] == MULTI){
+ if(type === "row"){
+ this._isUsingRowSelector = true;
+ }
+ this._startPoint[type] = this._lastEndPoint[type];
+ this._highlight(type, this._startPoint[type]);
+ this._isUsingRowSelector = false;
+ }else{
+ this._startPoint[type] = start;
+ }
+ //Now start selection
+ this._curType = type;
+ this._fireEvent("start", type);
+ this._isStartFocus = true;
+ this._isUsingRowSelector = true;
+ this._highlight(type, start, this._toSelect);
+ this._isStartFocus = false;
+ },
+ _endSelect: function(type){
+ // summary:
+ // End selection. Keep records, fire events and cleanup status.
+ // tag:
+ // private
+ // type: String
+ // "row", "col", or "cell"
+ if(type === "row"){
+ delete this._isUsingRowSelector;
+ }
+ if(type == "all"){
+ this._endSelect("col");
+ this._endSelect("row");
+ this._endSelect("cell");
+ }else if(this._selecting[type]){
+ this._addToSelected(type);
+ this._lastAnchorPoint[type] = this._startPoint[type];
+ this._lastEndPoint[type] = this._currentPoint[type];
+ if(this._toSelect){
+ this._lastSelectedAnchorPoint[type] = this._lastAnchorPoint[type];
+ this._lastSelectedEndPoint[type] = this._lastEndPoint[type];
+ }
+ this._startPoint[type] = this._currentPoint[type] = null;
+ this._selecting[type] = false;
+ this._lastType = type;
+ this._fireEvent("end", type);
+ }
+ },
+ _fireEvent: function(evtName, type){
+ switch(evtName){
+ case "start":
+ this.grid[this._toSelect ? "onStartSelect" : "onStartDeselect"](type, this._startPoint[type], this._selected);
+ break;
+ case "end":
+ this.grid[this._toSelect ? "onEndSelect" : "onEndDeselect"](type, this._lastAnchorPoint[type], this._lastEndPoint[type], this._selected);
+ break;
+ }
+ },
+ _calcToHighlight: function(type, target, toHighlight, toSelect){
+ // summary:
+ // Calculate what status should *target* have.
+ // If *toSelect* is not provided, this is a no op.
+ // This function is time-critical!!
+ if(toSelect !== undefined){
+ var sltd;
+ if(this._usingKeyboard && !toHighlight){
+ var last = this._isInLastRange(this._lastType, target);
+ if(last){
+ sltd = this._isSelected(type, target);
+ //This 2 cases makes the keyboard swipe selection valid!
+ if(toSelect && sltd){
+ return false;
+ }
+ if(!toSelect && !sltd && this._isInLastRange(this._lastType, target, true)){
+ return true;
+ }
+ }
+ }
+ return toHighlight ? toSelect : (sltd || this._isSelected(type, target));
+ }
+ return toHighlight;
+ },
+ _highlightNode: function(node, toHighlight){
+ // summary:
+ // Do the actual highlight work.
+ if(node){
+ var selectCSSClass = "dojoxGridRowSelected";
+ var selectCellClass = "dojoxGridCellSelected";
+ html.toggleClass(node, selectCSSClass, toHighlight);
+ html.toggleClass(node, selectCellClass, toHighlight);
+ }
+ },
+ _highlightHeader: function(colIdx, toHighlight){
+ var cells = this.grid.layout.cells;
+ var node = cells[colIdx].getHeaderNode();
+ var selectedClass = "dojoxGridHeaderSelected";
+ html.toggleClass(node, selectedClass, toHighlight);
+ },
+ _highlightRowSelector: function(rowIdx, toHighlight){
+ //var t1 = (new Date()).getTime();
+ var rowSelector = this.grid.views.views[0];
+ if(rowSelector instanceof _RowSelector){
+ var node = rowSelector.getRowNode(rowIdx);
+ if(node){
+ var selectedClass = "dojoxGridRowSelectorSelected";
+ html.toggleClass(node, selectedClass, toHighlight);
+ }
+ }
+ //console.log((new Date()).getTime() - t1);
+ },
+ _highlightSingle: function(type, toHighlight, target, toSelect, isRefresh){
+ // summary:
+ // Highlight a single item.
+ // This function is time critical!!
+ var _this = this, toHL, g = _this.grid, cells = g.layout.cells;
+ switch(type){
+ case "cell":
+ toHL = this._calcToHighlight(type, target, toHighlight, toSelect);
+ var c = cells[target.col];
+ if(!c.hidden && !c.notselectable){
+ this._highlightNode(target.node || c.getNode(target.row), toHL);
+ }
+ break;
+ case "col":
+ toHL = this._calcToHighlight(type, target, toHighlight, toSelect);
+ this._highlightHeader(target.col, toHL);
+ query("td[idx='" + target.col + "']", g.domNode).forEach(function(cellNode){
+ var rowNode = cells[target.col].view.content.findRowTarget(cellNode);
+ if(rowNode){
+ var rowIndex = rowNode[dojox.grid.util.rowIndexTag];
+ _this._highlightSingle("cell", toHL, {
+ "row": rowIndex,
+ "col": target.col,
+ "node": cellNode
+ });
+ }
+ });
+ break;
+ case "row":
+ toHL = this._calcToHighlight(type, target, toHighlight, toSelect);
+ this._highlightRowSelector(target.row, toHL);
+ if(this._config.cell){
+ array.forEach(cells, function(cell){
+ _this._highlightSingle("cell", toHL, {
+ "row": target.row,
+ "col": cell.index,
+ "node": cell.getNode(target.row)
+ });
+ });
+ }
+ //To avoid dead lock
+ this._selectedRowModified = true;
+ if(!isRefresh){
+ g.selection.setSelected(target.row, toHL);
+ }
+ }
+ },
+ _highlight: function(type, target, toSelect){
+ // summary:
+ // Highlight from start point to target.
+ // toSelect: Boolean
+ // Whether we are selecting or deselecting.
+ // This function is time critical!!
+ if(this._selecting[type] && target !== null){
+ var start = this._startPoint[type],
+ current = this._currentPoint[type],
+ _this = this,
+ highlight = function(from, to, toHL){
+ _this._forEach(type, from, to, function(item){
+ _this._highlightSingle(type, toHL, item, toSelect);
+ }, true);
+ };
+ switch(type){
+ case "col": case "row":
+ if(current !== null){
+ if(_inRange(type, target, start, current, true)){
+ //target is between start and current, some selected should be deselected.
+ highlight(current, target, false);
+ }else{
+ if(_inRange(type, start, target, current, true)){
+ //selection has jumped to different direction, all should be deselected.
+ highlight(current, start, false);
+ current = start;
+ }
+ highlight(target, current, true);
+ }
+ }else{
+ //First time select.
+ this._highlightSingle(type, true, target, toSelect);
+ }
+ break;
+ case "cell":
+ if(current !== null){
+ if(_inRange("row", target, start, current, true) ||
+ _inRange("col", target, start, current, true) ||
+ _inRange("row", start, target, current, true) ||
+ _inRange("col", start, target, current, true)){
+ highlight(start, current, false);
+ }
+ }
+ highlight(start, target, true);
+ }
+ this._currentPoint[type] = target;
+ this._focusPoint(type, this._currentPoint);
+ }
+ },
+ _focusPoint: function(type, point){
+ // summary:
+ // Focus the current point, so when you move mouse, the focus indicator follows you.
+ if(!this._isStartFocus){
+ var current = point[type],
+ f = this.grid.focus;
+ if(type == "col"){
+ f._colHeadFocusIdx = current.col;
+ f.focusArea("header");
+ }else if(type == "row"){
+ f.focusArea("rowHeader", {
+ "rowIndex": current.row
+ });
+ }else if(type == "cell"){
+ f.setFocusIndex(current.row, current.col);
+ }
+ }
+ },
+ _blurPoint: function(type, point){
+ // summary:
+ // Blur the current point.
+ var f = this.grid.focus;
+ if(type == "col"){
+ f._blurHeader();
+ }else if(type == "cell"){
+ f._blurContent();
+ }
+ },
+ _addToSelected: function(type){
+ // summary:
+ // Record the selected items.
+ var toSelect = this._toSelect, _this = this,
+ toAdd = [], toRemove = [],
+ start = this._startPoint[type],
+ end = this._currentPoint[type];
+ if(this._usingKeyboard){
+ //If using keyboard, selection will be ended after every move. But we have to remember the original selection status,
+ //so as to return to correct status when we shrink the selection region.
+ this._forEach(type, this._lastAnchorPoint[type], this._lastEndPoint[type], function(item){
+ //If the original selected item is not in current range, change its status.
+ if(!_inRange(type, item, start, end)){
+ (toSelect ? toRemove : toAdd).push(item);
+ }
+ });
+ }
+ this._forEach(type, start, end, function(item){
+ var isSelected = _this._isSelected(type, item);
+ if(toSelect && !isSelected){
+ //Add new selected items
+ toAdd.push(item);
+ }else if(!toSelect){
+ //Remove deselected items.
+ toRemove.push(item);
+ }
+ });
+ this._add(type, toAdd);
+ this._remove(type, toRemove);
+
+ // have to keep record in original grid selection
+ array.forEach(this._selected.row, function(item){
+ if(item.except.length > 0){
+ //to avoid dead lock
+ this._selectedRowModified = true;
+ this.grid.selection.setSelected(item.row, false);
+ }
+ }, this);
+ },
+ _forEach: function(type, start, end, func, halfClose){
+ // summary:
+ // Go through items from *start* point to *end* point.
+ // This function is time critical!!
+ if(!this._isValid(type, start, true) || !this._isValid(type, end, true)){
+ return;
+ }
+ switch(type){
+ case "col": case "row":
+ start = start[type];
+ end = end[type];
+ var dir = end > start ? 1 : -1;
+ if(!halfClose){
+ end += dir;
+ }
+ for(; start != end; start += dir){
+ func(_createItem(type, start));
+ }
+ break;
+ case "cell":
+ var colDir = end.col > start.col ? 1 : -1,
+ rowDir = end.row > start.row ? 1 : -1;
+ for(var i = start.row, p = end.row + rowDir; i != p; i += rowDir){
+ for(var j = start.col, q = end.col + colDir; j != q; j += colDir){
+ func(_createItem(type, i, j));
+ }
+ }
+ }
+ },
+ _makeupForExceptions: function(type, newCellItems){
+ // summary:
+ // When new cells is selected, maybe they will fill in the "holes" in selected rows and columns.
+ var makedUps = [];
+ array.forEach(this._selected[type], function(v1){
+ array.forEach(newCellItems, function(v2){
+ if(v1[type] == v2[type]){
+ var pos = array.indexOf(v1.except, v2[_theOther[type]]);
+ if(pos >= 0){
+ v1.except.splice(pos, 1);
+ }
+ makedUps.push(v2);
+ }
+ });
+ });
+ return makedUps;
+ },
+ _makeupForCells: function(type, newItems){
+ // summary:
+ // When some rows/cols are selected, maybe they can cover some of the selected cells,
+ // and fill some of the "holes" in the selected cols/rows.
+ var toRemove = [];
+ array.forEach(this._selected.cell, function(v1){
+ array.some(newItems, function(v2){
+ if(v1[type] == v2[type]){
+ toRemove.push(v1);
+ return true;
+ }
+ return false;
+ });
+ });
+ this._remove("cell", toRemove);
+ array.forEach(this._selected[_theOther[type]], function(v1){
+ array.forEach(newItems, function(v2){
+ var pos = array.indexOf(v1.except, v2[type]);
+ if(pos >= 0){
+ v1.except.splice(pos, 1);
+ }
+ });
+ });
+ },
+ _addException: function(type, items){
+ // summary:
+ // If some rows/cols are deselected, maybe they have created "holes" in selected cols/rows.
+ array.forEach(this._selected[type], function(v1){
+ array.forEach(items, function(v2){
+ v1.except.push(v2[_theOther[type]]);
+ });
+ });
+ },
+ _addCellException: function(type, items){
+ // summary:
+ // If some cells are deselected, maybe they have created "holes" in selected rows/cols.
+ array.forEach(this._selected[type], function(v1){
+ array.forEach(items, function(v2){
+ if(v1[type] == v2[type]){
+ v1.except.push(v2[_theOther[type]]);
+ }
+ });
+ });
+ },
+ _add: function(type, items){
+ // summary:
+ // Add to the selection record.
+ var cells = this.grid.layout.cells;
+ if(type == "cell"){
+ var colMakedup = this._makeupForExceptions("col", items);
+ var rowMakedup = this._makeupForExceptions("row", items);
+ //Step over hidden columns.
+ items = array.filter(items, function(item){
+ return array.indexOf(colMakedup, item) < 0 && array.indexOf(rowMakedup, item) < 0 &&
+ !cells[item.col].hidden && !cells[item.col].notselectable;
+ });
+ }else{
+ if(type == "col"){
+ //Step over hidden columns.
+ items = array.filter(items, function(item){
+ return !cells[item.col].hidden && !cells[item.col].notselectable;
+ });
+ }
+ this._makeupForCells(type, items);
+ this._selected[type] = array.filter(this._selected[type], function(v){
+ return array.every(items, function(item){
+ return v[type] !== item[type];
+ });
+ });
+ }
+ if(type != "col" && this.grid._hasIdentity){
+ array.forEach(items, function(item){
+ var record = this.grid._by_idx[item.row];
+ if(record){
+ item.id = record.idty;
+ }
+ }, this);
+ }
+ this._selected[type] = this._selected[type].concat(items);
+ },
+ _remove: function(type, items){
+ // summary:
+ // Remove from the selection record.
+ var comp = lang.partial(_isEqual, type);
+ this._selected[type] = array.filter(this._selected[type], function(v1){
+ return !array.some(items, function(v2){
+ return comp(v1, v2);
+ });
+ });
+ if(type == "cell"){
+ this._addCellException("col", items);
+ this._addCellException("row", items);
+ }else if(this._config.cell){
+ this._addException(_theOther[type], items);
+ }
+ },
+ _isCellNotInExcept: function(type, item){
+ // summary:
+ // Return true only when a cell is covered by selected row/col, and its not a "hole".
+ var attr = item[type], corres = item[_theOther[type]];
+ return array.some(this._selected[type], function(v){
+ return v[type] == attr && array.indexOf(v.except, corres) < 0;
+ });
+ },
+ _isSelected: function(type, item){
+ // summary:
+ // Return true when the item is selected. (or logically selected, i.e, covered by a row/col).
+ if(!item){ return false; }
+ var res = array.some(this._selected[type], function(v){
+ var ret = _isEqual(type, item, v);
+ if(ret && type !== "cell"){
+ return v.except.length === 0;
+ }
+ return ret;
+ });
+ if(!res && type === "cell"){
+ res = (this._isCellNotInExcept("col", item) || this._isCellNotInExcept("row", item));
+ if(type === "cell"){
+ res = res && !this.grid.layout.cells[item.col].notselectable;
+ }
+ }
+ return res;
+ },
+ _isInLastRange: function(type, item, isSelected){
+ // summary:
+ // Return true only when the item is in the last seletion/deseletion range.
+ var start = this[isSelected ? "_lastSelectedAnchorPoint" : "_lastAnchorPoint"][type],
+ end = this[isSelected ? "_lastSelectedEndPoint" : "_lastEndPoint"][type];
+ if(!item || !start || !end){ return false; }
+ return _inRange(type, item, start, end);
+ },
+ _isValid: function(type, item, allowNotSelectable){
+ // summary:
+ // Check whether the item is a valid __SelectItem for the given type.
+ if(!item){ return false; }
+ try{
+ var g = this.grid, index = item[type];
+ switch(type){
+ case "col":
+ return index >= 0 && index < g.layout.cells.length && lang.isArray(item.except) &&
+ (allowNotSelectable || !g.layout.cells[index].notselectable);
+ case "row":
+ return index >= 0 && index < g.rowCount && lang.isArray(item.except);
+ case "cell":
+ return item.col >= 0 && item.col < g.layout.cells.length &&
+ item.row >= 0 && item.row < g.rowCount &&
+ (allowNotSelectable || !g.layout.cells[item.col].notselectable);
+ }
+ }catch(e){}
+ return false;
+ }
+});
+
+EnhancedGrid.registerPlugin(Selector/*name:'selector'*/, {
+ "dependency": ["autoScroll"]
+});
+
+return Selector;
+
+}); \ No newline at end of file