mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-28 16:30:59 +01:00
AphrontFormCountedToggleButtonsControl
Summary: Like AphrontFormToggleButtonsControl, but with mouseover counters. These counters let you know how many of each thing there are in each category, which is useful when using this control for filtering a list of things in multiple dimensions. Test Plan: `/uiexample/view/PhabricatorCountedToggleButtonsExample/` Reviewers: epriestley CC: aran, Korvin Maniphest Tasks: T2094 Differential Revision: https://secure.phabricator.com/D5118
This commit is contained in:
parent
6ab2db6d4d
commit
a1b98c5cb7
5 changed files with 311 additions and 40 deletions
|
@ -683,7 +683,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'aphront-form-view-css' =>
|
||||
array(
|
||||
'uri' => '/res/c1cf5cce/rsrc/css/aphront/form-view.css',
|
||||
'uri' => '/res/efaecc2d/rsrc/css/aphront/form-view.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -3562,7 +3562,7 @@ celerity_register_resource_map(array(
|
|||
), array(
|
||||
'packages' =>
|
||||
array(
|
||||
'0f595159' =>
|
||||
'b481b309' =>
|
||||
array(
|
||||
'name' => 'core.pkg.css',
|
||||
'symbols' =>
|
||||
|
@ -3605,7 +3605,7 @@ celerity_register_resource_map(array(
|
|||
35 => 'phabricator-object-item-list-view-css',
|
||||
36 => 'global-drag-and-drop-css',
|
||||
),
|
||||
'uri' => '/res/pkg/0f595159/core.pkg.css',
|
||||
'uri' => '/res/pkg/b481b309/core.pkg.css',
|
||||
'type' => 'css',
|
||||
),
|
||||
'95ceba95' =>
|
||||
|
@ -3796,17 +3796,17 @@ celerity_register_resource_map(array(
|
|||
'reverse' =>
|
||||
array(
|
||||
'aphront-attached-file-view-css' => 'eb35a026',
|
||||
'aphront-crumbs-view-css' => '0f595159',
|
||||
'aphront-dialog-view-css' => '0f595159',
|
||||
'aphront-error-view-css' => '0f595159',
|
||||
'aphront-form-view-css' => '0f595159',
|
||||
'aphront-list-filter-view-css' => '0f595159',
|
||||
'aphront-pager-view-css' => '0f595159',
|
||||
'aphront-panel-view-css' => '0f595159',
|
||||
'aphront-table-view-css' => '0f595159',
|
||||
'aphront-tokenizer-control-css' => '0f595159',
|
||||
'aphront-tooltip-css' => '0f595159',
|
||||
'aphront-typeahead-control-css' => '0f595159',
|
||||
'aphront-crumbs-view-css' => 'b481b309',
|
||||
'aphront-dialog-view-css' => 'b481b309',
|
||||
'aphront-error-view-css' => 'b481b309',
|
||||
'aphront-form-view-css' => 'b481b309',
|
||||
'aphront-list-filter-view-css' => 'b481b309',
|
||||
'aphront-pager-view-css' => 'b481b309',
|
||||
'aphront-panel-view-css' => 'b481b309',
|
||||
'aphront-table-view-css' => 'b481b309',
|
||||
'aphront-tokenizer-control-css' => 'b481b309',
|
||||
'aphront-tooltip-css' => 'b481b309',
|
||||
'aphront-typeahead-control-css' => 'b481b309',
|
||||
'differential-changeset-view-css' => '8aaacd1b',
|
||||
'differential-core-view-css' => '8aaacd1b',
|
||||
'differential-inline-comment-editor' => '322728f3',
|
||||
|
@ -3820,7 +3820,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' => '0f595159',
|
||||
'global-drag-and-drop-css' => 'b481b309',
|
||||
'inline-comment-summary-css' => '8aaacd1b',
|
||||
'javelin-aphlict' => '95ceba95',
|
||||
'javelin-behavior' => 'cd1d650a',
|
||||
|
@ -3892,48 +3892,48 @@ celerity_register_resource_map(array(
|
|||
'javelin-util' => 'cd1d650a',
|
||||
'javelin-vector' => 'cd1d650a',
|
||||
'javelin-workflow' => 'cd1d650a',
|
||||
'lightbox-attachment-css' => '0f595159',
|
||||
'lightbox-attachment-css' => 'b481b309',
|
||||
'maniphest-task-summary-css' => 'eb35a026',
|
||||
'maniphest-transaction-detail-css' => 'eb35a026',
|
||||
'phabricator-busy' => '95ceba95',
|
||||
'phabricator-content-source-view-css' => '8aaacd1b',
|
||||
'phabricator-core-buttons-css' => '0f595159',
|
||||
'phabricator-core-css' => '0f595159',
|
||||
'phabricator-crumbs-view-css' => '0f595159',
|
||||
'phabricator-directory-css' => '0f595159',
|
||||
'phabricator-core-buttons-css' => 'b481b309',
|
||||
'phabricator-core-css' => 'b481b309',
|
||||
'phabricator-crumbs-view-css' => 'b481b309',
|
||||
'phabricator-directory-css' => 'b481b309',
|
||||
'phabricator-drag-and-drop-file-upload' => '322728f3',
|
||||
'phabricator-dropdown-menu' => '95ceba95',
|
||||
'phabricator-file-upload' => '95ceba95',
|
||||
'phabricator-filetree-view-css' => '0f595159',
|
||||
'phabricator-flag-css' => '0f595159',
|
||||
'phabricator-form-view-css' => '0f595159',
|
||||
'phabricator-header-view-css' => '0f595159',
|
||||
'phabricator-jump-nav' => '0f595159',
|
||||
'phabricator-filetree-view-css' => 'b481b309',
|
||||
'phabricator-flag-css' => 'b481b309',
|
||||
'phabricator-form-view-css' => 'b481b309',
|
||||
'phabricator-header-view-css' => 'b481b309',
|
||||
'phabricator-jump-nav' => 'b481b309',
|
||||
'phabricator-keyboard-shortcut' => '95ceba95',
|
||||
'phabricator-keyboard-shortcut-manager' => '95ceba95',
|
||||
'phabricator-main-menu-view' => '0f595159',
|
||||
'phabricator-main-menu-view' => 'b481b309',
|
||||
'phabricator-menu-item' => '95ceba95',
|
||||
'phabricator-nav-view-css' => '0f595159',
|
||||
'phabricator-nav-view-css' => 'b481b309',
|
||||
'phabricator-notification' => '95ceba95',
|
||||
'phabricator-notification-css' => '0f595159',
|
||||
'phabricator-notification-menu-css' => '0f595159',
|
||||
'phabricator-object-item-list-view-css' => '0f595159',
|
||||
'phabricator-notification-css' => 'b481b309',
|
||||
'phabricator-notification-menu-css' => 'b481b309',
|
||||
'phabricator-object-item-list-view-css' => 'b481b309',
|
||||
'phabricator-object-selector-css' => '8aaacd1b',
|
||||
'phabricator-paste-file-upload' => '95ceba95',
|
||||
'phabricator-prefab' => '95ceba95',
|
||||
'phabricator-project-tag-css' => 'eb35a026',
|
||||
'phabricator-remarkup-css' => '0f595159',
|
||||
'phabricator-remarkup-css' => 'b481b309',
|
||||
'phabricator-shaped-request' => '322728f3',
|
||||
'phabricator-side-menu-view-css' => '0f595159',
|
||||
'phabricator-standard-page-view' => '0f595159',
|
||||
'phabricator-side-menu-view-css' => 'b481b309',
|
||||
'phabricator-standard-page-view' => 'b481b309',
|
||||
'phabricator-textareautils' => '95ceba95',
|
||||
'phabricator-tooltip' => '95ceba95',
|
||||
'phabricator-transaction-view-css' => '0f595159',
|
||||
'phabricator-zindex-css' => '0f595159',
|
||||
'sprite-apps-large-css' => '0f595159',
|
||||
'sprite-gradient-css' => '0f595159',
|
||||
'sprite-icon-css' => '0f595159',
|
||||
'sprite-menu-css' => '0f595159',
|
||||
'syntax-highlighting-css' => '0f595159',
|
||||
'phabricator-transaction-view-css' => 'b481b309',
|
||||
'phabricator-zindex-css' => 'b481b309',
|
||||
'sprite-apps-large-css' => 'b481b309',
|
||||
'sprite-gradient-css' => 'b481b309',
|
||||
'sprite-icon-css' => 'b481b309',
|
||||
'sprite-menu-css' => 'b481b309',
|
||||
'syntax-highlighting-css' => 'b481b309',
|
||||
),
|
||||
));
|
||||
|
|
|
@ -33,6 +33,7 @@ phutil_register_library_map(array(
|
|||
'AphrontFileResponse' => 'aphront/response/AphrontFileResponse.php',
|
||||
'AphrontFormCheckboxControl' => 'view/form/control/AphrontFormCheckboxControl.php',
|
||||
'AphrontFormControl' => 'view/form/control/AphrontFormControl.php',
|
||||
'AphrontFormCountedToggleButtonsControl' => 'view/form/control/AphrontFormCountedToggleButtonsControl.php',
|
||||
'AphrontFormCropControl' => 'view/form/control/AphrontFormCropControl.php',
|
||||
'AphrontFormDateControl' => 'view/form/control/AphrontFormDateControl.php',
|
||||
'AphrontFormDividerControl' => 'view/form/control/AphrontFormDividerControl.php',
|
||||
|
@ -824,6 +825,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCountdownListController' => 'applications/countdown/controller/PhabricatorCountdownListController.php',
|
||||
'PhabricatorCountdownRemarkupRule' => 'applications/countdown/remarkup/PhabricatorCountdownRemarkupRule.php',
|
||||
'PhabricatorCountdownViewController' => 'applications/countdown/controller/PhabricatorCountdownViewController.php',
|
||||
'PhabricatorCountedToggleButtonsExample' => 'applications/uiexample/examples/PhabricatorCountedToggleButtonsExample.php',
|
||||
'PhabricatorCrumbView' => 'view/layout/PhabricatorCrumbView.php',
|
||||
'PhabricatorCrumbsView' => 'view/layout/PhabricatorCrumbsView.php',
|
||||
'PhabricatorCursorPagedPolicyAwareQuery' => 'infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php',
|
||||
|
@ -1604,6 +1606,7 @@ phutil_register_library_map(array(
|
|||
'AphrontFileResponse' => 'AphrontResponse',
|
||||
'AphrontFormCheckboxControl' => 'AphrontFormControl',
|
||||
'AphrontFormControl' => 'AphrontView',
|
||||
'AphrontFormCountedToggleButtonsControl' => 'AphrontFormControl',
|
||||
'AphrontFormCropControl' => 'AphrontFormControl',
|
||||
'AphrontFormDateControl' => 'AphrontFormControl',
|
||||
'AphrontFormDividerControl' => 'AphrontFormControl',
|
||||
|
@ -2356,6 +2359,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCountdownListController' => 'PhabricatorCountdownController',
|
||||
'PhabricatorCountdownRemarkupRule' => 'PhutilRemarkupRule',
|
||||
'PhabricatorCountdownViewController' => 'PhabricatorCountdownController',
|
||||
'PhabricatorCountedToggleButtonsExample' => 'PhabricatorUIExample',
|
||||
'PhabricatorCrumbView' => 'AphrontView',
|
||||
'PhabricatorCrumbsView' => 'AphrontView',
|
||||
'PhabricatorCursorPagedPolicyAwareQuery' => 'PhabricatorPolicyAwareQuery',
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorCountedToggleButtonsExample
|
||||
extends PhabricatorUIExample {
|
||||
|
||||
public function getName() {
|
||||
return 'Counted Toggle Buttons';
|
||||
}
|
||||
|
||||
public function getDescription() {
|
||||
return 'Like AphrontFormToggleButtonsControl, but with counters.';
|
||||
}
|
||||
|
||||
private static function buildTreesList() {
|
||||
$all_trees = array(
|
||||
array(
|
||||
'name' => 'Oak',
|
||||
'leaves' => 'deciduous',
|
||||
'wood' => 'hard',
|
||||
'branches' => 'climbable',
|
||||
),
|
||||
array(
|
||||
'name' => 'Pine',
|
||||
'leaves' => 'coniferous',
|
||||
'wood' => 'soft',
|
||||
'branches' => 'spindly',
|
||||
),
|
||||
array(
|
||||
'name' => 'Spruce',
|
||||
'leaves' => 'coniferous',
|
||||
'wood' => 'soft',
|
||||
'branches' => 'sticky',
|
||||
),
|
||||
array(
|
||||
'name' => 'Ash',
|
||||
'leaves' => 'deciduous',
|
||||
'wood' => 'hard',
|
||||
'branches' => 'climbable',
|
||||
),
|
||||
array(
|
||||
'name' => 'Holly',
|
||||
'leaves' => 'waxy',
|
||||
'wood' => 'hard',
|
||||
'branches' => 'prickly',
|
||||
),
|
||||
);
|
||||
|
||||
for ($ii = 0; $ii < 345; $ii++) {
|
||||
$name = sprintf("Soylent UltraTree \xE2\x84\xA2 Mutation 0xPD%03x", $ii);
|
||||
$all_trees[] = array(
|
||||
'name' => $name,
|
||||
'leaves' => 'carcinogenic',
|
||||
'wood' => 'metallic',
|
||||
'branches' => 'sentient',
|
||||
);
|
||||
}
|
||||
|
||||
return $all_trees;
|
||||
}
|
||||
|
||||
public function renderExample() {
|
||||
$request = $this->getRequest();
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($request->getUser());
|
||||
|
||||
$attributes = array('leaves', 'wood', 'branches');
|
||||
|
||||
$all_trees = self::buildTreesList();
|
||||
$trees = $all_trees;
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
$form_value = $request->getStr($attribute);
|
||||
|
||||
$buttons = array(null => 'all');
|
||||
foreach ($all_trees as $dict) {
|
||||
$value = $dict[$attribute];
|
||||
$buttons[$value] = $value;
|
||||
}
|
||||
|
||||
// The trees filtered by other attributes, before we filter by this
|
||||
// attribute
|
||||
$trees_before = $all_trees;
|
||||
foreach ($attributes as $other_attribute) {
|
||||
if ($other_attribute != $attribute) {
|
||||
$trees_before = $this->filterTrees($trees_before, $other_attribute);
|
||||
}
|
||||
}
|
||||
|
||||
$counters = array(null => count($trees_before));
|
||||
foreach ($trees_before as $dict) {
|
||||
$value = $dict[$attribute];
|
||||
if (!isset($counters[$value])) {
|
||||
$counters[$value] = 0;
|
||||
}
|
||||
$counters[$value]++;
|
||||
}
|
||||
|
||||
$trees = $this->filterTrees($trees, $attribute);
|
||||
|
||||
$control = id(new AphrontFormCountedToggleButtonsControl())
|
||||
->setLabel(ucfirst($attribute))
|
||||
->setName($attribute)
|
||||
->setValue($form_value)
|
||||
->setBaseURI($request->getRequestURI(), $attribute)
|
||||
->setButtons($buttons)
|
||||
->setCounters($counters);
|
||||
|
||||
$form->appendChild($control);
|
||||
}
|
||||
|
||||
$rows = array();
|
||||
foreach ($trees as $dict) {
|
||||
$row = array_select_keys($dict, $attributes);
|
||||
array_unshift($row, $dict['name']);
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
$headers = $attributes;
|
||||
array_unshift($headers, 'name');
|
||||
$table = id(new AphrontTableView($rows))
|
||||
->setHeaders($headers);
|
||||
|
||||
$panel = id(new AphrontPanelView())
|
||||
->setHeader('Counters!')
|
||||
->setWidth(AphrontPanelView::WIDTH_FULL)
|
||||
->appendChild($form)
|
||||
->appendChild($table);
|
||||
|
||||
return $panel;
|
||||
}
|
||||
|
||||
private function filterTrees($trees, $attribute) {
|
||||
$form_value = $this->getRequest()->getStr($attribute);
|
||||
if (!$form_value) {
|
||||
return $trees;
|
||||
}
|
||||
|
||||
$new = array();
|
||||
foreach ($trees as $dict) {
|
||||
if ($dict[$attribute] == $form_value) {
|
||||
$new[] = $dict;
|
||||
}
|
||||
}
|
||||
return $new;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
final class AphrontFormCountedToggleButtonsControl extends AphrontFormControl {
|
||||
|
||||
private $baseURI;
|
||||
private $param;
|
||||
|
||||
private $buttons;
|
||||
private $counters = array();
|
||||
|
||||
public function setBaseURI(PhutilURI $uri, $param) {
|
||||
$this->baseURI = $uri;
|
||||
$this->param = $param;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setButtons(array $buttons) {
|
||||
$this->buttons = $buttons;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCounters(array $counters) {
|
||||
$this->counters = $counters;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getCustomControlClass() {
|
||||
return 'aphront-form-control-counted-togglebuttons';
|
||||
}
|
||||
|
||||
protected function renderInput() {
|
||||
if (!$this->baseURI) {
|
||||
throw new Exception('Call setBaseURI() before render()!');
|
||||
}
|
||||
|
||||
$selected = $this->getValue();
|
||||
|
||||
$out = array();
|
||||
foreach ($this->buttons as $value => $label) {
|
||||
if ($value == $selected) {
|
||||
$more = ' toggle-selected toggle-fixed';
|
||||
} else {
|
||||
$more = null;
|
||||
}
|
||||
|
||||
$counter = idx($this->counters, $value);
|
||||
|
||||
if ($counter > 0) {
|
||||
$href = $this->baseURI->alter($this->param, $value);
|
||||
$counter_markup = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'counter',
|
||||
),
|
||||
$counter);
|
||||
} else {
|
||||
$href = null;
|
||||
$counter_markup = '';
|
||||
$more .= ' disabled';
|
||||
}
|
||||
|
||||
$attributes = array(
|
||||
'class' => 'toggle'.$more,
|
||||
);
|
||||
if ($href) {
|
||||
$attributes['href'] = $href;
|
||||
}
|
||||
|
||||
$out[] = phutil_tag(
|
||||
'a',
|
||||
$attributes,
|
||||
array(
|
||||
$counter_markup,
|
||||
$label));
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
}
|
|
@ -368,3 +368,42 @@ table.aphront-form-control-checkbox-layout th {
|
|||
padding: 12px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.aphront-form-control-counted-togglebuttons {
|
||||
padding-top: 7px;
|
||||
}
|
||||
|
||||
.aphront-form-control-counted-togglebuttons .toggle {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.aphront-form-control-counted-togglebuttons .toggle-fixed {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.aphront-form-control-counted-togglebuttons .toggle .counter {
|
||||
font-size: smaller;
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: -9px;
|
||||
right: -8px;
|
||||
padding: 0px 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.aphront-form-control-counted-togglebuttons:hover .toggle .counter {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.aphront-form-control-counted-togglebuttons .toggle .counter {
|
||||
background: gray;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.aphront-form-control-counted-togglebuttons .toggle-selected .counter {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.aphront-form-control-counted-togglebuttons .toggle.disabled:hover {
|
||||
background-color: #a7a7a7;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue