diff --git a/core/field.js b/core/field.js
index 6a8e21f5b..ae622802e 100644
--- a/core/field.js
+++ b/core/field.js
@@ -962,7 +962,7 @@ Blockly.Field.prototype.getClickTarget_ = function() {
*/
Blockly.Field.prototype.getAbsoluteXY_ = function() {
return Blockly.utils.style.getPageOffset(
- /** @type {!SVGRectElement} */ (this.borderRect_));
+ /** @type {!SVGRectElement} */ (this.getClickTarget_()));
};
/**
diff --git a/core/field_textinput.js b/core/field_textinput.js
index 631923a71..28976de79 100644
--- a/core/field_textinput.js
+++ b/core/field_textinput.js
@@ -84,6 +84,13 @@ Blockly.FieldTextInput = function(opt_value, opt_validator, opt_config) {
* @private
*/
this.onKeyInputWrapper_ = null;
+
+ /**
+ * Whether the field should consider the whole parent block to be its click
+ * target.
+ * @type {boolean}
+ */
+ this.fullBlockClickTarget_ = false;
};
Blockly.utils.object.inherits(Blockly.FieldTextInput, Blockly.Field);
@@ -128,6 +135,50 @@ Blockly.FieldTextInput.prototype.configure_ = function(config) {
}
};
+/**
+ * Create the block UI for this field.
+ * @package
+ */
+Blockly.FieldTextInput.prototype.initView = function() {
+ var renderer = this.sourceBlock_.workspace.getRenderer();
+ if (renderer.getConstants().FULL_BLOCK_FIELDS) {
+ // Step one: figure out if this is the only field on this block.
+ // Rendering is quite different in that case.
+ var nFields = 0;
+ var nConnections = 0;
+
+ // Count the number of fields, excluding text fields
+ for (var i = 0, input; (input = this.sourceBlock_.inputList[i]); i++) {
+ for (var j = 0, field; (field = input.fieldRow[j]); j++) {
+ if (!(field instanceof Blockly.FieldLabel)) {
+ nFields ++;
+ }
+ }
+ if (input.connection) {
+ nConnections++;
+ }
+ }
+ // The special case is when this is the only non-label field on the block
+ // and it has an output but no inputs.
+ this.fullBlockClickTarget_ =
+ nFields <= 1 && this.sourceBlock_.outputConnection && !nConnections;
+ } else {
+ this.fullBlockClickTarget_ = false;
+ }
+
+ if (this.fullBlockClickTarget_) {
+ // Don't create a border rect.
+ this.size_.height =
+ Math.max(this.size_.height, Blockly.Field.BORDER_RECT_DEFAULT_HEIGHT);
+ this.size_.width =
+ Math.max(this.size_.width, Blockly.Field.X_PADDING);
+ this.clickTarget_ = this.sourceBlock_.getSvgRoot();
+ } else {
+ this.createBorderRect_();
+ }
+ this.createTextElement_();
+};
+
/**
* Ensure that the input value casts to a valid string.
* @param {*=} opt_newValue The input value.
@@ -297,6 +348,16 @@ Blockly.FieldTextInput.prototype.widgetCreate_ = function() {
htmlInput.value = htmlInput.defaultValue = this.getEditorText_(this.value_);
htmlInput.untypedDefaultValue_ = this.value_;
htmlInput.oldValue_ = null;
+
+ if (this.fullBlockClickTarget_) {
+ var bBox = this.getScaledBBox();
+ var borderRadius = (bBox.bottom - bBox.top) / 2;
+ htmlInput.style.borderRadius = borderRadius + 'px';
+ // Pull stroke colour from the existing shadow block
+ var strokeColour = this.sourceBlock_.style.colourTertiary;
+ div.style.borderColor = strokeColour;
+ }
+
if (Blockly.utils.userAgent.GECKO) {
// In FF, ensure the browser reflows before resizing to avoid issue #2777.
setTimeout(this.resizeEditor_.bind(this), 0);
@@ -544,4 +605,27 @@ Blockly.FieldTextInput.prototype.getValueFromEditorText_ = function(text) {
return text;
};
+/**
+ * @override
+ */
+Blockly.FieldTextInput.prototype.getScaledBBox = function() {
+ if (this.fullBlockClickTarget_) {
+ var heightWidth = this.sourceBlock_.getHeightWidth();
+ } else {
+ var heightWidth = this.borderRect_.getBBox();
+ }
+
+ var scale = this.sourceBlock_.workspace.scale;
+ var xy = this.getAbsoluteXY_();
+ var scaledHeight = heightWidth.height * scale;
+ var scaledWidth = heightWidth.width * scale;
+
+ return {
+ top: xy.y,
+ bottom: xy.y + scaledHeight,
+ left: xy.x,
+ right: xy.x + scaledWidth
+ };
+};
+
Blockly.fieldRegistry.register('field_input', Blockly.FieldTextInput);
diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js
index 6aa0863f6..250ca4e65 100644
--- a/core/renderers/common/constants.js
+++ b/core/renderers/common/constants.js
@@ -163,6 +163,13 @@ Blockly.blockRendering.ConstantProvider = function() {
* @private
*/
this.disabledPattern_ = null;
+
+ /**
+ * Whether text input and colour fields fill up the entire source block.
+ * @type {boolean}
+ * @package
+ */
+ this.FULL_BLOCK_FIELDS = false;
};
/**
diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js
index a75255ff4..43270431f 100644
--- a/core/renderers/zelos/constants.js
+++ b/core/renderers/zelos/constants.js
@@ -105,6 +105,11 @@ Blockly.zelos.ConstantProvider = function() {
* @private
*/
this.highlightGlowFilter_ = null;
+
+ /**
+ * @override
+ */
+ this.FULL_BLOCK_FIELDS = true;
};
Blockly.utils.object.inherits(Blockly.zelos.ConstantProvider,
Blockly.blockRendering.ConstantProvider);
diff --git a/tests/blocks/test_blocks.js b/tests/blocks/test_blocks.js
index bf79c2f9d..f7dc74ddb 100644
--- a/tests/blocks/test_blocks.js
+++ b/tests/blocks/test_blocks.js
@@ -350,6 +350,22 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
"tooltip": "",
"helpUrl": ""
},
+ {
+ "type": "test_fields_only_text_input",
+ "message0": "%1",
+ "args0": [
+ {
+ "type": "field_input",
+ "name": "TEXT_INPUT",
+ "text": "default"
+ }
+ ],
+ "style": "math_blocks",
+ "tooltip": "",
+ "helpUrl": "",
+ "output": "String",
+ "style": "textInput"
+ },
{
"type": "test_fields_multilinetext",
"message0": "code %1",
diff --git a/tests/playground.html b/tests/playground.html
index 742b5858f..425910213 100644
--- a/tests/playground.html
+++ b/tests/playground.html
@@ -1471,6 +1471,7 @@ var spaghettiXml = [
+