Commit 648cdbf3 authored by Susan Rati Lane's avatar Susan Rati Lane Committed by Evan W. Patton

Cycle through warning and error blocks

Change-Id: I7d3f5864bd65c3607a0f7083e8df44aef79c8cb9
parent f5a769a4
......@@ -630,7 +630,7 @@ public class BlocklyPanel extends HTMLPanel {
block.rename(e.oldValue, e.newValue);
}
cb(e);
if (workspace.rendered) {
if (workspace.rendered && !e.isTransient) {
var handler = this.getWarningHandler();
if (handler) {
// [lyn 12/31/2013] Check for duplicate component event handlers before
......
......@@ -413,6 +413,7 @@ Blockly.ai_inject = function(container, workspace) {
// var block = blocks[i];
// block.render(false);
// }
workspace.getWarningHandler().determineDuplicateComponentEventHandlers();
workspace.getWarningHandler().checkAllBlocksForWarningsAndErrors();
// center on blocks
workspace.setScale(1);
......
......@@ -845,20 +845,7 @@ Blockly.Blocks['procedures_callnoreturn'] = {
var def = Blockly.Procedures.getDefinition(name, workspace);
if (def) {
def.select();
var event = new AI.Events.WorkspaceMove(workspace.id);
// Attempt to center the definition block, but preserve a minimum X, Y position so that
// the definition of the block always appears on screen for visually large procedures
var xy = def.getRelativeToSurfaceXY();
var wh = def.getHeightWidth();
var metrics = def.workspace.getMetrics();
var minTop = xy.y - metrics.contentTop;
var minLeft = xy.x - metrics.contentLeft;
var midX = minLeft + (wh.width - metrics.viewWidth) / 2;
var midY = minTop + (wh.height - metrics.viewHeight) / 2;
def.workspace.scrollbar.set(Math.min(minLeft, midX), Math.min(minTop, midY));
event.recordNew();
Blockly.Events.fire(event);
workspace.centerOnBlock(def.id);
workspace.getParentSvg().parentElement.focus();
}
};
......
......@@ -20,6 +20,8 @@ Blockly.WarningHandler = function(workspace) {
this.allBlockWarnings = [{name:'checkBlockAtRoot'},{name:'checkEmptySockets'}];
this.cachedGlobalNames = [];
this.showWarningsToggle = false;
this.warningIdHash = {};
this.errorIdHash = {};
};
Blockly.WarningHandler.prototype.cacheGlobalNames = false;
......@@ -30,6 +32,8 @@ Blockly.WarningHandler.WarningState = {
WARNING: 1,
ERROR: 2
};
Blockly.WarningHandler.prototype.currentWarning = 0;
Blockly.WarningHandler.prototype.currentError = 0;
Blockly.WarningHandler.prototype.updateWarningErrorCount = function() {
//update the error and warning count in the UI
......@@ -40,6 +44,15 @@ Blockly.WarningHandler.prototype.updateWarningErrorCount = function() {
}
};
Blockly.WarningHandler.prototype.updateCurrentWarningAndError = function() {
//update the error and warning count in the UI
var indicator = this.workspace.getWarningIndicator();
if (indicator) {
// indicator is only available after the workspace has been drawn.
indicator.updateCurrentWarningAndError(this.currentWarning, this.currentError)
}
};
//noinspection JSUnusedGlobalSymbols
/**
* Call to toggle the visibility of the warnings on the blocks.
......@@ -107,6 +120,59 @@ Blockly.WarningHandler.prototype.checkAllBlocksForWarningsAndErrors = function()
}
};
Blockly.WarningHandler.prototype.previousWarning = function() {
var k = Object.keys(this.warningIdHash);
if (this.currentWarning < k.length)
this.workspace.getBlockById(k[this.currentWarning]).setHighlighted(false);
if (this.currentWarning > 0) {
this.currentWarning--;
} else this.currentWarning = k.length - 1;
this.workspace.centerOnBlock(k[this.currentWarning]);
this.workspace.getBlockById(k[this.currentWarning]).setHighlighted(true);
this.updateCurrentWarningAndError();
};
Blockly.WarningHandler.prototype.nextWarning = function() {
var k = Object.keys(this.warningIdHash);
if (this.currentWarning < k.length)
this.workspace.getBlockById(k[this.currentWarning]).setHighlighted(false);
if (this.currentWarning < k.length - 1) {
this.currentWarning++;
} else this.currentWarning = 0;
this.workspace.centerOnBlock(k[this.currentWarning]);
this.workspace.getBlockById(k[this.currentWarning]).setHighlighted(true);
this.updateCurrentWarningAndError();
};
Blockly.WarningHandler.prototype.previousError = function() {
var k = Object.keys(this.errorIdHash);
if (this.currentError < k.length)
this.workspace.getBlockById(k[this.currentError]).setHighlighted(false);
if (k.length > 0) {
if (this.currentError > 0) {
this.currentError--;
} else this.currentError = k.length - 1;
this.workspace.centerOnBlock(k[this.currentError]);
this.workspace.getBlockById(k[this.currentError]).setHighlighted(true);
this.updateCurrentWarningAndError();
}
};
Blockly.WarningHandler.prototype.nextError = function() {
var k = Object.keys(this.errorIdHash);
if (this.currentError < k.length)
this.workspace.getBlockById(k[this.currentError]).setHighlighted(false);
if (k.length > 0) {
if (this.currentError < k.length - 1) {
this.currentError++;
} else this.currentError = 0;
this.workspace.centerOnBlock(k[this.currentError]);
this.workspace.getBlockById(k[this.currentError]).setHighlighted(true);
this.updateCurrentWarningAndError();
}
};
//Takes a block as the context (this), puts
//the appropriate error or warning on the block,
//and returns the corresponding warning state
......@@ -114,6 +180,8 @@ Blockly.WarningHandler.prototype.checkErrors = function(block) {
// [lyn, 11/11/2013] Special case: ignore blocks in flyout for purposes of error handling
// Otherwise, blocks in drawer having connected subblocks (see Blockly.Drawer.defaultBlockXMLStrings)
// will increment warning indicator.
block.setHighlighted(false);
this.updateWarningErrorCount();
if (block.isInFlyout) {
return Blockly.WarningHandler.WarningState.NO_ERROR;
}
......@@ -124,11 +192,13 @@ Blockly.WarningHandler.prototype.checkErrors = function(block) {
if(block.hasWarning) {
block.hasWarning = false;
this.warningCount--;
delete this.warningIdHash[block.id];
this.updateWarningErrorCount();
}
if(block.hasError) {
block.hasError = false;
this.errorCount--;
delete this.errorIdHash[block.id];
this.updateWarningErrorCount();
}
return Blockly.WarningHandler.WarningState.NO_ERROR;
......@@ -159,6 +229,7 @@ Blockly.WarningHandler.prototype.checkErrors = function(block) {
if(!block.hasError) {
block.hasError = true;
this.errorCount++;
this.errorIdHash[block.id] = true;
this.updateWarningErrorCount();
}
//If the block has a warning,
......@@ -166,6 +237,7 @@ Blockly.WarningHandler.prototype.checkErrors = function(block) {
if(block.hasWarning) {
block.hasWarning = false;
this.warningCount--;
delete this.warningIdHash[block.id];
this.updateWarningErrorCount();
}
......@@ -182,6 +254,7 @@ Blockly.WarningHandler.prototype.checkErrors = function(block) {
if(block.hasError) {
block.hasError = false;
this.errorCount--;
delete this.errorIdHash[block.id];
this.updateWarningErrorCount();
}
//if there are no errors, check for warnings
......@@ -190,6 +263,7 @@ Blockly.WarningHandler.prototype.checkErrors = function(block) {
if(!block.hasWarning) {
block.hasWarning = true;
this.warningCount++;
this.warningIdHash[block.id] = true;
this.updateWarningErrorCount();
}
return Blockly.WarningHandler.WarningState.WARNING;
......@@ -203,6 +277,7 @@ Blockly.WarningHandler.prototype.checkErrors = function(block) {
if(block.hasWarning) {
block.hasWarning = false;
this.warningCount--;
delete this.warningIdHash[block.id];
this.updateWarningErrorCount();
}
......@@ -496,11 +571,13 @@ Blockly.WarningHandler.prototype.checkDisposedBlock = function(block){
if(block.hasWarning) {
block.hasWarning = false;
this.warningCount--;
delete this.warningIdHash[block.id];
this.updateWarningErrorCount();
}
if(block.hasError) {
block.hasError = false;
this.errorCount--;
delete this.errorIdHash[block.id];
this.updateWarningErrorCount();
}
};
......
......@@ -77,40 +77,40 @@ Blockly.WarningIndicator.prototype.createDom = function() {
this.svgGroup_ = Blockly.utils.createSvgElement('g',
{'id': "indicatorWarning"}, null);
this.warningCount_ = Blockly.utils.createSvgElement('text',
{'fill': "black", 'transform':"translate(20,14)"},
{'fill': "black", 'transform':"translate(20,-1)"},
this.svgGroup_);
this.warningCount_.textContent = "0";
this.iconGroup_ = Blockly.utils.createSvgElement('g',
{'class': 'blocklyIconGroup', 'translate':"transform(0,0)"}, this.svgGroup_);
{'class': 'blocklyIconGroup', 'translate':"transform(0,-15)"}, this.svgGroup_);
var iconShield = Blockly.utils.createSvgElement('path',
{'class': 'blocklyWarningIconShield',
'd': 'M 2,15 Q -1,15 0.5,12 L 6.5,1.7 Q 8,-1 9.5,1.7 L 15.5,12 ' +
'Q 17,15 14,15 z'},
'd': 'M 2,0 Q -1,0 0.5,-3 L 6.5,-13.3 Q 8,-16 9.5,-13.3 L 15.5,-3 ' +
'Q 17,0 14,0 z'},
this.iconGroup_);
this.iconMark_ = Blockly.utils.createSvgElement('text',
{'class': 'blocklyWarningIconMark',
'x': Blockly.Error.ICON_RADIUS,
'y': 2 * Blockly.Error.ICON_RADIUS - 3}, this.iconGroup_);
'y': 2 * Blockly.Error.ICON_RADIUS - 18}, this.iconGroup_);
this.iconMark_.appendChild(document.createTextNode('!'));
this.errorCount_ = Blockly.utils.createSvgElement('text',
{'fill': "black", 'transform':"translate(75,14)"},
{'fill': "black", 'transform':"translate(85,-1)"},
this.svgGroup_);
this.errorCount_.textContent = "0";
this.iconErrorGroup_ = Blockly.utils.createSvgElement('g',
{'class': 'blocklyIconGroup', 'transform':"translate(55,0)"}, this.svgGroup_);
{'class': 'blocklyIconGroup', 'transform':"translate(65,0)"}, this.svgGroup_);
Blockly.utils.createSvgElement('circle',
{'class': 'blocklyErrorIconOutline',
'r': Blockly.Error.ICON_RADIUS,
'cx': Blockly.Error.ICON_RADIUS,
'cy': Blockly.Error.ICON_RADIUS}, this.iconErrorGroup_);
'cy': Blockly.Error.ICON_RADIUS - 15}, this.iconErrorGroup_);
Blockly.utils.createSvgElement('path',
{'class': 'blocklyErrorIconX',
'd': 'M 4,4 12,12 8,8 4,12 12,4'},
'd': 'M 4,-11 12,-3 8,-7 4,-3 12,-11'},
// X fills circle vvv
//'d': 'M 3.1931458,3.1931458 12.756854,12.756854 8,8 3.0931458,12.756854 12.756854,3.0931458'},
this.iconErrorGroup_);
......@@ -124,6 +124,22 @@ Blockly.WarningIndicator.prototype.createDom = function() {
this.warningToggleGroup_);
this.warningToggleText_.textContent = Blockly.Msg.SHOW_WARNINGS;
this.warningNavPrevious_ = Blockly.utils.createSvgElement('path',
{'fill': "#eeeeee", "d": "M 0,7 L 10,17 L 20,7 Z", 'style':"stroke:black;stroke-width:1;cursor:pointer;"},
this.svgGroup_);
this.warningNavNext_ = Blockly.utils.createSvgElement('path',
{'fill': "#eeeeee", "d": "M 10,-31 L 0,-21 L 20,-21 Z", 'style':"stroke:black;stroke-width:1;cursor:pointer;"},
this.svgGroup_);
this.errorNavPrevious_ = Blockly.utils.createSvgElement('path',
{'fill': "#eeeeee", "d": "M 67,7 L 77,17 L 87,7 Z", 'style':"stroke:black;stroke-width:1;cursor:pointer;"},
this.svgGroup_);
this.errorNavNext_ = Blockly.utils.createSvgElement('path',
{'fill': "#eeeeee", "d": "M 87,-21 L 67,-21 L 77,-31 Z", 'style':"stroke:black;stroke-width:1;cursor:pointer;"},
this.svgGroup_);
return this.svgGroup_;
};
......@@ -135,14 +151,26 @@ Blockly.WarningIndicator.prototype.init = function() {
// If the document resizes, reposition the warning indicator.
Blockly.bindEvent_(window, 'resize', this, this.position_);
Blockly.bindEvent_(this.warningToggleGroup_, 'click', this, Blockly.WarningIndicator.prototype.onclickWarningToggle);
Blockly.bindEvent_(this.warningNavPrevious_, 'click', this, Blockly.WarningIndicator.prototype.onclickWarningNavPrevious);
Blockly.bindEvent_(this.warningNavNext_, 'click', this, Blockly.WarningIndicator.prototype.onclickWarningNavNext);
Blockly.bindEvent_(this.errorNavPrevious_, 'click', this, Blockly.WarningIndicator.prototype.onclickErrorNavPrevious);
Blockly.bindEvent_(this.errorNavNext_, 'click', this, Blockly.WarningIndicator.prototype.onclickErrorNavNext);
// We stop propagating the mousedown event so that Blockly doesn't prevent click events in Firefox, which breaks
// the click event handler above.
Blockly.bindEvent_(this.warningToggleGroup_, 'mousedown', this, function(e) { e.stopPropagation() });
Blockly.bindEvent_(this.warningNavPrevious_, 'mousedown', this, function(e) { e.stopPropagation() });
Blockly.bindEvent_(this.warningNavNext_, 'mousedown', this, function(e) { e.stopPropagation() });
Blockly.bindEvent_(this.errorNavPrevious_, 'mousedown', this, function(e) { e.stopPropagation() });
Blockly.bindEvent_(this.errorNavNext_, 'mousedown', this, function(e) { e.stopPropagation() });
// Stopping propagation of the mousedown event breaks touch events on tablets. We register here for touchend on the
// toggle button so that we can simulate a click event.
Blockly.bindEvent_(this.warningToggleGroup_, 'touchend', this, Blockly.WarningIndicator.prototype.onclickWarningToggle);
Blockly.bindEvent_(this.warningNavPrevious_, 'touchend', this, function(e) { e.stopPropagation() });
Blockly.bindEvent_(this.warningNavNext_, 'touchend', this, function(e) { e.stopPropagation() });
Blockly.bindEvent_(this.errorNavPrevious_, 'touchend', this, function(e) { e.stopPropagation() });
Blockly.bindEvent_(this.errorNavNext_, 'touchend', this, function(e) { e.stopPropagation() });
};
/**
......@@ -167,6 +195,10 @@ Blockly.WarningIndicator.prototype.dispose = function() {
this.warningToggle_ = null;
this.warningToggleText_ = null;
this.warningNavPrevious_ = null;
this.warningNavLeftText_ = null;
this.warningNavNext_ = null;
this.warningNavRightText_ = null;
};
......@@ -191,7 +223,6 @@ Blockly.WarningIndicator.prototype.position_ = function() {
'translate(' + this.left_ + ',' + this.top_ + ')');
};
/**
* Update the error and warning count on the indicator.
*
......@@ -201,6 +232,11 @@ Blockly.WarningIndicator.prototype.updateWarningAndErrorCount = function() {
this.warningCount_.textContent = this.workspace_.getWarningHandler().warningCount;
}
Blockly.WarningIndicator.prototype.updateCurrentWarningAndError = function(currentWarning, currentError) {
this.errorCount_.textContent = currentError + "/" + this.workspace_.getWarningHandler().errorCount;
this.warningCount_.textContent = currentWarning + "/" + this.workspace_.getWarningHandler().warningCount;
}
/**
* Change the warning toggle button to have the correct text.
*
......@@ -220,3 +256,18 @@ Blockly.WarningIndicator.prototype.updateWarningToggleText = function() {
Blockly.WarningIndicator.prototype.onclickWarningToggle = function() {
window.parent.BlocklyPanel_callToggleWarning();
}
Blockly.WarningIndicator.prototype.onclickWarningNavPrevious = function() {
this.workspace_.getWarningHandler().previousWarning();
}
Blockly.WarningIndicator.prototype.onclickWarningNavNext = function() {
this.workspace_.getWarningHandler().nextWarning();
}
Blockly.WarningIndicator.prototype.onclickErrorNavPrevious = function() {
this.workspace_.getWarningHandler().previousError();
}
Blockly.WarningIndicator.prototype.onclickErrorNavNext = function() {
this.workspace_.getWarningHandler().nextError();
}
......@@ -1102,8 +1102,69 @@ Blockly.WorkspaceSvg.prototype.requestConnectionDBUpdate = function() {
};
/**
* Refresh the state of the backpack. Called from BlocklyPanel.java
* Scroll the workspace to center on the given block.
* @param {?string} id ID of block center on.
* @public
*/
// TODO: This is code from a later version of Blockly. Remove on next Blockly update.
Blockly.WorkspaceSvg.prototype.centerOnBlock = function(id) {
if (!this.scrollbar) {
console.warn('Tried to scroll a non-scrollable workspace.');
return;
}
var block = this.getBlockById(id);
if (!block) {
return;
}
// XY is in workspace coordinates.
var xy = block.getRelativeToSurfaceXY();
// Height/width is in workspace units.
var heightWidth = block.getHeightWidth();
// Find the enter of the block in workspace units.
var blockCenterY = xy.y + heightWidth.height / 2;
// In RTL the block's position is the top right of the block, not top left.
var multiplier = this.RTL ? -1 : 1;
var blockCenterX = xy.x + (multiplier * heightWidth.width / 2);
// Workspace scale, used to convert from workspace coordinates to pixels.
var scale = this.scale;
// Center in pixels. 0, 0 is at the workspace origin. These numbers may
// be negative.
var pixelX = blockCenterX * scale;
var pixelY = blockCenterY * scale;
var metrics = this.getMetrics();
// Scrolling to here would put the block in the top-left corner of the
// visible workspace.
var scrollToBlockX = pixelX - metrics.contentLeft;
var scrollToBlockY = pixelY - metrics.contentTop;
// viewHeight and viewWidth are in pixels.
var halfViewWidth = metrics.viewWidth / 2;
var halfViewHeight = metrics.viewHeight / 2;
// Put the block in the center of the visible workspace instead.
var scrollToCenterX = scrollToBlockX - halfViewWidth;
var scrollToCenterY = scrollToBlockY - halfViewHeight;
Blockly.hideChaff();
var event = new AI.Events.WorkspaceMove(this.id);
this.scrollbar.set(scrollToCenterX, scrollToCenterY);
event.recordNew();
Blockly.Events.fire(event);
};
/*
* Refresh the state of the backpack. Called from BlocklyPanel.java
*/
Blockly.WorkspaceSvg.prototype.refreshBackpack = function() {
if (this.backpack_) {
this.backpack_.resize();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment