1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-09-20 01:08:50 +02:00

Add support for aural-only and visual-only elements

Summary:
Ref T4843. This adds support to `javelin_tag()` for an `aural` attribute. When specified, `true` values mean "this content is aural-only", while `false` values mean "this content is not aural".

  - I've attempted to find the best modern approaches for marking this content, but the `aural` attribute should let us change the mechanism later.
  - Make the "beta" markers on application navigation visual only (see T4843). This information is of very low importance, the application navigation is accessed frequently, and the information is available on the application list.
  - Partially convert the main navigation. This is mostly to test things, since I want to get more concrete feedback about approaches here.
  - Add a `?__aural__=1` attribute, which renders the page with aural-only elements visible and visual-only elements colored.

Test Plan: {F146476}

Reviewers: btrahan, scp, chad

Reviewed By: chad

Subscribers: aklapper, qgil, epriestley

Maniphest Tasks: T4843

Differential Revision: https://secure.phabricator.com/D8830
This commit is contained in:
epriestley 2014-05-01 07:18:18 -07:00
parent 3fde020049
commit e8cebb7da5
15 changed files with 171 additions and 20 deletions

View file

@ -7,7 +7,7 @@
return array(
'names' =>
array(
'core.pkg.css' => 'b7ba02ba',
'core.pkg.css' => 'cc50ddf5',
'core.pkg.js' => '417722ff',
'darkconsole.pkg.js' => 'ca8671ce',
'differential.pkg.css' => '8a064eb7',
@ -105,10 +105,10 @@ return array(
'rsrc/css/application/subscriptions/subscribers-list.css' => '5bb30c78',
'rsrc/css/application/tokens/tokens.css' => '5f7bca25',
'rsrc/css/application/uiexample/example.css' => '528b19de',
'rsrc/css/core/core.css' => 'da26ddb2',
'rsrc/css/core/core.css' => '7dff07c3',
'rsrc/css/core/remarkup.css' => '98a7627b',
'rsrc/css/core/syntax.css' => '3c18c1cb',
'rsrc/css/core/z-index.css' => '0d89d53c',
'rsrc/css/core/z-index.css' => '7e4989ed',
'rsrc/css/diviner/diviner-shared.css' => '38813222',
'rsrc/css/font/font-awesome.css' => '62bc244d',
'rsrc/css/font/font-glyphicons-halflings.css' => 'c4c1c6b6',
@ -686,7 +686,7 @@ return array(
'phabricator-busy' => '6453c869',
'phabricator-chatlog-css' => '852140ff',
'phabricator-content-source-view-css' => '4b8b05d4',
'phabricator-core-css' => 'da26ddb2',
'phabricator-core-css' => '7dff07c3',
'phabricator-countdown-css' => '86b7b0a0',
'phabricator-crumbs-view-css' => '0222cbe0',
'phabricator-drag-and-drop-file-upload' => 'ae6abfba',
@ -735,7 +735,7 @@ return array(
'phabricator-uiexample-reactor-select' => '189e4fe3',
'phabricator-uiexample-reactor-sendclass' => 'bf97561d',
'phabricator-uiexample-reactor-sendproperties' => '551add57',
'phabricator-zindex-css' => '0d89d53c',
'phabricator-zindex-css' => '7e4989ed',
'phame-css' => '19ecc703',
'pholio-css' => '2fa97dbe',
'pholio-edit-css' => 'b9e59b6d',

View file

@ -40,6 +40,7 @@ final class PhabricatorApplicationAuth extends PhabricatorApplication {
->setWorkflow(true)
->setHref('/logout/')
->setSelected(($controller instanceof PhabricatorLogoutController))
->setAural(pht('Log Out'))
->setOrder(900);
$items[] = $item;
} else {
@ -53,6 +54,7 @@ final class PhabricatorApplicationAuth extends PhabricatorApplication {
// TODO: Login icon?
->setIcon('power')
->setHref('/auth/start/')
->setAural(pht('Log In'))
->setOrder(900);
$items[] = $item;
}

View file

@ -31,10 +31,13 @@ final class PhabricatorApplicationHelp extends PhabricatorApplication {
}
if ($application && $application->getHelpURI()) {
$help_name = pht('%s Help', $application->getName());
$item = id(new PHUIListItemView())
->setName(pht('%s Help', $application->getName()))
->setName($help_name)
->addClass('core-menu-item')
->setIcon('info-sm')
->setAural($help_name)
->setOrder(200)
->setHref($application->getHelpURI());
$items[] = $item;

View file

@ -60,6 +60,7 @@ final class PhabricatorApplicationHome extends PhabricatorApplication {
->setHref('/home/create/')
->addSigil('quick-create-menu')
->setID($create_id)
->setAural(pht('Quick Create'))
->setOrder(300);
$items[] = $item;
}

View file

@ -167,7 +167,7 @@ abstract class PhabricatorHomeController extends PhabricatorController {
}
}
$nav->addFilter(
$nav->addFilter(
'',
pht('Customize Applications...'),
'/settings/panel/home/');

View file

@ -39,9 +39,10 @@ final class PhabricatorApplicationLaunchView extends AphrontView {
$application->getName());
if ($application->isBeta()) {
$content[] = phutil_tag(
$content[] = javelin_tag(
'span',
array(
'aural' => false,
'class' => 'phabricator-application-beta',
),
"\xCE\xB2");

View file

@ -120,6 +120,7 @@ final class PhabricatorApplicationPeople extends PhabricatorApplication {
->setName($user->getUsername())
->setHref('/p/'.$user->getUsername().'/')
->addClass('core-menu-item')
->setAural(pht('Profile'))
->setOrder(100);
$classes = array(

View file

@ -46,6 +46,7 @@ final class PhabricatorApplicationSettings extends PhabricatorApplication {
->addClass('core-menu-item')
->setSelected($selected)
->setHref('/settings/')
->setAural(pht('Settings'))
->setOrder(400);
$items[] = $item;
}

View file

@ -36,6 +36,20 @@ function javelin_tag(
}
}
if (isset($attributes['aural'])) {
if ($attributes['aural']) {
$class = idx($attributes, 'class', '');
$class = rtrim('aural-only '.$class);
$attributes['class'] = $class;
} else {
$class = idx($attributes, 'class', '');
$class = rtrim('visual-only '.$class);
$attributes['class'] = $class;
$attributes['aria-hidden'] = 'true';
}
unset($attributes['aural']);
}
return phutil_tag($tag, $attributes, $content);
}

View file

@ -133,13 +133,22 @@ final class PhabricatorRemarkupControl extends AphrontFormTextAreaControl {
$target = '_blank';
}
$content = null;
$tip = idx($spec, 'tip');
if ($tip) {
$meta['tip'] = $tip;
$content = phutil_tag(
'span',
array(
'class' => 'aural-only',
),
$tip);
}
require_celerity_resource('sprite-icons-css');
$buttons[] = javelin_tag(
'a',
array(
@ -156,7 +165,7 @@ final class PhabricatorRemarkupControl extends AphrontFormTextAreaControl {
array(
'class' => 'remarkup-assist sprite-icons remarkup-assist-'.$action,
),
''));
$content));
}
$buttons = phutil_tag(

View file

@ -430,6 +430,10 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView {
$classes[] = 'printable';
}
if ($this->getRequest()->getStr('__aural__')) {
$classes[] = 'audible';
}
return implode(' ', $classes);
}

View file

@ -34,9 +34,10 @@ final class PhabricatorMainMenuView extends AphrontView {
$alerts = array();
$search_button = '';
$app_button = '';
$aural = null;
if ($user->isLoggedIn() && $user->isUserActivated()) {
list($menu, $dropdowns) = $this->renderNotificationMenu();
list($menu, $dropdowns, $aural) = $this->renderNotificationMenu();
$alerts[] = $menu;
$menus = array_merge($menus, $dropdowns);
$app_button = $this->renderApplicationMenuButton($header_id);
@ -51,14 +52,24 @@ final class PhabricatorMainMenuView extends AphrontView {
$search_menu = $this->renderPhabricatorSearchMenu();
if ($alerts) {
$alerts = phutil_tag(
$alerts = javelin_tag(
'div',
array(
'class' => 'phabricator-main-menu-alerts',
'aural' => false,
),
$alerts);
}
if ($aural) {
$aural = javelin_tag(
'span',
array(
'aural' => true,
),
phutil_implode_html(' ', $aural));
}
$application_menu = $this->renderApplicationMenu();
$classes = array();
$classes[] = 'phabricator-main-menu';
@ -76,6 +87,7 @@ final class PhabricatorMainMenuView extends AphrontView {
$search_button,
$this->renderPhabricatorLogo(),
$alerts,
$aural,
$application_menu,
$search_menu,
$menus,
@ -236,12 +248,20 @@ final class PhabricatorMainMenuView extends AphrontView {
'class' => 'phabricator-main-menu-logo',
'href' => '/',
),
phutil_tag(
'span',
array(
'class' => 'sprite-menu menu-logo-image '.$class,
),
''));
array(
javelin_tag(
'span',
array(
'aural' => true,
),
pht('Home')),
phutil_tag(
'span',
array(
'class' => 'sprite-menu menu-logo-image '.$class,
),
''),
));
}
private function renderNotificationMenu() {
@ -256,6 +276,8 @@ final class PhabricatorMainMenuView extends AphrontView {
'alert-notifications',
);
$aural = array();
$message_tag = '';
$message_notification_dropdown = '';
$conpherence = 'PhabricatorApplicationConpherence';
@ -270,6 +292,20 @@ final class PhabricatorMainMenuView extends AphrontView {
->withParticipationStatus($unread_status)
->execute();
$message_count_number = idx($unread, $user->getPHID(), 0);
if ($message_count_number) {
$aural[] = phutil_tag(
'a',
array(
'href' => '/conpherence/',
),
pht(
'%s unread messages.',
new PhutilNumber($message_count_number)));
} else {
$aural[] = pht('No messages.');
}
if ($message_count_number > 999) {
$message_count_number = "\xE2\x88\x9E";
}
@ -333,6 +369,19 @@ final class PhabricatorMainMenuView extends AphrontView {
$count_number = id(new PhabricatorFeedStoryNotification())
->countUnread($user);
if ($count_number) {
$aural[] = phutil_tag(
'a',
array(
'href' => '/notification/',
),
pht(
'%s unread notifications.',
new PhutilNumber($count_number)));
} else {
$aural[] = pht('No notifications.');
}
if ($count_number > 999) {
$count_number = "\xE2\x88\x9E";
}
@ -397,8 +446,12 @@ final class PhabricatorMainMenuView extends AphrontView {
}
return array(
hsprintf('%s%s', $bubble_tag, $message_tag),
$dropdowns
array(
$bubble_tag,
$message_tag,
),
$dropdowns,
$aural,
);
}

View file

@ -25,6 +25,16 @@ final class PHUIListItemView extends AphrontTagView {
private $renderNameAsTooltip;
private $statusColor;
private $order;
private $aural;
public function setAural($aural) {
$this->aural = $aural;
return $this;
}
public function getAural() {
return $this->aural;
}
public function setOrder($order) {
$this->order = $order;
@ -170,10 +180,21 @@ final class PHUIListItemView extends AphrontTagView {
$external = " \xE2\x86\x97";
}
// If this element has an aural representation, make any name visual
// only. This is primarily dealing with the links in the main menu like
// "Profile" and "Logout". If we don't hide the name, the mobile
// version of these elements will have two redundant names.
$classes = array();
$classes[] = 'phui-list-item-name';
if ($this->aural !== null) {
$classes[] = 'visual-only';
}
$name = phutil_tag(
'span',
array(
'class' => 'phui-list-item-name',
'class' => implode(' ', $classes),
),
array(
$this->name,
@ -182,6 +203,16 @@ final class PHUIListItemView extends AphrontTagView {
}
}
$aural = null;
if ($this->aural !== null) {
$aural = phutil_tag(
'span',
array(
'class' => 'aural-only',
),
$this->aural);
}
if ($this->icon) {
$icon_name = $this->icon;
if ($this->getDisabled()) {
@ -210,6 +241,7 @@ final class PHUIListItemView extends AphrontTagView {
'sigil' => $sigil,
),
array(
$aural,
$icon,
$this->renderChildren(),
$name,

View file

@ -123,3 +123,29 @@ hr {
background: #bbbbbb;
border: none;
}
.aural-only {
position: absolute !important;
clip: rect(1px, 1px, 1px, 1px);
}
.visual-only {
/* These elements are hidden by the 'aria-hidden' attribute. */
}
.audible .aural-only {
clip: auto;
background: #006699;
color: #ffffff;
}
.audible .aural-only a {
color: #ffffff;
font-weight: bold;
}
.audible .visual-only {
position: absolute !important;
background: #990066;
opacity: 0.25;
}

View file

@ -148,3 +148,7 @@ div.jx-typeahead-results {
.jx-tooltip-container {
z-index: 51;
}
.audible .aural-only {
z-index: 100;
}