1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093 |
- define("dojox/grid/enhanced/plugins/DnD", [
- "dojo/_base/kernel",
- "dojo/_base/declare",
- "dojo/_base/connect",
- "dojo/_base/array",
- "dojo/_base/lang",
- "dojo/_base/html",
- "dojo/_base/json",
- "dojo/_base/window",
- "dojo/query",
- "dojo/keys",
- "dojo/dnd/Source",
- "dojo/dnd/Avatar",
- "../_Plugin",
- "../../EnhancedGrid",
- "./Selector",
- "./Rearrange",
- "dojo/dnd/Manager"
- ], function(dojo, declare, connect, array, lang, html, json, win, query, keys, Source, Avatar, _Plugin, EnhancedGrid){
- var _devideToArrays = function(a){
- a.sort(function(v1, v2){
- return v1 - v2;
- });
- var arr = [[a[0]]];
- for(var i = 1, j = 0; i < a.length; ++i){
- if(a[i] == a[i-1] + 1){
- arr[j].push(a[i]);
- }else{
- arr[++j] = [a[i]];
- }
- }
- return arr;
- },
- _joinToArray = function(arrays){
- var a = arrays[0];
- for(var i = 1; i < arrays.length; ++i){
- a = a.concat(arrays[i]);
- }
- return a;
- };
- var GridDnDElement = declare("dojox.grid.enhanced.plugins.GridDnDElement", null, {
- constructor: function(dndPlugin){
- this.plugin = dndPlugin;
- this.node = html.create("div");
- this._items = {};
- },
- destroy: function(){
- this.plugin = null;
- html.destroy(this.node);
- this.node = null;
- this._items = null;
- },
- createDnDNodes: function(dndRegion){
- this.destroyDnDNodes();
- var acceptType = ["grid/" + dndRegion.type + "s"];
- var itemNodeIdBase = this.plugin.grid.id + "_dndItem";
- array.forEach(dndRegion.selected, function(range, i){
- var id = itemNodeIdBase + i;
- this._items[id] = {
- "type": acceptType,
- "data": range,
- "dndPlugin": this.plugin
- };
- this.node.appendChild(html.create("div", {
- "id": id
- }));
- }, this);
- },
- getDnDNodes: function(){
- return array.map(this.node.childNodes, function(node){
- return node;
- });
- },
- destroyDnDNodes: function(){
- html.empty(this.node);
- this._items = {};
- },
- getItem: function(nodeId){
- return this._items[nodeId];
- }
- });
- var GridDnDSource = declare("dojox.grid.enhanced.plugins.GridDnDSource", Source,{
- accept: ["grid/cells", "grid/rows", "grid/cols"],
- constructor: function(node, param){
- this.grid = param.grid;
- this.dndElem = param.dndElem;
- this.dndPlugin = param.dnd;
- this.sourcePlugin = null;
- },
- destroy: function(){
- this.inherited(arguments);
- this.grid = null;
- this.dndElem = null;
- this.dndPlugin = null;
- this.sourcePlugin = null;
- },
- getItem: function(nodeId){
- return this.dndElem.getItem(nodeId);
- },
- checkAcceptance: function(source, nodes){
- if(this != source && nodes[0]){
- var item = source.getItem(nodes[0].id);
- if(item.dndPlugin){
- var type = item.type;
- for(var j = 0; j < type.length; ++j){
- if(type[j] in this.accept){
- if(this.dndPlugin._canAccept(item.dndPlugin)){
- this.sourcePlugin = item.dndPlugin;
- }else{
- return false;
- }
- break;
- }
- }
- }else if("grid/rows" in this.accept){
- var rows = [];
- array.forEach(nodes, function(node){
- var item = source.getItem(node.id);
- if(item.data && array.indexOf(item.type, "grid/rows") >= 0){
- var rowData = item.data;
- if(typeof item.data == "string"){
- rowData = json.fromJson(item.data);
- }
- if(rowData){
- rows.push(rowData);
- }
- }
- });
- if(rows.length){
- this.sourcePlugin = {
- _dndRegion: {
- type: "row",
- selected: [rows]
- }
- };
- }else{
- return false;
- }
- }
- }
- return this.inherited(arguments);
- },
- onDraggingOver: function(){
- this.dndPlugin.onDraggingOver(this.sourcePlugin);
- },
- onDraggingOut: function(){
- this.dndPlugin.onDraggingOut(this.sourcePlugin);
- },
- onDndDrop: function(source, nodes, copy, target){
- //this.inherited(arguments);
- this.onDndCancel();
- if(this != source && this == target){
- this.dndPlugin.onDragIn(this.sourcePlugin, copy);
- }
- }
- });
- var GridDnDAvatar = declare("dojox.grid.enhanced.plugins.GridDnDAvatar", Avatar, {
- construct: function(){
- // summary:
- // constructor function;
- // it is separate so it can be (dynamically) overwritten in case of need
- this._itemType = this.manager._dndPlugin._dndRegion.type;
- this._itemCount = this._getItemCount();
-
- this.isA11y = html.hasClass(win.body(), "dijit_a11y");
- var a = html.create("table", {
- "border": "0",
- "cellspacing": "0",
- "class": "dojoxGridDndAvatar",
- "style": {
- position: "absolute",
- zIndex: "1999",
- margin: "0px"
- }
- }),
- source = this.manager.source,
- b = html.create("tbody", null, a),
- tr = html.create("tr", null, b),
- td = html.create("td", {
- "class": "dojoxGridDnDIcon"
- }, tr);
- if(this.isA11y){
- html.create("span", {
- "id" : "a11yIcon",
- "innerHTML" : this.manager.copy ? '+' : "<"
- }, td);
- }
- td = html.create("td", {
- "class" : "dojoxGridDnDItemIcon " + this._getGridDnDIconClass()
- }, tr);
- td = html.create("td", null, tr);
- html.create("span", {
- "class": "dojoxGridDnDItemCount",
- "innerHTML": source.generateText ? this._generateText() : ""
- }, td);
- // we have to set the opacity on IE only after the node is live
- html.style(tr, {
- "opacity": 0.9
- });
- this.node = a;
- },
- _getItemCount: function(){
- var selected = this.manager._dndPlugin._dndRegion.selected,
- count = 0;
- switch(this._itemType){
- case "cell":
- selected = selected[0];
- var cells = this.manager._dndPlugin.grid.layout.cells,
- colCount = selected.max.col - selected.min.col + 1,
- rowCount = selected.max.row - selected.min.row + 1;
- if(colCount > 1){
- for(var i = selected.min.col; i <= selected.max.col; ++i){
- if(cells[i].hidden){
- --colCount;
- }
- }
- }
- count = colCount * rowCount;
- break;
- case "row":
- case "col":
- count = _joinToArray(selected).length;
- }
- return count;
- },
- _getGridDnDIconClass: function(){
- return {
- "row": ["dojoxGridDnDIconRowSingle", "dojoxGridDnDIconRowMulti"],
- "col": ["dojoxGridDnDIconColSingle", "dojoxGridDnDIconColMulti"],
- "cell": ["dojoxGridDnDIconCellSingle", "dojoxGridDnDIconCellMulti"]
- }[this._itemType][this._itemCount == 1 ? 0 : 1];
- },
- _generateText: function(){
- // summary:
- // generates a proper text to reflect copying or moving of items
- return "(" + this._itemCount + ")";
- }
- });
- var DnD = declare("dojox.grid.enhanced.plugins.DnD", _Plugin, {
- // summary:
- // Provide drag and drop for grid columns/rows/cells within grid and out of grid.
- // The store of grid must implement dojo.data.api.Write.
- // DnD selected columns:
- // Support moving within grid, moving/copying out of grid to a non-grid DnD target.
- // DnD selected rows:
- // Support moving within grid, moving/copying out of grid to any DnD target.
- // DnD selected cells (in rectangle shape only):
- // Support moving/copying within grid, moving/copying out of grid to any DnD target.
- //
-
- // name: String,
- // plugin name;
- name: "dnd",
-
- _targetAnchorBorderWidth: 2,
- _copyOnly: false,
- _config: {
- "row":{
- "within":true,
- "in":true,
- "out":true
- },
- "col":{
- "within":true,
- "in":true,
- "out":true
- },
- "cell":{
- "within":true,
- "in":true,
- "out":true
- }
- },
- constructor: function(grid, args){
- this.grid = grid;
- this._config = lang.clone(this._config);
- args = lang.isObject(args) ? args : {};
- this.setupConfig(args.dndConfig);
- this._copyOnly = !!args.copyOnly;
-
- //Get the plugins we are dependent on.
- this._mixinGrid();
- this.selector = grid.pluginMgr.getPlugin("selector");
- this.rearranger = grid.pluginMgr.getPlugin("rearrange");
- //TODO: waiting for a better plugin framework to pass args to dependent plugins.
- this.rearranger.setArgs(args);
-
- //Initialized the components we need.
- this._clear();
- this._elem = new GridDnDElement(this);
- this._source = new GridDnDSource(this._elem.node, {
- "grid": grid,
- "dndElem": this._elem,
- "dnd": this
- });
- this._container = query(".dojoxGridMasterView", this.grid.domNode)[0];
- this._initEvents();
- },
- destroy: function(){
- this.inherited(arguments);
- this._clear();
- this._source.destroy();
- this._elem.destroy();
- this._container = null;
- this.grid = null;
- this.selector = null;
- this.rearranger = null;
- this._config = null;
- },
- _mixinGrid: function(){
- // summary:
- // Provide APIs for grid.
- this.grid.setupDnDConfig = lang.hitch(this, "setupConfig");
- this.grid.dndCopyOnly = lang.hitch(this, "copyOnly");
- },
- setupConfig: function(config){
- // summary:
- // Configure which DnD functionalities are needed.
- // Combination of any item from type set ("row", "col", "cell")
- // and any item from mode set("within", "in", "out") is configurable.
- //
- // "row", "col", "cell" are straitforward, while the other 3 are explained below:
- // "within": DnD within grid, that is, column/row reordering and cell moving/copying.
- // "in": Whether allowed to accept rows/cells (currently not support columns) from another grid.
- // "out": Whether allowed to drag out of grid, to another grid or even to any other DnD target.
- //
- // If not provided in the config, will use the default.
- // When declared together, Mode set has higher priority than type set.
- // config: Object
- // DnD configuration object.
- // See the examples below.
- // example:
- // The following code disables row DnD within grid,
- // but still can drag rows out of grid or drag rows from other gird.
- // | setUpConfig({
- // | "row": {
- // | "within": false
- // | }
- // | });
- //
- // The opposite way is also okay:
- // | setUpConfig({
- // | "within": {
- // | "row": false
- // | }
- // | });
- //
- // And if you'd like to disable/enable a whole set, here's a shortcut:
- // | setUpConfig({
- // | "cell", true,
- // | "out": false
- // | });
- //
- // Because mode has higher priority than type, the following will disable row dnd within grid:
- // | setUpConfig({
- // | "within", {
- // | "row": false;
- // | },
- // | "row", {
- // | "within": true
- // | }
- // | });
- if(config && lang.isObject(config)){
- var firstLevel = ["row", "col", "cell"],
- secondLevel = ["within", "in", "out"],
- cfg = this._config;
- array.forEach(firstLevel, function(type){
- if(type in config){
- var t = config[type];
- if(t && lang.isObject(t)){
- array.forEach(secondLevel, function(mode){
- if(mode in t){
- cfg[type][mode] = !!t[mode];
- }
- });
- }else{
- array.forEach(secondLevel, function(mode){
- cfg[type][mode] = !!t;
- });
- }
- }
- });
- array.forEach(secondLevel, function(mode){
- if(mode in config){
- var m = config[mode];
- if(m && lang.isObject(m)){
- array.forEach(firstLevel, function(type){
- if(type in m){
- cfg[type][mode] = !!m[type];
- }
- });
- }else{
- array.forEach(firstLevel, function(type){
- cfg[type][mode] = !!m;
- });
- }
- }
- });
- }
- },
- copyOnly: function(isCopyOnly){
- // summary:
- // Setter/getter of this._copyOnly.
- if(typeof isCopyOnly != "undefined"){
- this._copyOnly = !!isCopyOnly;
- }
- return this._copyOnly;
- },
- _isOutOfGrid: function(evt){
- var gridPos = html.position(this.grid.domNode), x = evt.clientX, y = evt.clientY;
- return y < gridPos.y || y > gridPos.y + gridPos.h ||
- x < gridPos.x || x > gridPos.x + gridPos.w;
- },
- _onMouseMove: function(evt){
- if(this._dndRegion && !this._dnding && !this._externalDnd){
- this._dnding = true;
- this._startDnd(evt);
- }else{
- if(this._isMouseDown && !this._dndRegion){
- delete this._isMouseDown;
- this._oldCursor = html.style(win.body(), "cursor");
- html.style(win.body(), "cursor", "not-allowed");
- }
- //TODO: should implement as mouseenter/mouseleave
- //But we have an avatar under mouse when dnd, and this will cause a lot of mouseenter in FF.
- var isOut = this._isOutOfGrid(evt);
- if(!this._alreadyOut && isOut){
- this._alreadyOut = true;
- if(this._dnding){
- this._destroyDnDUI(true, false);
- }
- this._moveEvent = evt;
- this._source.onOutEvent();
- }else if(this._alreadyOut && !isOut){
- this._alreadyOut = false;
- if(this._dnding){
- this._createDnDUI(evt, true);
- }
- this._moveEvent = evt;
- this._source.onOverEvent();
- }
- }
- },
- _onMouseUp: function(){
- if(!this._extDnding && !this._isSource){
- var isInner = this._dnding && !this._alreadyOut;
- if(isInner && this._config[this._dndRegion.type]["within"]){
- this._rearrange();
- }
- this._endDnd(isInner);
- }
- html.style(win.body(), "cursor", this._oldCursor || "");
- delete this._isMouseDown;
- },
- _initEvents: function(){
- var g = this.grid, s = this.selector;
- this.connect(win.doc, "onmousemove", "_onMouseMove");
- this.connect(win.doc, "onmouseup", "_onMouseUp");
-
- this.connect(g, "onCellMouseOver", function(evt){
- if(!this._dnding && !s.isSelecting() && !evt.ctrlKey){
- this._dndReady = s.isSelected("cell", evt.rowIndex, evt.cell.index);
- s.selectEnabled(!this._dndReady);
- }
- });
- this.connect(g, "onHeaderCellMouseOver", function(evt){
- if(this._dndReady){
- s.selectEnabled(true);
- }
- });
- this.connect(g, "onRowMouseOver", function(evt){
- if(this._dndReady && !evt.cell){
- s.selectEnabled(true);
- }
- });
- this.connect(g, "onCellMouseDown", function(evt){
- if(!evt.ctrlKey && this._dndReady){
- this._dndRegion = this._getDnDRegion(evt.rowIndex, evt.cell.index);
- this._isMouseDown = true;
- }
- });
- this.connect(g, "onCellMouseUp", function(evt){
- if(!this._dndReady && !s.isSelecting() && evt.cell){
- this._dndReady = s.isSelected("cell", evt.rowIndex, evt.cell.index);
- s.selectEnabled(!this._dndReady);
- }
- });
- this.connect(g, "onCellClick", function(evt){
- if(this._dndReady && !evt.ctrlKey && !evt.shiftKey){
- s.select("cell", evt.rowIndex, evt.cell.index);
- }
- });
- this.connect(g, "onEndAutoScroll", function(isVertical, isForward, view, target, evt){
- if(this._dnding){
- this._markTargetAnchor(evt);
- }
- });
- this.connect(win.doc, "onkeydown", function(evt){
- if(evt.keyCode == keys.ESCAPE){
- this._endDnd(false);
- }else if(evt.keyCode == keys.CTRL){
- s.selectEnabled(true);
- this._isCopy = true;
- }
- });
- this.connect(win.doc, "onkeyup", function(evt){
- if(evt.keyCode == keys.CTRL){
- s.selectEnabled(!this._dndReady);
- this._isCopy = false;
- }
- });
- },
- _clear: function(){
- this._dndRegion = null;
- this._target = null;
- this._moveEvent = null;
- this._targetAnchor = {};
- this._dnding = false;
- this._externalDnd = false;
- this._isSource = false;
- this._alreadyOut = false;
- this._extDnding = false;
- },
- _getDnDRegion: function(rowIndex, colIndex){
- var s = this.selector,
- selected = s._selected,
- flag = (!!selected.cell.length) | (!!selected.row.length << 1) | (!!selected.col.length << 2),
- type;
- switch(flag){
- case 1:
- type = "cell";
- if(!this._config[type]["within"] && !this._config[type]["out"]){
- return null;
- }
- var cells = this.grid.layout.cells,
- getCount = function(range){
- var hiddenColCnt = 0;
- for(var i = range.min.col; i <= range.max.col; ++i){
- if(cells[i].hidden){
- ++hiddenColCnt;
- }
- }
- return (range.max.row - range.min.row + 1) * (range.max.col - range.min.col + 1 - hiddenColCnt);
- },
- inRange = function(item, range){
- return item.row >= range.min.row && item.row <= range.max.row &&
- item.col >= range.min.col && item.col <= range.max.col;
- },
- range = {
- max: {
- row: -1,
- col: -1
- },
- min: {
- row: Infinity,
- col: Infinity
- }
- };
-
- array.forEach(selected[type], function(item){
- if(item.row < range.min.row){
- range.min.row = item.row;
- }
- if(item.row > range.max.row){
- range.max.row = item.row;
- }
- if(item.col < range.min.col){
- range.min.col = item.col;
- }
- if(item.col > range.max.col){
- range.max.col = item.col;
- }
- });
- if(array.some(selected[type], function(item){
- return item.row == rowIndex && item.col == colIndex;
- })){
- if(getCount(range) == selected[type].length && array.every(selected[type], function(item){
- return inRange(item, range);
- })){
- return {
- "type": type,
- "selected": [range],
- "handle": {
- "row": rowIndex,
- "col": colIndex
- }
- };
- }
- }
- return null;
- case 2: case 4:
- type = flag == 2 ? "row" : "col";
- if(!this._config[type]["within"] && !this._config[type]["out"]){
- return null;
- }
- var res = s.getSelected(type);
- if(res.length){
- return {
- "type": type,
- "selected": _devideToArrays(res),
- "handle": flag == 2 ? rowIndex : colIndex
- };
- }
- return null;
- }
- return null;
- },
- _startDnd: function(evt){
- this._createDnDUI(evt);
- },
- _endDnd: function(destroySource){
- this._destroyDnDUI(false, destroySource);
- this._clear();
- },
- _createDnDUI: function(evt, isMovingIn){
- //By default the master view of grid do not have height, because the children in it are all positioned absolutely.
- //But we need it to contain avatars.
- var viewPos = html.position(this.grid.views.views[0].domNode);
- html.style(this._container, "height", viewPos.h + "px");
- try{
- //If moving in from out side, dnd source is already created.
- if(!isMovingIn){
- this._createSource(evt);
- }
- this._createMoveable(evt);
- this._oldCursor = html.style(win.body(), "cursor");
- html.style(win.body(), "cursor", "default");
- }catch(e){
- console.warn("DnD._createDnDUI() error:", e);
- }
- },
- _destroyDnDUI: function(isMovingOut, destroySource){
- try{
- if(destroySource){
- this._destroySource();
- }
- this._unmarkTargetAnchor();
- if(!isMovingOut){
- this._destroyMoveable();
- }
- html.style(win.body(), "cursor", this._oldCursor);
- }catch(e){
- console.warn("DnD._destroyDnDUI() error:", this.grid.id, e);
- }
- },
- _createSource: function(evt){
- this._elem.createDnDNodes(this._dndRegion);
- var m = dojo.dnd.manager();
- var oldMakeAvatar = m.makeAvatar;
- m._dndPlugin = this;
- m.makeAvatar = function(){
- var avatar = new GridDnDAvatar(m);
- delete m._dndPlugin;
- return avatar;
- };
- m.startDrag(this._source, this._elem.getDnDNodes(), evt.ctrlKey);
- m.makeAvatar = oldMakeAvatar;
- m.onMouseMove(evt);
- },
- _destroySource: function(){
- connect.publish("/dnd/cancel");
- },
- _createMoveable: function(evt){
- if(!this._markTagetAnchorHandler){
- this._markTagetAnchorHandler = this.connect(win.doc, "onmousemove", "_markTargetAnchor");
- }
- },
- _destroyMoveable: function(){
- this.disconnect(this._markTagetAnchorHandler);
- delete this._markTagetAnchorHandler;
- },
- _calcColTargetAnchorPos: function(evt, containerPos){
- // summary:
- // Calculate the position of the column DnD avatar
- var i, headPos, left, target, ex = evt.clientX,
- cells = this.grid.layout.cells,
- ltr = html._isBodyLtr(),
- headers = this._getVisibleHeaders();
- for(i = 0; i < headers.length; ++i){
- headPos = html.position(headers[i].node);
- if(ltr ? ((i === 0 || ex >= headPos.x) && ex < headPos.x + headPos.w) :
- ((i === 0 || ex < headPos.x + headPos.w) && ex >= headPos.x)){
- left = headPos.x + (ltr ? 0 : headPos.w);
- break;
- }else if(ltr ? (i === headers.length - 1 && ex >= headPos.x + headPos.w) :
- (i === headers.length - 1 && ex < headPos.x)){
- ++i;
- left = headPos.x + (ltr ? headPos.w : 0);
- break;
- }
- }
- if(i < headers.length){
- target = headers[i].cell.index;
- if(this.selector.isSelected("col", target) && this.selector.isSelected("col", target - 1)){
- var ranges = this._dndRegion.selected;
- for(i = 0; i < ranges.length; ++i){
- if(array.indexOf(ranges[i], target) >= 0){
- target = ranges[i][0];
- headPos = html.position(cells[target].getHeaderNode());
- left = headPos.x + (ltr ? 0 : headPos.w);
- break;
- }
- }
- }
- }else{
- target = cells.length;
- }
- this._target = target;
- return left - containerPos.x;
- },
- _calcRowTargetAnchorPos: function(evt, containerPos){
- // summary:
- // Calculate the position of the row DnD avatar
- var g = this.grid, top, i = 0,
- cells = g.layout.cells;
- while(cells[i].hidden){ ++i; }
- var cell = g.layout.cells[i],
- rowIndex = g.scroller.firstVisibleRow,
- cellNode = cell.getNode(rowIndex);
- if(!cellNode){
- //if the target grid is empty, set to -1
- //which will be processed in Rearrange
- this._target = -1;
- return 0; //position of the insert bar
- }
- var nodePos = html.position(cellNode);
- while(nodePos.y + nodePos.h < evt.clientY){
- if(++rowIndex >= g.rowCount){
- break;
- }
- nodePos = html.position(cell.getNode(rowIndex));
- }
- if(rowIndex < g.rowCount){
- if(this.selector.isSelected("row", rowIndex) && this.selector.isSelected("row", rowIndex - 1)){
- var ranges = this._dndRegion.selected;
- for(i = 0; i < ranges.length; ++i){
- if(array.indexOf(ranges[i], rowIndex) >= 0){
- rowIndex = ranges[i][0];
- nodePos = html.position(cell.getNode(rowIndex));
- break;
- }
- }
- }
- top = nodePos.y;
- }else{
- top = nodePos.y + nodePos.h;
- }
- this._target = rowIndex;
- return top - containerPos.y;
- },
- _calcCellTargetAnchorPos: function(evt, containerPos, targetAnchor){
- // summary:
- // Calculate the position of the cell DnD avatar
- var s = this._dndRegion.selected[0],
- origin = this._dndRegion.handle,
- g = this.grid, ltr = html._isBodyLtr(),
- cells = g.layout.cells, headPos,
- minPos, maxPos, headers,
- height, width, left, top,
- minCol, maxCol, i,
- preSpan = origin.col - s.min.col,
- postSpan = s.max.col - origin.col,
- leftTopDiv, rightBottomDiv;
- if(!targetAnchor.childNodes.length){
- leftTopDiv = html.create("div", {
- "class": "dojoxGridCellBorderLeftTopDIV"
- }, targetAnchor);
- rightBottomDiv = html.create("div", {
- "class": "dojoxGridCellBorderRightBottomDIV"
- }, targetAnchor);
- }else{
- leftTopDiv = query(".dojoxGridCellBorderLeftTopDIV", targetAnchor)[0];
- rightBottomDiv = query(".dojoxGridCellBorderRightBottomDIV", targetAnchor)[0];
- }
- for(i = s.min.col + 1; i < origin.col; ++i){
- if(cells[i].hidden){
- --preSpan;
- }
- }
- for(i = origin.col + 1; i < s.max.col; ++i){
- if(cells[i].hidden){
- --postSpan;
- }
- }
- headers = this._getVisibleHeaders();
- //calc width
- for(i = preSpan; i < headers.length - postSpan; ++i){
- headPos = html.position(headers[i].node);
- if((evt.clientX >= headPos.x && evt.clientX < headPos.x + headPos.w) || //within in this column
- //prior to this column, but within range
- (i == preSpan && (ltr ? evt.clientX < headPos.x : evt.clientX >= headPos.x + headPos.w)) ||
- //post to this column, but within range
- (i == headers.length - postSpan - 1 && (ltr ? evt.clientX >= headPos.x + headPos.w : evt < headPos.x))){
- minCol = headers[i - preSpan];
- maxCol = headers[i + postSpan];
- minPos = html.position(minCol.node);
- maxPos = html.position(maxCol.node);
- minCol = minCol.cell.index;
- maxCol = maxCol.cell.index;
- left = ltr ? minPos.x : maxPos.x;
- width = ltr ? (maxPos.x + maxPos.w - minPos.x) : (minPos.x + minPos.w - maxPos.x);
- break;
- }
- }
- //calc height
- i = 0;
- while(cells[i].hidden){ ++i; }
- var cell = cells[i],
- rowIndex = g.scroller.firstVisibleRow,
- nodePos = html.position(cell.getNode(rowIndex));
- while(nodePos.y + nodePos.h < evt.clientY){
- if(++rowIndex < g.rowCount){
- nodePos = html.position(cell.getNode(rowIndex));
- }else{
- break;
- }
- }
- var minRow = rowIndex >= origin.row - s.min.row ? rowIndex - origin.row + s.min.row : 0;
- var maxRow = minRow + s.max.row - s.min.row;
- if(maxRow >= g.rowCount){
- maxRow = g.rowCount - 1;
- minRow = maxRow - s.max.row + s.min.row;
- }
- minPos = html.position(cell.getNode(minRow));
- maxPos = html.position(cell.getNode(maxRow));
- top = minPos.y;
- height = maxPos.y + maxPos.h - minPos.y;
- this._target = {
- "min":{
- "row": minRow,
- "col": minCol
- },
- "max":{
- "row": maxRow,
- "col": maxCol
- }
- };
- var anchorBorderSize = (html.marginBox(leftTopDiv).w - html.contentBox(leftTopDiv).w) / 2;
- var leftTopCellPos = html.position(cells[minCol].getNode(minRow));
- html.style(leftTopDiv, {
- "width": (leftTopCellPos.w - anchorBorderSize) + "px",
- "height": (leftTopCellPos.h - anchorBorderSize) + "px"
- });
- var rightBottomCellPos = html.position(cells[maxCol].getNode(maxRow));
- html.style(rightBottomDiv, {
- "width": (rightBottomCellPos.w - anchorBorderSize) + "px",
- "height": (rightBottomCellPos.h - anchorBorderSize) + "px"
- });
- return {
- h: height,
- w: width,
- l: left - containerPos.x,
- t: top - containerPos.y
- };
- },
- _markTargetAnchor: function(evt){
- try{
- var t = this._dndRegion.type;
- if(this._alreadyOut || (this._dnding && !this._config[t]["within"]) || (this._extDnding && !this._config[t]["in"])){
- return;
- }
- var height, width, left, top,
- targetAnchor = this._targetAnchor[t],
- pos = html.position(this._container);
- if(!targetAnchor){
- targetAnchor = this._targetAnchor[t] = html.create("div", {
- "class": (t == "cell") ? "dojoxGridCellBorderDIV" : "dojoxGridBorderDIV"
- });
- html.style(targetAnchor, "display", "none");
- this._container.appendChild(targetAnchor);
- }
- switch(t){
- case "col":
- height = pos.h;
- width = this._targetAnchorBorderWidth;
- left = this._calcColTargetAnchorPos(evt, pos);
- top = 0;
- break;
- case "row":
- height = this._targetAnchorBorderWidth;
- width = pos.w;
- left = 0;
- top = this._calcRowTargetAnchorPos(evt, pos);
- break;
- case "cell":
- var cellPos = this._calcCellTargetAnchorPos(evt, pos, targetAnchor);
- height = cellPos.h;
- width = cellPos.w;
- left = cellPos.l;
- top = cellPos.t;
- }
- if(typeof height == "number" && typeof width == "number" && typeof left == "number" && typeof top == "number"){
- html.style(targetAnchor, {
- "height": height + "px",
- "width": width + "px",
- "left": left + "px",
- "top": top + "px"
- });
- html.style(targetAnchor, "display", "");
- }else{
- this._target = null;
- }
- }catch(e){
- console.warn("DnD._markTargetAnchor() error:",e);
- }
- },
- _unmarkTargetAnchor: function(){
- if(this._dndRegion){
- var targetAnchor = this._targetAnchor[this._dndRegion.type];
- if(targetAnchor){
- html.style(this._targetAnchor[this._dndRegion.type], "display", "none");
- }
- }
- },
- _getVisibleHeaders: function(){
- return array.map(array.filter(this.grid.layout.cells, function(cell){
- return !cell.hidden;
- }), function(cell){
- return {
- "node": cell.getHeaderNode(),
- "cell": cell
- };
- });
- },
- _rearrange: function(){
- if(this._target === null){
- return;
- }
- var t = this._dndRegion.type;
- var ranges = this._dndRegion.selected;
- if(t === "cell"){
- this.rearranger[(this._isCopy || this._copyOnly) ? "copyCells" : "moveCells"](ranges[0], this._target === -1 ? null : this._target);
- }else{
- this.rearranger[t == "col" ? "moveColumns" : "moveRows"](_joinToArray(ranges), this._target === -1 ? null: this._target);
- }
- this._target = null;
- },
- onDraggingOver: function(sourcePlugin){
- if(!this._dnding && sourcePlugin){
- sourcePlugin._isSource = true;
- this._extDnding = true;
- if(!this._externalDnd){
- this._externalDnd = true;
- this._dndRegion = this._mapRegion(sourcePlugin.grid, sourcePlugin._dndRegion);
- }
- this._createDnDUI(this._moveEvent,true);
- this.grid.pluginMgr.getPlugin("autoScroll").readyForAutoScroll = true;
- }
- },
- _mapRegion: function(srcGrid, dndRegion){
- if(dndRegion.type === "cell"){
- var srcRange = dndRegion.selected[0];
- var cells = this.grid.layout.cells;
- var srcCells = srcGrid.layout.cells;
- var c, cnt = 0;
- for(c = srcRange.min.col; c <= srcRange.max.col; ++c){
- if(!srcCells[c].hidden){
- ++cnt;
- }
- }
- for(c = 0; cnt > 0; ++c){
- if(!cells[c].hidden){
- --cnt;
- }
- }
- var region = lang.clone(dndRegion);
- region.selected[0].min.col = 0;
- region.selected[0].max.col = c - 1;
- for(c = srcRange.min.col; c <= dndRegion.handle.col; ++c){
- if(!srcCells[c].hidden){
- ++cnt;
- }
- }
- for(c = 0; cnt > 0; ++c){
- if(!cells[c].hidden){
- --cnt;
- }
- }
- region.handle.col = c;
- }
- return dndRegion;
- },
- onDraggingOut: function(sourcePlugin){
- if(this._externalDnd){
- this._extDnding = false;
- this._destroyDnDUI(true, false);
- if(sourcePlugin){
- sourcePlugin._isSource = false;
- }
- }
- },
- onDragIn: function(sourcePlugin, isCopy){
- var success = false;
- if(this._target !== null){
- var type = sourcePlugin._dndRegion.type;
- var ranges = sourcePlugin._dndRegion.selected;
- switch(type){
- case "cell":
- this.rearranger.changeCells(sourcePlugin.grid, ranges[0], this._target);
- break;
- case "row":
- var range = _joinToArray(ranges);
- this.rearranger.insertRows(sourcePlugin.grid, range, this._target);
- break;
- }
- success = true;
- }
- this._endDnd(true);
- if(sourcePlugin.onDragOut){
- sourcePlugin.onDragOut(success && !isCopy);
- }
- },
- onDragOut: function(isMove){
- if(isMove && !this._copyOnly){
- var type = this._dndRegion.type;
- var ranges = this._dndRegion.selected;
- switch(type){
- case "cell":
- this.rearranger.clearCells(ranges[0]);
- break;
- case "row":
- this.rearranger.removeRows(_joinToArray(ranges));
- break;
- }
- }
- this._endDnd(true);
- },
- _canAccept: function(sourcePlugin){
- if(!sourcePlugin){
- return false;
- }
- var srcRegion = sourcePlugin._dndRegion;
- var type = srcRegion.type;
- if(!this._config[type]["in"] || !sourcePlugin._config[type]["out"]){
- return false;
- }
- var g = this.grid;
- var ranges = srcRegion.selected;
- var colCnt = array.filter(g.layout.cells, function(cell){
- return !cell.hidden;
- }).length;
- var rowCnt = g.rowCount;
- var res = true;
- switch(type){
- case "cell":
- ranges = ranges[0];
- res = g.store.getFeatures()["dojo.data.api.Write"] &&
- (ranges.max.row - ranges.min.row) <= rowCnt &&
- array.filter(sourcePlugin.grid.layout.cells, function(cell){
- return cell.index >= ranges.min.col && cell.index <= ranges.max.col && !cell.hidden;
- }).length <= colCnt;
- //intentional drop through - don't break
- case "row":
- if(sourcePlugin._allDnDItemsLoaded()){
- return res;
- }
- }
- return false;
- },
- _allDnDItemsLoaded: function(){
- if(this._dndRegion){
- var type = this._dndRegion.type,
- ranges = this._dndRegion.selected,
- rows = [];
- switch(type){
- case "cell":
- for(var i = ranges[0].min.row, max = ranges[0].max.row; i <= max; ++i){
- rows.push(i);
- }
- break;
- case "row":
- rows = _joinToArray(ranges);
- break;
- default:
- return false;
- }
- var cache = this.grid._by_idx;
- return array.every(rows, function(rowIndex){
- return !!cache[rowIndex];
- });
- }
- return false;
- }
- });
- EnhancedGrid.registerPlugin(DnD/*name:'dnd'*/, {
- "dependency": ["selector", "rearrange"]
- });
- return DnD;
- });
|