Index: resources/celerity/map.php =================================================================== --- resources/celerity/map.php +++ resources/celerity/map.php @@ -7,7 +7,7 @@ return array( 'names' => array( - 'core.pkg.css' => '16ef3940', + 'core.pkg.css' => '31a9b9ad', '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' => '00fdad60', + 'rsrc/css/phui/phui-object-item-list-view.css' => '3fd9223e', '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', @@ -145,7 +145,7 @@ 'rsrc/css/phui/phui-status.css' => '2f562399', 'rsrc/css/phui/phui-text.css' => '23e9b4b7', 'rsrc/css/phui/phui-workboard-view.css' => 'bf70dd2e', - 'rsrc/css/phui/phui-workpanel-view.css' => '26f738ce', + 'rsrc/css/phui/phui-workpanel-view.css' => 'ffb31e99', 'rsrc/css/sprite-actions.css' => '4557baf8', 'rsrc/css/sprite-apps-large.css' => 'e37c2ff1', 'rsrc/css/sprite-apps-xlarge.css' => 'db66c878', @@ -392,7 +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-boards.js' => '9c9f91ec', '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', @@ -417,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' => '5fb99faa', + 'rsrc/js/core/DraggableList.js' => '14824eb5', 'rsrc/js/core/DropdownMenu.js' => '2f6f80f4', 'rsrc/js/core/DropdownMenuItem.js' => '0f386ef4', 'rsrc/js/core/FileUpload.js' => '96713558', @@ -603,7 +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-boards' => '9c9f91ec', 'javelin-behavior-project-create' => '065227cc', 'javelin-behavior-refresh-csrf' => 'c4b31646', 'javelin-behavior-releeph-preview-branch' => '9eb2cedb', @@ -675,7 +675,7 @@ 'phabricator-countdown-css' => '86b7b0a0', 'phabricator-crumbs-view-css' => '2d9db584', 'phabricator-drag-and-drop-file-upload' => 'ae6abfba', - 'phabricator-draggable-list' => '5fb99faa', + 'phabricator-draggable-list' => '14824eb5', 'phabricator-dropdown-menu' => '2f6f80f4', 'phabricator-fatal-config-template-css' => '25d446d6', 'phabricator-feed-css' => '4716c86f', @@ -743,7 +743,7 @@ 'phui-info-panel-css' => '27ea50a1', 'phui-list-view-css' => '2edb76cf', 'phui-object-box-css' => '4f916b80', - 'phui-object-item-list-view-css' => '00fdad60', + 'phui-object-item-list-view-css' => '3fd9223e', 'phui-pinboard-view-css' => '53c5fca0', 'phui-property-list-view-css' => '354465ae', 'phui-remarkup-preview-css' => '19ad512b', @@ -751,7 +751,7 @@ 'phui-status-list-view-css' => '2f562399', 'phui-text-css' => '23e9b4b7', 'phui-workboard-view-css' => 'bf70dd2e', - 'phui-workpanel-view-css' => '26f738ce', + 'phui-workpanel-view-css' => 'ffb31e99', 'policy-css' => '957ea14c', 'policy-edit-css' => '05cca26a', 'ponder-comment-table-css' => '6cdccea7', @@ -871,6 +871,15 @@ 4 => 'javelin-util', 5 => 'phabricator-shaped-request', ), + '14824eb5' => + array( + 0 => 'javelin-install', + 1 => 'javelin-dom', + 2 => 'javelin-stratcom', + 3 => 'javelin-util', + 4 => 'javelin-vector', + 5 => 'javelin-magical-init', + ), '1693a296' => array( 0 => 'javelin-behavior', @@ -1155,15 +1164,6 @@ 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', @@ -1400,6 +1400,13 @@ 3 => 'javelin-vector', 4 => 'phabricator-hovercard', ), + '9c9f91ec' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-dom', + 2 => 'javelin-util', + 3 => 'phabricator-draggable-list', + ), '9db3d160' => array( 0 => 'javelin-behavior', @@ -1713,13 +1720,6 @@ 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 @@ -84,6 +84,7 @@ ->setUser($viewer) ->setCards(true) ->setFlush(true) + ->setAllowEmptyList(true) ->addSigil('project-column'); $task_phids = idx($task_map, $column->getPHID(), array()); foreach (array_select_keys($tasks, $task_phids) as $task) { @@ -91,6 +92,10 @@ } $panel->setCards($cards); + if (!$task_phids) { + $cards->addClass('project-column-empty'); + } + $board->addPanel($panel); } Index: src/view/phui/PHUIObjectItemListView.php =================================================================== --- src/view/phui/PHUIObjectItemListView.php +++ src/view/phui/PHUIObjectItemListView.php @@ -10,6 +10,17 @@ private $noDataString; private $flush; private $plain; + private $allowEmptyList; + + + public function setAllowEmptyList($allow_empty_list) { + $this->allowEmptyList = $allow_empty_list; + return $this; + } + + public function getAllowEmptyList() { + return $this->allowEmptyList; + } public function setFlush($flush) { $this->flush = $flush; @@ -92,6 +103,8 @@ if ($this->items) { $items = $this->items; + } else if ($this->allowEmptyList) { + $items = null; } else { $string = nonempty($this->noDataString, pht('No data.')); $items = id(new AphrontErrorView()) 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 @@ -571,8 +571,3 @@ padding-left: 0; padding-top: 0; } - -.drag-target-list { - /* TODO: This is a work in progress. */ - background: red; -} Index: webroot/rsrc/css/phui/phui-workpanel-view.css =================================================================== --- webroot/rsrc/css/phui/phui-workpanel-view.css +++ webroot/rsrc/css/phui/phui-workpanel-view.css @@ -56,7 +56,16 @@ width: 300px; } +.phui-workpanel-body .phui-object-item-list-view { + min-height: 54px; +} + .device .aphront-multi-column-outer div.aphront-multi-column-column-outer .phui-workpanel-body { width: auto; } + +.project-column-empty { + /* TODO: Use this to put some kind of reasonable null state in the columns? */ + background: {$red}; +} Index: webroot/rsrc/js/application/projects/behavior-project-boards.js =================================================================== --- webroot/rsrc/js/application/projects/behavior-project-boards.js +++ webroot/rsrc/js/application/projects/behavior-project-boards.js @@ -12,6 +12,10 @@ return JX.DOM.scry(col, 'li', 'project-card'); } + function onupdate(node) { + JX.DOM.alterClass(node, 'project-column-empty', !this.findItems().length); + } + var lists = []; var ii; var cols = JX.DOM.scry(JX.$(config.boardID), 'ul', 'project-column'); @@ -19,6 +23,10 @@ for (ii = 0; ii < cols.length; ii++) { var list = new JX.DraggableList('project-card', cols[ii]) .setFindItemsHandler(JX.bind(null, finditems, cols[ii])); + + list.listen('didSend', JX.bind(list, onupdate, cols[ii])); + list.listen('didReceive', JX.bind(list, onupdate, cols[ii])); + lists.push(list); } Index: webroot/rsrc/js/core/DraggableList.js =================================================================== --- webroot/rsrc/js/core/DraggableList.js +++ webroot/rsrc/js/core/DraggableList.js @@ -31,7 +31,9 @@ 'didBeginDrag', 'didCancelDrag', 'didEndDrag', - 'didDrop'], + 'didDrop', + 'didSend', + 'didReceive'], properties : { findItemsHandler : null @@ -378,18 +380,28 @@ return; } - var target = this._target; - var dragging = this._dragging; - var ghost = this.getGhostNode(); + var p = JX.$V(e); + var dragging = this._dragging; this._dragging = null; + var target = false; + var ghost = false; + + var target_list = this._getTargetList(p); + if (target_list) { + target = target_list._target; + ghost = target_list.getGhostNode(); + } + JX.$V(0, 0).setPos(dragging); if (target !== false) { JX.DOM.remove(dragging); JX.DOM.replace(ghost, dragging); - this.invoke('didDrop', dragging, target); + this.invoke('didSend', dragging, target_list); + target_list.invoke('didReceive', dragging, this); + target_list.invoke('didDrop', dragging, target, this); } else { this.invoke('didCancelDrag', dragging); }