Page MenuHomePhabricator

D7941.diff
No OneTemporary

D7941.diff

Index: resources/celerity/map.php
===================================================================
--- resources/celerity/map.php
+++ resources/celerity/map.php
@@ -7,7 +7,7 @@
return array(
'names' =>
array(
- 'core.pkg.css' => '6d59624c',
+ 'core.pkg.css' => 'ac7deb21',
'core.pkg.js' => 'c907bd96',
'darkconsole.pkg.js' => 'ca8671ce',
'differential.pkg.css' => '827749c1',
@@ -137,7 +137,7 @@
'rsrc/css/phui/phui-info-panel.css' => '27ea50a1',
'rsrc/css/phui/phui-list.css' => '2edb76cf',
'rsrc/css/phui/phui-object-box.css' => '4f916b80',
- 'rsrc/css/phui/phui-object-item-list-view.css' => '642fe6b9',
+ 'rsrc/css/phui/phui-object-item-list-view.css' => 'fdd2c06f',
'rsrc/css/phui/phui-pinboard-view.css' => '53c5fca0',
'rsrc/css/phui/phui-property-list-view.css' => '354465ae',
'rsrc/css/phui/phui-remarkup-preview.css' => '19ad512b',
@@ -392,6 +392,7 @@
'rsrc/js/application/policy/behavior-policy-control.js' => 'c01153ea',
'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '263aeb8c',
'rsrc/js/application/ponder/behavior-votebox.js' => '327dbe61',
+ 'rsrc/js/application/projects/behavior-project-boards.js' => 'd4cbe3d5',
'rsrc/js/application/projects/behavior-project-create.js' => '065227cc',
'rsrc/js/application/releeph/releeph-preview-branch.js' => '9eb2cedb',
'rsrc/js/application/releeph/releeph-request-state-change.js' => 'fe7fc914',
@@ -416,7 +417,7 @@
'rsrc/js/application/uiexample/notification-example.js' => 'c51a6616',
'rsrc/js/core/Busy.js' => '6453c869',
'rsrc/js/core/DragAndDropFileUpload.js' => 'ae6abfba',
- 'rsrc/js/core/DraggableList.js' => '6f5a879c',
+ 'rsrc/js/core/DraggableList.js' => '5fb99faa',
'rsrc/js/core/DropdownMenu.js' => '2f6f80f4',
'rsrc/js/core/DropdownMenuItem.js' => '0f386ef4',
'rsrc/js/core/FileUpload.js' => '96713558',
@@ -602,6 +603,7 @@
'javelin-behavior-policy-control' => 'c01153ea',
'javelin-behavior-policy-rule-editor' => '263aeb8c',
'javelin-behavior-ponder-votebox' => '327dbe61',
+ 'javelin-behavior-project-boards' => 'd4cbe3d5',
'javelin-behavior-project-create' => '065227cc',
'javelin-behavior-refresh-csrf' => 'c4b31646',
'javelin-behavior-releeph-preview-branch' => '9eb2cedb',
@@ -673,7 +675,7 @@
'phabricator-countdown-css' => '86b7b0a0',
'phabricator-crumbs-view-css' => '2d9db584',
'phabricator-drag-and-drop-file-upload' => 'ae6abfba',
- 'phabricator-draggable-list' => '6f5a879c',
+ 'phabricator-draggable-list' => '5fb99faa',
'phabricator-dropdown-menu' => '2f6f80f4',
'phabricator-fatal-config-template-css' => '25d446d6',
'phabricator-feed-css' => '4716c86f',
@@ -741,7 +743,7 @@
'phui-info-panel-css' => '27ea50a1',
'phui-list-view-css' => '2edb76cf',
'phui-object-box-css' => '4f916b80',
- 'phui-object-item-list-view-css' => '642fe6b9',
+ 'phui-object-item-list-view-css' => 'fdd2c06f',
'phui-pinboard-view-css' => '53c5fca0',
'phui-property-list-view-css' => '354465ae',
'phui-remarkup-preview-css' => '19ad512b',
@@ -1153,6 +1155,15 @@
array(
0 => 'javelin-install',
),
+ '5fb99faa' =>
+ array(
+ 0 => 'javelin-install',
+ 1 => 'javelin-dom',
+ 2 => 'javelin-stratcom',
+ 3 => 'javelin-util',
+ 4 => 'javelin-vector',
+ 5 => 'javelin-magical-init',
+ ),
'61d927ec' =>
array(
0 => 'javelin-behavior',
@@ -1192,15 +1203,6 @@
1 => 'javelin-dom',
2 => 'javelin-workflow',
),
- '6f5a879c' =>
- array(
- 0 => 'javelin-install',
- 1 => 'javelin-dom',
- 2 => 'javelin-stratcom',
- 3 => 'javelin-util',
- 4 => 'javelin-vector',
- 5 => 'javelin-magical-init',
- ),
'71755c79' =>
array(
0 => 'javelin-behavior',
@@ -1711,6 +1713,13 @@
1 => 'javelin-dom',
2 => 'javelin-view',
),
+ 'd4cbe3d5' =>
+ array(
+ 0 => 'javelin-behavior',
+ 1 => 'javelin-dom',
+ 2 => 'javelin-util',
+ 3 => 'phabricator-draggable-list',
+ ),
'd6ca6b1c' =>
array(
0 => 'javelin-install',
Index: src/applications/project/controller/PhabricatorProjectBoardController.php
===================================================================
--- src/applications/project/controller/PhabricatorProjectBoardController.php
+++ src/applications/project/controller/PhabricatorProjectBoardController.php
@@ -61,9 +61,18 @@
$task_map[$default_phid][] = $task->getPHID();
}
+ $board_id = celerity_generate_unique_node_id();
+
$board = id(new PHUIWorkboardView())
->setUser($viewer)
- ->setFluidishLayout(true);
+ ->setFluidishLayout(true)
+ ->setID($board_id);
+
+ $this->initBehavior(
+ 'project-boards',
+ array(
+ 'boardID' => $board_id,
+ ));
foreach ($columns as $column) {
$panel = id(new PHUIWorkpanelView())
@@ -74,7 +83,8 @@
$cards = id(new PHUIObjectItemListView())
->setUser($viewer)
->setCards(true)
- ->setFlush(true);
+ ->setFlush(true)
+ ->addSigil('project-column');
$task_phids = idx($task_map, $column->getPHID(), array());
foreach (array_select_keys($tasks, $task_phids) as $task) {
$cards->addItem($this->renderTaskCard($task));
@@ -148,6 +158,7 @@
->setHeader($task->getTitle())
->setGrippable($can_edit)
->setHref('/T'.$task->getID())
+ ->addSigil('project-card')
->addAction(
id(new PHUIListItemView())
->setName(pht('Edit'))
Index: webroot/rsrc/css/phui/phui-object-item-list-view.css
===================================================================
--- webroot/rsrc/css/phui/phui-object-item-list-view.css
+++ webroot/rsrc/css/phui/phui-object-item-list-view.css
@@ -572,3 +572,7 @@
padding-top: 0;
}
+.drag-target-list {
+ /* TODO: This is a work in progress. */
+ background: red;
+}
Index: webroot/rsrc/js/application/projects/behavior-project-boards.js
===================================================================
--- /dev/null
+++ webroot/rsrc/js/application/projects/behavior-project-boards.js
@@ -0,0 +1,29 @@
+/**
+ * @provides javelin-behavior-project-boards
+ * @requires javelin-behavior
+ * javelin-dom
+ * javelin-util
+ * phabricator-draggable-list
+ */
+
+JX.behavior('project-boards', function(config) {
+
+ function finditems(col) {
+ return JX.DOM.scry(col, 'li', 'project-card');
+ }
+
+ var lists = [];
+ var ii;
+ var cols = JX.DOM.scry(JX.$(config.boardID), 'ul', 'project-column');
+
+ for (ii = 0; ii < cols.length; ii++) {
+ var list = new JX.DraggableList('project-card', cols[ii])
+ .setFindItemsHandler(JX.bind(null, finditems, cols[ii]));
+ lists.push(list);
+ }
+
+ for (ii = 0; ii < lists.length; ii++) {
+ lists[ii].setGroup(lists);
+ }
+
+});
Index: webroot/rsrc/js/core/DraggableList.js
===================================================================
--- webroot/rsrc/js/core/DraggableList.js
+++ webroot/rsrc/js/core/DraggableList.js
@@ -14,6 +14,7 @@
construct : function(sigil, root) {
this._sigil = sigil;
this._root = root || document.body;
+ this._group = [this];
// NOTE: Javelin does not dispatch mousemove by default.
JX.enableDispatch(document.body, 'mousemove');
@@ -46,6 +47,11 @@
_dimensions : null,
_ghostHandler : null,
_ghostNode : null,
+ _group : null,
+
+ getRootNode : function() {
+ return this._root;
+ },
setGhostHandler : function(handler) {
this._ghostHandler = handler;
@@ -68,8 +74,41 @@
return this;
},
+ setGroup : function(lists) {
+ var result = [];
+ var need_self = true;
+ for (var ii = 0; ii < lists.length; ii++) {
+ if (lists[ii] == this) {
+ need_self = false;
+ }
+ result.push(lists[ii]);
+ }
+
+ if (need_self) {
+ result.push(this);
+ }
+
+ this._group = result;
+ return this;
+ },
+
+ _canDragX : function() {
+ return this._hasGroup();
+ },
+
+ _hasGroup : function() {
+ return (this._group.length > 1);
+ },
+
_defaultGhostHandler : function(ghost, target) {
- var parent = this._dragging.parentNode;
+ var parent;
+
+ if (!this._hasGroup()) {
+ parent = this._dragging.parentNode;
+ } else {
+ parent = this.getRootNode();
+ }
+
if (target && target.nextSibling) {
parent.insertBefore(ghost, target.nextSibling);
} else if (!target && parent.firstChild) {
@@ -116,6 +155,24 @@
this._origin = JX.$V(e);
this._dimensions = JX.$V(this._dragging);
+ for (var ii = 0; ii < this._group.length; ii++) {
+ this._group[ii]._clearTarget();
+ this._group[ii]._generateTargets();
+ }
+
+ 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';
+ }
+
+ JX.DOM.alterClass(this._dragging, 'drag-dragging', true);
+ }
+ },
+
+ _generateTargets : function() {
var targets = [];
var items = this.findItems();
for (var ii = 0; ii < items.length; ii++) {
@@ -126,30 +183,73 @@
}
targets.sort(function(u, v) { return v.y - u.y; });
this._targets = targets;
- this._target = false;
- if (!this.invoke('didBeginDrag', this._dragging).getPrevented()) {
- var ghost = this.getGhostNode();
- ghost.style.height = JX.Vector.getDim(this._dragging).y + 'px';
- JX.DOM.alterClass(this._dragging, 'drag-dragging', true);
+ return this;
+ },
+
+ _getTargetList : function(p) {
+ var target_list;
+ if (this._hasGroup()) {
+ var group = this._group;
+ for (var ii = 0; ii < group.length; ii++) {
+ var root = group[ii].getRootNode();
+ var rp = JX.$V(root);
+ var rd = JX.Vector.getDim(root);
+
+ var is_target = false;
+ if (p.x >= rp.x && p.y >= rp.y) {
+ if (p.x <= (rp.x + rd.x) && p.y <= (rp.y + rd.y)) {
+ is_target = true;
+ target_list = group[ii];
+ }
+ }
+
+ JX.DOM.alterClass(root, 'drag-target-list', is_target);
+ }
+ } else {
+ target_list = this;
}
+
+ return target_list;
},
- _onmove : function(e) {
- if (!this._dragging) {
- return;
+ _setTarget : function(cur_target) {
+ var ghost = this.getGhostNode();
+ var target = this._target;
+
+ if (cur_target !== target) {
+ this._clearTarget();
+ if (cur_target !== false) {
+ var ok = this.getGhostHandler()(ghost, cur_target);
+ // If the handler returns explicit `false`, prevent the drag.
+ if (ok === false) {
+ cur_target = false;
+ }
+ }
+
+ this._target = cur_target;
+ }
+
+ return this;
+ },
+
+ _clearTarget : function() {
+ var target = this._target;
+ var ghost = this.getGhostNode();
+
+ if (target !== false) {
+ JX.DOM.remove(ghost);
}
+ this._target = false;
+ return this;
+ },
+
+ _getCurrentTarget : function(p) {
var ghost = this.getGhostNode();
var target = this._target;
var targets = this._targets;
var dragging = this._dragging;
- var origin = this._origin;
-
- var p = JX.$V(e);
-
- // Compute the size and position of the drop target indicator, because we
- // need to update our static position computations to account for it.
var adjust_h = JX.Vector.getDim(ghost).y;
var adjust_y = JX.$V(ghost).y;
@@ -187,11 +287,16 @@
// Don't choose the dragged row or its predecessor as targets.
cur_target = targets[ii].item;
- if (cur_target == dragging) {
- cur_target = false;
- }
- if (targets[ii - 1] && targets[ii - 1].item == dragging) {
- cur_target = false;
+ if (!dragging) {
+ // If the item on the cursor isn't from this list, it can't be
+ // dropped onto itself or its predecessor in this list.
+ } else {
+ if (cur_target == dragging) {
+ cur_target = false;
+ }
+ if (targets[ii - 1] && targets[ii - 1].item == dragging) {
+ cur_target = false;
+ }
}
break;
@@ -199,41 +304,42 @@
// If the dragged row is the first row, don't allow it to be dragged
// into the first position, since this operation doesn't make sense.
- if (cur_target === null) {
+ if (dragging && cur_target === null) {
var first_item = targets[targets.length - 1].item;
if (dragging === first_item) {
cur_target = false;
}
}
- // If we've selected a new target, update the UI to show where we're
- // going to drop the row.
+ return cur_target;
+ },
- if (cur_target !== target) {
+ _onmove : function(e) {
+ if (!this._dragging) {
+ return;
+ }
- if (target !== false) {
- JX.DOM.remove(ghost);
- }
+ var p = JX.$V(e);
- if (cur_target !== false) {
- var ok = this.getGhostHandler()(ghost, cur_target);
- // If the handler returns explicit `false`, prevent the drag.
- if (ok === false) {
- cur_target = false;
- }
- }
+ var group = this._group;
+ var target_list = this._getTargetList(p);
- target = cur_target;
+ // Compute the size and position of the drop target indicator, because we
+ // need to update our static position computations to account for it.
- if (target !== false) {
+ var cur_target = false;
+ if (target_list) {
+ cur_target = target_list._getCurrentTarget(p);
+ }
- // If we've changed where the ghost node is, update the adjustments
- // so we accurately reflect document state when we tweak things below.
- // This avoids a flash of bad state as the mouse is dragged upward
- // across the document.
+ // If we've selected a new target, update the UI to show where we're
+ // going to drop the row.
- adjust_h = JX.Vector.getDim(ghost).y;
- adjust_y = JX.$V(ghost).y;
+ for (var ii = 0; ii < group.length; ii++) {
+ if (group[ii] == target_list) {
+ group[ii]._setTarget(cur_target);
+ } else {
+ group[ii]._clearTarget();
}
}
@@ -241,16 +347,28 @@
// adjust the cursor position for the change in node document position.
// Do this before choosing a new target to avoid a flash of nonsense.
- if (target !== false) {
+ var origin = this._origin;
+
+ 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.x = 0;
+ if (this._canDragX()) {
+ p.x -= origin.x;
+ } else {
+ p.x = 0;
+ }
+
p.y -= origin.y;
- p.setPos(dragging);
- this._target = target;
+ p.setPos(this._dragging);
e.kill();
},
@@ -276,6 +394,12 @@
this.invoke('didCancelDrag', dragging);
}
+ var group = this._group;
+ for (var ii = 0; ii < group.length; ii++) {
+ JX.DOM.alterClass(group[ii].getRootNode(), 'drag-target-list', false);
+ group[ii]._clearTarget();
+ }
+
if (!this.invoke('didEndDrag', dragging).getPrevented()) {
JX.DOM.alterClass(dragging, 'drag-dragging', false);
}

File Metadata

Mime Type
text/plain
Expires
Wed, Mar 5, 2:11 PM (16 h, 40 m ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7225740
Default Alt Text
D7941.diff (15 KB)

Event Timeline