diff --git a/client/constants.js b/client/constants.js
index 149dc79c..8f1a5573 100644
--- a/client/constants.js
+++ b/client/constants.js
@@ -4,8 +4,8 @@ export const TOGGLE_SKETCH = 'TOGGLE_SKETCH';
export const START_SKETCH = 'START_SKETCH';
export const STOP_SKETCH = 'STOP_SKETCH';
-export const START_TEXT_OUTPUT = 'START_TEXT_OUTPUT';
-export const STOP_TEXT_OUTPUT = 'STOP_TEXT_OUTPUT';
+export const START_ACCESSIBLE_OUTPUT = 'START_ACCESSIBLE_OUTPUT';
+export const STOP_ACCESSIBLE_OUTPUT = 'STOP_ACCESSIBLE_OUTPUT';
export const OPEN_PREFERENCES = 'OPEN_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_PREFERENCES = 'SET_PREFERENCES';
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 CLOSE_PROJECT_OPTIONS = 'CLOSE_PROJECT_OPTIONS';
diff --git a/client/modules/IDE/actions/ide.js b/client/modules/IDE/actions/ide.js
index 4f5c0662..0e8fa3ae 100644
--- a/client/modules/IDE/actions/ide.js
+++ b/client/modules/IDE/actions/ide.js
@@ -31,15 +31,15 @@ export function endSketchRefresh() {
};
}
-export function startTextOutput() {
+export function startAccessibleOutput() {
return {
- type: ActionTypes.START_TEXT_OUTPUT
+ type: ActionTypes.START_ACCESSIBLE_OUTPUT
};
}
-export function stopTextOutput() {
+export function stopAccessibleOutput() {
return {
- type: ActionTypes.STOP_TEXT_OUTPUT
+ type: ActionTypes.STOP_ACCESSIBLE_OUTPUT
};
}
diff --git a/client/modules/IDE/actions/preferences.js b/client/modules/IDE/actions/preferences.js
index bdc40f76..4f735280 100644
--- a/client/modules/IDE/actions/preferences.js
+++ b/client/modules/IDE/actions/preferences.js
@@ -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) {
// return {
// type: ActionTypes.SET_THEME,
@@ -180,4 +216,3 @@ export function setAutorefresh(value) {
}
};
}
-
diff --git a/client/modules/IDE/components/AccessibleOutput.jsx b/client/modules/IDE/components/AccessibleOutput.jsx
new file mode 100644
index 00000000..a3688bd7
--- /dev/null
+++ b/client/modules/IDE/components/AccessibleOutput.jsx
@@ -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 (
+ { this.accessibleOutputModal = element; }}
+ tabIndex="0"
+ aria-label="accessible-output"
+ title="canvas text output"
+ >
+ {(() => { // eslint-disable-line
+ if (this.props.textOutput) {
+ return (
+
+ );
+ }
+ })()}
+ {(() => { // eslint-disable-line
+ if (this.props.gridOutput) {
+ return (
+
+ );
+ }
+ })()}
+
+ );
+ }
+}
+
+AccessibleOutput.propTypes = {
+ isPlaying: PropTypes.bool.isRequired,
+ previewIsRefreshing: PropTypes.bool.isRequired,
+ textOutput: PropTypes.bool.isRequired,
+ gridOutput: PropTypes.bool.isRequired
+};
+
+export default AccessibleOutput;
diff --git a/client/modules/IDE/components/GridOutput.jsx b/client/modules/IDE/components/GridOutput.jsx
new file mode 100644
index 00000000..17fb1213
--- /dev/null
+++ b/client/modules/IDE/components/GridOutput.jsx
@@ -0,0 +1,38 @@
+import React, { PropTypes } from 'react';
+
+class GridOutput extends React.Component {
+ componentDidMount() {
+ this.GridOutputModal.focus();
+ }
+ render() {
+ return (
+ { this.GridOutputModal = element; }}
+ >
+ Grid Output
+
+
+
+
+
+
+ );
+ }
+}
+
+export default GridOutput;
diff --git a/client/modules/IDE/components/Preferences.jsx b/client/modules/IDE/components/Preferences.jsx
index cb549a13..24203322 100644
--- a/client/modules/IDE/components/Preferences.jsx
+++ b/client/modules/IDE/components/Preferences.jsx
@@ -261,50 +261,41 @@ class Preferences extends React.Component {
{ this.canvasTextOutput = element; }}
- tabIndex="0"
- aria-label="text-output"
- title="canvas text output"
+ id="textOutput-content"
+ ref={(element) => { this.TextOutputModal = element; }}
>
- Output
-
+ Text Output
{
this.props.clearConsole();
- this.props.startTextOutput();
+ this.props.startAccessibleOutput();
this.props.startSketchAndRefresh();
}}
aria-label="play sketch"
@@ -85,7 +85,7 @@ class Toolbar extends React.Component {
{(() => {
- 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 (
-
);
}
@@ -362,9 +368,13 @@ class IDEView extends React.Component {
files={this.props.files}
content={this.props.selectedFile.content}
isPlaying={this.props.ide.isPlaying}
- isTextOutputPlaying={this.props.ide.isTextOutputPlaying}
+ isAccessibleOutputPlaying={this.props.ide.isAccessibleOutputPlaying}
textOutput={this.props.preferences.textOutput}
+ gridOutput={this.props.preferences.gridOutput}
+ soundOutput={this.props.preferences.soundOutput}
setTextOutput={this.props.setTextOutput}
+ setGridOutput={this.props.setGridOutput}
+ setSoundOutput={this.props.setSoundOutput}
dispatchConsoleEvent={this.props.dispatchConsoleEvent}
autorefresh={this.props.preferences.autorefresh}
previewIsRefreshing={this.props.ide.previewIsRefreshing}
@@ -494,7 +504,7 @@ IDEView.propTypes = {
saveProject: PropTypes.func.isRequired,
ide: PropTypes.shape({
isPlaying: PropTypes.bool.isRequired,
- isTextOutputPlaying: PropTypes.bool.isRequired,
+ isAccessibleOutputPlaying: PropTypes.bool.isRequired,
consoleEvent: PropTypes.array,
modalIsVisible: PropTypes.bool.isRequired,
sidebarIsExpanded: PropTypes.bool.isRequired,
@@ -516,8 +526,8 @@ IDEView.propTypes = {
helpType: PropTypes.string
}).isRequired,
stopSketch: PropTypes.func.isRequired,
- startTextOutput: PropTypes.func.isRequired,
- stopTextOutput: PropTypes.func.isRequired,
+ startAccessibleOutput: PropTypes.func.isRequired,
+ stopAccessibleOutput: PropTypes.func.isRequired,
project: PropTypes.shape({
id: PropTypes.string,
name: PropTypes.string.isRequired,
@@ -542,7 +552,9 @@ IDEView.propTypes = {
isTabIndent: PropTypes.bool.isRequired,
autosave: 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,
autorefresh: PropTypes.bool.isRequired
}).isRequired,
@@ -554,6 +566,8 @@ IDEView.propTypes = {
setAutosave: PropTypes.func.isRequired,
setLintWarning: PropTypes.func.isRequired,
setTextOutput: PropTypes.func.isRequired,
+ setGridOutput: PropTypes.func.isRequired,
+ setSoundOutput: PropTypes.func.isRequired,
files: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
diff --git a/client/modules/IDE/reducers/ide.js b/client/modules/IDE/reducers/ide.js
index 6ad8bf1f..30d0b553 100644
--- a/client/modules/IDE/reducers/ide.js
+++ b/client/modules/IDE/reducers/ide.js
@@ -2,7 +2,7 @@ import * as ActionTypes from '../../../constants';
const initialState = {
isPlaying: false,
- isTextOutputPlaying: false,
+ isAccessibleOutputPlaying: false,
modalIsVisible: false,
sidebarIsExpanded: false,
consoleIsExpanded: true,
@@ -27,10 +27,10 @@ const ide = (state = initialState, action) => {
return Object.assign({}, state, { isPlaying: true });
case ActionTypes.STOP_SKETCH:
return Object.assign({}, state, { isPlaying: false });
- case ActionTypes.START_TEXT_OUTPUT:
- return Object.assign({}, state, { isTextOutputPlaying: true });
- case ActionTypes.STOP_TEXT_OUTPUT:
- return Object.assign({}, state, { isTextOutputPlaying: false });
+ case ActionTypes.START_ACCESSIBLE_OUTPUT:
+ return Object.assign({}, state, { isAccessibleOutputPlaying: true });
+ case ActionTypes.STOP_ACCESSIBLE_OUTPUT:
+ return Object.assign({}, state, { isAccessibleOutputPlaying: false });
case ActionTypes.CONSOLE_EVENT:
return Object.assign({}, state, { consoleEvent: action.event });
case ActionTypes.SHOW_MODAL:
diff --git a/client/modules/IDE/reducers/preferences.js b/client/modules/IDE/reducers/preferences.js
index f4161670..8441f042 100644
--- a/client/modules/IDE/reducers/preferences.js
+++ b/client/modules/IDE/reducers/preferences.js
@@ -6,7 +6,9 @@ const initialState = {
isTabIndent: true,
autosave: true,
lintWarning: false,
- textOutput: 0,
+ textOutput: false,
+ gridOutput: false,
+ soundOutput: false,
theme: 'light',
autorefresh: false
};
@@ -31,6 +33,10 @@ const preferences = (state = initialState, action) => {
return Object.assign({}, state, { lintWarning: action.value });
case ActionTypes.SET_TEXT_OUTPUT:
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:
return action.preferences;
case ActionTypes.SET_THEME:
diff --git a/client/styles/components/_preferences.scss b/client/styles/components/_preferences.scss
index e684cd96..f4938d3f 100644
--- a/client/styles/components/_preferences.scss
+++ b/client/styles/components/_preferences.scss
@@ -126,7 +126,7 @@
}
.preference__option:last-child {
- padding-right: 0;
+ padding-right: 0;
}
.preference__preview-button {
@@ -151,5 +151,5 @@
}
.preference__option.preference__canvas:not(:last-child) {
- padding-right: #{20 / $base-font-size}rem;
-}
\ No newline at end of file
+ padding-right: #{14 / $base-font-size}rem;
+}
diff --git a/client/styles/layout/_ide.scss b/client/styles/layout/_ide.scss
index 87e3724c..cb446951 100644
--- a/client/styles/layout/_ide.scss
+++ b/client/styles/layout/_ide.scss
@@ -31,7 +31,7 @@
@extend %hidden-element;
}
-.text-output {
+.accessible-output {
@extend %hidden-element;
}
diff --git a/server/models/user.js b/server/models/user.js
index cd43c7c9..0f89cb15 100644
--- a/server/models/user.js
+++ b/server/models/user.js
@@ -19,7 +19,9 @@ const userSchema = new Schema({
isTabIndent: { type: Boolean, default: false },
autosave: { type: Boolean, default: true },
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' },
autorefresh: { type: Boolean, default: false }
}
diff --git a/static/p5-interceptor b/static/p5-interceptor
index 344fedf8..5b924f34 160000
--- a/static/p5-interceptor
+++ b/static/p5-interceptor
@@ -1 +1 @@
-Subproject commit 344fedf8d868c62adc571bf4212c6bea3cd20247
+Subproject commit 5b924f3460886b82d72d0ab0d709f323f8b9a588