Skip to content

Commit

Permalink
Merge pull request #21163 from code-dot-org/dtp_candidate_5fdd3ce8
Browse files Browse the repository at this point in the history
DTP (Test > Production: 5fdd3ce)
  • Loading branch information
davidsbailey committed Mar 9, 2018
2 parents 28b82a7 + 93e6f5d commit 1a3bcd9
Show file tree
Hide file tree
Showing 154 changed files with 1,997 additions and 455 deletions.
7 changes: 5 additions & 2 deletions apps/i18n/common/en_us.json
Expand Up @@ -82,6 +82,7 @@
"censusCybersecurity": "Cybersecurity",
"censusDataAnalysis": "Data analysis",
"censusEmail": "What is your email address?",
"censusEthicalSocial": "Ethical and social issues in computing",
"censusFollowUpFrequency": "How often per week does this class meet?",
"censusFollowUp": "Your school offers a semester or year long computer science class! What topics does this course include?",
"censusFollowUpTellUsMore": "Please tell us more about this course. For example, name of the class, how often it meets, description of what is taught.",
Expand Down Expand Up @@ -173,6 +174,7 @@
"contractMatchBadName": "Your contract has the wrong name.",
"contractMatchBadNameCase": "Function names are case-sensitive. Try changing the case of your contract's name.",
"contractMatchBadRange": "Your contract has the wrong range.",
"controlProjectSharing": "Control project sharing",
"copy": "Copy",
"copyright": "Copyright",
"correct": "Correct",
Expand Down Expand Up @@ -394,6 +396,7 @@
"dropletBlock_whileBlock_description": "Creates a loop consisting of a conditional expression and a block of statements executed for each iteration of the loop. The loop continues to execute as long as the condition evaluates to true",
"dropletBlock_whileBlock_signatureOverride": "while loop",
"edit": "Edit",
"editAll": "Edit all",
"editSectionDetails": "Edit Section Details",
"editable": "Editable",
"eligibilityExplanation": "In order to be eligible to receive a code for a subsidized Circuit Playground kit, you must meet the following requirements:",
Expand Down Expand Up @@ -425,10 +428,10 @@
"emptyTopLevelBlock": "There are no blocks to run. You must attach a block to the {topLevelBlockName} block.",
"enable": "Enable",
"enableLessonExtras": "Enable Lesson Extras (CS Fundamentals Only)",
"enableMaker": "Enable Maker Toolkit (BETA)",
"enableMaker": "Enable Maker Toolkit",
"enableMakerDialogTitle": "Enable Maker Toolkit?",
"enableMakerDialogWarning": "Warning: Your app will NOT work unless you have an Adafruit Circuit Playground board.",
"enableMakerDialogDescription": "This is a new feature for the Computer Science Discoveries curriculum being piloted this year. See the setup page for more details:",
"enableMakerDialogDescription": "Maker Toolkit is a feature used in the Computer Science Discoveries curriculum. See the setup page for more details:",
"enableMakerDialogSetupPageLinkText": "Maker Toolkit Setup",
"enablePairProgramming": "Enable Pair Programming",
"end": "end",
Expand Down
31 changes: 29 additions & 2 deletions apps/src/block_utils.js
Expand Up @@ -426,6 +426,27 @@ const interpolateInputs = function (blockly, block, inputs) {
};
exports.interpolateInputs = interpolateInputs;

/**
* Add pre-labeled inputs
* @param {Blockly} blockly The Blockly object provided to install()
* @param {Block} block The block to add the inputs to
* @param {Object[]} args The list of inputs
* @param {String} args[].name The name for this input, conventionally all-caps
* @param {String} args[].type The type for this input, defaults to allowing any
* type
* @param {String} args[].label The text to display to the left of the input
*/
const addInputs = function (blockly, block, args) {
block.appendDummyInput()
.appendTitle('show title screen');
args.forEach(arg => {
block.appendValueInput(arg.name)
.setCheck(arg.type || Blockly.BlockValueType.NONE)
.setAlign(Blockly.ALIGN_RIGHT)
.appendTitle(arg.label);
});
};

/**
* Create a block generator that creats blocks that directly map to a javascript
* function call, method call, or other (hopefully simple) expression.
Expand Down Expand Up @@ -475,6 +496,7 @@ exports.createJsWrapperBlockCreator = function (
* block without a previous statement connector.
* @param {boolean} opts.eventLoopBlock Generate an "event loop" block, which
* looks like a loop block but without previous or next statement connectors
* @param {boolean} opts.inline Render inputs inline, defaults to false
*/
return ({
color,
Expand All @@ -488,6 +510,7 @@ exports.createJsWrapperBlockCreator = function (
methodCall,
eventBlock,
eventLoopBlock,
inline,
}) => {
if (!func === !expression) {
throw new Error('Provide either func or expression, but not both');
Expand All @@ -510,9 +533,13 @@ exports.createJsWrapperBlockCreator = function (
});
}

interpolateInputs(blockly, this, determineInputs(blockText, inputs));
if (inline === false) {
addInputs(blockly, this, args);
} else {
interpolateInputs(blockly, this, determineInputs(blockText, inputs));
this.setInputsInline(true);
}

this.setInputsInline(true);
if (returnType) {
this.setOutput(true, returnType);
} else if (eventLoopBlock) {
Expand Down
@@ -1,6 +1,8 @@
import React, {PropTypes} from 'react';
import { connect } from 'react-redux';
import {
Row,
Col,
Button,
SplitButton,
MenuItem,
Expand Down Expand Up @@ -308,7 +310,11 @@ export class DetailViewContents extends React.Component {
} else {
// Render just the select; otherwise, rendering a single element in an
// InputGroup makes it look funky
return selectControl;
return (
<div style={styles.statusSelectGroup}>
{selectControl}
</div>
);
}
};

Expand Down Expand Up @@ -450,8 +456,8 @@ export class DetailViewContents extends React.Component {
<h4>
Notes
</h4>
<div className="row">
<div className="col-md-8">
<Row>
<Col md={8}>
<FormControl
id="Notes"
disabled={!this.state.editing}
Expand All @@ -460,8 +466,8 @@ export class DetailViewContents extends React.Component {
onChange={this.handleNotesChange}
style={styles.notes}
/>
</div>
</div>
</Col>
</Row>
<br />
</div>
);
Expand Down
Expand Up @@ -77,7 +77,7 @@ class AnimationPickerListItem extends React.Component {
const iconImageSrc = this.props.category ? `/blockly/media/gamelab/animation-previews/${this.props.category}.png` : '';

return (
<div style={styles.root} onClick={this.props.onClick}>
<div style={styles.root} onClick={this.props.onClick} className="uitest-animation-picker-item">
<div style={thumbnailStyle}>
{this.props.animationProps &&
<AnimationPreview
Expand Down
17 changes: 17 additions & 0 deletions apps/src/gamelab/GameLabJr.interpreted.js
Expand Up @@ -31,6 +31,7 @@ let sprites = [];
let score = 0;
let game_over = false;
let show_score = false;
let title = '', subTitle = '';

// Behaviors

Expand Down Expand Up @@ -233,6 +234,15 @@ function isDestroyed(sprite) {
return World.allSprites.indexOf(sprite) === -1;
}

function showTitleScreen(titleArg, subTitleArg) {
title = titleArg;
subTitle = subTitleArg;
}

function hideTitleScreen() {
title = subTitle = '';
}

function draw() {
background(World.background_color || "white");

Expand Down Expand Up @@ -303,5 +313,12 @@ function draw() {
textAlign(CENTER);
textSize(50);
text("Game Over", 200, 200);
} else if (title) {
fill("black");
textAlign(CENTER);
textSize(50);
text(title, 200, 150);
textSize(35);
text(subTitle, 200, 250);
}
}
41 changes: 16 additions & 25 deletions apps/src/gamelab/animationListModule.js
Expand Up @@ -321,31 +321,22 @@ export function setInitialAnimationList(serializedAnimationList) {
}

export function addBlankAnimation() {
const key = createUuid();
return (dispatch, getState) => {
// Special behavior here:
// By pushing an animation that is "loadedFromSource" but has a null
// blob and dataURI, Piskel will know to create a new document with
// the given dimensions.
dispatch(addAnimationAction(
key,
{
name: generateAnimationName('animation', getState().animationList.propsByKey),
sourceUrl: null,
frameSize: {x: 100, y: 100},
frameCount: 1,
looping: true,
frameDelay: 4,
version: null,
loadedFromSource: true,
saved: false,
blob: null,
dataURI: null,
hasNewVersionThisSession: false
}));
dispatch(selectAnimation(key));
projectChanged();
};
// To avoid special cases and saving tons of blank animations to our server,
// we're actually adding a secret blank library animation any time the user
// picks "Draw my own." As soon as the user makes any changes to the
// animation it gets saved as a custom animation in their own project, just
// like we do with other library animations.
return addLibraryAnimation(
{
name: 'animation',
sourceUrl: '/api/v1/animation-library/mUlvnlbeZ5GHYr_Lb4NIuMwPs7kGxHWz/category_backgrounds/blank.png',
frameSize: {x: 100, y: 100},
frameCount: 1,
looping: true,
frameDelay: 4,
version: 'mUlvnlbeZ5GHYr_Lb4NIuMwPs7kGxHWz',
}
);
}

/**
Expand Down
18 changes: 18 additions & 0 deletions apps/src/gamelab/blocks.js
Expand Up @@ -245,5 +245,23 @@ export default {
],
methodCall: true,
});

createJsWrapperBlock({
color: WORLD_COLOR,
func: 'showTitleScreen',
blockText: 'show title screen',
args: [
{ name: 'TITLE', label: 'title', type: blockly.BlockValueType.STRING },
{ name: 'SUBTITLE', label: 'text', type: blockly.BlockValueType.STRING }
],
inline: false,
});

createJsWrapperBlock({
color: WORLD_COLOR,
func: 'hideTitleScreen',
blockText: 'hide title screen',
args: [],
});
},
};
28 changes: 13 additions & 15 deletions apps/src/templates/HintDisplayLightbulb.jsx
Expand Up @@ -3,28 +3,26 @@ import Lightbulb from './Lightbulb';

import { connect } from 'react-redux';

const HintDisplayLightbulb = React.createClass({
propTypes: {
class HintDisplayLightbulb extends React.Component {
static propTypes = {
unseenHints: PropTypes.arrayOf(PropTypes.object),
isMinecraft: PropTypes.bool
},

getInitialState() {
return {
shouldAnimate: false
};
},
};

getCount() {
return this.props.unseenHints.length;
},
state = {
shouldAnimate: false
};

componentWillReceiveProps(nextProps) {
const receivingNewHints = nextProps.unseenHints.length > this.getCount();
this.setState({
shouldAnimate: receivingNewHints
});
},
}

getCount() {
return this.props.unseenHints.length;
}

render() {
return (
Expand All @@ -37,8 +35,8 @@ const HintDisplayLightbulb = React.createClass({
/>
</div>
);
},
});
}
}

export default connect(function propsFromStore(state) {
return {
Expand Down
56 changes: 29 additions & 27 deletions apps/src/templates/ReadOnlyBlockSpace.jsx
@@ -1,4 +1,4 @@
import React, {PropTypes} from 'react';
import React, { PropTypes } from 'react';

/**
* Many of our hints include Blockly blocks. Unfortunately, Blockly
Expand All @@ -7,30 +7,22 @@ import React, {PropTypes} from 'react';
* React render method once we're confident that this component is in
* the DOM.
*/
var ReadOnlyBlockSpace = React.createClass({
propTypes: {
export default class ReadOnlyBlockSpace extends React.Component {
static propTypes = {
block: PropTypes.object.isRequired,
},
};

getInitialState: function () {
return {
height: 100,
blockSpace: undefined
};
},

componentDidUpdate: function () {
if (this.state.blockSpace) {
this.state.blockSpace.blockSpaceEditor.svgResize();
}
},
state = {
height: 100,
blockSpace: undefined,
};

componentDidMount: function () {
if (!document.body.contains(this.refs.container)) {
componentDidMount() {
if (!document.body.contains(this.container)) {
return new Error('ReadOnlyBlockSpace component MUST be rendered into a container that already exists in the DOM');
}

let blockSpace = Blockly.BlockSpace.createReadOnlyBlockSpace(this.refs.container, this.props.block, {
let blockSpace = Blockly.BlockSpace.createReadOnlyBlockSpace(this.container, this.props.block, {
noScrolling: true
});

Expand All @@ -43,18 +35,28 @@ var ReadOnlyBlockSpace = React.createClass({
// eslint-disable-next-line react/no-did-mount-set-state
this.setState({
height,
blockSpace
blockSpace,
});
},
}

render: function () {
componentDidUpdate() {
if (this.state.blockSpace) {
this.state.blockSpace.blockSpaceEditor.svgResize();
}
}

render() {
const style = {
maxHeight: this.state.height,
paddingBottom: 10
paddingBottom: 10,
};

return (<div className="block-space" ref="container" style={style}/>);
return (
<div
className="block-space"
ref={(container) => { this.container = container; }}
style={style}
/>
);
}
});

module.exports = ReadOnlyBlockSpace;
}

0 comments on commit 1a3bcd9

Please sign in to comment.