Skip to content

Commit

Permalink
fixes to source-pane accessibility
Browse files Browse the repository at this point in the history
- make document outline view aria-hidden when visibly hidden
- annotate document outline view splitter
- initial wiring for command to speak editor status
- mark various source pane tabpanels with correct role, and give them labels (text editor, object explorer, code browser, data viewer, url viewer. profile results)
-
  • Loading branch information
gtritchie committed Jan 13, 2020
1 parent 72da8be commit 5f25c09
Show file tree
Hide file tree
Showing 20 changed files with 206 additions and 45 deletions.
11 changes: 10 additions & 1 deletion src/gwt/src/org/rstudio/core/client/a11y/A11y.java
@@ -1,7 +1,7 @@
/*
* A11y.java
*
* Copyright (C) 2009-19 by RStudio, Inc.
* Copyright (C) 2009-20 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
Expand Down Expand Up @@ -102,6 +102,15 @@ public static void setARIAHidden(Element el)
el.setAttribute("aria-hidden", "true");
}

/**
* Make an element visible to screen readers.
* @param el
*/
public static void setARIAVisible(Element el)
{
el.removeAttribute("aria-hidden");
}

public static void setVisuallyHidden(Widget widget)
{
setVisuallyHidden(widget.getElement());
Expand Down
@@ -1,7 +1,7 @@
/*
* AriaLiveStatusWidget.java
*
* Copyright (C) 2019 by RStudio, Inc.
* Copyright (C) 2019-20 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
Expand Down Expand Up @@ -36,21 +36,24 @@ public void announce(String message, int speakDelayMs)
{
if (speakDelayMs < 0)
{
if (updateReaderTimer_.isRunning())
updateReaderTimer_.cancel();
clearMessage();
return;
}

resultsMessage_ = message;
if (updateReaderTimer_.isRunning())
updateReaderTimer_.cancel();
if (clearReaderTimer_.isRunning())
clearReaderTimer_.cancel();
updateReaderTimer_.schedule(speakDelayMs);
}

public void clearMessage()
{
if (updateReaderTimer_.isRunning())
updateReaderTimer_.cancel();
if (clearReaderTimer_.isRunning())
clearReaderTimer_.cancel();
getElement().setInnerText("");
}

Expand All @@ -63,8 +66,23 @@ public void clearMessage()
public void run()
{
getElement().setInnerText(resultsMessage_);
if (clearReaderTimer_.isRunning())
clearReaderTimer_.cancel();
clearReaderTimer_.schedule(4000);
}
};

/**
* Timer for clearing the previous message if nothing new arrives
*/
private Timer clearReaderTimer_ = new Timer()
{
@Override
public void run()
{
getElement().setInnerText("");
}
};

private String resultsMessage_;
}
Expand Up @@ -351,7 +351,7 @@ public void onFileUpload(FileUploadEvent event)
@Override
public void onAriaLiveStatus(AriaLiveStatusEvent event)
{
int delayMs = userPrefs_.get().typingStatusDelayMs().getValue();
int delayMs = event.getImmediate() ? 0 : userPrefs_.get().typingStatusDelayMs().getValue();
if (!ModalDialogTracker.dispatchAriaLiveStatus(event.getMessage(), delayMs))
view_.reportStatus(event.getMessage(), userPrefs_.get().typingStatusDelayMs().getValue());
}
Expand Down Expand Up @@ -1012,6 +1012,12 @@ else if (!sessionInfo.getShowIdentity() || !sessionInfo.getAllowFullUI())
commands_.importDatasetFromXLS().remove();
}

// remove commands that only make sense if screen reader is enabled
if (!userPrefs_.get().enableScreenReader().getValue())
{
commands_.speakEditorLocation().remove();
}

