Currently, MediaWiki has a mess of resources, some but not all of which are upstream libraries.
This means that occasionally people will attempt to make local modifications of the libraries
by accident, or deliberately but do not flag it, making dependency management a challenge (and
fixing upstream-related bugs a headache).
Instead, we now split the /resources directory into a /resources/lib directory for those items
which are used purely as intact upstream libraries, and a /resources/src directroy for those
which are either local libraries written for MediaWiki and mastered here, or downstream forks
of upstream libraries which require particular care and attention when being upgraded. Also,
some incidental files which are not to be loaded as part of a module have been moved to better
locations.
Upstream libaries
* jquery
resources/jquery/jquery.js
* jquery.appear
resources/jquery/jquery.appear.js
* jquery.async
resources/jquery/jquery.async.js
* jquery.chosen
resources/jquery.chosen/*
* jquery.cookie
resources/jquery/jquery.cookie.js
* jquery.form
resources/jquery/jquery.form.js
* jquery.fullscreen.js
resources/jquery/jquery.fullscreen.js
* jquery.hoverIntent
resources/jquery/jquery.hoverIntent.js
* jquery.json
resources/jquery/jquery.json.js
* jquery.mockjax
resources/jquery/jquery.mockjax.js
* jquery.qunit
resources/jquery/jquery.qunit.css
resources/jquery/jquery.qunit.js
* jquery.jStorage
resources/jquery/jquery.jStorage.js
* jquery.throttle-debounce
resources/jquery/jquery.ba-throttle-debounce.js
* jquery.validate
resources/jquery/jquery.validate.js
* jquery.xmldom
resources/jquery/jquery.xmldom.js
* moment
resources/moment/*
* OOjs
resource/oojs/*
* OOjs UI
resources/oojs-ui/*
* jquery.ui.*
resources/jquery.ui/*
resources/jquery.ui/themes/default moved to resources/lib/jquery.ui/themes/
resources/jquery.ui/themes/vector moved to resources/src/jquery.ui-themes/
* jquery.effects.*
resources/jquery.effects/*
* sinon
resources/sinonjs/*
Upstream libraries forked for MediaWiki
* jquery.color
resources/jquery/jquery.color.js
* jquery.tipsy
resources/jquery.tipsy/*
Local libraries
* jquery.arrowSteps
resources/jquery/jquery.arrowSteps.css
resources/jquery/jquery.arrowSteps.js
resources/jquery/images/jquery.arrowSteps.divider-ltr.png
resources/jquery/images/jquery.arrowSteps.divider-rtl.png
resources/jquery/images/jquery.arrowSteps.head-ltr.png
resources/jquery/images/jquery.arrowSteps.head-rtl.png
resources/jquery/images/jquery.arrowSteps.tail-ltr.png
resources/jquery/images/jquery.arrowSteps.tail-rtl.png
* jquery.autoEllipsis
resources/jquery/jquery.autoEllipsis.js
* jquery.badge
resources/jquery/jquery.badge.css
resources/jquery/jquery.badge.js
* jquery.byteLength
resources/jquery/jquery.byteLength.js
* jquery.byteLimit
resources/jquery/jquery.byteLimit.js
* jquery.checkboxShiftClick
resources/jquery/jquery.checkboxShiftClick.js
* jquery.client
resources/jquery/jquery.client.js
* jquery.colorUtil
resources/jquery/jquery.colorUtil.js
* jquery.delayedBind
resources/jquery/jquery.delayedBind.js
* jquery.expandableField
resources/jquery/jquery.expandableField.js
* jquery.farbtastic
resources/jquery/jquery.farbtastic.css
resources/jquery/jquery.farbtastic.js
resources/jquery/images/marker.png
resources/jquery/images/mask.png
resources/jquery/images/wheel.png
* jquery.footHovzer
resources/jquery/jquery.footHovzer.css
resources/jquery/jquery.footHovzer.js
* jquery.getAttrs
resources/jquery/jquery.getAttrs.js
* jquery.hidpi
resources/jquery/jquery.hidpi.js
* jquery.highlightText
resources/jquery/jquery.highlightText.js
* jquery.localize
resources/jquery/jquery.localize.js
* jquery.makeCollapsible
resources/jquery/jquery.makeCollapsible.css
resources/jquery/jquery.makeCollapsible.js
* jquery.mw-jump
resources/jquery/jquery.mw-jump.js
* jquery.mwExtension
resources/jquery/jquery.mwExtension.js
* jquery.placeholder
resources/jquery/jquery.placeholder.js
* jquery.spinner
resources/jquery/jquery.spinner.css
resources/jquery/jquery.spinner.js
resources/jquery/images/spinner-large.gif
resources/jquery/images/spinner.gif
* jquery.suggestions
resources/jquery/jquery.suggestions.css
resources/jquery/jquery.suggestions.js
* jquery.tabIndex
resources/jquery/jquery.tabIndex.js
* jquery.tablesorter
resources/jquery/jquery.tablesorter.css
resources/jquery/jquery.tablesorter.js
resources/jquery/images/sort_both.gif
resources/jquery/images/sort_down.gif
resources/jquery/images/sort_none.gif
resources/jquery/images/sort_up.gif
* jquery.textSelection
resources/jquery/jquery.textSelection.js
* jquery.qunit.completenessTest
resources/jquery/jquery.qunit.completenessTest.js
* mediawiki
resources/mediawiki/mediawiki.js
resources/mediawiki/mediawiki.log.js
* mediawiki.api
resources/mediawiki.api/mediawiki.api.js
* mediawiki.api.category
resources/mediawiki.api/mediawiki.api.category.js
* mediawiki.api.edit
resources/mediawiki.api/mediawiki.api.edit.js
* mediawiki.api.login
resources/mediawiki.api/mediawiki.api.login.js
* mediawiki.api.parse
resources/mediawiki.api/mediawiki.api.parse.js
* mediawiki.api.watch
resources/mediawiki.api/mediawiki.api.watch.js
* mediawiki.debug
resources/mediawiki/mediawiki.debug.js
resources/mediawiki/mediawiki.debug.less
resources/mediawiki/mediawiki.debug.profile.css
resources/mediawiki/mediawiki.debug.profile.js
* mediawiki.debug.init
resources/mediawiki/mediawiki.debug.init.js
* mediawiki.feedback
resources/mediawiki/mediawiki.feedback.css
resources/mediawiki/mediawiki.feedback.js
resources/mediawiki/mediawiki.feedback.spinner.gif
* mediawiki.hidpi
resources/mediawiki/mediawiki.hidpi.js
* mediawiki.hlist
resources/mediawiki/mediawiki.hlist.css
resources/mediawiki/mediawiki.hlist.js
* mediawiki.htmlform
resources/mediawiki/mediawiki.htmlform.js
* mediawiki.icon
resources/mediawiki/mediawiki.icon.less
resources/mediawiki/images/arrow-collapsed-ltr.png
resources/mediawiki/images/arrow-collapsed-ltr.svg
resources/mediawiki/images/arrow-collapsed-rtl.png
resources/mediawiki/images/arrow-collapsed-rtl.svg
resources/mediawiki/images/arrow-expanded.png
resources/mediawiki/images/arrow-expanded.svg
* mediawiki.inspect
resources/mediawiki/mediawiki.inspect.js
* mediawiki.notification
resources/mediawiki/mediawiki.notification.css
resources/mediawiki/mediawiki.notification.hideForPrint.css
resources/mediawiki/mediawiki.notification.js
* mediawiki.notify
resources/mediawiki/mediawiki.notify.js
* mediawiki.searchSuggest
resources/mediawiki/mediawiki.searchSuggest.css
resources/mediawiki/mediawiki.searchSuggest.js
* mediawiki.Title
resources/mediawiki/mediawiki.Title.js
* mediawiki.toc
resources/mediawiki/mediawiki.toc.js
* mediawiki.Uri
resources/mediawiki/mediawiki.Uri.js
* mediawiki.user
resources/mediawiki/mediawiki.user.js
* mediawiki.util
resources/mediawiki/mediawiki.util.js
* mediawiki.action.edit
resources/mediawiki.action/mediawiki.action.edit.js
* mediawiki.action.edit.styles
resources/mediawiki.action/mediawiki.action.edit.styles.css
* mediawiki.action.edit.collapsibleFooter
resources/mediawiki.action/mediawiki.action.edit.collapsibleFooter.css
resources/mediawiki.action/mediawiki.action.edit.collapsibleFooter.js
* mediawiki.action.edit.preview
resources/mediawiki.action/mediawiki.action.edit.preview.js
* mediawiki.action.history
resources/mediawiki.action/mediawiki.action.history.js
* mediawiki.action.history.diff
resources/mediawiki.action/mediawiki.action.history.diff.css
* mediawiki.action.view.dblClickEdit
resources/mediawiki.action/mediawiki.action.view.dblClickEdit.js
* mediawiki.action.view.metadata
resources/mediawiki.action/mediawiki.action.view.metadata.js
* mediawiki.action.view.postEdit
resources/mediawiki.action/mediawiki.action.view.postEdit.css
resources/mediawiki.action/mediawiki.action.view.postEdit.js
resources/mediawiki.action/images/green-checkmark.png
* mediawiki.action.view.redirectToFragment
resources/mediawiki.action/mediawiki.action.view.redirectToFragment.js
* mediawiki.action.view.rightClickEdit
resources/mediawiki.action/mediawiki.action.view.rightClickEdit.js
* mediawiki.action.edit.editWarning
resources/mediawiki.action/mediawiki.action.edit.editWarning.js
* mediawiki.action.watch.ajax
No files associated with this resource.
* mediawiki.language
resources/mediawiki.language/mediawiki.language.js
resources/mediawiki.language/mediawiki.language.numbers.js
resources/mediawiki.language/languages/bs.js
resources/mediawiki.language/languages/dsb.js
resources/mediawiki.language/languages/fi.js
resources/mediawiki.language/languages/ga.js
resources/mediawiki.language/languages/he.js
resources/mediawiki.language/languages/hsb.js
resources/mediawiki.language/languages/hu.js
resources/mediawiki.language/languages/hy.js
resources/mediawiki.language/languages/la.js
resources/mediawiki.language/languages/os.js
resources/mediawiki.language/languages/ru.js
resources/mediawiki.language/languages/sl.js
resources/mediawiki.language/languages/uk.js
* mediawiki.cldr
resources/mediawiki.language/mediawiki.cldr.js
* mediawiki.libs.pluralruleparser
Possibly should be moved to /lib
resources/mediawiki.libs/CLDRPluralRuleParser.js
* mediawiki.language.init
resources/mediawiki.language/mediawiki.language.init.js
* mediawiki.jqueryMsg
resources/mediawiki/mediawiki.jqueryMsg.js
resources/mediawiki/mediawiki.jqueryMsg.peg
* mediawiki.language.months
resources/mediawiki.language/mediawiki.language.months.js
* mediawiki.libs.jpegmeta
resources/mediawiki.libs/mediawiki.libs.jpegmeta.js
* mediawiki.page.gallery
resources/mediawiki.page/mediawiki.page.gallery.js
* mediawiki.page.ready
resources/mediawiki.page/mediawiki.page.ready.js
* mediawiki.page.startup
resources/mediawiki.page/mediawiki.page.startup.js
* mediawiki.page.patrol.ajax
resources/mediawiki.page/mediawiki.page.patrol.ajax.js
* mediawiki.page.watch.ajax
resources/mediawiki.page/mediawiki.page.watch.ajax.js
* mediawiki.page.image.pagination
resources/mediawiki.page/mediawiki.page.image.pagination.js
* mediawiki.special
resources/mediawiki.special/mediawiki.special.css
resources/mediawiki.special/mediawiki.special.js
* mediawiki.special.block
resources/mediawiki.special/mediawiki.special.block.css
resources/mediawiki.special/mediawiki.special.block.js
* mediawiki.special.changeemail
resources/mediawiki.special/mediawiki.special.changeemail.css
resources/mediawiki.special/mediawiki.special.changeemail.js
* mediawiki.special.changeslist
resources/mediawiki.special/mediawiki.special.changeslist.css
* mediawiki.special.changeslist.legend
resources/mediawiki.special/mediawiki.special.changeslist.legend.css
* mediawiki.special.changeslist.legend.js
resources/mediawiki.special/mediawiki.special.changeslist.legend.js
* mediawiki.special.changeslist.enhanced
resources/mediawiki.special/mediawiki.special.changeslist.enhanced.css
* mediawiki.special.movePage
resources/mediawiki.special/mediawiki.special.movePage.js
* mediawiki.special.pagesWithProp
resources/mediawiki.special/mediawiki.special.pagesWithProp.css
* mediawiki.special.preferences
resources/mediawiki.special/mediawiki.special.preferences.css
resources/mediawiki.special/mediawiki.special.preferences.js
* mediawiki.special.recentchanges
resources/mediawiki.special/mediawiki.special.recentchanges.js
* mediawiki.special.search
resources/mediawiki.special/mediawiki.special.search.css
resources/mediawiki.special/mediawiki.special.search.js
* mediawiki.special.undelete
resources/mediawiki.special/mediawiki.special.undelete.js
* mediawiki.special.upload
resources/mediawiki.special/mediawiki.special.upload.js
* mediawiki.special.userlogin.common.styles
resources/mediawiki.special/mediawiki.special.userlogin.common.css
resources/mediawiki.special/images/icon-lock.png
* mediawiki.special.userlogin.signup.styles
resources/mediawiki.special/mediawiki.special.userlogin.signup.css
resources/mediawiki.special/images/icon-edits.png
resources/mediawiki.special/images/icon-pages.png
resources/mediawiki.special/images/icon-contributors.png
* mediawiki.special.userlogin.login.styles
resources/mediawiki.special/mediawiki.special.userlogin.login.css
resources/mediawiki.special/images/glyph-people-large.png
* mediawiki.special.userlogin.common.js
resources/mediawiki.special/mediawiki.special.userlogin.common.js
* mediawiki.special.userlogin.signup.js
resources/mediawiki.special/mediawiki.special.userlogin.signup.js
* mediawiki.special.javaScriptTest
resources/mediawiki.special/mediawiki.special.javaScriptTest.js
* mediawiki.special.version
resources/mediawiki.special/mediawiki.special.version.css
* mediawiki.ui
resources/mediawiki.ui/default.less
resources/mediawiki.ui/vector.less
resources/mediawiki.ui/components/utilities.less
resources/mediawiki.ui/components/default/forms.less
resources/mediawiki.ui/components/vector/containers.less
resources/mediawiki.ui/components/vector/forms.less
resources/mediawiki.ui/mixins/effects.less
resources/mediawiki.ui/mixins/forms.less
resources/mediawiki.ui/mixins/type.less
resources/mediawiki.ui/mixins/utilities.less
resources/mediawiki.ui/settings/colors.less
resources/mediawiki.ui/settings/typography.less
resources/mediawiki.ui/styleguide.md
* mediawiki.ui.button
resources/mediawiki.ui/components/default/buttons.less
resources/mediawiki.ui/components/vector/buttons.less
Legacy modules, untouched:
* mediawiki.legacy.ajax
* mediawiki.legacy.commonPrint
* mediawiki.legacy.config
* mediawiki.legacy.protect
* mediawiki.legacy.shared
* mediawiki.legacy.oldshared
* mediawiki.legacy.upload
* mediawiki.legacy.wikibits
Miscellaneous files moved elsewhere
* A currently-failing (unused?) script attempting to build some kss style documentation.
Previously in the root of the resources directory, now moved to a new folder, /docs/kss.
Makefile
README.txt
package.json
scripts/nodecheck.sh
styleguide-template/index.html
styleguide-template/public/kss.less
styleguide-template/public/less.js
* ResourceLoader startup JS code was also moved to /src
resources/startup.js
* mediawiki.mixins, hard-coded to be loaded by ResourceLoader, also moved to /src
resources/mediawiki.less/mediawiki.mixins.animation.less
resources/mediawiki.less/mediawiki.mixins.less
resources/mediawiki.less/mediawiki.mixins.rotation.less
* jquery.cycle.all.js appears not to be refered to (?!):
(added in 2f1f0abc6b)
resources/jquery/jquery.cycle.all.js
Change-Id: Id5ead1453412e763bdb3763084e43694517088fd
1166 lines
36 KiB
JavaScript
1166 lines
36 KiB
JavaScript
/**
|
|
* jQuery Validation Plugin 1.8.1
|
|
*
|
|
* http://bassistance.de/jquery-plugins/jquery-plugin-validation/
|
|
* http://docs.jquery.com/Plugins/Validation
|
|
*
|
|
* Copyright (c) 2006 - 2011 Jörn Zaefferer
|
|
*
|
|
* Dual licensed under the MIT and GPL licenses:
|
|
* http://www.opensource.org/licenses/mit-license.php
|
|
* http://www.gnu.org/licenses/gpl.html
|
|
*/
|
|
|
|
(function($) {
|
|
|
|
$.extend($.fn, {
|
|
// http://docs.jquery.com/Plugins/Validation/validate
|
|
validate: function( options ) {
|
|
|
|
// if nothing is selected, return nothing; can't chain anyway
|
|
if (!this.length) {
|
|
options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" );
|
|
return;
|
|
}
|
|
|
|
// check if a validator for this form was already created
|
|
var validator = $.data(this[0], 'validator');
|
|
if ( validator ) {
|
|
return validator;
|
|
}
|
|
|
|
validator = new $.validator( options, this[0] );
|
|
$.data(this[0], 'validator', validator);
|
|
|
|
if ( validator.settings.onsubmit ) {
|
|
|
|
// allow suppresing validation by adding a cancel class to the submit button
|
|
this.find("input, button").filter(".cancel").click(function() {
|
|
validator.cancelSubmit = true;
|
|
});
|
|
|
|
// when a submitHandler is used, capture the submitting button
|
|
if (validator.settings.submitHandler) {
|
|
this.find("input, button").filter(":submit").click(function() {
|
|
validator.submitButton = this;
|
|
});
|
|
}
|
|
|
|
// validate the form on submit
|
|
this.submit( function( event ) {
|
|
if ( validator.settings.debug )
|
|
// prevent form submit to be able to see console output
|
|
event.preventDefault();
|
|
|
|
function handle() {
|
|
if ( validator.settings.submitHandler ) {
|
|
if (validator.submitButton) {
|
|
// insert a hidden input as a replacement for the missing submit button
|
|
var hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);
|
|
}
|
|
validator.settings.submitHandler.call( validator, validator.currentForm );
|
|
if (validator.submitButton) {
|
|
// and clean up afterwards; thanks to no-block-scope, hidden can be referenced
|
|
hidden.remove();
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// prevent submit for invalid forms or custom submit handlers
|
|
if ( validator.cancelSubmit ) {
|
|
validator.cancelSubmit = false;
|
|
return handle();
|
|
}
|
|
if ( validator.form() ) {
|
|
if ( validator.pendingRequest ) {
|
|
validator.formSubmitted = true;
|
|
return false;
|
|
}
|
|
return handle();
|
|
} else {
|
|
validator.focusInvalid();
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
return validator;
|
|
},
|
|
// http://docs.jquery.com/Plugins/Validation/valid
|
|
valid: function() {
|
|
if ( $(this[0]).is('form')) {
|
|
return this.validate().form();
|
|
} else {
|
|
var valid = true;
|
|
var validator = $(this[0].form).validate();
|
|
this.each(function() {
|
|
valid &= validator.element(this);
|
|
});
|
|
return valid;
|
|
}
|
|
},
|
|
// attributes: space seperated list of attributes to retrieve and remove
|
|
removeAttrs: function(attributes) {
|
|
var result = {},
|
|
$element = this;
|
|
$.each(attributes.split(/\s/), function(index, value) {
|
|
result[value] = $element.attr(value);
|
|
$element.removeAttr(value);
|
|
});
|
|
return result;
|
|
},
|
|
// http://docs.jquery.com/Plugins/Validation/rules
|
|
rules: function(command, argument) {
|
|
var element = this[0];
|
|
|
|
if (command) {
|
|
var settings = $.data(element.form, 'validator').settings;
|
|
var staticRules = settings.rules;
|
|
var existingRules = $.validator.staticRules(element);
|
|
switch(command) {
|
|
case "add":
|
|
$.extend(existingRules, $.validator.normalizeRule(argument));
|
|
staticRules[element.name] = existingRules;
|
|
if (argument.messages)
|
|
settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );
|
|
break;
|
|
case "remove":
|
|
if (!argument) {
|
|
delete staticRules[element.name];
|
|
return existingRules;
|
|
}
|
|
var filtered = {};
|
|
$.each(argument.split(/\s/), function(index, method) {
|
|
filtered[method] = existingRules[method];
|
|
delete existingRules[method];
|
|
});
|
|
return filtered;
|
|
}
|
|
}
|
|
|
|
var data = $.validator.normalizeRules(
|
|
$.extend(
|
|
{},
|
|
$.validator.metadataRules(element),
|
|
$.validator.classRules(element),
|
|
$.validator.attributeRules(element),
|
|
$.validator.staticRules(element)
|
|
), element);
|
|
|
|
// make sure required is at front
|
|
if (data.required) {
|
|
var param = data.required;
|
|
delete data.required;
|
|
data = $.extend({required: param}, data);
|
|
}
|
|
|
|
return data;
|
|
}
|
|
});
|
|
|
|
// Custom selectors
|
|
$.extend($.expr[":"], {
|
|
// http://docs.jquery.com/Plugins/Validation/blank
|
|
blank: function(a) {return !$.trim("" + a.value);},
|
|
// http://docs.jquery.com/Plugins/Validation/filled
|
|
filled: function(a) {return !!$.trim("" + a.value);},
|
|
// http://docs.jquery.com/Plugins/Validation/unchecked
|
|
unchecked: function(a) {return !a.checked;}
|
|
});
|
|
|
|
// constructor for validator
|
|
$.validator = function( options, form ) {
|
|
this.settings = $.extend( true, {}, $.validator.defaults, options );
|
|
this.currentForm = form;
|
|
this.init();
|
|
};
|
|
|
|
$.validator.format = function(source, params) {
|
|
if ( arguments.length == 1 )
|
|
return function() {
|
|
var args = $.makeArray(arguments);
|
|
args.unshift(source);
|
|
return $.validator.format.apply( this, args );
|
|
};
|
|
if ( arguments.length > 2 && params.constructor != Array ) {
|
|
params = $.makeArray(arguments).slice(1);
|
|
}
|
|
if ( params.constructor != Array ) {
|
|
params = [ params ];
|
|
}
|
|
$.each(params, function(i, n) {
|
|
source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
|
|
});
|
|
return source;
|
|
};
|
|
|
|
$.extend($.validator, {
|
|
|
|
defaults: {
|
|
messages: {},
|
|
groups: {},
|
|
rules: {},
|
|
errorClass: "error",
|
|
validClass: "valid",
|
|
errorElement: "label",
|
|
focusInvalid: true,
|
|
errorContainer: $( [] ),
|
|
errorLabelContainer: $( [] ),
|
|
onsubmit: true,
|
|
ignore: [],
|
|
ignoreTitle: false,
|
|
onfocusin: function(element) {
|
|
this.lastActive = element;
|
|
|
|
// hide error label and remove error class on focus if enabled
|
|
if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
|
|
this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
|
|
this.addWrapper(this.errorsFor(element)).hide();
|
|
}
|
|
},
|
|
onfocusout: function(element) {
|
|
if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
|
|
this.element(element);
|
|
}
|
|
},
|
|
onkeyup: function(element) {
|
|
if ( element.name in this.submitted || element == this.lastElement ) {
|
|
this.element(element);
|
|
}
|
|
},
|
|
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)
|
|
this.element(element.parentNode);
|
|
},
|
|
highlight: function(element, errorClass, validClass) {
|
|
if (element.type === 'radio') {
|
|
this.findByName(element.name).addClass(errorClass).removeClass(validClass);
|
|
} else {
|
|
$(element).addClass(errorClass).removeClass(validClass);
|
|
}
|
|
},
|
|
unhighlight: function(element, errorClass, validClass) {
|
|
if (element.type === 'radio') {
|
|
this.findByName(element.name).removeClass(errorClass).addClass(validClass);
|
|
} else {
|
|
$(element).removeClass(errorClass).addClass(validClass);
|
|
}
|
|
}
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
|
|
setDefaults: function(settings) {
|
|
$.extend( $.validator.defaults, settings );
|
|
},
|
|
|
|
messages: {
|
|
required: "This field is required.",
|
|
remote: "Please fix this field.",
|
|
email: "Please enter a valid email address.",
|
|
url: "Please enter a valid URL.",
|
|
date: "Please enter a valid date.",
|
|
dateISO: "Please enter a valid date (ISO).",
|
|
number: "Please enter a valid number.",
|
|
digits: "Please enter only digits.",
|
|
creditcard: "Please enter a valid credit card number.",
|
|
equalTo: "Please enter the same value again.",
|
|
accept: "Please enter a value with a valid extension.",
|
|
maxlength: $.validator.format("Please enter no more than {0} characters."),
|
|
minlength: $.validator.format("Please enter at least {0} characters."),
|
|
rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
|
|
range: $.validator.format("Please enter a value between {0} and {1}."),
|
|
max: $.validator.format("Please enter a value less than or equal to {0}."),
|
|
min: $.validator.format("Please enter a value greater than or equal to {0}.")
|
|
},
|
|
|
|
autoCreateRanges: false,
|
|
|
|
prototype: {
|
|
|
|
init: function() {
|
|
this.labelContainer = $(this.settings.errorLabelContainer);
|
|
this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
|
|
this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );
|
|
this.submitted = {};
|
|
this.valueCache = {};
|
|
this.pendingRequest = 0;
|
|
this.pending = {};
|
|
this.invalid = {};
|
|
this.reset();
|
|
|
|
var groups = (this.groups = {});
|
|
$.each(this.settings.groups, function(key, value) {
|
|
$.each(value.split(/\s/), function(index, name) {
|
|
groups[name] = key;
|
|
});
|
|
});
|
|
var 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/, "");
|
|
validator.settings[eventType] && validator.settings[eventType].call(validator, this[0] );
|
|
}
|
|
$(this.currentForm)
|
|
.validateDelegate(":text, :password, :file, select, textarea", "focusin focusout keyup", delegate)
|
|
.validateDelegate(":radio, :checkbox, select, option", "click", delegate);
|
|
|
|
if (this.settings.invalidHandler)
|
|
$(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/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.showErrors();
|
|
return this.valid();
|
|
},
|
|
|
|
checkForm: function() {
|
|
this.prepareForm();
|
|
for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
|
|
this.check( elements[i] );
|
|
}
|
|
return this.valid();
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Validator/element
|
|
element: function( element ) {
|
|
element = this.clean( element );
|
|
this.lastElement = element;
|
|
this.prepareElement( element );
|
|
this.currentElements = $(element);
|
|
var result = this.check( element );
|
|
if ( result ) {
|
|
delete this.invalid[element.name];
|
|
} else {
|
|
this.invalid[element.name] = true;
|
|
}
|
|
if ( !this.numberOfInvalids() ) {
|
|
// Hide error containers on last error
|
|
this.toHide = this.toHide.add( this.containers );
|
|
}
|
|
this.showErrors();
|
|
return result;
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Validator/showErrors
|
|
showErrors: function(errors) {
|
|
if(errors) {
|
|
// add items to error list and map
|
|
$.extend( this.errorMap, errors );
|
|
this.errorList = [];
|
|
for ( var name in errors ) {
|
|
this.errorList.push({
|
|
message: errors[name],
|
|
element: this.findByName(name)[0]
|
|
});
|
|
}
|
|
// remove items from success list
|
|
this.successList = $.grep( this.successList, function(element) {
|
|
return !(element.name in errors);
|
|
});
|
|
}
|
|
this.settings.showErrors
|
|
? this.settings.showErrors.call( this, this.errorMap, this.errorList )
|
|
: this.defaultShowErrors();
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Validator/resetForm
|
|
resetForm: function() {
|
|
if ( $.fn.resetForm )
|
|
$( this.currentForm ).resetForm();
|
|
this.submitted = {};
|
|
this.prepareForm();
|
|
this.hideErrors();
|
|
this.elements().removeClass( this.settings.errorClass );
|
|
},
|
|
|
|
numberOfInvalids: function() {
|
|
return this.objectLength(this.invalid);
|
|
},
|
|
|
|
objectLength: function( obj ) {
|
|
var count = 0;
|
|
for ( var i in obj )
|
|
count++;
|
|
return count;
|
|
},
|
|
|
|
hideErrors: function() {
|
|
this.addWrapper( this.toHide ).hide();
|
|
},
|
|
|
|
valid: function() {
|
|
return this.size() == 0;
|
|
},
|
|
|
|
size: function() {
|
|
return this.errorList.length;
|
|
},
|
|
|
|
focusInvalid: function() {
|
|
if( this.settings.focusInvalid ) {
|
|
try {
|
|
$(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
|
|
.filter(":visible")
|
|
.focus()
|
|
// manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
|
|
.trigger("focusin");
|
|
} catch(e) {
|
|
// ignore IE throwing errors when focusing hidden elements
|
|
}
|
|
}
|
|
},
|
|
|
|
findLastActive: function() {
|
|
var lastActive = this.lastActive;
|
|
return lastActive && $.grep(this.errorList, function(n) {
|
|
return n.element.name == lastActive.name;
|
|
}).length == 1 && lastActive;
|
|
},
|
|
|
|
elements: function() {
|
|
var validator = this,
|
|
rulesCache = {};
|
|
|
|
// select all valid inputs inside the form (no submit or reset buttons)
|
|
return $(this.currentForm)
|
|
.find("input, select, textarea")
|
|
.not(":submit, :reset, :image, [disabled]")
|
|
.not( this.settings.ignore )
|
|
.filter(function() {
|
|
!this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this);
|
|
|
|
// select only the first element for each name, and only those with rules specified
|
|
if ( this.name in rulesCache || !validator.objectLength($(this).rules()) )
|
|
return false;
|
|
|
|
rulesCache[this.name] = true;
|
|
return true;
|
|
});
|
|
},
|
|
|
|
clean: function( selector ) {
|
|
return $( selector )[0];
|
|
},
|
|
|
|
errors: function() {
|
|
return $( this.settings.errorElement + "." + this.settings.errorClass, this.errorContext );
|
|
},
|
|
|
|
reset: function() {
|
|
this.successList = [];
|
|
this.errorList = [];
|
|
this.errorMap = {};
|
|
this.toShow = $([]);
|
|
this.toHide = $([]);
|
|
this.currentElements = $([]);
|
|
},
|
|
|
|
prepareForm: function() {
|
|
this.reset();
|
|
this.toHide = this.errors().add( this.containers );
|
|
},
|
|
|
|
prepareElement: function( element ) {
|
|
this.reset();
|
|
this.toHide = this.errorsFor(element);
|
|
},
|
|
|
|
check: function( element ) {
|
|
element = this.clean( element );
|
|
|
|
// if radio/checkbox, validate first element in group instead
|
|
if (this.checkable(element)) {
|
|
element = this.findByName( element.name ).not(this.settings.ignore)[0];
|
|
}
|
|
|
|
var rules = $(element).rules();
|
|
var dependencyMismatch = false;
|
|
for (var method in rules ) {
|
|
var rule = { method: method, parameters: rules[method] };
|
|
try {
|
|
var result = $.validator.methods[method].call( this, element.value.replace(/\r/g, ""), 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" ) {
|
|
dependencyMismatch = true;
|
|
continue;
|
|
}
|
|
dependencyMismatch = false;
|
|
|
|
if ( result == "pending" ) {
|
|
this.toHide = this.toHide.not( this.errorsFor(element) );
|
|
return;
|
|
}
|
|
|
|
if( !result ) {
|
|
this.formatAndAdd( element, rule );
|
|
return false;
|
|
}
|
|
} catch(e) {
|
|
this.settings.debug && window.console && console.log("exception occured when checking element " + element.id
|
|
+ ", check the '" + rule.method + "' method", e);
|
|
throw e;
|
|
}
|
|
}
|
|
if (dependencyMismatch)
|
|
return;
|
|
if ( this.objectLength(rules) )
|
|
this.successList.push(element);
|
|
return true;
|
|
},
|
|
|
|
// return the custom message for the given element and validation method
|
|
// specified in the element's "messages" metadata
|
|
customMetaMessage: function(element, method) {
|
|
if (!$.metadata)
|
|
return;
|
|
|
|
var meta = this.settings.meta
|
|
? $(element).metadata()[this.settings.meta]
|
|
: $(element).metadata();
|
|
|
|
return meta && meta.messages && meta.messages[method];
|
|
},
|
|
|
|
// return the custom message for the given element name and validation method
|
|
customMessage: function( name, method ) {
|
|
var m = this.settings.messages[name];
|
|
return m && (m.constructor == String
|
|
? m
|
|
: m[method]);
|
|
},
|
|
|
|
// return the first defined argument, allowing empty strings
|
|
findDefined: function() {
|
|
for(var i = 0; i < arguments.length; i++) {
|
|
if (arguments[i] !== undefined)
|
|
return arguments[i];
|
|
}
|
|
return undefined;
|
|
},
|
|
|
|
defaultMessage: function( element, method) {
|
|
return this.findDefined(
|
|
this.customMessage( element.name, method ),
|
|
this.customMetaMessage( element, method ),
|
|
// title is never undefined, so handle empty string as undefined
|
|
!this.settings.ignoreTitle && element.title || undefined,
|
|
$.validator.messages[method],
|
|
"<strong>Warning: No message defined for " + element.name + "</strong>"
|
|
);
|
|
},
|
|
|
|
formatAndAdd: function( element, rule ) {
|
|
var message = this.defaultMessage( element, rule.method ),
|
|
theregex = /\$?\{(\d+)\}/g;
|
|
if ( typeof message == "function" ) {
|
|
message = message.call(this, rule.parameters, element);
|
|
} else if (theregex.test(message)) {
|
|
message = jQuery.format(message.replace(theregex, '{$1}'), rule.parameters);
|
|
}
|
|
this.errorList.push({
|
|
message: message,
|
|
element: element
|
|
});
|
|
|
|
this.errorMap[element.name] = message;
|
|
this.submitted[element.name] = message;
|
|
},
|
|
|
|
addWrapper: function(toToggle) {
|
|
if ( this.settings.wrapper )
|
|
toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
|
|
return toToggle;
|
|
},
|
|
|
|
defaultShowErrors: function() {
|
|
for ( var i = 0; this.errorList[i]; i++ ) {
|
|
var error = this.errorList[i];
|
|
this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
|
|
this.showLabel( error.element, error.message );
|
|
}
|
|
if( this.errorList.length ) {
|
|
this.toShow = this.toShow.add( this.containers );
|
|
}
|
|
if (this.settings.success) {
|
|
for ( var i = 0; this.successList[i]; i++ ) {
|
|
this.showLabel( this.successList[i] );
|
|
}
|
|
}
|
|
if (this.settings.unhighlight) {
|
|
for ( var i = 0, elements = this.validElements(); elements[i]; i++ ) {
|
|
this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
|
|
}
|
|
}
|
|
this.toHide = this.toHide.not( this.toShow );
|
|
this.hideErrors();
|
|
this.addWrapper( this.toShow ).show();
|
|
},
|
|
|
|
validElements: function() {
|
|
return this.currentElements.not(this.invalidElements());
|
|
},
|
|
|
|
invalidElements: function() {
|
|
return $(this.errorList).map(function() {
|
|
return this.element;
|
|
});
|
|
},
|
|
|
|
showLabel: function(element, message) {
|
|
var label = this.errorsFor( element );
|
|
if ( label.length ) {
|
|
// refresh error/success class
|
|
label.removeClass().addClass( this.settings.errorClass );
|
|
|
|
// check if we have a generated label, replace the message then
|
|
label.attr("generated") && label.html(message);
|
|
} else {
|
|
// create label
|
|
label = $("<" + this.settings.errorElement + "/>")
|
|
.attr({"for": this.idOrName(element), generated: true})
|
|
.addClass(this.settings.errorClass)
|
|
.html(message || "");
|
|
if ( this.settings.wrapper ) {
|
|
// make sure the element is visible, even in IE
|
|
// actually showing the wrapped element is handled elsewhere
|
|
label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
|
|
}
|
|
if ( !this.labelContainer.append(label).length )
|
|
this.settings.errorPlacement
|
|
? this.settings.errorPlacement(label, $(element) )
|
|
: label.insertAfter(element);
|
|
}
|
|
if ( !message && this.settings.success ) {
|
|
label.text("");
|
|
typeof this.settings.success == "string"
|
|
? label.addClass( this.settings.success )
|
|
: this.settings.success( label );
|
|
}
|
|
this.toShow = this.toShow.add(label);
|
|
},
|
|
|
|
errorsFor: function(element) {
|
|
var name = this.idOrName(element);
|
|
return this.errors().filter(function() {
|
|
return $(this).attr('for') == name;
|
|
});
|
|
},
|
|
|
|
idOrName: function(element) {
|
|
return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
|
|
},
|
|
|
|
checkable: function( element ) {
|
|
return /radio|checkbox/i.test(element.type);
|
|
},
|
|
|
|
findByName: function( name ) {
|
|
// select by name and filter by form for performance over form.find("[name=...]")
|
|
var form = this.currentForm;
|
|
return $(document.getElementsByName(name)).map(function(index, element) {
|
|
return element.form == form && element.name == name && element || null;
|
|
});
|
|
},
|
|
|
|
getLength: function(value, element) {
|
|
switch( element.nodeName.toLowerCase() ) {
|
|
case 'select':
|
|
return $("option:selected", element).length;
|
|
case 'input':
|
|
if( this.checkable( element) )
|
|
return this.findByName(element.name).filter(':checked').length;
|
|
}
|
|
return value.length;
|
|
},
|
|
|
|
depend: function(param, element) {
|
|
return this.dependTypes[typeof param]
|
|
? this.dependTypes[typeof param](param, element)
|
|
: true;
|
|
},
|
|
|
|
dependTypes: {
|
|
"boolean": function(param, element) {
|
|
return param;
|
|
},
|
|
"string": function(param, element) {
|
|
return !!$(param, element.form).length;
|
|
},
|
|
"function": function(param, element) {
|
|
return param(element);
|
|
}
|
|
},
|
|
|
|
optional: function(element) {
|
|
return !$.validator.methods.required.call(this, $.trim(element.value), element) && "dependency-mismatch";
|
|
},
|
|
|
|
startRequest: function(element) {
|
|
if (!this.pending[element.name]) {
|
|
this.pendingRequest++;
|
|
this.pending[element.name] = true;
|
|
}
|
|
},
|
|
|
|
stopRequest: function(element, valid) {
|
|
this.pendingRequest--;
|
|
// sometimes synchronization fails, make sure pendingRequest is never < 0
|
|
if (this.pendingRequest < 0)
|
|
this.pendingRequest = 0;
|
|
delete this.pending[element.name];
|
|
if ( valid && this.pendingRequest == 0 && this.formSubmitted && this.form() ) {
|
|
$(this.currentForm).submit();
|
|
this.formSubmitted = false;
|
|
} else if (!valid && this.pendingRequest == 0 && this.formSubmitted) {
|
|
$(this.currentForm).triggerHandler("invalid-form", [this]);
|
|
this.formSubmitted = false;
|
|
}
|
|
},
|
|
|
|
previousValue: function(element) {
|
|
return $.data(element, "previousValue") || $.data(element, "previousValue", {
|
|
old: null,
|
|
valid: true,
|
|
message: this.defaultMessage( element, "remote" )
|
|
});
|
|
}
|
|
|
|
},
|
|
|
|
classRuleSettings: {
|
|
required: {required: true},
|
|
email: {email: true},
|
|
url: {url: true},
|
|
date: {date: true},
|
|
dateISO: {dateISO: true},
|
|
dateDE: {dateDE: true},
|
|
number: {number: true},
|
|
numberDE: {numberDE: true},
|
|
digits: {digits: true},
|
|
creditcard: {creditcard: true}
|
|
},
|
|
|
|
addClassRules: function(className, rules) {
|
|
className.constructor == String ?
|
|
this.classRuleSettings[className] = rules :
|
|
$.extend(this.classRuleSettings, className);
|
|
},
|
|
|
|
classRules: function(element) {
|
|
var rules = {};
|
|
var classes = $(element).attr('class');
|
|
classes && $.each(classes.split(' '), function() {
|
|
if (this in $.validator.classRuleSettings) {
|
|
$.extend(rules, $.validator.classRuleSettings[this]);
|
|
}
|
|
});
|
|
return rules;
|
|
},
|
|
|
|
attributeRules: function(element) {
|
|
var rules = {};
|
|
var $element = $(element);
|
|
|
|
for (var method in $.validator.methods) {
|
|
var value = $element.attr(method);
|
|
if (value) {
|
|
rules[method] = value;
|
|
}
|
|
}
|
|
|
|
// maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
|
|
if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) {
|
|
delete rules.maxlength;
|
|
}
|
|
|
|
return rules;
|
|
},
|
|
|
|
metadataRules: function(element) {
|
|
if (!$.metadata) return {};
|
|
|
|
var meta = $.data(element.form, 'validator').settings.meta;
|
|
return meta ?
|
|
$(element).metadata()[meta] :
|
|
$(element).metadata();
|
|
},
|
|
|
|
staticRules: function(element) {
|
|
var rules = {};
|
|
var validator = $.data(element.form, 'validator');
|
|
if (validator.settings.rules) {
|
|
rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
|
|
}
|
|
return rules;
|
|
},
|
|
|
|
normalizeRules: function(rules, element) {
|
|
// handle dependency check
|
|
$.each(rules, function(prop, val) {
|
|
// ignore rule when param is explicitly false, eg. required:false
|
|
if (val === false) {
|
|
delete rules[prop];
|
|
return;
|
|
}
|
|
if (val.param || val.depends) {
|
|
var keepRule = true;
|
|
switch (typeof val.depends) {
|
|
case "string":
|
|
keepRule = !!$(val.depends, element.form).length;
|
|
break;
|
|
case "function":
|
|
keepRule = val.depends.call(element, element);
|
|
break;
|
|
}
|
|
if (keepRule) {
|
|
rules[prop] = val.param !== undefined ? val.param : true;
|
|
} else {
|
|
delete rules[prop];
|
|
}
|
|
}
|
|
});
|
|
|
|
// evaluate parameters
|
|
$.each(rules, function(rule, parameter) {
|
|
rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
|
|
});
|
|
|
|
// clean number parameters
|
|
$.each(['minlength', 'maxlength', 'min', 'max'], function() {
|
|
if (rules[this]) {
|
|
rules[this] = Number(rules[this]);
|
|
}
|
|
});
|
|
$.each(['rangelength', 'range'], function() {
|
|
if (rules[this]) {
|
|
rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
|
|
}
|
|
});
|
|
|
|
if ($.validator.autoCreateRanges) {
|
|
// auto-create ranges
|
|
if (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];
|
|
delete rules.minlength;
|
|
delete rules.maxlength;
|
|
}
|
|
}
|
|
|
|
// To support custom messages in metadata ignore rule methods titled "messages"
|
|
if (rules.messages) {
|
|
delete rules.messages;
|
|
}
|
|
|
|
return rules;
|
|
},
|
|
|
|
// Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
|
|
normalizeRule: function(data) {
|
|
if( typeof data == "string" ) {
|
|
var transformed = {};
|
|
$.each(data.split(/\s/), function() {
|
|
transformed[this] = true;
|
|
});
|
|
data = transformed;
|
|
}
|
|
return data;
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Validator/addMethod
|
|
addMethod: function(name, method, message) {
|
|
$.validator.methods[name] = method;
|
|
$.validator.messages[name] = message != undefined ? message : $.validator.messages[name];
|
|
if (method.length < 3) {
|
|
$.validator.addClassRules(name, $.validator.normalizeRule(name));
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Methods/required
|
|
required: function(value, element, param) {
|
|
// check if dependency is met
|
|
if ( !this.depend(param, element) )
|
|
return "dependency-mismatch";
|
|
switch( element.nodeName.toLowerCase() ) {
|
|
case 'select':
|
|
// could be an array for select-multiple or a string, both are fine this way
|
|
var val = $(element).val();
|
|
return val && val.length > 0;
|
|
case 'input':
|
|
if ( this.checkable(element) )
|
|
return this.getLength(value, element) > 0;
|
|
default:
|
|
return $.trim(value).length > 0;
|
|
}
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Methods/remote
|
|
remote: function(value, element, param) {
|
|
if ( this.optional(element) )
|
|
return "dependency-mismatch";
|
|
|
|
var previous = this.previousValue(element);
|
|
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;
|
|
|
|
if ( this.pending[element.name] ) {
|
|
return "pending";
|
|
}
|
|
if ( previous.old === value ) {
|
|
return previous.valid;
|
|
}
|
|
|
|
previous.old = value;
|
|
var validator = this;
|
|
this.startRequest(element);
|
|
var data = {};
|
|
data[element.name] = value;
|
|
$.ajax($.extend(true, {
|
|
url: param,
|
|
mode: "abort",
|
|
port: "validate" + element.name,
|
|
dataType: "json",
|
|
data: data,
|
|
success: function(response) {
|
|
validator.settings.messages[element.name].remote = previous.originalMessage;
|
|
var valid = response === true;
|
|
if ( valid ) {
|
|
var submitted = validator.formSubmitted;
|
|
validator.prepareElement(element);
|
|
validator.formSubmitted = submitted;
|
|
validator.successList.push(element);
|
|
validator.showErrors();
|
|
} else {
|
|
var errors = {};
|
|
var message = response || validator.defaultMessage( element, "remote" );
|
|
errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
|
|
validator.showErrors(errors);
|
|
}
|
|
previous.valid = valid;
|
|
validator.stopRequest(element, valid);
|
|
}
|
|
}, param));
|
|
return "pending";
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Methods/minlength
|
|
minlength: function(value, element, param) {
|
|
return this.optional(element) || this.getLength($.trim(value), element) >= param;
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Methods/maxlength
|
|
maxlength: function(value, element, param) {
|
|
return this.optional(element) || this.getLength($.trim(value), element) <= param;
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Methods/rangelength
|
|
rangelength: function(value, element, param) {
|
|
var length = this.getLength($.trim(value), element);
|
|
return this.optional(element) || ( length >= param[0] && length <= param[1] );
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Methods/min
|
|
min: function( value, element, param ) {
|
|
return this.optional(element) || value >= param;
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Methods/max
|
|
max: function( value, element, param ) {
|
|
return this.optional(element) || value <= param;
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Methods/range
|
|
range: function( value, element, param ) {
|
|
return this.optional(element) || ( value >= param[0] && value <= param[1] );
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Methods/email
|
|
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);
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Methods/url
|
|
url: function(value, element) {
|
|
// contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
|
|
return this.optional(element) || /^(https?|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
|
|
date: function(value, element) {
|
|
return this.optional(element) || !/Invalid|NaN/.test(new Date(value));
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Methods/dateISO
|
|
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
|
|
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
|
|
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
|
|
creditcard: function(value, element) {
|
|
if ( this.optional(element) )
|
|
return "dependency-mismatch";
|
|
// accept only digits and dashes
|
|
if (/[^0-9-]+/.test(value))
|
|
return false;
|
|
var nCheck = 0,
|
|
nDigit = 0,
|
|
bEven = false;
|
|
|
|
value = value.replace(/\D/g, "");
|
|
|
|
for (var n = value.length - 1; n >= 0; n--) {
|
|
var cDigit = value.charAt(n);
|
|
var nDigit = parseInt(cDigit, 10);
|
|
if (bEven) {
|
|
if ((nDigit *= 2) > 9)
|
|
nDigit -= 9;
|
|
}
|
|
nCheck += nDigit;
|
|
bEven = !bEven;
|
|
}
|
|
|
|
return (nCheck % 10) == 0;
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Methods/accept
|
|
accept: function(value, element, param) {
|
|
param = typeof param == "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif";
|
|
return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i"));
|
|
},
|
|
|
|
// http://docs.jquery.com/Plugins/Validation/Methods/equalTo
|
|
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
|
|
var target = $(param).unbind(".validate-equalTo").bind("blur.validate-equalTo", function() {
|
|
$(element).valid();
|
|
});
|
|
return value == target.val();
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
// deprecated, use $.validator.format instead
|
|
$.format = $.validator.format;
|
|
|
|
})(jQuery);
|
|
|
|
// ajax mode: abort
|
|
// 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 = {};
|
|
// Use a prefilter if available (1.5+)
|
|
if ( $.ajaxPrefilter ) {
|
|
$.ajaxPrefilter(function(settings, _, xhr) {
|
|
var port = settings.port;
|
|
if (settings.mode == "abort") {
|
|
if ( pendingRequests[port] ) {
|
|
pendingRequests[port].abort();
|
|
}
|
|
pendingRequests[port] = xhr;
|
|
}
|
|
});
|
|
} else {
|
|
// Proxy ajax
|
|
var ajax = $.ajax;
|
|
$.ajax = function(settings) {
|
|
var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
|
|
port = ( "port" in settings ? settings : $.ajaxSettings ).port;
|
|
if (mode == "abort") {
|
|
if ( pendingRequests[port] ) {
|
|
pendingRequests[port].abort();
|
|
}
|
|
return (pendingRequests[port] = ajax.apply(this, arguments));
|
|
}
|
|
return ajax.apply(this, arguments);
|
|
};
|
|
}
|
|
})(jQuery);
|
|
|
|
// provides cross-browser focusin and focusout events
|
|
// IE has native support, in other browsers, use event caputuring (neither bubbles)
|
|
|
|
// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
|
|
// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target
|
|
;(function($) {
|
|
// only implement if not provided by jQuery core (since 1.4)
|
|
// TODO verify if jQuery 1.4's implementation is compatible with older jQuery special-event APIs
|
|
if (!jQuery.event.special.focusin && !jQuery.event.special.focusout && document.addEventListener) {
|
|
$.each({
|
|
focus: 'focusin',
|
|
blur: 'focusout'
|
|
}, function( original, fix ){
|
|
$.event.special[fix] = {
|
|
setup:function() {
|
|
this.addEventListener( original, handler, true );
|
|
},
|
|
teardown:function() {
|
|
this.removeEventListener( original, handler, true );
|
|
},
|
|
handler: function(e) {
|
|
arguments[0] = $.event.fix(e);
|
|
arguments[0].type = fix;
|
|
return $.event.handle.apply(this, arguments);
|
|
}
|
|
};
|
|
function handler(e) {
|
|
e = $.event.fix(e);
|
|
e.type = fix;
|
|
return $.event.handle.call(this, e);
|
|
}
|
|
});
|
|
};
|
|
$.extend($.fn, {
|
|
validateDelegate: function(delegate, type, handler) {
|
|
return this.bind(type, function(event) {
|
|
var target = $(event.target);
|
|
if (target.is(delegate)) {
|
|
return handler.apply(target, arguments);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
})(jQuery);
|