diff --git a/core/field.js b/core/field.js index 54554129a..e4336819b 100644 --- a/core/field.js +++ b/core/field.js @@ -31,6 +31,7 @@ goog.provide('Blockly.Field'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Gesture'); +goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.Size'); goog.require('Blockly.utils.userAgent'); @@ -44,15 +45,30 @@ goog.require('Blockly.utils.style'); * @param {Function=} opt_validator A function that is called to validate * changes to the field's value. Takes in a value & returns a validated * value, or null to abort the change. + * @param {Object=} opt_config A map of options used to configure the field. See + * the individual field's documentation for a list of properties this + * parameter supports. * @constructor */ -Blockly.Field = function(value, opt_validator) { +Blockly.Field = function(value, opt_validator, opt_config) { /** * The size of the area rendered by the field. * @type {Blockly.utils.Size} */ this.size_ = new Blockly.utils.Size(0, 0); + if (opt_config) { + var tooltip = opt_config['tooltip']; + if (typeof tooltip == 'string') { + tooltip = Blockly.utils.replaceMessageReferences( + opt_config['tooltip']); + } + tooltip && this.setTooltip(tooltip); + + // TODO (#2884): Possibly add CSS class config option. + // TODO (#2885): Possibly add cursor config option. + } + this.setValue(value); opt_validator && this.setValidator(opt_validator); }; diff --git a/core/field_registry.js b/core/field_registry.js index 3bc0c549d..7556bd0d6 100644 --- a/core/field_registry.js +++ b/core/field_registry.js @@ -28,8 +28,6 @@ goog.provide('Blockly.fieldRegistry'); -goog.require('Blockly.utils'); - /** * The set of all registered fields, keyed by field type as used in the JSON @@ -81,12 +79,5 @@ Blockly.fieldRegistry.fromJson = function(options) { ' #1584), or the registration is not being reached.'); return null; } - - var field = fieldClass.fromJson(options); - if (options['tooltip'] !== undefined) { - var rawValue = options['tooltip']; - var localizedText = Blockly.utils.replaceMessageReferences(rawValue); - field.setTooltip(localizedText); - } - return field; + return fieldClass.fromJson(options); }; diff --git a/tests/mocha/field_test.js b/tests/mocha/field_test.js index 6d5454434..3ae3024fb 100644 --- a/tests/mocha/field_test.js +++ b/tests/mocha/field_test.js @@ -341,145 +341,200 @@ suite('Abstract Fields', function() { chai.assert(this.field.doValueUpdate_.calledOnce); }); }); - suite('setTooltip', function() { - setup(function() { - this.workspace = new Blockly.WorkspaceSvg({}); - this.workspace.createDom(); - }); - teardown(function() { - this.workspace = null; - }); - test('Before Append', function() { - Blockly.Blocks['tooltip'] = { - init: function() { - var field = new Blockly.FieldTextInput('default'); - field.setTooltip('tooltip'); - this.appendDummyInput() - .appendField(field, 'TOOLTIP'); - }, - }; - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - '' - ).children[0], this.workspace); - var field = block.getField('TOOLTIP'); - chai.assert.equal(field.getClickTarget_().tooltip, 'tooltip'); - delete Blockly.Blocks['tooltip']; - }); - test('After Append', function() { - Blockly.Blocks['tooltip'] = { - init: function() { - var field = new Blockly.FieldTextInput('default'); - this.appendDummyInput() - .appendField(field, 'TOOLTIP'); - field.setTooltip('tooltip'); - }, - }; - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - '' - ).children[0], this.workspace); - var field = block.getField('TOOLTIP'); - chai.assert.equal(field.getClickTarget_().tooltip, 'tooltip'); - delete Blockly.Blocks['tooltip']; - }); - test('After Block Creation', function() { - Blockly.Blocks['tooltip'] = { - init: function() { - var field = new Blockly.FieldTextInput('default'); - this.appendDummyInput() - .appendField(field, 'TOOLTIP'); - }, - }; - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - '' - ).children[0], this.workspace); - var field = block.getField('TOOLTIP'); - field.setTooltip('tooltip'); - chai.assert.equal(field.getClickTarget_().tooltip, 'tooltip'); - delete Blockly.Blocks['tooltip']; - }); - test('Dynamic Function', function() { - Blockly.Blocks['tooltip'] = { - init: function() { - var field = new Blockly.FieldTextInput('default'); - field.setTooltip(this.tooltipFunc); - this.appendDummyInput() - .appendField(field, 'TOOLTIP'); - }, + suite('Customization', function() { + // All this field does is wrap the abstract field. + function CustomField(opt_config) { + CustomField.superClass_.constructor.call( + this, 'value', null, opt_config); + } + goog.inherits(CustomField, Blockly.Field); + CustomField.fromJson = function(options) { + return new CustomField(options); + }; - tooltipFunc: function() { - return this.getFieldValue('TOOLTIP'); - } - }; - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - '' - ).children[0], this.workspace); - var field = block.getField('TOOLTIP'); - chai.assert.equal(field.getClickTarget_().tooltip, block.tooltipFunc); - delete Blockly.Blocks['tooltip']; - }); - test('Element', function() { - Blockly.Blocks['tooltip'] = { - init: function() { - var field = new Blockly.FieldTextInput('default'); - field.setTooltip(this.element); - this.appendDummyInput() - .appendField(field, 'TOOLTIP'); - }, - element: { - tooltip: 'tooltip' - } - }; - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - '' - ).children[0], this.workspace); - var field = block.getField('TOOLTIP'); - chai.assert.equal(field.getClickTarget_().tooltip, block.element); - delete Blockly.Blocks['tooltip']; - }); - test('Null', function() { - Blockly.Blocks['tooltip'] = { - init: function() { - var field = new Blockly.FieldTextInput('default'); - field.setTooltip(null); - this.appendDummyInput() - .appendField(field, 'TOOLTIP'); - }, - }; - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - '' - ).children[0], this.workspace); - var field = block.getField('TOOLTIP'); - chai.assert.equal(field.getClickTarget_().tooltip, block); - delete Blockly.Blocks['tooltip']; - }); - test('Undefined', function() { - Blockly.Blocks['tooltip'] = { - init: function() { - var field = new Blockly.FieldTextInput('default'); - this.appendDummyInput() - .appendField(field, 'TOOLTIP'); - }, - }; - var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( - '' + - ' ' + - '' - ).children[0], this.workspace); - var field = block.getField('TOOLTIP'); - chai.assert.equal(field.getClickTarget_().tooltip, block); - delete Blockly.Blocks['tooltip']; + suite('Tooltip', function() { + test('JS Constructor', function() { + var field = new Blockly.Field('value', null, { + tooltip: 'test tooltip', + }); + chai.assert.equal(field.tooltip_, 'test tooltip'); + }); + test('JS Constructor - Dynamic', function() { + var returnTooltip = function() { + return 'dynamic tooltip text'; + }; + var field = new Blockly.Field('value', null, { + tooltip: returnTooltip + }); + chai.assert.equal(field.tooltip_, returnTooltip); + }); + test('JSON Definition', function() { + var field = CustomField.fromJson({ + tooltip: "test tooltip" + }); + chai.assert.equal(field.tooltip_, 'test tooltip'); + }); + suite('W/ Msg References', function() { + setup(function() { + Blockly.Msg['TOOLTIP'] = 'test tooltip'; + }); + teardown(function() { + delete Blockly.Msg['TOOLTIP']; + }); + test('JS Constructor', function() { + var field = new Blockly.Field('value', null, { + tooltip: '%{BKY_TOOLTIP}', + }); + chai.assert.equal(field.tooltip_, 'test tooltip'); + }); + test('JSON Definition', function() { + var field = CustomField.fromJson({ + tooltip: "%{BKY_TOOLTIP}" + }); + chai.assert.equal(field.tooltip_, 'test tooltip'); + }); + }); + suite('setTooltip', function() { + setup(function() { + this.workspace = new Blockly.WorkspaceSvg({}); + this.workspace.createDom(); + }); + teardown(function() { + this.workspace = null; + }); + test('Before Append', function() { + Blockly.Blocks['tooltip'] = { + init: function() { + var field = new Blockly.FieldTextInput('default'); + field.setTooltip('tooltip'); + this.appendDummyInput() + .appendField(field, 'TOOLTIP'); + }, + }; + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + '' + ).children[0], this.workspace); + var field = block.getField('TOOLTIP'); + chai.assert.equal(field.getClickTarget_().tooltip, 'tooltip'); + delete Blockly.Blocks['tooltip']; + }); + test('After Append', function() { + Blockly.Blocks['tooltip'] = { + init: function() { + var field = new Blockly.FieldTextInput('default'); + this.appendDummyInput() + .appendField(field, 'TOOLTIP'); + field.setTooltip('tooltip'); + }, + }; + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + '' + ).children[0], this.workspace); + var field = block.getField('TOOLTIP'); + chai.assert.equal(field.getClickTarget_().tooltip, 'tooltip'); + delete Blockly.Blocks['tooltip']; + }); + test('After Block Creation', function() { + Blockly.Blocks['tooltip'] = { + init: function() { + var field = new Blockly.FieldTextInput('default'); + this.appendDummyInput() + .appendField(field, 'TOOLTIP'); + }, + }; + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + '' + ).children[0], this.workspace); + var field = block.getField('TOOLTIP'); + field.setTooltip('tooltip'); + chai.assert.equal(field.getClickTarget_().tooltip, 'tooltip'); + delete Blockly.Blocks['tooltip']; + }); + test('Dynamic Function', function() { + Blockly.Blocks['tooltip'] = { + init: function() { + var field = new Blockly.FieldTextInput('default'); + field.setTooltip(this.tooltipFunc); + this.appendDummyInput() + .appendField(field, 'TOOLTIP'); + }, + + tooltipFunc: function() { + return this.getFieldValue('TOOLTIP'); + } + }; + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + '' + ).children[0], this.workspace); + var field = block.getField('TOOLTIP'); + chai.assert.equal(field.getClickTarget_().tooltip, block.tooltipFunc); + delete Blockly.Blocks['tooltip']; + }); + test('Element', function() { + Blockly.Blocks['tooltip'] = { + init: function() { + var field = new Blockly.FieldTextInput('default'); + field.setTooltip(this.element); + this.appendDummyInput() + .appendField(field, 'TOOLTIP'); + }, + element: { + tooltip: 'tooltip' + } + }; + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + '' + ).children[0], this.workspace); + var field = block.getField('TOOLTIP'); + chai.assert.equal(field.getClickTarget_().tooltip, block.element); + delete Blockly.Blocks['tooltip']; + }); + test('Null', function() { + Blockly.Blocks['tooltip'] = { + init: function() { + var field = new Blockly.FieldTextInput('default'); + field.setTooltip(null); + this.appendDummyInput() + .appendField(field, 'TOOLTIP'); + }, + }; + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + '' + ).children[0], this.workspace); + var field = block.getField('TOOLTIP'); + chai.assert.equal(field.getClickTarget_().tooltip, block); + delete Blockly.Blocks['tooltip']; + }); + test('Undefined', function() { + Blockly.Blocks['tooltip'] = { + init: function() { + var field = new Blockly.FieldTextInput('default'); + this.appendDummyInput() + .appendField(field, 'TOOLTIP'); + }, + }; + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + '' + ).children[0], this.workspace); + var field = block.getField('TOOLTIP'); + chai.assert.equal(field.getClickTarget_().tooltip, block); + delete Blockly.Blocks['tooltip']; + }); + }); }); }); });