resolve mc
This commit is contained in:
commit
57b5f2f5bb
31 changed files with 9306 additions and 24591 deletions
24
.env.example
24
.env.example
|
@ -1,22 +1,22 @@
|
|||
API_URL=/api
|
||||
MONGO_URL=mongodb://localhost:27017/p5js-web-editor
|
||||
PORT=8000
|
||||
SESSION_SECRET=whatever_you_want_this_to_be_it_only_matters_for_production
|
||||
AWS_ACCESS_KEY=<your-aws-access-key>
|
||||
AWS_SECRET_KEY=<your-aws-secret-key>
|
||||
AWS_REGION=<your-aws-region>
|
||||
S3_BUCKET=<your-s3-bucket>
|
||||
AWS_SECRET_KEY=<your-aws-secret-key>
|
||||
EMAIL_SENDER=<transactional-email-sender>
|
||||
EMAIL_VERIFY_SECRET_TOKEN=whatever_you_want_this_to_be_it_only_matters_for_production
|
||||
EXAMPLE_USER_EMAIL=examples@p5js.org
|
||||
EXAMPLE_USER_PASSWORD=hellop5js
|
||||
GG_EXAMPLES_EMAIL=benedikt.gross@generative-gestaltung.de
|
||||
GG_EXAMPLES_PASS=generativedesign
|
||||
GG_EXAMPLES_USERNAME=generative-design
|
||||
GITHUB_ID=<your-github-client-id>
|
||||
GITHUB_SECRET=<your-github-client-secret>
|
||||
GOOGLE_ID=<your-google-client-id> (use google+ api)
|
||||
GOOGLE_SECRET=<your-google-client-secret> (use google+ api)
|
||||
MAILGUN_DOMAIN=<your-mailgun-domain>
|
||||
MAILGUN_KEY=<your-mailgun-api-key>
|
||||
EMAIL_SENDER=<transactional-email-sender>
|
||||
EMAIL_VERIFY_SECRET_TOKEN=whatever_you_want_this_to_be_it_only_matters_for_production
|
||||
MONGO_URL=mongodb://localhost:27017/p5js-web-editor
|
||||
PORT=8000
|
||||
S3_BUCKET=<your-s3-bucket>
|
||||
S3_BUCKET_URL_BASE=<alt-for-s3-url>
|
||||
EXAMPLE_USER_EMAIL=examples@p5js.org
|
||||
EXAMPLE_USER_PASSWORD=hellop5js
|
||||
GG_EXAMPLES_USERNAME=generative-design
|
||||
GG_EXAMPLES_PASS=generativedesign
|
||||
GG_EXAMPLES_EMAIL=benedikt.gross@generative-gestaltung.de
|
||||
SESSION_SECRET=whatever_you_want_this_to_be_it_only_matters_for_production
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
"no-console": 0,
|
||||
"no-alert": 0,
|
||||
"no-underscore-dangle": 0,
|
||||
"max-len": [1, 120, 2, {ignoreComments: true}],
|
||||
"max-len": [1, 120, 2, {"ignoreComments": true, "ignoreTemplateLiterals": true}],
|
||||
"quote-props": [1, "consistent-as-needed"],
|
||||
"no-unused-vars": [1, {"vars": "local", "args": "none"}],
|
||||
"consistent-return": ["error", { "treatUndefinedAsUnspecified": true }],
|
||||
|
|
1
.github/CODE_OF_CONDUCT.md
vendored
1
.github/CODE_OF_CONDUCT.md
vendored
|
@ -20,4 +20,5 @@ If you believe someone is violating the code of conduct, we ask that you report
|
|||
Participants asked to stop any harassing behavior are expected to comply immediately. If a participant engages in harassing behavior, the p5.js Team may take any action they deem appropriate, up to and including expulsion from all p5.js spaces and identification of the participant as a harasser to other p5.js members or the general public.
|
||||
|
||||
## Also
|
||||
|
||||
* You can read our [community statement](http://p5js.org/community/) on our website.
|
4
.github/CONTRIBUTING.md
vendored
4
.github/CONTRIBUTING.md
vendored
|
@ -7,7 +7,7 @@ Here are links to all the sections in this document:
|
|||
<!-- If you change any of the headings in this document, remember to update the table of contents. -->
|
||||
|
||||
- [Code of Conduct](#code-of-conduct)
|
||||
- [How Can I Contribute ?](#how-can-i-contribute?)
|
||||
- [How Can I Contribute?](#how-can-i-contribute)
|
||||
- [First Timers](#first-timers)
|
||||
- [Want something more challenging](#want-something-more-challenging)
|
||||
- [Feature Enhancement](#feature-enhancement)
|
||||
|
@ -73,5 +73,3 @@ Tips
|
|||
----
|
||||
|
||||
* If it seems difficult to summarize what your commit does, it may be because it includes several logical changes or bug fixes, and are better split up into several commits using `git add -p`.
|
||||
|
||||
|
||||
|
|
15
.github/ISSUE_TEMPLATE.md
vendored
15
.github/ISSUE_TEMPLATE.md
vendored
|
@ -1,23 +1,22 @@
|
|||
<!--
|
||||
Hi there! If you are here to report a bug, or to discuss a feature (new or existing), you can use the below template to get started quickly. Fill out all those parts which you're comfortable with, and delete the remaining ones.
|
||||
|
||||
To check any option, replace the "[ ]" with a "[x]". Be sure to check out how it looks in the Preview tab!
|
||||
|
||||
Feel free to remove any portion of the template that is not relevant for your issue.
|
||||
-->
|
||||
|
||||
#### Nature of issue?
|
||||
|
||||
- [ ] Found a bug
|
||||
- [ ] Existing feature enhancement
|
||||
- [ ] New feature request
|
||||
<!-- Select any one issue and delete the other two -->
|
||||
|
||||
- Found a bug
|
||||
- Existing feature enhancement
|
||||
- New feature request
|
||||
|
||||
<!-- If you found a bug, the following information might prove to be helpful for us. Simply remove whatever you can't determine/don't know. -->
|
||||
#### Details about the bug:
|
||||
|
||||
- Web browser and version: <!-- On Chrome/FireFox/Opera you can enter "about:" in the address bar to find out the version -->
|
||||
- Operating System: <!-- Ex: Windows/MacOSX/Linux along with version -->
|
||||
- Steps to reproduce this:
|
||||
- Steps to reproduce this bug:
|
||||
|
||||
<!-- Include a simple code snippet that demonstrates the problem, along with any console errors produced. If this isn't possible, then simply describe the issue as best you can! Feel free to link to the web editor or include pictures or a video. -->
|
||||
|
||||
<!-- If you want to enhance an existing feature, please describe here, otherwise remove this section -->
|
||||
|
|
10
.github/PULL_REQUEST_TEMPLATE.md
vendored
10
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -1,7 +1,5 @@
|
|||
Before your pull request is reviewed and merged, please ensure that:
|
||||
I have verified that this pull request:
|
||||
|
||||
* [ ] there are no linting errors -- `npm run lint`
|
||||
* [ ] your code is in a uniquely-named feature branch and has been rebased on top of the latest master. If you're asked to make more changes, make sure you rebase onto master then too!
|
||||
* [ ] your pull request is descriptively named and links to an issue number, i.e. `Fixes #123`
|
||||
|
||||
Thank you!
|
||||
* [ ] has no linting errors (`npm run lint`)
|
||||
* [ ] is from a uniquely-named feature branch and has been rebased on top of the latest master. (If I was asked to make more changes, I have made sure to rebase onto master then too)
|
||||
* [ ] is descriptively named and links to an issue number, i.e. `Fixes #123`
|
|
@ -1,7 +1,7 @@
|
|||
sudo: required
|
||||
language: node_js
|
||||
node_js:
|
||||
- "8.11.1"
|
||||
- "10.15.0"
|
||||
|
||||
cache:
|
||||
directories:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM node:8.11.1 as base
|
||||
FROM node:10.15.0 as base
|
||||
ENV APP_HOME=/usr/src/app \
|
||||
TERM=xterm
|
||||
RUN mkdir -p $APP_HOME
|
||||
|
|
1
Procfile
Normal file
1
Procfile
Normal file
|
@ -0,0 +1 @@
|
|||
web: MONGO_URL=$MONGO_URI MAILGUN_KEY=$MAILGUN_API_KEY npm run start:prod
|
93
app.json
Normal file
93
app.json
Normal file
|
@ -0,0 +1,93 @@
|
|||
{
|
||||
"name": "p5.js Web Editor",
|
||||
"description": "The p5.js Web Editor is an in-browser editor for creative coding, specifically for writing p5.js sketches.",
|
||||
"repository": "https://github.com/processing/p5.js-web-editor",
|
||||
"logo": "https://p5js.org/assets/img/p5js.svg",
|
||||
"keywords": ["processing", "p5js", "p5.js"],
|
||||
"addons": [
|
||||
{
|
||||
"plan": "mongolab:sandbox",
|
||||
"as": "MONGO"
|
||||
},
|
||||
{
|
||||
"plan": "mailgun:starter",
|
||||
"as": "MAILGUN"
|
||||
}
|
||||
],
|
||||
"env": {
|
||||
"API_URL": {
|
||||
"value": "/api"
|
||||
},
|
||||
"AWS_ACCESS_KEY": {
|
||||
"description": "AWS Access Key",
|
||||
"value": "placeholder"
|
||||
},
|
||||
"AWS_SECRET_KEY": {
|
||||
"description": "AWS Secret Key",
|
||||
"value": "placeholder"
|
||||
},
|
||||
"AWS_REGION": {
|
||||
"description": "AWS Region for the S3_BUCKET",
|
||||
"value": "placeholder"
|
||||
},
|
||||
"EMAIL_SENDER": {
|
||||
"description": "The sending email address for transactional emails.",
|
||||
"value": "no-reply@mydomain.com"
|
||||
},
|
||||
"EMAIL_VERIFY_SECRET_TOKEN": {
|
||||
"description": "A secret key for...? Not sure where used.",
|
||||
"generator": "secret"
|
||||
},
|
||||
"EXAMPLE_USER_EMAIL": {
|
||||
"description": "The email address for the account holding the default Example sketches",
|
||||
"value": "examples@p5js.org"
|
||||
},
|
||||
"EXAMPLE_USER_PASSWORD": {
|
||||
"value": "hellop5js"
|
||||
},
|
||||
"GG_EXAMPLES_EMAIL": {
|
||||
"description": "The email address for the account holding the Generative Design Example sketches",
|
||||
"value": "benedikt.gross@generative-gestaltung.de"
|
||||
},
|
||||
"GG_EXAMPLES_PASS": {
|
||||
"value": "generativedesign"
|
||||
},
|
||||
"GG_EXAMPLES_USERNAME": {
|
||||
"value": "generative-design"
|
||||
},
|
||||
"GITHUB_ID": {
|
||||
"description": "The GitHub Client Id for sign in with GitHub support",
|
||||
"value": "placeholder"
|
||||
},
|
||||
"GITHUB_SECRET": {
|
||||
"description": "The GitHub Client Secret",
|
||||
"value": "placeholder"
|
||||
},
|
||||
"GOOGLE_ID": {
|
||||
"description": "The Google Client Id for sign in with Google support",
|
||||
"value": "placeholder"
|
||||
},
|
||||
"GOOGLE_SECRET": {
|
||||
"description": "The Google Client Secret",
|
||||
"value": "placeholder"
|
||||
},
|
||||
"NODE_ENV": {
|
||||
"value": "production"
|
||||
},
|
||||
"S3_BUCKET": {
|
||||
"desription": "Name of the S3 bucket for asset storage",
|
||||
"value": "placeholder"
|
||||
},
|
||||
"S3_BUCKET_URL_BASE": {
|
||||
"description": "S3 bucket URL base",
|
||||
"required": false
|
||||
},
|
||||
"SESSION_SECRET": {
|
||||
"description": "A secret key for verifying the integrity of signed cookies.",
|
||||
"generator": "secret"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"postdeploy": "MONGO_URL=$MONGO_URI MAILGUN_KEY=$MAILGUN_API_KEY npm run fetch-examples:prod"
|
||||
}
|
||||
}
|
|
@ -8,9 +8,7 @@ import InlineSVG from 'react-inlinesvg';
|
|||
import classNames from 'classnames';
|
||||
import * as IDEActions from '../modules/IDE/actions/ide';
|
||||
|
||||
import {
|
||||
metaKeyName,
|
||||
} from '../utils/metaKey';
|
||||
import { metaKeyName, } from '../utils/metaKey';
|
||||
|
||||
const triangleUrl = require('../images/down-filled-triangle.svg');
|
||||
const logoUrl = require('../images/p5js-logo-small.svg');
|
||||
|
@ -221,6 +219,7 @@ class Nav extends React.PureComponent {
|
|||
Open
|
||||
</Link>
|
||||
</li> }
|
||||
{ __process.env.EXAMPLES_ENABLED &&
|
||||
<li className="nav__dropdown-item">
|
||||
<Link
|
||||
to="/p5/sketches"
|
||||
|
@ -230,7 +229,7 @@ class Nav extends React.PureComponent {
|
|||
>
|
||||
Examples
|
||||
</Link>
|
||||
</li>
|
||||
</li> }
|
||||
</ul>
|
||||
</li>
|
||||
<li className={navDropdownState.edit}>
|
||||
|
|
11
client/images/share.svg
Normal file
11
client/images/share.svg
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="100px" height="100px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
|
||||
<g>
|
||||
<path d="M77.202,60.609v12.399c0,2.08-1.681,3.761-3.761,3.761H25.761c-2.08,0-3.84-1.681-3.84-3.761v-35.44
|
||||
c0-2.16,1.76-3.84,3.84-3.84h14.64v5.76h-12.72v31.521h43.761V60.609H77.202z M60.002,37.248l-2.801-11.36l22.161,16.4
|
||||
L57.201,57.809l2.801-11.28c0,0-16.241-0.24-16.881,16.72h-2.88C40.241,63.248,40.001,38.368,60.002,37.248z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 828 B |
|
@ -5,10 +5,12 @@ import each from 'async/each';
|
|||
import { isEqual, pick } from 'lodash';
|
||||
import * as ActionTypes from '../../../constants';
|
||||
import { showToast, setToastText } from './toast';
|
||||
import { setUnsavedChanges,
|
||||
import {
|
||||
setUnsavedChanges,
|
||||
justOpenedProject,
|
||||
resetJustOpenedProject,
|
||||
showErrorModal } from './ide';
|
||||
showErrorModal
|
||||
} from './ide';
|
||||
import { clearState, saveState } from '../../../persistState';
|
||||
|
||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Clipboard from 'clipboard';
|
||||
import InlineSVG from 'react-inlinesvg';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import shareUrl from '../../../images/share.svg';
|
||||
|
||||
class CopyableInput extends React.Component {
|
||||
constructor(props) {
|
||||
|
@ -34,8 +38,12 @@ class CopyableInput extends React.Component {
|
|||
value,
|
||||
hasPreviewLink
|
||||
} = this.props;
|
||||
const copyableInputClass = classNames({
|
||||
'copyable-input': true,
|
||||
'copyable-input--with-preview': hasPreviewLink
|
||||
});
|
||||
return (
|
||||
<div className="copyable-input">
|
||||
<div className={copyableInputClass}>
|
||||
<div
|
||||
className="copyable-input__value-container tooltipped-no-delay"
|
||||
aria-label="Copied to Clipboard!"
|
||||
|
@ -44,10 +52,7 @@ class CopyableInput extends React.Component {
|
|||
>
|
||||
<label className="copyable-input__label" htmlFor={`copyable-input__value-${label}`}>
|
||||
<div className="copyable-input__label-container">
|
||||
{label} {hasPreviewLink &&
|
||||
<a target="_blank" href={value}>
|
||||
Open
|
||||
</a>}
|
||||
{label}
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
|
@ -59,6 +64,17 @@ class CopyableInput extends React.Component {
|
|||
/>
|
||||
</label>
|
||||
</div>
|
||||
{hasPreviewLink &&
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={value}
|
||||
className="copyable-input__preview"
|
||||
title={`open ${label.toLowerCase()} view in new tab`}
|
||||
>
|
||||
<InlineSVG src={shareUrl} alt={`open ${label} view in new tab`} />
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -32,9 +32,7 @@ import '../../../utils/p5-javascript';
|
|||
import '../../../utils/webGL-clike';
|
||||
import Timer from '../components/Timer';
|
||||
import EditorAccessibility from '../components/EditorAccessibility';
|
||||
import {
|
||||
metaKey,
|
||||
} from '../../../utils/metaKey';
|
||||
import { metaKey, } from '../../../utils/metaKey';
|
||||
|
||||
import search from '../../../utils/codemirror-search';
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
metaKeyName,
|
||||
} from '../../../utils/metaKey';
|
||||
import { metaKeyName, } from '../../../utils/metaKey';
|
||||
|
||||
function KeyboardShortcutModal() {
|
||||
return (
|
||||
|
|
|
@ -81,7 +81,10 @@ class PreviewFrame extends React.Component {
|
|||
|
||||
handleConsoleEvent(messageEvent) {
|
||||
if (Array.isArray(messageEvent.data)) {
|
||||
const decodedMessages = messageEvent.data.map(message => Object.assign(Decode(message.log), { source: message.source }));
|
||||
const decodedMessages = messageEvent.data.map(message =>
|
||||
Object.assign(Decode(message.log), {
|
||||
source: message.source
|
||||
}));
|
||||
|
||||
decodedMessages.every((message, index, arr) => {
|
||||
const { data: args } = message;
|
||||
|
|
|
@ -19,6 +19,11 @@ class ShareModal extends React.PureComponent {
|
|||
label="Embed"
|
||||
value={`<iframe src="${hostname}/${ownerUsername}/embed/${projectId}"></iframe>`}
|
||||
/>
|
||||
<CopyableInput
|
||||
label="Present"
|
||||
hasPreviewLink
|
||||
value={`${hostname}/${ownerUsername}/present/${projectId}`}
|
||||
/>
|
||||
<CopyableInput
|
||||
label="Fullscreen"
|
||||
hasPreviewLink
|
||||
|
@ -26,6 +31,7 @@ class ShareModal extends React.PureComponent {
|
|||
/>
|
||||
<CopyableInput
|
||||
label="Edit"
|
||||
hasPreviewLink
|
||||
value={`${hostname}/${ownerUsername}/sketches/${projectId}`}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -87,11 +87,17 @@
|
|||
border-color: getThemifyVariable('button-background-hover-color');
|
||||
background-color: getThemifyVariable('button-background-hover-color');
|
||||
color: getThemifyVariable('button-hover-color');
|
||||
& g {
|
||||
fill: getThemifyVariable('button-hover-color');
|
||||
}
|
||||
}
|
||||
&:enabled:active {
|
||||
border-color: getThemifyVariable('button-background-active-color');
|
||||
background-color: getThemifyVariable('button-background-active-color');
|
||||
color: getThemifyVariable('button-active-color');
|
||||
& g {
|
||||
fill: getThemifyVariable('button-active-color');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
.copyable-input__value {
|
||||
width: 100%;
|
||||
font-size: #{16 / $base-font-size}rem;
|
||||
.copyable-input--with-preview & {
|
||||
border-radius: 2px 0 0 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.copyable-input__label {
|
||||
|
@ -32,7 +35,6 @@
|
|||
.copyable-input {
|
||||
padding-bottom: #{30 / $base-font-size}rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.copyable-input__value-container {
|
||||
|
@ -56,3 +58,16 @@
|
|||
border-top-color: getThemifyVariable('button-background-hover-color');
|
||||
}
|
||||
}
|
||||
|
||||
.copyable-input__preview {
|
||||
@extend %button;
|
||||
@include themify() {
|
||||
align-self: flex-end;
|
||||
border-radius: 0 2px 2px 0;
|
||||
padding: #{2 / $base-font-size}rem 0;
|
||||
}
|
||||
& svg {
|
||||
height: #{30 / $base-font-size}rem;
|
||||
width: #{30 / $base-font-size}rem;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import {
|
||||
EXTERNAL_LINK_REGEX
|
||||
} from '../../server/utils/fileUtils';
|
||||
import { EXTERNAL_LINK_REGEX } from '../../server/utils/fileUtils';
|
||||
|
||||
export const hijackConsoleErrorsScript = (offs) => {
|
||||
const s = `
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
/* eslint-disable */
|
||||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||
|
||||
/*eslint-disable*/
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("codemirror"));
|
||||
|
@ -12,11 +12,6 @@
|
|||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
function expressionAllowed(stream, state, backUp) {
|
||||
return /^(?:operator|sof|keyword c|case|new|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
|
||||
(state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
|
||||
}
|
||||
|
||||
CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit;
|
||||
var statementIndent = parserConfig.statementIndent;
|
||||
|
@ -26,13 +21,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
|
||||
|
||||
// Tokenizer
|
||||
|
||||
var keywords = function(){
|
||||
function kw(type) {return {type: type, style: "keyword"};}
|
||||
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
|
||||
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
|
||||
var p5Function = {type: "p5-function", style: "p5-function"};
|
||||
var p5Variable = {type: "p5-variable", style: "p5-variable"};
|
||||
var p5Function = {type: "variable", style: "p5-function"};
|
||||
var p5Variable = {type: "variable", style: "p5-variable"};
|
||||
|
||||
var jsKeywords = {
|
||||
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
|
||||
|
@ -151,7 +145,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
return jsKeywords;
|
||||
}();
|
||||
|
||||
var isOperatorChar = /[+\-*&%=<>!?|~^]/;
|
||||
var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
|
||||
var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
|
||||
|
||||
function readRegexp(stream) {
|
||||
|
@ -186,17 +180,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
return ret(ch);
|
||||
} else if (ch == "=" && stream.eat(">")) {
|
||||
return ret("=>", "operator");
|
||||
} else if (ch == "0" && stream.eat(/x/i)) {
|
||||
stream.eatWhile(/[\da-f]/i);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "0" && stream.eat(/o/i)) {
|
||||
stream.eatWhile(/[0-7]/i);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "0" && stream.eat(/b/i)) {
|
||||
stream.eatWhile(/[01]/i);
|
||||
} else if (ch == "0" && stream.match(/^(?:x[\da-f]+|o[0-7]+|b[01]+)n?/i)) {
|
||||
return ret("number", "number");
|
||||
} else if (/\d/.test(ch)) {
|
||||
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
|
||||
stream.match(/^\d*(?:n|(?:\.\d*)?(?:[eE][+\-]?\d+)?)?/);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "/") {
|
||||
if (stream.eat("*")) {
|
||||
|
@ -207,10 +194,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
return ret("comment", "comment");
|
||||
} else if (expressionAllowed(stream, state, 1)) {
|
||||
readRegexp(stream);
|
||||
stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
|
||||
stream.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/);
|
||||
return ret("regexp", "string-2");
|
||||
} else {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
stream.eat("=");
|
||||
return ret("operator", "operator", stream.current());
|
||||
}
|
||||
} else if (ch == "`") {
|
||||
|
@ -220,13 +207,27 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
stream.skipToEnd();
|
||||
return ret("error", "error");
|
||||
} else if (isOperatorChar.test(ch)) {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
if (ch != ">" || !state.lexical || state.lexical.type != ">") {
|
||||
if (stream.eat("=")) {
|
||||
if (ch == "!" || ch == "=") stream.eat("=")
|
||||
} else if (/[<>*+\-]/.test(ch)) {
|
||||
stream.eat(ch)
|
||||
if (ch == ">") stream.eat(ch)
|
||||
}
|
||||
}
|
||||
return ret("operator", "operator", stream.current());
|
||||
} else if (wordRE.test(ch)) {
|
||||
stream.eatWhile(wordRE);
|
||||
var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
|
||||
return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
|
||||
ret("variable", "variable", word);
|
||||
var word = stream.current()
|
||||
if (state.lastType != ".") {
|
||||
if (keywords.propertyIsEnumerable(word)) {
|
||||
var kw = keywords[word]
|
||||
return ret(kw.type, kw.style, word)
|
||||
}
|
||||
if (word == "async" && stream.match(/^(\s|\/\*.*?\*\/)*[\[\(\w]/, false))
|
||||
return ret("async", "keyword", word)
|
||||
}
|
||||
return ret("variable", "variable", word)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -362,35 +363,69 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
pass.apply(null, arguments);
|
||||
return true;
|
||||
}
|
||||
function register(varname) {
|
||||
function inList(list) {
|
||||
for (var v = list; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
function inList(name, list) {
|
||||
for (var v = list; v; v = v.next) if (v.name == name) return true
|
||||
return false;
|
||||
}
|
||||
function register(varname) {
|
||||
var state = cx.state;
|
||||
cx.marked = "def";
|
||||
if (state.context) {
|
||||
if (inList(state.localVars)) return;
|
||||
state.localVars = {name: varname, next: state.localVars};
|
||||
} else {
|
||||
if (inList(state.globalVars)) return;
|
||||
if (parserConfig.globalVars)
|
||||
state.globalVars = {name: varname, next: state.globalVars};
|
||||
if (state.lexical.info == "var" && state.context && state.context.block) {
|
||||
// FIXME function decls are also not block scoped
|
||||
var newContext = registerVarScoped(varname, state.context)
|
||||
if (newContext != null) {
|
||||
state.context = newContext
|
||||
return
|
||||
}
|
||||
} else if (!inList(varname, state.localVars)) {
|
||||
state.localVars = new Var(varname, state.localVars)
|
||||
return
|
||||
}
|
||||
}
|
||||
window.register = register;
|
||||
// Fall through means this is global
|
||||
if (parserConfig.globalVars && !inList(varname, state.globalVars))
|
||||
state.globalVars = new Var(varname, state.globalVars)
|
||||
}
|
||||
function registerVarScoped(varname, context) {
|
||||
if (!context) {
|
||||
return null
|
||||
} else if (context.block) {
|
||||
var inner = registerVarScoped(varname, context.prev)
|
||||
if (!inner) return null
|
||||
if (inner == context.prev) return context
|
||||
return new Context(inner, context.vars, true)
|
||||
} else if (inList(varname, context.vars)) {
|
||||
return context
|
||||
} else {
|
||||
return new Context(context.prev, new Var(varname, context.vars), false)
|
||||
}
|
||||
}
|
||||
|
||||
function isModifier(name) {
|
||||
return name == "public" || name == "private" || name == "protected" || name == "abstract" || name == "readonly"
|
||||
}
|
||||
|
||||
// Combinators
|
||||
|
||||
var defaultVars = {name: "this", next: {name: "arguments"}};
|
||||
function Context(prev, vars, block) { this.prev = prev; this.vars = vars; this.block = block }
|
||||
function Var(name, next) { this.name = name; this.next = next }
|
||||
|
||||
var defaultVars = new Var("this", new Var("arguments", null))
|
||||
function pushcontext() {
|
||||
cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
|
||||
cx.state.localVars = defaultVars;
|
||||
cx.state.context = new Context(cx.state.context, cx.state.localVars, false)
|
||||
cx.state.localVars = defaultVars
|
||||
}
|
||||
function pushblockcontext() {
|
||||
cx.state.context = new Context(cx.state.context, cx.state.localVars, true)
|
||||
cx.state.localVars = null
|
||||
}
|
||||
function popcontext() {
|
||||
cx.state.localVars = cx.state.context.vars;
|
||||
cx.state.context = cx.state.context.prev;
|
||||
cx.state.localVars = cx.state.context.vars
|
||||
cx.state.context = cx.state.context.prev
|
||||
}
|
||||
popcontext.lex = true
|
||||
function pushlex(type, info) {
|
||||
var result = function() {
|
||||
var state = cx.state, indent = state.indented;
|
||||
|
@ -415,17 +450,19 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
function expect(wanted) {
|
||||
function exp(type) {
|
||||
if (type == wanted) return cont();
|
||||
else if (wanted == ";") return pass();
|
||||
else if (wanted == ";" || type == "}" || type == ")" || type == "]") return pass();
|
||||
else return cont(exp);
|
||||
};
|
||||
return exp;
|
||||
}
|
||||
|
||||
function statement(type, value) {
|
||||
if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
|
||||
if (type == "var") return cont(pushlex("vardef", value), vardef, expect(";"), poplex);
|
||||
if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex);
|
||||
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
|
||||
if (type == "{") return cont(pushlex("}"), block, poplex);
|
||||
if (type == "keyword d") return cx.stream.match(/^\s*$/, false) ? cont() : cont(pushlex("stat"), maybeexpression, expect(";"), poplex);
|
||||
if (type == "debugger") return cont(expect(";"));
|
||||
if (type == "{") return cont(pushlex("}"), pushblockcontext, block, poplex, popcontext);
|
||||
if (type == ";") return cont();
|
||||
if (type == "if") {
|
||||
if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
|
||||
|
@ -434,59 +471,78 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
}
|
||||
if (type == "function") return cont(functiondef);
|
||||
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
|
||||
if (type == "variable") return cont(pushlex("stat"), maybelabel);
|
||||
if (type == "switch") return cont(pushlex("form"), parenExpr, pushlex("}", "switch"), expect("{"),
|
||||
block, poplex, poplex);
|
||||
if (type == "class" || (isTS && value == "interface")) {
|
||||
cx.marked = "keyword"
|
||||
return cont(pushlex("form", type == "class" ? type : value), className, poplex)
|
||||
}
|
||||
if (type == "variable") {
|
||||
if (isTS && value == "declare") {
|
||||
cx.marked = "keyword"
|
||||
return cont(statement)
|
||||
} else if (isTS && (value == "module" || value == "enum" || value == "type") && cx.stream.match(/^\s*\w/, false)) {
|
||||
cx.marked = "keyword"
|
||||
if (value == "enum") return cont(enumdef);
|
||||
else if (value == "type") return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
|
||||
else return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
|
||||
} else if (isTS && value == "namespace") {
|
||||
cx.marked = "keyword"
|
||||
return cont(pushlex("form"), expression, statement, poplex)
|
||||
} else if (isTS && value == "abstract") {
|
||||
cx.marked = "keyword"
|
||||
return cont(statement)
|
||||
} else {
|
||||
return cont(pushlex("stat"), maybelabel);
|
||||
}
|
||||
}
|
||||
if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"), pushblockcontext,
|
||||
block, poplex, poplex, popcontext);
|
||||
if (type == "case") return cont(expression, expect(":"));
|
||||
if (type == "default") return cont(expect(":"));
|
||||
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
|
||||
statement, poplex, popcontext);
|
||||
if (type == "class") return cont(pushlex("form"), className, poplex);
|
||||
if (type == "catch") return cont(pushlex("form"), pushcontext, maybeCatchBinding, statement, poplex, popcontext);
|
||||
if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
|
||||
if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
|
||||
if (type == "module") return cont(pushlex("form"), pattern, pushlex("}"), expect("{"), block, poplex, poplex)
|
||||
if (type == "type") return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
|
||||
if (type == "async") return cont(statement)
|
||||
if (value == "@") return cont(expression, statement)
|
||||
return pass(pushlex("stat"), expression, expect(";"), poplex);
|
||||
}
|
||||
function expression(type) {
|
||||
return expressionInner(type, false);
|
||||
function maybeCatchBinding(type) {
|
||||
if (type == "(") return cont(funarg, expect(")"))
|
||||
}
|
||||
function expressionNoComma(type) {
|
||||
return expressionInner(type, true);
|
||||
function expression(type, value) {
|
||||
return expressionInner(type, value, false);
|
||||
}
|
||||
function expressionNoComma(type, value) {
|
||||
return expressionInner(type, value, true);
|
||||
}
|
||||
function parenExpr(type) {
|
||||
if (type != "(") return pass()
|
||||
return cont(pushlex(")"), expression, expect(")"), poplex)
|
||||
}
|
||||
function expressionInner(type, noComma) {
|
||||
function expressionInner(type, value, noComma) {
|
||||
if (cx.state.fatArrowAt == cx.stream.start) {
|
||||
var body = noComma ? arrowBodyNoComma : arrowBody;
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext);
|
||||
else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
|
||||
}
|
||||
|
||||
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
|
||||
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
|
||||
if (type == "function") return cont(functiondef, maybeop);
|
||||
if (type == "class") return cont(pushlex("form"), classExpression, poplex);
|
||||
if (type == "keyword c" || type == "async") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
|
||||
if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), classExpression, poplex); }
|
||||
if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression);
|
||||
if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
|
||||
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
|
||||
if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
|
||||
if (type == "{") return contCommasep(objprop, "}", null, maybeop);
|
||||
if (type == "quasi") return pass(quasi, maybeop);
|
||||
if (type == "new") return cont(maybeTarget(noComma));
|
||||
if (type == "import") return cont(expression);
|
||||
return cont();
|
||||
}
|
||||
function maybeexpression(type) {
|
||||
if (type.match(/[;\}\)\],]/)) return pass();
|
||||
return pass(expression);
|
||||
}
|
||||
function maybeexpressionNoComma(type) {
|
||||
if (type.match(/[;\}\)\],]/)) return pass();
|
||||
return pass(expressionNoComma);
|
||||
}
|
||||
|
||||
function maybeoperatorComma(type, value) {
|
||||
if (type == ",") return cont(expression);
|
||||
|
@ -497,7 +553,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
var expr = noComma == false ? expression : expressionNoComma;
|
||||
if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
|
||||
if (type == "operator") {
|
||||
if (/\+\+|--/.test(value)) return cont(me);
|
||||
if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me);
|
||||
if (isTS && value == "<" && cx.stream.match(/^([^>]|<.*?>)*>\s*\(/, false))
|
||||
return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, me);
|
||||
if (value == "?") return cont(expression, expect(":"), expr);
|
||||
return cont(expr);
|
||||
}
|
||||
|
@ -506,6 +564,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
|
||||
if (type == ".") return cont(property, me);
|
||||
if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
|
||||
if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) }
|
||||
if (type == "regexp") {
|
||||
cx.state.lastType = cx.marked = "operator"
|
||||
cx.stream.backUp(cx.stream.pos - cx.stream.start - 1)
|
||||
return cont(expr)
|
||||
}
|
||||
}
|
||||
function quasi(type, value) {
|
||||
if (type != "quasi") return pass();
|
||||
|
@ -530,6 +594,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
function maybeTarget(noComma) {
|
||||
return function(type) {
|
||||
if (type == ".") return cont(noComma ? targetNoComma : target);
|
||||
else if (type == "variable" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma)
|
||||
else return pass(noComma ? expressionNoComma : expression);
|
||||
};
|
||||
}
|
||||
|
@ -553,18 +618,25 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
} else if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property";
|
||||
if (value == "get" || value == "set") return cont(getterSetter);
|
||||
var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params
|
||||
if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false)))
|
||||
cx.state.fatArrowAt = cx.stream.pos + m[0].length
|
||||
return cont(afterprop);
|
||||
} else if (type == "number" || type == "string") {
|
||||
cx.marked = jsonldMode ? "property" : (cx.style + " property");
|
||||
return cont(afterprop);
|
||||
} else if (type == "jsonld-keyword") {
|
||||
return cont(afterprop);
|
||||
} else if (type == "modifier") {
|
||||
} else if (isTS && isModifier(value)) {
|
||||
cx.marked = "keyword"
|
||||
return cont(objprop)
|
||||
} else if (type == "[") {
|
||||
return cont(expression, expect("]"), afterprop);
|
||||
return cont(expression, maybetype, expect("]"), afterprop);
|
||||
} else if (type == "spread") {
|
||||
return cont(expression);
|
||||
return cont(expressionNoComma, afterprop);
|
||||
} else if (value == "*") {
|
||||
cx.marked = "keyword";
|
||||
return cont(objprop);
|
||||
} else if (type == ":") {
|
||||
return pass(afterprop)
|
||||
}
|
||||
|
@ -578,9 +650,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
if (type == ":") return cont(expressionNoComma);
|
||||
if (type == "(") return pass(functiondef);
|
||||
}
|
||||
function commasep(what, end) {
|
||||
function commasep(what, end, sep) {
|
||||
function proceed(type, value) {
|
||||
if (type == ",") {
|
||||
if (sep ? sep.indexOf(type) > -1 : type == ",") {
|
||||
var lex = cx.state.lexical;
|
||||
if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
|
||||
return cont(function(type, value) {
|
||||
|
@ -589,6 +661,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
}, proceed);
|
||||
}
|
||||
if (type == end || value == end) return cont();
|
||||
if (sep && sep.indexOf(";") > -1) return pass(what)
|
||||
return cont(expect(end));
|
||||
}
|
||||
return function(type, value) {
|
||||
|
@ -611,38 +684,79 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
if (value == "?") return cont(maybetype);
|
||||
}
|
||||
}
|
||||
function typeexpr(type) {
|
||||
if (type == "variable") {cx.marked = "variable-3"; return cont(afterType);}
|
||||
if (type == "{") return cont(commasep(typeprop, "}"))
|
||||
function mayberettype(type) {
|
||||
if (isTS && type == ":") {
|
||||
if (cx.stream.match(/^\s*\w+\s+is\b/, false)) return cont(expression, isKW, typeexpr)
|
||||
else return cont(typeexpr)
|
||||
}
|
||||
}
|
||||
function isKW(_, value) {
|
||||
if (value == "is") {
|
||||
cx.marked = "keyword"
|
||||
return cont()
|
||||
}
|
||||
}
|
||||
function typeexpr(type, value) {
|
||||
if (value == "keyof" || value == "typeof") {
|
||||
cx.marked = "keyword"
|
||||
return cont(value == "keyof" ? typeexpr : expressionNoComma)
|
||||
}
|
||||
if (type == "variable" || value == "void") {
|
||||
cx.marked = "type"
|
||||
return cont(afterType)
|
||||
}
|
||||
if (type == "string" || type == "number" || type == "atom") return cont(afterType);
|
||||
if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType)
|
||||
if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType)
|
||||
if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType)
|
||||
if (type == "<") return cont(commasep(typeexpr, ">"), typeexpr)
|
||||
}
|
||||
function maybeReturnType(type) {
|
||||
if (type == "=>") return cont(typeexpr)
|
||||
}
|
||||
function typeprop(type) {
|
||||
function typeprop(type, value) {
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property"
|
||||
return cont(typeprop)
|
||||
} else if (value == "?") {
|
||||
return cont(typeprop)
|
||||
} else if (type == ":") {
|
||||
return cont(typeexpr)
|
||||
} else if (type == "[") {
|
||||
return cont(expression, maybetype, expect("]"), typeprop)
|
||||
} else if (type == "(") {
|
||||
return cont(pushlex(")"), commasep(funarg, ")"), poplex, typeprop)
|
||||
}
|
||||
}
|
||||
function typearg(type) {
|
||||
if (type == "variable") return cont(typearg)
|
||||
else if (type == ":") return cont(typeexpr)
|
||||
function typearg(type, value) {
|
||||
if (type == "variable" && cx.stream.match(/^\s*[?:]/, false) || value == "?") return cont(typearg)
|
||||
if (type == ":") return cont(typeexpr)
|
||||
return pass(typeexpr)
|
||||
}
|
||||
function afterType(type, value) {
|
||||
if (value == "<") return cont(commasep(typeexpr, ">"), afterType)
|
||||
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
|
||||
if (value == "|" || type == "." || value == "&") return cont(typeexpr)
|
||||
if (type == "[") return cont(expect("]"), afterType)
|
||||
if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) }
|
||||
}
|
||||
function vardef() {
|
||||
function maybeTypeArgs(_, value) {
|
||||
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
|
||||
}
|
||||
function typeparam() {
|
||||
return pass(typeexpr, maybeTypeDefault)
|
||||
}
|
||||
function maybeTypeDefault(_, value) {
|
||||
if (value == "=") return cont(typeexpr)
|
||||
}
|
||||
function vardef(_, value) {
|
||||
if (value == "enum") {cx.marked = "keyword"; return cont(enumdef)}
|
||||
return pass(pattern, maybetype, maybeAssign, vardefCont);
|
||||
}
|
||||
function pattern(type, value) {
|
||||
if (type == "modifier") return cont(pattern)
|
||||
if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(pattern) }
|
||||
if (type == "variable") { register(value); return cont(); }
|
||||
if (type == "spread") return cont(pattern);
|
||||
if (type == "[") return contCommasep(pattern, "]");
|
||||
if (type == "[") return contCommasep(eltpattern, "]");
|
||||
if (type == "{") return contCommasep(proppattern, "}");
|
||||
}
|
||||
function proppattern(type, value) {
|
||||
|
@ -653,8 +767,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
if (type == "variable") cx.marked = "property";
|
||||
if (type == "spread") return cont(pattern);
|
||||
if (type == "}") return pass();
|
||||
if (type == "[") return cont(expression, expect(']'), expect(':'), proppattern);
|
||||
return cont(expect(":"), pattern, maybeAssign);
|
||||
}
|
||||
function eltpattern() {
|
||||
return pass(pattern, maybeAssign)
|
||||
}
|
||||
function maybeAssign(_type, value) {
|
||||
if (value == "=") return cont(expressionNoComma);
|
||||
}
|
||||
|
@ -664,7 +782,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
function maybeelse(type, value) {
|
||||
if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
|
||||
}
|
||||
function forspec(type) {
|
||||
function forspec(type, value) {
|
||||
if (value == "await") return cont(forspec);
|
||||
if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
|
||||
}
|
||||
function forspec1(type) {
|
||||
|
@ -688,10 +807,19 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
function functiondef(type, value) {
|
||||
if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
|
||||
if (type == "variable") {register(value); return cont(functiondef);}
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext);
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, statement, popcontext);
|
||||
if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondef)
|
||||
}
|
||||
function funarg(type) {
|
||||
function functiondecl(type, value) {
|
||||
if (value == "*") {cx.marked = "keyword"; return cont(functiondecl);}
|
||||
if (type == "variable") {register(value); return cont(functiondecl);}
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, popcontext);
|
||||
if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondecl)
|
||||
}
|
||||
function funarg(type, value) {
|
||||
if (value == "@") cont(expression, funarg)
|
||||
if (type == "spread") return cont(funarg);
|
||||
if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); }
|
||||
return pass(pattern, maybetype, maybeAssign);
|
||||
}
|
||||
function classExpression(type, value) {
|
||||
|
@ -703,40 +831,56 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
if (type == "variable") {register(value); return cont(classNameAfter);}
|
||||
}
|
||||
function classNameAfter(type, value) {
|
||||
if (value == "extends" || value == "implements") return cont(isTS ? typeexpr : expression, classNameAfter);
|
||||
if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter)
|
||||
if (value == "extends" || value == "implements" || (isTS && type == ",")) {
|
||||
if (value == "implements") cx.marked = "keyword";
|
||||
return cont(isTS ? typeexpr : expression, classNameAfter);
|
||||
}
|
||||
if (type == "{") return cont(pushlex("}"), classBody, poplex);
|
||||
}
|
||||
function classBody(type, value) {
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
if ((value == "static" || value == "get" || value == "set" ||
|
||||
(isTS && (value == "public" || value == "private" || value == "protected" || value == "readonly" || value == "abstract"))) &&
|
||||
cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false)) {
|
||||
if (type == "async" ||
|
||||
(type == "variable" &&
|
||||
(value == "static" || value == "get" || value == "set" || (isTS && isModifier(value))) &&
|
||||
cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) {
|
||||
cx.marked = "keyword";
|
||||
return cont(classBody);
|
||||
}
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property";
|
||||
return cont(isTS ? classfield : functiondef, classBody);
|
||||
}
|
||||
if (type == "[")
|
||||
return cont(expression, maybetype, expect("]"), isTS ? classfield : functiondef, classBody)
|
||||
if (value == "*") {
|
||||
cx.marked = "keyword";
|
||||
return cont(classBody);
|
||||
}
|
||||
if (type == ";") return cont(classBody);
|
||||
if (type == "}") return cont();
|
||||
if (value == "@") return cont(expression, classBody)
|
||||
}
|
||||
function classfield(type, value) {
|
||||
if (value == "?") return cont(classfield)
|
||||
if (type == ":") return cont(typeexpr, maybeAssign)
|
||||
return pass(functiondef)
|
||||
if (value == "=") return cont(expressionNoComma)
|
||||
var context = cx.state.lexical.prev, isInterface = context && context.info == "interface"
|
||||
return pass(isInterface ? functiondecl : functiondef)
|
||||
}
|
||||
function afterExport(_type, value) {
|
||||
function afterExport(type, value) {
|
||||
if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
|
||||
if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
|
||||
if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";"));
|
||||
return pass(statement);
|
||||
}
|
||||
function exportField(type, value) {
|
||||
if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); }
|
||||
if (type == "variable") return pass(expressionNoComma, exportField);
|
||||
}
|
||||
function afterImport(type) {
|
||||
if (type == "string") return cont();
|
||||
return pass(importSpec, maybeFrom);
|
||||
if (type == "(") return pass(expression);
|
||||
return pass(importSpec, maybeMoreImports, maybeFrom);
|
||||
}
|
||||
function importSpec(type, value) {
|
||||
if (type == "{") return contCommasep(importSpec, "}");
|
||||
|
@ -744,6 +888,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
if (value == "*") cx.marked = "keyword";
|
||||
return cont(maybeAs);
|
||||
}
|
||||
function maybeMoreImports(type) {
|
||||
if (type == ",") return cont(importSpec, maybeMoreImports)
|
||||
}
|
||||
function maybeAs(_type, value) {
|
||||
if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
|
||||
}
|
||||
|
@ -754,6 +901,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
if (type == "]") return cont();
|
||||
return pass(commasep(expressionNoComma, "]"));
|
||||
}
|
||||
function enumdef() {
|
||||
return pass(pushlex("form"), pattern, expect("{"), pushlex("}"), commasep(enummember, "}"), poplex, poplex)
|
||||
}
|
||||
function enummember() {
|
||||
return pass(pattern, maybeAssign);
|
||||
}
|
||||
|
||||
function isContinuedStatement(state, textAfter) {
|
||||
return state.lastType == "operator" || state.lastType == "," ||
|
||||
|
@ -761,6 +914,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
/[,.]/.test(textAfter.charAt(0));
|
||||
}
|
||||
|
||||
function expressionAllowed(stream, state, backUp) {
|
||||
return state.tokenize == tokenBase &&
|
||||
/^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
|
||||
(state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
|
||||
}
|
||||
|
||||
// Interface
|
||||
|
||||
return {
|
||||
|
@ -771,7 +930,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
cc: [],
|
||||
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
|
||||
localVars: parserConfig.localVars,
|
||||
context: parserConfig.localVars && {vars: parserConfig.localVars},
|
||||
context: parserConfig.localVars && new Context(null, null, false),
|
||||
indented: basecolumn || 0
|
||||
};
|
||||
if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
|
||||
|
@ -812,7 +971,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
lexical = lexical.prev;
|
||||
var type = lexical.type, closing = firstChar == type;
|
||||
|
||||
if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
|
||||
if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info.length + 1 : 0);
|
||||
else if (type == "form" && firstChar == "{") return lexical.indented;
|
||||
else if (type == "form") return lexical.indented + indentUnit;
|
||||
else if (type == "stat")
|
||||
|
@ -826,6 +985,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
|
||||
blockCommentStart: jsonMode ? null : "/*",
|
||||
blockCommentEnd: jsonMode ? null : "*/",
|
||||
blockCommentContinue: jsonMode ? null : " * ",
|
||||
lineComment: jsonMode ? null : "//",
|
||||
fold: "brace",
|
||||
closeBrackets: "()[]{}''\"\"``",
|
||||
|
@ -835,6 +995,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
jsonMode: jsonMode,
|
||||
|
||||
expressionAllowed: expressionAllowed,
|
||||
|
||||
skipExpression: function(state) {
|
||||
var top = state.cc[state.cc.length - 1]
|
||||
if (top == expression || top == expressionNoComma) state.cc.pop()
|
||||
|
|
|
@ -38,3 +38,14 @@ You'll only need to do this if you're testing the production environment locally
|
|||
7. `$ npm run build`
|
||||
8. Since production assumes your environment variables are in the shell environment, and not in a `.env` file, you will have to run `export $(grep -v '^#' .env | xargs)` or a similar command, see this [Stack Overflow answer](https://stackoverflow.com/a/20909045/4086967).
|
||||
9. `$ npm run start:prod`
|
||||
|
||||
## Self Hosting - Heroku Deployment
|
||||
|
||||
If you are interested in hosting and deploying your own p5.js Web Editor instance, you can! It would be the same as the official editor instance at editor.p5js.org, except with a different domain, and you would be in charge of the maintenance. We recommend using Heroku as you can host it for free.
|
||||
|
||||
1. Sign up for a free account at: [Heroku](https://www.heroku.com/)
|
||||
2. Click here: [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/processing/p5.js-web-editor/tree/master)
|
||||
3. Enter a unique *App name*, this will become part of the url (i.e. https://app-name.herokuapp.com/)
|
||||
4. Update any configuration variables, or accept the defaults for a quick evaluation (they can be changed later to enable full functionality)
|
||||
5. Click on the "Deploy app" button
|
||||
6. When complete, click on the "View app" button
|
||||
|
|
31251
package-lock.json
generated
31251
package-lock.json
generated
File diff suppressed because it is too large
Load diff
130
package.json
130
package.json
|
@ -16,7 +16,8 @@
|
|||
"fetch-examples": "cross-env NODE_ENV=development node ./server/scripts/fetch-examples.js",
|
||||
"fetch-examples-gg": "cross-env NODE_ENV=development node ./server/scripts/fetch-examples-gg.js",
|
||||
"fetch-examples:prod": "cross-env NODE_ENV=production node ./dist/fetch-examples.bundle.js",
|
||||
"fetch-examples-gg:prod": "cross-env NODE_ENV=production node ./dist/fetch-examples-gg.bundle.js"
|
||||
"fetch-examples-gg:prod": "cross-env NODE_ENV=production node ./dist/fetch-examples-gg.bundle.js",
|
||||
"heroku-postbuild": "touch .env; npm run build"
|
||||
},
|
||||
"main": "index.js",
|
||||
"author": "Cassie Tarakajian",
|
||||
|
@ -27,119 +28,120 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"babel-eslint": "^7.1.1",
|
||||
"babel-loader": "^7.1.4",
|
||||
"babel-plugin-transform-react-constant-elements": "^6.8.0",
|
||||
"babel-plugin-transform-react-inline-elements": "^6.8.0",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.2.6",
|
||||
"babel-loader": "^7.1.5",
|
||||
"babel-plugin-transform-react-constant-elements": "^6.23.0",
|
||||
"babel-plugin-transform-react-inline-elements": "^6.22.0",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.2.12",
|
||||
"babel-plugin-webpack-loaders": "^0.9.0",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-react": "^6.5.0",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"babel-preset-react-optimize": "^1.0.1",
|
||||
"babel-preset-stage-0": "^6.5.0",
|
||||
"chunk-manifest-webpack-plugin": "^1.1.2",
|
||||
"babel-preset-stage-0": "^6.24.1",
|
||||
"chunk-manifest-webpack-plugin": "github:catarak/chunk-manifest-webpack-plugin",
|
||||
"css-loader": "^0.23.1",
|
||||
"cssnano": "^3.7.1",
|
||||
"eslint": "^4.9.0",
|
||||
"cssnano": "^3.10.0",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-airbnb": "^16.1.0",
|
||||
"eslint-plugin-import": "^2.2.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.0.3",
|
||||
"eslint-plugin-react": "^7.7.0",
|
||||
"eslint-plugin-import": "^2.14.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.1.2",
|
||||
"eslint-plugin-react": "^7.12.3",
|
||||
"extract-text-webpack-plugin": "^3.0.2",
|
||||
"file-loader": "^2.0.0",
|
||||
"node-sass": "^4.9.0",
|
||||
"nodemon": "^1.9.2",
|
||||
"postcss-cssnext": "^2.7.0",
|
||||
"node-sass": "^4.11.0",
|
||||
"nodemon": "^1.18.9",
|
||||
"postcss-cssnext": "^2.11.0",
|
||||
"postcss-focus": "^1.0.0",
|
||||
"postcss-loader": "^0.9.1",
|
||||
"postcss-reporter": "^1.3.3",
|
||||
"rimraf": "^2.6.2",
|
||||
"sass-loader": "^6.0.6",
|
||||
"style-loader": "^0.13.1",
|
||||
"webpack-manifest-plugin": "^2.0.0",
|
||||
"postcss-reporter": "^1.4.1",
|
||||
"rimraf": "^2.6.3",
|
||||
"sass-loader": "^6.0.7",
|
||||
"style-loader": "^0.13.2",
|
||||
"webpack-manifest-plugin": "^2.0.4",
|
||||
"webpack-node-externals": "^1.7.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.9.0"
|
||||
"node": "10.15.0",
|
||||
"npm": "6.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"archiver": "^1.1.0",
|
||||
"async": "^2.0.0",
|
||||
"async": "^2.6.1",
|
||||
"axios": "^0.12.0",
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-polyfill": "^6.8.0",
|
||||
"babel-register": "^6.8.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"babel-register": "^6.26.0",
|
||||
"bcrypt-nodejs": "0.0.3",
|
||||
"blob-util": "^1.2.1",
|
||||
"body-parser": "^1.15.1",
|
||||
"bson-objectid": "^1.1.4",
|
||||
"classnames": "^2.2.5",
|
||||
"body-parser": "^1.18.3",
|
||||
"bson-objectid": "^1.2.4",
|
||||
"classnames": "^2.2.6",
|
||||
"clipboard": "^1.7.1",
|
||||
"codemirror": "^5.38.0",
|
||||
"connect-mongo": "^1.2.0",
|
||||
"console-feed": "^2.8.1",
|
||||
"cookie-parser": "^1.4.1",
|
||||
"cors": "^2.8.1",
|
||||
"cross-env": "^5.1.3",
|
||||
"codemirror": "^5.42.2",
|
||||
"connect-mongo": "^1.3.2",
|
||||
"console-feed": "^2.8.5",
|
||||
"cookie-parser": "^1.4.3",
|
||||
"cors": "^2.8.5",
|
||||
"cross-env": "^5.2.0",
|
||||
"csslint": "^0.10.0",
|
||||
"decomment": "^0.8.7",
|
||||
"dotenv": "^2.0.0",
|
||||
"dropzone": "^4.3.0",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"eslint-loader": "^1.3.0",
|
||||
"express": "^4.13.4",
|
||||
"express-basic-auth": "^1.1.5",
|
||||
"express-session": "^1.13.0",
|
||||
"htmlhint": "^0.9.13",
|
||||
"is-url": "^1.2.2",
|
||||
"js-beautify": "^1.6.4",
|
||||
"express": "^4.16.4",
|
||||
"express-basic-auth": "^1.1.6",
|
||||
"express-session": "^1.15.6",
|
||||
"htmlhint": "^0.10.1",
|
||||
"is-url": "^1.2.4",
|
||||
"js-beautify": "^1.8.9",
|
||||
"jsdom": "^9.8.3",
|
||||
"jshint": "^2.9.4",
|
||||
"lodash": "^4.16.4",
|
||||
"jshint": "^2.9.7",
|
||||
"lodash": "^4.17.11",
|
||||
"loop-protect": "github:catarak/loop-protect",
|
||||
"mjml": "^3.3.2",
|
||||
"moment": "^2.14.1",
|
||||
"moment": "^2.23.0",
|
||||
"mongoose": "^4.6.8",
|
||||
"node-uuid": "^1.4.7",
|
||||
"nodemailer": "^2.6.4",
|
||||
"nodemailer-mailgun-transport": "^1.2.2",
|
||||
"nodemailer-mailgun-transport": "^1.4.0",
|
||||
"passport": "^0.3.2",
|
||||
"passport-github": "^1.1.0",
|
||||
"passport-google-oauth20": "^1.0.0",
|
||||
"passport-local": "^1.0.0",
|
||||
"pretty-bytes": "^3.0.1",
|
||||
"primer-tooltips": "^1.4.1",
|
||||
"project-name-generator": "^2.1.3",
|
||||
"prop-types": "^15.6.0",
|
||||
"primer-tooltips": "^1.5.11",
|
||||
"project-name-generator": "^2.1.5",
|
||||
"prop-types": "^15.6.2",
|
||||
"q": "^1.4.1",
|
||||
"react": "^16.4.0",
|
||||
"react-dom": "^16.4.0",
|
||||
"react": "^16.7.0",
|
||||
"react-dom": "^16.7.0",
|
||||
"react-helmet": "^5.1.3",
|
||||
"react-hot-loader": "^4.1.2",
|
||||
"react-hot-loader": "^4.6.3",
|
||||
"react-inlinesvg": "^0.7.5",
|
||||
"react-redux": "^5.0.6",
|
||||
"react-router": "^3.2.0",
|
||||
"react-split-pane": "^0.1.44",
|
||||
"react-tabs": "^2.2.1",
|
||||
"redux": "^3.5.2",
|
||||
"redux-devtools": "^3.4.1",
|
||||
"react-redux": "^5.1.1",
|
||||
"react-router": "^3.2.1",
|
||||
"react-split-pane": "^0.1.76",
|
||||
"react-tabs": "^2.3.0",
|
||||
"redux": "^3.7.2",
|
||||
"redux-devtools": "^3.4.2",
|
||||
"redux-devtools-dock-monitor": "^1.1.3",
|
||||
"redux-devtools-log-monitor": "^1.4.0",
|
||||
"redux-form": "^5.3.3",
|
||||
"redux-thunk": "^2.1.0",
|
||||
"request": "^2.76.0",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"request": "^2.88.0",
|
||||
"request-promise": "^4.1.1",
|
||||
"s3": "^4.4.0",
|
||||
"s3-policy": "^0.2.0",
|
||||
"sass-extract": "^2.1.0",
|
||||
"sass-extract-js": "^0.4.0",
|
||||
"sass-extract-loader": "^1.1.0",
|
||||
"shortid": "^2.2.6",
|
||||
"shortid": "^2.2.14",
|
||||
"slugify": "^1.3.4",
|
||||
"srcdoc-polyfill": "^0.2.0",
|
||||
"url": "^0.11.0",
|
||||
"webpack": "^3.1.0",
|
||||
"webpack": "^3.12.0",
|
||||
"webpack-dev-middleware": "^2.0.6",
|
||||
"webpack-hot-middleware": "^2.10.0",
|
||||
"xhr": "^2.2.1"
|
||||
"webpack-hot-middleware": "^2.24.3",
|
||||
"xhr": "^2.5.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,8 @@ import {
|
|||
injectMediaUrls,
|
||||
resolvePathsForElementsWithAttribute,
|
||||
resolveScripts,
|
||||
resolveStyles } from '../utils/previewGeneration';
|
||||
resolveStyles
|
||||
} from '../utils/previewGeneration';
|
||||
import { get404Sketch } from '../views/404Page';
|
||||
|
||||
export function serveProject(req, res) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import * as EmbedController from '../controllers/embed.controller';
|
|||
const router = new Router();
|
||||
|
||||
router.get('/:username/embed/:project_id', EmbedController.serveProject);
|
||||
router.get('/:username/present/:project_id', EmbedController.serveProject);
|
||||
router.get('/embed/:project_id', EmbedController.serveProject);
|
||||
|
||||
export default router;
|
||||
|
|
|
@ -49,7 +49,7 @@ mongoose.connection.on('error', () => {
|
|||
function getCategories() {
|
||||
const categories = [];
|
||||
const options = {
|
||||
url: `https://api.github.com/repos/processing/p5.js-website/contents/dist/assets/examples/en?client_id=${
|
||||
url: `https://api.github.com/repos/processing/p5.js-website/contents/src/data/examples/en?client_id=${
|
||||
clientId}&client_secret=${clientSecret}`,
|
||||
method: 'GET',
|
||||
headers,
|
||||
|
@ -134,7 +134,7 @@ function getSketchContent(projectsInAllCategories) {
|
|||
|
||||
function createProjectsInP5user(projectsInAllCategories) {
|
||||
const options = {
|
||||
url: `https://api.github.com/repos/processing/p5.js-website/contents/dist/assets/examples/assets?client_id=${
|
||||
url: `https://api.github.com/repos/processing/p5.js-website/contents/src/data/examples/assets?client_id=${
|
||||
clientId}&client_secret=${clientSecret}`,
|
||||
method: 'GET',
|
||||
headers,
|
||||
|
@ -264,7 +264,7 @@ function createProjectsInP5user(projectsInAllCategories) {
|
|||
const fileID = objectID().toHexString();
|
||||
newProject.files.push({
|
||||
name: assetName,
|
||||
url: `https://rawgit.com/processing/p5.js-website/master/dist/assets/examples/assets/${assetName}`,
|
||||
url: `https://rawgit.com/processing/p5.js-website/master/src/data/examples/assets/${assetName}`,
|
||||
id: fileID,
|
||||
_id: fileID,
|
||||
children: [],
|
||||
|
|
|
@ -1,44 +1,7 @@
|
|||
import User from '../models/user';
|
||||
import Project from '../models/project';
|
||||
|
||||
export function get404Sketch(callback) {
|
||||
User.findOne({ username: 'p5' }, (userErr, user) => { // Find p5 user
|
||||
if (userErr) {
|
||||
throw userErr;
|
||||
} else {
|
||||
Project.find({ user: user._id }, (projErr, projects) => { // Find example projects
|
||||
// Choose a random sketch
|
||||
const randomIndex = Math.floor(Math.random() * projects.length);
|
||||
const sketch = projects[randomIndex];
|
||||
let instanceMode = false;
|
||||
|
||||
// Get sketch files
|
||||
let htmlFile = sketch.files.filter(file => file.name.match(/.*\.html$/i))[0].content;
|
||||
const jsFiles = sketch.files.filter(file => file.name.match(/.*\.js$/i));
|
||||
const cssFiles = sketch.files.filter(file => file.name.match(/.*\.css$/i));
|
||||
const linkedFiles = sketch.files.filter(file => file.url);
|
||||
|
||||
instanceMode = jsFiles.find(file => file.name === 'sketch.js').content.includes('Instance Mode');
|
||||
|
||||
jsFiles.forEach((file) => { // Add js files as script tags
|
||||
const html = htmlFile.split('</body>');
|
||||
html[0] = `${html[0]}<script>${file.content}</script>`;
|
||||
htmlFile = html.join('</body>');
|
||||
});
|
||||
|
||||
cssFiles.forEach((file) => { // Add css files as style tags
|
||||
const html = htmlFile.split('</head>');
|
||||
html[0] = `${html[0]}<style>${file.content}</style>`;
|
||||
htmlFile = html.join('</head>');
|
||||
});
|
||||
|
||||
linkedFiles.forEach((file) => { // Add linked files as link tags
|
||||
const html = htmlFile.split('<head>');
|
||||
html[1] = `<link href=${file.url}>${html[1]}`;
|
||||
htmlFile = html.join('<head>');
|
||||
});
|
||||
|
||||
// Add 404 html and position canvas
|
||||
function insertErrorMessage(htmlFile) {
|
||||
const html = htmlFile.split('</head>');
|
||||
const metaDescription = 'A web editor for p5.js, a JavaScript library with the goal of making coding accessible to artists, designers, educators, and beginners.'; // eslint-disable-line
|
||||
html[0] = `
|
||||
|
@ -86,7 +49,10 @@ export function get404Sketch(callback) {
|
|||
type='image/x-icon'
|
||||
>
|
||||
`;
|
||||
const body = html[1].split('<body>');
|
||||
html[1] = `
|
||||
${body[0]}
|
||||
<body>
|
||||
<div class="header">
|
||||
<div class="message-container">
|
||||
<h1>404 Page Not Found</h1>
|
||||
|
@ -96,9 +62,50 @@ export function get404Sketch(callback) {
|
|||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
${html[1]}
|
||||
${body[1]}
|
||||
`;
|
||||
return html.join('</head>');
|
||||
}
|
||||
|
||||
export function get404Sketch(callback) {
|
||||
User.findOne({ username: 'p5' }, (userErr, user) => { // Find p5 user
|
||||
if (userErr) {
|
||||
throw userErr;
|
||||
} else if (user) {
|
||||
Project.find({ user: user._id }, (projErr, projects) => { // Find example projects
|
||||
// Choose a random sketch
|
||||
const randomIndex = Math.floor(Math.random() * projects.length);
|
||||
const sketch = projects[randomIndex];
|
||||
let instanceMode = false;
|
||||
|
||||
// Get sketch files
|
||||
let htmlFile = sketch.files.filter(file => file.name.match(/.*\.html$/i))[0].content;
|
||||
const jsFiles = sketch.files.filter(file => file.name.match(/.*\.js$/i));
|
||||
const cssFiles = sketch.files.filter(file => file.name.match(/.*\.css$/i));
|
||||
const linkedFiles = sketch.files.filter(file => file.url);
|
||||
|
||||
instanceMode = jsFiles.find(file => file.name === 'sketch.js').content.includes('Instance Mode');
|
||||
|
||||
jsFiles.forEach((file) => { // Add js files as script tags
|
||||
const html = htmlFile.split('</body>');
|
||||
html[0] = `${html[0]}<script>${file.content}</script>`;
|
||||
htmlFile = html.join('</body>');
|
||||
});
|
||||
|
||||
cssFiles.forEach((file) => { // Add css files as style tags
|
||||
const html = htmlFile.split('</head>');
|
||||
html[0] = `${html[0]}<style>${file.content}</style>`;
|
||||
htmlFile = html.join('</head>');
|
||||
});
|
||||
|
||||
linkedFiles.forEach((file) => { // Add linked files as link tags
|
||||
const html = htmlFile.split('<head>');
|
||||
html[1] = `<link href=${file.url}>${html[1]}`;
|
||||
htmlFile = html.join('<head>');
|
||||
});
|
||||
|
||||
// Add 404 html and position canvas
|
||||
htmlFile = insertErrorMessage(htmlFile);
|
||||
|
||||
// Fix links to assets
|
||||
htmlFile = htmlFile.replace(
|
||||
|
@ -118,9 +125,17 @@ export function get404Sketch(callback) {
|
|||
|
||||
callback(htmlFile);
|
||||
});
|
||||
} else {
|
||||
callback(insertErrorMessage(`<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>`));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default get404Sketch;
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
export function renderIndex() {
|
||||
const assetsManifest = process.env.webpackAssets && JSON.parse(process.env.webpackAssets);
|
||||
const chunkManifest = process.env.webpackChunkAssets && JSON.parse(process.env.webpackChunkAssets);
|
||||
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
@ -29,7 +28,8 @@ export function renderIndex() {
|
|||
window.process.env.AWS_REGION = '${process.env.AWS_REGION}';
|
||||
window.process.env.FORCE_TO_HTTPS = ${process.env.FORCE_TO_HTTPS === 'false' ? false : undefined};
|
||||
window.process.env.CLIENT = true;
|
||||
window.process.env.LOGIN_ENABLED = ${process.env.LOGIN_ENABLED === 'false' ? false : true}
|
||||
window.process.env.LOGIN_ENABLED = ${process.env.LOGIN_ENABLED === 'false' ? false : true};
|
||||
window.process.env.EXAMPLES_ENABLED = ${process.env.EXAMPLES_ENABLED === 'false' ? false : true};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -116,6 +116,7 @@ module.exports = [{
|
|||
new ChunkManifestPlugin({
|
||||
filename: 'chunk-manifest.json',
|
||||
manifestVariable: 'webpackManifest',
|
||||
inlineManifest: false
|
||||
}),
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
sourceMap: true,
|
||||
|
|
Loading…
Reference in a new issue