Merge pull request #736 from google/fraser-develop

Allow images in dropdown menus.
This commit is contained in:
Rachel Fenichel
2016-11-15 13:07:46 -08:00
committed by GitHub
13 changed files with 303 additions and 167 deletions

View File

@@ -631,7 +631,7 @@ Blockly.Block.prototype.getColour = function() {
* @param {number|string} colour HSV hue value, or #RRGGBB string.
*/
Blockly.Block.prototype.setColour = function(colour) {
var hue = parseFloat(colour);
var hue = Number(colour);
if (!isNaN(hue)) {
this.colour_ = Blockly.hueToRgb(hue);
} else if (goog.isString(colour) && colour.match(/^#[0-9a-fA-F]{6}$/)) {

View File

@@ -82,7 +82,8 @@ Blockly.ContextMenu.show = function(e, options, rtl) {
var menuDom = menu.getElement();
Blockly.addClass_(menuDom, 'blocklyContextMenu');
// Prevent system context menu when right-clicking a Blockly context menu.
Blockly.bindEventWithChecks_(menuDom, 'contextmenu', null, Blockly.noEvent);
Blockly.bindEventWithChecks_(menuDom, 'contextmenu', null,
Blockly.utils.noEvent);
// Record menuSize after adding menu.
var menuSize = goog.style.getSize(menuDom);

View File

@@ -45,7 +45,7 @@ goog.require('goog.userAgent');
* @constructor
*/
Blockly.Field = function(text, opt_validator) {
this.size_ = new goog.math.Size(0, 25);
this.size_ = new goog.math.Size(0, Blockly.BlockSvg.MIN_BLOCK_Y);
this.setValue(text);
this.setValidator(opt_validator);
};
@@ -156,7 +156,7 @@ Blockly.Field.prototype.init = function() {
Blockly.bindEventWithChecks_(this.fieldGroup_, 'mouseup', this,
this.onMouseUp_);
// Force a render.
this.updateTextNode_();
this.render_();
};
/**
@@ -285,33 +285,48 @@ Blockly.Field.prototype.getSvgRoot = function() {
* @private
*/
Blockly.Field.prototype.render_ = function() {
if (this.visible_ && this.textElement_) {
var key = this.textElement_.textContent + '\n' +
this.textElement_.className.baseVal;
if (Blockly.Field.cacheWidths_ && Blockly.Field.cacheWidths_[key]) {
var width = Blockly.Field.cacheWidths_[key];
} else {
try {
var width = this.textElement_.getComputedTextLength();
} catch (e) {
// MSIE 11 is known to throw "Unexpected call to method or property
// access." if Blockly is hidden.
var width = this.textElement_.textContent.length * 8;
}
if (Blockly.Field.cacheWidths_) {
Blockly.Field.cacheWidths_[key] = width;
}
}
if (this.borderRect_) {
this.borderRect_.setAttribute('width',
width + Blockly.BlockSvg.SEP_SPACE_X);
}
} else {
var width = 0;
if (!this.visible_) {
this.size_.width = 0;
return;
}
// Replace the text.
goog.dom.removeChildren(/** @type {!Element} */ (this.textElement_));
var textNode = document.createTextNode(this.getDisplayText_());
this.textElement_.appendChild(textNode);
var width = Blockly.Field.getCachedWidth(this.textElement_);
if (this.borderRect_) {
this.borderRect_.setAttribute('width',
width + Blockly.BlockSvg.SEP_SPACE_X);
}
this.size_.width = width;
};
/**
* Gets the width of a text element, caching it in the process.
* @param {!Element} textElement An SVG 'text' element.
* @retur {number} Width of element.
*/
Blockly.Field.getCachedWidth = function(textElement) {
var key = textElement.textContent + '\n' + textElement.className.baseVal;
if (Blockly.Field.cacheWidths_ && Blockly.Field.cacheWidths_[key]) {
var width = Blockly.Field.cacheWidths_[key];
} else {
try {
var width = textElement.getComputedTextLength();
} catch (e) {
// MSIE 11 is known to throw "Unexpected call to method or property
// access." if Blockly is hidden.
var width = textElement.textContent.length * 8;
}
if (Blockly.Field.cacheWidths_) {
Blockly.Field.cacheWidths_[key] = width;
}
}
return width;
};
/**
* Start caching field widths. Every call to this function MUST also call
* stopCache. Caches must not survive between execution threads.
@@ -358,6 +373,31 @@ Blockly.Field.prototype.getScaledBBox_ = function() {
bBox.height * this.sourceBlock_.workspace.scale);
};
/**
* Get the text from this field as displayed on screen. May differ from getText
* due to ellipsis, and other formatting.
* @return {string} Currently displayed text.
* @private
*/
Blockly.Field.prototype.getDisplayText_ = function() {
var text = this.text_;
if (!text) {
// Prevent the field from disappearing if empty.
return Blockly.Field.NBSP;
}
if (text.length > this.maxDisplayLength) {
// Truncate displayed string and add an ellipsis ('...').
text = text.substring(0, this.maxDisplayLength - 2) + '\u2026';
}
// Replace whitespace with non-breaking spaces so the text doesn't collapse.
text = text.replace(/\s/g, Blockly.Field.NBSP);
if (this.sourceBlock_.RTL) {
// The SVG is LTR, force text to be RTL.
text += '\u200F';
}
return text;
};
/**
* Get the text from this field.
* @return {string} Current text.
@@ -381,7 +421,8 @@ Blockly.Field.prototype.setText = function(text) {
return;
}
this.text_ = text;
this.updateTextNode_();
// Set width to 0 to force a rerender of this field.
this.size_.width = 0;
if (this.sourceBlock_ && this.sourceBlock_.rendered) {
this.sourceBlock_.render();
@@ -389,40 +430,6 @@ Blockly.Field.prototype.setText = function(text) {
}
};
/**
* Update the text node of this field to display the current text.
* @private
*/
Blockly.Field.prototype.updateTextNode_ = function() {
if (!this.textElement_) {
// Not rendered yet.
return;
}
var text = this.text_;
if (text.length > this.maxDisplayLength) {
// Truncate displayed string and add an ellipsis ('...').
text = text.substring(0, this.maxDisplayLength - 2) + '\u2026';
}
// Replace whitespace with non-breaking spaces so the text doesn't collapse.
text = text.replace(/\s/g, Blockly.Field.NBSP);
if (this.sourceBlock_.RTL && text) {
// The SVG is LTR, force text to be RTL.
text += '\u200F';
}
if (!text) {
// Prevent the field from disappearing if empty.
text = Blockly.Field.NBSP;
}
// Replace the text.
goog.dom.removeChildren(/** @type {!Element} */ (this.textElement_));
var textNode = document.createTextNode(text);
this.textElement_.appendChild(textNode);
// Cached width is obsolete. Clear it.
this.size_.width = 0;
};
/**
* By default there is no difference between the human-readable text and
* the language-neutral values. Subclasses (such as dropdown) may define this.

View File

@@ -39,8 +39,8 @@ goog.require('goog.userAgent');
/**
* Class for an editable dropdown field.
* @param {(!Array.<!Array.<string>>|!Function)} menuGenerator An array of
* options for a dropdown list, or a function which generates these options.
* @param {(!Array.<!Array>|!Function)} menuGenerator An array of options
* for a dropdown list, or a function which generates these options.
* @param {Function=} opt_validator A function that is executed when a new
* option is selected, with the newly selected value as its sole argument.
* If it returns a value, that value (which must be one of the options) will
@@ -76,12 +76,27 @@ Blockly.FieldDropdown.ARROW_CHAR = goog.userAgent.ANDROID ? '\u25BC' : '\u25BE';
Blockly.FieldDropdown.prototype.CURSOR = 'default';
/**
* Language-neutral currently selected string.
* @type {string}
* Language-neutral currently selected string or image object.
* @type {string|!Object}
* @private
*/
Blockly.FieldDropdown.prototype.value_ = '';
/**
* SVG image element if currently selected option is an image, or null.
* @type {SVGElement}
* @private
*/
Blockly.FieldDropdown.prototype.imageElement_ = null;
/**
* Object wih src, height, width, and alt attributes if currently selected
* option is an image, or null.
* @type {Object}
* @private
*/
Blockly.FieldDropdown.prototype.imageJson_ = null;
/**
* Install this dropdown on a block.
*/
@@ -124,9 +139,16 @@ Blockly.FieldDropdown.prototype.showEditor_ = function() {
menu.setRightToLeft(this.sourceBlock_.RTL);
var options = this.getOptions_();
for (var i = 0; i < options.length; i++) {
var text = options[i][0]; // Human-readable text.
var value = options[i][1]; // Language-neutral value.
var menuItem = new goog.ui.MenuItem(text);
var content = options[i][0]; // Human-readable text or image.
var value = options[i][1]; // Language-neutral value.
if (typeof content == 'object') {
// An image, not text.
var image = new Image(content['width'], content['height']);
image.src = content['src'];
image.alt = content['alt'] || '';
content = image;
}
var menuItem = new goog.ui.MenuItem(content);
menuItem.setRightToLeft(this.sourceBlock_.RTL);
menuItem.setValue(value);
menuItem.setCheckable(true);
@@ -221,7 +243,14 @@ Blockly.FieldDropdown.prototype.trimOptions_ = function() {
if (!goog.isArray(options) || options.length < 2) {
return;
}
var strings = options.map(function(t) {return t[0];});
var strings = [];
for (var i = 0; i < options.length; i++) {
var text = options[i][0];
if (typeof text != 'string') {
return; // No text splitting if there is an image in the list.
}
strings.push(text);
}
var shortest = Blockly.shortestStringLength(strings);
var prefixLength = Blockly.commonWordPrefix(strings, shortest);
var suffixLength = Blockly.commonWordSuffix(strings, shortest);
@@ -251,8 +280,8 @@ Blockly.FieldDropdown.prototype.trimOptions_ = function() {
/**
* Return a list of the options for this dropdown.
* @return {!Array.<!Array.<string>>} Array of option tuples:
* (human-readable text, language-neutral name).
* @return {!Array.<!Array>} Array of option tuples:
* (human-readable text or image, language-neutral name).
* @private
*/
Blockly.FieldDropdown.prototype.getOptions_ = function() {
@@ -288,7 +317,14 @@ Blockly.FieldDropdown.prototype.setValue = function(newValue) {
for (var i = 0; i < options.length; i++) {
// Options are tuples of human-readable text and language-neutral values.
if (options[i][1] == newValue) {
this.setText(options[i][0]);
var content = options[i][0];
if (typeof content == 'object') {
this.imageJson_ = content;
this.setText(content.alt);
} else {
this.imageJson_ = null;
this.setText(content);
}
return;
}
}
@@ -298,34 +334,63 @@ Blockly.FieldDropdown.prototype.setValue = function(newValue) {
};
/**
* Set the text in this field. Trigger a rerender of the source block.
* @param {?string} text New text.
* Draws the border with the correct width.
* @private
*/
Blockly.FieldDropdown.prototype.setText = function(text) {
Blockly.FieldDropdown.prototype.render_ = function() {
if (!this.visible_) {
this.size_.width = 0;
return;
}
if (this.sourceBlock_ && this.arrow_) {
// Update arrow's colour.
this.arrow_.style.fill = this.sourceBlock_.getColour();
}
if (text === null || text === this.text_) {
// No change if null.
return;
}
this.text_ = text;
this.updateTextNode_();
goog.dom.removeChildren(/** @type {!Element} */ (this.textElement_));
goog.dom.removeNode(this.imageElement_);
this.imageElement_ = null;
if (this.textElement_) {
if (this.imageJson_) {
// Image option is selected.
this.imageElement_ = Blockly.createSvgElement('image',
{'y': 5,
'height': this.imageJson_.height + 'px',
'width': this.imageJson_.width + 'px'}, this.fieldGroup_);
this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink',
'xlink:href', this.imageJson_.src);
// Insert dropdown arrow.
this.textElement_.appendChild(this.arrow_);
var arrowWidth = Blockly.Field.getCachedWidth(this.arrow_);
this.size_.height = Number(this.imageJson_.height) + 19;
this.size_.width = Number(this.imageJson_.width) + arrowWidth;
if (this.sourceBlock_.RTL) {
this.imageElement_.setAttribute('x', arrowWidth);
this.textElement_.setAttribute('x', -1);
} else {
this.textElement_.setAttribute('text-anchor', 'end');
this.textElement_.setAttribute('x', this.size_.width + 1);
}
} else {
// Text option is selected.
// Replace the text.
var textNode = document.createTextNode(this.getDisplayText_());
this.textElement_.appendChild(textNode);
// Insert dropdown arrow.
if (this.sourceBlock_.RTL) {
this.textElement_.insertBefore(this.arrow_, this.textElement_.firstChild);
} else {
this.textElement_.appendChild(this.arrow_);
}
}
this.textElement_.setAttribute('text-anchor', 'start');
this.textElement_.setAttribute('x', 0);
if (this.sourceBlock_ && this.sourceBlock_.rendered) {
this.sourceBlock_.render();
this.sourceBlock_.bumpNeighbours_();
this.size_.height = Blockly.BlockSvg.MIN_BLOCK_Y;
this.size_.width = Blockly.Field.getCachedWidth(this.textElement_);
}
this.borderRect_.setAttribute('height', this.size_.height - 9);
this.borderRect_.setAttribute('width',
this.size_.width + Blockly.BlockSvg.SEP_SPACE_X);
};
/**

View File

@@ -74,7 +74,7 @@ Blockly.FieldLabel.prototype.init = function() {
this.textElement_.tooltip = this.sourceBlock_;
Blockly.Tooltip.bindMouseEvents(this.textElement_);
// Force a render.
this.updateTextNode_();
this.render_();
};
/**

View File

@@ -92,7 +92,7 @@ Blockly.hasClass_ = function(element, className) {
/**
* Bind an event to a function call. When calling the function, verifies that
* it belongs to the touch stream that is currently being processsed, and splits
* it belongs to the touch stream that is currently being processed, and splits
* multitouch events into multiple events as needed.
* @param {!Node} node Node upon which to listen.
* @param {string} name Event name to listen to (e.g. 'mousedown').
@@ -219,7 +219,7 @@ Blockly.unbindEvent_ = function(bindData) {
* Don't do anything for this event, just halt propagation.
* @param {!Event} e An event.
*/
Blockly.noEvent = function(e) {
Blockly.utils.noEvent = function(e) {
// This event has been handled. No need to bubble up to the document.
e.preventDefault();
e.stopPropagation();
@@ -561,7 +561,7 @@ Blockly.genUid.soup_ = '!#$%()*+,-./:;=?@[]^_`{|}~' +
Blockly.utils.wrap = function(text, limit) {
var lines = text.split('\n');
for (var i = 0; i < lines.length; i++) {
lines[i] = Blockly.utils.wrap_line_(lines[i], limit);
lines[i] = Blockly.utils.wrapLine_(lines[i], limit);
}
return lines.join('\n');
};
@@ -573,7 +573,7 @@ Blockly.utils.wrap = function(text, limit) {
* @return {string} Wrapped text.
* @private
*/
Blockly.utils.wrap_line_ = function(text, limit) {
Blockly.utils.wrapLine_ = function(text, limit) {
if (text.length <= limit) {
// Short text, no need to wrap.
return text;

View File

@@ -616,18 +616,20 @@ AppController.prototype.onresize = function(event) {
};
/**
* Handler for the window's 'onbeforeunload' event. When a user has unsaved
* Handler for the window's 'beforeunload' event. When a user has unsaved
* changes and refreshes or leaves the page, confirm that they want to do so
* before actually refreshing.
* @param {!Event} e beforeunload event.
*/
AppController.prototype.confirmLeavePage = function() {
AppController.prototype.confirmLeavePage = function(e) {
if ((!BlockFactory.isStarterBlock() &&
!FactoryUtils.savedBlockChanges(this.blockLibraryController)) ||
this.workspaceFactoryController.hasUnsavedChanges()) {
// When a string is assigned to the returnValue Event property, a dialog box
// appears, asking the users for confirmation to leave the page.
return 'You will lose any unsaved changes. Are you sure you want ' +
'to exit this page?';
!FactoryUtils.savedBlockChanges(blocklyFactory.blockLibraryController)) ||
blocklyFactory.workspaceFactoryController.hasUnsavedChanges()) {
var confirmationMessage = 'You will lose any unsaved changes. ' +
'Are you sure you want to exit this page?';
e.returnValue = confirmationMessage;
return confirmationMessage;
}
};

View File

@@ -47,7 +47,7 @@ Blockly.Blocks['factory_base'] = {
['↓ bottom connection', 'BOTTOM']],
function(option) {
this.sourceBlock_.updateShape_(option);
// Connect a shadow block to this new input.
// Connect a shadow block to this new input.
this.sourceBlock_.spawnOutputShadow_(option);
});
this.appendDummyInput()
@@ -318,11 +318,12 @@ Blockly.Blocks['field_dropdown'] = {
this.appendDummyInput()
.appendField('dropdown')
.appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
this.optionCount_ = 3;
this.optionList_ = ['text', 'text', 'text'];
this.updateShape_();
this.setPreviousStatement(true, 'Field');
this.setNextStatement(true, 'Field');
this.setMutator(new Blockly.Mutator(['field_dropdown_option']));
this.setMutator(new Blockly.Mutator(['field_dropdown_option_text',
'field_dropdown_option_image']));
this.setColour(160);
this.setTooltip('Dropdown menu with a list of options.');
this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386');
@@ -330,12 +331,21 @@ Blockly.Blocks['field_dropdown'] = {
mutationToDom: function(workspace) {
// Create XML to represent menu options.
var container = document.createElement('mutation');
container.setAttribute('options', this.optionCount_);
container.setAttribute('options', JSON.stringify(this.optionList_));
return container;
},
domToMutation: function(container) {
// Parse XML to restore the menu options.
this.optionCount_ = parseInt(container.getAttribute('options'), 10);
var value = JSON.parse(container.getAttribute('options'));
if (typeof value == 'number') {
// Old format from before images were added. November 2016.
this.optionList_ = [];
for (var i = 0; i < value; i++) {
this.optionList_.push('text');
}
} else {
this.optionList_ = value;
}
this.updateShape_();
},
decompose: function(workspace) {
@@ -343,8 +353,9 @@ Blockly.Blocks['field_dropdown'] = {
var containerBlock = workspace.newBlock('field_dropdown_container');
containerBlock.initSvg();
var connection = containerBlock.getInput('STACK').connection;
for (var i = 0; i < this.optionCount_; i++) {
var optionBlock = workspace.newBlock('field_dropdown_option');
for (var i = 0; i < this.optionList_.length; i++) {
var optionBlock = workspace.newBlock(
'field_dropdown_option_' + this.optionList_[i]);
optionBlock.initSvg();
connection.connect(optionBlock.previousConnection);
connection = optionBlock.nextConnection;
@@ -355,26 +366,41 @@ Blockly.Blocks['field_dropdown'] = {
// Reconfigure this block based on the mutator dialog's components.
var optionBlock = containerBlock.getInputTargetBlock('STACK');
// Count number of inputs.
this.optionList_.length = 0;
var data = [];
while (optionBlock) {
if (optionBlock.type == 'field_dropdown_option_text') {
this.optionList_.push('text');
} else if (optionBlock.type == 'field_dropdown_option_image') {
this.optionList_.push('image');
}
data.push([optionBlock.userData_, optionBlock.cpuData_]);
optionBlock = optionBlock.nextConnection &&
optionBlock.nextConnection.targetBlock();
}
this.optionCount_ = data.length;
this.updateShape_();
// Restore any data.
for (var i = 0; i < this.optionCount_; i++) {
this.setFieldValue(data[i][0] || 'option', 'USER' + i);
this.setFieldValue(data[i][1] || 'OPTIONNAME', 'CPU' + i);
for (var i = 0; i < this.optionList_.length; i++) {
var userData = data[i][0];
if (userData !== undefined) {
if (typeof userData == 'string') {
this.setFieldValue(userData || 'option', 'USER' + i);
} else {
this.setFieldValue(userData.src, 'SRC' + i);
this.setFieldValue(userData.width, 'WIDTH' + i);
this.setFieldValue(userData.height, 'HEIGHT' + i);
this.setFieldValue(userData.alt, 'ALT' + i);
}
this.setFieldValue(data[i][1] || 'OPTIONNAME', 'CPU' + i);
}
}
},
saveConnections: function(containerBlock) {
// Store names and values for each option.
// Store all data for each option.
var optionBlock = containerBlock.getInputTargetBlock('STACK');
var i = 0;
while (optionBlock) {
optionBlock.userData_ = this.getFieldValue('USER' + i);
optionBlock.userData_ = this.getUserData(i);
optionBlock.cpuData_ = this.getFieldValue('CPU' + i);
i++;
optionBlock = optionBlock.nextConnection &&
@@ -382,28 +408,61 @@ Blockly.Blocks['field_dropdown'] = {
}
},
updateShape_: function() {
// Modify this block to have the correct number of options.
// Add new options.
for (var i = 0; i < this.optionCount_; i++) {
if (!this.getInput('OPTION' + i)) {
// Delete everything.
var i = 0;
while (this.getInput('OPTION' + i)) {
this.removeInput('OPTION' + i);
this.removeInput('OPTION_IMAGE' + i, true);
i++;
}
// Rebuild block.
var src = 'https://www.gstatic.com/codesite/ph/images/star_on.gif';
for (var i = 0; i <= this.optionList_.length; i++) {
var type = this.optionList_[i];
if (type == 'text') {
this.appendDummyInput('OPTION' + i)
.appendField('•')
.appendField(new Blockly.FieldTextInput('option'), 'USER' + i)
.appendField(',')
.appendField(new Blockly.FieldTextInput('OPTIONNAME'), 'CPU' + i);
} else if (type == 'image') {
this.appendDummyInput('OPTION' + i)
.appendField('•')
.appendField('image')
.appendField(new Blockly.FieldTextInput(src), 'SRC' + i);
this.appendDummyInput('OPTION_IMAGE' + i)
.appendField(' ')
.appendField('width')
.appendField(new Blockly.FieldNumber('15', 0, NaN, 1), 'WIDTH' + i)
.appendField('height')
.appendField(new Blockly.FieldNumber('15', 0, NaN, 1), 'HEIGHT' + i)
.appendField('alt text')
.appendField(new Blockly.FieldTextInput('*'), 'ALT' + i)
.appendField(',')
.appendField(new Blockly.FieldTextInput('OPTIONNAME'), 'CPU' + i);
}
}
// Remove deleted options.
while (this.getInput('OPTION' + i)) {
this.removeInput('OPTION' + i);
i++;
}
},
onchange: function() {
if (this.workspace && this.optionCount_ < 1) {
if (this.workspace && this.optionList_.length < 1) {
this.setWarningText('Drop down menu must\nhave at least one option.');
} else {
fieldNameCheck(this);
}
},
getUserData: function(n) {
if (this.optionList_[n] == 'text') {
return this.getFieldValue('USER' + n);
}
if (this.optionList_[n] == 'image') {
return {
src: this.getFieldValue('SRC' + n),
width: Number(this.getFieldValue('WIDTH' + n)),
height: Number(this.getFieldValue('HEIGHT' + n)),
alt: this.getFieldValue('ALT' + n)
};
}
throw 'Unknown dropdown type';
}
};
@@ -421,15 +480,29 @@ Blockly.Blocks['field_dropdown_container'] = {
}
};
Blockly.Blocks['field_dropdown_option'] = {
// Add option.
Blockly.Blocks['field_dropdown_option_text'] = {
// Add text option.
init: function() {
this.setColour(160);
this.appendDummyInput()
.appendField('option');
.appendField('text option');
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setTooltip('Add a new option to the dropdown menu.');
this.setTooltip('Add a new text option to the dropdown menu.');
this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386');
this.contextMenu = false;
}
};
Blockly.Blocks['field_dropdown_option_image'] = {
// Add image option.
init: function() {
this.setColour(160);
this.appendDummyInput()
.appendField('image option');
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setTooltip('Add a new image option to the dropdown menu.');
this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386');
this.contextMenu = false;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -278,7 +278,7 @@ FactoryUtils.formatJavaScript_ = function(blockType, rootBlock, workspace) {
// Dummy inputs don't have names. Other inputs do.
if (contentsBlock.type != 'input_dummy') {
name =
FactoryUtils.escapeString(contentsBlock.getFieldValue('INPUTNAME'));
JSON.stringify(contentsBlock.getFieldValue('INPUTNAME'));
}
code.push(' this.' + TYPES[contentsBlock.type] + '(' + name + ')');
var check = FactoryUtils.getOptTypesFrom(contentsBlock, 'TYPE');
@@ -373,13 +373,13 @@ FactoryUtils.getFieldsJs_ = function(block) {
switch (block.type) {
case 'field_static':
// Result: 'hello'
fields.push(FactoryUtils.escapeString(block.getFieldValue('TEXT')));
fields.push(JSON.stringify(block.getFieldValue('TEXT')));
break;
case 'field_input':
// Result: new Blockly.FieldTextInput('Hello'), 'GREET'
fields.push('new Blockly.FieldTextInput(' +
FactoryUtils.escapeString(block.getFieldValue('TEXT')) + '), ' +
FactoryUtils.escapeString(block.getFieldValue('FIELDNAME')));
JSON.stringify(block.getFieldValue('TEXT')) + '), ' +
JSON.stringify(block.getFieldValue('FIELDNAME')));
break;
case 'field_number':
// Result: new Blockly.FieldNumber(10, 0, 100, 1), 'NUMBER'
@@ -400,63 +400,61 @@ FactoryUtils.getFieldsJs_ = function(block) {
}
}
fields.push('new Blockly.FieldNumber(' + args.join(', ') + '), ' +
FactoryUtils.escapeString(block.getFieldValue('FIELDNAME')));
JSON.stringify(block.getFieldValue('FIELDNAME')));
break;
case 'field_angle':
// Result: new Blockly.FieldAngle(90), 'ANGLE'
fields.push('new Blockly.FieldAngle(' +
parseFloat(block.getFieldValue('ANGLE')) + '), ' +
FactoryUtils.escapeString(block.getFieldValue('FIELDNAME')));
JSON.stringify(block.getFieldValue('FIELDNAME')));
break;
case 'field_checkbox':
// Result: new Blockly.FieldCheckbox('TRUE'), 'CHECK'
fields.push('new Blockly.FieldCheckbox(' +
FactoryUtils.escapeString(block.getFieldValue('CHECKED')) +
JSON.stringify(block.getFieldValue('CHECKED')) +
'), ' +
FactoryUtils.escapeString(block.getFieldValue('FIELDNAME')));
JSON.stringify(block.getFieldValue('FIELDNAME')));
break;
case 'field_colour':
// Result: new Blockly.FieldColour('#ff0000'), 'COLOUR'
fields.push('new Blockly.FieldColour(' +
FactoryUtils.escapeString(block.getFieldValue('COLOUR')) +
JSON.stringify(block.getFieldValue('COLOUR')) +
'), ' +
FactoryUtils.escapeString(block.getFieldValue('FIELDNAME')));
JSON.stringify(block.getFieldValue('FIELDNAME')));
break;
case 'field_date':
// Result: new Blockly.FieldDate('2015-02-04'), 'DATE'
fields.push('new Blockly.FieldDate(' +
FactoryUtils.escapeString(block.getFieldValue('DATE')) + '), ' +
FactoryUtils.escapeString(block.getFieldValue('FIELDNAME')));
JSON.stringify(block.getFieldValue('DATE')) + '), ' +
JSON.stringify(block.getFieldValue('FIELDNAME')));
break;
case 'field_variable':
// Result: new Blockly.FieldVariable('item'), 'VAR'
var varname
= FactoryUtils.escapeString(block.getFieldValue('TEXT') || null);
= JSON.stringify(block.getFieldValue('TEXT') || null);
fields.push('new Blockly.FieldVariable(' + varname + '), ' +
FactoryUtils.escapeString(block.getFieldValue('FIELDNAME')));
JSON.stringify(block.getFieldValue('FIELDNAME')));
break;
case 'field_dropdown':
// Result:
// new Blockly.FieldDropdown([['yes', '1'], ['no', '0']]), 'TOGGLE'
var options = [];
for (var i = 0; i < block.optionCount_; i++) {
options[i] = '[' +
FactoryUtils.escapeString(block.getFieldValue('USER' + i)) +
', ' +
FactoryUtils.escapeString(block.getFieldValue('CPU' + i)) + ']';
for (var i = 0; i < block.optionList_.length; i++) {
options[i] = JSON.stringify([block.getUserData(i),
block.getFieldValue('CPU' + i)]);
}
if (options.length) {
fields.push('new Blockly.FieldDropdown([' +
options.join(', ') + ']), ' +
FactoryUtils.escapeString(block.getFieldValue('FIELDNAME')));
JSON.stringify(block.getFieldValue('FIELDNAME')));
}
break;
case 'field_image':
// Result: new Blockly.FieldImage('http://...', 80, 60)
var src = FactoryUtils.escapeString(block.getFieldValue('SRC'));
// Result: new Blockly.FieldImage('http://...', 80, 60, '*')
var src = JSON.stringify(block.getFieldValue('SRC'));
var width = Number(block.getFieldValue('WIDTH'));
var height = Number(block.getFieldValue('HEIGHT'));
var alt = FactoryUtils.escapeString(block.getFieldValue('ALT'));
var alt = JSON.stringify(block.getFieldValue('ALT'));
fields.push('new Blockly.FieldImage(' +
src + ', ' + width + ', ' + height + ', ' + alt + ')');
break;
@@ -546,8 +544,8 @@ FactoryUtils.getFieldsJson_ = function(block) {
break;
case 'field_dropdown':
var options = [];
for (var i = 0; i < block.optionCount_; i++) {
options[i] = [block.getFieldValue('USER' + i),
for (var i = 0; i < block.optionList_.length; i++) {
options[i] = [block.getUserData(i),
block.getFieldValue('CPU' + i)];
}
if (options.length) {
@@ -608,7 +606,7 @@ FactoryUtils.getTypesFrom_ = function(block, name) {
if (!typeBlock || typeBlock.disabled) {
types = [];
} else if (typeBlock.type == 'type_other') {
types = [FactoryUtils.escapeString(typeBlock.getFieldValue('TYPE'))];
types = [JSON.stringify(typeBlock.getFieldValue('TYPE'))];
} else if (typeBlock.type == 'type_group') {
types = [];
for (var n = 0; n < typeBlock.typeCount_; n++) {
@@ -623,20 +621,11 @@ FactoryUtils.getTypesFrom_ = function(block, name) {
hash[types[n]] = true;
}
} else {
types = [FactoryUtils.escapeString(typeBlock.valueType)];
types = [JSON.stringify(typeBlock.valueType)];
}
return types;
};
/**
* Escape a string.
* @param {string} string String to escape.
* @return {string} Escaped string surrouned by quotes.
*/
FactoryUtils.escapeString = function(string) {
return JSON.stringify(string);
};
/**
* Return the uneditable container block that everything else attaches to in
* given workspace.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,5 +1,3 @@
<!-- TODO(quachtina96): move the CSS out to a separate file -->
<!DOCTYPE html>
<html>
<head>
@@ -37,11 +35,12 @@
var init = function() {
blocklyFactory = new AppController();
blocklyFactory.init();
window.addEventListener('beforeunload', blocklyFactory.confirmLeavePage);
};
window.addEventListener('load', init);
</script>
</head>
<body onbeforeunload="return blocklyFactory.confirmLeavePage()">
<body>
<h1><a href="https://developers.google.com/blockly/">Blockly</a> &gt;
<a href="../index.html">Demos</a> &gt; Blockly Developer Tools
<button id="helpButton" title="View documentation in new window.">

View File

@@ -199,7 +199,7 @@
<tr>
<td>
<a href="blockfactory/index.html">
<img src="blockfactory/devtools.png" height=96 width=184>
<img src="blockfactory/icon.png" height=80 width=173>
</a>
</td>
<td>