react-templates/playground/CodeMirrorEditor.js

176 lines
6.4 KiB
JavaScript

define([
'react', 'react-dom', 'lodash', 'jquery', './libs/codemirror-4.8/lib/codemirror',
'./CMLint',
'./libs/codemirror-4.8/mode/javascript/javascript',
'./libs/codemirror-4.8/addon/hint/html-hint',
'./libs/codemirror-4.8/addon/hint/show-hint',
'./libs/codemirror-4.8/addon/hint/xml-hint',
'./libs/codemirror-4.8/addon/hint/html-hint',
//'./libs/codemirror-4.8/addon/display/panel',
'./libs/codemirror-4.8/mode/xml/xml',
//'./libs/codemirror-4.8/mode/css/css',
'./libs/codemirror-4.8/addon/runmode/runmode'
//'./libs/codemirror-4.8/addon/display/placeholder'
], function (React, ReactDOM, _, $, CodeMirror, CMLint) {
'use strict'
//codeMirror: 'libs/codemirror-4.8/lib/codemirror',
//htmlmixed: 'libs/codemirror-4.8/mode/htmlmixed/htmlmixed',
//javascript: 'libs/codemirror-4.8/mode/javascript/javascript'
var rtSchema = {
div: {
attrs: {
'rt-props': null,
'rt-if': null,
'rt-repeat': null,
'rt-class': null,
'rt-scope': null,
valueLink: null,
key: null,
ref: null,
dangerouslySetInnerHTML: null
}
}
}
var tags = CodeMirror.htmlSchema
Object.keys(CodeMirror.htmlSchema).forEach(function (i) {
tags[i].attrs = _.defaults(rtSchema.div.attrs, tags[i].attrs)
})
function completeAfter(cm, pred) {
//var cur = cm.getCursor();
if (!pred || pred()) {
setTimeout(function () {
if (!cm.state.completionActive) {
cm.showHint({completeSingle: false})
}
}, 100)
}
return CodeMirror.Pass
}
function completeIfAfterLt(cm) {
return completeAfter(cm, function () {
var cur = cm.getCursor()
return cm.getRange(CodeMirror.Pos(cur.line, cur.ch - 1), cur) === '<' //eslint-disable-line new-cap
})
}
function completeIfInTag(cm) {
return completeAfter(cm, function () {
var tok = cm.getTokenAt(cm.getCursor())
if (tok.type === 'string' && (!/['"]/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length === 1)) {
return false
}
var inner = CodeMirror.innerMode(cm.getMode(), tok.state).state
return inner.tagName
})
}
return React.createClass({
displayName: 'CodeMirrorEditor',
propTypes: {
id: React.PropTypes.string,
readOnly: React.PropTypes.bool,
runMode: React.PropTypes.bool,
mode: React.PropTypes.string,
value: React.PropTypes.string,
valueLink: React.PropTypes.string,
onChange: React.PropTypes.func
},
getDefaultProps: function () {
return {
readOnly: false,
mode: 'html'
}
},
getInitialState: function () {
return {
editorId: _.uniqueId()
}
},
//componentWillMount: function () {
//},
render: function () {
var props = _.omit(this.props, ['ref', 'key', 'value', 'valueLink', 'onChange'])
props.id = this.props.id || this.state.editorId
props.defaultValue = this.props.valueLink ? this.props.valueLink() : this.props.value
return React.DOM.textarea(props)
},
componentWillUpdate: function (nextProps/*, nextState*/) {
var value = nextProps.valueLink ? nextProps.valueLink() : nextProps.value
if (this.editor && this.editor.getValue() !== value) {
this.editor.setValue(value || '')
}
},
componentDidMount: function () {
var value = this.props.valueLink ? this.props.valueLink() : this.props.value
var options = {
readOnly: this.props.readOnly,
lineWrapping: true,
smartIndent: true,
matchBrackets: true,
value: value,
lineNumbers: true,
mode: 'javascript',
gutters: ['CodeMirror-linenumbers', 'rt-annotations'],
theme: 'solarized' //solarized_light solarized-light
}
if (this.props.mode === 'html') {
options.mode = 'text/html'
options.extraKeys = {
"'<'": completeAfter,
"'/'": completeIfAfterLt,
"' '": completeIfInTag,
"'='": completeIfInTag,
'Ctrl-Space': 'autocomplete'
}
options.hintOptions = {schemaInfo: tags}
//options.gutters = ['CodeMirror-lint-markers'];
//options.lint = true;
} else {
options.mode = 'javascript'
//options.gutters = ['CodeMirror-lint-markers'];
//options.lint = true;
}
this.editor = CodeMirror.fromTextArea(ReactDOM.findDOMNode(this), options)
if (!this.props.readOnly) {
this.editor.on('change', function (/*e*/) {
if (this.props.valueLink) {
this.props.valueLink(this.editor.getValue())
} else if (this.props.onChange) {
this.props.onChange({target: {value: this.editor.getValue()}})
}
}.bind(this))
}
},
//showMessage: function (msg) {
// //var anOption = document.createElement('div');
// //anOption.innerText = msg;
// //anOption.setAttribute('class', 'error-panel');
// //if (this.panel) {
// // this.panel.clear();
// //}
// //this.panel = this.editor.addPanel(anOption, {height: 22}); // {position: 'bottom'}
//},
//clearMessage: function () {
// if (this.panel) {
// this.panel.clear();
// this.panel = null;
// }
//},
annotate: function (annot) {
CMLint.annotate(this.editor, annot)
},
clearAnnotations: function () {
CMLint.clearMarks(this.editor)
},
componentWillUnmount: function () {
this.editor.toTextArea()
}
})
})