Accessibility (#361)

* add p5 interceptor submodule

* update package

* remoce interceptor

* update interceptor;

* merge scripts

* change postinstall script

* refactor interceptor files

* remove merge conflicts

* change source files

* add registry class

* provide seperate outputs for text and grid

* switch textOutput to boolean

* make both modules usable together

* update interceptor for safari

* fix grid label

* add sound output as well

* change file strucure

* change constants

* change input lables

* switch submodule branch

* change variable name

* change grid to table

* remove role from table elements

* switch submodule branch
This commit is contained in:
Mathura MG 2017-05-31 12:23:30 -07:00 committed by Cassie Tarakajian
parent 8e1a65daed
commit 82207a50d3
16 changed files with 261 additions and 122 deletions

View file

@ -4,8 +4,8 @@ export const TOGGLE_SKETCH = 'TOGGLE_SKETCH';
export const START_SKETCH = 'START_SKETCH'; export const START_SKETCH = 'START_SKETCH';
export const STOP_SKETCH = 'STOP_SKETCH'; export const STOP_SKETCH = 'STOP_SKETCH';
export const START_TEXT_OUTPUT = 'START_TEXT_OUTPUT'; export const START_ACCESSIBLE_OUTPUT = 'START_ACCESSIBLE_OUTPUT';
export const STOP_TEXT_OUTPUT = 'STOP_TEXT_OUTPUT'; export const STOP_ACCESSIBLE_OUTPUT = 'STOP_ACCESSIBLE_OUTPUT';
export const OPEN_PREFERENCES = 'OPEN_PREFERENCES'; export const OPEN_PREFERENCES = 'OPEN_PREFERENCES';
export const CLOSE_PREFERENCES = 'CLOSE_PREFERENCES'; export const CLOSE_PREFERENCES = 'CLOSE_PREFERENCES';
@ -69,6 +69,8 @@ export const SET_AUTOSAVE = 'SET_AUTOSAVE';
export const SET_LINT_WARNING = 'SET_LINT_WARNING'; export const SET_LINT_WARNING = 'SET_LINT_WARNING';
export const SET_PREFERENCES = 'SET_PREFERENCES'; export const SET_PREFERENCES = 'SET_PREFERENCES';
export const SET_TEXT_OUTPUT = 'SET_TEXT_OUTPUT'; export const SET_TEXT_OUTPUT = 'SET_TEXT_OUTPUT';
export const SET_GRID_OUTPUT = 'SET_GRID_OUTPUT';
export const SET_SOUND_OUTPUT = 'SET_SOUND_OUTPUT';
export const OPEN_PROJECT_OPTIONS = 'OPEN_PROJECT_OPTIONS'; export const OPEN_PROJECT_OPTIONS = 'OPEN_PROJECT_OPTIONS';
export const CLOSE_PROJECT_OPTIONS = 'CLOSE_PROJECT_OPTIONS'; export const CLOSE_PROJECT_OPTIONS = 'CLOSE_PROJECT_OPTIONS';

View file

@ -31,15 +31,15 @@ export function endSketchRefresh() {
}; };
} }
export function startTextOutput() { export function startAccessibleOutput() {
return { return {
type: ActionTypes.START_TEXT_OUTPUT type: ActionTypes.START_ACCESSIBLE_OUTPUT
}; };
} }
export function stopTextOutput() { export function stopAccessibleOutput() {
return { return {
type: ActionTypes.STOP_TEXT_OUTPUT type: ActionTypes.STOP_ACCESSIBLE_OUTPUT
}; };
} }

View file

