mirror of
https://github.com/google/blockly.git
synced 2026-01-10 02:17:09 +01:00
Refactored field validation.
This commit is contained in:
@@ -831,7 +831,6 @@ Blockly.Blocks['lists_split'] = {
|
||||
updateType_: function(newMode) {
|
||||
var mode = this.getFieldValue('MODE');
|
||||
if (mode != newMode) {
|
||||
this.setFieldValue(newMode, 'MODE');
|
||||
var inputConnection = this.getInput('INPUT').connection;
|
||||
inputConnection.setShadowDom(null);
|
||||
var inputBlock = inputConnection.targetBlock();
|
||||
|
||||
@@ -864,11 +864,7 @@ Blockly.Constants.Text.TEXT_CHARAT_EXTENSION = function() {
|
||||
if (newAt != this.isAt_) {
|
||||
var block = this.sourceBlock_;
|
||||
block.updateAt_(newAt);
|
||||
// This menu has been destroyed and replaced. Update the replacement.
|
||||
block.setFieldValue(value, 'WHERE');
|
||||
return null;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
this.updateAt_(true);
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
|
||||
156
core/field.js
156
core/field.js
@@ -39,14 +39,15 @@ goog.require('goog.style');
|
||||
|
||||
/**
|
||||
* Abstract class for an editable field.
|
||||
* @param {string} text The initial content of the field.
|
||||
* @param {function(string):(string|null|undefined)=} opt_validator An optional
|
||||
* function that is called to validate user input. See setValidator().
|
||||
* @param {*} value The initial value of the field.
|
||||
* @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.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Field = function(text, opt_validator) {
|
||||
Blockly.Field = function(value, opt_validator) {
|
||||
this.size_ = new goog.math.Size(0, Blockly.BlockSvg.MIN_BLOCK_Y);
|
||||
this.setValue(text);
|
||||
this.setValue(value);
|
||||
this.setValidator(opt_validator);
|
||||
};
|
||||
|
||||
@@ -123,6 +124,14 @@ Blockly.Field.prototype.name = undefined;
|
||||
*/
|
||||
Blockly.Field.prototype.maxDisplayLength = 50;
|
||||
|
||||
/**
|
||||
* Get the current value of the field.
|
||||
* @return {*} Current value.
|
||||
*/
|
||||
Blockly.Field.prototype.getValue = function() {
|
||||
return this.value_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Visible text to display.
|
||||
* @type {string}
|
||||
@@ -233,10 +242,11 @@ Blockly.Field.prototype.initView = function() {
|
||||
'y': 0,
|
||||
'height': 16
|
||||
}, this.fieldGroup_);
|
||||
/** @type {!Element} */
|
||||
this.textElement_ = Blockly.utils.createSvgElement('text',
|
||||
{'class': 'blocklyText', 'y': this.size_.height - 12.5},
|
||||
this.fieldGroup_);
|
||||
var textNode = document.createTextNode('');
|
||||
this.textElement_.appendChild(textNode);
|
||||
|
||||
this.updateEditable();
|
||||
|
||||
@@ -375,14 +385,15 @@ Blockly.Field.prototype.setVisible = function(visible) {
|
||||
* Sets a new validation function for editable fields, or clears a previously
|
||||
* set validator.
|
||||
*
|
||||
* The validator function takes in the text form of the users input, and
|
||||
* optionally returns the accepted field text. Alternatively, if the function
|
||||
* returns null, the field value change aborts. If the function does not return
|
||||
* anything (or returns undefined), the input value is accepted as valid. This
|
||||
* is a shorthand for fields using the validator function call as a field-level
|
||||
* change event notification.
|
||||
* The validator function takes in the new field value, and returns
|
||||
* validated value. The validated value could be the input value, a modified
|
||||
* version of the input value, or null to abort the change.
|
||||
*
|
||||
* @param {?function(string):(string|null|undefined)} handler The validator
|
||||
* If the function does not return anything (or returns undefined) the new
|
||||
* value is accepted as valid. This is to allow for fields using the
|
||||
* validated founction as a field-level change event notification.
|
||||
*
|
||||
* @param {Function=} handler The validator
|
||||
* function or null to clear a previous validator.
|
||||
*/
|
||||
Blockly.Field.prototype.setValidator = function(handler) {
|
||||
@@ -401,6 +412,8 @@ Blockly.Field.prototype.getValidator = function() {
|
||||
* Validates a change. Does nothing. Subclasses may override this.
|
||||
* @param {string} text The user's text.
|
||||
* @return {string} No change needed.
|
||||
* @deprecated May 2019. Override doClassValidation and other relevant 'do'
|
||||
* functions instead.
|
||||
*/
|
||||
Blockly.Field.prototype.classValidator = function(text) {
|
||||
return text;
|
||||
@@ -411,6 +424,7 @@ Blockly.Field.prototype.classValidator = function(text) {
|
||||
* function for the field's class and its parents.
|
||||
* @param {string} text Proposed text.
|
||||
* @return {?string} Revised text, or null if invalid.
|
||||
* @deprecated May 2019. setValue now contains all relevant logic.
|
||||
*/
|
||||
Blockly.Field.prototype.callValidator = function(text) {
|
||||
var classResult = this.classValidator(text);
|
||||
@@ -452,15 +466,15 @@ Blockly.Field.prototype.updateColour = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws the border with the correct width.
|
||||
* Saves the computed width in a property.
|
||||
* Used by getSize() to move/resize any dom elements, and get the new size.
|
||||
*
|
||||
* All rendering that has an effect on the size/shape of the block should be
|
||||
* done here, and should be triggered by getSize().
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Field.prototype.render_ = function() {
|
||||
// Replace the text.
|
||||
this.textElement_.textContent = this.getDisplayText_();
|
||||
this.updateWidth();
|
||||
this.isDirty_ = false;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -547,6 +561,7 @@ Blockly.Field.stopCache = function() {
|
||||
Blockly.Field.prototype.getSize = function() {
|
||||
if (this.isDirty_) {
|
||||
this.render_();
|
||||
this.isDirty_ = false;
|
||||
} else if (this.visible_ && this.size_.width == 0) {
|
||||
// If the field is not visible the width will be 0 as well, one of the
|
||||
// problems with the old system.
|
||||
@@ -644,39 +659,106 @@ Blockly.Field.prototype.forceRerender = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* By default there is no difference between the human-readable text and
|
||||
* the language-neutral values. Subclasses (such as dropdown) may define this.
|
||||
* @return {string} Current value.
|
||||
*/
|
||||
Blockly.Field.prototype.getValue = function() {
|
||||
return this.getText();
|
||||
};
|
||||
|
||||
/**
|
||||
* By default there is no difference between the human-readable text and
|
||||
* the language-neutral values. Subclasses (such as dropdown) may define this.
|
||||
* @param {string} newValue New value.
|
||||
* Used to change the value of the field. Handles validation and events.
|
||||
* Subclasses should override doClassValidation_ and doValueUpdate_ rather
|
||||
* than this method.
|
||||
* @param {*} newValue New value.
|
||||
*/
|
||||
Blockly.Field.prototype.setValue = function(newValue) {
|
||||
var doLogging = false;
|
||||
if (newValue === null) {
|
||||
// No change if null.
|
||||
doLogging && console.log('null, return');
|
||||
// Not a valid value to check.
|
||||
return;
|
||||
}
|
||||
// Validate input.
|
||||
var validated = this.callValidator(newValue);
|
||||
if (validated !== null) {
|
||||
newValue = validated;
|
||||
|
||||
newValue = this.doClassValidation_(newValue);
|
||||
if (newValue === null) {
|
||||
doLogging && console.log('invalid, return');
|
||||
this.doValueInvalid_();
|
||||
if (this.isDirty_) {
|
||||
this.forceRerender();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var localValidator = this.getValidator();
|
||||
if (localValidator) {
|
||||
var validatedValue = localValidator.call(this, newValue);
|
||||
// Sometimes local validators are used as change listeners (bad!) which
|
||||
// means they might return undefined accidentally, so we'll just ignore that.
|
||||
if (validatedValue !== undefined) {
|
||||
newValue = validatedValue;
|
||||
}
|
||||
if (newValue === null) {
|
||||
doLogging && console.log('invalid, return');
|
||||
this.doValueInvalid_();
|
||||
if (this.isDirty_) {
|
||||
this.forceRerender();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Check for change.
|
||||
var oldValue = this.getValue();
|
||||
if (oldValue == newValue) {
|
||||
if (oldValue === newValue) {
|
||||
doLogging && console.log('same, return');
|
||||
// No change.
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
|
||||
Blockly.Events.fire(new Blockly.Events.BlockChange(
|
||||
this.sourceBlock_, 'field', this.name, oldValue, newValue));
|
||||
}
|
||||
this.setText(newValue);
|
||||
this.doValueUpdate_(newValue);
|
||||
if (this.isDirty_) {
|
||||
this.forceRerender();
|
||||
}
|
||||
doLogging && console.log(this.value_);
|
||||
};
|
||||
|
||||
/**
|
||||
* A generic value possessed by the field.
|
||||
* Should generally be non-null, only null when the field is created.
|
||||
* @type {*}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Field.prototype.value_ = null;
|
||||
|
||||
/**
|
||||
* Used to validate a value. Returns input by default. Can be overridden by
|
||||
* subclasses, see FieldDropdown.
|
||||
* @param {*} newValue The value to be validated.
|
||||
* @return {*} The validated value, same as input by default.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Field.prototype.doClassValidation_ = function(newValue) {
|
||||
// For backwards compatibility.
|
||||
newValue = this.classValidator(newValue);
|
||||
return newValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to update the value of a field. Can be overridden by subclasses to do
|
||||
* custom storage of values/updating of external things.
|
||||
* @param {*} newValue The value to be saved.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Field.prototype.doValueUpdate_ = function(newValue) {
|
||||
this.value_ = newValue;
|
||||
this.isDirty_ = true;
|
||||
// For backwards compatibility.
|
||||
this.text_ = String(newValue);
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to notify the field an invalid value was input. Can be overiden by
|
||||
* subclasses, see FieldTextInput.
|
||||
* No-op by default.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.Field.prototype.doValueInvalid_ = function() {
|
||||
// NOP
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,21 +34,19 @@ goog.require('Blockly.utils');
|
||||
|
||||
/**
|
||||
* Class for an editable angle field.
|
||||
* @param {(string|number)=} opt_value The initial content of the field. The
|
||||
* value should cast to a number, and if it does not, '0' will be used.
|
||||
* @param {Function=} opt_validator An optional function that is called
|
||||
* to validate any constraints on what the user entered. Takes the new
|
||||
* text as an argument and returns the accepted text or null to abort
|
||||
* the change.
|
||||
* @param {string|number=} opt_value The initial value of the field. Should cast
|
||||
* to a number. Defaults to 0.
|
||||
* @param {Function=} opt_validator A function that is called to validate
|
||||
* changes to the field's value. Takes in a number & returns a
|
||||
* validated number, or null to abort the change.
|
||||
* @extends {Blockly.FieldTextInput}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldAngle = function(opt_value, opt_validator) {
|
||||
// Add degree symbol: '360°' (LTR) or '°360' (RTL)
|
||||
this.symbol_ = Blockly.utils.createSvgElement('tspan', {}, null);
|
||||
this.symbol_.appendChild(document.createTextNode('\u00B0'));
|
||||
|
||||
opt_value = (opt_value && !isNaN(opt_value)) ? String(opt_value) : '0';
|
||||
opt_value = this.doClassValidation_(opt_value);
|
||||
if (opt_value === null) {
|
||||
opt_value = 0;
|
||||
}
|
||||
Blockly.FieldAngle.superClass_.constructor.call(
|
||||
this, opt_value, opt_validator);
|
||||
};
|
||||
@@ -120,18 +118,25 @@ Blockly.FieldAngle.WRAP = 360;
|
||||
Blockly.FieldAngle.RADIUS = Blockly.FieldAngle.HALF - 1;
|
||||
|
||||
/**
|
||||
* Adds degree symbol and recalculates width.
|
||||
* Saves the computed width in a property.
|
||||
* Create the block UI for this field.
|
||||
* @package
|
||||
*/
|
||||
Blockly.FieldAngle.prototype.initView = function() {
|
||||
Blockly.FieldAngle.superClass_.initView.call(this);
|
||||
// Add the degree symbol to the left of the number, even in RTL (issue #2380)
|
||||
this.symbol_ = Blockly.utils.createSvgElement('tspan', {}, null);
|
||||
this.symbol_.appendChild(document.createTextNode('\u00B0'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the graph when the field rerenders.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldAngle.prototype.render_ = function() {
|
||||
// Update textElement.
|
||||
this.textElement_.textContent = this.getDisplayText_();
|
||||
|
||||
// Insert degree symbol.
|
||||
// Degree symbol should be left of number, even in RTL (issue #2380).
|
||||
this.textElement_.appendChild(this.symbol_);
|
||||
this.updateWidth();
|
||||
this.updateGraph_();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -208,7 +213,6 @@ Blockly.FieldAngle.prototype.showEditor_ = function() {
|
||||
}, svg);
|
||||
}
|
||||
|
||||
|
||||
var border = this.sourceBlock_.getColourBorder();
|
||||
border = border.colourBorder == null ? border.colourLight : border.colourBorder;
|
||||
|
||||
@@ -244,6 +248,7 @@ Blockly.FieldAngle.prototype.hide_ = function() {
|
||||
* @param {!Event} e Mouse move event.
|
||||
*/
|
||||
Blockly.FieldAngle.prototype.onMouseMove = function(e) {
|
||||
// Calculate angle.
|
||||
var bBox = this.gauge_.ownerSVGElement.getBoundingClientRect();
|
||||
var dx = e.clientX - bBox.left - Blockly.FieldAngle.HALF;
|
||||
var dy = e.clientY - bBox.top - Blockly.FieldAngle.HALF;
|
||||
@@ -268,24 +273,16 @@ Blockly.FieldAngle.prototype.onMouseMove = function(e) {
|
||||
angle = Math.round(angle / Blockly.FieldAngle.ROUND) *
|
||||
Blockly.FieldAngle.ROUND;
|
||||
}
|
||||
angle = this.callValidator(angle);
|
||||
Blockly.FieldTextInput.htmlInput_.value = angle;
|
||||
this.setValue(angle);
|
||||
this.validate_();
|
||||
this.resizeEditor_();
|
||||
};
|
||||
|
||||
/**
|
||||
* Insert a degree symbol.
|
||||
* @param {?string} text New text.
|
||||
*/
|
||||
Blockly.FieldAngle.prototype.setText = function(text) {
|
||||
Blockly.FieldAngle.superClass_.setText.call(this, text);
|
||||
if (!this.textElement_) {
|
||||
// Not rendered yet.
|
||||
return;
|
||||
// Update value.
|
||||
var angleString = String(angle);
|
||||
if (angleString != this.text_) {
|
||||
Blockly.FieldTextInput.htmlInput_.value = angle;
|
||||
this.setValue(angle);
|
||||
// Always render the input angle.
|
||||
this.text_ = angleString;
|
||||
this.forceRerender();
|
||||
}
|
||||
this.updateGraph_();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -296,6 +293,7 @@ Blockly.FieldAngle.prototype.updateGraph_ = function() {
|
||||
if (!this.gauge_) {
|
||||
return;
|
||||
}
|
||||
// Always display the input (i.e. getText) even if it is invalid.
|
||||
var angleDegrees = Number(this.getText()) + Blockly.FieldAngle.OFFSET;
|
||||
var angleRadians = Blockly.utils.toRadians(angleDegrees);
|
||||
var path = ['M ', Blockly.FieldAngle.HALF, ',', Blockly.FieldAngle.HALF];
|
||||
@@ -326,18 +324,16 @@ Blockly.FieldAngle.prototype.updateGraph_ = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensure that only an angle may be entered.
|
||||
* @param {string} text The user's text.
|
||||
* @return {?string} A string representing a valid angle, or null if invalid.
|
||||
* Ensure that the input value is a valid angle.
|
||||
* @param {string|number=} newValue The input value.
|
||||
* @return {?number} A valid angle, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldAngle.prototype.classValidator = function(text) {
|
||||
if (text === null) {
|
||||
return null;
|
||||
}
|
||||
var n = parseFloat(text || 0);
|
||||
if (isNaN(n)) {
|
||||
Blockly.FieldAngle.prototype.doClassValidation_ = function(newValue) {
|
||||
if (isNaN(newValue)) {
|
||||
return null;
|
||||
}
|
||||
var n = parseFloat(newValue || 0);
|
||||
n = n % 360;
|
||||
if (n < 0) {
|
||||
n += 360;
|
||||
@@ -345,7 +341,7 @@ Blockly.FieldAngle.prototype.classValidator = function(text) {
|
||||
if (n > Blockly.FieldAngle.WRAP) {
|
||||
n -= 360;
|
||||
}
|
||||
return String(n);
|
||||
return n;
|
||||
};
|
||||
|
||||
Blockly.Field.register('field_angle', Blockly.FieldAngle);
|
||||
|
||||
@@ -32,19 +32,22 @@ goog.require('Blockly.utils');
|
||||
|
||||
/**
|
||||
* Class for a checkbox field.
|
||||
* @param {string=} opt_state The initial state of the field ('TRUE' or
|
||||
* 'FALSE'), defaults to 'FALSE'.
|
||||
* @param {Function=} opt_validator A function that is executed when a new
|
||||
* option is selected. Its sole argument is the new checkbox state. If
|
||||
* it returns a value, this becomes the new checkbox state, unless the
|
||||
* value is null, in which case the change is aborted.
|
||||
* @param {string|boolean=} opt_value The initial value of the field. Should
|
||||
* either be 'TRUE', 'FALSE' or a boolean. Defaults to 'FALSE'.
|
||||
* @param {Function=} opt_validator A function that is called to validate
|
||||
* changes to the field's value. Takes in a value ('TRUE' or 'FALSE') &
|
||||
* returns a validated value ('TRUE' or 'FALSE'), or null to abort the
|
||||
* change.
|
||||
* @extends {Blockly.Field}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldCheckbox = function(opt_state, opt_validator) {
|
||||
Blockly.FieldCheckbox.superClass_.constructor.call(this, '', opt_validator);
|
||||
// Set the initial state.
|
||||
this.setValue(opt_state);
|
||||
Blockly.FieldCheckbox = function(opt_value, opt_validator) {
|
||||
opt_value = this.doClassValidation_(opt_value);
|
||||
if (opt_value === null) {
|
||||
opt_value = 'FALSE';
|
||||
}
|
||||
Blockly.FieldCheckbox.superClass_.constructor.call(this, opt_value, opt_validator);
|
||||
this.size_.width = Blockly.FieldCheckbox.WIDTH;
|
||||
};
|
||||
goog.inherits(Blockly.FieldCheckbox, Blockly.Field);
|
||||
|
||||
@@ -56,9 +59,23 @@ goog.inherits(Blockly.FieldCheckbox, Blockly.Field);
|
||||
* @nocollapse
|
||||
*/
|
||||
Blockly.FieldCheckbox.fromJson = function(options) {
|
||||
return new Blockly.FieldCheckbox(options['checked'] ? 'TRUE' : 'FALSE');
|
||||
return new Blockly.FieldCheckbox(options['checked']);
|
||||
};
|
||||
|
||||
/**
|
||||
* The width of a checkbox field.
|
||||
* @type {number}
|
||||
* @const
|
||||
*/
|
||||
Blockly.FieldCheckbox.WIDTH = 5;
|
||||
|
||||
/**
|
||||
* Character for the checkmark.
|
||||
* @type {string}
|
||||
* @const
|
||||
*/
|
||||
Blockly.FieldCheckbox.CHECK_CHAR = '\u2713';
|
||||
|
||||
/**
|
||||
* Serializable fields are saved by the XML renderer, non-serializable fields
|
||||
* are not. Editable fields should also be serializable.
|
||||
@@ -67,11 +84,6 @@ Blockly.FieldCheckbox.fromJson = function(options) {
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Character for the checkmark.
|
||||
*/
|
||||
Blockly.FieldCheckbox.CHECK_CHAR = '\u2713';
|
||||
|
||||
/**
|
||||
* Mouse cursor style when over the hotspot that initiates editability.
|
||||
*/
|
||||
@@ -91,49 +103,98 @@ Blockly.FieldCheckbox.prototype.initView = function() {
|
||||
this.fieldGroup_);
|
||||
var textNode = document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);
|
||||
this.checkElement_.appendChild(textNode);
|
||||
this.checkElement_.style.display = this.state_ ? 'block' : 'none';
|
||||
};
|
||||
this.checkElement_.style.display = this.value_ ? 'block' : 'none';
|
||||
|
||||
/**
|
||||
* Return 'TRUE' if the checkbox is checked, 'FALSE' otherwise.
|
||||
* @return {string} Current state.
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.getValue = function() {
|
||||
return String(this.state_).toUpperCase();
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the checkbox to be checked if newBool is 'TRUE' or true,
|
||||
* unchecks otherwise.
|
||||
* @param {string|boolean} newBool New state.
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.setValue = function(newBool) {
|
||||
var newState = (typeof newBool == 'string') ?
|
||||
(newBool.toUpperCase() == 'TRUE') : !!newBool;
|
||||
if (this.state_ !== newState) {
|
||||
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
|
||||
Blockly.Events.fire(new Blockly.Events.BlockChange(
|
||||
this.sourceBlock_, 'field', this.name, this.state_, newState));
|
||||
}
|
||||
this.state_ = newState;
|
||||
if (this.checkElement_) {
|
||||
this.checkElement_.style.display = newState ? 'block' : 'none';
|
||||
}
|
||||
if (this.borderRect_) {
|
||||
this.borderRect_.setAttribute('width',
|
||||
this.size_.width + Blockly.BlockSvg.SEP_SPACE_X);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggle the state of the checkbox.
|
||||
* Checkboxes have a constant width.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.render_ = function() {
|
||||
this.size_.width = Blockly.FieldCheckbox.WIDTH;
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggle the state of the checkbox on click.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.showEditor_ = function() {
|
||||
var newState = !this.state_;
|
||||
if (this.sourceBlock_) {
|
||||
// Call any validation function, and allow it to override.
|
||||
newState = this.callValidator(newState);
|
||||
this.setValue(!this.value_);
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensure that the input value is valid ('TRUE' or 'FALSE').
|
||||
* @param {string|boolean=} newValue The input value.
|
||||
* @return {?string} A valid value ('TRUE' or 'FALSE), or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.doClassValidation_ = function(newValue) {
|
||||
if (newValue === true || newValue === 'TRUE') {
|
||||
return 'TRUE';
|
||||
}
|
||||
if (newState !== null) {
|
||||
this.setValue(String(newState).toUpperCase());
|
||||
if (newValue === false || newValue === 'FALSE') {
|
||||
return 'FALSE';
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the value of the field, and update the checkElement.
|
||||
* @param {string} newValue The new value ('TRUE' or 'FALSE') of the field.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.doValueUpdate_ = function(newValue) {
|
||||
this.value_ = this.convertValueToBool_(newValue);
|
||||
// Update visual.
|
||||
if (this.checkElement_) {
|
||||
this.checkElement_.style.display = this.value_ ? 'block' : 'none';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the value of this field, either 'TRUE' or 'FALSE'.
|
||||
* @return {string} The value of this field.
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.getValue = function() {
|
||||
return this.value_ ? 'TRUE' : 'FALSE';
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the boolean value of this field.
|
||||
* @return {string} The boolean value of this field.
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.getValueBoolean = function() {
|
||||
return this.value_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the text of this field. Used when the block is collapsed.
|
||||
* @return {string} Text representing the value of this field
|
||||
* ('true' or 'false').
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.getText = function() {
|
||||
return String(this.convertValueToBool_(this.value_));
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a value into a pure boolean.
|
||||
*
|
||||
* Converts 'TRUE' to true and 'FALSE' to false correctly, everything else
|
||||
* is cast to a boolean.
|
||||
* @param {*} value The value to convert.
|
||||
* @return {boolean} The converted value.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.convertValueToBool_ = function(value) {
|
||||
if (typeof value == 'string') {
|
||||
return value == 'TRUE';
|
||||
} else {
|
||||
return !!value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -34,21 +34,21 @@ goog.require('goog.math.Size');
|
||||
|
||||
/**
|
||||
* Class for a colour input field.
|
||||
* @param {string=} opt_colour The initial colour in '#rrggbb' format, defaults
|
||||
* to the first value in the default colour array.
|
||||
* @param {Function=} opt_validator A function that is executed when a new
|
||||
* colour is selected. Its sole argument is the new colour value. Its
|
||||
* return value becomes the selected colour, unless it is undefined, in
|
||||
* which case the new colour stands, or it is null, in which case the change
|
||||
* is aborted.
|
||||
* @param {string=} opt_value The initial value of the field. Should be in
|
||||
* '#rrggbb' format. Defaults to the first value in the default colour array.
|
||||
* @param {Function=} opt_validator A function that is called to validate
|
||||
* changes to the field's value. Takes in a colour string & returns a
|
||||
* validated colour string ('#rrggbb' format), or null to abort the change.
|
||||
* @extends {Blockly.Field}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldColour = function(opt_colour, opt_validator) {
|
||||
opt_colour = opt_colour || Blockly.FieldColour.COLOURS[0];
|
||||
Blockly.FieldColour.superClass_.constructor
|
||||
.call(this, opt_colour, opt_validator);
|
||||
this.setText(Blockly.Field.NBSP + Blockly.Field.NBSP + Blockly.Field.NBSP);
|
||||
Blockly.FieldColour = function(opt_value, opt_validator) {
|
||||
opt_value = this.doClassValidation_(opt_value);
|
||||
if (opt_value === null) {
|
||||
opt_value = Blockly.FieldColour.COLOURS[0];
|
||||
}
|
||||
Blockly.FieldColour.superClass_.constructor.call(
|
||||
this, opt_value, opt_validator);
|
||||
};
|
||||
goog.inherits(Blockly.FieldColour, Blockly.Field);
|
||||
|
||||
@@ -63,14 +63,6 @@ Blockly.FieldColour.fromJson = function(options) {
|
||||
return new Blockly.FieldColour(options['colour']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializable fields are saved by the XML renderer, non-serializable fields
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
* @const
|
||||
*/
|
||||
Blockly.FieldColour.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Default width of a colour field.
|
||||
* @type {number}
|
||||
@@ -87,6 +79,20 @@ Blockly.FieldColour.DEFAULT_WIDTH = 16;
|
||||
*/
|
||||
Blockly.FieldColour.DEFAULT_HEIGHT = 12;
|
||||
|
||||
/**
|
||||
* Regex that defines the form of a colour string.
|
||||
* @type {RegExp}
|
||||
*/
|
||||
Blockly.FieldColour.COLOUR_REGEX = new RegExp('#[0-9a-fA-F]{6}');
|
||||
|
||||
/**
|
||||
* Serializable fields are saved by the XML renderer, non-serializable fields
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
* @const
|
||||
*/
|
||||
Blockly.FieldColour.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Array of colours used by this field. If null, use the global list.
|
||||
* @type {Array.<string>}
|
||||
@@ -137,7 +143,7 @@ Blockly.FieldColour.prototype.initView = function() {
|
||||
this.borderRect_.style['fillOpacity'] = 1;
|
||||
this.borderRect_.setAttribute('width',
|
||||
this.size_.width + Blockly.BlockSvg.SEP_SPACE_X);
|
||||
this.setValue(this.getValue());
|
||||
this.borderRect_.style.fill = this.value_;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -154,42 +160,44 @@ Blockly.FieldColour.prototype.dispose = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Colour fields are fixed with, no need to update.
|
||||
* Render the colour field.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldColour.prototype.updateWidth = function() {
|
||||
// NOP
|
||||
Blockly.FieldColour.prototype.render_ = function() {
|
||||
this.size_.width = Blockly.FieldColour.DEFAULT_WIDTH;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the current colour.
|
||||
* @return {string} Current colour in '#rrggbb' format.
|
||||
* Ensure that the input value is a valid colour.
|
||||
* @param {string=} newValue The input value.
|
||||
* @return {?string} A valid colour, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldColour.prototype.getValue = function() {
|
||||
return this.colour_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the colour.
|
||||
* @param {string} colour The new colour in '#rrggbb' format.
|
||||
*/
|
||||
Blockly.FieldColour.prototype.setValue = function(colour) {
|
||||
if (this.sourceBlock_ && Blockly.Events.isEnabled() &&
|
||||
this.colour_ != colour) {
|
||||
Blockly.Events.fire(new Blockly.Events.BlockChange(
|
||||
this.sourceBlock_, 'field', this.name, this.colour_, colour));
|
||||
Blockly.FieldColour.prototype.doClassValidation_ = function(newValue) {
|
||||
if (Blockly.FieldColour.COLOUR_REGEX.test(newValue)) {
|
||||
return newValue.toLowerCase();
|
||||
}
|
||||
this.colour_ = colour;
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the value of this colour field, and update the displayed colour.
|
||||
* @param {string} newValue The new colour in '#rrggbb' format.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldColour.prototype.doValueUpdate_ = function(newValue) {
|
||||
this.value_ = newValue;
|
||||
if (this.borderRect_) {
|
||||
this.borderRect_.style.fill = colour;
|
||||
this.borderRect_.style.fill = newValue;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the text from this field. Used when the block is collapsed.
|
||||
* @return {string} Current text.
|
||||
* Get the text for this field. Used when the block is collapsed.
|
||||
* @return {string} Text representing the value of this field.
|
||||
*/
|
||||
Blockly.FieldColour.prototype.getText = function() {
|
||||
var colour = this.colour_;
|
||||
var colour = this.value_;
|
||||
// Try to use #rgb format if possible, rather than #rrggbb.
|
||||
var m = colour.match(/^#(.)\1(.)\2(.)\3$/);
|
||||
if (m) {
|
||||
|
||||
@@ -40,21 +40,20 @@ goog.require('goog.ui.DatePicker');
|
||||
|
||||
/**
|
||||
* Class for a date input field.
|
||||
* @param {string=} opt_date The initial date, defaults to the current day.
|
||||
* @param {Function=} opt_validator A function that is executed when a new
|
||||
* date is selected. Its sole argument is the new date value. Its
|
||||
* return value becomes the selected date, unless it is undefined, in
|
||||
* which case the new date stands, or it is null, in which case the change
|
||||
* is aborted.
|
||||
* @param {string=} opt_value The initial value of the field. Should be in
|
||||
* 'YYYY-MM-DD' format. Defaults to the current date.
|
||||
* @param {Function=} opt_validator A function that is called to validate
|
||||
* changes to the field's value. Takes in a date string & returns a
|
||||
* validated date string ('YYYY-MM-DD' format), or null to abort the change.
|
||||
* @extends {Blockly.Field}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldDate = function(opt_date, opt_validator) {
|
||||
if (!opt_date) {
|
||||
opt_date = new goog.date.Date().toIsoString(true);
|
||||
Blockly.FieldDate = function(opt_value, opt_validator) {
|
||||
opt_value = this.doClassValidation_(opt_value);
|
||||
if (!opt_value) {
|
||||
opt_value = new goog.date.Date().toIsoString(true);
|
||||
}
|
||||
Blockly.FieldDate.superClass_.constructor.call(this, opt_date, opt_validator);
|
||||
this.setValue(opt_date);
|
||||
Blockly.FieldDate.superClass_.constructor.call(this, opt_value, opt_validator);
|
||||
};
|
||||
goog.inherits(Blockly.FieldDate, Blockly.Field);
|
||||
|
||||
@@ -91,28 +90,21 @@ Blockly.FieldDate.prototype.dispose = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the current date.
|
||||
* @return {string} Current date.
|
||||
* Ensure that the input value is a valid date.
|
||||
* @param {string=} newValue The input value.
|
||||
* @return {?string} A valid date, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldDate.prototype.getValue = function() {
|
||||
return this.date_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the date.
|
||||
* @param {string} date The new date.
|
||||
*/
|
||||
Blockly.FieldDate.prototype.setValue = function(date) {
|
||||
if (this.sourceBlock_) {
|
||||
var validated = this.callValidator(date);
|
||||
// If the new date is invalid, validation returns null.
|
||||
// In this case we still want to display the illegal result.
|
||||
if (validated !== null) {
|
||||
date = validated;
|
||||
}
|
||||
Blockly.FieldDate.prototype.doClassValidation_ = function(newValue) {
|
||||
if (!newValue) {
|
||||
return null;
|
||||
}
|
||||
this.date_ = date;
|
||||
Blockly.Field.prototype.setText.call(this, date);
|
||||
// Check if the new value is parsable or not.
|
||||
var date = goog.date.Date.fromIsoString(newValue);
|
||||
if (!date || date.toIsoString(true) != newValue) {
|
||||
return null;
|
||||
}
|
||||
return newValue;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -142,10 +134,6 @@ Blockly.FieldDate.prototype.showEditor_ = function() {
|
||||
function(event) {
|
||||
var date = event.date ? event.date.toIsoString(true) : '';
|
||||
Blockly.WidgetDiv.hide();
|
||||
if (thisField.sourceBlock_) {
|
||||
// Call any validation function, and allow it to override.
|
||||
date = thisField.callValidator(date);
|
||||
}
|
||||
thisField.setValue(date);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -42,11 +42,10 @@ goog.require('goog.ui.MenuItem');
|
||||
* Class for an editable dropdown field.
|
||||
* @param {(!Array.<!Array>|!Function)} menuGenerator An array of options
|
||||
* for a dropdown list, or a function which generates these options.
|
||||
* @param {Function=} opt_validator A function that is executed when a new
|
||||
* option is selected, with the newly selected value as its sole argument.
|
||||
* If it returns a value, that value (which must be one of the options) will
|
||||
* become selected in place of the newly selected option, unless the return
|
||||
* value is null, in which case the change is aborted.
|
||||
* @param {Function=} opt_validator A function that is called to validate
|
||||
* changes to the field's value. Takes in a language-neutral dropdown
|
||||
* option & returns a validated language-neutral dropdown option, or null to
|
||||
* abort the change.
|
||||
* @extends {Blockly.Field}
|
||||
* @constructor
|
||||
*/
|
||||
@@ -105,13 +104,6 @@ Blockly.FieldDropdown.ARROW_CHAR =
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.CURSOR = 'default';
|
||||
|
||||
/**
|
||||
* Language-neutral currently selected string or image object.
|
||||
* @type {string|!Object}
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.value_ = '';
|
||||
|
||||
/**
|
||||
* SVG image element if currently selected option is an image, or null.
|
||||
* @type {SVGElement}
|
||||
@@ -276,14 +268,7 @@ Blockly.FieldDropdown.prototype.getAnchorDimensions_ = function() {
|
||||
* @param {!goog.ui.MenuItem} menuItem The MenuItem selected within menu.
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.onItemSelected = function(menu, menuItem) {
|
||||
var value = menuItem.getValue();
|
||||
if (this.sourceBlock_) {
|
||||
// Call any validation function, and allow it to override.
|
||||
value = this.callValidator(value);
|
||||
}
|
||||
if (value !== null) {
|
||||
this.setValue(value);
|
||||
}
|
||||
this.setValue(menuItem.getValue());
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -386,32 +371,43 @@ Blockly.FieldDropdown.prototype.getOptions = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the language-neutral value from this dropdown menu.
|
||||
* @return {string} Current text.
|
||||
* Ensure that the input value is a valid language-neutral option.
|
||||
* @param {string=} newValue The input value.
|
||||
* @return {?string} A valid language-neutral option, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.getValue = function() {
|
||||
return this.value_;
|
||||
Blockly.FieldDropdown.prototype.doClassValidation_ = function(newValue) {
|
||||
var isValueValid = false;
|
||||
var options = this.getOptions();
|
||||
for (var i = 0, option; option = options[i]; i++) {
|
||||
// Options are tuples of human-readable text and language-neutral values.
|
||||
if (option[1] == newValue) {
|
||||
isValueValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isValueValid) {
|
||||
if (this.sourceBlock_) {
|
||||
console.warn('Cannot set the dropdown\'s value to an unavailable option.' +
|
||||
' Block type: ' + this.sourceBlock_.type + ', Field name: ' + this.name +
|
||||
', Value: ' + newValue);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return newValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the language-neutral value for this dropdown menu.
|
||||
* @param {string} newValue New value to set.
|
||||
* Update the value of this dropdown field.
|
||||
* @param {string} newValue The new language-enutral value.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.setValue = function(newValue) {
|
||||
if (newValue === null || (newValue === this.value_ && this.text_)) {
|
||||
return; // No change if null and text_ was initialized.
|
||||
}
|
||||
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
|
||||
Blockly.Events.fire(new Blockly.Events.BlockChange(
|
||||
this.sourceBlock_, 'field', this.name, this.value_, newValue));
|
||||
}
|
||||
this.value_ = newValue;
|
||||
// Look up and display the human-readable text.
|
||||
Blockly.FieldDropdown.prototype.doValueUpdate_ = function(newValue) {
|
||||
Blockly.FieldDropdown.superClass_.doValueUpdate_.call(this, newValue);
|
||||
var options = this.getOptions();
|
||||
for (var i = 0; i < options.length; i++) {
|
||||
// Options are tuples of human-readable text and language-neutral values.
|
||||
if (options[i][1] == newValue) {
|
||||
var content = options[i][0];
|
||||
for (var i = 0, option; option = options[i]; i++) {
|
||||
if (option[1] == this.value_) {
|
||||
var content = option[0];
|
||||
if (typeof content == 'object') {
|
||||
this.imageJson_ = content;
|
||||
this.text_ = content.alt;
|
||||
@@ -419,15 +415,8 @@ Blockly.FieldDropdown.prototype.setValue = function(newValue) {
|
||||
this.imageJson_ = null;
|
||||
this.text_ = content;
|
||||
}
|
||||
// Always rerender if either the value or the text has changed.
|
||||
this.forceRerender();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Value not found. Add it, maybe it will become valid once set
|
||||
// (like variable names).
|
||||
this.text_ = newValue;
|
||||
this.forceRerender();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,7 +34,7 @@ goog.require('goog.math.Size');
|
||||
|
||||
/**
|
||||
* Class for an image on a block.
|
||||
* @param {string=} src The URL of the image, defaults to an empty string.
|
||||
* @param {string=} src The URL of the image. Defaults to an empty string.
|
||||
* @param {!(string|number)} width Width of the image.
|
||||
* @param {!(string|number)} height Height of the image.
|
||||
* @param {string=} opt_alt Optional alt text for when block is collapsed.
|
||||
@@ -66,8 +66,8 @@ Blockly.FieldImage = function(src, width, height,
|
||||
|
||||
this.flipRtl_ = opt_flipRtl;
|
||||
this.tooltip_ = '';
|
||||
this.text_ = opt_alt || '';
|
||||
this.setValue(src || '');
|
||||
this.setText(opt_alt || '');
|
||||
|
||||
if (typeof opt_onClick == 'function') {
|
||||
this.clickHandler_ = opt_onClick;
|
||||
@@ -111,11 +111,12 @@ Blockly.FieldImage.prototype.initView = function() {
|
||||
'image',
|
||||
{
|
||||
'height': this.height_ + 'px',
|
||||
'width': this.width_ + 'px'
|
||||
'width': this.width_ + 'px',
|
||||
'alt': this.text_
|
||||
},
|
||||
this.fieldGroup_);
|
||||
this.setValue(this.src_);
|
||||
this.setText(this.text_);
|
||||
this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink',
|
||||
'xlink:href', this.value_);
|
||||
this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_);
|
||||
|
||||
if (this.tooltip_) {
|
||||
@@ -166,28 +167,28 @@ Blockly.FieldImage.prototype.setTooltip = function(newTip) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the source URL of this image.
|
||||
* @return {string} Current text.
|
||||
* @override
|
||||
* Ensure that the input value (the source URL) is a string.
|
||||
* @param {string=} newValue The input value
|
||||
* @return {?string} A string, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldImage.prototype.getValue = function() {
|
||||
return this.src_;
|
||||
Blockly.FieldImage.prototype.doClassValidation_ = function(newValue) {
|
||||
if (typeof newValue != 'string') {
|
||||
return null;
|
||||
}
|
||||
return newValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the source URL of this image.
|
||||
* @param {?string} src New source.
|
||||
* @override
|
||||
* Update the value of this image field, and update the displayed image.
|
||||
* @param {string} newValue The new image src.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldImage.prototype.setValue = function(src) {
|
||||
if (src === null) {
|
||||
// No change if null.
|
||||
return;
|
||||
}
|
||||
this.src_ = src;
|
||||
Blockly.FieldImage.prototype.doValueUpdate_ = function(newValue) {
|
||||
this.value_ = newValue;
|
||||
if (this.imageElement_) {
|
||||
this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink',
|
||||
'xlink:href', src || '');
|
||||
'xlink:href', this.value_ || '');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -220,22 +221,8 @@ Blockly.FieldImage.prototype.setText = function(alt) {
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldImage.prototype.render_ = function() {
|
||||
// NOP
|
||||
};
|
||||
|
||||
/**
|
||||
* Images are fixed width, no need to render even if forced.
|
||||
*/
|
||||
Blockly.FieldImage.prototype.forceRerender = function() {
|
||||
// NOP
|
||||
};
|
||||
|
||||
/**
|
||||
* Images are fixed width, no need to update.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldImage.prototype.updateWidth = function() {
|
||||
// NOP
|
||||
this.size_.width = this.width_;
|
||||
this.size_.height = this.height_ + 2 * Blockly.BlockSvg.INLINE_PADDING_Y;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,19 +36,20 @@ goog.require('goog.math.Size');
|
||||
|
||||
/**
|
||||
* Class for a non-editable, non-serializable text field.
|
||||
* @param {string=} text The initial content of the field, defaults to an
|
||||
* empty string.
|
||||
* @param {string=} opt_value The initial value of the field. Should cast to a
|
||||
* string. Defaults to an empty string if null or undefined.
|
||||
* @param {string=} opt_class Optional CSS class for the field's text.
|
||||
* @extends {Blockly.Field}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldLabel = function(text, opt_class) {
|
||||
Blockly.FieldLabel = function(opt_value, opt_class) {
|
||||
this.size_ = new goog.math.Size(0, 17.5);
|
||||
this.class_ = opt_class;
|
||||
if (text === null || text === undefined) {
|
||||
text = '';
|
||||
opt_value = this.doClassValidation_(opt_value);
|
||||
if (opt_value === null) {
|
||||
opt_value = '';
|
||||
}
|
||||
this.setValue(String(text));
|
||||
this.setValue(opt_value);
|
||||
this.tooltip_ = '';
|
||||
};
|
||||
goog.inherits(Blockly.FieldLabel, Blockly.Field);
|
||||
@@ -84,6 +85,8 @@ Blockly.FieldLabel.prototype.initView = function() {
|
||||
'class': 'blocklyText',
|
||||
'y': this.size_.height - 5
|
||||
}, this.fieldGroup_);
|
||||
var textNode = document.createTextNode('');
|
||||
this.textElement_.appendChild(textNode);
|
||||
if (this.class_) {
|
||||
Blockly.utils.addClass(this.textElement_, this.class_);
|
||||
}
|
||||
@@ -107,6 +110,19 @@ Blockly.FieldLabel.prototype.dispose = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensure that the input value casts to a valid string.
|
||||
* @param {string=} newValue The input value.
|
||||
* @return {?string} A valid string, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldLabel.prototype.doClassValidation_ = function(newValue) {
|
||||
if (newValue === null || newValue === undefined) {
|
||||
return null;
|
||||
}
|
||||
return String(newValue);
|
||||
};
|
||||
|
||||
/**
|
||||
* Change the tooltip text for this field.
|
||||
* @param {string|!Element} newTip Text for tooltip or a parent element to
|
||||
|
||||
@@ -33,14 +33,15 @@ goog.require('Blockly.utils');
|
||||
|
||||
/**
|
||||
* Class for a non-editable, serializable text field.
|
||||
* @param {!string} text The initial content of the field.
|
||||
* @param {*} opt_value The initial value of the field. Should cast to a
|
||||
* string. Defaults to an empty string if null or undefined.
|
||||
* @param {string=} opt_class Optional CSS class for the field's text.
|
||||
* @extends {Blockly.FieldLabel}
|
||||
* @constructor
|
||||
*
|
||||
*/
|
||||
Blockly.FieldLabelSerializable = function(text, opt_class) {
|
||||
Blockly.FieldLabelSerializable.superClass_.constructor.call(this, text,
|
||||
Blockly.FieldLabelSerializable = function(opt_value, opt_class) {
|
||||
Blockly.FieldLabelSerializable.superClass_.constructor.call(this, opt_value,
|
||||
opt_class);
|
||||
};
|
||||
goog.inherits(Blockly.FieldLabelSerializable, Blockly.FieldLabel);
|
||||
|
||||
@@ -31,22 +31,23 @@ goog.require('Blockly.FieldTextInput');
|
||||
|
||||
/**
|
||||
* Class for an editable number field.
|
||||
* @param {(string|number)=} opt_value The initial content of the field.
|
||||
* The value should cast to a number, and if it does not, '0' will be used.
|
||||
* @param {string|number=} opt_value The initial value of the field. Should cast
|
||||
* to a number. Defaults to 0.
|
||||
* @param {(string|number)=} opt_min Minimum value.
|
||||
* @param {(string|number)=} opt_max Maximum value.
|
||||
* @param {(string|number)=} opt_precision Precision for value.
|
||||
* @param {Function=} opt_validator An optional function that is called
|
||||
* to validate any constraints on what the user entered. Takes the new
|
||||
* text as an argument and returns either the accepted text, a replacement
|
||||
* text, or null to abort the change.
|
||||
* @extends {Blockly.FieldTextInput}
|
||||
* @param {Function=} opt_validator A function that is called to validate
|
||||
* changes to the field's value. Takes in a number & returns a validated
|
||||
* number, or null to abort the change.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldNumber = function(opt_value, opt_min, opt_max, opt_precision,
|
||||
opt_validator) {
|
||||
this.setConstraints(opt_min, opt_max, opt_precision);
|
||||
opt_value = (opt_value && !isNaN(opt_value)) ? String(opt_value) : '0';
|
||||
opt_value = this.doClassValidation_(opt_value);
|
||||
if (opt_value === null) {
|
||||
opt_value = 0;
|
||||
}
|
||||
Blockly.FieldNumber.superClass_.constructor.call(
|
||||
this, opt_value, opt_validator);
|
||||
};
|
||||
@@ -98,21 +99,26 @@ Blockly.FieldNumber.prototype.setConstraints = function(min, max, precision) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensure that only a number in the correct range may be entered.
|
||||
* @param {string} text The user's text.
|
||||
* @return {?string} A string representing a valid number, or null if invalid.
|
||||
* Ensure that the input value is a valid number (must fulfill the
|
||||
* constraints placed on the field).
|
||||
* @param {string|number=} newValue The input value.
|
||||
* @return {?number} A valid number, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.classValidator = function(text) {
|
||||
if (text === null) {
|
||||
Blockly.FieldNumber.prototype.doClassValidation_ = function(newValue) {
|
||||
if (newValue === null || newValue === undefined) {
|
||||
return null;
|
||||
}
|
||||
text = String(text);
|
||||
// Clean up text.
|
||||
newValue = String(newValue);
|
||||
// TODO: Handle cases like 'ten', '1.203,14', etc.
|
||||
// 'O' is sometimes mistaken for '0' by inexperienced users.
|
||||
text = text.replace(/O/ig, '0');
|
||||
newValue = newValue.replace(/O/ig, '0');
|
||||
// Strip out thousands separators.
|
||||
text = text.replace(/,/g, '');
|
||||
var n = parseFloat(text || 0);
|
||||
newValue = newValue.replace(/,/g, '');
|
||||
|
||||
// Clean up number.
|
||||
var n = parseFloat(newValue || 0);
|
||||
if (isNaN(n)) {
|
||||
// Invalid number.
|
||||
return null;
|
||||
@@ -123,8 +129,10 @@ Blockly.FieldNumber.prototype.classValidator = function(text) {
|
||||
if (this.precision_ && isFinite(n)) {
|
||||
n = Math.round(n / this.precision_) * this.precision_;
|
||||
}
|
||||
return (this.fractionalDigits_ == -1) ? String(n) :
|
||||
n.toFixed(this.fractionalDigits_);
|
||||
// Clean up floating point errors.
|
||||
n = (this.fractionalDigits_ == -1) ? n :
|
||||
Number(n.toFixed(this.fractionalDigits_));
|
||||
return n;
|
||||
};
|
||||
|
||||
Blockly.Field.register('field_number', Blockly.FieldNumber);
|
||||
|
||||
@@ -37,20 +37,20 @@ goog.require('goog.math.Coordinate');
|
||||
|
||||
/**
|
||||
* Class for an editable text field.
|
||||
* @param {string=} text The initial content of the field, defaults to an
|
||||
* empty string.
|
||||
* @param {Function=} opt_validator An optional function that is called
|
||||
* to validate any constraints on what the user entered. Takes the new
|
||||
* text as an argument and returns either the accepted text, a replacement
|
||||
* text, or null to abort the change.
|
||||
* @param {string=} opt_value The initial value of the field. Should cast to a
|
||||
* string. Defaults to an empty string if null or undefined.
|
||||
* @param {Function=} opt_validator A function that is called to validate
|
||||
* changes to the field's value. Takes in a string & returns a validated
|
||||
* string, or null to abort the change.
|
||||
* @extends {Blockly.Field}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.FieldTextInput = function(text, opt_validator) {
|
||||
if (text === null || text === undefined) {
|
||||
text = '';
|
||||
Blockly.FieldTextInput = function(opt_value, opt_validator) {
|
||||
opt_value = this.doClassValidation_(opt_value);
|
||||
if (opt_value === null) {
|
||||
opt_value = '';
|
||||
}
|
||||
Blockly.FieldTextInput.superClass_.constructor.call(this, String(text),
|
||||
Blockly.FieldTextInput.superClass_.constructor.call(this, opt_value,
|
||||
opt_validator);
|
||||
};
|
||||
goog.inherits(Blockly.FieldTextInput, Blockly.Field);
|
||||
@@ -114,43 +114,75 @@ Blockly.FieldTextInput.prototype.dispose = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the value of this field.
|
||||
* @param {?string} newValue New value.
|
||||
* @override
|
||||
* Ensure that the input value casts to a valid string.
|
||||
* @param {string=} newValue The input value.
|
||||
* @return {?string} A valid string, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.setValue = function(newValue) {
|
||||
if (newValue !== null) { // No change if null.
|
||||
if (this.sourceBlock_) {
|
||||
var validated = this.callValidator(newValue);
|
||||
// If the new value is invalid, validation returns null.
|
||||
// In this case we still want to display the illegal result.
|
||||
if (validated !== null) {
|
||||
newValue = validated;
|
||||
Blockly.FieldTextInput.prototype.doClassValidation_ = function(newValue) {
|
||||
if (newValue === null || newValue === undefined) {
|
||||
return null;
|
||||
}
|
||||
return String(newValue);
|
||||
};
|
||||
|
||||
/**
|
||||
* Called by setValue if the text input is not valid. If the field is
|
||||
* currently being edited it reverts value of the field to the previous
|
||||
* value while allowing the display text to be handled by the htmlInput_.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.doValueInvalid_ = function() {
|
||||
if (this.isBeingEdited_) {
|
||||
this.isTextValid_ = false;
|
||||
var htmlInput = Blockly.FieldTextInput.htmlInput_;
|
||||
if (htmlInput) {
|
||||
var oldValue = this.value_;
|
||||
// Revert value when the text becomes invalid.
|
||||
this.value_ = htmlInput.untypedDefaultValue_;
|
||||
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
|
||||
Blockly.Events.fire(new Blockly.Events.BlockChange(
|
||||
this.sourceBlock_, 'field', this.name, oldValue, this.value_));
|
||||
}
|
||||
}
|
||||
Blockly.Field.prototype.setValue.call(this, newValue);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the text in this field and fire a change event.
|
||||
* @param {*} newText New text.
|
||||
* Called by setValue if the text input is valid. Updates the value of the
|
||||
* field, and updates the text of the field if it is not currently being
|
||||
* edited (i.e. handled by the htmlInput_).
|
||||
* @param {!string} newValue The new validated value of the field.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.setText = function(newText) {
|
||||
if (newText === null) {
|
||||
// No change if null.
|
||||
return;
|
||||
Blockly.FieldTextInput.prototype.doValueUpdate_ = function(newValue) {
|
||||
this.isTextValid_ = true;
|
||||
this.value_ = newValue;
|
||||
if (!this.isBeingEdited_) {
|
||||
// This should only occur if setValue is triggered programmatically.
|
||||
this.text_ = String(newValue);
|
||||
this.isDirty_ = true;
|
||||
}
|
||||
newText = String(newText);
|
||||
if (newText === this.text_) {
|
||||
// No change.
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the colour of the htmlInput given the current validity of the
|
||||
* field's value.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.render_ = function() {
|
||||
Blockly.FieldTextInput.superClass_.render_.call(this);
|
||||
// This logic is done in render_ rather than doValueInvalid_ or
|
||||
// doValueUpdate_ so that the code is more centralized.
|
||||
if (this.isBeingEdited_) {
|
||||
var htmlInput = Blockly.FieldTextInput.htmlInput_;
|
||||
this.resizeEditor_();
|
||||
if (!this.isTextValid_) {
|
||||
Blockly.utils.addClass(htmlInput, 'blocklyInvalidInput');
|
||||
} else {
|
||||
Blockly.utils.removeClass(htmlInput, 'blocklyInvalidInput');
|
||||
}
|
||||
}
|
||||
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
|
||||
Blockly.Events.fire(new Blockly.Events.BlockChange(
|
||||
this.sourceBlock_, 'field', this.name, this.text_, newText));
|
||||
}
|
||||
Blockly.Field.prototype.setText.call(this, newText);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -188,9 +220,6 @@ Blockly.FieldTextInput.prototype.showPromptEditor_ = function() {
|
||||
var fieldText = this;
|
||||
Blockly.prompt(Blockly.Msg['CHANGE_VALUE_TITLE'], this.text_,
|
||||
function(newValue) {
|
||||
if (fieldText.sourceBlock_) {
|
||||
newValue = fieldText.callValidator(newValue);
|
||||
}
|
||||
fieldText.setValue(newValue);
|
||||
});
|
||||
};
|
||||
@@ -202,8 +231,13 @@ Blockly.FieldTextInput.prototype.showPromptEditor_ = function() {
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) {
|
||||
// Start editing.
|
||||
this.isBeingEdited_ = true;
|
||||
|
||||
// Show the div.
|
||||
Blockly.WidgetDiv.show(this, this.sourceBlock_.RTL, this.widgetDispose_());
|
||||
var div = Blockly.WidgetDiv.DIV;
|
||||
|
||||
// Create the input.
|
||||
var htmlInput = document.createElement('input');
|
||||
htmlInput.className = 'blocklyHtmlInput';
|
||||
@@ -212,20 +246,25 @@ Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) {
|
||||
(Blockly.FieldTextInput.FONTSIZE * this.workspace_.scale) + 'pt';
|
||||
div.style.fontSize = fontSize;
|
||||
htmlInput.style.fontSize = fontSize;
|
||||
|
||||
Blockly.FieldTextInput.htmlInput_ = htmlInput;
|
||||
div.appendChild(htmlInput);
|
||||
|
||||
htmlInput.value = htmlInput.defaultValue = this.text_;
|
||||
// Assign the current value to the input & resize.
|
||||
htmlInput.value = htmlInput.defaultValue = this.value_;
|
||||
htmlInput.untypedDefaultValue_ = this.value_;
|
||||
htmlInput.oldValue_ = null;
|
||||
this.validate_();
|
||||
this.resizeEditor_();
|
||||
|
||||
// Give it focus.
|
||||
if (!quietInput) {
|
||||
htmlInput.focus();
|
||||
htmlInput.select();
|
||||
}
|
||||
|
||||
// Bind events.
|
||||
this.bindEvents_(htmlInput);
|
||||
|
||||
// Save it.
|
||||
Blockly.FieldTextInput.htmlInput_ = htmlInput;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -239,7 +278,7 @@ Blockly.FieldTextInput.prototype.bindEvents_ = function(htmlInput) {
|
||||
htmlInput.onKeyDownWrapper_ =
|
||||
Blockly.bindEventWithChecks_(
|
||||
htmlInput, 'keydown', this, this.onHtmlInputKeyDown_);
|
||||
// Bind to keyup -- trap Enter; resize after every keystroke.
|
||||
// Bind to keyup -- resize after every keystroke.
|
||||
htmlInput.onKeyUpWrapper_ =
|
||||
Blockly.bindEventWithChecks_(
|
||||
htmlInput, 'keyup', this, this.onHtmlInputChange_);
|
||||
@@ -294,7 +333,6 @@ Blockly.FieldTextInput.prototype.onHtmlInputKeyDown_ = function(e) {
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.onHtmlInputChange_ = function(_e) {
|
||||
var htmlInput = Blockly.FieldTextInput.htmlInput_;
|
||||
// Update source block.
|
||||
var text = htmlInput.value;
|
||||
if (text !== htmlInput.oldValue_) {
|
||||
htmlInput.oldValue_ = text;
|
||||
@@ -304,40 +342,15 @@ Blockly.FieldTextInput.prototype.onHtmlInputChange_ = function(_e) {
|
||||
// broader fix for all field types.
|
||||
Blockly.Events.setGroup(true);
|
||||
this.setValue(text);
|
||||
// Always render the input text.
|
||||
this.text_ = Blockly.FieldTextInput.htmlInput_.value;
|
||||
this.forceRerender();
|
||||
Blockly.Events.setGroup(false);
|
||||
this.validate_();
|
||||
} else if (Blockly.userAgent.WEBKIT) {
|
||||
// Cursor key. Render the source block to show the caret moving.
|
||||
// Chrome only (version 26, OS X).
|
||||
this.sourceBlock_.render();
|
||||
}
|
||||
this.resizeEditor_();
|
||||
Blockly.svgResize(this.sourceBlock_.workspace);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check to see if the contents of the editor validates.
|
||||
* Style the editor accordingly.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.validate_ = function() {
|
||||
var valid = true;
|
||||
if (!Blockly.FieldTextInput.htmlInput_) {
|
||||
throw Error('htmlInput not defined');
|
||||
}
|
||||
var htmlInput = Blockly.FieldTextInput.htmlInput_;
|
||||
if (this.sourceBlock_) {
|
||||
valid = this.callValidator(htmlInput.value);
|
||||
}
|
||||
if (valid === null) {
|
||||
Blockly.utils.addClass(htmlInput, 'blocklyInvalidInput');
|
||||
} else {
|
||||
Blockly.utils.removeClass(htmlInput, 'blocklyInvalidInput');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Resize the editor and the underlying block to fit the text.
|
||||
* Resize the editor to fit the text.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.resizeEditor_ = function() {
|
||||
@@ -376,12 +389,30 @@ Blockly.FieldTextInput.prototype.widgetDispose_ = function() {
|
||||
var thisField = this;
|
||||
return function() {
|
||||
var htmlInput = Blockly.FieldTextInput.htmlInput_;
|
||||
// Save the edit (if it validates).
|
||||
thisField.maybeSaveEdit_();
|
||||
|
||||
// Finalize value.
|
||||
thisField.isBeingEdited_ = false;
|
||||
// No need to call setValue because if the widget is being closed the
|
||||
// latest input text has already been validated.
|
||||
if (thisField.value_ != thisField.text_) {
|
||||
// At the end of an edit the text should be the same as the value. It
|
||||
// may not be if the input text is different than the validated text.
|
||||
// We should fix that.
|
||||
thisField.text_ = String(thisField.value_);
|
||||
thisField.isTextValid_ = true;
|
||||
thisField.forceRerender();
|
||||
}
|
||||
// Otherwise don't rerender.
|
||||
|
||||
// Call onFinishEditing
|
||||
// TODO: Get rid of this or make it less of a hack.
|
||||
if (thisField.onFinishEditing_) {
|
||||
thisField.onFinishEditing_(thisField.value_);
|
||||
}
|
||||
|
||||
// Remove htmlInput.
|
||||
thisField.unbindEvents_(htmlInput);
|
||||
Blockly.FieldTextInput.htmlInput_ = null;
|
||||
Blockly.Events.setGroup(false);
|
||||
|
||||
// Delete style properties.
|
||||
var style = Blockly.WidgetDiv.DIV.style;
|
||||
@@ -391,36 +422,11 @@ Blockly.FieldTextInput.prototype.widgetDispose_ = function() {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempt to save the text field changes when the user input loses focus.
|
||||
* If the value is not valid, revert to the default value.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.maybeSaveEdit_ = function() {
|
||||
var htmlInput = Blockly.FieldTextInput.htmlInput_;
|
||||
// Save the edit (if it validates).
|
||||
var text = htmlInput.value;
|
||||
if (this.sourceBlock_) {
|
||||
var text1 = this.callValidator(text);
|
||||
if (text1 === null) {
|
||||
// Invalid edit.
|
||||
text = htmlInput.defaultValue;
|
||||
} else {
|
||||
// Validation function has changed the text.
|
||||
text = text1;
|
||||
if (this.onFinishEditing_) {
|
||||
this.onFinishEditing_(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setText(text);
|
||||
this.sourceBlock_.rendered && this.sourceBlock_.render();
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensure that only a number may be entered.
|
||||
* @param {string} text The user's text.
|
||||
* @return {?string} A string representing a valid number, or null if invalid.
|
||||
* @deprecated
|
||||
*/
|
||||
Blockly.FieldTextInput.numberValidator = function(text) {
|
||||
console.warn('Blockly.FieldTextInput.numberValidator is deprecated. ' +
|
||||
@@ -442,6 +448,7 @@ Blockly.FieldTextInput.numberValidator = function(text) {
|
||||
* Ensure that only a nonnegative integer may be entered.
|
||||
* @param {string} text The user's text.
|
||||
* @return {?string} A string representing a valid int, or null if invalid.
|
||||
* @deprecated
|
||||
*/
|
||||
Blockly.FieldTextInput.nonnegativeIntegerValidator = function(text) {
|
||||
var n = Blockly.FieldTextInput.numberValidator(text);
|
||||
|
||||
@@ -39,8 +39,9 @@ goog.require('goog.math.Size');
|
||||
* Class for a variable's dropdown field.
|
||||
* @param {?string} varname The default name for the variable. If null,
|
||||
* a unique variable name will be generated.
|
||||
* @param {Function=} opt_validator A function that is executed when a new
|
||||
* option is selected. Its sole argument is the new option value.
|
||||
* @param {Function=} opt_validator A function that is called to validate
|
||||
* changes to the field's value. Takes in a variable ID & returns a
|
||||
* validated variable ID, or null to abort the change.
|
||||
* @param {Array.<string>=} opt_variableTypes A list of the types of variables
|
||||
* to include in the dropdown.
|
||||
* @param {string=} opt_defaultType The type of variable to create if this
|
||||
@@ -78,6 +79,13 @@ Blockly.FieldVariable.fromJson = function(options) {
|
||||
return new Blockly.FieldVariable(varname, null, variableTypes, defaultType);
|
||||
};
|
||||
|
||||
/**
|
||||
* The workspace that this variable field belongs to.
|
||||
* @type {?Blockly.Workspace}
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.workspace_ = null;
|
||||
|
||||
/**
|
||||
* Serializable fields are saved by the XML renderer, non-serializable fields
|
||||
* are not. Editable fields should also be serializable.
|
||||
@@ -96,28 +104,28 @@ Blockly.FieldVariable.prototype.initModel = function() {
|
||||
if (this.variable_) {
|
||||
return; // Initialization already happened.
|
||||
}
|
||||
this.workspace_ = this.sourceBlock_.workspace;
|
||||
var variable = Blockly.Variables.getOrCreateVariablePackage(
|
||||
this.workspace_, null, this.defaultVariableName, this.defaultType_);
|
||||
|
||||
// Don't fire a change event for this setValue. It would have null as the
|
||||
// old value, which is not valid.
|
||||
Blockly.Events.disable();
|
||||
try {
|
||||
this.setValue(variable.getId());
|
||||
} finally {
|
||||
Blockly.Events.enable();
|
||||
}
|
||||
this.setValue(variable.getId());
|
||||
Blockly.Events.enable();
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize this field based on the given XML.
|
||||
* @param {!Element} fieldElement The element containing information about the
|
||||
* variable field's state.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.fromXml = function(fieldElement) {
|
||||
var id = fieldElement.getAttribute('id');
|
||||
var variableName = fieldElement.textContent;
|
||||
var variableType = fieldElement.getAttribute('variabletype') || '';
|
||||
|
||||
var variable = Blockly.Variables.getOrCreateVariablePackage(
|
||||
this.workspace_ || this.sourceBlock_.workspace, id,
|
||||
variableName, variableType);
|
||||
this.workspace_, id, variableName, variableType);
|
||||
|
||||
// This should never happen :)
|
||||
if (variableType != null && variableType !== variable.type) {
|
||||
@@ -130,6 +138,12 @@ Blockly.FieldVariable.prototype.fromXml = function(fieldElement) {
|
||||
this.setValue(variable.getId());
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize this field to Xml.
|
||||
* @param {!Element} fieldElement The element to populate with info about the
|
||||
* field's state.
|
||||
* @return {!Element} The element containing info about the field's state.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.toXml = function(fieldElement) {
|
||||
// Make sure the variable is initialized.
|
||||
this.initModel();
|
||||
@@ -160,6 +174,7 @@ Blockly.FieldVariable.prototype.setSourceBlock = function(block) {
|
||||
throw Error('Variable fields are not allowed to exist on shadow blocks.');
|
||||
}
|
||||
Blockly.FieldVariable.superClass_.setSourceBlock.call(this, block);
|
||||
this.workspace_ = block.workspace;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -192,30 +207,57 @@ Blockly.FieldVariable.prototype.getVariable = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the variable ID.
|
||||
* @param {string} id New variable ID, which must reference an existing
|
||||
* variable.
|
||||
* Gets the validation function for this field, or null if not set.
|
||||
* Returns null if the variable is not set, because validators should not
|
||||
* run on the initial setValue call, because the field won't be attached to
|
||||
* a block and workspace at that point.
|
||||
* @return {Function} Validation function, or null.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.setValue = function(id) {
|
||||
var workspace = this.sourceBlock_.workspace;
|
||||
var variable = Blockly.Variables.getVariable(workspace, id);
|
||||
|
||||
if (!variable) {
|
||||
throw Error('Variable id doesn\'t point to a real variable! ID was ' + id);
|
||||
Blockly.FieldVariable.prototype.getValidator = function() {
|
||||
// Validators shouldn't operate on the initial setValue call.
|
||||
// Normally this is achieved by calling setValidator after setValue, but
|
||||
// this is not a possibility with variable fields.
|
||||
if (this.variable_) {
|
||||
return this.validator_;
|
||||
}
|
||||
// Type checks!
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensure that the id belongs to a valid variable of an allowed type.
|
||||
* @param {string} newId The id of the new variable to set.
|
||||
* @return {?string} The validated id, or null if invalid.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.doClassValidation_ = function(newId) {
|
||||
var variable = Blockly.Variables.getVariable(this.workspace_, newId);
|
||||
if (!variable) {
|
||||
console.warn('Variable id doesn\'t point to a real variable! ' +
|
||||
'ID was ' + newId);
|
||||
return null;
|
||||
}
|
||||
// Type Checks.
|
||||
var type = variable.type;
|
||||
if (!this.typeIsAllowed_(type)) {
|
||||
throw Error('Variable type doesn\'t match this field! Type was ' + type);
|
||||
console.warn('Variable type doesn\'t match this field! Type was ' + type);
|
||||
return null;
|
||||
}
|
||||
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
|
||||
var oldValue = this.variable_ ? this.variable_.getId() : null;
|
||||
Blockly.Events.fire(new Blockly.Events.BlockChange(
|
||||
this.sourceBlock_, 'field', this.name, oldValue, id));
|
||||
}
|
||||
this.variable_ = variable;
|
||||
this.value_ = id;
|
||||
this.setText(variable.name);
|
||||
return newId;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the value of this variable field, as well as its variable and text.
|
||||
*
|
||||
* The variable ID should be valid at this point, but if a variable field
|
||||
* validator returns a bad ID, this could break.
|
||||
* @param {string} newId The id of the new variable.
|
||||
* @protected
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.doValueUpdate_ = function(newId) {
|
||||
this.variable_ = Blockly.Variables.getVariable(this.workspace_, newId);
|
||||
this.value_ = newId;
|
||||
this.text_ = (this.variable_.name);
|
||||
this.isDirty_ = true;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -248,9 +290,8 @@ Blockly.FieldVariable.prototype.getVariableTypes_ = function() {
|
||||
var variableTypes = this.variableTypes;
|
||||
if (variableTypes === null) {
|
||||
// If variableTypes is null, return all variable types.
|
||||
if (this.sourceBlock_) {
|
||||
var workspace = this.sourceBlock_.workspace;
|
||||
return workspace.getVariableTypes();
|
||||
if (this.workspace_) {
|
||||
return this.workspace_.getVariableTypes();
|
||||
}
|
||||
}
|
||||
variableTypes = variableTypes || [''];
|
||||
@@ -315,18 +356,14 @@ Blockly.FieldVariable.dropdownCreate = function() {
|
||||
' variable selected.');
|
||||
}
|
||||
var name = this.getText();
|
||||
var workspace = null;
|
||||
if (this.sourceBlock_) {
|
||||
workspace = this.sourceBlock_.workspace;
|
||||
}
|
||||
var variableModelList = [];
|
||||
if (workspace) {
|
||||
if (this.workspace_) {
|
||||
var variableTypes = this.getVariableTypes_();
|
||||
// Get a copy of the list, so that adding rename and new variable options
|
||||
// doesn't modify the workspace's list.
|
||||
for (var i = 0; i < variableTypes.length; i++) {
|
||||
var variableType = variableTypes[i];
|
||||
var variables = workspace.getVariablesOfType(variableType);
|
||||
var variables = this.workspace_.getVariablesOfType(variableType);
|
||||
variableModelList = variableModelList.concat(variables);
|
||||
}
|
||||
}
|
||||
@@ -359,20 +396,19 @@ Blockly.FieldVariable.dropdownCreate = function() {
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.onItemSelected = function(menu, menuItem) {
|
||||
var id = menuItem.getValue();
|
||||
if (this.sourceBlock_ && this.sourceBlock_.workspace) {
|
||||
var workspace = this.sourceBlock_.workspace;
|
||||
// Handle special cases.
|
||||
if (this.workspace_) {
|
||||
if (id == Blockly.RENAME_VARIABLE_ID) {
|
||||
// Rename variable.
|
||||
Blockly.Variables.renameVariable(workspace, this.variable_);
|
||||
Blockly.Variables.renameVariable(this.workspace_, this.variable_);
|
||||
return;
|
||||
} else if (id == Blockly.DELETE_VARIABLE_ID) {
|
||||
// Delete variable.
|
||||
workspace.deleteVariableById(this.variable_.getId());
|
||||
this.workspace_.deleteVariableById(this.variable_.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO (#1529): Call any validation function, and allow it to override.
|
||||
}
|
||||
// Handle unspecial case.
|
||||
this.setValue(id);
|
||||
};
|
||||
|
||||
|
||||
@@ -263,6 +263,21 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
"tooltip": "",
|
||||
"helpUrl": ""
|
||||
},
|
||||
{
|
||||
"type": "test_fields_image",
|
||||
"message0": "image %1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_image",
|
||||
"name": "IMAGE",
|
||||
"src": "https://blockly-demo.appspot.com/static/tests/media/a.png",
|
||||
"width": 32,
|
||||
"height": 32,
|
||||
"alt": "A"
|
||||
}
|
||||
],
|
||||
"colour": 230
|
||||
},
|
||||
{
|
||||
"type": "test_numbers_float",
|
||||
"message0": "float %1",
|
||||
@@ -670,6 +685,420 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
}
|
||||
]); // END JSON EXTRACT (Do not delete this comment.)
|
||||
|
||||
Blockly.Blocks['test_validators_text_null'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("always null")
|
||||
.appendField(new Blockly.FieldTextInput("default", this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('All input validates to null (invalid). The display' +
|
||||
' text will remain the input text, but the value should be the default' +
|
||||
' text. The input should be red after the first keystroke.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['test_validators_text_A'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("remove \'a\'")
|
||||
.appendField(new Blockly.FieldTextInput("default", this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('All \'a\' characters are removed from field value.' +
|
||||
' The display text will include invalid \'a\' characters while the' +
|
||||
' field is being edited, but the value will not.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
return newValue.replace(/\a/g, '');
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['test_validators_text_B'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("\'b\' -> null")
|
||||
.appendField(new Blockly.FieldTextInput("default", this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('Upon detecting a \'b\' character the input will' +
|
||||
' validated to null (invalid). Upon removal it should revert to being' +
|
||||
' valid. The display text will remain the input text, but if the input' +
|
||||
' text is invalid the value should be the default text.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
if (newValue.indexOf('b') != -1) {
|
||||
return null;
|
||||
}
|
||||
return newValue;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['test_validators_angle_null'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("always null")
|
||||
.appendField(new Blockly.FieldAngle(90, this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('All input validates to null (invalid). The field' +
|
||||
' will display the input while the field is being edited (this' +
|
||||
' includes the text and the graphic), but the value should be the' +
|
||||
' default value. The input should be red after the first' +
|
||||
' keystroke.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['test_validators_angle_mult30_force'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("force mult of 30")
|
||||
.appendField(new Blockly.FieldAngle(90, this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('The input value will be rounded to the nearest' +
|
||||
' multiple of 30. The field will display the input while the field is' +
|
||||
' being edited (this includes the text and the graphic), but the value' +
|
||||
' will be the validated (rounded) value. Note: If you want to do' +
|
||||
' rounding this is not the proper way, use the ROUND property of the' +
|
||||
' field angle instead.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
return Math.round(newValue / 30) * 30;
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['test_validators_angle_mult30_null'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("not mult of 30 -> null")
|
||||
.appendField(new Blockly.FieldAngle(90, this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('If the input value is not a multiple of 30, the' +
|
||||
' input will validated to null (invalid). The field will display the' +
|
||||
' input while the field is being edited (this includes the text and' +
|
||||
' the graphic), but if the input value is invalid the value should be' +
|
||||
' the default value.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
if (newValue % 30 != 0) {
|
||||
return null;
|
||||
}
|
||||
return newValue;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['test_validators_checkbox_null'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("always null")
|
||||
.appendField(new Blockly.FieldCheckbox(true, this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('The new input always validates to null (invalid).' +
|
||||
' This means that the field value should not change.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['test_validators_checkbox_match'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("force match")
|
||||
.appendField(new Blockly.FieldCheckbox(true), "MATCH")
|
||||
.appendField(new Blockly.FieldCheckbox(true, this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('The validator for this block only works on the' +
|
||||
' end-most checkbox. The validator will always return the value of the' +
|
||||
' start-most checkbox. Therefor they should always match.')
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
return this.sourceBlock_.getFieldValue('MATCH');
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['test_validators_checkbox_not_match_null'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("not match -> null")
|
||||
.appendField(new Blockly.FieldCheckbox(true), "MATCH")
|
||||
.appendField(new Blockly.FieldCheckbox(true, this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('The validator for this block only works on the' +
|
||||
' end-most checkbox. If the new value does not match the value of the' +
|
||||
' start-most checkbox, it will return null (invalid), which means the' +
|
||||
' field value should not change. Therfore they should always match.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
if (this.sourceBlock_.getFieldValue('MATCH') != newValue) {
|
||||
return null;
|
||||
}
|
||||
return newValue;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['test_validators_colour_null'] = {
|
||||
init: function() {
|
||||
var colourField = new Blockly.FieldColour('#ff0000', this.validate);
|
||||
colourField.setColours([
|
||||
'#ffffff', '#ffdcdc', '#ffb4b4','#ff8c8c','#ff6464','#ff3c3c','#ff1414',
|
||||
'#00ffff', '#00dcdc', '#00b4b4','#008c8c','#006464','#003c3c','#001414']);
|
||||
|
||||
this.appendDummyInput()
|
||||
.appendField("always null")
|
||||
.appendField(colourField, "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('All input validates to null (invalid). This means' +
|
||||
' the field value should not change.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['test_validators_colour_force_red'] = {
|
||||
init: function() {
|
||||
var colourField = new Blockly.FieldColour('#ff0000', this.validate);
|
||||
colourField.setColours([
|
||||
'#ffffff', '#ffdcdc', '#ffb4b4','#ff8c8c','#ff6464','#ff3c3c','#ff1414',
|
||||
'#00ffff', '#00dcdc', '#00b4b4','#008c8c','#006464','#003c3c','#001414']);
|
||||
|
||||
this.appendDummyInput()
|
||||
.appendField("force full red")
|
||||
.appendField(colourField, "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('The input will have its red value replaced with' +
|
||||
' full red.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
return '#ff' + newValue.substr(3, 4);
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['test_validators_colour_red_null'] = {
|
||||
init: function() {
|
||||
var colourField = new Blockly.FieldColour('#ff0000', this.validate);
|
||||
colourField.setColours([
|
||||
'#ffffff', '#ffdcdc', '#ffb4b4','#ff8c8c','#ff6464','#ff3c3c','#ff1414',
|
||||
'#00ffff', '#00dcdc', '#00b4b4','#008c8c','#006464','#003c3c','#001414']);
|
||||
|
||||
this.appendDummyInput()
|
||||
.appendField("not red -> null")
|
||||
.appendField(colourField, "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('If the input does not have full red, the input will' +
|
||||
' validate to null (invalid). Otherwise it will return the input value');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
if (newValue.substr(1, 2) != 'ff') {
|
||||
return null;
|
||||
}
|
||||
return newValue;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['test_validators_date_null'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("always null")
|
||||
.appendField(new Blockly.FieldDate("2020-02-20", this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('All input validates to null (invalid). This means' +
|
||||
' the field value should not change.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['test_validators_date_force_20s'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("force day 20s")
|
||||
.appendField(new Blockly.FieldDate("2020-02-20", this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('The input\'s date will change to always be in the' +
|
||||
' 20s.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
return newValue.substr(0, 8) + '2' + newValue.substr(9, 1);
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['test_validators_date_20s_null'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("not 20s -> null")
|
||||
.appendField(new Blockly.FieldDate("2020-02-20", this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('If the input is not in the 20s, the input will' +
|
||||
' validate to null (invalid). Otherwise it will return the input value.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
if (newValue.charAt(8) != '2') {
|
||||
return null;
|
||||
}
|
||||
return newValue;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['test_validators_dropdown_null'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("always null")
|
||||
.appendField(new Blockly.FieldDropdown([
|
||||
["1a","1A"], ["1b","1B"], ["1c","1C"],
|
||||
["2a","2A"], ["2b","2B"], ["2c","2C"]], this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('All input validates to null (invalid). This means' +
|
||||
' the field value should not change.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['test_validators_dropdown_force_1s'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("force 1s")
|
||||
.appendField(new Blockly.FieldDropdown([
|
||||
["1a","1A"], ["1b","1B"], ["1c","1C"],
|
||||
["2a","2A"], ["2b","2B"], ["2c","2C"]], this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('The input\'s value will always change to start with' +
|
||||
' 1.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
return '1' + newValue.charAt(1);
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['test_validators_dropdown_1s_null'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("not 1s -> null")
|
||||
.appendField(new Blockly.FieldDropdown([
|
||||
["1a","1A"], ["1b","1B"], ["1c","1C"],
|
||||
["2a","2A"], ["2b","2B"], ["2c","2C"]], this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('If the input does not start with 1, the input will' +
|
||||
' validate to null (invalid). Otherwise it will return the input value.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
if (newValue.charAt(0) != '1') {
|
||||
return null;
|
||||
}
|
||||
return newValue;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['test_validators_number_null'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("always null")
|
||||
.appendField(new Blockly.FieldNumber(123, null, null, null, this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('All input validates to null (invalid). The field' +
|
||||
' will display the input while the field is being edited, but the value' +
|
||||
' should be the default value. The input should be red after the first' +
|
||||
' keystroke.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['test_validators_number_mult10_force'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("force mult of 10")
|
||||
.appendField(new Blockly.FieldNumber(123, null, null, null, this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('Theinput value will be rounded to the nearest' +
|
||||
' multiple of 10. The field will display the input while the field is' +
|
||||
' being edited, but the value should be the validated (rounded) value.' +
|
||||
' Note: If you want to do rounding this is not the proper way, use the' +
|
||||
' precision option of the number field constructor instead.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
return Math.round(newValue / 10) * 10;
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['test_validators_number_mult10_null'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("not mult of 10 -> null")
|
||||
.appendField(new Blockly.FieldNumber(123, null, null, null, this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('If the input value is not a multiple of 10, the' +
|
||||
' input will validate to null (invalid). The field will display the' +
|
||||
' input while the field is being edited, but if the input value is' +
|
||||
' invalid the value should be the default value.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
if (newValue % 10 != 0) {
|
||||
return null;
|
||||
}
|
||||
return newValue;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['test_validators_variable_null'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("always null")
|
||||
.appendField(new Blockly.FieldVariable('1a', this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('All ids validate to null (invalid). This means' +
|
||||
' the variable should not change.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['test_validators_variable_force_1s'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("force 1s")
|
||||
.appendField(new Blockly.FieldVariable('1a', this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('The id will always change to start with 1.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
return '1' + newValue.charAt(1);
|
||||
}
|
||||
};
|
||||
Blockly.Blocks['test_validators_variable_1s_null'] = {
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField("not 1s -> null")
|
||||
.appendField(new Blockly.FieldVariable('1a', this.validate), "INPUT");
|
||||
this.setColour(230);
|
||||
this.setCommentText('If the id does not start with 1, the id will' +
|
||||
' validate to null (invalid). Otherwise it will return the id.');
|
||||
},
|
||||
|
||||
validate: function(newValue) {
|
||||
if (newValue.charAt(0) != '1') {
|
||||
return null;
|
||||
}
|
||||
return newValue;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['test_basic_empty_with_mutator'] = {
|
||||
init: function() {
|
||||
this.setMutator(new Blockly.Mutator(['math_number']));
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2017 Google Inc.
|
||||
* https://developers.google.com/blockly/
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Tests for Blockly.FieldAngle
|
||||
* @author Anm@anm.me (Andrew n marshall)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
function test_fieldangle_constructor() {
|
||||
assertEquals(new Blockly.FieldAngle().getValue(), '0');
|
||||
assertEquals(new Blockly.FieldAngle(null).getValue(), '0');
|
||||
assertEquals(new Blockly.FieldAngle(undefined).getValue(), '0');
|
||||
assertEquals(new Blockly.FieldAngle(1).getValue(), '1');
|
||||
assertEquals(new Blockly.FieldAngle(1.5).getValue(), '1.5');
|
||||
assertEquals(new Blockly.FieldAngle('2').getValue(), '2');
|
||||
assertEquals(new Blockly.FieldAngle('2.5').getValue(), '2.5');
|
||||
|
||||
// Bad values
|
||||
assertEquals(new Blockly.FieldAngle('bad').getValue(), '0');
|
||||
assertEquals(new Blockly.FieldAngle(NaN).getValue(), '0');
|
||||
}
|
||||
|
||||
function test_fieldangle_fromJson() {
|
||||
assertEquals(Blockly.FieldAngle.fromJson({}).getValue(), '0');
|
||||
assertEquals(Blockly.FieldAngle.fromJson({ angle: 1 }).getValue(), '1');
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2017 Google Inc.
|
||||
* https://developers.google.com/blockly/
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Tests for Blockly.FieldNumber
|
||||
* @author Anm@anm.me (Andrew n marshall)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
function test_fieldnumber_constructor() {
|
||||
// No arguments
|
||||
var field = new Blockly.FieldNumber();
|
||||
assertEquals(field.getValue(), '0');
|
||||
assertEquals(field.min_, -Infinity);
|
||||
assertEquals(field.max_, Infinity);
|
||||
assertEquals(field.precision_, 0);
|
||||
|
||||
// Numeric values
|
||||
field = new Blockly.FieldNumber(1);
|
||||
assertEquals(field.getValue(), '1');
|
||||
field = new Blockly.FieldNumber(1.5);
|
||||
assertEquals(field.getValue(), '1.5');
|
||||
|
||||
// String value
|
||||
field = new Blockly.FieldNumber('2');
|
||||
assertEquals(field.getValue(), '2');
|
||||
field = new Blockly.FieldNumber('2.5');
|
||||
assertEquals(field.getValue(), '2.5');
|
||||
|
||||
// All values
|
||||
field = new Blockly.FieldNumber(
|
||||
/* value */ 0,
|
||||
/* min */ -128,
|
||||
/* max */ 127,
|
||||
/* precision */ 1);
|
||||
assertEquals(field.getValue(), '0');
|
||||
assertEquals(field.min_, -128);
|
||||
assertEquals(field.max_, 127);
|
||||
assertEquals(field.precision_, 1);
|
||||
|
||||
// Bad value defaults to '0'
|
||||
field = new Blockly.FieldNumber('bad');
|
||||
assertEquals(field.getValue(), '0');
|
||||
field = new Blockly.FieldNumber(NaN);
|
||||
assertEquals(field.getValue(), '0');
|
||||
}
|
||||
|
||||
function test_fieldnumber_fromJson() {
|
||||
assertEquals(Blockly.FieldNumber.fromJson({}).getValue(), '0');
|
||||
assertEquals(Blockly.FieldNumber.fromJson({ value: 1 }).getValue(), '1');
|
||||
|
||||
// All options
|
||||
var field = Blockly.FieldNumber.fromJson({
|
||||
value: 0,
|
||||
min: -128,
|
||||
max: 127,
|
||||
precision: 1
|
||||
});
|
||||
assertEquals(field.getValue(), '0');
|
||||
assertEquals(field.min_, -128);
|
||||
assertEquals(field.max_, 127);
|
||||
assertEquals(field.precision_, 1);
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2017 Google Inc.
|
||||
* https://developers.google.com/blockly/
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Tests for Blockly.FieldVariable
|
||||
* @author marisaleung@google.com (Marisa Leung)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.require('goog.testing');
|
||||
goog.require('goog.testing.MockControl');
|
||||
|
||||
var workspace;
|
||||
var mockControl_;
|
||||
|
||||
function fieldVariableTestWithMocks_setUp() {
|
||||
workspace = new Blockly.Workspace();
|
||||
mockControl_ = new goog.testing.MockControl();
|
||||
}
|
||||
|
||||
function fieldVariableTestWithMocks_tearDown() {
|
||||
mockControl_.$tearDown();
|
||||
workspace.dispose();
|
||||
}
|
||||
|
||||
function fieldVariable_mockBlock(workspace) {
|
||||
return {'workspace': workspace, 'isShadow': function(){return false;}};
|
||||
}
|
||||
|
||||
function fieldVariable_createAndInitField(workspace) {
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
var mockBlock = fieldVariable_mockBlock(workspace);
|
||||
fieldVariable.setSourceBlock(mockBlock);
|
||||
// No view to initialize, but the model still needs work.
|
||||
fieldVariable.initModel();
|
||||
return fieldVariable;
|
||||
}
|
||||
|
||||
function test_fieldVariable_Constructor() {
|
||||
workspace = new Blockly.Workspace();
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
// The field does not have a variable until after init() is called.
|
||||
assertEquals('', fieldVariable.getText());
|
||||
workspace.dispose();
|
||||
}
|
||||
|
||||
function test_fieldVariable_setValueMatchId() {
|
||||
// Expect the fieldVariable value to be set to variable name
|
||||
fieldVariableTestWithMocks_setUp();
|
||||
workspace.createVariable('name2', null, 'id2');
|
||||
|
||||
var fieldVariable = fieldVariable_createAndInitField(workspace);
|
||||
|
||||
var oldId = fieldVariable.getValue();
|
||||
var event = new Blockly.Events.BlockChange(
|
||||
fieldVariable.sourceBlock_, 'field', undefined, oldId, 'id2');
|
||||
setUpMockMethod(mockControl_, Blockly.Events, 'fire', [event], null);
|
||||
|
||||
fieldVariable.setValue('id2');
|
||||
assertEquals('name2', fieldVariable.getText());
|
||||
assertEquals('id2', fieldVariable.getValue());
|
||||
fieldVariableTestWithMocks_tearDown();
|
||||
}
|
||||
|
||||
function test_fieldVariable_setValueNoVariable() {
|
||||
fieldVariableTestWithMocks_setUp();
|
||||
|
||||
var fieldVariable = fieldVariable_createAndInitField(workspace);
|
||||
var mockBlock = fieldVariable.sourceBlock_;
|
||||
mockBlock.isShadow = function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
try {
|
||||
fieldVariable.setValue('id1');
|
||||
// Calling setValue with a variable that doesn't exist throws an error.
|
||||
fail();
|
||||
} catch (e) {
|
||||
// expected
|
||||
} finally {
|
||||
fieldVariableTestWithMocks_tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
function test_fieldVariable_dropdownCreateVariablesExist() {
|
||||
// Expect that the dropdown options will contain the variables that exist.
|
||||
workspace = new Blockly.Workspace();
|
||||
workspace.createVariable('name1', '', 'id1');
|
||||
workspace.createVariable('name2', '', 'id2');
|
||||
|
||||
var fieldVariable = fieldVariable_createAndInitField(workspace);
|
||||
|
||||
var result_options = Blockly.FieldVariable.dropdownCreate.call(
|
||||
fieldVariable);
|
||||
|
||||
assertEquals(result_options.length, 3);
|
||||
isEqualArrays(result_options[0], ['name1', 'id1']);
|
||||
isEqualArrays(result_options[1], ['name2', 'id2']);
|
||||
|
||||
workspace.dispose();
|
||||
}
|
||||
|
||||
function test_fieldVariable_setValueNull() {
|
||||
// This should no longer create a variable for the selected option.
|
||||
fieldVariableTestWithMocks_setUp();
|
||||
setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['id1', null]);
|
||||
|
||||
var fieldVariable = fieldVariable_createAndInitField(workspace);
|
||||
try {
|
||||
fieldVariable.setValue(null);
|
||||
fail();
|
||||
} catch (e) {
|
||||
// expected
|
||||
} finally {
|
||||
fieldVariableTestWithMocks_tearDown();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function test_fieldVariable_getVariableTypes_undefinedVariableTypes() {
|
||||
// Expect that since variableTypes is undefined, only type empty string
|
||||
// will be returned (regardless of what types are available on the workspace).
|
||||
workspace = new Blockly.Workspace();
|
||||
workspace.createVariable('name1', 'type1');
|
||||
workspace.createVariable('name2', 'type2');
|
||||
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
var resultTypes = fieldVariable.getVariableTypes_();
|
||||
isEqualArrays(resultTypes, ['']);
|
||||
workspace.dispose();
|
||||
}
|
||||
|
||||
function test_fieldVariable_getVariableTypes_givenVariableTypes() {
|
||||
// Expect that since variableTypes is defined, it will be the return value,
|
||||
// regardless of what types are available on the workspace.
|
||||
workspace = new Blockly.Workspace();
|
||||
workspace.createVariable('name1', 'type1');
|
||||
workspace.createVariable('name2', 'type2');
|
||||
|
||||
var fieldVariable = new Blockly.FieldVariable(
|
||||
'name1', null, ['type1', 'type2'], 'type1');
|
||||
var resultTypes = fieldVariable.getVariableTypes_();
|
||||
isEqualArrays(resultTypes, ['type1', 'type2']);
|
||||
assertEquals('Default type was wrong', 'type1', fieldVariable.defaultType_);
|
||||
workspace.dispose();
|
||||
}
|
||||
|
||||
function test_fieldVariable_getVariableTypes_nullVariableTypes() {
|
||||
// Expect all variable types to be returned.
|
||||
// The variable does not need to be initialized to do this--it just needs a
|
||||
// pointer to the workspace.
|
||||
workspace = new Blockly.Workspace();
|
||||
workspace.createVariable('name1', 'type1');
|
||||
workspace.createVariable('name2', 'type2');
|
||||
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
var mockBlock = fieldVariable_mockBlock(workspace);
|
||||
fieldVariable.setSourceBlock(mockBlock);
|
||||
fieldVariable.variableTypes = null;
|
||||
|
||||
var resultTypes = fieldVariable.getVariableTypes_();
|
||||
// The empty string is always one of the options.
|
||||
isEqualArrays(resultTypes, ['type1', 'type2', '']);
|
||||
workspace.dispose();
|
||||
}
|
||||
|
||||
function test_fieldVariable_getVariableTypes_emptyListVariableTypes() {
|
||||
// Expect an error to be thrown.
|
||||
workspace = new Blockly.Workspace();
|
||||
workspace.createVariable('name1', 'type1');
|
||||
workspace.createVariable('name2', 'type2');
|
||||
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
var mockBlock = fieldVariable_mockBlock(workspace);
|
||||
fieldVariable.setSourceBlock(mockBlock);
|
||||
fieldVariable.variableTypes = [];
|
||||
|
||||
try {
|
||||
fieldVariable.getVariableTypes_();
|
||||
fail();
|
||||
} catch (e) {
|
||||
//expected
|
||||
} finally {
|
||||
workspace.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
function test_fieldVariable_defaultType_exists() {
|
||||
var fieldVariable = new Blockly.FieldVariable(null, null, ['b'], 'b');
|
||||
assertEquals('The variable field\'s default type should be "b"',
|
||||
'b', fieldVariable.defaultType_);
|
||||
}
|
||||
|
||||
function test_fieldVariable_noDefaultType() {
|
||||
var fieldVariable = new Blockly.FieldVariable(null);
|
||||
assertEquals('The variable field\'s default type should be the empty string',
|
||||
'', fieldVariable.defaultType_);
|
||||
assertNull('The variable field\'s allowed types should be null',
|
||||
fieldVariable.variableTypes);
|
||||
}
|
||||
|
||||
function test_fieldVariable_defaultTypeMismatch() {
|
||||
try {
|
||||
var fieldVariable = new Blockly.FieldVariable(null, null, ['a'], 'b');
|
||||
fail('Variable field creation should have failed due to an invalid ' +
|
||||
'default type');
|
||||
} catch (e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
function test_fieldVariable_defaultTypeMismatch_empty() {
|
||||
try {
|
||||
var fieldVariable = new Blockly.FieldVariable(null, null, ['a']);
|
||||
fail('Variable field creation should have failed due to an invalid ' +
|
||||
'default type');
|
||||
} catch (e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,7 @@
|
||||
<script src="connection_test.js"></script>
|
||||
<script src="event_test.js"></script>
|
||||
<script src="extensions_test.js"></script>
|
||||
<script src="field_angle_test.js"></script>
|
||||
<script src="field_number_test.js"></script>
|
||||
<script src="field_test.js"></script>
|
||||
<script src="field_variable_test.js"></script>
|
||||
<script src="generator_test.js"></script>
|
||||
<script src="gesture_test.js"></script>
|
||||
<script src="input_test.js"></script>
|
||||
|
||||
@@ -127,7 +127,7 @@ suite ('Angle Fields', function() {
|
||||
this.angleField.setValue(undefined);
|
||||
assertValueDefault(this.angleField);
|
||||
});
|
||||
test.skip('Non-Parsable String', function() {
|
||||
test('Non-Parsable String', function() {
|
||||
this.angleField.setValue('bad');
|
||||
assertValueDefault(this.angleField);
|
||||
});
|
||||
@@ -164,15 +164,15 @@ suite ('Angle Fields', function() {
|
||||
this.angleField.setValue(null);
|
||||
assertValue(this.angleField, 1);
|
||||
});
|
||||
test.skip('Undefined', function() {
|
||||
test('Undefined', function() {
|
||||
this.angleField.setValue(undefined);
|
||||
assertValue(this.angleField, 1);
|
||||
});
|
||||
test.skip('Non-Parsable String', function() {
|
||||
test('Non-Parsable String', function() {
|
||||
this.angleField.setValue('bad');
|
||||
assertValue(this.angleField, 1);
|
||||
});
|
||||
test.skip('NaN', function() {
|
||||
test('NaN', function() {
|
||||
this.angleField.setValue(NaN);
|
||||
assertValue(this.angleField, 1);
|
||||
});
|
||||
@@ -198,7 +198,7 @@ suite ('Angle Fields', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
suite.skip('Validators', function() {
|
||||
suite('Validators', function() {
|
||||
setup(function() {
|
||||
this.angleField = new Blockly.FieldAngle(1);
|
||||
Blockly.FieldTextInput.htmlInput_ = Object.create(null);
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
suite.skip('Checkbox Fields', function() {
|
||||
suite('Checkbox Fields', function() {
|
||||
function assertValue(checkboxField, expectedValue, expectedText) {
|
||||
var actualValue = checkboxField.getValue();
|
||||
var actualText = checkboxField.getText();
|
||||
|
||||
@@ -57,11 +57,11 @@ suite ('Colour Fields', function() {
|
||||
var colourField = new Blockly.FieldColour(undefined);
|
||||
assertValueDefault(colourField);
|
||||
});
|
||||
test.skip('Non-Parsable String', function() {
|
||||
test('Non-Parsable String', function() {
|
||||
var colourField = new Blockly.FieldColour('bad');
|
||||
assertValueDefault(colourField);
|
||||
});
|
||||
test.skip('#AAAAAA', function() {
|
||||
test('#AAAAAA', function() {
|
||||
var colourField = new Blockly.FieldColour('#AAAAAA');
|
||||
assertValue(colourField, '#aaaaaa', '#aaa');
|
||||
});
|
||||
@@ -69,7 +69,7 @@ suite ('Colour Fields', function() {
|
||||
var colourField = new Blockly.FieldColour('#aaaaaa');
|
||||
assertValue(colourField, '#aaaaaa', '#aaa');
|
||||
});
|
||||
test.skip('#AAAA00', function() {
|
||||
test('#AAAA00', function() {
|
||||
var colourField = new Blockly.FieldColour('#AAAA00');
|
||||
assertValue(colourField, '#aaaa00', '#aa0');
|
||||
});
|
||||
@@ -77,7 +77,7 @@ suite ('Colour Fields', function() {
|
||||
var colourField = new Blockly.FieldColour('#aaaa00');
|
||||
assertValue(colourField, '#aaaa00', '#aa0');
|
||||
});
|
||||
test.skip('#BCBCBC', function() {
|
||||
test('#BCBCBC', function() {
|
||||
var colourField = new Blockly.FieldColour('#BCBCBC');
|
||||
assertValue(colourField, '#bcbcbc', '#bcbcbc');
|
||||
});
|
||||
@@ -99,11 +99,11 @@ suite ('Colour Fields', function() {
|
||||
var colourField = new Blockly.FieldColour.fromJson({ colour:undefined });
|
||||
assertValueDefault(colourField);
|
||||
});
|
||||
test.skip('Non-Parsable String', function() {
|
||||
test('Non-Parsable String', function() {
|
||||
var colourField = new Blockly.FieldColour.fromJson({ colour:'bad' });
|
||||
assertValueDefault(colourField);
|
||||
});
|
||||
test.skip('#AAAAAA', function() {
|
||||
test('#AAAAAA', function() {
|
||||
var colourField = Blockly.FieldColour.fromJson({ colour: '#AAAAAA' });
|
||||
assertValue(colourField, '#aaaaaa', '#aaa');
|
||||
});
|
||||
@@ -111,7 +111,7 @@ suite ('Colour Fields', function() {
|
||||
var colourField = Blockly.FieldColour.fromJson({ colour: '#aaaaaa' });
|
||||
assertValue(colourField, '#aaaaaa', '#aaa');
|
||||
});
|
||||
test.skip('#AAAA00', function() {
|
||||
test('#AAAA00', function() {
|
||||
var colourField = Blockly.FieldColour.fromJson({ colour: '#AAAA00' });
|
||||
assertValue(colourField, '#aaaa00', '#aa0');
|
||||
});
|
||||
@@ -119,7 +119,7 @@ suite ('Colour Fields', function() {
|
||||
var colourField = Blockly.FieldColour.fromJson({ colour: '#aaaa00' });
|
||||
assertValue(colourField, '#aaaa00', '#aa0');
|
||||
});
|
||||
test.skip('#BCBCBC', function() {
|
||||
test('#BCBCBC', function() {
|
||||
var colourField = Blockly.FieldColour.fromJson({ colour: '#BCBCBC' });
|
||||
assertValue(colourField, '#bcbcbc', '#bcbcbc');
|
||||
});
|
||||
@@ -133,15 +133,15 @@ suite ('Colour Fields', function() {
|
||||
setup(function() {
|
||||
this.colourField = new Blockly.FieldColour();
|
||||
});
|
||||
test.skip('Null', function() {
|
||||
test('Null', function() {
|
||||
this.colourField.setValue(null);
|
||||
assertValueDefault(this.colourField);
|
||||
});
|
||||
test.skip('Undefined', function() {
|
||||
test('Undefined', function() {
|
||||
this.colourField.setValue(undefined);
|
||||
assertValueDefault(this.colourField);
|
||||
});
|
||||
test.skip('Non-Parsable String', function() {
|
||||
test('Non-Parsable String', function() {
|
||||
this.colourField.setValue('bad');
|
||||
assertValueDefault(this.colourField);
|
||||
});
|
||||
@@ -158,15 +158,15 @@ suite ('Colour Fields', function() {
|
||||
setup(function() {
|
||||
this.colourField = new Blockly.FieldColour('#aaaaaa');
|
||||
});
|
||||
test.skip('Null', function() {
|
||||
test('Null', function() {
|
||||
this.colourField.setValue(null);
|
||||
assertValue(this.colourField, '#aaaaaa', '#aaa');
|
||||
});
|
||||
test.skip('Undefined', function() {
|
||||
test('Undefined', function() {
|
||||
this.colourField.setValue(undefined);
|
||||
assertValue(this.colourField, '#aaaaaa', '#aaa');
|
||||
});
|
||||
test.skip('Non-Parsable String', function() {
|
||||
test('Non-Parsable String', function() {
|
||||
this.colourField.setValue('bad');
|
||||
assertValue(this.colourField, '#aaaaaa', '#aaa');
|
||||
});
|
||||
@@ -180,7 +180,7 @@ suite ('Colour Fields', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
suite.skip('Validators', function() {
|
||||
suite('Validators', function() {
|
||||
setup(function() {
|
||||
this.colourField = new Blockly.FieldColour('#aaaaaa');
|
||||
});
|
||||
|
||||
@@ -42,7 +42,7 @@ suite ('Date Fields', function() {
|
||||
var dateField = new Blockly.FieldDate(undefined);
|
||||
assertValueDefault(dateField);
|
||||
});
|
||||
test.skip('Non-Parsable String', function() {
|
||||
test('Non-Parsable String', function() {
|
||||
var dateField = new Blockly.FieldDate('bad');
|
||||
assertValueDefault(dateField);
|
||||
});
|
||||
@@ -50,11 +50,11 @@ suite ('Date Fields', function() {
|
||||
var dateField = new Blockly.FieldDate('2020-02-20');
|
||||
assertValue(dateField, '2020-02-20');
|
||||
});
|
||||
test.skip('Invalid Date - Month(2020-13-20)', function() {
|
||||
test('Invalid Date - Month(2020-13-20)', function() {
|
||||
var dateField = new Blockly.FieldDate('2020-13-20');
|
||||
assertValueDefault(dateField);
|
||||
});
|
||||
test.skip('Invalid Date - Day(2020-02-32)', function() {
|
||||
test('Invalid Date - Day(2020-02-32)', function() {
|
||||
var dateField = new Blockly.FieldDate('2020-02-32');
|
||||
assertValueDefault(dateField);
|
||||
});
|
||||
@@ -72,7 +72,7 @@ suite ('Date Fields', function() {
|
||||
var dateField = Blockly.FieldDate.fromJson({ date: undefined });
|
||||
assertValueDefault(dateField);
|
||||
});
|
||||
test.skip('Non-Parsable String', function() {
|
||||
test('Non-Parsable String', function() {
|
||||
var dateField = Blockly.FieldDate.fromJson({ date: 'bad' });
|
||||
assertValueDefault(dateField);
|
||||
});
|
||||
@@ -80,11 +80,11 @@ suite ('Date Fields', function() {
|
||||
var dateField = Blockly.FieldDate.fromJson({ date: '2020-02-20' });
|
||||
assertValue(dateField, '2020-02-20');
|
||||
});
|
||||
test.skip('Invalid Date - Month(2020-13-20)', function() {
|
||||
test('Invalid Date - Month(2020-13-20)', function() {
|
||||
var dateField = Blockly.FieldDate.fromJson({ date: '2020-13-20' });
|
||||
assertValueDefault(dateField);
|
||||
});
|
||||
test.skip('Invalid Date - Day(2020-02-32)', function() {
|
||||
test('Invalid Date - Day(2020-02-32)', function() {
|
||||
var dateField = Blockly.FieldDate.fromJson({ date: '2020-02-32' });
|
||||
assertValueDefault(dateField);
|
||||
});
|
||||
@@ -94,23 +94,23 @@ suite ('Date Fields', function() {
|
||||
setup(function() {
|
||||
this.dateField = new Blockly.FieldDate();
|
||||
});
|
||||
test.skip('Null', function() {
|
||||
test('Null', function() {
|
||||
this.dateField.setValue(null);
|
||||
assertValueDefault(this.dateField);
|
||||
});
|
||||
test.skip('Undefined', function() {
|
||||
test('Undefined', function() {
|
||||
this.dateField.setValue(undefined);
|
||||
assertValueDefault(this.dateField);
|
||||
});
|
||||
test.skip('Non-Parsable String', function() {
|
||||
test('Non-Parsable String', function() {
|
||||
this.dateField.setValue('bad');
|
||||
assertValueDefault(this.dateField);
|
||||
});
|
||||
test.skip('Invalid Date - Month(2020-13-20)', function() {
|
||||
test('Invalid Date - Month(2020-13-20)', function() {
|
||||
this.dateField.setValue('2020-13-20');
|
||||
assertValueDefault(this.dateField);
|
||||
});
|
||||
test.skip('Invalid Date - Day(2020-02-32)', function() {
|
||||
test('Invalid Date - Day(2020-02-32)', function() {
|
||||
this.dateField.setValue('2020-02-32');
|
||||
assertValueDefault(this.dateField);
|
||||
});
|
||||
@@ -123,23 +123,23 @@ suite ('Date Fields', function() {
|
||||
setup(function() {
|
||||
this.dateField = new Blockly.FieldDate('2020-02-20');
|
||||
});
|
||||
test.skip('Null', function() {
|
||||
test('Null', function() {
|
||||
this.dateField.setValue(null);
|
||||
assertValue(this.dateField, '2020-02-20');
|
||||
});
|
||||
test.skip('Undefined', function() {
|
||||
test('Undefined', function() {
|
||||
this.dateField.setValue(undefined);
|
||||
assertValue(this.dateField, '2020-02-20');
|
||||
});
|
||||
test.skip('Non-Parsable String', function() {
|
||||
test('Non-Parsable String', function() {
|
||||
this.dateField.setValue('bad');
|
||||
assertValue(this.dateField, '2020-02-20');
|
||||
});
|
||||
test.skip('Invalid Date - Month(2020-13-20)', function() {
|
||||
test('Invalid Date - Month(2020-13-20)', function() {
|
||||
this.dateField.setValue('2020-13-20');
|
||||
assertValue(this.dateField, '2020-02-20');
|
||||
});
|
||||
test.skip('Invalid Date - Day(2020-02-32)', function() {
|
||||
test('Invalid Date - Day(2020-02-32)', function() {
|
||||
this.dateField.setValue('2020-02-32');
|
||||
assertValue(this.dateField, '2020-02-20');
|
||||
});
|
||||
@@ -149,7 +149,7 @@ suite ('Date Fields', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
suite.skip('Validators', function() {
|
||||
suite('Validators', function() {
|
||||
setup(function() {
|
||||
this.dateField = new Blockly.FieldDate('2020-02-20');
|
||||
});
|
||||
|
||||
@@ -148,11 +148,11 @@ suite ('Dropdown Fields', function() {
|
||||
this.dropdownField.setValue(null);
|
||||
assertValue(this.dropdownField, 'A', 'a');
|
||||
});
|
||||
test.skip('Undefined', function() {
|
||||
test('Undefined', function() {
|
||||
this.dropdownField.setValue(undefined);
|
||||
assertValue(this.dropdownField, 'A', 'a');
|
||||
});
|
||||
test.skip('Invalid ID', function() {
|
||||
test('Invalid ID', function() {
|
||||
this.dropdownField.setValue('bad');
|
||||
assertValue(this.dropdownField, 'A', 'a');
|
||||
});
|
||||
@@ -161,7 +161,7 @@ suite ('Dropdown Fields', function() {
|
||||
assertValue(this.dropdownField, 'B', 'b');
|
||||
});
|
||||
});
|
||||
suite.skip('Validators', function() {
|
||||
suite('Validators', function() {
|
||||
setup(function() {
|
||||
this.dropdownField = new Blockly.FieldDropdown([
|
||||
["1a","1A"], ["1b","1B"], ["1c","1C"],
|
||||
|
||||
@@ -149,7 +149,7 @@ suite ('Image Fields', function() {
|
||||
this.imageField.setValue(null);
|
||||
assertValue(this.imageField, 'src', 'alt');
|
||||
});
|
||||
test.skip('Undefined', function() {
|
||||
test('Undefined', function() {
|
||||
this.imageField.setValue(undefined);
|
||||
assertValue(this.imageField, 'src', 'alt');
|
||||
});
|
||||
|
||||
@@ -108,7 +108,7 @@ suite ('Label Serializable Fields', function() {
|
||||
this.labelField.setValue(null);
|
||||
assertValueDefault(this.labelField);
|
||||
});
|
||||
test.skip('Undefined', function() {
|
||||
test('Undefined', function() {
|
||||
this.labelField.setValue(undefined);
|
||||
assertValueDefault(this.labelField);
|
||||
});
|
||||
@@ -120,7 +120,7 @@ suite ('Label Serializable Fields', function() {
|
||||
this.labelField.setValue(1);
|
||||
assertValue(this.labelField, '1');
|
||||
});
|
||||
test.skip('Number (Falsy)', function() {
|
||||
test('Number (Falsy)', function() {
|
||||
this.labelField.setValue(0);
|
||||
assertValue(this.labelField, '0');
|
||||
});
|
||||
@@ -128,7 +128,7 @@ suite ('Label Serializable Fields', function() {
|
||||
this.labelField.setValue(true);
|
||||
assertValue(this.labelField, 'true');
|
||||
});
|
||||
test.skip('Boolean False', function() {
|
||||
test('Boolean False', function() {
|
||||
this.labelField.setValue(false);
|
||||
assertValue(this.labelField, 'false');
|
||||
});
|
||||
@@ -141,7 +141,7 @@ suite ('Label Serializable Fields', function() {
|
||||
this.labelField.setValue(null);
|
||||
assertValue(this.labelField, 'value');
|
||||
});
|
||||
test.skip('Undefined', function() {
|
||||
test('Undefined', function() {
|
||||
this.labelField.setValue(undefined);
|
||||
assertValue(this.labelField, 'value');
|
||||
});
|
||||
|
||||
@@ -105,7 +105,7 @@ suite ('Label Fields', function() {
|
||||
this.labelField.setValue(null);
|
||||
assertValueDefault(this.labelField);
|
||||
});
|
||||
test.skip('Undefined', function() {
|
||||
test('Undefined', function() {
|
||||
this.labelField.setValue(undefined);
|
||||
assertValueDefault(this.labelField);
|
||||
});
|
||||
@@ -117,7 +117,7 @@ suite ('Label Fields', function() {
|
||||
this.labelField.setValue(1);
|
||||
assertValue(this.labelField, '1');
|
||||
});
|
||||
test.skip('Number (Falsy)', function() {
|
||||
test('Number (Falsy)', function() {
|
||||
this.labelField.setValue(0);
|
||||
assertValue(this.labelField, '0');
|
||||
});
|
||||
@@ -125,7 +125,7 @@ suite ('Label Fields', function() {
|
||||
this.labelField.setValue(true);
|
||||
assertValue(this.labelField, 'true');
|
||||
});
|
||||
test.skip('Boolean False', function() {
|
||||
test('Boolean False', function() {
|
||||
this.labelField.setValue(false);
|
||||
assertValue(this.labelField, 'false');
|
||||
});
|
||||
@@ -138,7 +138,7 @@ suite ('Label Fields', function() {
|
||||
this.labelField.setValue(null);
|
||||
assertValue(this.labelField, 'value');
|
||||
});
|
||||
test.skip('Undefined', function() {
|
||||
test('Undefined', function() {
|
||||
this.labelField.setValue(undefined);
|
||||
assertValue(this.labelField, 'value');
|
||||
});
|
||||
|
||||
@@ -136,15 +136,15 @@ suite ('Number Fields', function() {
|
||||
this.numberField.setValue(null);
|
||||
assertValueDefault(this.numberField);
|
||||
});
|
||||
test.skip('Undefined', function() {
|
||||
test('Undefined', function() {
|
||||
this.numberField.setValue(undefined);
|
||||
assertValueDefault(this.numberField);
|
||||
});
|
||||
test.skip('Non-Parsable String', function() {
|
||||
test('Non-Parsable String', function() {
|
||||
this.numberField.setValue('bad');
|
||||
assertValueDefault(this.numberField);
|
||||
});
|
||||
test.skip('NaN', function() {
|
||||
test('NaN', function() {
|
||||
this.numberField.setValue(NaN);
|
||||
assertValueDefault(this.numberField);
|
||||
});
|
||||
@@ -173,15 +173,15 @@ suite ('Number Fields', function() {
|
||||
this.numberField.setValue(null);
|
||||
assertValue(this.numberField, 1);
|
||||
});
|
||||
test.skip('Undefined', function() {
|
||||
test('Undefined', function() {
|
||||
this.numberField.setValue(undefined);
|
||||
assertValue(this.numberField, 1);
|
||||
});
|
||||
test.skip('Non-Parsable String', function() {
|
||||
test('Non-Parsable String', function() {
|
||||
this.numberField.setValue('bad');
|
||||
assertValue(this.numberField, 1);
|
||||
});
|
||||
test.skip('NaN', function() {
|
||||
test('NaN', function() {
|
||||
this.numberField.setValue(NaN);
|
||||
assertValue(this.numberField, 1);
|
||||
});
|
||||
@@ -228,7 +228,7 @@ suite ('Number Fields', function() {
|
||||
numberField.setValue(123.456);
|
||||
assertValue(numberField, 123);
|
||||
});
|
||||
test.skip('1.5', function() {
|
||||
test('1.5', function() {
|
||||
var numberField = new Blockly.FieldNumber
|
||||
.fromJson({ precision: 1.5 });
|
||||
numberField.setValue(123.456);
|
||||
@@ -295,7 +295,7 @@ suite ('Number Fields', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
suite.skip('Validators', function() {
|
||||
suite('Validators', function() {
|
||||
setup(function() {
|
||||
this.numberFieldField = new Blockly.FieldNumber(1);
|
||||
Blockly.FieldTextInput.htmlInput_ = Object.create(null);
|
||||
|
||||
@@ -107,7 +107,7 @@ suite ('Text Input Fields', function() {
|
||||
this.textInputField.setValue(null);
|
||||
assertValueDefault(this.textInputField);
|
||||
});
|
||||
test.skip('Undefined', function() {
|
||||
test('Undefined', function() {
|
||||
this.textInputField.setValue(undefined);
|
||||
assertValueDefault(this.textInputField);
|
||||
});
|
||||
@@ -119,7 +119,7 @@ suite ('Text Input Fields', function() {
|
||||
this.textInputField.setValue(1);
|
||||
assertValue(this.textInputField, '1');
|
||||
});
|
||||
test.skip('Number (Falsy)', function() {
|
||||
test('Number (Falsy)', function() {
|
||||
this.textInputField.setValue(0);
|
||||
assertValue(this.textInputField, '0');
|
||||
});
|
||||
@@ -127,7 +127,7 @@ suite ('Text Input Fields', function() {
|
||||
this.textInputField.setValue(true);
|
||||
assertValue(this.textInputField, 'true');
|
||||
});
|
||||
test.skip('Boolean False', function() {
|
||||
test('Boolean False', function() {
|
||||
this.textInputField.setValue(false);
|
||||
assertValue(this.textInputField, 'false');
|
||||
});
|
||||
@@ -140,7 +140,7 @@ suite ('Text Input Fields', function() {
|
||||
this.textInputField.setValue(null);
|
||||
assertValue(this.textInputField, 'value');
|
||||
});
|
||||
test.skip('Undefined', function() {
|
||||
test('Undefined', function() {
|
||||
this.textInputField.setValue(undefined);
|
||||
assertValue(this.textInputField, 'value');
|
||||
});
|
||||
@@ -166,7 +166,7 @@ suite ('Text Input Fields', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
suite.skip('Validators', function() {
|
||||
suite('Validators', function() {
|
||||
setup(function() {
|
||||
this.textInputField = new Blockly.FieldTextInput('value');
|
||||
Blockly.FieldTextInput.htmlInput_ = Object.create(null);
|
||||
|
||||
@@ -127,13 +127,13 @@ suite('Variable Fields', function() {
|
||||
});
|
||||
});
|
||||
suite('setValue', function() {
|
||||
test.skip('Null', function() {
|
||||
test('Null', function() {
|
||||
var variableField = createAndInitFieldConstructor(
|
||||
this.workspace, 'name1');
|
||||
variableField.setValue(null);
|
||||
assertValue(variableField, 'name1');
|
||||
});
|
||||
test.skip('Undefined', function() {
|
||||
test('Undefined', function() {
|
||||
var variableField = createAndInitFieldConstructor(
|
||||
this.workspace, 'name1');
|
||||
variableField.setValue(undefined);
|
||||
@@ -152,14 +152,14 @@ suite('Variable Fields', function() {
|
||||
assertEquals('id2', variableField.getValue());
|
||||
chai.assert.notEqual(oldId, variableField.getValue());
|
||||
});
|
||||
test.skip('Variable Does not Exist', function() {
|
||||
test('Variable Does not Exist', function() {
|
||||
var variableField = createAndInitFieldConstructor(
|
||||
this.workspace, 'name1');
|
||||
variableField.setValue('id1');
|
||||
assertValue(variableField, 'name1');
|
||||
});
|
||||
});
|
||||
suite.skip('Validators', function() {
|
||||
suite('Validators', function() {
|
||||
setup(function() {
|
||||
this.workspace.createVariable('name1', null, 'id1');
|
||||
this.workspace.createVariable('name2', null, 'id2');
|
||||
|
||||
@@ -144,6 +144,15 @@ function start() {
|
||||
}
|
||||
|
||||
function addToolboxButtonCallbacks() {
|
||||
var addAllBlocksToWorkspace = function(button) {
|
||||
var workspace = button.getTargetWorkspace();
|
||||
var blocks = button.workspace_.getTopBlocks();
|
||||
for(var i = 0, block; block = blocks[i]; i++) {
|
||||
var xml = Blockly.Xml.textToDom('<xml></xml>');
|
||||
xml.appendChild(Blockly.Xml.blockToDom(block));
|
||||
Blockly.Xml.appendDomToWorkspace(xml, workspace);
|
||||
}
|
||||
};
|
||||
var randomizeLabelText = function(button) {
|
||||
var blocks = button.targetWorkspace_
|
||||
.getBlocksByType('test_fields_label_serializable');
|
||||
@@ -177,13 +186,59 @@ function addToolboxButtonCallbacks() {
|
||||
block.setShadow(!block.isShadow());
|
||||
}
|
||||
};
|
||||
var toggleCollapsed = function(button) {
|
||||
var blocks = button.workspace_.getAllBlocks();
|
||||
for(var i = 0, block; block = blocks[i]; i++) {
|
||||
block.setCollapsed(!block.isCollapsed());
|
||||
}
|
||||
};
|
||||
var setInput = function(button) {
|
||||
Blockly.prompt('Input text to set.', 'ab', function(input) {
|
||||
var blocks = button.getTargetWorkspace().getAllBlocks();
|
||||
for(var i = 0, block; block = blocks[i]; i++) {
|
||||
if (block.getField('INPUT')) {
|
||||
block.setFieldValue(input, 'INPUT');
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
var changeImage = function(button) {
|
||||
var blocks = button.workspace_.getBlocksByType('test_fields_image');
|
||||
var possible = 'abcdefghijklm';
|
||||
var image = possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
var src = 'https://blockly-demo.appspot.com/static/tests/media/'
|
||||
+ image + '.png';
|
||||
for (var i = 0, block; block = blocks[i]; i++) {
|
||||
var imageField = block.getField('IMAGE');
|
||||
imageField.setValue(src);
|
||||
imageField.setText(image);
|
||||
}
|
||||
};
|
||||
var addVariables = function(button) {
|
||||
workspace.createVariable('1a', '', '1A');
|
||||
workspace.createVariable('1b', '', '1B');
|
||||
workspace.createVariable('1c', '', '1C');
|
||||
workspace.createVariable('2a', '', '2A');
|
||||
workspace.createVariable('2b', '', '2B');
|
||||
workspace.createVariable('2c', '', '2C');
|
||||
};
|
||||
|
||||
workspace.registerButtonCallback(
|
||||
'addVariables', addVariables);
|
||||
workspace.registerButtonCallback(
|
||||
'changeImage', changeImage);
|
||||
workspace.registerButtonCallback(
|
||||
'addAllBlocksToWorkspace', addAllBlocksToWorkspace);
|
||||
workspace.registerButtonCallback(
|
||||
'setInput', setInput);
|
||||
workspace.registerButtonCallback(
|
||||
'setRandomStyle', setRandomStyle);
|
||||
workspace.registerButtonCallback(
|
||||
'toggleEnabled', toggleEnabled);
|
||||
workspace.registerButtonCallback(
|
||||
'toggleShadow', toggleShadow);
|
||||
workspace.registerButtonCallback(
|
||||
'toggleCollapsed', toggleCollapsed);
|
||||
workspace.registerButtonCallback(
|
||||
'randomizeLabelText', randomizeLabelText);
|
||||
workspace.registerButtonCallback(
|
||||
@@ -1236,11 +1291,15 @@ h1 {
|
||||
</category>
|
||||
<category name="Fields" expanded="true">
|
||||
<category name="Defaults">
|
||||
<button text="add blocks to workspace" callbackKey="addAllBlocksToWorkspace"></button>
|
||||
<sep gap="8"></sep>
|
||||
<button text="set random style" callbackKey="setRandomStyle"></button>
|
||||
<sep gap="8"></sep>
|
||||
<button text="toggle enabled" callbackKey="toggleEnabled"></button>
|
||||
<sep gap="8"></sep>
|
||||
<button text="toggle shadow" callbackKey="toggleShadow"></button>
|
||||
<sep gap="8"></sep>
|
||||
<button text="toggle collapsed" callbackKey="toggleCollapsed"></button>
|
||||
<block type="test_fields_angle"></block>
|
||||
<block type="test_fields_date"></block>
|
||||
<block type="test_fields_checkbox"></block>
|
||||
@@ -1248,7 +1307,11 @@ h1 {
|
||||
<block type="test_fields_text_input"></block>
|
||||
<block type="test_fields_variable"></block>
|
||||
<button text="randomize label text" callbackKey="randomizeLabelText"></button>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_fields_label_serializable"></block>
|
||||
<button text="change image" callbackKey="changeImage"></button>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_fields_image"></block>
|
||||
</category>
|
||||
<category name="Numbers">
|
||||
<block type="test_numbers_float">
|
||||
@@ -1298,6 +1361,69 @@ h1 {
|
||||
<field name="TEXT">Zalgo in text field: B̛̻̦̬̘̰͎̥̈̔͊͞ͅl̡͖̫̺̬̖̣̳̃̀́͑͑̕͟͠͝o̢̹͙̮̫͔͋̉̊̑̿̽̚c̸̹̹̜͙̹̠͋̒͑̊̇͝k̡͉̫͇̖̳͖̊͒́̆̄̎̂̔̕͜͞l̰̙̞̳̩̠͖̯̀̆̈́̿̈̓͗y̨̡̟͇̮͈̬̙̲̏̅̀͘͠</field>
|
||||
</block>
|
||||
</category>
|
||||
<category name="Validators">
|
||||
<button text="add blocks to workspace" callbackKey="addAllBlocksToWorkspace"></button>
|
||||
<sep gap="8"></sep>
|
||||
<button text="set input" callbackKey="setInput"></button>
|
||||
<label text="Angles"></label>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_angle_null"></block>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_angle_mult30_force"></block>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_angle_mult30_null"></block>
|
||||
<label text="Checkboxes"></label>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_checkbox_null"></block>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_checkbox_match"></block>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_checkbox_not_match_null"></block>
|
||||
<label text="Colours"></label>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_colour_null"></block>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_colour_force_red"></block>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_colour_red_null"></block>
|
||||
<label text="Dates"></label>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_date_null"></block>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_date_force_20s"></block>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_date_20s_null"></block>
|
||||
<label text="Dropdowns"></label>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_dropdown_null"></block>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_dropdown_force_1s"></block>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_dropdown_1s_null"></block>
|
||||
<label text="Numbers"></label>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_number_null"></block>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_number_mult10_force"></block>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_number_mult10_null"></block>
|
||||
<label text="Text"></label>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_text_null"></block>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_text_A"></block>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_text_B"></block>
|
||||
<label text="Variables"></label>
|
||||
<sep gap="8"></sep>
|
||||
<button text="add test variables" callbackKey="addVariables" web-class="modifiesWorkspace"></button>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_variable_null"></block>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_variable_force_1s"></block>
|
||||
<sep gap="12"></sep>
|
||||
<block type="test_validators_variable_1s_null"></block>
|
||||
</category>
|
||||
</category>
|
||||
<category name="Mutators">
|
||||
<label text="logic_compare"></label>
|
||||
|
||||
Reference in New Issue
Block a user