Merge pull request #50 from MathuraMG/output
Create text output for canvas
This commit is contained in:
commit
1734852f68
20 changed files with 579 additions and 16 deletions
|
@ -4,6 +4,9 @@ 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 STOP_TEXT_OUTPUT = 'STOP_TEXT_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';
|
||||||
export const SET_FONT_SIZE = 'SET_FONT_SIZE';
|
export const SET_FONT_SIZE = 'SET_FONT_SIZE';
|
||||||
|
@ -61,6 +64,7 @@ export const HIDE_EDIT_FILE_NAME = 'HIDE_EDIT_FILE_NAME';
|
||||||
export const SET_AUTOSAVE = 'SET_AUTOSAVE';
|
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';
|
||||||
|
|
||||||
// eventually, handle errors more specifically and better
|
// eventually, handle errors more specifically and better
|
||||||
export const ERROR = 'ERROR';
|
export const ERROR = 'ERROR';
|
||||||
|
|
|
@ -18,6 +18,18 @@ export function stopSketch() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function startTextOutput() {
|
||||||
|
return {
|
||||||
|
type: ActionTypes.START_TEXT_OUTPUT
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stopTextOutput() {
|
||||||
|
return {
|
||||||
|
type: ActionTypes.STOP_TEXT_OUTPUT
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function setSelectedFile(fileId) {
|
export function setSelectedFile(fileId) {
|
||||||
return {
|
return {
|
||||||
type: ActionTypes.SET_SELECTED_FILE,
|
type: ActionTypes.SET_SELECTED_FILE,
|
||||||
|
|
|
@ -118,3 +118,21 @@ export function setLintWarning(value) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setTextOutput(value) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
dispatch({
|
||||||
|
type: ActionTypes.SET_TEXT_OUTPUT,
|
||||||
|
value
|
||||||
|
});
|
||||||
|
const state = getState();
|
||||||
|
if (state.user.authenticated) {
|
||||||
|
const formParams = {
|
||||||
|
preferences: {
|
||||||
|
textOutput: value
|
||||||
|
}
|
||||||
|
};
|
||||||
|
updatePreferences(formParams, dispatch);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -89,8 +89,6 @@ class Editor extends React.Component {
|
||||||
this._cm.setOption('mode', 'htmlmixed');
|
this._cm.setOption('mode', 'htmlmixed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('componentDidUpdate in editor');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
@ -101,14 +99,14 @@ class Editor extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<section title="code editor" role="main">
|
||||||
<div ref="container" className="editor-holder" tabIndex="0" title="code editor" role="main">
|
<div ref="container" className="editor-holder" tabIndex="0">
|
||||||
</div>
|
</div>
|
||||||
<EditorAccessibility
|
<EditorAccessibility
|
||||||
lintMessages={this.props.lintMessages}
|
lintMessages={this.props.lintMessages}
|
||||||
lineNumber={this.props.lineNumber}
|
lineNumber={this.props.lineNumber}
|
||||||
/>
|
/>
|
||||||
</div>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,14 @@ class Preferences extends React.Component {
|
||||||
preference__option: true,
|
preference__option: true,
|
||||||
'preference__option--selected': !this.props.lintWarning
|
'preference__option--selected': !this.props.lintWarning
|
||||||
});
|
});
|
||||||
|
let textOutputOnClass = classNames({
|
||||||
|
preference__option: true,
|
||||||
|
'preference__option--selected': this.props.textOutput
|
||||||
|
});
|
||||||
|
let textOutputOffClass = classNames({
|
||||||
|
preference__option: true,
|
||||||
|
'preference__option--selected': !this.props.textOutput
|
||||||
|
});
|
||||||
return (
|
return (
|
||||||
<section className={preferencesContainerClass} tabIndex="0" title="preference-menu">
|
<section className={preferencesContainerClass} tabIndex="0" title="preference-menu">
|
||||||
<div className="preferences__heading">
|
<div className="preferences__heading">
|
||||||
|
@ -169,6 +177,22 @@ class Preferences extends React.Component {
|
||||||
>Off</button>
|
>Off</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="preference">
|
||||||
|
<h4 className="preference__title">Accessible Text-based Canvas</h4>
|
||||||
|
<h6 className="preference__subtitle">Used with screen reader</h6>
|
||||||
|
<div className="preference__options">
|
||||||
|
<button
|
||||||
|
className={textOutputOnClass}
|
||||||
|
onClick={() => this.props.setTextOutput(true)}
|
||||||
|
aria-label="text output on"
|
||||||
|
>On</button>
|
||||||
|
<button
|
||||||
|
className={textOutputOffClass}
|
||||||
|
onClick={() => this.props.setTextOutput(false)}
|
||||||
|
aria-label="text output off"
|
||||||
|
>Off</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -186,6 +210,8 @@ 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.bool.isRequired,
|
||||||
|
setTextOutput: PropTypes.func.isRequired,
|
||||||
lintWarning: PropTypes.bool.isRequired,
|
lintWarning: PropTypes.bool.isRequired,
|
||||||
setLintWarning: PropTypes.func.isRequired
|
setLintWarning: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
|
@ -134,12 +134,18 @@ class PreviewFrame extends React.Component {
|
||||||
htmlFile = htmlFile.replace(fileRegex, `<style>\n${cssFile.content}\n</style>`);
|
htmlFile = htmlFile.replace(fileRegex, `<style>\n${cssFile.content}\n</style>`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// const htmlHead = htmlFile.match(/(?:<head.*?>)([\s\S]*?)(?:<\/head>)/gmi);
|
if (this.props.textOutput || this.props.isTextOutputPlaying) {
|
||||||
// const headRegex = new RegExp('head', 'i');
|
const htmlHead = htmlFile.match(/(?:<head.*?>)([\s\S]*?)(?:<\/head>)/gmi);
|
||||||
// let htmlHeadContents = htmlHead[0].split(headRegex)[1];
|
const headRegex = new RegExp('head', 'i');
|
||||||
// htmlHeadContents = htmlHeadContents.slice(1, htmlHeadContents.length - 2);
|
let htmlHeadContents = htmlHead[0].split(headRegex)[1];
|
||||||
// htmlHeadContents += '<link rel="stylesheet" type="text/css" href="/preview-styles.css" />\n';
|
htmlHeadContents = htmlHeadContents.slice(1, htmlHeadContents.length - 2);
|
||||||
// htmlFile = htmlFile.replace(/(?:<head.*?>)([\s\S]*?)(?:<\/head>)/gmi, `<head>\n${htmlHeadContents}\n</head>`);
|
htmlHeadContents += '<script src="/loadData.js"></script>\n';
|
||||||
|
htmlHeadContents += '<script src="/interceptor-functions.js"></script>\n';
|
||||||
|
htmlHeadContents += '<script src="/intercept-p5.js"></script>\n';
|
||||||
|
htmlHeadContents += '<script type="text/javascript" src="/ntc.min.js"></script>';
|
||||||
|
htmlFile = htmlFile.replace(/(?:<head.*?>)([\s\S]*?)(?:<\/head>)/gmi, `<head>\n${htmlHeadContents}\n</head>`);
|
||||||
|
}
|
||||||
|
|
||||||
htmlFile += hijackConsoleScript;
|
htmlFile += hijackConsoleScript;
|
||||||
|
|
||||||
return htmlFile;
|
return htmlFile;
|
||||||
|
@ -181,6 +187,8 @@ class PreviewFrame extends React.Component {
|
||||||
|
|
||||||
PreviewFrame.propTypes = {
|
PreviewFrame.propTypes = {
|
||||||
isPlaying: PropTypes.bool.isRequired,
|
isPlaying: PropTypes.bool.isRequired,
|
||||||
|
isTextOutputPlaying: PropTypes.bool.isRequired,
|
||||||
|
textOutput: PropTypes.bool.isRequired,
|
||||||
head: PropTypes.object.isRequired,
|
head: PropTypes.object.isRequired,
|
||||||
content: PropTypes.string,
|
content: PropTypes.string,
|
||||||
htmlFile: PropTypes.shape({
|
htmlFile: PropTypes.shape({
|
||||||
|
|
37
client/modules/IDE/components/TextOutput.js
Normal file
37
client/modules/IDE/components/TextOutput.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class TextOutput extends React.Component {
|
||||||
|
componentDidMount() {
|
||||||
|
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
className="text-output"
|
||||||
|
id="canvas-sub"
|
||||||
|
tabIndex="0"
|
||||||
|
aria-label="text-output"
|
||||||
|
title="canvas text output"
|
||||||
|
>
|
||||||
|
<section id="textOutput-content">
|
||||||
|
</section>
|
||||||
|
<p
|
||||||
|
tabIndex="0"
|
||||||
|
role="region"
|
||||||
|
id="textOutput-content-summary"
|
||||||
|
aria-label="text output summary"
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<table
|
||||||
|
tabIndex="0"
|
||||||
|
role="region"
|
||||||
|
id="textOutput-content-details"
|
||||||
|
aria-label="text output summary details"
|
||||||
|
>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TextOutput;
|
|
@ -54,8 +54,18 @@ class Toolbar extends React.Component {
|
||||||
<button className={playButtonClass} onClick={this.props.startSketch} aria-label="play sketch">
|
<button className={playButtonClass} onClick={this.props.startSketch} aria-label="play sketch">
|
||||||
<InlineSVG src={playUrl} alt="Play Sketch" />
|
<InlineSVG src={playUrl} alt="Play Sketch" />
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
<button className={stopButtonClass} onClick={this.props.stopSketch} aria-label="stop sketch">
|
className="toolbar__play-sketch-button"
|
||||||
|
onClick={() => { this.props.startTextOutput(); this.props.startSketch(); }}
|
||||||
|
aria-label="play sketch with output text"
|
||||||
|
>
|
||||||
|
<InlineSVG src={playUrl} alt="Play Sketch with output text" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={stopButtonClass}
|
||||||
|
onClick={() => { this.props.stopTextOutput(); this.props.stopSketch(); }}
|
||||||
|
aria-label="stop sketch"
|
||||||
|
>
|
||||||
<InlineSVG src={stopUrl} alt="Stop Sketch" />
|
<InlineSVG src={stopUrl} alt="Stop Sketch" />
|
||||||
</button>
|
</button>
|
||||||
<div className={nameContainerClass}>
|
<div className={nameContainerClass}>
|
||||||
|
@ -106,6 +116,8 @@ Toolbar.propTypes = {
|
||||||
preferencesIsVisible: PropTypes.bool.isRequired,
|
preferencesIsVisible: PropTypes.bool.isRequired,
|
||||||
startSketch: PropTypes.func.isRequired,
|
startSketch: PropTypes.func.isRequired,
|
||||||
stopSketch: PropTypes.func.isRequired,
|
stopSketch: PropTypes.func.isRequired,
|
||||||
|
startTextOutput: PropTypes.func.isRequired,
|
||||||
|
stopTextOutput: 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({
|
||||||
|
|
|
@ -3,6 +3,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 Preferences from '../components/Preferences';
|
import Preferences from '../components/Preferences';
|
||||||
import NewFileModal from '../components/NewFileModal';
|
import NewFileModal from '../components/NewFileModal';
|
||||||
import Nav from '../../../components/Nav';
|
import Nav from '../../../components/Nav';
|
||||||
|
@ -121,11 +122,15 @@ class IDEView extends React.Component {
|
||||||
isPlaying={this.props.ide.isPlaying}
|
isPlaying={this.props.ide.isPlaying}
|
||||||
startSketch={this.props.startSketch}
|
startSketch={this.props.startSketch}
|
||||||
stopSketch={this.props.stopSketch}
|
stopSketch={this.props.stopSketch}
|
||||||
|
startTextOutput={this.props.startTextOutput}
|
||||||
|
stopTextOutput={this.props.stopTextOutput}
|
||||||
|
projectName={this.props.project.name}
|
||||||
setProjectName={this.props.setProjectName}
|
setProjectName={this.props.setProjectName}
|
||||||
showEditProjectName={this.props.showEditProjectName}
|
showEditProjectName={this.props.showEditProjectName}
|
||||||
hideEditProjectName={this.props.hideEditProjectName}
|
hideEditProjectName={this.props.hideEditProjectName}
|
||||||
openPreferences={this.props.openPreferences}
|
openPreferences={this.props.openPreferences}
|
||||||
preferencesIsVisible={this.props.ide.preferencesIsVisible}
|
preferencesIsVisible={this.props.ide.preferencesIsVisible}
|
||||||
|
setTextOutput={this.props.setTextOutput}
|
||||||
owner={this.props.project.owner}
|
owner={this.props.project.owner}
|
||||||
project={this.props.project}
|
project={this.props.project}
|
||||||
/>
|
/>
|
||||||
|
@ -143,6 +148,8 @@ class IDEView extends React.Component {
|
||||||
setAutosave={this.props.setAutosave}
|
setAutosave={this.props.setAutosave}
|
||||||
lintWarning={this.props.preferences.lintWarning}
|
lintWarning={this.props.preferences.lintWarning}
|
||||||
setLintWarning={this.props.setLintWarning}
|
setLintWarning={this.props.setLintWarning}
|
||||||
|
textOutput={this.props.preferences.textOutput}
|
||||||
|
setTextOutput={this.props.setTextOutput}
|
||||||
/>
|
/>
|
||||||
<div className="editor-preview-container">
|
<div className="editor-preview-container">
|
||||||
<SplitPane
|
<SplitPane
|
||||||
|
@ -208,6 +215,16 @@ class IDEView extends React.Component {
|
||||||
<div>
|
<div>
|
||||||
<div className="preview-frame-overlay" ref="overlay">
|
<div className="preview-frame-overlay" ref="overlay">
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
{(() => {
|
||||||
|
if ((this.props.preferences.textOutput && this.props.ide.isPlaying) || this.props.ide.isTextOutputPlaying) {
|
||||||
|
return (
|
||||||
|
<TextOutput />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
<PreviewFrame
|
<PreviewFrame
|
||||||
htmlFile={this.props.htmlFile}
|
htmlFile={this.props.htmlFile}
|
||||||
jsFiles={this.props.jsFiles}
|
jsFiles={this.props.jsFiles}
|
||||||
|
@ -218,6 +235,8 @@ class IDEView extends React.Component {
|
||||||
<link type="text/css" rel="stylesheet" href="/preview-styles.css" />
|
<link type="text/css" rel="stylesheet" href="/preview-styles.css" />
|
||||||
}
|
}
|
||||||
isPlaying={this.props.ide.isPlaying}
|
isPlaying={this.props.ide.isPlaying}
|
||||||
|
isTextOutputPlaying={this.props.ide.isTextOutputPlaying}
|
||||||
|
textOutput={this.props.preferences.textOutput}
|
||||||
dispatchConsoleEvent={this.props.dispatchConsoleEvent}
|
dispatchConsoleEvent={this.props.dispatchConsoleEvent}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -267,6 +286,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,
|
||||||
consoleEvent: PropTypes.object,
|
consoleEvent: PropTypes.object,
|
||||||
modalIsVisible: PropTypes.bool.isRequired,
|
modalIsVisible: PropTypes.bool.isRequired,
|
||||||
sidebarIsExpanded: PropTypes.bool.isRequired,
|
sidebarIsExpanded: PropTypes.bool.isRequired,
|
||||||
|
@ -275,6 +295,8 @@ IDEView.propTypes = {
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
startSketch: PropTypes.func.isRequired,
|
startSketch: PropTypes.func.isRequired,
|
||||||
stopSketch: PropTypes.func.isRequired,
|
stopSketch: PropTypes.func.isRequired,
|
||||||
|
startTextOutput: PropTypes.func.isRequired,
|
||||||
|
stopTextOutput: PropTypes.func.isRequired,
|
||||||
project: PropTypes.shape({
|
project: PropTypes.shape({
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
|
@ -297,7 +319,8 @@ IDEView.propTypes = {
|
||||||
indentationAmount: PropTypes.number.isRequired,
|
indentationAmount: PropTypes.number.isRequired,
|
||||||
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.bool.isRequired
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
closePreferences: PropTypes.func.isRequired,
|
closePreferences: PropTypes.func.isRequired,
|
||||||
setFontSize: PropTypes.func.isRequired,
|
setFontSize: PropTypes.func.isRequired,
|
||||||
|
@ -306,6 +329,7 @@ IDEView.propTypes = {
|
||||||
indentWithSpace: PropTypes.func.isRequired,
|
indentWithSpace: PropTypes.func.isRequired,
|
||||||
setAutosave: PropTypes.func.isRequired,
|
setAutosave: PropTypes.func.isRequired,
|
||||||
setLintWarning: PropTypes.func.isRequired,
|
setLintWarning: PropTypes.func.isRequired,
|
||||||
|
setTextOutput: PropTypes.func.isRequired,
|
||||||
files: PropTypes.array.isRequired,
|
files: PropTypes.array.isRequired,
|
||||||
updateFileContent: PropTypes.func.isRequired,
|
updateFileContent: PropTypes.func.isRequired,
|
||||||
selectedFile: PropTypes.shape({
|
selectedFile: PropTypes.shape({
|
||||||
|
|
|
@ -2,6 +2,7 @@ import * as ActionTypes from '../../../constants';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
isPlaying: false,
|
isPlaying: false,
|
||||||
|
isTextOutputPlaying: false,
|
||||||
selectedFile: '1',
|
selectedFile: '1',
|
||||||
consoleEvent: {
|
consoleEvent: {
|
||||||
method: undefined,
|
method: undefined,
|
||||||
|
@ -21,6 +22,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:
|
||||||
|
return Object.assign({}, state, { isTextOutputPlaying: true });
|
||||||
|
case ActionTypes.STOP_TEXT_OUTPUT:
|
||||||
|
return Object.assign({}, state, { isTextOutputPlaying: false });
|
||||||
case ActionTypes.SET_SELECTED_FILE:
|
case ActionTypes.SET_SELECTED_FILE:
|
||||||
case ActionTypes.SET_PROJECT:
|
case ActionTypes.SET_PROJECT:
|
||||||
case ActionTypes.NEW_PROJECT:
|
case ActionTypes.NEW_PROJECT:
|
||||||
|
|
|
@ -5,7 +5,8 @@ const initialState = {
|
||||||
indentationAmount: 2,
|
indentationAmount: 2,
|
||||||
isTabIndent: true,
|
isTabIndent: true,
|
||||||
autosave: true,
|
autosave: true,
|
||||||
lintWarning: false
|
lintWarning: false,
|
||||||
|
textOutput: false
|
||||||
};
|
};
|
||||||
|
|
||||||
const preferences = (state = initialState, action) => {
|
const preferences = (state = initialState, action) => {
|
||||||
|
@ -26,6 +27,8 @@ const preferences = (state = initialState, action) => {
|
||||||
return Object.assign({}, state, { autosave: action.value });
|
return Object.assign({}, state, { autosave: action.value });
|
||||||
case ActionTypes.SET_LINT_WARNING:
|
case ActionTypes.SET_LINT_WARNING:
|
||||||
return Object.assign({}, state, { lintWarning: action.value });
|
return Object.assign({}, state, { lintWarning: action.value });
|
||||||
|
case ActionTypes.SET_TEXT_OUTPUT:
|
||||||
|
return Object.assign({}, state, { textOutput: action.value });
|
||||||
case ActionTypes.SET_PREFERENCES:
|
case ActionTypes.SET_PREFERENCES:
|
||||||
return action.preferences;
|
return action.preferences;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -46,6 +46,13 @@
|
||||||
margin-bottom: #{10 / $base-font-size}rem;
|
margin-bottom: #{10 / $base-font-size}rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.preference__subtitle {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: #{10 / $base-font-size}rem;
|
||||||
|
margin-top: 0;
|
||||||
|
color: $light-inactive-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
.preference__value {
|
.preference__value {
|
||||||
border: 2px solid $light-button-border-color;
|
border: 2px solid $light-button-border-color;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toolbar__play-sketch-button {
|
||||||
|
@extend %hidden-element;
|
||||||
|
}
|
||||||
|
|
||||||
.toolbar__stop-button {
|
.toolbar__stop-button {
|
||||||
@extend %toolbar-button;
|
@extend %toolbar-button;
|
||||||
&--selected {
|
&--selected {
|
||||||
|
|
|
@ -33,6 +33,10 @@
|
||||||
@extend %hidden-element;
|
@extend %hidden-element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-output {
|
||||||
|
@extend %hidden-element;
|
||||||
|
}
|
||||||
|
|
||||||
.preview-frame {
|
.preview-frame {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -14,7 +14,8 @@ const userSchema = new Schema({
|
||||||
indentationAmount: { type: Number, default: 2 },
|
indentationAmount: { type: Number, default: 2 },
|
||||||
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: Boolean, default: false }
|
||||||
}
|
}
|
||||||
}, { timestamps: true });
|
}, { timestamps: true });
|
||||||
|
|
||||||
|
|
1
static/data.min.json
Normal file
1
static/data.min.json
Normal file
File diff suppressed because one or more lines are too long
52
static/intercept-p5.js
Normal file
52
static/intercept-p5.js
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
var textOutputElement;
|
||||||
|
var canvasLocation ='';
|
||||||
|
|
||||||
|
funcNames = allData["classitems"].map(function(x){
|
||||||
|
if(x["overloads"]) {
|
||||||
|
tempParam = x["overloads"][0]["params"];
|
||||||
|
} else {
|
||||||
|
tempParam = x["params"];
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name: x["name"],
|
||||||
|
params: tempParam,
|
||||||
|
class: x["class"],
|
||||||
|
module: x["module"],
|
||||||
|
submodule: x["submodule"]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
funcNames = funcNames.filter(function(x) {
|
||||||
|
var className = x["class"];
|
||||||
|
return (x["name"] && x["params"] && (className==='p5'));
|
||||||
|
})
|
||||||
|
|
||||||
|
funcNames.forEach(function(x){
|
||||||
|
var document = parent.document;
|
||||||
|
var originalFunc = p5.prototype[x.name];
|
||||||
|
p5.prototype[x.name] = function(){
|
||||||
|
orgArg = arguments;
|
||||||
|
|
||||||
|
if(frameCount == 0) { //for setup
|
||||||
|
Interceptor.setupObject = Interceptor.populateObject(x,arguments, Interceptor.setupObject, document.getElementById('textOutput-content-details'),false);
|
||||||
|
Interceptor.getSummary(Interceptor.setupObject,Interceptor.drawObject,document.getElementById('textOutput-content-summary'));
|
||||||
|
var table = document.getElementById('textOutput-content-details');
|
||||||
|
table.innerHTML = '';
|
||||||
|
Interceptor.populateTable(table,Interceptor.setupObject.objectArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(frameCount%100 == 0 ) {
|
||||||
|
Interceptor.drawObject = Interceptor.populateObject(x,arguments, Interceptor.drawObject, document.getElementById('textOutput-content-details'),true);
|
||||||
|
Interceptor.isCleared = false;
|
||||||
|
}
|
||||||
|
//reset some of the variables
|
||||||
|
else if(frameCount%100 == 1 ) {
|
||||||
|
if(!Interceptor.isCleared){
|
||||||
|
var table = document.getElementById('textOutput-content-details');
|
||||||
|
Interceptor.getSummary(Interceptor.setupObject,Interceptor.drawObject,document.getElementById('textOutput-content-summary'));
|
||||||
|
Interceptor.populateTable(table,Interceptor.setupObject.objectArray.concat(Interceptor.drawObject.objectArray));
|
||||||
|
}
|
||||||
|
Interceptor.drawObject = Interceptor.clearVariables(Interceptor.drawObject);
|
||||||
|
}
|
||||||
|
return originalFunc.apply(this,arguments);
|
||||||
|
}
|
||||||
|
});
|
327
static/interceptor-functions.js
Normal file
327
static/interceptor-functions.js
Normal file
|
@ -0,0 +1,327 @@
|
||||||
|
String.prototype.paddingLeft = function (paddingValue) {
|
||||||
|
return String(paddingValue + this).slice(-paddingValue.length);
|
||||||
|
};
|
||||||
|
|
||||||
|
function MergeObjRecursive(obj1, obj2) {
|
||||||
|
var obj3 = {};
|
||||||
|
for(p in obj1) {
|
||||||
|
obj3[p] = obj1[p];
|
||||||
|
}
|
||||||
|
for(p in obj2) {
|
||||||
|
if(Object.keys(obj3).indexOf(p)<0){
|
||||||
|
obj3[p] = obj2[p];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
obj3[p] = obj3[p] + obj2[p];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Array.prototype.equals)
|
||||||
|
// attach the .equals method to Array's prototype to call it on any array
|
||||||
|
Array.prototype.equals = function (array) {
|
||||||
|
// if the other array is a falsy value, return
|
||||||
|
if (!array)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// compare lengths - can save a lot of time
|
||||||
|
if (this.length != array.length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (var i = 0, l=this.length; i < l; i++) {
|
||||||
|
// Check if we have nested arrays
|
||||||
|
if (this[i] instanceof Array && array[i] instanceof Array) {
|
||||||
|
// recurse into the nested arrays
|
||||||
|
if (!this[i].equals(array[i]))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (this[i] != array[i]) {
|
||||||
|
// Warning - two different object instances will never be equal: {x:20} != {x:20}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Hide method from for-in loops
|
||||||
|
Object.defineProperty(Array.prototype, "equals", {enumerable: false});
|
||||||
|
|
||||||
|
|
||||||
|
var Interceptor = {
|
||||||
|
prevTotalCount :0,
|
||||||
|
totalCount : 0,
|
||||||
|
currentColor : 'white',
|
||||||
|
bgColor : 'white',
|
||||||
|
canvasDetails : {
|
||||||
|
width : 0,
|
||||||
|
height: 0
|
||||||
|
},
|
||||||
|
setupObject : {
|
||||||
|
objectArray : [],
|
||||||
|
objectCount : 0,
|
||||||
|
objectTypeCount : {}
|
||||||
|
},
|
||||||
|
drawObject : {
|
||||||
|
objectArray : [],
|
||||||
|
objectCount : 0,
|
||||||
|
objectTypeCount : {}
|
||||||
|
},
|
||||||
|
isCleared : false,
|
||||||
|
getColorName : function(arguments) {
|
||||||
|
if(arguments.length==3) {
|
||||||
|
//assuming that we are doing RGB - convert RGB values to a name
|
||||||
|
var color = '#' + arguments[0].toString(16).paddingLeft("00") + arguments[1].toString(16).paddingLeft("00") + arguments[2].toString(16).paddingLeft("00");
|
||||||
|
var n_match = ntc.name(color);
|
||||||
|
return n_match[1];
|
||||||
|
}
|
||||||
|
else if(arguments.length==1) {
|
||||||
|
if(!(typeof(arguments[0])).localeCompare("number")) {
|
||||||
|
//assuming that we are doing RGB - this would be a grayscale number
|
||||||
|
if(arguments[0]<10) {
|
||||||
|
return 'black';
|
||||||
|
}
|
||||||
|
else if(arguments[0]>240) {
|
||||||
|
return 'white';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'grey';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(!(typeof(arguments[0])).localeCompare("string")) {
|
||||||
|
if(!arguments[0].charAt(0).localeCompare('#')) {
|
||||||
|
//if user has entered a hex color
|
||||||
|
var n_match = ntc.name(arguments[0]);
|
||||||
|
return n_match[1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return arguments[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
canvasLocator : function(arguments,canvasX,canvasY){
|
||||||
|
var x,y;
|
||||||
|
var isNum1 = false;
|
||||||
|
var isNum2 = false;
|
||||||
|
for(var i=0;i<arguments.length;i++) {
|
||||||
|
a = arguments[i];
|
||||||
|
if(!isNum1 && !isNum2 && !(typeof(a)).localeCompare('number')) {
|
||||||
|
x = a;
|
||||||
|
isNum1 = true;
|
||||||
|
} else if (isNum1 && !isNum2 && !(typeof(a)).localeCompare('number')) {
|
||||||
|
y = a;
|
||||||
|
isNum2 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(x<0.4*canvasX) {
|
||||||
|
if(y<0.4*canvasY) {
|
||||||
|
return 'top left';
|
||||||
|
}
|
||||||
|
else if(y>0.6*canvasY) {
|
||||||
|
return 'bottom left';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'mid left';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(x>0.6*canvasX) {
|
||||||
|
if(y<0.4*canvasY) {
|
||||||
|
return 'top right';
|
||||||
|
}
|
||||||
|
else if(y>0.6*canvasY) {
|
||||||
|
return 'bottom right';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'mid right';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(y<0.4*canvasY) {
|
||||||
|
return 'top middle';
|
||||||
|
}
|
||||||
|
else if(y>0.6*canvasY) {
|
||||||
|
return 'bottom middle';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'middle';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clearVariables : function(object) {
|
||||||
|
object.objectTypeCount = {};
|
||||||
|
object.objectCount = 0;
|
||||||
|
this.isCleared = true;
|
||||||
|
return object;
|
||||||
|
},
|
||||||
|
|
||||||
|
populateObject : function(x,arguments, object ,table, isDraw) {
|
||||||
|
objectCount = object.objectCount;
|
||||||
|
objectArray = object.objectArray;
|
||||||
|
objectTypeCount = object.objectTypeCount;
|
||||||
|
if(!isDraw) {
|
||||||
|
//check for special function in setup -> createCanvas
|
||||||
|
if(!x.name.localeCompare('createCanvas')) {
|
||||||
|
this.canvasDetails.width = arguments[0];
|
||||||
|
this.canvasDetails.height = arguments[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//check for speacial functions in general -> background/fill
|
||||||
|
if(!x.name.localeCompare('fill')) {
|
||||||
|
this.currentColor = this.getColorName(arguments);
|
||||||
|
}
|
||||||
|
else if(!x.name.localeCompare('background')) {
|
||||||
|
this.bgColor = this.getColorName(arguments);
|
||||||
|
}
|
||||||
|
else if(!x.module.localeCompare('Shape') || !x.module.localeCompare('Typography') &&((!x.submodule)||(x.submodule.localeCompare('Attributes')!=0)) ){
|
||||||
|
|
||||||
|
var canvasLocation = this.canvasLocator(arguments ,width,height);
|
||||||
|
|
||||||
|
objectArray[objectCount] = {
|
||||||
|
'type' : x.name,
|
||||||
|
'location': canvasLocation,
|
||||||
|
'colour': this.currentColor
|
||||||
|
};
|
||||||
|
//add the object(shape/text) parameters in objectArray
|
||||||
|
for(var i=0;i<arguments.length;i++) {
|
||||||
|
if(!(typeof(arguments[i])).localeCompare('number')){
|
||||||
|
arguments[i] = round(arguments[i]);
|
||||||
|
}
|
||||||
|
objectArray[objectCount][x.params[i].description.slice(3,-5)]=arguments[i];
|
||||||
|
}
|
||||||
|
if(objectTypeCount[x.name]) {
|
||||||
|
objectTypeCount[x.name]++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
objectTypeCount[x.name]=1;
|
||||||
|
}
|
||||||
|
//creating the table to contain the object(shape/text) details
|
||||||
|
|
||||||
|
objectCount++;
|
||||||
|
}
|
||||||
|
return ({
|
||||||
|
objectCount : objectCount,
|
||||||
|
objectArray : objectArray,
|
||||||
|
objectTypeCount : objectTypeCount
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
populateTable : function(table, objectArray) {
|
||||||
|
if(this.totalCount<20) {
|
||||||
|
if(this.prevTotalCount > this.totalCount) {
|
||||||
|
for(var j =0;j<this.totalCount;j++) {
|
||||||
|
var row = table.children[j];
|
||||||
|
var tempCol = row.children.length;
|
||||||
|
var properties = Object.keys(objectArray[j]);
|
||||||
|
|
||||||
|
if(tempCol<=properties.length){ //ie - there are more cols now
|
||||||
|
for(var i =0;i<tempCol;i++) {
|
||||||
|
row.children[i].innerHTML = properties[i] + ' : ' + objectArray[j][properties[i]];
|
||||||
|
}
|
||||||
|
for(var i=tempCol;i < properties.length;i++) {
|
||||||
|
var col = document.createElement('td');
|
||||||
|
col.innerHTML = properties[i] + ' : ' + objectArray[j][properties[i]];
|
||||||
|
row.appendChild(col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else{ // ie - there are fewer cols now
|
||||||
|
for(var i =0;i<properties.length;i++) {
|
||||||
|
row.children[i].innerHTML = properties[i] + ' : ' + objectArray[j][properties[i]];
|
||||||
|
}
|
||||||
|
for(var i=properties.length;i<tempCol;i++) {
|
||||||
|
var tempCol = row.children[i];
|
||||||
|
row.removeChild(tempCol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
for(var j = this.totalCount;j<this.prevTotalCount;j++) {
|
||||||
|
var tempRow = table.children[j];
|
||||||
|
table.removeChild(tempRow);
|
||||||
|
}
|
||||||
|
} else if(this.prevTotalCount <= this.totalCount) {
|
||||||
|
for(var j =0;j<this.prevTotalCount;j++) {
|
||||||
|
var row = table.children[j];
|
||||||
|
var tempCol = row.children.length;
|
||||||
|
var properties = Object.keys(objectArray[j]);
|
||||||
|
|
||||||
|
if(tempCol<=properties.length){ //ie - there are more cols now
|
||||||
|
for(var i =0;i<tempCol;i++) {
|
||||||
|
row.children[i].innerHTML = properties[i] + ' : ' + objectArray[j][properties[i]];
|
||||||
|
}
|
||||||
|
for(var i=tempCol;i < properties.length;i++) {
|
||||||
|
var col = document.createElement('td');
|
||||||
|
col.innerHTML = properties[i] + ' : ' + objectArray[j][properties[i]];
|
||||||
|
row.appendChild(col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else{ // ie - there are fewer cols now
|
||||||
|
for(var i =0;i<properties.length;i++) {
|
||||||
|
row.children[i].innerHTML = properties[i] + ' : ' + objectArray[j][properties[i]];
|
||||||
|
}
|
||||||
|
for(var i=properties.length;i<tempCol;i++) {
|
||||||
|
var tempCol = row.children[i];
|
||||||
|
row.removeChild(tempCol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(var j = this.prevTotalCount;j<this.totalCount;j++) {
|
||||||
|
var row = document.createElement('tr');
|
||||||
|
var properties = Object.keys(objectArray[j]);
|
||||||
|
for(var i =0;i<properties.length;i++) {
|
||||||
|
var col = document.createElement('td');
|
||||||
|
col.innerHTML = properties[i] + ' : ' + objectArray[j][properties[i]];
|
||||||
|
row.appendChild(col);
|
||||||
|
}
|
||||||
|
table.appendChild(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getSummary : function(object1, object2, element) {
|
||||||
|
this.prevTotalCount = this.totalCount;
|
||||||
|
this.totalCount = object1.objectCount + object2.objectCount;
|
||||||
|
element.innerHTML = '';
|
||||||
|
element.innerHTML += 'Canvas size is ' + this.canvasDetails.width + ' by ' + this.canvasDetails.height + ' pixels ';
|
||||||
|
element.innerHTML += ' and has a background colour of ' + this.bgColor + '. ';
|
||||||
|
element.innerHTML += 'This canvas contains ' + this.totalCount;
|
||||||
|
if(this.totalCount > 1 ) {
|
||||||
|
element.innerHTML += ' objects. The objects are ';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
element.innerHTML += ' object. The object is ';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(object2.objectCount>0 || object1.objectCount>0 ) {
|
||||||
|
|
||||||
|
totObjectTypeCount = MergeObjRecursive(object1.objectTypeCount, object2.objectTypeCount);
|
||||||
|
var keys = Object.keys(totObjectTypeCount);
|
||||||
|
for(var i=0;i<keys.length;i++) {
|
||||||
|
element.innerHTML += totObjectTypeCount[keys[i]] + ' ' + keys[i] + ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
element.innerHTML += "<br>";
|
||||||
|
if(this.totalCount<20){
|
||||||
|
for(var i=0; i <object1.objectArray.length; i++) {
|
||||||
|
var objKeys = Object.keys(object1.objectArray[i]);
|
||||||
|
for(var j=0;j<objKeys.length;j++) {
|
||||||
|
element.innerHTML += objKeys[j] + ' is ' + object1.objectArray[i][objKeys[j]] + ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(var i=0; i <object2.objectArray.length; i++) {
|
||||||
|
var objKeys = Object.keys(object2.objectArray[i]);
|
||||||
|
for(var j=0;j<objKeys.length;j++) {
|
||||||
|
element.innerHTML += objKeys[j] + ' is ' + object2.objectArray[i][objKeys[j]] + ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
18
static/loadData.js
Normal file
18
static/loadData.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
var allData;
|
||||||
|
function fetchJSONFile(path, callback) {
|
||||||
|
var httpRequest = new XMLHttpRequest();
|
||||||
|
httpRequest.onreadystatechange = function() {
|
||||||
|
if (httpRequest.readyState === 4) {
|
||||||
|
if (httpRequest.status === 200) {
|
||||||
|
var data = JSON.parse(httpRequest.responseText);
|
||||||
|
if (callback) callback(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
httpRequest.open('GET', path,false);
|
||||||
|
httpRequest.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchJSONFile('data.min.json', function(data){
|
||||||
|
allData = data;
|
||||||
|
});
|
2
static/ntc.min.js
vendored
Normal file
2
static/ntc.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue