Forked mumble-django project from https://bitbucket.org/Svedrin/mumble-django
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4770 lines
155 KiB

  1. /*!
  2. * Ext JS Library 3.2.0
  3. * Copyright(c) 2006-2010 Ext JS, Inc.
  4. * licensing@extjs.com
  5. * http://www.extjs.com/license
  6. */
  7. /*
  8. * These classes are derivatives of the similarly named classes in the YUI Library.
  9. * The original license:
  10. * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
  11. * Code licensed under the BSD License:
  12. * http://developer.yahoo.net/yui/license.txt
  13. */
  14. (function() {
  15. var Event=Ext.EventManager;
  16. var Dom=Ext.lib.Dom;
  17. /**
  18. * @class Ext.dd.DragDrop
  19. * Defines the interface and base operation of items that that can be
  20. * dragged or can be drop targets. It was designed to be extended, overriding
  21. * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
  22. * Up to three html elements can be associated with a DragDrop instance:
  23. * <ul>
  24. * <li>linked element: the element that is passed into the constructor.
  25. * This is the element which defines the boundaries for interaction with
  26. * other DragDrop objects.</li>
  27. * <li>handle element(s): The drag operation only occurs if the element that
  28. * was clicked matches a handle element. By default this is the linked
  29. * element, but there are times that you will want only a portion of the
  30. * linked element to initiate the drag operation, and the setHandleElId()
  31. * method provides a way to define this.</li>
  32. * <li>drag element: this represents the element that would be moved along
  33. * with the cursor during a drag operation. By default, this is the linked
  34. * element itself as in {@link Ext.dd.DD}. setDragElId() lets you define
  35. * a separate element that would be moved, as in {@link Ext.dd.DDProxy}.
  36. * </li>
  37. * </ul>
  38. * This class should not be instantiated until the onload event to ensure that
  39. * the associated elements are available.
  40. * The following would define a DragDrop obj that would interact with any
  41. * other DragDrop obj in the "group1" group:
  42. * <pre>
  43. * dd = new Ext.dd.DragDrop("div1", "group1");
  44. * </pre>
  45. * Since none of the event handlers have been implemented, nothing would
  46. * actually happen if you were to run the code above. Normally you would
  47. * override this class or one of the default implementations, but you can
  48. * also override the methods you want on an instance of the class...
  49. * <pre>
  50. * dd.onDragDrop = function(e, id) {
  51. * &nbsp;&nbsp;alert("dd was dropped on " + id);
  52. * }
  53. * </pre>
  54. * @constructor
  55. * @param {String} id of the element that is linked to this instance
  56. * @param {String} sGroup the group of related DragDrop objects
  57. * @param {object} config an object containing configurable attributes
  58. * Valid properties for DragDrop:
  59. * padding, isTarget, maintainOffset, primaryButtonOnly
  60. */
  61. Ext.dd.DragDrop = function(id, sGroup, config) {
  62. if(id) {
  63. this.init(id, sGroup, config);
  64. }
  65. };
  66. Ext.dd.DragDrop.prototype = {
  67. /**
  68. * Set to false to enable a DragDrop object to fire drag events while dragging
  69. * over its own Element. Defaults to true - DragDrop objects do not by default
  70. * fire drag events to themselves.
  71. * @property ignoreSelf
  72. * @type Boolean
  73. */
  74. /**
  75. * The id of the element associated with this object. This is what we
  76. * refer to as the "linked element" because the size and position of
  77. * this element is used to determine when the drag and drop objects have
  78. * interacted.
  79. * @property id
  80. * @type String
  81. */
  82. id: null,
  83. /**
  84. * Configuration attributes passed into the constructor
  85. * @property config
  86. * @type object
  87. */
  88. config: null,
  89. /**
  90. * The id of the element that will be dragged. By default this is same
  91. * as the linked element, but could be changed to another element. Ex:
  92. * Ext.dd.DDProxy
  93. * @property dragElId
  94. * @type String
  95. * @private
  96. */
  97. dragElId: null,
  98. /**
  99. * The ID of the element that initiates the drag operation. By default
  100. * this is the linked element, but could be changed to be a child of this
  101. * element. This lets us do things like only starting the drag when the
  102. * header element within the linked html element is clicked.
  103. * @property handleElId
  104. * @type String
  105. * @private
  106. */
  107. handleElId: null,
  108. /**
  109. * An object who's property names identify HTML tags to be considered invalid as drag handles.
  110. * A non-null property value identifies the tag as invalid. Defaults to the
  111. * following value which prevents drag operations from being initiated by &lt;a> elements:<pre><code>
  112. {
  113. A: "A"
  114. }</code></pre>
  115. * @property invalidHandleTypes
  116. * @type Object
  117. */
  118. invalidHandleTypes: null,
  119. /**
  120. * An object who's property names identify the IDs of elements to be considered invalid as drag handles.
  121. * A non-null property value identifies the ID as invalid. For example, to prevent
  122. * dragging from being initiated on element ID "foo", use:<pre><code>
  123. {
  124. foo: true
  125. }</code></pre>
  126. * @property invalidHandleIds
  127. * @type Object
  128. */
  129. invalidHandleIds: null,
  130. /**
  131. * An Array of CSS class names for elements to be considered in valid as drag handles.
  132. * @property invalidHandleClasses
  133. * @type Array
  134. */
  135. invalidHandleClasses: null,
  136. /**
  137. * The linked element's absolute X position at the time the drag was
  138. * started
  139. * @property startPageX
  140. * @type int
  141. * @private
  142. */
  143. startPageX: 0,
  144. /**
  145. * The linked element's absolute X position at the time the drag was
  146. * started
  147. * @property startPageY
  148. * @type int
  149. * @private
  150. */
  151. startPageY: 0,
  152. /**
  153. * The group defines a logical collection of DragDrop objects that are
  154. * related. Instances only get events when interacting with other
  155. * DragDrop object in the same group. This lets us define multiple
  156. * groups using a single DragDrop subclass if we want.
  157. * @property groups
  158. * @type object An object in the format {'group1':true, 'group2':true}
  159. */
  160. groups: null,
  161. /**
  162. * Individual drag/drop instances can be locked. This will prevent
  163. * onmousedown start drag.
  164. * @property locked
  165. * @type boolean
  166. * @private
  167. */
  168. locked: false,
  169. /**
  170. * Lock this instance
  171. * @method lock
  172. */
  173. lock: function() {
  174. this.locked = true;
  175. },
  176. /**
  177. * When set to true, other DD objects in cooperating DDGroups do not receive
  178. * notification events when this DD object is dragged over them. Defaults to false.
  179. * @property moveOnly
  180. * @type boolean
  181. */
  182. moveOnly: false,
  183. /**
  184. * Unlock this instace
  185. * @method unlock
  186. */
  187. unlock: function() {
  188. this.locked = false;
  189. },
  190. /**
  191. * By default, all instances can be a drop target. This can be disabled by
  192. * setting isTarget to false.
  193. * @property isTarget
  194. * @type boolean
  195. */
  196. isTarget: true,
  197. /**
  198. * The padding configured for this drag and drop object for calculating
  199. * the drop zone intersection with this object.
  200. * @property padding
  201. * @type int[] An array containing the 4 padding values: [top, right, bottom, left]
  202. */
  203. padding: null,
  204. /**
  205. * Cached reference to the linked element
  206. * @property _domRef
  207. * @private
  208. */
  209. _domRef: null,
  210. /**
  211. * Internal typeof flag
  212. * @property __ygDragDrop
  213. * @private
  214. */
  215. __ygDragDrop: true,
  216. /**
  217. * Set to true when horizontal contraints are applied
  218. * @property constrainX
  219. * @type boolean
  220. * @private
  221. */
  222. constrainX: false,
  223. /**
  224. * Set to true when vertical contraints are applied
  225. * @property constrainY
  226. * @type boolean
  227. * @private
  228. */
  229. constrainY: false,
  230. /**
  231. * The left constraint
  232. * @property minX
  233. * @type int
  234. * @private
  235. */
  236. minX: 0,
  237. /**
  238. * The right constraint
  239. * @property maxX
  240. * @type int
  241. * @private
  242. */
  243. maxX: 0,
  244. /**
  245. * The up constraint
  246. * @property minY
  247. * @type int
  248. * @private
  249. */
  250. minY: 0,
  251. /**
  252. * The down constraint
  253. * @property maxY
  254. * @type int
  255. * @private
  256. */
  257. maxY: 0,
  258. /**
  259. * Maintain offsets when we resetconstraints. Set to true when you want
  260. * the position of the element relative to its parent to stay the same
  261. * when the page changes
  262. *
  263. * @property maintainOffset
  264. * @type boolean
  265. */
  266. maintainOffset: false,
  267. /**
  268. * Array of pixel locations the element will snap to if we specified a
  269. * horizontal graduation/interval. This array is generated automatically
  270. * when you define a tick interval.
  271. * @property xTicks
  272. * @type int[]
  273. */
  274. xTicks: null,
  275. /**
  276. * Array of pixel locations the element will snap to if we specified a
  277. * vertical graduation/interval. This array is generated automatically
  278. * when you define a tick interval.
  279. * @property yTicks
  280. * @type int[]
  281. */
  282. yTicks: null,
  283. /**
  284. * By default the drag and drop instance will only respond to the primary
  285. * button click (left button for a right-handed mouse). Set to true to
  286. * allow drag and drop to start with any mouse click that is propogated
  287. * by the browser
  288. * @property primaryButtonOnly
  289. * @type boolean
  290. */
  291. primaryButtonOnly: true,
  292. /**
  293. * The available property is false until the linked dom element is accessible.
  294. * @property available
  295. * @type boolean
  296. */
  297. available: false,
  298. /**
  299. * By default, drags can only be initiated if the mousedown occurs in the
  300. * region the linked element is. This is done in part to work around a
  301. * bug in some browsers that mis-report the mousedown if the previous
  302. * mouseup happened outside of the window. This property is set to true
  303. * if outer handles are defined.
  304. *
  305. * @property hasOuterHandles
  306. * @type boolean
  307. * @default false
  308. */
  309. hasOuterHandles: false,
  310. /**
  311. * Code that executes immediately before the startDrag event
  312. * @method b4StartDrag
  313. * @private
  314. */
  315. b4StartDrag: function(x, y) { },
  316. /**
  317. * Abstract method called after a drag/drop object is clicked
  318. * and the drag or mousedown time thresholds have beeen met.
  319. * @method startDrag
  320. * @param {int} X click location
  321. * @param {int} Y click location
  322. */
  323. startDrag: function(x, y) { /* override this */ },
  324. /**
  325. * Code that executes immediately before the onDrag event
  326. * @method b4Drag
  327. * @private
  328. */
  329. b4Drag: function(e) { },
  330. /**
  331. * Abstract method called during the onMouseMove event while dragging an
  332. * object.
  333. * @method onDrag
  334. * @param {Event} e the mousemove event
  335. */
  336. onDrag: function(e) { /* override this */ },
  337. /**
  338. * Abstract method called when this element fist begins hovering over
  339. * another DragDrop obj
  340. * @method onDragEnter
  341. * @param {Event} e the mousemove event
  342. * @param {String|DragDrop[]} id In POINT mode, the element
  343. * id this is hovering over. In INTERSECT mode, an array of one or more
  344. * dragdrop items being hovered over.
  345. */
  346. onDragEnter: function(e, id) { /* override this */ },
  347. /**
  348. * Code that executes immediately before the onDragOver event
  349. * @method b4DragOver
  350. * @private
  351. */
  352. b4DragOver: function(e) { },
  353. /**
  354. * Abstract method called when this element is hovering over another
  355. * DragDrop obj
  356. * @method onDragOver
  357. * @param {Event} e the mousemove event
  358. * @param {String|DragDrop[]} id In POINT mode, the element
  359. * id this is hovering over. In INTERSECT mode, an array of dd items
  360. * being hovered over.
  361. */
  362. onDragOver: function(e, id) { /* override this */ },
  363. /**
  364. * Code that executes immediately before the onDragOut event
  365. * @method b4DragOut
  366. * @private
  367. */
  368. b4DragOut: function(e) { },
  369. /**
  370. * Abstract method called when we are no longer hovering over an element
  371. * @method onDragOut
  372. * @param {Event} e the mousemove event
  373. * @param {String|DragDrop[]} id In POINT mode, the element
  374. * id this was hovering over. In INTERSECT mode, an array of dd items
  375. * that the mouse is no longer over.
  376. */
  377. onDragOut: function(e, id) { /* override this */ },
  378. /**
  379. * Code that executes immediately before the onDragDrop event
  380. * @method b4DragDrop
  381. * @private
  382. */
  383. b4DragDrop: function(e) { },
  384. /**
  385. * Abstract method called when this item is dropped on another DragDrop
  386. * obj
  387. * @method onDragDrop
  388. * @param {Event} e the mouseup event
  389. * @param {String|DragDrop[]} id In POINT mode, the element
  390. * id this was dropped on. In INTERSECT mode, an array of dd items this
  391. * was dropped on.
  392. */
  393. onDragDrop: function(e, id) { /* override this */ },
  394. /**
  395. * Abstract method called when this item is dropped on an area with no
  396. * drop target
  397. * @method onInvalidDrop
  398. * @param {Event} e the mouseup event
  399. */
  400. onInvalidDrop: function(e) { /* override this */ },
  401. /**
  402. * Code that executes immediately before the endDrag event
  403. * @method b4EndDrag
  404. * @private
  405. */
  406. b4EndDrag: function(e) { },
  407. /**
  408. * Fired when we are done dragging the object
  409. * @method endDrag
  410. * @param {Event} e the mouseup event
  411. */
  412. endDrag: function(e) { /* override this */ },
  413. /**
  414. * Code executed immediately before the onMouseDown event
  415. * @method b4MouseDown
  416. * @param {Event} e the mousedown event
  417. * @private
  418. */
  419. b4MouseDown: function(e) { },
  420. /**
  421. * Event handler that fires when a drag/drop obj gets a mousedown
  422. * @method onMouseDown
  423. * @param {Event} e the mousedown event
  424. */
  425. onMouseDown: function(e) { /* override this */ },
  426. /**
  427. * Event handler that fires when a drag/drop obj gets a mouseup
  428. * @method onMouseUp
  429. * @param {Event} e the mouseup event
  430. */
  431. onMouseUp: function(e) { /* override this */ },
  432. /**
  433. * Override the onAvailable method to do what is needed after the initial
  434. * position was determined.
  435. * @method onAvailable
  436. */
  437. onAvailable: function () {
  438. },
  439. /**
  440. * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
  441. * @type Object
  442. */
  443. defaultPadding : {left:0, right:0, top:0, bottom:0},
  444. /**
  445. * Initializes the drag drop object's constraints to restrict movement to a certain element.
  446. *
  447. * Usage:
  448. <pre><code>
  449. var dd = new Ext.dd.DDProxy("dragDiv1", "proxytest",
  450. { dragElId: "existingProxyDiv" });
  451. dd.startDrag = function(){
  452. this.constrainTo("parent-id");
  453. };
  454. </code></pre>
  455. * Or you can initalize it using the {@link Ext.Element} object:
  456. <pre><code>
  457. Ext.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
  458. startDrag : function(){
  459. this.constrainTo("parent-id");
  460. }
  461. });
  462. </code></pre>
  463. * @param {Mixed} constrainTo The element to constrain to.
  464. * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
  465. * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
  466. * an object containing the sides to pad. For example: {right:10, bottom:10}
  467. * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
  468. */
  469. constrainTo : function(constrainTo, pad, inContent){
  470. if(Ext.isNumber(pad)){
  471. pad = {left: pad, right:pad, top:pad, bottom:pad};
  472. }
  473. pad = pad || this.defaultPadding;
  474. var b = Ext.get(this.getEl()).getBox(),
  475. ce = Ext.get(constrainTo),
  476. s = ce.getScroll(),
  477. c,
  478. cd = ce.dom;
  479. if(cd == document.body){
  480. c = { x: s.left, y: s.top, width: Ext.lib.Dom.getViewWidth(), height: Ext.lib.Dom.getViewHeight()};
  481. }else{
  482. var xy = ce.getXY();
  483. c = {x : xy[0], y: xy[1], width: cd.clientWidth, height: cd.clientHeight};
  484. }
  485. var topSpace = b.y - c.y,
  486. leftSpace = b.x - c.x;
  487. this.resetConstraints();
  488. this.setXConstraint(leftSpace - (pad.left||0), // left
  489. c.width - leftSpace - b.width - (pad.right||0), //right
  490. this.xTickSize
  491. );
  492. this.setYConstraint(topSpace - (pad.top||0), //top
  493. c.height - topSpace - b.height - (pad.bottom||0), //bottom
  494. this.yTickSize
  495. );
  496. },
  497. /**
  498. * Returns a reference to the linked element
  499. * @method getEl
  500. * @return {HTMLElement} the html element
  501. */
  502. getEl: function() {
  503. if (!this._domRef) {
  504. this._domRef = Ext.getDom(this.id);
  505. }
  506. return this._domRef;
  507. },
  508. /**
  509. * Returns a reference to the actual element to drag. By default this is
  510. * the same as the html element, but it can be assigned to another
  511. * element. An example of this can be found in Ext.dd.DDProxy
  512. * @method getDragEl
  513. * @return {HTMLElement} the html element
  514. */
  515. getDragEl: function() {
  516. return Ext.getDom(this.dragElId);
  517. },
  518. /**
  519. * Sets up the DragDrop object. Must be called in the constructor of any
  520. * Ext.dd.DragDrop subclass
  521. * @method init
  522. * @param id the id of the linked element
  523. * @param {String} sGroup the group of related items
  524. * @param {object} config configuration attributes
  525. */
  526. init: function(id, sGroup, config) {
  527. this.initTarget(id, sGroup, config);
  528. Event.on(this.id, "mousedown", this.handleMouseDown, this);
  529. // Event.on(this.id, "selectstart", Event.preventDefault);
  530. },
  531. /**
  532. * Initializes Targeting functionality only... the object does not
  533. * get a mousedown handler.
  534. * @method initTarget
  535. * @param id the id of the linked element
  536. * @param {String} sGroup the group of related items
  537. * @param {object} config configuration attributes
  538. */
  539. initTarget: function(id, sGroup, config) {
  540. // configuration attributes
  541. this.config = config || {};
  542. // create a local reference to the drag and drop manager
  543. this.DDM = Ext.dd.DDM;
  544. // initialize the groups array
  545. this.groups = {};
  546. // assume that we have an element reference instead of an id if the
  547. // parameter is not a string
  548. if (typeof id !== "string") {
  549. id = Ext.id(id);
  550. }
  551. // set the id
  552. this.id = id;
  553. // add to an interaction group
  554. this.addToGroup((sGroup) ? sGroup : "default");
  555. // We don't want to register this as the handle with the manager
  556. // so we just set the id rather than calling the setter.
  557. this.handleElId = id;
  558. // the linked element is the element that gets dragged by default
  559. this.setDragElId(id);
  560. // by default, clicked anchors will not start drag operations.
  561. this.invalidHandleTypes = { A: "A" };
  562. this.invalidHandleIds = {};
  563. this.invalidHandleClasses = [];
  564. this.applyConfig();
  565. this.handleOnAvailable();
  566. },
  567. /**
  568. * Applies the configuration parameters that were passed into the constructor.
  569. * This is supposed to happen at each level through the inheritance chain. So
  570. * a DDProxy implentation will execute apply config on DDProxy, DD, and
  571. * DragDrop in order to get all of the parameters that are available in
  572. * each object.
  573. * @method applyConfig
  574. */
  575. applyConfig: function() {
  576. // configurable properties:
  577. // padding, isTarget, maintainOffset, primaryButtonOnly
  578. this.padding = this.config.padding || [0, 0, 0, 0];
  579. this.isTarget = (this.config.isTarget !== false);
  580. this.maintainOffset = (this.config.maintainOffset);
  581. this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
  582. },
  583. /**
  584. * Executed when the linked element is available
  585. * @method handleOnAvailable
  586. * @private
  587. */
  588. handleOnAvailable: function() {
  589. this.available = true;
  590. this.resetConstraints();
  591. this.onAvailable();
  592. },
  593. /**
  594. * Configures the padding for the target zone in px. Effectively expands
  595. * (or reduces) the virtual object size for targeting calculations.
  596. * Supports css-style shorthand; if only one parameter is passed, all sides
  597. * will have that padding, and if only two are passed, the top and bottom
  598. * will have the first param, the left and right the second.
  599. * @method setPadding
  600. * @param {int} iTop Top pad
  601. * @param {int} iRight Right pad
  602. * @param {int} iBot Bot pad
  603. * @param {int} iLeft Left pad
  604. */
  605. setPadding: function(iTop, iRight, iBot, iLeft) {
  606. // this.padding = [iLeft, iRight, iTop, iBot];
  607. if (!iRight && 0 !== iRight) {
  608. this.padding = [iTop, iTop, iTop, iTop];
  609. } else if (!iBot && 0 !== iBot) {
  610. this.padding = [iTop, iRight, iTop, iRight];
  611. } else {
  612. this.padding = [iTop, iRight, iBot, iLeft];
  613. }
  614. },
  615. /**
  616. * Stores the initial placement of the linked element.
  617. * @method setInitPosition
  618. * @param {int} diffX the X offset, default 0
  619. * @param {int} diffY the Y offset, default 0
  620. */
  621. setInitPosition: function(diffX, diffY) {
  622. var el = this.getEl();
  623. if (!this.DDM.verifyEl(el)) {
  624. return;
  625. }
  626. var dx = diffX || 0;
  627. var dy = diffY || 0;
  628. var p = Dom.getXY( el );
  629. this.initPageX = p[0] - dx;
  630. this.initPageY = p[1] - dy;
  631. this.lastPageX = p[0];
  632. this.lastPageY = p[1];
  633. this.setStartPosition(p);
  634. },
  635. /**
  636. * Sets the start position of the element. This is set when the obj
  637. * is initialized, the reset when a drag is started.
  638. * @method setStartPosition
  639. * @param pos current position (from previous lookup)
  640. * @private
  641. */
  642. setStartPosition: function(pos) {
  643. var p = pos || Dom.getXY( this.getEl() );
  644. this.deltaSetXY = null;
  645. this.startPageX = p[0];
  646. this.startPageY = p[1];
  647. },
  648. /**
  649. * Add this instance to a group of related drag/drop objects. All
  650. * instances belong to at least one group, and can belong to as many
  651. * groups as needed.
  652. * @method addToGroup
  653. * @param sGroup {string} the name of the group
  654. */
  655. addToGroup: function(sGroup) {
  656. this.groups[sGroup] = true;
  657. this.DDM.regDragDrop(this, sGroup);
  658. },
  659. /**
  660. * Remove's this instance from the supplied interaction group
  661. * @method removeFromGroup
  662. * @param {string} sGroup The group to drop
  663. */
  664. removeFromGroup: function(sGroup) {
  665. if (this.groups[sGroup]) {
  666. delete this.groups[sGroup];
  667. }
  668. this.DDM.removeDDFromGroup(this, sGroup);
  669. },
  670. /**
  671. * Allows you to specify that an element other than the linked element
  672. * will be moved with the cursor during a drag
  673. * @method setDragElId
  674. * @param id {string} the id of the element that will be used to initiate the drag
  675. */
  676. setDragElId: function(id) {
  677. this.dragElId = id;
  678. },
  679. /**
  680. * Allows you to specify a child of the linked element that should be
  681. * used to initiate the drag operation. An example of this would be if
  682. * you have a content div with text and links. Clicking anywhere in the
  683. * content area would normally start the drag operation. Use this method
  684. * to specify that an element inside of the content div is the element
  685. * that starts the drag operation.
  686. * @method setHandleElId
  687. * @param id {string} the id of the element that will be used to
  688. * initiate the drag.
  689. */
  690. setHandleElId: function(id) {
  691. if (typeof id !== "string") {
  692. id = Ext.id(id);
  693. }
  694. this.handleElId = id;
  695. this.DDM.regHandle(this.id, id);
  696. },
  697. /**
  698. * Allows you to set an element outside of the linked element as a drag
  699. * handle
  700. * @method setOuterHandleElId
  701. * @param id the id of the element that will be used to initiate the drag
  702. */
  703. setOuterHandleElId: function(id) {
  704. if (typeof id !== "string") {
  705. id = Ext.id(id);
  706. }
  707. Event.on(id, "mousedown",
  708. this.handleMouseDown, this);
  709. this.setHandleElId(id);
  710. this.hasOuterHandles = true;
  711. },
  712. /**
  713. * Remove all drag and drop hooks for this element
  714. * @method unreg
  715. */
  716. unreg: function() {
  717. Event.un(this.id, "mousedown",
  718. this.handleMouseDown);
  719. this._domRef = null;
  720. this.DDM._remove(this);
  721. },
  722. destroy : function(){
  723. this.unreg();
  724. },
  725. /**
  726. * Returns true if this instance is locked, or the drag drop mgr is locked
  727. * (meaning that all drag/drop is disabled on the page.)
  728. * @method isLocked
  729. * @return {boolean} true if this obj or all drag/drop is locked, else
  730. * false
  731. */
  732. isLocked: function() {
  733. return (this.DDM.isLocked() || this.locked);
  734. },
  735. /**
  736. * Fired when this object is clicked
  737. * @method handleMouseDown
  738. * @param {Event} e
  739. * @param {Ext.dd.DragDrop} oDD the clicked dd object (this dd obj)
  740. * @private
  741. */
  742. handleMouseDown: function(e, oDD){
  743. if (this.primaryButtonOnly && e.button != 0) {
  744. return;
  745. }
  746. if (this.isLocked()) {
  747. return;
  748. }
  749. this.DDM.refreshCache(this.groups);
  750. var pt = new Ext.lib.Point(Ext.lib.Event.getPageX(e), Ext.lib.Event.getPageY(e));
  751. if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
  752. } else {
  753. if (this.clickValidator(e)) {
  754. // set the initial element position
  755. this.setStartPosition();
  756. this.b4MouseDown(e);
  757. this.onMouseDown(e);
  758. this.DDM.handleMouseDown(e, this);
  759. this.DDM.stopEvent(e);
  760. } else {
  761. }
  762. }
  763. },
  764. clickValidator: function(e) {
  765. var target = e.getTarget();
  766. return ( this.isValidHandleChild(target) &&
  767. (this.id == this.handleElId ||
  768. this.DDM.handleWasClicked(target, this.id)) );
  769. },
  770. /**
  771. * Allows you to specify a tag name that should not start a drag operation
  772. * when clicked. This is designed to facilitate embedding links within a
  773. * drag handle that do something other than start the drag.
  774. * @method addInvalidHandleType
  775. * @param {string} tagName the type of element to exclude
  776. */
  777. addInvalidHandleType: function(tagName) {
  778. var type = tagName.toUpperCase();
  779. this.invalidHandleTypes[type] = type;
  780. },
  781. /**
  782. * Lets you to specify an element id for a child of a drag handle
  783. * that should not initiate a drag
  784. * @method addInvalidHandleId
  785. * @param {string} id the element id of the element you wish to ignore
  786. */
  787. addInvalidHandleId: function(id) {
  788. if (typeof id !== "string") {
  789. id = Ext.id(id);
  790. }
  791. this.invalidHandleIds[id] = id;
  792. },
  793. /**
  794. * Lets you specify a css class of elements that will not initiate a drag
  795. * @method addInvalidHandleClass
  796. * @param {string} cssClass the class of the elements you wish to ignore
  797. */
  798. addInvalidHandleClass: function(cssClass) {
  799. this.invalidHandleClasses.push(cssClass);
  800. },
  801. /**
  802. * Unsets an excluded tag name set by addInvalidHandleType
  803. * @method removeInvalidHandleType
  804. * @param {string} tagName the type of element to unexclude
  805. */
  806. removeInvalidHandleType: function(tagName) {
  807. var type = tagName.toUpperCase();
  808. // this.invalidHandleTypes[type] = null;
  809. delete this.invalidHandleTypes[type];
  810. },
  811. /**
  812. * Unsets an invalid handle id
  813. * @method removeInvalidHandleId
  814. * @param {string} id the id of the element to re-enable
  815. */
  816. removeInvalidHandleId: function(id) {
  817. if (typeof id !== "string") {
  818. id = Ext.id(id);
  819. }
  820. delete this.invalidHandleIds[id];
  821. },
  822. /**
  823. * Unsets an invalid css class
  824. * @method removeInvalidHandleClass
  825. * @param {string} cssClass the class of the element(s) you wish to
  826. * re-enable
  827. */
  828. removeInvalidHandleClass: function(cssClass) {
  829. for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
  830. if (this.invalidHandleClasses[i] == cssClass) {
  831. delete this.invalidHandleClasses[i];
  832. }
  833. }
  834. },
  835. /**
  836. * Checks the tag exclusion list to see if this click should be ignored
  837. * @method isValidHandleChild
  838. * @param {HTMLElement} node the HTMLElement to evaluate
  839. * @return {boolean} true if this is a valid tag type, false if not
  840. */
  841. isValidHandleChild: function(node) {
  842. var valid = true;
  843. // var n = (node.nodeName == "#text") ? node.parentNode : node;
  844. var nodeName;
  845. try {
  846. nodeName = node.nodeName.toUpperCase();
  847. } catch(e) {
  848. nodeName = node.nodeName;
  849. }
  850. valid = valid && !this.invalidHandleTypes[nodeName];
  851. valid = valid && !this.invalidHandleIds[node.id];
  852. for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
  853. valid = !Ext.fly(node).hasClass(this.invalidHandleClasses[i]);
  854. }
  855. return valid;
  856. },
  857. /**
  858. * Create the array of horizontal tick marks if an interval was specified
  859. * in setXConstraint().
  860. * @method setXTicks
  861. * @private
  862. */
  863. setXTicks: function(iStartX, iTickSize) {
  864. this.xTicks = [];
  865. this.xTickSize = iTickSize;
  866. var tickMap = {};
  867. for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
  868. if (!tickMap[i]) {
  869. this.xTicks[this.xTicks.length] = i;
  870. tickMap[i] = true;
  871. }
  872. }
  873. for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
  874. if (!tickMap[i]) {
  875. this.xTicks[this.xTicks.length] = i;
  876. tickMap[i] = true;
  877. }
  878. }
  879. this.xTicks.sort(this.DDM.numericSort) ;
  880. },
  881. /**
  882. * Create the array of vertical tick marks if an interval was specified in
  883. * setYConstraint().
  884. * @method setYTicks
  885. * @private
  886. */
  887. setYTicks: function(iStartY, iTickSize) {
  888. this.yTicks = [];
  889. this.yTickSize = iTickSize;
  890. var tickMap = {};
  891. for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
  892. if (!tickMap[i]) {
  893. this.yTicks[this.yTicks.length] = i;
  894. tickMap[i] = true;
  895. }
  896. }
  897. for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
  898. if (!tickMap[i]) {
  899. this.yTicks[this.yTicks.length] = i;
  900. tickMap[i] = true;
  901. }
  902. }
  903. this.yTicks.sort(this.DDM.numericSort) ;
  904. },
  905. /**
  906. * By default, the element can be dragged any place on the screen. Use
  907. * this method to limit the horizontal travel of the element. Pass in
  908. * 0,0 for the parameters if you want to lock the drag to the y axis.
  909. * @method setXConstraint
  910. * @param {int} iLeft the number of pixels the element can move to the left
  911. * @param {int} iRight the number of pixels the element can move to the
  912. * right
  913. * @param {int} iTickSize optional parameter for specifying that the
  914. * element
  915. * should move iTickSize pixels at a time.
  916. */
  917. setXConstraint: function(iLeft, iRight, iTickSize) {
  918. this.leftConstraint = iLeft;
  919. this.rightConstraint = iRight;
  920. this.minX = this.initPageX - iLeft;
  921. this.maxX = this.initPageX + iRight;
  922. if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
  923. this.constrainX = true;
  924. },
  925. /**
  926. * Clears any constraints applied to this instance. Also clears ticks
  927. * since they can't exist independent of a constraint at this time.
  928. * @method clearConstraints
  929. */
  930. clearConstraints: function() {
  931. this.constrainX = false;
  932. this.constrainY = false;
  933. this.clearTicks();
  934. },
  935. /**
  936. * Clears any tick interval defined for this instance
  937. * @method clearTicks
  938. */
  939. clearTicks: function() {
  940. this.xTicks = null;
  941. this.yTicks = null;
  942. this.xTickSize = 0;
  943. this.yTickSize = 0;
  944. },
  945. /**
  946. * By default, the element can be dragged any place on the screen. Set
  947. * this to limit the vertical travel of the element. Pass in 0,0 for the
  948. * parameters if you want to lock the drag to the x axis.
  949. * @method setYConstraint
  950. * @param {int} iUp the number of pixels the element can move up
  951. * @param {int} iDown the number of pixels the element can move down
  952. * @param {int} iTickSize optional parameter for specifying that the
  953. * element should move iTickSize pixels at a time.
  954. */
  955. setYConstraint: function(iUp, iDown, iTickSize) {
  956. this.topConstraint = iUp;
  957. this.bottomConstraint = iDown;
  958. this.minY = this.initPageY - iUp;
  959. this.maxY = this.initPageY + iDown;
  960. if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
  961. this.constrainY = true;
  962. },
  963. /**
  964. * resetConstraints must be called if you manually reposition a dd element.
  965. * @method resetConstraints
  966. * @param {boolean} maintainOffset
  967. */
  968. resetConstraints: function() {
  969. // Maintain offsets if necessary
  970. if (this.initPageX || this.initPageX === 0) {
  971. // figure out how much this thing has moved
  972. var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
  973. var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
  974. this.setInitPosition(dx, dy);
  975. // This is the first time we have detected the element's position
  976. } else {
  977. this.setInitPosition();
  978. }
  979. if (this.constrainX) {
  980. this.setXConstraint( this.leftConstraint,
  981. this.rightConstraint,
  982. this.xTickSize );
  983. }
  984. if (this.constrainY) {
  985. this.setYConstraint( this.topConstraint,
  986. this.bottomConstraint,
  987. this.yTickSize );
  988. }
  989. },
  990. /**
  991. * Normally the drag element is moved pixel by pixel, but we can specify
  992. * that it move a number of pixels at a time. This method resolves the
  993. * location when we have it set up like this.
  994. * @method getTick
  995. * @param {int} val where we want to place the object
  996. * @param {int[]} tickArray sorted array of valid points
  997. * @return {int} the closest tick
  998. * @private
  999. */
  1000. getTick: function(val, tickArray) {
  1001. if (!tickArray) {
  1002. // If tick interval is not defined, it is effectively 1 pixel,
  1003. // so we return the value passed to us.
  1004. return val;
  1005. } else if (tickArray[0] >= val) {
  1006. // The value is lower than the first tick, so we return the first
  1007. // tick.
  1008. return tickArray[0];
  1009. } else {
  1010. for (var i=0, len=tickArray.length; i<len; ++i) {
  1011. var next = i + 1;
  1012. if (tickArray[next] && tickArray[next] >= val) {
  1013. var diff1 = val - tickArray[i];
  1014. var diff2 = tickArray[next] - val;
  1015. return (diff2 > diff1) ? tickArray[i] : tickArray[next];
  1016. }
  1017. }
  1018. // The value is larger than the last tick, so we return the last
  1019. // tick.
  1020. return tickArray[tickArray.length - 1];
  1021. }
  1022. },
  1023. /**
  1024. * toString method
  1025. * @method toString
  1026. * @return {string} string representation of the dd obj
  1027. */
  1028. toString: function() {
  1029. return ("DragDrop " + this.id);
  1030. }
  1031. };
  1032. })();
  1033. /*!
  1034. * The drag and drop utility provides a framework for building drag and drop
  1035. * applications. In addition to enabling drag and drop for specific elements,
  1036. * the drag and drop elements are tracked by the manager class, and the
  1037. * interactions between the various elements are tracked during the drag and
  1038. * the implementing code is notified about these important moments.
  1039. */
  1040. // Only load the library once. Rewriting the manager class would orphan
  1041. // existing drag and drop instances.
  1042. if (!Ext.dd.DragDropMgr) {
  1043. /**
  1044. * @class Ext.dd.DragDropMgr
  1045. * DragDropMgr is a singleton that tracks the element interaction for
  1046. * all DragDrop items in the window. Generally, you will not call
  1047. * this class directly, but it does have helper methods that could
  1048. * be useful in your DragDrop implementations.
  1049. * @singleton
  1050. */
  1051. Ext.dd.DragDropMgr = function() {
  1052. var Event = Ext.EventManager;
  1053. return {
  1054. /**
  1055. * Two dimensional Array of registered DragDrop objects. The first
  1056. * dimension is the DragDrop item group, the second the DragDrop
  1057. * object.
  1058. * @property ids
  1059. * @type String[]
  1060. * @private
  1061. * @static
  1062. */
  1063. ids: {},
  1064. /**
  1065. * Array of element ids defined as drag handles. Used to determine
  1066. * if the element that generated the mousedown event is actually the
  1067. * handle and not the html element itself.
  1068. * @property handleIds
  1069. * @type String[]
  1070. * @private
  1071. * @static
  1072. */
  1073. handleIds: {},
  1074. /**
  1075. * the DragDrop object that is currently being dragged
  1076. * @property dragCurrent
  1077. * @type DragDrop
  1078. * @private
  1079. * @static
  1080. **/
  1081. dragCurrent: null,
  1082. /**
  1083. * the DragDrop object(s) that are being hovered over
  1084. * @property dragOvers
  1085. * @type Array
  1086. * @private
  1087. * @static
  1088. */
  1089. dragOvers: {},
  1090. /**
  1091. * the X distance between the cursor and the object being dragged
  1092. * @property deltaX
  1093. * @type int
  1094. * @private
  1095. * @static
  1096. */
  1097. deltaX: 0,
  1098. /**
  1099. * the Y distance between the cursor and the object being dragged
  1100. * @property deltaY
  1101. * @type int
  1102. * @private
  1103. * @static
  1104. */
  1105. deltaY: 0,
  1106. /**
  1107. * Flag to determine if we should prevent the default behavior of the
  1108. * events we define. By default this is true, but this can be set to
  1109. * false if you need the default behavior (not recommended)
  1110. * @property preventDefault
  1111. * @type boolean
  1112. * @static
  1113. */
  1114. preventDefault: true,
  1115. /**
  1116. * Flag to determine if we should stop the propagation of the events
  1117. * we generate. This is true by default but you may want to set it to
  1118. * false if the html element contains other features that require the
  1119. * mouse click.
  1120. * @property stopPropagation
  1121. * @type boolean
  1122. * @static
  1123. */
  1124. stopPropagation: true,
  1125. /**
  1126. * Internal flag that is set to true when drag and drop has been
  1127. * intialized
  1128. * @property initialized
  1129. * @private
  1130. * @static
  1131. */
  1132. initialized: false,
  1133. /**
  1134. * All drag and drop can be disabled.
  1135. * @property locked
  1136. * @private
  1137. * @static
  1138. */
  1139. locked: false,
  1140. /**
  1141. * Called the first time an element is registered.
  1142. * @method init
  1143. * @private
  1144. * @static
  1145. */
  1146. init: function() {
  1147. this.initialized = true;
  1148. },
  1149. /**
  1150. * In point mode, drag and drop interaction is defined by the
  1151. * location of the cursor during the drag/drop
  1152. * @property POINT
  1153. * @type int
  1154. * @static
  1155. */
  1156. POINT: 0,
  1157. /**
  1158. * In intersect mode, drag and drop interaction is defined by the
  1159. * overlap of two or more drag and drop objects.
  1160. * @property INTERSECT
  1161. * @type int
  1162. * @static
  1163. */
  1164. INTERSECT: 1,
  1165. /**
  1166. * The current drag and drop mode. Default: POINT
  1167. * @property mode
  1168. * @type int
  1169. * @static
  1170. */
  1171. mode: 0,
  1172. /**
  1173. * Runs method on all drag and drop objects
  1174. * @method _execOnAll
  1175. * @private
  1176. * @static
  1177. */
  1178. _execOnAll: function(sMethod, args) {
  1179. for (var i in this.ids) {
  1180. for (var j in this.ids[i]) {
  1181. var oDD = this.ids[i][j];
  1182. if (! this.isTypeOfDD(oDD)) {
  1183. continue;
  1184. }
  1185. oDD[sMethod].apply(oDD, args);
  1186. }
  1187. }
  1188. },
  1189. /**
  1190. * Drag and drop initialization. Sets up the global event handlers
  1191. * @method _onLoad
  1192. * @private
  1193. * @static
  1194. */
  1195. _onLoad: function() {
  1196. this.init();
  1197. Event.on(document, "mouseup", this.handleMouseUp, this, true);
  1198. Event.on(document, "mousemove", this.handleMouseMove, this, true);
  1199. Event.on(window, "unload", this._onUnload, this, true);
  1200. Event.on(window, "resize", this._onResize, this, true);
  1201. // Event.on(window, "mouseout", this._test);
  1202. },
  1203. /**
  1204. * Reset constraints on all drag and drop objs
  1205. * @method _onResize
  1206. * @private
  1207. * @static
  1208. */
  1209. _onResize: function(e) {
  1210. this._execOnAll("resetConstraints", []);
  1211. },
  1212. /**
  1213. * Lock all drag and drop functionality
  1214. * @method lock
  1215. * @static
  1216. */
  1217. lock: function() { this.locked = true; },
  1218. /**
  1219. * Unlock all drag and drop functionality
  1220. * @method unlock
  1221. * @static
  1222. */
  1223. unlock: function() { this.locked = false; },
  1224. /**
  1225. * Is drag and drop locked?
  1226. * @method isLocked
  1227. * @return {boolean} True if drag and drop is locked, false otherwise.
  1228. * @static
  1229. */
  1230. isLocked: function() { return this.locked; },
  1231. /**
  1232. * Location cache that is set for all drag drop objects when a drag is
  1233. * initiated, cleared when the drag is finished.
  1234. * @property locationCache
  1235. * @private
  1236. * @static
  1237. */
  1238. locationCache: {},
  1239. /**
  1240. * Set useCache to false if you want to force object the lookup of each
  1241. * drag and drop linked element constantly during a drag.
  1242. * @property useCache
  1243. * @type boolean
  1244. * @static
  1245. */
  1246. useCache: true,
  1247. /**
  1248. * The number of pixels that the mouse needs to move after the
  1249. * mousedown before the drag is initiated. Default=3;
  1250. * @property clickPixelThresh
  1251. * @type int
  1252. * @static
  1253. */
  1254. clickPixelThresh: 3,
  1255. /**
  1256. * The number of milliseconds after the mousedown event to initiate the
  1257. * drag if we don't get a mouseup event. Default=350
  1258. * @property clickTimeThresh
  1259. * @type int
  1260. * @static
  1261. */
  1262. clickTimeThresh: 350,
  1263. /**
  1264. * Flag that indicates that either the drag pixel threshold or the
  1265. * mousdown time threshold has been met
  1266. * @property dragThreshMet
  1267. * @type boolean
  1268. * @private
  1269. * @static
  1270. */
  1271. dragThreshMet: false,
  1272. /**
  1273. * Timeout used for the click time threshold
  1274. * @property clickTimeout
  1275. * @type Object
  1276. * @private
  1277. * @static
  1278. */
  1279. clickTimeout: null,
  1280. /**
  1281. * The X position of the mousedown event stored for later use when a
  1282. * drag threshold is met.
  1283. * @property startX
  1284. * @type int
  1285. * @private
  1286. * @static
  1287. */
  1288. startX: 0,
  1289. /**
  1290. * The Y position of the mousedown event stored for later use when a
  1291. * drag threshold is met.
  1292. * @property startY
  1293. * @type int
  1294. * @private
  1295. * @static
  1296. */
  1297. startY: 0,
  1298. /**
  1299. * Each DragDrop instance must be registered with the DragDropMgr.
  1300. * This is executed in DragDrop.init()
  1301. * @method regDragDrop
  1302. * @param {DragDrop} oDD the DragDrop object to register
  1303. * @param {String} sGroup the name of the group this element belongs to
  1304. * @static
  1305. */
  1306. regDragDrop: function(oDD, sGroup) {
  1307. if (!this.initialized) { this.init(); }
  1308. if (!this.ids[sGroup]) {
  1309. this.ids[sGroup] = {};
  1310. }
  1311. this.ids[sGroup][oDD.id] = oDD;
  1312. },
  1313. /**
  1314. * Removes the supplied dd instance from the supplied group. Executed
  1315. * by DragDrop.removeFromGroup, so don't call this function directly.
  1316. * @method removeDDFromGroup
  1317. * @private
  1318. * @static
  1319. */
  1320. removeDDFromGroup: function(oDD, sGroup) {
  1321. if (!this.ids[sGroup]) {
  1322. this.ids[sGroup] = {};
  1323. }
  1324. var obj = this.ids[sGroup];
  1325. if (obj && obj[oDD.id]) {
  1326. delete obj[oDD.id];
  1327. }
  1328. },
  1329. /**
  1330. * Unregisters a drag and drop item. This is executed in
  1331. * DragDrop.unreg, use that method instead of calling this directly.
  1332. * @method _remove
  1333. * @private
  1334. * @static
  1335. */
  1336. _remove: function(oDD) {
  1337. for (var g in oDD.groups) {
  1338. if (g && this.ids[g] && this.ids[g][oDD.id]) {
  1339. delete this.ids[g][oDD.id];
  1340. }
  1341. }
  1342. delete this.handleIds[oDD.id];
  1343. },
  1344. /**
  1345. * Each DragDrop handle element must be registered. This is done
  1346. * automatically when executing DragDrop.setHandleElId()
  1347. * @method regHandle
  1348. * @param {String} sDDId the DragDrop id this element is a handle for
  1349. * @param {String} sHandleId the id of the element that is the drag
  1350. * handle
  1351. * @static
  1352. */
  1353. regHandle: function(sDDId, sHandleId) {
  1354. if (!this.handleIds[sDDId]) {
  1355. this.handleIds[sDDId] = {};
  1356. }
  1357. this.handleIds[sDDId][sHandleId] = sHandleId;
  1358. },
  1359. /**
  1360. * Utility function to determine if a given element has been
  1361. * registered as a drag drop item.
  1362. * @method isDragDrop
  1363. * @param {String} id the element id to check
  1364. * @return {boolean} true if this element is a DragDrop item,
  1365. * false otherwise
  1366. * @static
  1367. */
  1368. isDragDrop: function(id) {
  1369. return ( this.getDDById(id) ) ? true : false;
  1370. },
  1371. /**
  1372. * Returns the drag and drop instances that are in all groups the
  1373. * passed in instance belongs to.
  1374. * @method getRelated
  1375. * @param {DragDrop} p_oDD the obj to get related data for
  1376. * @param {boolean} bTargetsOnly if true, only return targetable objs
  1377. * @return {DragDrop[]} the related instances
  1378. * @static
  1379. */
  1380. getRelated: function(p_oDD, bTargetsOnly) {
  1381. var oDDs = [];
  1382. for (var i in p_oDD.groups) {
  1383. for (var j in this.ids[i]) {
  1384. var dd = this.ids[i][j];
  1385. if (! this.isTypeOfDD(dd)) {
  1386. continue;
  1387. }
  1388. if (!bTargetsOnly || dd.isTarget) {
  1389. oDDs[oDDs.length] = dd;
  1390. }
  1391. }
  1392. }
  1393. return oDDs;
  1394. },
  1395. /**
  1396. * Returns true if the specified dd target is a legal target for
  1397. * the specifice drag obj
  1398. * @method isLegalTarget
  1399. * @param {DragDrop} oDD the drag obj
  1400. * @param {DragDrop} oTargetDD the target
  1401. * @return {boolean} true if the target is a legal target for the
  1402. * dd obj
  1403. * @static
  1404. */
  1405. isLegalTarget: function (oDD, oTargetDD) {
  1406. var targets = this.getRelated(oDD, true);
  1407. for (var i=0, len=targets.length;i<len;++i) {
  1408. if (targets[i].id == oTargetDD.id) {
  1409. return true;
  1410. }
  1411. }
  1412. return false;
  1413. },
  1414. /**
  1415. * My goal is to be able to transparently determine if an object is
  1416. * typeof DragDrop, and the exact subclass of DragDrop. typeof
  1417. * returns "object", oDD.constructor.toString() always returns
  1418. * "DragDrop" and not the name of the subclass. So for now it just
  1419. * evaluates a well-known variable in DragDrop.
  1420. * @method isTypeOfDD
  1421. * @param {Object} the object to evaluate
  1422. * @return {boolean} true if typeof oDD = DragDrop
  1423. * @static
  1424. */
  1425. isTypeOfDD: function (oDD) {
  1426. return (oDD && oDD.__ygDragDrop);
  1427. },
  1428. /**
  1429. * Utility function to determine if a given element has been
  1430. * registered as a drag drop handle for the given Drag Drop object.
  1431. * @method isHandle
  1432. * @param {String} id the element id to check
  1433. * @return {boolean} true if this element is a DragDrop handle, false
  1434. * otherwise
  1435. * @static
  1436. */
  1437. isHandle: function(sDDId, sHandleId) {
  1438. return ( this.handleIds[sDDId] &&
  1439. this.handleIds[sDDId][sHandleId] );
  1440. },
  1441. /**
  1442. * Returns the DragDrop instance for a given id
  1443. * @method getDDById
  1444. * @param {String} id the id of the DragDrop object
  1445. * @return {DragDrop} the drag drop object, null if it is not found
  1446. * @static
  1447. */
  1448. getDDById: function(id) {
  1449. for (var i in this.ids) {
  1450. if (this.ids[i][id]) {
  1451. return this.ids[i][id];
  1452. }
  1453. }
  1454. return null;
  1455. },
  1456. /**
  1457. * Fired after a registered DragDrop object gets the mousedown event.
  1458. * Sets up the events required to track the object being dragged
  1459. * @method handleMouseDown
  1460. * @param {Event} e the event
  1461. * @param oDD the DragDrop object being dragged
  1462. * @private
  1463. * @static
  1464. */
  1465. handleMouseDown: function(e, oDD) {
  1466. if(Ext.QuickTips){
  1467. Ext.QuickTips.disable();
  1468. }
  1469. if(this.dragCurrent){
  1470. // the original browser mouseup wasn't handled (e.g. outside FF browser window)
  1471. // so clean up first to avoid breaking the next drag
  1472. this.handleMouseUp(e);
  1473. }
  1474. this.currentTarget = e.getTarget();
  1475. this.dragCurrent = oDD;
  1476. var el = oDD.getEl();
  1477. // track start position
  1478. this.startX = e.getPageX();
  1479. this.startY = e.getPageY();
  1480. this.deltaX = this.startX - el.offsetLeft;
  1481. this.deltaY = this.startY - el.offsetTop;
  1482. this.dragThreshMet = false;
  1483. this.clickTimeout = setTimeout(
  1484. function() {
  1485. var DDM = Ext.dd.DDM;
  1486. DDM.startDrag(DDM.startX, DDM.startY);
  1487. },
  1488. this.clickTimeThresh );
  1489. },
  1490. /**
  1491. * Fired when either the drag pixel threshol or the mousedown hold
  1492. * time threshold has been met.
  1493. * @method startDrag
  1494. * @param x {int} the X position of the original mousedown
  1495. * @param y {int} the Y position of the original mousedown
  1496. * @static
  1497. */
  1498. startDrag: function(x, y) {
  1499. clearTimeout(this.clickTimeout);
  1500. if (this.dragCurrent) {
  1501. this.dragCurrent.b4StartDrag(x, y);
  1502. this.dragCurrent.startDrag(x, y);
  1503. }
  1504. this.dragThreshMet = true;
  1505. },
  1506. /**
  1507. * Internal function to handle the mouseup event. Will be invoked
  1508. * from the context of the document.
  1509. * @method handleMouseUp
  1510. * @param {Event} e the event
  1511. * @private
  1512. * @static
  1513. */
  1514. handleMouseUp: function(e) {
  1515. if(Ext.QuickTips){
  1516. Ext.QuickTips.enable();
  1517. }
  1518. if (! this.dragCurrent) {
  1519. return;
  1520. }
  1521. clearTimeout(this.clickTimeout);
  1522. if (this.dragThreshMet) {
  1523. this.fireEvents(e, true);
  1524. } else {
  1525. }
  1526. this.stopDrag(e);
  1527. this.stopEvent(e);
  1528. },
  1529. /**
  1530. * Utility to stop event propagation and event default, if these
  1531. * features are turned on.
  1532. * @method stopEvent
  1533. * @param {Event} e the event as returned by this.getEvent()
  1534. * @static
  1535. */
  1536. stopEvent: function(e){
  1537. if(this.stopPropagation) {
  1538. e.stopPropagation();
  1539. }
  1540. if (this.preventDefault) {
  1541. e.preventDefault();
  1542. }
  1543. },
  1544. /**
  1545. * Internal function to clean up event handlers after the drag
  1546. * operation is complete
  1547. * @method stopDrag
  1548. * @param {Event} e the event
  1549. * @private
  1550. * @static
  1551. */
  1552. stopDrag: function(e) {
  1553. // Fire the drag end event for the item that was dragged
  1554. if (this.dragCurrent) {
  1555. if (this.dragThreshMet) {
  1556. this.dragCurrent.b4EndDrag(e);
  1557. this.dragCurrent.endDrag(e);
  1558. }
  1559. this.dragCurrent.onMouseUp(e);
  1560. }
  1561. this.dragCurrent = null;
  1562. this.dragOvers = {};
  1563. },
  1564. /**
  1565. * Internal function to handle the mousemove event. Will be invoked
  1566. * from the context of the html element.
  1567. *
  1568. * @TODO figure out what we can do about mouse events lost when the
  1569. * user drags objects beyond the window boundary. Currently we can
  1570. * detect this in internet explorer by verifying that the mouse is
  1571. * down during the mousemove event. Firefox doesn't give us the
  1572. * button state on the mousemove event.
  1573. * @method handleMouseMove
  1574. * @param {Event} e the event
  1575. * @private
  1576. * @static
  1577. */
  1578. handleMouseMove: function(e) {
  1579. if (! this.dragCurrent) {
  1580. return true;
  1581. }
  1582. // var button = e.which || e.button;
  1583. // check for IE mouseup outside of page boundary
  1584. if (Ext.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
  1585. this.stopEvent(e);
  1586. return this.handleMouseUp(e);
  1587. }
  1588. if (!this.dragThreshMet) {
  1589. var diffX = Math.abs(this.startX - e.getPageX());
  1590. var diffY = Math.abs(this.startY - e.getPageY());
  1591. if (diffX > this.clickPixelThresh ||
  1592. diffY > this.clickPixelThresh) {
  1593. this.startDrag(this.startX, this.startY);
  1594. }
  1595. }
  1596. if (this.dragThreshMet) {
  1597. this.dragCurrent.b4Drag(e);
  1598. this.dragCurrent.onDrag(e);
  1599. if(!this.dragCurrent.moveOnly){
  1600. this.fireEvents(e, false);
  1601. }
  1602. }
  1603. this.stopEvent(e);
  1604. return true;
  1605. },
  1606. /**
  1607. * Iterates over all of the DragDrop elements to find ones we are
  1608. * hovering over or dropping on
  1609. * @method fireEvents
  1610. * @param {Event} e the event
  1611. * @param {boolean} isDrop is this a drop op or a mouseover op?
  1612. * @private
  1613. * @static
  1614. */
  1615. fireEvents: function(e, isDrop) {
  1616. var dc = this.dragCurrent;
  1617. // If the user did the mouse up outside of the window, we could
  1618. // get here even though we have ended the drag.
  1619. if (!dc || dc.isLocked()) {
  1620. return;
  1621. }
  1622. var pt = e.getPoint();
  1623. // cache the previous dragOver array
  1624. var oldOvers = [];
  1625. var outEvts = [];
  1626. var overEvts = [];
  1627. var dropEvts = [];
  1628. var enterEvts = [];
  1629. // Check to see if the object(s) we were hovering over is no longer
  1630. // being hovered over so we can fire the onDragOut event
  1631. for (var i in this.dragOvers) {
  1632. var ddo = this.dragOvers[i];
  1633. if (! this.isTypeOfDD(ddo)) {
  1634. continue;
  1635. }
  1636. if (! this.isOverTarget(pt, ddo, this.mode)) {
  1637. outEvts.push( ddo );
  1638. }
  1639. oldOvers[i] = true;
  1640. delete this.dragOvers[i];
  1641. }
  1642. for (var sGroup in dc.groups) {
  1643. if ("string" != typeof sGroup) {
  1644. continue;
  1645. }
  1646. for (i in this.ids[sGroup]) {
  1647. var oDD = this.ids[sGroup][i];
  1648. if (! this.isTypeOfDD(oDD)) {
  1649. continue;
  1650. }
  1651. if (oDD.isTarget && !oDD.isLocked() && ((oDD != dc) || (dc.ignoreSelf === false))) {
  1652. if (this.isOverTarget(pt, oDD, this.mode)) {
  1653. // look for drop interactions
  1654. if (isDrop) {
  1655. dropEvts.push( oDD );
  1656. // look for drag enter and drag over interactions
  1657. } else {
  1658. // initial drag over: dragEnter fires
  1659. if (!oldOvers[oDD.id]) {
  1660. enterEvts.push( oDD );
  1661. // subsequent drag overs: dragOver fires
  1662. } else {
  1663. overEvts.push( oDD );
  1664. }
  1665. this.dragOvers[oDD.id] = oDD;
  1666. }
  1667. }
  1668. }
  1669. }
  1670. }
  1671. if (this.mode) {
  1672. if (outEvts.length) {
  1673. dc.b4DragOut(e, outEvts);
  1674. dc.onDragOut(e, outEvts);
  1675. }
  1676. if (enterEvts.length) {
  1677. dc.onDragEnter(e, enterEvts);
  1678. }
  1679. if (overEvts.length) {
  1680. dc.b4DragOver(e, overEvts);
  1681. dc.onDragOver(e, overEvts);
  1682. }
  1683. if (dropEvts.length) {
  1684. dc.b4DragDrop(e, dropEvts);
  1685. dc.onDragDrop(e, dropEvts);
  1686. }
  1687. } else {
  1688. // fire dragout events
  1689. var len = 0;
  1690. for (i=0, len=outEvts.length; i<len; ++i) {
  1691. dc.b4DragOut(e, outEvts[i].id);
  1692. dc.onDragOut(e, outEvts[i].id);
  1693. }
  1694. // fire enter events
  1695. for (i=0,len=enterEvts.length; i<len; ++i) {
  1696. // dc.b4DragEnter(e, oDD.id);
  1697. dc.onDragEnter(e, enterEvts[i].id);
  1698. }
  1699. // fire over events
  1700. for (i=0,len=overEvts.length; i<len; ++i) {
  1701. dc.b4DragOver(e, overEvts[i].id);
  1702. dc.onDragOver(e, overEvts[i].id);
  1703. }
  1704. // fire drop events
  1705. for (i=0, len=dropEvts.length; i<len; ++i) {
  1706. dc.b4DragDrop(e, dropEvts[i].id);
  1707. dc.onDragDrop(e, dropEvts[i].id);
  1708. }
  1709. }
  1710. // notify about a drop that did not find a target
  1711. if (isDrop && !dropEvts.length) {
  1712. dc.onInvalidDrop(e);
  1713. }
  1714. },
  1715. /**
  1716. * Helper function for getting the best match from the list of drag
  1717. * and drop objects returned by the drag and drop events when we are
  1718. * in INTERSECT mode. It returns either the first object that the
  1719. * cursor is over, or the object that has the greatest overlap with
  1720. * the dragged element.
  1721. * @method getBestMatch
  1722. * @param {DragDrop[]} dds The array of drag and drop objects
  1723. * targeted
  1724. * @return {DragDrop} The best single match
  1725. * @static
  1726. */
  1727. getBestMatch: function(dds) {
  1728. var winner = null;
  1729. // Return null if the input is not what we expect
  1730. //if (!dds || !dds.length || dds.length == 0) {
  1731. // winner = null;
  1732. // If there is only one item, it wins
  1733. //} else if (dds.length == 1) {
  1734. var len = dds.length;
  1735. if (len == 1) {
  1736. winner = dds[0];
  1737. } else {
  1738. // Loop through the targeted items
  1739. for (var i=0; i<len; ++i) {
  1740. var dd = dds[i];
  1741. // If the cursor is over the object, it wins. If the
  1742. // cursor is over multiple matches, the first one we come
  1743. // to wins.
  1744. if (dd.cursorIsOver) {
  1745. winner = dd;
  1746. break;
  1747. // Otherwise the object with the most overlap wins
  1748. } else {
  1749. if (!winner ||
  1750. winner.overlap.getArea() < dd.overlap.getArea()) {
  1751. winner = dd;
  1752. }
  1753. }
  1754. }
  1755. }
  1756. return winner;
  1757. },
  1758. /**
  1759. * Refreshes the cache of the top-left and bottom-right points of the
  1760. * drag and drop objects in the specified group(s). This is in the
  1761. * format that is stored in the drag and drop instance, so typical
  1762. * usage is:
  1763. * <code>
  1764. * Ext.dd.DragDropMgr.refreshCache(ddinstance.groups);
  1765. * </code>
  1766. * Alternatively:
  1767. * <code>
  1768. * Ext.dd.DragDropMgr.refreshCache({group1:true, group2:true});
  1769. * </code>
  1770. * @TODO this really should be an indexed array. Alternatively this
  1771. * method could accept both.
  1772. * @method refreshCache
  1773. * @param {Object} groups an associative array of groups to refresh
  1774. * @static
  1775. */
  1776. refreshCache: function(groups) {
  1777. for (var sGroup in groups) {
  1778. if ("string" != typeof sGroup) {
  1779. continue;
  1780. }
  1781. for (var i in this.ids[sGroup]) {
  1782. var oDD = this.ids[sGroup][i];
  1783. if (this.isTypeOfDD(oDD)) {
  1784. // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
  1785. var loc = this.getLocation(oDD);
  1786. if (loc) {
  1787. this.locationCache[oDD.id] = loc;
  1788. } else {
  1789. delete this.locationCache[oDD.id];
  1790. // this will unregister the drag and drop object if
  1791. // the element is not in a usable state
  1792. // oDD.unreg();
  1793. }
  1794. }
  1795. }
  1796. }
  1797. },
  1798. /**
  1799. * This checks to make sure an element exists and is in the DOM. The
  1800. * main purpose is to handle cases where innerHTML is used to remove
  1801. * drag and drop objects from the DOM. IE provides an 'unspecified
  1802. * error' when trying to access the offsetParent of such an element
  1803. * @method verifyEl
  1804. * @param {HTMLElement} el the element to check
  1805. * @return {boolean} true if the element looks usable
  1806. * @static
  1807. */
  1808. verifyEl: function(el) {
  1809. if (el) {
  1810. var parent;
  1811. if(Ext.isIE){
  1812. try{
  1813. parent = el.offsetParent;
  1814. }catch(e){}
  1815. }else{
  1816. parent = el.offsetParent;
  1817. }
  1818. if (parent) {
  1819. return true;
  1820. }
  1821. }
  1822. return false;
  1823. },
  1824. /**
  1825. * Returns a Region object containing the drag and drop element's position
  1826. * and size, including the padding configured for it
  1827. * @method getLocation
  1828. * @param {DragDrop} oDD the drag and drop object to get the
  1829. * location for
  1830. * @return {Ext.lib.Region} a Region object representing the total area
  1831. * the element occupies, including any padding
  1832. * the instance is configured for.
  1833. * @static
  1834. */
  1835. getLocation: function(oDD) {
  1836. if (! this.isTypeOfDD(oDD)) {
  1837. return null;
  1838. }
  1839. var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
  1840. try {
  1841. pos= Ext.lib.Dom.getXY(el);
  1842. } catch (e) { }
  1843. if (!pos) {
  1844. return null;
  1845. }
  1846. x1 = pos[0];
  1847. x2 = x1 + el.offsetWidth;
  1848. y1 = pos[1];
  1849. y2 = y1 + el.offsetHeight;
  1850. t = y1 - oDD.padding[0];
  1851. r = x2 + oDD.padding[1];
  1852. b = y2 + oDD.padding[2];
  1853. l = x1 - oDD.padding[3];
  1854. return new Ext.lib.Region( t, r, b, l );
  1855. },
  1856. /**
  1857. * Checks the cursor location to see if it over the target
  1858. * @method isOverTarget
  1859. * @param {Ext.lib.Point} pt The point to evaluate
  1860. * @param {DragDrop} oTarget the DragDrop object we are inspecting
  1861. * @return {boolean} true if the mouse is over the target
  1862. * @private
  1863. * @static
  1864. */
  1865. isOverTarget: function(pt, oTarget, intersect) {
  1866. // use cache if available
  1867. var loc = this.locationCache[oTarget.id];
  1868. if (!loc || !this.useCache) {
  1869. loc = this.getLocation(oTarget);
  1870. this.locationCache[oTarget.id] = loc;
  1871. }
  1872. if (!loc) {
  1873. return false;
  1874. }
  1875. oTarget.cursorIsOver = loc.contains( pt );
  1876. // DragDrop is using this as a sanity check for the initial mousedown
  1877. // in this case we are done. In POINT mode, if the drag obj has no
  1878. // contraints, we are also done. Otherwise we need to evaluate the
  1879. // location of the target as related to the actual location of the
  1880. // dragged element.
  1881. var dc = this.dragCurrent;
  1882. if (!dc || !dc.getTargetCoord ||
  1883. (!intersect && !dc.constrainX && !dc.constrainY)) {
  1884. return oTarget.cursorIsOver;
  1885. }
  1886. oTarget.overlap = null;
  1887. // Get the current location of the drag element, this is the
  1888. // location of the mouse event less the delta that represents
  1889. // where the original mousedown happened on the element. We
  1890. // need to consider constraints and ticks as well.
  1891. var pos = dc.getTargetCoord(pt.x, pt.y);
  1892. var el = dc.getDragEl();
  1893. var curRegion = new Ext.lib.Region( pos.y,
  1894. pos.x + el.offsetWidth,
  1895. pos.y + el.offsetHeight,
  1896. pos.x );
  1897. var overlap = curRegion.intersect(loc);
  1898. if (overlap) {
  1899. oTarget.overlap = overlap;
  1900. return (intersect) ? true : oTarget.cursorIsOver;
  1901. } else {
  1902. return false;
  1903. }
  1904. },
  1905. /**
  1906. * unload event handler
  1907. * @method _onUnload
  1908. * @private
  1909. * @static
  1910. */
  1911. _onUnload: function(e, me) {
  1912. Ext.dd.DragDropMgr.unregAll();
  1913. },
  1914. /**
  1915. * Cleans up the drag and drop events and objects.
  1916. * @method unregAll
  1917. * @private
  1918. * @static
  1919. */
  1920. unregAll: function() {
  1921. if (this.dragCurrent) {
  1922. this.stopDrag();
  1923. this.dragCurrent = null;
  1924. }
  1925. this._execOnAll("unreg", []);
  1926. for (var i in this.elementCache) {
  1927. delete this.elementCache[i];
  1928. }
  1929. this.elementCache = {};
  1930. this.ids = {};
  1931. },
  1932. /**
  1933. * A cache of DOM elements
  1934. * @property elementCache
  1935. * @private
  1936. * @static
  1937. */
  1938. elementCache: {},
  1939. /**
  1940. * Get the wrapper for the DOM element specified
  1941. * @method getElWrapper
  1942. * @param {String} id the id of the element to get
  1943. * @return {Ext.dd.DDM.ElementWrapper} the wrapped element
  1944. * @private
  1945. * @deprecated This wrapper isn't that useful
  1946. * @static
  1947. */
  1948. getElWrapper: function(id) {
  1949. var oWrapper = this.elementCache[id];
  1950. if (!oWrapper || !oWrapper.el) {
  1951. oWrapper = this.elementCache[id] =
  1952. new this.ElementWrapper(Ext.getDom(id));
  1953. }
  1954. return oWrapper;
  1955. },
  1956. /**
  1957. * Returns the actual DOM element
  1958. * @method getElement
  1959. * @param {String} id the id of the elment to get
  1960. * @return {Object} The element
  1961. * @deprecated use Ext.lib.Ext.getDom instead
  1962. * @static
  1963. */
  1964. getElement: function(id) {
  1965. return Ext.getDom(id);
  1966. },
  1967. /**
  1968. * Returns the style property for the DOM element (i.e.,
  1969. * document.getElById(id).style)
  1970. * @method getCss
  1971. * @param {String} id the id of the elment to get
  1972. * @return {Object} The style property of the element
  1973. * @deprecated use Ext.lib.Dom instead
  1974. * @static
  1975. */
  1976. getCss: function(id) {
  1977. var el = Ext.getDom(id);
  1978. return (el) ? el.style : null;
  1979. },
  1980. /**
  1981. * Inner class for cached elements
  1982. * @class Ext.dd.DragDropMgr.ElementWrapper
  1983. * @for DragDropMgr
  1984. * @private
  1985. * @deprecated
  1986. */
  1987. ElementWrapper: function(el) {
  1988. /**
  1989. * The element
  1990. * @property el
  1991. */
  1992. this.el = el || null;
  1993. /**
  1994. * The element id
  1995. * @property id
  1996. */
  1997. this.id = this.el && el.id;
  1998. /**
  1999. * A reference to the style property
  2000. * @property css
  2001. */
  2002. this.css = this.el && el.style;
  2003. },
  2004. /**
  2005. * Returns the X position of an html element
  2006. * @method getPosX
  2007. * @param el the element for which to get the position
  2008. * @return {int} the X coordinate
  2009. * @for DragDropMgr
  2010. * @deprecated use Ext.lib.Dom.getX instead
  2011. * @static
  2012. */
  2013. getPosX: function(el) {
  2014. return Ext.lib.Dom.getX(el);
  2015. },
  2016. /**
  2017. * Returns the Y position of an html element
  2018. * @method getPosY
  2019. * @param el the element for which to get the position
  2020. * @return {int} the Y coordinate
  2021. * @deprecated use Ext.lib.Dom.getY instead
  2022. * @static
  2023. */
  2024. getPosY: function(el) {
  2025. return Ext.lib.Dom.getY(el);
  2026. },
  2027. /**
  2028. * Swap two nodes. In IE, we use the native method, for others we
  2029. * emulate the IE behavior
  2030. * @method swapNode
  2031. * @param n1 the first node to swap
  2032. * @param n2 the other node to swap
  2033. * @static
  2034. */
  2035. swapNode: function(n1, n2) {
  2036. if (n1.swapNode) {
  2037. n1.swapNode(n2);
  2038. } else {
  2039. var p = n2.parentNode;
  2040. var s = n2.nextSibling;
  2041. if (s == n1) {
  2042. p.insertBefore(n1, n2);
  2043. } else if (n2 == n1.nextSibling) {
  2044. p.insertBefore(n2, n1);
  2045. } else {
  2046. n1.parentNode.replaceChild(n2, n1);
  2047. p.insertBefore(n1, s);
  2048. }
  2049. }
  2050. },
  2051. /**
  2052. * Returns the current scroll position
  2053. * @method getScroll
  2054. * @private
  2055. * @static
  2056. */
  2057. getScroll: function () {
  2058. var t, l, dde=document.documentElement, db=document.body;
  2059. if (dde && (dde.scrollTop || dde.scrollLeft)) {
  2060. t = dde.scrollTop;
  2061. l = dde.scrollLeft;
  2062. } else if (db) {
  2063. t = db.scrollTop;
  2064. l = db.scrollLeft;
  2065. } else {
  2066. }
  2067. return { top: t, left: l };
  2068. },
  2069. /**
  2070. * Returns the specified element style property
  2071. * @method getStyle
  2072. * @param {HTMLElement} el the element
  2073. * @param {string} styleProp the style property
  2074. * @return {string} The value of the style property
  2075. * @deprecated use Ext.lib.Dom.getStyle
  2076. * @static
  2077. */
  2078. getStyle: function(el, styleProp) {
  2079. return Ext.fly(el).getStyle(styleProp);
  2080. },
  2081. /**
  2082. * Gets the scrollTop
  2083. * @method getScrollTop
  2084. * @return {int} the document's scrollTop
  2085. * @static
  2086. */
  2087. getScrollTop: function () {
  2088. return this.getScroll().top;
  2089. },
  2090. /**
  2091. * Gets the scrollLeft
  2092. * @method getScrollLeft
  2093. * @return {int} the document's scrollTop
  2094. * @static
  2095. */
  2096. getScrollLeft: function () {
  2097. return this.getScroll().left;
  2098. },
  2099. /**
  2100. * Sets the x/y position of an element to the location of the
  2101. * target element.
  2102. * @method moveToEl
  2103. * @param {HTMLElement} moveEl The element to move
  2104. * @param {HTMLElement} targetEl The position reference element
  2105. * @static
  2106. */
  2107. moveToEl: function (moveEl, targetEl) {
  2108. var aCoord = Ext.lib.Dom.getXY(targetEl);
  2109. Ext.lib.Dom.setXY(moveEl, aCoord);
  2110. },
  2111. /**
  2112. * Numeric array sort function
  2113. * @method numericSort
  2114. * @static
  2115. */
  2116. numericSort: function(a, b) {
  2117. return (a - b);
  2118. },
  2119. /**
  2120. * Internal counter
  2121. * @property _timeoutCount
  2122. * @private
  2123. * @static
  2124. */
  2125. _timeoutCount: 0,
  2126. /**
  2127. * Trying to make the load order less important. Without this we get
  2128. * an error if this file is loaded before the Event Utility.
  2129. * @method _addListeners
  2130. * @private
  2131. * @static
  2132. */
  2133. _addListeners: function() {
  2134. var DDM = Ext.dd.DDM;
  2135. if ( Ext.lib.Event && document ) {
  2136. DDM._onLoad();
  2137. } else {
  2138. if (DDM._timeoutCount > 2000) {
  2139. } else {
  2140. setTimeout(DDM._addListeners, 10);
  2141. if (document && document.body) {
  2142. DDM._timeoutCount += 1;
  2143. }
  2144. }
  2145. }
  2146. },
  2147. /**
  2148. * Recursively searches the immediate parent and all child nodes for
  2149. * the handle element in order to determine wheter or not it was
  2150. * clicked.
  2151. * @method handleWasClicked
  2152. * @param node the html element to inspect
  2153. * @static
  2154. */
  2155. handleWasClicked: function(node, id) {
  2156. if (this.isHandle(id, node.id)) {
  2157. return true;
  2158. } else {
  2159. // check to see if this is a text node child of the one we want
  2160. var p = node.parentNode;
  2161. while (p) {
  2162. if (this.isHandle(id, p.id)) {
  2163. return true;
  2164. } else {
  2165. p = p.parentNode;
  2166. }
  2167. }
  2168. }
  2169. return false;
  2170. }
  2171. };
  2172. }();
  2173. // shorter alias, save a few bytes
  2174. Ext.dd.DDM = Ext.dd.DragDropMgr;
  2175. Ext.dd.DDM._addListeners();
  2176. }
  2177. /**
  2178. * @class Ext.dd.DD
  2179. * A DragDrop implementation where the linked element follows the
  2180. * mouse cursor during a drag.
  2181. * @extends Ext.dd.DragDrop
  2182. * @constructor
  2183. * @param {String} id the id of the linked element
  2184. * @param {String} sGroup the group of related DragDrop items
  2185. * @param {object} config an object containing configurable attributes
  2186. * Valid properties for DD:
  2187. * scroll
  2188. */
  2189. Ext.dd.DD = function(id, sGroup, config) {
  2190. if (id) {
  2191. this.init(id, sGroup, config);
  2192. }
  2193. };
  2194. Ext.extend(Ext.dd.DD, Ext.dd.DragDrop, {
  2195. /**
  2196. * When set to true, the utility automatically tries to scroll the browser
  2197. * window when a drag and drop element is dragged near the viewport boundary.
  2198. * Defaults to true.
  2199. * @property scroll
  2200. * @type boolean
  2201. */
  2202. scroll: true,
  2203. /**
  2204. * Sets the pointer offset to the distance between the linked element's top
  2205. * left corner and the location the element was clicked
  2206. * @method autoOffset
  2207. * @param {int} iPageX the X coordinate of the click
  2208. * @param {int} iPageY the Y coordinate of the click
  2209. */
  2210. autoOffset: function(iPageX, iPageY) {
  2211. var x = iPageX - this.startPageX;
  2212. var y = iPageY - this.startPageY;
  2213. this.setDelta(x, y);
  2214. },
  2215. /**
  2216. * Sets the pointer offset. You can call this directly to force the
  2217. * offset to be in a particular location (e.g., pass in 0,0 to set it
  2218. * to the center of the object)
  2219. * @method setDelta
  2220. * @param {int} iDeltaX the distance from the left
  2221. * @param {int} iDeltaY the distance from the top
  2222. */
  2223. setDelta: function(iDeltaX, iDeltaY) {
  2224. this.deltaX = iDeltaX;
  2225. this.deltaY = iDeltaY;
  2226. },
  2227. /**
  2228. * Sets the drag element to the location of the mousedown or click event,
  2229. * maintaining the cursor location relative to the location on the element
  2230. * that was clicked. Override this if you want to place the element in a
  2231. * location other than where the cursor is.
  2232. * @method setDragElPos
  2233. * @param {int} iPageX the X coordinate of the mousedown or drag event
  2234. * @param {int} iPageY the Y coordinate of the mousedown or drag event
  2235. */
  2236. setDragElPos: function(iPageX, iPageY) {
  2237. // the first time we do this, we are going to check to make sure
  2238. // the element has css positioning
  2239. var el = this.getDragEl();
  2240. this.alignElWithMouse(el, iPageX, iPageY);
  2241. },
  2242. /**
  2243. * Sets the element to the location of the mousedown or click event,
  2244. * maintaining the cursor location relative to the location on the element
  2245. * that was clicked. Override this if you want to place the element in a
  2246. * location other than where the cursor is.
  2247. * @method alignElWithMouse
  2248. * @param {HTMLElement} el the element to move
  2249. * @param {int} iPageX the X coordinate of the mousedown or drag event
  2250. * @param {int} iPageY the Y coordinate of the mousedown or drag event
  2251. */
  2252. alignElWithMouse: function(el, iPageX, iPageY) {
  2253. var oCoord = this.getTargetCoord(iPageX, iPageY);
  2254. var fly = el.dom ? el : Ext.fly(el, '_dd');
  2255. if (!this.deltaSetXY) {
  2256. var aCoord = [oCoord.x, oCoord.y];
  2257. fly.setXY(aCoord);
  2258. var newLeft = fly.getLeft(true);
  2259. var newTop = fly.getTop(true);
  2260. this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
  2261. } else {
  2262. fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
  2263. }
  2264. this.cachePosition(oCoord.x, oCoord.y);
  2265. this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
  2266. return oCoord;
  2267. },
  2268. /**
  2269. * Saves the most recent position so that we can reset the constraints and
  2270. * tick marks on-demand. We need to know this so that we can calculate the
  2271. * number of pixels the element is offset from its original position.
  2272. * @method cachePosition
  2273. * @param iPageX the current x position (optional, this just makes it so we
  2274. * don't have to look it up again)
  2275. * @param iPageY the current y position (optional, this just makes it so we
  2276. * don't have to look it up again)
  2277. */
  2278. cachePosition: function(iPageX, iPageY) {
  2279. if (iPageX) {
  2280. this.lastPageX = iPageX;
  2281. this.lastPageY = iPageY;
  2282. } else {
  2283. var aCoord = Ext.lib.Dom.getXY(this.getEl());
  2284. this.lastPageX = aCoord[0];
  2285. this.lastPageY = aCoord[1];
  2286. }
  2287. },
  2288. /**
  2289. * Auto-scroll the window if the dragged object has been moved beyond the
  2290. * visible window boundary.
  2291. * @method autoScroll
  2292. * @param {int} x the drag element's x position
  2293. * @param {int} y the drag element's y position
  2294. * @param {int} h the height of the drag element
  2295. * @param {int} w the width of the drag element
  2296. * @private
  2297. */
  2298. autoScroll: function(x, y, h, w) {
  2299. if (this.scroll) {
  2300. // The client height
  2301. var clientH = Ext.lib.Dom.getViewHeight();
  2302. // The client width
  2303. var clientW = Ext.lib.Dom.getViewWidth();
  2304. // The amt scrolled down
  2305. var st = this.DDM.getScrollTop();
  2306. // The amt scrolled right
  2307. var sl = this.DDM.getScrollLeft();
  2308. // Location of the bottom of the element
  2309. var bot = h + y;
  2310. // Location of the right of the element
  2311. var right = w + x;
  2312. // The distance from the cursor to the bottom of the visible area,
  2313. // adjusted so that we don't scroll if the cursor is beyond the
  2314. // element drag constraints
  2315. var toBot = (clientH + st - y - this.deltaY);
  2316. // The distance from the cursor to the right of the visible area
  2317. var toRight = (clientW + sl - x - this.deltaX);
  2318. // How close to the edge the cursor must be before we scroll
  2319. // var thresh = (document.all) ? 100 : 40;
  2320. var thresh = 40;
  2321. // How many pixels to scroll per autoscroll op. This helps to reduce
  2322. // clunky scrolling. IE is more sensitive about this ... it needs this
  2323. // value to be higher.
  2324. var scrAmt = (document.all) ? 80 : 30;
  2325. // Scroll down if we are near the bottom of the visible page and the
  2326. // obj extends below the crease
  2327. if ( bot > clientH && toBot < thresh ) {
  2328. window.scrollTo(sl, st + scrAmt);
  2329. }
  2330. // Scroll up if the window is scrolled down and the top of the object
  2331. // goes above the top border
  2332. if ( y < st && st > 0 && y - st < thresh ) {
  2333. window.scrollTo(sl, st - scrAmt);
  2334. }
  2335. // Scroll right if the obj is beyond the right border and the cursor is
  2336. // near the border.
  2337. if ( right > clientW && toRight < thresh ) {
  2338. window.scrollTo(sl + scrAmt, st);
  2339. }
  2340. // Scroll left if the window has been scrolled to the right and the obj
  2341. // extends past the left border
  2342. if ( x < sl && sl > 0 && x - sl < thresh ) {
  2343. window.scrollTo(sl - scrAmt, st);
  2344. }
  2345. }
  2346. },
  2347. /**
  2348. * Finds the location the element should be placed if we want to move
  2349. * it to where the mouse location less the click offset would place us.
  2350. * @method getTargetCoord
  2351. * @param {int} iPageX the X coordinate of the click
  2352. * @param {int} iPageY the Y coordinate of the click
  2353. * @return an object that contains the coordinates (Object.x and Object.y)
  2354. * @private
  2355. */
  2356. getTargetCoord: function(iPageX, iPageY) {
  2357. var x = iPageX - this.deltaX;
  2358. var y = iPageY - this.deltaY;
  2359. if (this.constrainX) {
  2360. if (x < this.minX) { x = this.minX; }
  2361. if (x > this.maxX) { x = this.maxX; }
  2362. }
  2363. if (this.constrainY) {
  2364. if (y < this.minY) { y = this.minY; }
  2365. if (y > this.maxY) { y = this.maxY; }
  2366. }
  2367. x = this.getTick(x, this.xTicks);
  2368. y = this.getTick(y, this.yTicks);
  2369. return {x:x, y:y};
  2370. },
  2371. /**
  2372. * Sets up config options specific to this class. Overrides
  2373. * Ext.dd.DragDrop, but all versions of this method through the
  2374. * inheritance chain are called
  2375. */
  2376. applyConfig: function() {
  2377. Ext.dd.DD.superclass.applyConfig.call(this);
  2378. this.scroll = (this.config.scroll !== false);
  2379. },
  2380. /**
  2381. * Event that fires prior to the onMouseDown event. Overrides
  2382. * Ext.dd.DragDrop.
  2383. */
  2384. b4MouseDown: function(e) {
  2385. // this.resetConstraints();
  2386. this.autoOffset(e.getPageX(),
  2387. e.getPageY());
  2388. },
  2389. /**
  2390. * Event that fires prior to the onDrag event. Overrides
  2391. * Ext.dd.DragDrop.
  2392. */
  2393. b4Drag: function(e) {
  2394. this.setDragElPos(e.getPageX(),
  2395. e.getPageY());
  2396. },
  2397. toString: function() {
  2398. return ("DD " + this.id);
  2399. }
  2400. //////////////////////////////////////////////////////////////////////////
  2401. // Debugging ygDragDrop events that can be overridden
  2402. //////////////////////////////////////////////////////////////////////////
  2403. /*
  2404. startDrag: function(x, y) {
  2405. },
  2406. onDrag: function(e) {
  2407. },
  2408. onDragEnter: function(e, id) {
  2409. },
  2410. onDragOver: function(e, id) {
  2411. },
  2412. onDragOut: function(e, id) {
  2413. },
  2414. onDragDrop: function(e, id) {
  2415. },
  2416. endDrag: function(e) {
  2417. }
  2418. */
  2419. });
  2420. /**
  2421. * @class Ext.dd.DDProxy
  2422. * A DragDrop implementation that inserts an empty, bordered div into
  2423. * the document that follows the cursor during drag operations. At the time of
  2424. * the click, the frame div is resized to the dimensions of the linked html
  2425. * element, and moved to the exact location of the linked element.
  2426. *
  2427. * References to the "frame" element refer to the single proxy element that
  2428. * was created to be dragged in place of all DDProxy elements on the
  2429. * page.
  2430. *
  2431. * @extends Ext.dd.DD
  2432. * @constructor
  2433. * @param {String} id the id of the linked html element
  2434. * @param {String} sGroup the group of related DragDrop objects
  2435. * @param {object} config an object containing configurable attributes
  2436. * Valid properties for DDProxy in addition to those in DragDrop:
  2437. * resizeFrame, centerFrame, dragElId
  2438. */
  2439. Ext.dd.DDProxy = function(id, sGroup, config) {
  2440. if (id) {
  2441. this.init(id, sGroup, config);
  2442. this.initFrame();
  2443. }
  2444. };
  2445. /**
  2446. * The default drag frame div id
  2447. * @property Ext.dd.DDProxy.dragElId
  2448. * @type String
  2449. * @static
  2450. */
  2451. Ext.dd.DDProxy.dragElId = "ygddfdiv";
  2452. Ext.extend(Ext.dd.DDProxy, Ext.dd.DD, {
  2453. /**
  2454. * By default we resize the drag frame to be the same size as the element
  2455. * we want to drag (this is to get the frame effect). We can turn it off
  2456. * if we want a different behavior.
  2457. * @property resizeFrame
  2458. * @type boolean
  2459. */
  2460. resizeFrame: true,
  2461. /**
  2462. * By default the frame is positioned exactly where the drag element is, so
  2463. * we use the cursor offset provided by Ext.dd.DD. Another option that works only if
  2464. * you do not have constraints on the obj is to have the drag frame centered
  2465. * around the cursor. Set centerFrame to true for this effect.
  2466. * @property centerFrame
  2467. * @type boolean
  2468. */
  2469. centerFrame: false,
  2470. /**
  2471. * Creates the proxy element if it does not yet exist
  2472. * @method createFrame
  2473. */
  2474. createFrame: function() {
  2475. var self = this;
  2476. var body = document.body;
  2477. if (!body || !body.firstChild) {
  2478. setTimeout( function() { self.createFrame(); }, 50 );
  2479. return;
  2480. }
  2481. var div = this.getDragEl();
  2482. if (!div) {
  2483. div = document.createElement("div");
  2484. div.id = this.dragElId;
  2485. var s = div.style;
  2486. s.position = "absolute";
  2487. s.visibility = "hidden";
  2488. s.cursor = "move";
  2489. s.border = "2px solid #aaa";
  2490. s.zIndex = 999;
  2491. // appendChild can blow up IE if invoked prior to the window load event
  2492. // while rendering a table. It is possible there are other scenarios
  2493. // that would cause this to happen as well.
  2494. body.insertBefore(div, body.firstChild);
  2495. }
  2496. },
  2497. /**
  2498. * Initialization for the drag frame element. Must be called in the
  2499. * constructor of all subclasses
  2500. * @method initFrame
  2501. */
  2502. initFrame: function() {
  2503. this.createFrame();
  2504. },
  2505. applyConfig: function() {
  2506. Ext.dd.DDProxy.superclass.applyConfig.call(this);
  2507. this.resizeFrame = (this.config.resizeFrame !== false);
  2508. this.centerFrame = (this.config.centerFrame);
  2509. this.setDragElId(this.config.dragElId || Ext.dd.DDProxy.dragElId);
  2510. },
  2511. /**
  2512. * Resizes the drag frame to the dimensions of the clicked object, positions
  2513. * it over the object, and finally displays it
  2514. * @method showFrame
  2515. * @param {int} iPageX X click position
  2516. * @param {int} iPageY Y click position
  2517. * @private
  2518. */
  2519. showFrame: function(iPageX, iPageY) {
  2520. var el = this.getEl();
  2521. var dragEl = this.getDragEl();
  2522. var s = dragEl.style;
  2523. this._resizeProxy();
  2524. if (this.centerFrame) {
  2525. this.setDelta( Math.round(parseInt(s.width, 10)/2),
  2526. Math.round(parseInt(s.height, 10)/2) );
  2527. }
  2528. this.setDragElPos(iPageX, iPageY);
  2529. Ext.fly(dragEl).show();
  2530. },
  2531. /**
  2532. * The proxy is automatically resized to the dimensions of the linked
  2533. * element when a drag is initiated, unless resizeFrame is set to false
  2534. * @method _resizeProxy
  2535. * @private
  2536. */
  2537. _resizeProxy: function() {
  2538. if (this.resizeFrame) {
  2539. var el = this.getEl();
  2540. Ext.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
  2541. }
  2542. },
  2543. // overrides Ext.dd.DragDrop
  2544. b4MouseDown: function(e) {
  2545. var x = e.getPageX();
  2546. var y = e.getPageY();
  2547. this.autoOffset(x, y);
  2548. this.setDragElPos(x, y);
  2549. },
  2550. // overrides Ext.dd.DragDrop
  2551. b4StartDrag: function(x, y) {
  2552. // show the drag frame
  2553. this.showFrame(x, y);
  2554. },
  2555. // overrides Ext.dd.DragDrop
  2556. b4EndDrag: function(e) {
  2557. Ext.fly(this.getDragEl()).hide();
  2558. },
  2559. // overrides Ext.dd.DragDrop
  2560. // By default we try to move the element to the last location of the frame.
  2561. // This is so that the default behavior mirrors that of Ext.dd.DD.
  2562. endDrag: function(e) {
  2563. var lel = this.getEl();
  2564. var del = this.getDragEl();
  2565. // Show the drag frame briefly so we can get its position
  2566. del.style.visibility = "";
  2567. this.beforeMove();
  2568. // Hide the linked element before the move to get around a Safari
  2569. // rendering bug.
  2570. lel.style.visibility = "hidden";
  2571. Ext.dd.DDM.moveToEl(lel, del);
  2572. del.style.visibility = "hidden";
  2573. lel.style.visibility = "";
  2574. this.afterDrag();
  2575. },
  2576. beforeMove : function(){
  2577. },
  2578. afterDrag : function(){
  2579. },
  2580. toString: function() {
  2581. return ("DDProxy " + this.id);
  2582. }
  2583. });
  2584. /**
  2585. * @class Ext.dd.DDTarget
  2586. * A DragDrop implementation that does not move, but can be a drop
  2587. * target. You would get the same result by simply omitting implementation
  2588. * for the event callbacks, but this way we reduce the processing cost of the
  2589. * event listener and the callbacks.
  2590. * @extends Ext.dd.DragDrop
  2591. * @constructor
  2592. * @param {String} id the id of the element that is a drop target
  2593. * @param {String} sGroup the group of related DragDrop objects
  2594. * @param {object} config an object containing configurable attributes
  2595. * Valid properties for DDTarget in addition to those in
  2596. * DragDrop:
  2597. * none
  2598. */
  2599. Ext.dd.DDTarget = function(id, sGroup, config) {
  2600. if (id) {
  2601. this.initTarget(id, sGroup, config);
  2602. }
  2603. };
  2604. // Ext.dd.DDTarget.prototype = new Ext.dd.DragDrop();
  2605. Ext.extend(Ext.dd.DDTarget, Ext.dd.DragDrop, {
  2606. /**
  2607. * @hide
  2608. * Overridden and disabled. A DDTarget does not support being dragged.
  2609. * @method
  2610. */
  2611. getDragEl: Ext.emptyFn,
  2612. /**
  2613. * @hide
  2614. * Overridden and disabled. A DDTarget does not support being dragged.
  2615. * @method
  2616. */
  2617. isValidHandleChild: Ext.emptyFn,
  2618. /**
  2619. * @hide
  2620. * Overridden and disabled. A DDTarget does not support being dragged.
  2621. * @method
  2622. */
  2623. startDrag: Ext.emptyFn,
  2624. /**
  2625. * @hide
  2626. * Overridden and disabled. A DDTarget does not support being dragged.
  2627. * @method
  2628. */
  2629. endDrag: Ext.emptyFn,
  2630. /**
  2631. * @hide
  2632. * Overridden and disabled. A DDTarget does not support being dragged.
  2633. * @method
  2634. */
  2635. onDrag: Ext.emptyFn,
  2636. /**
  2637. * @hide
  2638. * Overridden and disabled. A DDTarget does not support being dragged.
  2639. * @method
  2640. */
  2641. onDragDrop: Ext.emptyFn,
  2642. /**
  2643. * @hide
  2644. * Overridden and disabled. A DDTarget does not support being dragged.
  2645. * @method
  2646. */
  2647. onDragEnter: Ext.emptyFn,
  2648. /**
  2649. * @hide
  2650. * Overridden and disabled. A DDTarget does not support being dragged.
  2651. * @method
  2652. */
  2653. onDragOut: Ext.emptyFn,
  2654. /**
  2655. * @hide
  2656. * Overridden and disabled. A DDTarget does not support being dragged.
  2657. * @method
  2658. */
  2659. onDragOver: Ext.emptyFn,
  2660. /**
  2661. * @hide
  2662. * Overridden and disabled. A DDTarget does not support being dragged.
  2663. * @method
  2664. */
  2665. onInvalidDrop: Ext.emptyFn,
  2666. /**
  2667. * @hide
  2668. * Overridden and disabled. A DDTarget does not support being dragged.
  2669. * @method
  2670. */
  2671. onMouseDown: Ext.emptyFn,
  2672. /**
  2673. * @hide
  2674. * Overridden and disabled. A DDTarget does not support being dragged.
  2675. * @method
  2676. */
  2677. onMouseUp: Ext.emptyFn,
  2678. /**
  2679. * @hide
  2680. * Overridden and disabled. A DDTarget does not support being dragged.
  2681. * @method
  2682. */
  2683. setXConstraint: Ext.emptyFn,
  2684. /**
  2685. * @hide
  2686. * Overridden and disabled. A DDTarget does not support being dragged.
  2687. * @method
  2688. */
  2689. setYConstraint: Ext.emptyFn,
  2690. /**
  2691. * @hide
  2692. * Overridden and disabled. A DDTarget does not support being dragged.
  2693. * @method
  2694. */
  2695. resetConstraints: Ext.emptyFn,
  2696. /**
  2697. * @hide
  2698. * Overridden and disabled. A DDTarget does not support being dragged.
  2699. * @method
  2700. */
  2701. clearConstraints: Ext.emptyFn,
  2702. /**
  2703. * @hide
  2704. * Overridden and disabled. A DDTarget does not support being dragged.
  2705. * @method
  2706. */
  2707. clearTicks: Ext.emptyFn,
  2708. /**
  2709. * @hide
  2710. * Overridden and disabled. A DDTarget does not support being dragged.
  2711. * @method
  2712. */
  2713. setInitPosition: Ext.emptyFn,
  2714. /**
  2715. * @hide
  2716. * Overridden and disabled. A DDTarget does not support being dragged.
  2717. * @method
  2718. */
  2719. setDragElId: Ext.emptyFn,
  2720. /**
  2721. * @hide
  2722. * Overridden and disabled. A DDTarget does not support being dragged.
  2723. * @method
  2724. */
  2725. setHandleElId: Ext.emptyFn,
  2726. /**
  2727. * @hide
  2728. * Overridden and disabled. A DDTarget does not support being dragged.
  2729. * @method
  2730. */
  2731. setOuterHandleElId: Ext.emptyFn,
  2732. /**
  2733. * @hide
  2734. * Overridden and disabled. A DDTarget does not support being dragged.
  2735. * @method
  2736. */
  2737. addInvalidHandleClass: Ext.emptyFn,
  2738. /**
  2739. * @hide
  2740. * Overridden and disabled. A DDTarget does not support being dragged.
  2741. * @method
  2742. */
  2743. addInvalidHandleId: Ext.emptyFn,
  2744. /**
  2745. * @hide
  2746. * Overridden and disabled. A DDTarget does not support being dragged.
  2747. * @method
  2748. */
  2749. addInvalidHandleType: Ext.emptyFn,
  2750. /**
  2751. * @hide
  2752. * Overridden and disabled. A DDTarget does not support being dragged.
  2753. * @method
  2754. */
  2755. removeInvalidHandleClass: Ext.emptyFn,
  2756. /**
  2757. * @hide
  2758. * Overridden and disabled. A DDTarget does not support being dragged.
  2759. * @method
  2760. */
  2761. removeInvalidHandleId: Ext.emptyFn,
  2762. /**
  2763. * @hide
  2764. * Overridden and disabled. A DDTarget does not support being dragged.
  2765. * @method
  2766. */
  2767. removeInvalidHandleType: Ext.emptyFn,
  2768. toString: function() {
  2769. return ("DDTarget " + this.id);
  2770. }
  2771. });/**
  2772. * @class Ext.dd.DragTracker
  2773. * @extends Ext.util.Observable
  2774. * A DragTracker listens for drag events on an Element and fires events at the start and end of the drag,
  2775. * as well as during the drag. This is useful for components such as {@link Ext.Slider}, where there is
  2776. * an element that can be dragged around to change the Slider's value.
  2777. * DragTracker provides a series of template methods that should be overridden to provide functionality
  2778. * in response to detected drag operations. These are onBeforeStart, onStart, onDrag and onEnd.
  2779. * See {@link Ext.Slider}'s initEvents function for an example implementation.
  2780. */
  2781. Ext.dd.DragTracker = Ext.extend(Ext.util.Observable, {
  2782. /**
  2783. * @cfg {Boolean} active
  2784. * Defaults to <tt>false</tt>.
  2785. */
  2786. active: false,
  2787. /**
  2788. * @cfg {Number} tolerance
  2789. * Number of pixels the drag target must be moved before dragging is considered to have started. Defaults to <tt>5</tt>.
  2790. */
  2791. tolerance: 5,
  2792. /**
  2793. * @cfg {Boolean/Number} autoStart
  2794. * Defaults to <tt>false</tt>. Specify <tt>true</tt> to defer trigger start by 1000 ms.
  2795. * Specify a Number for the number of milliseconds to defer trigger start.
  2796. */
  2797. autoStart: false,
  2798. constructor : function(config){
  2799. Ext.apply(this, config);
  2800. this.addEvents(
  2801. /**
  2802. * @event mousedown
  2803. * @param {Object} this
  2804. * @param {Object} e event object
  2805. */
  2806. 'mousedown',
  2807. /**
  2808. * @event mouseup
  2809. * @param {Object} this
  2810. * @param {Object} e event object
  2811. */
  2812. 'mouseup',
  2813. /**
  2814. * @event mousemove
  2815. * @param {Object} this
  2816. * @param {Object} e event object
  2817. */
  2818. 'mousemove',
  2819. /**
  2820. * @event dragstart
  2821. * @param {Object} this
  2822. * @param {Object} startXY the page coordinates of the event
  2823. */
  2824. 'dragstart',
  2825. /**
  2826. * @event dragend
  2827. * @param {Object} this
  2828. * @param {Object} e event object
  2829. */
  2830. 'dragend',
  2831. /**
  2832. * @event drag
  2833. * @param {Object} this
  2834. * @param {Object} e event object
  2835. */
  2836. 'drag'
  2837. );
  2838. this.dragRegion = new Ext.lib.Region(0,0,0,0);
  2839. if(this.el){
  2840. this.initEl(this.el);
  2841. }
  2842. Ext.dd.DragTracker.superclass.constructor.call(this, config);
  2843. },
  2844. initEl: function(el){
  2845. this.el = Ext.get(el);
  2846. el.on('mousedown', this.onMouseDown, this,
  2847. this.delegate ? {delegate: this.delegate} : undefined);
  2848. },
  2849. destroy : function(){
  2850. this.el.un('mousedown', this.onMouseDown, this);
  2851. },
  2852. onMouseDown: function(e, target){
  2853. if(this.fireEvent('mousedown', this, e) !== false && this.onBeforeStart(e) !== false){
  2854. this.startXY = this.lastXY = e.getXY();
  2855. this.dragTarget = this.delegate ? target : this.el.dom;
  2856. if(this.preventDefault !== false){
  2857. e.preventDefault();
  2858. }
  2859. var doc = Ext.getDoc();
  2860. doc.on('mouseup', this.onMouseUp, this);
  2861. doc.on('mousemove', this.onMouseMove, this);
  2862. doc.on('selectstart', this.stopSelect, this);
  2863. if(this.autoStart){
  2864. this.timer = this.triggerStart.defer(this.autoStart === true ? 1000 : this.autoStart, this);
  2865. }
  2866. }
  2867. },
  2868. onMouseMove: function(e, target){
  2869. // HACK: IE hack to see if button was released outside of window. */
  2870. if(this.active && Ext.isIE && !e.browserEvent.button){
  2871. e.preventDefault();
  2872. this.onMouseUp(e);
  2873. return;
  2874. }
  2875. e.preventDefault();
  2876. var xy = e.getXY(), s = this.startXY;
  2877. this.lastXY = xy;
  2878. if(!this.active){
  2879. if(Math.abs(s[0]-xy[0]) > this.tolerance || Math.abs(s[1]-xy[1]) > this.tolerance){
  2880. this.triggerStart();
  2881. }else{
  2882. return;
  2883. }
  2884. }
  2885. this.fireEvent('mousemove', this, e);
  2886. this.onDrag(e);
  2887. this.fireEvent('drag', this, e);
  2888. },
  2889. onMouseUp: function(e) {
  2890. var doc = Ext.getDoc();
  2891. doc.un('mousemove', this.onMouseMove, this);
  2892. doc.un('mouseup', this.onMouseUp, this);
  2893. doc.un('selectstart', this.stopSelect, this);
  2894. e.preventDefault();
  2895. this.clearStart();
  2896. var wasActive = this.active;
  2897. this.active = false;
  2898. delete this.elRegion;
  2899. this.fireEvent('mouseup', this, e);
  2900. if(wasActive){
  2901. this.onEnd(e);
  2902. this.fireEvent('dragend', this, e);
  2903. }
  2904. },
  2905. triggerStart: function(isTimer) {
  2906. this.clearStart();
  2907. this.active = true;
  2908. this.onStart(this.startXY);
  2909. this.fireEvent('dragstart', this, this.startXY);
  2910. },
  2911. clearStart : function() {
  2912. if(this.timer){
  2913. clearTimeout(this.timer);
  2914. delete this.timer;
  2915. }
  2916. },
  2917. stopSelect : function(e) {
  2918. e.stopEvent();
  2919. return false;
  2920. },
  2921. /**
  2922. * Template method which should be overridden by each DragTracker instance. Called when the user first clicks and
  2923. * holds the mouse button down. Return false to disallow the drag
  2924. * @param {Ext.EventObject} e The event object
  2925. */
  2926. onBeforeStart : function(e) {
  2927. },
  2928. /**
  2929. * Template method which should be overridden by each DragTracker instance. Called when a drag operation starts
  2930. * (e.g. the user has moved the tracked element beyond the specified tolerance)
  2931. * @param {Array} xy x and y co-ordinates of the original location of the tracked element
  2932. */
  2933. onStart : function(xy) {
  2934. },
  2935. /**
  2936. * Template method which should be overridden by each DragTracker instance. Called whenever a drag has been detected.
  2937. * @param {Ext.EventObject} e The event object
  2938. */
  2939. onDrag : function(e) {
  2940. },
  2941. /**
  2942. * Template method which should be overridden by each DragTracker instance. Called when a drag operation has been completed
  2943. * (e.g. the user clicked and held the mouse down, dragged the element and then released the mouse button)
  2944. * @param {Ext.EventObject} e The event object
  2945. */
  2946. onEnd : function(e) {
  2947. },
  2948. /**
  2949. * Returns the drag target
  2950. * @return {Ext.Element} The element currently being tracked
  2951. */
  2952. getDragTarget : function(){
  2953. return this.dragTarget;
  2954. },
  2955. getDragCt : function(){
  2956. return this.el;
  2957. },
  2958. getXY : function(constrain){
  2959. return constrain ?
  2960. this.constrainModes[constrain].call(this, this.lastXY) : this.lastXY;
  2961. },
  2962. getOffset : function(constrain){
  2963. var xy = this.getXY(constrain);
  2964. var s = this.startXY;
  2965. return [s[0]-xy[0], s[1]-xy[1]];
  2966. },
  2967. constrainModes: {
  2968. 'point' : function(xy){
  2969. if(!this.elRegion){
  2970. this.elRegion = this.getDragCt().getRegion();
  2971. }
  2972. var dr = this.dragRegion;
  2973. dr.left = xy[0];
  2974. dr.top = xy[1];
  2975. dr.right = xy[0];
  2976. dr.bottom = xy[1];
  2977. dr.constrainTo(this.elRegion);
  2978. return [dr.left, dr.top];
  2979. }
  2980. }
  2981. });/**
  2982. * @class Ext.dd.ScrollManager
  2983. * <p>Provides automatic scrolling of overflow regions in the page during drag operations.</p>
  2984. * <p>The ScrollManager configs will be used as the defaults for any scroll container registered with it,
  2985. * but you can also override most of the configs per scroll container by adding a
  2986. * <tt>ddScrollConfig</tt> object to the target element that contains these properties: {@link #hthresh},
  2987. * {@link #vthresh}, {@link #increment} and {@link #frequency}. Example usage:
  2988. * <pre><code>
  2989. var el = Ext.get('scroll-ct');
  2990. el.ddScrollConfig = {
  2991. vthresh: 50,
  2992. hthresh: -1,
  2993. frequency: 100,
  2994. increment: 200
  2995. };
  2996. Ext.dd.ScrollManager.register(el);
  2997. </code></pre>
  2998. * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
  2999. * @singleton
  3000. */
  3001. Ext.dd.ScrollManager = function(){
  3002. var ddm = Ext.dd.DragDropMgr;
  3003. var els = {};
  3004. var dragEl = null;
  3005. var proc = {};
  3006. var onStop = function(e){
  3007. dragEl = null;
  3008. clearProc();
  3009. };
  3010. var triggerRefresh = function(){
  3011. if(ddm.dragCurrent){
  3012. ddm.refreshCache(ddm.dragCurrent.groups);
  3013. }
  3014. };
  3015. var doScroll = function(){
  3016. if(ddm.dragCurrent){
  3017. var dds = Ext.dd.ScrollManager;
  3018. var inc = proc.el.ddScrollConfig ?
  3019. proc.el.ddScrollConfig.increment : dds.increment;
  3020. if(!dds.animate){
  3021. if(proc.el.scroll(proc.dir, inc)){
  3022. triggerRefresh();
  3023. }
  3024. }else{
  3025. proc.el.scroll(proc.dir, inc, true, dds.animDuration, triggerRefresh);
  3026. }
  3027. }
  3028. };
  3029. var clearProc = function(){
  3030. if(proc.id){
  3031. clearInterval(proc.id);
  3032. }
  3033. proc.id = 0;
  3034. proc.el = null;
  3035. proc.dir = "";
  3036. };
  3037. var startProc = function(el, dir){
  3038. clearProc();
  3039. proc.el = el;
  3040. proc.dir = dir;
  3041. var freq = (el.ddScrollConfig && el.ddScrollConfig.frequency) ?
  3042. el.ddScrollConfig.frequency : Ext.dd.ScrollManager.frequency;
  3043. proc.id = setInterval(doScroll, freq);
  3044. };
  3045. var onFire = function(e, isDrop){
  3046. if(isDrop || !ddm.dragCurrent){ return; }
  3047. var dds = Ext.dd.ScrollManager;
  3048. if(!dragEl || dragEl != ddm.dragCurrent){
  3049. dragEl = ddm.dragCurrent;
  3050. // refresh regions on drag start
  3051. dds.refreshCache();
  3052. }
  3053. var xy = Ext.lib.Event.getXY(e);
  3054. var pt = new Ext.lib.Point(xy[0], xy[1]);
  3055. for(var id in els){
  3056. var el = els[id], r = el._region;
  3057. var c = el.ddScrollConfig ? el.ddScrollConfig : dds;
  3058. if(r && r.contains(pt) && el.isScrollable()){
  3059. if(r.bottom - pt.y <= c.vthresh){
  3060. if(proc.el != el){
  3061. startProc(el, "down");
  3062. }
  3063. return;
  3064. }else if(r.right - pt.x <= c.hthresh){
  3065. if(proc.el != el){
  3066. startProc(el, "left");
  3067. }
  3068. return;
  3069. }else if(pt.y - r.top <= c.vthresh){
  3070. if(proc.el != el){
  3071. startProc(el, "up");
  3072. }
  3073. return;
  3074. }else if(pt.x - r.left <= c.hthresh){
  3075. if(proc.el != el){
  3076. startProc(el, "right");
  3077. }
  3078. return;
  3079. }
  3080. }
  3081. }
  3082. clearProc();
  3083. };
  3084. ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
  3085. ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
  3086. return {
  3087. /**
  3088. * Registers new overflow element(s) to auto scroll
  3089. * @param {Mixed/Array} el The id of or the element to be scrolled or an array of either
  3090. */
  3091. register : function(el){
  3092. if(Ext.isArray(el)){
  3093. for(var i = 0, len = el.length; i < len; i++) {
  3094. this.register(el[i]);
  3095. }
  3096. }else{
  3097. el = Ext.get(el);
  3098. els[el.id] = el;
  3099. }
  3100. },
  3101. /**
  3102. * Unregisters overflow element(s) so they are no longer scrolled
  3103. * @param {Mixed/Array} el The id of or the element to be removed or an array of either
  3104. */
  3105. unregister : function(el){
  3106. if(Ext.isArray(el)){
  3107. for(var i = 0, len = el.length; i < len; i++) {
  3108. this.unregister(el[i]);
  3109. }
  3110. }else{
  3111. el = Ext.get(el);
  3112. delete els[el.id];
  3113. }
  3114. },
  3115. /**
  3116. * The number of pixels from the top or bottom edge of a container the pointer needs to be to
  3117. * trigger scrolling (defaults to 25)
  3118. * @type Number
  3119. */
  3120. vthresh : 25,
  3121. /**
  3122. * The number of pixels from the right or left edge of a container the pointer needs to be to
  3123. * trigger scrolling (defaults to 25)
  3124. * @type Number
  3125. */
  3126. hthresh : 25,
  3127. /**
  3128. * The number of pixels to scroll in each scroll increment (defaults to 50)
  3129. * @type Number
  3130. */
  3131. increment : 100,
  3132. /**
  3133. * The frequency of scrolls in milliseconds (defaults to 500)
  3134. * @type Number
  3135. */
  3136. frequency : 500,
  3137. /**
  3138. * True to animate the scroll (defaults to true)
  3139. * @type Boolean
  3140. */
  3141. animate: true,
  3142. /**
  3143. * The animation duration in seconds -
  3144. * MUST BE less than Ext.dd.ScrollManager.frequency! (defaults to .4)
  3145. * @type Number
  3146. */
  3147. animDuration: .4,
  3148. /**
  3149. * Manually trigger a cache refresh.
  3150. */
  3151. refreshCache : function(){
  3152. for(var id in els){
  3153. if(typeof els[id] == 'object'){ // for people extending the object prototype
  3154. els[id]._region = els[id].getRegion();
  3155. }
  3156. }
  3157. }
  3158. };
  3159. }();/**
  3160. * @class Ext.dd.Registry
  3161. * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
  3162. * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
  3163. * @singleton
  3164. */
  3165. Ext.dd.Registry = function(){
  3166. var elements = {};
  3167. var handles = {};
  3168. var autoIdSeed = 0;
  3169. var getId = function(el, autogen){
  3170. if(typeof el == "string"){
  3171. return el;
  3172. }
  3173. var id = el.id;
  3174. if(!id && autogen !== false){
  3175. id = "extdd-" + (++autoIdSeed);
  3176. el.id = id;
  3177. }
  3178. return id;
  3179. };
  3180. return {
  3181. /**
  3182. * Resgister a drag drop element
  3183. * @param {String/HTMLElement} element The id or DOM node to register
  3184. * @param {Object} data (optional) An custom data object that will be passed between the elements that are involved
  3185. * in drag drop operations. You can populate this object with any arbitrary properties that your own code
  3186. * knows how to interpret, plus there are some specific properties known to the Registry that should be
  3187. * populated in the data object (if applicable):
  3188. * <pre>
  3189. Value Description<br />
  3190. --------- ------------------------------------------<br />
  3191. handles Array of DOM nodes that trigger dragging<br />
  3192. for the element being registered<br />
  3193. isHandle True if the element passed in triggers<br />
  3194. dragging itself, else false
  3195. </pre>
  3196. */
  3197. register : function(el, data){
  3198. data = data || {};
  3199. if(typeof el == "string"){
  3200. el = document.getElementById(el);
  3201. }
  3202. data.ddel = el;
  3203. elements[getId(el)] = data;
  3204. if(data.isHandle !== false){
  3205. handles[data.ddel.id] = data;
  3206. }
  3207. if(data.handles){
  3208. var hs = data.handles;
  3209. for(var i = 0, len = hs.length; i < len; i++){
  3210. handles[getId(hs[i])] = data;
  3211. }
  3212. }
  3213. },
  3214. /**
  3215. * Unregister a drag drop element
  3216. * @param {String/HTMLElement} element The id or DOM node to unregister
  3217. */
  3218. unregister : function(el){
  3219. var id = getId(el, false);
  3220. var data = elements[id];
  3221. if(data){
  3222. delete elements[id];
  3223. if(data.handles){
  3224. var hs = data.handles;
  3225. for(var i = 0, len = hs.length; i < len; i++){
  3226. delete handles[getId(hs[i], false)];
  3227. }
  3228. }
  3229. }
  3230. },
  3231. /**
  3232. * Returns the handle registered for a DOM Node by id
  3233. * @param {String/HTMLElement} id The DOM node or id to look up
  3234. * @return {Object} handle The custom handle data
  3235. */
  3236. getHandle : function(id){
  3237. if(typeof id != "string"){ // must be element?
  3238. id = id.id;
  3239. }
  3240. return handles[id];
  3241. },
  3242. /**
  3243. * Returns the handle that is registered for the DOM node that is the target of the event
  3244. * @param {Event} e The event
  3245. * @return {Object} handle The custom handle data
  3246. */
  3247. getHandleFromEvent : function(e){
  3248. var t = Ext.lib.Event.getTarget(e);
  3249. return t ? handles[t.id] : null;
  3250. },
  3251. /**
  3252. * Returns a custom data object that is registered for a DOM node by id
  3253. * @param {String/HTMLElement} id The DOM node or id to look up
  3254. * @return {Object} data The custom data
  3255. */
  3256. getTarget : function(id){
  3257. if(typeof id != "string"){ // must be element?
  3258. id = id.id;
  3259. }
  3260. return elements[id];
  3261. },
  3262. /**
  3263. * Returns a custom data object that is registered for the DOM node that is the target of the event
  3264. * @param {Event} e The event
  3265. * @return {Object} data The custom data
  3266. */
  3267. getTargetFromEvent : function(e){
  3268. var t = Ext.lib.Event.getTarget(e);
  3269. return t ? elements[t.id] || handles[t.id] : null;
  3270. }
  3271. };
  3272. }();/**
  3273. * @class Ext.dd.StatusProxy
  3274. * A specialized drag proxy that supports a drop status icon, {@link Ext.Layer} styles and auto-repair. This is the
  3275. * default drag proxy used by all Ext.dd components.
  3276. * @constructor
  3277. * @param {Object} config
  3278. */
  3279. Ext.dd.StatusProxy = function(config){
  3280. Ext.apply(this, config);
  3281. this.id = this.id || Ext.id();
  3282. this.el = new Ext.Layer({
  3283. dh: {
  3284. id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
  3285. {tag: "div", cls: "x-dd-drop-icon"},
  3286. {tag: "div", cls: "x-dd-drag-ghost"}
  3287. ]
  3288. },
  3289. shadow: !config || config.shadow !== false
  3290. });
  3291. this.ghost = Ext.get(this.el.dom.childNodes[1]);
  3292. this.dropStatus = this.dropNotAllowed;
  3293. };
  3294. Ext.dd.StatusProxy.prototype = {
  3295. /**
  3296. * @cfg {String} dropAllowed
  3297. * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
  3298. */
  3299. dropAllowed : "x-dd-drop-ok",
  3300. /**
  3301. * @cfg {String} dropNotAllowed
  3302. * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
  3303. */
  3304. dropNotAllowed : "x-dd-drop-nodrop",
  3305. /**
  3306. * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
  3307. * over the current target element.
  3308. * @param {String} cssClass The css class for the new drop status indicator image
  3309. */
  3310. setStatus : function(cssClass){
  3311. cssClass = cssClass || this.dropNotAllowed;
  3312. if(this.dropStatus != cssClass){
  3313. this.el.replaceClass(this.dropStatus, cssClass);
  3314. this.dropStatus = cssClass;
  3315. }
  3316. },
  3317. /**
  3318. * Resets the status indicator to the default dropNotAllowed value
  3319. * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
  3320. */
  3321. reset : function(clearGhost){
  3322. this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
  3323. this.dropStatus = this.dropNotAllowed;
  3324. if(clearGhost){
  3325. this.ghost.update("");
  3326. }
  3327. },
  3328. /**
  3329. * Updates the contents of the ghost element
  3330. * @param {String/HTMLElement} html The html that will replace the current innerHTML of the ghost element, or a
  3331. * DOM node to append as the child of the ghost element (in which case the innerHTML will be cleared first).
  3332. */
  3333. update : function(html){
  3334. if(typeof html == "string"){
  3335. this.ghost.update(html);
  3336. }else{
  3337. this.ghost.update("");
  3338. html.style.margin = "0";
  3339. this.ghost.dom.appendChild(html);
  3340. }
  3341. var el = this.ghost.dom.firstChild;
  3342. if(el){
  3343. Ext.fly(el).setStyle('float', 'none');
  3344. }
  3345. },
  3346. /**
  3347. * Returns the underlying proxy {@link Ext.Layer}
  3348. * @return {Ext.Layer} el
  3349. */
  3350. getEl : function(){
  3351. return this.el;
  3352. },
  3353. /**
  3354. * Returns the ghost element
  3355. * @return {Ext.Element} el
  3356. */
  3357. getGhost : function(){
  3358. return this.ghost;
  3359. },
  3360. /**
  3361. * Hides the proxy
  3362. * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
  3363. */
  3364. hide : function(clear){
  3365. this.el.hide();
  3366. if(clear){
  3367. this.reset(true);
  3368. }
  3369. },
  3370. /**
  3371. * Stops the repair animation if it's currently running
  3372. */
  3373. stop : function(){
  3374. if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
  3375. this.anim.stop();
  3376. }
  3377. },
  3378. /**
  3379. * Displays this proxy
  3380. */
  3381. show : function(){
  3382. this.el.show();
  3383. },
  3384. /**
  3385. * Force the Layer to sync its shadow and shim positions to the element
  3386. */
  3387. sync : function(){
  3388. this.el.sync();
  3389. },
  3390. /**
  3391. * Causes the proxy to return to its position of origin via an animation. Should be called after an
  3392. * invalid drop operation by the item being dragged.
  3393. * @param {Array} xy The XY position of the element ([x, y])
  3394. * @param {Function} callback The function to call after the repair is complete.
  3395. * @param {Object} scope The scope (<code>this</code> reference) in which the callback function is executed. Defaults to the browser window.
  3396. */
  3397. repair : function(xy, callback, scope){
  3398. this.callback = callback;
  3399. this.scope = scope;
  3400. if(xy && this.animRepair !== false){
  3401. this.el.addClass("x-dd-drag-repair");
  3402. this.el.hideUnders(true);
  3403. this.anim = this.el.shift({
  3404. duration: this.repairDuration || .5,
  3405. easing: 'easeOut',
  3406. xy: xy,
  3407. stopFx: true,
  3408. callback: this.afterRepair,
  3409. scope: this
  3410. });
  3411. }else{
  3412. this.afterRepair();
  3413. }
  3414. },
  3415. // private
  3416. afterRepair : function(){
  3417. this.hide(true);
  3418. if(typeof this.callback == "function"){
  3419. this.callback.call(this.scope || this);
  3420. }
  3421. this.callback = null;
  3422. this.scope = null;
  3423. },
  3424. destroy: function(){
  3425. Ext.destroy(this.ghost, this.el);
  3426. }
  3427. };/**
  3428. * @class Ext.dd.DragSource
  3429. * @extends Ext.dd.DDProxy
  3430. * A simple class that provides the basic implementation needed to make any element draggable.
  3431. * @constructor
  3432. * @param {Mixed} el The container element
  3433. * @param {Object} config
  3434. */
  3435. Ext.dd.DragSource = function(el, config){
  3436. this.el = Ext.get(el);
  3437. if(!this.dragData){
  3438. this.dragData = {};
  3439. }
  3440. Ext.apply(this, config);
  3441. if(!this.proxy){
  3442. this.proxy = new Ext.dd.StatusProxy();
  3443. }
  3444. Ext.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
  3445. {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
  3446. this.dragging = false;
  3447. };
  3448. Ext.extend(Ext.dd.DragSource, Ext.dd.DDProxy, {
  3449. /**
  3450. * @cfg {String} ddGroup
  3451. * A named drag drop group to which this object belongs. If a group is specified, then this object will only
  3452. * interact with other drag drop objects in the same group (defaults to undefined).
  3453. */
  3454. /**
  3455. * @cfg {String} dropAllowed
  3456. * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
  3457. */
  3458. dropAllowed : "x-dd-drop-ok",
  3459. /**
  3460. * @cfg {String} dropNotAllowed
  3461. * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
  3462. */
  3463. dropNotAllowed : "x-dd-drop-nodrop",
  3464. /**
  3465. * Returns the data object associated with this drag source
  3466. * @return {Object} data An object containing arbitrary data
  3467. */
  3468. getDragData : function(e){
  3469. return this.dragData;
  3470. },
  3471. // private
  3472. onDragEnter : function(e, id){
  3473. var target = Ext.dd.DragDropMgr.getDDById(id);
  3474. this.cachedTarget = target;
  3475. if(this.beforeDragEnter(target, e, id) !== false){
  3476. if(target.isNotifyTarget){
  3477. var status = target.notifyEnter(this, e, this.dragData);
  3478. this.proxy.setStatus(status);
  3479. }else{
  3480. this.proxy.setStatus(this.dropAllowed);
  3481. }
  3482. if(this.afterDragEnter){
  3483. /**
  3484. * An empty function by default, but provided so that you can perform a custom action
  3485. * when the dragged item enters the drop target by providing an implementation.
  3486. * @param {Ext.dd.DragDrop} target The drop target
  3487. * @param {Event} e The event object
  3488. * @param {String} id The id of the dragged element
  3489. * @method afterDragEnter
  3490. */
  3491. this.afterDragEnter(target, e, id);
  3492. }
  3493. }
  3494. },
  3495. /**
  3496. * An empty function by default, but provided so that you can perform a custom action
  3497. * before the dragged item enters the drop target and optionally cancel the onDragEnter.
  3498. * @param {Ext.dd.DragDrop} target The drop target
  3499. * @param {Event} e The event object
  3500. * @param {String} id The id of the dragged element
  3501. * @return {Boolean} isValid True if the drag event is valid, else false to cancel
  3502. */
  3503. beforeDragEnter : function(target, e, id){
  3504. return true;
  3505. },
  3506. // private
  3507. alignElWithMouse: function() {
  3508. Ext.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
  3509. this.proxy.sync();
  3510. },
  3511. // private
  3512. onDragOver : function(e, id){
  3513. var target = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(id);
  3514. if(this.beforeDragOver(target, e, id) !== false){
  3515. if(target.isNotifyTarget){
  3516. var status = target.notifyOver(this, e, this.dragData);
  3517. this.proxy.setStatus(status);
  3518. }
  3519. if(this.afterDragOver){
  3520. /**
  3521. * An empty function by default, but provided so that you can perform a custom action
  3522. * while the dragged item is over the drop target by providing an implementation.
  3523. * @param {Ext.dd.DragDrop} target The drop target
  3524. * @param {Event} e The event object
  3525. * @param {String} id The id of the dragged element
  3526. * @method afterDragOver
  3527. */
  3528. this.afterDragOver(target, e, id);
  3529. }
  3530. }
  3531. },
  3532. /**
  3533. * An empty function by default, but provided so that you can perform a custom action
  3534. * while the dragged item is over the drop target and optionally cancel the onDragOver.
  3535. * @param {Ext.dd.DragDrop} target The drop target
  3536. * @param {Event} e The event object
  3537. * @param {String} id The id of the dragged element
  3538. * @return {Boolean} isValid True if the drag event is valid, else false to cancel
  3539. */
  3540. beforeDragOver : function(target, e, id){
  3541. return true;
  3542. },
  3543. // private
  3544. onDragOut : function(e, id){
  3545. var target = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(id);
  3546. if(this.beforeDragOut(target, e, id) !== false){
  3547. if(target.isNotifyTarget){
  3548. target.notifyOut(this, e, this.dragData);
  3549. }
  3550. this.proxy.reset();
  3551. if(this.afterDragOut){
  3552. /**
  3553. * An empty function by default, but provided so that you can perform a custom action
  3554. * after the dragged item is dragged out of the target without dropping.
  3555. * @param {Ext.dd.DragDrop} target The drop target
  3556. * @param {Event} e The event object
  3557. * @param {String} id The id of the dragged element
  3558. * @method afterDragOut
  3559. */
  3560. this.afterDragOut(target, e, id);
  3561. }
  3562. }
  3563. this.cachedTarget = null;
  3564. },
  3565. /**
  3566. * An empty function by default, but provided so that you can perform a custom action before the dragged
  3567. * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
  3568. * @param {Ext.dd.DragDrop} target The drop target
  3569. * @param {Event} e The event object
  3570. * @param {String} id The id of the dragged element
  3571. * @return {Boolean} isValid True if the drag event is valid, else false to cancel
  3572. */
  3573. beforeDragOut : function(target, e, id){
  3574. return true;
  3575. },
  3576. // private
  3577. onDragDrop : function(e, id){
  3578. var target = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(id);
  3579. if(this.beforeDragDrop(target, e, id) !== false){
  3580. if(target.isNotifyTarget){
  3581. if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
  3582. this.onValidDrop(target, e, id);
  3583. }else{
  3584. this.onInvalidDrop(target, e, id);
  3585. }
  3586. }else{
  3587. this.onValidDrop(target, e, id);
  3588. }
  3589. if(this.afterDragDrop){
  3590. /**
  3591. * An empty function by default, but provided so that you can perform a custom action
  3592. * after a valid drag drop has occurred by providing an implementation.
  3593. * @param {Ext.dd.DragDrop} target The drop target
  3594. * @param {Event} e The event object
  3595. * @param {String} id The id of the dropped element
  3596. * @method afterDragDrop
  3597. */
  3598. this.afterDragDrop(target, e, id);
  3599. }
  3600. }
  3601. delete this.cachedTarget;
  3602. },
  3603. /**
  3604. * An empty function by default, but provided so that you can perform a custom action before the dragged
  3605. * item is dropped onto the target and optionally cancel the onDragDrop.
  3606. * @param {Ext.dd.DragDrop} target The drop target
  3607. * @param {Event} e The event object
  3608. * @param {String} id The id of the dragged element
  3609. * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
  3610. */
  3611. beforeDragDrop : function(target, e, id){
  3612. return true;
  3613. },
  3614. // private
  3615. onValidDrop : function(target, e, id){
  3616. this.hideProxy();
  3617. if(this.afterValidDrop){
  3618. /**
  3619. * An empty function by default, but provided so that you can perform a custom action
  3620. * after a valid drop has occurred by providing an implementation.
  3621. * @param {Object} target The target DD
  3622. * @param {Event} e The event object
  3623. * @param {String} id The id of the dropped element
  3624. * @method afterInvalidDrop
  3625. */
  3626. this.afterValidDrop(target, e, id);
  3627. }
  3628. },
  3629. // private
  3630. getRepairXY : function(e, data){
  3631. return this.el.getXY();
  3632. },
  3633. // private
  3634. onInvalidDrop : function(target, e, id){
  3635. this.beforeInvalidDrop(target, e, id);
  3636. if(this.cachedTarget){
  3637. if(this.cachedTarget.isNotifyTarget){
  3638. this.cachedTarget.notifyOut(this, e, this.dragData);
  3639. }
  3640. this.cacheTarget = null;
  3641. }
  3642. this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
  3643. if(this.afterInvalidDrop){
  3644. /**
  3645. * An empty function by default, but provided so that you can perform a custom action
  3646. * after an invalid drop has occurred by providing an implementation.
  3647. * @param {Event} e The event object
  3648. * @param {String} id The id of the dropped element
  3649. * @method afterInvalidDrop
  3650. */
  3651. this.afterInvalidDrop(e, id);
  3652. }
  3653. },
  3654. // private
  3655. afterRepair : function(){
  3656. if(Ext.enableFx){
  3657. this.el.highlight(this.hlColor || "c3daf9");
  3658. }
  3659. this.dragging = false;
  3660. },
  3661. /**
  3662. * An empty function by default, but provided so that you can perform a custom action after an invalid
  3663. * drop has occurred.
  3664. * @param {Ext.dd.DragDrop} target The drop target
  3665. * @param {Event} e The event object
  3666. * @param {String} id The id of the dragged element
  3667. * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
  3668. */
  3669. beforeInvalidDrop : function(target, e, id){
  3670. return true;
  3671. },
  3672. // private
  3673. handleMouseDown : function(e){
  3674. if(this.dragging) {
  3675. return;
  3676. }
  3677. var data = this.getDragData(e);
  3678. if(data && this.onBeforeDrag(data, e) !== false){
  3679. this.dragData = data;
  3680. this.proxy.stop();
  3681. Ext.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
  3682. }
  3683. },
  3684. /**
  3685. * An empty function by default, but provided so that you can perform a custom action before the initial
  3686. * drag event begins and optionally cancel it.
  3687. * @param {Object} data An object containing arbitrary data to be shared with drop targets
  3688. * @param {Event} e The event object
  3689. * @return {Boolean} isValid True if the drag event is valid, else false to cancel
  3690. */
  3691. onBeforeDrag : function(data, e){
  3692. return true;
  3693. },
  3694. /**
  3695. * An empty function by default, but provided so that you can perform a custom action once the initial
  3696. * drag event has begun. The drag cannot be canceled from this function.
  3697. * @param {Number} x The x position of the click on the dragged object
  3698. * @param {Number} y The y position of the click on the dragged object
  3699. */
  3700. onStartDrag : Ext.emptyFn,
  3701. // private override
  3702. startDrag : function(x, y){
  3703. this.proxy.reset();
  3704. this.dragging = true;
  3705. this.proxy.update("");
  3706. this.onInitDrag(x, y);
  3707. this.proxy.show();
  3708. },
  3709. // private
  3710. onInitDrag : function(x, y){
  3711. var clone = this.el.dom.cloneNode(true);
  3712. clone.id = Ext.id(); // prevent duplicate ids
  3713. this.proxy.update(clone);
  3714. this.onStartDrag(x, y);
  3715. return true;
  3716. },
  3717. /**
  3718. * Returns the drag source's underlying {@link Ext.dd.StatusProxy}
  3719. * @return {Ext.dd.StatusProxy} proxy The StatusProxy
  3720. */
  3721. getProxy : function(){
  3722. return this.proxy;
  3723. },
  3724. /**
  3725. * Hides the drag source's {@link Ext.dd.StatusProxy}
  3726. */
  3727. hideProxy : function(){
  3728. this.proxy.hide();
  3729. this.proxy.reset(true);
  3730. this.dragging = false;
  3731. },
  3732. // private
  3733. triggerCacheRefresh : function(){
  3734. Ext.dd.DDM.refreshCache(this.groups);
  3735. },
  3736. // private - override to prevent hiding
  3737. b4EndDrag: function(e) {
  3738. },
  3739. // private - override to prevent moving
  3740. endDrag : function(e){
  3741. this.onEndDrag(this.dragData, e);
  3742. },
  3743. // private
  3744. onEndDrag : function(data, e){
  3745. },
  3746. // private - pin to cursor
  3747. autoOffset : function(x, y) {
  3748. this.setDelta(-12, -20);
  3749. },
  3750. destroy: function(){
  3751. Ext.dd.DragSource.superclass.destroy.call(this);
  3752. Ext.destroy(this.proxy);
  3753. }
  3754. });/**
  3755. * @class Ext.dd.DropTarget
  3756. * @extends Ext.dd.DDTarget
  3757. * A simple class that provides the basic implementation needed to make any element a drop target that can have
  3758. * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
  3759. * @constructor
  3760. * @param {Mixed} el The container element
  3761. * @param {Object} config
  3762. */
  3763. Ext.dd.DropTarget = function(el, config){
  3764. this.el = Ext.get(el);
  3765. Ext.apply(this, config);
  3766. if(this.containerScroll){
  3767. Ext.dd.ScrollManager.register(this.el);
  3768. }
  3769. Ext.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
  3770. {isTarget: true});
  3771. };
  3772. Ext.extend(Ext.dd.DropTarget, Ext.dd.DDTarget, {
  3773. /**
  3774. * @cfg {String} ddGroup
  3775. * A named drag drop group to which this object belongs. If a group is specified, then this object will only
  3776. * interact with other drag drop objects in the same group (defaults to undefined).
  3777. */
  3778. /**
  3779. * @cfg {String} overClass
  3780. * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
  3781. */
  3782. /**
  3783. * @cfg {String} dropAllowed
  3784. * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
  3785. */
  3786. dropAllowed : "x-dd-drop-ok",
  3787. /**
  3788. * @cfg {String} dropNotAllowed
  3789. * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
  3790. */
  3791. dropNotAllowed : "x-dd-drop-nodrop",
  3792. // private
  3793. isTarget : true,
  3794. // private
  3795. isNotifyTarget : true,
  3796. /**
  3797. * The function a {@link Ext.dd.DragSource} calls once to notify this drop target that the source is now over the
  3798. * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
  3799. * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
  3800. * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target
  3801. * @param {Event} e The event
  3802. * @param {Object} data An object containing arbitrary data supplied by the drag source
  3803. * @return {String} status The CSS class that communicates the drop status back to the source so that the
  3804. * underlying {@link Ext.dd.StatusProxy} can be updated
  3805. */
  3806. notifyEnter : function(dd, e, data){
  3807. if(this.overClass){
  3808. this.el.addClass(this.overClass);
  3809. }
  3810. return this.dropAllowed;
  3811. },
  3812. /**
  3813. * The function a {@link Ext.dd.DragSource} calls continuously while it is being dragged over the target.
  3814. * This method will be called on every mouse movement while the drag source is over the drop target.
  3815. * This default implementation simply returns the dropAllowed config value.
  3816. * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target
  3817. * @param {Event} e The event
  3818. * @param {Object} data An object containing arbitrary data supplied by the drag source
  3819. * @return {String} status The CSS class that communicates the drop status back to the source so that the
  3820. * underlying {@link Ext.dd.StatusProxy} can be updated
  3821. */
  3822. notifyOver : function(dd, e, data){
  3823. return this.dropAllowed;
  3824. },
  3825. /**
  3826. * The function a {@link Ext.dd.DragSource} calls once to notify this drop target that the source has been dragged
  3827. * out of the target without dropping. This default implementation simply removes the CSS class specified by
  3828. * overClass (if any) from the drop element.
  3829. * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target
  3830. * @param {Event} e The event
  3831. * @param {Object} data An object containing arbitrary data supplied by the drag source
  3832. */
  3833. notifyOut : function(dd, e, data){
  3834. if(this.overClass){
  3835. this.el.removeClass(this.overClass);
  3836. }
  3837. },
  3838. /**
  3839. * The function a {@link Ext.dd.DragSource} calls once to notify this drop target that the dragged item has
  3840. * been dropped on it. This method has no default implementation and returns false, so you must provide an
  3841. * implementation that does something to process the drop event and returns true so that the drag source's
  3842. * repair action does not run.
  3843. * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target
  3844. * @param {Event} e The event
  3845. * @param {Object} data An object containing arbitrary data supplied by the drag source
  3846. * @return {Boolean} True if the drop was valid, else false
  3847. */
  3848. notifyDrop : function(dd, e, data){
  3849. return false;
  3850. }
  3851. });/**
  3852. * @class Ext.dd.DragZone
  3853. * @extends Ext.dd.DragSource
  3854. * <p>This class provides a container DD instance that allows dragging of multiple child source nodes.</p>
  3855. * <p>This class does not move the drag target nodes, but a proxy element which may contain
  3856. * any DOM structure you wish. The DOM element to show in the proxy is provided by either a
  3857. * provided implementation of {@link #getDragData}, or by registered draggables registered with {@link Ext.dd.Registry}</p>
  3858. * <p>If you wish to provide draggability for an arbitrary number of DOM nodes, each of which represent some
  3859. * application object (For example nodes in a {@link Ext.DataView DataView}) then use of this class
  3860. * is the most efficient way to "activate" those nodes.</p>
  3861. * <p>By default, this class requires that draggable child nodes are registered with {@link Ext.dd.Registry}.
  3862. * However a simpler way to allow a DragZone to manage any number of draggable elements is to configure
  3863. * the DragZone with an implementation of the {@link #getDragData} method which interrogates the passed
  3864. * mouse event to see if it has taken place within an element, or class of elements. This is easily done
  3865. * by using the event's {@link Ext.EventObject#getTarget getTarget} method to identify a node based on a
  3866. * {@link Ext.DomQuery} selector. For example, to make the nodes of a DataView draggable, use the following
  3867. * technique. Knowledge of the use of the DataView is required:</p><pre><code>
  3868. myDataView.on('render', function(v) {
  3869. myDataView.dragZone = new Ext.dd.DragZone(v.getEl(), {
  3870. // On receipt of a mousedown event, see if it is within a DataView node.
  3871. // Return a drag data object if so.
  3872. getDragData: function(e) {
  3873. // Use the DataView's own itemSelector (a mandatory property) to
  3874. // test if the mousedown is within one of the DataView's nodes.
  3875. var sourceEl = e.getTarget(v.itemSelector, 10);
  3876. // If the mousedown is within a DataView node, clone the node to produce
  3877. // a ddel element for use by the drag proxy. Also add application data
  3878. // to the returned data object.
  3879. if (sourceEl) {
  3880. d = sourceEl.cloneNode(true);
  3881. d.id = Ext.id();
  3882. return {
  3883. ddel: d,
  3884. sourceEl: sourceEl,
  3885. repairXY: Ext.fly(sourceEl).getXY(),
  3886. sourceStore: v.store,
  3887. draggedRecord: v.{@link Ext.DataView#getRecord getRecord}(sourceEl)
  3888. }
  3889. }
  3890. },
  3891. // Provide coordinates for the proxy to slide back to on failed drag.
  3892. // This is the original XY coordinates of the draggable element captured
  3893. // in the getDragData method.
  3894. getRepairXY: function() {
  3895. return this.dragData.repairXY;
  3896. }
  3897. });
  3898. });</code></pre>
  3899. * See the {@link Ext.dd.DropZone DropZone} documentation for details about building a DropZone which
  3900. * cooperates with this DragZone.
  3901. * @constructor
  3902. * @param {Mixed} el The container element
  3903. * @param {Object} config
  3904. */
  3905. Ext.dd.DragZone = function(el, config){
  3906. Ext.dd.DragZone.superclass.constructor.call(this, el, config);
  3907. if(this.containerScroll){
  3908. Ext.dd.ScrollManager.register(this.el);
  3909. }
  3910. };
  3911. Ext.extend(Ext.dd.DragZone, Ext.dd.DragSource, {
  3912. /**
  3913. * This property contains the data representing the dragged object. This data is set up by the implementation
  3914. * of the {@link #getDragData} method. It must contain a <tt>ddel</tt> property, but can contain
  3915. * any other data according to the application's needs.
  3916. * @type Object
  3917. * @property dragData
  3918. */
  3919. /**
  3920. * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
  3921. * for auto scrolling during drag operations.
  3922. */
  3923. /**
  3924. * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
  3925. * method after a failed drop (defaults to "c3daf9" - light blue)
  3926. */
  3927. /**
  3928. * Called when a mousedown occurs in this container. Looks in {@link Ext.dd.Registry}
  3929. * for a valid target to drag based on the mouse down. Override this method
  3930. * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
  3931. * object has a "ddel" attribute (with an HTML Element) for other functions to work.
  3932. * @param {EventObject} e The mouse down event
  3933. * @return {Object} The dragData
  3934. */
  3935. getDragData : function(e){
  3936. return Ext.dd.Registry.getHandleFromEvent(e);
  3937. },
  3938. /**
  3939. * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
  3940. * this.dragData.ddel
  3941. * @param {Number} x The x position of the click on the dragged object
  3942. * @param {Number} y The y position of the click on the dragged object
  3943. * @return {Boolean} true to continue the drag, false to cancel
  3944. */
  3945. onInitDrag : function(x, y){
  3946. this.proxy.update(this.dragData.ddel.cloneNode(true));
  3947. this.onStartDrag(x, y);
  3948. return true;
  3949. },
  3950. /**
  3951. * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
  3952. */
  3953. afterRepair : function(){
  3954. if(Ext.enableFx){
  3955. Ext.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
  3956. }
  3957. this.dragging = false;
  3958. },
  3959. /**
  3960. * Called before a repair of an invalid drop to get the XY to animate to. By default returns
  3961. * the XY of this.dragData.ddel
  3962. * @param {EventObject} e The mouse up event
  3963. * @return {Array} The xy location (e.g. [100, 200])
  3964. */
  3965. getRepairXY : function(e){
  3966. return Ext.Element.fly(this.dragData.ddel).getXY();
  3967. }
  3968. });/**
  3969. * @class Ext.dd.DropZone
  3970. * @extends Ext.dd.DropTarget
  3971. * <p>This class provides a container DD instance that allows dropping on multiple child target nodes.</p>
  3972. * <p>By default, this class requires that child nodes accepting drop are registered with {@link Ext.dd.Registry}.
  3973. * However a simpler way to allow a DropZone to manage any number of target elements is to configure the
  3974. * DropZone with an implementation of {@link #getTargetFromEvent} which interrogates the passed
  3975. * mouse event to see if it has taken place within an element, or class of elements. This is easily done
  3976. * by using the event's {@link Ext.EventObject#getTarget getTarget} method to identify a node based on a
  3977. * {@link Ext.DomQuery} selector.</p>
  3978. * <p>Once the DropZone has detected through calling getTargetFromEvent, that the mouse is over
  3979. * a drop target, that target is passed as the first parameter to {@link #onNodeEnter}, {@link #onNodeOver},
  3980. * {@link #onNodeOut}, {@link #onNodeDrop}. You may configure the instance of DropZone with implementations
  3981. * of these methods to provide application-specific behaviour for these events to update both
  3982. * application state, and UI state.</p>
  3983. * <p>For example to make a GridPanel a cooperating target with the example illustrated in
  3984. * {@link Ext.dd.DragZone DragZone}, the following technique might be used:</p><pre><code>
  3985. myGridPanel.on('render', function() {
  3986. myGridPanel.dropZone = new Ext.dd.DropZone(myGridPanel.getView().scroller, {
  3987. // If the mouse is over a grid row, return that node. This is
  3988. // provided as the "target" parameter in all "onNodeXXXX" node event handling functions
  3989. getTargetFromEvent: function(e) {
  3990. return e.getTarget(myGridPanel.getView().rowSelector);
  3991. },
  3992. // On entry into a target node, highlight that node.
  3993. onNodeEnter : function(target, dd, e, data){
  3994. Ext.fly(target).addClass('my-row-highlight-class');
  3995. },
  3996. // On exit from a target node, unhighlight that node.
  3997. onNodeOut : function(target, dd, e, data){
  3998. Ext.fly(target).removeClass('my-row-highlight-class');
  3999. },
  4000. // While over a target node, return the default drop allowed class which
  4001. // places a "tick" icon into the drag proxy.
  4002. onNodeOver : function(target, dd, e, data){
  4003. return Ext.dd.DropZone.prototype.dropAllowed;
  4004. },
  4005. // On node drop we can interrogate the target to find the underlying
  4006. // application object that is the real target of the dragged data.
  4007. // In this case, it is a Record in the GridPanel's Store.
  4008. // We can use the data set up by the DragZone's getDragData method to read
  4009. // any data we decided to attach in the DragZone's getDragData method.
  4010. onNodeDrop : function(target, dd, e, data){
  4011. var rowIndex = myGridPanel.getView().findRowIndex(target);
  4012. var r = myGridPanel.getStore().getAt(rowIndex);
  4013. Ext.Msg.alert('Drop gesture', 'Dropped Record id ' + data.draggedRecord.id +
  4014. ' on Record id ' + r.id);
  4015. return true;
  4016. }
  4017. });
  4018. }
  4019. </code></pre>
  4020. * See the {@link Ext.dd.DragZone DragZone} documentation for details about building a DragZone which
  4021. * cooperates with this DropZone.
  4022. * @constructor
  4023. * @param {Mixed} el The container element
  4024. * @param {Object} config
  4025. */
  4026. Ext.dd.DropZone = function(el, config){
  4027. Ext.dd.DropZone.superclass.constructor.call(this, el, config);
  4028. };
  4029. Ext.extend(Ext.dd.DropZone, Ext.dd.DropTarget, {
  4030. /**
  4031. * Returns a custom data object associated with the DOM node that is the target of the event. By default
  4032. * this looks up the event target in the {@link Ext.dd.Registry}, although you can override this method to
  4033. * provide your own custom lookup.
  4034. * @param {Event} e The event
  4035. * @return {Object} data The custom data
  4036. */
  4037. getTargetFromEvent : function(e){
  4038. return Ext.dd.Registry.getTargetFromEvent(e);
  4039. },
  4040. /**
  4041. * Called when the DropZone determines that a {@link Ext.dd.DragSource} has entered a drop node
  4042. * that has either been registered or detected by a configured implementation of {@link #getTargetFromEvent}.
  4043. * This method has no default implementation and should be overridden to provide
  4044. * node-specific processing if necessary.
  4045. * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
  4046. * {@link #getTargetFromEvent} for this node)
  4047. * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
  4048. * @param {Event} e The event
  4049. * @param {Object} data An object containing arbitrary data supplied by the drag source
  4050. */
  4051. onNodeEnter : function(n, dd, e, data){
  4052. },
  4053. /**
  4054. * Called while the DropZone determines that a {@link Ext.dd.DragSource} is over a drop node
  4055. * that has either been registered or detected by a configured implementation of {@link #getTargetFromEvent}.
  4056. * The default implementation returns this.dropNotAllowed, so it should be
  4057. * overridden to provide the proper feedback.
  4058. * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
  4059. * {@link #getTargetFromEvent} for this node)
  4060. * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
  4061. * @param {Event} e The event
  4062. * @param {Object} data An object containing arbitrary data supplied by the drag source
  4063. * @return {String} status The CSS class that communicates the drop status back to the source so that the
  4064. * underlying {@link Ext.dd.StatusProxy} can be updated
  4065. */
  4066. onNodeOver : function(n, dd, e, data){
  4067. return this.dropAllowed;
  4068. },
  4069. /**
  4070. * Called when the DropZone determines that a {@link Ext.dd.DragSource} has been dragged out of
  4071. * the drop node without dropping. This method has no default implementation and should be overridden to provide
  4072. * node-specific processing if necessary.
  4073. * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
  4074. * {@link #getTargetFromEvent} for this node)
  4075. * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
  4076. * @param {Event} e The event
  4077. * @param {Object} data An object containing arbitrary data supplied by the drag source
  4078. */
  4079. onNodeOut : function(n, dd, e, data){
  4080. },
  4081. /**
  4082. * Called when the DropZone determines that a {@link Ext.dd.DragSource} has been dropped onto
  4083. * the drop node. The default implementation returns false, so it should be overridden to provide the
  4084. * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
  4085. * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
  4086. * {@link #getTargetFromEvent} for this node)
  4087. * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
  4088. * @param {Event} e The event
  4089. * @param {Object} data An object containing arbitrary data supplied by the drag source
  4090. * @return {Boolean} True if the drop was valid, else false
  4091. */
  4092. onNodeDrop : function(n, dd, e, data){
  4093. return false;
  4094. },
  4095. /**
  4096. * Called while the DropZone determines that a {@link Ext.dd.DragSource} is being dragged over it,
  4097. * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
  4098. * it should be overridden to provide the proper feedback if necessary.
  4099. * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
  4100. * @param {Event} e The event
  4101. * @param {Object} data An object containing arbitrary data supplied by the drag source
  4102. * @return {String} status The CSS class that communicates the drop status back to the source so that the
  4103. * underlying {@link Ext.dd.StatusProxy} can be updated
  4104. */
  4105. onContainerOver : function(dd, e, data){
  4106. return this.dropNotAllowed;
  4107. },
  4108. /**
  4109. * Called when the DropZone determines that a {@link Ext.dd.DragSource} has been dropped on it,
  4110. * but not on any of its registered drop nodes. The default implementation returns false, so it should be
  4111. * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
  4112. * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
  4113. * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
  4114. * @param {Event} e The event
  4115. * @param {Object} data An object containing arbitrary data supplied by the drag source
  4116. * @return {Boolean} True if the drop was valid, else false
  4117. */
  4118. onContainerDrop : function(dd, e, data){
  4119. return false;
  4120. },
  4121. /**
  4122. * The function a {@link Ext.dd.DragSource} calls once to notify this drop zone that the source is now over
  4123. * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
  4124. * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
  4125. * you should override this method and provide a custom implementation.
  4126. * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
  4127. * @param {Event} e The event
  4128. * @param {Object} data An object containing arbitrary data supplied by the drag source
  4129. * @return {String} status The CSS class that communicates the drop status back to the source so that the
  4130. * underlying {@link Ext.dd.StatusProxy} can be updated
  4131. */
  4132. notifyEnter : function(dd, e, data){
  4133. return this.dropNotAllowed;
  4134. },
  4135. /**
  4136. * The function a {@link Ext.dd.DragSource} calls continuously while it is being dragged over the drop zone.
  4137. * This method will be called on every mouse movement while the drag source is over the drop zone.
  4138. * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
  4139. * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
  4140. * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
  4141. * registered node, it will call {@link #onContainerOver}.
  4142. * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
  4143. * @param {Event} e The event
  4144. * @param {Object} data An object containing arbitrary data supplied by the drag source
  4145. * @return {String} status The CSS class that communicates the drop status back to the source so that the
  4146. * underlying {@link Ext.dd.StatusProxy} can be updated
  4147. */
  4148. notifyOver : function(dd, e, data){
  4149. var n = this.getTargetFromEvent(e);
  4150. if(!n){ // not over valid drop target
  4151. if(this.lastOverNode){
  4152. this.onNodeOut(this.lastOverNode, dd, e, data);
  4153. this.lastOverNode = null;
  4154. }
  4155. return this.onContainerOver(dd, e, data);
  4156. }
  4157. if(this.lastOverNode != n){
  4158. if(this.lastOverNode){
  4159. this.onNodeOut(this.lastOverNode, dd, e, data);
  4160. }
  4161. this.onNodeEnter(n, dd, e, data);
  4162. this.lastOverNode = n;
  4163. }
  4164. return this.onNodeOver(n, dd, e, data);
  4165. },
  4166. /**
  4167. * The function a {@link Ext.dd.DragSource} calls once to notify this drop zone that the source has been dragged
  4168. * out of the zone without dropping. If the drag source is currently over a registered node, the notification
  4169. * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
  4170. * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target
  4171. * @param {Event} e The event
  4172. * @param {Object} data An object containing arbitrary data supplied by the drag zone
  4173. */
  4174. notifyOut : function(dd, e, data){
  4175. if(this.lastOverNode){
  4176. this.onNodeOut(this.lastOverNode, dd, e, data);
  4177. this.lastOverNode = null;
  4178. }
  4179. },
  4180. /**
  4181. * The function a {@link Ext.dd.DragSource} calls once to notify this drop zone that the dragged item has
  4182. * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
  4183. * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
  4184. * otherwise it will call {@link #onContainerDrop}.
  4185. * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
  4186. * @param {Event} e The event
  4187. * @param {Object} data An object containing arbitrary data supplied by the drag source
  4188. * @return {Boolean} True if the drop was valid, else false
  4189. */
  4190. notifyDrop : function(dd, e, data){
  4191. if(this.lastOverNode){
  4192. this.onNodeOut(this.lastOverNode, dd, e, data);
  4193. this.lastOverNode = null;
  4194. }
  4195. var n = this.getTargetFromEvent(e);
  4196. return n ?
  4197. this.onNodeDrop(n, dd, e, data) :
  4198. this.onContainerDrop(dd, e, data);
  4199. },
  4200. // private
  4201. triggerCacheRefresh : function(){
  4202. Ext.dd.DDM.refreshCache(this.groups);
  4203. }
  4204. });/**
  4205. * @class Ext.Element
  4206. */
  4207. Ext.Element.addMethods({
  4208. /**
  4209. * Initializes a {@link Ext.dd.DD} drag drop object for this element.
  4210. * @param {String} group The group the DD object is member of
  4211. * @param {Object} config The DD config object
  4212. * @param {Object} overrides An object containing methods to override/implement on the DD object
  4213. * @return {Ext.dd.DD} The DD object
  4214. */
  4215. initDD : function(group, config, overrides){
  4216. var dd = new Ext.dd.DD(Ext.id(this.dom), group, config);
  4217. return Ext.apply(dd, overrides);
  4218. },
  4219. /**
  4220. * Initializes a {@link Ext.dd.DDProxy} object for this element.
  4221. * @param {String} group The group the DDProxy object is member of
  4222. * @param {Object} config The DDProxy config object
  4223. * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
  4224. * @return {Ext.dd.DDProxy} The DDProxy object
  4225. */
  4226. initDDProxy : function(group, config, overrides){
  4227. var dd = new Ext.dd.DDProxy(Ext.id(this.dom), group, config);
  4228. return Ext.apply(dd, overrides);
  4229. },
  4230. /**
  4231. * Initializes a {@link Ext.dd.DDTarget} object for this element.
  4232. * @param {String} group The group the DDTarget object is member of
  4233. * @param {Object} config The DDTarget config object
  4234. * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
  4235. * @return {Ext.dd.DDTarget} The DDTarget object
  4236. */
  4237. initDDTarget : function(group, config, overrides){
  4238. var dd = new Ext.dd.DDTarget(Ext.id(this.dom), group, config);
  4239. return Ext.apply(dd, overrides);
  4240. }
  4241. });