@ -137,6 +137,42 @@ export function setTextOutput(value) {
}; };
} }
export function setGridOutput(value) {
return (dispatch, getState) => {
dispatch({
type: ActionTypes.SET_GRID_OUTPUT,
value
});
const state = getState();
if (state.user.authenticated) {
const formParams = {
preferences: {
gridOutput: value
}
};
updatePreferences(formParams, dispatch);
}
};
}
export function setSoundOutput(value) {
return (dispatch, getState) => {
dispatch({
type: ActionTypes.SET_SOUND_OUTPUT,
value
});
const state = getState();
if (state.user.authenticated) {
const formParams = {
preferences: {
soundOutput: value
}
};
updatePreferences(formParams, dispatch);
}
};
}
export function setTheme(value) { export function setTheme(value) {
// return { // return {
// type: ActionTypes.SET_THEME, // type: ActionTypes.SET_THEME,
@ -180,4 +216,3 @@ export function setAutorefresh(value) {
} }
}; };
} }

View file

@ -0,0 +1,51 @@
import React, { PropTypes } from 'react';
import GridOutput from '../components/GridOutput';
import TextOutput from '../components/TextOutput';
class AccessibleOutput extends React.Component {
componentDidMount() {
this.accessibleOutputModal.focus();
}
componentDidUpdate(prevProps) {
// if the user explicitly clicks on the play button, want to refocus on the text output
if (this.props.isPlaying && this.props.previewIsRefreshing) {
this.accessibleOutputModal.focus();
}
}
render() {
return (
<section
className="accessible-output"
id="canvas-sub"
ref={(element) => { this.accessibleOutputModal = element; }}
tabIndex="0"
aria-label="accessible-output"
title="canvas text output"
>
{(() => { // eslint-disable-line
if (this.props.textOutput) {
return (
<TextOutput />
);
}
})()}
{(() => { // eslint-disable-line
if (this.props.gridOutput) {
return (
<GridOutput />
);
}
})()}
</section>
);
}
}
AccessibleOutput.propTypes = {
isPlaying: PropTypes.bool.isRequired,
previewIsRefreshing: PropTypes.bool.isRequired,
textOutput: PropTypes.bool.isRequired,
gridOutput: PropTypes.bool.isRequired
};
export default AccessibleOutput;

View file

@ -0,0 +1,38 @@
import React, { PropTypes } from 'react';
class GridOutput extends React.Component {
componentDidMount() {
this.GridOutputModal.focus();
}
render() {
return (
<section
id="gridOutput-content"
ref={(element) => { this.GridOutputModal = element; }}
>
<h2> Grid Output </h2>
<p
tabIndex="0"
role="main"
id="gridOutput-content-summary"
aria-label="grid output summary"
>
</p>
<table
id="gridOutput-content-table"
summary="grid output details"
>
</table>
<div
tabIndex="0"
role="main"
id="gridOutput-content-details"
aria-label="grid output details"
>
</div>
</section>
);
}
}
export default GridOutput;

View file

