Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/fx/draglistgroup.js
2868 views
1
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview A DragListGroup is a class representing a group of one or more
17
* "drag lists" with items that can be dragged within them and between them.
18
*
19
* @see ../demos/draglistgroup.html
20
*/
21
22
23
goog.provide('goog.fx.DragListDirection');
24
goog.provide('goog.fx.DragListGroup');
25
goog.provide('goog.fx.DragListGroup.EventType');
26
goog.provide('goog.fx.DragListGroupEvent');
27
28
goog.require('goog.array');
29
goog.require('goog.asserts');
30
goog.require('goog.dom');
31
goog.require('goog.dom.classlist');
32
goog.require('goog.events');
33
goog.require('goog.events.Event');
34
goog.require('goog.events.EventHandler');
35
goog.require('goog.events.EventId');
36
goog.require('goog.events.EventTarget');
37
goog.require('goog.events.EventType');
38
goog.require('goog.fx.Dragger');
39
goog.require('goog.math.Coordinate');
40
goog.require('goog.string');
41
goog.require('goog.style');
42
43
44
45
/**
46
* A class representing a group of one or more "drag lists" with items that can
47
* be dragged within them and between them.
48
*
49
* Example usage:
50
* var dragListGroup = new goog.fx.DragListGroup();
51
* dragListGroup.setDragItemHandleHoverClass(className1, className2);
52
* dragListGroup.setDraggerElClass(className3);
53
* dragListGroup.addDragList(vertList, goog.fx.DragListDirection.DOWN);
54
* dragListGroup.addDragList(horizList, goog.fx.DragListDirection.RIGHT);
55
* dragListGroup.init();
56
*
57
* @extends {goog.events.EventTarget}
58
* @constructor
59
* @struct
60
*/
61
goog.fx.DragListGroup = function() {
62
goog.fx.DragListGroup.base(this, 'constructor');
63
64
/**
65
* The user-supplied CSS classes to add to a drag item on hover (not during a
66
* drag action).
67
* @private {Array|undefined}
68
*/
69
this.dragItemHoverClasses_;
70
71
/**
72
* The user-supplied CSS classes to add to a drag item handle on hover (not
73
* during a drag action).
74
* @private {Array|undefined}
75
*/
76
this.dragItemHandleHoverClasses_;
77
78
/**
79
* The user-supplied CSS classes to add to the current drag item (during a
80
* drag action).
81
* @private {Array|undefined}
82
*/
83
this.currDragItemClasses_;
84
85
/**
86
* The user-supplied CSS classes to add to the clone of the current drag item
87
* that's actually being dragged around (during a drag action).
88
* @private {Array<string>|undefined}
89
*/
90
this.draggerElClasses_;
91
92
/**
93
* The current drag item being moved.
94
* Note: This is only defined while a drag action is happening.
95
* @private {Element}
96
*/
97
this.currDragItem_;
98
99
/**
100
* The drag list that {@code this.currDragItem_} is currently hovering over,
101
* or null if it is not hovering over a list.
102
* @private {Element}
103
*/
104
this.currHoverList_;
105
106
/**
107
* The original drag list that the current drag item came from. We need to
108
* remember this in case the user drops the item outside of any lists, in
109
* which case we return the item to its original location.
110
* Note: This is only defined while a drag action is happening.
111
* @private {Element}
112
*/
113
this.origList_;
114
115
/**
116
* The original next item in the original list that the current drag item came
117
* from. We need to remember this in case the user drops the item outside of
118
* any lists, in which case we return the item to its original location.
119
* Note: This is only defined while a drag action is happening.
120
* @private {Element}
121
*/
122
this.origNextItem_;
123
124
/**
125
* The current item in the list we are hovering over. We need to remember
126
* this in case we do not update the position of the current drag item while
127
* dragging (see {@code updateWhileDragging_}). In this case the current drag
128
* item will be inserted into the list before this element when the drag ends.
129
* @private {Element}
130
*/
131
this.currHoverItem_;
132
133
/**
134
* The clone of the current drag item that's actually being dragged around.
135
* Note: This is only defined while a drag action is happening.
136
* @private {HTMLElement}
137
*/
138
this.draggerEl_;
139
140
/**
141
* The dragger object.
142
* Note: This is only defined while a drag action is happening.
143
* @private {goog.fx.Dragger}
144
*/
145
this.dragger_;
146
147
/**
148
* The amount of distance, in pixels, after which a mousedown or touchstart is
149
* considered a drag.
150
* @private {number}
151
*/
152
this.hysteresisDistance_ = 0;
153
154
155
/**
156
* The drag lists.
157
* @private {Array<Element>}
158
*/
159
this.dragLists_ = [];
160
161
/**
162
* All the drag items. Set by init().
163
* @private {Array<Element>}
164
*/
165
this.dragItems_ = [];
166
167
/**
168
* Which drag item corresponds to a given handle. Set by init().
169
* Specifically, this maps from the unique ID (as given by goog.getUid)
170
* of the handle to the drag item.
171
* @private {Object}
172
*/
173
this.dragItemForHandle_ = {};
174
175
/**
176
* The event handler for this instance.
177
* @private {goog.events.EventHandler<!goog.fx.DragListGroup>}
178
*/
179
this.eventHandler_ = new goog.events.EventHandler(this);
180
181
/**
182
* Whether the setup has been done to make all items in all lists draggable.
183
* @private {boolean}
184
*/
185
this.isInitialized_ = false;
186
187
/**
188
* Whether the currDragItem is always displayed. By default the list
189
* collapses, the currDragItem's display is set to none, when we do not
190
* hover over a draglist.
191
* @private {boolean}
192
*/
193
this.isCurrDragItemAlwaysDisplayed_ = false;
194
195
/**
196
* Whether to update the position of the currDragItem as we drag, i.e.,
197
* insert the currDragItem each time to the position where it would land if
198
* we were to end the drag at that point. Defaults to true.
199
* @private {boolean}
200
*/
201
this.updateWhileDragging_ = true;
202
};
203
goog.inherits(goog.fx.DragListGroup, goog.events.EventTarget);
204
205
206
/**
207
* Enum to indicate the direction that a drag list grows.
208
* @enum {number}
209
*/
210
goog.fx.DragListDirection = {
211
DOWN: 0, // common
212
RIGHT: 2, // common
213
LEFT: 3, // uncommon (except perhaps for right-to-left interfaces)
214
RIGHT_2D: 4, // common + handles multiple lines if items are wrapped
215
LEFT_2D: 5 // for rtl languages
216
};
217
218
219
/**
220
* Events dispatched by this class.
221
* @enum {!goog.events.EventId<!goog.fx.DragListGroupEvent>}
222
*/
223
goog.fx.DragListGroup.EventType = {
224
BEFOREDRAGSTART: new goog.events.EventId('beforedragstart'),
225
DRAGSTART: new goog.events.EventId('dragstart'),
226
BEFOREDRAGMOVE: new goog.events.EventId('beforedragmove'),
227
DRAGMOVE: new goog.events.EventId('dragmove'),
228
BEFOREDRAGEND: new goog.events.EventId('beforedragend'),
229
DRAGEND: new goog.events.EventId('dragend')
230
};
231
232
233
/**
234
* Sets the property of the currDragItem that it is always displayed in the
235
* list.
236
*/
237
goog.fx.DragListGroup.prototype.setIsCurrDragItemAlwaysDisplayed = function() {
238
this.isCurrDragItemAlwaysDisplayed_ = true;
239
};
240
241
242
/**
243
* Sets the private property updateWhileDragging_ to false. This disables the
244
* update of the position of the currDragItem while dragging. It will only be
245
* placed to its new location once the drag ends.
246
*/
247
goog.fx.DragListGroup.prototype.setNoUpdateWhileDragging = function() {
248
this.updateWhileDragging_ = false;
249
};
250
251
252
/**
253
* Sets the distance the user has to drag the element before a drag operation
254
* is started.
255
* @param {number} distance The number of pixels after which a mousedown and
256
* move is considered a drag.
257
*/
258
goog.fx.DragListGroup.prototype.setHysteresis = function(distance) {
259
this.hysteresisDistance_ = distance;
260
};
261
262
263
/**
264
* @return {number} distance The number of pixels after which a mousedown and
265
* move is considered a drag.
266
*/
267
goog.fx.DragListGroup.prototype.getHysteresis = function() {
268
return this.hysteresisDistance_;
269
};
270
271
272
/** @return {boolean} true if the user is currently dragging an element. */
273
goog.fx.DragListGroup.prototype.isDragging = function() {
274
return !!this.dragger_;
275
};
276
277
278
/**
279
* Adds a drag list to this DragListGroup.
280
* All calls to this method must happen before the call to init().
281
* Remember that all child nodes (except text nodes) will be made draggable to
282
* any other drag list in this group.
283
*
284
* @param {Element} dragListElement Must be a container for a list of items
285
* that should all be made draggable.
286
* @param {goog.fx.DragListDirection} growthDirection The direction that this
287
* drag list grows in (i.e. if an item is appended to the DOM, the list's
288
* bounding box expands in this direction).
289
* @param {boolean=} opt_unused Unused argument.
290
* @param {string=} opt_dragHoverClass CSS class to apply to this drag list when
291
* the draggerEl hovers over it during a drag action. If present, must be a
292
* single, valid classname (not a string of space-separated classnames).
293
*/
294
goog.fx.DragListGroup.prototype.addDragList = function(
295
dragListElement, growthDirection, opt_unused, opt_dragHoverClass) {
296
goog.asserts.assert(!this.isInitialized_);
297
298
dragListElement.dlgGrowthDirection_ = growthDirection;
299
dragListElement.dlgDragHoverClass_ = opt_dragHoverClass;
300
this.dragLists_.push(dragListElement);
301
};
302
303
304
/**
305
* Sets a user-supplied function used to get the "handle" element for a drag
306
* item. The function must accept exactly one argument. The argument may be
307
* any drag item element.
308
*
309
* If not set, the default implementation uses the whole drag item as the
310
* handle.
311
*
312
* @param {function(!Element): Element} getHandleForDragItemFn A function that,
313
* given any drag item, returns a reference to its "handle" element
314
* (which may be the drag item element itself).
315
*/
316
goog.fx.DragListGroup.prototype.setFunctionToGetHandleForDragItem = function(
317
getHandleForDragItemFn) {
318
goog.asserts.assert(!this.isInitialized_);
319
this.getHandleForDragItem_ = getHandleForDragItemFn;
320
};
321
322
323
/**
324
* Sets a user-supplied CSS class to add to a drag item on hover (not during a
325
* drag action).
326
* @param {...string} var_args The CSS class or classes.
327
*/
328
goog.fx.DragListGroup.prototype.setDragItemHoverClass = function(var_args) {
329
goog.asserts.assert(!this.isInitialized_);
330
this.dragItemHoverClasses_ = goog.array.slice(arguments, 0);
331
};
332
333
334
/**
335
* Sets a user-supplied CSS class to add to a drag item handle on hover (not
336
* during a drag action).
337
* @param {...string} var_args The CSS class or classes.
338
*/
339
goog.fx.DragListGroup.prototype.setDragItemHandleHoverClass = function(
340
var_args) {
341
goog.asserts.assert(!this.isInitialized_);
342
this.dragItemHandleHoverClasses_ = goog.array.slice(arguments, 0);
343
};
344
345
346
/**
347
* Sets a user-supplied CSS class to add to the current drag item (during a
348
* drag action).
349
*
350
* If not set, the default behavior adds visibility:hidden to the current drag
351
* item so that it is a block of empty space in the hover drag list (if any).
352
* If this class is set by the user, then the default behavior does not happen
353
* (unless, of course, the class also contains visibility:hidden).
354
*
355
* @param {...string} var_args The CSS class or classes.
356
*/
357
goog.fx.DragListGroup.prototype.setCurrDragItemClass = function(var_args) {
358
goog.asserts.assert(!this.isInitialized_);
359
this.currDragItemClasses_ = goog.array.slice(arguments, 0);
360
};
361
362
363
/**
364
* Sets a user-supplied CSS class to add to the clone of the current drag item
365
* that's actually being dragged around (during a drag action).
366
* @param {string} draggerElClass The CSS class.
367
*/
368
goog.fx.DragListGroup.prototype.setDraggerElClass = function(draggerElClass) {
369
goog.asserts.assert(!this.isInitialized_);
370
// Split space-separated classes up into an array.
371
this.draggerElClasses_ = goog.string.trim(draggerElClass).split(' ');
372
};
373
374
375
/**
376
* Performs the initial setup to make all items in all lists draggable.
377
*/
378
goog.fx.DragListGroup.prototype.init = function() {
379
if (this.isInitialized_) {
380
return;
381
}
382
383
for (var i = 0, numLists = this.dragLists_.length; i < numLists; i++) {
384
var dragList = this.dragLists_[i];
385
386
var dragItems = goog.dom.getChildren(dragList);
387
for (var j = 0, numItems = dragItems.length; j < numItems; ++j) {
388
this.listenForDragEvents(dragItems[j]);
389
}
390
}
391
392
this.isInitialized_ = true;
393
};
394
395
396
/**
397
* Adds a single item to the given drag list and sets up the drag listeners for
398
* it.
399
* If opt_index is specified the item is inserted at this index, otherwise the
400
* item is added as the last child of the list.
401
*
402
* @param {!Element} list The drag list where to add item to.
403
* @param {!Element} item The new element to add.
404
* @param {number=} opt_index Index where to insert the item in the list. If not
405
* specified item is inserted as the last child of list.
406
*/
407
goog.fx.DragListGroup.prototype.addItemToDragList = function(
408
list, item, opt_index) {
409
if (goog.isDef(opt_index)) {
410
goog.dom.insertChildAt(list, item, opt_index);
411
} else {
412
goog.dom.appendChild(list, item);
413
}
414
this.listenForDragEvents(item);
415
};
416
417
418
/** @override */
419
goog.fx.DragListGroup.prototype.disposeInternal = function() {
420
this.eventHandler_.dispose();
421
422
for (var i = 0, n = this.dragLists_.length; i < n; i++) {
423
var dragList = this.dragLists_[i];
424
// Note: IE doesn't allow 'delete' for fields on HTML elements (because
425
// they're not real JS objects in IE), so we just set them to undefined.
426
dragList.dlgGrowthDirection_ = undefined;
427
dragList.dlgDragHoverClass_ = undefined;
428
}
429
430
this.dragLists_.length = 0;
431
this.dragItems_.length = 0;
432
this.dragItemForHandle_ = null;
433
434
// In the case where a drag event is currently in-progress and dispose is
435
// called, this cleans up the extra state.
436
this.cleanupDragDom_();
437
438
goog.fx.DragListGroup.superClass_.disposeInternal.call(this);
439
};
440
441
442
/**
443
* Caches the heights of each drag list and drag item, except for the current
444
* drag item.
445
*
446
*/
447
goog.fx.DragListGroup.prototype.recacheListAndItemBounds = function() {
448
this.recacheListAndItemBounds_(this.currDragItem_);
449
};
450
451
452
/**
453
* Caches the heights of each drag list and drag item, except for the current
454
* drag item.
455
*
456
* @param {Element} currDragItem The item currently being dragged.
457
* @private
458
*/
459
goog.fx.DragListGroup.prototype.recacheListAndItemBounds_ = function(
460
currDragItem) {
461
for (var i = 0, n = this.dragLists_.length; i < n; i++) {
462
var dragList = this.dragLists_[i];
463
dragList.dlgBounds_ = goog.style.getBounds(dragList);
464
}
465
466
for (var i = 0, n = this.dragItems_.length; i < n; i++) {
467
var dragItem = this.dragItems_[i];
468
if (dragItem != currDragItem) {
469
dragItem.dlgBounds_ = goog.style.getBounds(dragItem);
470
}
471
}
472
};
473
474
475
/**
476
* Listens for drag events on the given drag item. This method is currently used
477
* to initialize drag items.
478
*
479
* @param {!Element} dragItem the element to initialize. This element has to be
480
* in one of the drag lists.
481
* @protected
482
*/
483
goog.fx.DragListGroup.prototype.listenForDragEvents = function(dragItem) {
484
var dragItemHandle = this.getHandleForDragItem_(dragItem);
485
var uid = goog.getUid(dragItemHandle);
486
this.dragItemForHandle_[uid] = dragItem;
487
488
if (this.dragItemHoverClasses_) {
489
this.eventHandler_.listen(
490
dragItem, goog.events.EventType.MOUSEOVER,
491
this.handleDragItemMouseover_);
492
this.eventHandler_.listen(
493
dragItem, goog.events.EventType.MOUSEOUT, this.handleDragItemMouseout_);
494
}
495
if (this.dragItemHandleHoverClasses_) {
496
this.eventHandler_.listen(
497
dragItemHandle, goog.events.EventType.MOUSEOVER,
498
this.handleDragItemHandleMouseover_);
499
this.eventHandler_.listen(
500
dragItemHandle, goog.events.EventType.MOUSEOUT,
501
this.handleDragItemHandleMouseout_);
502
}
503
504
this.dragItems_.push(dragItem);
505
this.eventHandler_.listen(
506
dragItemHandle,
507
[goog.events.EventType.MOUSEDOWN, goog.events.EventType.TOUCHSTART],
508
this.handlePotentialDragStart_);
509
};
510
511
512
/**
513
* Handles mouse and touch events which may start a drag action.
514
* @param {!goog.events.BrowserEvent} e MOUSEDOWN or TOUCHSTART event.
515
* @private
516
*/
517
goog.fx.DragListGroup.prototype.handlePotentialDragStart_ = function(e) {
518
var uid = goog.getUid(/** @type {Node} */ (e.currentTarget));
519
this.currDragItem_ = /** @type {Element} */ (this.dragItemForHandle_[uid]);
520
521
this.draggerEl_ = /** @type {!HTMLElement} */ (
522
this.createDragElementInternal(this.currDragItem_));
523
if (this.draggerElClasses_) {
524
// Add CSS class for the clone, if any.
525
goog.dom.classlist.addAll(
526
goog.asserts.assert(this.draggerEl_), this.draggerElClasses_ || []);
527
}
528
529
// Place the clone (i.e. draggerEl) at the same position as the actual
530
// current drag item. This is a bit tricky since
531
// goog.style.getPageOffset() gets the left-top pos of the border, but
532
// goog.style.setPageOffset() sets the left-top pos of the margin.
533
// It's difficult to adjust for the margins of the clone because it's
534
// difficult to read it: goog.style.getComputedStyle() doesn't work for IE.
535
// Instead, our workaround is simply to set the clone's margins to 0px.
536
this.draggerEl_.style.margin = '0';
537
this.draggerEl_.style.position = 'absolute';
538
this.draggerEl_.style.visibility = 'hidden';
539
var doc = goog.dom.getOwnerDocument(this.currDragItem_);
540
doc.body.appendChild(this.draggerEl_);
541
542
// Important: goog.style.setPageOffset() only works correctly for IE when the
543
// element is already in the document.
544
var currDragItemPos = goog.style.getPageOffset(this.currDragItem_);
545
goog.style.setPageOffset(this.draggerEl_, currDragItemPos);
546
547
this.dragger_ = new goog.fx.Dragger(this.draggerEl_);
548
this.dragger_.setHysteresis(this.hysteresisDistance_);
549
550
// Listen to events on the dragger. These handlers will be unregistered at
551
// DRAGEND, when the dragger is disposed of. We can't use eventHandler_,
552
// because it creates new references to the handler functions at each
553
// dragging action, and keeps them until DragListGroup is disposed of.
554
goog.events.listen(
555
this.dragger_, goog.fx.Dragger.EventType.START, this.handleDragStart_,
556
false, this);
557
goog.events.listen(
558
this.dragger_, goog.fx.Dragger.EventType.END, this.handleDragEnd_, false,
559
this);
560
goog.events.listen(
561
this.dragger_, goog.fx.Dragger.EventType.EARLY_CANCEL, this.cleanup_,
562
false, this);
563
this.dragger_.startDrag(e);
564
};
565
566
567
/**
568
* Creates copy of node being dragged.
569
*
570
* @param {Element} sourceEl Element to copy.
571
* @return {!Element} The clone of {@code sourceEl}.
572
* @deprecated Use goog.fx.Dragger.cloneNode().
573
* @private
574
*/
575
goog.fx.DragListGroup.prototype.cloneNode_ = function(sourceEl) {
576
return goog.fx.Dragger.cloneNode(sourceEl);
577
};
578
579
580
/**
581
* Generates an element to follow the cursor during dragging, given a drag
582
* source element. The default behavior is simply to clone the source element,
583
* but this may be overridden in subclasses. This method is called by
584
* {@code createDragElement()} before the drag class is added.
585
*
586
* @param {Element} sourceEl Drag source element.
587
* @return {!Element} The new drag element.
588
* @protected
589
* @suppress {deprecated}
590
*/
591
goog.fx.DragListGroup.prototype.createDragElementInternal = function(sourceEl) {
592
return this.cloneNode_(sourceEl);
593
};
594
595
596
/**
597
* Handles the start of a drag action.
598
* @param {!goog.fx.DragEvent} e goog.fx.Dragger.EventType.START event.
599
* @private
600
*/
601
goog.fx.DragListGroup.prototype.handleDragStart_ = function(e) {
602
if (!this.dispatchEvent(
603
new goog.fx.DragListGroupEvent(
604
goog.fx.DragListGroup.EventType.BEFOREDRAGSTART, this,
605
e.browserEvent, this.currDragItem_, null, null))) {
606
e.preventDefault();
607
this.cleanup_();
608
return;
609
}
610
611
// Record the original location of the current drag item.
612
// Note: this.origNextItem_ may be null.
613
this.origList_ = /** @type {Element} */ (this.currDragItem_.parentNode);
614
this.origNextItem_ = goog.dom.getNextElementSibling(this.currDragItem_);
615
this.currHoverItem_ = this.origNextItem_;
616
this.currHoverList_ = this.origList_;
617
618
// If there's a CSS class specified for the current drag item, add it.
619
// Otherwise, make the actual current drag item hidden (takes up space).
620
if (this.currDragItemClasses_) {
621
goog.dom.classlist.addAll(
622
goog.asserts.assert(this.currDragItem_),
623
this.currDragItemClasses_ || []);
624
} else {
625
this.currDragItem_.style.visibility = 'hidden';
626
}
627
628
// Precompute distances from top-left corner to center for efficiency.
629
var draggerElSize = goog.style.getSize(this.draggerEl_);
630
this.draggerEl_.halfWidth = draggerElSize.width / 2;
631
this.draggerEl_.halfHeight = draggerElSize.height / 2;
632
633
this.draggerEl_.style.visibility = '';
634
635
// Record the bounds of all the drag lists and all the other drag items. This
636
// caching is for efficiency, so that we don't have to recompute the bounds on
637
// each drag move. Do this in the state where the current drag item is not in
638
// any of the lists, except when update while dragging is disabled, as in this
639
// case the current drag item does not get removed until drag ends.
640
if (this.updateWhileDragging_) {
641
this.currDragItem_.style.display = 'none';
642
}
643
this.recacheListAndItemBounds_(this.currDragItem_);
644
this.currDragItem_.style.display = '';
645
646
// Listen to events on the dragger.
647
goog.events.listen(
648
this.dragger_, goog.fx.Dragger.EventType.DRAG, this.handleDragMove_,
649
false, this);
650
651
this.dispatchEvent(
652
new goog.fx.DragListGroupEvent(
653
goog.fx.DragListGroup.EventType.DRAGSTART, this, e.browserEvent,
654
this.currDragItem_, this.draggerEl_, this.dragger_));
655
};
656
657
658
/**
659
* Handles a drag movement (i.e. DRAG event fired by the dragger).
660
*
661
* @param {goog.fx.DragEvent} dragEvent Event object fired by the dragger.
662
* @return {boolean} The return value for the event.
663
* @private
664
*/
665
goog.fx.DragListGroup.prototype.handleDragMove_ = function(dragEvent) {
666
667
// Compute the center of the dragger element (i.e. the cloned drag item).
668
var draggerElPos = goog.style.getPageOffset(this.draggerEl_);
669
var draggerElCenter = new goog.math.Coordinate(
670
draggerElPos.x + this.draggerEl_.halfWidth,
671
draggerElPos.y + this.draggerEl_.halfHeight);
672
673
// Check whether the center is hovering over one of the drag lists.
674
var hoverList = this.getHoverDragList_(draggerElCenter);
675
676
// If hovering over a list, find the next item (if drag were to end now).
677
var hoverNextItem =
678
hoverList ? this.getHoverNextItem_(hoverList, draggerElCenter) : null;
679
680
var rv = this.dispatchEvent(
681
new goog.fx.DragListGroupEvent(
682
goog.fx.DragListGroup.EventType.BEFOREDRAGMOVE, this, dragEvent,
683
this.currDragItem_, this.draggerEl_, this.dragger_, draggerElCenter,
684
hoverList, hoverNextItem));
685
if (!rv) {
686
return false;
687
}
688
689
if (hoverList) {
690
if (this.updateWhileDragging_) {
691
this.insertCurrDragItem_(hoverList, hoverNextItem);
692
} else {
693
// If update while dragging is disabled do not insert
694
// the dragged item, but update the hovered item instead.
695
this.updateCurrHoverItem(hoverNextItem, draggerElCenter);
696
}
697
this.currDragItem_.style.display = '';
698
// Add drag list's hover class (if any).
699
if (hoverList.dlgDragHoverClass_) {
700
goog.dom.classlist.add(
701
goog.asserts.assert(hoverList), hoverList.dlgDragHoverClass_);
702
}
703
704
} else {
705
// Not hovering over a drag list, so remove the item altogether unless
706
// specified otherwise by the user.
707
if (!this.isCurrDragItemAlwaysDisplayed_) {
708
this.currDragItem_.style.display = 'none';
709
}
710
711
// Remove hover classes (if any) from all drag lists.
712
for (var i = 0, n = this.dragLists_.length; i < n; i++) {
713
var dragList = this.dragLists_[i];
714
if (dragList.dlgDragHoverClass_) {
715
goog.dom.classlist.remove(
716
goog.asserts.assert(dragList), dragList.dlgDragHoverClass_);
717
}
718
}
719
}
720
721
// If the current hover list is different than the last, the lists may have
722
// shrunk, so we should recache the bounds.
723
if (hoverList != this.currHoverList_) {
724
this.currHoverList_ = hoverList;
725
this.recacheListAndItemBounds_(this.currDragItem_);
726
}
727
728
this.dispatchEvent(
729
new goog.fx.DragListGroupEvent(
730
goog.fx.DragListGroup.EventType.DRAGMOVE, this, dragEvent,
731
/** @type {Element} */ (this.currDragItem_), this.draggerEl_,
732
this.dragger_, draggerElCenter, hoverList, hoverNextItem));
733
734
// Return false to prevent selection due to mouse drag.
735
return false;
736
};
737
738
739
/**
740
* Clear all our temporary fields that are only defined while dragging, and
741
* all the bounds info stored on the drag lists and drag elements.
742
* @param {!goog.events.Event=} opt_e EARLY_CANCEL event from the dragger if
743
* cleanup_ was called as an event handler.
744
* @private
745
*/
746
goog.fx.DragListGroup.prototype.cleanup_ = function(opt_e) {
747
this.cleanupDragDom_();
748
749
this.currDragItem_ = null;
750
this.currHoverList_ = null;
751
this.origList_ = null;
752
this.origNextItem_ = null;
753
this.draggerEl_ = null;
754
this.dragger_ = null;
755
756
// Note: IE doesn't allow 'delete' for fields on HTML elements (because
757
// they're not real JS objects in IE), so we just set them to null.
758
for (var i = 0, n = this.dragLists_.length; i < n; i++) {
759
this.dragLists_[i].dlgBounds_ = null;
760
}
761
for (var i = 0, n = this.dragItems_.length; i < n; i++) {
762
this.dragItems_[i].dlgBounds_ = null;
763
}
764
};
765
766
767
/**
768
* Handles the end or the cancellation of a drag action, i.e. END or CLEANUP
769
* event fired by the dragger.
770
*
771
* @param {!goog.fx.DragEvent} dragEvent Event object fired by the dragger.
772
* @return {boolean} Whether the event was handled.
773
* @private
774
*/
775
goog.fx.DragListGroup.prototype.handleDragEnd_ = function(dragEvent) {
776
var rv = this.dispatchEvent(
777
new goog.fx.DragListGroupEvent(
778
goog.fx.DragListGroup.EventType.BEFOREDRAGEND, this, dragEvent,
779
/** @type {Element} */ (this.currDragItem_), this.draggerEl_,
780
this.dragger_));
781
if (!rv) {
782
return false;
783
}
784
785
// If update while dragging is disabled insert the current drag item into
786
// its intended location.
787
if (!this.updateWhileDragging_) {
788
this.insertCurrHoverItem();
789
}
790
791
// The DRAGEND handler may need the new order of the list items. Clean up the
792
// garbage.
793
// TODO(user): Regression test.
794
this.cleanupDragDom_();
795
796
this.dispatchEvent(
797
new goog.fx.DragListGroupEvent(
798
goog.fx.DragListGroup.EventType.DRAGEND, this, dragEvent,
799
this.currDragItem_, this.draggerEl_, this.dragger_));
800
801
this.cleanup_();
802
803
return true;
804
};
805
806
807
/**
808
* Cleans up DOM changes that are made by the {@code handleDrag*} methods.
809
* @private
810
*/
811
goog.fx.DragListGroup.prototype.cleanupDragDom_ = function() {
812
// Disposes of the dragger and remove the cloned drag item.
813
goog.dispose(this.dragger_);
814
if (this.draggerEl_) {
815
goog.dom.removeNode(this.draggerEl_);
816
}
817
818
// If the current drag item is not in any list, put it back in its original
819
// location.
820
if (this.currDragItem_ && this.currDragItem_.style.display == 'none') {
821
// Note: this.origNextItem_ may be null, but insertBefore() still works.
822
this.origList_.insertBefore(this.currDragItem_, this.origNextItem_);
823
this.currDragItem_.style.display = '';
824
}
825
826
// If there's a CSS class specified for the current drag item, remove it.
827
// Otherwise, make the current drag item visible (instead of empty space).
828
if (this.currDragItemClasses_ && this.currDragItem_) {
829
goog.dom.classlist.removeAll(
830
goog.asserts.assert(this.currDragItem_),
831
this.currDragItemClasses_ || []);
832
} else if (this.currDragItem_) {
833
this.currDragItem_.style.visibility = '';
834
}
835
836
// Remove hover classes (if any) from all drag lists.
837
for (var i = 0, n = this.dragLists_.length; i < n; i++) {
838
var dragList = this.dragLists_[i];
839
if (dragList.dlgDragHoverClass_) {
840
goog.dom.classlist.remove(
841
goog.asserts.assert(dragList), dragList.dlgDragHoverClass_);
842
}
843
}
844
};
845
846
847
/**
848
* Default implementation of the function to get the "handle" element for a
849
* drag item. By default, we use the whole drag item as the handle. Users can
850
* change this by calling setFunctionToGetHandleForDragItem().
851
*
852
* @param {!Element} dragItem The drag item to get the handle for.
853
* @return {Element} The dragItem element itself.
854
* @private
855
*/
856
goog.fx.DragListGroup.prototype.getHandleForDragItem_ = function(dragItem) {
857
return dragItem;
858
};
859
860
861
/**
862
* Handles a MOUSEOVER event fired on a drag item.
863
* @param {goog.events.BrowserEvent} e The event.
864
* @private
865
*/
866
goog.fx.DragListGroup.prototype.handleDragItemMouseover_ = function(e) {
867
var targetEl = goog.asserts.assertElement(e.currentTarget);
868
goog.dom.classlist.addAll(targetEl, this.dragItemHoverClasses_ || []);
869
};
870
871
872
/**
873
* Handles a MOUSEOUT event fired on a drag item.
874
* @param {goog.events.BrowserEvent} e The event.
875
* @private
876
*/
877
goog.fx.DragListGroup.prototype.handleDragItemMouseout_ = function(e) {
878
var targetEl = goog.asserts.assertElement(e.currentTarget);
879
goog.dom.classlist.removeAll(targetEl, this.dragItemHoverClasses_ || []);
880
};
881
882
883
/**
884
* Handles a MOUSEOVER event fired on the handle element of a drag item.
885
* @param {goog.events.BrowserEvent} e The event.
886
* @private
887
*/
888
goog.fx.DragListGroup.prototype.handleDragItemHandleMouseover_ = function(e) {
889
var targetEl = goog.asserts.assertElement(e.currentTarget);
890
goog.dom.classlist.addAll(targetEl, this.dragItemHandleHoverClasses_ || []);
891
};
892
893
894
/**
895
* Handles a MOUSEOUT event fired on the handle element of a drag item.
896
* @param {goog.events.BrowserEvent} e The event.
897
* @private
898
*/
899
goog.fx.DragListGroup.prototype.handleDragItemHandleMouseout_ = function(e) {
900
var targetEl = goog.asserts.assertElement(e.currentTarget);
901
goog.dom.classlist.removeAll(
902
targetEl, this.dragItemHandleHoverClasses_ || []);
903
};
904
905
906
/**
907
* Helper for handleDragMove_().
908
* Given the position of the center of the dragger element, figures out whether
909
* it's currently hovering over any of the drag lists.
910
*
911
* @param {goog.math.Coordinate} draggerElCenter The center position of the
912
* dragger element.
913
* @return {Element} If currently hovering over a drag list, returns the drag
914
* list element. Else returns null.
915
* @private
916
*/
917
goog.fx.DragListGroup.prototype.getHoverDragList_ = function(draggerElCenter) {
918
919
// If the current drag item was in a list last time we did this, then check
920
// that same list first.
921
var prevHoverList = null;
922
if (this.currDragItem_.style.display != 'none') {
923
prevHoverList = /** @type {Element} */ (this.currDragItem_.parentNode);
924
// Important: We can't use the cached bounds for this list because the
925
// cached bounds are based on the case where the current drag item is not
926
// in the list. Since the current drag item is known to be in this list, we
927
// must recompute the list's bounds.
928
var prevHoverListBounds = goog.style.getBounds(prevHoverList);
929
if (this.isInRect_(draggerElCenter, prevHoverListBounds)) {
930
return prevHoverList;
931
}
932
}
933
934
for (var i = 0, n = this.dragLists_.length; i < n; i++) {
935
var dragList = this.dragLists_[i];
936
if (dragList == prevHoverList) {
937
continue;
938
}
939
if (this.isInRect_(draggerElCenter, dragList.dlgBounds_)) {
940
return dragList;
941
}
942
}
943
944
return null;
945
};
946
947
948
/**
949
* Checks whether a coordinate position resides inside a rectangle.
950
* @param {goog.math.Coordinate} pos The coordinate position.
951
* @param {goog.math.Rect} rect The rectangle.
952
* @return {boolean} True if 'pos' is within the bounds of 'rect'.
953
* @private
954
*/
955
goog.fx.DragListGroup.prototype.isInRect_ = function(pos, rect) {
956
return pos.x > rect.left && pos.x < rect.left + rect.width &&
957
pos.y > rect.top && pos.y < rect.top + rect.height;
958
};
959
960
961
/**
962
* Updates the value of currHoverItem_.
963
*
964
* This method is used for insertion only when updateWhileDragging_ is false.
965
* The below implementation is the basic one. This method can be extended by
966
* a subclass to support changes to hovered item (eg: highlighting). Parametr
967
* opt_draggerElCenter can be used for more sophisticated effects.
968
*
969
* @param {Element} hoverNextItem element of the list that is hovered over.
970
* @param {goog.math.Coordinate=} opt_draggerElCenter current position of
971
* the dragged element.
972
* @protected
973
*/
974
goog.fx.DragListGroup.prototype.updateCurrHoverItem = function(
975
hoverNextItem, opt_draggerElCenter) {
976
if (hoverNextItem) {
977
this.currHoverItem_ = hoverNextItem;
978
}
979
};
980
981
982
/**
983
* Inserts the currently dragged item in its new place.
984
*
985
* This method is used for insertion only when updateWhileDragging_ is false
986
* (otherwise there is no need for that). In the basic implementation
987
* the element is inserted before the currently hovered over item (this can
988
* be changed by overriding the method in subclasses).
989
*
990
* @protected
991
*/
992
goog.fx.DragListGroup.prototype.insertCurrHoverItem = function() {
993
this.origList_.insertBefore(this.currDragItem_, this.currHoverItem_);
994
};
995
996
997
/**
998
* Helper for handleDragMove_().
999
* Given the position of the center of the dragger element, plus the drag list
1000
* that it's currently hovering over, figures out the next drag item in the
1001
* list that follows the current position of the dragger element. (I.e. if
1002
* the drag action ends right now, it would become the item after the current
1003
* drag item.)
1004
*
1005
* @param {Element} hoverList The drag list that we're hovering over.
1006
* @param {goog.math.Coordinate} draggerElCenter The center position of the
1007
* dragger element.
1008
* @return {Element} Returns the earliest item in the hover list that belongs
1009
* after the current position of the dragger element. If all items in the
1010
* list should come before the current drag item, then returns null.
1011
* @private
1012
*/
1013
goog.fx.DragListGroup.prototype.getHoverNextItem_ = function(
1014
hoverList, draggerElCenter) {
1015
if (hoverList == null) {
1016
throw Error('getHoverNextItem_ called with null hoverList.');
1017
}
1018
1019
// The definition of what it means for the draggerEl to be "before" a given
1020
// item in the hover drag list is not always the same. It changes based on
1021
// the growth direction of the hover drag list in question.
1022
/** @type {number} */
1023
var relevantCoord = 0;
1024
var getRelevantBoundFn;
1025
var isBeforeFn;
1026
var pickClosestRow = false;
1027
var distanceToClosestRow = undefined;
1028
switch (hoverList.dlgGrowthDirection_) {
1029
case goog.fx.DragListDirection.DOWN:
1030
// "Before" means draggerElCenter.y is less than item's bottom y-value.
1031
relevantCoord = draggerElCenter.y;
1032
getRelevantBoundFn = goog.fx.DragListGroup.getBottomBound_;
1033
isBeforeFn = goog.fx.DragListGroup.isLessThan_;
1034
break;
1035
case goog.fx.DragListDirection.RIGHT_2D:
1036
pickClosestRow = true;
1037
case goog.fx.DragListDirection.RIGHT:
1038
// "Before" means draggerElCenter.x is less than item's right x-value.
1039
relevantCoord = draggerElCenter.x;
1040
getRelevantBoundFn = goog.fx.DragListGroup.getRightBound_;
1041
isBeforeFn = goog.fx.DragListGroup.isLessThan_;
1042
break;
1043
case goog.fx.DragListDirection.LEFT_2D:
1044
pickClosestRow = true;
1045
case goog.fx.DragListDirection.LEFT:
1046
// "Before" means draggerElCenter.x is greater than item's left x-value.
1047
relevantCoord = draggerElCenter.x;
1048
getRelevantBoundFn = goog.fx.DragListGroup.getLeftBound_;
1049
isBeforeFn = goog.fx.DragListGroup.isGreaterThan_;
1050
break;
1051
}
1052
1053
// This holds the earliest drag item found so far that should come after
1054
// this.currDragItem_ in the hover drag list (based on draggerElCenter).
1055
var earliestAfterItem = null;
1056
// This is the position of the relevant bound for the earliestAfterItem,
1057
// where "relevant" is determined by the growth direction of hoverList.
1058
var earliestAfterItemRelevantBound;
1059
1060
var hoverListItems = goog.dom.getChildren(hoverList);
1061
for (var i = 0, n = hoverListItems.length; i < n; i++) {
1062
var item = hoverListItems[i];
1063
if (item == this.currDragItem_) {
1064
continue;
1065
}
1066
1067
var relevantBound = getRelevantBoundFn(item.dlgBounds_);
1068
// When the hoverlist is broken into multiple rows (i.e., in the case of
1069
// LEFT_2D and RIGHT_2D) it is no longer enough to only look at the
1070
// x-coordinate alone in order to find the {@earliestAfterItem} in the
1071
// hoverlist. Make sure it is chosen from the row closest to the
1072
// {@code draggerElCenter}.
1073
if (pickClosestRow) {
1074
var distanceToRow = goog.fx.DragListGroup.verticalDistanceFromItem_(
1075
item, draggerElCenter);
1076
// Initialize the distance to the closest row to the current value if
1077
// undefined.
1078
if (!goog.isDef(distanceToClosestRow)) {
1079
distanceToClosestRow = distanceToRow;
1080
}
1081
if (isBeforeFn(relevantCoord, relevantBound) &&
1082
(earliestAfterItemRelevantBound == undefined ||
1083
(distanceToRow < distanceToClosestRow) ||
1084
((distanceToRow == distanceToClosestRow) &&
1085
(isBeforeFn(relevantBound, earliestAfterItemRelevantBound) ||
1086
relevantBound == earliestAfterItemRelevantBound)))) {
1087
earliestAfterItem = item;
1088
earliestAfterItemRelevantBound = relevantBound;
1089
}
1090
// Update distance to closest row.
1091
if (distanceToRow < distanceToClosestRow) {
1092
distanceToClosestRow = distanceToRow;
1093
}
1094
} else if (
1095
isBeforeFn(relevantCoord, relevantBound) &&
1096
(earliestAfterItemRelevantBound == undefined ||
1097
isBeforeFn(relevantBound, earliestAfterItemRelevantBound))) {
1098
earliestAfterItem = item;
1099
earliestAfterItemRelevantBound = relevantBound;
1100
}
1101
}
1102
// If we ended up picking an element that is not in the closest row it can
1103
// only happen if we should have picked the last one in which case there is
1104
// no consecutive element.
1105
if (!goog.isNull(earliestAfterItem) &&
1106
goog.fx.DragListGroup.verticalDistanceFromItem_(
1107
earliestAfterItem, draggerElCenter) > distanceToClosestRow) {
1108
return null;
1109
} else {
1110
return earliestAfterItem;
1111
}
1112
};
1113
1114
1115
/**
1116
* Private helper for getHoverNextItem().
1117
* Given an item and a target determine the vertical distance from the item's
1118
* center to the target.
1119
* @param {Element} item The item to measure the distance from.
1120
* @param {goog.math.Coordinate} target The (x,y) coordinate of the target
1121
* to measure the distance to.
1122
* @return {number} The vertical distance between the center of the item and
1123
* the target.
1124
* @private
1125
*/
1126
goog.fx.DragListGroup.verticalDistanceFromItem_ = function(item, target) {
1127
var itemBounds = item.dlgBounds_;
1128
var itemCenterY = itemBounds.top + (itemBounds.height - 1) / 2;
1129
return Math.abs(target.y - itemCenterY);
1130
};
1131
1132
1133
/**
1134
* Private helper for getHoverNextItem_().
1135
* Given the bounds of an item, computes the item's bottom y-value.
1136
* @param {goog.math.Rect} itemBounds The bounds of the item.
1137
* @return {number} The item's bottom y-value.
1138
* @private
1139
*/
1140
goog.fx.DragListGroup.getBottomBound_ = function(itemBounds) {
1141
return itemBounds.top + itemBounds.height - 1;
1142
};
1143
1144
1145
/**
1146
* Private helper for getHoverNextItem_().
1147
* Given the bounds of an item, computes the item's right x-value.
1148
* @param {goog.math.Rect} itemBounds The bounds of the item.
1149
* @return {number} The item's right x-value.
1150
* @private
1151
*/
1152
goog.fx.DragListGroup.getRightBound_ = function(itemBounds) {
1153
return itemBounds.left + itemBounds.width - 1;
1154
};
1155
1156
1157
/**
1158
* Private helper for getHoverNextItem_().
1159
* Given the bounds of an item, computes the item's left x-value.
1160
* @param {goog.math.Rect} itemBounds The bounds of the item.
1161
* @return {number} The item's left x-value.
1162
* @private
1163
*/
1164
goog.fx.DragListGroup.getLeftBound_ = function(itemBounds) {
1165
return itemBounds.left || 0;
1166
};
1167
1168
1169
/**
1170
* Private helper for getHoverNextItem_().
1171
* @param {number} a Number to compare.
1172
* @param {number} b Number to compare.
1173
* @return {boolean} Whether a is less than b.
1174
* @private
1175
*/
1176
goog.fx.DragListGroup.isLessThan_ = function(a, b) {
1177
return a < b;
1178
};
1179
1180
1181
/**
1182
* Private helper for getHoverNextItem_().
1183
* @param {number} a Number to compare.
1184
* @param {number} b Number to compare.
1185
* @return {boolean} Whether a is greater than b.
1186
* @private
1187
*/
1188
goog.fx.DragListGroup.isGreaterThan_ = function(a, b) {
1189
return a > b;
1190
};
1191
1192
1193
/**
1194
* Inserts the current drag item to the appropriate location in the drag list
1195
* that we're hovering over (if the current drag item is not already there).
1196
*
1197
* @param {Element} hoverList The drag list we're hovering over.
1198
* @param {Element} hoverNextItem The next item in the hover drag list.
1199
* @private
1200
*/
1201
goog.fx.DragListGroup.prototype.insertCurrDragItem_ = function(
1202
hoverList, hoverNextItem) {
1203
if (this.currDragItem_.parentNode != hoverList ||
1204
goog.dom.getNextElementSibling(this.currDragItem_) != hoverNextItem) {
1205
// The current drag item is not in the correct location, so we move it.
1206
// Note: hoverNextItem may be null, but insertBefore() still works.
1207
hoverList.insertBefore(this.currDragItem_, hoverNextItem);
1208
}
1209
};
1210
1211
1212
1213
/**
1214
* The event object dispatched by DragListGroup.
1215
* The fields draggerElCenter, hoverList, and hoverNextItem are only available
1216
* for the BEFOREDRAGMOVE and DRAGMOVE events.
1217
*
1218
* @param {goog.fx.DragListGroup.EventType} type
1219
* @param {goog.fx.DragListGroup} dragListGroup A reference to the associated
1220
* DragListGroup object.
1221
* @param {goog.events.BrowserEvent|goog.fx.DragEvent} event The event fired
1222
* by the browser or fired by the dragger.
1223
* @param {Element} currDragItem The current drag item being moved.
1224
* @param {Element} draggerEl The clone of the current drag item that's actually
1225
* being dragged around.
1226
* @param {goog.fx.Dragger} dragger The dragger object.
1227
* @param {goog.math.Coordinate=} opt_draggerElCenter The current center
1228
* position of the draggerEl.
1229
* @param {Element=} opt_hoverList The current drag list that's being hovered
1230
* over, or null if the center of draggerEl is outside of any drag lists.
1231
* If not null and the drag action ends right now, then currDragItem will
1232
* end up in this list.
1233
* @param {Element=} opt_hoverNextItem The current next item in the hoverList
1234
* that the draggerEl is hovering over. (I.e. If the drag action ends
1235
* right now, then this item would become the next item after the new
1236
* location of currDragItem.) May be null if not applicable or if
1237
* currDragItem would be added to the end of hoverList.
1238
* @constructor
1239
* @struct
1240
* @extends {goog.events.Event}
1241
*/
1242
goog.fx.DragListGroupEvent = function(
1243
type, dragListGroup, event, currDragItem, draggerEl, dragger,
1244
opt_draggerElCenter, opt_hoverList, opt_hoverNextItem) {
1245
goog.events.Event.call(this, type);
1246
1247
/**
1248
* A reference to the associated DragListGroup object.
1249
* @type {goog.fx.DragListGroup}
1250
*/
1251
this.dragListGroup = dragListGroup;
1252
1253
/**
1254
* The event fired by the browser or fired by the dragger.
1255
* @type {goog.events.BrowserEvent|goog.fx.DragEvent}
1256
*/
1257
this.event = event;
1258
1259
/**
1260
* The current drag item being move.
1261
* @type {Element}
1262
*/
1263
this.currDragItem = currDragItem;
1264
1265
/**
1266
* The clone of the current drag item that's actually being dragged around.
1267
* @type {Element}
1268
*/
1269
this.draggerEl = draggerEl;
1270
1271
/**
1272
* The dragger object.
1273
* @type {goog.fx.Dragger}
1274
*/
1275
this.dragger = dragger;
1276
1277
/**
1278
* The current center position of the draggerEl.
1279
* @type {goog.math.Coordinate|undefined}
1280
*/
1281
this.draggerElCenter = opt_draggerElCenter;
1282
1283
/**
1284
* The current drag list that's being hovered over, or null if the center of
1285
* draggerEl is outside of any drag lists. (I.e. If not null and the drag
1286
* action ends right now, then currDragItem will end up in this list.)
1287
* @type {Element|undefined}
1288
*/
1289
this.hoverList = opt_hoverList;
1290
1291
/**
1292
* The current next item in the hoverList that the draggerEl is hovering over.
1293
* (I.e. If the drag action ends right now, then this item would become the
1294
* next item after the new location of currDragItem.) May be null if not
1295
* applicable or if currDragItem would be added to the end of hoverList.
1296
* @type {Element|undefined}
1297
*/
1298
this.hoverNextItem = opt_hoverNextItem;
1299
};
1300
goog.inherits(goog.fx.DragListGroupEvent, goog.events.Event);
1301
1302