mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-14 16:51:08 +01:00
Allow tasks to be dragged-and-dropped between workboard columns (UI only)
Summary: Ref T1344. Allows you to drag tasks within a column and between columns, and handles all the multi-column state / targeting / ghosting stuff. This is a UI-only change; you can't actually do anything meaningful with these yet. Roughly, I added the idea of a DraggableList existing within a "group" of draggable lists. Normally, that group only has one item, but on boards it has all of the columns. Then I made all of the relevant operations just apply to the whole group of lists. Test Plan: - Verified existing funtionality in Maniphest and ApplicationSearch is unaffected, by dragging around tasks to reprioritize them and dragging around search items. - Dragged tasks between columns on a board view. {F101196} Reviewers: chad, btrahan Reviewed By: btrahan CC: chad, aran Maniphest Tasks: T1344 Differential Revision: https://secure.phabricator.com/D7941
This commit is contained in:
parent
284465f638
commit
826914e990
5 changed files with 244 additions and 67 deletions
|
@ -7,7 +7,7 @@
|
||||||
return array(
|
return array(
|
||||||
'names' =>
|
'names' =>
|
||||||
array(
|
array(
|
||||||
'core.pkg.css' => '6d59624c',
|
'core.pkg.css' => 'ac7deb21',
|
||||||
'core.pkg.js' => 'c907bd96',
|
'core.pkg.js' => 'c907bd96',
|
||||||
'darkconsole.pkg.js' => 'ca8671ce',
|
'darkconsole.pkg.js' => 'ca8671ce',
|
||||||
'differential.pkg.css' => '827749c1',
|
'differential.pkg.css' => '827749c1',
|
||||||
|
@ -137,7 +137,7 @@ return array(
|
||||||
'rsrc/css/phui/phui-info-panel.css' => '27ea50a1',
|
'rsrc/css/phui/phui-info-panel.css' => '27ea50a1',
|
||||||
'rsrc/css/phui/phui-list.css' => '2edb76cf',
|
'rsrc/css/phui/phui-list.css' => '2edb76cf',
|
||||||
'rsrc/css/phui/phui-object-box.css' => '4f916b80',
|
'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-pinboard-view.css' => '53c5fca0',
|
||||||
'rsrc/css/phui/phui-property-list-view.css' => '354465ae',
|
'rsrc/css/phui/phui-property-list-view.css' => '354465ae',
|
||||||
'rsrc/css/phui/phui-remarkup-preview.css' => '19ad512b',
|
'rsrc/css/phui/phui-remarkup-preview.css' => '19ad512b',
|
||||||
|
@ -392,6 +392,7 @@ return array(
|
||||||
'rsrc/js/application/policy/behavior-policy-control.js' => 'c01153ea',
|
'rsrc/js/application/policy/behavior-policy-control.js' => 'c01153ea',
|
||||||
'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '263aeb8c',
|
'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '263aeb8c',
|
||||||
'rsrc/js/application/ponder/behavior-votebox.js' => '327dbe61',
|
'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/projects/behavior-project-create.js' => '065227cc',
|
||||||
'rsrc/js/application/releeph/releeph-preview-branch.js' => '9eb2cedb',
|
'rsrc/js/application/releeph/releeph-preview-branch.js' => '9eb2cedb',
|
||||||
'rsrc/js/application/releeph/releeph-request-state-change.js' => 'fe7fc914',
|
'rsrc/js/application/releeph/releeph-request-state-change.js' => 'fe7fc914',
|
||||||
|
@ -416,7 +417,7 @@ return array(
|
||||||
'rsrc/js/application/uiexample/notification-example.js' => 'c51a6616',
|
'rsrc/js/application/uiexample/notification-example.js' => 'c51a6616',
|
||||||
'rsrc/js/core/Busy.js' => '6453c869',
|
'rsrc/js/core/Busy.js' => '6453c869',
|
||||||
'rsrc/js/core/DragAndDropFileUpload.js' => 'ae6abfba',
|
'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/DropdownMenu.js' => '2f6f80f4',
|
||||||
'rsrc/js/core/DropdownMenuItem.js' => '0f386ef4',
|
'rsrc/js/core/DropdownMenuItem.js' => '0f386ef4',
|
||||||
'rsrc/js/core/FileUpload.js' => '96713558',
|
'rsrc/js/core/FileUpload.js' => '96713558',
|
||||||
|
@ -602,6 +603,7 @@ return array(
|
||||||
'javelin-behavior-policy-control' => 'c01153ea',
|
'javelin-behavior-policy-control' => 'c01153ea',
|
||||||
'javelin-behavior-policy-rule-editor' => '263aeb8c',
|
'javelin-behavior-policy-rule-editor' => '263aeb8c',
|
||||||
'javelin-behavior-ponder-votebox' => '327dbe61',
|
'javelin-behavior-ponder-votebox' => '327dbe61',
|
||||||
|
'javelin-behavior-project-boards' => 'd4cbe3d5',
|
||||||
'javelin-behavior-project-create' => '065227cc',
|
'javelin-behavior-project-create' => '065227cc',
|
||||||
'javelin-behavior-refresh-csrf' => 'c4b31646',
|
'javelin-behavior-refresh-csrf' => 'c4b31646',
|
||||||
'javelin-behavior-releeph-preview-branch' => '9eb2cedb',
|
'javelin-behavior-releeph-preview-branch' => '9eb2cedb',
|
||||||
|
@ -673,7 +675,7 @@ return array(
|
||||||
'phabricator-countdown-css' => '86b7b0a0',
|
'phabricator-countdown-css' => '86b7b0a0',
|
||||||
'phabricator-crumbs-view-css' => '2d9db584',
|
'phabricator-crumbs-view-css' => '2d9db584',
|
||||||
'phabricator-drag-and-drop-file-upload' => 'ae6abfba',
|
'phabricator-drag-and-drop-file-upload' => 'ae6abfba',
|
||||||
'phabricator-draggable-list' => '6f5a879c',
|
'phabricator-draggable-list' => '5fb99faa',
|
||||||
'phabricator-dropdown-menu' => '2f6f80f4',
|
'phabricator-dropdown-menu' => '2f6f80f4',
|
||||||
'phabricator-fatal-config-template-css' => '25d446d6',
|
'phabricator-fatal-config-template-css' => '25d446d6',
|
||||||
'phabricator-feed-css' => '4716c86f',
|
'phabricator-feed-css' => '4716c86f',
|
||||||
|
@ -741,7 +743,7 @@ return array(
|
||||||
'phui-info-panel-css' => '27ea50a1',
|
'phui-info-panel-css' => '27ea50a1',
|
||||||
'phui-list-view-css' => '2edb76cf',
|
'phui-list-view-css' => '2edb76cf',
|
||||||
'phui-object-box-css' => '4f916b80',
|
'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-pinboard-view-css' => '53c5fca0',
|
||||||
'phui-property-list-view-css' => '354465ae',
|
'phui-property-list-view-css' => '354465ae',
|
||||||
'phui-remarkup-preview-css' => '19ad512b',
|
'phui-remarkup-preview-css' => '19ad512b',
|
||||||
|
@ -1153,6 +1155,15 @@ return array(
|
||||||
array(
|
array(
|
||||||
0 => 'javelin-install',
|
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' =>
|
'61d927ec' =>
|
||||||
array(
|
array(
|
||||||
0 => 'javelin-behavior',
|
0 => 'javelin-behavior',
|
||||||
|
@ -1192,15 +1203,6 @@ return array(
|
||||||
1 => 'javelin-dom',
|
1 => 'javelin-dom',
|
||||||
2 => 'javelin-workflow',
|
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' =>
|
'71755c79' =>
|
||||||
array(
|
array(
|
||||||
0 => 'javelin-behavior',
|
0 => 'javelin-behavior',
|
||||||
|
@ -1711,6 +1713,13 @@ return array(
|
||||||
1 => 'javelin-dom',
|
1 => 'javelin-dom',
|
||||||
2 => 'javelin-view',
|
2 => 'javelin-view',
|
||||||
),
|
),
|
||||||
|
'd4cbe3d5' =>
|
||||||
|
array(
|
||||||
|
0 => 'javelin-behavior',
|
||||||
|
1 => 'javelin-dom',
|
||||||
|
2 => 'javelin-util',
|
||||||
|
3 => 'phabricator-draggable-list',
|
||||||
|
),
|
||||||
'd6ca6b1c' =>
|
'd6ca6b1c' =>
|
||||||
array(
|
array(
|
||||||
0 => 'javelin-install',
|
0 => 'javelin-install',
|
||||||
|
|
|
@ -61,9 +61,18 @@ final class PhabricatorProjectBoardController
|
||||||
$task_map[$default_phid][] = $task->getPHID();
|
$task_map[$default_phid][] = $task->getPHID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$board_id = celerity_generate_unique_node_id();
|
||||||
|
|
||||||
$board = id(new PHUIWorkboardView())
|
$board = id(new PHUIWorkboardView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setFluidishLayout(true);
|
->setFluidishLayout(true)
|
||||||
|
->setID($board_id);
|
||||||
|
|
||||||
|
$this->initBehavior(
|
||||||
|
'project-boards',
|
||||||
|
array(
|
||||||
|
'boardID' => $board_id,
|
||||||
|
));
|
||||||
|
|
||||||
foreach ($columns as $column) {
|
foreach ($columns as $column) {
|
||||||
$panel = id(new PHUIWorkpanelView())
|
$panel = id(new PHUIWorkpanelView())
|
||||||
|
@ -74,7 +83,8 @@ final class PhabricatorProjectBoardController
|
||||||
$cards = id(new PHUIObjectItemListView())
|
$cards = id(new PHUIObjectItemListView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setCards(true)
|
->setCards(true)
|
||||||
->setFlush(true);
|
->setFlush(true)
|
||||||
|
->addSigil('project-column');
|
||||||
$task_phids = idx($task_map, $column->getPHID(), array());
|
$task_phids = idx($task_map, $column->getPHID(), array());
|
||||||
foreach (array_select_keys($tasks, $task_phids) as $task) {
|
foreach (array_select_keys($tasks, $task_phids) as $task) {
|
||||||
$cards->addItem($this->renderTaskCard($task));
|
$cards->addItem($this->renderTaskCard($task));
|
||||||
|
@ -148,6 +158,7 @@ final class PhabricatorProjectBoardController
|
||||||
->setHeader($task->getTitle())
|
->setHeader($task->getTitle())
|
||||||
->setGrippable($can_edit)
|
->setGrippable($can_edit)
|
||||||
->setHref('/T'.$task->getID())
|
->setHref('/T'.$task->getID())
|
||||||
|
->addSigil('project-card')
|
||||||
->addAction(
|
->addAction(
|
||||||
id(new PHUIListItemView())
|
id(new PHUIListItemView())
|
||||||
->setName(pht('Edit'))
|
->setName(pht('Edit'))
|
||||||
|
|
|
@ -572,3 +572,7 @@
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.drag-target-list {
|
||||||
|
/* TODO: This is a work in progress. */
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
|
@ -14,6 +14,7 @@ JX.install('DraggableList', {
|
||||||
construct : function(sigil, root) {
|
construct : function(sigil, root) {
|
||||||
this._sigil = sigil;
|
this._sigil = sigil;
|
||||||
this._root = root || document.body;
|
this._root = root || document.body;
|
||||||
|
this._group = [this];
|
||||||
|
|
||||||
// NOTE: Javelin does not dispatch mousemove by default.
|
// NOTE: Javelin does not dispatch mousemove by default.
|
||||||
JX.enableDispatch(document.body, 'mousemove');
|
JX.enableDispatch(document.body, 'mousemove');
|
||||||
|
@ -46,6 +47,11 @@ JX.install('DraggableList', {
|
||||||
_dimensions : null,
|
_dimensions : null,
|
||||||
_ghostHandler : null,
|
_ghostHandler : null,
|
||||||
_ghostNode : null,
|
_ghostNode : null,
|
||||||
|
_group : null,
|
||||||
|
|
||||||
|
getRootNode : function() {
|
||||||
|
return this._root;
|
||||||
|
},
|
||||||
|
|
||||||
setGhostHandler : function(handler) {
|
setGhostHandler : function(handler) {
|
||||||
this._ghostHandler = handler;
|
this._ghostHandler = handler;
|
||||||
|
@ -68,8 +74,41 @@ JX.install('DraggableList', {
|
||||||
return this;
|
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) {
|
_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) {
|
if (target && target.nextSibling) {
|
||||||
parent.insertBefore(ghost, target.nextSibling);
|
parent.insertBefore(ghost, target.nextSibling);
|
||||||
} else if (!target && parent.firstChild) {
|
} else if (!target && parent.firstChild) {
|
||||||
|
@ -116,6 +155,24 @@ JX.install('DraggableList', {
|
||||||
this._origin = JX.$V(e);
|
this._origin = JX.$V(e);
|
||||||
this._dimensions = JX.$V(this._dragging);
|
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 targets = [];
|
||||||
var items = this.findItems();
|
var items = this.findItems();
|
||||||
for (var ii = 0; ii < items.length; ii++) {
|
for (var ii = 0; ii < items.length; ii++) {
|
||||||
|
@ -126,30 +183,73 @@ JX.install('DraggableList', {
|
||||||
}
|
}
|
||||||
targets.sort(function(u, v) { return v.y - u.y; });
|
targets.sort(function(u, v) { return v.y - u.y; });
|
||||||
this._targets = targets;
|
this._targets = targets;
|
||||||
this._target = false;
|
|
||||||
|
|
||||||
if (!this.invoke('didBeginDrag', this._dragging).getPrevented()) {
|
return this;
|
||||||
var ghost = this.getGhostNode();
|
|
||||||
ghost.style.height = JX.Vector.getDim(this._dragging).y + 'px';
|
|
||||||
JX.DOM.alterClass(this._dragging, 'drag-dragging', true);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onmove : function(e) {
|
_getTargetList : function(p) {
|
||||||
if (!this._dragging) {
|
var target_list;
|
||||||
return;
|
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;
|
||||||
|
},
|
||||||
|
|
||||||
|
_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 ghost = this.getGhostNode();
|
||||||
var target = this._target;
|
var target = this._target;
|
||||||
var targets = this._targets;
|
var targets = this._targets;
|
||||||
var dragging = this._dragging;
|
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_h = JX.Vector.getDim(ghost).y;
|
||||||
var adjust_y = JX.$V(ghost).y;
|
var adjust_y = JX.$V(ghost).y;
|
||||||
|
@ -187,11 +287,16 @@ JX.install('DraggableList', {
|
||||||
// Don't choose the dragged row or its predecessor as targets.
|
// Don't choose the dragged row or its predecessor as targets.
|
||||||
|
|
||||||
cur_target = targets[ii].item;
|
cur_target = targets[ii].item;
|
||||||
if (cur_target == dragging) {
|
if (!dragging) {
|
||||||
cur_target = false;
|
// If the item on the cursor isn't from this list, it can't be
|
||||||
}
|
// dropped onto itself or its predecessor in this list.
|
||||||
if (targets[ii - 1] && targets[ii - 1].item == dragging) {
|
} else {
|
||||||
cur_target = false;
|
if (cur_target == dragging) {
|
||||||
|
cur_target = false;
|
||||||
|
}
|
||||||
|
if (targets[ii - 1] && targets[ii - 1].item == dragging) {
|
||||||
|
cur_target = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -199,41 +304,42 @@ JX.install('DraggableList', {
|
||||||
|
|
||||||
// If the dragged row is the first row, don't allow it to be dragged
|
// 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.
|
// 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;
|
var first_item = targets[targets.length - 1].item;
|
||||||
if (dragging === first_item) {
|
if (dragging === first_item) {
|
||||||
cur_target = false;
|
cur_target = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return cur_target;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onmove : function(e) {
|
||||||
|
if (!this._dragging) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var p = JX.$V(e);
|
||||||
|
|
||||||
|
var group = this._group;
|
||||||
|
var target_list = this._getTargetList(p);
|
||||||
|
|
||||||
|
// Compute the size and position of the drop target indicator, because we
|
||||||
|
// need to update our static position computations to account for it.
|
||||||
|
|
||||||
|
var cur_target = false;
|
||||||
|
if (target_list) {
|
||||||
|
cur_target = target_list._getCurrentTarget(p);
|
||||||
|
}
|
||||||
|
|
||||||
// If we've selected a new target, update the UI to show where we're
|
// If we've selected a new target, update the UI to show where we're
|
||||||
// going to drop the row.
|
// going to drop the row.
|
||||||
|
|
||||||
if (cur_target !== target) {
|
for (var ii = 0; ii < group.length; ii++) {
|
||||||
|
if (group[ii] == target_list) {
|
||||||
if (target !== false) {
|
group[ii]._setTarget(cur_target);
|
||||||
JX.DOM.remove(ghost);
|
} else {
|
||||||
}
|
group[ii]._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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
target = cur_target;
|
|
||||||
|
|
||||||
if (target !== false) {
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
|
|
||||||
adjust_h = JX.Vector.getDim(ghost).y;
|
|
||||||
adjust_y = JX.$V(ghost).y;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,16 +347,28 @@ JX.install('DraggableList', {
|
||||||
// adjust the cursor position for the change in node document position.
|
// adjust the cursor position for the change in node document position.
|
||||||
// Do this before choosing a new target to avoid a flash of nonsense.
|
// 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) {
|
if (adjust_y <= origin.y) {
|
||||||
p.y -= adjust_h;
|
p.y -= adjust_h;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.x = 0;
|
if (this._canDragX()) {
|
||||||
|
p.x -= origin.x;
|
||||||
|
} else {
|
||||||
|
p.x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
p.y -= origin.y;
|
p.y -= origin.y;
|
||||||
p.setPos(dragging);
|
p.setPos(this._dragging);
|
||||||
this._target = target;
|
|
||||||
|
|
||||||
e.kill();
|
e.kill();
|
||||||
},
|
},
|
||||||
|
@ -276,6 +394,12 @@ JX.install('DraggableList', {
|
||||||
this.invoke('didCancelDrag', dragging);
|
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()) {
|
if (!this.invoke('didEndDrag', dragging).getPrevented()) {
|
||||||
JX.DOM.alterClass(dragging, 'drag-dragging', false);
|
JX.DOM.alterClass(dragging, 'drag-dragging', false);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue