├── .gitignore ├── LICENSE ├── README.md ├── build.js ├── example ├── browserify │ ├── app.js │ ├── index.html │ ├── index.js │ └── server.js └── standalone │ ├── app.js │ └── index.html ├── index.js ├── package.json └── standalone.js /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | pids 10 | logs 11 | results 12 | npm-debug.log 13 | node_modules 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Forbes Lindesay 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-code-mirror 2 | 3 | Deprecated. Use https://github.com/scniro/react-codemirror2 4 | 5 | ## Installation 6 | 7 | npm install react-code-mirror 8 | 9 | If you're not using browserify/node you can also just load the standalone.js file (having first loaded CodeMirror and React. 10 | 11 | ## Usage 12 | 13 | See example folder 14 | 15 | It can also render server side, providing you don't `require('codemirror')` anywhere on the server. If you render server side it will just render the mobile view (i.e. a textarea) that will get upgraded to the full CodeMirror editor on the client. 16 | 17 | ## License 18 | 19 | MIT 20 | -------------------------------------------------------------------------------- /build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | 5 | var src = fs.readFileSync(__dirname + '/index.js', 'utf8'); 6 | 7 | src = src.replace(/^(.)/gm, ' $1'); 8 | src = 'CodeMirrorEditor = (function (require, module) {\n' + src + '\n return module.exports;\n}(function (id) {\n' + 9 | ' if (id === "react") return React;\n' + 10 | ' else if (id === "codemirror") return CodeMirror;\n' + 11 | ' else throw new Error("Unexpected require of " + id);' + 12 | '\n}, {exports: {}}));'; 13 | src = '// auto-generated from index.js via build.js, do not edit directly\n' + src; 14 | 15 | fs.writeFileSync(__dirname + '/standalone.js', src); 16 | -------------------------------------------------------------------------------- /example/browserify/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var React = require('react'); 4 | var CodeMirror = React.createFactory(require('../../')); 5 | 6 | var div = React.createFactory('div'); 7 | var h1 = React.createFactory('h1'); 8 | var p = React.createFactory('p'); 9 | var pre = React.createFactory('pre'); 10 | var code = React.createFactory('code'); 11 | 12 | module.exports = React.createClass({ 13 | getInitialState: function () { 14 | return { 15 | src: 'function add(a, b) {\n' + 16 | ' return a + b;\n' + 17 | '}' 18 | }; 19 | }, 20 | render: function () { 21 | return div({}, 22 | h1({}, 'Using "defaultValue"'), 23 | p({}, 'This creates an editable code mirror editor, as you would expect. ' + 24 | 'Note that it will not respond to changes in the model though.'), 25 | CodeMirror({ 26 | style: {border: '1px solid black'}, 27 | textAreaClassName: ['form-control'], 28 | textAreaStyle: {minHeight: '10em'}, 29 | defaultValue: this.state.src, 30 | mode: 'javascript', 31 | theme: 'solarized', 32 | lineNumbers: true 33 | }), 34 | h1({}, 'Using "value" and no "onChange"'), 35 | p({}, 'This creates a read only code mirror editor that responds to changes.'), 36 | CodeMirror({ 37 | style: {border: '1px solid black'}, 38 | textAreaClassName: ['form-control'], 39 | textAreaStyle: {minHeight: '10em'}, 40 | value: this.state.src, 41 | mode: 'javascript', 42 | theme: 'solarized', 43 | lineNumbers: true, 44 | readOnly: true 45 | }), 46 | h1({}, 'Using "value" with "onChange"'), 47 | p({}, 'This creates a typical, editable code mirror editor that responds to changes.'), 48 | CodeMirror({ 49 | style: {border: '1px solid black'}, 50 | textAreaClassName: ['form-control'], 51 | textAreaStyle: {minHeight: '10em'}, 52 | value: this.state.src, 53 | mode: 'javascript', 54 | theme: 'solarized', 55 | lineNumbers: true, 56 | onChange: function (e) { 57 | this.setState({src: e.target.value}); 58 | }.bind(this) 59 | }), 60 | h1({}, 'Using the forceTextArea option'), 61 | p({}, 'This is the default fallback option for mobile browsers and works seamlessly.'), 62 | CodeMirror({ 63 | forceTextArea: true, 64 | textAreaClassName: ['form-control'], 65 | textAreaStyle: {minHeight: '10em'}, 66 | value: this.state.src, 67 | mode: 'javascript', 68 | theme: 'solarized', 69 | lineNumbers: true, 70 | onChange: function (e) { 71 | this.setState({src: e.target.value}); 72 | }.bind(this) 73 | }), 74 | h1({}, 'Just a pre/code'), 75 | p({}, 'Just so you can see the output.'), 76 | pre({}, code({}, this.state.src)) 77 | ); 78 | } 79 | }); 80 | -------------------------------------------------------------------------------- /example/browserify/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
{{component}}
11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /example/browserify/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var React = require('react'); 4 | var ReactDOM = require('react-dom'); 5 | var Application = require('./app.js'); 6 | require('codemirror/mode/javascript/javascript'); 7 | 8 | ReactDOM.render(React.createElement(Application), document.getElementById('container')); 9 | -------------------------------------------------------------------------------- /example/browserify/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var fs = require('fs'); 5 | var React = require('react'); 6 | var ReactDOMServer = require('react-dom/server'); 7 | var express = require('express'); 8 | var browserify = require('browserify-middleware'); 9 | var Application = require('./app'); 10 | 11 | var app = express(); 12 | 13 | app.get('/', function (req, res) { 14 | var html = fs.readFileSync(__dirname + '/index.html', 'utf8'); 15 | html = html.replace('{{component}}', ReactDOMServer.renderToString(React.createElement(Application))); 16 | res.send(html); 17 | }); 18 | app.get('/index.js', browserify(__dirname + '/index.js')); 19 | app.get('/codemirror.css', function (req, res) { 20 | res.sendFile(require.resolve('codemirror/lib/codemirror.css')); 21 | }); 22 | app.get('/codemirror/theme/:theme.css', function (req, res) { 23 | assert(/^[a-z0-9\-]+$/.test(req.params.theme)); 24 | res.sendFile(require.resolve('codemirror/theme/' + req.params.theme + '.css')); 25 | }); 26 | 27 | app.listen(3000); 28 | -------------------------------------------------------------------------------- /example/standalone/app.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict'; 3 | 4 | var CodeMirror = React.createFactory(CodeMirrorEditor); 5 | var div = React.createFactory('div'); 6 | var h1 = React.createFactory('h1'); 7 | var p = React.createFactory('p'); 8 | var pre = React.createFactory('pre'); 9 | var code = React.createFactory('code'); 10 | 11 | var Application = React.createClass({ 12 | getInitialState: function () { 13 | return { 14 | src: 'function add(a, b) {\n' + 15 | ' return a + b;\n' + 16 | '}' 17 | }; 18 | }, 19 | render: function () { 20 | return div({}, 21 | h1({}, 'Using "defaultValue"'), 22 | p({}, 'This creates an editable code mirror editor, as you would expect. ' + 23 | 'Note that it will not respond to changes in the model though.'), 24 | CodeMirror({ 25 | style: {border: '1px solid black'}, 26 | textAreaClassName: ['form-control'], 27 | textAreaStyle: {minHeight: '10em'}, 28 | defaultValue: this.state.src, 29 | mode: 'javascript', 30 | theme: 'solarized', 31 | lineNumbers: true 32 | }), 33 | h1({}, 'Using "value" and no "onChange"'), 34 | p({}, 'This creates a read only code mirror editor that responds to changes.'), 35 | CodeMirror({ 36 | style: {border: '1px solid black'}, 37 | textAreaClassName: ['form-control'], 38 | textAreaStyle: {minHeight: '10em'}, 39 | value: this.state.src, 40 | mode: 'javascript', 41 | theme: 'solarized', 42 | lineNumbers: true, 43 | readOnly: true 44 | }), 45 | h1({}, 'Using "value" with "onChange"'), 46 | p({}, 'This creates a typical, editable code mirror editor that responds to changes.'), 47 | CodeMirror({ 48 | style: {border: '1px solid black'}, 49 | textAreaClassName: ['form-control'], 50 | textAreaStyle: {minHeight: '10em'}, 51 | value: this.state.src, 52 | mode: 'javascript', 53 | theme: 'solarized', 54 | lineNumbers: true, 55 | onChange: function (e) { 56 | this.setState({src: e.target.value}); 57 | }.bind(this) 58 | }), 59 | h1({}, 'Using the forceTextArea option'), 60 | p({}, 'This is the default fallback option for mobile browsers and works seamlessly.'), 61 | CodeMirror({ 62 | forceTextArea: true, 63 | textAreaClassName: ['form-control'], 64 | textAreaStyle: {minHeight: '10em'}, 65 | value: this.state.src, 66 | mode: 'javascript', 67 | theme: 'solarized', 68 | lineNumbers: true, 69 | onChange: function (e) { 70 | this.setState({src: e.target.value}); 71 | }.bind(this) 72 | }), 73 | h1({}, 'Just a pre/code'), 74 | p({}, 'Just so you can see the output.'), 75 | pre({}, code({}, this.state.src)) 76 | ); 77 | } 78 | }); 79 | 80 | React.render(React.createElement(Application), document.getElementById('container')); 81 | }()); 82 | -------------------------------------------------------------------------------- /example/standalone/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var React = require('react'); 4 | var CodeMirror; 5 | 6 | // adapted from: 7 | // https://github.com/facebook/react/blob/master/docs/_js/live_editor.js#L16 8 | 9 | // also used as an example: 10 | // https://github.com/facebook/react/blob/master/src/browser/ui/dom/components/ReactDOMInput.js 11 | 12 | var IS_MOBILE = typeof navigator === 'undefined' || ( 13 | navigator.userAgent.match(/Android/i) 14 | || navigator.userAgent.match(/webOS/i) 15 | || navigator.userAgent.match(/iPhone/i) 16 | || navigator.userAgent.match(/iPad/i) 17 | || navigator.userAgent.match(/iPod/i) 18 | || navigator.userAgent.match(/BlackBerry/i) 19 | || navigator.userAgent.match(/Windows Phone/i) 20 | ); 21 | 22 | if (!IS_MOBILE) { 23 | CodeMirror = require('codemirror'); 24 | } 25 | 26 | var CodeMirrorEditor = React.createClass({ 27 | getInitialState: function() { 28 | return { isControlled: this.props.value != null }; 29 | }, 30 | 31 | propTypes: { 32 | value: React.PropTypes.string, 33 | defaultValue: React.PropTypes.string, 34 | style: React.PropTypes.object, 35 | className: React.PropTypes.string, 36 | onChange: React.PropTypes.func 37 | }, 38 | 39 | componentDidMount: function() { 40 | var isTextArea = this.props.forceTextArea || IS_MOBILE; 41 | if (!isTextArea) { 42 | var editor = this.refs.editor; 43 | if (!editor.getAttribute) editor = editor.getDOMNode(); 44 | this.editor = CodeMirror.fromTextArea(editor, this.props); 45 | this.editor.on('change', this.handleChange); 46 | } 47 | }, 48 | 49 | componentDidUpdate: function() { 50 | if (this.editor) { 51 | if (this.props.value != null) { 52 | if (this.editor.getValue() !== this.props.value) { 53 | this.editor.setValue(this.props.value); 54 | } 55 | } 56 | } 57 | }, 58 | 59 | handleChange: function() { 60 | if (this.editor) { 61 | var value = this.editor.getValue(); 62 | if (value !== this.props.value) { 63 | this.props.onChange && this.props.onChange({target: {value: value}}); 64 | if (this.editor.getValue() !== this.props.value) { 65 | if (this.state.isControlled) { 66 | this.editor.setValue(this.props.value); 67 | } else { 68 | this.props.value = value; 69 | } 70 | } 71 | } 72 | } 73 | }, 74 | 75 | render: function() { 76 | var editor = React.createElement('textarea', { 77 | ref: 'editor', 78 | value: this.props.value, 79 | readOnly: this.props.readOnly, 80 | defaultValue: this.props.defaultValue, 81 | onChange: this.props.onChange, 82 | style: this.props.textAreaStyle, 83 | className: this.props.textAreaClassName || this.props.textAreaClass 84 | }); 85 | 86 | return React.createElement('div', {style: this.props.style, className: this.props.className}, editor); 87 | } 88 | }); 89 | 90 | module.exports = CodeMirrorEditor; 91 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-code-mirror", 3 | "version": "3.1.0", 4 | "description": "CodeMirror component for Facebook React", 5 | "keywords": [ 6 | "react", 7 | "react-component" 8 | ], 9 | "peerDependencies": { 10 | "codemirror": ">=4.6.0 <6.0.0", 11 | "react": ">=0.12.0 <16.0.0" 12 | }, 13 | "devDependencies": { 14 | "browserify-middleware": "^3.0.1", 15 | "codemirror": "^5.18.2", 16 | "express": "^4.9.5", 17 | "react": "^15.3.1", 18 | "react-dom": "^15.3.1", 19 | "umd": "^2.1.0" 20 | }, 21 | "scripts": { 22 | "prepublish": "node build" 23 | }, 24 | "repository": { 25 | "type": "git", 26 | "url": "https://github.com/ForbesLindesay/react-code-mirror.git" 27 | }, 28 | "author": "ForbesLindesay", 29 | "license": "MIT" 30 | } -------------------------------------------------------------------------------- /standalone.js: -------------------------------------------------------------------------------- 1 | // auto-generated from index.js via build.js, do not edit directly 2 | CodeMirrorEditor = (function (require, module) { 3 | 'use strict'; 4 | 5 | var React = require('react'); 6 | var CodeMirror; 7 | 8 | // adapted from: 9 | // https://github.com/facebook/react/blob/master/docs/_js/live_editor.js#L16 10 | 11 | // also used as an example: 12 | // https://github.com/facebook/react/blob/master/src/browser/ui/dom/components/ReactDOMInput.js 13 | 14 | var IS_MOBILE = typeof navigator === 'undefined' || ( 15 | navigator.userAgent.match(/Android/i) 16 | || navigator.userAgent.match(/webOS/i) 17 | || navigator.userAgent.match(/iPhone/i) 18 | || navigator.userAgent.match(/iPad/i) 19 | || navigator.userAgent.match(/iPod/i) 20 | || navigator.userAgent.match(/BlackBerry/i) 21 | || navigator.userAgent.match(/Windows Phone/i) 22 | ); 23 | 24 | if (!IS_MOBILE) { 25 | CodeMirror = require('codemirror'); 26 | } 27 | 28 | var CodeMirrorEditor = React.createClass({ 29 | getInitialState: function() { 30 | return { isControlled: this.props.value != null }; 31 | }, 32 | 33 | propTypes: { 34 | value: React.PropTypes.string, 35 | defaultValue: React.PropTypes.string, 36 | style: React.PropTypes.object, 37 | className: React.PropTypes.string, 38 | onChange: React.PropTypes.func 39 | }, 40 | 41 | componentDidMount: function() { 42 | var isTextArea = this.props.forceTextArea || IS_MOBILE; 43 | if (!isTextArea) { 44 | var editor = this.refs.editor; 45 | if (!editor.getAttribute) editor = editor.getDOMNode(); 46 | this.editor = CodeMirror.fromTextArea(editor, this.props); 47 | this.editor.on('change', this.handleChange); 48 | } 49 | }, 50 | 51 | componentDidUpdate: function() { 52 | if (this.editor) { 53 | if (this.props.value != null) { 54 | if (this.editor.getValue() !== this.props.value) { 55 | this.editor.setValue(this.props.value); 56 | } 57 | } 58 | } 59 | }, 60 | 61 | handleChange: function() { 62 | if (this.editor) { 63 | var value = this.editor.getValue(); 64 | if (value !== this.props.value) { 65 | this.props.onChange && this.props.onChange({target: {value: value}}); 66 | if (this.editor.getValue() !== this.props.value) { 67 | if (this.state.isControlled) { 68 | this.editor.setValue(this.props.value); 69 | } else { 70 | this.props.value = value; 71 | } 72 | } 73 | } 74 | } 75 | }, 76 | 77 | render: function() { 78 | var editor = React.createElement('textarea', { 79 | ref: 'editor', 80 | value: this.props.value, 81 | readOnly: this.props.readOnly, 82 | defaultValue: this.props.defaultValue, 83 | onChange: this.props.onChange, 84 | style: this.props.textAreaStyle, 85 | className: this.props.textAreaClassName || this.props.textAreaClass 86 | }); 87 | 88 | return React.createElement('div', {style: this.props.style, className: this.props.className}, editor); 89 | } 90 | }); 91 | 92 | module.exports = CodeMirrorEditor; 93 | 94 | return module.exports; 95 | }(function (id) { 96 | if (id === "react") return React; 97 | else if (id === "codemirror") return CodeMirror; 98 | else throw new Error("Unexpected require of " + id); 99 | }, {exports: {}})); --------------------------------------------------------------------------------