// If no project, ensure we show the product-edition title; if there is a project
// open this was already done
if (!Desktop.isDesktop() &&
Expand Down
@@ -1,7 +1,7 @@
/*
* AriaLiveStatusEvent.java
*
* Copyright (C) 2019 by RStudio, Inc.
* Copyright (C) 2019-20 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
Expand All @@ -25,14 +25,25 @@ public interface Handler extends EventHandler
}

public AriaLiveStatusEvent(String message)
{
this(message, false);
}

public AriaLiveStatusEvent(String message, boolean immediate)
{
message_ = message;
immediate_ = immediate;
}

public String getMessage()
{
return message_;
}

public boolean getImmediate()
{
return immediate_;
}

@Override
protected void dispatch(AriaLiveStatusEvent.Handler handler)
Expand All @@ -47,6 +58,7 @@ public Type<AriaLiveStatusEvent.Handler> getAssociatedType()
}

private final String message_;
private final boolean immediate_;

public static final Type<AriaLiveStatusEvent.Handler> TYPE = new Type<>();
}
@@ -1,7 +1,7 @@
/*
* SatelliteWindow.java
*
* Copyright (C) 2009-19 by RStudio, Inc.
* Copyright (C) 2009-20 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
Expand Down Expand Up @@ -144,7 +144,7 @@ public void onResize()
@Override
public void onAriaLiveStatus(AriaLiveStatusEvent event)
{
int delayMs = RStudioGinjector.INSTANCE.getUserPrefs().typingStatusDelayMs().getValue();
int delayMs = event.getImmediate() ? 0 : RStudioGinjector.INSTANCE.getUserPrefs().typingStatusDelayMs().getValue();
if (!ModalDialogTracker.dispatchAriaLiveStatus(event.getMessage(), delayMs))
ariaLiveStatusWidget_.announce(event.getMessage(), delayMs);
}
Expand Down
Expand Up @@ -502,6 +502,9 @@ well as menu structures (for main menu and popup menus).
<cmd refid="toggleScreenReaderSupport"/>
<cmd refid="toggleTabKeyMovesFocus"/>
<separator/>
<menu label="Speak">
<cmd refid="speakEditorLocation"/>
</menu>
<cmd refid="focusMainToolbar"/>
<separator/>
<cmd refid="showAccessibilityOptions"/>
Expand Down Expand Up @@ -828,6 +831,7 @@ well as menu structures (for main menu and popup menus).
<shortcut refid="projectOptions" value="Shift+Meta+," if="org.rstudio.core.client.BrowseCap.isMacintosh()"/>
<shortcut refid="goToHelp" value="Ctrl+C Ctrl+V" disableModes="default,vim,sublime"/>
<shortcut refid="toggleTabKeyMovesFocus" value="Ctrl+Alt+Shift+T"/>
<shortcut refid="speakEditorLocation" value="Ctrl+Shift+B"/>
</shortcutgroup>
<shortcutgroup name="Console">
<shortcut refid="consoleClear" value="Ctrl+L" disableModes="emacs"/>
Expand Down Expand Up @@ -3621,4 +3625,8 @@ well as menu structures (for main menu and popup menus).
menuLabel="Sign Ou_t"
desc="Sign out from RStudio"
windowMode="main"/>

<cmd id="speakEditorLocation"
menuLabel="Speak Text Editor Location"
windowMode="main"/>
</commands>
Expand Up @@ -640,6 +640,7 @@
public abstract AppCommand toggleTabKeyMovesFocus();
public abstract AppCommand showAccessibilityOptions();
public abstract AppCommand focusMainToolbar();
public abstract AppCommand speakEditorLocation();

// Internal
public abstract AppCommand showDomElements();
Expand Down
Expand Up @@ -30,7 +30,7 @@
overflow: hidden;
margin-top: 20px;
font-style: italic;
color: rgb(128, 128, 128) !important;
color: rgb(117, 117, 117) !important;
}

.tree {
Expand Down
@@ -1,7 +1,7 @@
/*
* DocumentOutlineWidget.java
*
* Copyright (C) 2009-12 by RStudio, Inc.
* Copyright (C) 2009-20 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
Expand All @@ -14,10 +14,13 @@
*/
package org.rstudio.studio.client.workbench.views.source;

import com.google.gwt.aria.client.OrientationValue;
import com.google.gwt.aria.client.Roles;
import org.rstudio.core.client.CommandWithArg;
import org.rstudio.core.client.Counter;
import org.rstudio.core.client.HandlerRegistrations;
import org.rstudio.core.client.StringUtil;
import org.rstudio.core.client.a11y.A11y;
import org.rstudio.core.client.dom.DomUtils;
import org.rstudio.core.client.theme.res.ThemeStyles;
import org.rstudio.studio.client.RStudioGinjector;
Expand Down Expand Up @@ -63,6 +66,9 @@ public VerticalSeparator()
{
panel_ = new FlowPanel();
panel_.addStyleName(RES.styles().leftSeparator());
Roles.getSeparatorRole().set(panel_.getElement());
Roles.getSeparatorRole().setAriaOrientationProperty(panel_.getElement(),
OrientationValue.VERTICAL);
initWidget(panel_);
}

Expand Down Expand Up @@ -228,6 +234,7 @@ public DocumentOutlineWidget(TextEditingTarget target)

tree_ = new Tree();
tree_.addStyleName(RES.styles().tree());
Roles.getTreeRole().setAriaLabelProperty(tree_.getElement(), "Document Outline");

panel_ = new FlowPanel();
panel_.addStyleName(RES.styles().panel());
Expand All @@ -252,6 +259,14 @@ public void onEditorThemeStyleChanged(EditorThemeStyleChangedEvent event)
updateStyles(emptyPlaceholder_, event.getStyle());
}

public void setAriaVisible(boolean visible)
{
if (visible)
A11y.setARIAVisible(getElement());
else
A11y.setARIAHidden(getElement());
}

private void initHandlers()
{
handlers_.add(target_.getDocDisplay().addScopeTreeReadyHandler(new ScopeTreeReadyEvent.Handler()
Expand Down
@@ -1,7 +1,7 @@
/*
* Source.java
*
* Copyright (C) 2009-19 by RStudio, Inc.
* Copyright (C) 2009-20 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
Expand Down Expand Up @@ -65,6 +65,7 @@
import org.rstudio.studio.client.application.ApplicationAction;
import org.rstudio.studio.client.application.ApplicationUtils;
import org.rstudio.studio.client.application.Desktop;
import org.rstudio.studio.client.application.events.AriaLiveStatusEvent;
import org.rstudio.studio.client.application.events.CrossWindowEvent;
import org.rstudio.studio.client.application.events.EventBus;
import org.rstudio.studio.client.common.FileDialogs;
Expand Down Expand Up @@ -4184,6 +4185,19 @@ public void onOpenPreviousFileOnFilesystem()
openAdjacentFile(false);
}

@Handler
public void onSpeakEditorLocation()
{
String announcement;
if (view_.getTabCount() == 0)
announcement = "No documents open in editor";
else
{
announcement = "Nothing to see here";
}
events_.fireEvent(new AriaLiveStatusEvent(announcement, true));
}

@Handler
public void onZoomIn()
{
Expand Down
@@ -1,7 +1,7 @@
/*
* SourceShim.java
*
* Copyright (C) 2009-19 by RStudio, Inc.
* Copyright (C) 2009-20 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
Expand Down Expand Up @@ -155,7 +155,9 @@ public abstract static class AsyncSource extends AsyncShim<Source>
public abstract void onOpenNextFileOnFilesystem();
@Handler
public abstract void onOpenPreviousFileOnFilesystem();

@Handler
public abstract void onSpeakEditorLocation();

// NOTE: These aren't really Source-level commands, but we
// need them to be registered for both the whole application
// as well as popped-out source windows.
Expand Down
@@ -1,7 +1,7 @@
/*
* CodeBrowserEditingTarget.java
*
* Copyright (C) 2009-19 by RStudio, Inc.
* Copyright (C) 2009-20 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
Expand Down Expand Up @@ -88,6 +88,7 @@ public interface Display extends TextDisplay,
void findPrevious();
void findFromSelection();
void scrollToLeft();
void setAccessibleName(String name);
}

interface MyBinder extends CommandBinder<Commands, CodeBrowserEditingTarget>
Expand Down Expand Up @@ -201,6 +202,9 @@ public void execute()
{
docDisplay_.setCode("", false);
}

name_.addValueChangeHandler(event -> view_.setAccessibleName(name_.getValue()));
name_.fireChangeEvent();
}

public void showFunction(SearchPathFunctionDefinition functionDef)
Expand Down Expand Up @@ -812,8 +816,7 @@ public void onResponseReceived(
private SourceDocument doc_;

private final Value<Boolean> dirtyState_ = new Value<Boolean>(false);
private ArrayList<HandlerRegistration> releaseOnDismiss_ =
new ArrayList<HandlerRegistration>();
private ArrayList<HandlerRegistration> releaseOnDismiss_ = new ArrayList<>();
private final SourceServerOperations server_;
private final Commands commands_;
private final EventBus events_;
Expand All @@ -823,7 +826,7 @@ public void onResponseReceived(
private Display view_;
private HandlerRegistration commandReg_;
private boolean shownWarningBar_ = false;
private final Value<String> name_ = new Value<String>("Source Viewer");
private final Value<String> name_ = new Value<>("Source Viewer");
private DocDisplay docDisplay_;
private EditingTargetCodeExecution codeExecution_;

Expand Down

0 comments on commit 5f25c09

Please sign in to comment.