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 = [ +