From c87ee6a0e7c2e0fa917a10b67a1d0fb3350b9dac Mon Sep 17 00:00:00 2001 From: Gary Sharp Date: Sat, 10 May 2014 20:26:57 +1000 Subject: [PATCH] Update: jQuery Validate & Unobtrusive Updated --- Disco.Web/ClientSource/Scripts/Core.js | 1065 +++++++++-------- Disco.Web/ClientSource/Scripts/Core.js.bundle | 6 +- Disco.Web/ClientSource/Scripts/Core.min.js | 2 +- .../ClientSource/Scripts/Core.min.js.map | 4 +- .../Scripts/Core/jquery.validate-vsdoc.js | 4 +- .../Scripts/Core/jquery.validate.js | 342 +++--- .../Core/jquery.validate.unobtrusive.js | 722 +++++------ Disco.Web/Disco.Web.csproj | 6 +- Disco.Web/packages.config | 4 +- 9 files changed, 1189 insertions(+), 966 deletions(-) diff --git a/Disco.Web/ClientSource/Scripts/Core.js b/Disco.Web/ClientSource/Scripts/Core.js index eb7b1932..027b5822 100644 --- a/Disco.Web/ClientSource/Scripts/Core.js +++ b/Disco.Web/ClientSource/Scripts/Core.js @@ -10226,20 +10226,17 @@ if ( typeof window === "object" && typeof window.document === "object" ) { ///#source 1 1 /ClientSource/Scripts/Core/jquery.validate.js /*! - * jQuery Validation Plugin 1.11.1 + * jQuery Validation Plugin v1.12.0 * - * http://bassistance.de/jquery-plugins/jquery-plugin-validation/ - * http://docs.jquery.com/Plugins/Validation + * http://jqueryvalidation.org/ * - * Copyright 2013 Jörn Zaefferer - * Released under the MIT license: - * http://www.opensource.org/licenses/mit-license.php + * Copyright (c) 2014 Jörn Zaefferer + * Released under the MIT license */ - (function($) { $.extend($.fn, { - // http://docs.jquery.com/Plugins/Validation/validate + // http://jqueryvalidation.org/validate/ validate: function( options ) { // if nothing is selected, return nothing; can't chain anyway @@ -10322,20 +10319,22 @@ $.extend($.fn, { return validator; }, - // http://docs.jquery.com/Plugins/Validation/valid + // http://jqueryvalidation.org/valid/ valid: function() { + var valid, validator; + if ( $(this[0]).is("form")) { - return this.validate().form(); + valid = this.validate().form(); } else { - var valid = true; - var validator = $(this[0].form).validate(); + valid = true; + validator = $(this[0].form).validate(); this.each(function() { - valid = valid && validator.element(this); + valid = validator.element(this) && valid; }); - return valid; } + return valid; }, - // attributes: space seperated list of attributes to retrieve and remove + // attributes: space separated list of attributes to retrieve and remove removeAttrs: function( attributes ) { var result = {}, $element = this; @@ -10345,18 +10344,19 @@ $.extend($.fn, { }); return result; }, - // http://docs.jquery.com/Plugins/Validation/rules + // http://jqueryvalidation.org/rules/ rules: function( command, argument ) { - var element = this[0]; + var element = this[0], + settings, staticRules, existingRules, data, param, filtered; if ( command ) { - var settings = $.data(element.form, "validator").settings; - var staticRules = settings.rules; - var existingRules = $.validator.staticRules(element); - switch(command) { + settings = $.data(element.form, "validator").settings; + staticRules = settings.rules; + existingRules = $.validator.staticRules(element); + switch (command) { case "add": $.extend(existingRules, $.validator.normalizeRule(argument)); - // remove messages from rules, but allow them to be set separetely + // remove messages from rules, but allow them to be set separately delete existingRules.messages; staticRules[element.name] = existingRules; if ( argument.messages ) { @@ -10368,16 +10368,19 @@ $.extend($.fn, { delete staticRules[element.name]; return existingRules; } - var filtered = {}; + filtered = {}; $.each(argument.split(/\s/), function( index, method ) { filtered[method] = existingRules[method]; delete existingRules[method]; + if ( method === "required" ) { + $(element).removeAttr("aria-required"); + } }); return filtered; } } - var data = $.validator.normalizeRules( + data = $.validator.normalizeRules( $.extend( {}, $.validator.classRules(element), @@ -10388,9 +10391,17 @@ $.extend($.fn, { // make sure required is at front if ( data.required ) { - var param = data.required; + param = data.required; delete data.required; - data = $.extend({required: param}, data); + data = $.extend({ required: param }, data ); + $(element).attr( "aria-required", "true" ); + } + + // make sure remote is at back + if ( data.remote ) { + param = data.remote; + delete data.remote; + data = $.extend( data, { remote: param }); } return data; @@ -10399,11 +10410,11 @@ $.extend($.fn, { // Custom selectors $.extend($.expr[":"], { - // http://docs.jquery.com/Plugins/Validation/blank + // http://jqueryvalidation.org/blank-selector/ blank: function( a ) { return !$.trim("" + $(a).val()); }, - // http://docs.jquery.com/Plugins/Validation/filled + // http://jqueryvalidation.org/filled-selector/ filled: function( a ) { return !!$.trim("" + $(a).val()); }, - // http://docs.jquery.com/Plugins/Validation/unchecked + // http://jqueryvalidation.org/unchecked-selector/ unchecked: function( a ) { return !$(a).prop("checked"); } }); @@ -10414,6 +10425,7 @@ $.validator = function( options, form ) { this.init(); }; +// http://jqueryvalidation.org/jQuery.validator.format/ $.validator.format = function( source, params ) { if ( arguments.length === 1 ) { return function() { @@ -10451,7 +10463,7 @@ $.extend($.validator, { onsubmit: true, ignore: ":hidden", ignoreTitle: false, - onfocusin: function( element, event ) { + onfocusin: function( element ) { this.lastActive = element; // hide error label and remove error class on focus if enabled @@ -10462,7 +10474,7 @@ $.extend($.validator, { this.addWrapper(this.errorsFor(element)).hide(); } }, - onfocusout: function( element, event ) { + onfocusout: function( element ) { if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) { this.element(element); } @@ -10474,13 +10486,13 @@ $.extend($.validator, { this.element(element); } }, - onclick: function( element, event ) { + onclick: function( element ) { // click on selects, radiobuttons and checkboxes if ( element.name in this.submitted ) { this.element(element); - } + // or option elements, check parent select in that case - else if ( element.parentNode.name in this.submitted ) { + } else if ( element.parentNode.name in this.submitted ) { this.element(element.parentNode); } }, @@ -10500,7 +10512,7 @@ $.extend($.validator, { } }, - // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults + // http://jqueryvalidation.org/jQuery.validator.setDefaults/ setDefaults: function( settings ) { $.extend( $.validator.defaults, settings ); }, @@ -10539,7 +10551,8 @@ $.extend($.validator, { this.invalid = {}; this.reset(); - var groups = (this.groups = {}); + var groups = (this.groups = {}), + rules; $.each(this.settings.groups, function( key, value ) { if ( typeof value === "string" ) { value = value.split(/\s/); @@ -10548,16 +10561,17 @@ $.extend($.validator, { groups[name] = key; }); }); - var rules = this.settings.rules; + rules = this.settings.rules; $.each(rules, function( key, value ) { rules[key] = $.validator.normalizeRule(value); }); function delegate(event) { var validator = $.data(this[0].form, "validator"), - eventType = "on" + event.type.replace(/^validate/, ""); - if ( validator.settings[eventType] ) { - validator.settings[eventType].call(validator, this[0], event); + eventType = "on" + event.type.replace(/^validate/, ""), + settings = validator.settings; + if ( settings[eventType] && !this.is( settings.ignore ) ) { + settings[eventType].call(validator, this[0], event); } } $(this.currentForm) @@ -10572,15 +10586,19 @@ $.extend($.validator, { if ( this.settings.invalidHandler ) { $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler); } + + // Add aria-required to any Static/Data/Class required fields before first validation + // Screen readers require this attribute to be present before the initial submission http://www.w3.org/TR/WCAG-TECHS/ARIA2.html + $(this.currentForm).find("[required], [data-rule-required], .required").attr("aria-required", "true"); }, - // http://docs.jquery.com/Plugins/Validation/Validator/form + // http://jqueryvalidation.org/Validator.form/ form: function() { this.checkForm(); $.extend(this.submitted, this.errorMap); this.invalid = $.extend({}, this.errorMap); if ( !this.valid() ) { - $(this.currentForm).triggerHandler("invalid-form", [this]); + $(this.currentForm).triggerHandler("invalid-form", [ this ]); } this.showErrors(); return this.valid(); @@ -10594,18 +10612,30 @@ $.extend($.validator, { return this.valid(); }, - // http://docs.jquery.com/Plugins/Validation/Validator/element + // http://jqueryvalidation.org/Validator.element/ element: function( element ) { - element = this.validationTargetFor( this.clean( element ) ); - this.lastElement = element; - this.prepareElement( element ); - this.currentElements = $(element); - var result = this.check( element ) !== false; - if ( result ) { - delete this.invalid[element.name]; + var cleanElement = this.clean( element ), + checkElement = this.validationTargetFor( cleanElement ), + result = true; + + this.lastElement = checkElement; + + if ( checkElement === undefined ) { + delete this.invalid[ cleanElement.name ]; } else { - this.invalid[element.name] = true; + this.prepareElement( checkElement ); + this.currentElements = $( checkElement ); + + result = this.check( checkElement ) !== false; + if (result) { + delete this.invalid[checkElement.name]; + } else { + this.invalid[checkElement.name] = true; + } } + // Add aria-invalid status for screen readers + $( element ).attr( "aria-invalid", !result ); + if ( !this.numberOfInvalids() ) { // Hide error containers on last error this.toHide = this.toHide.add( this.containers ); @@ -10614,7 +10644,7 @@ $.extend($.validator, { return result; }, - // http://docs.jquery.com/Plugins/Validation/Validator/showErrors + // http://jqueryvalidation.org/Validator.showErrors/ showErrors: function( errors ) { if ( errors ) { // add items to error list and map @@ -10638,7 +10668,7 @@ $.extend($.validator, { } }, - // http://docs.jquery.com/Plugins/Validation/Validator/resetForm + // http://jqueryvalidation.org/Validator.resetForm/ resetForm: function() { if ( $.fn.resetForm ) { $(this.currentForm).resetForm(); @@ -10647,7 +10677,10 @@ $.extend($.validator, { this.lastElement = null; this.prepareForm(); this.hideErrors(); - this.elements().removeClass( this.settings.errorClass ).removeData( "previousValue" ); + this.elements() + .removeClass( this.settings.errorClass ) + .removeData( "previousValue" ) + .removeAttr( "aria-invalid" ); }, numberOfInvalids: function() { @@ -10655,8 +10688,10 @@ $.extend($.validator, { }, objectLength: function( obj ) { - var count = 0; - for ( var i in obj ) { + /* jshint unused: false */ + var count = 0, + i; + for ( i in obj ) { count++; } return count; @@ -10724,7 +10759,7 @@ $.extend($.validator, { }, errors: function() { - var errorClass = this.settings.errorClass.replace(" ", "."); + var errorClass = this.settings.errorClass.split(" ").join("."); return $(this.settings.errorElement + "." + errorClass, this.errorContext); }, @@ -10748,13 +10783,15 @@ $.extend($.validator, { }, elementValue: function( element ) { - var type = $(element).attr("type"), - val = $(element).val(); + var val, + $element = $(element), + type = $element.attr("type"); if ( type === "radio" || type === "checkbox" ) { - return $("input[name='" + $(element).attr("name") + "']:checked").val(); + return $("input[name='" + $element.attr("name") + "']:checked").val(); } + val = $element.val(); if ( typeof val === "string" ) { return val.replace(/\r/g, ""); } @@ -10764,20 +10801,23 @@ $.extend($.validator, { check: function( element ) { element = this.validationTargetFor( this.clean( element ) ); - var rules = $(element).rules(); - var dependencyMismatch = false; - var val = this.elementValue(element); - var result; + var rules = $(element).rules(), + rulesCount = $.map( rules, function(n, i) { + return i; + }).length, + dependencyMismatch = false, + val = this.elementValue(element), + result, method, rule; - for (var method in rules ) { - var rule = { method: method, parameters: rules[method] }; + for (method in rules ) { + rule = { method: method, parameters: rules[method] }; try { result = $.validator.methods[method].call( this, val, element, rule.parameters ); // if a method indicates that the field is optional and therefore valid, // don't mark it as valid when there are no other rules - if ( result === "dependency-mismatch" ) { + if ( result === "dependency-mismatch" && rulesCount === 1 ) { dependencyMismatch = true; continue; } @@ -10810,8 +10850,10 @@ $.extend($.validator, { // return the custom message for the given element and validation method // specified in the element's HTML5 data attribute + // return the generic message if present and no method specific message is present customDataMessage: function( element, method ) { - return $(element).data("msg-" + method.toLowerCase()) || (element.attributes && $(element).attr("data-msg-" + method.toLowerCase())); + return $( element ).data( "msg" + method[ 0 ].toUpperCase() + + method.substring( 1 ).toLowerCase() ) || $( element ).data("msg"); }, // return the custom message for the given element name and validation method @@ -10822,7 +10864,7 @@ $.extend($.validator, { // return the first defined argument, allowing empty strings findDefined: function() { - for(var i = 0; i < arguments.length; i++) { + for (var i = 0; i < arguments.length; i++) { if ( arguments[i] !== undefined ) { return arguments[i]; } @@ -10851,7 +10893,8 @@ $.extend($.validator, { } this.errorList.push({ message: message, - element: element + element: element, + method: rule.method }); this.errorMap[element.name] = message; @@ -10866,9 +10909,9 @@ $.extend($.validator, { }, defaultShowErrors: function() { - var i, elements; + var i, elements, error; for ( i = 0; this.errorList[i]; i++ ) { - var error = this.errorList[i]; + error = this.errorList[i]; if ( this.settings.highlight ) { this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass ); } @@ -10967,7 +11010,7 @@ $.extend($.validator, { }, getLength: function( value, element ) { - switch( element.nodeName.toLowerCase() ) { + switch ( element.nodeName.toLowerCase() ) { case "select": return $("option:selected", element).length; case "input": @@ -10983,7 +11026,7 @@ $.extend($.validator, { }, dependTypes: { - "boolean": function( param, element ) { + "boolean": function( param ) { return param; }, "string": function( param, element ) { @@ -11017,7 +11060,7 @@ $.extend($.validator, { $(this.currentForm).submit(); this.formSubmitted = false; } else if (!valid && this.pendingRequest === 0 && this.formSubmitted) { - $(this.currentForm).triggerHandler("invalid-form", [this]); + $(this.currentForm).triggerHandler("invalid-form", [ this ]); this.formSubmitted = false; } }, @@ -11033,14 +11076,14 @@ $.extend($.validator, { }, classRuleSettings: { - required: {required: true}, - email: {email: true}, - url: {url: true}, - date: {date: true}, - dateISO: {dateISO: true}, - number: {number: true}, - digits: {digits: true}, - creditcard: {creditcard: true} + required: { required: true }, + email: { email: true }, + url: { url: true }, + date: { date: true }, + dateISO: { dateISO: true }, + number: { number: true }, + digits: { digits: true }, + creditcard: { creditcard: true } }, addClassRules: function( className, rules ) { @@ -11052,8 +11095,9 @@ $.extend($.validator, { }, classRules: function( element ) { - var rules = {}; - var classes = $(element).attr("class"); + var rules = {}, + classes = $(element).attr("class"); + if ( classes ) { $.each(classes.split(" "), function() { if ( this in $.validator.classRuleSettings ) { @@ -11065,16 +11109,16 @@ $.extend($.validator, { }, attributeRules: function( element ) { - var rules = {}; - var $element = $(element); - var type = $element[0].getAttribute("type"); + var rules = {}, + $element = $(element), + type = element.getAttribute("type"), + method, value; - for (var method in $.validator.methods) { - var value; + for (method in $.validator.methods) { // support for in both html5 and older browsers if ( method === "required" ) { - value = $element.get(0).getAttribute(method); + value = element.getAttribute(method); // Some browsers return an empty string for the required attribute // and non-HTML5 browsers might have required="" markup if ( value === "" ) { @@ -11092,9 +11136,9 @@ $.extend($.validator, { value = Number(value); } - if ( value ) { + if ( value || value === 0 ) { rules[method] = value; - } else if ( type === method && type !== 'range' ) { + } else if ( type === method && type !== "range" ) { // exception: the jquery validate 'range' method // does not test for the html5 'range' type rules[method] = true; @@ -11111,19 +11155,20 @@ $.extend($.validator, { dataRules: function( element ) { var method, value, - rules = {}, $element = $(element); - for (method in $.validator.methods) { - value = $element.data("rule-" + method.toLowerCase()); + rules = {}, $element = $( element ); + for ( method in $.validator.methods ) { + value = $element.data( "rule" + method[ 0 ].toUpperCase() + method.substring( 1 ).toLowerCase() ); if ( value !== undefined ) { - rules[method] = value; + rules[ method ] = value; } } return rules; }, staticRules: function( element ) { - var rules = {}; - var validator = $.data(element.form, "validator"); + var rules = {}, + validator = $.data(element.form, "validator"); + if ( validator.settings.rules ) { rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {}; } @@ -11162,19 +11207,19 @@ $.extend($.validator, { }); // clean number parameters - $.each(['minlength', 'maxlength'], function() { + $.each([ "minlength", "maxlength" ], function() { if ( rules[this] ) { rules[this] = Number(rules[this]); } }); - $.each(['rangelength', 'range'], function() { + $.each([ "rangelength", "range" ], function() { var parts; if ( rules[this] ) { if ( $.isArray(rules[this]) ) { - rules[this] = [Number(rules[this][0]), Number(rules[this][1])]; + rules[this] = [ Number(rules[this][0]), Number(rules[this][1]) ]; } else if ( typeof rules[this] === "string" ) { parts = rules[this].split(/[\s,]+/); - rules[this] = [Number(parts[0]), Number(parts[1])]; + rules[this] = [ Number(parts[0]), Number(parts[1]) ]; } } }); @@ -11182,12 +11227,12 @@ $.extend($.validator, { if ( $.validator.autoCreateRanges ) { // auto-create ranges if ( rules.min && rules.max ) { - rules.range = [rules.min, rules.max]; + rules.range = [ rules.min, rules.max ]; delete rules.min; delete rules.max; } if ( rules.minlength && rules.maxlength ) { - rules.rangelength = [rules.minlength, rules.maxlength]; + rules.rangelength = [ rules.minlength, rules.maxlength ]; delete rules.minlength; delete rules.maxlength; } @@ -11208,7 +11253,7 @@ $.extend($.validator, { return data; }, - // http://docs.jquery.com/Plugins/Validation/Validator/addMethod + // http://jqueryvalidation.org/jQuery.validator.addMethod/ addMethod: function( name, method, message ) { $.validator.methods[name] = method; $.validator.messages[name] = message !== undefined ? message : $.validator.messages[name]; @@ -11219,7 +11264,7 @@ $.extend($.validator, { methods: { - // http://docs.jquery.com/Plugins/Validation/Methods/required + // http://jqueryvalidation.org/required-method/ required: function( value, element, param ) { // check if dependency is met if ( !this.depend(param, element) ) { @@ -11236,40 +11281,43 @@ $.extend($.validator, { return $.trim(value).length > 0; }, - // http://docs.jquery.com/Plugins/Validation/Methods/email + // http://jqueryvalidation.org/email-method/ email: function( value, element ) { - // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/ - return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(value); + // From http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#e-mail-state-%28type=email%29 + // Retrieved 2014-01-14 + // If you have a problem with this implementation, report a bug against the above spec + // Or use custom methods to implement your own email validation + return this.optional(element) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(value); }, - // http://docs.jquery.com/Plugins/Validation/Methods/url + // http://jqueryvalidation.org/url-method/ url: function( value, element ) { // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/ return this.optional(element) || /^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value); }, - // http://docs.jquery.com/Plugins/Validation/Methods/date + // http://jqueryvalidation.org/date-method/ date: function( value, element ) { return this.optional(element) || !/Invalid|NaN/.test(new Date(value).toString()); }, - // http://docs.jquery.com/Plugins/Validation/Methods/dateISO + // http://jqueryvalidation.org/dateISO-method/ dateISO: function( value, element ) { return this.optional(element) || /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(value); }, - // http://docs.jquery.com/Plugins/Validation/Methods/number + // http://jqueryvalidation.org/number-method/ number: function( value, element ) { return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value); }, - // http://docs.jquery.com/Plugins/Validation/Methods/digits + // http://jqueryvalidation.org/digits-method/ digits: function( value, element ) { return this.optional(element) || /^\d+$/.test(value); }, - // http://docs.jquery.com/Plugins/Validation/Methods/creditcard - // based on http://en.wikipedia.org/wiki/Luhn + // http://jqueryvalidation.org/creditcard-method/ + // based on http://en.wikipedia.org/wiki/Luhn/ creditcard: function( value, element ) { if ( this.optional(element) ) { return "dependency-mismatch"; @@ -11280,12 +11328,19 @@ $.extend($.validator, { } var nCheck = 0, nDigit = 0, - bEven = false; + bEven = false, + n, cDigit; value = value.replace(/\D/g, ""); - for (var n = value.length - 1; n >= 0; n--) { - var cDigit = value.charAt(n); + // Basing min and max length on + // http://developer.ean.com/general_info/Valid_Credit_Card_Types + if ( value.length < 13 || value.length > 19 ) { + return false; + } + + for ( n = value.length - 1; n >= 0; n--) { + cDigit = value.charAt(n); nDigit = parseInt(cDigit, 10); if ( bEven ) { if ( (nDigit *= 2) > 9 ) { @@ -11299,40 +11354,40 @@ $.extend($.validator, { return (nCheck % 10) === 0; }, - // http://docs.jquery.com/Plugins/Validation/Methods/minlength + // http://jqueryvalidation.org/minlength-method/ minlength: function( value, element, param ) { var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element); return this.optional(element) || length >= param; }, - // http://docs.jquery.com/Plugins/Validation/Methods/maxlength + // http://jqueryvalidation.org/maxlength-method/ maxlength: function( value, element, param ) { var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element); return this.optional(element) || length <= param; }, - // http://docs.jquery.com/Plugins/Validation/Methods/rangelength + // http://jqueryvalidation.org/rangelength-method/ rangelength: function( value, element, param ) { var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element); return this.optional(element) || ( length >= param[0] && length <= param[1] ); }, - // http://docs.jquery.com/Plugins/Validation/Methods/min + // http://jqueryvalidation.org/min-method/ min: function( value, element, param ) { return this.optional(element) || value >= param; }, - // http://docs.jquery.com/Plugins/Validation/Methods/max + // http://jqueryvalidation.org/max-method/ max: function( value, element, param ) { return this.optional(element) || value <= param; }, - // http://docs.jquery.com/Plugins/Validation/Methods/range + // http://jqueryvalidation.org/range-method/ range: function( value, element, param ) { return this.optional(element) || ( value >= param[0] && value <= param[1] ); }, - // http://docs.jquery.com/Plugins/Validation/Methods/equalTo + // http://jqueryvalidation.org/equalTo-method/ equalTo: function( value, element, param ) { // bind to the blur event of the target in order to revalidate whenever the target field is updated // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead @@ -11345,29 +11400,31 @@ $.extend($.validator, { return value === target.val(); }, - // http://docs.jquery.com/Plugins/Validation/Methods/remote + // http://jqueryvalidation.org/remote-method/ remote: function( value, element, param ) { if ( this.optional(element) ) { return "dependency-mismatch"; } - var previous = this.previousValue(element); + var previous = this.previousValue(element), + validator, data; + if (!this.settings.messages[element.name] ) { this.settings.messages[element.name] = {}; } previous.originalMessage = this.settings.messages[element.name].remote; this.settings.messages[element.name].remote = previous.message; - param = typeof param === "string" && {url:param} || param; + param = typeof param === "string" && { url: param } || param; if ( previous.old === value ) { return previous.valid; } previous.old = value; - var validator = this; + validator = this; this.startRequest(element); - var data = {}; + data = {}; data[element.name] = value; $.ajax($.extend(true, { url: param, @@ -11375,19 +11432,22 @@ $.extend($.validator, { port: "validate" + element.name, dataType: "json", data: data, + context: validator.currentForm, success: function( response ) { + var valid = response === true || response === "true", + errors, message, submitted; + validator.settings.messages[element.name].remote = previous.originalMessage; - var valid = response === true || response === "true"; if ( valid ) { - var submitted = validator.formSubmitted; + submitted = validator.formSubmitted; validator.prepareElement(element); validator.formSubmitted = submitted; validator.successList.push(element); delete validator.invalid[element.name]; validator.showErrors(); } else { - var errors = {}; - var message = response || validator.defaultMessage( element, "remote" ); + errors = {}; + message = response || validator.defaultMessage( element, "remote" ); errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message; validator.invalid[element.name] = true; validator.showErrors(errors); @@ -11403,8 +11463,9 @@ $.extend($.validator, { }); -// deprecated, use $.validator.format instead -$.format = $.validator.format; +$.format = function deprecated() { + throw "$.format has been deprecated. Please use $.validator.format instead."; +}; }(jQuery)); @@ -11412,7 +11473,8 @@ $.format = $.validator.format; // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]}); // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() (function($) { - var pendingRequests = {}; + var pendingRequests = {}, + ajax; // Use a prefilter if available (1.5+) if ( $.ajaxPrefilter ) { $.ajaxPrefilter(function( settings, _, xhr ) { @@ -11426,7 +11488,7 @@ $.format = $.validator.format; }); } else { // Proxy ajax - var ajax = $.ajax; + ajax = $.ajax; $.ajax = function( settings ) { var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode, port = ( "port" in settings ? settings : $.ajaxSettings ).port; @@ -11459,350 +11521,399 @@ $.format = $.validator.format; ///#source 1 1 /ClientSource/Scripts/Core/jquery.validate.unobtrusive.js /* NUGET: BEGIN LICENSE TEXT -* -* Microsoft grants you the right to use these script files for the sole -* purpose of either: (i) interacting through your browser with the Microsoft -* website or online service, subject to the applicable licensing or use -* terms; or (ii) using the files as included with a Microsoft product subject -* to that product's license terms. Microsoft reserves all other rights to the -* files not expressly granted by Microsoft, whether by implication, estoppel -* or otherwise. Insofar as a script file is dual licensed under GPL, -* Microsoft neither took the code under GPL nor distributes it thereunder but -* under the terms set out in this paragraph. All notices and licenses -* below are for informational purposes only. -* -* NUGET: END LICENSE TEXT */ + * + * Microsoft grants you the right to use these script files for the sole + * purpose of either: (i) interacting through your browser with the Microsoft + * website or online service, subject to the applicable licensing or use + * terms; or (ii) using the files as included with a Microsoft product subject + * to that product's license terms. Microsoft reserves all other rights to the + * files not expressly granted by Microsoft, whether by implication, estoppel + * or otherwise. Insofar as a script file is dual licensed under GPL, + * Microsoft neither took the code under GPL nor distributes it thereunder but + * under the terms set out in this paragraph. All notices and licenses + * below are for informational purposes only. + * + * NUGET: END LICENSE TEXT */ /*! ** Unobtrusive validation support library for jQuery and jQuery Validate ** Copyright (C) Microsoft Corporation. All rights reserved. */ + /*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */ /*global document: false, jQuery: false */ -(function ($) { -var $jQval = $.validator, -adapters, -data_validation = "unobtrusiveValidation"; -function setValidationValues(options, ruleName, value) { -options.rules[ruleName] = value; -if (options.message) { -options.messages[ruleName] = options.message; -} -} -function splitAndTrim(value) { -return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g); -} -function escapeAttributeValue(value) { -// As mentioned on http://api.jquery.com/category/selectors/ -return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1"); -} -function getModelPrefix(fieldName) { -return fieldName.substr(0, fieldName.lastIndexOf(".") + 1); -} -function appendModelPrefix(value, prefix) { -if (value.indexOf("*.") === 0) { -value = value.replace("*.", prefix); -} -return value; -} -function onError(error, inputElement) { // 'this' is the form element -var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"), -replaceAttrValue = container.attr("data-valmsg-replace"), -replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null; -container.removeClass("field-validation-valid").addClass("field-validation-error"); -error.data("unobtrusiveContainer", container); -if (replace) { -container.empty(); -error.removeClass("input-validation-error").appendTo(container); -} -else { -error.hide(); -} -} -function onErrors(event, validator) { // 'this' is the form element -var container = $(this).find("[data-valmsg-summary=true]"), -list = container.find("ul"); -if (list && list.length && validator.errorList.length) { -list.empty(); -container.addClass("validation-summary-errors").removeClass("validation-summary-valid"); -$.each(validator.errorList, function () { -$("
  • ").html(this.message).appendTo(list); -}); -} -} -function onSuccess(error) { // 'this' is the form element -var container = error.data("unobtrusiveContainer"), -replaceAttrValue = container.attr("data-valmsg-replace"), -replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null; -if (container) { -container.addClass("field-validation-valid").removeClass("field-validation-error"); -error.removeData("unobtrusiveContainer"); -if (replace) { -container.empty(); -} -} -} -function onReset(event) { // 'this' is the form element -var $form = $(this); -$form.data("validator").resetForm(); -$form.find(".validation-summary-errors") -.addClass("validation-summary-valid") -.removeClass("validation-summary-errors"); -$form.find(".field-validation-error") -.addClass("field-validation-valid") -.removeClass("field-validation-error") -.removeData("unobtrusiveContainer") -.find(">*") // If we were using valmsg-replace, get the underlying error -.removeData("unobtrusiveContainer"); -} -function validationInfo(form) { -var $form = $(form), -result = $form.data(data_validation), -onResetProxy = $.proxy(onReset, form); -if (!result) { -result = { -options: { // options structure passed to jQuery Validate's validate() method -errorClass: "input-validation-error", -errorElement: "span", -errorPlacement: $.proxy(onError, form), -invalidHandler: $.proxy(onErrors, form), -messages: {}, -rules: {}, -success: $.proxy(onSuccess, form) -}, -attachValidation: function () { -$form -.unbind("reset." + data_validation, onResetProxy) -.bind("reset." + data_validation, onResetProxy) -.validate(this.options); -}, -validate: function () { // a validation function that is called by unobtrusive Ajax -$form.validate(); -return $form.valid(); -} -}; -$form.data(data_validation, result); -} -return result; -} -$jQval.unobtrusive = { -adapters: [], -parseElement: function (element, skipAttach) { -/// -/// Parses a single HTML element for unobtrusive validation attributes. -/// -/// The HTML element to be parsed. -/// [Optional] true to skip attaching the -/// validation to the form. If parsing just this single element, you should specify true. -/// If parsing several elements, you should specify false, and manually attach the validation -/// to the form when you are finished. The default is false. -var $element = $(element), -form = $element.parents("form")[0], -valInfo, rules, messages; -if (!form) { // Cannot do client-side validation without a form -return; -} -valInfo = validationInfo(form); -valInfo.options.rules[element.name] = rules = {}; -valInfo.options.messages[element.name] = messages = {}; -$.each(this.adapters, function () { -var prefix = "data-val-" + this.name, -message = $element.attr(prefix), -paramValues = {}; -if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy) -prefix += "-"; -$.each(this.params, function () { -paramValues[this] = $element.attr(prefix + this); -}); -this.adapt({ -element: element, -form: form, -message: message, -params: paramValues, -rules: rules, -messages: messages -}); -} -}); -$.extend(rules, { "__dummy__": true }); -if (!skipAttach) { -valInfo.attachValidation(); -} -}, -parse: function (selector) { -/// -/// Parses all the HTML elements in the specified selector. It looks for input elements decorated -/// with the [data-val=true] attribute value and enables validation according to the data-val-* -/// attribute values. -/// -/// Any valid jQuery selector. -var $forms = $(selector) -.parents("form") -.andSelf() -.add($(selector).find("form")) -.filter("form"); -// :input is a psuedoselector provided by jQuery which selects input and input-like elements -// combining :input with other selectors significantly decreases performance. -$(selector).find(":input").filter("[data-val=true]").each(function () { -$jQval.unobtrusive.parseElement(this, true); -}); -$forms.each(function () { -var info = validationInfo(this); -if (info) { -info.attachValidation(); -} -}); -} -}; -adapters = $jQval.unobtrusive.adapters; -adapters.add = function (adapterName, params, fn) { -/// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation. -/// The name of the adapter to be added. This matches the name used -/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). -/// [Optional] An array of parameter names (strings) that will -/// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and -/// mmmm is the parameter name). -/// The function to call, which adapts the values from the HTML -/// attributes into jQuery Validate rules and/or messages. -/// -if (!fn) { // Called with no params, just a function -fn = params; -params = []; -} -this.push({ name: adapterName, params: params, adapt: fn }); -return this; -}; -adapters.addBool = function (adapterName, ruleName) { -/// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where -/// the jQuery Validate validation rule has no parameter values. -/// The name of the adapter to be added. This matches the name used -/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). -/// [Optional] The name of the jQuery Validate rule. If not provided, the value -/// of adapterName will be used instead. -/// -return this.add(adapterName, function (options) { -setValidationValues(options, ruleName || adapterName, true); -}); -}; -adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) { -/// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where -/// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and -/// one for min-and-max). The HTML parameters are expected to be named -min and -max. -/// The name of the adapter to be added. This matches the name used -/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). -/// The name of the jQuery Validate rule to be used when you only -/// have a minimum value. -/// The name of the jQuery Validate rule to be used when you only -/// have a maximum value. -/// The name of the jQuery Validate rule to be used when you -/// have both a minimum and maximum value. -/// [Optional] The name of the HTML attribute that -/// contains the minimum value. The default is "min". -/// [Optional] The name of the HTML attribute that -/// contains the maximum value. The default is "max". -/// -return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) { -var min = options.params.min, -max = options.params.max; -if (min && max) { -setValidationValues(options, minMaxRuleName, [min, max]); -} -else if (min) { -setValidationValues(options, minRuleName, min); -} -else if (max) { -setValidationValues(options, maxRuleName, max); -} -}); -}; -adapters.addSingleVal = function (adapterName, attribute, ruleName) { -/// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where -/// the jQuery Validate validation rule has a single value. -/// The name of the adapter to be added. This matches the name used -/// in the data-val-nnnn HTML attribute(where nnnn is the adapter name). -/// [Optional] The name of the HTML attribute that contains the value. -/// The default is "val". -/// [Optional] The name of the jQuery Validate rule. If not provided, the value -/// of adapterName will be used instead. -/// -return this.add(adapterName, [attribute || "val"], function (options) { -setValidationValues(options, ruleName || adapterName, options.params[attribute]); -}); -}; -$jQval.addMethod("__dummy__", function (value, element, params) { -return true; -}); -$jQval.addMethod("regex", function (value, element, params) { -var match; -if (this.optional(element)) { -return true; -} -match = new RegExp(params).exec(value); -return (match && (match.index === 0) && (match[0].length === value.length)); -}); -$jQval.addMethod("nonalphamin", function (value, element, nonalphamin) { -var match; -if (nonalphamin) { -match = value.match(/\W/g); -match = match && match.length >= nonalphamin; -} -return match; -}); -if ($jQval.methods.extension) { -adapters.addSingleVal("accept", "mimtype"); -adapters.addSingleVal("extension", "extension"); -} else { -// for backward compatibility, when the 'extension' validation method does not exist, such as with versions -// of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for -// validating the extension, and ignore mime-type validations as they are not supported. -adapters.addSingleVal("extension", "extension", "accept"); -} -adapters.addSingleVal("regex", "pattern"); -adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"); -adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range"); -adapters.add("equalto", ["other"], function (options) { -var prefix = getModelPrefix(options.element.name), -other = options.params.other, -fullOtherName = appendModelPrefix(other, prefix), -element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0]; -setValidationValues(options, "equalTo", element); -}); -adapters.add("required", function (options) { -// jQuery Validate equates "required" with "mandatory" for checkbox elements -if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") { -setValidationValues(options, "required", true); -} -}); -adapters.add("remote", ["url", "type", "additionalfields"], function (options) { -var value = { -url: options.params.url, -type: options.params.type || "GET", -data: {} -}, -prefix = getModelPrefix(options.element.name); -$.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) { -var paramName = appendModelPrefix(fieldName, prefix); -value.data[paramName] = function () { -return $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']").val(); -}; -}); -setValidationValues(options, "remote", value); -}); -adapters.add("password", ["min", "nonalphamin", "regex"], function (options) { -if (options.params.min) { -setValidationValues(options, "minlength", options.params.min); -} -if (options.params.nonalphamin) { -setValidationValues(options, "nonalphamin", options.params.nonalphamin); -} -if (options.params.regex) { -setValidationValues(options, "regex", options.params.regex); -} -}); -$(function () { -$jQval.unobtrusive.parse(document); -}); -}(jQuery)); +(function ($) { + var $jQval = $.validator, + adapters, + data_validation = "unobtrusiveValidation"; + + function setValidationValues(options, ruleName, value) { + options.rules[ruleName] = value; + if (options.message) { + options.messages[ruleName] = options.message; + } + } + + function splitAndTrim(value) { + return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g); + } + + function escapeAttributeValue(value) { + // As mentioned on http://api.jquery.com/category/selectors/ + return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1"); + } + + function getModelPrefix(fieldName) { + return fieldName.substr(0, fieldName.lastIndexOf(".") + 1); + } + + function appendModelPrefix(value, prefix) { + if (value.indexOf("*.") === 0) { + value = value.replace("*.", prefix); + } + return value; + } + + function onError(error, inputElement) { // 'this' is the form element + var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"), + replaceAttrValue = container.attr("data-valmsg-replace"), + replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null; + + container.removeClass("field-validation-valid").addClass("field-validation-error"); + error.data("unobtrusiveContainer", container); + + if (replace) { + container.empty(); + error.removeClass("input-validation-error").appendTo(container); + } + else { + error.hide(); + } + } + + function onErrors(event, validator) { // 'this' is the form element + var container = $(this).find("[data-valmsg-summary=true]"), + list = container.find("ul"); + + if (list && list.length && validator.errorList.length) { + list.empty(); + container.addClass("validation-summary-errors").removeClass("validation-summary-valid"); + + $.each(validator.errorList, function () { + $("
  • ").html(this.message).appendTo(list); + }); + } + } + + function onSuccess(error) { // 'this' is the form element + var container = error.data("unobtrusiveContainer"), + replaceAttrValue = container.attr("data-valmsg-replace"), + replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null; + + if (container) { + container.addClass("field-validation-valid").removeClass("field-validation-error"); + error.removeData("unobtrusiveContainer"); + + if (replace) { + container.empty(); + } + } + } + + function onReset(event) { // 'this' is the form element + var $form = $(this); + $form.data("validator").resetForm(); + $form.find(".validation-summary-errors") + .addClass("validation-summary-valid") + .removeClass("validation-summary-errors"); + $form.find(".field-validation-error") + .addClass("field-validation-valid") + .removeClass("field-validation-error") + .removeData("unobtrusiveContainer") + .find(">*") // If we were using valmsg-replace, get the underlying error + .removeData("unobtrusiveContainer"); + } + + function validationInfo(form) { + var $form = $(form), + result = $form.data(data_validation), + onResetProxy = $.proxy(onReset, form); + + if (!result) { + result = { + options: { // options structure passed to jQuery Validate's validate() method + errorClass: "input-validation-error", + errorElement: "span", + errorPlacement: $.proxy(onError, form), + invalidHandler: $.proxy(onErrors, form), + messages: {}, + rules: {}, + success: $.proxy(onSuccess, form) + }, + attachValidation: function () { + $form + .unbind("reset." + data_validation, onResetProxy) + .bind("reset." + data_validation, onResetProxy) + .validate(this.options); + }, + validate: function () { // a validation function that is called by unobtrusive Ajax + $form.validate(); + return $form.valid(); + } + }; + $form.data(data_validation, result); + } + + return result; + } + + $jQval.unobtrusive = { + adapters: [], + + parseElement: function (element, skipAttach) { + /// + /// Parses a single HTML element for unobtrusive validation attributes. + /// + /// The HTML element to be parsed. + /// [Optional] true to skip attaching the + /// validation to the form. If parsing just this single element, you should specify true. + /// If parsing several elements, you should specify false, and manually attach the validation + /// to the form when you are finished. The default is false. + var $element = $(element), + form = $element.parents("form")[0], + valInfo, rules, messages; + + if (!form) { // Cannot do client-side validation without a form + return; + } + + valInfo = validationInfo(form); + valInfo.options.rules[element.name] = rules = {}; + valInfo.options.messages[element.name] = messages = {}; + + $.each(this.adapters, function () { + var prefix = "data-val-" + this.name, + message = $element.attr(prefix), + paramValues = {}; + + if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy) + prefix += "-"; + + $.each(this.params, function () { + paramValues[this] = $element.attr(prefix + this); + }); + + this.adapt({ + element: element, + form: form, + message: message, + params: paramValues, + rules: rules, + messages: messages + }); + } + }); + + $.extend(rules, { "__dummy__": true }); + + if (!skipAttach) { + valInfo.attachValidation(); + } + }, + + parse: function (selector) { + /// + /// Parses all the HTML elements in the specified selector. It looks for input elements decorated + /// with the [data-val=true] attribute value and enables validation according to the data-val-* + /// attribute values. + /// + /// Any valid jQuery selector. + var $forms = $(selector) + .parents("form") + .andSelf() + .add($(selector).find("form")) + .filter("form"); + + // :input is a psuedoselector provided by jQuery which selects input and input-like elements + // combining :input with other selectors significantly decreases performance. + $(selector).find(":input").filter("[data-val=true]").each(function () { + $jQval.unobtrusive.parseElement(this, true); + }); + + $forms.each(function () { + var info = validationInfo(this); + if (info) { + info.attachValidation(); + } + }); + } + }; + + adapters = $jQval.unobtrusive.adapters; + + adapters.add = function (adapterName, params, fn) { + /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation. + /// The name of the adapter to be added. This matches the name used + /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). + /// [Optional] An array of parameter names (strings) that will + /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and + /// mmmm is the parameter name). + /// The function to call, which adapts the values from the HTML + /// attributes into jQuery Validate rules and/or messages. + /// + if (!fn) { // Called with no params, just a function + fn = params; + params = []; + } + this.push({ name: adapterName, params: params, adapt: fn }); + return this; + }; + + adapters.addBool = function (adapterName, ruleName) { + /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where + /// the jQuery Validate validation rule has no parameter values. + /// The name of the adapter to be added. This matches the name used + /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). + /// [Optional] The name of the jQuery Validate rule. If not provided, the value + /// of adapterName will be used instead. + /// + return this.add(adapterName, function (options) { + setValidationValues(options, ruleName || adapterName, true); + }); + }; + + adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) { + /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where + /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and + /// one for min-and-max). The HTML parameters are expected to be named -min and -max. + /// The name of the adapter to be added. This matches the name used + /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). + /// The name of the jQuery Validate rule to be used when you only + /// have a minimum value. + /// The name of the jQuery Validate rule to be used when you only + /// have a maximum value. + /// The name of the jQuery Validate rule to be used when you + /// have both a minimum and maximum value. + /// [Optional] The name of the HTML attribute that + /// contains the minimum value. The default is "min". + /// [Optional] The name of the HTML attribute that + /// contains the maximum value. The default is "max". + /// + return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) { + var min = options.params.min, + max = options.params.max; + + if (min && max) { + setValidationValues(options, minMaxRuleName, [min, max]); + } + else if (min) { + setValidationValues(options, minRuleName, min); + } + else if (max) { + setValidationValues(options, maxRuleName, max); + } + }); + }; + + adapters.addSingleVal = function (adapterName, attribute, ruleName) { + /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where + /// the jQuery Validate validation rule has a single value. + /// The name of the adapter to be added. This matches the name used + /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name). + /// [Optional] The name of the HTML attribute that contains the value. + /// The default is "val". + /// [Optional] The name of the jQuery Validate rule. If not provided, the value + /// of adapterName will be used instead. + /// + return this.add(adapterName, [attribute || "val"], function (options) { + setValidationValues(options, ruleName || adapterName, options.params[attribute]); + }); + }; + + $jQval.addMethod("__dummy__", function (value, element, params) { + return true; + }); + + $jQval.addMethod("regex", function (value, element, params) { + var match; + if (this.optional(element)) { + return true; + } + + match = new RegExp(params).exec(value); + return (match && (match.index === 0) && (match[0].length === value.length)); + }); + + $jQval.addMethod("nonalphamin", function (value, element, nonalphamin) { + var match; + if (nonalphamin) { + match = value.match(/\W/g); + match = match && match.length >= nonalphamin; + } + return match; + }); + + if ($jQval.methods.extension) { + adapters.addSingleVal("accept", "mimtype"); + adapters.addSingleVal("extension", "extension"); + } else { + // for backward compatibility, when the 'extension' validation method does not exist, such as with versions + // of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for + // validating the extension, and ignore mime-type validations as they are not supported. + adapters.addSingleVal("extension", "extension", "accept"); + } + + adapters.addSingleVal("regex", "pattern"); + adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"); + adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range"); + adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength"); + adapters.add("equalto", ["other"], function (options) { + var prefix = getModelPrefix(options.element.name), + other = options.params.other, + fullOtherName = appendModelPrefix(other, prefix), + element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0]; + + setValidationValues(options, "equalTo", element); + }); + adapters.add("required", function (options) { + // jQuery Validate equates "required" with "mandatory" for checkbox elements + if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") { + setValidationValues(options, "required", true); + } + }); + adapters.add("remote", ["url", "type", "additionalfields"], function (options) { + var value = { + url: options.params.url, + type: options.params.type || "GET", + data: {} + }, + prefix = getModelPrefix(options.element.name); + + $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) { + var paramName = appendModelPrefix(fieldName, prefix); + value.data[paramName] = function () { + return $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']").val(); + }; + }); + + setValidationValues(options, "remote", value); + }); + adapters.add("password", ["min", "nonalphamin", "regex"], function (options) { + if (options.params.min) { + setValidationValues(options, "minlength", options.params.min); + } + if (options.params.nonalphamin) { + setValidationValues(options, "nonalphamin", options.params.nonalphamin); + } + if (options.params.regex) { + setValidationValues(options, "regex", options.params.regex); + } + }); + + $(function () { + $jQval.unobtrusive.parse(document); + }); +}(jQuery)); ///#source 1 1 /ClientSource/Scripts/Core/disco.unobtrusiveValidation.extensions.js // Adapted from: http://xhalent.wordpress.com/2011/01/24/applying-unobtrusive-validation-to-dynamic-content/ (function ($) { diff --git a/Disco.Web/ClientSource/Scripts/Core.js.bundle b/Disco.Web/ClientSource/Scripts/Core.js.bundle index ad663f44..f4236368 100644 --- a/Disco.Web/ClientSource/Scripts/Core.js.bundle +++ b/Disco.Web/ClientSource/Scripts/Core.js.bundle @@ -8,9 +8,9 @@ /ClientSource/Scripts/Core/jquery-ui-1.10.3.js /ClientSource/Scripts/Core/jquery.watermark.js /ClientSource/Scripts/Core/jquery.dataTables.js - /ClientSource/Scripts/Core/moment.js - /ClientSource/Scripts/Core/moment.en-au.js - /ClientSource/Scripts/Core/disco.moment.extensions.js + /ClientSource/Scripts/Core/moment.js + /ClientSource/Scripts/Core/moment.en-au.js + /ClientSource/Scripts/Core/disco.moment.extensions.js /ClientSource/Scripts/Core/livestamp.js /ClientSource/Scripts/Core/disco.dataTables.extensions.js /ClientSource/Scripts/Core/disco.uicore.js diff --git a/Disco.Web/ClientSource/Scripts/Core.min.js b/Disco.Web/ClientSource/Scripts/Core.min.js index 0f1cb6e8..831bced9 100644 --- a/Disco.Web/ClientSource/Scripts/Core.min.js +++ b/Disco.Web/ClientSource/Scripts/Core.min.js @@ -1,4 +1,4 @@ -window.Modernizr=function(n,t,i){function a(n){c.cssText=n}function vt(n,t){return a(y.join(n+";")+(t||""))}function h(n,t){return typeof n===t}function v(n,t){return!!~(""+n).indexOf(t)}function lt(n,t){var u,r;for(u in n)if(r=n[u],!v(r,"-")&&c[r]!==i)return t=="pfx"?r:!0;return!1}function yt(n,t,r){var f,u;for(f in n)if(u=t[n[f]],u!==i)return r===!1?n[f]:h(u,"function")?u.bind(r||t):u;return!1}function f(n,t,i){var r=n.charAt(0).toUpperCase()+n.slice(1),u=(n+" "+ot.join(r+" ")+r).split(" ");return h(t,"string")||h(t,"undefined")?lt(u,t):(u=(n+" "+st.join(r+" ")+r).split(" "),yt(u,t,i))}function pt(){u.input=function(i){for(var r=0,u=i.length;r',n,"<\/style>"].join(""),f.id=e,(h?f:o).innerHTML+=l,o.appendChild(f),h||(o.style.background="",o.style.overflow="hidden",v=s.style.overflow,s.style.overflow="hidden",s.appendChild(o)),a=i(f,n),h?f.parentNode.removeChild(f):(o.parentNode.removeChild(o),s.style.overflow=v),!!a},at=function(t){var i=n.matchMedia||n.msMatchMedia,r;return i?i(t).matches:(l("@media "+t+" { #"+e+" { position: absolute; } }",function(t){r=(n.getComputedStyle?getComputedStyle(t,null):t.currentStyle).position=="absolute"}),r)},ct=function(){function r(r,u){u=u||t.createElement(n[r]||"div");r="on"+r;var f=r in u;return f||(u.setAttribute||(u=t.createElement("div")),u.setAttribute&&u.removeAttribute&&(u.setAttribute(r,""),f=h(u[r],"function"),h(u[r],"undefined")||(u[r]=i),u.removeAttribute(r))),u=null,f}var n={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return r}(),it={}.hasOwnProperty,rt,k;rt=h(it,"undefined")||h(it.call,"undefined")?function(n,t){return t in n&&h(n.constructor.prototype[t],"undefined")}:function(n,t){return it.call(n,t)};Function.prototype.bind||(Function.prototype.bind=function(n){var t=this,i,r;if(typeof t!="function")throw new TypeError;return i=tt.call(arguments,1),r=function(){var f,e,u;return this instanceof r?(f=function(){},f.prototype=t.prototype,e=new f,u=t.apply(e,i.concat(tt.call(arguments))),Object(u)===u)?u:e:t.apply(n,i.concat(tt.call(arguments)))},r});r.flexbox=function(){return f("flexWrap")};r.flexboxlegacy=function(){return f("boxDirection")};r.canvas=function(){var n=t.createElement("canvas");return!!(n.getContext&&n.getContext("2d"))};r.canvastext=function(){return!!(u.canvas&&h(t.createElement("canvas").getContext("2d").fillText,"function"))};r.webgl=function(){return!!n.WebGLRenderingContext};r.touch=function(){var i;return"ontouchstart"in n||n.DocumentTouch&&t instanceof DocumentTouch?i=!0:l(["@media (",y.join("touch-enabled),("),e,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(n){i=n.offsetTop===9}),i};r.geolocation=function(){return"geolocation"in navigator};r.postmessage=function(){return!!n.postMessage};r.websqldatabase=function(){return!!n.openDatabase};r.indexedDB=function(){return!!f("indexedDB",n)};r.hashchange=function(){return ct("hashchange",n)&&(t.documentMode===i||t.documentMode>7)};r.history=function(){return!!(n.history&&history.pushState)};r.draganddrop=function(){var n=t.createElement("div");return"draggable"in n||"ondragstart"in n&&"ondrop"in n};r.websockets=function(){return"WebSocket"in n||"MozWebSocket"in n};r.rgba=function(){return a("background-color:rgba(150,255,150,.5)"),v(c.backgroundColor,"rgba")};r.hsla=function(){return a("background-color:hsla(120,40%,100%,.5)"),v(c.backgroundColor,"rgba")||v(c.backgroundColor,"hsla")};r.multiplebgs=function(){return a("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(c.background)};r.backgroundsize=function(){return f("backgroundSize")};r.borderimage=function(){return f("borderImage")};r.borderradius=function(){return f("borderRadius")};r.boxshadow=function(){return f("boxShadow")};r.textshadow=function(){return t.createElement("div").style.textShadow===""};r.opacity=function(){return vt("opacity:.55"),/^0.55$/.test(c.opacity)};r.cssanimations=function(){return f("animationName")};r.csscolumns=function(){return f("columnCount")};r.cssgradients=function(){var n="background-image:";return a((n+"-webkit- ".split(" ").join("gradient(linear,left top,right bottom,from(#9f9),to(white));"+n)+y.join("linear-gradient(left top,#9f9, white);"+n)).slice(0,-n.length)),v(c.backgroundImage,"gradient")};r.cssreflections=function(){return f("boxReflect")};r.csstransforms=function(){return!!f("transform")};r.csstransforms3d=function(){var n=!!f("perspective");return n&&"webkitPerspective"in s.style&&l("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(t){n=t.offsetLeft===9&&t.offsetHeight===3}),n};r.csstransitions=function(){return f("transition")};r.fontface=function(){var n;return l('@font-face {font-family:"font";src:url("https://")}',function(i,r){var f=t.getElementById("smodernizr"),u=f.sheet||f.styleSheet,e=u?u.cssRules&&u.cssRules[0]?u.cssRules[0].cssText:u.cssText||"":"";n=/src/i.test(e)&&e.indexOf(r.split(" ")[0])===0}),n};r.generatedcontent=function(){var n;return l(["#",e,"{font:0/0 a}#",e,':after{content:"',g,'";visibility:hidden;font:3px/1 a}'].join(""),function(t){n=t.offsetHeight>=3}),n};r.video=function(){var i=t.createElement("video"),n=!1;try{(n=!!i.canPlayType)&&(n=new Boolean(n),n.ogg=i.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),n.h264=i.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),n.webm=i.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,""))}catch(r){}return n};r.audio=function(){var i=t.createElement("audio"),n=!1;try{(n=!!i.canPlayType)&&(n=new Boolean(n),n.ogg=i.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),n.mp3=i.canPlayType("audio/mpeg;").replace(/^no$/,""),n.wav=i.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),n.m4a=(i.canPlayType("audio/x-m4a;")||i.canPlayType("audio/aac;")).replace(/^no$/,""))}catch(r){}return n};r.localstorage=function(){try{return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch(n){return!1}};r.sessionstorage=function(){try{return sessionStorage.setItem(e,e),sessionStorage.removeItem(e),!0}catch(n){return!1}};r.webworkers=function(){return!!n.Worker};r.applicationcache=function(){return!!n.applicationCache};r.svg=function(){return!!t.createElementNS&&!!t.createElementNS(p.svg,"svg").createSVGRect};r.inlinesvg=function(){var n=t.createElement("div");return n.innerHTML="",(n.firstChild&&n.firstChild.namespaceURI)==p.svg};r.smil=function(){return!!t.createElementNS&&/SVGAnimate/.test(ft.call(t.createElementNS(p.svg,"animate")))};r.svgclippaths=function(){return!!t.createElementNS&&/SVGClipPath/.test(ft.call(t.createElementNS(p.svg,"clipPath")))};for(k in r)rt(r,k)&&(b=k.toLowerCase(),u[b]=r[k](),nt.push((u[b]?"":"no-")+b));return u.input||pt(),u.addTest=function(n,t){if(typeof n=="object")for(var r in n)rt(n,r)&&u.addTest(r,n[r]);else{if(n=n.toLowerCase(),u[n]!==i)return u;t=typeof t=="function"?t():t;typeof d!="undefined"&&d&&(s.className+=" "+(t?"":"no-")+n);u[n]=t}return u},a(""),ut=o=null,function(n,t){function p(n,t){var i=n.createElement("p"),r=n.getElementsByTagName("head")[0]||n.documentElement;return i.innerHTML="x