@ -261,50 +261,41 @@ class Preferences extends React.Component {
<div className="preference__options"> <div className="preference__options">
<input <input
type="radio" type="checkbox"
onChange={() => this.props.setTextOutput(1)} onChange={(event) => {
this.props.setTextOutput(event.target.checked);
}}
aria-label="text output on" aria-label="text output on"
name="text output" name="text output"
id="text-output-on" id="text-output-on"
className="preference__radio-button"
value="On" value="On"
checked={Boolean(this.props.textOutput === 1)} checked={(this.props.textOutput)}
/> />
<label htmlFor="text-output-on" className="preference__option preference__canvas">Plain-text</label> <label htmlFor="text-output-on" className="preference__option preference__canvas">Plain-text</label>
<input <input
type="radio" type="checkbox"
onChange={() => this.props.setTextOutput(2)} onChange={(event) => {
aria-label="table text output on" this.props.setGridOutput(event.target.checked);
name="table text output" }}
id="grid-output-on" aria-label="table output on"
className="preference__radio-button" name="table output"
value="Grid On" id="table-output-on"
checked={Boolean(this.props.textOutput === 2)} value="On"
checked={(this.props.gridOutput)}
/> />
<label htmlFor="grid-output-on" className="preference__option preference__canvas">Table-text</label> <label htmlFor="table-output-on" className="preference__option preference__canvas">Table-text</label>
<input <input
type="radio" type="checkbox"
onChange={() => this.props.setTextOutput(3)} onChange={(event) => {
this.props.setSoundOutput(event.target.checked);
}}
aria-label="sound output on" aria-label="sound output on"
name="sound output" name="sound output"
id="sound-output-on" id="sound-output-on"
className="preference__radio-button"
value="On" value="On"
checked={Boolean(this.props.textOutput === 3)} checked={(this.props.soundOutput)}
/> />
<label htmlFor="sound-output-on" className="preference__option preference__canvas">Sound</label> <label htmlFor="sound-output-on" className="preference__option preference__canvas">Sound</label>
<input
type="radio"
onChange={() => this.props.setTextOutput(0)}
aria-label="text output off"
name="text output"
id="text-output-off"
className="preference__radio-button"
value="Off"
checked={!(this.props.textOutput)}
/>
<label htmlFor="text-output-off" className="preference__option preference__canvas">Off</label>
</div> </div>
</div> </div>
</section> </section>
@ -324,8 +315,12 @@ Preferences.propTypes = {
setFontSize: PropTypes.func.isRequired, setFontSize: PropTypes.func.isRequired,
autosave: PropTypes.bool.isRequired, autosave: PropTypes.bool.isRequired,
setAutosave: PropTypes.func.isRequired, setAutosave: PropTypes.func.isRequired,
textOutput: PropTypes.number.isRequired, textOutput: PropTypes.bool.isRequired,
gridOutput: PropTypes.bool.isRequired,
soundOutput: PropTypes.bool.isRequired,
setTextOutput: PropTypes.func.isRequired, setTextOutput: PropTypes.func.isRequired,
setGridOutput: PropTypes.func.isRequired,
setSoundOutput: PropTypes.func.isRequired,
lintWarning: PropTypes.bool.isRequired, lintWarning: PropTypes.bool.isRequired,
setLintWarning: PropTypes.func.isRequired, setLintWarning: PropTypes.func.isRequired,
theme: PropTypes.string.isRequired, theme: PropTypes.string.isRequired,

View file

@ -114,7 +114,7 @@ class PreviewFrame extends React.Component {
} }
// if user switches textoutput preferences // if user switches textoutput preferences
if (this.props.isTextOutputPlaying !== prevProps.isTextOutputPlaying) { if (this.props.isAccessibleOutputPlaying !== prevProps.isAccessibleOutputPlaying) {
this.renderSketch(); this.renderSketch();
return; return;
} }
@ -124,6 +124,16 @@ class PreviewFrame extends React.Component {
return; return;
} }
if (this.props.gridOutput !== prevProps.gridOutput) {
this.renderSketch();
return;
}
if (this.props.soundOutput !== prevProps.soundOutput) {
this.renderSketch();
return;
}
if (this.props.fullView && this.props.files[0].id !== prevProps.files[0].id) { if (this.props.fullView && this.props.files[0].id !== prevProps.files[0].id) {
this.renderSketch(); this.renderSketch();
} }
@ -165,38 +175,41 @@ class PreviewFrame extends React.Component {
'/loop-protect.min.js', '/loop-protect.min.js',
'/hijackConsole.js' '/hijackConsole.js'
]; ];
if (this.props.isTextOutputPlaying || (this.props.textOutput !== 0 && this.props.isPlaying)) { if (this.props.isAccessibleOutputPlaying || ((this.props.textOutput || this.props.gridOutput || this.props.soundOutput) && this.props.isPlaying)) {
let interceptorScripts = []; let interceptorScripts = [];
if (this.props.textOutput === 0) { interceptorScripts = [
this.props.setTextOutput(1); '/p5-interceptor/registry.js',
'/p5-interceptor/loadData.js',
'/p5-interceptor/interceptorHelperFunctions.js',
'/p5-interceptor/baseInterceptor.js',
'/p5-interceptor/entities/entity.min.js',
'/p5-interceptor/ntc.min.js'
];
if (!this.props.textOutput && !this.props.gridOutput && !this.props.soundOutput) {
this.props.setTextOutput(true);
} }
if (this.props.textOutput === 1) { if (this.props.textOutput) {
interceptorScripts = [ let textInterceptorScripts = [];
'/p5-interceptor/registry.js', textInterceptorScripts = [
'/p5-interceptor/loadData.js',
'/p5-interceptor/interceptorHelperFunctions.js',
'/p5-interceptor/baseInterceptor.js',
'/p5-interceptor/entities/entity.min.js',
'/p5-interceptor/textInterceptor/interceptorFunctions.js', '/p5-interceptor/textInterceptor/interceptorFunctions.js',
'/p5-interceptor/textInterceptor/interceptorP5.js', '/p5-interceptor/textInterceptor/interceptorP5.js'
'/p5-interceptor/ntc.min.js'
]; ];
} else if (this.props.textOutput === 2) { interceptorScripts = interceptorScripts.concat(textInterceptorScripts);
interceptorScripts = [ }
'/p5-interceptor/registry.js', if (this.props.gridOutput) {
'/p5-interceptor/loadData.js', let gridInterceptorScripts = [];
'/p5-interceptor/interceptorHelperFunctions.js', gridInterceptorScripts = [
'/p5-interceptor/baseInterceptor.js',
'/p5-interceptor/entities/entity.min.js',
'/p5-interceptor/gridInterceptor/interceptorFunctions.js', '/p5-interceptor/gridInterceptor/interceptorFunctions.js',
'/p5-interceptor/gridInterceptor/interceptorP5.js', '/p5-interceptor/gridInterceptor/interceptorP5.js'
'/p5-interceptor/ntc.min.js'
]; ];
} else if (this.props.textOutput === 3) { interceptorScripts = interceptorScripts.concat(gridInterceptorScripts);
interceptorScripts = [ }
'/p5-interceptor/loadData.js', if (this.props.soundOutput) {
let soundInterceptorScripts = [];
soundInterceptorScripts = [
'/p5-interceptor/soundInterceptor/interceptorP5.js' '/p5-interceptor/soundInterceptor/interceptorP5.js'
]; ];
interceptorScripts = interceptorScripts.concat(soundInterceptorScripts);
} }
scriptsToInject = scriptsToInject.concat(interceptorScripts); scriptsToInject = scriptsToInject.concat(interceptorScripts);
} }
@ -373,8 +386,10 @@ class PreviewFrame extends React.Component {
PreviewFrame.propTypes = { PreviewFrame.propTypes = {
isPlaying: PropTypes.bool.isRequired, isPlaying: PropTypes.bool.isRequired,
isTextOutputPlaying: PropTypes.bool.isRequired, isAccessibleOutputPlaying: PropTypes.bool.isRequired,
textOutput: PropTypes.number.isRequired, textOutput: PropTypes.bool.isRequired,
gridOutput: PropTypes.bool.isRequired,
soundOutput: PropTypes.bool.isRequired,
setTextOutput: PropTypes.func.isRequired, setTextOutput: PropTypes.func.isRequired,
htmlFile: PropTypes.shape({ htmlFile: PropTypes.shape({
content: PropTypes.string.isRequired content: PropTypes.string.isRequired

View file

@ -1,28 +1,16 @@
import React, { PropTypes } from 'react'; import React from 'react';
class TextOutput extends React.Component { class TextOutput extends React.Component {
componentDidMount() { componentDidMount() {
this.canvasTextOutput.focus(); this.TextOutputModal.focus();
}
componentDidUpdate(prevProps) {
// if the user explicitly clicks on the play button, want to refocus on the text output
if (this.props.isPlaying && this.props.previewIsRefreshing) {
this.canvasTextOutput.focus();
}
} }
render() { render() {
return ( return (
<section <section
className="text-output" id="textOutput-content"
id="canvas-sub" ref={(element) => { this.TextOutputModal = element; }}
ref={(element) => { this.canvasTextOutput = element; }}
tabIndex="0"
aria-label="text-output"
title="canvas text output"
> >
<h2> Output </h2> <h2> Text Output </h2>
<section id="textOutput-content">
</section>
<p <p
tabIndex="0" tabIndex="0"
role="main" role="main"
@ -31,10 +19,8 @@ class TextOutput extends React.Component {
> >
</p> </p>
<table <table
tabIndex="0"
role="main"
id="textOutput-content-table" id="textOutput-content-table"
aria-label="text output details" summary="text output details"
> >
</table> </table>
<div <div
@ -49,9 +35,4 @@ class TextOutput extends React.Component {
} }
} }
TextOutput.propTypes = {
isPlaying: PropTypes.bool.isRequired,
previewIsRefreshing: PropTypes.bool.isRequired
};
export default TextOutput; export default TextOutput;

View file

@ -64,7 +64,7 @@ class Toolbar extends React.Component {
className="toolbar__play-sketch-button" className="toolbar__play-sketch-button"
onClick={() => { onClick={() => {
this.props.clearConsole(); this.props.clearConsole();
this.props.startTextOutput(); this.props.startAccessibleOutput();
this.props.startSketchAndRefresh(); this.props.startSketchAndRefresh();
}} }}
aria-label="play sketch" aria-label="play sketch"
@ -85,7 +85,7 @@ class Toolbar extends React.Component {
</button> </button>
<button <button
className={stopButtonClass} className={stopButtonClass}
onClick={() => { this.props.stopTextOutput(); this.props.stopSketch(); }} onClick={() => { this.props.stopAccessibleOutput(); this.props.stopSketch(); }}
aria-label="stop sketch" aria-label="stop sketch"
> >
<InlineSVG src={stopUrl} alt="Stop Sketch" /> <InlineSVG src={stopUrl} alt="Stop Sketch" />
@ -184,8 +184,8 @@ Toolbar.propTypes = {
isPlaying: PropTypes.bool.isRequired, isPlaying: PropTypes.bool.isRequired,
preferencesIsVisible: PropTypes.bool.isRequired, preferencesIsVisible: PropTypes.bool.isRequired,
stopSketch: PropTypes.func.isRequired, stopSketch: PropTypes.func.isRequired,
startTextOutput: PropTypes.func.isRequired, startAccessibleOutput: PropTypes.func.isRequired,
stopTextOutput: PropTypes.func.isRequired, stopAccessibleOutput: PropTypes.func.isRequired,
setProjectName: PropTypes.func.isRequired, setProjectName: PropTypes.func.isRequired,
openPreferences: PropTypes.func.isRequired, openPreferences: PropTypes.func.isRequired,
owner: PropTypes.shape({ owner: PropTypes.shape({

View file

@ -7,7 +7,7 @@ import Editor from '../components/Editor';
import Sidebar from '../components/Sidebar'; import Sidebar from '../components/Sidebar';
import PreviewFrame from '../components/PreviewFrame'; import PreviewFrame from '../components/PreviewFrame';
import Toolbar from '../components/Toolbar'; import Toolbar from '../components/Toolbar';
import TextOutput from '../components/TextOutput'; import AccessibleOutput from '../components/AccessibleOutput';
import Preferences from '../components/Preferences'; import Preferences from '../components/Preferences';
import NewFileModal from '../components/NewFileModal'; import NewFileModal from '../components/NewFileModal';
import NewFolderModal from '../components/NewFolderModal'; import NewFolderModal from '../components/NewFolderModal';
@ -165,15 +165,14 @@ class IDEView extends React.Component {
this.props.startSketchAndRefresh(); this.props.startSketchAndRefresh();
} else if (e.keyCode === 50 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac)) && e.shiftKey) { } else if (e.keyCode === 50 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac)) && e.shiftKey) {
e.preventDefault(); e.preventDefault();
this.props.setTextOutput(0); this.props.setTextOutput(false);
this.props.setGridOutput(false);
this.props.setSoundOutput(false);
} else if (e.keyCode === 49 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac)) && e.shiftKey) { } else if (e.keyCode === 49 && ((e.metaKey && this.isMac) || (e.ctrlKey && !this.isMac)) && e.shiftKey) {
e.preventDefault(); e.preventDefault();
if (this.props.preferences.textOutput === 3) { this.props.setTextOutput(true);
this.props.preferences.textOutput = 1; this.props.setGridOutput(true);
} else { this.props.setSoundOutput(true);
this.props.preferences.textOutput += 1;
}
this.props.setTextOutput(this.props.preferences.textOutput);
} }
} }
@ -217,8 +216,8 @@ class IDEView extends React.Component {
className="Toolbar" className="Toolbar"
isPlaying={this.props.ide.isPlaying} isPlaying={this.props.ide.isPlaying}
stopSketch={this.props.stopSketch} stopSketch={this.props.stopSketch}
startTextOutput={this.props.startTextOutput} startAccessibleOutput={this.props.startAccessibleOutput}
stopTextOutput={this.props.stopTextOutput} stopAccessibleOutput={this.props.stopAccessibleOutput}
projectName={this.props.project.name} projectName={this.props.project.name}
setProjectName={this.props.setProjectName} setProjectName={this.props.setProjectName}
showEditProjectName={this.props.showEditProjectName} showEditProjectName={this.props.showEditProjectName}
@ -228,6 +227,8 @@ class IDEView extends React.Component {
serveSecure={this.props.project.serveSecure} serveSecure={this.props.project.serveSecure}
setServeSecure={this.props.setServeSecure} setServeSecure={this.props.setServeSecure}
setTextOutput={this.props.setTextOutput} setTextOutput={this.props.setTextOutput}
setGridOutput={this.props.setGridOutput}
setSoundOutput={this.props.setSoundOutput}
owner={this.props.project.owner} owner={this.props.project.owner}
project={this.props.project} project={this.props.project}
infiniteLoop={this.props.ide.infiniteLoop} infiniteLoop={this.props.ide.infiniteLoop}
@ -254,7 +255,10 @@ class IDEView extends React.Component {
lintWarning={this.props.preferences.lintWarning} lintWarning={this.props.preferences.lintWarning}
setLintWarning={this.props.setLintWarning} setLintWarning={this.props.setLintWarning}
textOutput={this.props.preferences.textOutput} textOutput={this.props.preferences.textOutput}
gridOutput={this.props.preferences.gridOutput}
setTextOutput={this.props.setTextOutput} setTextOutput={this.props.setTextOutput}
setGridOutput={this.props.setGridOutput}
setSoundOutput={this.props.setSoundOutput}
theme={this.props.preferences.theme} theme={this.props.preferences.theme}
setTheme={this.props.setTheme} setTheme={this.props.setTheme}
/> />
@ -346,11 +350,13 @@ class IDEView extends React.Component {
</div> </div>
<div> <div>
{(() => { {(() => {
if ((this.props.preferences.textOutput && this.props.ide.isPlaying) || this.props.ide.isTextOutputPlaying) { if (((this.props.preferences.textOutput || this.props.preferences.gridOutput || this.props.preferences.soundOutput) && this.props.ide.isPlaying) || this.props.ide.isAccessibleOutputPlaying) {
return ( return (
<TextOutput <AccessibleOutput
isPlaying={this.props.ide.isPlaying} isPlaying={this.props.ide.isPlaying}
previewIsRefreshing={this.props.ide.previewIsRefreshing} previewIsRefreshing={this.props.ide.previewIsRefreshing}
textOutput={this.props.preferences.textOutput}
gridOutput={this.props.preferences.gridOutput}
/> />
); );
} }
@ -362,9 +368,13 @@ class IDEView extends React.Component {
files={this.props.files} files={this.props.files}
content={this.props.selectedFile.content} content={this.props.selectedFile.content}
isPlaying={this.props.ide.isPlaying} isPlaying={this.props.ide.isPlaying}
isTextOutputPlaying={this.props.ide.isTextOutputPlaying} isAccessibleOutputPlaying={this.props.ide.isAccessibleOutputPlaying}
textOutput={this.props.preferences.textOutput} textOutput={this.props.preferences.textOutput}
gridOutput={this.props.preferences.gridOutput}
soundOutput={this.props.preferences.soundOutput}
setTextOutput={this.props.setTextOutput} setTextOutput={this.props.setTextOutput}
setGridOutput={this.props.setGridOutput}
setSoundOutput={this.props.setSoundOutput}
dispatchConsoleEvent={this.props.dispatchConsoleEvent} dispatchConsoleEvent={this.props.dispatchConsoleEvent}
autorefresh={this.props.preferences.autorefresh} autorefresh={this.props.preferences.autorefresh}
previewIsRefreshing={this.props.ide.previewIsRefreshing} previewIsRefreshing={this.props.ide.previewIsRefreshing}
@ -494,7 +504,7 @@ IDEView.propTypes = {
saveProject: PropTypes.func.isRequired, saveProject: PropTypes.func.isRequired,
ide: PropTypes.shape({ ide: PropTypes.shape({
isPlaying: PropTypes.bool.isRequired, isPlaying: PropTypes.bool.isRequired,
isTextOutputPlaying: PropTypes.bool.isRequired, isAccessibleOutputPlaying: PropTypes.bool.isRequired,
consoleEvent: PropTypes.array, consoleEvent: PropTypes.array,
modalIsVisible: PropTypes.bool.isRequired, modalIsVisible: PropTypes.bool.isRequired,
sidebarIsExpanded: PropTypes.bool.isRequired, sidebarIsExpanded: PropTypes.bool.isRequired,
@ -516,8 +526,8 @@ IDEView.propTypes = {
helpType: PropTypes.string helpType: PropTypes.string
}).isRequired, }).isRequired,
stopSketch: PropTypes.func.isRequired, stopSketch: PropTypes.func.isRequired,
startTextOutput: PropTypes.func.isRequired, startAccessibleOutput: PropTypes.func.isRequired,
stopTextOutput: PropTypes.func.isRequired, stopAccessibleOutput: PropTypes.func.isRequired,
project: PropTypes.shape({ project: PropTypes.shape({
id: PropTypes.string, id: PropTypes.string,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
@ -542,7 +552,9 @@ IDEView.propTypes = {
isTabIndent: PropTypes.bool.isRequired, isTabIndent: PropTypes.bool.isRequired,
autosave: PropTypes.bool.isRequired, autosave: PropTypes.bool.isRequired,
lintWarning: PropTypes.bool.isRequired, lintWarning: PropTypes.bool.isRequired,
textOutput: PropTypes.number.isRequired, textOutput: PropTypes.bool.isRequired,
gridOutput: PropTypes.bool.isRequired,
soundOutput: PropTypes.bool.isRequired,
theme: PropTypes.string.isRequired, theme: PropTypes.string.isRequired,
autorefresh: PropTypes.bool.isRequired autorefresh: PropTypes.bool.isRequired
}).isRequired, }).isRequired,
@ -554,6 +566,8 @@ IDEView.propTypes = {
setAutosave: PropTypes.func.isRequired, setAutosave: PropTypes.func.isRequired,
setLintWarning: PropTypes.func.isRequired, setLintWarning: PropTypes.func.isRequired,
setTextOutput: PropTypes.func.isRequired, setTextOutput: PropTypes.func.isRequired,
setGridOutput: PropTypes.func.isRequired,
setSoundOutput: PropTypes.func.isRequired,
files: PropTypes.arrayOf(PropTypes.shape({ files: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.string.isRequired, id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,

View file

@ -2,7 +2,7 @@ import * as ActionTypes from '../../../constants';
const initialState = { const initialState = {
isPlaying: false, isPlaying: false,
isTextOutputPlaying: false, isAccessibleOutputPlaying: false,
modalIsVisible: false, modalIsVisible: false,
sidebarIsExpanded: false, sidebarIsExpanded: false,
consoleIsExpanded: true, consoleIsExpanded: true,
@ -27,10 +27,10 @@ const ide = (state = initialState, action) => {
return Object.assign({}, state, { isPlaying: true }); return Object.assign({}, state, { isPlaying: true });
case ActionTypes.STOP_SKETCH: case ActionTypes.STOP_SKETCH:
return Object.assign({}, state, { isPlaying: false }); return Object.assign({}, state, { isPlaying: false });
case ActionTypes.START_TEXT_OUTPUT: case ActionTypes.START_ACCESSIBLE_OUTPUT:
return Object.assign({}, state, { isTextOutputPlaying: true }); return Object.assign({}, state, { isAccessibleOutputPlaying: true });
case ActionTypes.STOP_TEXT_OUTPUT: case ActionTypes.STOP_ACCESSIBLE_OUTPUT:
return Object.assign({}, state, { isTextOutputPlaying: false }); return Object.assign({}, state, { isAccessibleOutputPlaying: false });
case ActionTypes.CONSOLE_EVENT: case ActionTypes.CONSOLE_EVENT:
return Object.assign({}, state, { consoleEvent: action.event }); return Object.assign({}, state, { consoleEvent: action.event });
case ActionTypes.SHOW_MODAL: case ActionTypes.SHOW_MODAL:

View file

@ -6,7 +6,9 @@ const initialState = {
isTabIndent: true, isTabIndent: true,
autosave: true, autosave: true,
lintWarning: false, lintWarning: false,
textOutput: 0, textOutput: false,
gridOutput: false,
soundOutput: false,
theme: 'light', theme: 'light',
autorefresh: false autorefresh: false
}; };
@ -31,6 +33,10 @@ const preferences = (state = initialState, action) => {
return Object.assign({}, state, { lintWarning: action.value }); return Object.assign({}, state, { lintWarning: action.value });
case ActionTypes.SET_TEXT_OUTPUT: case ActionTypes.SET_TEXT_OUTPUT:
return Object.assign({}, state, { textOutput: action.value }); return Object.assign({}, state, { textOutput: action.value });
case ActionTypes.SET_GRID_OUTPUT:
return Object.assign({}, state, { gridOutput: action.value });
case ActionTypes.SET_SOUND_OUTPUT:
return Object.assign({}, state, { soundOutput: action.value });
case ActionTypes.SET_PREFERENCES: case ActionTypes.SET_PREFERENCES:
return action.preferences; return action.preferences;
case ActionTypes.SET_THEME: case ActionTypes.SET_THEME:

View file

@ -126,7 +126,7 @@
} }
.preference__option:last-child { .preference__option:last-child {
padding-right: 0; padding-right: 0;
} }
.preference__preview-button { .preference__preview-button {
@ -151,5 +151,5 @@
} }
.preference__option.preference__canvas:not(:last-child) { .preference__option.preference__canvas:not(:last-child) {
padding-right: #{20 / $base-font-size}rem; padding-right: #{14 / $base-font-size}rem;
} }

View file

@ -31,7 +31,7 @@
@extend %hidden-element; @extend %hidden-element;
} }
.text-output { .accessible-output {
@extend %hidden-element; @extend %hidden-element;
} }

View file

@ -19,7 +19,9 @@ const userSchema = new Schema({
isTabIndent: { type: Boolean, default: false }, isTabIndent: { type: Boolean, default: false },
autosave: { type: Boolean, default: true }, autosave: { type: Boolean, default: true },
lintWarning: { type: Boolean, default: false }, lintWarning: { type: Boolean, default: false },
textOutput: { type: Number, default: 0 }, textOutput: { type: Boolean, default: false },
gridOutput: { type: Boolean, default: false },
soundOutput: { type: Boolean, default: false },
theme: { type: String, default: 'light' }, theme: { type: String, default: 'light' },
autorefresh: { type: Boolean, default: false } autorefresh: { type: Boolean, default: false }
} }

@ -1 +1 @@
Subproject commit 344fedf8d868c62adc571bf4212c6bea3cd20247 Subproject commit 5b924f3460886b82d72d0ab0d709f323f8b9a588