mirror of
https://github.com/chinchang/web-maker.git
synced 2025-10-10 19:14:33 +02:00
25
gulpfile.js
25
gulpfile.js
@@ -22,8 +22,8 @@ function minifyJs(fileName) {
|
|||||||
).code;
|
).code;
|
||||||
fs.writeFileSync(fileName, minifiedContent);
|
fs.writeFileSync(fileName, minifiedContent);
|
||||||
console.log(
|
console.log(
|
||||||
`[${fileName}]: ${content.length / 1024}M -> ${minifiedContent.length /
|
`[${fileName}]: ${content.length / 1024}K -> ${minifiedContent.length /
|
||||||
1024}M`
|
1024}K`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
gulp.task('runWebpack', function() {
|
gulp.task('runWebpack', function() {
|
||||||
@@ -41,6 +41,9 @@ gulp.task('copyFiles', function() {
|
|||||||
gulp.src('src/lib/transpilers/*').pipe(gulp.dest('app/lib/transpilers')),
|
gulp.src('src/lib/transpilers/*').pipe(gulp.dest('app/lib/transpilers')),
|
||||||
gulp.src('src/lib/prettier-worker.js').pipe(gulp.dest('app/lib/')),
|
gulp.src('src/lib/prettier-worker.js').pipe(gulp.dest('app/lib/')),
|
||||||
gulp.src('src/lib/prettier/*').pipe(gulp.dest('app/lib/prettier')),
|
gulp.src('src/lib/prettier/*').pipe(gulp.dest('app/lib/prettier')),
|
||||||
|
gulp
|
||||||
|
.src(['!src/lib/monaco/monaco.bundle.js', 'src/lib/monaco/**/*'])
|
||||||
|
.pipe(gulp.dest('app/lib/monaco')),
|
||||||
gulp.src('src/lib/screenlog.js').pipe(gulp.dest('app/lib')),
|
gulp.src('src/lib/screenlog.js').pipe(gulp.dest('app/lib')),
|
||||||
gulp.src('icons/*').pipe(gulp.dest('app/icons')),
|
gulp.src('icons/*').pipe(gulp.dest('app/icons')),
|
||||||
gulp.src('src/assets/*').pipe(gulp.dest('app/assets')),
|
gulp.src('src/assets/*').pipe(gulp.dest('app/assets')),
|
||||||
@@ -63,6 +66,7 @@ gulp.task('copyFiles', function() {
|
|||||||
.src('build/vendor.*.js')
|
.src('build/vendor.*.js')
|
||||||
.pipe(rename('vendor.js'))
|
.pipe(rename('vendor.js'))
|
||||||
.pipe(gulp.dest('app')),
|
.pipe(gulp.dest('app')),
|
||||||
|
gulp.src('build/monaco.*.js').pipe(gulp.dest('app')),
|
||||||
|
|
||||||
// Following CSS are copied to build/ folder where they'll be referenced by
|
// Following CSS are copied to build/ folder where they'll be referenced by
|
||||||
// useRef plugin to concat into one.
|
// useRef plugin to concat into one.
|
||||||
@@ -120,8 +124,11 @@ gulp.task('minify', function() {
|
|||||||
debug: true
|
debug: true
|
||||||
},
|
},
|
||||||
details => {
|
details => {
|
||||||
console.log(`${details.name}: ${details.stats.originalSize}`);
|
console.log(
|
||||||
console.log(`${details.name}: ${details.stats.minifiedSize}`);
|
`${details.name}: ${details.stats.originalSize} 👉🏼 ${
|
||||||
|
details.stats.minifiedSize
|
||||||
|
}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -138,7 +145,7 @@ gulp.task('fixIndex', function() {
|
|||||||
|
|
||||||
// vendor.hash.js gets created outside our markers, so remove it
|
// vendor.hash.js gets created outside our markers, so remove it
|
||||||
contents = contents.replace(
|
contents = contents.replace(
|
||||||
/\<script src="\/vendor\.[\S\s]*?\<\/script\>/,
|
/\<script src="[\S\s]*?vendor\.[\S\s]*?\<\/script\>/,
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -171,18 +178,12 @@ gulp.task('packageExtension', function() {
|
|||||||
child_process.execSync('cp src/options.html extension');
|
child_process.execSync('cp src/options.html extension');
|
||||||
child_process.execSync('cp src/eventPage.js extension');
|
child_process.execSync('cp src/eventPage.js extension');
|
||||||
child_process.execSync('cp src/icon-16.png extension');
|
child_process.execSync('cp src/icon-16.png extension');
|
||||||
child_process.execSync(
|
child_process.execSync('rm -rf extension/service-worker.js');
|
||||||
'rm -rf extension/service-worker.js extension/partials'
|
|
||||||
);
|
|
||||||
return merge(
|
return merge(
|
||||||
gulp
|
gulp
|
||||||
.src('build/bundle.*.js')
|
.src('build/bundle.*.js')
|
||||||
.pipe(rename('script.js'))
|
.pipe(rename('script.js'))
|
||||||
.pipe(gulp.dest('extension')),
|
.pipe(gulp.dest('extension')),
|
||||||
gulp
|
|
||||||
.src('build/vendor.*.js')
|
|
||||||
.pipe(rename('vendor.js'))
|
|
||||||
.pipe(gulp.dest('extension')),
|
|
||||||
|
|
||||||
gulp
|
gulp
|
||||||
.src('extension/**/*')
|
.src('extension/**/*')
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
import CopyWebpackPlugin from 'copy-webpack-plugin';
|
|
||||||
var CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
|
var CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,6 +28,12 @@ export default function(config, env, helpers) {
|
|||||||
if (env.isProd) {
|
if (env.isProd) {
|
||||||
config.devtool = false; // disable sourcemaps
|
config.devtool = false; // disable sourcemaps
|
||||||
|
|
||||||
|
// To support chunk loading in root and also /app path
|
||||||
|
config.output.publicPath = './';
|
||||||
|
|
||||||
|
// Remove the default hash append in chunk name
|
||||||
|
config.output.chunkFilename = '[name].chunk.js';
|
||||||
|
|
||||||
config.plugins.push(
|
config.plugins.push(
|
||||||
new CommonsChunkPlugin({
|
new CommonsChunkPlugin({
|
||||||
name: 'vendor',
|
name: 'vendor',
|
||||||
|
390
src/components/CodeEditor.jsx
Normal file
390
src/components/CodeEditor.jsx
Normal file
@@ -0,0 +1,390 @@
|
|||||||
|
import { h, Component } from 'preact';
|
||||||
|
import CodeMirror from '../CodeMirror';
|
||||||
|
|
||||||
|
import 'codemirror/addon/edit/matchbrackets.js';
|
||||||
|
import 'codemirror/addon/edit/matchtags.js';
|
||||||
|
import 'codemirror/addon/edit/closebrackets.js';
|
||||||
|
import 'codemirror/addon/edit/closetag.js';
|
||||||
|
import 'codemirror/addon/comment/comment.js';
|
||||||
|
import 'codemirror/addon/fold/foldcode.js';
|
||||||
|
import 'codemirror/addon/fold/foldgutter.js';
|
||||||
|
import 'codemirror/addon/fold/xml-fold.js';
|
||||||
|
import 'codemirror/addon/fold/indent-fold.js';
|
||||||
|
import 'codemirror/addon/fold/comment-fold.js';
|
||||||
|
import 'codemirror/addon/fold/brace-fold.js';
|
||||||
|
import 'codemirror/addon/hint/show-hint.js';
|
||||||
|
import 'codemirror/addon/hint/javascript-hint.js';
|
||||||
|
import 'codemirror/addon/hint/xml-hint.js';
|
||||||
|
import 'codemirror/addon/hint/html-hint.js';
|
||||||
|
import 'codemirror/addon/hint/css-hint.js';
|
||||||
|
import 'codemirror/addon/selection/active-line.js';
|
||||||
|
import 'codemirror/addon/search/searchcursor.js';
|
||||||
|
import 'codemirror/addon/search/search.js';
|
||||||
|
import 'codemirror/addon/dialog/dialog.js';
|
||||||
|
import 'codemirror/addon/search/jump-to-line.js';
|
||||||
|
|
||||||
|
import 'codemirror/mode/xml/xml.js';
|
||||||
|
import 'codemirror/mode/css/css.js';
|
||||||
|
import 'codemirror/mode/javascript/javascript.js';
|
||||||
|
import 'codemirror/mode/htmlmixed/htmlmixed.js';
|
||||||
|
import 'codemirror/keymap/sublime.js';
|
||||||
|
import 'codemirror/keymap/vim.js';
|
||||||
|
import 'code-blast-codemirror/code-blast.js';
|
||||||
|
|
||||||
|
import emmet from '@emmetio/codemirror-plugin';
|
||||||
|
import { prettify, loadCss } from '../utils';
|
||||||
|
import { modes } from '../codeModes';
|
||||||
|
import { deferred } from '../deferred';
|
||||||
|
|
||||||
|
emmet(CodeMirror);
|
||||||
|
let monacoDepsDeferred;
|
||||||
|
|
||||||
|
window.MonacoEnvironment = {
|
||||||
|
getWorkerUrl(moduleId, label) {
|
||||||
|
switch (label) {
|
||||||
|
case 'html':
|
||||||
|
return 'lib/monaco/workers/html.worker.bundle.js';
|
||||||
|
case 'json':
|
||||||
|
return 'lib/monaco/workers/json.worker.bundle.js';
|
||||||
|
case 'css':
|
||||||
|
case 'scss':
|
||||||
|
case 'less':
|
||||||
|
return 'lib/monaco/workers/css.worker.bundle.js';
|
||||||
|
case 'typescript':
|
||||||
|
case 'javascript':
|
||||||
|
return 'lib/monaco/workers/ts.worker.bundle.js';
|
||||||
|
default:
|
||||||
|
return 'lib/monaco/workers/editor.worker.bundle.js';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class CodeEditor extends Component {
|
||||||
|
componentDidMount() {
|
||||||
|
this.initEditor();
|
||||||
|
}
|
||||||
|
shouldComponentUpdate(nextProps) {
|
||||||
|
if (nextProps.prefs !== this.props.prefs) {
|
||||||
|
const { prefs } = nextProps;
|
||||||
|
|
||||||
|
if (this.props.type === 'monaco') {
|
||||||
|
this.instance.updateOptions({ fontSize: prefs.fontSize });
|
||||||
|
} else {
|
||||||
|
this.instance.setOption(
|
||||||
|
'indentWithTabs',
|
||||||
|
prefs.indentWith !== 'spaces'
|
||||||
|
);
|
||||||
|
this.instance.setOption(
|
||||||
|
'blastCode',
|
||||||
|
prefs.isCodeBlastOn ? { effect: 2, shake: false } : false
|
||||||
|
);
|
||||||
|
this.instance.setOption('theme', prefs.editorTheme);
|
||||||
|
|
||||||
|
this.instance.setOption('indentUnit', +prefs.indentSize);
|
||||||
|
this.instance.setOption('tabSize', +prefs.indentSize);
|
||||||
|
|
||||||
|
this.instance.setOption('keyMap', prefs.keymap);
|
||||||
|
this.instance.setOption('lineWrapping', prefs.lineWrap);
|
||||||
|
this.instance.setOption('lineWrapping', prefs.autoCloseTags);
|
||||||
|
|
||||||
|
this.instance.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only condition when this component updates is when prop.type changes
|
||||||
|
if (nextProps.type !== this.props.type) {
|
||||||
|
if (
|
||||||
|
this.node.parentElement.querySelector('.monaco-editor, .CodeMirror')
|
||||||
|
) {
|
||||||
|
this.node.parentElement
|
||||||
|
.querySelector('.monaco-editor, .CodeMirror')
|
||||||
|
.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
// prop.type changed, reinit the editor
|
||||||
|
this.initEditor();
|
||||||
|
}
|
||||||
|
setModel(model) {
|
||||||
|
this.instance.swapDoc
|
||||||
|
? this.instance.swapDoc(model)
|
||||||
|
: this.instance.setModel(model);
|
||||||
|
}
|
||||||
|
setValue(value) {
|
||||||
|
// HACK: We set a flag on window for an ultra-short duration, which 'change'
|
||||||
|
// listener uses to set the change.origin to 'setValue', otherwise it's
|
||||||
|
// '+input'
|
||||||
|
if (this.props.type === 'monaco') {
|
||||||
|
window.monacoSetValTriggered = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
window.monacoSetValTriggered = false;
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
this.instance.setValue(value);
|
||||||
|
// We save last set value so that when editor type changes, we can
|
||||||
|
// populate that last value
|
||||||
|
this.lastSetValue = value;
|
||||||
|
}
|
||||||
|
getValue() {
|
||||||
|
return this.instance.getValue();
|
||||||
|
}
|
||||||
|
saveViewState() {
|
||||||
|
if (this.props.type === 'monaco') {
|
||||||
|
return this.instance.saveViewState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
restoreViewState(state) {
|
||||||
|
if (this.props.type === 'monaco') {
|
||||||
|
this.instance.restoreViewState(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setOption(option, value) {
|
||||||
|
if (this.props.type === 'monaco') {
|
||||||
|
this.monacoEditorReadyDeferred.promise.then(() => {
|
||||||
|
this.instance.updateOptions({ [option]: value });
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.instance.setOption(option, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setLanguage(value) {
|
||||||
|
if (!window.monaco) return;
|
||||||
|
|
||||||
|
if (this.props.type === 'monaco') {
|
||||||
|
monaco.editor.setModelLanguage(
|
||||||
|
this.instance.getModel(),
|
||||||
|
this.getMonacoLanguageFromMode(modes[value].cmMode)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.instance.setOption('mode', modes[value].cmMode);
|
||||||
|
CodeMirror.autoLoadMode(
|
||||||
|
this.instance,
|
||||||
|
modes[value].cmPath || modes[value].cmMode
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearGutter(gutterName) {
|
||||||
|
if (this.instance.clearGutter) {
|
||||||
|
this.instance.clearGutter(gutterName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showErrors(errors) {
|
||||||
|
if (this.props.type === 'codemirror') {
|
||||||
|
errors.forEach(function(error) {
|
||||||
|
this.instance.operation(function() {
|
||||||
|
var n = document.createElement('div');
|
||||||
|
n.setAttribute('data-title', error.message);
|
||||||
|
n.classList.add('gutter-error-marker');
|
||||||
|
editor.setGutterMarker(error.lineNumber, 'error-gutter', n);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
this.instance.refresh ? this.instance.refresh() : this.instance.layout();
|
||||||
|
}
|
||||||
|
focus() {
|
||||||
|
this.instance.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts codemirror mode value to monaco language values.
|
||||||
|
* TODO: Refactor to not be codemirror related.
|
||||||
|
* @param {string} mode Codemirror mode value
|
||||||
|
*/
|
||||||
|
getMonacoLanguageFromMode(mode) {
|
||||||
|
if (['htmlmixed'].includes(mode)) {
|
||||||
|
return 'html';
|
||||||
|
}
|
||||||
|
if (['css', 'sass', 'scss', 'less', 'stylus'].includes(mode)) {
|
||||||
|
return 'css';
|
||||||
|
}
|
||||||
|
if (['javascript', 'text/typescript-jsx', 'jsx'].includes(mode)) {
|
||||||
|
return 'javascript';
|
||||||
|
}
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the asynchronous deps according to the editor type.
|
||||||
|
*/
|
||||||
|
async loadDeps() {
|
||||||
|
if (this.props.type === 'monaco') {
|
||||||
|
if (!monacoDepsDeferred) {
|
||||||
|
monacoDepsDeferred = deferred();
|
||||||
|
loadCss({ url: 'lib/monaco/monaco.css', id: 'monaco-css' });
|
||||||
|
import(/* webpackChunkName: "monaco" */ '../lib/monaco/monaco.bundle.js').then(
|
||||||
|
() => {
|
||||||
|
monacoDepsDeferred.resolve();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return monacoDepsDeferred.promise;
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
async initEditor() {
|
||||||
|
this.monacoEditorReadyDeferred = deferred();
|
||||||
|
await this.loadDeps();
|
||||||
|
|
||||||
|
const { options, prefs } = this.props;
|
||||||
|
if (this.props.type === 'monaco') {
|
||||||
|
this.instance = monaco.editor.create(this.node, {
|
||||||
|
language: this.getMonacoLanguageFromMode(options.mode),
|
||||||
|
value: this.lastSetValue || '',
|
||||||
|
roundedSelection: false,
|
||||||
|
scrollBeyondLastLine: false,
|
||||||
|
theme: 'vs-dark',
|
||||||
|
fontSize: prefs.fontSize,
|
||||||
|
minimap: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
wordWrap: 'on',
|
||||||
|
renderWhitespace: 'all',
|
||||||
|
fontLigatures: true,
|
||||||
|
automaticLayout: true
|
||||||
|
});
|
||||||
|
window.monacoInstance = this.instance;
|
||||||
|
this.instance.onDidChangeModelContent(change => {
|
||||||
|
this.props.onChange(this.instance, {
|
||||||
|
...change,
|
||||||
|
origin: window.monacoSetValTriggered ? 'setValue' : '+input'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.instance.addCommand(
|
||||||
|
monaco.KeyMod.WinCtrl | monaco.KeyMod.Shift | monaco.KeyCode.KEY_F,
|
||||||
|
() => {
|
||||||
|
if (options.prettier) {
|
||||||
|
prettify({
|
||||||
|
content: this.instance.getValue(),
|
||||||
|
type: options.prettierParser
|
||||||
|
}).then(formattedCode => this.instance.setValue(formattedCode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.monacoEditorReadyDeferred.resolve();
|
||||||
|
} else {
|
||||||
|
this.instance = CodeMirror.fromTextArea(this.node, {
|
||||||
|
mode: options.mode,
|
||||||
|
value: this.lastSetValue || '',
|
||||||
|
lineNumbers: true,
|
||||||
|
lineWrapping: !!prefs.lineWrap,
|
||||||
|
autofocus: options.autofocus || false,
|
||||||
|
autoCloseBrackets: true,
|
||||||
|
autoCloseTags: !!prefs.autoCloseTags,
|
||||||
|
matchBrackets: true,
|
||||||
|
matchTags: options.matchTags || false,
|
||||||
|
tabMode: 'indent',
|
||||||
|
keyMap: prefs.keyMap || 'sublime',
|
||||||
|
theme: prefs.editorTheme || 'monokai',
|
||||||
|
lint: !!options.lint,
|
||||||
|
tabSize: +prefs.indentSize || 2,
|
||||||
|
indentWithTabs: prefs.indentWith !== 'spaces',
|
||||||
|
indentUnit: +prefs.indentSize,
|
||||||
|
foldGutter: true,
|
||||||
|
styleActiveLine: true,
|
||||||
|
gutters: options.gutters || [],
|
||||||
|
// cursorScrollMargin: '20', has issue with scrolling
|
||||||
|
profile: options.profile || '',
|
||||||
|
extraKeys: {
|
||||||
|
Up: function(editor) {
|
||||||
|
// Stop up/down keys default behavior when saveditempane is open
|
||||||
|
// if (isSavedItemsPaneOpen) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
CodeMirror.commands.goLineUp(editor);
|
||||||
|
},
|
||||||
|
Down: function(editor) {
|
||||||
|
// if (isSavedItemsPaneOpen) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
CodeMirror.commands.goLineDown(editor);
|
||||||
|
},
|
||||||
|
'Shift-Tab': function(editor) {
|
||||||
|
CodeMirror.commands.indentAuto(editor);
|
||||||
|
},
|
||||||
|
'Shift-Ctrl-F': function(editor) {
|
||||||
|
if (options.prettier) {
|
||||||
|
prettify({
|
||||||
|
content: editor.getValue(),
|
||||||
|
type: options.prettierParser
|
||||||
|
}).then(formattedCode => editor.setValue(formattedCode));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Tab: function(editor) {
|
||||||
|
if (options.emmet) {
|
||||||
|
const didEmmetWork = editor.execCommand(
|
||||||
|
'emmetExpandAbbreviation'
|
||||||
|
);
|
||||||
|
if (didEmmetWork === true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const input = $('[data-setting=indentWith]:checked');
|
||||||
|
if (
|
||||||
|
!editor.somethingSelected() &&
|
||||||
|
(!prefs.indentWith || prefs.indentWith === 'spaces')
|
||||||
|
) {
|
||||||
|
// softtabs adds spaces. This is required because by default tab key will put tab, but we want
|
||||||
|
// to indent with spaces if `spaces` is preferred mode of indentation.
|
||||||
|
// `somethingSelected` needs to be checked otherwise, all selected code is replaced with softtab.
|
||||||
|
CodeMirror.commands.insertSoftTab(editor);
|
||||||
|
} else {
|
||||||
|
CodeMirror.commands.defaultTab(editor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Enter: 'emmetInsertLineBreak'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.instance.on('focus', editor => {
|
||||||
|
if (typeof this.props.onFocus === 'function')
|
||||||
|
this.props.onFocus(editor);
|
||||||
|
});
|
||||||
|
this.instance.on('change', this.props.onChange);
|
||||||
|
this.instance.addKeyMap({
|
||||||
|
'Ctrl-Space': 'autocomplete'
|
||||||
|
});
|
||||||
|
this.instance.on('inputRead', (editor, input) => {
|
||||||
|
// Process further If this has autocompletition on and also the global
|
||||||
|
// autocomplete setting is on.
|
||||||
|
if (
|
||||||
|
!this.props.options.noAutocomplete &&
|
||||||
|
this.props.prefs.autoComplete
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
input.origin !== '+input' ||
|
||||||
|
input.text[0] === ';' ||
|
||||||
|
input.text[0] === ',' ||
|
||||||
|
input.text[0] === ' '
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CodeMirror.commands.autocomplete(editor, null, {
|
||||||
|
completeSingle: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// this.props.onCreation(this.instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const node =
|
||||||
|
this.props.type === 'monaco' ? (
|
||||||
|
<div ref={el => (this.node = el)} style="width:100%;height:100%;" />
|
||||||
|
) : (
|
||||||
|
<textarea ref={el => (this.node = el)} />
|
||||||
|
);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
import { h, Component } from 'preact';
|
import { h, Component } from 'preact';
|
||||||
import UserCodeMirror from './UserCodeMirror.jsx';
|
import CodeEditor from './CodeEditor.jsx';
|
||||||
import { computeHtml, computeCss, computeJs } from '../computes';
|
import { computeHtml, computeCss, computeJs } from '../computes';
|
||||||
import { modes, HtmlModes, CssModes, JsModes } from '../codeModes';
|
import { modes, HtmlModes, CssModes, JsModes } from '../codeModes';
|
||||||
import { log, writeFile, loadJS, getCompleteHtml } from '../utils';
|
import { log, writeFile, loadJS, getCompleteHtml } from '../utils';
|
||||||
@@ -13,7 +13,7 @@ import { PreviewDimension } from './PreviewDimension.jsx';
|
|||||||
const minCodeWrapSize = 33;
|
const minCodeWrapSize = 33;
|
||||||
|
|
||||||
/* global htmlCodeEl
|
/* global htmlCodeEl
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default class ContentWrap extends Component {
|
export default class ContentWrap extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -173,15 +173,7 @@ export default class ContentWrap extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showErrors(lang, errors) {
|
showErrors(lang, errors) {
|
||||||
var editor = this.cm[lang];
|
this.cm[lang].showErrors(errors);
|
||||||
errors.forEach(function(e) {
|
|
||||||
editor.operation(function() {
|
|
||||||
var n = document.createElement('div');
|
|
||||||
n.setAttribute('data-title', e.message);
|
|
||||||
n.classList.add('gutter-error-marker');
|
|
||||||
editor.setGutterMarker(e.lineNumber, 'error-gutter', n);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -488,35 +480,23 @@ export default class ContentWrap extends Component {
|
|||||||
updateHtmlMode(value) {
|
updateHtmlMode(value) {
|
||||||
this.props.onCodeModeChange('html', value);
|
this.props.onCodeModeChange('html', value);
|
||||||
this.props.currentItem.htmlMode = value;
|
this.props.currentItem.htmlMode = value;
|
||||||
this.cm.html.setOption('mode', modes[value].cmMode);
|
this.cm.html.setLanguage(value);
|
||||||
CodeMirror.autoLoadMode(
|
|
||||||
this.cm.html,
|
|
||||||
modes[value].cmPath || modes[value].cmMode
|
|
||||||
);
|
|
||||||
return this.handleModeRequirements(value);
|
return this.handleModeRequirements(value);
|
||||||
}
|
}
|
||||||
updateCssMode(value) {
|
updateCssMode(value) {
|
||||||
this.props.onCodeModeChange('css', value);
|
this.props.onCodeModeChange('css', value);
|
||||||
this.props.currentItem.cssMode = value;
|
this.props.currentItem.cssMode = value;
|
||||||
this.cm.css.setOption('mode', modes[value].cmMode);
|
|
||||||
this.cm.css.setOption('readOnly', modes[value].cmDisable);
|
this.cm.css.setOption('readOnly', modes[value].cmDisable);
|
||||||
window.cssSettingsBtn.classList[
|
window.cssSettingsBtn.classList[
|
||||||
modes[value].hasSettings ? 'remove' : 'add'
|
modes[value].hasSettings ? 'remove' : 'add'
|
||||||
]('hide');
|
]('hide');
|
||||||
CodeMirror.autoLoadMode(
|
this.cm.css.setLanguage(value);
|
||||||
this.cm.css,
|
|
||||||
modes[value].cmPath || modes[value].cmMode
|
|
||||||
);
|
|
||||||
return this.handleModeRequirements(value);
|
return this.handleModeRequirements(value);
|
||||||
}
|
}
|
||||||
updateJsMode(value) {
|
updateJsMode(value) {
|
||||||
this.props.onCodeModeChange('js', value);
|
this.props.onCodeModeChange('js', value);
|
||||||
this.props.currentItem.jsMode = value;
|
this.props.currentItem.jsMode = value;
|
||||||
this.cm.js.setOption('mode', modes[value].cmMode);
|
this.cm.js.setLanguage(value);
|
||||||
CodeMirror.autoLoadMode(
|
|
||||||
this.cm.js,
|
|
||||||
modes[value].cmPath || modes[value].cmMode
|
|
||||||
);
|
|
||||||
return this.handleModeRequirements(value);
|
return this.handleModeRequirements(value);
|
||||||
}
|
}
|
||||||
codeModeChangeHandler(e) {
|
codeModeChangeHandler(e) {
|
||||||
@@ -708,7 +688,8 @@ export default class ContentWrap extends Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<UserCodeMirror
|
<CodeEditor
|
||||||
|
type={this.props.prefs.isMonacoEditorOn ? 'monaco' : 'codemirror'}
|
||||||
options={{
|
options={{
|
||||||
mode: 'htmlmixed',
|
mode: 'htmlmixed',
|
||||||
profile: 'xhtml',
|
profile: 'xhtml',
|
||||||
@@ -721,7 +702,7 @@ export default class ContentWrap extends Component {
|
|||||||
}}
|
}}
|
||||||
prefs={this.props.prefs}
|
prefs={this.props.prefs}
|
||||||
onChange={this.onHtmlCodeChange.bind(this)}
|
onChange={this.onHtmlCodeChange.bind(this)}
|
||||||
onCreation={el => (this.cm.html = el)}
|
ref={editor => (this.cm.html = editor)}
|
||||||
onFocus={this.editorFocusHandler.bind(this)}
|
onFocus={this.editorFocusHandler.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -775,7 +756,8 @@ export default class ContentWrap extends Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<UserCodeMirror
|
<CodeEditor
|
||||||
|
type={this.props.prefs.isMonacoEditorOn ? 'monaco' : 'codemirror'}
|
||||||
options={{
|
options={{
|
||||||
mode: 'css',
|
mode: 'css',
|
||||||
gutters: [
|
gutters: [
|
||||||
@@ -789,7 +771,7 @@ export default class ContentWrap extends Component {
|
|||||||
}}
|
}}
|
||||||
prefs={this.props.prefs}
|
prefs={this.props.prefs}
|
||||||
onChange={this.onCssCodeChange.bind(this)}
|
onChange={this.onCssCodeChange.bind(this)}
|
||||||
onCreation={el => (this.cm.css = el)}
|
ref={editor => (this.cm.css = editor)}
|
||||||
onFocus={this.editorFocusHandler.bind(this)}
|
onFocus={this.editorFocusHandler.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -830,7 +812,8 @@ export default class ContentWrap extends Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<UserCodeMirror
|
<CodeEditor
|
||||||
|
type={this.props.prefs.isMonacoEditorOn ? 'monaco' : 'codemirror'}
|
||||||
options={{
|
options={{
|
||||||
mode: 'javascript',
|
mode: 'javascript',
|
||||||
gutters: [
|
gutters: [
|
||||||
@@ -844,7 +827,7 @@ export default class ContentWrap extends Component {
|
|||||||
prefs={this.props.prefs}
|
prefs={this.props.prefs}
|
||||||
autoComplete={this.props.prefs.autoComplete}
|
autoComplete={this.props.prefs.autoComplete}
|
||||||
onChange={this.onJsCodeChange.bind(this)}
|
onChange={this.onJsCodeChange.bind(this)}
|
||||||
onCreation={el => (this.cm.js = el)}
|
ref={editor => (this.cm.js = editor)}
|
||||||
onFocus={this.editorFocusHandler.bind(this)}
|
onFocus={this.editorFocusHandler.bind(this)}
|
||||||
/>
|
/>
|
||||||
{/* Inlet(scope.cm.js); */}
|
{/* Inlet(scope.cm.js); */}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { h, Component } from 'preact';
|
import { h, Component } from 'preact';
|
||||||
import UserCodeMirror from './UserCodeMirror';
|
import CodeEditor from './CodeEditor';
|
||||||
import { modes, HtmlModes, CssModes, JsModes } from '../codeModes';
|
import { modes, HtmlModes, CssModes, JsModes } from '../codeModes';
|
||||||
import { log, loadJS } from '../utils';
|
import { log, loadJS } from '../utils';
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ import { PreviewDimension } from './PreviewDimension';
|
|||||||
const minCodeWrapSize = 33;
|
const minCodeWrapSize = 33;
|
||||||
|
|
||||||
/* global htmlCodeEl
|
/* global htmlCodeEl
|
||||||
*/
|
*/
|
||||||
export default class ContentWrapFiles extends Component {
|
export default class ContentWrapFiles extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -86,7 +86,7 @@ export default class ContentWrapFiles extends Component {
|
|||||||
this.state.selectedFile &&
|
this.state.selectedFile &&
|
||||||
this.fileBuffers[this.state.selectedFile.path]
|
this.fileBuffers[this.state.selectedFile.path]
|
||||||
) {
|
) {
|
||||||
this.fileBuffers[this.state.selectedFile.path].setValue(
|
this.fileBuffers[this.state.selectedFile.path].model.setValue(
|
||||||
getFileFromPath(
|
getFileFromPath(
|
||||||
nextProps.currentItem.files,
|
nextProps.currentItem.files,
|
||||||
this.state.selectedFile.path
|
this.state.selectedFile.path
|
||||||
@@ -168,12 +168,23 @@ export default class ContentWrapFiles extends Component {
|
|||||||
CodeMirror.autoLoadMode(this.cm, mode);
|
CodeMirror.autoLoadMode(this.cm, mode);
|
||||||
}
|
}
|
||||||
if (mime === 'application/json') {
|
if (mime === 'application/json') {
|
||||||
mime = 'application/ld+json';
|
mime = this.props.prefs.isMonacoEditorOn ? 'json' : 'application/ld+json';
|
||||||
|
}
|
||||||
|
if (!this.props.prefs.isMonacoEditorOn) {
|
||||||
|
this.fileBuffers[file.path] = {
|
||||||
|
model: CodeMirror.Doc(
|
||||||
|
file.content || '',
|
||||||
|
detectedMode ? mime : 'text/plain'
|
||||||
|
)
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
this.fileBuffers[file.path] = {
|
||||||
|
model: monaco.editor.createModel(
|
||||||
|
file.content || '',
|
||||||
|
mime || 'javascript'
|
||||||
|
)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
this.fileBuffers[file.path] = CodeMirror.Doc(
|
|
||||||
file.content || '',
|
|
||||||
detectedMode ? mime : 'text/plain'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onHtmlCodeChange(editor, change) {
|
onHtmlCodeChange(editor, change) {
|
||||||
@@ -184,10 +195,10 @@ export default class ContentWrapFiles extends Component {
|
|||||||
this.cmCodes.html,
|
this.cmCodes.html,
|
||||||
change.origin !== 'setValue'
|
change.origin !== 'setValue'
|
||||||
);
|
);
|
||||||
this.onCodeChange(editor, change);
|
this.onCodeChange(change);
|
||||||
}
|
}
|
||||||
|
|
||||||
onCodeChange(editor, change) {
|
onCodeChange(change) {
|
||||||
clearTimeout(this.updateTimer);
|
clearTimeout(this.updateTimer);
|
||||||
|
|
||||||
this.updateTimer = setTimeout(() => {
|
this.updateTimer = setTimeout(() => {
|
||||||
@@ -249,19 +260,11 @@ export default class ContentWrapFiles extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cleanupErrors() {
|
cleanupErrors() {
|
||||||
this.cm.clearGutter('error-gutter');
|
this.editor.clearGutter('error-gutter');
|
||||||
}
|
}
|
||||||
|
|
||||||
showErrors(lang, errors) {
|
showErrors(errors) {
|
||||||
var editor = this.cm;
|
this.editor.showErrors(errors);
|
||||||
errors.forEach(function(e) {
|
|
||||||
editor.operation(function() {
|
|
||||||
var n = document.createElement('div');
|
|
||||||
n.setAttribute('data-title', e.message);
|
|
||||||
n.classList.add('gutter-error-marker');
|
|
||||||
editor.setGutterMarker(e.lineNumber, 'error-gutter', n);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -305,9 +308,11 @@ export default class ContentWrapFiles extends Component {
|
|||||||
}
|
}
|
||||||
refreshEditor() {
|
refreshEditor() {
|
||||||
if (this.state.selectedFile) {
|
if (this.state.selectedFile) {
|
||||||
this.cm.setValue(this.state.selectedFile.content);
|
this.editor.setValue(this.state.selectedFile.content);
|
||||||
|
}
|
||||||
|
if (this.editor) {
|
||||||
|
this.editor.refresh();
|
||||||
}
|
}
|
||||||
this.cm.refresh();
|
|
||||||
window.cm = this.cm;
|
window.cm = this.cm;
|
||||||
|
|
||||||
this.clearConsole();
|
this.clearConsole();
|
||||||
@@ -498,25 +503,26 @@ export default class ContentWrapFiles extends Component {
|
|||||||
this.props.onFolderSelect(file);
|
this.props.onFolderSelect(file);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.fileBuffers[file.path]) {
|
||||||
|
this.createEditorDoc(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentState = this.editor.saveViewState();
|
||||||
|
if (currentState && this.state.selectedFile) {
|
||||||
|
this.fileBuffers[this.state.selectedFile.path].state = currentState;
|
||||||
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
editorOptions: this.getEditorOptions(file.name),
|
editorOptions: this.getEditorOptions(file.name),
|
||||||
selectedFile: file
|
selectedFile: file
|
||||||
});
|
});
|
||||||
if (!this.fileBuffers[file.path]) {
|
|
||||||
this.createEditorDoc(file);
|
|
||||||
}
|
|
||||||
this.cm.swapDoc(this.fileBuffers[file.path]);
|
|
||||||
|
|
||||||
// var cmMode = 'html';
|
this.editor.setModel(this.fileBuffers[file.path].model);
|
||||||
// if (file.name.match(/\.css$/)) {
|
if (this.fileBuffers[file.path].state) {
|
||||||
// this.updateCssMode('css');
|
this.editor.restoreViewState(this.fileBuffers[file.path].state);
|
||||||
// } else if (file.name.match(/\.js$/)) {
|
}
|
||||||
// this.updateCssMode('js');
|
|
||||||
// } else {
|
this.editor.focus();
|
||||||
// this.updateCssMode('html');
|
|
||||||
// }
|
|
||||||
// this.cm.setValue(file.content || '');
|
|
||||||
this.cm.focus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessageFromConsole() {
|
onMessageFromConsole() {
|
||||||
@@ -637,14 +643,15 @@ export default class ContentWrapFiles extends Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<UserCodeMirror
|
<CodeEditor
|
||||||
|
type={this.props.prefs.isMonacoEditorOn ? 'monaco' : 'codemirror'}
|
||||||
value={
|
value={
|
||||||
this.state.selectedFile ? this.state.selectedFile.content : ''
|
this.state.selectedFile ? this.state.selectedFile.content : ''
|
||||||
}
|
}
|
||||||
options={this.state.editorOptions}
|
options={this.state.editorOptions}
|
||||||
prefs={this.props.prefs}
|
prefs={this.props.prefs}
|
||||||
onChange={this.onHtmlCodeChange.bind(this)}
|
onChange={this.onHtmlCodeChange.bind(this)}
|
||||||
onCreation={editor => (this.cm = editor)}
|
ref={editor => (this.editor = editor)}
|
||||||
onFocus={this.editorFocusHandler.bind(this)}
|
onFocus={this.editorFocusHandler.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -11,6 +11,10 @@ function CheckboxSetting({ label, onChange, pref }) {
|
|||||||
</Switch>
|
</Switch>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
function HelpText({ children }) {
|
||||||
|
return <p class="help-text">{children}</p>;
|
||||||
|
}
|
||||||
|
|
||||||
export default class Settings extends Component {
|
export default class Settings extends Component {
|
||||||
updateSetting(e, settingName) {
|
updateSetting(e, settingName) {
|
||||||
const value =
|
const value =
|
||||||
@@ -34,47 +38,45 @@ export default class Settings extends Component {
|
|||||||
pref={prefs.preserveLastCode}
|
pref={prefs.preserveLastCode}
|
||||||
onChange={e => this.updateSetting(e, 'preserveLastCode')}
|
onChange={e => this.updateSetting(e, 'preserveLastCode')}
|
||||||
/>
|
/>
|
||||||
<p class="help-text">
|
<HelpText>Loads the last open creation when app starts</HelpText>
|
||||||
Loads the last open creation when app starts
|
|
||||||
</p>
|
|
||||||
<Divider />
|
<Divider />
|
||||||
<CheckboxSetting
|
<CheckboxSetting
|
||||||
label="Fast/light version"
|
label="Fast/light version"
|
||||||
pref={prefs.lightVersion}
|
pref={prefs.lightVersion}
|
||||||
onChange={e => this.updateSetting(e, 'lightVersion')}
|
onChange={e => this.updateSetting(e, 'lightVersion')}
|
||||||
/>
|
/>
|
||||||
<p class="help-text">
|
<HelpText>
|
||||||
Switch to lighter version for better performance. Removes things
|
Switch to lighter version for better performance. Removes things
|
||||||
like blur etc.
|
like blur etc.
|
||||||
</p>
|
</HelpText>
|
||||||
<Divider />
|
<Divider />
|
||||||
<CheckboxSetting
|
<CheckboxSetting
|
||||||
label="Auto-preview"
|
label="Auto-preview"
|
||||||
pref={prefs.autoPreview}
|
pref={prefs.autoPreview}
|
||||||
onChange={e => this.updateSetting(e, 'autoPreview')}
|
onChange={e => this.updateSetting(e, 'autoPreview')}
|
||||||
/>
|
/>
|
||||||
<p class="help-text">
|
<HelpText>
|
||||||
Refreshes the preview as you code. Otherwise use the 'Run' button
|
Refreshes the preview as you code. Otherwise use the 'Run' button
|
||||||
</p>
|
</HelpText>
|
||||||
<Divider />
|
<Divider />
|
||||||
<CheckboxSetting
|
<CheckboxSetting
|
||||||
label="Auto-save"
|
label="Auto-save"
|
||||||
pref={prefs.autoSave}
|
pref={prefs.autoSave}
|
||||||
onChange={e => this.updateSetting(e, 'autoSave')}
|
onChange={e => this.updateSetting(e, 'autoSave')}
|
||||||
/>
|
/>
|
||||||
<p class="help-text">
|
<HelpText>
|
||||||
Auto-save keeps saving your code at regular intervals after you
|
Auto-save keeps saving your code at regular intervals after you
|
||||||
hit save manually the first time
|
hit save manually the first time
|
||||||
</p>
|
</HelpText>
|
||||||
<Divider />
|
<Divider />
|
||||||
<CheckboxSetting
|
<CheckboxSetting
|
||||||
label="Refresh preview on resize"
|
label="Refresh preview on resize"
|
||||||
pref={prefs.refreshOnResize}
|
pref={prefs.refreshOnResize}
|
||||||
onChange={e => this.updateSetting(e, 'refreshOnResize')}
|
onChange={e => this.updateSetting(e, 'refreshOnResize')}
|
||||||
/>
|
/>
|
||||||
<p class="help-text">
|
<HelpText>
|
||||||
Preview will refresh when you resize the preview pane
|
Preview will refresh when you resize the preview pane
|
||||||
</p>
|
</HelpText>
|
||||||
<div class="show-when-extension">
|
<div class="show-when-extension">
|
||||||
<Divider />
|
<Divider />
|
||||||
<CheckboxSetting
|
<CheckboxSetting
|
||||||
@@ -83,10 +85,10 @@ export default class Settings extends Component {
|
|||||||
onChange={e => this.updateSetting(e, 'replaceNewTab')}
|
onChange={e => this.updateSetting(e, 'replaceNewTab')}
|
||||||
showWhenExtension
|
showWhenExtension
|
||||||
/>
|
/>
|
||||||
<p class="help-text">
|
<HelpText>
|
||||||
Turning this on will start showing Web Maker in every new tab
|
Turning this on will start showing Web Maker in every new tab
|
||||||
you open
|
you open
|
||||||
</p>
|
</HelpText>
|
||||||
</div>
|
</div>
|
||||||
<Divider />
|
<Divider />
|
||||||
<CheckboxSetting
|
<CheckboxSetting
|
||||||
@@ -94,9 +96,9 @@ export default class Settings extends Component {
|
|||||||
pref={prefs.preserveConsoleLogs}
|
pref={prefs.preserveConsoleLogs}
|
||||||
onChange={e => this.updateSetting(e, 'preserveConsoleLogs')}
|
onChange={e => this.updateSetting(e, 'preserveConsoleLogs')}
|
||||||
/>
|
/>
|
||||||
<p class="help-text">
|
<HelpText>
|
||||||
Preserves the console logs across your preview refreshes
|
Preserves the console logs across your preview refreshes
|
||||||
</p>
|
</HelpText>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel label="Indentation">
|
<TabPanel label="Indentation">
|
||||||
<div class="line">
|
<div class="line">
|
||||||
@@ -151,6 +153,17 @@ export default class Settings extends Component {
|
|||||||
<TabPanel label="Editor">
|
<TabPanel label="Editor">
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
|
<CheckboxSetting
|
||||||
|
title="Use experimental Monaco editor"
|
||||||
|
label="Use Monaco Editor"
|
||||||
|
pref={prefs.isMonacoEditorOn}
|
||||||
|
onChange={e => this.updateSetting(e, 'isMonacoEditorOn')}
|
||||||
|
/>
|
||||||
|
<HelpText>
|
||||||
|
(Experimental) Switches from CodeMirror to Monaco. Many other
|
||||||
|
settings might not be available in Monaco.
|
||||||
|
</HelpText>
|
||||||
|
<Divider />
|
||||||
<div class="line">
|
<div class="line">
|
||||||
<span>Default Preprocessors</span>
|
<span>Default Preprocessors</span>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
@@ -308,21 +321,20 @@ export default class Settings extends Component {
|
|||||||
pref={prefs.isCodeBlastOn}
|
pref={prefs.isCodeBlastOn}
|
||||||
onChange={e => this.updateSetting(e, 'isCodeBlastOn')}
|
onChange={e => this.updateSetting(e, 'isCodeBlastOn')}
|
||||||
/>
|
/>
|
||||||
<p class="help-text">
|
<HelpText>Enjoy wonderful particle blasts while you type</HelpText>
|
||||||
Enjoy wonderful particle blasts while you type
|
|
||||||
</p>
|
|
||||||
<Divider />
|
<Divider />
|
||||||
<CheckboxSetting
|
<CheckboxSetting
|
||||||
label="Js13kGames Mode"
|
label="Js13kGames Mode"
|
||||||
pref={prefs.isJs13kModeOn}
|
pref={prefs.isJs13kModeOn}
|
||||||
onChange={e => this.updateSetting(e, 'isJs13kModeOn')}
|
onChange={e => this.updateSetting(e, 'isJs13kModeOn')}
|
||||||
/>
|
/>
|
||||||
<p class="help-text">
|
<HelpText>
|
||||||
Make the app ready to build some games for{' '}
|
Make the app ready to build some games for{' '}
|
||||||
<a href="https://js13kgames.com/" target="_blank" rel="noopener">
|
<a href="https://js13kgames.com/" target="_blank" rel="noopener">
|
||||||
Js13kGames
|
Js13kGames
|
||||||
</a>.
|
</a>
|
||||||
</p>
|
.
|
||||||
|
</HelpText>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel label="Advanced">
|
<TabPanel label="Advanced">
|
||||||
<div>
|
<div>
|
||||||
@@ -338,11 +350,11 @@ export default class Settings extends Component {
|
|||||||
ms
|
ms
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<p class="help-text">
|
<HelpText>
|
||||||
If any loop iteration takes more than the defined time, it is
|
If any loop iteration takes more than the defined time, it is
|
||||||
detected as a potential infinite loop and further iterations are
|
detected as a potential infinite loop and further iterations are
|
||||||
stopped.
|
stopped.
|
||||||
</p>
|
</HelpText>
|
||||||
</div>
|
</div>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
|
@@ -5,7 +5,11 @@ export class SplitPane extends Component {
|
|||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.updateSplit();
|
this.updateSplit();
|
||||||
}
|
}
|
||||||
|
componentWillUpdate() {
|
||||||
|
if (this.splitInstance) {
|
||||||
|
this.splitInstance.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (this.hasGutter() && !this.hasPropsChanged(prevProps, this.props)) {
|
if (this.hasGutter() && !this.hasPropsChanged(prevProps, this.props)) {
|
||||||
return;
|
return;
|
||||||
@@ -33,13 +37,8 @@ export class SplitPane extends Component {
|
|||||||
const { children, ...options } = this.props;
|
const { children, ...options } = this.props;
|
||||||
options.gutterSize = 6;
|
options.gutterSize = 6;
|
||||||
|
|
||||||
if (this.splitInstance && this.hasGutter()) {
|
|
||||||
this.splitInstance.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* eslint-disable new-cap */
|
/* eslint-disable new-cap */
|
||||||
this.splitInstance = Split([...this.parent.children], options);
|
this.splitInstance = Split([...this.parent.children], options);
|
||||||
console.log('recreating split');
|
|
||||||
|
|
||||||
/* eslint-enable new-cap */
|
/* eslint-enable new-cap */
|
||||||
|
|
||||||
|
@@ -1,176 +0,0 @@
|
|||||||
import { h, Component } from 'preact';
|
|
||||||
import CodeMirror from '../CodeMirror';
|
|
||||||
|
|
||||||
import 'codemirror/addon/edit/matchbrackets.js';
|
|
||||||
import 'codemirror/addon/edit/matchtags.js';
|
|
||||||
import 'codemirror/addon/edit/closebrackets.js';
|
|
||||||
import 'codemirror/addon/edit/closetag.js';
|
|
||||||
import 'codemirror/addon/comment/comment.js';
|
|
||||||
import 'codemirror/addon/fold/foldcode.js';
|
|
||||||
import 'codemirror/addon/fold/foldgutter.js';
|
|
||||||
import 'codemirror/addon/fold/xml-fold.js';
|
|
||||||
import 'codemirror/addon/fold/indent-fold.js';
|
|
||||||
import 'codemirror/addon/fold/comment-fold.js';
|
|
||||||
import 'codemirror/addon/fold/brace-fold.js';
|
|
||||||
import 'codemirror/addon/hint/show-hint.js';
|
|
||||||
import 'codemirror/addon/hint/javascript-hint.js';
|
|
||||||
import 'codemirror/addon/hint/xml-hint.js';
|
|
||||||
import 'codemirror/addon/hint/html-hint.js';
|
|
||||||
import 'codemirror/addon/hint/css-hint.js';
|
|
||||||
import 'codemirror/addon/selection/active-line.js';
|
|
||||||
import 'codemirror/addon/search/searchcursor.js';
|
|
||||||
import 'codemirror/addon/search/search.js';
|
|
||||||
import 'codemirror/addon/dialog/dialog.js';
|
|
||||||
import 'codemirror/addon/search/jump-to-line.js';
|
|
||||||
|
|
||||||
import 'codemirror/mode/xml/xml.js';
|
|
||||||
import 'codemirror/mode/css/css.js';
|
|
||||||
import 'codemirror/mode/javascript/javascript.js';
|
|
||||||
import 'codemirror/mode/htmlmixed/htmlmixed.js';
|
|
||||||
import 'codemirror/keymap/sublime.js';
|
|
||||||
import 'codemirror/keymap/vim.js';
|
|
||||||
import 'code-blast-codemirror/code-blast.js';
|
|
||||||
|
|
||||||
import emmet from '@emmetio/codemirror-plugin';
|
|
||||||
import { prettify } from '../utils';
|
|
||||||
|
|
||||||
emmet(CodeMirror);
|
|
||||||
|
|
||||||
export default class UserCodeMirror extends Component {
|
|
||||||
componentDidMount() {
|
|
||||||
this.initEditor();
|
|
||||||
}
|
|
||||||
shouldComponentUpdate(nextProps) {
|
|
||||||
if (nextProps.prefs !== this.props.prefs) {
|
|
||||||
const { prefs } = nextProps;
|
|
||||||
|
|
||||||
this.cm.setOption('indentWithTabs', prefs.indentWith !== 'spaces');
|
|
||||||
this.cm.setOption(
|
|
||||||
'blastCode',
|
|
||||||
prefs.isCodeBlastOn ? { effect: 2, shake: false } : false
|
|
||||||
);
|
|
||||||
this.cm.setOption('theme', prefs.editorTheme);
|
|
||||||
|
|
||||||
this.cm.setOption('indentUnit', +prefs.indentSize);
|
|
||||||
this.cm.setOption('tabSize', +prefs.indentSize);
|
|
||||||
|
|
||||||
this.cm.setOption('keyMap', prefs.keymap);
|
|
||||||
this.cm.setOption('lineWrapping', prefs.lineWrap);
|
|
||||||
this.cm.setOption('lineWrapping', prefs.autoCloseTags);
|
|
||||||
|
|
||||||
this.cm.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initEditor() {
|
|
||||||
const { options, prefs } = this.props;
|
|
||||||
this.cm = CodeMirror.fromTextArea(this.textarea, {
|
|
||||||
mode: options.mode,
|
|
||||||
lineNumbers: true,
|
|
||||||
lineWrapping: !!prefs.lineWrap,
|
|
||||||
autofocus: options.autofocus || false,
|
|
||||||
autoCloseBrackets: true,
|
|
||||||
autoCloseTags: !!prefs.autoCloseTags,
|
|
||||||
matchBrackets: true,
|
|
||||||
matchTags: options.matchTags || false,
|
|
||||||
tabMode: 'indent',
|
|
||||||
keyMap: prefs.keyMap || 'sublime',
|
|
||||||
theme: prefs.editorTheme || 'monokai',
|
|
||||||
lint: !!options.lint,
|
|
||||||
tabSize: +prefs.indentSize || 2,
|
|
||||||
indentWithTabs: prefs.indentWith !== 'spaces',
|
|
||||||
indentUnit: +prefs.indentSize,
|
|
||||||
foldGutter: true,
|
|
||||||
styleActiveLine: true,
|
|
||||||
gutters: options.gutters || [],
|
|
||||||
// cursorScrollMargin: '20', has issue with scrolling
|
|
||||||
profile: options.profile || '',
|
|
||||||
extraKeys: {
|
|
||||||
Up: function(editor) {
|
|
||||||
// Stop up/down keys default behavior when saveditempane is open
|
|
||||||
// if (isSavedItemsPaneOpen) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
CodeMirror.commands.goLineUp(editor);
|
|
||||||
},
|
|
||||||
Down: function(editor) {
|
|
||||||
// if (isSavedItemsPaneOpen) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
CodeMirror.commands.goLineDown(editor);
|
|
||||||
},
|
|
||||||
'Shift-Tab': function(editor) {
|
|
||||||
CodeMirror.commands.indentAuto(editor);
|
|
||||||
},
|
|
||||||
'Shift-Ctrl-F': function(editor) {
|
|
||||||
if (options.prettier) {
|
|
||||||
prettify({
|
|
||||||
content: editor.getValue(),
|
|
||||||
type: options.prettierParser
|
|
||||||
}).then(formattedCode => editor.setValue(formattedCode));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Tab: function(editor) {
|
|
||||||
if (options.emmet) {
|
|
||||||
const didEmmetWork = editor.execCommand('emmetExpandAbbreviation');
|
|
||||||
if (didEmmetWork === true) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const input = $('[data-setting=indentWith]:checked');
|
|
||||||
if (
|
|
||||||
!editor.somethingSelected() &&
|
|
||||||
(!prefs.indentWith || prefs.indentWith === 'spaces')
|
|
||||||
) {
|
|
||||||
// softtabs adds spaces. This is required because by default tab key will put tab, but we want
|
|
||||||
// to indent with spaces if `spaces` is preferred mode of indentation.
|
|
||||||
// `somethingSelected` needs to be checked otherwise, all selected code is replaced with softtab.
|
|
||||||
CodeMirror.commands.insertSoftTab(editor);
|
|
||||||
} else {
|
|
||||||
CodeMirror.commands.defaultTab(editor);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Enter: 'emmetInsertLineBreak'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.cm.on('focus', editor => {
|
|
||||||
if (typeof this.props.onFocus === 'function') this.props.onFocus(editor);
|
|
||||||
});
|
|
||||||
this.cm.on('change', this.props.onChange);
|
|
||||||
this.cm.addKeyMap({
|
|
||||||
'Ctrl-Space': 'autocomplete'
|
|
||||||
});
|
|
||||||
this.cm.on('inputRead', (editor, input) => {
|
|
||||||
// Process further If this has autocompletition on and also the global
|
|
||||||
// autocomplete setting is on.
|
|
||||||
if (!this.props.options.noAutocomplete && this.props.prefs.autoComplete) {
|
|
||||||
if (
|
|
||||||
input.origin !== '+input' ||
|
|
||||||
input.text[0] === ';' ||
|
|
||||||
input.text[0] === ',' ||
|
|
||||||
input.text[0] === ' '
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CodeMirror.commands.autocomplete(this.cm, null, {
|
|
||||||
completeSingle: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.props.onCreation(this.cm);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<textarea
|
|
||||||
ref={el => (this.textarea = el)}
|
|
||||||
name=""
|
|
||||||
id=""
|
|
||||||
cols="30"
|
|
||||||
rows="10"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -133,7 +133,8 @@ export default class App extends Component {
|
|||||||
layoutMode: 2,
|
layoutMode: 2,
|
||||||
isJs13kModeOn: false,
|
isJs13kModeOn: false,
|
||||||
autoCloseTags: true,
|
autoCloseTags: true,
|
||||||
lang: 'en'
|
lang: 'en',
|
||||||
|
isMonacoEditorOn: false
|
||||||
};
|
};
|
||||||
this.prefs = {};
|
this.prefs = {};
|
||||||
|
|
||||||
@@ -1527,20 +1528,6 @@ export default class App extends Component {
|
|||||||
|
|
||||||
<Alerts />
|
<Alerts />
|
||||||
|
|
||||||
<form
|
|
||||||
style="display:none;"
|
|
||||||
action="https://codepen.io/pen/define"
|
|
||||||
method="POST"
|
|
||||||
target="_blank"
|
|
||||||
id="js-codepen-form"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="hidden"
|
|
||||||
name="data"
|
|
||||||
value="{"title": "New Pen!", "html": "<div>Hello, World!</div>"}"
|
|
||||||
/>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
show={this.state.isAddLibraryModalOpen}
|
show={this.state.isAddLibraryModalOpen}
|
||||||
closeHandler={() => this.setState({ isAddLibraryModalOpen: false })}
|
closeHandler={() => this.setState({ isAddLibraryModalOpen: false })}
|
||||||
@@ -1674,7 +1661,7 @@ export default class App extends Component {
|
|||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
name="data"
|
name="data"
|
||||||
value="{"title": "New Pen!", "html": "<div>Hello, World!</div>"}"
|
value='{"title": "New Pen!", "html": "<div>Hello, World!</div>"}'
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -55,9 +55,9 @@ import { log } from './utils';
|
|||||||
if (db) {
|
if (db) {
|
||||||
return resolve(db);
|
return resolve(db);
|
||||||
}
|
}
|
||||||
const _firestore = firebase.firestore();
|
const firestoreInstance = firebase.firestore();
|
||||||
_firestore.settings({ timestampsInSnapshots: true });
|
firestoreInstance.settings({ timestampsInSnapshots: true });
|
||||||
return _firestore
|
return firestoreInstance
|
||||||
.enablePersistence({ experimentalTabSynchronization: true })
|
.enablePersistence({ experimentalTabSynchronization: true })
|
||||||
.then(function() {
|
.then(function() {
|
||||||
// Initialize Cloud Firestore through firebase
|
// Initialize Cloud Firestore through firebase
|
||||||
|
6
src/lib/monaco/monaco.bundle.js
Normal file
6
src/lib/monaco/monaco.bundle.js
Normal file
File diff suppressed because one or more lines are too long
3843
src/lib/monaco/monaco.css
Normal file
3843
src/lib/monaco/monaco.css
Normal file
File diff suppressed because one or more lines are too long
2
src/lib/monaco/workers/css.worker.bundle.js
Normal file
2
src/lib/monaco/workers/css.worker.bundle.js
Normal file
File diff suppressed because one or more lines are too long
2
src/lib/monaco/workers/editor.worker.bundle.js
Normal file
2
src/lib/monaco/workers/editor.worker.bundle.js
Normal file
File diff suppressed because one or more lines are too long
8
src/lib/monaco/workers/html.worker.bundle.js
Normal file
8
src/lib/monaco/workers/html.worker.bundle.js
Normal file
File diff suppressed because one or more lines are too long
2
src/lib/monaco/workers/json.worker.bundle.js
Normal file
2
src/lib/monaco/workers/json.worker.bundle.js
Normal file
File diff suppressed because one or more lines are too long
17
src/lib/monaco/workers/ts.worker.bundle.js
Normal file
17
src/lib/monaco/workers/ts.worker.bundle.js
Normal file
File diff suppressed because one or more lines are too long
@@ -49,6 +49,11 @@ if (
|
|||||||
// It's the perfect time to display a "New content is available; please refresh."
|
// It's the perfect time to display a "New content is available; please refresh."
|
||||||
// message in the page's interface.
|
// message in the page's interface.
|
||||||
console.log('New or updated content is available.');
|
console.log('New or updated content is available.');
|
||||||
|
if (window.alertsService) {
|
||||||
|
window.alertsService.add(
|
||||||
|
'New version available. Please refresh the page.'
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// At this point, everything has been precached.
|
// At this point, everything has been precached.
|
||||||
// It's the perfect time to display a "Content is cached for offline use." message.
|
// It's the perfect time to display a "Content is cached for offline use." message.
|
||||||
|
15
src/utils.js
15
src/utils.js
@@ -305,6 +305,21 @@ export function loadJS(src) {
|
|||||||
return d.promise;
|
return d.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function loadCss({ url, id }) {
|
||||||
|
var d = deferred();
|
||||||
|
var style = window.document.createElement('link');
|
||||||
|
style.setAttribute('href', url);
|
||||||
|
style.setAttribute('rel', 'stylesheet');
|
||||||
|
if (id) {
|
||||||
|
style.setAttribute('id', id);
|
||||||
|
}
|
||||||
|
document.head.appendChild(style);
|
||||||
|
style.onload = function() {
|
||||||
|
d.resolve();
|
||||||
|
};
|
||||||
|
return d.promise;
|
||||||
|
}
|
||||||
|
|
||||||
/* eslint-disable max-params */
|
/* eslint-disable max-params */
|
||||||
export function getCompleteHtml(html, css, js, item, isForExport) {
|
export function getCompleteHtml(html, css, js, item, isForExport) {
|
||||||
/* eslint-enable max-params */
|
/* eslint-enable max-params */
|
||||||
|
Reference in New Issue
Block a user