From 0126a8363e384229d36fe42fe49600680c60a29e Mon Sep 17 00:00:00 2001 From: Brad Buchanan Date: Tue, 1 Mar 2016 17:52:05 -0800 Subject: [PATCH 01/11] Update React from 0.13.1 to 0.14.7 --- apps/Gruntfile.js | 1 + apps/package.json | 5 +++-- apps/src/StudioApp.js | 10 +++++----- apps/src/applab/DesignToolboxElement.jsx | 2 +- apps/src/applab/applab.js | 6 +++--- .../designElements/ColorPickerPropertyRow.jsx | 2 +- apps/src/applab/designMode.js | 2 +- apps/src/assetManagement/AssetUploader.jsx | 6 +++--- apps/src/assetManagement/show.js | 2 +- apps/src/authoredHints.js | 2 +- apps/src/bounce/bounce.js | 2 +- apps/src/calc/calc.js | 2 +- apps/src/craft/craft.js | 2 +- apps/src/eval/eval.js | 2 +- apps/src/flappy/flappy.js | 2 +- apps/src/gamelab/GameLab.js | 2 +- apps/src/jigsaw/jigsaw.js | 2 +- apps/src/maze/maze.js | 2 +- apps/src/netsim/netsim.js | 2 +- apps/src/studio/studio.js | 2 +- apps/src/templates/Hint.jsx | 2 +- apps/src/templates/ProtectedStatefulDiv.jsx | 2 +- apps/src/templates/ShareWarnings.jsx | 2 +- apps/src/turtle/turtle.js | 2 +- apps/test/ToggleButtonTest.js | 4 ++-- apps/test/shareWarningsDialogTest.js | 18 +++++++++--------- apps/test/solutions/applab/ec_design.js | 3 +-- apps/test/solutions/applab/ec_screens.js | 3 +-- code-studio/package.json | 3 ++- code-studio/src/js/code-studio.js | 1 + .../src/js/components/BeeCellEditor.jsx | 2 +- code-studio/src/js/components/CellEditor.jsx | 2 +- code-studio/src/js/components/GridEditor.jsx | 2 +- code-studio/src/js/components/dialog.jsx | 2 +- .../src/js/components/report_abuse_form.jsx | 8 ++++---- .../src/js/components/send_to_phone.jsx | 4 ++-- code-studio/src/js/components/small_footer.jsx | 4 ++-- code-studio/src/js/initApp/renderAbusive.js | 2 +- code-studio/src/js/levels/contract_match.jsx | 8 ++++---- code-studio/src/js/react-only.js | 1 + dashboard/app/assets/javascripts/header.js | 2 +- dashboard/app/assets/javascripts/progress.js | 4 ++-- .../app/views/layouts/_small_footer.html.haml | 2 +- .../app/views/levels/editors/_grid.html.haml | 2 +- .../report_abuse/report_abuse_form.html.haml | 2 +- 45 files changed, 74 insertions(+), 71 deletions(-) diff --git a/apps/Gruntfile.js b/apps/Gruntfile.js index fad9540d302c1..2773ab33ba1b6 100644 --- a/apps/Gruntfile.js +++ b/apps/Gruntfile.js @@ -475,6 +475,7 @@ module.exports = function (grunt) { $: true, jQuery: true, React: true, + ReactDOM: true, Blockly: true, Phaser: true, //TODO: Eliminate the globals below here. Could at least warn about them diff --git a/apps/package.json b/apps/package.json index 3aaf37c798fe9..cf602cc3a9ec4 100644 --- a/apps/package.json +++ b/apps/package.json @@ -77,8 +77,9 @@ "node-sass": "1.2.2", "npm-which": "2.0.0", "phantomjs-prebuilt": "^2.1.3", - "react": "0.13.3", - "react-tools": "0.13.3", + "react": "^0.14", + "react-addons-test-utils": "^0.14", + "react-dom": "^0.14", "require-globify": "1.2.1", "rgbcolor": "0.0.4", "sanitize-html": "^1.11.3", diff --git a/apps/src/StudioApp.js b/apps/src/StudioApp.js index c4c221e4408d3..d6e7a30d94ae3 100644 --- a/apps/src/StudioApp.js +++ b/apps/src/StudioApp.js @@ -496,7 +496,7 @@ StudioApp.prototype.init = function(config) { defaultBtnSelector: 'again-button', id: 'showVersionsModal' }); - React.render(React.createElement(VersionHistory, { + ReactDOM.render(React.createElement(VersionHistory, { handleClearPuzzle: this.handleClearPuzzle.bind(this, config) }), codeDiv); @@ -734,7 +734,7 @@ StudioApp.prototype.renderShareFooter_ = function(container) { phoneFooter: true }; - React.render(React.createElement(window.dashboard.SmallFooter, reactProps), + ReactDOM.render(React.createElement(window.dashboard.SmallFooter, reactProps), footerDiv); }; @@ -1075,7 +1075,7 @@ StudioApp.prototype.showInstructions_ = function(level, autoClose, showHints) { // Now that our elements are guaranteed to be in the DOM, we can // render in our react components $(this.instructionsDialog.div).on('show.bs.modal', function () { - React.render(instructionsContent, instructionsReactContainer); + ReactDOM.render(instructionsContent, instructionsReactContainer); }); if (autoClose) { @@ -1728,7 +1728,7 @@ StudioApp.prototype.handleHideSource_ = function (options) { var div = document.createElement('div'); document.body.appendChild(div); - React.render(React.createElement(WireframeSendToPhone, { + ReactDOM.render(React.createElement(WireframeSendToPhone, { channelId: dashboard.project.getCurrentId(), appType: dashboard.project.getStandaloneApp() }), div); @@ -2349,7 +2349,7 @@ StudioApp.prototype.displayAlert = function (parentSelector, props) { }, props); var element = React.createElement(Alert, reactProps); - React.render(element, container[0]); + ReactDOM.render(element, container[0]); }; /** diff --git a/apps/src/applab/DesignToolboxElement.jsx b/apps/src/applab/DesignToolboxElement.jsx index 42bc2f87dd0c8..48832f12a1339 100644 --- a/apps/src/applab/DesignToolboxElement.jsx +++ b/apps/src/applab/DesignToolboxElement.jsx @@ -54,7 +54,7 @@ module.exports = React.createClass({ * Create a draggable item as we drag an item from the toolbox. */ makeDraggable: function () { - $(this.getDOMNode()).find('.new-design-element').draggable({ + $(ReactDOM.findDOMNode(this)).find('.new-design-element').draggable({ // Create an item (without an id) for dragging that looks identical to the // element that will ultimately be dropped. Note, this item has no // containment, and doesn't snap to a grid as we drag (but does on drop) diff --git a/apps/src/applab/applab.js b/apps/src/applab/applab.js index 92f14c9c16ad4..017517a1615ac 100644 --- a/apps/src/applab/applab.js +++ b/apps/src/applab/applab.js @@ -382,7 +382,7 @@ function renderFooterInSharedGame() { }); } - React.render(React.createElement(window.dashboard.SmallFooter,{ + ReactDOM.render(React.createElement(window.dashboard.SmallFooter,{ i18nDropdown: '', copyrightInBase: false, copyrightStrings: copyrightStrings, @@ -551,7 +551,7 @@ Applab.startSharedAppAfterWarnings = function () { var modal = document.createElement('div'); document.body.appendChild(modal); - return React.render(React.createElement(ShareWarningsDialog, { + return ReactDOM.render(React.createElement(ShareWarningsDialog, { showStoreDataAlert: showStoreDataAlert, is13Plus: is13Plus, handleClose: function () { @@ -907,7 +907,7 @@ Applab.render = function () { onScreenChange: designMode.changeScreen, onScreenCreate: designMode.createScreen }); - React.render(React.createElement(AppLabView, nextProps), Applab.reactMountPoint_); + ReactDOM.render(React.createElement(AppLabView, nextProps), Applab.reactMountPoint_); }; /** diff --git a/apps/src/applab/designElements/ColorPickerPropertyRow.jsx b/apps/src/applab/designElements/ColorPickerPropertyRow.jsx index 23db69b238fcc..e2a97002be9d5 100644 --- a/apps/src/applab/designElements/ColorPickerPropertyRow.jsx +++ b/apps/src/applab/designElements/ColorPickerPropertyRow.jsx @@ -28,7 +28,7 @@ var ColorPickerPropertyRow = React.createClass({ * Make our button a colpick color picker, if it isn't already */ ensureColorPicker: function () { - var element = React.findDOMNode(this.refs.colorPicker); + var element = ReactDOM.findDOMNode(this.refs.colorPicker); $(element).colpick({ color: this.state.value, layout: 'rgbhex', diff --git a/apps/src/applab/designMode.js b/apps/src/applab/designMode.js index 9eb9901278f96..bda711265ec2b 100644 --- a/apps/src/applab/designMode.js +++ b/apps/src/applab/designMode.js @@ -875,7 +875,7 @@ designMode.renderDesignWorkspace = function(element) { handleManageAssets: showAssetManager, isDimmed: Applab.running }; - React.render(React.createElement(DesignWorkspace, props), designWorkspace); + ReactDOM.render(React.createElement(DesignWorkspace, props), designWorkspace); }; /** diff --git a/apps/src/assetManagement/AssetUploader.jsx b/apps/src/assetManagement/AssetUploader.jsx index f9f4277f8429a..569e5df392461 100644 --- a/apps/src/assetManagement/AssetUploader.jsx +++ b/apps/src/assetManagement/AssetUploader.jsx @@ -14,7 +14,7 @@ module.exports = React.createClass({ componentDidMount: function () { var props = this.props; - $(React.findDOMNode(this.refs.uploader)).fileupload({ + $(ReactDOM.findDOMNode(this.refs.uploader)).fileupload({ dataType: 'json', url: '/v3/assets/' + props.channelId + '/', // prevent fileupload from replacing the input DOM element, which @@ -34,7 +34,7 @@ module.exports = React.createClass({ }, componentWillUnmount: function () { - $(React.findDOMNode(this.refs.uploader)).fileupload('destroy'); + $(ReactDOM.findDOMNode(this.refs.uploader)).fileupload('destroy'); }, /** @@ -42,7 +42,7 @@ module.exports = React.createClass({ * Forward clicks on the button to the hidden file input. */ fileUploadClicked: function () { - var uploader = React.findDOMNode(this.refs.uploader); + var uploader = ReactDOM.findDOMNode(this.refs.uploader); uploader.click(); }, diff --git a/apps/src/assetManagement/show.js b/apps/src/assetManagement/show.js index 10e32838e94be..97e85583f5b24 100644 --- a/apps/src/assetManagement/show.js +++ b/apps/src/assetManagement/show.js @@ -19,7 +19,7 @@ module.exports = function(assetChosen, typeFilter) { defaultBtnSelector: 'again-button', id: 'manageAssetsModal' }); - React.render(React.createElement(AssetManager, { + ReactDOM.render(React.createElement(AssetManager, { typeFilter: typeFilter, channelId: dashboard.project.getCurrentId(), uploadsEnabled: !dashboard.project.exceedsAbuseThreshold(), diff --git a/apps/src/authoredHints.js b/apps/src/authoredHints.js index b9e671bc2eb32..78efad5a9286c 100644 --- a/apps/src/authoredHints.js +++ b/apps/src/authoredHints.js @@ -251,7 +251,7 @@ AuthoredHints.prototype.showHint_ = function (hint, callback) { }.bind(this), }); - React.render(element, container); + ReactDOM.render(element, container); return container; }.bind(this), diff --git a/apps/src/bounce/bounce.js b/apps/src/bounce/bounce.js index 057e992917d9d..b5cb9e0585bbe 100644 --- a/apps/src/bounce/bounce.js +++ b/apps/src/bounce/bounce.js @@ -805,7 +805,7 @@ Bounce.init = function(config) { dom.addClickTouchEvent(finishButton, Bounce.onPuzzleComplete); }; - React.render(React.createElement(AppView, { + ReactDOM.render(React.createElement(AppView, { assetUrl: studioApp.assetUrl, isEmbedView: !!config.embed, isShareView: !!config.share, diff --git a/apps/src/calc/calc.js b/apps/src/calc/calc.js index bfd3cfee9f60c..7a90160e4107c 100644 --- a/apps/src/calc/calc.js +++ b/apps/src/calc/calc.js @@ -227,7 +227,7 @@ Calc.init = function(config) { }); }; - React.render(React.createElement(AppView, { + ReactDOM.render(React.createElement(AppView, { assetUrl: studioApp.assetUrl, isEmbedView: !!config.embed, isShareView: !!config.share, diff --git a/apps/src/craft/craft.js b/apps/src/craft/craft.js index 5f56bb3d1ff0e..1536443249cf4 100644 --- a/apps/src/craft/craft.js +++ b/apps/src/craft/craft.js @@ -334,7 +334,7 @@ Craft.init = function (config) { } }; - React.render(React.createElement(AppView, { + ReactDOM.render(React.createElement(AppView, { assetUrl: studioApp.assetUrl, isEmbedView: !!config.embed, isShareView: !!config.share, diff --git a/apps/src/eval/eval.js b/apps/src/eval/eval.js index 2a069d5af0a5c..97965c3eac03a 100644 --- a/apps/src/eval/eval.js +++ b/apps/src/eval/eval.js @@ -173,7 +173,7 @@ Eval.init = function(config) { }); }; - React.render(React.createElement(AppView, { + ReactDOM.render(React.createElement(AppView, { assetUrl: studioApp.assetUrl, isEmbedView: !!config.embed, isShareView: !!config.share, diff --git a/apps/src/flappy/flappy.js b/apps/src/flappy/flappy.js index bfd665825d38f..ad22535d93aad 100644 --- a/apps/src/flappy/flappy.js +++ b/apps/src/flappy/flappy.js @@ -607,7 +607,7 @@ Flappy.init = function(config) { dom.addClickTouchEvent(rightButton, Flappy.onPuzzleComplete); }; - React.render(React.createElement(AppView, { + ReactDOM.render(React.createElement(AppView, { assetUrl: studioApp.assetUrl, isEmbedView: !!config.embed, isShareView: !!config.share, diff --git a/apps/src/gamelab/GameLab.js b/apps/src/gamelab/GameLab.js index 8bb31e9a0676b..9cbfe47acd260 100644 --- a/apps/src/gamelab/GameLab.js +++ b/apps/src/gamelab/GameLab.js @@ -154,7 +154,7 @@ GameLab.prototype.init = function (config) { }); }.bind(this); - React.render(React.createElement(AppView, { + ReactDOM.render(React.createElement(AppView, { assetUrl: this.studioApp_.assetUrl, isEmbedView: !!config.embed, isShareView: !!config.share, diff --git a/apps/src/jigsaw/jigsaw.js b/apps/src/jigsaw/jigsaw.js index 71b1f799bb209..20d33f2a81a8e 100644 --- a/apps/src/jigsaw/jigsaw.js +++ b/apps/src/jigsaw/jigsaw.js @@ -186,7 +186,7 @@ Jigsaw.init = function(config) { } }; - React.render(React.createElement(AppView, { + ReactDOM.render(React.createElement(AppView, { assetUrl: studioApp.assetUrl, isEmbedView: !!config.embed, isShareView: !!config.share, diff --git a/apps/src/maze/maze.js b/apps/src/maze/maze.js index a10c288cccf08..e34f4fa48b452 100644 --- a/apps/src/maze/maze.js +++ b/apps/src/maze/maze.js @@ -644,7 +644,7 @@ Maze.init = function(config) { }); }; - React.render(React.createElement(AppView, { + ReactDOM.render(React.createElement(AppView, { assetUrl: studioApp.assetUrl, isEmbedView: !!config.embed, isShareView: !!config.share, diff --git a/apps/src/netsim/netsim.js b/apps/src/netsim/netsim.js index 73cc8fc7c6d93..e07f0b4c9a0b9 100644 --- a/apps/src/netsim/netsim.js +++ b/apps/src/netsim/netsim.js @@ -257,7 +257,7 @@ NetSim.prototype.init = function(config) { this.runLoop_.begin(); }.bind(this); - React.render(React.createElement(NetSimView, { + ReactDOM.render(React.createElement(NetSimView, { assetUrl: this.studioApp_.assetUrl, isEmbedView: !!config.embed, isShareView: !!config.share, diff --git a/apps/src/studio/studio.js b/apps/src/studio/studio.js index 438e4faaa792f..dc2ec64c548bc 100644 --- a/apps/src/studio/studio.js +++ b/apps/src/studio/studio.js @@ -2005,7 +2005,7 @@ Studio.init = function(config) { } }; - React.render(React.createElement(AppView, { + ReactDOM.render(React.createElement(AppView, { assetUrl: studioApp.assetUrl, isEmbedView: !!config.embed, isShareView: !!config.share, diff --git a/apps/src/templates/Hint.jsx b/apps/src/templates/Hint.jsx index 695693b691eb8..310aa4188e46c 100644 --- a/apps/src/templates/Hint.jsx +++ b/apps/src/templates/Hint.jsx @@ -8,7 +8,7 @@ module.exports = React.createClass({ * @see HintsDisplay.injectBlocklyHint */ injectBlocklyHint: function () { - var node = React.findDOMNode(this.refs.hintBlock); + var node = ReactDOM.findDOMNode(this.refs.hintBlock); // Only render if the node exists in the DOM if (node && document.body.contains(node)) { Blockly.BlockSpace.createReadOnlyBlockSpace(node, this.props.hint.block); diff --git a/apps/src/templates/ProtectedStatefulDiv.jsx b/apps/src/templates/ProtectedStatefulDiv.jsx index b9e62507296b6..3cb1c0c04eb78 100644 --- a/apps/src/templates/ProtectedStatefulDiv.jsx +++ b/apps/src/templates/ProtectedStatefulDiv.jsx @@ -19,7 +19,7 @@ var ProtectedStatefulDiv = React.createClass({ componentDidMount: function () { if (typeof this.props.renderContents === 'function') { - this.refs.root.getDOMNode().innerHTML = this.props.renderContents(); + this.refs.root.innerHTML = this.props.renderContents(); } }, diff --git a/apps/src/templates/ShareWarnings.jsx b/apps/src/templates/ShareWarnings.jsx index 0d211375f92a9..52b7b7922f343 100644 --- a/apps/src/templates/ShareWarnings.jsx +++ b/apps/src/templates/ShareWarnings.jsx @@ -22,7 +22,7 @@ var SharingWarnings = module.exports = React.createClass({ return; } - var ageElement = React.findDOMNode(this.refs.age); + var ageElement = ReactDOM.findDOMNode(this.refs.age); if (ageElement.value === '') { // ignore close if we haven't selected a value from dropdown return; diff --git a/apps/src/turtle/turtle.js b/apps/src/turtle/turtle.js index 101e3488283d9..edcb2103df18f 100644 --- a/apps/src/turtle/turtle.js +++ b/apps/src/turtle/turtle.js @@ -233,7 +233,7 @@ Artist.prototype.init = function(config) { }); }.bind(this); - React.render(React.createElement(AppView, { + ReactDOM.render(React.createElement(AppView, { assetUrl: this.studioApp_.assetUrl, isEmbedView: !!config.embed, isShareView: !!config.share, diff --git a/apps/test/ToggleButtonTest.js b/apps/test/ToggleButtonTest.js index be022eeaac21a..31202cc532453 100644 --- a/apps/test/ToggleButtonTest.js +++ b/apps/test/ToggleButtonTest.js @@ -3,8 +3,8 @@ */ var testUtils = require('./util/testUtils'); var assert = testUtils.assert; -window.React = require('react/addons'); -var ReactTestUtils = React.addons.TestUtils; +window.React = require('react'); +var ReactTestUtils = require('react-addons-test-utils'); window.$ = require('jquery'); describe('ToggleButton', function () { diff --git a/apps/test/shareWarningsDialogTest.js b/apps/test/shareWarningsDialogTest.js index 0c44f7365c899..62b7342f190de 100644 --- a/apps/test/shareWarningsDialogTest.js +++ b/apps/test/shareWarningsDialogTest.js @@ -1,6 +1,6 @@ window.React = require('react'); -require('react/addons'); -var ReactTestUtils = React.addons.TestUtils; +window.ReactDOM = require('react-dom'); +var ReactTestUtils = require('react-addons-test-utils'); var testUtils = require('./util/testUtils'); var assert = testUtils.assert; @@ -16,7 +16,7 @@ describe('ShareWarningsDialog', function () { if (!ReactTestUtils.isDOMComponent(childComponent)) { return false; } - var dom = childComponent.getDOMNode(); + var dom = childComponent; return dom.tagName === tagName && dom.innerHTML === text; } @@ -131,7 +131,7 @@ describe('ShareWarningsDialog', function () { 'button')[0]; assert(okButton, 'have an ok button'); - ReactTestUtils.Simulate.click(okButton.getDOMNode()); + ReactTestUtils.Simulate.click(okButton); assert(handleCloseCalled, 'closed dialog'); assert.equal(componentInstance.state.modalIsOpen, false); @@ -157,7 +157,7 @@ describe('ShareWarningsDialog', function () { 'button')[0]; assert(okButton, 'have an ok button'); - ReactTestUtils.Simulate.click(okButton.getDOMNode()); + ReactTestUtils.Simulate.click(okButton); assert(!handleCloseCalled, 'closed dialog'); assert.equal(componentInstance.state.modalIsOpen, true); @@ -181,13 +181,13 @@ describe('ShareWarningsDialog', function () { var select = ReactTestUtils.scryRenderedDOMComponentsWithTag(shareWarnings, 'select')[0]; - select.getDOMNode().value = "13"; + select.value = "13"; var okButton = ReactTestUtils.scryRenderedDOMComponentsWithTag(shareWarnings, 'button')[0]; assert(okButton, 'have an ok button'); - ReactTestUtils.Simulate.click(okButton.getDOMNode()); + ReactTestUtils.Simulate.click(okButton); assert(handleCloseCalled, 'closed dialog'); assert.equal(componentInstance.state.modalIsOpen, false); @@ -211,13 +211,13 @@ describe('ShareWarningsDialog', function () { var select = ReactTestUtils.scryRenderedDOMComponentsWithTag(shareWarnings, 'select')[0]; - select.getDOMNode().value = "12"; + select.value = "12"; var okButton = ReactTestUtils.scryRenderedDOMComponentsWithTag(shareWarnings, 'button')[0]; assert(okButton, 'have an ok button'); - ReactTestUtils.Simulate.click(okButton.getDOMNode()); + ReactTestUtils.Simulate.click(okButton); assert(handleTooYoungCalled, 'closed dialog'); }); }); diff --git a/apps/test/solutions/applab/ec_design.js b/apps/test/solutions/applab/ec_design.js index 55c7b25aaabe3..f7fa528821052 100644 --- a/apps/test/solutions/applab/ec_design.js +++ b/apps/test/solutions/applab/ec_design.js @@ -2,8 +2,7 @@ var testUtils = require('../../util/testUtils'); var TestResults = require('@cdo/apps/constants').TestResults; var _ = require('lodash'); var $ = require('jquery'); -require('react/addons'); -var ReactTestUtils = React.addons.TestUtils; +var ReactTestUtils = require('react-addons-test-utils'); // i'd like this test to not run through level tests, which has a lot of hacks, // but this is the easiest approach for now. hopefully at some point in the diff --git a/apps/test/solutions/applab/ec_screens.js b/apps/test/solutions/applab/ec_screens.js index e4fb3b03bd9a7..c8b1404eb6c96 100644 --- a/apps/test/solutions/applab/ec_screens.js +++ b/apps/test/solutions/applab/ec_screens.js @@ -2,8 +2,7 @@ var testUtils = require('../../util/testUtils'); var TestResults = require('@cdo/apps/constants').TestResults; var _ = require('lodash'); var $ = require('jquery'); -require('react/addons'); -var ReactTestUtils = React.addons.TestUtils; +var ReactTestUtils = require('react-addons-test-utils'); // i'd like this test to not run through level tests, which has a lot of hacks, // but this is the easiest approach for now. hopefully at some point in the diff --git a/code-studio/package.json b/code-studio/package.json index f4c0ca9915b68..56a83720cf169 100644 --- a/code-studio/package.json +++ b/code-studio/package.json @@ -74,7 +74,8 @@ "linklocal": "^2.5.2", "lodash": "^3.10.1", "marked": "0.3.2", - "react": "^0.13.1", + "react": "^0.14", + "react-dom": "^0.14", "video.js": "4.5.2" } } diff --git a/code-studio/src/js/code-studio.js b/code-studio/src/js/code-studio.js index d16ff71aaf375..99afc95cd066a 100644 --- a/code-studio/src/js/code-studio.js +++ b/code-studio/src/js/code-studio.js @@ -15,6 +15,7 @@ require('./consoleShim')(window); require('./videos'); window.React = require('react'); +window.ReactDOM = require('react-dom'); // TODO (bbuchanan): Stop including these components in a global way, just // require them specifically where needed. require('./components/abuse_error.jsx'); diff --git a/code-studio/src/js/components/BeeCellEditor.jsx b/code-studio/src/js/components/BeeCellEditor.jsx index ac681fcf71bb3..067e597f79d3f 100644 --- a/code-studio/src/js/components/BeeCellEditor.jsx +++ b/code-studio/src/js/components/BeeCellEditor.jsx @@ -19,7 +19,7 @@ var BeeCellEditor = React.createClass({ handleChange: function (event) { var values = {}; - var nodes = this.getDOMNode().querySelectorAll('[name]'); + var nodes = ReactDOM.findDOMNode(this).querySelectorAll('[name]'); // see "Iterating over Node Lists" here for an explanation of this // strange-looking for loop // https://google.github.io/styleguide/javascriptguide.xml?showone=Tips_and_Tricks#Tips_and_Tricks diff --git a/code-studio/src/js/components/CellEditor.jsx b/code-studio/src/js/components/CellEditor.jsx index c6d0c1050cb51..f5b575cf32026 100644 --- a/code-studio/src/js/components/CellEditor.jsx +++ b/code-studio/src/js/components/CellEditor.jsx @@ -17,7 +17,7 @@ var CellEditor = React.createClass({ handleChange: function (event) { var values = {}; - var nodes = this.getDOMNode().querySelectorAll('[name]'); + var nodes = ReactDOM.findDOMNode(this).querySelectorAll('[name]'); for (var i = 0, node; (node = nodes[i]); i++) { values[node.name] = isNaN(node.value) ? undefined : parseInt(node.value); } diff --git a/code-studio/src/js/components/GridEditor.jsx b/code-studio/src/js/components/GridEditor.jsx index 4cf40515a2879..910585f60eca3 100644 --- a/code-studio/src/js/components/GridEditor.jsx +++ b/code-studio/src/js/components/GridEditor.jsx @@ -20,7 +20,7 @@ var CellJSON = React.createClass({ }, componentDidUpdate: function () { - var node = this.refs.serializedInput.getDOMNode(); + var node = this.refs.serializedInput; node.focus(); node.select(); }, diff --git a/code-studio/src/js/components/dialog.jsx b/code-studio/src/js/components/dialog.jsx index 8cfdb2331066a..2e6ef499dbd25 100644 --- a/code-studio/src/js/components/dialog.jsx +++ b/code-studio/src/js/components/dialog.jsx @@ -31,7 +31,7 @@ var Dialog = React.createClass({ focusDialog: function () { if (this.props.isOpen) { - this.refs.dialog.getDOMNode().focus(); + this.refs.dialog.focus(); } }, diff --git a/code-studio/src/js/components/report_abuse_form.jsx b/code-studio/src/js/components/report_abuse_form.jsx index 14481c6cd25a7..8bbf58b2f6902 100644 --- a/code-studio/src/js/components/report_abuse_form.jsx +++ b/code-studio/src/js/components/report_abuse_form.jsx @@ -70,25 +70,25 @@ var ReportAbuseForm = React.createClass({ handleSubmit: function (event) { var i18n = this.props.i18n; - if (React.findDOMNode(this.refs.email).value === '') { + if (ReactDOM.findDOMNode(this.refs.email).value === '') { alert(i18n.t('project.abuse.report_abuse_form.validation.email')); event.preventDefault(); return; } - if (React.findDOMNode(this.refs.age).value === '') { + if (ReactDOM.findDOMNode(this.refs.age).value === '') { alert(i18n.t('project.abuse.report_abuse_form.validation.age')); event.preventDefault(); return; } - if (React.findDOMNode(this.refs.abuse_type).value === '') { + if (ReactDOM.findDOMNode(this.refs.abuse_type).value === '') { alert(i18n.t('project.abuse.report_abuse_form.validation.abuse_type')); event.preventDefault(); return; } - if (React.findDOMNode(this.refs.abuse_detail).value === '') { + if (ReactDOM.findDOMNode(this.refs.abuse_detail).value === '') { alert(i18n.t('project.abuse.report_abuse_form.validation.abuse_detail')); event.preventDefault(); return; diff --git a/code-studio/src/js/components/send_to_phone.jsx b/code-studio/src/js/components/send_to_phone.jsx index 5cf0492ae9f18..d1777b405f410 100644 --- a/code-studio/src/js/components/send_to_phone.jsx +++ b/code-studio/src/js/components/send_to_phone.jsx @@ -59,7 +59,7 @@ var SendToPhone = React.createClass({ return; } - var phone = this.refs.phone.getDOMNode(); + var phone = this.refs.phone; $(phone).mask('(000) 000-0000', { onComplete: function () { this.setState({sendState: SendState.canSubmit}); @@ -76,7 +76,7 @@ var SendToPhone = React.createClass({ if (this.state.sendState !== SendState.canSubmit) { return; } - var phone = this.refs.phone.getDOMNode(); + var phone = this.refs.phone; this.setState({sendState: SendState.sending}); diff --git a/code-studio/src/js/components/small_footer.jsx b/code-studio/src/js/components/small_footer.jsx index 9b0f4f99d622b..d33ffd17408e0 100644 --- a/code-studio/src/js/components/small_footer.jsx +++ b/code-studio/src/js/components/small_footer.jsx @@ -60,7 +60,7 @@ var SmallFooter = React.createClass({ }, captureBaseElementDimensions: function () { - var base = React.findDOMNode(this.refs.base); + var base = ReactDOM.findDOMNode(this.refs.base); this.setState({ baseWidth: base.offsetWidth, baseHeight: base.offsetHeight @@ -71,7 +71,7 @@ var SmallFooter = React.createClass({ // The first time we click anywhere, hide any open children $(document.body).one('click', function (event) { // menu copyright has its own click handler - if (event.target === React.findDOMNode(this.refs.menuCopyright)) { + if (event.target === ReactDOM.findDOMNode(this.refs.menuCopyright)) { return; } diff --git a/code-studio/src/js/initApp/renderAbusive.js b/code-studio/src/js/initApp/renderAbusive.js index 058222a867408..20556caf02556 100644 --- a/code-studio/src/js/initApp/renderAbusive.js +++ b/code-studio/src/js/initApp/renderAbusive.js @@ -6,7 +6,7 @@ var AbuseExclamation = require('../components/abuse_exclamation.jsx'); * Renders our AbuseExclamation component, and potentially updates admin box */ module.exports = function () { - React.render(React.createElement(AbuseExclamation, { + ReactDOM.render(React.createElement(AbuseExclamation, { i18n: { tos: window.dashboard.i18n.t('project.abuse.tos'), contact_us: window.dashboard.i18n.t('project.abuse.contact_us'), diff --git a/code-studio/src/js/levels/contract_match.jsx b/code-studio/src/js/levels/contract_match.jsx index 0affea78694d5..fc8d266585dc0 100644 --- a/code-studio/src/js/levels/contract_match.jsx +++ b/code-studio/src/js/levels/contract_match.jsx @@ -225,20 +225,20 @@ $(window).load(function () { ); }, componentDidMount: function () { - $(React.findDOMNode(this)).coloriconselectmenu({ + $(ReactDOM.findDOMNode(this)).coloriconselectmenu({ select: function () { addSquareIconToButton(this); }, change: this.selectmenuChange }); - $(React.findDOMNode(this)).coloriconselectmenu("styleCurrentValue"); + $(ReactDOM.findDOMNode(this)).coloriconselectmenu("styleCurrentValue"); }, componentWillUnmount: function () { - $(React.findDOMNode(this)).coloriconselectmenu('destroy'); + $(ReactDOM.findDOMNode(this)).coloriconselectmenu('destroy'); } }); - var contractForm = React.render(, document.getElementById('contractForm')); + var contractForm = ReactDOM.render(, document.getElementById('contractForm')); /** * Creates a getResult function compatible with _dialog.html.haml's getResult call diff --git a/code-studio/src/js/react-only.js b/code-studio/src/js/react-only.js index bc375fed05263..403e6ff40362d 100644 --- a/code-studio/src/js/react-only.js +++ b/code-studio/src/js/react-only.js @@ -5,3 +5,4 @@ */ window.React = require('react'); +window.ReactDOM = require('react-dom'); diff --git a/dashboard/app/assets/javascripts/header.js b/dashboard/app/assets/javascripts/header.js index ab199b3611722..85fb7c5ed52c7 100644 --- a/dashboard/app/assets/javascripts/header.js +++ b/dashboard/app/assets/javascripts/header.js @@ -179,7 +179,7 @@ dashboard.header = (function () { appType: dashboard.project.getStandaloneApp(), onClickPopup: dashboard.popupWindow }); - React.render(dialog, dialogDom); + ReactDOM.render(dialog, dialogDom); }); } diff --git a/dashboard/app/assets/javascripts/progress.js b/dashboard/app/assets/javascripts/progress.js index 9a2b82f791b92..e0a986b37171c 100644 --- a/dashboard/app/assets/javascripts/progress.js +++ b/dashboard/app/assets/javascripts/progress.js @@ -106,14 +106,14 @@ window.dashboard.progress = (function () { }; }); - $('.progress_container').replaceWith(React.renderToStaticMarkup(React.createElement(dashboard.StageProgress, { + $('.progress_container').replaceWith(ReactDOM.renderToStaticMarkup(React.createElement(dashboard.StageProgress, { levels: combinedProgress, currentLevelIndex: currentLevelIndex }))); }; progress.renderCourseProgress = function (scriptData) { - $('.user-stats-block').prepend(React.renderToStaticMarkup(React.createElement(dashboard.CourseProgress, { + $('.user-stats-block').prepend(ReactDOM.renderToStaticMarkup(React.createElement(dashboard.CourseProgress, { stages: scriptData.stages }))); progress.populateProgress(scriptData.name); diff --git a/dashboard/app/views/layouts/_small_footer.html.haml b/dashboard/app/views/layouts/_small_footer.html.haml index a56d53b3f67c7..36b4d0fc37308 100644 --- a/dashboard/app/views/layouts/_small_footer.html.haml +++ b/dashboard/app/views/layouts/_small_footer.html.haml @@ -40,5 +40,5 @@ :javascript // Render the footer on the non-share pages - React.render(React.createElement(window.dashboard.SmallFooter, #{reactProps.to_json}), + ReactDOM.render(React.createElement(window.dashboard.SmallFooter, #{reactProps.to_json}), document.getElementById('page-small-footer')); diff --git a/dashboard/app/views/levels/editors/_grid.html.haml b/dashboard/app/views/levels/editors/_grid.html.haml index 186441f264a98..febdb83d2bc50 100644 --- a/dashboard/app/views/levels/editors/_grid.html.haml +++ b/dashboard/app/views/levels/editors/_grid.html.haml @@ -85,7 +85,7 @@ var serializedMaze = eval(#{@level.properties['serialized_maze'].try(:to_json)}); var renderGridEditor = function () { - React.render(React.createElement(dashboard.GridEditor, { + ReactDOM.render(React.createElement(dashboard.GridEditor, { maze: maze, initialDirt: initialDirt, serializedMaze: serializedMaze, diff --git a/dashboard/app/views/report_abuse/report_abuse_form.html.haml b/dashboard/app/views/report_abuse/report_abuse_form.html.haml index 3bde73b116c9e..3d6649f85e56a 100644 --- a/dashboard/app/views/report_abuse/report_abuse_form.html.haml +++ b/dashboard/app/views/report_abuse/report_abuse_form.html.haml @@ -7,7 +7,7 @@ var props = #{@react_props.to_json}; props.abuseUrl = document.referrer; props.i18n = window.dashboard.i18n; - React.render( + ReactDOM.render( React.createElement(window.dashboard.ReportAbuseForm, props), document.getElementById('report-abuse-form')); }); From 8ff512d7a0667f1b63db6cd7e7fa048d873a807e Mon Sep 17 00:00:00 2001 From: Brad Buchanan Date: Wed, 2 Mar 2016 10:27:09 -0800 Subject: [PATCH 02/11] Pin React to 0.14.7 --- apps/package.json | 6 +++--- code-studio/package.json | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/package.json b/apps/package.json index cf602cc3a9ec4..1be8d0d0e36d1 100644 --- a/apps/package.json +++ b/apps/package.json @@ -77,9 +77,9 @@ "node-sass": "1.2.2", "npm-which": "2.0.0", "phantomjs-prebuilt": "^2.1.3", - "react": "^0.14", - "react-addons-test-utils": "^0.14", - "react-dom": "^0.14", + "react": "0.14.7", + "react-addons-test-utils": "0.14.7", + "react-dom": "0.14.7", "require-globify": "1.2.1", "rgbcolor": "0.0.4", "sanitize-html": "^1.11.3", diff --git a/code-studio/package.json b/code-studio/package.json index 56a83720cf169..4a2891ede1f9a 100644 --- a/code-studio/package.json +++ b/code-studio/package.json @@ -74,8 +74,8 @@ "linklocal": "^2.5.2", "lodash": "^3.10.1", "marked": "0.3.2", - "react": "^0.14", - "react-dom": "^0.14", + "react": "0.14.7", + "react-dom": "0.14.7", "video.js": "4.5.2" } } From 0a8c8f26641f1482506e7d65960acb63a82735bf Mon Sep 17 00:00:00 2001 From: Brad Buchanan Date: Wed, 2 Mar 2016 10:33:10 -0800 Subject: [PATCH 03/11] Remove unneeded calls to ReactDOM.findDOMNode() --- apps/src/applab/designElements/ColorPickerPropertyRow.jsx | 3 +-- apps/src/assetManagement/AssetUploader.jsx | 7 +++---- apps/src/templates/Hint.jsx | 2 +- apps/src/templates/ShareWarnings.jsx | 2 +- code-studio/src/js/components/report_abuse_form.jsx | 8 ++++---- code-studio/src/js/components/small_footer.jsx | 4 ++-- 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/apps/src/applab/designElements/ColorPickerPropertyRow.jsx b/apps/src/applab/designElements/ColorPickerPropertyRow.jsx index e2a97002be9d5..180d8e32d6957 100644 --- a/apps/src/applab/designElements/ColorPickerPropertyRow.jsx +++ b/apps/src/applab/designElements/ColorPickerPropertyRow.jsx @@ -28,8 +28,7 @@ var ColorPickerPropertyRow = React.createClass({ * Make our button a colpick color picker, if it isn't already */ ensureColorPicker: function () { - var element = ReactDOM.findDOMNode(this.refs.colorPicker); - $(element).colpick({ + $(this.refs.colorPicker).colpick({ color: this.state.value, layout: 'rgbhex', submit: 0, diff --git a/apps/src/assetManagement/AssetUploader.jsx b/apps/src/assetManagement/AssetUploader.jsx index 569e5df392461..7e237b381c06f 100644 --- a/apps/src/assetManagement/AssetUploader.jsx +++ b/apps/src/assetManagement/AssetUploader.jsx @@ -14,7 +14,7 @@ module.exports = React.createClass({ componentDidMount: function () { var props = this.props; - $(ReactDOM.findDOMNode(this.refs.uploader)).fileupload({ + $(this.refs.uploader).fileupload({ dataType: 'json', url: '/v3/assets/' + props.channelId + '/', // prevent fileupload from replacing the input DOM element, which @@ -34,7 +34,7 @@ module.exports = React.createClass({ }, componentWillUnmount: function () { - $(ReactDOM.findDOMNode(this.refs.uploader)).fileupload('destroy'); + $(this.refs.uploader).fileupload('destroy'); }, /** @@ -42,8 +42,7 @@ module.exports = React.createClass({ * Forward clicks on the button to the hidden file input. */ fileUploadClicked: function () { - var uploader = ReactDOM.findDOMNode(this.refs.uploader); - uploader.click(); + this.refs.uploader.click(); }, render: function () { diff --git a/apps/src/templates/Hint.jsx b/apps/src/templates/Hint.jsx index 310aa4188e46c..d1c06c622d8d6 100644 --- a/apps/src/templates/Hint.jsx +++ b/apps/src/templates/Hint.jsx @@ -8,7 +8,7 @@ module.exports = React.createClass({ * @see HintsDisplay.injectBlocklyHint */ injectBlocklyHint: function () { - var node = ReactDOM.findDOMNode(this.refs.hintBlock); + var node = this.refs.hintBlock; // Only render if the node exists in the DOM if (node && document.body.contains(node)) { Blockly.BlockSpace.createReadOnlyBlockSpace(node, this.props.hint.block); diff --git a/apps/src/templates/ShareWarnings.jsx b/apps/src/templates/ShareWarnings.jsx index 52b7b7922f343..0e48574b20b0f 100644 --- a/apps/src/templates/ShareWarnings.jsx +++ b/apps/src/templates/ShareWarnings.jsx @@ -22,7 +22,7 @@ var SharingWarnings = module.exports = React.createClass({ return; } - var ageElement = ReactDOM.findDOMNode(this.refs.age); + var ageElement = this.refs.age; if (ageElement.value === '') { // ignore close if we haven't selected a value from dropdown return; diff --git a/code-studio/src/js/components/report_abuse_form.jsx b/code-studio/src/js/components/report_abuse_form.jsx index 8bbf58b2f6902..e75f00b74b778 100644 --- a/code-studio/src/js/components/report_abuse_form.jsx +++ b/code-studio/src/js/components/report_abuse_form.jsx @@ -70,25 +70,25 @@ var ReportAbuseForm = React.createClass({ handleSubmit: function (event) { var i18n = this.props.i18n; - if (ReactDOM.findDOMNode(this.refs.email).value === '') { + if (this.refs.email.value === '') { alert(i18n.t('project.abuse.report_abuse_form.validation.email')); event.preventDefault(); return; } - if (ReactDOM.findDOMNode(this.refs.age).value === '') { + if (this.refs.age.value === '') { alert(i18n.t('project.abuse.report_abuse_form.validation.age')); event.preventDefault(); return; } - if (ReactDOM.findDOMNode(this.refs.abuse_type).value === '') { + if (this.refs.abuse_type.value === '') { alert(i18n.t('project.abuse.report_abuse_form.validation.abuse_type')); event.preventDefault(); return; } - if (ReactDOM.findDOMNode(this.refs.abuse_detail).value === '') { + if (this.refs.abuse_detail.value === '') { alert(i18n.t('project.abuse.report_abuse_form.validation.abuse_detail')); event.preventDefault(); return; diff --git a/code-studio/src/js/components/small_footer.jsx b/code-studio/src/js/components/small_footer.jsx index d33ffd17408e0..90d6b6c1eb296 100644 --- a/code-studio/src/js/components/small_footer.jsx +++ b/code-studio/src/js/components/small_footer.jsx @@ -60,7 +60,7 @@ var SmallFooter = React.createClass({ }, captureBaseElementDimensions: function () { - var base = ReactDOM.findDOMNode(this.refs.base); + var base = this.refs.base; this.setState({ baseWidth: base.offsetWidth, baseHeight: base.offsetHeight @@ -71,7 +71,7 @@ var SmallFooter = React.createClass({ // The first time we click anywhere, hide any open children $(document.body).one('click', function (event) { // menu copyright has its own click handler - if (event.target === ReactDOM.findDOMNode(this.refs.menuCopyright)) { + if (event.target === this.refs.menuCopyright) { return; } From 0c6891167e85eb13988d8aa215da19647d0d1750 Mon Sep 17 00:00:00 2001 From: Brad Buchanan Date: Wed, 2 Mar 2016 11:21:23 -0800 Subject: [PATCH 04/11] Re-add two necessary calls to ReactDOM.findDOMNode() --- apps/src/templates/ShareWarnings.jsx | 2 +- code-studio/src/js/components/report_abuse_form.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/src/templates/ShareWarnings.jsx b/apps/src/templates/ShareWarnings.jsx index 0e48574b20b0f..52b7b7922f343 100644 --- a/apps/src/templates/ShareWarnings.jsx +++ b/apps/src/templates/ShareWarnings.jsx @@ -22,7 +22,7 @@ var SharingWarnings = module.exports = React.createClass({ return; } - var ageElement = this.refs.age; + var ageElement = ReactDOM.findDOMNode(this.refs.age); if (ageElement.value === '') { // ignore close if we haven't selected a value from dropdown return; diff --git a/code-studio/src/js/components/report_abuse_form.jsx b/code-studio/src/js/components/report_abuse_form.jsx index e75f00b74b778..e1a7e14dbbf0c 100644 --- a/code-studio/src/js/components/report_abuse_form.jsx +++ b/code-studio/src/js/components/report_abuse_form.jsx @@ -76,7 +76,7 @@ var ReportAbuseForm = React.createClass({ return; } - if (this.refs.age.value === '') { + if (ReactDOM.findDOMNode(this.refs.age).value === '') { alert(i18n.t('project.abuse.report_abuse_form.validation.age')); event.preventDefault(); return; From 6792db9f5f76396023591ccc699a85839fd3c1ba Mon Sep 17 00:00:00 2001 From: Brad Buchanan Date: Wed, 2 Mar 2016 11:28:41 -0800 Subject: [PATCH 05/11] Fix warning when rendering VersionHistory.jsx Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of `exports`. See https://fb.me/react-warning-keys for more information. Fixed by passing the version ID as the key to help React keep track of the rows. Also updated component delcaration pattern to follow our convention, for easier reading in the React debug tools. --- apps/src/templates/VersionHistory.jsx | 4 +++- apps/src/templates/VersionRow.jsx | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/src/templates/VersionHistory.jsx b/apps/src/templates/VersionHistory.jsx index 6231e76a467e4..b8d4daf302b17 100644 --- a/apps/src/templates/VersionHistory.jsx +++ b/apps/src/templates/VersionHistory.jsx @@ -5,7 +5,7 @@ var sourcesApi = require('../clientApi').sources; /** * A component for viewing project version history. */ -module.exports = React.createClass({ +var VersionHistory = React.createClass({ propTypes: { handleClearPuzzle: React.PropTypes.func.isRequired }, @@ -101,6 +101,7 @@ module.exports = React.createClass({ } else { var rows = this.state.versions.map(function (version) { return ; @@ -138,3 +139,4 @@ module.exports = React.createClass({ ); } }); +module.exports = VersionHistory; diff --git a/apps/src/templates/VersionRow.jsx b/apps/src/templates/VersionRow.jsx index 4f0165a999981..e649f07da09a0 100644 --- a/apps/src/templates/VersionRow.jsx +++ b/apps/src/templates/VersionRow.jsx @@ -4,7 +4,7 @@ /** * A single row in the VersionHistory dialog, describing one version of a project. */ -module.exports = React.createClass({ +var VersionRow = React.createClass({ propTypes: { lastModified: React.PropTypes.instanceOf(Date), isLatest: React.PropTypes.bool, @@ -46,3 +46,4 @@ module.exports = React.createClass({ $('.versionTimestamp').timeago(); } }); +module.exports = VersionRow; From 314e0ffa0e75a40350bbd1b3911584a820cede64 Mon Sep 17 00:00:00 2001 From: Brad Buchanan Date: Wed, 2 Mar 2016 13:02:19 -0800 Subject: [PATCH 06/11] Clean up warning in report_abuse_form.jsx Warning: Failed form propType: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`. Check the render method of `AgeDropdown`. I solved by changing the select 'value' to 'defaultValue' which seems in the spirit of this component. Possible future work: Why does report_abuse_form.jsx have its own AgeDropdown instead of using AgeDropdown.jsx? --- code-studio/src/js/components/report_abuse_form.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code-studio/src/js/components/report_abuse_form.jsx b/code-studio/src/js/components/report_abuse_form.jsx index e1a7e14dbbf0c..1af50efba250e 100644 --- a/code-studio/src/js/components/report_abuse_form.jsx +++ b/code-studio/src/js/components/report_abuse_form.jsx @@ -37,7 +37,7 @@ var AgeDropdown = React.createClass({ } return ( - { ages.map(function (age) { return ; }) From 9db37f48b4308375905915d23f59cd36d9eaa18b Mon Sep 17 00:00:00 2001 From: Brad Buchanan Date: Wed, 2 Mar 2016 13:18:07 -0800 Subject: [PATCH 07/11] Don't use renderToStaticMarkup to render course progress. Stop using [renderToStaticMarkup](https://facebook.github.io/react/docs/top-level-api.html#reactdomserver.rendertostaticmarkup) to render course progress because it's not supposed to be used in client code, and has been [moved to ReactDOMServer in React 0.14](https://facebook.github.io/react/blog/2015/10/07/react-v0.14.html#two-packages-react-and-react-dom). Instead, create and prepend a mount point and render into that using regular ReactDOM.render. This may affect an [old TODO from 6343](https://github.com/code-dot-org/code-dot-org/pull/6343#discussion_r49917074). FYI @joshlory. --- dashboard/app/assets/javascripts/progress.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dashboard/app/assets/javascripts/progress.js b/dashboard/app/assets/javascripts/progress.js index e0a986b37171c..bb8c2117ef425 100644 --- a/dashboard/app/assets/javascripts/progress.js +++ b/dashboard/app/assets/javascripts/progress.js @@ -113,9 +113,11 @@ window.dashboard.progress = (function () { }; progress.renderCourseProgress = function (scriptData) { - $('.user-stats-block').prepend(ReactDOM.renderToStaticMarkup(React.createElement(dashboard.CourseProgress, { + var mountPoint = document.createElement('div'); + $('.user-stats-block').prepend(mountPoint); + ReactDOM.render(React.createElement(dashboard.CourseProgress, { stages: scriptData.stages - }))); + }), mountPoint); progress.populateProgress(scriptData.name); }; From 42d03fee4ca4fe6d9a2cc760734159a7344ae7b0 Mon Sep 17 00:00:00 2001 From: Brad Buchanan Date: Wed, 2 Mar 2016 13:39:36 -0800 Subject: [PATCH 08/11] Remove another case of renderToStaticMarkup. Again replacing with creating a mountPoint and using ReactDOM.render() to render inside it. FYI @joshlory --- dashboard/app/assets/javascripts/progress.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dashboard/app/assets/javascripts/progress.js b/dashboard/app/assets/javascripts/progress.js index bb8c2117ef425..87219f90abbd5 100644 --- a/dashboard/app/assets/javascripts/progress.js +++ b/dashboard/app/assets/javascripts/progress.js @@ -106,10 +106,13 @@ window.dashboard.progress = (function () { }; }); - $('.progress_container').replaceWith(ReactDOM.renderToStaticMarkup(React.createElement(dashboard.StageProgress, { + var mountPoint = document.createElement('div'); + mountPoint.style.display = 'inline-block'; + $('.progress_container').replaceWith(mountPoint); + ReactDOM.render(React.createElement(dashboard.StageProgress, { levels: combinedProgress, currentLevelIndex: currentLevelIndex - }))); + }), mountPoint); }; progress.renderCourseProgress = function (scriptData) { From 19f99b0060c3d3c4a9ccae062ae88fb4899d5f3a Mon Sep 17 00:00:00 2001 From: Brad Buchanan Date: Wed, 2 Mar 2016 13:40:50 -0800 Subject: [PATCH 09/11] Fix React warnings around authored hints. Any time React renders an array of components, each component in the array must have a "key" property that helps React manage the components efficiently. I'm doing a sort of clumsy update here to meet this requirement - there may be a cleaner way to restructure these. Also updated the Authored Hints components to follow our new declaration standard, so their names show up nicely in the React dev tools. FYI @Hamms --- apps/src/templates/HintSelect.jsx | 3 ++- apps/src/templates/HintsDisplay.jsx | 9 +++++---- apps/src/templates/Instructions.jsx | 9 +++++---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/apps/src/templates/HintSelect.jsx b/apps/src/templates/HintSelect.jsx index cc314e2630648..9d5f55e9ed28e 100644 --- a/apps/src/templates/HintSelect.jsx +++ b/apps/src/templates/HintSelect.jsx @@ -1,6 +1,6 @@ var msg = require('../locale'); -module.exports = React.createClass({ +var HintSelect = React.createClass({ propTypes: { showInstructions: React.PropTypes.func.isRequired, showHint: React.PropTypes.func.isRequired @@ -15,3 +15,4 @@ module.exports = React.createClass({ ); } }); +module.exports = HintSelect; diff --git a/apps/src/templates/HintsDisplay.jsx b/apps/src/templates/HintsDisplay.jsx index ff6bbb930fe8f..b5e3eb122743e 100644 --- a/apps/src/templates/HintsDisplay.jsx +++ b/apps/src/templates/HintsDisplay.jsx @@ -11,7 +11,7 @@ var Hint = require('./Hint.jsx'); * Closing the instructions and re-opening them will reset this * Component, allowing the button to be pressed once more. */ -module.exports = React.createClass({ +var HintsDisplay = React.createClass({ propTypes: { hintReviewTitle: React.PropTypes.string.isRequired, @@ -71,10 +71,10 @@ module.exports = React.createClass({ var seenHints; if (hintsToShow && hintsToShow.length) { seenHints = [ -

{ this.props.hintReviewTitle }

, -
    +

    { this.props.hintReviewTitle }

    , +
      {hintsToShow.map(function (hint) { - return ; + return ; })}
    ]; @@ -98,3 +98,4 @@ module.exports = React.createClass({ ); } }); +module.exports = HintsDisplay; diff --git a/apps/src/templates/Instructions.jsx b/apps/src/templates/Instructions.jsx index c0559fceb7f9b..33dd81b178a2d 100644 --- a/apps/src/templates/Instructions.jsx +++ b/apps/src/templates/Instructions.jsx @@ -1,4 +1,4 @@ -module.exports = React.createClass({ +var Instructions = React.createClass({ propTypes: { puzzleTitle: React.PropTypes.string, @@ -38,14 +38,14 @@ module.exports = React.createClass({ dangerouslySetInnerHTML={{ __html: this.props.renderedMarkdown }} />); } else { - body = [

    { this.props.puzzleTitle }

    ]; + body = [

    { this.props.puzzleTitle }

    ]; if (this.props.instructions) { - body.push(

    ); + body.push(

    ); } if (this.props.instructions2) { - body.push(

    ); + body.push(

    ); } } @@ -63,3 +63,4 @@ module.exports = React.createClass({ ); } }); +module.exports = Instructions; From 08d0d8e9cf001cf61e66cd8ede6053ea385505f4 Mon Sep 17 00:00:00 2001 From: Brad Buchanan Date: Wed, 2 Mar 2016 13:49:27 -0800 Subject: [PATCH 10/11] Fix contract_match.jsx React warnings. Warning: Failed form propType: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`. Check the render method of `TypeChooser`. Fix: Changed select "value" to "defaultValue". Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of `exports`. See https://fb.me/react-warning-keys for more information. Fix: Add "key" property to

    returned by map function. FYI @bcjordan --- code-studio/src/js/levels/contract_match.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code-studio/src/js/levels/contract_match.jsx b/code-studio/src/js/levels/contract_match.jsx index fc8d266585dc0..24414ecd9c7d7 100644 --- a/code-studio/src/js/levels/contract_match.jsx +++ b/code-studio/src/js/levels/contract_match.jsx @@ -188,7 +188,7 @@ $(window).load(function () { }); var typeChoiceNodes = sortedDomains.map(function (object) { return ( -
    +
    +