Merge remote-tracking branch 'upstream/develop' into cleanup/mainWorkspaceMetrics

This commit is contained in:
Rachel Fenichel 2016-08-22 15:09:47 -07:00
commit 546504a88a
11 changed files with 136 additions and 87 deletions

View file

@ -46,7 +46,8 @@ blocklyApp.FieldComponent = ng.core
<li [id]="idMap[optionValue]" role="treeitem" *ngFor="#optionValue of getOptions()"
[attr.aria-labelledBy]="generateAriaLabelledByAttr(idMap[optionValue + 'Button'], 'blockly-button')">
<button [id]="idMap[optionValue + 'Button']" (click)="handleDropdownChange(field, optionValue)"
[disabled]="disabled" tabindex="-1">
[disabled]="disabled" tabindex="-1"
[attr.aria-label]="optionText[optionValue] + ' Press Enter to select this value'">
{{optionText[optionValue]}}
</button>
</li>

View file

@ -290,6 +290,8 @@ blocklyApp.TreeService = ng.core
break;
} else if (currentNode.tagName == 'INPUT') {
currentNode.focus();
this.notificationsService.setStatusMessage(
'Type a value, then press Escape to exit');
break;
} else if (currentNode.tagName == 'LI') {
continue;

View file

@ -30,6 +30,7 @@ goog.require('Blockly.Field');
goog.require('Blockly.Msg');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.userAgent');
@ -124,7 +125,8 @@ Blockly.FieldTextInput.prototype.showEditor_ = function(opt_quietInput) {
Blockly.WidgetDiv.show(this, this.sourceBlock_.RTL, this.widgetDispose_());
var div = Blockly.WidgetDiv.DIV;
// Create the input.
var htmlInput = goog.dom.createDom('input', 'blocklyHtmlInput');
var htmlInput =
goog.dom.createDom(goog.dom.TagName.INPUT, 'blocklyHtmlInput');
htmlInput.setAttribute('spellcheck', this.spellcheck_);
var fontSize =
(Blockly.FieldTextInput.FONTSIZE * this.workspace_.scale) + 'pt';

View file

@ -28,6 +28,7 @@ goog.provide('Blockly.Toolbox');
goog.require('Blockly.Flyout');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.BrowserFeature');
goog.require('goog.html.SafeHtml');
@ -147,7 +148,8 @@ Blockly.Toolbox.prototype.init = function() {
var svg = this.workspace_.getParentSvg();
// Create an HTML container for the Toolbox menu.
this.HtmlDiv = goog.dom.createDom('div', 'blocklyToolboxDiv');
this.HtmlDiv =
goog.dom.createDom(goog.dom.TagName.DIV, 'blocklyToolboxDiv');
this.HtmlDiv.setAttribute('dir', workspace.RTL ? 'RTL' : 'LTR');
svg.parentNode.insertBefore(this.HtmlDiv, svg);
@ -186,8 +188,11 @@ Blockly.Toolbox.prototype.init = function() {
tree.setShowLines(false);
tree.setShowExpandIcons(false);
tree.setSelectedItem(null);
this.populate_(workspace.options.languageTree);
var openNode = this.populate_(workspace.options.languageTree);
tree.render(this.HtmlDiv);
if (openNode) {
tree.setSelectedItem(openNode);
}
this.addColour_();
this.position();
};
@ -255,14 +260,16 @@ Blockly.Toolbox.prototype.position = function() {
/**
* Fill the toolbox with categories and blocks.
* @param {Node} newTree DOM tree of blocks, or null.
* @param {!Node} newTree DOM tree of blocks.
* @return {Node} Tree node to open at startup (or null).
* @private
*/
Blockly.Toolbox.prototype.populate_ = function(newTree) {
this.tree_.removeChildren(); // Delete any existing content.
this.tree_.blocks = [];
this.hasColours_ = false;
this.syncTrees_(newTree, this.tree_, this.workspace_.options.pathToMedia);
var openNode =
this.syncTrees_(newTree, this.tree_, this.workspace_.options.pathToMedia);
if (this.tree_.blocks.length) {
throw 'Toolbox cannot have both blocks and categories in the root level.';
@ -270,16 +277,19 @@ Blockly.Toolbox.prototype.populate_ = function(newTree) {
// Fire a resize event since the toolbox may have changed width and height.
this.workspace_.resizeContents();
return openNode;
};
/**
* Sync trees of the toolbox.
* @param {Node} treeIn DOM tree of blocks, or null.
* @param {Blockly.Toolbox.TreeControl} treeOut
* @param {!Node} treeIn DOM tree of blocks.
* @param {!Blockly.Toolbox.TreeControl} treeOut
* @param {string} pathToMedia
* @return {Node} Tree node to open at startup (or null).
* @private
*/
Blockly.Toolbox.prototype.syncTrees_ = function(treeIn, treeOut, pathToMedia) {
var openNode = null;
var lastElement = null;
for (var i = 0, childIn; childIn = treeIn.childNodes[i]; i++) {
if (!childIn.tagName) {
@ -296,7 +306,10 @@ Blockly.Toolbox.prototype.syncTrees_ = function(treeIn, treeOut, pathToMedia) {
// Variables and procedures are special dynamic categories.
childOut.blocks = custom;
} else {
this.syncTrees_(childIn, childOut, pathToMedia);
var newOpenNode = this.syncTrees_(childIn, childOut, pathToMedia);
if (newOpenNode) {
openNode = newOpenNode;
}
}
var colour = childIn.getAttribute('colour');
if (goog.isString(colour)) {
@ -311,7 +324,9 @@ Blockly.Toolbox.prototype.syncTrees_ = function(treeIn, treeOut, pathToMedia) {
}
if (childIn.getAttribute('expanded') == 'true') {
if (childOut.blocks.length) {
this.tree_.setSelectedItem(childOut);
// This is a category that directly contians blocks.
// After the tree is rendered, open this category and show flyout.
openNode = childOut;
}
childOut.setExpanded(true);
} else {
@ -346,6 +361,7 @@ Blockly.Toolbox.prototype.syncTrees_ = function(treeIn, treeOut, pathToMedia) {
break;
}
}
return openNode;
};
/**

View file

@ -32,6 +32,7 @@
goog.provide('Blockly.Tooltip');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
/**
@ -120,7 +121,8 @@ Blockly.Tooltip.createDom = function() {
return; // Already created.
}
// Create an HTML container for popup overlays (e.g. editor widgets).
Blockly.Tooltip.DIV = goog.dom.createDom('div', 'blocklyTooltipDiv');
Blockly.Tooltip.DIV =
goog.dom.createDom(goog.dom.TagName.DIV, 'blocklyTooltipDiv');
document.body.appendChild(Blockly.Tooltip.DIV);
};

View file

@ -30,6 +30,7 @@ goog.provide('Blockly.WidgetDiv');
goog.require('Blockly.Css');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.style');
@ -61,7 +62,8 @@ Blockly.WidgetDiv.createDom = function() {
return; // Already created.
}
// Create an HTML container for popup overlays (e.g. editor widgets).
Blockly.WidgetDiv.DIV = goog.dom.createDom('div', 'blocklyWidgetDiv');
Blockly.WidgetDiv.DIV =
goog.dom.createDom(goog.dom.TagName.DIV, 'blocklyWidgetDiv');
document.body.appendChild(Blockly.WidgetDiv.DIV);
};

View file

@ -304,6 +304,9 @@ AppController.prototype.onTab = function() {
FactoryUtils.hide('workspaceFactoryContent');
} else if (this.selectedTab == 'WORKSPACE_FACTORY') {
// Update block library category.
var categoryXml = this.exporter.getBlockLibCategory();
this.workspaceFactoryController.setBlockLibCategory(categoryXml);
// Hide container of exporter.
FactoryUtils.hide('blockLibraryExporter');
// Show workspace factory container.

View file

@ -15,7 +15,7 @@
<script src="workspacefactory/wfactory_view.js"></script>
<script src="workspacefactory/wfactory_generator.js"></script>
<script src="workspacefactory/wfactory_init.js"></script>
<script src="workspacefactory/standard_categories.js"></script>
<script src="standard_categories.js"></script>
<script src="/storage.js"></script>
<script src="../../../closure-library/closure/goog/base.js"></script>
<script src="factory_utils.js"></script>
@ -487,13 +487,6 @@
</shadow>
</value>
</block>
<block type="math_change">
<value name="DELTA">
<shadow type="math_number">
<field name="NUM">1</field>
</shadow>
</value>
</block>
<block type="math_round">
<value name="NUM">
<shadow type="math_number">
@ -715,7 +708,8 @@
<category name="Variables" colour="330" custom="VARIABLE"></category>
<category name="Functions" colour="290" custom="PROCEDURE"></category>
<sep></sep>
<category name="Block Library" colour="260" id="blockLibCategory"></category>
</xml>
</body>
</html>
</html>

View file

@ -22,16 +22,25 @@
* @fileoverview Contains a map of standard Blockly categories used to load
* standard Blockly categories into the user's toolbox. The map is keyed by
* the lower case name of the category, and contains the Category object for
* that particular category.
* that particular category. Also has a list of core block types provided
* by Blockly.
*
* @author Emma Dauterman (evd2014)
*/
'use strict';
WorkspaceFactoryController.prototype.standardCategories = Object.create(null);
/**
* Namespace for StandardCategories
*/
goog.provide('StandardCategories');
WorkspaceFactoryController.prototype.standardCategories['logic'] =
// Map of standard category information necessary to add a standard category
// to the toolbox.
StandardCategories.categoryMap = Object.create(null);
StandardCategories.categoryMap['logic'] =
new ListElement(ListElement.TYPE_CATEGORY, 'Logic');
WorkspaceFactoryController.prototype.standardCategories['logic'].xml =
StandardCategories.categoryMap['logic'].xml =
Blockly.Xml.textToDom(
'<xml>' +
'<block type="controls_if"></block>' +
@ -42,12 +51,11 @@ WorkspaceFactoryController.prototype.standardCategories['logic'].xml =
'<block type="logic_null"></block>' +
'<block type="logic_ternary"></block>' +
'</xml>');
WorkspaceFactoryController.prototype.standardCategories['logic'].color =
'#5C81A6';
StandardCategories.categoryMap['logic'].color ='#5C81A6';
WorkspaceFactoryController.prototype.standardCategories['loops'] =
StandardCategories.categoryMap['loops'] =
new ListElement(ListElement.TYPE_CATEGORY, 'Loops');
WorkspaceFactoryController.prototype.standardCategories['loops'].xml =
StandardCategories.categoryMap['loops'].xml =
Blockly.Xml.textToDom(
'<xml>' +
'<block type="controls_repeat_ext">' +
@ -78,12 +86,11 @@ WorkspaceFactoryController.prototype.standardCategories['loops'].xml =
'<block type="controls_forEach"></block>' +
'<block type="controls_flow_statements"></block>' +
'</xml>');
WorkspaceFactoryController.prototype.standardCategories['loops'].color =
'#5CA65C';
StandardCategories.categoryMap['loops'].color = '#5CA65C';
WorkspaceFactoryController.prototype.standardCategories['math'] =
StandardCategories.categoryMap['math'] =
new ListElement(ListElement.TYPE_CATEGORY, 'Math');
WorkspaceFactoryController.prototype.standardCategories['math'].xml =
StandardCategories.categoryMap['math'].xml =
Blockly.Xml.textToDom(
'<xml>' +
'<block type="math_number"></block>' +
@ -121,13 +128,6 @@ WorkspaceFactoryController.prototype.standardCategories['math'].xml =
'</shadow>' +
'</value>' +
'</block>' +
'<block type="math_change">' +
'<value name="DELTA">' +
'<shadow type="math_number">' +
'<field name="NUM">1</field>' +
'</shadow>' +
'</value>' +
'</block>' +
'<block type="math_round">' +
'<value name="NUM">' +
'<shadow type="math_number">' +
@ -179,12 +179,11 @@ WorkspaceFactoryController.prototype.standardCategories['math'].xml =
'</block>' +
'<block type="math_random_float"></block>' +
'</xml>');
WorkspaceFactoryController.prototype.standardCategories['math'].color =
'#5C68A6';
StandardCategories.categoryMap['math'].color = '#5C68A6';
WorkspaceFactoryController.prototype.standardCategories['text'] =
StandardCategories.categoryMap['text'] =
new ListElement(ListElement.TYPE_CATEGORY, 'Text');
WorkspaceFactoryController.prototype.standardCategories['text'].xml =
StandardCategories.categoryMap['text'].xml =
Blockly.Xml.textToDom(
'<xml>' +
'<block type="text"></block>' +
@ -263,12 +262,11 @@ WorkspaceFactoryController.prototype.standardCategories['text'].xml =
'</value>' +
'</block>' +
'</xml>');
WorkspaceFactoryController.prototype.standardCategories['text'].color =
'#5CA68D';
StandardCategories.categoryMap['text'].color = '#5CA68D';
WorkspaceFactoryController.prototype.standardCategories['lists'] =
StandardCategories.categoryMap['lists'] =
new ListElement(ListElement.TYPE_CATEGORY, 'Lists');
WorkspaceFactoryController.prototype.standardCategories['lists'].xml =
StandardCategories.categoryMap['lists'].xml =
Blockly.Xml.textToDom(
'<xml>' +
'<block type="lists_create_with">' +
@ -321,12 +319,11 @@ WorkspaceFactoryController.prototype.standardCategories['lists'].xml =
'</block>' +
'<block type="lists_sort"></block>' +
'</xml>');
WorkspaceFactoryController.prototype.standardCategories['lists'].color =
'#745CA6';
StandardCategories.categoryMap['lists'].color = '#745CA6';
WorkspaceFactoryController.prototype.standardCategories['colour'] =
StandardCategories.categoryMap['colour'] =
new ListElement(ListElement.TYPE_CATEGORY, 'Colour');
WorkspaceFactoryController.prototype.standardCategories['colour'].xml =
StandardCategories.categoryMap['colour'].xml =
Blockly.Xml.textToDom(
'<xml>' +
'<block type="colour_picker"></block>' +
@ -366,19 +363,33 @@ WorkspaceFactoryController.prototype.standardCategories['colour'].xml =
'</value>' +
'</block>' +
'</xml>');
WorkspaceFactoryController.prototype.standardCategories['colour'].color =
'#A6745C';
StandardCategories.categoryMap['colour'].color = '#A6745C';
WorkspaceFactoryController.prototype.standardCategories['functions'] =
StandardCategories.categoryMap['functions'] =
new ListElement(ListElement.TYPE_CATEGORY, 'Functions');
WorkspaceFactoryController.prototype.standardCategories['functions'].color =
'#9A5CA6'
WorkspaceFactoryController.prototype.standardCategories['functions'].custom =
'PROCEDURE';
StandardCategories.categoryMap['functions'].color = '#9A5CA6'
StandardCategories.categoryMap['functions'].custom = 'PROCEDURE';
WorkspaceFactoryController.prototype.standardCategories['variables'] =
StandardCategories.categoryMap['variables'] =
new ListElement(ListElement.TYPE_CATEGORY, 'Variables');
WorkspaceFactoryController.prototype.standardCategories['variables'].color =
'#A65C81';
WorkspaceFactoryController.prototype.standardCategories['variables'].custom =
'VARIABLE';
StandardCategories.categoryMap['variables'].color = '#A65C81';
StandardCategories.categoryMap['variables'].custom = 'VARIABLE';
// All standard block types in provided in Blockly core.
StandardCategories.coreBlockTypes = ["controls_if", "logic_compare",
"logic_operation", "logic_negate", "logic_boolean", "logic_null",
"logic_ternary", "controls_repeat_ext", "controls_whileUntil",
"controls_for", "controls_forEach", "controls_flow_statements",
"math_number", "math_arithmetic", "math_single", "math_trig",
"math_constant", "math_number_property", "math_change", "math_round",
"math_on_list", "math_modulo", "math_constrain", "math_random_int",
"math_random_float", "text", "text_join", "text_append", "text_length",
"text_isEmpty", "text_indexOf", "variables_get", "text_charAt",
"text_getSubstring", "text_changeCase", "text_trim", "text_print",
"text_prompt_ext", "colour_picker", "colour_random", "colour_rgb",
"colour_blend", "lists_create_with", "lists_repeat", "lists_length",
"lists_isEmpty", "lists_indexOf", "lists_getIndex", "lists_setIndex",
"lists_getSublist", "lists_split", "lists_sort", "variables_set",
"procedures_defreturn", "procedures_ifreturn", "procedures_defnoreturn",
"procedures_callreturn"];

View file

@ -35,6 +35,7 @@
*/
goog.require('FactoryUtils');
goog.require('StandardCategories');
/**
* Class for a WorkspaceFactoryController
@ -232,7 +233,6 @@ WorkspaceFactoryController.prototype.removeElement = function() {
// when there are no categories.
this.allowToSetDefaultOptions();
}
// Update preview.
this.updatePreview();
};
@ -288,12 +288,6 @@ WorkspaceFactoryController.prototype.clearAndLoadElement = function(id) {
this.view.setCategoryTabSelection(this.model.getSelectedId(), false);
}
// If switching from a separator, enable workspace in view.
if (this.model.getSelectedId() != null && this.model.getSelected().type ==
ListElement.TYPE_SEPARATOR) {
this.view.disableWorkspace(false);
}
// If switching to another category, set category selection in the model and
// view.
if (id != null) {
@ -305,16 +299,19 @@ WorkspaceFactoryController.prototype.clearAndLoadElement = function(id) {
// Selects the next tab.
this.view.setCategoryTabSelection(id, true);
// Mark all shadow blocks laoded and order blocks as if shown in a flyout.
this.view.markShadowBlocks(this.model.getShadowBlocksInWorkspace
(this.toolboxWorkspace.getAllBlocks()));
this.toolboxWorkspace.cleanUp();
// Update category editing buttons.
this.view.updateState(this.model.getIndexByElementId
(this.model.getSelectedId()), this.model.getSelected());
} else {
// Update category editing buttons for no categories.
this.view.updateState(-1, null);
}
// Mark all shadow blocks laoded and order blocks as if shown in a flyout.
this.view.markShadowBlocks(this.model.getShadowBlocksInWorkspace
(this.toolboxWorkspace.getAllBlocks()));
this.toolboxWorkspace.cleanUp();
// Update category editing buttons.
this.view.updateState(this.model.getIndexByElementId
(this.model.getSelectedId()), this.model.getSelected());
};
/**
@ -559,8 +556,7 @@ WorkspaceFactoryController.prototype.changeSelectedCategoryColor =
/**
* Tied to the "Standard Category" dropdown option, this function prompts
* the user for a name of a standard Blockly category (case insensitive) and
* loads it as a new category and switches to it. Leverages standardCategories
* map in standard_categories.js.
* loads it as a new category and switches to it. Leverages StandardCategories.
*/
WorkspaceFactoryController.prototype.loadCategory = function() {
// Prompt user for the name of the standard category to load.
@ -584,7 +580,7 @@ WorkspaceFactoryController.prototype.loadCategory = function() {
return;
}
// Check if the user can create a category with that name.
var standardCategory = this.standardCategories[name.toLowerCase()]
var standardCategory = StandardCategories.categoryMap[name.toLowerCase()]
if (this.model.hasCategoryByName(standardCategory.name)) {
alert('You already have a category with the name ' + standardCategory.name
+ '. Rename your category and try again.');
@ -608,7 +604,7 @@ WorkspaceFactoryController.prototype.loadCategory = function() {
// Switch to loaded category.
this.switchElement(copy.id);
// Convert actual shadow blocks to user-generated shadow blocks.
this.convertShadowBlocks_();
this.convertShadowBlocks();
// Save state from workspace before updating preview.
this.saveStateFromWorkspace();
if (isFirstCategory) {
@ -625,11 +621,11 @@ WorkspaceFactoryController.prototype.loadCategory = function() {
* category (case insensitive).
*
* @param {string} name The name of the category that should be checked if it's
* in standardCategories
* in StandardCategories categoryMap
* @return {boolean} True if name is a standard category name, false otherwise.
*/
WorkspaceFactoryController.prototype.isStandardCategoryName = function(name) {
for (var category in this.standardCategories) {
for (var category in StandardCategories.categoryMap) {
if (name.toLowerCase() == category) {
return true;
}
@ -1177,3 +1173,22 @@ WorkspaceFactoryController.prototype.importBlocks =
reader.readAsText(file);
};
/*
* Updates the block library category in the toolbox workspace toolbox.
*
* @param {!Element} categoryXml XML for the block library category.
*/
WorkspaceFactoryController.prototype.setBlockLibCategory =
function(categoryXml) {
var blockLibCategory = document.getElementById('blockLibCategory');
// Set category id so that it can be easily replaced, and set a standard,
// arbitrary block library color.
categoryXml.setAttribute('id', 'blockLibCategory');
categoryXml.setAttribute('colour', 260);
// Update the toolbox and toolboxWorkspace.
this.toolbox.replaceChild(categoryXml, blockLibCategory);
this.toolboxWorkspace.updateToolbox(this.toolbox);
};

View file

@ -282,7 +282,8 @@ WorkspaceFactoryView.prototype.disableWorkspace = function(disable) {
* @return {boolean} True if the workspace should be disabled, false otherwise.
*/
WorkspaceFactoryView.prototype.shouldDisableWorkspace = function(category) {
return category != null && (category.type == ListElement.TYPE_SEPARATOR ||
return category != null && category.type != ListElement.TYPE_FLYOUT &&
(category.type == ListElement.TYPE_SEPARATOR ||
category.custom == 'VARIABLE' || category.custom == 'PROCEDURE');
};