Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Wrapper Step 4: Extract PlaySpaceHeader from ejs #7063

Merged
merged 12 commits into from
Mar 2, 2016
Merged
6 changes: 3 additions & 3 deletions apps/src/StudioApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -1142,14 +1142,14 @@ function resizePinnedBelowVisualizationArea() {
return;
}

var designToggleRow = document.getElementById('designToggleRow');
var playSpaceHeader = document.getElementById('playSpaceHeader');
var visualization = document.getElementById('visualization');
var gameButtons = document.getElementById('gameButtons');
var smallFooter = document.querySelector('#page-small-footer .small-footer-base');

var top = 0;
if (designToggleRow) {
top += $(designToggleRow).outerHeight(true);
if (playSpaceHeader) {
top += $(playSpaceHeader).outerHeight(true);
}

if (visualization) {
Expand Down
82 changes: 82 additions & 0 deletions apps/src/applab/AppLabView.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
'use strict';

var PlaySpaceHeader = require('./PlaySpaceHeader.jsx');
var ProtectedStatefulDiv = require('../templates/ProtectedStatefulDiv.jsx');
var StudioAppWrapper = require('../templates/StudioAppWrapper.jsx');

/**
* Top-level React wrapper for our standard blockly apps.
*/
var AppLabView = React.createClass({
propTypes: {
assetUrl: React.PropTypes.func.isRequired,
isDesignModeHidden: React.PropTypes.bool.isRequired,
isEditingProject: React.PropTypes.bool.isRequired,
isEmbedView: React.PropTypes.bool.isRequired,
isReadOnlyView: React.PropTypes.bool.isRequired,
isShareView: React.PropTypes.bool.isRequired,
isViewDataButtonHidden: React.PropTypes.bool.isRequired,

startInDesignMode: React.PropTypes.bool.isRequired,
activeScreenId: React.PropTypes.string,
screenIds: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,
onDesignModeButton: React.PropTypes.func.isRequired,
onCodeModeButton: React.PropTypes.func.isRequired,
onViewDataButton: React.PropTypes.func.isRequired,
onScreenChange: React.PropTypes.func.isRequired,
onScreenCreate: React.PropTypes.func.isRequired,

renderCodeWorkspace: React.PropTypes.func.isRequired,
renderVisualizationColumn: React.PropTypes.func.isRequired,
onMount: React.PropTypes.func.isRequired
},

componentDidMount: function () {
this.props.onMount();
},

render: function () {
var playSpaceHeader;
if (!this.props.isReadOnlyView) {
playSpaceHeader = <PlaySpaceHeader
hideToggle={this.shouldHideToggle()}
hideViewDataButton={this.shouldHideViewDataButton()}
startInDesignMode={this.props.startInDesignMode}
activeScreenId={this.props.activeScreenId}
screenIds={this.props.screenIds}
onDesignModeButton={this.props.onDesignModeButton}
onCodeModeButton={this.props.onCodeModeButton}
onViewDataButton={this.props.onViewDataButton}
onScreenChange={this.props.onScreenChange}
onScreenCreate={this.props.onScreenCreate} />;
}

return (
<StudioAppWrapper
assetUrl={this.props.assetUrl}
isEmbedView={this.props.isEmbedView}
isShareView={this.props.isShareView}>
<div id="visualizationColumn">
{playSpaceHeader}
<ProtectedStatefulDiv renderContents={this.props.renderVisualizationColumn} />
</div>
<ProtectedStatefulDiv id="visualizationResizeBar" className="fa fa-ellipsis-v" />
<ProtectedStatefulDiv
id="codeWorkspace"
renderContents={this.props.renderCodeWorkspace} />
</StudioAppWrapper>
);
},

shouldHideToggle: function () {
return this.props.isShareView || this.props.isDesignModeHidden;
},

shouldHideViewDataButton: function () {
return this.props.isViewDataButtonHidden ||
this.props.isDesignModeHidden ||
this.props.isShareView ||
!this.props.isEditingProject;
}
});
module.exports = AppLabView;
29 changes: 13 additions & 16 deletions apps/src/applab/PlaySpaceHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var PlaySpaceHeader = React.createClass({
hideToggle: React.PropTypes.bool.isRequired,
hideViewDataButton: React.PropTypes.bool.isRequired,
startInDesignMode: React.PropTypes.bool.isRequired,
initialScreen: React.PropTypes.string.isRequired,
activeScreenId: React.PropTypes.string,
screenIds: React.PropTypes.array.isRequired,
onDesignModeButton: React.PropTypes.func.isRequired,
onCodeModeButton: React.PropTypes.func.isRequired,
Expand All @@ -30,8 +30,7 @@ var PlaySpaceHeader = React.createClass({

getInitialState: function () {
return {
mode: this.props.startInDesignMode ? Mode.DESIGN : Mode.CODE,
activeScreen: null
mode: this.props.startInDesignMode ? Mode.DESIGN : Mode.CODE
};
},

Expand All @@ -58,10 +57,6 @@ var PlaySpaceHeader = React.createClass({
this.props.onScreenChange(screenId);
},

componentWillReceiveProps: function (newProps) {
this.setState({ activeScreen: newProps.initialScreen });
},

render: function () {
var leftSide, rightSide;

Expand All @@ -79,19 +74,21 @@ var PlaySpaceHeader = React.createClass({
} else if (this.state.mode === Mode.DESIGN) {
rightSide = <ScreenSelector
screenIds={this.props.screenIds}
activeScreen={this.state.activeScreen}
activeScreenId={this.props.activeScreenId}
onChange={this.handleScreenChange} />;
}

return (
<table style={{width: '100%'}}>
<tbody>
<tr>
<td style={{width: '120px'}}>{leftSide}</td>
<td style={{maxWidth: 0}}>{rightSide}</td>
</tr>
</tbody>
</table>
<div id="playSpaceHeader">
<table style={{width: '100%'}}>
<tbody>
<tr>
<td style={{width: '120px'}}>{leftSide}</td>
<td style={{maxWidth: 0}}>{rightSide}</td>
</tr>
</tbody>
</table>
</div>
);
}
});
Expand Down
4 changes: 2 additions & 2 deletions apps/src/applab/ScreenSelector.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var elementUtils = require('./designElements/elementUtils');
var ScreenSelector = React.createClass({
propTypes: {
screenIds: React.PropTypes.array.isRequired,
activeScreen: React.PropTypes.string.isRequired,
activeScreenId: React.PropTypes.string,
onChange: React.PropTypes.func.isRequired
},

Expand Down Expand Up @@ -52,7 +52,7 @@ var ScreenSelector = React.createClass({
<select
id="screenSelector"
style={dropdownStyle}
value={this.props.activeScreen}
value={this.props.activeScreenId}
onChange={this.props.onChange}
disabled={Applab.isRunning()}>
{options}
Expand Down
64 changes: 44 additions & 20 deletions apps/src/applab/applab.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var api = require('./api');
var apiBlockly = require('./apiBlockly');
var dontMarshalApi = require('./dontMarshalApi');
var blocks = require('./blocks');
var AppView = require('../templates/AppView.jsx');
var AppLabView = require('./AppLabView.jsx');
var codeWorkspaceEjs = require('../templates/codeWorkspace.html.ejs');
var visualizationColumnEjs = require('../templates/visualizationColumn.html.ejs');
var dom = require('../dom');
Expand Down Expand Up @@ -769,13 +769,7 @@ Applab.init = function(config) {
appWidth: Applab.appWidth,
appHeight: Applab.footerlessAppHeight
}),
controls: firstControlsRow,
extraControlRows: extraControlRows,
pinWorkspaceToBottom: true,
// TODO (brent) - seems a little gross that we've made this part of a
// template shared across all apps
// disable designMode if we're readonly
hasDesignMode: !config.readonlyWorkspace,
controls: firstControlsRow
}
});
}.bind(this);
Expand Down Expand Up @@ -856,7 +850,7 @@ Applab.init = function(config) {

designMode.renderDesignWorkspace();

designMode.configurePlaySpaceHeader();
designMode.loadDefaultScreen();

designMode.toggleDesignMode(Applab.startInDesignMode());

Expand All @@ -867,14 +861,53 @@ Applab.init = function(config) {
}
}.bind(this);

React.render(React.createElement(AppView, {
Applab.reactInitialProps_ = {
assetUrl: studioApp.assetUrl,
isDesignModeHidden: !!config.level.hideDesignMode,
isEmbedView: !!config.embed,
isReadOnlyView: !!config.readonlyWorkspace,
isShareView: !!config.share,
isViewDataButtonHidden: !!config.level.hideViewDataButton,
renderCodeWorkspace: renderCodeWorkspace,
renderVisualizationColumn: renderVisualizationColumn,
onMount: onMount
}), document.getElementById(config.containerId));
};

Applab.reactMountPoint_ = document.getElementById(config.containerId);

Applab.render();
};

/**
* Cache of props, established during init, to use when re-rendering top-level
* view. Eventually, it would be best to replace these with a Redux store.
* @type {Object}
*/
Applab.reactInitialProps_ = {};

/**
* Element on which to mount the top-level React view.
* @type {Element}
* @private
*/
Applab.reactMountPoint_ = null;

/**
* Trigger a top-level React render
*/
Applab.render = function () {
var nextProps = $.extend({}, Applab.reactInitialProps_, {
isEditingProject: window.dashboard && window.dashboard.project.isEditing(),
startInDesignMode: Applab.startInDesignMode(),
activeScreenId: designMode.getCurrentScreenId(),
screenIds: designMode.getAllScreenIds(),
onDesignModeButton: Applab.onDesignModeButton,
onCodeModeButton: Applab.onCodeModeButton,
onViewDataButton: Applab.onViewData,
onScreenChange: designMode.changeScreen,
onScreenCreate: designMode.createScreen
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should all of these on* methods not be in reactInitialProps_ since presumably they wont be changing on rerender? Or is the goal here just to show which things we might be able to move into a redux store?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just put everything that got defined in Applab.init() into reactInitialProps_ - maybe I should have named it reactDefinedOnInitProps_. The rest of these might be defined as "things I can get at anytime." Eventually I'd like both these and the reactInitialProps_ to get absorbed into redux, this just seemed like an appropriate intermediate step.

});
React.render(React.createElement(AppLabView, nextProps), Applab.reactMountPoint_);
};

/**
Expand Down Expand Up @@ -1498,15 +1531,6 @@ Applab.startInDesignMode = function () {
return !!level.designModeAtStart;
};

Applab.hideDesignModeToggle = function () {
return !!level.hideDesignMode || !!studioApp.share;
};

Applab.hideViewDataButton = function () {
var isEditing = window.dashboard && window.dashboard.project.isEditing();
return !!level.hideViewDataButton || !!level.hideDesignMode || !!studioApp.share || !isEditing;
};

Applab.isInDesignMode = function () {
return $('#designWorkspace').is(':visible');
};
Expand Down
41 changes: 6 additions & 35 deletions apps/src/applab/designMode.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// TODO (brent) - make it so that we dont need to specify .jsx. This currently
// works in our grunt build, but not in tests
var DesignWorkspace = require('./DesignWorkspace.jsx');
var PlaySpaceHeader = require('./PlaySpaceHeader.jsx');
var showAssetManager = require('../assetManagement/show');
var assetPrefix = require('../assetManagement/assetPrefix');
var elementLibrary = require('./designElements/library');
Expand Down Expand Up @@ -108,7 +107,7 @@ designMode.editElementProperties = function(element) {
designMode.resetPropertyTab = function() {
var element = currentlyEditedElement || designMode.activeScreen();
designMode.editElementProperties(element);
designMode.renderToggleRow();
Applab.render();
};

/**
Expand Down Expand Up @@ -800,15 +799,6 @@ designMode.configureDragAndDrop = function () {
});
};

designMode.configurePlaySpaceHeader = function () {
var designToggleRow = document.getElementById('designToggleRow');
if (!designToggleRow) {
return;
}

designMode.loadDefaultScreen();
};

/**
* Create a new screen
* @returns {string} The id of the newly created screen
Expand All @@ -827,44 +817,25 @@ designMode.createScreen = function () {
*/
designMode.changeScreen = function (screenId) {
currentScreenId = screenId;
var screenIds = [];
elementUtils.getScreens().each(function () {
screenIds.push(elementUtils.getId(this));
$(this).toggle(elementUtils.getId(this) === screenId);
});

designMode.renderToggleRow(screenIds);
Applab.render();

designMode.editElementProperties(elementUtils.getPrefixedElementById(screenId));
};

/** @returns {string} Id of active/visible screen */
designMode.getCurrentScreenId = function() {
return currentScreenId;
};

designMode.renderToggleRow = function (screenIds) {
screenIds = screenIds || elementUtils.getScreens().get().map(function (screen) {
/** @returns {string[]} Array of all screen Ids in current app */
designMode.getAllScreenIds = function () {
return elementUtils.getScreens().get().map(function (screen) {
return elementUtils.getId(screen);
});

var designToggleRow = document.getElementById('designToggleRow');
if (designToggleRow) {
React.render(
React.createElement(PlaySpaceHeader, {
hideToggle: Applab.hideDesignModeToggle(),
hideViewDataButton: Applab.hideViewDataButton(),
startInDesignMode: Applab.startInDesignMode(),
initialScreen: currentScreenId,
screenIds: screenIds,
onDesignModeButton: Applab.onDesignModeButton,
onCodeModeButton: Applab.onCodeModeButton,
onViewDataButton: Applab.onViewData,
onScreenChange: designMode.changeScreen,
onScreenCreate: designMode.createScreen
}),
designToggleRow
);
}
};

/**
Expand Down
2 changes: 1 addition & 1 deletion apps/src/templates/AppView.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

var ProtectedStatefulDiv = require('./ProtectedStatefulDiv.jsx');
var StudioAppWrapper = require('../templates/StudioAppWrapper.jsx');
var StudioAppWrapper = require('./StudioAppWrapper.jsx');

/**
* Top-level React wrapper for our standard blockly apps.
Expand Down
4 changes: 0 additions & 4 deletions apps/src/templates/visualizationColumn.html.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ var hideRunButton = locals.hideRunButton || false;
</div>
<% }; -%>

<% if (data.hasDesignMode) { %>
<div id="designToggleRow"></div>
<% } %>

<div id="visualization">
<%- data.visualization %>
</div>
Expand Down
Loading