Validation textarea的Dojo验证

Validation textarea的Dojo验证,validation,textarea,dojo,required,Validation,Textarea,Dojo,Required,我第一次尝试使用dojo,所以这可能是显而易见的 我有一个非常简单的表格,里面有一个需要填写的文本区域 描述: 下一个 dijit.form.Textarea不进行任何验证。下面是一个自定义ValidationTextArea,供面临相同问题的任何人使用: dojo.provide(“dijit.form.ValidationTextArea”); dojo.require(“dojo.i18n”); require(“dijit.form.TextBox”); require(“dijit

我第一次尝试使用dojo,所以这可能是显而易见的

我有一个非常简单的表格,里面有一个需要填写的文本区域


描述:
下一个

dijit.form.Textarea不进行任何验证。下面是一个自定义ValidationTextArea,供面临相同问题的任何人使用:

dojo.provide(“dijit.form.ValidationTextArea”);
dojo.require(“dojo.i18n”);
require(“dijit.form.TextBox”);
require(“dijit.Tooltip”);
dojo.requireLocalization(“dijit.form”、“validate”);
/*=====
dijit.form.ValidationTextBox.\uu约束=函数(){
//地区:字符串
//用于验证的区域设置从该小部件的lang属性中提取值
//有什么事吗
//传递给regExpGen函数的各种标志
this.locale=“”;
这个;
}
=====*/
dojo.declare(
“dijit.form.ValidationTextArea”,
dijit.form.TextBox,
{
//总结:
//textbox小部件的基类,能够验证各种类型的内容并提供用户反馈。
//标签:
//保护
templateString:“”,
基类:“dijitTextArea”,
attributeMap:dojo.delegate(dijit.form.\u FormValueWidget.prototype.attributeMap{
行:“文本框”,列:“文本框”
}),
//行:编号
//文本的行数。
行:“3”,
//行:编号
//每行的字符数。
科尔斯:“20”,
//必填项:布尔值
//用户需要在此字段中输入数据。
必填项:false,
//提示消息:字符串
//如果已定义,则在文本框的焦点处立即显示此提示字符串(如果为空)。
//可以将其视为告诉用户要做什么的工具提示,而不是错误消息
//这会告诉用户他们做错了什么。
//
//当用户开始键入时,消息消失。
提示信息:“,
//invalidMessage:字符串
//值无效时显示的消息。
invalidMessage:“$\u unset\u$”,//如果未被覆盖,则从消息文件读取
//约束:dijit.form.ValidationTextBox.\u约束
//将参数传递给验证器函数所需的用户定义对象
约束:{},
//regExp:[扩展保护]字符串
//用于验证输入的正则表达式字符串
//不要同时指定regExp和regExpGen
regExp:“(.|[\r\n])*”,
regExpGen:function(/*dijit.form.ValidationTextBox.\uu约束*/Constraints){
//总结:
//当依赖于约束时,用于生成regExp的可重写函数。
//不要同时指定regExp和regExpGen。
//标签:
//扩展保护
返回this.regExp;//字符串
},
//状态:[只读]字符串
//显示输入(正常、警告或错误)的当前状态(即验证结果)
州:“,
//tooltipPosition:字符串[]
//有关此参数的详细信息,请参见“dijit.Tooltip.defaultPosition”的说明。
工具提示位置:[],
_setValueAttr:函数(){
//总结:
//钩子使attr('value',…)工作。
这是继承的(论点);
验证(以此为重点);
},
验证器:函数(/*anything*/value,/*dijit.form.ValidationTextBox.\uu约束*/Constraints){
//总结:
//用于根据正则表达式验证文本输入的可重写函数。
//标签:
//保护
返回(新的RegExp(“^(?“+this.regExpGen(约束)+”)+(this.required?”:“?”+“$”))。测试(值)&&
(!this.required | |!this._isEmpty(值))&&
(this._isEmpty(value)| this.parse(value,constraints)!==未定义);//布尔值
},
_isValidSubset:函数(){
//总结:
//如果值已经有效或可以通过追加字符使其有效,则返回true。
//这用于在用户[可能]仍在键入时进行验证。
返回this.textbox.value.search(this.\u partialre)==0;
},
isValid:函数(/*布尔*/isFocused){
//总结:
//测试值是否有效。
//可以在子类中用自己的例程重写。
//标签:
//保护
返回this.validator(this.textbox.value,this.constraints);
},
_isEmpty:函数(值){
//总结:
//检查空格
返回//^\s*$/.test(值);//布尔值
},
getErrorMessage:函数(/*Boolean*/isFocused){
//总结:
//如果合适,返回错误消息以显示
//标签:
//保护
返回this.invalidMessage;//字符串
},
getPromptMessage:函数(/*Boolean*/isFocused){
//总结:
//返回提示消息以显示小部件首次聚焦的时间
//标签:
//保护
返回this.promptMessage;//字符串
},
_maskValidSubsetError:是的,
验证:函数(/*Boolean*/isFocused){
//总结:
//由oninit、onblur和onkeypress调用。
//说明:
//如果合适,显示丢失或无效的消息,并突出显示文本框字段。
//标签:
//保护
var message=“”;
var isValid=this.disabled | | this
define("dijit/form/SimpleValidationTextArea", [
    "dojo/_base/declare", // declare
    "dojo/_base/kernel", // kernel.deprecated
    "dojo/i18n", // i18n.getLocalization
    "./TextBox",
    "../Tooltip",
    "dojo/text!./templates/ValidationTextBox.html",
    "dojo/dom-class", // domClass.add
    "dojo/sniff", // has("ie") has("opera")
    "dojo/i18n!./nls/validate"
], function(declare, kernel, i18n, TextBox, Tooltip, template, domClass, has){

//To use this widget you need to add this line to your css file
//errorBorder{ border-color: #D46464; }

var SimpleValidationTextArea;
return SimpleValidationTextArea = declare("dijit.form.SimpleValidationTextArea", TextBox, {
    /* from SimpleTextarea */

    // summary:
    //      A simple textarea that degrades, and responds to
    //      minimal LayoutContainer usage, and works with dijit/form/Form.
    //      Doesn't automatically size according to input, like Textarea.
    //
    // example:
    //  |   <textarea data-dojo-type="dijit/form/SimpleTextarea" name="foo" value="bar" rows=30 cols=40></textarea>
    //
    // example:
    //  |   new SimpleTextarea({ rows:20, cols:30 }, "foo");

    baseClass: "dijitValidationTextBox dijitTextArea",

    // rows: Number
    //      The number of rows of text.
    rows: "3",

    // rows: Number
    //      The number of characters per line.
    cols: "20",

    templateString: "<textarea ${!nameAttrSetting} data-dojo-attach-point='focusNode,containerNode,textbox' autocomplete='off'></textarea>",

    buildRendering: function(){
        this.inherited(arguments);
        if(has("ie") && this.cols){ // attribute selectors is not supported in IE6
            domClass.add(this.textbox, "dijitTextAreaCols");
        }
    },

    filter: function(/*String*/ value){
        // Override TextBox.filter to deal with newlines... specifically (IIRC) this is for IE which writes newlines
        // as \r\n instead of just \n
        if(value){
            value = value.replace(/\r/g,"");
        }
        return this.inherited(arguments);
    },

    _onInput: function(/*Event?*/ e){
        // Override TextBox._onInput() to enforce maxLength restriction
        if(this.maxLength){
            var maxLength = parseInt(this.maxLength);
            var value = this.textbox.value.replace(/\r/g,'');
            var overflow = value.length - maxLength;
            if(overflow > 0){
                var textarea = this.textbox;
                if(textarea.selectionStart){
                    var pos = textarea.selectionStart;
                    var cr = 0;
                    if(has("opera")){
                        cr = (this.textbox.value.substring(0,pos).match(/\r/g) || []).length;
                    }
                    this.textbox.value = value.substring(0,pos-overflow-cr)+value.substring(pos-cr);
                    textarea.setSelectionRange(pos-overflow, pos-overflow);
                }else if(this.ownerDocument.selection){ //IE
                    textarea.focus();
                    var range = this.ownerDocument.selection.createRange();
                    // delete overflow characters
                    range.moveStart("character", -overflow);
                    range.text = '';
                    // show cursor
                    range.select();
                }
            }
        }
        this.inherited(arguments);
    },

    /* -from SimpleTextarea */

    // summary:
    //      Base class for textbox widgets with the ability to validate content of various types and provide user feedback.

    // required: Boolean
    //      User is required to enter data into this field.
    required: false,

    // promptMessage: String
    //      If defined, display this hint string immediately on focus to the textbox, if empty.
    //      Also displays if the textbox value is Incomplete (not yet valid but will be with additional input).
    //      Think of this like a tooltip that tells the user what to do, not an error message
    //      that tells the user what they've done wrong.
    //
    //      Message disappears when user starts typing.
    promptMessage: "",

    // invalidMessage: String
    //      The message to display if value is invalid.
    //      The translated string value is read from the message file by default.
    //      Set to "" to use the promptMessage instead.
    invalidMessage: "$_unset_$",

    // missingMessage: String
    //      The message to display if value is empty and the field is required.
    //      The translated string value is read from the message file by default.
    //      Set to "" to use the invalidMessage instead.
    missingMessage: "$_unset_$",

    // message: String
    //      Currently error/prompt message.
    //      When using the default tooltip implementation, this will only be
    //      displayed when the field is focused.
    message: "",

    // constraints: __Constraints
    //      user-defined object needed to pass parameters to the validator functions
    constraints: {},

    // pattern: [extension protected] String|Function(constraints) returning a string.
    //      This defines the regular expression used to validate the input.
    //      Do not add leading ^ or $ characters since the widget adds these.
    //      A function may be used to generate a valid pattern when dependent on constraints or other runtime factors.
    //      set('pattern', String|Function).
    pattern: ".*",

    // regExp: Deprecated [extension protected] String.  Use "pattern" instead.
    regExp: "",

    regExpGen: function(/*__Constraints*/ /*===== constraints =====*/){
        // summary:
        //      Deprecated.  Use set('pattern', Function) instead.
    },

    // state: [readonly] String
    //      Shows current state (ie, validation result) of input (""=Normal, Incomplete, or Error)
    state: "",

    // tooltipPosition: String[]
    //      See description of `dijit/Tooltip.defaultPosition` for details on this parameter.
    tooltipPosition: [],

    _deprecateRegExp: function(attr, value){
        if(value != SimpleValidationTextArea.prototype[attr]){
            kernel.deprecated("SimpleValidationTextArea id="+this.id+", set('" + attr + "', ...) is deprecated.  Use set('pattern', ...) instead.", "", "2.0");
            this.set('pattern', value);
        }
    },
    _setRegExpGenAttr: function(/*Function*/ newFcn){
        this._deprecateRegExp("regExpGen", newFcn);
        this.regExpGen = this._getPatternAttr; // backward compat with this.regExpGen(this.constraints)
    },
    _setRegExpAttr: function(/*String*/ value){
        this._deprecateRegExp("regExp", value);
    },

    _setValueAttr: function(){
        // summary:
        //      Hook so set('value', ...) works.
        this.inherited(arguments);
        this.validate(this.focused);
    },

    validator: function(/*anything*/ value, /*__Constraints*/ constraints){
        // summary:
        //      Overridable function used to validate the text input against the regular expression.
        // tags:
        //      protected
        return (new RegExp("^(?:" + this._getPatternAttr(constraints) + ")"+(this.required?"":"?")+"$")).test(value) &&
            (!this.required || !this._isEmpty(value)) &&
            (this._isEmpty(value) || this.parse(value, constraints) !== undefined); // Boolean
    },

    _isValidSubset: function(){
        // summary:
        //      Returns true if the value is either already valid or could be made valid by appending characters.
        //      This is used for validation while the user [may be] still typing.
        return this.textbox.value.search(this._partialre) == 0;
    },

    isValid: function(/*Boolean*/ /*===== isFocused =====*/){
        // summary:
        //      Tests if value is valid.
        //      Can override with your own routine in a subclass.
        // tags:
        //      protected
        return this.validator(this.textbox.value, this.constraints);
    },

    _isEmpty: function(value){
        // summary:
        //      Checks for whitespace
        return (this.trim ? /^\s*$/ : /^$/).test(value); // Boolean
    },

    getErrorMessage: function(/*Boolean*/ /*===== isFocused =====*/){
        // summary:
        //      Return an error message to show if appropriate
        // tags:
        //      protected
        var invalid = this.invalidMessage == "$_unset_$" ? this.messages.invalidMessage :
            !this.invalidMessage ? this.promptMessage : this.invalidMessage;
        var missing = this.missingMessage == "$_unset_$" ? this.messages.missingMessage :
            !this.missingMessage ? invalid : this.missingMessage;
        return (this.required && this._isEmpty(this.textbox.value)) ? missing : invalid; // String
    },

    getPromptMessage: function(/*Boolean*/ /*===== isFocused =====*/){
        // summary:
        //      Return a hint message to show when widget is first focused
        // tags:
        //      protected
        return this.promptMessage; // String
    },

    _maskValidSubsetError: true,
    validate: function(/*Boolean*/ isFocused){
        // summary:
        //      Called by oninit, onblur, and onkeypress.
        // description:
        //      Show missing or invalid messages if appropriate, and highlight textbox field.
        // tags:
        //      protected
        var message = "";
        var isValid = this.disabled || this.isValid(isFocused);
        if(isValid){ this._maskValidSubsetError = true; }
        var isEmpty = this._isEmpty(this.textbox.value);
        var isValidSubset = !isValid && isFocused && this._isValidSubset();
        this._set("state", isValid ? "" : (((((!this._hasBeenBlurred || isFocused) && isEmpty) || isValidSubset) && (this._maskValidSubsetError || (isValidSubset && !this._hasBeenBlurred && isFocused))) ? "Incomplete" : "Error"));
        this.focusNode.setAttribute("aria-invalid", isValid ? "false" : "true");

        if(this.state == "Error"){
            this._maskValidSubsetError = isFocused && isValidSubset; // we want the error to show up after a blur and refocus
            message = this.getErrorMessage(isFocused);
            domClass.add(this.domNode, "errorBorder");
        }else if(this.state == "Incomplete"){
            message = this.getPromptMessage(isFocused); // show the prompt whenever the value is not yet complete
            this._maskValidSubsetError = !this._hasBeenBlurred || isFocused; // no Incomplete warnings while focused
        }else if(isEmpty){
            message = this.getPromptMessage(isFocused); // show the prompt whenever there's no error and no text
        }else if(this.state == ''){ //everything is fine
            domClass.remove(this.domNode, "errorBorder");
        }
        this.set("message", message);

        return isValid;
    },

    displayMessage: function(/*String*/ message){
        // summary:
        //      Overridable method to display validation errors/hints.
        //      By default uses a tooltip.
        // tags:
        //      extension
        if(message && this.focused){
            Tooltip.show(message, this.domNode, this.tooltipPosition, !this.isLeftToRight());
        }else{
            Tooltip.hide(this.domNode);
        }
    },

    _refreshState: function(){
        // Overrides TextBox._refreshState()
        if(this._created){
            this.validate(this.focused);
        }
        this.inherited(arguments);
    },

    //////////// INITIALIZATION METHODS ///////////////////////////////////////

    constructor: function(params /*===== , srcNodeRef =====*/){
        // summary:
        //      Create the widget.
        // params: Object|null
        //      Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
        //      and functions, typically callbacks like onClick.
        //      The hash can contain any of the widget's properties, excluding read-only properties.
        // srcNodeRef: DOMNode|String?
        //      If a srcNodeRef (DOM node) is specified, replace srcNodeRef with my generated DOM tree.

        this.constraints = {};
        this.baseClass += ' dijitSimpleValidationTextArea';
    },

    startup: function(){
        this.inherited(arguments);
        this._refreshState(); // after all _set* methods have run
    },

    _setConstraintsAttr: function(/*__Constraints*/ constraints){
        if(!constraints.locale && this.lang){
            constraints.locale = this.lang;
        }
        this._set("constraints", constraints);
        this._refreshState();
    },

    _setPatternAttr: function(/*String|Function*/ pattern){
        this._set("pattern", pattern); // don't set on INPUT to avoid native HTML5 validation
    },

    _getPatternAttr: function(/*__Constraints*/ constraints){
        // summary:
        //      Hook to get the current regExp and to compute the partial validation RE.
        var p = this.pattern;
        var type = (typeof p).toLowerCase();
        if(type == "function"){
            p = this.pattern(constraints || this.constraints);
        }
        if(p != this._lastRegExp){
            var partialre = "";
            this._lastRegExp = p;
            // parse the regexp and produce a new regexp that matches valid subsets
            // if the regexp is .* then there's no use in matching subsets since everything is valid
            if(p != ".*"){
                p.replace(/\\.|\[\]|\[.*?[^\\]{1}\]|\{.*?\}|\(\?[=:!]|./g,
                function(re){
                    switch(re.charAt(0)){
                        case '{':
                        case '+':
                        case '?':
                        case '*':
                        case '^':
                        case '$':
                        case '|':
                        case '(':
                            partialre += re;
                            break;
                        case ")":
                            partialre += "|$)";
                            break;
                         default:
                            partialre += "(?:"+re+"|$)";
                            break;
                    }
                });
            }
            try{ // this is needed for now since the above regexp parsing needs more test verification
                "".search(partialre);
            }catch(e){ // should never be here unless the original RE is bad or the parsing is bad
                partialre = this.pattern;
                console.warn('RegExp error in ' + this.declaredClass + ': ' + this.pattern);
            } // should never be here unless the original RE is bad or the parsing is bad
            this._partialre = "^(?:" + partialre + ")$";
        }
        return p;
    },

    postMixInProperties: function(){
        if(!this.value && this.srcNodeRef){
            this.value = this.srcNodeRef.value;
        }
        this.inherited(arguments);
        this.messages = i18n.getLocalization("dijit.form", "validate", this.lang);
        this._setConstraintsAttr(this.constraints); // this needs to happen now (and later) due to codependency on _set*Attr calls attachPoints
    },

    _setDisabledAttr: function(/*Boolean*/ value){
        this.inherited(arguments);  // call FormValueWidget._setDisabledAttr()
        this._refreshState();
    },

    _setRequiredAttr: function(/*Boolean*/ value){
        this._set("required", value);
        this.focusNode.setAttribute("aria-required", value);
        this._refreshState();
    },

    _setMessageAttr: function(/*String*/ message){
        this._set("message", message);
        this.displayMessage(message);
    },

    reset:function(){
        // Overrides dijit/form/TextBox.reset() by also
        // hiding errors about partial matches
        this._maskValidSubsetError = true;
        this.inherited(arguments);
    },

    _onBlur: function(){
        // the message still exists but for back-compat, and to erase the tooltip
        // (if the message is being displayed as a tooltip), call displayMessage('')
        this.displayMessage('');

        this.inherited(arguments);
    }
});
});
define("custom/ValidationTextarea", [
"dojo/_base/declare", // declare
"dojo/dom-class", // domClass.add
"dojo/sniff", // has("ie") has("opera")
"dijit/form/ValidationTextBox"
], function(declare, domClass, has, ValidationTextBox){

return declare("custom/ValidationTextarea", ValidationTextBox, {        

    baseClass: "dijitValidationTextBox dijitTextBox dijitTextArea",

...
    pattern: "[\\S\\s]+", /* Match not-whitepsace or whitespace. Default pattern for ValidationTextBox is .* which does not match new line characters */

... remaining lines