diff options
Diffstat (limited to 'contexts/data/lib/closure-library/closure/goog/fx/draglistgroup.js')
-rw-r--r-- | contexts/data/lib/closure-library/closure/goog/fx/draglistgroup.js | 1268 |
1 files changed, 0 insertions, 1268 deletions
diff --git a/contexts/data/lib/closure-library/closure/goog/fx/draglistgroup.js b/contexts/data/lib/closure-library/closure/goog/fx/draglistgroup.js deleted file mode 100644 index 6f36719..0000000 --- a/contexts/data/lib/closure-library/closure/goog/fx/draglistgroup.js +++ /dev/null @@ -1,1268 +0,0 @@ -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A DragListGroup is a class representing a group of one or more - * "drag lists" with items that can be dragged within them and between them. - * - * @see ../demos/draglistgroup.html - */ - - -goog.provide('goog.fx.DragListDirection'); -goog.provide('goog.fx.DragListGroup'); -goog.provide('goog.fx.DragListGroup.EventType'); -goog.provide('goog.fx.DragListGroupEvent'); - -goog.require('goog.asserts'); -goog.require('goog.dom'); -goog.require('goog.dom.NodeType'); -goog.require('goog.dom.classes'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventHandler'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('goog.fx.Dragger'); -goog.require('goog.fx.Dragger.EventType'); -goog.require('goog.math.Coordinate'); -goog.require('goog.style'); - - - -/** - * A class representing a group of one or more "drag lists" with items that can - * be dragged within them and between them. - * - * Example usage: - * var dragListGroup = new goog.fx.DragListGroup(); - * dragListGroup.setDragItemHandleHoverClass(className1, className2); - * dragListGroup.setDraggerElClass(className3); - * dragListGroup.addDragList(vertList, goog.fx.DragListDirection.DOWN); - * dragListGroup.addDragList(horizList, goog.fx.DragListDirection.RIGHT); - * dragListGroup.init(); - * - * @extends {goog.events.EventTarget} - * @constructor - */ -goog.fx.DragListGroup = function() { - goog.events.EventTarget.call(this); - - /** - * The drag lists. - * @type {Array.<Element>} - * @private - */ - this.dragLists_ = []; - - /** - * All the drag items. Set by init(). - * @type {Array.<Element>} - * @private - */ - this.dragItems_ = []; - - /** - * Which drag item corresponds to a given handle. Set by init(). - * Specifically, this maps from the unique ID (as given by goog.getUid) - * of the handle to the drag item. - * @type {Object} - * @private - */ - this.dragItemForHandle_ = {}; - - /** - * The event handler for this instance. - * @type {goog.events.EventHandler} - * @private - */ - this.eventHandler_ = new goog.events.EventHandler(this); - - /** - * Whether the setup has been done to make all items in all lists draggable. - * @type {boolean} - * @private - */ - this.isInitialized_ = false; - - /** - * Whether the currDragItem is always displayed. By default the list - * collapses, the currDragItem's display is set to none, when we do not - * hover over a draglist. - * @type {boolean} - * @private - */ - this.isCurrDragItemAlwaysDisplayed_ = false; - - /** - * Whether to update the position of the currDragItem as we drag, i.e., - * insert the currDragItem each time to the position where it would land if - * we were to end the drag at that point. Defaults to true. - * @type {boolean} - * @private - */ - this.updateWhileDragging_ = true; -}; -goog.inherits(goog.fx.DragListGroup, goog.events.EventTarget); - - -/** - * Enum to indicate the direction that a drag list grows. - * @enum {number} - */ -goog.fx.DragListDirection = { - DOWN: 0, // common - RIGHT: 2, // common - LEFT: 3, // uncommon (except perhaps for right-to-left interfaces) - RIGHT_2D: 4, // common + handles multiple lines if items are wrapped - LEFT_2D: 5 // for rtl languages -}; - - -/** - * Events dispatched by this class. - * @type {Object} - */ -goog.fx.DragListGroup.EventType = { - BEFOREDRAGSTART: 'beforedragstart', - DRAGSTART: 'dragstart', - BEFOREDRAGMOVE: 'beforedragmove', - DRAGMOVE: 'dragmove', - BEFOREDRAGEND: 'beforedragend', - DRAGEND: 'dragend' -}; - - -// The next 4 are user-supplied CSS classes. - - -/** - * The user-supplied CSS classes to add to a drag item on hover (not during a - * drag action). - * @type {Array|undefined} - * @private - */ -goog.fx.DragListGroup.prototype.dragItemHoverClasses_; - - -/** - * The user-supplied CSS classes to add to a drag item handle on hover (not - * during a drag action). - * @type {Array|undefined} - * @private - */ -goog.fx.DragListGroup.prototype.dragItemHandleHoverClasses_; - - -/** - * The user-supplied CSS classes to add to the current drag item (during a drag - * action). - * @type {Array|undefined} - * @private - */ -goog.fx.DragListGroup.prototype.currDragItemClasses_; - - -/** - * The user-supplied CSS class to add to the clone of the current drag item - * that's actually being dragged around (during a drag action). - * @type {string|undefined} - * @private - */ -goog.fx.DragListGroup.prototype.draggerElClass_; - - -// The next 5 are info applicable during a drag action. - - -/** - * The current drag item being moved. - * Note: This is only defined while a drag action is happening. - * @type {Element} - * @private - */ -goog.fx.DragListGroup.prototype.currDragItem_; - - -/** - * The drag list that {@code this.currDragItem_} is currently hovering over, or - * null if it is not hovering over a list. - * @type {Element} - * @private - */ -goog.fx.DragListGroup.prototype.currHoverList_; - - -/** - * The original drag list that the current drag item came from. We need to - * remember this in case the user drops the item outside of any lists, in which - * case we return the item to its original location. - * Note: This is only defined while a drag action is happening. - * @type {Element} - * @private - */ -goog.fx.DragListGroup.prototype.origList_; - - -/** - * The original next item in the original list that the current drag item came - * from. We need to remember this in case the user drops the item outside of - * any lists, in which case we return the item to its original location. - * Note: This is only defined while a drag action is happening. - * @type {Element} - * @private - */ -goog.fx.DragListGroup.prototype.origNextItem_; - - -/** - * The current item in the list we are hovering over. We need to remember - * this in case we do not update the position of the current drag item while - * dragging (see {@code updateWhileDragging_}). In this case the current drag - * item will be inserted into the list before this element when the drag ends. - * @type {Element} - * @private - */ -goog.fx.DragListGroup.prototype.currHoverItem_; - - -/** - * The clone of the current drag item that's actually being dragged around. - * Note: This is only defined while a drag action is happening. - * @type {Element} - * @private - */ -goog.fx.DragListGroup.prototype.draggerEl_; - - -/** - * The dragger object. - * Note: This is only defined while a drag action is happening. - * @type {goog.fx.Dragger} - * @private - */ -goog.fx.DragListGroup.prototype.dragger_; - - -/** - * The amount of distance, in pixels, after which a mousedown or touchstart is - * considered a drag. - * @type {number} - * @private - */ -goog.fx.DragListGroup.prototype.hysteresisDistance_ = 0; - - -/** - * Sets the property of the currDragItem that it is always displayed in the - * list. - */ -goog.fx.DragListGroup.prototype.setIsCurrDragItemAlwaysDisplayed = function() { - this.isCurrDragItemAlwaysDisplayed_ = true; -}; - - -/** - * Sets the private property updateWhileDragging_ to false. This disables the - * update of the position of the currDragItem while dragging. It will only be - * placed to its new location once the drag ends. - */ -goog.fx.DragListGroup.prototype.setNoUpdateWhileDragging = function() { - this.updateWhileDragging_ = false; -}; - - -/** - * Sets the distance the user has to drag the element before a drag operation - * is started. - * @param {number} distance The number of pixels after which a mousedown and - * move is considered a drag. - */ -goog.fx.DragListGroup.prototype.setHysteresis = function(distance) { - this.hysteresisDistance_ = distance; -}; - - -/** - * @return {number} distance The number of pixels after which a mousedown and - * move is considered a drag. - */ -goog.fx.DragListGroup.prototype.getHysteresis = function() { - return this.hysteresisDistance_; -}; - - -/** - * Adds a drag list to this DragListGroup. - * All calls to this method must happen before the call to init(). - * Remember that all child nodes (except text nodes) will be made draggable to - * any other drag list in this group. - * - * @param {Element} dragListElement Must be a container for a list of items - * that should all be made draggable. - * @param {goog.fx.DragListDirection} growthDirection The direction that this - * drag list grows in (i.e. if an item is appended to the DOM, the list's - * bounding box expands in this direction). - * @param {boolean=} opt_unused Unused argument. - * @param {string=} opt_dragHoverClass CSS class to apply to this drag list when - * the draggerEl hovers over it during a drag action. - */ -goog.fx.DragListGroup.prototype.addDragList = function( - dragListElement, growthDirection, opt_unused, opt_dragHoverClass) { - goog.asserts.assert(!this.isInitialized_); - - dragListElement.dlgGrowthDirection_ = growthDirection; - dragListElement.dlgDragHoverClass_ = opt_dragHoverClass; - this.dragLists_.push(dragListElement); -}; - - -/** - * Sets a user-supplied function used to get the "handle" element for a drag - * item. The function must accept exactly one argument. The argument may be - * any drag item element. - * - * If not set, the default implementation uses the whole drag item as the - * handle. - * - * @param {function(Element): Element} getHandleForDragItemFn A function that, - * given any drag item, returns a reference to its "handle" element - * (which may be the drag item element itself). - */ -goog.fx.DragListGroup.prototype.setFunctionToGetHandleForDragItem = function( - getHandleForDragItemFn) { - goog.asserts.assert(!this.isInitialized_); - this.getHandleForDragItem_ = getHandleForDragItemFn; -}; - - -/** - * Sets a user-supplied CSS class to add to a drag item on hover (not during a - * drag action). - * @param {...!string} var_args The CSS class or classes. - */ -goog.fx.DragListGroup.prototype.setDragItemHoverClass = function(var_args) { - goog.asserts.assert(!this.isInitialized_); - this.dragItemHoverClasses_ = goog.array.slice(arguments, 0); -}; - - -/** - * Sets a user-supplied CSS class to add to a drag item handle on hover (not - * during a drag action). - * @param {...!string} var_args The CSS class or classes. - */ -goog.fx.DragListGroup.prototype.setDragItemHandleHoverClass = function( - var_args) { - goog.asserts.assert(!this.isInitialized_); - this.dragItemHandleHoverClasses_ = goog.array.slice(arguments, 0); -}; - - -/** - * Sets a user-supplied CSS class to add to the current drag item (during a - * drag action). - * - * If not set, the default behavior adds visibility:hidden to the current drag - * item so that it is a block of empty space in the hover drag list (if any). - * If this class is set by the user, then the default behavior does not happen - * (unless, of course, the class also contains visibility:hidden). - * - * @param {...!string} var_args The CSS class or classes. - */ -goog.fx.DragListGroup.prototype.setCurrDragItemClass = function(var_args) { - goog.asserts.assert(!this.isInitialized_); - this.currDragItemClasses_ = goog.array.slice(arguments, 0); -}; - - -/** - * Sets a user-supplied CSS class to add to the clone of the current drag item - * that's actually being dragged around (during a drag action). - * @param {string} draggerElClass The CSS class. - */ -goog.fx.DragListGroup.prototype.setDraggerElClass = function(draggerElClass) { - goog.asserts.assert(!this.isInitialized_); - this.draggerElClass_ = draggerElClass; -}; - - -/** - * Performs the initial setup to make all items in all lists draggable. - */ -goog.fx.DragListGroup.prototype.init = function() { - if (this.isInitialized_) { - return; - } - - for (var i = 0, numLists = this.dragLists_.length; i < numLists; i++) { - var dragList = this.dragLists_[i]; - - var dragItems = goog.dom.getChildren(dragList); - for (var j = 0, numItems = dragItems.length; j < numItems; ++j) { - var dragItem = dragItems[j]; - var dragItemHandle = this.getHandleForDragItem_(dragItem); - - var uid = goog.getUid(dragItemHandle); - this.dragItemForHandle_[uid] = dragItem; - - if (this.dragItemHoverClasses_) { - this.eventHandler_.listen( - dragItem, goog.events.EventType.MOUSEOVER, - this.handleDragItemMouseover_); - this.eventHandler_.listen( - dragItem, goog.events.EventType.MOUSEOUT, - this.handleDragItemMouseout_); - } - if (this.dragItemHandleHoverClasses_) { - this.eventHandler_.listen( - dragItemHandle, goog.events.EventType.MOUSEOVER, - this.handleDragItemHandleMouseover_); - this.eventHandler_.listen( - dragItemHandle, goog.events.EventType.MOUSEOUT, - this.handleDragItemHandleMouseout_); - } - - this.dragItems_.push(dragItem); - this.eventHandler_.listen(dragItemHandle, - [goog.events.EventType.MOUSEDOWN, goog.events.EventType.TOUCHSTART], - this.handlePotentialDragStart_); - } - } - - this.isInitialized_ = true; -}; - - -/** @override */ -goog.fx.DragListGroup.prototype.disposeInternal = function() { - this.eventHandler_.dispose(); - - for (var i = 0, n = this.dragLists_.length; i < n; i++) { - var dragList = this.dragLists_[i]; - // Note: IE doesn't allow 'delete' for fields on HTML elements (because - // they're not real JS objects in IE), so we just set them to undefined. - dragList.dlgGrowthDirection_ = undefined; - dragList.dlgDragHoverClass_ = undefined; - } - - this.dragLists_.length = 0; - this.dragItems_.length = 0; - this.dragItemForHandle_ = null; - - // In the case where a drag event is currently in-progress and dispose is - // called, this cleans up the extra state. - this.cleanupDragDom_(); - - goog.fx.DragListGroup.superClass_.disposeInternal.call(this); -}; - - -/** - * Caches the heights of each drag list and drag item, except for the current - * drag item. - * - * @param {Element} currDragItem The item currently being dragged. - * @private - */ -goog.fx.DragListGroup.prototype.recacheListAndItemBounds_ = function( - currDragItem) { - for (var i = 0, n = this.dragLists_.length; i < n; i++) { - var dragList = this.dragLists_[i]; - dragList.dlgBounds_ = goog.style.getBounds(dragList); - } - - for (var i = 0, n = this.dragItems_.length; i < n; i++) { - var dragItem = this.dragItems_[i]; - if (dragItem != currDragItem) { - dragItem.dlgBounds_ = goog.style.getBounds(dragItem); - } - } -}; - - -/** - * Handles mouse and touch events which may start a drag action. - * @param {!goog.events.BrowserEvent} e MOUSEDOWN or TOUCHSTART event. - * @private - */ -goog.fx.DragListGroup.prototype.handlePotentialDragStart_ = function(e) { - var uid = goog.getUid(/** @type {Node} */ (e.currentTarget)); - this.currDragItem_ = /** @type {Element} */ (this.dragItemForHandle_[uid]); - - this.draggerEl_ = this.cloneNode_(this.currDragItem_); - if (this.draggerElClass_) { - // Add CSS class for the clone, if any. - goog.dom.classes.add(this.draggerEl_, this.draggerElClass_); - } - - // Place the clone (i.e. draggerEl) at the same position as the actual - // current drag item. This is a bit tricky since - // goog.style.getPageOffset() gets the left-top pos of the border, but - // goog.style.setPageOffset() sets the left-top pos of the margin. - // It's difficult to adjust for the margins of the clone because it's - // difficult to read it: goog.style.getComputedStyle() doesn't work for IE. - // Instead, our workaround is simply to set the clone's margins to 0px. - this.draggerEl_.style.margin = '0'; - this.draggerEl_.style.position = 'absolute'; - this.draggerEl_.style.visibility = 'hidden'; - var doc = goog.dom.getOwnerDocument(this.currDragItem_); - doc.body.appendChild(this.draggerEl_); - - // Important: goog.style.setPageOffset() only works correctly for IE when the - // element is already in the document. - var currDragItemPos = goog.style.getPageOffset(this.currDragItem_); - goog.style.setPageOffset(this.draggerEl_, currDragItemPos); - - this.dragger_ = new goog.fx.Dragger(this.draggerEl_); - this.dragger_.setHysteresis(this.hysteresisDistance_); - - // Listen to events on the dragger. These handlers will be unregistered at - // DRAGEND, when the dragger is disposed of. We can't use eventHandler_, - // because it creates new references to the handler functions at each - // dragging action, and keeps them until DragListGroup is disposed of. - goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.START, - this.handleDragStart_, false, this); - goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.END, - this.handleDragEnd_, false, this); - goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.EARLY_CANCEL, - this.cleanup_, false, this); - this.dragger_.startDrag(e); -}; - - -/** - * Handles the start of a drag action. - * @param {!goog.fx.DragEvent} e goog.fx.Dragger.EventType.START event. - * @private - */ -goog.fx.DragListGroup.prototype.handleDragStart_ = function(e) { - if (!this.dispatchEvent(new goog.fx.DragListGroupEvent( - goog.fx.DragListGroup.EventType.BEFOREDRAGSTART, this, e.browserEvent, - this.currDragItem_, null, null))) { - e.preventDefault(); - this.cleanup_(); - return; - } - - // Record the original location of the current drag item. - // Note: this.origNextItem_ may be null. - this.origList_ = /** @type {Element} */ (this.currDragItem_.parentNode); - this.origNextItem_ = goog.dom.getNextElementSibling(this.currDragItem_); - this.currHoverItem_ = this.origNextItem_; - this.currHoverList_ = this.origList_; - - // If there's a CSS class specified for the current drag item, add it. - // Otherwise, make the actual current drag item hidden (takes up space). - if (this.currDragItemClasses_) { - goog.dom.classes.add.apply(null, - goog.array.concat(this.currDragItem_, this.currDragItemClasses_)); - } else { - this.currDragItem_.style.visibility = 'hidden'; - } - - // Precompute distances from top-left corner to center for efficiency. - var draggerElSize = goog.style.getSize(this.draggerEl_); - this.draggerEl_.halfWidth = draggerElSize.width / 2; - this.draggerEl_.halfHeight = draggerElSize.height / 2; - - this.draggerEl_.style.visibility = ''; - - // Record the bounds of all the drag lists and all the other drag items. This - // caching is for efficiency, so that we don't have to recompute the bounds on - // each drag move. Do this in the state where the current drag item is not in - // any of the lists, except when update while dragging is disabled, as in this - // case the current drag item does not get removed until drag ends. - if (this.updateWhileDragging_) { - this.currDragItem_.style.display = 'none'; - } - this.recacheListAndItemBounds_(this.currDragItem_); - this.currDragItem_.style.display = ''; - - // Listen to events on the dragger. - goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.DRAG, - this.handleDragMove_, false, this); - - this.dispatchEvent( - new goog.fx.DragListGroupEvent( - goog.fx.DragListGroup.EventType.DRAGSTART, this, e.browserEvent, - this.currDragItem_, this.draggerEl_, this.dragger_)); -}; - - -/** - * Handles a drag movement (i.e. DRAG event fired by the dragger). - * - * @param {goog.fx.DragEvent} dragEvent Event object fired by the dragger. - * @return {boolean} The return value for the event. - * @private - */ -goog.fx.DragListGroup.prototype.handleDragMove_ = function(dragEvent) { - - // Compute the center of the dragger element (i.e. the cloned drag item). - var draggerElPos = goog.style.getPageOffset(this.draggerEl_); - var draggerElCenter = new goog.math.Coordinate( - draggerElPos.x + this.draggerEl_.halfWidth, - draggerElPos.y + this.draggerEl_.halfHeight); - - // Check whether the center is hovering over one of the drag lists. - var hoverList = this.getHoverDragList_(draggerElCenter); - - // If hovering over a list, find the next item (if drag were to end now). - var hoverNextItem = - hoverList ? this.getHoverNextItem_(hoverList, draggerElCenter) : null; - - var rv = this.dispatchEvent( - new goog.fx.DragListGroupEvent( - goog.fx.DragListGroup.EventType.BEFOREDRAGMOVE, this, dragEvent, - this.currDragItem_, this.draggerEl_, this.dragger_, - draggerElCenter, hoverList, hoverNextItem)); - if (!rv) { - return false; - } - - if (hoverList) { - if (this.updateWhileDragging_) { - this.insertCurrDragItem_(hoverList, hoverNextItem); - } else { - // If update while dragging is disabled do not insert - // the dragged item, but update the hovered item instead. - this.updateCurrHoverItem(hoverNextItem, draggerElCenter); - } - this.currDragItem_.style.display = ''; - // Add drag list's hover class (if any). - if (hoverList.dlgDragHoverClass_) { - goog.dom.classes.add(hoverList, hoverList.dlgDragHoverClass_); - } - - } else { - // Not hovering over a drag list, so remove the item altogether unless - // specified otherwise by the user. - if (!this.isCurrDragItemAlwaysDisplayed_) { - this.currDragItem_.style.display = 'none'; - } - - // Remove hover classes (if any) from all drag lists. - for (var i = 0, n = this.dragLists_.length; i < n; i++) { - var dragList = this.dragLists_[i]; - if (dragList.dlgDragHoverClass_) { - goog.dom.classes.remove(dragList, dragList.dlgDragHoverClass_); - } - } - } - - // If the current hover list is different than the last, the lists may have - // shrunk, so we should recache the bounds. - if (hoverList != this.currHoverList_) { - this.currHoverList_ = hoverList; - this.recacheListAndItemBounds_(this.currDragItem_); - } - - this.dispatchEvent( - new goog.fx.DragListGroupEvent( - goog.fx.DragListGroup.EventType.DRAGMOVE, this, dragEvent, - /** @type {Element} */ (this.currDragItem_), - this.draggerEl_, this.dragger_, - draggerElCenter, hoverList, hoverNextItem)); - - // Return false to prevent selection due to mouse drag. - return false; -}; - - -/** - * Clear all our temporary fields that are only defined while dragging, and - * all the bounds info stored on the drag lists and drag elements. - * @param {!goog.events.Event=} opt_e EARLY_CANCEL event from the dragger if - * cleanup_ was called as an event handler. - * @private - */ -goog.fx.DragListGroup.prototype.cleanup_ = function(opt_e) { - this.cleanupDragDom_(); - - this.currDragItem_ = null; - this.currHoverList_ = null; - this.origList_ = null; - this.origNextItem_ = null; - this.draggerEl_ = null; - this.dragger_ = null; - - // Note: IE doesn't allow 'delete' for fields on HTML elements (because - // they're not real JS objects in IE), so we just set them to null. - for (var i = 0, n = this.dragLists_.length; i < n; i++) { - this.dragLists_[i].dlgBounds_ = null; - } - for (var i = 0, n = this.dragItems_.length; i < n; i++) { - this.dragItems_[i].dlgBounds_ = null; - } -}; - - -/** - * Handles the end or the cancellation of a drag action, i.e. END or CLEANUP - * event fired by the dragger. - * - * @param {!goog.fx.DragEvent} dragEvent Event object fired by the dragger. - * @return {boolean} Whether the event was handled. - * @private - */ -goog.fx.DragListGroup.prototype.handleDragEnd_ = function(dragEvent) { - var rv = this.dispatchEvent( - new goog.fx.DragListGroupEvent( - goog.fx.DragListGroup.EventType.BEFOREDRAGEND, this, dragEvent, - /** @type {Element} */ (this.currDragItem_), - this.draggerEl_, this.dragger_)); - if (!rv) { - return false; - } - - // If update while dragging is disabled insert the current drag item into - // its intended location. - if (!this.updateWhileDragging_) { - this.insertCurrHoverItem(); - } - - // The DRAGEND handler may need the new order of the list items. Clean up the - // garbage. - // TODO(user): Regression test. - this.cleanupDragDom_(); - - this.dispatchEvent( - new goog.fx.DragListGroupEvent( - goog.fx.DragListGroup.EventType.DRAGEND, this, dragEvent, - this.currDragItem_, this.draggerEl_, this.dragger_)); - - this.cleanup_(); - - return true; -}; - - -/** - * Cleans up DOM changes that are made by the {@code handleDrag*} methods. - * @private - */ -goog.fx.DragListGroup.prototype.cleanupDragDom_ = function() { - // Disposes of the dragger and remove the cloned drag item. - goog.dispose(this.dragger_); - if (this.draggerEl_) { - goog.dom.removeNode(this.draggerEl_); - } - - // If the current drag item is not in any list, put it back in its original - // location. - if (this.currDragItem_ && this.currDragItem_.style.display == 'none') { - // Note: this.origNextItem_ may be null, but insertBefore() still works. - this.origList_.insertBefore(this.currDragItem_, this.origNextItem_); - this.currDragItem_.style.display = ''; - } - - // If there's a CSS class specified for the current drag item, remove it. - // Otherwise, make the current drag item visible (instead of empty space). - if (this.currDragItemClasses_ && this.currDragItem_) { - goog.dom.classes.remove.apply(null, - goog.array.concat(this.currDragItem_, this.currDragItemClasses_)); - } else if (this.currDragItem_) { - this.currDragItem_.style.visibility = 'visible'; - } - - // Remove hover classes (if any) from all drag lists. - for (var i = 0, n = this.dragLists_.length; i < n; i++) { - var dragList = this.dragLists_[i]; - if (dragList.dlgDragHoverClass_) { - goog.dom.classes.remove(dragList, dragList.dlgDragHoverClass_); - } - } -}; - - -/** - * Default implementation of the function to get the "handle" element for a - * drag item. By default, we use the whole drag item as the handle. Users can - * change this by calling setFunctionToGetHandleForDragItem(). - * - * @param {Element} dragItem The drag item to get the handle for. - * @return {Element} The dragItem element itself. - * @private - */ -goog.fx.DragListGroup.prototype.getHandleForDragItem_ = function(dragItem) { - return dragItem; -}; - - -/** - * Handles a MOUSEOVER event fired on a drag item. - * @param {goog.events.BrowserEvent} e The event. - * @private - */ -goog.fx.DragListGroup.prototype.handleDragItemMouseover_ = function(e) { - goog.dom.classes.add.apply(null, - goog.array.concat(/** @type {Element} */ (e.currentTarget), - this.dragItemHoverClasses_)); -}; - - -/** - * Handles a MOUSEOUT event fired on a drag item. - * @param {goog.events.BrowserEvent} e The event. - * @private - */ -goog.fx.DragListGroup.prototype.handleDragItemMouseout_ = function(e) { - goog.dom.classes.remove.apply(null, - goog.array.concat(/** @type {Element} */ (e.currentTarget), - this.dragItemHoverClasses_)); -}; - - -/** - * Handles a MOUSEOVER event fired on the handle element of a drag item. - * @param {goog.events.BrowserEvent} e The event. - * @private - */ -goog.fx.DragListGroup.prototype.handleDragItemHandleMouseover_ = function(e) { - goog.dom.classes.add.apply(null, - goog.array.concat(/** @type {Element} */ (e.currentTarget), - this.dragItemHandleHoverClasses_)); -}; - - -/** - * Handles a MOUSEOUT event fired on the handle element of a drag item. - * @param {goog.events.BrowserEvent} e The event. - * @private - */ -goog.fx.DragListGroup.prototype.handleDragItemHandleMouseout_ = function(e) { - goog.dom.classes.remove.apply(null, - goog.array.concat(/** @type {Element} */ (e.currentTarget), - this.dragItemHandleHoverClasses_)); -}; - - -/** - * Helper for handleDragMove_(). - * Given the position of the center of the dragger element, figures out whether - * it's currently hovering over any of the drag lists. - * - * @param {goog.math.Coordinate} draggerElCenter The center position of the - * dragger element. - * @return {Element} If currently hovering over a drag list, returns the drag - * list element. Else returns null. - * @private - */ -goog.fx.DragListGroup.prototype.getHoverDragList_ = function(draggerElCenter) { - - // If the current drag item was in a list last time we did this, then check - // that same list first. - var prevHoverList = null; - if (this.currDragItem_.style.display != 'none') { - prevHoverList = /** @type {Element} */ (this.currDragItem_.parentNode); - // Important: We can't use the cached bounds for this list because the - // cached bounds are based on the case where the current drag item is not - // in the list. Since the current drag item is known to be in this list, we - // must recompute the list's bounds. - var prevHoverListBounds = goog.style.getBounds(prevHoverList); - if (this.isInRect_(draggerElCenter, prevHoverListBounds)) { - return prevHoverList; - } - } - - for (var i = 0, n = this.dragLists_.length; i < n; i++) { - var dragList = this.dragLists_[i]; - if (dragList == prevHoverList) { - continue; - } - if (this.isInRect_(draggerElCenter, dragList.dlgBounds_)) { - return dragList; - } - } - - return null; -}; - - -/** - * Checks whether a coordinate position resides inside a rectangle. - * @param {goog.math.Coordinate} pos The coordinate position. - * @param {goog.math.Rect} rect The rectangle. - * @return {boolean} True if 'pos' is within the bounds of 'rect'. - * @private - */ -goog.fx.DragListGroup.prototype.isInRect_ = function(pos, rect) { - return pos.x > rect.left && pos.x < rect.left + rect.width && - pos.y > rect.top && pos.y < rect.top + rect.height; -}; - - -/** - * Updates the value of currHoverItem_. - * - * This method is used for insertion only when updateWhileDragging_ is false. - * The below implementation is the basic one. This method can be extended by - * a subclass to support changes to hovered item (eg: highlighting). Parametr - * opt_draggerElCenter can be used for more sophisticated effects. - * - * @param {Element} hoverNextItem element of the list that is hovered over. - * @param {goog.math.Coordinate=} opt_draggerElCenter current position of - * the dragged element. - * @protected - */ -goog.fx.DragListGroup.prototype.updateCurrHoverItem = function( - hoverNextItem, opt_draggerElCenter) { - if (hoverNextItem) { - this.currHoverItem_ = hoverNextItem; - } -}; - - -/** - * Inserts the currently dragged item in its new place. - * - * This method is used for insertion only when updateWhileDragging_ is false - * (otherwise there is no need for that). In the basic implementation - * the element is inserted before the currently hovered over item (this can - * be changed by overriding the method in subclasses). - * - * @protected - */ -goog.fx.DragListGroup.prototype.insertCurrHoverItem = function() { - this.origList_.insertBefore(this.currDragItem_, this.currHoverItem_); -}; - - -/** - * Helper for handleDragMove_(). - * Given the position of the center of the dragger element, plus the drag list - * that it's currently hovering over, figures out the next drag item in the - * list that follows the current position of the dragger element. (I.e. if - * the drag action ends right now, it would become the item after the current - * drag item.) - * - * @param {Element} hoverList The drag list that we're hovering over. - * @param {goog.math.Coordinate} draggerElCenter The center position of the - * dragger element. - * @return {Element} Returns the earliest item in the hover list that belongs - * after the current position of the dragger element. If all items in the - * list should come before the current drag item, then returns null. - * @private - */ -goog.fx.DragListGroup.prototype.getHoverNextItem_ = function( - hoverList, draggerElCenter) { - if (hoverList == null) { - throw Error('getHoverNextItem_ called with null hoverList.'); - } - - // The definition of what it means for the draggerEl to be "before" a given - // item in the hover drag list is not always the same. It changes based on - // the growth direction of the hover drag list in question. - /** @type {number} */ - var relevantCoord; - var getRelevantBoundFn; - var isBeforeFn; - var pickClosestRow = false; - var distanceToClosestRow = undefined; - switch (hoverList.dlgGrowthDirection_) { - case goog.fx.DragListDirection.DOWN: - // "Before" means draggerElCenter.y is less than item's bottom y-value. - relevantCoord = draggerElCenter.y; - getRelevantBoundFn = goog.fx.DragListGroup.getBottomBound_; - isBeforeFn = goog.fx.DragListGroup.isLessThan_; - break; - case goog.fx.DragListDirection.RIGHT_2D: - pickClosestRow = true; - case goog.fx.DragListDirection.RIGHT: - // "Before" means draggerElCenter.x is less than item's right x-value. - relevantCoord = draggerElCenter.x; - getRelevantBoundFn = goog.fx.DragListGroup.getRightBound_; - isBeforeFn = goog.fx.DragListGroup.isLessThan_; - break; - case goog.fx.DragListDirection.LEFT_2D: - pickClosestRow = true; - case goog.fx.DragListDirection.LEFT: - // "Before" means draggerElCenter.x is greater than item's left x-value. - relevantCoord = draggerElCenter.x; - getRelevantBoundFn = goog.fx.DragListGroup.getLeftBound_; - isBeforeFn = goog.fx.DragListGroup.isGreaterThan_; - break; - } - - // This holds the earliest drag item found so far that should come after - // this.currDragItem_ in the hover drag list (based on draggerElCenter). - var earliestAfterItem = null; - // This is the position of the relevant bound for the earliestAfterItem, - // where "relevant" is determined by the growth direction of hoverList. - var earliestAfterItemRelevantBound; - - var hoverListItems = goog.dom.getChildren(hoverList); - for (var i = 0, n = hoverListItems.length; i < n; i++) { - var item = hoverListItems[i]; - if (item == this.currDragItem_) { - continue; - } - - var relevantBound = getRelevantBoundFn(item.dlgBounds_); - // When the hoverlist is broken into multiple rows (i.e., in the case of - // LEFT_2D and RIGHT_2D) it is no longer enough to only look at the - // x-coordinate alone in order to find the {@earliestAfterItem} in the - // hoverlist. Make sure it is chosen from the row closest to the - // {@code draggerElCenter}. - if (pickClosestRow) { - var distanceToRow = goog.fx.DragListGroup.verticalDistanceFromItem_(item, - draggerElCenter); - // Initialize the distance to the closest row to the current value if - // undefined. - if (!goog.isDef(distanceToClosestRow)) { - distanceToClosestRow = distanceToRow; - } - if (isBeforeFn(relevantCoord, relevantBound) && - (earliestAfterItemRelevantBound == undefined || - (distanceToRow < distanceToClosestRow) || - ((distanceToRow == distanceToClosestRow) && - (isBeforeFn(relevantBound, earliestAfterItemRelevantBound) || - relevantBound == earliestAfterItemRelevantBound)))) { - earliestAfterItem = item; - earliestAfterItemRelevantBound = relevantBound; - } - // Update distance to closest row. - if (distanceToRow < distanceToClosestRow) { - distanceToClosestRow = distanceToRow; - } - } else if (isBeforeFn(relevantCoord, relevantBound) && - (earliestAfterItemRelevantBound == undefined || - isBeforeFn(relevantBound, earliestAfterItemRelevantBound))) { - earliestAfterItem = item; - earliestAfterItemRelevantBound = relevantBound; - } - } - // If we ended up picking an element that is not in the closest row it can - // only happen if we should have picked the last one in which case there is - // no consecutive element. - if (!goog.isNull(earliestAfterItem) && - goog.fx.DragListGroup.verticalDistanceFromItem_( - earliestAfterItem, draggerElCenter) > distanceToClosestRow) { - return null; - } else { - return earliestAfterItem; - } -}; - - -/** - * Private helper for getHoverNextItem(). - * Given an item and a target determine the vertical distance from the item's - * center to the target. - * @param {Element} item The item to measure the distance from. - * @param {goog.math.Coordinate} target The (x,y) coordinate of the target - * to measure the distance to. - * @return {number} The vertical distance between the center of the item and - * the target. - * @private - */ -goog.fx.DragListGroup.verticalDistanceFromItem_ = function(item, target) { - var itemBounds = item.dlgBounds_; - var itemCenterY = itemBounds.top + (itemBounds.height - 1) / 2; - return Math.abs(target.y - itemCenterY); -}; - - -/** - * Private helper for getHoverNextItem_(). - * Given the bounds of an item, computes the item's bottom y-value. - * @param {goog.math.Rect} itemBounds The bounds of the item. - * @return {number} The item's bottom y-value. - * @private - */ -goog.fx.DragListGroup.getBottomBound_ = function(itemBounds) { - return itemBounds.top + itemBounds.height - 1; -}; - - -/** - * Private helper for getHoverNextItem_(). - * Given the bounds of an item, computes the item's right x-value. - * @param {goog.math.Rect} itemBounds The bounds of the item. - * @return {number} The item's right x-value. - * @private - */ -goog.fx.DragListGroup.getRightBound_ = function(itemBounds) { - return itemBounds.left + itemBounds.width - 1; -}; - - -/** - * Private helper for getHoverNextItem_(). - * Given the bounds of an item, computes the item's left x-value. - * @param {goog.math.Rect} itemBounds The bounds of the item. - * @return {number} The item's left x-value. - * @private - */ -goog.fx.DragListGroup.getLeftBound_ = function(itemBounds) { - return itemBounds.left || 0; -}; - - -/** - * Private helper for getHoverNextItem_(). - * @param {number} a Number to compare. - * @param {number} b Number to compare. - * @return {boolean} Whether a is less than b. - * @private - */ -goog.fx.DragListGroup.isLessThan_ = function(a, b) { - return a < b; -}; - - -/** - * Private helper for getHoverNextItem_(). - * @param {number} a Number to compare. - * @param {number} b Number to compare. - * @return {boolean} Whether a is greater than b. - * @private - */ -goog.fx.DragListGroup.isGreaterThan_ = function(a, b) { - return a > b; -}; - - -/** - * Inserts the current drag item to the appropriate location in the drag list - * that we're hovering over (if the current drag item is not already there). - * - * @param {Element} hoverList The drag list we're hovering over. - * @param {Element} hoverNextItem The next item in the hover drag list. - * @private - */ -goog.fx.DragListGroup.prototype.insertCurrDragItem_ = function( - hoverList, hoverNextItem) { - if (this.currDragItem_.parentNode != hoverList || - goog.dom.getNextElementSibling(this.currDragItem_) != hoverNextItem) { - // The current drag item is not in the correct location, so we move it. - // Note: hoverNextItem may be null, but insertBefore() still works. - hoverList.insertBefore(this.currDragItem_, hoverNextItem); - } -}; - - -/** - * Note: Copied from abstractdragdrop.js. TODO(user): consolidate. - * Creates copy of node being dragged. - * - * @param {Element} sourceEl Element to copy. - * @return {Element} The clone of {@code sourceEl}. - * @private - */ -goog.fx.DragListGroup.prototype.cloneNode_ = function(sourceEl) { - var clonedEl = /** @type {Element} */ (sourceEl.cloneNode(true)); - switch (sourceEl.tagName.toLowerCase()) { - case 'tr': - return goog.dom.createDom( - 'table', null, goog.dom.createDom('tbody', null, clonedEl)); - case 'td': - case 'th': - return goog.dom.createDom( - 'table', null, goog.dom.createDom('tbody', null, goog.dom.createDom( - 'tr', null, clonedEl))); - default: - return clonedEl; - } -}; - - - -/** - * The event object dispatched by DragListGroup. - * The fields draggerElCenter, hoverList, and hoverNextItem are only available - * for the BEFOREDRAGMOVE and DRAGMOVE events. - * - * @param {string} type The event type string. - * @param {goog.fx.DragListGroup} dragListGroup A reference to the associated - * DragListGroup object. - * @param {goog.events.BrowserEvent|goog.fx.DragEvent} event The event fired - * by the browser or fired by the dragger. - * @param {Element} currDragItem The current drag item being moved. - * @param {Element} draggerEl The clone of the current drag item that's actually - * being dragged around. - * @param {goog.fx.Dragger} dragger The dragger object. - * @param {goog.math.Coordinate=} opt_draggerElCenter The current center - * position of the draggerEl. - * @param {Element=} opt_hoverList The current drag list that's being hovered - * over, or null if the center of draggerEl is outside of any drag lists. - * If not null and the drag action ends right now, then currDragItem will - * end up in this list. - * @param {Element=} opt_hoverNextItem The current next item in the hoverList - * that the draggerEl is hovering over. (I.e. If the drag action ends - * right now, then this item would become the next item after the new - * location of currDragItem.) May be null if not applicable or if - * currDragItem would be added to the end of hoverList. - * @constructor - * @extends {goog.events.Event} - */ -goog.fx.DragListGroupEvent = function( - type, dragListGroup, event, currDragItem, draggerEl, dragger, - opt_draggerElCenter, opt_hoverList, opt_hoverNextItem) { - goog.events.Event.call(this, type); - - /** - * A reference to the associated DragListGroup object. - * @type {goog.fx.DragListGroup} - */ - this.dragListGroup = dragListGroup; - - /** - * The event fired by the browser or fired by the dragger. - * @type {goog.events.BrowserEvent|goog.fx.DragEvent} - */ - this.event = event; - - /** - * The current drag item being move. - * @type {Element} - */ - this.currDragItem = currDragItem; - - /** - * The clone of the current drag item that's actually being dragged around. - * @type {Element} - */ - this.draggerEl = draggerEl; - - /** - * The dragger object. - * @type {goog.fx.Dragger} - */ - this.dragger = dragger; - - /** - * The current center position of the draggerEl. - * @type {goog.math.Coordinate|undefined} - */ - this.draggerElCenter = opt_draggerElCenter; - - /** - * The current drag list that's being hovered over, or null if the center of - * draggerEl is outside of any drag lists. (I.e. If not null and the drag - * action ends right now, then currDragItem will end up in this list.) - * @type {Element|undefined} - */ - this.hoverList = opt_hoverList; - - /** - * The current next item in the hoverList that the draggerEl is hovering over. - * (I.e. If the drag action ends right now, then this item would become the - * next item after the new location of currDragItem.) May be null if not - * applicable or if currDragItem would be added to the end of hoverList. - * @type {Element|undefined} - */ - this.hoverNextItem = opt_hoverNextItem; -}; -goog.inherits(goog.fx.DragListGroupEvent, goog.events.Event); |