diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php
index 5a0c1c88e2..b5cd31bcf7 100644
--- a/src/__celerity_resource_map__.php
+++ b/src/__celerity_resource_map__.php
@@ -1638,13 +1638,14 @@ celerity_register_resource_map(array(
),
'javelin-behavior-maniphest-batch-selector' =>
array(
- 'uri' => '/res/398cf8d7/rsrc/js/application/maniphest/behavior-batch-selector.js',
+ 'uri' => '/res/f8cf3b84/rsrc/js/application/maniphest/behavior-batch-selector.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'javelin-stratcom',
+ 3 => 'javelin-util',
),
'disk' => '/rsrc/js/application/maniphest/behavior-batch-selector.js',
),
@@ -1663,7 +1664,7 @@ celerity_register_resource_map(array(
),
'javelin-behavior-maniphest-subpriority-editor' =>
array(
- 'uri' => '/res/5e02f19a/rsrc/js/application/maniphest/behavior-subpriorityeditor.js',
+ 'uri' => '/res/21b73c2a/rsrc/js/application/maniphest/behavior-subpriorityeditor.js',
'type' => 'js',
'requires' =>
array(
@@ -2632,7 +2633,7 @@ celerity_register_resource_map(array(
),
'maniphest-task-summary-css' =>
array(
- 'uri' => '/res/b3930263/rsrc/css/application/maniphest/task-summary.css',
+ 'uri' => '/res/7aa9e2eb/rsrc/css/application/maniphest/task-summary.css',
'type' => 'css',
'requires' =>
array(
@@ -2995,7 +2996,7 @@ celerity_register_resource_map(array(
),
'phabricator-object-item-list-view-css' =>
array(
- 'uri' => '/res/aa09c531/rsrc/css/layout/phabricator-object-item-list-view.css',
+ 'uri' => '/res/7d35d590/rsrc/css/layout/phabricator-object-item-list-view.css',
'type' => 'css',
'requires' =>
array(
@@ -3693,7 +3694,7 @@ celerity_register_resource_map(array(
), array(
'packages' =>
array(
- '6c294512' =>
+ 'a56848af' =>
array(
'name' => 'core.pkg.css',
'symbols' =>
@@ -3735,7 +3736,7 @@ celerity_register_resource_map(array(
34 => 'phabricator-object-item-list-view-css',
35 => 'global-drag-and-drop-css',
),
- 'uri' => '/res/pkg/6c294512/core.pkg.css',
+ 'uri' => '/res/pkg/a56848af/core.pkg.css',
'type' => 'css',
),
'95ceba95' =>
@@ -3895,7 +3896,7 @@ celerity_register_resource_map(array(
'uri' => '/res/pkg/fe22443b/javelin.pkg.js',
'type' => 'js',
),
- 'c41b4907' =>
+ '6b1fccc6' =>
array(
'name' => 'maniphest.pkg.css',
'symbols' =>
@@ -3905,10 +3906,10 @@ celerity_register_resource_map(array(
2 => 'aphront-attached-file-view-css',
3 => 'phabricator-project-tag-css',
),
- 'uri' => '/res/pkg/c41b4907/maniphest.pkg.css',
+ 'uri' => '/res/pkg/6b1fccc6/maniphest.pkg.css',
'type' => 'css',
),
- '7707de41' =>
+ 'f85eb6d8' =>
array(
'name' => 'maniphest.pkg.js',
'symbols' =>
@@ -3919,23 +3920,23 @@ celerity_register_resource_map(array(
3 => 'javelin-behavior-maniphest-transaction-expand',
4 => 'javelin-behavior-maniphest-subpriority-editor',
),
- 'uri' => '/res/pkg/7707de41/maniphest.pkg.js',
+ 'uri' => '/res/pkg/f85eb6d8/maniphest.pkg.js',
'type' => 'js',
),
),
'reverse' =>
array(
- 'aphront-attached-file-view-css' => 'c41b4907',
- 'aphront-dialog-view-css' => '6c294512',
- 'aphront-error-view-css' => '6c294512',
- 'aphront-form-view-css' => '6c294512',
- 'aphront-list-filter-view-css' => '6c294512',
- 'aphront-pager-view-css' => '6c294512',
- 'aphront-panel-view-css' => '6c294512',
- 'aphront-table-view-css' => '6c294512',
- 'aphront-tokenizer-control-css' => '6c294512',
- 'aphront-tooltip-css' => '6c294512',
- 'aphront-typeahead-control-css' => '6c294512',
+ 'aphront-attached-file-view-css' => '6b1fccc6',
+ 'aphront-dialog-view-css' => 'a56848af',
+ 'aphront-error-view-css' => 'a56848af',
+ 'aphront-form-view-css' => 'a56848af',
+ 'aphront-list-filter-view-css' => 'a56848af',
+ 'aphront-pager-view-css' => 'a56848af',
+ 'aphront-panel-view-css' => 'a56848af',
+ 'aphront-table-view-css' => 'a56848af',
+ 'aphront-tokenizer-control-css' => 'a56848af',
+ 'aphront-tooltip-css' => 'a56848af',
+ 'aphront-typeahead-control-css' => 'a56848af',
'differential-changeset-view-css' => '8aaacd1b',
'differential-core-view-css' => '8aaacd1b',
'differential-inline-comment-editor' => '322728f3',
@@ -3949,7 +3950,7 @@ celerity_register_resource_map(array(
'differential-table-of-contents-css' => '8aaacd1b',
'diffusion-commit-view-css' => 'c8ce2d88',
'diffusion-icons-css' => 'c8ce2d88',
- 'global-drag-and-drop-css' => '6c294512',
+ 'global-drag-and-drop-css' => 'a56848af',
'inline-comment-summary-css' => '8aaacd1b',
'javelin-aphlict' => '95ceba95',
'javelin-behavior' => 'fe22443b',
@@ -3982,11 +3983,11 @@ celerity_register_resource_map(array(
'javelin-behavior-konami' => '95ceba95',
'javelin-behavior-lightbox-attachments' => '95ceba95',
'javelin-behavior-load-blame' => '322728f3',
- 'javelin-behavior-maniphest-batch-selector' => '7707de41',
- 'javelin-behavior-maniphest-subpriority-editor' => '7707de41',
- 'javelin-behavior-maniphest-transaction-controls' => '7707de41',
- 'javelin-behavior-maniphest-transaction-expand' => '7707de41',
- 'javelin-behavior-maniphest-transaction-preview' => '7707de41',
+ 'javelin-behavior-maniphest-batch-selector' => 'f85eb6d8',
+ 'javelin-behavior-maniphest-subpriority-editor' => 'f85eb6d8',
+ 'javelin-behavior-maniphest-transaction-controls' => 'f85eb6d8',
+ 'javelin-behavior-maniphest-transaction-expand' => 'f85eb6d8',
+ 'javelin-behavior-maniphest-transaction-preview' => 'f85eb6d8',
'javelin-behavior-phabricator-active-nav' => '95ceba95',
'javelin-behavior-phabricator-autofocus' => '95ceba95',
'javelin-behavior-phabricator-gesture' => '95ceba95',
@@ -4021,48 +4022,48 @@ celerity_register_resource_map(array(
'javelin-util' => 'fe22443b',
'javelin-vector' => 'fe22443b',
'javelin-workflow' => 'fe22443b',
- 'lightbox-attachment-css' => '6c294512',
- 'maniphest-task-summary-css' => 'c41b4907',
- 'maniphest-transaction-detail-css' => 'c41b4907',
+ 'lightbox-attachment-css' => 'a56848af',
+ 'maniphest-task-summary-css' => '6b1fccc6',
+ 'maniphest-transaction-detail-css' => '6b1fccc6',
'phabricator-busy' => '95ceba95',
'phabricator-content-source-view-css' => '8aaacd1b',
- 'phabricator-core-buttons-css' => '6c294512',
- 'phabricator-core-css' => '6c294512',
- 'phabricator-crumbs-view-css' => '6c294512',
- 'phabricator-directory-css' => '6c294512',
+ 'phabricator-core-buttons-css' => 'a56848af',
+ 'phabricator-core-css' => 'a56848af',
+ 'phabricator-crumbs-view-css' => 'a56848af',
+ 'phabricator-directory-css' => 'a56848af',
'phabricator-drag-and-drop-file-upload' => '322728f3',
'phabricator-dropdown-menu' => '95ceba95',
'phabricator-file-upload' => '95ceba95',
- 'phabricator-filetree-view-css' => '6c294512',
- 'phabricator-flag-css' => '6c294512',
- 'phabricator-form-view-css' => '6c294512',
- 'phabricator-header-view-css' => '6c294512',
- 'phabricator-jump-nav' => '6c294512',
+ 'phabricator-filetree-view-css' => 'a56848af',
+ 'phabricator-flag-css' => 'a56848af',
+ 'phabricator-form-view-css' => 'a56848af',
+ 'phabricator-header-view-css' => 'a56848af',
+ 'phabricator-jump-nav' => 'a56848af',
'phabricator-keyboard-shortcut' => '95ceba95',
'phabricator-keyboard-shortcut-manager' => '95ceba95',
- 'phabricator-main-menu-view' => '6c294512',
+ 'phabricator-main-menu-view' => 'a56848af',
'phabricator-menu-item' => '95ceba95',
- 'phabricator-nav-view-css' => '6c294512',
+ 'phabricator-nav-view-css' => 'a56848af',
'phabricator-notification' => '95ceba95',
- 'phabricator-notification-css' => '6c294512',
- 'phabricator-notification-menu-css' => '6c294512',
- 'phabricator-object-item-list-view-css' => '6c294512',
+ 'phabricator-notification-css' => 'a56848af',
+ 'phabricator-notification-menu-css' => 'a56848af',
+ 'phabricator-object-item-list-view-css' => 'a56848af',
'phabricator-object-selector-css' => '8aaacd1b',
'phabricator-paste-file-upload' => '95ceba95',
'phabricator-prefab' => '95ceba95',
- 'phabricator-project-tag-css' => 'c41b4907',
- 'phabricator-remarkup-css' => '6c294512',
+ 'phabricator-project-tag-css' => '6b1fccc6',
+ 'phabricator-remarkup-css' => 'a56848af',
'phabricator-shaped-request' => '322728f3',
- 'phabricator-side-menu-view-css' => '6c294512',
- 'phabricator-standard-page-view' => '6c294512',
+ 'phabricator-side-menu-view-css' => 'a56848af',
+ 'phabricator-standard-page-view' => 'a56848af',
'phabricator-textareautils' => '95ceba95',
'phabricator-tooltip' => '95ceba95',
- 'phabricator-transaction-view-css' => '6c294512',
- 'phabricator-zindex-css' => '6c294512',
- 'sprite-apps-large-css' => '6c294512',
- 'sprite-gradient-css' => '6c294512',
- 'sprite-icon-css' => '6c294512',
- 'sprite-menu-css' => '6c294512',
- 'syntax-highlighting-css' => '6c294512',
+ 'phabricator-transaction-view-css' => 'a56848af',
+ 'phabricator-zindex-css' => 'a56848af',
+ 'sprite-apps-large-css' => 'a56848af',
+ 'sprite-gradient-css' => 'a56848af',
+ 'sprite-icon-css' => 'a56848af',
+ 'sprite-menu-css' => 'a56848af',
+ 'syntax-highlighting-css' => 'a56848af',
),
));
diff --git a/src/applications/maniphest/controller/ManiphestSubpriorityController.php b/src/applications/maniphest/controller/ManiphestSubpriorityController.php
index 07fa1e174d..4cbeb661c6 100644
--- a/src/applications/maniphest/controller/ManiphestSubpriorityController.php
+++ b/src/applications/maniphest/controller/ManiphestSubpriorityController.php
@@ -7,6 +7,7 @@ final class ManiphestSubpriorityController extends ManiphestController {
public function processRequest() {
$request = $this->getRequest();
+ $user = $request->getUser();
if (!$request->validateCSRF()) {
return new Aphront403Response();
@@ -50,15 +51,26 @@ final class ManiphestSubpriorityController extends ManiphestController {
$task->setSubpriority($new_sub);
$task->save();
- $pri_class = ManiphestTaskSummaryView::getPriorityClass(
- $task->getPriority());
- $class = 'maniphest-task-handle maniphest-active-handle '.$pri_class;
+ $phids = $task->getProjectPHIDs();
+ if ($task->getOwnerPHID()) {
+ $phids[] = $task->getOwnerPHID();
+ }
- $response = array(
- 'className' => $class,
- );
+ $handles = id(new PhabricatorObjectHandleData($phids))
+ ->setViewer($user)
+ ->loadHandles();
- return id(new AphrontAjaxResponse())->setContent($response);
+ $view = id(new ManiphestTaskListView())
+ ->setUser($user)
+ ->setShowSubpriorityControls(true)
+ ->setShowBatchControls(true)
+ ->setHandles($handles)
+ ->setTasks(array($task));
+
+ return id(new AphrontAjaxResponse())->setContent(
+ array(
+ 'tasks' => $view,
+ ));
}
}
diff --git a/src/applications/maniphest/controller/ManiphestTaskListController.php b/src/applications/maniphest/controller/ManiphestTaskListController.php
index abceea780f..7fbb2bf339 100644
--- a/src/applications/maniphest/controller/ManiphestTaskListController.php
+++ b/src/applications/maniphest/controller/ManiphestTaskListController.php
@@ -378,23 +378,12 @@ final class ManiphestTaskListController extends ManiphestController {
$selector->appendChild($lists);
$selector->appendChild($this->renderBatchEditor($query));
- $form_id = celerity_generate_unique_node_id();
- $selector = phabricator_form(
- $user,
- array(
- 'method' => 'POST',
- 'action' => '/maniphest/batch/',
- 'id' => $form_id,
- ),
- $selector->render());
-
$list_container->appendChild($selector);
$list_container->appendChild($pager);
Javelin::initBehavior(
'maniphest-subpriority-editor',
array(
- 'root' => $form_id,
'uri' => '/maniphest/subpriority/',
));
}
@@ -644,6 +633,8 @@ final class ManiphestTaskListController extends ManiphestController {
}
private function renderBatchEditor(PhabricatorSearchQuery $search_query) {
+ $user = $this->getRequest()->getUser();
+
Javelin::initBehavior(
'maniphest-batch-selector',
array(
@@ -651,6 +642,8 @@ final class ManiphestTaskListController extends ManiphestController {
'selectNone' => 'batch-select-none',
'submit' => 'batch-select-submit',
'status' => 'batch-select-status-cell',
+ 'idContainer' => 'batch-select-id-container',
+ 'formID' => 'batch-select-form',
));
$select_all = javelin_tag(
@@ -690,7 +683,14 @@ final class ManiphestTaskListController extends ManiphestController {
),
pht('Export to Excel'));
- return hsprintf(
+ $hidden = phutil_tag(
+ 'div',
+ array(
+ 'id' => 'batch-select-id-container',
+ ),
+ '');
+
+ $editor = hsprintf(
'
'.
''.
'
'.
@@ -698,16 +698,28 @@ final class ManiphestTaskListController extends ManiphestController {
'%s%s '.
'%s '.
'%s '.
- '%s '.
+ '%s%s '.
''.
'
'.
- '',
+ '
',
pht('Batch Task Editor'),
$select_all,
$select_none,
$export,
- pht('0 Selected'),
- $submit);
+ '',
+ $submit,
+ $hidden);
+
+ $editor = phabricator_form(
+ $user,
+ array(
+ 'method' => 'POST',
+ 'action' => '/maniphest/batch/',
+ 'id' => 'batch-select-form',
+ ),
+ $editor);
+
+ return $editor;
}
private function buildQueryFromRequest() {
diff --git a/src/applications/maniphest/view/ManiphestTaskListView.php b/src/applications/maniphest/view/ManiphestTaskListView.php
index 556d460753..3862913d40 100644
--- a/src/applications/maniphest/view/ManiphestTaskListView.php
+++ b/src/applications/maniphest/view/ManiphestTaskListView.php
@@ -33,19 +33,74 @@ final class ManiphestTaskListView extends ManiphestView {
}
public function render() {
+ $handles = $this->handles;
+
+ $list = new PhabricatorObjectItemListView();
+ $list->setCards(true);
+ $list->setFlush(true);
+
+ $status_map = ManiphestTaskStatus::getTaskStatusMap();
+ $color_map = array(
+ ManiphestTaskPriority::PRIORITY_UNBREAK_NOW => 'magenta',
+ ManiphestTaskPriority::PRIORITY_TRIAGE => 'violet',
+ ManiphestTaskPriority::PRIORITY_HIGH => 'red',
+ ManiphestTaskPriority::PRIORITY_NORMAL => 'orange',
+ ManiphestTaskPriority::PRIORITY_LOW => 'yellow',
+ ManiphestTaskPriority::PRIORITY_WISH => 'sky',
+ );
- $views = array();
foreach ($this->tasks as $task) {
- $view = new ManiphestTaskSummaryView();
- $view->setTask($task);
- $view->setShowBatchControls($this->showBatchControls);
- $view->setShowSubpriorityControls($this->showSubpriorityControls);
- $view->setUser($this->user);
- $view->setHandles($this->handles);
- $views[] = $view->render();
+ $item = new PhabricatorObjectItemView();
+ $item->setObjectName('T'.$task->getID());
+ $item->setHeader($task->getTitle());
+ $item->setHref('/T'.$task->getID());
+
+ if ($task->getOwnerPHID()) {
+ $owner = $handles[$task->getOwnerPHID()];
+ $item->addHandleIcon(
+ $owner,
+ pht('Assigned: %s', $owner->getName()));
+ }
+
+ $status = $task->getStatus();
+ if ($status != ManiphestTaskStatus::STATUS_OPEN) {
+ $item->addFootIcon(
+ ($status == ManiphestTaskStatus::STATUS_CLOSED_RESOLVED)
+ ? 'enable-white'
+ : 'delete-white',
+ idx($status_map, $status, 'Unknown'));
+ }
+
+ $item->setBarColor(idx($color_map, $task->getPriority(), 'grey'));
+
+ $item->addIcon(
+ 'none',
+ phabricator_datetime($task->getDateModified(), $this->getUser()));
+
+ if ($this->showSubpriorityControls) {
+ $item->setGrippable(true);
+ $item->addSigil('maniphest-task');
+ }
+
+ if ($task->getProjectPHIDs()) {
+ $projects_view = new ManiphestTaskProjectsView();
+ $projects_view->setHandles(
+ array_select_keys(
+ $handles,
+ $task->getProjectPHIDs()));
+
+ $item->addAttribute($projects_view);
+ }
+
+ $item->setMetadata(
+ array(
+ 'taskID' => $task->getID(),
+ ));
+
+ $list->addItem($item);
}
- return $views;
+ return $list;
}
}
diff --git a/src/applications/maniphest/view/ManiphestTaskSummaryView.php b/src/applications/maniphest/view/ManiphestTaskSummaryView.php
deleted file mode 100644
index bf0de2a01f..0000000000
--- a/src/applications/maniphest/view/ManiphestTaskSummaryView.php
+++ /dev/null
@@ -1,196 +0,0 @@
-task = $task;
- return $this;
- }
-
- public function setHandles(array $handles) {
- assert_instances_of($handles, 'PhabricatorObjectHandle');
- $this->handles = $handles;
- return $this;
- }
-
- public function setShowBatchControls($show_batch_controls) {
- $this->showBatchControls = $show_batch_controls;
- return $this;
- }
-
- public function setShowSubpriorityControls($show_subpriority_controls) {
- $this->showSubpriorityControls = $show_subpriority_controls;
- return $this;
- }
-
- public static function getPriorityClass($priority) {
- $classes = array(
- ManiphestTaskPriority::PRIORITY_UNBREAK_NOW => 'pri-unbreak',
- ManiphestTaskPriority::PRIORITY_TRIAGE => 'pri-triage',
- ManiphestTaskPriority::PRIORITY_HIGH => 'pri-high',
- ManiphestTaskPriority::PRIORITY_NORMAL => 'pri-normal',
- ManiphestTaskPriority::PRIORITY_LOW => 'pri-low',
- ManiphestTaskPriority::PRIORITY_WISH => 'pri-wish',
- );
-
- return idx($classes, $priority);
- }
-
- public function render() {
-
- if (!$this->user) {
- throw new Exception("Call setUser() before rendering!");
- }
-
- $task = $this->task;
- $handles = $this->handles;
-
- require_celerity_resource('maniphest-task-summary-css');
-
- $pri_class = self::getPriorityClass($task->getPriority());
- $status_map = ManiphestTaskStatus::getTaskStatusMap();
-
- $batch = null;
- if ($this->showBatchControls) {
- $batch = phutil_tag(
- 'td',
- array(
- 'rowspan' => 2,
- 'class' => 'maniphest-task-batch',
- ),
- javelin_tag(
- 'input',
- array(
- 'type' => 'checkbox',
- 'name' => 'batch[]',
- 'value' => $task->getID(),
- 'sigil' => 'maniphest-batch',
- )));
- }
-
- $projects_view = new ManiphestTaskProjectsView();
- $projects_view->setHandles(
- array_select_keys(
- $this->handles,
- $task->getProjectPHIDs()));
-
- $control_class = null;
- $control_sigil = null;
- if ($this->showSubpriorityControls) {
- $control_class = 'maniphest-active-handle';
- $control_sigil = 'maniphest-task-handle';
- }
-
- $handle = javelin_tag(
- 'td',
- array(
- 'rowspan' => 2,
- 'class' => 'maniphest-task-handle '.$pri_class.' '.$control_class,
- 'sigil' => $control_sigil,
- ),
- '');
-
- $task_name = phutil_tag(
- 'span',
- array(
- 'class' => 'maniphest-task-name',
- ),
- phutil_tag(
- 'a',
- array(
- 'href' => '/T'.$task->getID(),
- ),
- $task->getTitle()));
-
- $task_updated = phutil_tag(
- 'span',
- array(
- 'class' => 'maniphest-task-updated',
- ),
- phabricator_date($task->getDateModified(), $this->user));
-
- $task_info = phutil_tag(
- 'td',
- array(
- 'colspan' => 2,
- 'class' => 'maniphest-task-number',
- ),
- array(
- 'T'.$task->getID(),
- $task_name,
- $task_updated,
- ));
-
- $owner = '';
- if ($task->getOwnerPHID()) {
- $owner = pht('Assigned to %s',
- $handles[$task->getOwnerPHID()]->renderLink());
- }
-
- $task_owner = phutil_tag(
- 'span',
- array(
- 'class' => 'maniphest-task-owner',
- ),
- $task->getOwnerPHID()
- ? $owner
- : phutil_tag('em', array(), pht('None')));
-
- $task_status = phutil_tag(
- 'td',
- array(
- 'class' => 'maniphest-task-status',
- ),
- array(
- idx($status_map, $task->getStatus(), pht('Unknown')),
- $task_owner,
- ));
-
- $task_projects = phutil_tag(
- 'td',
- array(
- 'class' => 'maniphest-task-projects',
- ),
- $projects_view->render());
-
- $row1 = phutil_tag(
- 'tr',
- array(),
- array(
- $handle,
- $batch,
- $task_info,
- ));
-
- $row2 = phutil_tag(
- 'tr',
- array(),
- array(
- $task_status,
- $task_projects,
- ));
-
- return javelin_tag(
- 'table',
- array(
- 'class' => 'maniphest-task-summary',
- 'sigil' => 'maniphest-task',
- 'meta' => array(
- 'taskID' => $task->getID(),
- ),
- ),
- array(
- $row1,
- $row2,
- ));
- }
-
-}
diff --git a/src/applications/project/controller/PhabricatorProjectProfileController.php b/src/applications/project/controller/PhabricatorProjectProfileController.php
index a4b22e6fdf..4c85607be2 100644
--- a/src/applications/project/controller/PhabricatorProjectProfileController.php
+++ b/src/applications/project/controller/PhabricatorProjectProfileController.php
@@ -240,6 +240,8 @@ final class PhabricatorProjectProfileController
PhabricatorProject $project,
PhabricatorProjectProfile $profile) {
+ $user = $this->getRequest()->getUser();
+
$query = id(new ManiphestTaskQuery())
->withAnyProjects(array($project->getPHID()))
->withStatus(ManiphestTaskQuery::STATUS_OPEN)
@@ -250,23 +252,16 @@ final class PhabricatorProjectProfileController
$count = $query->getRowCount();
$phids = mpull($tasks, 'getOwnerPHID');
+ $phids = array_merge(
+ $phids,
+ array_mergev(mpull($tasks, 'getProjectPHIDs')));
$phids = array_filter($phids);
$handles = $this->loadViewerHandles($phids);
- $task_views = array();
- foreach ($tasks as $task) {
- $view = id(new ManiphestTaskSummaryView())
- ->setTask($task)
- ->setHandles($handles)
- ->setUser($this->getRequest()->getUser());
- $task_views[] = $view->render();
- }
-
- if (empty($tasks)) {
- $task_views = phutil_tag('em', array(), pht('No open tasks.'));
- } else {
- $task_views = phutil_implode_html('', $task_views);
- }
+ $task_list = new ManiphestTaskListView();
+ $task_list->setUser($user);
+ $task_list->setTasks($tasks);
+ $task_list->setHandles($handles);
$open = number_format($count);
@@ -286,7 +281,7 @@ final class PhabricatorProjectProfileController
'
',
pht('Open Tasks (%s)', $open),
- $task_views,
+ $task_list,
$more_link);
return $content;
diff --git a/src/view/layout/PhabricatorObjectItemListView.php b/src/view/layout/PhabricatorObjectItemListView.php
index a88d46af2c..74b0dc233f 100644
--- a/src/view/layout/PhabricatorObjectItemListView.php
+++ b/src/view/layout/PhabricatorObjectItemListView.php
@@ -8,6 +8,12 @@ final class PhabricatorObjectItemListView extends AphrontView {
private $stackable;
private $cards;
private $noDataString;
+ private $flush;
+
+ public function setFlush($flush) {
+ $this->flush = $flush;
+ return $this;
+ }
public function setHeader($header) {
$this->header = $header;
@@ -74,6 +80,9 @@ final class PhabricatorObjectItemListView extends AphrontView {
if ($this->cards) {
$classes[] = 'phabricator-object-list-cards';
}
+ if ($this->flush) {
+ $classes[] = 'phabricator-object-list-flush';
+ }
return phutil_tag(
'ul',
diff --git a/src/view/layout/PhabricatorObjectItemView.php b/src/view/layout/PhabricatorObjectItemView.php
index 6423b10867..df5dfa1a70 100644
--- a/src/view/layout/PhabricatorObjectItemView.php
+++ b/src/view/layout/PhabricatorObjectItemView.php
@@ -1,6 +1,6 @@
icons) {
+ $item_classes[] = 'phabricator-object-item-with-icons';
+ }
+
+ if ($this->attributes) {
+ $item_classes[] = 'phabricator-object-item-with-attrs';
+ }
+
+ if ($this->handleIcons) {
+ $item_classes[] = 'phabricator-object-item-with-handle-icons';
+ }
+
+ if ($this->barColor) {
+ $item_classes[] = 'phabricator-object-item-bar-color-'.$this->barColor;
+ }
+
+ if ($this->footIcons) {
+ $item_classes[] = 'phabricator-object-item-with-foot-icons';
+ }
+
+ switch ($this->effect) {
+ case 'highlighted':
+ $item_classes[] = 'phabricator-object-item-highlighted';
+ break;
+ case 'selected':
+ $item_classes[] = 'phabricator-object-item-selected';
+ break;
+ case null:
+ break;
+ default:
+ throw new Exception(pht("Invalid effect!"));
+ }
+
+ if ($this->getGrippable()) {
+ $item_classes[] = 'phabricator-object-item-grippable';
+ }
+
+ return array(
+ 'class' => $item_classes,
+ );
+ }
+
+ public function getTagContent() {
+ $content_classes = array();
$content_classes[] = 'phabricator-object-item-content';
$header_name = null;
@@ -131,10 +180,11 @@ final class PhabricatorObjectItemView extends AphrontView {
),
$this->header);
- $header = phutil_tag(
+ $header = javelin_tag(
'div',
array(
'class' => 'phabricator-object-item-name',
+ 'sigil' => 'slippery',
),
array(
$header_name,
@@ -162,7 +212,6 @@ final class PhabricatorObjectItemView extends AphrontView {
),
$spec['label']);
-
if ($spec['href']) {
$icon_href = phutil_tag(
'a',
@@ -172,10 +221,16 @@ final class PhabricatorObjectItemView extends AphrontView {
$icon_href = array($label, $icon);
}
+ $classes = array();
+ $classes[] = 'phabricator-object-item-icon';
+ if ($spec['icon'] == 'none') {
+ $classes[] = 'phabricator-object-item-icon-none';
+ }
+
$icon_list[] = phutil_tag(
'li',
array(
- 'class' => 'phabricator-object-item-icon',
+ 'class' => implode(' ', $classes),
),
$icon_href);
}
@@ -186,7 +241,6 @@ final class PhabricatorObjectItemView extends AphrontView {
'class' => 'phabricator-object-item-icons',
),
$icon_list);
- $item_classes[] = 'phabricator-object-item-with-icons';
}
if ($this->handleIcons) {
@@ -200,7 +254,6 @@ final class PhabricatorObjectItemView extends AphrontView {
'class' => 'phabricator-object-item-handle-icons',
),
$handle_bar);
- $item_classes[] = 'phabricator-object-item-with-handle-icons';
}
if ($icons) {
@@ -240,7 +293,6 @@ final class PhabricatorObjectItemView extends AphrontView {
'class' => 'phabricator-object-item-attributes',
),
$attrs);
- $item_classes[] = 'phabricator-object-item-with-attrs';
}
$foot = null;
@@ -255,30 +307,10 @@ final class PhabricatorObjectItemView extends AphrontView {
'class' => 'phabricator-object-item-foot-icons',
),
$foot_bar);
- $item_classes[] = 'phabricator-object-item-with-foot-icons';
- }
-
- $item_classes[] = 'phabricator-object-item';
- if ($this->barColor) {
- $item_classes[] = 'phabricator-object-item-bar-color-'.$this->barColor;
- }
-
- switch ($this->effect) {
- case 'highlighted':
- $item_classes[] = 'phabricator-object-item-highlighted';
- break;
- case 'selected':
- $item_classes[] = 'phabricator-object-item-selected';
- break;
- case null:
- break;
- default:
- throw new Exception(pht("Invalid effect!"));
}
$grippable = null;
if ($this->getGrippable()) {
- $item_classes[] = 'phabricator-object-item-grippable';
$grippable = phutil_tag(
'div',
array(
@@ -300,20 +332,15 @@ final class PhabricatorObjectItemView extends AphrontView {
));
return phutil_tag(
- 'li',
+ 'div',
array(
- 'class' => implode(' ', $item_classes),
+ 'class' => 'phabricator-object-item-frame',
),
- phutil_tag(
- 'div',
- array(
- 'class' => 'phabricator-object-item-frame',
- ),
- array(
- $grippable,
- $icons,
- $content,
- )));
+ array(
+ $grippable,
+ $icons,
+ $content,
+ ));
}
private function renderFootIcon($icon, $label) {
diff --git a/webroot/rsrc/css/application/maniphest/task-summary.css b/webroot/rsrc/css/application/maniphest/task-summary.css
index 4d0609d2c6..ddc881844e 100644
--- a/webroot/rsrc/css/application/maniphest/task-summary.css
+++ b/webroot/rsrc/css/application/maniphest/task-summary.css
@@ -2,123 +2,19 @@
* @provides maniphest-task-summary-css
*/
-.maniphest-task-summary {
- width: 100%;
- margin: 0 0 -1px 0;
- border-collapse: separate;
- color: #333;
- border: 1px solid #c0c5d1;
-}
-
.maniphest-task-group {
padding-bottom: 30px;
}
-.maniphest-task-summary td {
- padding: 0 10px;
- background: #fff;
-}
-
-.maniphest-task-summary td em {
- color: #888888;
-}
-
.maniphest-batch-selected td {
background: #fff;
}
-.maniphest-task-summary .maniphest-task-handle {
- padding: 0 4px 0 0;
- width: 5px;
-}
-
-.maniphest-task-summary td.maniphest-task-batch {
- padding: 15px 4px 0 10px;
- width: 8px;
- text-align: center;
- overflow: hidden;
-}
-
.device-phone .maniphest-task-batch,
.device-phone .maniphest-task-updated {
display: none;
}
-.maniphest-task-summary td.maniphest-task-batch,
-.maniphest-task-summary td.maniphest-task-batch input {
- cursor: pointer;
-}
-
-.maniphest-task-summary td.maniphest-task-batch input {
- margin: 0;
-}
-
-.maniphest-task-summary td.maniphest-task-number {
- padding: 6px 0 2px 10px;
- font-weight: bold;
- color: #333;
-}
-
-.maniphest-task-summary td.maniphest-task-status {
- padding: 2px 10px 6px 10px;
- text-align: left;
- color: #777;
- font-size: 12px;
-}
-
-.maniphest-task-summary .maniphest-task-owner {
- padding-left: 20px;
-}
-
-.maniphest-task-summary .maniphest-task-name {
- font-weight: bold;
- overflow: hidden;
- margin-left: 5px;
-}
-
-.maniphest-task-summary td.maniphest-task-projects {
- text-align: right;
- padding: 0px 8px;
-}
-
-.maniphest-task-summary .maniphest-task-updated {
- float: right;
- padding: 0 8px;
- color: #777;
- font-size: 11px;
- font-weight: normal;
-}
-
-.maniphest-task-summary .pri-unbreak {
- border-color: #ff0000;
- background-color: #ff0000;
-}
-
-.maniphest-task-summary .pri-triage {
- border-color: #ee00ee;
- background-color: #ee00ee;
-}
-
-.maniphest-task-summary .pri-high {
- border-color: #ff6622;
- background-color: #ff6622;
-}
-
-.maniphest-task-summary .pri-normal {
- border-color: #ffaa66;
- background-color: #ffaa66;
-}
-
-.maniphest-task-summary .pri-low {
- border-color: #eecc66;
- background-color: #eecc66;
-}
-
-.maniphest-task-summary .pri-wish {
- border-color: #0099ff;
- background-color: #0099ff;
-}
-
.maniphest-task-group-header {
font-size: 16px;
font-weight: bold;
@@ -179,26 +75,20 @@
width: 100%;
}
-td.maniphest-active-handle {
- cursor: move;
- background-image: url('/rsrc/image/grippy_texture.png');
- background-position: 3px 0px;
- background-repeat: repeat-y;
-}
-
.maniphest-subpriority-target {
position: relative;
border: 1px dashed #aaaaaa;
background: #f9f9f9;
+ margin: 4px;
}
.maniphest-task-loading {
- opacity: 0.5;
+ opacity: 0.75;
}
.maniphest-task-dragging {
position: relative;
- opacity: 0.5;
+ opacity: 0.90;
}
.maniphest-list-container {
diff --git a/webroot/rsrc/css/layout/phabricator-object-item-list-view.css b/webroot/rsrc/css/layout/phabricator-object-item-list-view.css
index f58329f84b..ca07e242b3 100644
--- a/webroot/rsrc/css/layout/phabricator-object-item-list-view.css
+++ b/webroot/rsrc/css/layout/phabricator-object-item-list-view.css
@@ -38,7 +38,7 @@
}
.phabricator-object-item-name {
- display: block;
+ display: inline-block;
font-weight: bold;
font-size: 14px;
padding: 0 10px;
@@ -49,9 +49,9 @@
padding: 8px 0;
}
-
.phabricator-object-item-objname {
color: #222222;
+ cursor: text;
}
.phabricator-object-item-with-attrs .phabricator-object-item-name {
diff --git a/webroot/rsrc/js/application/maniphest/behavior-batch-selector.js b/webroot/rsrc/js/application/maniphest/behavior-batch-selector.js
index 0e37e80a32..d5aaa60d98 100644
--- a/webroot/rsrc/js/application/maniphest/behavior-batch-selector.js
+++ b/webroot/rsrc/js/application/maniphest/behavior-batch-selector.js
@@ -3,39 +3,42 @@
* @requires javelin-behavior
* javelin-dom
* javelin-stratcom
+ * javelin-util
*/
JX.behavior('maniphest-batch-selector', function(config) {
- // When a task row's selection state is changed, this issues updates to other
- // parts of the application.
+ var selected = {};
- var onchange = function(task) {
- var input = JX.DOM.find(task, 'input', 'maniphest-batch');
- var state = input.checked;
+ // Test if a task node is selected.
- JX.DOM.alterClass(task, 'maniphest-batch-selected', state);
-
- JX.Stratcom.invoke(
- (state ? 'maniphest-batch-task-add' : 'maniphest-batch-task-rem'),
- null,
- {id: input.value})
- };
+ var get_id = function(task) {
+ return JX.Stratcom.getData(task).taskID;
+ }
+ var is_selected = function(task) {
+ return (get_id(task) in selected);
+ }
// Change the selected state of a task.
- // If 'to' is undefined, toggle. Otherwise, set to true or false.
var change = function(task, to) {
-
- var input = JX.DOM.find(task, 'input', 'maniphest-batch');
- var state = input.checked;
if (to === undefined) {
- input.checked = !input.checked;
- } else {
- input.checked = to;
+ to = !is_selected(task);
}
- onchange(task);
+
+ if (to) {
+ selected[get_id(task)] = true;
+ } else {
+ delete selected[get_id(task)];
+ }
+
+ JX.DOM.alterClass(
+ task,
+ 'phabricator-object-item-selected',
+ is_selected(task));
+
+ update();
};
@@ -43,62 +46,72 @@ JX.behavior('maniphest-batch-selector', function(config) {
// buttons).
var changeall = function(to) {
- var inputs = JX.DOM.scry(document.body, 'table', 'maniphest-task');
+ var inputs = JX.DOM.scry(document.body, 'li', 'maniphest-task');
for (var ii = 0; ii < inputs.length; ii++) {
change(inputs[ii], to);
}
}
+ // Clear any document text selection after toggling a task via shift click,
+ // since errant clicks tend to start selecting various ranges otherwise.
+
+ var clear_selection = function() {
+ if (window.getSelection) {
+ if (window.getSelection().empty) {
+ window.getSelection().empty();
+ } else if (window.getSelection().removeAllRanges) {
+ window.getSelection().removeAllRanges();
+ }
+ } else if (document.selection) {
+ document.selection.empty();
+ }
+ }
// Update the status text showing how many tasks are selected, and the button
// state.
- var selected = {};
- var selected_count = 0;
-
var update = function() {
- var status = (selected_count == 1)
- ? '1 Selected Task'
- : selected_count + ' Selected Tasks';
+ var count = JX.keys(selected).length;
+ var status;
+ if (count == 0) {
+ status = 'Shift-Click to Select Tasks';
+ } else if (status == 1) {
+ status = '1 Selected Task';
+ } else {
+ status = count + ' Selected Tasks';
+ }
JX.DOM.setContent(JX.$(config.status), status);
var submit = JX.$(config.submit);
- var disable = (selected_count == 0);
+ var disable = (count == 0);
submit.disabled = disable;
JX.DOM.alterClass(submit, 'disabled', disable);
};
-
- // When the user clicks the entire surrounding the checkbox, count it
- // as a checkbox click.
+ // When he user shift-clicks the task, update the rest of the application
+ // state.
JX.Stratcom.listen(
'click',
'maniphest-task',
function(e) {
- if (!JX.DOM.isNode(e.getTarget(), 'td')) {
- // Only count clicks in the , not (e.g.) the table border.
+ var raw = e.getRawEvent();
+ if (!raw.shiftKey) {
return;
}
- // Check if the clicked contains a checkbox.
- var inputs = JX.DOM.scry(e.getTarget(), 'input', 'maniphest-batch');
- if (!inputs.length) {
+ if (raw.ctrlKey || raw.altKey || raw.metaKey || e.isRightButton()) {
return;
}
+ if (JX.Stratcom.pass(e)) {
+ return;
+ }
+
+ e.kill();
change(e.getNode('maniphest-task'));
- });
-
- // When he user clicks the , update the rest of the application
- // state.
-
- JX.Stratcom.listen(
- ['click', 'onchange'],
- 'maniphest-batch',
- function(e) {
- onchange(e.getNode('maniphest-task'));
+ clear_selection();
});
@@ -125,30 +138,21 @@ JX.behavior('maniphest-batch-selector', function(config) {
e.kill();
});
+ // When the user submits the form, dump selected state into it.
- JX.Stratcom.listen(
- 'maniphest-batch-task-add',
+ JX.DOM.listen(
+ JX.$(config.formID),
+ 'submit',
null,
function(e) {
- var id = e.getData().id;
- if (!(id in selected)) {
- selected[id] = true;
- selected_count++;
- update();
+ var inputs = [];
+ for (var k in selected) {
+ inputs.push(
+ JX.$N('input', {type: 'hidden', name: 'batch[]', value: k}));
}
+ JX.DOM.setContent(JX.$(config.idContainer), inputs);
});
-
- JX.Stratcom.listen(
- 'maniphest-batch-task-rem',
- null,
- function(e) {
- var id = e.getData().id;
- if (id in selected) {
- delete selected[id];
- selected_count--;
- update();
- }
- });
+ update();
});
diff --git a/webroot/rsrc/js/application/maniphest/behavior-subpriorityeditor.js b/webroot/rsrc/js/application/maniphest/behavior-subpriorityeditor.js
index 7674f1b43f..242a8dd684 100644
--- a/webroot/rsrc/js/application/maniphest/behavior-subpriorityeditor.js
+++ b/webroot/rsrc/js/application/maniphest/behavior-subpriorityeditor.js
@@ -15,18 +15,27 @@ JX.behavior('maniphest-subpriority-editor', function(config) {
var origin = null;
var targets = null;
var target = null;
- var droptarget = JX.$N('div', {className: 'maniphest-subpriority-target'});
+ var droptarget = JX.$N('li', {className: 'maniphest-subpriority-target'});
var ondrag = function(e) {
if (dragging || sending) {
return;
}
+ if (!e.isNormalMouseEvent()) {
+ return;
+ }
+
+ // Can't grab onto slippery nodes.
+ if (e.getNode('slippery')) {
+ return;
+ }
+
dragging = e.getNode('maniphest-task');
origin = JX.$V(e);
- var tasks = JX.DOM.scry(JX.$(config.root), 'table', 'maniphest-task');
- var heads = JX.DOM.scry(JX.$(config.root), 'h1', 'task-group');
+ var tasks = JX.DOM.scry(document.body, 'li', 'maniphest-task');
+ var heads = JX.DOM.scry(document.body, 'h1', 'task-group');
var nodes = tasks.concat(heads);
@@ -107,10 +116,19 @@ JX.behavior('maniphest-subpriority-editor', function(config) {
if (cur_target) {
if (cur_target.nextSibling) {
- cur_target.parentNode.insertBefore(
- droptarget,
- cur_target.nextSibling);
+ if (JX.DOM.isType(cur_target, 'h1')) {
+ // Dropping at the beginning of a priority list.
+ cur_target.nextSibling.insertBefore(
+ droptarget,
+ cur_target.nextSibling.firstChild);
+ } else {
+ // Dropping in the middle of a priority list.
+ cur_target.parentNode.insertBefore(
+ droptarget,
+ cur_target.nextSibling);
+ }
} else {
+ // Dropping at the end of a priority list.
cur_target.parentNode.appendChild(droptarget);
}
}
@@ -180,9 +198,10 @@ JX.behavior('maniphest-subpriority-editor', function(config) {
JX.DOM.alterClass(sending, 'maniphest-task-loading', true);
var onresponse = function(r) {
- JX.DOM.alterClass(sending, 'maniphest-task-loading', false);
- var handle = JX.DOM.find(sending, 'td', 'maniphest-task-handle');
- handle.className = r.className;
+ var nodes = JX.$H(r.tasks).getFragment().firstChild;
+ var task = JX.DOM.find(nodes, 'li', 'maniphest-task');
+ JX.DOM.replace(sending, task);
+
sending = null;
};
@@ -196,8 +215,8 @@ JX.behavior('maniphest-subpriority-editor', function(config) {
// NOTE: Javelin does not dispatch mousemove by default.
JX.enableDispatch(document.body, 'mousemove');
- JX.Stratcom.listen('mousedown', 'maniphest-task-handle', ondrag);
- JX.Stratcom.listen('mousemove', null, onmove);
- JX.Stratcom.listen('mouseup', null, ondrop);
+ JX.Stratcom.listen('mousedown', 'maniphest-task', ondrag);
+ JX.Stratcom.listen('mousemove', null, onmove);
+ JX.Stratcom.listen('mouseup', null, ondrop);
});