diff --git a/blocks_vertical/procedures.js b/blocks_vertical/procedures.js
index 373e3e42f9..19fe551290 100644
--- a/blocks_vertical/procedures.js
+++ b/blocks_vertical/procedures.js
@@ -97,11 +97,17 @@ Blockly.ScratchBlocks.ProcedureUtils.definitionDomToMutation = function(xmlEleme
this.procCode_ = xmlElement.getAttribute('proccode');
this.warp_ = JSON.parse(xmlElement.getAttribute('warp'));
+ var prevArgIds = this.argumentIds_;
+ var prevDisplayNames = this.displayNames_;
+
this.argumentIds_ = JSON.parse(xmlElement.getAttribute('argumentids'));
this.displayNames_ = JSON.parse(xmlElement.getAttribute('argumentnames'));
this.argumentDefaults_ = JSON.parse(
xmlElement.getAttribute('argumentdefaults'));
this.updateDisplay_();
+ if (this.updateArgumentReporterNames_) {
+ this.updateArgumentReporterNames_(prevArgIds, prevDisplayNames);
+ }
};
// End of serialization and deserialization.
@@ -708,6 +714,62 @@ Blockly.ScratchBlocks.ProcedureUtils.removeArgumentCallback_ = function(
}
};
+/**
+ * Update argument reporter field values after an edit to the prototype mutation
+ * using previous argument ids and names.
+ * Because the argument reporters only store names and not which argument ids they
+ * are linked to, it would not be safe to update all argument reporters on the workspace
+ * since they may be argument reporters with the same name from a different procedure.
+ * Until there is a more explicit way of identifying argument reporter blocks using ids,
+ * be conservative and only update argument reporters that are used in the
+ * stack below the prototype, ie the definition.
+ * @param {!Array} prevArgIds The previous ordering of argument ids.
+ * @param {!Array} prevDisplayNames The previous argument names.
+ * @this Blockly.Block
+ */
+Blockly.ScratchBlocks.ProcedureUtils.updateArgumentReporterNames_ = function(prevArgIds, prevDisplayNames) {
+ var nameChanges = [];
+ var argReporters = [];
+ var definitionBlock = this.getParent();
+ if (!definitionBlock) return;
+
+ // Create a list of argument reporters that are descendants of the definition stack (see above comment)
+ var allBlocks = definitionBlock.getDescendants(false);
+ for (var i = 0; i < allBlocks.length; i++) {
+ var block = allBlocks[i];
+ if ((block.type === 'argument_reporter_string_number' ||
+ block.type === 'argument_reporter_boolean') &&
+ !block.isShadow()) { // Exclude arg reporters in the prototype block, which are shadows.
+ argReporters.push(block);
+ }
+ }
+
+ // Create a list of "name changes", including the new name and blocks matching the old name
+ // Only search over the current set of argument ids, ignore args that have been removed
+ for (var i = 0, id; id = this.argumentIds_[i]; i++) {
+ // Find the previous index of this argument id. Could be -1 if it is newly added.
+ var prevIndex = prevArgIds.indexOf(id);
+ if (prevIndex == -1) continue; // Newly added argument, no corresponding previous argument to update.
+ var prevName = prevDisplayNames[prevIndex];
+ if (prevName != this.displayNames_[i]) {
+ nameChanges.push({
+ newName: this.displayNames_[i],
+ blocks: argReporters.filter(function(block) {
+ return block.getFieldValue('VALUE') == prevName;
+ })
+ });
+ }
+ }
+
+ // Finally update the blocks for each name change.
+ // Do this after creating the lists to avoid cycles of renaming.
+ for (var j = 0, nameChange; nameChange = nameChanges[j]; j++) {
+ for (var k = 0, block; block = nameChange.blocks[k]; k++) {
+ block.setFieldValue(nameChange.newName, 'VALUE');
+ }
+ }
+};
+
Blockly.Blocks['procedures_definition'] = {
/**
* Block for defining a procedure with no return value.
@@ -792,7 +854,8 @@ Blockly.Blocks['procedures_prototype'] = {
addProcedureLabel_: Blockly.ScratchBlocks.ProcedureUtils.addLabelField_,
// Only exists on procedures_prototype.
- createArgumentReporter_: Blockly.ScratchBlocks.ProcedureUtils.createArgumentReporter_
+ createArgumentReporter_: Blockly.ScratchBlocks.ProcedureUtils.createArgumentReporter_,
+ updateArgumentReporterNames_: Blockly.ScratchBlocks.ProcedureUtils.updateArgumentReporterNames_
};
Blockly.Blocks['procedures_declaration'] = {
diff --git a/core/block_transformer.js b/core/block_transformer.js
index 74036e676e..a76e60ab21 100644
--- a/core/block_transformer.js
+++ b/core/block_transformer.js
@@ -22,6 +22,7 @@ Blockly.BlockTransformer.prototype.executeAction = function (action) {
let result = true;
try {
result = this.apply(action);
+ Blockly.Events.fireNow_();
} catch (err) {
throw "failed to apply transformation:" +
JSON.stringify(action)
@@ -40,7 +41,8 @@ Blockly.BlockTransformer.prototype.VarDeclareAction = function (action) {
type: "var_create",
varType: "",
varName: action.name,
- varId: action.id
+ varId: action.id,
+ isLocal: action.target==='_stage_'?false:true
};
let varCreateEvent = new Blockly.Events.VarCreate(null);
@@ -50,10 +52,10 @@ Blockly.BlockTransformer.prototype.VarDeclareAction = function (action) {
return true;
}
-Blockly.BlockTransformer.prototype.VarRename = function (action) {
+Blockly.BlockTransformer.prototype.VarRenameAction = function (action) {
let varRenameJson = {
type: "var_rename",
- varId: action.id,
+ varId: action.var_id,
oldName: action.oldName,
newName: action.newName
};
@@ -80,7 +82,7 @@ Blockly.BlockTransformer.prototype.InsertBlockAction = function (action) {
try {
let targetBlock = this.workspace.getBlockById(action.target_block);
let insertedBlock = this.workspace.getBlockById(action.inserted_block);
- let previousBlock = targetBlock.previousConnection.targetBlock();
+ let previousBlock = targetBlock.previousConnection?targetBlock.previousConnection.targetBlock():null;
let moveEventJsonSpec = null;
@@ -211,5 +213,21 @@ Blockly.BlockTransformer.prototype.ReplaceAction = function (action) {
};
+Blockly.BlockTransformer.prototype.VarDeleteAction = function (action) {
+ let varDeleteJson = {
+ type: "var_delete",
+ varId: action.var_id,
+ // var_name: action.var_name,
+ // target: action.target
+ };
+
+ let varDeleteEvent = new Blockly.Events.VarDelete(null);
+ varDeleteEvent.id = action.var_id;
+ varDeleteEvent.fromJson(varDeleteJson);
+ varDeleteEvent.workspaceId = this.workspace.id;
+ varDeleteEvent.run(true);
+ return true;
+}
+
// Blockly.Workspace.prototype.createVariable
// Blockly.Workspace.prototype.deleteVariableById
\ No newline at end of file
diff --git a/core/css.js b/core/css.js
index a630879938..95e5eaa80c 100644
--- a/core/css.js
+++ b/core/css.js
@@ -1033,7 +1033,7 @@ Blockly.Css.CONTENT = [
'outline: none;',
'padding: 4px 0;',
'position: absolute;',
- 'overflow-y: auto;',
+ 'overflow-y: hidden;',
'overflow-x: hidden;',
'z-index: 20000;', /* Arbitrary, but some apps depend on it... */
'}',
diff --git a/core/gesture.js b/core/gesture.js
index 6fde8771e7..daf1d640e6 100644
--- a/core/gesture.js
+++ b/core/gesture.js
@@ -590,6 +590,7 @@ Blockly.Gesture.prototype.handleUp = function(e) {
this.doBubbleClick_();
} else if (this.isFieldClick_()) {
this.doFieldClick_();
+ this.startWorkspace_.setActiveFieldValue(this.startField_.sourceBlock_); //for contextualized hints
} else if (this.isBlockClick_()) {
this.doBlockClick_();
} else if (this.isWorkspaceClick_()) {
diff --git a/core/inject.js b/core/inject.js
index 01f9d9c700..96ea8de8f3 100644
--- a/core/inject.js
+++ b/core/inject.js
@@ -216,6 +216,80 @@ Blockly.createDom_ = function(container, options) {
// copy ends
+ // another copy
+ var focusBlocksGlowFilter = Blockly.utils.createSvgElement('filter',
+ {'id': 'blocklyFocusBlocksGlowFilter',
+ 'height': '160%',
+ 'width': '180%',
+ y: '-30%',
+ x: '-40%'
+ },
+ defs);
+
+ options.focusBlocksGlowBlur = Blockly.utils.createSvgElement('feGaussianBlur',
+ {'in': 'SourceGraphic',
+ 'stdDeviation': 1.5},
+ focusBlocksGlowFilter);
+ // Set all gaussian blur pixels to 1 opacity before applying flood
+ var componentTransfer2 = Blockly.utils.createSvgElement('feComponentTransfer', {'result': 'outBlur'}, focusBlocksGlowFilter);
+ Blockly.utils.createSvgElement('feFuncA',
+ {'type': 'table',
+ 'tableValues': '0' + goog.string.repeat(' 1', 16)},
+ componentTransfer2);
+ // Color the highlight
+ Blockly.utils.createSvgElement('feFlood',
+ {'flood-color': 'lightgreen',
+ 'flood-opacity': Blockly.Colours.stackGlowOpacity,
+ 'result': 'outColor'},
+ focusBlocksGlowFilter);
+ Blockly.utils.createSvgElement('feComposite',
+ {'in': 'outColor',
+ 'in2': 'outBlur',
+ 'operator': 'in',
+ 'result': 'outGlow'},
+ focusBlocksGlowFilter);
+ Blockly.utils.createSvgElement('feComposite',
+ {'in': 'SourceGraphic', 'in2': 'outGlow', 'operator': 'over'}, focusBlocksGlowFilter);
+ // copy end
+
+ // another copy
+ var focusBlocksStackGlowFilter = Blockly.utils.createSvgElement('filter',
+ {'id': 'focusBlocksStackGlowFilter',
+ 'height': '160%',
+ 'width': '180%',
+ y: '-30%',
+ x: '-40%'
+ },
+ defs);
+
+ options.focusBlocksStackGlowBlur = Blockly.utils.createSvgElement('feGaussianBlur',
+ {'in': 'SourceGraphic',
+ 'stdDeviation': 4},
+ focusBlocksStackGlowFilter);
+ // Set all gaussian blur pixels to 1 opacity before applying flood
+ var componentTransfer2 = Blockly.utils.createSvgElement('feComponentTransfer', {'result': 'outBlur'}, focusBlocksStackGlowFilter);
+ Blockly.utils.createSvgElement('feFuncA',
+ {'type': 'table',
+ 'tableValues': '0' + goog.string.repeat(' 1', 16)},
+ componentTransfer2);
+ // Color the highlight
+ Blockly.utils.createSvgElement('feFlood',
+ {'flood-color': 'lightgreen',
+ 'flood-opacity': Blockly.Colours.stackGlowOpacity,
+ 'result': 'outColor'},
+ focusBlocksStackGlowFilter);
+ Blockly.utils.createSvgElement('feComposite',
+ {'in': 'outColor',
+ 'in2': 'outBlur',
+ 'operator': 'in',
+ 'result': 'outGlow'},
+ focusBlocksStackGlowFilter);
+ Blockly.utils.createSvgElement('feComposite',
+ {'in': 'SourceGraphic', 'in2': 'outGlow', 'operator': 'over'}, focusBlocksStackGlowFilter);
+
+
+ // copy end
+
// Filter for replacement marker
var replacementGlowFilter = Blockly.utils.createSvgElement('filter',
diff --git a/core/utils.js b/core/utils.js
index 8b47816d20..1c28de01db 100644
--- a/core/utils.js
+++ b/core/utils.js
@@ -976,7 +976,7 @@ Blockly.utils.getBoundingPath = function(block1, block2=null){
var substack = block2.inputList[1].connection ? block2.inputList[1].connection.targetConnection.getSourceBlock() : block2.inputList[2].connection.targetConnection.getSourceBlock();
var newTranslate = parseInt(substack.getSvgRoot().getAttribute("transform").replace("translate(","").split(",")[0]);
d = d + " H" + pd2[2] + Blockly.utils.pathBetween(substack, null, newTranslate)
- + " H" + pd2[4];
+ + " H" + pd2[5];
d = d + " H" + pd2[6] + " H" + pd2[7];
} else if(block2Type == "if_else"){
var substack1 = block2.inputList[2].connection.targetConnection.getSourceBlock();
@@ -994,6 +994,77 @@ Blockly.utils.getBoundingPath = function(block1, block2=null){
return d;
};
+
+Blockly.utils.getBoundingPathForControlBlock = function(block){
+ var d = "";
+ var pd1 = block.svgPath_.getAttribute("d").split(" H");
+
+ d = d + pd1[0] + " H" + pd1[1];
+ var blockType = block.type.replace("control_","");
+ d = d + Blockly.utils.pathBetweenForControlBlock(block,null, true);
+ if(["if","repeat","repeat_until","forever"].includes(blockType)){
+ if(["if"].includes(blockType)){
+ d = d + " H" + pd1[5] + " H" + pd1[6];
+ }else if(["forever"].includes(blockType)){
+ d = d + " H" + pd1[6];
+ }else if(["repeat"].includes(blockType)){
+ d = d + " H" + pd1[6] + " H"+ pd1[7];
+ }
+ else{
+ d = d + " H" + pd1[6] + " H" + pd1[7];
+ }
+ } else if(blockType == "if_else"){
+ d = d + " H" + pd1[8] + " H" + pd1[9];
+ } else {
+
+ }
+ return d;
+};
+
+Blockly.utils.pathBetweenForControlBlock = function(block1, translate=0, topMost){
+ var d = "";
+ var block = block1;
+ while (block != null){
+ var pd = block.svgPath_.getAttribute("d").split(" H");
+ pd[2] = pd[2].replace(pd[2].split(" ")[1],parseInt(pd[2].split(" ")[1]) + translate);
+ var blockType = block.type.replace("control_","");
+ if(["repeat","repeat_until","forever"].includes(blockType)){
+ pd[5] = pd[5].replace(pd[5].split(" ")[1],parseInt(pd[5].split(" ")[1]) + translate )
+ var substack = block.inputList[1].connection ? block.inputList[1].connection.targetConnection.getSourceBlock() : block.inputList[2].connection.targetConnection.getSourceBlock();
+ var newTranslate = parseInt(substack.getSvgRoot().getAttribute("transform").replace("translate(","").split(",")[0]) + translate;
+ d = d + " H" + pd[2] + Blockly.utils.pathBetweenForControlBlock(substack, newTranslate, false)
+ + " H" + pd[5];
+ } else if(blockType == "if"){
+ pd[4] = pd[4].replace(pd[4].split(" ")[1],parseInt(pd[4].split(" ")[1]) + translate )
+ var substack = block.inputList[1].connection ? block.inputList[1].connection.targetConnection.getSourceBlock() : block.inputList[2].connection.targetConnection.getSourceBlock();
+ var newTranslate = parseInt(substack.getSvgRoot().getAttribute("transform").replace("translate(","").split(",")[0]) + translate;
+ d = d + " H" + pd[2] + Blockly.utils.pathBetweenForControlBlock(substack, newTranslate, false)
+ + " H" + pd[4];
+ } else if(blockType == "if_else"){
+ pd[5] = pd[5].replace(pd[5].split(" ")[1],parseInt(pd[5].split(" ")[1]) + translate )
+ pd[7] = pd[7].replace(pd[7].split(" ")[1],parseInt(pd[7].split(" ")[1]) + translate )
+ var substack1 = block.inputList[2].connection.targetConnection.getSourceBlock();
+ var substack2 = block.inputList[4].connection.targetConnection.getSourceBlock();
+ var newTranslate1 = parseInt(substack1.getSvgRoot().getAttribute("transform").replace("translate(","").split(",")[0]) + translate;
+ var newTranslate2 = parseInt(substack2.getSvgRoot().getAttribute("transform").replace("translate(","").split(",")[0]) + translate;
+ d = d + " H" + pd[2] + Blockly.utils.pathBetweenForControlBlock(substack1, newTranslate1, false)
+ + " H" + pd[5] + Blockly.utils.pathBetweenForControlBlock(substack2, newTranslate2, false)
+ + " H" + pd[7];
+ } else {
+ d = d + " H" + pd[2];
+ }
+
+ if(!topMost){
+ block = block.getNextBlock();
+ }else{
+ block = null;
+ }
+ }
+
+ return d;
+};
+
+
/**
*Returns path string for nested blocks
*/
diff --git a/core/workspace.js b/core/workspace.js
index bb514653c8..26785c7f44 100644
--- a/core/workspace.js
+++ b/core/workspace.js
@@ -689,6 +689,10 @@ Blockly.Workspace.prototype.showHint = function(){
}
}
+Blockly.Workspace.prototype.setActiveFieldValue = function(shadowBlock){
+ this.workspaceHint.setActiveFieldValue(shadowBlock);
+}
+
// Export symbols that would otherwise be renamed by Closure compiler.
Blockly.Workspace.prototype['clear'] = Blockly.Workspace.prototype.clear;
Blockly.Workspace.prototype['clearUndo'] =
diff --git a/core/workspace_hint.js b/core/workspace_hint.js
index 0923270952..27f432d683 100644
--- a/core/workspace_hint.js
+++ b/core/workspace_hint.js
@@ -9,6 +9,7 @@ goog.require('Blockly.Icon');
Blockly.WorkspaceHint = function (workspace) {
this.workspace_ = workspace;
+ this.activeFieldValue = null;
};
Blockly.WorkspaceHint.prototype.WIDTH_ = 20;
@@ -131,4 +132,9 @@ Blockly.WorkspaceHint.prototype.showContextMenu_ = function (e) {
Blockly.ContextMenu.show(e, menuOptions, this.workspace_.RTL);
+}
+
+Blockly.WorkspaceHint.prototype.setActiveFieldValue = function (shadowBlock) {
+ // set activeField (shadowId) attribute in workspaceHint: shadowBlock.id
+ this.activeFieldValue = shadowBlock;
}
\ No newline at end of file
diff --git a/core/workspace_svg.js b/core/workspace_svg.js
index 39ab1eb5d7..a7784bec3d 100644
--- a/core/workspace_svg.js
+++ b/core/workspace_svg.js
@@ -995,10 +995,29 @@ Blockly.WorkspaceSvg.prototype.glowMessyBlock = function(ids, isMessyGlowingBloc
* @param {?string} start id ID of block to find.
* @param {?string} (optional) end id ID of block to find.
*/
-Blockly.WorkspaceSvg.prototype.drawHighlightBox = function(id, id2=null) {
+Blockly.WorkspaceSvg.prototype.drawHighlightBox = function (id, id2 = null, options) {
+ var svg = null;
var block1 = null, block2 = null;
+
if (id) {
block1 = this.getBlockById(id);
+ if (block1.getFirstStatementConnection()&&!block2) {
+ svg = Blockly.utils.createSvgElement('path',
+ {
+ 'd': Blockly.utils.getBoundingPathForControlBlock(block1),
+ 'class': 'blocklyBlockBackground',
+ 'fill': 'black',
+ 'fill-opacity': '0',
+ 'stroke': options?options.color:'lightgreen',
+ 'stroke-width': options?'7px':'1px'
+ },
+ block1.getSvgRoot());
+ if(!options){
+ svg.setAttribute('filter', 'url(#' + 'blocklyFocusBlocksGlowFilter' + ')');
+ }
+ this.highlightBoxs_.push(svg);
+ return;
+ }
if (!block1) {
throw 'Tried to highlight block that does not exist.';
}
@@ -1009,27 +1028,63 @@ Blockly.WorkspaceSvg.prototype.drawHighlightBox = function(id, id2=null) {
throw 'Tried to highlight block that does not exist.';
}
}
- this.highlightBoxs_.push(Blockly.utils.createSvgElement('path',
- {
- 'd': Blockly.utils.getBoundingPath(block1,block2),
- 'class': 'blocklyPath blocklyBlockBackground',
- 'stroke': 'black',
- 'style': 'stroke-width: 5px',
- 'fill-opacity': '0',
- 'fill': 'black'
- },
- block1.getSvgRoot()));
+
+ svg = Blockly.utils.createSvgElement('path',
+ {
+ 'd': Blockly.utils.getBoundingPath(block1, block2),
+ 'class': 'blocklyBlockBackground',
+ 'fill': 'black',
+ 'fill-opacity': '0',
+ 'stroke': 'lightgreen',
+ 'stroke-width': options?'7px':'1px'
+ },
+ block1.getSvgRoot());
+ if(!options){
+ svg.setAttribute('filter', 'url(#' + 'blocklyFocusBlocksGlowFilter' + ')');
+ }
+
+ this.highlightBoxs_.push(svg);
+
};
+
/**
* Remove all highlighting boxes for given block/blocks in the workspace.
*/
-Blockly.WorkspaceSvg.prototype.removeHighlightBox = function() {
- for ( var i=0; i900036810361610";
+ fromXml();
+ }
+
+ function highlightBlocksSetup(){
+ var input = document.getElementById('importExport');
+ input.value =
+ // "1090101500"
+ //"101010_mouse_1010"
+ // "1010"
+ // "10_mouse_"
+ "15101010"
+ ;
fromXml();
- Blockly.selected = workspace.getBlockById('*`#p/~R4kNb@uT|}iU@u');
- if (Blockly.selected) {
- Blockly.selected.setHintText("abc");
- Blockly.selected.hint.setVisible(true);
- }
-
- }
+// Blockly.selected = workspace.getBlockById('*`#p/~R4kNb@uT|}iU@u');
+// if (Blockly.selected) {
+// Blockly.selected.setHintText("abc");
+// Blockly.selected.hint.setVisible(true);
+// }
+ // workspace.drawHighlightBox('`!ttdW7uQ~+?pJ#xb@n`','1TQo0bqgwh%R+%QOA50o');
+ workspace.drawHighlightBox('Dy;gx(37]2W3a!e[wJQY','|e^K(I@{c_CD)8fhn%+`')
+ // workspace.drawHighlightBox('target',null,{color:'#3C91E6'})
+ }
+
+ function highlighFieldSetup(){
+ var input = document.getElementById('importExport');
+ input.value =
+ "COLOR185"
+ ;
+ fromXml();
+ const shadowId = "qPI5(v*?$FK4-a6xxFY2";
+ var block = workspace.getBlockById("N$(lwZyb{)yHn|!6*sDM");
+ window.block = block;
+
+ // highlight
+ workspace.highlightField('qPI5(v*?$FK4-a6xxFY2');
+ // workspace.unHighlightField('qPI5(v*?$FK4-a6xxFY2');
+
+ }
function setLocale(locale) {
workspace.getFlyout().setRecyclingEnabled(false);
@@ -600,5 +646,6 @@ Vertical Blocks
+