require('./codeEditor.less'); const React = require('react'); const createClass = require('create-react-class'); const _ = require('lodash'); const cx = require('classnames'); let CodeMirror; if(typeof navigator !== 'undefined'){ CodeMirror = require('codemirror'); //Language Modes require('codemirror/mode/gfm/gfm.js'); //Github flavoured markdown require('codemirror/mode/css/css.js'); require('codemirror/mode/javascript/javascript.js'); } const CodeEditor = createClass({ getDefaultProps : function() { return { language : '', value : '', wrap : true, onChange : ()=>{} }; }, getInitialState : function() { return { docs : {} }; }, componentDidMount : function() { this.buildEditor(); this.codeMirror.setValue(this.props.value); this.codeMirror.clearHistory(); }, componentDidUpdate : function(prevProps) { if(prevProps.view !== this.props.view){ //view changed; swap documents let newDoc; if(!this.state.docs[this.props.view]) { newDoc = CodeMirror.Doc(this.props.value, this.props.language); } else { newDoc = this.state.docs[this.props.view]; } const oldDoc = { [prevProps.view]: this.codeMirror.swapDoc(newDoc) }; this.setState((prevState)=>({ docs : _.merge({}, prevState.docs, oldDoc) })); this.props.rerenderParent(); } else if(this.codeMirror?.getValue() != this.props.value) { //update editor contents if brew.text is changed from outside this.codeMirror.setValue(this.props.value); } }, buildEditor : function() { this.codeMirror = CodeMirror(this.refs.editor, { lineNumbers : true, lineWrapping : this.props.wrap, indentWithTabs : true, tabSize : 2, historyEventDelay : 250, extraKeys : { 'Ctrl-B' : this.makeBold, 'Cmd-B' : this.makeBold, 'Ctrl-I' : this.makeItalic, 'Cmd-I' : this.makeItalic, 'Ctrl-M' : this.makeSpan, 'Cmd-M' : this.makeSpan, 'Ctrl-/' : this.makeComment, 'Cmd-/' : this.makeComment } }); // Note: codeMirror passes a copy of itself in this callback. cm === this.codeMirror. Either one works. this.codeMirror.on('change', (cm)=>{this.props.onChange(cm.getValue());}); this.updateSize(); }, makeBold : function() { const selection = this.codeMirror.getSelection(), t = selection.slice(0, 2) === '**' && selection.slice(-2) === '**'; this.codeMirror.replaceSelection(t ? selection.slice(2, -2) : `**${selection}**`, 'around'); if(selection.length === 0){ const cursor = this.codeMirror.getCursor(); this.codeMirror.setCursor({ line: cursor.line, ch: cursor.ch - 2 }); } }, makeItalic : function() { const selection = this.codeMirror.getSelection(), t = selection.slice(0, 1) === '_' && selection.slice(-1) === '_'; this.codeMirror.replaceSelection(t ? selection.slice(1, -1) : `_${selection}_`, 'around'); if(selection.length === 0){ const cursor = this.codeMirror.getCursor(); this.codeMirror.setCursor({ line: cursor.line, ch: cursor.ch - 1 }); } }, makeSpan : function() { const selection = this.codeMirror.getSelection(), t = selection.slice(0, 2) === '{{' && selection.slice(-2) === '}}'; this.codeMirror.replaceSelection(t ? selection.slice(2, -2) : `{{ ${selection}}}`, 'around'); if(selection.length === 0){ const cursor = this.codeMirror.getCursor(); this.codeMirror.setCursor({ line: cursor.line, ch: cursor.ch - 2 }); } }, makeComment : function() { const selection = this.codeMirror.getSelection(), t = selection.slice(0, 4) === ''; this.codeMirror.replaceSelection(t ? selection.slice(4, -3) : ``, 'around'); if(selection.length === 0){ const cursor = this.codeMirror.getCursor(); this.codeMirror.setCursor({ line: cursor.line, ch: cursor.ch - 4 }); } }, //=-- Externally used -==// setCursorPosition : function(line, char){ setTimeout(()=>{ this.codeMirror.focus(); this.codeMirror.doc.setCursor(line, char); }, 10); }, getCursorPosition : function(){ return this.codeMirror.getCursor(); }, updateSize : function(){ this.codeMirror.refresh(); }, redo : function(){ return this.codeMirror.redo(); }, undo : function(){ return this.codeMirror.undo(); }, historySize : function(){ return this.codeMirror.doc.historySize(); }, //----------------------// render : function(){ return