From a97968b9ff98be82ab2dc19b50c23962bd0c2fe0 Mon Sep 17 00:00:00 2001 From: Bob Trahan Date: Tue, 2 Apr 2013 09:32:40 -0700 Subject: [PATCH] Conpherence - people widget Summary: adds ye olde people widget. Features include - handle-based display, so we get status for free. (Note less pretty than M14 would have it!) - can add a person - can remove a person - can see the people already in the conpherence Test Plan: added and removed people and noted they joined / re-added as appropriate. Tried to add someone already in the conpherence and got a "transaction has no effect" message Reviewers: epriestley, chad Reviewed By: epriestley CC: aran, Korvin Maniphest Tasks: T2399 Differential Revision: https://secure.phabricator.com/D5466 --- src/__celerity_resource_map__.php | 6 +- src/__phutil_library_map__.php | 6 +- .../ConpherenceUpdateController.php | 117 ++++++++++++++---- .../ConpherenceWidgetController.php | 89 +++++++------ .../conpherence/editor/ConpherenceEditor.php | 29 +++-- .../storage/ConpherenceTransaction.php | 11 ++ .../view/ConpherenceFileWidgetView.php | 24 +--- .../view/ConpherencePeopleWidgetView.php | 110 ++++++++++++++++ .../view/ConpherenceWidgetView.php | 33 +++++ .../PhabricatorBaseEnglishTranslation.php | 7 ++ .../application/conpherence/widget-pane.css | 85 +++++++++++++ .../application/conpherence/behavior-menu.js | 8 +- .../conpherence/behavior-widget-pane.js | 55 ++++++++ 13 files changed, 485 insertions(+), 95 deletions(-) create mode 100644 src/applications/conpherence/view/ConpherencePeopleWidgetView.php create mode 100644 src/applications/conpherence/view/ConpherenceWidgetView.php diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index e986594e78..9d2f240dbd 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -903,7 +903,7 @@ celerity_register_resource_map(array( ), 'conpherence-widget-pane-css' => array( - 'uri' => '/res/bd8ca250/rsrc/css/application/conpherence/widget-pane.css', + 'uri' => '/res/65c7c73f/rsrc/css/application/conpherence/widget-pane.css', 'type' => 'css', 'requires' => array( @@ -1253,7 +1253,7 @@ celerity_register_resource_map(array( ), 'javelin-behavior-conpherence-menu' => array( - 'uri' => '/res/35811cd4/rsrc/js/application/conpherence/behavior-menu.js', + 'uri' => '/res/29585411/rsrc/js/application/conpherence/behavior-menu.js', 'type' => 'js', 'requires' => array( @@ -1283,7 +1283,7 @@ celerity_register_resource_map(array( ), 'javelin-behavior-conpherence-widget-pane' => array( - 'uri' => '/res/45d53f1f/rsrc/js/application/conpherence/behavior-widget-pane.js', + 'uri' => '/res/c0990399/rsrc/js/application/conpherence/behavior-widget-pane.js', 'type' => 'js', 'requires' => array( diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index f5d37cb1f5..3a5f3e41fa 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -239,6 +239,7 @@ phutil_register_library_map(array( 'ConpherenceParticipantQuery' => 'applications/conpherence/query/ConpherenceParticipantQuery.php', 'ConpherenceParticipationStatus' => 'applications/conpherence/constants/ConpherenceParticipationStatus.php', 'ConpherencePeopleMenuEventListener' => 'applications/conpherence/events/ConpherencePeopleMenuEventListener.php', + 'ConpherencePeopleWidgetView' => 'applications/conpherence/view/ConpherencePeopleWidgetView.php', 'ConpherenceReplyHandler' => 'applications/conpherence/mail/ConpherenceReplyHandler.php', 'ConpherenceSettings' => 'applications/conpherence/constants/ConpherenceSettings.php', 'ConpherenceThread' => 'applications/conpherence/storage/ConpherenceThread.php', @@ -252,6 +253,7 @@ phutil_register_library_map(array( 'ConpherenceUpdateController' => 'applications/conpherence/controller/ConpherenceUpdateController.php', 'ConpherenceViewController' => 'applications/conpherence/controller/ConpherenceViewController.php', 'ConpherenceWidgetController' => 'applications/conpherence/controller/ConpherenceWidgetController.php', + 'ConpherenceWidgetView' => 'applications/conpherence/view/ConpherenceWidgetView.php', 'DarkConsoleController' => 'aphront/console/DarkConsoleController.php', 'DarkConsoleCore' => 'aphront/console/DarkConsoleCore.php', 'DarkConsoleDataController' => 'aphront/console/DarkConsoleDataController.php', @@ -1941,7 +1943,7 @@ phutil_register_library_map(array( 'ConpherenceController' => 'PhabricatorController', 'ConpherenceDAO' => 'PhabricatorLiskDAO', 'ConpherenceEditor' => 'PhabricatorApplicationTransactionEditor', - 'ConpherenceFileWidgetView' => 'AphrontView', + 'ConpherenceFileWidgetView' => 'ConpherenceWidgetView', 'ConpherenceFormDragAndDropUploadControl' => 'AphrontFormControl', 'ConpherenceImageData' => 'ConpherenceConstants', 'ConpherenceLayoutView' => 'AphrontView', @@ -1952,6 +1954,7 @@ phutil_register_library_map(array( 'ConpherenceParticipantQuery' => 'PhabricatorOffsetPagedQuery', 'ConpherenceParticipationStatus' => 'ConpherenceConstants', 'ConpherencePeopleMenuEventListener' => 'PhutilEventListener', + 'ConpherencePeopleWidgetView' => 'ConpherenceWidgetView', 'ConpherenceReplyHandler' => 'PhabricatorMailReplyHandler', 'ConpherenceSettings' => 'ConpherenceConstants', 'ConpherenceThread' => @@ -1969,6 +1972,7 @@ phutil_register_library_map(array( 'ConpherenceUpdateController' => 'ConpherenceController', 'ConpherenceViewController' => 'ConpherenceController', 'ConpherenceWidgetController' => 'ConpherenceController', + 'ConpherenceWidgetView' => 'AphrontView', 'DarkConsoleController' => 'PhabricatorController', 'DarkConsoleDataController' => 'PhabricatorController', 'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin', diff --git a/src/applications/conpherence/controller/ConpherenceUpdateController.php b/src/applications/conpherence/controller/ConpherenceUpdateController.php index e6078cccbc..19aafe7aa4 100644 --- a/src/applications/conpherence/controller/ConpherenceUpdateController.php +++ b/src/applications/conpherence/controller/ConpherenceUpdateController.php @@ -38,7 +38,7 @@ final class ConpherenceUpdateController $action = $request->getStr('action', 'metadata'); $latest_transaction_id = null; - $fancy_ajax_style = true; + $response_mode = 'ajax'; $error_view = null; $e_file = array(); $errors = array(); @@ -56,11 +56,36 @@ final class ConpherenceUpdateController switch ($action) { case 'message': $message = $request->getStr('text'); - $latest_transaction_id = $request->getInt('latest_transaction_id'); $xactions = $editor->generateTransactionsFromText( $conpherence, $message); break; + case 'add_person': + $xactions = array(); + $person_tokenizer = $request->getArr('add_person'); + $person_phid = reset($person_tokenizer); + if ($person_phid) { + $xactions[] = id(new ConpherenceTransaction()) + ->setTransactionType( + ConpherenceTransactionType::TYPE_PARTICIPANTS) + ->setNewValue(array('+' => array($person_phid))); + } + break; + case 'remove_person': + $xactions = array(); + if (!$request->isContinueRequest()) { + // do nothing; we'll display a confirmation dialogue instead + break; + } + $person_phid = $request->getStr('remove_person'); + if ($person_phid && $person_phid == $user->getPHID()) { + $xactions[] = id(new ConpherenceTransaction()) + ->setTransactionType( + ConpherenceTransactionType::TYPE_PARTICIPANTS) + ->setNewValue(array('-' => array($person_phid))); + $response_mode = 'go-home'; + } + break; case 'notifications': $notifications = $request->getStr('notifications'); $participant = $conpherence->getParticipant($user->getPHID()); @@ -116,7 +141,7 @@ final class ConpherenceUpdateController // use the existing title in this image upload case $title = $conpherence->getTitle(); $updated = true; - $fancy_ajax_style = false; + $response_mode = 'redirect'; } // all other metadata updates are continue requests @@ -159,20 +184,29 @@ final class ConpherenceUpdateController if ($xactions) { try { $xactions = $editor->applyTransactions($conpherence, $xactions); - if ($fancy_ajax_style) { + } catch (PhabricatorApplicationTransactionNoEffectException $ex) { + return id(new PhabricatorApplicationTransactionNoEffectResponse()) + ->setCancelURI($this->getApplicationURI($conpherence_id.'/')) + ->setException($ex); + } + switch ($response_mode) { + case 'ajax': + $latest_transaction_id = $request->getInt('latest_transaction_id'); $content = $this->loadAndRenderUpdates( $conpherence_id, $latest_transaction_id); return id(new AphrontAjaxResponse()) ->setContent($content); - } else { + break; + case 'go-home': + return id(new AphrontRedirectResponse()) + ->setURI($this->getApplicationURI()); + break; + case 'redirect': + default: return id(new AphrontRedirectResponse()) ->setURI($this->getApplicationURI($conpherence->getID().'/')); - } - } catch (PhabricatorApplicationTransactionNoEffectException $ex) { - return id(new PhabricatorApplicationTransactionNoEffectResponse()) - ->setCancelURI($this->getApplicationURI($conpherence_id.'/')) - ->setException($ex); + break; } } } @@ -185,6 +219,9 @@ final class ConpherenceUpdateController } switch ($action) { + case 'remove_person': + $dialogue = $this->renderRemovePersonDialogue($conpherence); + break; case 'metadata': default: $dialogue = $this->renderMetadataDialogue($conpherence, $error_view); @@ -201,6 +238,37 @@ final class ConpherenceUpdateController } + private function renderRemovePersonDialogue( + ConpherenceThread $conpherence) { + + $request = $this->getRequest(); + $user = $request->getUser(); + $remove_person = $request->getStr('remove_person'); + $participants = $conpherence->getParticipants(); + $message = pht( + 'Are you sure you want to remove yourself from this conpherence? '); + if (count($participants) == 1) { + $message .= pht( + 'The conpherence will be inaccessible forever and ever.'); + } else { + $message .= pht( + 'Someone else in the conpherence can add you back later.'); + } + $body = phutil_tag( + 'p', + array( + ), + $message); + + require_celerity_resource('conpherence-update-css'); + return id(new AphrontDialogView()) + ->setTitle(pht('Update Conpherence Participants')) + ->addHiddenInput('action', 'remove_person') + ->addHiddenInput('__continue__', true) + ->addHiddenInput('remove_person', $remove_person) + ->appendChild($body); + } + private function renderMetadataDialogue( ConpherenceThread $conpherence, $error_view) { @@ -225,15 +293,15 @@ final class ConpherenceUpdateController 'src' => $conpherence->loadImageURI(ConpherenceImageData::SIZE_HEAD), )))) - ->appendChild( - id(new AphrontFormCropControl()) - ->setLabel(pht('Crop Image')) - ->setValue($image) - ->setWidth(ConpherenceImageData::HEAD_WIDTH) - ->setHeight(ConpherenceImageData::HEAD_HEIGHT)) - ->appendChild( - id(new ConpherenceFormDragAndDropUploadControl()) - ->setLabel(pht('Change Image'))); + ->appendChild( + id(new AphrontFormCropControl()) + ->setLabel(pht('Crop Image')) + ->setValue($image) + ->setWidth(ConpherenceImageData::HEAD_WIDTH) + ->setHeight(ConpherenceImageData::HEAD_HEIGHT)) + ->appendChild( + id(new ConpherenceFormDragAndDropUploadControl()) + ->setLabel(pht('Change Image'))); } else { $form ->appendChild( @@ -274,11 +342,15 @@ final class ConpherenceUpdateController $header = $this->buildHeaderPaneContent($conpherence); + $widget_uri = $this->getApplicationURI('update/'.$conpherence->getID().'/'); $file_widget = id(new ConpherenceFileWidgetView()) ->setUser($this->getRequest()->getUser()) ->setConpherence($conpherence) - ->setUpdateURI( - $this->getApplicationURI('update/'.$conpherence->getID().'/')); + ->setUpdateURI($widget_uri); + $people_widget = id(new ConpherencePeopleWidgetView()) + ->setUser($user) + ->setConpherence($conpherence) + ->setUpdateURI($widget_uri); $content = array( 'transactions' => $rendered_transactions, @@ -286,7 +358,8 @@ final class ConpherenceUpdateController 'nav_item' => hsprintf('%s', $nav_item), 'conpherence_phid' => $conpherence->getPHID(), 'header' => hsprintf('%s', $header), - 'file_widget' => $file_widget->render() + 'file_widget' => $file_widget->render(), + 'people_widget' => $people_widget->render() ); return $content; } diff --git a/src/applications/conpherence/controller/ConpherenceWidgetController.php b/src/applications/conpherence/controller/ConpherenceWidgetController.php index 7c1cd51d20..4cfe468b25 100644 --- a/src/applications/conpherence/controller/ConpherenceWidgetController.php +++ b/src/applications/conpherence/controller/ConpherenceWidgetController.php @@ -69,6 +69,9 @@ final class ConpherenceWidgetController extends Javelin::initBehavior( 'conpherence-widget-pane', array( + 'header' => 'conpherence-header-pane', + 'messages' => 'conpherence-messages', + 'people_widget' => 'widgets-people', 'file_widget' => 'widgets-files', 'settings_widget' => 'widgets-settings', 'widgetRegistery' => array( @@ -83,7 +86,8 @@ final class ConpherenceWidgetController extends $conpherence = $this->getConpherence(); - $widgets = phutil_tag( + $widgets = array(); + $widgets[] = phutil_tag( 'div', array( 'class' => 'widgets-header' @@ -167,50 +171,50 @@ final class ConpherenceWidgetController extends 'class' => 'sprite-conpherence conpherence_settings_off', ), '') - ))). - phutil_tag( + ))); + $user = $this->getRequest()->getUser(); + // now the widget bodies + $widgets[] = phutil_tag( 'div', array( 'class' => 'widgets-body', 'id' => 'widgets-people', 'style' => 'display: none;' ), - $this->renderPeopleWidgetPaneContent()). - javelin_tag( - 'div', - array( - 'class' => 'widgets-body', - 'id' => 'widgets-files', - 'sigil' => 'conpherence-widget-files', - ), - id(new ConpherenceFileWidgetView()) - ->setUser($this->getRequest()->getUser()) - ->setConpherence($conpherence) - ->setUpdateURI( - $this->getApplicationURI('update/'.$conpherence->getID().'/')) - ->render()). - phutil_tag( - 'div', - array( - 'class' => 'widgets-body', - 'id' => 'widgets-calendar', - 'style' => 'display: none;' - ), - $this->renderCalendarWidgetPaneContent()). - phutil_tag( - 'div', - array( - 'class' => 'widgets-body', - 'id' => 'widgets-settings', - 'style' => 'display: none' - ), - $this->renderSettingsWidgetPaneContent()); + id(new ConpherencePeopleWidgetView()) + ->setUser($user) + ->setConpherence($conpherence) + ->setUpdateURI($this->getWidgetURI())); + $widgets[] = phutil_tag( + 'div', + array( + 'class' => 'widgets-body', + 'id' => 'widgets-files', + ), + id(new ConpherenceFileWidgetView()) + ->setUser($user) + ->setConpherence($conpherence) + ->setUpdateURI($this->getWidgetURI())); + $widgets[] = phutil_tag( + 'div', + array( + 'class' => 'widgets-body', + 'id' => 'widgets-calendar', + 'style' => 'display: none;' + ), + $this->renderCalendarWidgetPaneContent()); + $widgets[] = phutil_tag( + 'div', + array( + 'class' => 'widgets-body', + 'id' => 'widgets-settings', + 'style' => 'display: none' + ), + $this->renderSettingsWidgetPaneContent()); - return array('widgets' => $widgets); - } - - private function renderPeopleWidgetPaneContent() { - return 'TODO - people'; + // without this implosion we get "," between each element in our widgets + // array + return array('widgets' => phutil_implode_html('', $widgets)); } private function renderSettingsWidgetPaneContent() { @@ -244,8 +248,6 @@ final class ConpherenceWidgetController extends ->setName('notifications') ->setValue($notifications); - $href = $this->getApplicationURI( - 'update/'.$conpherence->getID().'/'); $layout = array( $options, phutil_tag( @@ -268,7 +270,7 @@ final class ConpherenceWidgetController extends $user, array( 'method' => 'POST', - 'action' => $href, + 'action' => $this->getWidgetURI(), ), $layout); } @@ -369,4 +371,9 @@ final class ConpherenceWidgetController extends return $timestamps; } + private function getWidgetURI() { + $conpherence = $this->getConpherence(); + return $this->getApplicationURI('update/'.$conpherence->getID().'/'); + } + } diff --git a/src/applications/conpherence/editor/ConpherenceEditor.php b/src/applications/conpherence/editor/ConpherenceEditor.php index 98c60685fe..50df899217 100644 --- a/src/applications/conpherence/editor/ConpherenceEditor.php +++ b/src/applications/conpherence/editor/ConpherenceEditor.php @@ -159,23 +159,35 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor { } break; case ConpherenceTransactionType::TYPE_PARTICIPANTS: - $participants = array(); - foreach ($xaction->getNewValue() as $participant) { - if ($participant == $this->getActor()->getPHID()) { + + $participants = $object->getParticipants(); + + $old_map = array_fuse($xaction->getOldValue()); + $new_map = array_fuse($xaction->getNewValue()); + + $remove = array_keys(array_diff_key($old_map, $new_map)); + foreach ($remove as $phid) { + $remove_participant = $participants[$phid]; + $remove_participant->delete(); + unset($participants[$phid]); + } + + $add = array_keys(array_diff_key($new_map, $old_map)); + foreach ($add as $phid) { + if ($phid == $this->getActor()->getPHID()) { $status = ConpherenceParticipationStatus::UP_TO_DATE; } else { $status = ConpherenceParticipationStatus::BEHIND; } - $participants[] = + $participants[$phid] = id(new ConpherenceParticipant()) ->setConpherencePHID($object->getPHID()) - ->setParticipantPHID($participant) + ->setParticipantPHID($phid) ->setParticipationStatus($status) ->setDateTouched(time()) ->setBehindTransactionPHID($xaction->getPHID()) ->save(); } - $participants = mpull($participants, null, 'getParticipantPHID'); $object->attachParticipants($participants); break; } @@ -224,11 +236,14 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor { } protected function getMailTo(PhabricatorLiskDAO $object) { + $to_phids = array(); $participants = $object->getParticipants(); + if (empty($participants)) { + return $to_phids; + } $preferences = id(new PhabricatorUserPreferences()) ->loadAllWhere('userPHID in (%Ls)', array_keys($participants)); $preferences = mpull($preferences, null, 'getUserPHID'); - $to_phids = array(); foreach ($participants as $phid => $participant) { $default = ConpherenceSettings::EMAIL_ALWAYS; $preference = idx($preferences, $phid); diff --git a/src/applications/conpherence/storage/ConpherenceTransaction.php b/src/applications/conpherence/storage/ConpherenceTransaction.php index a3808b15c4..7bc0b31f37 100644 --- a/src/applications/conpherence/storage/ConpherenceTransaction.php +++ b/src/applications/conpherence/storage/ConpherenceTransaction.php @@ -21,6 +21,17 @@ final class ConpherenceTransaction extends PhabricatorApplicationTransaction { return pht('conpherence'); } + public function getNoEffectDescription() { + switch ($this->getTransactionType()) { + case ConpherenceTransactionType::TYPE_PARTICIPANTS: + return pht( + 'You can not add a participant who has already been added.'); + break; + } + + return parent::getNoEffectDescription(); + } + public function shouldHide() { $old = $this->getOldValue(); diff --git a/src/applications/conpherence/view/ConpherenceFileWidgetView.php b/src/applications/conpherence/view/ConpherenceFileWidgetView.php index 15aa3d125f..f7d53509e6 100644 --- a/src/applications/conpherence/view/ConpherenceFileWidgetView.php +++ b/src/applications/conpherence/view/ConpherenceFileWidgetView.php @@ -1,25 +1,9 @@ updateURI = $update_uri; - return $this; - } - public function getUpdateURI() { - return $this->updateURI; - } - - public function setConpherence(ConpherenceThread $conpherence) { - $this->conpherence = $conpherence; - return $this; - } - public function getConpherence() { - return $this->conpherence; - } +/** + * @group conpherence + */ +final class ConpherenceFileWidgetView extends ConpherenceWidgetView { public function render() { require_celerity_resource('sprite-docs-css'); diff --git a/src/applications/conpherence/view/ConpherencePeopleWidgetView.php b/src/applications/conpherence/view/ConpherencePeopleWidgetView.php new file mode 100644 index 0000000000..9f5048b04e --- /dev/null +++ b/src/applications/conpherence/view/ConpherencePeopleWidgetView.php @@ -0,0 +1,110 @@ +getConpherence(); + $widget_data = $conpherence->getWidgetData(); + $user = $this->getUser(); + $conpherence = $this->getConpherence(); + $participants = $conpherence->getParticipants(); + $handles = $conpherence->getHandles(); + + // ye olde add people widget + $add_widget = phabricator_form( + $user, + array( + 'method' => 'POST', + 'action' => $this->getUpdateURI(), + ), + array( + id(new AphrontFormTokenizerControl()) + ->setPlaceholder(pht('Add a person...')) + ->setName('add_person') + ->setUser($user) + ->setDatasource('/typeahead/common/users/') + ->setLimit(1), + javelin_tag( + 'button', + array( + 'sigil' => 'add-person', + 'class' => 'people-add-button', + 'meta' => array( + 'action' => 'add_person', + 'latest_transaction_id' => $this->getLatestTransactionID() + ) + ), + pht('Add')) + )); + $header = phutil_tag( + 'div', + array( + 'class' => 'people-widget-header' + ), + array( + phutil_tag( + 'div', + array( + 'class' => 'add-people-widget', + ), + $add_widget), + phutil_tag( + 'div', + array( + 'class' => 'divider' + ), + '') + )); + + $body = array(); + // future proof by using participants to iterate through handles; + // we may have non-people handles sooner or later + foreach ($participants as $user_phid => $participant) { + $handle = $handles[$user_phid]; + $remove_html = ''; + if ($user_phid == $user->getPHID()) { + $remove_html = javelin_tag( + 'a', + array( + 'class' => 'remove', + 'sigil' => 'remove-person', + 'meta' => array( + 'remove_person' => $handle->getPHID(), + 'action' => 'remove_person', + 'latest_transaction_id' => $this->getLatestTransactionID() + ) + ), + phutil_tag( + 'span', + array( + 'class' => 'icon' + ), + 'x')); + } + $body[] = phutil_tag( + 'div', + array( + 'class' => 'person-entry' + ), + array( + phutil_tag( + 'a', + array( + 'class' => 'pic', + ), + phutil_tag( + 'img', + array( + 'src' => $handle->getImageURI() + ), + '')), + $handle->renderLink(), + $remove_html)); + } + + return array($header, $body); + + } +} diff --git a/src/applications/conpherence/view/ConpherenceWidgetView.php b/src/applications/conpherence/view/ConpherenceWidgetView.php new file mode 100644 index 0000000000..57dbc5aee5 --- /dev/null +++ b/src/applications/conpherence/view/ConpherenceWidgetView.php @@ -0,0 +1,33 @@ +updateURI = $update_uri; + return $this; + } + public function getUpdateURI() { + return $this->updateURI; + } + + public function setConpherence(ConpherenceThread $conpherence) { + $this->conpherence = $conpherence; + return $this; + } + public function getConpherence() { + return $this->conpherence; + } + + public function getLatestTransactionID() { + $transactions = $this->getConpherence()->getTransactions(); + $latest = end($transactions); + return $latest->getID(); + } + +} diff --git a/src/infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php b/src/infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php index 6cf673a379..1b3640906c 100644 --- a/src/infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php +++ b/src/infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php @@ -217,6 +217,13 @@ abstract class PhabricatorBaseEnglishTranslation ), ), + '%d people(s)' => array( + array( + '%d person', + '%d people', + ), + ), + '%s Line(s)' => array( '%s Line', '%s Lines', diff --git a/webroot/rsrc/css/application/conpherence/widget-pane.css b/webroot/rsrc/css/application/conpherence/widget-pane.css index 7c85d7e868..2de198970c 100644 --- a/webroot/rsrc/css/application/conpherence/widget-pane.css +++ b/webroot/rsrc/css/application/conpherence/widget-pane.css @@ -192,6 +192,91 @@ padding-bottom: 1px; } +/* people widget */ +.conpherence-widget-pane .people-widget-header { + float: left; + width: 280px; +} + +.conpherence-widget-pane .people-widget-header .divider { + float: left; + clear: both; + width: 260px; + margin: 0px 0px 0px 10px; + border: 1px dashed #bfbfbf; +} +.conpherence-widget-pane .people-widget-header .add-people-widget { + float: left; + padding: 10px 0px 10px 0px; + width: 280px; +} + +.conpherence-widget-pane .people-widget-header .add-people-widget +.aphront-form-control-tokenizer { + float: left; + width: 180px; + padding: 0px 0px 0px 10px +} + +.conpherence-widget-pane .people-widget-header .add-people-widget +.jx-tokenizer-input { + padding: 1px 3px 1px 3px; +} + +.conpherence-widget-pane .people-widget-header .add-people-widget +.people-add-button { + float: right; + margin: 0px 10px 0px 0px; + padding: 3px 16px 4px 16px; +} + +.conpherence-widget-pane .person-entry { + float: left; + width: 270px; + clear: both; + padding: 10px 0px 0px 8px; +} + +.conpherence-widget-pane .person-entry a { + float: left; + clear: none; + font-size: 14px; + font-weight: bold; + width: 166px; +} + +.conpherence-widget-pane .person-entry .pic { + float: left; + clear: left; + margin: 0px 10px 0px 0px; + width: 50px; + padding: 0; +} + +.conpherence-widget-pane .person-entry .remove { + float: right; + clear: right; + margin: 0; + width: 34px; + height: 36px; + text-align: center; + font-size: 22px; + font-weight: bold; + padding: 8px 0px 8px 0px; +} + +.conpherence-widget-pane .person-entry .remove:hover { + text-decoration: none; +} + +.conpherence-widget-pane .person-entry .remove .icon { + color: #bfbfbf; +} + +.conpherence-widget-pane .person-entry .remove:hover .icon { + color: #18559d; +} + /* settings widget */ .conpherence-widget-pane .notifications-update { margin: 2px 0px 0px 8px; diff --git a/webroot/rsrc/js/application/conpherence/behavior-menu.js b/webroot/rsrc/js/application/conpherence/behavior-menu.js index 7feff51285..bda3f09063 100644 --- a/webroot/rsrc/js/application/conpherence/behavior-menu.js +++ b/webroot/rsrc/js/application/conpherence/behavior-menu.js @@ -136,11 +136,17 @@ JX.behavior('conpherence-menu', function(config) { JX.$H(r.header) ); - // update the menu entry as well + // update the menu entry JX.DOM.replace( JX.$(r.conpherence_phid + '-nav-item'), JX.$H(r.nav_item) ); + + // update the people widget + JX.DOM.setContent( + JX.$(config.people_widget), + JX.$H(r.people_widget) + ); }) .start(); }); diff --git a/webroot/rsrc/js/application/conpherence/behavior-widget-pane.js b/webroot/rsrc/js/application/conpherence/behavior-widget-pane.js index 036dee5417..1a6243f1ae 100644 --- a/webroot/rsrc/js/application/conpherence/behavior-widget-pane.js +++ b/webroot/rsrc/js/application/conpherence/behavior-widget-pane.js @@ -39,6 +39,61 @@ JX.behavior('conpherence-widget-pane', function(config) { } ); + /* people widget */ + var peopleRoot = JX.$(config.people_widget); + var peopleUpdateHandler = function (r) { + // update the transactions + var messages = JX.$(config.messages); + JX.DOM.appendContent(messages, JX.$H(r.transactions)); + messages.scrollTop = messages.scrollHeight; + + // update the menu entry as well + JX.DOM.replace( + JX.$(r.conpherence_phid + '-nav-item'), + JX.$H(r.nav_item) + ); + + // update the header + JX.DOM.setContent( + JX.$(config.header), + JX.$H(r.header) + ); + + // update the people widget + JX.DOM.setContent( + JX.$(config.people_widget), + JX.$H(r.people_widget) + ); + }; + + JX.DOM.listen( + peopleRoot, + ['click'], + 'add-person', + function (e) { + e.kill(); + var form = JX.DOM.find(peopleRoot, 'form'); + var data = e.getNodeData('add-person'); + JX.Workflow.newFromForm(form, data) + .setHandler(peopleUpdateHandler) + .start(); + } + ); + + JX.DOM.listen( + peopleRoot, + ['click'], + 'remove-person', + function (e) { + var form = JX.DOM.find(peopleRoot, 'form'); + var data = e.getNodeData('remove-person'); + JX.Workflow.newFromForm(form, data) + .setHandler(peopleUpdateHandler) + .start(); + } + ); + + /* settings widget */ var settingsRoot = JX.$(config.settings_widget); var onsubmitSettings = function (e) {