1 /** 2 * @fileOverview 3 * Copyright (c) 2013 Regione Autonoma della Sardegna 4 * Published under the GPL license.<br> 5 * See <a href="https://sardegnageoportale.it/webgis/license.txt">https://sardegnageoportale.it/webgis/license.txt</a> 6 * for the full text of the license. 7 * @version 0.1 8 */ 9 10 /** 11 * @include GeoExt/widgets/MapPanel.js 12 * @require OpenLayers/Layer.js 13 */ 14 15 /** 16 * @namespace framework.plugins 17 */ 18 Ext.namespace("GeoExt.tree"); 19 20 /** 21 * The TreeNode UI implementation is separate from the tree implementation, and allows customizing of the appearance of tree nodes. 22 * @name_ LayerNodeUI 23 * @class Layer node object. 24 * @constructor 25 * @extends <a target="_blank" href="http://all-docs.info/extjs4/docs/api/Ext.tree.TreeNodeUI.html">Ext.tree.TreeNodeUI</a> 26 */ 27 GeoExt.tree.LayerNodeUI = Ext.extend(Ext.tree.TreeNodeUI, 28 /** 29 * @lends GeoExt.tree.LayerNodeUI.prototype 30 */ 31 { 32 33 /** 34 * @private 35 * @param {Object} config configurations object 36 */ 37 constructor: function(config) { 38 GeoExt.tree.LayerNodeUI.superclass.constructor.apply(this, arguments); 39 }, 40 41 /** 42 * @private 43 * @param {boolan} bulkRender configurations object 44 */ 45 render: function(bulkRender) { 46 var a = this.node.attributes; 47 if (a.checked === undefined) { 48 a.checked = this.node.layer.getVisibility(); 49 } 50 /* Ext.tree.treeNodeUI render looks for and handles checked 51 * attribute, but not the disabled attribute, so we set it 52 * directly on the node object and not the attributes hash*/ 53 if (a.disabled === undefined && this.node.autoDisable) { 54 this.node.disabled = this.node.layer.inRange === false || !this.node.layer.calculateInRange(); 55 } 56 GeoExt.tree.LayerNodeUI.superclass.render.apply(this, arguments); 57 var cb = this.checkbox; 58 if(a.checkedGroup) { 59 // replace the checkbox with a radio button 60 var radio = Ext.DomHelper.insertAfter(cb, 61 ['<input type="radio" name="', a.checkedGroup, 62 '_checkbox" class="', cb.className, 63 cb.checked ? '" checked="checked"' : '', 64 '"></input>'].join("")); 65 radio.defaultChecked = cb.defaultChecked; 66 Ext.get(cb).remove(); 67 this.checkbox = radio; 68 } 69 this.enforceOneVisible(); 70 }, 71 72 /** Method . 73 * onClick method 74 * @private 75 * @param {Object} e 76 */ 77 onClick: function(e) { 78 79 // Setting background color baselayer 80 var container = Ext.get(this.node.layer.map.getViewport()); 81 82 if(e.getTarget('.x-tree-node-cb', 1)) { 83 this.toggleCheck(this.isChecked()); 84 } else { 85 GeoExt.tree.LayerNodeUI.superclass.onClick.apply(this, arguments); 86 } 87 88 if (this.node.attributes.checkedGroup === "background") { 89 if (this.node.attributes.layer.background){ 90 if(this.node.attributes.layer.visibility === true) 91 container.setStyle('background-color', this.node.attributes.layer.background); 92 } 93 else 94 container.setStyle('background-color', "FFFFFF"); 95 } 96 }, 97 98 /** 99 * toggleCheck method 100 * @private 101 * @param {boolean} value 102 */ 103 toggleCheck: function(value) { 104 value = (value === undefined ? !this.isChecked() : value); 105 GeoExt.tree.LayerNodeUI.superclass.toggleCheck.call(this, value); 106 107 this.enforceOneVisible(); 108 }, 109 110 /** 111 * Makes sure that only one layer is visible if checkedGroup is set. 112 * @private 113 */ 114 enforceOneVisible: function() { 115 var attributes = this.node.attributes; 116 var group = attributes.checkedGroup; 117 // If we are in the baselayer group, the map will take care of 118 // enforcing visibility. 119 if(group && group !== "gx_baselayer") { 120 var layer = this.node.layer; 121 var checkedNodes = this.node.getOwnerTree().getChecked(); 122 var checkedCount = 0; 123 // enforce "not more than one visible" 124 Ext.each(checkedNodes, function(n){ 125 var l = n.layer; 126 if(!n.hidden && n.attributes.checkedGroup === group) { 127 checkedCount++; 128 if(l != layer && attributes.checked) { 129 l.setVisibility(false); 130 if (l.layerNT) { 131 l.map.removeLayer(l.layerNT); 132 } 133 134 } 135 } 136 }); 137 138 //CONTROLLO LAYER TMS "NON DISPONIBILE 139 if (layer.layerNT && layer.map && layer.visibility) { 140 layer.map.addLayer(layer.layerNT); 141 layer.layerNT.setZIndex(-9); 142 layer.setZIndex(-10); 143 } 144 145 // enforce "at least one visible" 146 if(checkedCount === 0 && attributes.checked == false) { 147 layer.setVisibility(true); 148 } 149 } 150 }, 151 152 /** 153 * For radio buttons, makes sure that we do not use the option group of 154 * the original, otherwise only the original or the clone can be checked 155 * @private 156 * @param {String} ghostNode DOMElement 157 */ 158 appendDDGhost : function(ghostNode){ 159 var n = this.elNode.cloneNode(true); 160 var radio = Ext.DomQuery.select("input[type='radio']", n); 161 Ext.each(radio, function(r) { 162 r.name = r.name + "_clone"; 163 }); 164 ghostNode.appendChild(n); 165 } 166 }); 167 168 169 170 /** 171 * A subclass of 'Ext.tree.TreeNode' that is connected to an 172 * 'OpenLayers.Layer' by setting the node's layer property. Checking or 173 * unchecking the checkbox of this node will directly affect the layer and 174 * vice versa. The default iconCls for this node's icon is 175 * "gx-tree-layer-icon", unless it has children. 176 * 177 * Setting the node's layer property to a layer name instead of an object 178 * will also work. As soon as a layer is found, it will be stored as layer 179 * property in the attributes hash. 180 * 181 * The node's text property defaults to the layer name. 182 * 183 * If the node has a checkedGroup attribute configured, it will be 184 * rendered with a radio button instead of the checkbox. The value of 185 * the checkedGroup attribute is a string, identifying the options group 186 * for the node. 187 * 188 * To use this node type in a ``TreePanel`` config, set ``nodeType`` to 189 * "gx_layer". 190 * @name_ LayerNode 191 * @class A subclass of 'Ext.tree.TreeNode' that is connected to an 'OpenLayers.Layer' by setting the node's layer property. 192 * @constructor 193 * @extends <a target="_blank" href="http://dev.sencha.com/deploy/ext-1.1.1/docs/output/Ext.tree.AsyncTreeNode.html">Ext.tree.AsyncTreeNode</a> 194 */ 195 GeoExt.tree.LayerNode = Ext.extend(Ext.tree.AsyncTreeNode, 196 /** 197 * @lends GeoExt.tree.LayerNode.prototype 198 */ 199 { 200 201 /** 202 * The layer that this layer node will 203 * be bound to, or the name of the layer (has to match the layer's 204 * name property). If a layer name is provided, ``layerStore`` also has 205 * to be provided. 206 * @public 207 * @type OpenLayers.Layer/String 208 */ 209 layer: null, 210 211 /** 212 * Should this node automattically disable itself when the layer 213 * is out of range and enable itself when the layer is in range. 214 * Defaults to true, unless ``layer`` has ``isBaseLayer``==true 215 * or ``alwaysInRange``==true. 216 * @public 217 * @type boolean 218 */ 219 autoDisable: null, 220 221 /** 222 * The layer store containing the layer that this node represents. If set 223 * to "auto", the node will query the ComponentManager for a 224 * :class:`GeoExt.MapPanel`, take the first one it finds and take its layer 225 * store. This property is only required if ``layer`` is provided as a 226 * string. 227 * @public 228 * @type GeoExt.data.LayerStore/String 229 */ 230 layerStore: null, 231 232 /** private: method[constructor] 233 * Private constructor override. 234 */ 235 236 /** 237 * Constructor. 238 * @public 239 * @param {Object} config object configuration 240 */ 241 constructor: function(config) { 242 config.leaf = config.leaf || !(config.children || config.loader); 243 244 if(!config.iconCls && !config.children) { 245 config.iconCls = "gx-tree-layer-icon"; 246 } 247 if(config.loader && !(config.loader instanceof Ext.tree.TreeLoader)) { 248 config.loader = new GeoExt.tree.LayerParamLoader(config.loader); 249 } 250 251 this.defaultUI = this.defaultUI || GeoExt.tree.LayerNodeUI; 252 253 Ext.apply(this, { 254 layer: config.layer, 255 layerStore: config.layerStore, 256 autoDisable: config.autoDisable 257 }); 258 if (config.text) { 259 this.fixedText = true; 260 } 261 GeoExt.tree.LayerNode.superclass.constructor.apply(this, arguments); 262 }, 263 264 /** 265 * render method 266 * @private 267 * @param {boolean} bulkRender 268 */ 269 render: function(bulkRender) { 270 var layer = this.layer instanceof OpenLayers.Layer && this.layer; 271 if(!layer) { 272 // guess the store if not provided 273 if(!this.layerStore || this.layerStore == "auto") { 274 this.layerStore = GeoExt.MapPanel.guess().layers; 275 } 276 // now we try to find the layer by its name in the layer store 277 var i = this.layerStore.findBy(function(o) { 278 return o.get("title") == this.layer; 279 }, this); 280 if(i != -1) { 281 // if we found the layer, we can assign it and everything 282 // will be fine 283 layer = this.layerStore.getAt(i).getLayer(); 284 } 285 } 286 if (!this.rendered || !layer) { 287 var ui = this.getUI(); 288 289 if(layer) { 290 this.layer = layer; 291 // no DD and radio buttons for base layers 292 if(layer.isBaseLayer) { 293 this.draggable = false; 294 Ext.applyIf(this.attributes, { 295 checkedGroup: "gx_baselayer" 296 }); 297 } 298 299 //base layers & alwaysInRange layers should never be auto-disabled 300 this.autoDisable = !(this.autoDisable===false || this.layer.isBaseLayer || this.layer.alwaysInRange); 301 302 if(!this.text) { 303 this.text = layer.name; 304 } 305 306 ui.show(); 307 this.addVisibilityEventHandlers(); 308 } else { 309 ui.hide(); 310 } 311 312 if(this.layerStore instanceof GeoExt.data.LayerStore) { 313 this.addStoreEventHandlers(layer); 314 } 315 } 316 GeoExt.tree.LayerNode.superclass.render.apply(this, arguments); 317 }, 318 319 /** private: method[addVisibilityHandlers] 320 * Adds handlers that sync the checkbox state with the layer's visibility 321 * state 322 */ 323 324 /** 325 * Adds handlers that sync the checkbox state with the layer's visibility state 326 * @private 327 */ 328 addVisibilityEventHandlers: function() { 329 this.layer.events.on({ 330 "visibilitychanged": this.onLayerVisibilityChanged, 331 scope: this 332 }); 333 this.on({ 334 "checkchange": this.onCheckChange, 335 scope: this 336 }); 337 if(this.autoDisable){ 338 if (this.layer.map) { 339 this.layer.map.events.register("moveend", this, this.onMapMoveend); 340 } else { 341 this.layer.events.register("added", this, function added() { 342 this.layer.events.unregister("added", this, added); 343 this.layer.map.events.register("moveend", this, this.onMapMoveend); 344 }); 345 } 346 } 347 }, 348 349 /** 350 * handler for visibilitychanged events on the layer. 351 * @private 352 * @param {Object} target Target link to the father object 353 */ 354 onLayerVisibilityChanged: function() { 355 if(!this._visibilityChanging) { 356 this.getUI().toggleCheck(this.layer.getVisibility()); 357 } 358 }, 359 360 /** 361 * handler for checkchange events. 362 * @private 363 * @param {GeoExt.tree.LayerNode} node 364 * @param {boolan} checked 365 */ 366 onCheckChange: function(node, checked) { 367 if(checked != this.layer.getVisibility()) { 368 this._visibilityChanging = true; 369 var layer = this.layer; 370 if(checked && layer.isBaseLayer && layer.map) { 371 layer.map.setBaseLayer(layer); 372 } else { 373 layer.setVisibility(checked); 374 } 375 delete this._visibilityChanging; 376 377 if(node.parentNode && node.parentNode.fireEvent) 378 node.parentNode.fireEvent('childcheckchange',node,checked); 379 } 380 }, 381 382 /** 383 * handler for map moveend events to determine if node should be 384 * disabled or enabled 385 * @private 386 * @param {OpenLayers.Event} evt 387 */ 388 onMapMoveend: function(evt){ 389 /* scoped to node */ 390 if (this.autoDisable) { 391 if (this.layer.inRange === false) { 392 this.disable(); 393 } 394 else { 395 this.enable(); 396 } 397 } 398 }, 399 400 /** 401 * Adds handlers that make sure the node disappeares when the layer is 402 * removed from the store, and appears when it is re-added. 403 * @private 404 */ 405 addStoreEventHandlers: function() { 406 this.layerStore.on({ 407 "add": this.onStoreAdd, 408 "remove": this.onStoreRemove, 409 "update": this.onStoreUpdate, 410 scope: this 411 }); 412 }, 413 414 /** private: method[onStoreAdd] 415 * :param store: ``Ext.data.Store`` 416 * :param records: ``Array(Ext.data.Record)`` 417 * :param index: ``Number`` 418 * 419 * handler for add events on the store 420 */ 421 422 /** 423 * handler for add events on the store. 424 * @private 425 * @param {Ext.data.Store} store 426 * @param {Array(Ext.data.Record)} records 427 * @param {Number} index 428 */ 429 onStoreAdd: function(store, records, index) { 430 var l; 431 for(var i=0; i<records.length; ++i) { 432 l = records[i].getLayer(); 433 if(this.layer == l) { 434 this.getUI().show(); 435 break; 436 } else if (this.layer == l.name) { 437 // layer is a string, which means the node has not yet 438 // been rendered because the layer was not found. But 439 // now we have the layer and can render. 440 this.render(); 441 break; 442 } 443 } 444 }, 445 446 /** 447 * handler for remove events on the store. 448 * @private 449 * @param {Ext.data.Store} store 450 * @param {Array(Ext.data.Record)} records 451 * @param {Number} index 452 */ 453 onStoreRemove: function(store, record, index) { 454 if(this.layer == record.getLayer()) { 455 this.getUI().hide(); 456 } 457 }, 458 459 /** 460 * Listener for the store's update event. 461 * @private 462 * @param {Ext.data.Store} store 463 * @param {Array(Ext.data.Record)} records 464 * @param {Number} index 465 */ 466 onStoreUpdate: function(store, record, operation) { 467 var layer = record.getLayer(); 468 if(!this.fixedText && (this.layer == layer && this.text !== layer.name)) { 469 this.setText(layer.name); 470 } 471 }, 472 473 /** private: method[destroy] 474 */ 475 476 /** 477 * Delete layer 478 * @private 479 */ 480 destroy: function() { 481 var layer = this.layer; 482 if (layer instanceof OpenLayers.Layer) { 483 if (layer.map) { 484 layer.map.events.unregister("moveend", this, this.onMapMoveend); 485 } 486 layer.events.un({ 487 "visibilitychanged": this.onLayerVisibilityChanged, 488 scope: this 489 }); 490 } 491 delete this.layer; 492 var layerStore = this.layerStore; 493 if(layerStore) { 494 layerStore.un("add", this.onStoreAdd, this); 495 layerStore.un("remove", this.onStoreRemove, this); 496 layerStore.un("update", this.onStoreUpdate, this); 497 } 498 delete this.layerStore; 499 this.un("checkchange", this.onCheckChange, this); 500 501 GeoExt.tree.LayerNode.superclass.destroy.apply(this, arguments); 502 } 503 }); 504 505 /** 506 * NodeType: gx_layer 507 */ 508 Ext.tree.TreePanel.nodeTypes.gx_layer = GeoExt.tree.LayerNode; 509 510 /** 511 * Extension for drag node effects 512 */ 513 Ext.extend(Ext.tree.TreeDropZone, Ext.dd.DropZone, { 514 /** 515 * @cfg {String} ddGroup 516 * A named drag drop group to which this object belongs. If a group is specified, then this object will only 517 * interact with other drag drop objects in the same group (defaults to 'TreeDD'). 518 */ 519 ddGroup : "TreeDD", 520 521 /** 522 * @cfg {String} expandDelay 523 * The delay in milliseconds to wait before expanding a target tree node while dragging a droppable node 524 * over the target (defaults to 1000) 525 */ 526 expandDelay : 1000, 527 528 // private 529 expandNode : function(node){ 530 if(node.hasChildNodes() && !node.isExpanded()){ 531 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this)); 532 } 533 }, 534 535 // private 536 queueExpand : function(node){ 537 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]); 538 }, 539 540 // private 541 cancelExpand : function(){ 542 if(this.expandProcId){ 543 clearTimeout(this.expandProcId); 544 this.expandProcId = false; 545 } 546 }, 547 548 // private 549 isValidDropPoint : function(n, pt, dd, e, data){ 550 if(!n || !data){ return false; } 551 var targetNode = n.node; 552 var dropNode = data.node; 553 // default drop rules 554 if(!(targetNode && targetNode.isTarget && pt)){ 555 return false; 556 } 557 if(pt == "append" && targetNode.allowChildren === false){ 558 return false; 559 } 560 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){ 561 return false; 562 } 563 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){ 564 return false; 565 } 566 // reuse the object 567 var overEvent = this.dragOverData; 568 overEvent.tree = this.tree; 569 overEvent.target = targetNode; 570 overEvent.data = data; 571 overEvent.point = pt; 572 overEvent.source = dd; 573 overEvent.rawEvent = e; 574 overEvent.dropNode = dropNode; 575 overEvent.cancel = false; 576 var result = this.tree.fireEvent("nodedragover", overEvent); 577 return overEvent.cancel === false && result !== false; 578 }, 579 580 // private 581 getDropPoint : function(e, n, dd){ 582 var tn = n.node; 583 if(tn.isRoot){ 584 return tn.allowChildren !== false ? "append" : false; // always append for root 585 } 586 var dragEl = n.ddel; 587 var t = Ext.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight; 588 var y = Ext.lib.Event.getPageY(e); 589 var noAppend = tn.allowChildren === false || tn.isLeaf(); 590 if(this.appendOnly || tn.parentNode.allowChildren === false){ 591 return noAppend ? false : "append"; 592 } 593 var noBelow = false; 594 if(!this.allowParentInsert){ 595 noBelow = tn.hasChildNodes() && tn.isExpanded(); 596 } 597 var q = (b - t) / (noAppend ? 2 : 3); 598 if(y >= t && y < (t + q)){ 599 return "above"; 600 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){ 601 return "below"; 602 }else{ 603 return "append"; 604 } 605 }, 606 607 // private 608 onNodeEnter : function(n, dd, e, data){ 609 if(!data.node.layer && (n.node.layer || (n.node.firstChild && n.node.expanded))){ 610 var node = n.node; 611 if(n.node.layer) 612 node = node.parentNode; 613 if(!this.listCloseNodes) 614 this.listCloseNodes = []; 615 node.collapse(); 616 this.listCloseNodes.push(node); 617 } 618 this.cancelExpand(); 619 }, 620 621 onContainerOver : function(dd, e, data) { 622 if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) { 623 return this.dropAllowed; 624 } 625 return this.dropNotAllowed; 626 }, 627 628 // private 629 onNodeOver : function(n, dd, e, data){ 630 var pt = this.getDropPoint(e, n, dd); 631 var node = n.node; 632 633 // auto node expand check 634 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){ 635 this.queueExpand(node); 636 }else if(pt != "append"){ 637 this.cancelExpand(); 638 } 639 640 // set the insert point style on the target node 641 var returnCls = this.dropNotAllowed; 642 if(this.isValidDropPoint(n, pt, dd, e, data)){ 643 if(pt){ 644 var el = n.ddel; 645 var cls; 646 if(pt == "above"){ 647 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between"; 648 cls = "x-tree-drag-insert-above"; 649 }else if(pt == "below"){ 650 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between"; 651 cls = "x-tree-drag-insert-below"; 652 }else{ 653 if(data.node.layer && !node.layer){ 654 returnCls = "x-tree-drop-ok-append"; 655 cls = "x-tree-drag-append"; 656 }else{ 657 returnCls = "x-dd-drop-nodrop"; 658 cls = "_noclass"; 659 } 660 } 661 if(this.lastInsertClass != cls){ 662 Ext.fly(el).replaceClass(this.lastInsertClass, cls); 663 this.lastInsertClass = cls; 664 } 665 } 666 } 667 return returnCls; 668 }, 669 670 // private 671 onNodeOut : function(n, dd, e, data){ 672 this.cancelExpand(); 673 this.removeDropIndicators(n); 674 }, 675 676 // private 677 onNodeDrop : function(n, dd, e, data){ 678 var point = this.getDropPoint(e, n, dd); 679 var targetNode = n.node; 680 targetNode.ui.startDrop(); 681 if(!this.isValidDropPoint(n, point, dd, e, data)){ 682 targetNode.ui.endDrop(); 683 return false; 684 } 685 // first try to find the drop node 686 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null); 687 //reopen the closed nodes 688 if(this.listCloseNodes){ 689 for(var i=0;i<this.listCloseNodes.length;i++){ 690 this.listCloseNodes[i].expand(); 691 } 692 this.listCloseNodes = null; 693 } 694 return this.processDrop(targetNode, data, point, dd, e, dropNode); 695 }, 696 697 onContainerDrop : function(dd, e, data){ 698 if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) { 699 var targetNode = this.tree.getRootNode(); 700 targetNode.ui.startDrop(); 701 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, 'append', e) : null); 702 return this.processDrop(targetNode, data, 'append', dd, e, dropNode); 703 } 704 return false; 705 }, 706 707 // private 708 processDrop: function(target, data, point, dd, e, dropNode){ 709 var dropEvent = { 710 tree : this.tree, 711 target: target, 712 data: data, 713 point: point, 714 source: dd, 715 rawEvent: e, 716 dropNode: dropNode, 717 cancel: !dropNode, 718 dropStatus: false 719 }; 720 var retval = this.tree.fireEvent("beforenodedrop", dropEvent); 721 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){ 722 target.ui.endDrop(); 723 return dropEvent.dropStatus; 724 } 725 726 target = dropEvent.target; 727 if(point == 'append' && !target.isExpanded()){ 728 target.expand(false, null, function(){ 729 this.completeDrop(dropEvent); 730 }.createDelegate(this)); 731 }else{ 732 this.completeDrop(dropEvent); 733 } 734 return true; 735 }, 736 737 // private 738 completeDrop : function(de){ 739 var ns = de.dropNode, p = de.point, t = de.target; 740 if(!Ext.isArray(ns)){ 741 ns = [ns]; 742 } 743 var n; 744 for(var i = 0, len = ns.length; i < len; i++){ 745 n = ns[i]; 746 if(p == "above"){ 747 t.parentNode.insertBefore(n, t); 748 }else if(p == "below"){ 749 t.parentNode.insertBefore(n, t.nextSibling); 750 }else{ 751 t.appendChild(n); 752 } 753 } 754 n.ui.focus(); 755 if(Ext.enableFx && this.tree.hlDrop){ 756 n.ui.highlight(); 757 } 758 t.ui.endDrop(); 759 this.tree.fireEvent("nodedrop", de); 760 }, 761 762 // private 763 afterNodeMoved : function(dd, data, e, targetNode, dropNode){ 764 if(Ext.enableFx && this.tree.hlDrop){ 765 dropNode.ui.focus(); 766 dropNode.ui.highlight(); 767 } 768 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e); 769 }, 770 771 // private 772 getTree : function(){ 773 return this.tree; 774 }, 775 776 // private 777 removeDropIndicators : function(n){ 778 if(n && n.ddel){ 779 var el = n.ddel; 780 Ext.fly(el).removeClass([ 781 "x-tree-drag-insert-above", 782 "x-tree-drag-insert-below", 783 "x-tree-drag-append"]); 784 this.lastInsertClass = "_noclass"; 785 } 786 }, 787 788 // private 789 beforeDragDrop : function(target, e, id){ 790 this.cancelExpand(); 791 return true; 792 }, 793 794 // private 795 afterRepair : function(data){ 796 if(data && Ext.enableFx){ 797 data.node.ui.highlight(); 798 } 799 this.hideProxy(); 800 } 801 }); 802