mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Merge pull request #4747 from GogoVega/tooltip-input-validation
Add tooltip and message validation to `typedInput`
This commit is contained in:
		| @@ -367,7 +367,8 @@ | |||||||
|             valueLabel: contextLabel, |             valueLabel: contextLabel, | ||||||
|             autoComplete: contextAutoComplete |             autoComplete: contextAutoComplete | ||||||
|         }, |         }, | ||||||
|         global: {value:"global",label:"global.",hasValue:true, |         global: { | ||||||
|  |             value: "global", label: "global.", hasValue: true, | ||||||
|             options: [], |             options: [], | ||||||
|             validate: RED.utils.validatePropertyExpression, |             validate: RED.utils.validatePropertyExpression, | ||||||
|             parse: contextParse, |             parse: contextParse, | ||||||
| @@ -376,15 +377,17 @@ | |||||||
|             autoComplete: contextAutoComplete |             autoComplete: contextAutoComplete | ||||||
|         }, |         }, | ||||||
|         str: { value: "str", label: "string", icon: "red/images/typedInput/az.svg" }, |         str: { value: "str", label: "string", icon: "red/images/typedInput/az.svg" }, | ||||||
|         num: {value:"num",label:"number",icon:"red/images/typedInput/09.svg",validate: function(v) { |         num: { value: "num", label: "number", icon: "red/images/typedInput/09.svg", validate: function (v, o) { | ||||||
|             return (true === RED.utils.validateTypedProperty(v, "num")); |             return RED.utils.validateTypedProperty(v, "num", o); | ||||||
|         } }, |         } }, | ||||||
|         bool: { value: "bool", label: "boolean", icon: "red/images/typedInput/bool.svg", options: ["true", "false"] }, |         bool: { value: "bool", label: "boolean", icon: "red/images/typedInput/bool.svg", options: ["true", "false"] }, | ||||||
|         json: { |         json: { | ||||||
|             value: "json", |             value: "json", | ||||||
|             label: "JSON", |             label: "JSON", | ||||||
|             icon: "red/images/typedInput/json.svg", |             icon: "red/images/typedInput/json.svg", | ||||||
|             validate: function(v) { try{JSON.parse(v);return true;}catch(e){return false;}}, |             validate: function (v, o) { | ||||||
|  |                 return RED.utils.validateTypedProperty(v, "json", o); | ||||||
|  |             }, | ||||||
|             expand: function () { |             expand: function () { | ||||||
|                 var that = this; |                 var that = this; | ||||||
|                 var value = this.value(); |                 var value = this.value(); | ||||||
| @@ -431,7 +434,9 @@ | |||||||
|             value: "jsonata", |             value: "jsonata", | ||||||
|             label: "expression", |             label: "expression", | ||||||
|             icon: "red/images/typedInput/expr.svg", |             icon: "red/images/typedInput/expr.svg", | ||||||
|             validate: function(v) { try{jsonata(v);return true;}catch(e){return false;}}, |             validate: function (v, o) { | ||||||
|  |                 return RED.utils.validateTypedProperty(v, "jsonata", o); | ||||||
|  |             }, | ||||||
|             expand: function () { |             expand: function () { | ||||||
|                 var that = this; |                 var that = this; | ||||||
|                 RED.editor.editExpression({ |                 RED.editor.editExpression({ | ||||||
| @@ -1538,26 +1543,48 @@ | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         validate: function() { |         validate: function(options) { | ||||||
|             var result; |             let valid = true; | ||||||
|             var value = this.value(); |             const value = this.value(); | ||||||
|             var type = this.type(); |             const type = this.type(); | ||||||
|             if (this.typeMap[type] && this.typeMap[type].validate) { |             if (this.typeMap[type] && this.typeMap[type].validate) { | ||||||
|                 var val = this.typeMap[type].validate; |                 const validate = this.typeMap[type].validate; | ||||||
|                 if (typeof val === 'function') { |                 if (typeof validate === 'function') { | ||||||
|                     result = val(value); |                     valid = validate(value, {}); | ||||||
|                 } else { |                 } else { | ||||||
|                     result = val.test(value); |                     // Regex | ||||||
|  |                     valid = validate.test(value); | ||||||
|  |                     if (!valid) { | ||||||
|  |                         valid = RED._("validator.errors.invalid-regexp"); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             if ((typeof valid === "string") || !valid) { | ||||||
|  |                 this.element.addClass("input-error"); | ||||||
|  |                 this.uiSelect.addClass("input-error"); | ||||||
|  |                 if (typeof valid === "string") { | ||||||
|  |                     let tooltip = this.element.data("tooltip"); | ||||||
|  |                     if (tooltip) { | ||||||
|  |                         tooltip.setContent(valid); | ||||||
|  |                     } else { | ||||||
|  |                         tooltip = RED.popover.tooltip(this.elementDiv, valid); | ||||||
|  |                         this.element.data("tooltip", tooltip); | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 result = true; |                 this.element.removeClass("input-error"); | ||||||
|  |                 this.uiSelect.removeClass("input-error"); | ||||||
|  |                 const tooltip = this.element.data("tooltip"); | ||||||
|  |                 if (tooltip) { | ||||||
|  |                     this.element.data("tooltip", null); | ||||||
|  |                     tooltip.delete(); | ||||||
|                 } |                 } | ||||||
|             if (result) { |  | ||||||
|                 this.uiSelect.removeClass('input-error'); |  | ||||||
|             } else { |  | ||||||
|                 this.uiSelect.addClass('input-error'); |  | ||||||
|             } |             } | ||||||
|             return result; |             if (options?.returnErrorMessage === true) { | ||||||
|  |                 return valid; | ||||||
|  |             } | ||||||
|  |             // Must return a boolean for no 3.x validator | ||||||
|  |             return (typeof valid === "string") ? false : valid; | ||||||
|         }, |         }, | ||||||
|         show: function() { |         show: function() { | ||||||
|             this.uiSelect.show(); |             this.uiSelect.show(); | ||||||
|   | |||||||
| @@ -190,7 +190,10 @@ RED.editor = (function() { | |||||||
|                 const input = $("#"+prefix+"-"+property); |                 const input = $("#"+prefix+"-"+property); | ||||||
|                 const isTypedInput = input.length > 0 && input.next(".red-ui-typedInput-container").length > 0; |                 const isTypedInput = input.length > 0 && input.next(".red-ui-typedInput-container").length > 0; | ||||||
|                 if (isTypedInput) { |                 if (isTypedInput) { | ||||||
|                     valid = input.typedInput("validate"); |                     valid = input.typedInput("validate", { returnErrorMessage: true }); | ||||||
|  |                     if (typeof valid === "string") { | ||||||
|  |                         return label ? label + ": " + valid : valid; | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -901,11 +901,25 @@ RED.utils = (function() { | |||||||
|         return parts; |         return parts; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function validatePropertyExpression(str) { |     /** | ||||||
|  |      * Validate a property expression | ||||||
|  |      * @param {*} str - the property value | ||||||
|  |      * @returns {boolean|string} whether the node proprty is valid. `true`: valid `false|String`: invalid | ||||||
|  |      */ | ||||||
|  |     function validatePropertyExpression(str, opt) { | ||||||
|         try { |         try { | ||||||
|             var parts = normalisePropertyExpression(str); |             const parts = normalisePropertyExpression(str); | ||||||
|             return true; |             return true; | ||||||
|         } catch(err) { |         } catch(err) { | ||||||
|  |             // If the validator has opt, it is a 3.x validator that | ||||||
|  |             // can return a String to mean 'invalid' and provide a reason | ||||||
|  |             if (opt) { | ||||||
|  |                 if (opt.label) { | ||||||
|  |                     return opt.label + ': ' + err.message; | ||||||
|  |                 } | ||||||
|  |                 return err.message; | ||||||
|  |             } | ||||||
|  |             // Otherwise, a 2.x returns a false value | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -923,22 +937,24 @@ RED.utils = (function() { | |||||||
|             // Allow ${ENV_VAR} value |             // Allow ${ENV_VAR} value | ||||||
|             return true |             return true | ||||||
|         } |         } | ||||||
|         let error |         let error; | ||||||
|         if (propertyType === 'json') { |         if (propertyType === 'json') { | ||||||
|             try { |             try { | ||||||
|                 JSON.parse(propertyValue); |                 JSON.parse(propertyValue); | ||||||
|             } catch(err) { |             } catch(err) { | ||||||
|                 error = RED._("validator.errors.invalid-json", { |                 error = RED._("validator.errors.invalid-json", { | ||||||
|                     error: err.message |                     error: err.message | ||||||
|                 }) |                 }); | ||||||
|             } |             } | ||||||
|         } else if (propertyType === 'msg' || propertyType === 'flow' || propertyType === 'global' ) { |         } else if (propertyType === 'msg' || propertyType === 'flow' || propertyType === 'global' ) { | ||||||
|             if (!RED.utils.validatePropertyExpression(propertyValue)) { |             // To avoid double label | ||||||
|                 error = RED._("validator.errors.invalid-prop") |             const valid = RED.utils.validatePropertyExpression(propertyValue, opt ? {} : null); | ||||||
|  |             if (valid !== true) { | ||||||
|  |                 error = opt ? valid : RED._("validator.errors.invalid-prop"); | ||||||
|             } |             } | ||||||
|         } else if (propertyType === 'num') { |         } else if (propertyType === 'num') { | ||||||
|             if (!/^NaN$|^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$|^[+-]?(0b|0B)[01]+$|^[+-]?(0o|0O)[0-7]+$|^[+-]?(0x|0X)[0-9a-fA-F]+$/.test(propertyValue)) { |             if (!/^NaN$|^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$|^[+-]?(0b|0B)[01]+$|^[+-]?(0o|0O)[0-7]+$|^[+-]?(0x|0X)[0-9a-fA-F]+$/.test(propertyValue)) { | ||||||
|                 error = RED._("validator.errors.invalid-num") |                 error = RED._("validator.errors.invalid-num"); | ||||||
|             } |             } | ||||||
|         } else if (propertyType === 'jsonata') { |         } else if (propertyType === 'jsonata') { | ||||||
|             try {  |             try {  | ||||||
| @@ -946,16 +962,16 @@ RED.utils = (function() { | |||||||
|             } catch(err) { |             } catch(err) { | ||||||
|                 error = RED._("validator.errors.invalid-expr", { |                 error = RED._("validator.errors.invalid-expr", { | ||||||
|                     error: err.message |                     error: err.message | ||||||
|                 }) |                 }); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if (error) { |         if (error) { | ||||||
|             if (opt && opt.label) { |             if (opt && opt.label) { | ||||||
|                 return opt.label+': '+error |                 return opt.label + ': ' + error; | ||||||
|             } |             } | ||||||
|             return error |             return error; | ||||||
|         } |         } | ||||||
|         return true |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function getMessageProperty(msg,expr) { |     function getMessageProperty(msg,expr) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user