Skip to content

Commit d361074

Browse files
authored
Merge branch 'develop' into autocomplete
2 parents d994594 + b3e49da commit d361074

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1917
-1265
lines changed

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ ML5_LIBRARY_PASS=helloml5
2222
MOBILE_ENABLED=true
2323
MONGO_URL=mongodb://localhost:27017/p5js-web-editor
2424
PORT=8000
25+
PREVIEW_PORT=8002
26+
EDITOR_URL=http://localhost:8000
27+
PREVIEW_URL=http://localhost:8002
2528
S3_BUCKET=<your-s3-bucket>
2629
S3_BUCKET_URL_BASE=<alt-for-s3-url>
2730
SESSION_SECRET=whatever_you_want_this_to_be_it_only_matters_for_production

client/index.integration.test.jsx

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ describe('index.jsx integration', () => {
139139
expect(
140140
screen.getByRole('heading', { name: /preview/i })
141141
).toBeInTheDocument();
142-
const preview = screen.getByRole('main', { name: /sketch output/i });
142+
const preview = screen.getByTitle(/sketch preview/i);
143143
expect(preview).toBeInTheDocument();
144144
});
145145

@@ -152,24 +152,27 @@ describe('index.jsx integration', () => {
152152
expect(screen.getByText('Sketch Files')).toBeInTheDocument();
153153
});
154154

155-
it('clicking on play updates the preview iframe with a srcdoc, stop clears it', () => {
156-
const playButton = screen.getByRole('button', {
157-
name: /play only visual sketch/i
158-
});
159-
const preview = screen.getByRole('main', { name: /sketch output/i });
160-
expect(preview.getAttribute('srcdoc')).toBeFalsy();
161-
act(() => {
162-
fireEvent.click(playButton);
163-
});
164-
165-
expect(preview.getAttribute('srcdoc')).toBeTruthy();
166-
167-
const stopButton = screen.getByRole('button', {
168-
name: /stop sketch/i
169-
});
170-
act(() => {
171-
fireEvent.click(stopButton);
172-
});
173-
expect(preview.getAttribute('srcdoc')).toMatch(/(^|")\s*($|")/);
174-
});
155+
// this test doesn't make sense anymore :/
156+
// how to fix it? could check if sketch gets sent to iframe
157+
// via postmessage or something
158+
// it('clicking on play updates the preview iframe with a srcdoc, stop clears it', () => {
159+
// const playButton = screen.getByRole('button', {
160+
// name: /play only visual sketch/i
161+
// });
162+
// const preview = screen.getByRole('main', { name: /sketch preview/i });
163+
// expect(preview.getAttribute('srcdoc')).toBeFalsy();
164+
// act(() => {
165+
// fireEvent.click(playButton);
166+
// });
167+
168+
// expect(preview.getAttribute('srcdoc')).toBeTruthy();
169+
170+
// const stopButton = screen.getByRole('button', {
171+
// name: /stop sketch/i
172+
// });
173+
// act(() => {
174+
// fireEvent.click(stopButton);
175+
// });
176+
// expect(preview.getAttribute('srcdoc')).toMatch(/(^|")\s*($|")/);
177+
// });
175178
});

client/modules/IDE/actions/ide.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as ActionTypes from '../../../constants';
22
import { clearConsole } from './console';
3+
import { dispatchMessage, MessageTypes } from '../../../utils/dispatcher';
34

45
export function startVisualSketch() {
56
return {
@@ -248,9 +249,23 @@ export function showRuntimeErrorWarning() {
248249
}
249250

250251
export function startSketch() {
251-
return (dispatch) => {
252+
return (dispatch, getState) => {
252253
dispatch(clearConsole());
253-
dispatch(startSketchAndRefresh());
254+
dispatch(startVisualSketch());
255+
dispatch(showRuntimeErrorWarning());
256+
const state = getState();
257+
dispatchMessage({
258+
type: MessageTypes.SKETCH,
259+
payload: {
260+
files: state.files,
261+
basePath: window.location.pathname,
262+
gridOutput: state.preferences.gridOutput,
263+
textOutput: state.preferences.textOutput
264+
}
265+
});
266+
dispatchMessage({
267+
type: MessageTypes.START
268+
});
254269
};
255270
}
256271

@@ -264,6 +279,9 @@ export function startAccessibleSketch() {
264279

265280
export function stopSketch() {
266281
return (dispatch) => {
282+
dispatchMessage({
283+
type: MessageTypes.STOP
284+
});
267285
dispatch(stopAccessibleOutput());
268286
dispatch(stopVisualSketch());
269287
};

client/modules/IDE/actions/preferences.js

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -159,24 +159,6 @@ export function setGridOutput(value) {
159159
};
160160
}
161161

162-
export function setSoundOutput(value) {
163-
return (dispatch, getState) => {
164-
dispatch({
165-
type: ActionTypes.SET_SOUND_OUTPUT,
166-
value
167-
});
168-
const state = getState();
169-
if (state.user.authenticated) {
170-
const formParams = {
171-
preferences: {
172-
soundOutput: value
173-
}
174-
};
175-
updatePreferences(formParams, dispatch);
176-
}
177-
};
178-
}
179-
180162
export function setTheme(value) {
181163
// return {
182164
// type: ActionTypes.SET_THEME,
@@ -225,7 +207,6 @@ export function setAllAccessibleOutput(value) {
225207
return (dispatch) => {
226208
dispatch(setTextOutput(value));
227209
dispatch(setGridOutput(value));
228-
dispatch(setSoundOutput(value));
229210
};
230211
}
231212

client/modules/IDE/actions/project.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export function setNewProject(project) {
5454
export function getProject(id, username) {
5555
return (dispatch, getState) => {
5656
dispatch(justOpenedProject());
57-
apiClient
57+
return apiClient
5858
.get(`/${username}/projects/${id}`)
5959
.then((response) => {
6060
dispatch(setProject(response.data));

client/modules/IDE/components/ConsoleInput.jsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import CodeMirror from 'codemirror';
44
import { Encode } from 'console-feed';
55

66
import RightArrowIcon from '../../../images/right-arrow.svg';
7-
import { dispatch } from '../../../utils/dispatcher';
7+
import { dispatchMessage, MessageTypes } from '../../../utils/dispatcher';
88

99
// heavily inspired by
1010
// https://github.com/codesandbox/codesandbox-client/blob/92a1131f4ded6f7d9c16945dc7c18aa97c8ada27/packages/app/src/app/components/Preview/DevTools/Console/Input/index.tsx
@@ -19,7 +19,8 @@ class ConsoleInput extends React.Component {
1919
}
2020

2121
componentDidMount() {
22-
this._cm = CodeMirror(this.codemirrorContainer, { // eslint-disable-line
22+
this._cm = CodeMirror(this.codemirrorContainer, {
23+
// eslint-disable-line
2324
theme: `p5-${this.props.theme}`,
2425
scrollbarStyle: null,
2526
keymap: 'sublime',
@@ -39,9 +40,12 @@ class ConsoleInput extends React.Component {
3940
{ log: Encode({ method: 'command', data: [value] }) }
4041
];
4142
const consoleEvent = [{ method: 'command', data: [value] }];
42-
dispatch({
43-
source: 'console',
44-
messages
43+
dispatchMessage({
44+
type: MessageTypes.EXECUTE,
45+
payload: {
46+
source: 'console',
47+
messages
48+
}
4549
});
4650
this.props.dispatchConsoleEvent(consoleEvent);
4751
cm.setValue('');

client/modules/IDE/components/Editor.jsx

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import babelParser from 'prettier/parser-babel';
88
import htmlParser from 'prettier/parser-html';
99
import cssParser from 'prettier/parser-postcss';
1010
import { withTranslation } from 'react-i18next';
11+
import StackTrace from 'stacktrace-js';
1112
import 'codemirror/mode/css/css';
1213
import 'codemirror/addon/selection/active-line';
1314
import 'codemirror/addon/lint/lint';
@@ -119,7 +120,6 @@ class Editor extends React.Component {
119120
styleSelectedText: true,
120121
lint: {
121122
onUpdateLinting: (annotations) => {
122-
this.props.hideRuntimeErrorWarning();
123123
this.updateLintingMessageAccessibility(annotations);
124124
},
125125
options: {
@@ -167,10 +167,11 @@ class Editor extends React.Component {
167167
'change',
168168
debounce(() => {
169169
this.props.setUnsavedChanges(true);
170+
this.props.hideRuntimeErrorWarning();
170171
this.props.updateFileContent(this.props.file.id, this._cm.getValue());
171172
if (this.props.autorefresh && this.props.isPlaying) {
172173
this.props.clearConsole();
173-
this.props.startRefreshSketch();
174+
this.props.startSketch();
174175
}
175176
}, 1000)
176177
);
@@ -259,41 +260,45 @@ class Editor extends React.Component {
259260
);
260261
}
261262

262-
if (prevProps.consoleEvents !== this.props.consoleEvents) {
263-
this.props.showRuntimeErrorWarning();
264-
}
265-
for (let i = 0; i < this._cm.lineCount(); i += 1) {
266-
this._cm.removeLineClass(i, 'background', 'line-runtime-error');
267-
}
268263
if (this.props.runtimeErrorWarningVisible) {
269-
this.props.consoleEvents.forEach((consoleEvent) => {
270-
if (consoleEvent.method === 'error') {
271-
if (
272-
consoleEvent.data &&
273-
consoleEvent.data[0] &&
274-
consoleEvent.data[0].indexOf &&
275-
consoleEvent.data[0].indexOf(')') > -1
276-
) {
277-
const n = consoleEvent.data[0].replace(')', '').split(' ');
278-
const lineNumber = parseInt(n[n.length - 1], 10) - 1;
279-
const { source } = consoleEvent;
280-
const fileName = this.props.file.name;
281-
const errorFromJavaScriptFile = `${source}.js` === fileName;
282-
const errorFromIndexHTML =
283-
source === fileName && fileName === 'index.html';
284-
if (
285-
!Number.isNaN(lineNumber) &&
286-
(errorFromJavaScriptFile || errorFromIndexHTML)
287-
) {
264+
if (this.props.consoleEvents.length !== prevProps.consoleEvents.length) {
265+
this.props.consoleEvents.forEach((consoleEvent) => {
266+
if (consoleEvent.method === 'error') {
267+
// It doesn't work if you create a new Error, but this works
268+
// LOL
269+
const errorObj = { stack: consoleEvent.data[0].toString() };
270+
StackTrace.fromError(errorObj).then((stackLines) => {
271+
this.props.expandConsole();
272+
const line = stackLines.find(
273+
(l) => l.fileName && l.fileName.startsWith('/')
274+
);
275+
if (!line) return;
276+
const fileNameArray = line.fileName.split('/');
277+
const fileName = fileNameArray.slice(-1)[0];
278+
const filePath = fileNameArray.slice(0, -1).join('/');
279+
const fileWithError = this.props.files.find(
280+
(f) => f.name === fileName && f.filePath === filePath
281+
);
282+
this.props.setSelectedFile(fileWithError.id);
288283
this._cm.addLineClass(
289-
lineNumber,
284+
line.lineNumber - 1,
290285
'background',
291286
'line-runtime-error'
292287
);
293-
}
288+
});
294289
}
290+
});
291+
} else {
292+
for (let i = 0; i < this._cm.lineCount(); i += 1) {
293+
this._cm.removeLineClass(i, 'background', 'line-runtime-error');
295294
}
296-
});
295+
}
296+
}
297+
298+
if (this.props.file.id !== prevProps.file.id) {
299+
for (let i = 0; i < this._cm.lineCount(); i += 1) {
300+
this._cm.removeLineClass(i, 'background', 'line-runtime-error');
301+
}
297302
}
298303
}
299304

@@ -486,7 +491,7 @@ Editor.propTypes = {
486491
method: PropTypes.string.isRequired,
487492
args: PropTypes.arrayOf(PropTypes.string)
488493
})
489-
),
494+
).isRequired,
490495
updateLintMessage: PropTypes.func.isRequired,
491496
clearLintMessage: PropTypes.func.isRequired,
492497
updateFileContent: PropTypes.func.isRequired,
@@ -499,7 +504,7 @@ Editor.propTypes = {
499504
url: PropTypes.string
500505
}).isRequired,
501506
setUnsavedChanges: PropTypes.func.isRequired,
502-
startRefreshSketch: PropTypes.func.isRequired,
507+
startSketch: PropTypes.func.isRequired,
503508
autorefresh: PropTypes.bool.isRequired,
504509
isPlaying: PropTypes.bool.isRequired,
505510
theme: PropTypes.string.isRequired,
@@ -517,15 +522,13 @@ Editor.propTypes = {
517522
expandSidebar: PropTypes.func.isRequired,
518523
isUserOwner: PropTypes.bool.isRequired,
519524
clearConsole: PropTypes.func.isRequired,
520-
showRuntimeErrorWarning: PropTypes.func.isRequired,
525+
// showRuntimeErrorWarning: PropTypes.func.isRequired,
521526
hideRuntimeErrorWarning: PropTypes.func.isRequired,
522527
runtimeErrorWarningVisible: PropTypes.bool.isRequired,
523528
provideController: PropTypes.func.isRequired,
524-
t: PropTypes.func.isRequired
525-
};
526-
527-
Editor.defaultProps = {
528-
consoleEvents: []
529+
t: PropTypes.func.isRequired,
530+
setSelectedFile: PropTypes.func.isRequired,
531+
expandConsole: PropTypes.func.isRequired
529532
};
530533

531534
function mapStateToProps(state) {
@@ -542,7 +545,7 @@ function mapStateToProps(state) {
542545
user: state.user,
543546
project: state.project,
544547
toast: state.toast,
545-
console: state.console,
548+
consoleEvents: state.console,
546549

547550
...state.preferences,
548551
...state.ide,

client/modules/IDE/components/Preferences/index.jsx

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -437,23 +437,6 @@ class Preferences extends React.Component {
437437
>
438438
{this.props.t('Preferences.TableText')}
439439
</label>
440-
<input
441-
type="checkbox"
442-
onChange={(event) => {
443-
this.props.setSoundOutput(event.target.checked);
444-
}}
445-
aria-label={this.props.t('Preferences.SoundOutputARIA')}
446-
name="sound output"
447-
id="sound-output-on"
448-
value="On"
449-
checked={this.props.soundOutput}
450-
/>
451-
<label
452-
htmlFor="sound-output-on"
453-
className="preference__option preference__canvas"
454-
>
455-
{this.props.t('Preferences.Sound')}
456-
</label>
457440
</div>
458441
</div>
459442
</TabPanel>
@@ -474,10 +457,8 @@ Preferences.propTypes = {
474457
setLinewrap: PropTypes.func.isRequired,
475458
textOutput: PropTypes.bool.isRequired,
476459
gridOutput: PropTypes.bool.isRequired,
477-
soundOutput: PropTypes.bool.isRequired,
478460
setTextOutput: PropTypes.func.isRequired,
479461
setGridOutput: PropTypes.func.isRequired,
480-
setSoundOutput: PropTypes.func.isRequired,
481462
lintWarning: PropTypes.bool.isRequired,
482463
setLintWarning: PropTypes.func.isRequired,
483464
theme: PropTypes.string.isRequired,

0 commit comments

Comments
 (0)