mirror of
https://we.phorge.it/source/phorge.git
synced 2025-02-19 18:28:39 +01: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:
parent
3fde020049
commit
e8cebb7da5
15 changed files with 171 additions and 20 deletions
|
@ -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',
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ abstract class PhabricatorHomeController extends PhabricatorController {
|
|||
}
|
||||
}
|
||||
|
||||
$nav->addFilter(
|
||||
$nav->addFilter(
|
||||
'',
|
||||
pht('Customize Applications...'),
|
||||
'/settings/panel/home/');
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -46,6 +46,7 @@ final class PhabricatorApplicationSettings extends PhabricatorApplication {
|
|||
->addClass('core-menu-item')
|
||||
->setSelected($selected)
|
||||
->setHref('/settings/')
|
||||
->setAural(pht('Settings'))
|
||||
->setOrder(400);
|
||||
$items[] = $item;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -430,6 +430,10 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
|||
$classes[] = 'printable';
|
||||
}
|
||||
|
||||
if ($this->getRequest()->getStr('__aural__')) {
|
||||
$classes[] = 'audible';
|
||||
}
|
||||
|
||||
return implode(' ', $classes);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -148,3 +148,7 @@ div.jx-typeahead-results {
|
|||
.jx-tooltip-container {
|
||||
z-index: 51;
|
||||
}
|
||||
|
||||
.audible .aural-only {
|
||||
z-index: 100;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue