mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 00:42:41 +01:00
Share rendering code for embedded votes and vote detail
Summary: We have two separate pieces of rendering code and both are pretty ugly. Move them toward being more reasonable. This could no doubt be improved: - Getting a text style which was readable on both the dark and light bars was hard, maybe we should change the colors or maybe I am just bad. - Could probably benefit from actual competent design in general. - JS magic is temporarily ineffective, I'll restore that in the future. - Embed style is a little funky (margin/centering). - Could use a little cleanup. Test Plan: {F50226} {F50227} {F50228} Reviewers: chad, btrahan Reviewed By: btrahan CC: aran Differential Revision: https://secure.phabricator.com/D6465
This commit is contained in:
parent
0a3c03d5b6
commit
89ee928a51
9 changed files with 485 additions and 497 deletions
|
@ -3475,7 +3475,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'phabricator-slowvote-css' =>
|
'phabricator-slowvote-css' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/d1c2e05a/rsrc/css/application/slowvote/slowvote.css',
|
'uri' => '/res/11373549/rsrc/css/application/slowvote/slowvote.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -3702,7 +3702,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'phabricator-zindex-css' =>
|
'phabricator-zindex-css' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/99a9447b/rsrc/css/core/z-index.css',
|
'uri' => '/res/a50437bf/rsrc/css/core/z-index.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -4149,7 +4149,7 @@ celerity_register_resource_map(array(
|
||||||
), array(
|
), array(
|
||||||
'packages' =>
|
'packages' =>
|
||||||
array(
|
array(
|
||||||
'c01cebae' =>
|
'f32a863a' =>
|
||||||
array(
|
array(
|
||||||
'name' => 'core.pkg.css',
|
'name' => 'core.pkg.css',
|
||||||
'symbols' =>
|
'symbols' =>
|
||||||
|
@ -4197,7 +4197,7 @@ celerity_register_resource_map(array(
|
||||||
40 => 'phabricator-property-list-view-css',
|
40 => 'phabricator-property-list-view-css',
|
||||||
41 => 'phabricator-tag-view-css',
|
41 => 'phabricator-tag-view-css',
|
||||||
),
|
),
|
||||||
'uri' => '/res/pkg/c01cebae/core.pkg.css',
|
'uri' => '/res/pkg/f32a863a/core.pkg.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
),
|
),
|
||||||
'75ccea43' =>
|
'75ccea43' =>
|
||||||
|
@ -4391,16 +4391,16 @@ celerity_register_resource_map(array(
|
||||||
'reverse' =>
|
'reverse' =>
|
||||||
array(
|
array(
|
||||||
'aphront-attached-file-view-css' => 'adc3c36d',
|
'aphront-attached-file-view-css' => 'adc3c36d',
|
||||||
'aphront-dialog-view-css' => 'c01cebae',
|
'aphront-dialog-view-css' => 'f32a863a',
|
||||||
'aphront-error-view-css' => 'c01cebae',
|
'aphront-error-view-css' => 'f32a863a',
|
||||||
'aphront-form-view-css' => 'c01cebae',
|
'aphront-form-view-css' => 'f32a863a',
|
||||||
'aphront-list-filter-view-css' => 'c01cebae',
|
'aphront-list-filter-view-css' => 'f32a863a',
|
||||||
'aphront-pager-view-css' => 'c01cebae',
|
'aphront-pager-view-css' => 'f32a863a',
|
||||||
'aphront-panel-view-css' => 'c01cebae',
|
'aphront-panel-view-css' => 'f32a863a',
|
||||||
'aphront-table-view-css' => 'c01cebae',
|
'aphront-table-view-css' => 'f32a863a',
|
||||||
'aphront-tokenizer-control-css' => 'c01cebae',
|
'aphront-tokenizer-control-css' => 'f32a863a',
|
||||||
'aphront-tooltip-css' => 'c01cebae',
|
'aphront-tooltip-css' => 'f32a863a',
|
||||||
'aphront-typeahead-control-css' => 'c01cebae',
|
'aphront-typeahead-control-css' => 'f32a863a',
|
||||||
'differential-changeset-view-css' => 'dd27a69b',
|
'differential-changeset-view-css' => 'dd27a69b',
|
||||||
'differential-core-view-css' => 'dd27a69b',
|
'differential-core-view-css' => 'dd27a69b',
|
||||||
'differential-inline-comment-editor' => '504ca7d2',
|
'differential-inline-comment-editor' => '504ca7d2',
|
||||||
|
@ -4414,7 +4414,7 @@ celerity_register_resource_map(array(
|
||||||
'differential-table-of-contents-css' => 'dd27a69b',
|
'differential-table-of-contents-css' => 'dd27a69b',
|
||||||
'diffusion-commit-view-css' => 'c8ce2d88',
|
'diffusion-commit-view-css' => 'c8ce2d88',
|
||||||
'diffusion-icons-css' => 'c8ce2d88',
|
'diffusion-icons-css' => 'c8ce2d88',
|
||||||
'global-drag-and-drop-css' => 'c01cebae',
|
'global-drag-and-drop-css' => 'f32a863a',
|
||||||
'inline-comment-summary-css' => 'dd27a69b',
|
'inline-comment-summary-css' => 'dd27a69b',
|
||||||
'javelin-aphlict' => '75ccea43',
|
'javelin-aphlict' => '75ccea43',
|
||||||
'javelin-behavior' => 'a9f14d76',
|
'javelin-behavior' => 'a9f14d76',
|
||||||
|
@ -4488,55 +4488,55 @@ celerity_register_resource_map(array(
|
||||||
'javelin-util' => 'a9f14d76',
|
'javelin-util' => 'a9f14d76',
|
||||||
'javelin-vector' => 'a9f14d76',
|
'javelin-vector' => 'a9f14d76',
|
||||||
'javelin-workflow' => 'a9f14d76',
|
'javelin-workflow' => 'a9f14d76',
|
||||||
'lightbox-attachment-css' => 'c01cebae',
|
'lightbox-attachment-css' => 'f32a863a',
|
||||||
'maniphest-task-summary-css' => 'adc3c36d',
|
'maniphest-task-summary-css' => 'adc3c36d',
|
||||||
'maniphest-transaction-detail-css' => 'adc3c36d',
|
'maniphest-transaction-detail-css' => 'adc3c36d',
|
||||||
'phabricator-action-list-view-css' => 'c01cebae',
|
'phabricator-action-list-view-css' => 'f32a863a',
|
||||||
'phabricator-application-launch-view-css' => 'c01cebae',
|
'phabricator-application-launch-view-css' => 'f32a863a',
|
||||||
'phabricator-busy' => '75ccea43',
|
'phabricator-busy' => '75ccea43',
|
||||||
'phabricator-content-source-view-css' => 'dd27a69b',
|
'phabricator-content-source-view-css' => 'dd27a69b',
|
||||||
'phabricator-core-css' => 'c01cebae',
|
'phabricator-core-css' => 'f32a863a',
|
||||||
'phabricator-crumbs-view-css' => 'c01cebae',
|
'phabricator-crumbs-view-css' => 'f32a863a',
|
||||||
'phabricator-drag-and-drop-file-upload' => '504ca7d2',
|
'phabricator-drag-and-drop-file-upload' => '504ca7d2',
|
||||||
'phabricator-dropdown-menu' => '75ccea43',
|
'phabricator-dropdown-menu' => '75ccea43',
|
||||||
'phabricator-file-upload' => '75ccea43',
|
'phabricator-file-upload' => '75ccea43',
|
||||||
'phabricator-filetree-view-css' => 'c01cebae',
|
'phabricator-filetree-view-css' => 'f32a863a',
|
||||||
'phabricator-flag-css' => 'c01cebae',
|
'phabricator-flag-css' => 'f32a863a',
|
||||||
'phabricator-form-view-css' => 'c01cebae',
|
'phabricator-form-view-css' => 'f32a863a',
|
||||||
'phabricator-header-view-css' => 'c01cebae',
|
'phabricator-header-view-css' => 'f32a863a',
|
||||||
'phabricator-hovercard' => '75ccea43',
|
'phabricator-hovercard' => '75ccea43',
|
||||||
'phabricator-jump-nav' => 'c01cebae',
|
'phabricator-jump-nav' => 'f32a863a',
|
||||||
'phabricator-keyboard-shortcut' => '75ccea43',
|
'phabricator-keyboard-shortcut' => '75ccea43',
|
||||||
'phabricator-keyboard-shortcut-manager' => '75ccea43',
|
'phabricator-keyboard-shortcut-manager' => '75ccea43',
|
||||||
'phabricator-main-menu-view' => 'c01cebae',
|
'phabricator-main-menu-view' => 'f32a863a',
|
||||||
'phabricator-menu-item' => '75ccea43',
|
'phabricator-menu-item' => '75ccea43',
|
||||||
'phabricator-nav-view-css' => 'c01cebae',
|
'phabricator-nav-view-css' => 'f32a863a',
|
||||||
'phabricator-notification' => '75ccea43',
|
'phabricator-notification' => '75ccea43',
|
||||||
'phabricator-notification-css' => 'c01cebae',
|
'phabricator-notification-css' => 'f32a863a',
|
||||||
'phabricator-notification-menu-css' => 'c01cebae',
|
'phabricator-notification-menu-css' => 'f32a863a',
|
||||||
'phabricator-object-item-list-view-css' => 'c01cebae',
|
'phabricator-object-item-list-view-css' => 'f32a863a',
|
||||||
'phabricator-object-selector-css' => 'dd27a69b',
|
'phabricator-object-selector-css' => 'dd27a69b',
|
||||||
'phabricator-phtize' => '75ccea43',
|
'phabricator-phtize' => '75ccea43',
|
||||||
'phabricator-prefab' => '75ccea43',
|
'phabricator-prefab' => '75ccea43',
|
||||||
'phabricator-project-tag-css' => 'adc3c36d',
|
'phabricator-project-tag-css' => 'adc3c36d',
|
||||||
'phabricator-property-list-view-css' => 'c01cebae',
|
'phabricator-property-list-view-css' => 'f32a863a',
|
||||||
'phabricator-remarkup-css' => 'c01cebae',
|
'phabricator-remarkup-css' => 'f32a863a',
|
||||||
'phabricator-shaped-request' => '504ca7d2',
|
'phabricator-shaped-request' => '504ca7d2',
|
||||||
'phabricator-side-menu-view-css' => 'c01cebae',
|
'phabricator-side-menu-view-css' => 'f32a863a',
|
||||||
'phabricator-standard-page-view' => 'c01cebae',
|
'phabricator-standard-page-view' => 'f32a863a',
|
||||||
'phabricator-tag-view-css' => 'c01cebae',
|
'phabricator-tag-view-css' => 'f32a863a',
|
||||||
'phabricator-textareautils' => '75ccea43',
|
'phabricator-textareautils' => '75ccea43',
|
||||||
'phabricator-tooltip' => '75ccea43',
|
'phabricator-tooltip' => '75ccea43',
|
||||||
'phabricator-transaction-view-css' => 'c01cebae',
|
'phabricator-transaction-view-css' => 'f32a863a',
|
||||||
'phabricator-zindex-css' => 'c01cebae',
|
'phabricator-zindex-css' => 'f32a863a',
|
||||||
'phui-button-css' => 'c01cebae',
|
'phui-button-css' => 'f32a863a',
|
||||||
'phui-form-css' => 'c01cebae',
|
'phui-form-css' => 'f32a863a',
|
||||||
'phui-icon-view-css' => 'c01cebae',
|
'phui-icon-view-css' => 'f32a863a',
|
||||||
'phui-spacing-css' => 'c01cebae',
|
'phui-spacing-css' => 'f32a863a',
|
||||||
'sprite-apps-large-css' => 'c01cebae',
|
'sprite-apps-large-css' => 'f32a863a',
|
||||||
'sprite-gradient-css' => 'c01cebae',
|
'sprite-gradient-css' => 'f32a863a',
|
||||||
'sprite-icons-css' => 'c01cebae',
|
'sprite-icons-css' => 'f32a863a',
|
||||||
'sprite-menu-css' => 'c01cebae',
|
'sprite-menu-css' => 'f32a863a',
|
||||||
'syntax-highlighting-css' => 'c01cebae',
|
'syntax-highlighting-css' => 'f32a863a',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
|
@ -51,7 +51,7 @@ final class PhabricatorSlowvoteEditController
|
||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
$v_question = $request->getStr('question');
|
$v_question = $request->getStr('question');
|
||||||
$v_description = $request->getStr('description');
|
$v_description = $request->getStr('description');
|
||||||
$v_responses = $request->getInt('responses');
|
$v_responses = (int)$request->getInt('responses');
|
||||||
$v_shuffle = (int)$request->getBool('shuffle');
|
$v_shuffle = (int)$request->getBool('shuffle');
|
||||||
|
|
||||||
if ($is_new) {
|
if ($is_new) {
|
||||||
|
|
|
@ -13,116 +13,40 @@ final class PhabricatorSlowvotePollController
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processRequest() {
|
public function processRequest() {
|
||||||
|
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$user = $request->getUser();
|
$user = $request->getUser();
|
||||||
$viewer_phid = $user->getPHID();
|
|
||||||
|
|
||||||
$poll = id(new PhabricatorSlowvoteQuery())
|
$poll = id(new PhabricatorSlowvoteQuery())
|
||||||
->setViewer($user)
|
->setViewer($user)
|
||||||
->withIDs(array($this->id))
|
->withIDs(array($this->id))
|
||||||
->needOptions(true)
|
->needOptions(true)
|
||||||
->needChoices(true)
|
->needChoices(true)
|
||||||
|
->needViewerChoices(true)
|
||||||
->executeOne();
|
->executeOne();
|
||||||
if (!$poll) {
|
if (!$poll) {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
$options = $poll->getOptions();
|
$poll_view = id(new SlowvoteEmbedView())
|
||||||
$choices = $poll->getChoices();
|
->setHeadless(true)
|
||||||
|
->setUser($user)
|
||||||
$choices_by_option = mgroup($choices, 'getOptionID');
|
->setPoll($poll);
|
||||||
$choices_by_user = mgroup($choices, 'getAuthorPHID');
|
|
||||||
$viewer_choices = idx($choices_by_user, $viewer_phid, array());
|
|
||||||
|
|
||||||
if ($request->isAjax()) {
|
if ($request->isAjax()) {
|
||||||
$embed = id(new SlowvoteEmbedView())
|
|
||||||
->setPoll($poll)
|
|
||||||
->setOptions($options)
|
|
||||||
->setViewerChoices($viewer_choices);
|
|
||||||
|
|
||||||
return id(new AphrontAjaxResponse())
|
return id(new AphrontAjaxResponse())
|
||||||
->setContent(array(
|
->setContent(
|
||||||
'pollID' => $poll->getID(),
|
array(
|
||||||
'contentHTML' => $embed->render()));
|
'pollID' => $poll->getID(),
|
||||||
|
'contentHTML' => $poll_view->render(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
require_celerity_resource('phabricator-slowvote-css');
|
|
||||||
|
|
||||||
$phids = array_merge(
|
|
||||||
mpull($choices, 'getAuthorPHID'),
|
|
||||||
array(
|
|
||||||
$poll->getAuthorPHID(),
|
|
||||||
));
|
|
||||||
|
|
||||||
$query = new PhabricatorObjectHandleData($phids);
|
|
||||||
$query->setViewer($user);
|
|
||||||
$handles = $query->loadHandles();
|
|
||||||
$objects = $query->loadObjects();
|
|
||||||
|
|
||||||
if ($poll->getShuffle()) {
|
|
||||||
shuffle($options);
|
|
||||||
}
|
|
||||||
|
|
||||||
$option_markup = array();
|
|
||||||
foreach ($options as $option) {
|
|
||||||
$option_markup[] = $this->renderPollOption(
|
|
||||||
$poll,
|
|
||||||
$viewer_choices,
|
|
||||||
$option);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($poll->getMethod()) {
|
|
||||||
case PhabricatorSlowvotePoll::METHOD_PLURALITY:
|
|
||||||
$choice_ids = array();
|
|
||||||
foreach ($choices_by_user as $user_phid => $user_choices) {
|
|
||||||
$choice_ids[$user_phid] = head($user_choices)->getOptionID();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PhabricatorSlowvotePoll::METHOD_APPROVAL:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Exception("Unknown poll method!");
|
|
||||||
}
|
|
||||||
|
|
||||||
$result_markup = $this->renderResultMarkup(
|
|
||||||
$poll,
|
|
||||||
$options,
|
|
||||||
$choices,
|
|
||||||
$viewer_choices,
|
|
||||||
$choices_by_option,
|
|
||||||
$handles,
|
|
||||||
$objects);
|
|
||||||
|
|
||||||
if ($viewer_choices) {
|
|
||||||
$instructions =
|
|
||||||
pht('Your vote has been recorded... but there is still ample time to '.
|
|
||||||
'rethink your position. Have you thoroughly considered all possible '.
|
|
||||||
'eventualities?');
|
|
||||||
} else {
|
|
||||||
$instructions =
|
|
||||||
pht('This is a weighty matter indeed. Consider your choices with the '.
|
|
||||||
'greatest of care.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$form = id(new AphrontFormView())
|
|
||||||
->setUser($user)
|
|
||||||
->setFlexible(true)
|
|
||||||
->setAction(sprintf('/vote/%d/', $poll->getID()))
|
|
||||||
->appendChild(hsprintf(
|
|
||||||
'<p class="aphront-form-instructions">%s</p>',
|
|
||||||
$instructions))
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormMarkupControl())
|
|
||||||
->setLabel(pht('Vote'))
|
|
||||||
->setValue($option_markup))
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormSubmitControl())
|
|
||||||
->setValue(pht('Engage in Deliberations')));
|
|
||||||
|
|
||||||
$header = id(new PhabricatorHeaderView())
|
$header = id(new PhabricatorHeaderView())
|
||||||
->setHeader($poll->getQuestion());
|
->setHeader($poll->getQuestion());
|
||||||
|
|
||||||
|
$xaction_header = id(new PhabricatorHeaderView())
|
||||||
|
->setHeader(pht('Ongoing Deliberations'));
|
||||||
|
|
||||||
$actions = $this->buildActionView($poll);
|
$actions = $this->buildActionView($poll);
|
||||||
$properties = $this->buildPropertyView($poll);
|
$properties = $this->buildPropertyView($poll);
|
||||||
|
|
||||||
|
@ -131,15 +55,6 @@ final class PhabricatorSlowvotePollController
|
||||||
id(new PhabricatorCrumbView())
|
id(new PhabricatorCrumbView())
|
||||||
->setName('V'.$poll->getID()));
|
->setName('V'.$poll->getID()));
|
||||||
|
|
||||||
$panel = new AphrontPanelView();
|
|
||||||
$panel->setWidth(AphrontPanelView::WIDTH_WIDE);
|
|
||||||
$panel->appendChild($result_markup);
|
|
||||||
|
|
||||||
$content = array(
|
|
||||||
$form,
|
|
||||||
hsprintf('<br /><br />'),
|
|
||||||
$panel);
|
|
||||||
|
|
||||||
$xactions = $this->buildTransactions($poll);
|
$xactions = $this->buildTransactions($poll);
|
||||||
$add_comment = $this->buildCommentForm($poll);
|
$add_comment = $this->buildCommentForm($poll);
|
||||||
|
|
||||||
|
@ -149,7 +64,13 @@ final class PhabricatorSlowvotePollController
|
||||||
$header,
|
$header,
|
||||||
$actions,
|
$actions,
|
||||||
$properties,
|
$properties,
|
||||||
$content,
|
phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'ml',
|
||||||
|
),
|
||||||
|
$poll_view),
|
||||||
|
$xaction_header,
|
||||||
$xactions,
|
$xactions,
|
||||||
$add_comment,
|
$add_comment,
|
||||||
),
|
),
|
||||||
|
@ -161,208 +82,6 @@ final class PhabricatorSlowvotePollController
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private function renderPollOption(
|
|
||||||
PhabricatorSlowvotePoll $poll,
|
|
||||||
array $viewer_choices,
|
|
||||||
PhabricatorSlowvoteOption $option) {
|
|
||||||
assert_instances_of($viewer_choices, 'PhabricatorSlowvoteChoice');
|
|
||||||
|
|
||||||
$id = $option->getID();
|
|
||||||
switch ($poll->getMethod()) {
|
|
||||||
case PhabricatorSlowvotePoll::METHOD_PLURALITY:
|
|
||||||
|
|
||||||
// Render a radio button.
|
|
||||||
|
|
||||||
$selected_option = head($viewer_choices);
|
|
||||||
if ($selected_option) {
|
|
||||||
$selected = $selected_option->getOptionID();
|
|
||||||
} else {
|
|
||||||
$selected = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($selected == $id) {
|
|
||||||
$checked = "checked";
|
|
||||||
} else {
|
|
||||||
$checked = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$input = phutil_tag(
|
|
||||||
'input',
|
|
||||||
array(
|
|
||||||
'type' => 'radio',
|
|
||||||
'name' => 'vote[]',
|
|
||||||
'value' => $id,
|
|
||||||
'checked' => $checked,
|
|
||||||
));
|
|
||||||
break;
|
|
||||||
case PhabricatorSlowvotePoll::METHOD_APPROVAL:
|
|
||||||
|
|
||||||
// Render a check box.
|
|
||||||
|
|
||||||
$checked = null;
|
|
||||||
foreach ($viewer_choices as $choice) {
|
|
||||||
if ($choice->getOptionID() == $id) {
|
|
||||||
$checked = 'checked';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$input = phutil_tag(
|
|
||||||
'input',
|
|
||||||
array(
|
|
||||||
'type' => 'checkbox',
|
|
||||||
'name' => 'vote[]',
|
|
||||||
'checked' => $checked,
|
|
||||||
'value' => $id,
|
|
||||||
));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Exception("Unknown poll method!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($checked) {
|
|
||||||
$checked_class = 'phabricator-slowvote-checked';
|
|
||||||
} else {
|
|
||||||
$checked_class = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return phutil_tag(
|
|
||||||
'label',
|
|
||||||
array(
|
|
||||||
'class' => 'phabricator-slowvote-label '.$checked_class,
|
|
||||||
),
|
|
||||||
array($input, $option->getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private function renderVoteCount(
|
|
||||||
PhabricatorSlowvotePoll $poll,
|
|
||||||
array $choices,
|
|
||||||
array $chosen) {
|
|
||||||
assert_instances_of($choices, 'PhabricatorSlowvoteChoice');
|
|
||||||
assert_instances_of($chosen, 'PhabricatorSlowvoteChoice');
|
|
||||||
|
|
||||||
switch ($poll->getMethod()) {
|
|
||||||
case PhabricatorSlowvotePoll::METHOD_PLURALITY:
|
|
||||||
$out_of_total = count($choices);
|
|
||||||
break;
|
|
||||||
case PhabricatorSlowvotePoll::METHOD_APPROVAL:
|
|
||||||
// Count unique respondents for approval votes.
|
|
||||||
$out_of_total = count(mpull($choices, null, 'getAuthorPHID'));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Exception("Unknown poll method!");
|
|
||||||
}
|
|
||||||
|
|
||||||
return sprintf(
|
|
||||||
'%d / %d (%d%%)',
|
|
||||||
number_format(count($chosen)),
|
|
||||||
number_format($out_of_total),
|
|
||||||
$out_of_total
|
|
||||||
? round(100 * count($chosen) / $out_of_total)
|
|
||||||
: 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function renderResultMarkup(
|
|
||||||
PhabricatorSlowvotePoll $poll,
|
|
||||||
array $options,
|
|
||||||
array $choices,
|
|
||||||
array $viewer_choices,
|
|
||||||
array $choices_by_option,
|
|
||||||
array $handles,
|
|
||||||
array $objects) {
|
|
||||||
assert_instances_of($options, 'PhabricatorSlowvoteOption');
|
|
||||||
assert_instances_of($choices, 'PhabricatorSlowvoteChoice');
|
|
||||||
assert_instances_of($viewer_choices, 'PhabricatorSlowvoteChoice');
|
|
||||||
assert_instances_of($handles, 'PhabricatorObjectHandle');
|
|
||||||
assert_instances_of($objects, 'PhabricatorLiskDAO');
|
|
||||||
|
|
||||||
$viewer_phid = $this->getRequest()->getUser()->getPHID();
|
|
||||||
|
|
||||||
$can_see_responses = false;
|
|
||||||
$need_vote = false;
|
|
||||||
switch ($poll->getResponseVisibility()) {
|
|
||||||
case PhabricatorSlowvotePoll::RESPONSES_VISIBLE:
|
|
||||||
$can_see_responses = true;
|
|
||||||
break;
|
|
||||||
case PhabricatorSlowvotePoll::RESPONSES_VOTERS:
|
|
||||||
$can_see_responses = (bool)$viewer_choices;
|
|
||||||
$need_vote = true;
|
|
||||||
break;
|
|
||||||
case PhabricatorSlowvotePoll::RESPONSES_OWNER:
|
|
||||||
$can_see_responses = ($viewer_phid == $poll->getAuthorPHID());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$result_markup = id(new AphrontFormLayoutView())
|
|
||||||
->appendChild(phutil_tag('h1', array(), pht('Ongoing Deliberation')));
|
|
||||||
|
|
||||||
if (!$can_see_responses) {
|
|
||||||
if ($need_vote) {
|
|
||||||
$reason = pht("You must vote to see the results.");
|
|
||||||
} else {
|
|
||||||
$reason = pht("The results are not public.");
|
|
||||||
}
|
|
||||||
$result_markup
|
|
||||||
->appendChild(hsprintf(
|
|
||||||
'<p class="aphront-form-instructions"><em>%s</em></p>',
|
|
||||||
$reason));
|
|
||||||
return $result_markup;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($options as $option) {
|
|
||||||
$id = $option->getID();
|
|
||||||
|
|
||||||
$chosen = idx($choices_by_option, $id, array());
|
|
||||||
$users = array_select_keys($handles, mpull($chosen, 'getAuthorPHID'));
|
|
||||||
if ($users) {
|
|
||||||
$user_markup = array();
|
|
||||||
foreach ($users as $handle) {
|
|
||||||
$object = idx($objects, $handle->getPHID());
|
|
||||||
if (!$object) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$profile_image = $handle->getImageURI();
|
|
||||||
|
|
||||||
$user_markup[] = phutil_tag(
|
|
||||||
'a',
|
|
||||||
array(
|
|
||||||
'href' => $handle->getURI(),
|
|
||||||
'class' => 'phabricator-slowvote-facepile',
|
|
||||||
),
|
|
||||||
phutil_tag(
|
|
||||||
'img',
|
|
||||||
array(
|
|
||||||
'src' => $profile_image,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$user_markup = pht('This option has failed to appeal to anyone.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$vote_count = $this->renderVoteCount(
|
|
||||||
$poll,
|
|
||||||
$choices,
|
|
||||||
$chosen);
|
|
||||||
|
|
||||||
$result_markup->appendChild(hsprintf(
|
|
||||||
'<div>'.
|
|
||||||
'<div class="phabricator-slowvote-count">%s</div>'.
|
|
||||||
'<h1>%s</h1>'.
|
|
||||||
'<hr class="phabricator-slowvote-hr" />'.
|
|
||||||
'%s'.
|
|
||||||
'<div style="clear: both;"></div>'.
|
|
||||||
'<hr class="phabricator-slowvote-hr" />'.
|
|
||||||
'</div>',
|
|
||||||
$vote_count,
|
|
||||||
$option->getName(),
|
|
||||||
phutil_tag('div', array(), $user_markup)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result_markup;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function buildActionView(PhabricatorSlowvotePoll $poll) {
|
private function buildActionView(PhabricatorSlowvotePoll $poll) {
|
||||||
$viewer = $this->getRequest()->getUser();
|
$viewer = $this->getRequest()->getUser();
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,14 @@ final class PhabricatorSlowvoteEditor
|
||||||
|
|
||||||
switch ($xaction->getTransactionType()) {
|
switch ($xaction->getTransactionType()) {
|
||||||
case PhabricatorSlowvoteTransaction::TYPE_RESPONSES:
|
case PhabricatorSlowvoteTransaction::TYPE_RESPONSES:
|
||||||
|
if ($old === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return ((int)$old !== (int)$new);
|
return ((int)$old !== (int)$new);
|
||||||
case PhabricatorSlowvoteTransaction::TYPE_SHUFFLE:
|
case PhabricatorSlowvoteTransaction::TYPE_SHUFFLE:
|
||||||
|
if ($old === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return ((bool)$old !== (bool)$new);
|
return ((bool)$old !== (bool)$new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,16 +25,11 @@ final class SlowvoteRemarkupRule
|
||||||
protected function renderObjectEmbed($object, $handle, $options) {
|
protected function renderObjectEmbed($object, $handle, $options) {
|
||||||
$viewer = $this->getEngine()->getConfig('viewer');
|
$viewer = $this->getEngine()->getConfig('viewer');
|
||||||
|
|
||||||
$options = $object->getOptions();
|
|
||||||
$choices = $object->getChoices();
|
|
||||||
$viewer_choices = $object->getViewerChoices($viewer);
|
|
||||||
|
|
||||||
$embed = id(new SlowvoteEmbedView())
|
$embed = id(new SlowvoteEmbedView())
|
||||||
->setPoll($object)
|
->setUser($viewer)
|
||||||
->setOptions($options)
|
->setPoll($object);
|
||||||
->setViewerChoices($viewer_choices);
|
|
||||||
|
|
||||||
return $embed->render();
|
return $embed;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ final class PhabricatorSlowvotePoll extends PhabricatorSlowvoteDAO
|
||||||
}
|
}
|
||||||
|
|
||||||
public function attachViewerChoices(PhabricatorUser $viewer, array $choices) {
|
public function attachViewerChoices(PhabricatorUser $viewer, array $choices) {
|
||||||
assert_instances_of($choices, 'PhabricatorSlowvoteOption');
|
assert_instances_of($choices, 'PhabricatorSlowvoteChoice');
|
||||||
$this->viewerChoices[$viewer->getPHID()] = $choices;
|
$this->viewerChoices[$viewer->getPHID()] = $choices;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,123 +6,349 @@
|
||||||
final class SlowvoteEmbedView extends AphrontView {
|
final class SlowvoteEmbedView extends AphrontView {
|
||||||
|
|
||||||
private $poll;
|
private $poll;
|
||||||
private $options;
|
private $handles;
|
||||||
private $viewerChoices;
|
private $headless;
|
||||||
|
|
||||||
|
public function setHeadless($headless) {
|
||||||
|
$this->headless = $headless;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function setPoll(PhabricatorSlowvotePoll $poll) {
|
public function setPoll(PhabricatorSlowvotePoll $poll) {
|
||||||
$this->poll = $poll;
|
$this->poll = $poll;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setOptions(array $options) {
|
public function getPoll() {
|
||||||
$this->options = $options;
|
return $this->poll;
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setViewerChoices(array $viewer_choices) {
|
|
||||||
$this->viewerChoices = $viewer_choices;
|
|
||||||
return $this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render() {
|
public function render() {
|
||||||
|
|
||||||
if (!$this->poll) {
|
if (!$this->poll) {
|
||||||
throw new Exception("Call setPoll() before render()!");
|
throw new Exception("Call setPoll() before render()!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->options) {
|
$poll = $this->poll;
|
||||||
throw new Exception("Call setOptions() before render()!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->poll->getShuffle()) {
|
$phids = array();
|
||||||
shuffle($this->options);
|
foreach ($poll->getChoices() as $choice) {
|
||||||
|
$phids[] = $choice->getAuthorPHID();
|
||||||
|
}
|
||||||
|
$phids[] = $poll->getAuthorPHID();
|
||||||
|
|
||||||
|
$this->handles = id(new PhabricatorObjectHandleData($phids))
|
||||||
|
->setViewer($this->getUser())
|
||||||
|
->loadHandles();
|
||||||
|
|
||||||
|
$options = $poll->getOptions();
|
||||||
|
|
||||||
|
if ($poll->getShuffle()) {
|
||||||
|
shuffle($options);
|
||||||
}
|
}
|
||||||
|
|
||||||
require_celerity_resource('phabricator-slowvote-css');
|
require_celerity_resource('phabricator-slowvote-css');
|
||||||
require_celerity_resource('javelin-behavior-slowvote-embed');
|
require_celerity_resource('javelin-behavior-slowvote-embed');
|
||||||
|
|
||||||
$config = array(
|
$config = array(
|
||||||
'pollID' => $this->poll->getID());
|
'pollID' => $poll->getID());
|
||||||
Javelin::initBehavior('slowvote-embed', $config);
|
Javelin::initBehavior('slowvote-embed', $config);
|
||||||
|
|
||||||
$user_choices = array();
|
$user_choices = $poll->getViewerChoices($this->getUser());
|
||||||
if (!empty($this->viewerChoices)) {
|
$user_choices = mpull($user_choices, 'getOptionID', 'getOptionID');
|
||||||
$user_choices = mpull($this->viewerChoices, null, 'getOptionID');
|
|
||||||
}
|
|
||||||
|
|
||||||
$options = array();
|
$out = array();
|
||||||
$ribbon_colors = array('#DF0101', '#DF7401', '#D7DF01', '#74DF00',
|
foreach ($options as $option) {
|
||||||
'#01DF01', '#01DF74', '#01DFD7', '#0174DF', '#0101DF', '#5F04B4',
|
$is_selected = isset($user_choices[$option->getID()]);
|
||||||
'#B404AE');
|
$out[] = $this->renderLabel($option, $is_selected);
|
||||||
shuffle($ribbon_colors);
|
|
||||||
|
|
||||||
foreach ($this->options as $option) {
|
|
||||||
$classes = 'phabricator-slowvote-embed-option-text';
|
|
||||||
|
|
||||||
$selected = '';
|
|
||||||
|
|
||||||
|
|
||||||
if (idx($user_choices, $option->getID(), false)) {
|
|
||||||
$classes .= ' phabricator-slowvote-embed-option-selected';
|
|
||||||
$selected = '@';
|
|
||||||
}
|
|
||||||
|
|
||||||
$is_selected = javelin_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => 'phabricator-slowvote-embed-option-vote',
|
|
||||||
'sigil' => 'slowvote-embed-vote'
|
|
||||||
),
|
|
||||||
$selected);
|
|
||||||
|
|
||||||
$option_text = javelin_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => $classes,
|
|
||||||
'sigil' => 'slowvote-option',
|
|
||||||
'meta' => array(
|
|
||||||
'optionID' => $option->getID()
|
|
||||||
)
|
|
||||||
),
|
|
||||||
array($is_selected, $option->getName()));
|
|
||||||
|
|
||||||
$options[] = phutil_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => 'phabricator-slowvote-embed-option',
|
|
||||||
'style' =>
|
|
||||||
sprintf('border-left: 7px solid %s;', array_shift($ribbon_colors))
|
|
||||||
),
|
|
||||||
array($option_text));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$link_to_slowvote = phutil_tag(
|
$link_to_slowvote = phutil_tag(
|
||||||
'a',
|
'a',
|
||||||
array(
|
array(
|
||||||
'href' => '/V'.$this->poll->getID()
|
'href' => '/V'.$poll->getID()
|
||||||
),
|
),
|
||||||
$this->poll->getQuestion());
|
$poll->getQuestion());
|
||||||
|
|
||||||
$header = phutil_tag(
|
if ($this->headless) {
|
||||||
'div',
|
$header = null;
|
||||||
array(),
|
} else {
|
||||||
array('V'.$this->poll->getID().': ', $link_to_slowvote));
|
$header = phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'slowvote-header',
|
||||||
|
),
|
||||||
|
phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'slowvote-header-content',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'V'.$poll->getID(),
|
||||||
|
' ',
|
||||||
|
$link_to_slowvote)));
|
||||||
|
|
||||||
$body = phutil_tag(
|
$description = null;
|
||||||
|
if ($poll->getDescription()) {
|
||||||
|
$description = PhabricatorMarkupEngine::renderOneObject(
|
||||||
|
id(new PhabricatorMarkupOneOff())->setContent(
|
||||||
|
$poll->getDescription()),
|
||||||
|
'default',
|
||||||
|
$this->getUser());
|
||||||
|
$description = phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'slowvote-description',
|
||||||
|
),
|
||||||
|
$description);
|
||||||
|
}
|
||||||
|
|
||||||
|
$header = array(
|
||||||
|
$header,
|
||||||
|
$description);
|
||||||
|
}
|
||||||
|
|
||||||
|
$vis = $poll->getResponseVisibility();
|
||||||
|
if ($this->areResultsVisible()) {
|
||||||
|
if ($vis == PhabricatorSlowvotePoll::RESPONSES_OWNER) {
|
||||||
|
$quip = pht('Only you can see the results.');
|
||||||
|
} else {
|
||||||
|
$quip = pht('Voting improves cardiovascular endurance.');
|
||||||
|
}
|
||||||
|
} else if ($vis == PhabricatorSlowvotePoll::RESPONSES_VOTERS) {
|
||||||
|
$quip = pht('You must vote to see the results.');
|
||||||
|
} else if ($vis == PhabricatorSlowvotePoll::RESPONSES_OWNER) {
|
||||||
|
$quip = pht('Only the author can see the results.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$hint = phutil_tag(
|
||||||
|
'span',
|
||||||
|
array(
|
||||||
|
'class' => 'slowvote-hint',
|
||||||
|
),
|
||||||
|
$quip);
|
||||||
|
|
||||||
|
$submit = phutil_tag(
|
||||||
'div',
|
'div',
|
||||||
array(),
|
array(
|
||||||
$options);
|
'class' => 'slowvote-footer',
|
||||||
|
),
|
||||||
|
phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'slowvote-footer-content',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
$hint,
|
||||||
|
phutil_tag(
|
||||||
|
'button',
|
||||||
|
array(
|
||||||
|
),
|
||||||
|
pht('Engage in Deliberations')),
|
||||||
|
)));
|
||||||
|
|
||||||
|
$body = phabricator_form(
|
||||||
|
$this->getUser(),
|
||||||
|
array(
|
||||||
|
'action' => '/vote/'.$poll->getID().'/',
|
||||||
|
'method' => 'POST',
|
||||||
|
'class' => 'slowvote-body',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'slowvote-body-content',
|
||||||
|
),
|
||||||
|
$out),
|
||||||
|
$submit,
|
||||||
|
));
|
||||||
|
|
||||||
return javelin_tag(
|
return javelin_tag(
|
||||||
'div',
|
'div',
|
||||||
array(
|
array(
|
||||||
'class' => 'phabricator-slowvote-embed',
|
'class' => 'slowvote-embed',
|
||||||
'sigil' => 'slowvote-embed',
|
'sigil' => 'slowvote-embed',
|
||||||
'meta' => array(
|
'meta' => array(
|
||||||
'pollID' => $this->poll->getID()
|
'pollID' => $poll->getID()
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
array($header, $body));
|
array($header, $body));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function renderLabel(PhabricatorSlowvoteOption $option, $selected) {
|
||||||
|
$classes = array();
|
||||||
|
$classes[] = 'slowvote-option-label';
|
||||||
|
|
||||||
|
$status = $this->renderStatus($option);
|
||||||
|
$voters = $this->renderVoters($option);
|
||||||
|
|
||||||
|
return phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'slowvote-option-label-group',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
phutil_tag(
|
||||||
|
'label',
|
||||||
|
array(
|
||||||
|
'class' => implode(' ', $classes),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'slowvote-control-offset',
|
||||||
|
),
|
||||||
|
$option->getName()),
|
||||||
|
$this->renderBar($option),
|
||||||
|
phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'slowvote-above-the-bar',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
$this->renderControl($option, $selected),
|
||||||
|
)),
|
||||||
|
)),
|
||||||
|
$status,
|
||||||
|
$voters,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function renderBar(PhabricatorSlowvoteOption $option) {
|
||||||
|
if (!$this->areResultsVisible()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$poll = $this->getPoll();
|
||||||
|
|
||||||
|
$choices = mgroup($poll->getChoices(), 'getOptionID');
|
||||||
|
$choices = count(idx($choices, $option->getID(), array()));
|
||||||
|
$count = count(mgroup($poll->getChoices(), 'getAuthorPHID'));
|
||||||
|
|
||||||
|
return phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'slowvote-bar',
|
||||||
|
'style' => sprintf(
|
||||||
|
'width: %.1f%%;',
|
||||||
|
$count ? 100 * ($choices / $count) : 0),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'slowvote-control-offset',
|
||||||
|
),
|
||||||
|
$option->getName()),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function renderControl(PhabricatorSlowvoteOption $option, $selected) {
|
||||||
|
$types = array(
|
||||||
|
PhabricatorSlowvotePoll::METHOD_PLURALITY => 'radio',
|
||||||
|
PhabricatorSlowvotePoll::METHOD_APPROVAL => 'checkbox',
|
||||||
|
);
|
||||||
|
|
||||||
|
return phutil_tag(
|
||||||
|
'input',
|
||||||
|
array(
|
||||||
|
'type' => idx($types, $this->getPoll()->getMethod()),
|
||||||
|
'name' => 'vote[]',
|
||||||
|
'value' => $option->getID(),
|
||||||
|
'checked' => ($selected ? 'checked' : null),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function renderVoters(PhabricatorSlowvoteOption $option) {
|
||||||
|
if (!$this->areResultsVisible()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$poll = $this->getPoll();
|
||||||
|
|
||||||
|
$choices = mgroup($poll->getChoices(), 'getOptionID');
|
||||||
|
$choices = idx($choices, $option->getID(), array());
|
||||||
|
|
||||||
|
if (!$choices) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$handles = $this->handles;
|
||||||
|
$authors = mpull($choices, 'getAuthorPHID', 'getAuthorPHID');
|
||||||
|
|
||||||
|
$viewer_phid = $this->getUser()->getPHID();
|
||||||
|
|
||||||
|
// Put the viewer first if they've voted for this option.
|
||||||
|
$authors = array_select_keys($authors, array($viewer_phid))
|
||||||
|
+ $authors;
|
||||||
|
|
||||||
|
$voters = array();
|
||||||
|
foreach ($authors as $author_phid) {
|
||||||
|
$handle = $handles[$author_phid];
|
||||||
|
|
||||||
|
$voters[] = javelin_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'slowvote-voter',
|
||||||
|
'style' => 'background-image: url('.$handle->getImageURI().')',
|
||||||
|
'sigil' => 'has-tooltip',
|
||||||
|
'meta' => array(
|
||||||
|
'tip' => $handle->getName(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'slowvote-voters',
|
||||||
|
),
|
||||||
|
$voters);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function renderStatus(PhabricatorSlowvoteOption $option) {
|
||||||
|
if (!$this->areResultsVisible()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$poll = $this->getPoll();
|
||||||
|
|
||||||
|
$choices = mgroup($poll->getChoices(), 'getOptionID');
|
||||||
|
$choices = count(idx($choices, $option->getID(), array()));
|
||||||
|
$count = count(mgroup($poll->getChoices(), 'getAuthorPHID'));
|
||||||
|
|
||||||
|
$percent = sprintf('%d%%', $count ? 100 * $choices / $count : 0);
|
||||||
|
|
||||||
|
switch ($poll->getMethod()) {
|
||||||
|
case PhabricatorSlowvotePoll::METHOD_PLURALITY:
|
||||||
|
$status = pht('%s (%d / %d)', $percent, $choices, $count);
|
||||||
|
break;
|
||||||
|
case PhabricatorSlowvotePoll::METHOD_APPROVAL:
|
||||||
|
$status = pht('%s Approval (%d / %d)', $percent, $choices, $count);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'slowvote-status',
|
||||||
|
),
|
||||||
|
$status);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function areResultsVisible() {
|
||||||
|
$poll = $this->getPoll();
|
||||||
|
|
||||||
|
$vis = $poll->getResponseVisibility();
|
||||||
|
if ($vis == PhabricatorSlowvotePoll::RESPONSES_VISIBLE) {
|
||||||
|
return true;
|
||||||
|
} else if ($vis == PhabricatorSlowvotePoll::RESPONSES_OWNER) {
|
||||||
|
return ($poll->getAuthorPHID() == $this->getUser()->getPHID());
|
||||||
|
} else {
|
||||||
|
$choices = mgroup($poll->getChoices(), 'getAuthorPHID');
|
||||||
|
return (bool)idx($choices, $this->getUser()->getPHID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,90 +2,124 @@
|
||||||
* @provides phabricator-slowvote-css
|
* @provides phabricator-slowvote-css
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.phabricator-slowvote-comments {
|
.slowvote-embed {
|
||||||
width: 100%;
|
margin: 24px 12px;
|
||||||
|
background: #ffffff;
|
||||||
|
border-color: #888888;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.20),
|
||||||
|
inset 0 0 2px rgba(0, 0, 0, 0.10);
|
||||||
}
|
}
|
||||||
|
|
||||||
.phabricator-slowvote-comments th {
|
.slowvote-header {
|
||||||
width: 150px;
|
font-weight: bold;
|
||||||
text-align: right;
|
line-height: 16px;
|
||||||
padding: 6px 4px 6px;
|
border-bottom: 1px solid #bbbbbb;
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.phabricator-slowvote-comments td {
|
.slowvote-description {
|
||||||
vertical-align: top;
|
|
||||||
padding: 6px 2px;
|
|
||||||
border-bottom: 1px solid #d0d0d0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phabricator-slowvote-datestamp {
|
|
||||||
font-size: 9px;
|
|
||||||
font-family: "Verdana";
|
|
||||||
color: #666666;
|
color: #666666;
|
||||||
margin-top: 1px;
|
padding: 8px;
|
||||||
|
border-bottom: 1px solid #bbbbbb;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phabricator-slowvote-hr {
|
.slowvote-header-content {
|
||||||
border: none;
|
padding: 8px;
|
||||||
height: 1px;
|
|
||||||
position: relative;
|
|
||||||
background: #c0c0c0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.phabricator-slowvote-count {
|
.slowvote-body {
|
||||||
float: right;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.phabricator-slowvote-label {
|
.slowvote-body-content {
|
||||||
|
padding: 4px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slowvote-option-label {
|
||||||
|
border: 1px solid #666666;
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #222222;
|
|
||||||
text-align: left;
|
|
||||||
margin: 0px 0px 6px;
|
|
||||||
padding: 6px 4px;
|
|
||||||
background: #cccccc;
|
|
||||||
border-bottom: 1px solid #aaaaaa;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aphront-form-input .phabricator-slowvote-label input {
|
|
||||||
display: inline;
|
|
||||||
width: auto;
|
|
||||||
margin-right: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phabricator-slowvote-facepile {
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
float: left;
|
padding: 8px 4px;
|
||||||
margin: 0px 4px 6px 0px;
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: {$lightblue};
|
||||||
}
|
}
|
||||||
|
|
||||||
.phabricator-slowvote-embed {
|
.slowvote-bar {
|
||||||
width: 400px;
|
position: absolute;
|
||||||
background: #f7f7f7;
|
top: 0;
|
||||||
border: 1px solid #dbdbdb;
|
left: 0;
|
||||||
padding: 5px;
|
bottom: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: {$blue};
|
||||||
}
|
}
|
||||||
|
|
||||||
.phabricator-slowvote-embed-option {
|
.slowvote-control-offset {
|
||||||
margin: 1px;
|
white-space: nowrap;
|
||||||
background: #F0FFFF;
|
position: absolute;
|
||||||
|
left: 32px;
|
||||||
|
top: 8px;
|
||||||
|
width: 100%;
|
||||||
|
color: #000000;
|
||||||
|
text-shadow: 0 1px 0 #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phabricator-slowvote-embed-option-vote {
|
.slowvote-bar .slowvote-control-offset {
|
||||||
|
color: #ffffff;
|
||||||
|
text-shadow: 0 1px 0 #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slowvote-option-label-group {
|
||||||
|
margin: 8px 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slowvote-option-label input[type="radio"],
|
||||||
|
.slowvote-option-label input[type="checkbox"] {
|
||||||
|
margin: 0 12px 0 8px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slowvote-above-the-bar {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slowvote-status {
|
||||||
|
text-align: right;
|
||||||
|
color: #333333;
|
||||||
|
font-weight: normal;
|
||||||
|
padding: 2px 0;
|
||||||
|
line-height: 15px;
|
||||||
|
text-align: right;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slowvote-voter {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 1em;
|
width: 25px;
|
||||||
|
height: 25px;
|
||||||
|
background: #f3f3f3;
|
||||||
|
background-size: 25px 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phabricator-slowvote-embed-option-text {
|
.slowvote-footer {
|
||||||
border: 1px solid #dbdbdb;
|
border-top-width: 1px;
|
||||||
border-left: 0px;
|
border-top-style: solid;
|
||||||
|
border-top-color: #bbbbbb;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slowvote-footer-content {
|
||||||
|
padding: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slowvote-footer-content .slowvote-hint {
|
||||||
|
line-height: 24px;
|
||||||
|
color: #888888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slowvote-footer-content button {
|
||||||
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,14 @@
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.slowvote-bar {
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slowvote-above-the-bar {
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
.phabricator-timeline-icon-fill {
|
.phabricator-timeline-icon-fill {
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue