mirror of
https://github.com/google/blockly.git
synced 2026-01-10 18:37:09 +01:00
@@ -168,7 +168,9 @@ Blockly.BlockDragger.prototype.startBlockDrag = function(currentDragDeltaXY) {
|
||||
this.draggingBlock_.moveToDragSurface_();
|
||||
|
||||
if (this.workspace_.toolbox_) {
|
||||
this.workspace_.toolbox_.addDeleteStyle();
|
||||
var style = this.draggingBlock_.isDeletable() ? 'blocklyToolboxDelete' :
|
||||
'blocklyToolboxGrab';
|
||||
this.workspace_.toolbox_.addStyle(style);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -224,7 +226,9 @@ Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) {
|
||||
this.workspace_.setResizesEnabled(true);
|
||||
|
||||
if (this.workspace_.toolbox_) {
|
||||
this.workspace_.toolbox_.removeDeleteStyle();
|
||||
var style = this.draggingBlock_.isDeletable() ? 'blocklyToolboxDelete' :
|
||||
'blocklyToolboxGrab';
|
||||
this.workspace_.toolbox_.removeStyle(style);
|
||||
}
|
||||
Blockly.Events.setGroup(false);
|
||||
};
|
||||
|
||||
@@ -253,6 +253,12 @@ Blockly.Css.CONTENT = [
|
||||
'cursor: url("<<<PATH>>>/handdelete.cur"), auto;',
|
||||
'}',
|
||||
|
||||
'.blocklyToolboxGrab {',
|
||||
'cursor: url("<<<PATH>>>/handclosed.cur"), auto;',
|
||||
'cursor: grabbing;',
|
||||
'cursor: -webkit-grabbing;',
|
||||
'}',
|
||||
|
||||
'.blocklyDragging>.blocklyPath,',
|
||||
'.blocklyDragging>.blocklyPathLight {',
|
||||
'fill-opacity: .8;',
|
||||
@@ -499,6 +505,9 @@ Blockly.Css.CONTENT = [
|
||||
|
||||
'.blocklyDropdownMenu {',
|
||||
'padding: 0 !important;',
|
||||
/* max-height value is same as the constant
|
||||
* Blockly.FieldDropdown.MAX_MENU_HEIGHT defined in field_dropdown.js. */
|
||||
'max-height: 300px !important;',
|
||||
'}',
|
||||
|
||||
/* Override the default Closure URL. */
|
||||
|
||||
@@ -68,6 +68,12 @@ goog.inherits(Blockly.FieldDropdown, Blockly.Field);
|
||||
*/
|
||||
Blockly.FieldDropdown.CHECKMARK_OVERHANG = 25;
|
||||
|
||||
/**
|
||||
* Maximum height of the dropdown menu,it's also referenced in css.js as
|
||||
* part of .blocklyDropdownMenu.
|
||||
*/
|
||||
Blockly.FieldDropdown.MAX_MENU_HEIGHT = 300;
|
||||
|
||||
/**
|
||||
* Android can't (in 2014) display "▾", so use "▼" instead.
|
||||
*/
|
||||
@@ -239,6 +245,10 @@ Blockly.FieldDropdown.prototype.positionMenu_ = function(menu) {
|
||||
this.createWidget_(menu);
|
||||
var menuSize = Blockly.utils.uiMenu.getSize(menu);
|
||||
|
||||
if (menuSize.height > Blockly.FieldDropdown.MAX_MENU_HEIGHT) {
|
||||
menuSize.height = Blockly.FieldDropdown.MAX_MENU_HEIGHT;
|
||||
}
|
||||
|
||||
if (this.sourceBlock_.RTL) {
|
||||
Blockly.utils.uiMenu.adjustBBoxesForRTL(viewportBBox, anchorBBox, menuSize);
|
||||
}
|
||||
|
||||
@@ -175,6 +175,13 @@ Blockly.FieldImage.prototype.render_ = function() {
|
||||
// NOP
|
||||
};
|
||||
|
||||
/**
|
||||
* Images are fixed width, no need to render even if forced.
|
||||
*/
|
||||
Blockly.FieldImage.prototype.forceRerender = function() {
|
||||
// NOP
|
||||
};
|
||||
|
||||
/**
|
||||
* Images are fixed width, no need to update.
|
||||
* @private
|
||||
|
||||
@@ -596,6 +596,33 @@ Blockly.Flyout.prototype.onMouseDown_ = function(e) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to get the list of variables that have been added to the
|
||||
* workspace after adding a new block, using the given list of variables that
|
||||
* were in the workspace before the new block was added.
|
||||
* @param {!Array.<!Blockly.VariableModel>} originalVariables The array of
|
||||
* variables that existed in the workspace before adding the new block.
|
||||
* @return {!Array.<!Blockly.VariableModel>} The new array of variables that were
|
||||
* freshly added to the workspace after creating the new block, or [] if no
|
||||
* new variables were added to the workspace.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Flyout.prototype.getAddedVariables_ = function(originalVariables) {
|
||||
var allCurrentVariables = this.targetWorkspace_.getAllVariables();
|
||||
var addedVariables = [];
|
||||
if (originalVariables.length != allCurrentVariables.length) {
|
||||
for (var i = 0; i < allCurrentVariables.length; i++) {
|
||||
var variable = allCurrentVariables[i];
|
||||
// For any variable that is present in allCurrentVariables but not
|
||||
// present in originalVariables, add the variable to addedVariables.
|
||||
if (!originalVariables.includes(variable)) {
|
||||
addedVariables.push(variable);
|
||||
}
|
||||
}
|
||||
}
|
||||
return addedVariables;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a copy of this block on the workspace.
|
||||
* @param {!Blockly.BlockSvg} originalBlock The block to copy from the flyout.
|
||||
@@ -606,6 +633,7 @@ Blockly.Flyout.prototype.onMouseDown_ = function(e) {
|
||||
Blockly.Flyout.prototype.createBlock = function(originalBlock) {
|
||||
var newBlock = null;
|
||||
Blockly.Events.disable();
|
||||
var variablesBeforeCreation = this.targetWorkspace_.getAllVariables();
|
||||
this.targetWorkspace_.setResizesEnabled(false);
|
||||
try {
|
||||
newBlock = this.placeNewBlock_(originalBlock);
|
||||
@@ -615,9 +643,16 @@ Blockly.Flyout.prototype.createBlock = function(originalBlock) {
|
||||
Blockly.Events.enable();
|
||||
}
|
||||
|
||||
var newVariables = this.getAddedVariables_(variablesBeforeCreation);
|
||||
|
||||
if (Blockly.Events.isEnabled()) {
|
||||
Blockly.Events.setGroup(true);
|
||||
Blockly.Events.fire(new Blockly.Events.Create(newBlock));
|
||||
// Fire a VarCreate event for each (if any) new variable created.
|
||||
for(var i = 0; i < newVariables.length; i++) {
|
||||
var thisVariable = newVariables[i];
|
||||
Blockly.Events.fire(new Blockly.Events.VarCreate(thisVariable));
|
||||
}
|
||||
}
|
||||
if (this.autoClose) {
|
||||
this.hide();
|
||||
|
||||
@@ -422,21 +422,23 @@ Blockly.Toolbox.prototype.clearSelection = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds styles on the toolbox indicating blocks will be deleted.
|
||||
* Adds a style on the toolbox. Usually used to change the cursor.
|
||||
* @param {string} style The name of the class to add.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Toolbox.prototype.addDeleteStyle = function() {
|
||||
Blockly.Toolbox.prototype.addStyle = function(style) {
|
||||
Blockly.utils.addClass(/** @type {!Element} */ (this.HtmlDiv),
|
||||
'blocklyToolboxDelete');
|
||||
style);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove styles from the toolbox that indicate blocks will be deleted.
|
||||
* Removes a style from the toolbox. Usually used to change the cursor.
|
||||
* @param {string} style The name of the class to remove.
|
||||
* @package
|
||||
*/
|
||||
Blockly.Toolbox.prototype.removeDeleteStyle = function() {
|
||||
Blockly.Toolbox.prototype.removeStyle = function(style) {
|
||||
Blockly.utils.removeClass(/** @type {!Element} */ (this.HtmlDiv),
|
||||
'blocklyToolboxDelete');
|
||||
style);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
127
core/xml.js
127
core/xml.js
@@ -86,6 +86,50 @@ Blockly.Xml.blockToDomWithXY = function(block, opt_noId) {
|
||||
return element;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a field as XML.
|
||||
* @param {!Blockly.Field} field The field to encode.
|
||||
* @param {!Blockly.Workspace} workspace The workspace that the field is in.
|
||||
* @return {?Element} XML element, or null if the field did not need to be
|
||||
* serialized.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Xml.fieldToDom_ = function(field, workspace) {
|
||||
if (field.name && field.EDITABLE) {
|
||||
var container = goog.dom.createDom('field', null, field.getValue());
|
||||
container.setAttribute('name', field.name);
|
||||
if (field instanceof Blockly.FieldVariable) {
|
||||
var variable = workspace.getVariable(field.getValue());
|
||||
if (variable) {
|
||||
container.setAttribute('id', variable.getId());
|
||||
container.setAttribute('variabletype', variable.type);
|
||||
}
|
||||
}
|
||||
return container;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode all of a block's fields as XML and attach them to the given tree of
|
||||
* XML elements.
|
||||
* @param {!Blockly.Block} block A block with fields to be encoded.
|
||||
* @param {!Element} element The XML element to which the field DOM should be
|
||||
* attached.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Xml.allFieldsToDom_ = function(block, element) {
|
||||
var workspace = block.workspace;
|
||||
for (var i = 0, input; input = block.inputList[i]; i++) {
|
||||
for (var j = 0, field; field = input.fieldRow[j]; j++) {
|
||||
var fieldDom = Blockly.Xml.fieldToDom_(field, workspace);
|
||||
if (fieldDom) {
|
||||
element.appendChild(fieldDom);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a block subtree as XML.
|
||||
* @param {!Blockly.Block} block The root block to encode.
|
||||
@@ -105,25 +149,8 @@ Blockly.Xml.blockToDom = function(block, opt_noId) {
|
||||
element.appendChild(mutation);
|
||||
}
|
||||
}
|
||||
function fieldToDom(field) {
|
||||
if (field.name && field.EDITABLE) {
|
||||
var container = goog.dom.createDom('field', null, field.getValue());
|
||||
container.setAttribute('name', field.name);
|
||||
if (field instanceof Blockly.FieldVariable) {
|
||||
var variable = block.workspace.getVariable(field.getValue());
|
||||
if (variable) {
|
||||
container.setAttribute('id', variable.getId());
|
||||
container.setAttribute('variabletype', variable.type);
|
||||
}
|
||||
}
|
||||
element.appendChild(container);
|
||||
}
|
||||
}
|
||||
for (var i = 0, input; input = block.inputList[i]; i++) {
|
||||
for (var j = 0, field; field = input.fieldRow[j]; j++) {
|
||||
fieldToDom(field);
|
||||
}
|
||||
}
|
||||
|
||||
Blockly.Xml.allFieldsToDom_(block, element);
|
||||
|
||||
var commentText = block.getCommentText();
|
||||
if (commentText) {
|
||||
@@ -583,31 +610,7 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) {
|
||||
// Titles were renamed to field in December 2013.
|
||||
// Fall through.
|
||||
case 'field':
|
||||
var field = block.getField(name);
|
||||
var text = xmlChild.textContent;
|
||||
if (field instanceof Blockly.FieldVariable) {
|
||||
// TODO (marisaleung): When we change setValue and getValue to
|
||||
// interact with IDs instead of names, update this so that we get
|
||||
// the variable based on ID instead of textContent.
|
||||
var type = xmlChild.getAttribute('variabletype') || '';
|
||||
var variable = workspace.getVariable(text);
|
||||
if (!variable) {
|
||||
variable = workspace.createVariable(text, type,
|
||||
xmlChild.getAttribute(id));
|
||||
}
|
||||
if (type != null && type !== variable.type) {
|
||||
throw Error('Serialized variable type with id \'' +
|
||||
variable.getId() + '\' had type ' + variable.type + ', and ' +
|
||||
'does not match variable field that references it: ' +
|
||||
Blockly.Xml.domToText(xmlChild) + '.');
|
||||
}
|
||||
}
|
||||
if (!field) {
|
||||
console.warn('Ignoring non-existent field ' + name + ' in block ' +
|
||||
prototypeName);
|
||||
break;
|
||||
}
|
||||
field.setValue(text);
|
||||
Blockly.Xml.domToField_(block, name, xmlChild);
|
||||
break;
|
||||
case 'value':
|
||||
case 'statement':
|
||||
@@ -695,6 +698,42 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) {
|
||||
return block;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode an XML field tag and set the value of that field on the given block.
|
||||
* @param {!Blockly.Block} block The block that is currently being deserialized.
|
||||
* @param {string} fieldName The name of the field on the block.
|
||||
* @param {!Element} xml The field tag to decode.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Xml.domToField_ = function(block, fieldName, xml) {
|
||||
var field = block.getField(fieldName);
|
||||
if (!field) {
|
||||
console.warn('Ignoring non-existent field ' + fieldName + ' in block ' +
|
||||
block.type);
|
||||
return;
|
||||
}
|
||||
|
||||
var text = xml.textContent;
|
||||
if (field instanceof Blockly.FieldVariable) {
|
||||
// TODO (#1199): When we change setValue and getValue to
|
||||
// interact with IDs instead of names, update this so that we get
|
||||
// the variable based on ID instead of textContent.
|
||||
var type = xml.getAttribute('variabletype') || '';
|
||||
var variable = block.workspace.getVariable(text);
|
||||
if (!variable) {
|
||||
variable = block.workspace.createVariable(text, type,
|
||||
xml.getAttribute('id'));
|
||||
}
|
||||
if (type != null && type !== variable.type) {
|
||||
throw Error('Serialized variable type with id \'' +
|
||||
variable.getId() + '\' had type ' + variable.type + ', and ' +
|
||||
'does not match variable field that references it: ' +
|
||||
Blockly.Xml.domToText(xml) + '.');
|
||||
}
|
||||
}
|
||||
field.setValue(text);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove any 'next' block (statements in a stack).
|
||||
* @param {!Element} xmlBlock XML block element.
|
||||
|
||||
Reference in New Issue
Block a user