1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-24 14:30:56 +01:00

AphrontBars

Summary: Aphront widgets that render the either a discrete or continuous value as a horizontal shape.  Like a progress bar, or a five-star rating bar.

Test Plan:
`/uiexample/view/PhabricatorAphrontBarExample/` ...which shows this, amongst other things:

{F33898}

Reviewers: epriestley, chad

Reviewed By: epriestley

CC: aran, Korvin

Maniphest Tasks: T2094

Differential Revision: https://secure.phabricator.com/D5122
This commit is contained in:
Edward Speyer 2013-03-05 16:46:09 +00:00
parent fd13275f7e
commit c2c8c34e84
7 changed files with 417 additions and 0 deletions

View file

@ -604,6 +604,15 @@ celerity_register_resource_map(array(
),
'disk' => '/rsrc/css/aphront/attached-file-view.css',
),
'aphront-bars' =>
array(
'uri' => '/res/d7bd9032/rsrc/css/core/aphront-bars.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/core/aphront-bars.css',
),
'aphront-calendar-view-css' =>
array(
'uri' => '/res/73061a31/rsrc/css/aphront/calendar-view.css',

View file

@ -17,6 +17,7 @@ phutil_register_library_map(array(
'AphrontAjaxResponse' => 'aphront/response/AphrontAjaxResponse.php',
'AphrontApplicationConfiguration' => 'aphront/configuration/AphrontApplicationConfiguration.php',
'AphrontAttachedFileView' => 'view/control/AphrontAttachedFileView.php',
'AphrontBarView' => 'view/widget/bars/AphrontBarView.php',
'AphrontCSRFException' => 'aphront/exception/AphrontCSRFException.php',
'AphrontCalendarEventView' => 'applications/calendar/view/AphrontCalendarEventView.php',
'AphrontCalendarMonthView' => 'applications/calendar/view/AphrontCalendarMonthView.php',
@ -53,6 +54,7 @@ phutil_register_library_map(array(
'AphrontFormToggleButtonsControl' => 'view/form/control/AphrontFormToggleButtonsControl.php',
'AphrontFormTokenizerControl' => 'view/form/control/AphrontFormTokenizerControl.php',
'AphrontFormView' => 'view/form/AphrontFormView.php',
'AphrontGlyphBarView' => 'view/widget/bars/AphrontGlyphBarView.php',
'AphrontHTMLResponse' => 'aphront/response/AphrontHTMLResponse.php',
'AphrontHTTPSink' => 'aphront/sink/AphrontHTTPSink.php',
'AphrontHTTPSinkTestCase' => 'aphront/sink/__tests__/AphrontHTTPSinkTestCase.php',
@ -71,6 +73,7 @@ phutil_register_library_map(array(
'AphrontPagerView' => 'view/control/AphrontPagerView.php',
'AphrontPanelView' => 'view/layout/AphrontPanelView.php',
'AphrontPlainTextResponse' => 'aphront/response/AphrontPlainTextResponse.php',
'AphrontProgressBarView' => 'view/widget/bars/AphrontProgressBarView.php',
'AphrontProxyResponse' => 'aphront/response/AphrontProxyResponse.php',
'AphrontRedirectException' => 'aphront/exception/AphrontRedirectException.php',
'AphrontRedirectResponse' => 'aphront/response/AphrontRedirectResponse.php',
@ -638,6 +641,7 @@ phutil_register_library_map(array(
'PhabricatorActionView' => 'view/layout/PhabricatorActionView.php',
'PhabricatorAllCapsTranslation' => 'infrastructure/internationalization/PhabricatorAllCapsTranslation.php',
'PhabricatorAnchorView' => 'view/layout/PhabricatorAnchorView.php',
'PhabricatorAphrontBarExample' => 'applications/uiexample/examples/PhabricatorAphrontBarExample.php',
'PhabricatorApplication' => 'applications/base/PhabricatorApplication.php',
'PhabricatorApplicationApplications' => 'applications/meta/application/PhabricatorApplicationApplications.php',
'PhabricatorApplicationAudit' => 'applications/audit/application/PhabricatorApplicationAudit.php',
@ -1570,6 +1574,7 @@ phutil_register_library_map(array(
'Aphront404Response' => 'AphrontHTMLResponse',
'AphrontAjaxResponse' => 'AphrontResponse',
'AphrontAttachedFileView' => 'AphrontView',
'AphrontBarView' => 'AphrontView',
'AphrontCSRFException' => 'AphrontException',
'AphrontCalendarEventView' => 'AphrontView',
'AphrontCalendarMonthView' => 'AphrontView',
@ -1606,6 +1611,7 @@ phutil_register_library_map(array(
'AphrontFormToggleButtonsControl' => 'AphrontFormControl',
'AphrontFormTokenizerControl' => 'AphrontFormControl',
'AphrontFormView' => 'AphrontView',
'AphrontGlyphBarView' => 'AphrontBarView',
'AphrontHTMLResponse' => 'AphrontResponse',
'AphrontHTTPSinkTestCase' => 'PhabricatorTestCase',
'AphrontIsolatedDatabaseConnectionTestCase' => 'PhabricatorTestCase',
@ -1623,6 +1629,7 @@ phutil_register_library_map(array(
'AphrontPagerView' => 'AphrontView',
'AphrontPanelView' => 'AphrontView',
'AphrontPlainTextResponse' => 'AphrontResponse',
'AphrontProgressBarView' => 'AphrontBarView',
'AphrontProxyResponse' => 'AphrontResponse',
'AphrontRedirectException' => 'AphrontException',
'AphrontRedirectResponse' => 'AphrontResponse',
@ -2134,6 +2141,7 @@ phutil_register_library_map(array(
'PhabricatorActionView' => 'AphrontView',
'PhabricatorAllCapsTranslation' => 'PhabricatorTranslation',
'PhabricatorAnchorView' => 'AphrontView',
'PhabricatorAphrontBarExample' => 'PhabricatorUIExample',
'PhabricatorApplicationApplications' => 'PhabricatorApplication',
'PhabricatorApplicationAudit' => 'PhabricatorApplication',
'PhabricatorApplicationAuth' => 'PhabricatorApplication',

View file

@ -0,0 +1,75 @@
<?php
final class PhabricatorAphrontBarExample extends PhabricatorUIExample {
public function getName() {
return "Bars";
}
public function getDescription() {
return 'Like fractions, but more horizontal.';
}
public function renderExample() {
$out = '';
$out .= $this->renderTestThings('AphrontProgressBarView', 13, 10);
$out .= $this->renderTestThings('AphrontGlyphBarView', 13, 10);
$out .= $this->renderWeirdOrderGlyphBars();
$out .= $this->renderAsciiStarBar();
return phutil_safe_html($out);
}
private function wrap($title, $thing) {
return id(new AphrontPanelView())
->setHeader($title)
->appendChild($thing)
->render();
}
private function renderTestThings($class, $max, $incr) {
$bars = array();
for ($ii = 0; $ii <= $max; $ii++) {
$bars[] = newv($class, array())
->setValue($ii * $incr)
->setMax($max * $incr)
->setCaption("{$ii} outta {$max} ain't bad!");
}
return $this->wrap(
"Test {$class}",
phutil_implode_html('', mpull($bars, 'render')));
}
private function renderWeirdOrderGlyphBars() {
$views = array();
$indices = array(1, 3, 7, 4, 2, 8, 9, 5, 10, 6);
$max = count($indices);
foreach ($indices as $index) {
$views[] = id(new AphrontGlyphBarView())
->setValue($index)
->setMax($max)
->setNumGlyphs(5)
->setCaption("Lol score is {$index}/{$max}")
->setGlyph(hsprintf('%s', 'LOL!'))
->setBackgroundGlyph(hsprintf('%s', '____'))
->render();
$views[] = hsprintf('<div style="clear:both;"></div>');
}
return $this->wrap(
"Glyph bars in weird order",
phutil_implode_html('', $views));
}
private function renderAsciiStarBar() {
return $this->wrap(
"Ascii star glyph bar",
id(new AphrontGlyphBarView())
->setValue(50)
->setMax(100)
->setCaption('Glyphs!')
->setNumGlyphs(10)
->setGlyph(hsprintf('%s', '*'))
->render());
}
}

View file

@ -0,0 +1,63 @@
<?php
abstract class AphrontBarView extends AphrontView {
private $color;
private $caption = '';
const COLOR_DEFAULT = 'default';
const COLOR_WARNING = 'warning';
const COLOR_DANGER = 'danger';
const COLOR_AUTO_BADNESS = 'auto_badness'; // more = bad! :(
const COLOR_AUTO_GOODNESS = 'auto_goodness'; // more = good! :)
const THRESHOLD_DANGER = 0.85;
const THRESHOLD_WARNING = 0.75;
abstract protected function getRatio();
abstract protected function getDefaultColor();
final public function setColor($color) {
$this->color = $color;
return $this;
}
final public function setCaption($text) {
$this->caption = $text;
return $this;
}
final protected function getColor() {
$color = $this->color;
if (!$color) {
$color = $this->getDefaultColor();
}
switch ($color) {
case self::COLOR_DEFAULT:
case self::COLOR_WARNING:
case self::COLOR_DANGER:
return $color;
}
$ratio = $this->getRatio();
if ($color === self::COLOR_AUTO_GOODNESS) {
$ratio = 1.0 - $ratio;
}
if ($ratio >= self::THRESHOLD_DANGER) {
return self::COLOR_DANGER;
} else if ($ratio >= self::THRESHOLD_WARNING) {
return self::COLOR_WARNING;
} else {
return self::COLOR_DEFAULT;
}
}
final protected function getCaption() {
return $this->caption;
}
}

View file

@ -0,0 +1,102 @@
<?php
final class AphrontGlyphBarView extends AphrontBarView {
const BLACK_STAR = "\xE2\x98\x85";
const WHITE_STAR = "\xE2\x98\x86";
private $value;
private $max = 100;
private $numGlyphs = 5;
private $fgGlyph;
private $bgGlyph;
public function getDefaultColor() {
return AphrontBarView::COLOR_AUTO_GOODNESS;
}
public function setValue($value) {
$this->value = $value;
return $this;
}
public function setMax($max) {
$this->max = $max;
return $this;
}
public function setNumGlyphs($nn) {
$this->numGlyphs = $nn;
return $this;
}
public function setGlyph(PhutilSafeHTML $fg_glyph) {
$this->fgGlyph = $fg_glyph;
return $this;
}
public function setBackgroundGlyph(PhutilSafeHTML $bg_glyph) {
$this->bgGlyph = $bg_glyph;
return $this;
}
protected function getRatio() {
return min($this->value, $this->max) / $this->max;
}
public function render() {
require_celerity_resource('aphront-bars');
$ratio = $this->getRatio();
$percentage = 100 * $ratio;
$is_star = false;
if ($this->fgGlyph) {
$fg_glyph = $this->fgGlyph;
if ($this->bgGlyph) {
$bg_glyph = $this->bgGlyph;
} else {
$bg_glyph = $fg_glyph;
}
} else {
$is_star = true;
$fg_glyph = self::BLACK_STAR;
$bg_glyph = self::WHITE_STAR;
}
$fg_glyphs = array_fill(0, $this->numGlyphs, $fg_glyph);
$bg_glyphs = array_fill(0, $this->numGlyphs, $bg_glyph);
$color = $this->getColor();
return phutil_tag(
'div',
array(
'class' => "aphront-bar glyph color-{$color}",
),
array(
phutil_tag(
'div',
array(
'class' => 'glyphs'.($is_star ? ' starstar' : ''),
),
array(
phutil_tag(
'div',
array(
'class' => 'fg',
'style' => "width: {$percentage}%;",
),
$fg_glyphs),
phutil_tag(
'div',
array(),
$bg_glyphs)
)),
phutil_tag(
'div',
array('class' => 'caption'),
$this->getCaption())
));
}
}

View file

@ -0,0 +1,60 @@
<?php
final class AphrontProgressBarView extends AphrontBarView {
const WIDTH = 100;
private $value;
private $max = 100;
private $alt = '';
public function getDefaultColor() {
return AphrontBarView::COLOR_AUTO_BADNESS;
}
public function setValue($value) {
$this->value = $value;
return $this;
}
public function setMax($max) {
$this->max = $max;
return $this;
}
public function setAlt($text) {
$this->alt = $text;
return $this;
}
protected function getRatio() {
return min($this->value, $this->max) / $this->max;
}
public function render() {
require_celerity_resource('aphront-bars');
$ratio = $this->getRatio();
$width = self::WIDTH * $ratio;
$color = $this->getColor();
return phutil_tag(
'div',
array(
'class' => "aphront-bar progress color-{$color}",
),
array(
phutil_tag(
'div',
array('title' => $this->alt),
phutil_tag(
'div',
array('style' => hsprintf("width: %dpx;", $width)),
'')),
phutil_tag(
'span',
array(),
$this->getCaption())));
}
}

View file

@ -0,0 +1,100 @@
/**
* @provides aphront-bars
*/
/**
* Progress bars
*/
div.aphront-bar.progress {
border: 0px;
}
div.aphront-bar.progress div {
width: 100px;
border: 1px solid;
border-top-color: #A4A4A4;
border-right-color: #BBB;
border-bottom-color: #D5D5D5;
border-left-color: #BBB;
background: white;
float: left;
margin-right: 1em;
}
div.aphront-bar.progress div div {
height: 10px;
}
div.aphront-bar.progress span {
color: #555;
}
/**
* Glyph bars
*/
div.aphront-bar.glyph {
clear: both;
}
div.aphront-bar.glyph div.glyphs {
padding: 0;
margin: 0;
float: left;
position: relative;
color: #aaa;
font-family: monospace;
height: 1.3em;
}
div.aphront-bar.glyph div.glyphs.starstar {
/* http://daringfireball.net/2005/08/star_star */
font-family: "Hiragino Kaku Gothic Pro", "Osaka", "Zapf Dingbats";
}
div.aphront-bar.glyph div.glyphs div.fg {
padding: 0;
margin: 0;
float: left;
position: absolute;
overflow: hidden;
}
div.aphront-bar.glyph div.caption {
padding: 0;
margin: 0;
float: left;
margin-left: 1.5em;
color: #666;
}
/**
* Common color classes
*/
div.aphront-bar.progress.color-default div div {
background: #6D84B4;
}
div.aphront-bar.glyph.color-default div.glyphs div.fg {
color: #6D84B4;
}
div.aphront-bar.progress.color-warning div div {
background: #FFCC5F;
}
div.aphront-bar.glyph.color-warning div.glyphs div.fg {
color: #FFCC5F;
}
div.aphront-bar.progress.color-danger div div {
background: #FF6E6E;
}
div.aphront-bar.glyph.color-danger div.glyphs div.fg {
color: #FF6E6E;
}