Chromium Code Reviews| Index: chrome/browser/resources/ntp/draganddrop.js |
| diff --git a/chrome/browser/resources/ntp/draganddrop.js b/chrome/browser/resources/ntp/draganddrop.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4d517dde486139cebae21d6860925851a0040d36 |
| --- /dev/null |
| +++ b/chrome/browser/resources/ntp/draganddrop.js |
| @@ -0,0 +1,186 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
|
Aaron Boodman
2011/01/22 23:42:57
Seems like this file should be called drag_drop_co
jstritar
2011/01/24 01:00:42
Done.
|
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +// The delegate interface: |
| +// dragContainer --> |
| +// element containing the draggable items |
| +// |
| +// transitionsDuration --> |
| +// length of time of transitions in ms |
| +// |
| +// dragItem --> |
| +// get / set property containing the item being dragged |
| +// |
| +// dimensions --> |
| +// property that specifies the dimensions of the items |
| +// The object should contain the following properties: |
| +// itemHeight, itemWidth, marginWidth, marginHeight, borderWidth |
|
Aaron Boodman
2011/01/22 23:42:57
Why does this class care about marginWidth/height
jstritar
2011/01/24 01:00:42
I removed the dependency on the dimensions.
|
| +// |
| +// getItem(e) --> |
| +// get's the item that is under the mouse event |e| |
| +// |
| +// canDropOn(position) --> |
| +// returns true if the position index is a valid place to drop an item |
| +// |
| +// setDragPlaceholder(position) --> |
| +// tells the delegate that the dragged item is currently above |
| +// |position| |
| +// |
| +// saveDrag() --> |
| +// tells the delegate that the drag is done. move the item to the |
| +// position last specified by setDragPlaceholder. (e.g., commit changes) |
| +// |
| + |
| +function DragAndDropController(delegate) { |
| + this.delegate = delegate; |
|
Aaron Boodman
2011/01/22 23:42:57
this.delegate_ ?
jstritar
2011/01/24 01:00:42
Done.
|
| + |
| + this.installHandlers_(); |
| +} |
| + |
| +DragAndDropController.prototype = { |
| + startX_: 0, |
| + startY_: 0, |
| + startScreenX_: 0, |
| + startScreenY_: 0, |
| + |
| + installHandlers_: function() { |
| + var el = this.delegate.dragContainer; |
| + el.addEventListener('dragstart', this.handleDragStart_.bind(this)); |
| + el.addEventListener('dragenter', this.handleDragEnter_.bind(this)); |
| + el.addEventListener('dragover', this.handleDragOver_.bind(this)); |
| + el.addEventListener('dragleave', this.handleDragLeave_.bind(this)); |
| + el.addEventListener('drop', this.handleDrop_.bind(this)); |
| + el.addEventListener('dragend', this.handleDragEnd_.bind(this)); |
| + el.addEventListener('drag', this.handleDrag_.bind(this)); |
| + el.addEventListener('mousedown', this.handleMouseDown_.bind(this)); |
| + }, |
| + |
| + isDragging: function() { |
| + return !!this.delegate.dragItem; |
|
Aaron Boodman
2011/01/22 23:42:57
Nit: prefer Boolean(this.delegate.dragItem) or thi
jstritar
2011/01/24 01:00:42
I realized I wasn't using this method, so I yanked
|
| + }, |
| + |
| + getIndexAt_: function(e) { |
|
Aaron Boodman
2011/01/22 23:42:57
Design nit: I think that knowledge of layout shoul
jstritar
2011/01/24 01:00:42
Great idea-- I think that's what felt off about th
|
| + var del = this.delegate; |
|
Aaron Boodman
2011/01/22 23:42:57
Careful with your abbreviations again. Since deleg
jstritar
2011/01/24 01:00:42
Done. Cleaned this up throughout the class.
|
| + var el = del.dragContainer; |
|
Aaron Boodman
2011/01/22 23:42:57
This variable is only used once, might as well jus
jstritar
2011/01/24 01:00:42
Done.
|
| + var rect = el.getBoundingClientRect(); |
| + var d = del.dimensions; |
| + var availableWidth = el.offsetWidth; |
| + |
| + var clientX = e.clientX + window.scrollX - rect.left; |
| + var clientY = e.clientY + window.scrollY - rect.top; |
| + |
| + var w = d.itemWidth + 2 * d.borderWidth + 2 * d.marginWidth; |
| + var h = d.itemHeight + 2 * d.borderWidth + 2 * d.marginHeight; |
| + |
| + var rtl = isRtl(); |
| + if (rtl) |
| + clientX = availableWidth - clientX; |
| + |
| + var row = Math.floor(clientY / h); |
| + var col = Math.floor(clientX / w); |
| + var index = Math.floor(availableWidth / w) * row + col; |
| + |
| + return index; |
| + }, |
| + |
| + // Listen to mousedown to get the relative position of the cursor when |
| + // starting drag and drop. |
| + handleMouseDown_: function(e) { |
| + var item = this.delegate.getItem(e); |
| + if (item) { |
|
Aaron Boodman
2011/01/22 23:42:57
Invert check and return early. Multiple places in
jstritar
2011/01/24 01:00:42
Done.
|
| + this.startX_ = item.offsetLeft; |
| + this.startY_ = item.offsetTop; |
| + this.startScreenX_ = e.screenX; |
| + this.startScreenY_ = e.screenY; |
| + |
| + // We don't want to focus the item on mousedown. However, to prevent |
| + // focus one has to call preventDefault but this also prevents the drag |
| + // and drop (sigh) so we only prevent it when the user is not doing a |
| + // left mouse button drag. |
| + if (e.button != 0) // LEFT |
| + e.preventDefault(); |
| + } |
| + }, |
| + |
| + handleDragStart_: function(e) { |
| + var item = this.delegate.getItem(e); |
| + if (item) { |
| + // Don't set data since HTML5 does not allow setting the name for |
| + // url-list. Instead, we just rely on the dragging of link behavior. |
| + this.delegate.dragItem = item; |
| + item.classList.add('dragging'); |
| + item.style.zIndex = 2; |
| + |
| + e.dataTransfer.effectAllowed = 'copyLinkMove'; |
| + } |
| + }, |
| + |
| + handleDragEnter_: function(e) { |
| + if (this.delegate.canDropOn(this.getIndexAt_(e))) |
| + e.preventDefault(); |
| + }, |
| + |
| + handleDragOver_: function(e) { |
| + var del = this.delegate; |
| + var position = this.getIndexAt_(e); |
| + if (del.canDropOn(position)) { |
| + del.setDragPlaceholder(position); |
| + e.preventDefault(); |
| + e.dataTransfer.dropEffect = 'move'; |
| + } |
| + }, |
| + |
| + handleDragLeave_: function(e) { |
| + if (this.delegate.canDropOn(this.getIndexAt_(e))) |
| + e.preventDefault(); |
| + }, |
| + |
| + handleDrop_: function(e) { |
| + var del = this.delegate; |
| + var dragItem = del.dragItem; |
| + if (dragItem) { |
| + dragItem.classList.remove('dragging'); |
| + del.dragItem = null; |
| + del.invalidate(); |
|
Aaron Boodman
2011/01/22 23:42:57
Seems like these two methods should be del.saveDra
jstritar
2011/01/24 01:00:42
Done.
|
| + del.layout(); |
| + |
| + setTimeout(function() { |
| + dragItem.style.pointerEvents = ''; |
| + dragItem.style.zIndex = ''; |
| + }, this.delegate.transitionsDuration + 10); |
| + } |
| + }, |
| + |
| + handleDragEnd_: function(e) { |
| + return this.handleDrop_(e); |
| + }, |
| + |
| + handleDrag_: function(e) { |
| + // Moves the drag item making sure that it is not displayed outside the |
| + // browser viewport. |
| + var del = this.delegate; |
| + var dragItem = del.dragItem; |
| + var rect = del.dragContainer.getBoundingClientRect(); |
| + |
| + var x = this.startX_ + e.screenX - this.startScreenX_; |
| + var y = this.startY_ + e.screenY - this.startScreenY_; |
| + |
| + // The position of the item is relative to #apps so we need to |
| + // subtract that when calculating the allowed position. |
| + x = Math.max(x, -rect.left); |
| + x = Math.min(x, document.body.clientWidth - rect.left - |
| + dragItem.offsetWidth - 2); |
| + |
| + // The shadow is 2px |
| + y = Math.max(-rect.top, y); |
| + y = Math.min(y, document.body.clientHeight - rect.top - |
| + dragItem.offsetHeight - 2); |
| + |
| + // Override right in case of RTL. |
| + dragItem.style.right = 'auto'; |
|
Aaron Boodman
2011/01/22 23:42:57
Don't think this line is needed.
jstritar
2011/01/24 01:00:42
Done.
|
| + dragItem.style.left = x + 'px'; |
| + dragItem.style.top = y + 'px'; |
| + dragItem.style.zIndex = 2; |
| + } |
| +}; |