Page MenuHomePhabricator

D10188.id36611.diff
No OneTemporary

D10188.id36611.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -8,7 +8,7 @@
return array(
'names' => array(
'core.pkg.css' => '764d4c80',
- 'core.pkg.js' => '5b832397',
+ 'core.pkg.js' => '53c6a7c5',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => '2de124c9',
'differential.pkg.js' => '5c2ba922',
@@ -413,7 +413,7 @@
'rsrc/js/application/phortune/phortune-credit-card-form.js' => '2290aeef',
'rsrc/js/application/policy/behavior-policy-control.js' => 'ae45872f',
'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '5e9f347c',
- 'rsrc/js/application/projects/behavior-project-boards.js' => '16c76360',
+ 'rsrc/js/application/projects/behavior-project-boards.js' => 'c05fb42a',
'rsrc/js/application/projects/behavior-project-create.js' => '065227cc',
'rsrc/js/application/projects/behavior-reorder-columns.js' => 'e1d25dfb',
'rsrc/js/application/releeph/releeph-preview-branch.js' => 'b2b4fbaf',
@@ -446,7 +446,7 @@
'rsrc/js/application/uiexample/notification-example.js' => '8ce821c5',
'rsrc/js/core/Busy.js' => '59a7976a',
'rsrc/js/core/DragAndDropFileUpload.js' => 'ad10aeac',
- 'rsrc/js/core/DraggableList.js' => '1fe26f18',
+ 'rsrc/js/core/DraggableList.js' => '8905523d',
'rsrc/js/core/FileUpload.js' => '477359c8',
'rsrc/js/core/Hovercard.js' => 'c6f720ff',
'rsrc/js/core/KeyboardShortcut.js' => '1ae869f2',
@@ -653,7 +653,7 @@
'javelin-behavior-phui-profile-menu' => '12884df9',
'javelin-behavior-policy-control' => 'ae45872f',
'javelin-behavior-policy-rule-editor' => '5e9f347c',
- 'javelin-behavior-project-boards' => '16c76360',
+ 'javelin-behavior-project-boards' => 'c05fb42a',
'javelin-behavior-project-create' => '065227cc',
'javelin-behavior-quicksand-blacklist' => '7927a7d3',
'javelin-behavior-recurring-edit' => '5f1c4d5f',
@@ -741,7 +741,7 @@
'phabricator-countdown-css' => 'e7544472',
'phabricator-dashboard-css' => 'eb458607',
'phabricator-drag-and-drop-file-upload' => 'ad10aeac',
- 'phabricator-draggable-list' => '1fe26f18',
+ 'phabricator-draggable-list' => '8905523d',
'phabricator-fatal-config-template-css' => '8e6c6fcd',
'phabricator-feed-css' => 'ecd4ec57',
'phabricator-file-upload' => '477359c8',
@@ -953,15 +953,6 @@
'javelin-dom',
'javelin-history',
),
- '16c76360' => array(
- 'javelin-behavior',
- 'javelin-dom',
- 'javelin-util',
- 'javelin-vector',
- 'javelin-stratcom',
- 'javelin-workflow',
- 'phabricator-draggable-list',
- ),
'1ad0a787' => array(
'javelin-install',
'javelin-reactor',
@@ -1007,14 +998,6 @@
'phuix-icon-view',
'javelin-behavior-phabricator-gesture',
),
- '1fe26f18' => array(
- 'javelin-install',
- 'javelin-dom',
- 'javelin-stratcom',
- 'javelin-util',
- 'javelin-vector',
- 'javelin-magical-init',
- ),
'21ba5861' => array(
'javelin-behavior',
'javelin-dom',
@@ -1492,6 +1475,14 @@
'javelin-stratcom',
'javelin-dom',
),
+ '8905523d' => array(
+ 'javelin-install',
+ 'javelin-dom',
+ 'javelin-stratcom',
+ 'javelin-util',
+ 'javelin-vector',
+ 'javelin-magical-init',
+ ),
'8a41885b' => array(
'javelin-install',
'javelin-dom',
@@ -1781,6 +1772,15 @@
'javelin-install',
'javelin-dom',
),
+ 'c05fb42a' => array(
+ 'javelin-behavior',
+ 'javelin-dom',
+ 'javelin-util',
+ 'javelin-vector',
+ 'javelin-stratcom',
+ 'javelin-workflow',
+ 'phabricator-draggable-list',
+ ),
'c1700f6f' => array(
'javelin-install',
'javelin-util',
diff --git a/webroot/rsrc/js/application/projects/behavior-project-boards.js b/webroot/rsrc/js/application/projects/behavior-project-boards.js
--- a/webroot/rsrc/js/application/projects/behavior-project-boards.js
+++ b/webroot/rsrc/js/application/projects/behavior-project-boards.js
@@ -232,6 +232,7 @@
for (ii = 0; ii < cols.length; ii++) {
var list = new JX.DraggableList('project-card', cols[ii])
.setFindItemsHandler(JX.bind(null, finditems, cols[ii]))
+ .setOuterContainer(JX.$(config.boardID))
.setCanDragX(true);
list.listen('didSend', JX.bind(list, onupdate, cols[ii]));
diff --git a/webroot/rsrc/js/core/DraggableList.js b/webroot/rsrc/js/core/DraggableList.js
--- a/webroot/rsrc/js/core/DraggableList.js
+++ b/webroot/rsrc/js/core/DraggableList.js
@@ -39,7 +39,8 @@
properties : {
findItemsHandler: null,
- canDragX: false
+ canDragX: false,
+ outerContainer: null
},
members : {
@@ -51,10 +52,15 @@
_ghostHandler : null,
_ghostNode : null,
_group : null,
- _lastMousePosition: null,
+ _cursorPosition: null,
+ _cursorOrigin: null,
+ _cursorScroll: null,
_frame: null,
_clone: null,
_offset: null,
+ _autoscroll: null,
+ _autoscroller: null,
+ _autotimer: null,
getRootNode : function() {
return this._root;
@@ -177,6 +183,10 @@
var drag = e.getNode(this._sigil);
+ this._autoscroll = {};
+ this._autoscroller = setInterval(JX.bind(this, this._onautoscroll), 10);
+ this._autotimer = null;
+
for (var ii = 0; ii < this._group.length; ii++) {
this._group[ii]._clearTarget();
}
@@ -398,14 +408,16 @@
// reuse the known position.
if (e.getType() == 'mousemove') {
- this._lastMousePosition = JX.$V(e);
+ this._cursorPosition = JX.$V(e);
+ this._cursorOrigin = JX.$V(e);
+ this._cursorScroll = JX.Vector.getScroll();
}
if (!this._dragging) {
return;
}
- if (!this._lastMousePosition) {
+ if (!this._cursorPosition) {
return;
}
@@ -413,9 +425,17 @@
// If this is a scroll event, the positions of drag targets may have
// changed.
this._dirtyTargetCache();
+
+ // Correct the cursor position to account for scrolling.
+ var s = JX.Vector.getScroll();
+ this._cursorPosition = new JX.$V(
+ this._cursorOrigin.x - (this._cursorScroll.x - s.x),
+ this._cursorOrigin.y - (this._cursorScroll.y - s.y));
}
- var p = JX.$V(this._lastMousePosition.x, this._lastMousePosition.y);
+ this._updateAutoscroll(this._cursorPosition);
+
+ var p = JX.$V(this._cursorPosition.x, this._cursorPosition.y);
var group = this._group;
var target_list = this._getTargetList(p);
@@ -454,6 +474,60 @@
e.kill();
},
+ _updateAutoscroll: function(p) {
+ var container = this._dragging.parentNode;
+ var autoscroll = {};
+
+ var outer = this.getOuterContainer();
+
+ var cpos;
+ var cdim;
+
+ while (container) {
+ if (outer && (container == outer)) {
+ break;
+ }
+
+ try {
+ cpos = JX.Vector.getPos(container);
+ cdim = JX.Vector.getDim(container);
+ if (container == document.body) {
+ cdim = JX.Vector.getViewport();
+ cpos.x += container.scrollLeft;
+ cpos.y += container.scrollTop;
+ }
+ } catch (ignored) {
+ break;
+ }
+
+ var fuzz = 64;
+
+ if (p.y <= cpos.y + fuzz) {
+ autoscroll.up = container;
+ }
+
+ if (p.y >= cpos.y + cdim.y - fuzz) {
+ autoscroll.down = container;
+ }
+
+ if (p.x <= cpos.x + fuzz) {
+ autoscroll.left = container;
+ }
+
+ if (p.x >= cpos.x + cdim.x - fuzz) {
+ autoscroll.right = container;
+ }
+
+ if (container == document.body) {
+ break;
+ }
+
+ container = container.parentNode;
+ }
+
+ this._autoscroll = autoscroll;
+ },
+
_onkey: function(e) {
// Cancel any current drag if the user presses escape.
if (this._dragging && (e.getSpecialKey() == 'esc')) {
@@ -464,6 +538,10 @@
},
_ondrop : function(e) {
+ if (this._dragging) {
+ e.kill();
+ }
+
var p = JX.$V(e);
this._drop(p);
},
@@ -475,6 +553,8 @@
var dragging = this._dragging;
this._dragging = null;
+ clearInterval(this._autoscroller);
+ this._autoscroller = null;
JX.DOM.remove(this._frame);
this._frame = null;
@@ -512,11 +592,72 @@
JX.DOM.alterClass(dragging, 'drag-dragging', false);
JX.Tooltip.unlock();
- e.kill();
-
this.invoke('didEndDrag', dragging);
},
+ _onautoscroll: function() {
+ var u = this._autoscroll.up;
+ var d = this._autoscroll.down;
+ var l = this._autoscroll.left;
+ var r = this._autoscroll.right;
+
+ var now = +new Date();
+
+ if (!this._autotimer) {
+ this._autotimer = now;
+ return;
+ }
+
+ var delta = now - this._autotimer;
+ this._autotimer = now;
+
+ var amount = 12 * (delta / 10);
+
+ if (u && (u != d)) {
+ this._tryScroll(this._dragging, u, 'scrollTop', amount);
+ }
+
+ if (d && (d != u)) {
+ this._tryScroll(this._dragging, d, 'scrollTop', -amount);
+ }
+
+ if (l && (l != r)) {
+ this._tryScroll(this._dragging, l, 'scrollLeft', amount);
+ }
+
+ if (r && (r != l)) {
+ this._tryScroll(this._dragging, r, 'scrollLeft', -amount);
+ }
+ },
+
+ /**
+ * Walk up the tree from a node to some parent, trying to scroll every
+ * container. Stop when we find a container which we're able to scroll.
+ */
+ _tryScroll: function(from, to, property, amount) {
+ var value;
+
+ var container = from.parentNode;
+ while (container) {
+ // Read the current scroll value.
+ value = container[property];
+
+ // Try to scroll.
+ container[property] -= amount;
+
+ // If we scrolled it, we're all done.
+ if (container[property] != value) {
+ break;
+ }
+
+ if (container == to) {
+ break;
+ }
+
+ container = container.parentNode;
+ }
+ },
+
lock : function() {
for (var ii = 0; ii < this._group.length; ii++) {
this._group[ii]._lock();

File Metadata

Mime Type
text/plain
Expires
Fri, Mar 7, 2:29 PM (4 d, 14 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7332904
Default Alt Text
D10188.id36611.diff (10 KB)

Event Timeline