UNPKG

react-bootstrap

Version:

Bootstrap 3 components build with React

223 lines (190 loc) 5.71 kB
/** * @jsx React.DOM */ var React = require('react'); var classSet = require('react/lib/cx'); var CodeMirror = global.CodeMirror; var JSXTransformer = global.JSXTransformer; var Accordion = require('../../cjs/Accordion'); var Alert = require('../../cjs/Alert'); var Button = require('../../cjs/Button'); var ButtonGroup = require('../../cjs/ButtonGroup'); var ButtonToolbar = require('../../cjs/ButtonToolbar'); var DropdownButton = require('../../cjs/DropdownButton'); var SplitButton = require('../../cjs/SplitButton'); var Nav = require('../../cjs/Nav'); var NavItem = require('../../cjs/NavItem'); var MenuItem = require('../../cjs/MenuItem'); var Modal = require('../../cjs/Modal'); var OverlayTrigger = require('../../cjs/OverlayTrigger'); var OverlayTriggerMixin = require('../../cjs/OverlayTriggerMixin'); var Panel = require('../../cjs/Panel'); var PanelGroup = require('../../cjs/PanelGroup'); var ProgressBar = require('../../cjs/ProgressBar'); var TabbedArea = require('../../cjs/TabbedArea'); var TabPane = require('../../cjs/TabPane'); var IS_MOBILE = typeof navigator !== 'undefined' && ( navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Windows Phone/i) ); var CodeMirrorEditor = React.createClass({ componentDidMount: function() { if (IS_MOBILE) return; this.editor = CodeMirror.fromTextArea(this.refs.editor.getDOMNode(), { mode: 'javascript', lineNumbers: false, lineWrapping: true, matchBrackets: true, tabSize: 2, theme: 'solarized-light', readOnly: this.props.readOnly }); this.editor.on('change', this.handleChange); }, componentDidUpdate: function() { if (this.props.readOnly) { this.editor.setValue(this.props.codeText); } }, handleChange: function() { if (!this.props.readOnly) { this.props.onChange && this.props.onChange(this.editor.getValue()); } }, render: function() { // wrap in a div to fully contain CodeMirror var editor; if (IS_MOBILE) { var preStyles = {overflow: 'scroll'}; editor = <pre style={preStyles}>{this.props.codeText}</pre>; } else { editor = <textarea ref="editor" defaultValue={this.props.codeText} />; } return ( <div style={this.props.style} className={this.props.className}> {editor} </div> ); } }); var selfCleaningTimeout = { componentDidUpdate: function() { clearTimeout(this.timeoutID); }, setTimeout: function() { clearTimeout(this.timeoutID); this.timeoutID = setTimeout.apply(null, arguments); } }; var ReactPlayground = React.createClass({ mixins: [selfCleaningTimeout], MODES: {JSX: 'JSX', JS: 'JS', NONE: null}, propTypes: { codeText: React.PropTypes.string.isRequired, transformer: React.PropTypes.func, renderCode: React.PropTypes.bool }, getDefaultProps: function() { return { transformer: function(code) { return JSXTransformer.transform(code).code; } }; }, getInitialState: function() { return { mode: this.MODES.NONE, code: this.props.codeText }; }, handleCodeChange: function(value) { this.setState({code: value}); this.executeCode(); }, handleCodeModeSwitch: function(mode) { this.setState({mode: mode}); }, handleCodeModeToggle: function(e) { var mode; e.preventDefault(); switch (this.state.mode) { case this.MODES.NONE: mode = this.MODES.JSX; break; case this.MODES.JSX: default: mode = this.MODES.NONE; } this.setState({mode: mode}); }, compileCode: function() { return this.props.transformer(this.state.code); }, render: function() { var classes = { 'bs-example': true }; var editor; if (this.props.exampleClassName){ classes[this.props.exampleClassName] = true; } if (this.state.mode !== this.MODES.NONE) { editor = ( <CodeMirrorEditor key="jsx" onChange={this.handleCodeChange} className="highlight" codeText={this.state.code}/> ); } return ( <div className="playground"> <div className={classSet(classes)}> <div ref="mount" /> </div> {editor} <a onClick={this.handleCodeModeToggle} href="#">{this.state.mode === this.MODES.NONE ? 'show code' : 'hide code'}</a> </div> ); }, componentDidMount: function() { this.executeCode(); }, componentWillUpdate: function(nextProps, nextState) { // execute code only when the state's not being updated by switching tab // this avoids re-displaying the error, which comes after a certain delay if (this.state.code !== nextState.code) { this.executeCode(); } }, executeCode: function() { var mountNode = this.refs.mount.getDOMNode(); try { React.unmountComponentAtNode(mountNode); } catch (e) { } try { var compiledCode = this.compileCode(); if (this.props.renderCode) { React.renderComponent( <CodeMirrorEditor codeText={compiledCode} readOnly={true} />, mountNode ); } else { eval(compiledCode); } } catch (err) { this.setTimeout(function() { React.renderComponent( <Alert bsStyle="danger">{err.toString()}</Alert>, mountNode ); }, 500); } } }); module.exports = ReactPlayground;