@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add more accessibility labels for screen readers

Summary:
Depends on D19594. See PHI823. Ref T13164.

- Add a label for the "X" button in comment areas, like "Remove Action: Change Subscribers".
- Add a label for the floating header display options menu in Differential.
- Add `role="button"` to `PHUIButtonView` objects that we render with an `<a ...>` tag.

Test Plan:
Viewed a revision with `?__aural__=true`:

- Saw "Remove Action: ..." label.
- Saw "Display Options" label.
- Used inspector to verify that some `<a class="button" ...>` now have `<a class="button" role="button" ...>`. This isn't exhaustive, but at least improves things. A specific example is the "edit", "reply", etc., actions on inline comments.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13164

Differential Revision: https://secure.phabricator.com/D19595

+71 -29
+24 -24
resources/celerity/map.php
··· 12 12 'core.pkg.css' => 'f515619b', 13 13 'core.pkg.js' => '2058ec09', 14 14 'differential.pkg.css' => '06dc617c', 15 - 'differential.pkg.js' => '11a08e85', 15 + 'differential.pkg.js' => 'c1cfa143', 16 16 'diffusion.pkg.css' => 'a2d17c7d', 17 17 'diffusion.pkg.js' => '6134c5a1', 18 18 'maniphest.pkg.css' => '4845691a', ··· 373 373 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375', 374 374 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 375 375 'rsrc/js/application/diff/DiffChangeset.js' => 'b49b59d6', 376 - 'rsrc/js/application/diff/DiffChangesetList.js' => '7b95a80a', 376 + 'rsrc/js/application/diff/DiffChangesetList.js' => 'e0b984b5', 377 377 'rsrc/js/application/diff/DiffInline.js' => 'e83d28f3', 378 378 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', 379 379 'rsrc/js/application/differential/behavior-comment-preview.js' => '51c5ad07', ··· 423 423 'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e2e0a072', 424 424 'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08', 425 425 'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f', 426 - 'rsrc/js/application/transactions/behavior-comment-actions.js' => '9a6dd75c', 426 + 'rsrc/js/application/transactions/behavior-comment-actions.js' => '54110499', 427 427 'rsrc/js/application/transactions/behavior-reorder-configs.js' => 'd7a74243', 428 428 'rsrc/js/application/transactions/behavior-reorder-fields.js' => 'b59e1e96', 429 429 'rsrc/js/application/transactions/behavior-show-older-transactions.js' => '8f29b364', ··· 506 506 'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8', 507 507 'rsrc/js/phuix/PHUIXActionView.js' => '8d4a8c72', 508 508 'rsrc/js/phuix/PHUIXAutocomplete.js' => 'df1bbd34', 509 - 'rsrc/js/phuix/PHUIXButtonView.js' => '8a91e1ac', 509 + 'rsrc/js/phuix/PHUIXButtonView.js' => '85ac9772', 510 510 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '04b2ae03', 511 511 'rsrc/js/phuix/PHUIXExample.js' => '68af71ca', 512 512 'rsrc/js/phuix/PHUIXFormControl.js' => '210a16c1', ··· 575 575 'javelin-behavior-bulk-job-reload' => 'edf8a145', 576 576 'javelin-behavior-calendar-month-view' => 'fe33e256', 577 577 'javelin-behavior-choose-control' => '327a00d1', 578 - 'javelin-behavior-comment-actions' => '9a6dd75c', 578 + 'javelin-behavior-comment-actions' => '54110499', 579 579 'javelin-behavior-config-reorder-fields' => 'b6993408', 580 580 'javelin-behavior-conpherence-menu' => '4047cd35', 581 581 'javelin-behavior-conpherence-participant-pane' => 'd057e45a', ··· 752 752 'phabricator-darkmessage' => 'c48cccdd', 753 753 'phabricator-dashboard-css' => 'fe5b1869', 754 754 'phabricator-diff-changeset' => 'b49b59d6', 755 - 'phabricator-diff-changeset-list' => '7b95a80a', 755 + 'phabricator-diff-changeset-list' => 'e0b984b5', 756 756 'phabricator-diff-inline' => 'e83d28f3', 757 757 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 758 758 'phabricator-draggable-list' => 'bea6e7f4', ··· 858 858 'phuix-action-list-view' => 'b5c256b8', 859 859 'phuix-action-view' => '8d4a8c72', 860 860 'phuix-autocomplete' => 'df1bbd34', 861 - 'phuix-button-view' => '8a91e1ac', 861 + 'phuix-button-view' => '85ac9772', 862 862 'phuix-dropdown-menu' => '04b2ae03', 863 863 'phuix-form-control-view' => '210a16c1', 864 864 'phuix-icon-view' => 'bff6884b', ··· 1251 1251 'javelin-vector', 1252 1252 'javelin-typeahead-static-source', 1253 1253 ), 1254 + 54110499 => array( 1255 + 'javelin-behavior', 1256 + 'javelin-stratcom', 1257 + 'javelin-workflow', 1258 + 'javelin-dom', 1259 + 'phuix-form-control-view', 1260 + 'phuix-icon-view', 1261 + 'javelin-behavior-phabricator-gesture', 1262 + ), 1254 1263 '549459b8' => array( 1255 1264 'javelin-behavior', 1256 1265 ), ··· 1500 1509 'owners-path-editor', 1501 1510 'javelin-behavior', 1502 1511 ), 1503 - '7b95a80a' => array( 1504 - 'javelin-install', 1505 - 'phuix-button-view', 1506 - ), 1507 1512 '7cbe244b' => array( 1508 1513 'javelin-install', 1509 1514 'javelin-util', ··· 1533 1538 'javelin-dom', 1534 1539 'javelin-stratcom', 1535 1540 ), 1541 + '85ac9772' => array( 1542 + 'javelin-install', 1543 + 'javelin-dom', 1544 + ), 1536 1545 '85ee8ce6' => array( 1537 1546 'aphront-dialog-view-css', 1538 1547 ), ··· 1557 1566 'javelin-workboard-column', 1558 1567 ), 1559 1568 '8a41885b' => array( 1560 - 'javelin-install', 1561 - 'javelin-dom', 1562 - ), 1563 - '8a91e1ac' => array( 1564 1569 'javelin-install', 1565 1570 'javelin-dom', 1566 1571 ), ··· 1639 1644 'javelin-uri', 1640 1645 'javelin-mask', 1641 1646 'phabricator-drag-and-drop-file-upload', 1642 - ), 1643 - '9a6dd75c' => array( 1644 - 'javelin-behavior', 1645 - 'javelin-stratcom', 1646 - 'javelin-workflow', 1647 - 'javelin-dom', 1648 - 'phuix-form-control-view', 1649 - 'phuix-icon-view', 1650 - 'javelin-behavior-phabricator-gesture', 1651 1647 ), 1652 1648 '9a860428' => array( 1653 1649 'javelin-behavior', ··· 2020 2016 'javelin-dom', 2021 2017 'phuix-icon-view', 2022 2018 'phabricator-prefab', 2019 + ), 2020 + 'e0b984b5' => array( 2021 + 'javelin-install', 2022 + 'phuix-button-view', 2023 2023 ), 2024 2024 'e1d25dfb' => array( 2025 2025 'javelin-behavior',
+1
src/applications/differential/view/DifferentialChangesetListView.php
··· 309 309 'Show All Inlines' => pht('Show All Inlines'), 310 310 311 311 'List Inline Comments' => pht('List Inline Comments'), 312 + 'Display Options' => pht('Display Options'), 312 313 313 314 'Hide or show all inline comments.' => 314 315 pht('Hide or show all inline comments.'),
+5 -1
src/applications/transactions/view/PhabricatorApplicationTransactionCommentView.php
··· 319 319 320 320 foreach ($comment_actions as $key => $comment_action) { 321 321 $key = $comment_action->getKey(); 322 + $label = $comment_action->getLabel(); 323 + 324 + 322 325 $action_map[$key] = array( 323 326 'key' => $key, 324 - 'label' => $comment_action->getLabel(), 327 + 'label' => $label, 325 328 'type' => $comment_action->getPHUIXControlType(), 326 329 'spec' => $comment_action->getPHUIXControlSpecification(), 327 330 'initialValue' => $comment_action->getInitialValue(), 328 331 'groupKey' => $comment_action->getGroupKey(), 329 332 'conflictKey' => $comment_action->getConflictKey(), 333 + 'auralLabel' => pht('Remove Action: %s', $label), 330 334 ); 331 335 332 336 $type_map[$key] = $comment_action;
+8
src/view/phui/PHUIButtonView.php
··· 233 233 $classes = array(); 234 234 } 235 235 236 + // See PHI823. If we aren't rendering a "<button>" tag, give the tag we 237 + // are rendering a "button" role as a hint to screen readers. 238 + $role = null; 239 + if ($this->tag !== 'button') { 240 + $role = 'button'; 241 + } 242 + 236 243 return array( 237 244 'class' => $classes, 238 245 'href' => $this->href, ··· 240 247 'title' => $this->title, 241 248 'sigil' => $sigil, 242 249 'meta' => $meta, 250 + 'role' => $role, 243 251 ); 244 252 } 245 253
+4 -3
webroot/rsrc/js/application/diff/DiffChangesetList.js
··· 1662 1662 1663 1663 _getMenuButton: function() { 1664 1664 if (!this._menuButton) { 1665 + var pht = this.getTranslations(); 1666 + 1665 1667 var button = new JX.PHUIXButtonView() 1666 1668 .setIcon('fa-bars') 1667 - .setButtonType(JX.PHUIXButtonView.BUTTONTYPE_SIMPLE); 1669 + .setButtonType(JX.PHUIXButtonView.BUTTONTYPE_SIMPLE) 1670 + .setAuralLabel(pht('Display Options')); 1668 1671 1669 1672 var dropdown = new JX.PHUIXDropdownMenu(button.getNode()); 1670 1673 this._menuItems = {}; ··· 1702 1705 } 1703 1706 1704 1707 dropdown.listen('open', JX.bind(this, this._ondropdown)); 1705 - 1706 - var pht = this.getTranslations(); 1707 1708 1708 1709 if (this.getInlineListURI()) { 1709 1710 list.addItem(
+4 -1
webroot/rsrc/js/application/transactions/behavior-comment-actions.js
··· 163 163 164 164 option.disabled = true; 165 165 166 + var aural = JX.$N('span', {className: 'aural-only'}, action.auralLabel); 167 + 166 168 var icon = new JX.PHUIXIconView() 167 169 .setIcon('fa-times-circle'); 168 - var remove = JX.$N('a', {href: '#'}, icon.getNode()); 170 + 171 + var remove = JX.$N('a', {href: '#'}, [aural, icon.getNode()]); 169 172 170 173 var control = new JX.PHUIXFormControl() 171 174 .setLabel(action.label)
+25
webroot/rsrc/js/phuix/PHUIXButtonView.js
··· 13 13 members: { 14 14 _node: null, 15 15 _textNode: null, 16 + _auralNode: null, 16 17 17 18 _iconView: null, 18 19 _color: null, ··· 69 70 return this; 70 71 }, 71 72 73 + setAuralLabel: function(label) { 74 + JX.DOM.setContent(this._getAuralNode(), label); 75 + this._redraw(); 76 + return this; 77 + }, 78 + 72 79 getNode: function() { 73 80 if (!this._node) { 74 81 var attrs = { ··· 95 102 return this._textNode; 96 103 }, 97 104 105 + _getAuralNode: function() { 106 + if (!this._auralNode) { 107 + var attrs = { 108 + className: 'aural-only' 109 + }; 110 + 111 + this._auralNode = JX.$N('span', attrs); 112 + } 113 + 114 + return this._auralNode; 115 + }, 116 + 98 117 _redraw: function() { 99 118 var node = this.getNode(); 100 119 120 + var aural = this._auralNode; 101 121 var icon = this._iconView; 102 122 var text = this._textNode; 103 123 104 124 var content = []; 125 + 126 + if (aural) { 127 + content.push(aural); 128 + } 129 + 105 130 if (icon) { 106 131 content.push(icon.getNode()); 107 132 }