mirror of
https://github.com/scratchfoundation/scratch-blocks.git
synced 2025-08-28 22:10:31 -04:00
Simplify field validator chaining.
This commit is contained in:
parent
f474e11345
commit
555eac8b7f
10 changed files with 59 additions and 128 deletions
|
@ -236,6 +236,37 @@ Blockly.Field.prototype.getValidator = function() {
|
|||
return this.validator_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calls the validation function for this field, as well as all the validation
|
||||
* function for the field's class and its parents.
|
||||
* @param {string} text Proposed text.
|
||||
* @return {?string} Revised text, or null if invalid.
|
||||
*/
|
||||
Blockly.Field.prototype.callValidator = function(text) {
|
||||
// Collect a list of validators, from Field, through to the subclass, ending
|
||||
// with the user's validator.
|
||||
var validators = [this.getValidator()];
|
||||
var fieldClass = this.constructor;
|
||||
while (fieldClass) {
|
||||
validators.unshift(fieldClass.classValidator);
|
||||
fieldClass = fieldClass.superClass_;
|
||||
}
|
||||
// Call each validator in turn, allowing each to rewrite or reject.
|
||||
for (var i = 0; i < validators.length; i++) {
|
||||
var validator = validators[i];
|
||||
if (validator) {
|
||||
var result = validator.call(this, text);
|
||||
if (result === null) {
|
||||
// Validator rejects value. Game over.
|
||||
return null;
|
||||
} else if (result !== undefined) {
|
||||
text = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the group element for this editable field.
|
||||
* Used for measuring the size and for positioning.
|
||||
|
|
|
@ -50,35 +50,6 @@ Blockly.FieldAngle = function(text, opt_validator) {
|
|||
};
|
||||
goog.inherits(Blockly.FieldAngle, Blockly.FieldTextInput);
|
||||
|
||||
/**
|
||||
* Sets a new change handler for angle field.
|
||||
* @param {Function} handler New change handler, or null.
|
||||
*/
|
||||
Blockly.FieldAngle.prototype.setValidator = function(handler) {
|
||||
var wrappedHandler;
|
||||
if (handler) {
|
||||
// Wrap the user's change handler together with the angle validator.
|
||||
wrappedHandler = function(value) {
|
||||
var v1 = handler.call(this, value);
|
||||
if (v1 === null) {
|
||||
var v2 = v1;
|
||||
} else {
|
||||
if (v1 === undefined) {
|
||||
v1 = value;
|
||||
}
|
||||
var v2 = Blockly.FieldAngle.angleValidator.call(this, v1);
|
||||
if (v2 === undefined) {
|
||||
v2 = v1;
|
||||
}
|
||||
}
|
||||
return v2 === value ? undefined : v2;
|
||||
};
|
||||
} else {
|
||||
wrappedHandler = Blockly.FieldAngle.angleValidator;
|
||||
}
|
||||
Blockly.FieldAngle.superClass_.setValidator.call(this, wrappedHandler);
|
||||
};
|
||||
|
||||
/**
|
||||
* Round angles to the nearest 15 degrees when using mouse.
|
||||
* Set to 0 to disable rounding.
|
||||
|
@ -303,8 +274,9 @@ 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.
|
||||
* @this {!Blockly.FieldAngle}
|
||||
*/
|
||||
Blockly.FieldAngle.angleValidator = function(text) {
|
||||
Blockly.FieldAngle.classValidator = function(text) {
|
||||
if (text === null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -107,12 +107,9 @@ Blockly.FieldCheckbox.prototype.setValue = function(strBool) {
|
|||
*/
|
||||
Blockly.FieldCheckbox.prototype.showEditor_ = function() {
|
||||
var newState = !this.state_;
|
||||
if (this.sourceBlock_ && this.validator_) {
|
||||
if (this.sourceBlock_) {
|
||||
// Call any validation function, and allow it to override.
|
||||
var override = this.validator_(newState);
|
||||
if (override !== undefined) {
|
||||
newState = override;
|
||||
}
|
||||
newState = this.callValidator(newState);
|
||||
}
|
||||
if (newState !== null) {
|
||||
this.setValue(String(newState).toUpperCase());
|
||||
|
|
|
@ -213,12 +213,9 @@ Blockly.FieldColour.prototype.showEditor_ = function() {
|
|||
function(event) {
|
||||
var colour = event.target.getSelectedColor() || '#000000';
|
||||
Blockly.WidgetDiv.hide();
|
||||
if (thisField.sourceBlock_ && thisField.validator_) {
|
||||
if (thisField.sourceBlock_) {
|
||||
// Call any validation function, and allow it to override.
|
||||
var override = thisField.validator_(colour);
|
||||
if (override !== undefined) {
|
||||
colour = override;
|
||||
}
|
||||
colour = thisField.callValidator(colour);
|
||||
}
|
||||
if (colour !== null) {
|
||||
thisField.setValue(colour);
|
||||
|
|
|
@ -82,11 +82,11 @@ Blockly.FieldDate.prototype.getValue = function() {
|
|||
* @param {string} date The new date.
|
||||
*/
|
||||
Blockly.FieldDate.prototype.setValue = function(date) {
|
||||
if (this.sourceBlock_ && this.validator_) {
|
||||
var validated = this.validator_(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 && validated !== undefined) {
|
||||
if (validated !== null) {
|
||||
date = validated;
|
||||
}
|
||||
}
|
||||
|
@ -149,12 +149,9 @@ Blockly.FieldDate.prototype.showEditor_ = function() {
|
|||
function(event) {
|
||||
var date = event.date ? event.date.toIsoString(true) : '';
|
||||
Blockly.WidgetDiv.hide();
|
||||
if (thisField.sourceBlock_ && thisField.validator_) {
|
||||
if (thisField.sourceBlock_) {
|
||||
// Call any validation function, and allow it to override.
|
||||
var override = thisField.validator_(date);
|
||||
if (override !== undefined) {
|
||||
date = override;
|
||||
}
|
||||
date = thisField.callValidator(date);
|
||||
}
|
||||
thisField.setValue(date);
|
||||
});
|
||||
|
|
|
@ -108,12 +108,9 @@ Blockly.FieldDropdown.prototype.showEditor_ = function() {
|
|||
var menuItem = e.target;
|
||||
if (menuItem) {
|
||||
var value = menuItem.getValue();
|
||||
if (thisField.sourceBlock_ && thisField.validator_) {
|
||||
if (thisField.sourceBlock_) {
|
||||
// Call any validation function, and allow it to override.
|
||||
var override = thisField.validator_(value);
|
||||
if (override !== undefined) {
|
||||
value = override;
|
||||
}
|
||||
value = thisField.callValidator(value);
|
||||
}
|
||||
if (value !== null) {
|
||||
thisField.setValue(value);
|
||||
|
|
|
@ -67,44 +67,16 @@ Blockly.FieldNumber.prototype.setConstraints = function(min, max, precision) {
|
|||
this.min_ = isNaN(min) ? -Infinity : min;
|
||||
max = parseFloat(max);
|
||||
this.max_ = isNaN(max) ? Infinity : max;
|
||||
this.setValue(this.numberValidator(this.getValue));
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets a new change handler for number field.
|
||||
* @param {Function} handler New change handler, or null.
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.setValidator = function(handler) {
|
||||
var wrappedHandler;
|
||||
if (handler) {
|
||||
// Wrap the user's change handler together with the angle validator.
|
||||
wrappedHandler = function(value) {
|
||||
var v1 = handler.call(this, value);
|
||||
if (v1 === null) {
|
||||
var v2 = v1;
|
||||
} else {
|
||||
if (v1 === undefined) {
|
||||
v1 = value;
|
||||
}
|
||||
var v2 = this.numberValidator(v1);
|
||||
if (v2 === undefined) {
|
||||
v2 = v1;
|
||||
}
|
||||
}
|
||||
return v2 === value ? undefined : v2;
|
||||
};
|
||||
} else {
|
||||
wrappedHandler = this.numberValidator;
|
||||
}
|
||||
Blockly.FieldNumber.superClass_.setValidator.call(this, wrappedHandler);
|
||||
this.setValue(this.callValidator(this.getValue));
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @this {!Blockly.FieldNumber}
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.numberValidator = function(text) {
|
||||
Blockly.FieldNumber.classValidator = function(text) {
|
||||
if (text === null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -82,11 +82,11 @@ Blockly.FieldTextInput.prototype.setValue = function(text) {
|
|||
if (text === null) {
|
||||
return; // No change if null.
|
||||
}
|
||||
if (this.sourceBlock_ && this.validator_) {
|
||||
var validated = this.validator_(text);
|
||||
if (this.sourceBlock_) {
|
||||
var validated = this.callValidator(text);
|
||||
// If the new text is invalid, validation returns null.
|
||||
// In this case we still want to display the illegal result.
|
||||
if (validated !== null && validated !== undefined) {
|
||||
if (validated !== null) {
|
||||
text = validated;
|
||||
}
|
||||
}
|
||||
|
@ -114,11 +114,8 @@ Blockly.FieldTextInput.prototype.showEditor_ = function(opt_quietInput) {
|
|||
goog.userAgent.IPAD)) {
|
||||
// Mobile browsers have issues with in-line textareas (focus & keyboards).
|
||||
var newValue = window.prompt(Blockly.Msg.CHANGE_VALUE_TITLE, this.text_);
|
||||
if (this.sourceBlock_ && this.validator_) {
|
||||
var override = this.validator_(newValue);
|
||||
if (override !== undefined) {
|
||||
newValue = override;
|
||||
}
|
||||
if (this.sourceBlock_) {
|
||||
newValue = this.callValidator(newValue);
|
||||
}
|
||||
this.setValue(newValue);
|
||||
return;
|
||||
|
@ -210,8 +207,8 @@ Blockly.FieldTextInput.prototype.validate_ = function() {
|
|||
var valid = true;
|
||||
goog.asserts.assertObject(Blockly.FieldTextInput.htmlInput_);
|
||||
var htmlInput = Blockly.FieldTextInput.htmlInput_;
|
||||
if (this.sourceBlock_ && this.validator_) {
|
||||
valid = this.validator_(htmlInput.value);
|
||||
if (this.sourceBlock_) {
|
||||
valid = this.callValidator(htmlInput.value);
|
||||
}
|
||||
if (valid === null) {
|
||||
Blockly.addClass_(htmlInput, 'blocklyInvalidInput');
|
||||
|
@ -264,12 +261,12 @@ Blockly.FieldTextInput.prototype.widgetDispose_ = function() {
|
|||
var htmlInput = Blockly.FieldTextInput.htmlInput_;
|
||||
// Save the edit (if it validates).
|
||||
var text = htmlInput.value;
|
||||
if (thisField.sourceBlock_ && thisField.validator_) {
|
||||
var text1 = thisField.validator_(text);
|
||||
if (thisField.sourceBlock_) {
|
||||
var text1 = thisField.callValidator(text);
|
||||
if (text1 === null) {
|
||||
// Invalid edit.
|
||||
text = htmlInput.defaultValue;
|
||||
} else if (text1 !== undefined) {
|
||||
} else {
|
||||
// Validation function has changed the text.
|
||||
text = text1;
|
||||
}
|
||||
|
|
|
@ -48,35 +48,6 @@ Blockly.FieldVariable = function(varname, opt_validator) {
|
|||
};
|
||||
goog.inherits(Blockly.FieldVariable, Blockly.FieldDropdown);
|
||||
|
||||
/**
|
||||
* Sets a new change handler for angle field.
|
||||
* @param {Function} handler New change handler, or null.
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.setValidator = function(handler) {
|
||||
var wrappedHandler;
|
||||
if (handler) {
|
||||
// Wrap the user's change handler together with the variable rename handler.
|
||||
wrappedHandler = function(value) {
|
||||
var v1 = handler.call(this, value);
|
||||
if (v1 === null) {
|
||||
var v2 = v1;
|
||||
} else {
|
||||
if (v1 === undefined) {
|
||||
v1 = value;
|
||||
}
|
||||
var v2 = Blockly.FieldVariable.dropdownChange.call(this, v1);
|
||||
if (v2 === undefined) {
|
||||
v2 = v1;
|
||||
}
|
||||
}
|
||||
return v2 === value ? undefined : v2;
|
||||
};
|
||||
} else {
|
||||
wrappedHandler = Blockly.FieldVariable.dropdownChange;
|
||||
}
|
||||
Blockly.FieldVariable.superClass_.setValidator.call(this, wrappedHandler);
|
||||
};
|
||||
|
||||
/**
|
||||
* Install this dropdown on a block.
|
||||
*/
|
||||
|
@ -158,7 +129,7 @@ Blockly.FieldVariable.dropdownCreate = function() {
|
|||
* handled (rename), or undefined if an existing variable was chosen.
|
||||
* @this {!Blockly.FieldVariable}
|
||||
*/
|
||||
Blockly.FieldVariable.dropdownChange = function(text) {
|
||||
Blockly.FieldVariable.classValidator = function(text) {
|
||||
function promptName(promptText, defaultText) {
|
||||
Blockly.hideChaff();
|
||||
var newVar = window.prompt(promptText, defaultText);
|
||||
|
|
|
@ -712,7 +712,7 @@ Blockly.WorkspaceSvg.prototype.moveDrag = function(e) {
|
|||
|
||||
/**
|
||||
* Is the user currently dragging a block or scrolling the workspace?
|
||||
* @return {boolean} True if currently dragging or scrolling
|
||||
* @return {boolean} True if currently dragging or scrolling.
|
||||
*/
|
||||
Blockly.WorkspaceSvg.prototype.isDragging = function() {
|
||||
return Blockly.dragMode_ == Blockly.DRAG_FREE || this.isScrolling;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue