Page MenuHomePhabricator

D15160.id.diff
No OneTemporary

D15160.id.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -7,8 +7,8 @@
*/
return array(
'names' => array(
- 'core.pkg.css' => '8b9c004a',
- 'core.pkg.js' => 'bf947f93',
+ 'core.pkg.css' => 'cd66e467',
+ 'core.pkg.js' => 'c5178ede',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => '2de124c9',
'differential.pkg.js' => '5c2ba922',
@@ -105,7 +105,7 @@
'rsrc/css/core/core.css' => '5b3563c8',
'rsrc/css/core/remarkup.css' => 'e1c8b32f',
'rsrc/css/core/syntax.css' => '9fd11da8',
- 'rsrc/css/core/z-index.css' => 'a36a45da',
+ 'rsrc/css/core/z-index.css' => '5c7025bf',
'rsrc/css/diviner/diviner-shared.css' => 'aa3656aa',
'rsrc/css/font/font-aleo.css' => '8bdb2835',
'rsrc/css/font/font-awesome.css' => 'c43323c5',
@@ -142,7 +142,7 @@
'rsrc/css/phui/phui-info-view.css' => '6d7c3509',
'rsrc/css/phui/phui-list.css' => '9da2aa00',
'rsrc/css/phui/phui-object-box.css' => '407eaf5a',
- 'rsrc/css/phui/phui-object-item-list-view.css' => 'febf4a79',
+ 'rsrc/css/phui/phui-object-item-list-view.css' => '699de05e',
'rsrc/css/phui/phui-pager.css' => 'bea33d23',
'rsrc/css/phui/phui-pinboard-view.css' => '2495140e',
'rsrc/css/phui/phui-profile-menu.css' => 'ab4fcf5f',
@@ -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' => '255d85da',
+ 'rsrc/js/core/DraggableList.js' => 'f1844746',
'rsrc/js/core/FileUpload.js' => '477359c8',
'rsrc/js/core/Hovercard.js' => 'c6f720ff',
'rsrc/js/core/KeyboardShortcut.js' => '1ae869f2',
@@ -741,7 +741,7 @@
'phabricator-countdown-css' => 'e7544472',
'phabricator-dashboard-css' => 'eb458607',
'phabricator-drag-and-drop-file-upload' => 'ad10aeac',
- 'phabricator-draggable-list' => '255d85da',
+ 'phabricator-draggable-list' => 'f1844746',
'phabricator-fatal-config-template-css' => '8e6c6fcd',
'phabricator-feed-css' => 'ecd4ec57',
'phabricator-file-upload' => '477359c8',
@@ -780,7 +780,7 @@
'phabricator-uiexample-reactor-select' => 'a155550f',
'phabricator-uiexample-reactor-sendclass' => '1def2711',
'phabricator-uiexample-reactor-sendproperties' => 'b1f0ccee',
- 'phabricator-zindex-css' => 'a36a45da',
+ 'phabricator-zindex-css' => '5c7025bf',
'phame-css' => '6d5b3682',
'pholio-css' => '95174bdd',
'pholio-edit-css' => '3ad9d1ee',
@@ -818,7 +818,7 @@
'phui-inline-comment-view-css' => '0fdb3667',
'phui-list-view-css' => '9da2aa00',
'phui-object-box-css' => '407eaf5a',
- 'phui-object-item-list-view-css' => 'febf4a79',
+ 'phui-object-item-list-view-css' => '699de05e',
'phui-pager-css' => 'bea33d23',
'phui-pinboard-view-css' => '2495140e',
'phui-profile-menu-css' => 'ab4fcf5f',
@@ -1021,14 +1021,6 @@
'phabricator-drag-and-drop-file-upload',
'phabricator-draggable-list',
),
- '255d85da' => array(
- 'javelin-install',
- 'javelin-dom',
- 'javelin-stratcom',
- 'javelin-util',
- 'javelin-vector',
- 'javelin-magical-init',
- ),
'2926fff2' => array(
'javelin-behavior',
'javelin-dom',
@@ -2019,6 +2011,14 @@
'javelin-workflow',
'javelin-json',
),
+ 'f1844746' => array(
+ 'javelin-install',
+ 'javelin-dom',
+ 'javelin-stratcom',
+ 'javelin-util',
+ 'javelin-vector',
+ 'javelin-magical-init',
+ ),
'f411b6ae' => array(
'javelin-behavior',
'javelin-stratcom',
diff --git a/src/view/phui/PHUIObjectItemView.php b/src/view/phui/PHUIObjectItemView.php
--- a/src/view/phui/PHUIObjectItemView.php
+++ b/src/view/phui/PHUIObjectItemView.php
@@ -383,17 +383,24 @@
),
$this->header);
- $header = javelin_tag(
+ // Wrap the header content in a <span> with the "slippery" sigil. This
+ // prevents us from beginning a drag if you click the text (like "T123"),
+ // but not if you click the white space after the header.
+ $header = phutil_tag(
'div',
array(
'class' => 'phui-object-item-name',
- 'sigil' => 'slippery',
),
- array(
- $this->headIcons,
- $header_name,
- $header_link,
- ));
+ javelin_tag(
+ 'span',
+ array(
+ 'sigil' => 'slippery',
+ ),
+ array(
+ $this->headIcons,
+ $header_name,
+ $header_link,
+ )));
$icons = array();
if ($this->icons) {
diff --git a/webroot/rsrc/css/core/z-index.css b/webroot/rsrc/css/core/z-index.css
--- a/webroot/rsrc/css/core/z-index.css
+++ b/webroot/rsrc/css/core/z-index.css
@@ -81,10 +81,6 @@
z-index: 5;
}
-.drag-dragging {
- z-index: 5;
-}
-
.phui-calendar-date-number {
z-index: 5;
}
@@ -114,6 +110,10 @@
z-index: 9;
}
+.drag-frame {
+ z-index: 10;
+}
+
.jx-mask {
z-index: 10;
}
diff --git a/webroot/rsrc/css/phui/phui-object-item-list-view.css b/webroot/rsrc/css/phui/phui-object-item-list-view.css
--- a/webroot/rsrc/css/phui/phui-object-item-list-view.css
+++ b/webroot/rsrc/css/phui/phui-object-item-list-view.css
@@ -593,15 +593,36 @@
}
.drag-dragging {
- position: relative;
- background: {$sh-yellowbackground};
- opacity: 0.9;
+ opacity: 0.25;
}
.drag-sending {
opacity: 0.5;
}
+.drag-clone,
+.drag-frame {
+ /* This allows mousewheel events to pass through the clone and frame while
+ they are being dragged. Without this, the mousewheel does not work during
+ a drag operation. */
+ pointer-events: none;
+}
+
+.drag-frame {
+ position: fixed;
+ overflow: hidden;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+}
+
+.drag-clone {
+ position: absolute;
+ list-style: none;
+}
+
+
/* - State ---------------------------------------------------------------------
Provides a list of object status or states, success or fail, etc
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
@@ -44,15 +44,15 @@
_root : null,
_dragging : null,
_locked : 0,
- _origin : null,
- _originScroll : null,
_target : null,
_targets : null,
_ghostHandler : null,
_ghostNode : null,
_group : null,
_lastMousePosition: null,
- _lastAdjust: null,
+ _frame: null,
+ _clone: null,
+ _offset: null,
getRootNode : function() {
return this._root;
@@ -131,7 +131,17 @@
}
}
- return handler();
+ var items = handler();
+
+ // Make sure the clone element is never included as a target.
+ for (var ii = 0; ii < items.length; ii++) {
+ if (items[ii] === this._clone) {
+ items.splice(ii, 1);
+ break;
+ }
+ }
+
+ return items;
},
_ondrag : function(e) {
@@ -167,24 +177,67 @@
e.kill();
- this._dragging = e.getNode(this._sigil);
- this._origin = JX.$V(e);
- this._originScroll = JX.Vector.getAggregateScrollForNode(this._dragging);
+ var drag = e.getNode(this._sigil);
for (var ii = 0; ii < this._group.length; ii++) {
this._group[ii]._clearTarget();
}
- if (!this.invoke('didBeginDrag', this._dragging).getPrevented()) {
- // Set the height of all the ghosts in the group. In the normal case,
- // this just sets this list's ghost height.
- for (var jj = 0; jj < this._group.length; jj++) {
- var ghost = this._group[jj].getGhostNode();
- ghost.style.height = JX.Vector.getDim(this._dragging).y + 'px';
- }
+ var pos = JX.$V(drag);
+ var dim = JX.Vector.getDim(drag);
- JX.DOM.alterClass(this._dragging, 'drag-dragging', true);
+ // Create and adjust the ghost nodes.
+ for (var jj = 0; jj < this._group.length; jj++) {
+ var ghost = this._group[jj].getGhostNode();
+ ghost.style.height = dim.y + 'px';
}
+
+ // Here's what's going on: we're cloning the thing that's being dragged.
+ // This is the "clone", stored in "this._clone". We're going to leave the
+ // original where it is in the document, and put the clone at top-level
+ // so it can be freely dragged around the whole document, even if it's
+ // inside a container with overflow hidden.
+
+ // Because the clone has been moved up, CSS classes which rely on some
+ // parent selector won't work. Draggable objects need to pick up all of
+ // their CSS properties without relying on container classes. This isn't
+ // great, but leaving them where they are in the document creates a large
+ // number of positioning problems with scrollable, absolute, relative,
+ // or overflow hidden containers.
+
+ // Note that we don't actually want to let the user drag it outside the
+ // document. One problem is that doing so lets the user drag objects
+ // infinitely far to the right by dragging them to the edge so the
+ // document extends, scrolling the document, dragging them to the edge
+ // of the new larger document, scrolling the document, and so on forever.
+
+ // To prevent this, we're putting a "frame" (stored in "this._frame") at
+ // top level, then putting the clone inside the frame. The frame has the
+ // same size as the entire viewport, and overflow hidden, so dragging the
+ // item outside the document just cuts it off.
+
+ // Create the clone for dragging.
+ var clone = drag.cloneNode(true);
+
+ pos.setPos(clone);
+ dim.setDim(clone);
+
+ JX.DOM.alterClass(drag, 'drag-dragging', true);
+ JX.DOM.alterClass(clone, 'drag-clone', true);
+
+ var frame = JX.$N('div', {className: 'drag-frame'});
+ frame.appendChild(clone);
+
+ document.body.appendChild(frame);
+
+ this._dragging = drag;
+ this._clone = clone;
+ this._frame = frame;
+
+ var cursor = JX.$V(e);
+ this._offset = new JX.Vector(pos.x - cursor.x, pos.y - cursor.y);
+
+ this.invoke('didBeginDrag', this._dragging);
},
_getTargets : function() {
@@ -195,18 +248,6 @@
var item = items[ii];
var ipos = JX.$V(item);
- if (item == this._dragging) {
- // If the item we're measuring is also the item we're dragging,
- // we need to measure its position as though it was still in the
- // list, not its current position in the document (which is
- // under the cursor). To do this, adjust the measured position by
- // removing the offsets we added to put the item underneath the
- // cursor.
- if (this._lastAdjust) {
- ipos.x -= this._lastAdjust.x;
- ipos.y -= this._lastAdjust.y;
- }
- }
targets.push({
item: items[ii],
@@ -398,39 +439,18 @@
}
}
- // If the drop target indicator is above the cursor in the document,
- // adjust the cursor position for the change in node document position.
- // Do this before choosing a new target to avoid a flash of nonsense.
-
- var scroll = JX.Vector.getAggregateScrollForNode(this._dragging);
-
- var origin = {
- x: this._origin.x + (this._originScroll.x - scroll.x),
- y: this._origin.y + (this._originScroll.y - scroll.y)
- };
+ var f = JX.$V(this._frame);
+ p.x -= f.x;
+ p.y -= f.y;
- var adjust_h = 0;
- var adjust_y = 0;
- if (this._target !== false) {
- var ghost = this.getGhostNode();
- adjust_h = JX.Vector.getDim(ghost).y;
- adjust_y = JX.$V(ghost).y;
-
- if (adjust_y <= origin.y) {
- p.y -= adjust_h;
- }
- }
+ p.y += this._offset.y;
+ this._clone.style.top = p.y + 'px';
if (this._canDragX()) {
- p.x -= origin.x;
- } else {
- p.x = 0;
+ p.x += this._offset.x;
+ this._clone.style.left = p.x + 'px';
}
- p.y -= origin.y;
- this._lastAdjust = new JX.Vector(p.x, p.y);
- p.setPos(this._dragging);
-
e.kill();
},
@@ -444,6 +464,10 @@
var dragging = this._dragging;
this._dragging = null;
+ JX.DOM.remove(this._frame);
+ this._frame = null;
+ this._clone = null;
+
var target = false;
var ghost = false;
@@ -469,7 +493,6 @@
for (var ii = 0; ii < group.length; ii++) {
JX.DOM.alterClass(group[ii].getRootNode(), 'drag-target-list', false);
group[ii]._clearTarget();
- group[ii]._lastAdjust = null;
}
if (!this.invoke('didEndDrag', dragging).getPrevented()) {

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 12, 12:11 AM (6 d, 19 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6749200
Default Alt Text
D15160.id.diff (12 KB)

Event Timeline