瀏覽代碼

Merge pull request #9622 from marthacryan/add-roles

Add aria roles and labels
Steven Silvester 4 年之前
父節點
當前提交
879385b7cb

+ 41 - 2
packages/application/src/shell.ts

@@ -2,6 +2,7 @@
 // Distributed under the terms of the Modified BSD License.
 
 import { DocumentRegistry, DocumentWidget } from '@jupyterlab/docregistry';
+import { ITranslator, nullTranslator } from '@jupyterlab/translation';
 
 import { classes, DockPanelSvg, LabIcon } from '@jupyterlab/ui-components';
 
@@ -91,6 +92,16 @@ export namespace ILabShell {
    */
   export type AreaConfig = DockLayout.AreaConfig;
 
+  /**
+   * An options object for creating a lab shell object.
+   */
+  export type IOptions = {
+    /**
+     * The application language translator.
+     */
+    translator?: ITranslator;
+  };
+
   /**
    * An arguments object for the changed signals.
    */
@@ -185,15 +196,22 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
   /**
    * Construct a new application shell.
    */
-  constructor() {
+  constructor(options?: ILabShell.IOptions) {
     super();
     this.addClass(APPLICATION_SHELL_CLASS);
     this.id = 'main';
 
+    const trans = ((options && options.translator) || nullTranslator).load(
+      'jupyterlab'
+    );
     const headerPanel = (this._headerPanel = new BoxPanel());
     const menuHandler = (this._menuHandler = new Private.PanelHandler());
+    menuHandler.panel.node.setAttribute('role', 'navigation');
+    menuHandler.panel.node.setAttribute('aria-label', trans.__('main'));
     const topHandler = (this._topHandler = new Private.PanelHandler());
+    topHandler.panel.node.setAttribute('role', 'banner');
     const bottomPanel = (this._bottomPanel = new BoxPanel());
+    bottomPanel.node.setAttribute('role', 'contentinfo');
     const hboxPanel = new BoxPanel();
     const dockPanel = (this._dockPanel = new DockPanelSvg());
     MessageLoop.installMessageHook(dockPanel, this._dockChildHook);
@@ -213,12 +231,32 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
 
     leftHandler.sideBar.addClass(SIDEBAR_CLASS);
     leftHandler.sideBar.addClass('jp-mod-left');
+    leftHandler.sideBar.node.setAttribute(
+      'aria-label',
+      trans.__('main sidebar')
+    );
+    leftHandler.sideBar.contentNode.setAttribute(
+      'aria-label',
+      trans.__('main sidebar')
+    );
+    leftHandler.sideBar.node.setAttribute('role', 'complementary');
     leftHandler.stackedPanel.id = 'jp-left-stack';
 
     rightHandler.sideBar.addClass(SIDEBAR_CLASS);
     rightHandler.sideBar.addClass('jp-mod-right');
+    rightHandler.sideBar.node.setAttribute(
+      'aria-label',
+      trans.__('alternate sidebar')
+    );
+    rightHandler.sideBar.contentNode.setAttribute(
+      'aria-label',
+      trans.__('alternate sidebar')
+    );
+    rightHandler.sideBar.node.setAttribute('role', 'complementary');
     rightHandler.stackedPanel.id = 'jp-right-stack';
 
+    dockPanel.node.setAttribute('role', 'main');
+
     hboxPanel.spacing = 0;
     dockPanel.spacing = 5;
     hsplitPanel.spacing = 1;
@@ -1298,7 +1336,8 @@ namespace Private {
       this._sideBar = new TabBar<Widget>({
         insertBehavior: 'none',
         removeBehavior: 'none',
-        allowDeselect: true
+        allowDeselect: true,
+        orientation: 'vertical'
       });
       this._stackedPanel = new StackedPanel();
       this._sideBar.hide();

+ 5 - 0
packages/apputils-extension/src/palette.ts

@@ -103,6 +103,11 @@ export namespace Palette {
     const modalPalette = new ModalCommandPalette({ commandPalette: palette });
     let modal = false;
 
+    palette.node.setAttribute('role', 'region');
+    palette.node.setAttribute(
+      'aria-label',
+      trans.__('Command Palette Section')
+    );
     shell.add(palette, 'left', { rank: 300 });
 
     if (settingRegistry) {

+ 6 - 1
packages/apputils/src/mainareawidget.ts

@@ -1,7 +1,7 @@
 // Copyright (c) Jupyter Development Team.
 // Distributed under the terms of the Modified BSD License.
 
-import { ITranslator } from '@jupyterlab/translation';
+import { ITranslator, nullTranslator } from '@jupyterlab/translation';
 
 import { Message, MessageLoop } from '@lumino/messaging';
 
@@ -37,8 +37,13 @@ export class MainAreaWidget<T extends Widget = Widget>
     this.addClass('jp-MainAreaWidget');
     this.id = DOMUtils.createDomID();
 
+    const trans = (options.translator || nullTranslator).load('jupyterlab');
     const content = (this._content = options.content);
+    content.node.setAttribute('role', 'region');
+    content.node.setAttribute('aria-label', trans.__('notebook content'));
     const toolbar = (this._toolbar = options.toolbar || new Toolbar());
+    toolbar.node.setAttribute('role', 'navigation');
+    toolbar.node.setAttribute('aria-label', trans.__('notebook actions'));
     const spinner = this._spinner;
 
     const layout = (this.layout = new BoxLayout({ spacing: 0 }));

+ 3 - 0
packages/debugger-extension/src/index.ts

@@ -512,6 +512,9 @@ const main: JupyterFrontEndPlugin<void> = {
       restorer.add(sidebar, 'debugger-sidebar');
     }
 
+    sidebar.node.setAttribute('role', 'region');
+    sidebar.node.setAttribute('aria-label', trans.__('Debugger section'));
+
     shell.add(sidebar, 'right');
 
     if (palette) {

+ 10 - 0
packages/extensionmanager-extension/src/index.ts

@@ -64,6 +64,11 @@ const plugin: JupyterFrontEndPlugin<void> = {
 
     if (enabled && labShell) {
       view = createView();
+      view.node.setAttribute('role', 'region');
+      view.node.setAttribute(
+        'aria-label',
+        trans.__('Extension Manager section')
+      );
       labShell.add(view, 'left', { rank: 1000 });
     }
 
@@ -80,6 +85,11 @@ const plugin: JupyterFrontEndPlugin<void> = {
               return;
             }
             view = view || createView();
+            view.node.setAttribute('role', 'region');
+            view.node.setAttribute(
+              'aria-label',
+              trans.__('Extension Manager section')
+            );
             if (labShell) {
               labShell.add(view, 'left', { rank: 1000 });
             }

+ 2 - 0
packages/filebrowser-extension/src/index.ts

@@ -167,6 +167,8 @@ const browser: JupyterFrontEndPlugin<void> = {
   ): void => {
     const trans = translator.load('jupyterlab');
     const browser = factory.defaultBrowser;
+    browser.node.setAttribute('role', 'region');
+    browser.node.setAttribute('aria-label', trans.__('File Browser Section'));
 
     // Let the application restorer track the primary file browser (that is
     // automatically created) for restoration of application state (e.g. setting

+ 6 - 0
packages/filebrowser/src/browser.ts

@@ -86,6 +86,12 @@ export class FileBrowser extends Widget {
     this._trans = this.translator.load('jupyterlab');
     this._crumbs = new BreadCrumbs({ model, translator });
     this.toolbar = new Toolbar<Widget>();
+    // a11y
+    this.toolbar.node.setAttribute('role', 'navigation');
+    this.toolbar.node.setAttribute(
+      'aria-label',
+      this._trans.__('file browser')
+    );
     this._directoryPending = false;
 
     const newFolder = new ToolbarButton({

+ 2 - 0
packages/running-extension/src/index.ts

@@ -58,6 +58,8 @@ function activate(
   running.id = 'jp-running-sessions';
   running.title.caption = trans.__('Running Terminals and Kernels');
   running.title.icon = runningIcon;
+  running.node.setAttribute('role', 'region');
+  running.node.setAttribute('aria-label', trans.__('Running Sessions section'));
 
   // Let the application restorer track the running panel for restoration of
   // application state (e.g. setting the running panel as the current side bar

+ 3 - 0
packages/toc-extension/src/index.ts

@@ -66,6 +66,9 @@ async function activateTOC(
   toc.title.icon = tocIcon;
   toc.title.caption = trans.__('Table of Contents');
   toc.id = 'table-of-contents';
+  toc.node.setAttribute('role', 'region');
+  toc.node.setAttribute('aria-label', trans.__('Table of Contents section'));
+
   labShell.add(toc, 'left', { rank: 400 });
 
   // Add the ToC widget to the application restorer: