From 09279c322d9a684179426d2226471892e2577276 Mon Sep 17 00:00:00 2001 From: Jimmy Jia Date: Wed, 29 Jul 2015 22:38:55 -0400 Subject: [PATCH] Initially render examples on the server --- docs/src/ReactPlayground.js | 349 ++++++++++++++++-------------------- 1 file changed, 156 insertions(+), 193 deletions(-) diff --git a/docs/src/ReactPlayground.js b/docs/src/ReactPlayground.js index 7c5458521f..1b9901c0b1 100644 --- a/docs/src/ReactPlayground.js +++ b/docs/src/ReactPlayground.js @@ -1,113 +1,65 @@ -import * as modReact from 'react'; -import * as modClassNames from 'classnames'; -import * as modAccordion from '../../src/Accordion'; -import * as modAlert from '../../src/Alert'; -import * as modBadge from '../../src/Badge'; -import * as modButton from '../../src/Button'; -import * as modButtonGroup from '../../src/ButtonGroup'; -import * as modButtonInput from '../../src/ButtonInput'; -import * as modButtonToolbar from '../../src/ButtonToolbar'; -import * as modCollapse from '../../src/Collapse'; -import * as modCollapsibleNav from '../../src/CollapsibleNav'; -import * as modCollapsibleMixin from '../../src/CollapsibleMixin'; -import * as modCarousel from '../../src/Carousel'; -import * as modCarouselItem from '../../src/CarouselItem'; -import * as modCol from '../../src/Col'; -import * as modDropdownButton from '../../src/DropdownButton'; -import * as modFade from '../../src/Fade'; -import * as modFormControls from '../../src/FormControls'; -import * as modGlyphicon from '../../src/Glyphicon'; -import * as modGrid from '../../src/Grid'; -import * as modInput from '../../src/Input'; -import * as modJumbotron from '../../src/Jumbotron'; -import * as modLabel from '../../src/Label'; -import * as modListGroup from '../../src/ListGroup'; -import * as modListGroupItem from '../../src/ListGroupItem'; -import * as modNav from '../../src/Nav'; -import * as modNavbar from '../../src/Navbar'; -import * as modNavItem from '../../src/NavItem'; -import * as modMenuItem from '../../src/MenuItem'; -import * as modModal from '../../src/Modal'; -import * as modOverlayTrigger from '../../src/OverlayTrigger'; -import * as modPageHeader from '../../src/PageHeader'; -import * as modPageItem from '../../src/PageItem'; -import * as modPager from '../../src/Pager'; -import * as modPagination from '../../src/Pagination'; -import * as modPanel from '../../src/Panel'; -import * as modPanelGroup from '../../src/PanelGroup'; -import * as modPopover from '../../src/Popover'; -import * as modProgressBar from '../../src/ProgressBar'; -import * as modRow from '../../src/Row'; -import * as modSplitButton from '../../src/SplitButton'; -import * as modTabbedArea from '../../src/TabbedArea'; -import * as modTable from '../../src/Table'; -import * as modTabPane from '../../src/TabPane'; -import * as modThumbnail from '../../src/Thumbnail'; -import * as modTooltip from '../../src/Tooltip'; -import * as modWell from '../../src/Well'; -import * as modPortal from '../../src/Portal'; -import * as modOverlay from '../../src/Overlay'; - -import babel from 'babel-core/browser'; - -import CodeExample from './CodeExample'; - - - -const classNames = modClassNames.default; +// These do not use ES6 imports, because the evaluated code requires un-mangled +// variable names. /* eslint-disable */ +const classNames = require('classnames'); +const React = require('react'); + +const Accordion = require('../../src/Accordion'); +const Alert = require('../../src/Alert'); +const Badge = require('../../src/Badge'); +const Button = require('../../src/Button'); +const ButtonGroup = require('../../src/ButtonGroup'); +const ButtonInput = require('../../src/ButtonInput'); +const ButtonToolbar = require('../../src/ButtonToolbar'); +const Carousel = require('../../src/Carousel'); +const CarouselItem = require('../../src/CarouselItem'); +const Col = require('../../src/Col'); +const Collapse = require('../../src/Collapse'); +const CollapsibleMixin = require('../../src/CollapsibleMixin'); +const CollapsibleNav = require('../../src/CollapsibleNav'); +const DropdownButton = require('../../src/DropdownButton'); +const Fade = require('../../src/Fade'); +const FormControls = require('../../src/FormControls'); +const Glyphicon = require('../../src/Glyphicon'); +const Grid = require('../../src/Grid'); +const Input = require('../../src/Input'); +const Jumbotron = require('../../src/Jumbotron'); +const Label = require('../../src/Label'); +const ListGroup = require('../../src/ListGroup'); +const ListGroupItem = require('../../src/ListGroupItem'); +const MenuItem = require('../../src/MenuItem'); +const Modal = require('../../src/Modal'); +const Nav = require('../../src/Nav'); +const Navbar = require('../../src/Navbar'); +const NavItem = require('../../src/NavItem'); +const Overlay = require('../../src/Overlay'); +const OverlayTrigger = require('../../src/OverlayTrigger'); +const PageHeader = require('../../src/PageHeader'); +const PageItem = require('../../src/PageItem'); +const Pager = require('../../src/Pager'); +const Pagination = require('../../src/Pagination'); +const Panel = require('../../src/Panel'); +const PanelGroup = require('../../src/PanelGroup'); +const Popover = require('../../src/Popover'); +const Portal = require('../../src/Portal'); +const ProgressBar = require('../../src/ProgressBar'); +const Row = require('../../src/Row'); +const SplitButton = require('../../src/SplitButton'); +const TabbedArea = require('../../src/TabbedArea'); +const Table = require('../../src/Table'); +const TabPane = require('../../src/TabPane'); +const Thumbnail = require('../../src/Thumbnail'); +const Tooltip = require('../../src/Tooltip'); +const Well = require('../../src/Well'); +/* eslint-enable */ -const Portal = modPortal.default; -const Collapse = modCollapse.default; -const Fade = modFade.default; -const React = modReact.default; -const Accordion = modAccordion.default; -const Alert = modAlert.default; -const Badge = modBadge.default; -const Button = modButton.default; -const ButtonGroup = modButtonGroup.default; -const ButtonInput = modButtonInput.default; -const ButtonToolbar = modButtonToolbar.default; -const CollapsibleNav = modCollapsibleNav.default; -const CollapsibleMixin = modCollapsibleMixin.default; -const Carousel = modCarousel.default; -const CarouselItem = modCarouselItem.default; -const Col = modCol.default; -const DropdownButton = modDropdownButton.default; -const FormControls = modFormControls; -const Glyphicon = modGlyphicon.default; -const Grid = modGrid.default; -const Input = modInput.default; -const Jumbotron = modJumbotron.default; -const Label = modLabel.default; -const ListGroup = modListGroup.default; -const ListGroupItem = modListGroupItem.default; -const Nav = modNav.default; -const Navbar = modNavbar.default; -const NavItem = modNavItem.default; -const MenuItem = modMenuItem.default; -const Modal = modModal.default; -const OverlayTrigger = modOverlayTrigger.default; -const PageHeader = modPageHeader.default; -const PageItem = modPageItem.default; -const Pagination = modPagination.default; -const Pager = modPager.default; -const Panel = modPanel.default; -const PanelGroup = modPanelGroup.default; -const Popover = modPopover.default; -const ProgressBar = modProgressBar.default; -const Row = modRow.default; -const SplitButton = modSplitButton.default; -const TabbedArea = modTabbedArea.default; -const Table = modTable.default; -const TabPane = modTabPane.default; -const Thumbnail = modThumbnail.default; -const Tooltip = modTooltip.default; -const Well = modWell.default; -const Overlay = modOverlay.default; +import babel from 'babel-core/browser'; +import CodeExample from './CodeExample'; -/* eslint-enable */ +// This is only used for the ReactPlayground component, not for any of the +// examples, so it's fine to import like this. +import SafeAnchor from '../../src/SafeAnchor'; const IS_MOBILE = typeof navigator !== 'undefined' && ( navigator.userAgent.match(/Android/i) @@ -192,12 +144,9 @@ const selfCleaningTimeout = { const 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 + transformer: React.PropTypes.func }, getDefaultProps() { @@ -210,119 +159,128 @@ const ReactPlayground = React.createClass({ getInitialState() { return { - mode: this.MODES.NONE, - code: this.props.codeText + code: this.props.codeText, + codeChanged: false, + showCode: false }; }, - handleCodeChange(value) { - this.setState({code: value}); - this.executeCode(); - }, - - handleCodeModeSwitch(mode) { - this.setState({mode}); - }, + componentWillMount() { + // For the initial render, we can hijack React.render to intercept the + // example element and render it normally. This is safe because it's code + // that we supply, so we can ensure ahead of time that it won't throw an + // exception while rendering. + const originalReactRender = React.render; + React.render = (element) => this._initialExample = element; - handleCodeModeToggle(e) { - let mode; + // Stub out mountNode for the example code. + const mountNode = null; // eslint-disable-line no-unused-vars - e.preventDefault(); + try { + const compiledCode = this.props.transformer(this.props.codeText); - switch (this.state.mode) { - case this.MODES.NONE: - mode = this.MODES.JSX; - break; - case this.MODES.JSX: - default: - mode = this.MODES.NONE; + /* eslint-disable */ + eval(compiledCode); + /* eslint-enable */ + } finally { + React.render = originalReactRender; } + }, + + componentWillUnmount() { + this.clearExample(); + }, - this.setState({mode}); + handleCodeChange(value) { + this.setState( + {code: value, codeChanged: true}, + this.executeCode + ); }, - compileCode() { - return this.props.transformer(this.state.code); + handleCodeModeToggle() { + this.setState({ + showCode: !this.state.showCode + }); }, render() { - let classes = { - 'bs-example': true - }; - let toggleClasses = { - 'code-toggle': true - }; - let editor; + return ( +
+ {this.renderExample()} - if (this.props.exampleClassName){ - classes[this.props.exampleClassName] = true; - } + {this.renderEditor()} + {this.renderToggle()} +
+ ); + }, - if (this.state.mode !== this.MODES.NONE) { - editor = ( - - ); - toggleClasses.open = true; + renderExample() { + let example; + if (this.state.codeChanged) { + example = ( +
+ ); + } else { + example = ( +
{this._initialExample}
+ ); } + return ( -
-
-
-
- {editor} - {this.state.mode === this.MODES.NONE ? 'show code' : 'hide code'} +
+ {example}
- ); + ); }, - componentDidMount() { - this.executeCode(); + renderEditor() { + if (!this.state.showCode) { + return null; + } + + return ( + + ); }, - componentWillUpdate(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(); - } + renderToggle() { + return ( + + {this.state.showCode ? 'hide code' : 'show code'} + + ); }, - componentWillUnmount() { - let mountNode = React.findDOMNode(this.refs.mount); + clearExample() { + const mountNode = React.findDOMNode(this.refs.mount); try { React.unmountComponentAtNode(mountNode); } catch (e) { console.error(e); } + + return mountNode; }, executeCode() { - let mountNode = React.findDOMNode(this.refs.mount); - - try { - React.unmountComponentAtNode(mountNode); - } catch (e) { - console.error(e); - } + const mountNode = this.clearExample(); let compiledCode = null; try { - compiledCode = this.compileCode(); + compiledCode = this.props.transformer(this.state.code); - if (this.props.renderCode) { - React.render( - , - mountNode - ); - } else { - /* eslint-disable */ - eval(compiledCode); - /* eslint-enable */ - } + /* eslint-disable */ + eval(compiledCode); + /* eslint-enable */ } catch (err) { if (compiledCode !== null) { console.log(err, compiledCode); @@ -330,12 +288,17 @@ const ReactPlayground = React.createClass({ console.log(err); } - this.updateTimeout(() => { - React.render( - {err.toString()}, - mountNode - ); - }, 500); + this.updateTimeout( + () => { + React.render( + + {err.toString()} + , + mountNode + ); + }, + 500 + ); } } });