mirror of
https://github.com/chinchang/web-maker.git
synced 2025-07-17 12:01:13 +02:00
add monaco firt draft. fixes #275
This commit is contained in:
255
src/components/CodeEditor.jsx
Normal file
255
src/components/CodeEditor.jsx
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
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';
|
||||||
|
|
||||||
|
import '../lib/monaco/monaco.bundle';
|
||||||
|
import '../lib/monaco/monaco.css';
|
||||||
|
|
||||||
|
emmet(CodeMirror);
|
||||||
|
window.MonacoEnvironment = {
|
||||||
|
getWorkerUrl(moduleId, label) {
|
||||||
|
let MonacoWorker;
|
||||||
|
|
||||||
|
switch (label) {
|
||||||
|
case 'html':
|
||||||
|
return 'lib/monaco/workers/html.worker.bundle.js';
|
||||||
|
case 'json':
|
||||||
|
return 'lib/monaco/workers/json.worker.bundle.js';
|
||||||
|
case 'css':
|
||||||
|
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;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
setModel(model) {
|
||||||
|
this.instance.swapDoc
|
||||||
|
? this.instance.swapDoc(model)
|
||||||
|
: this.instance.setModel(model);
|
||||||
|
}
|
||||||
|
setValue(value) {
|
||||||
|
this.instance.setValue
|
||||||
|
? this.instance.setValue(value)
|
||||||
|
: this.instance.setModel(model);
|
||||||
|
}
|
||||||
|
getValue() {
|
||||||
|
return this.instance.getValue();
|
||||||
|
}
|
||||||
|
saveViewState() {
|
||||||
|
if (this.props.mode === 'monaco') {
|
||||||
|
return this.instance.saveViewState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
restoreViewState(state) {
|
||||||
|
if (this.props.mode === 'monaco') {
|
||||||
|
this.instance.restoreViewState(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
this.instance.refresh ? this.instance.refresh() : this.instance.layout();
|
||||||
|
}
|
||||||
|
focus() {
|
||||||
|
this.instance.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
initEditor() {
|
||||||
|
const { options, prefs } = this.props;
|
||||||
|
if (this.props.mode === 'monaco') {
|
||||||
|
this.instance = monaco.editor.create(this.textarea, {
|
||||||
|
language: 'javascript',
|
||||||
|
roundedSelection: false,
|
||||||
|
scrollBeyondLastLine: false,
|
||||||
|
theme: 'vs-dark',
|
||||||
|
fontSize: prefs.fontSize,
|
||||||
|
minimap: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
wordWrap: 'on',
|
||||||
|
fontLigatures: true,
|
||||||
|
automaticLayout: true
|
||||||
|
});
|
||||||
|
window.monacoInstance = this.instance;
|
||||||
|
this.instance.onDidChangeModelContent(this.props.onChange);
|
||||||
|
setTimeout(() => {
|
||||||
|
// this.instance.layout();
|
||||||
|
}, 1000);
|
||||||
|
} else {
|
||||||
|
this.instance = CodeMirror.fromTextArea(
|
||||||
|
this.textarea.querySelector('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.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() {
|
||||||
|
return (
|
||||||
|
<div ref={el => (this.textarea = el)} style="width:100%;height:100%;">
|
||||||
|
{this.props.mode === 'monaco' ? null : <textarea />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -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) {
|
||||||
@@ -708,7 +708,7 @@ export default class ContentWrap extends Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<UserCodeMirror
|
<CodeEditor
|
||||||
options={{
|
options={{
|
||||||
mode: 'htmlmixed',
|
mode: 'htmlmixed',
|
||||||
profile: 'xhtml',
|
profile: 'xhtml',
|
||||||
@@ -775,7 +775,7 @@ export default class ContentWrap extends Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<UserCodeMirror
|
<CodeEditor
|
||||||
options={{
|
options={{
|
||||||
mode: 'css',
|
mode: 'css',
|
||||||
gutters: [
|
gutters: [
|
||||||
@@ -830,7 +830,7 @@ export default class ContentWrap extends Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<UserCodeMirror
|
<CodeEditor
|
||||||
options={{
|
options={{
|
||||||
mode: 'javascript',
|
mode: 'javascript',
|
||||||
gutters: [
|
gutters: [
|
||||||
|
@@ -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,32 +168,43 @@ 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) {
|
||||||
this.cmCodes.html = editor.getValue();
|
this.cmCodes.html = this.editor.getValue();
|
||||||
|
|
||||||
this.props.onCodeChange(
|
this.props.onCodeChange(
|
||||||
this.state.selectedFile,
|
this.state.selectedFile,
|
||||||
this.cmCodes.html,
|
this.cmCodes.html,
|
||||||
change.origin !== 'setValue'
|
change ? change.origin !== 'setValue' : true
|
||||||
);
|
);
|
||||||
this.onCodeChange(editor, change);
|
this.onCodeChange(change);
|
||||||
}
|
}
|
||||||
|
|
||||||
onCodeChange(editor, change) {
|
onCodeChange(change) {
|
||||||
clearTimeout(this.updateTimer);
|
clearTimeout(this.updateTimer);
|
||||||
|
|
||||||
this.updateTimer = setTimeout(() => {
|
this.updateTimer = setTimeout(() => {
|
||||||
// This is done so that multiple simultaneous setValue don't trigger too many preview refreshes
|
// This is done so that multiple simultaneous setValue don't trigger too many preview refreshes
|
||||||
// and in turn too many file writes on a single file (eg. preview.html).
|
// and in turn too many file writes on a single file (eg. preview.html).
|
||||||
if (change.origin !== 'setValue') {
|
if (change ? change.origin !== 'setValue' : true) {
|
||||||
// Specifically checking for false so that the condition doesn't get true even
|
// Specifically checking for false so that the condition doesn't get true even
|
||||||
// on absent key - possible when the setting key hasn't been fetched yet.
|
// on absent key - possible when the setting key hasn't been fetched yet.
|
||||||
if (this.prefs.autoPreview !== false) {
|
if (this.prefs.autoPreview !== false) {
|
||||||
@@ -249,7 +260,9 @@ export default class ContentWrapFiles extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cleanupErrors() {
|
cleanupErrors() {
|
||||||
this.cm.clearGutter('error-gutter');
|
if (!this.props.prefs.isMonacoEditorOn) {
|
||||||
|
// this.editor.clearGutter('error-gutter');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showErrors(lang, errors) {
|
showErrors(lang, errors) {
|
||||||
@@ -305,9 +318,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();
|
||||||
@@ -401,6 +416,7 @@ export default class ContentWrapFiles extends Component {
|
|||||||
}, 1);
|
}, 1);
|
||||||
}
|
}
|
||||||
this.updateSplits();
|
this.updateSplits();
|
||||||
|
// this.editor.refresh();
|
||||||
}
|
}
|
||||||
mainSplitDragHandler() {
|
mainSplitDragHandler() {
|
||||||
this.previewDimension.update({
|
this.previewDimension.update({
|
||||||
@@ -498,15 +514,24 @@ 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]);
|
|
||||||
|
|
||||||
|
this.editor.setModel(this.fileBuffers[file.path].model);
|
||||||
|
if (this.fileBuffers[file.path].state) {
|
||||||
|
this.editor.restoreViewState(this.fileBuffers[file.path].state);
|
||||||
|
}
|
||||||
// var cmMode = 'html';
|
// var cmMode = 'html';
|
||||||
// if (file.name.match(/\.css$/)) {
|
// if (file.name.match(/\.css$/)) {
|
||||||
// this.updateCssMode('css');
|
// this.updateCssMode('css');
|
||||||
@@ -516,7 +541,7 @@ export default class ContentWrapFiles extends Component {
|
|||||||
// this.updateCssMode('html');
|
// this.updateCssMode('html');
|
||||||
// }
|
// }
|
||||||
// this.cm.setValue(file.content || '');
|
// this.cm.setValue(file.content || '');
|
||||||
this.cm.focus();
|
this.editor.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessageFromConsole() {
|
onMessageFromConsole() {
|
||||||
@@ -637,15 +662,15 @@ export default class ContentWrapFiles extends Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<UserCodeMirror
|
<CodeEditor
|
||||||
mode={'monaco'}
|
mode={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>
|
||||||
|
@@ -151,6 +151,13 @@ 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')}
|
||||||
|
/>
|
||||||
|
<Divider />
|
||||||
<div class="line">
|
<div class="line">
|
||||||
<span>Default Preprocessors</span>
|
<span>Default Preprocessors</span>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
@@ -321,7 +328,8 @@ export default class Settings extends Component {
|
|||||||
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>
|
</p>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel label="Advanced">
|
<TabPanel label="Advanced">
|
||||||
|
@@ -1,199 +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;
|
|
||||||
if (this.props.mode === 'monaco') {
|
|
||||||
this.instance = monaco.editor.create(el, {
|
|
||||||
language: options.language,
|
|
||||||
roundedSelection: false,
|
|
||||||
scrollBeyondLastLine: false,
|
|
||||||
theme: 'vs-dark',
|
|
||||||
fontSize: 16,
|
|
||||||
minimap: {
|
|
||||||
enabled: false
|
|
||||||
},
|
|
||||||
wordWrap: 'on',
|
|
||||||
fontLigatures: true
|
|
||||||
});
|
|
||||||
this.instance.onDidChangeModelContent(onChange);
|
|
||||||
} else {
|
|
||||||
this.instance = 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.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() {
|
|
||||||
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 = {};
|
||||||
|
|
||||||
@@ -1537,7 +1538,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>
|
||||||
|
|
||||||
@@ -1674,7 +1675,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>
|
||||||
|
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
@@ -1931,10 +1931,6 @@ while the theme CSS file is loading */
|
|||||||
.tabs__tabpanel-wrap {
|
.tabs__tabpanel-wrap {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
.monaco-editor {
|
|
||||||
width: 100%;
|
|
||||||
height: 300px !important; /* 25px for header */
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
@media screen and (max-width: 600px) {
|
||||||
body {
|
body {
|
||||||
|
Reference in New Issue
Block a user