r67209 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r67208‎ | r67209 | r67210 >
Date:04:25, 2 June 2010
Author:neilk
Status:deferred
Tags:
Comment:
validation with deed form working from plugin -- not doing it custom anymore
Modified paths:
  • /trunk/extensions/UploadWizard/UploadWizard.i18n.php (modified) (history)
  • /trunk/extensions/UploadWizard/UploadWizardPage.js (modified) (history)
  • /trunk/extensions/UploadWizard/js/jquery/plugins/jquery.validate.additional-methods.js (added) (history)
  • /trunk/extensions/UploadWizard/js/jquery/plugins/jquery.validate.js (added) (history)
  • /trunk/extensions/UploadWizard/js/mw.UploadWizard.js (modified) (history)
  • /trunk/extensions/UploadWizard/loader.js (modified) (history)
  • /trunk/extensions/UploadWizard/styles/uploadWizard.css (modified) (history)

Diff [purge]

Index: trunk/extensions/UploadWizard/loader.js
@@ -23,6 +23,7 @@
2424 "mw.MockUploadHandler" : "js/mw.MockUploadHandler.js",
2525 "$j.fn.tipsy" : "js/jquery/plugins/jquery.tipsy.js",
2626 "$j.fn.morphCrossfade" : "js/jquery/plugins/jquery.morphCrossfade.js",
 27+ "$j.fn.validate" : "js/jquery/plugins/jquery.validate.js",
2728 "mw.style.tipsy" : "styles/jquery.tipsy.css"
2829 });
2930
@@ -59,6 +60,7 @@
6061 '$j.fn.autocomplete',
6162 '$j.fn.tipsy',
6263 '$j.fn.morphCrossfade',
 64+ '$j.fn.validate',
6365 'mw.style.tipsy',
6466 'mw.style.autocomplete'
6567 ],
Index: trunk/extensions/UploadWizard/styles/uploadWizard.css
@@ -523,5 +523,9 @@
524524
525525 .mwe-error {
526526 color: #ff0000;
527 - display: none;
528527 }
 528+
 529+input[type='text'].mwe-error {
 530+ color: black;
 531+ border: 1px solid #ff0000;
 532+}
Index: trunk/extensions/UploadWizard/UploadWizard.i18n.php
@@ -22,7 +22,7 @@
2323 'mwe-upwiz-step-thanks' => '4. Use your files',
2424 'mwe-upwiz-intro' => "Welcome to Wikimedia Commons, a repository of images, sounds, and movies that anyone can freely download and use. Add to humanity's knowledge by uploading files that could be used for an educational purpose.",
2525 'mwe-upwiz-add-file-n' => 'Add another file',
26 - 'mwe-upwiz-add-file-0' => 'Click here to add a file for upload',
 26+ 'mwe-upwiz-add-file-0' => 'Click here to upload a file',
2727 'mwe-upwiz-browse' => 'Browse...',
2828 'mwe-upwiz-transported' => 'OK',
2929 'mwe-upwiz-click-here' => 'Click here to select a file',
@@ -111,7 +111,12 @@
112112 'mwe-upwiz-license-incompatible-pd' => 'Public domain licenses are incompatible with any other kind of license.',
113113 'mwe-upwiz-license-incompatible-cc' => 'You can only choose one kind of Creative Commons license.',
114114 'mwe-upwiz-license-show-all' => 'Use a different license',
115 - 'mwe-upwiz-license-show-recommended' => 'Use the recommended license'
 115+ 'mwe-upwiz-license-show-recommended' => 'Use the recommended license',
 116+ 'mwe-upwiz-error-author-blank' => 'You must sign the field below with your username or real name.',
 117+ 'mwe-upwiz-error-author-too-long' => 'Your signature is too long. Make it shorter than $1 {{PLURAL:$1|character|characters}}.',
 118+ 'mwe-upwiz-error-author-too-short' => 'Your signature is too short. Make it longer than $1 {{PLURAL:$1|character|characters}}.',
 119+ 'mwe-upwiz-error-author-bad-chars' => 'Your signature contains symbols that aren\'t allowed. Please don\'t use wikitext or HTML here, just your username or real name.',
 120+
116121 );
117122
118123 /** Message documentation (Message documentation)
Index: trunk/extensions/UploadWizard/js/jquery/plugins/jquery.validate.js
@@ -0,0 +1,1145 @@
 2+/*
 3+ * jQuery validation plug-in 1.7
 4+ *
 5+ * http://bassistance.de/jquery-plugins/jquery-plugin-validation/
 6+ * http://docs.jquery.com/Plugins/Validation
 7+ *
 8+ * Copyright (c) 2006 - 2008 Jörn Zaefferer
 9+ *
 10+ * $Id: jquery.validate.js 6403 2009-06-17 14:27:16Z joern.zaefferer $
 11+ *
 12+ * Dual licensed under the MIT and GPL licenses:
 13+ * http://www.opensource.org/licenses/mit-license.php
 14+ * http://www.gnu.org/licenses/gpl.html
 15+ */
 16+
 17+(function($) {
 18+
 19+$.extend($.fn, {
 20+ // http://docs.jquery.com/Plugins/Validation/validate
 21+ validate: function( options ) {
 22+
 23+ // if nothing is selected, return nothing; can't chain anyway
 24+ if (!this.length) {
 25+ options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" );
 26+ return;
 27+ }
 28+
 29+ // check if a validator for this form was already created
 30+ var validator = $.data(this[0], 'validator');
 31+ if ( validator ) {
 32+ return validator;
 33+ }
 34+
 35+ validator = new $.validator( options, this[0] );
 36+ $.data(this[0], 'validator', validator);
 37+
 38+ if ( validator.settings.onsubmit ) {
 39+
 40+ // allow suppresing validation by adding a cancel class to the submit button
 41+ this.find("input, button").filter(".cancel").click(function() {
 42+ validator.cancelSubmit = true;
 43+ });
 44+
 45+ // when a submitHandler is used, capture the submitting button
 46+ if (validator.settings.submitHandler) {
 47+ this.find("input, button").filter(":submit").click(function() {
 48+ validator.submitButton = this;
 49+ });
 50+ }
 51+
 52+ // validate the form on submit
 53+ this.submit( function( event ) {
 54+ if ( validator.settings.debug )
 55+ // prevent form submit to be able to see console output
 56+ event.preventDefault();
 57+
 58+ function handle() {
 59+ if ( validator.settings.submitHandler ) {
 60+ if (validator.submitButton) {
 61+ // insert a hidden input as a replacement for the missing submit button
 62+ var hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);
 63+ }
 64+ validator.settings.submitHandler.call( validator, validator.currentForm );
 65+ if (validator.submitButton) {
 66+ // and clean up afterwards; thanks to no-block-scope, hidden can be referenced
 67+ hidden.remove();
 68+ }
 69+ return false;
 70+ }
 71+ return true;
 72+ }
 73+
 74+ // prevent submit for invalid forms or custom submit handlers
 75+ if ( validator.cancelSubmit ) {
 76+ validator.cancelSubmit = false;
 77+ return handle();
 78+ }
 79+ if ( validator.form() ) {
 80+ if ( validator.pendingRequest ) {
 81+ validator.formSubmitted = true;
 82+ return false;
 83+ }
 84+ return handle();
 85+ } else {
 86+ validator.focusInvalid();
 87+ return false;
 88+ }
 89+ });
 90+ }
 91+
 92+ return validator;
 93+ },
 94+ // http://docs.jquery.com/Plugins/Validation/valid
 95+ valid: function() {
 96+ if ( $(this[0]).is('form')) {
 97+ return this.validate().form();
 98+ } else {
 99+ var valid = true;
 100+ var validator = $(this[0].form).validate();
 101+ this.each(function() {
 102+ valid &= validator.element(this);
 103+ });
 104+ return valid;
 105+ }
 106+ },
 107+ // attributes: space seperated list of attributes to retrieve and remove
 108+ removeAttrs: function(attributes) {
 109+ var result = {},
 110+ $element = this;
 111+ $.each(attributes.split(/\s/), function(index, value) {
 112+ result[value] = $element.attr(value);
 113+ $element.removeAttr(value);
 114+ });
 115+ return result;
 116+ },
 117+ // http://docs.jquery.com/Plugins/Validation/rules
 118+ rules: function(command, argument) {
 119+ var element = this[0];
 120+
 121+ if (command) {
 122+ var settings = $.data(element.form, 'validator').settings;
 123+ var staticRules = settings.rules;
 124+ var existingRules = $.validator.staticRules(element);
 125+ switch(command) {
 126+ case "add":
 127+ $.extend(existingRules, $.validator.normalizeRule(argument));
 128+ staticRules[element.name] = existingRules;
 129+ if (argument.messages)
 130+ settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );
 131+ break;
 132+ case "remove":
 133+ if (!argument) {
 134+ delete staticRules[element.name];
 135+ return existingRules;
 136+ }
 137+ var filtered = {};
 138+ $.each(argument.split(/\s/), function(index, method) {
 139+ filtered[method] = existingRules[method];
 140+ delete existingRules[method];
 141+ });
 142+ return filtered;
 143+ }
 144+ }
 145+
 146+ var data = $.validator.normalizeRules(
 147+ $.extend(
 148+ {},
 149+ $.validator.metadataRules(element),
 150+ $.validator.classRules(element),
 151+ $.validator.attributeRules(element),
 152+ $.validator.staticRules(element)
 153+ ), element);
 154+
 155+ // make sure required is at front
 156+ if (data.required) {
 157+ var param = data.required;
 158+ delete data.required;
 159+ data = $.extend({required: param}, data);
 160+ }
 161+
 162+ return data;
 163+ }
 164+});
 165+
 166+// Custom selectors
 167+$.extend($.expr[":"], {
 168+ // http://docs.jquery.com/Plugins/Validation/blank
 169+ blank: function(a) {return !$.trim("" + a.value);},
 170+ // http://docs.jquery.com/Plugins/Validation/filled
 171+ filled: function(a) {return !!$.trim("" + a.value);},
 172+ // http://docs.jquery.com/Plugins/Validation/unchecked
 173+ unchecked: function(a) {return !a.checked;}
 174+});
 175+
 176+// constructor for validator
 177+$.validator = function( options, form ) {
 178+ this.settings = $.extend( true, {}, $.validator.defaults, options );
 179+ this.currentForm = form;
 180+ this.init();
 181+};
 182+
 183+$.validator.format = function(source, params) {
 184+ if ( arguments.length == 1 )
 185+ return function() {
 186+ var args = $.makeArray(arguments);
 187+ args.unshift(source);
 188+ return $.validator.format.apply( this, args );
 189+ };
 190+ if ( arguments.length > 2 && params.constructor != Array ) {
 191+ params = $.makeArray(arguments).slice(1);
 192+ }
 193+ if ( params.constructor != Array ) {
 194+ params = [ params ];
 195+ }
 196+ $.each(params, function(i, n) {
 197+ source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
 198+ });
 199+ return source;
 200+};
 201+
 202+$.extend($.validator, {
 203+
 204+ defaults: {
 205+ messages: {},
 206+ groups: {},
 207+ rules: {},
 208+ errorClass: "error",
 209+ validClass: "valid",
 210+ errorElement: "label",
 211+ focusInvalid: true,
 212+ errorContainer: $( [] ),
 213+ errorLabelContainer: $( [] ),
 214+ onsubmit: true,
 215+ ignore: [],
 216+ ignoreTitle: false,
 217+ onfocusin: function(element) {
 218+ this.lastActive = element;
 219+
 220+ // hide error label and remove error class on focus if enabled
 221+ if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
 222+ this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
 223+ this.errorsFor(element).hide();
 224+ }
 225+ },
 226+ onfocusout: function(element) {
 227+ if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
 228+ this.element(element);
 229+ }
 230+ },
 231+ onkeyup: function(element) {
 232+ if ( element.name in this.submitted || element == this.lastElement ) {
 233+ this.element(element);
 234+ }
 235+ },
 236+ onclick: function(element) {
 237+ // click on selects, radiobuttons and checkboxes
 238+ if ( element.name in this.submitted )
 239+ this.element(element);
 240+ // or option elements, check parent select in that case
 241+ else if (element.parentNode.name in this.submitted)
 242+ this.element(element.parentNode);
 243+ },
 244+ highlight: function( element, errorClass, validClass ) {
 245+ $(element).addClass(errorClass).removeClass(validClass);
 246+ },
 247+ unhighlight: function( element, errorClass, validClass ) {
 248+ $(element).removeClass(errorClass).addClass(validClass);
 249+ }
 250+ },
 251+
 252+ // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
 253+ setDefaults: function(settings) {
 254+ $.extend( $.validator.defaults, settings );
 255+ },
 256+
 257+ messages: {
 258+ required: "This field is required.",
 259+ remote: "Please fix this field.",
 260+ email: "Please enter a valid email address.",
 261+ url: "Please enter a valid URL.",
 262+ date: "Please enter a valid date.",
 263+ dateISO: "Please enter a valid date (ISO).",
 264+ number: "Please enter a valid number.",
 265+ digits: "Please enter only digits.",
 266+ creditcard: "Please enter a valid credit card number.",
 267+ equalTo: "Please enter the same value again.",
 268+ accept: "Please enter a value with a valid extension.",
 269+ maxlength: $.validator.format("Please enter no more than {0} characters."),
 270+ minlength: $.validator.format("Please enter at least {0} characters."),
 271+ rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
 272+ range: $.validator.format("Please enter a value between {0} and {1}."),
 273+ max: $.validator.format("Please enter a value less than or equal to {0}."),
 274+ min: $.validator.format("Please enter a value greater than or equal to {0}.")
 275+ },
 276+
 277+ autoCreateRanges: false,
 278+
 279+ prototype: {
 280+
 281+ init: function() {
 282+ this.labelContainer = $(this.settings.errorLabelContainer);
 283+ this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
 284+ this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );
 285+ this.submitted = {};
 286+ this.valueCache = {};
 287+ this.pendingRequest = 0;
 288+ this.pending = {};
 289+ this.invalid = {};
 290+ this.reset();
 291+
 292+ var groups = (this.groups = {});
 293+ $.each(this.settings.groups, function(key, value) {
 294+ $.each(value.split(/\s/), function(index, name) {
 295+ groups[name] = key;
 296+ });
 297+ });
 298+ var rules = this.settings.rules;
 299+ $.each(rules, function(key, value) {
 300+ rules[key] = $.validator.normalizeRule(value);
 301+ });
 302+
 303+ function delegate(event) {
 304+ var validator = $.data(this[0].form, "validator"),
 305+ eventType = "on" + event.type.replace(/^validate/, "");
 306+ validator.settings[eventType] && validator.settings[eventType].call(validator, this[0] );
 307+ }
 308+ $(this.currentForm)
 309+ .validateDelegate(":text, :password, :file, select, textarea", "focusin focusout keyup", delegate)
 310+ .validateDelegate(":radio, :checkbox, select, option", "click", delegate);
 311+
 312+ if (this.settings.invalidHandler)
 313+ $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
 314+ },
 315+
 316+ // http://docs.jquery.com/Plugins/Validation/Validator/form
 317+ form: function() {
 318+ this.checkForm();
 319+ $.extend(this.submitted, this.errorMap);
 320+ this.invalid = $.extend({}, this.errorMap);
 321+ if (!this.valid())
 322+ $(this.currentForm).triggerHandler("invalid-form", [this]);
 323+ this.showErrors();
 324+ return this.valid();
 325+ },
 326+
 327+ checkForm: function() {
 328+ this.prepareForm();
 329+ for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
 330+ this.check( elements[i] );
 331+ }
 332+ return this.valid();
 333+ },
 334+
 335+ // http://docs.jquery.com/Plugins/Validation/Validator/element
 336+ element: function( element ) {
 337+ element = this.clean( element );
 338+ this.lastElement = element;
 339+ this.prepareElement( element );
 340+ this.currentElements = $(element);
 341+ var result = this.check( element );
 342+ if ( result ) {
 343+ delete this.invalid[element.name];
 344+ } else {
 345+ this.invalid[element.name] = true;
 346+ }
 347+ if ( !this.numberOfInvalids() ) {
 348+ // Hide error containers on last error
 349+ this.toHide = this.toHide.add( this.containers );
 350+ }
 351+ this.showErrors();
 352+ return result;
 353+ },
 354+
 355+ // http://docs.jquery.com/Plugins/Validation/Validator/showErrors
 356+ showErrors: function(errors) {
 357+ if(errors) {
 358+ // add items to error list and map
 359+ $.extend( this.errorMap, errors );
 360+ this.errorList = [];
 361+ for ( var name in errors ) {
 362+ this.errorList.push({
 363+ message: errors[name],
 364+ element: this.findByName(name)[0]
 365+ });
 366+ }
 367+ // remove items from success list
 368+ this.successList = $.grep( this.successList, function(element) {
 369+ return !(element.name in errors);
 370+ });
 371+ }
 372+ this.settings.showErrors
 373+ ? this.settings.showErrors.call( this, this.errorMap, this.errorList )
 374+ : this.defaultShowErrors();
 375+ },
 376+
 377+ // http://docs.jquery.com/Plugins/Validation/Validator/resetForm
 378+ resetForm: function() {
 379+ if ( $.fn.resetForm )
 380+ $( this.currentForm ).resetForm();
 381+ this.submitted = {};
 382+ this.prepareForm();
 383+ this.hideErrors();
 384+ this.elements().removeClass( this.settings.errorClass );
 385+ },
 386+
 387+ numberOfInvalids: function() {
 388+ return this.objectLength(this.invalid);
 389+ },
 390+
 391+ objectLength: function( obj ) {
 392+ var count = 0;
 393+ for ( var i in obj )
 394+ count++;
 395+ return count;
 396+ },
 397+
 398+ hideErrors: function() {
 399+ this.addWrapper( this.toHide ).hide();
 400+ },
 401+
 402+ valid: function() {
 403+ return this.size() == 0;
 404+ },
 405+
 406+ size: function() {
 407+ return this.errorList.length;
 408+ },
 409+
 410+ focusInvalid: function() {
 411+ if( this.settings.focusInvalid ) {
 412+ try {
 413+ $(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
 414+ .filter(":visible")
 415+ .focus()
 416+ // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
 417+ .trigger("focusin");
 418+ } catch(e) {
 419+ // ignore IE throwing errors when focusing hidden elements
 420+ }
 421+ }
 422+ },
 423+
 424+ findLastActive: function() {
 425+ var lastActive = this.lastActive;
 426+ return lastActive && $.grep(this.errorList, function(n) {
 427+ return n.element.name == lastActive.name;
 428+ }).length == 1 && lastActive;
 429+ },
 430+
 431+ elements: function() {
 432+ var validator = this,
 433+ rulesCache = {};
 434+
 435+ // select all valid inputs inside the form (no submit or reset buttons)
 436+ // workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved
 437+ return $([]).add(this.currentForm.elements)
 438+ .filter(":input")
 439+ .not(":submit, :reset, :image, [disabled]")
 440+ .not( this.settings.ignore )
 441+ .filter(function() {
 442+ !this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this);
 443+
 444+ // select only the first element for each name, and only those with rules specified
 445+ if ( this.name in rulesCache || !validator.objectLength($(this).rules()) )
 446+ return false;
 447+
 448+ rulesCache[this.name] = true;
 449+ return true;
 450+ });
 451+ },
 452+
 453+ clean: function( selector ) {
 454+ return $( selector )[0];
 455+ },
 456+
 457+ errors: function() {
 458+ return $( this.settings.errorElement + "." + this.settings.errorClass, this.errorContext );
 459+ },
 460+
 461+ reset: function() {
 462+ this.successList = [];
 463+ this.errorList = [];
 464+ this.errorMap = {};
 465+ this.toShow = $([]);
 466+ this.toHide = $([]);
 467+ this.currentElements = $([]);
 468+ },
 469+
 470+ prepareForm: function() {
 471+ this.reset();
 472+ this.toHide = this.errors().add( this.containers );
 473+ },
 474+
 475+ prepareElement: function( element ) {
 476+ this.reset();
 477+ this.toHide = this.errorsFor(element);
 478+ },
 479+
 480+ check: function( element ) {
 481+ element = this.clean( element );
 482+
 483+ // if radio/checkbox, validate first element in group instead
 484+ if (this.checkable(element)) {
 485+ element = this.findByName( element.name )[0];
 486+ }
 487+ var rules = $(element).rules();
 488+ var dependencyMismatch = false;
 489+ for( method in rules ) {
 490+ var rule = { method: method, parameters: rules[method] };
 491+ try {
 492+ var result = $.validator.methods[method].call( this, element.value.replace(/\r/g, ""), element, rule.parameters );
 493+
 494+ // if a method indicates that the field is optional and therefore valid,
 495+ // don't mark it as valid when there are no other rules
 496+ if ( result == "dependency-mismatch" ) {
 497+ dependencyMismatch = true;
 498+ continue;
 499+ }
 500+ dependencyMismatch = false;
 501+
 502+ if ( result == "pending" ) {
 503+ this.toHide = this.toHide.not( this.errorsFor(element) );
 504+ return;
 505+ }
 506+
 507+ if( !result ) {
 508+ this.formatAndAdd( element, rule );
 509+ return false;
 510+ }
 511+ } catch(e) {
 512+ this.settings.debug && window.console && console.log("exception occured when checking element " + element.id
 513+ + ", check the '" + rule.method + "' method", e);
 514+ throw e;
 515+ }
 516+ }
 517+ if (dependencyMismatch)
 518+ return;
 519+ if ( this.objectLength(rules) )
 520+ this.successList.push(element);
 521+ return true;
 522+ },
 523+
 524+ // return the custom message for the given element and validation method
 525+ // specified in the element's "messages" metadata
 526+ customMetaMessage: function(element, method) {
 527+ if (!$.metadata)
 528+ return;
 529+
 530+ var meta = this.settings.meta
 531+ ? $(element).metadata()[this.settings.meta]
 532+ : $(element).metadata();
 533+
 534+ return meta && meta.messages && meta.messages[method];
 535+ },
 536+
 537+ // return the custom message for the given element name and validation method
 538+ customMessage: function( name, method ) {
 539+ var m = this.settings.messages[name];
 540+ return m && (m.constructor == String
 541+ ? m
 542+ : m[method]);
 543+ },
 544+
 545+ // return the first defined argument, allowing empty strings
 546+ findDefined: function() {
 547+ for(var i = 0; i < arguments.length; i++) {
 548+ if (arguments[i] !== undefined)
 549+ return arguments[i];
 550+ }
 551+ return undefined;
 552+ },
 553+
 554+ defaultMessage: function( element, method) {
 555+ return this.findDefined(
 556+ this.customMessage( element.name, method ),
 557+ this.customMetaMessage( element, method ),
 558+ // title is never undefined, so handle empty string as undefined
 559+ !this.settings.ignoreTitle && element.title || undefined,
 560+ $.validator.messages[method],
 561+ "<strong>Warning: No message defined for " + element.name + "</strong>"
 562+ );
 563+ },
 564+
 565+ formatAndAdd: function( element, rule ) {
 566+ var message = this.defaultMessage( element, rule.method ),
 567+ theregex = /\$?\{(\d+)\}/g;
 568+ if ( typeof message == "function" ) {
 569+ message = message.call(this, rule.parameters, element);
 570+ } else if (theregex.test(message)) {
 571+ message = jQuery.format(message.replace(theregex, '{$1}'), rule.parameters);
 572+ }
 573+ this.errorList.push({
 574+ message: message,
 575+ element: element
 576+ });
 577+
 578+ this.errorMap[element.name] = message;
 579+ this.submitted[element.name] = message;
 580+ },
 581+
 582+ addWrapper: function(toToggle) {
 583+ if ( this.settings.wrapper )
 584+ toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
 585+ return toToggle;
 586+ },
 587+
 588+ defaultShowErrors: function() {
 589+ for ( var i = 0; this.errorList[i]; i++ ) {
 590+ var error = this.errorList[i];
 591+ this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
 592+ this.showLabel( error.element, error.message );
 593+ }
 594+ if( this.errorList.length ) {
 595+ this.toShow = this.toShow.add( this.containers );
 596+ }
 597+ if (this.settings.success) {
 598+ for ( var i = 0; this.successList[i]; i++ ) {
 599+ this.showLabel( this.successList[i] );
 600+ }
 601+ }
 602+ if (this.settings.unhighlight) {
 603+ for ( var i = 0, elements = this.validElements(); elements[i]; i++ ) {
 604+ this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
 605+ }
 606+ }
 607+ this.toHide = this.toHide.not( this.toShow );
 608+ this.hideErrors();
 609+ this.addWrapper( this.toShow ).show();
 610+ },
 611+
 612+ validElements: function() {
 613+ return this.currentElements.not(this.invalidElements());
 614+ },
 615+
 616+ invalidElements: function() {
 617+ return $(this.errorList).map(function() {
 618+ return this.element;
 619+ });
 620+ },
 621+
 622+ showLabel: function(element, message) {
 623+ var label = this.errorsFor( element );
 624+ if ( label.length ) {
 625+ // refresh error/success class
 626+ label.removeClass().addClass( this.settings.errorClass );
 627+
 628+ // check if we have a generated label, replace the message then
 629+ label.attr("generated") && label.html(message);
 630+ } else {
 631+ // create label
 632+ label = $("<" + this.settings.errorElement + "/>")
 633+ .attr({"for": this.idOrName(element), generated: true})
 634+ .addClass(this.settings.errorClass)
 635+ .html(message || "");
 636+ if ( this.settings.wrapper ) {
 637+ // make sure the element is visible, even in IE
 638+ // actually showing the wrapped element is handled elsewhere
 639+ label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
 640+ }
 641+ if ( !this.labelContainer.append(label).length )
 642+ this.settings.errorPlacement
 643+ ? this.settings.errorPlacement(label, $(element) )
 644+ : label.insertAfter(element);
 645+ }
 646+ if ( !message && this.settings.success ) {
 647+ label.text("");
 648+ typeof this.settings.success == "string"
 649+ ? label.addClass( this.settings.success )
 650+ : this.settings.success( label );
 651+ }
 652+ this.toShow = this.toShow.add(label);
 653+ },
 654+
 655+ errorsFor: function(element) {
 656+ var name = this.idOrName(element);
 657+ return this.errors().filter(function() {
 658+ return $(this).attr('for') == name;
 659+ });
 660+ },
 661+
 662+ idOrName: function(element) {
 663+ return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
 664+ },
 665+
 666+ checkable: function( element ) {
 667+ return /radio|checkbox/i.test(element.type);
 668+ },
 669+
 670+ findByName: function( name ) {
 671+ // select by name and filter by form for performance over form.find("[name=...]")
 672+ var form = this.currentForm;
 673+ return $(document.getElementsByName(name)).map(function(index, element) {
 674+ return element.form == form && element.name == name && element || null;
 675+ });
 676+ },
 677+
 678+ getLength: function(value, element) {
 679+ switch( element.nodeName.toLowerCase() ) {
 680+ case 'select':
 681+ return $("option:selected", element).length;
 682+ case 'input':
 683+ if( this.checkable( element) )
 684+ return this.findByName(element.name).filter(':checked').length;
 685+ }
 686+ return value.length;
 687+ },
 688+
 689+ depend: function(param, element) {
 690+ return this.dependTypes[typeof param]
 691+ ? this.dependTypes[typeof param](param, element)
 692+ : true;
 693+ },
 694+
 695+ dependTypes: {
 696+ "boolean": function(param, element) {
 697+ return param;
 698+ },
 699+ "string": function(param, element) {
 700+ return !!$(param, element.form).length;
 701+ },
 702+ "function": function(param, element) {
 703+ return param(element);
 704+ }
 705+ },
 706+
 707+ optional: function(element) {
 708+ return !$.validator.methods.required.call(this, $.trim(element.value), element) && "dependency-mismatch";
 709+ },
 710+
 711+ startRequest: function(element) {
 712+ if (!this.pending[element.name]) {
 713+ this.pendingRequest++;
 714+ this.pending[element.name] = true;
 715+ }
 716+ },
 717+
 718+ stopRequest: function(element, valid) {
 719+ this.pendingRequest--;
 720+ // sometimes synchronization fails, make sure pendingRequest is never < 0
 721+ if (this.pendingRequest < 0)
 722+ this.pendingRequest = 0;
 723+ delete this.pending[element.name];
 724+ if ( valid && this.pendingRequest == 0 && this.formSubmitted && this.form() ) {
 725+ $(this.currentForm).submit();
 726+ this.formSubmitted = false;
 727+ } else if (!valid && this.pendingRequest == 0 && this.formSubmitted) {
 728+ $(this.currentForm).triggerHandler("invalid-form", [this]);
 729+ this.formSubmitted = false;
 730+ }
 731+ },
 732+
 733+ previousValue: function(element) {
 734+ return $.data(element, "previousValue") || $.data(element, "previousValue", {
 735+ old: null,
 736+ valid: true,
 737+ message: this.defaultMessage( element, "remote" )
 738+ });
 739+ }
 740+
 741+ },
 742+
 743+ classRuleSettings: {
 744+ required: {required: true},
 745+ email: {email: true},
 746+ url: {url: true},
 747+ date: {date: true},
 748+ dateISO: {dateISO: true},
 749+ dateDE: {dateDE: true},
 750+ number: {number: true},
 751+ numberDE: {numberDE: true},
 752+ digits: {digits: true},
 753+ creditcard: {creditcard: true}
 754+ },
 755+
 756+ addClassRules: function(className, rules) {
 757+ className.constructor == String ?
 758+ this.classRuleSettings[className] = rules :
 759+ $.extend(this.classRuleSettings, className);
 760+ },
 761+
 762+ classRules: function(element) {
 763+ var rules = {};
 764+ var classes = $(element).attr('class');
 765+ classes && $.each(classes.split(' '), function() {
 766+ if (this in $.validator.classRuleSettings) {
 767+ $.extend(rules, $.validator.classRuleSettings[this]);
 768+ }
 769+ });
 770+ return rules;
 771+ },
 772+
 773+ attributeRules: function(element) {
 774+ var rules = {};
 775+ var $element = $(element);
 776+
 777+ for (method in $.validator.methods) {
 778+ var value = $element.attr(method);
 779+ if (value) {
 780+ rules[method] = value;
 781+ }
 782+ }
 783+
 784+ // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
 785+ if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) {
 786+ delete rules.maxlength;
 787+ }
 788+
 789+ return rules;
 790+ },
 791+
 792+ metadataRules: function(element) {
 793+ if (!$.metadata) return {};
 794+
 795+ var meta = $.data(element.form, 'validator').settings.meta;
 796+ return meta ?
 797+ $(element).metadata()[meta] :
 798+ $(element).metadata();
 799+ },
 800+
 801+ staticRules: function(element) {
 802+ var rules = {};
 803+ var validator = $.data(element.form, 'validator');
 804+ if (validator.settings.rules) {
 805+ rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
 806+ }
 807+ return rules;
 808+ },
 809+
 810+ normalizeRules: function(rules, element) {
 811+ // handle dependency check
 812+ $.each(rules, function(prop, val) {
 813+ // ignore rule when param is explicitly false, eg. required:false
 814+ if (val === false) {
 815+ delete rules[prop];
 816+ return;
 817+ }
 818+ if (val.param || val.depends) {
 819+ var keepRule = true;
 820+ switch (typeof val.depends) {
 821+ case "string":
 822+ keepRule = !!$(val.depends, element.form).length;
 823+ break;
 824+ case "function":
 825+ keepRule = val.depends.call(element, element);
 826+ break;
 827+ }
 828+ if (keepRule) {
 829+ rules[prop] = val.param !== undefined ? val.param : true;
 830+ } else {
 831+ delete rules[prop];
 832+ }
 833+ }
 834+ });
 835+
 836+ // evaluate parameters
 837+ $.each(rules, function(rule, parameter) {
 838+ rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
 839+ });
 840+
 841+ // clean number parameters
 842+ $.each(['minlength', 'maxlength', 'min', 'max'], function() {
 843+ if (rules[this]) {
 844+ rules[this] = Number(rules[this]);
 845+ }
 846+ });
 847+ $.each(['rangelength', 'range'], function() {
 848+ if (rules[this]) {
 849+ rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
 850+ }
 851+ });
 852+
 853+ if ($.validator.autoCreateRanges) {
 854+ // auto-create ranges
 855+ if (rules.min && rules.max) {
 856+ rules.range = [rules.min, rules.max];
 857+ delete rules.min;
 858+ delete rules.max;
 859+ }
 860+ if (rules.minlength && rules.maxlength) {
 861+ rules.rangelength = [rules.minlength, rules.maxlength];
 862+ delete rules.minlength;
 863+ delete rules.maxlength;
 864+ }
 865+ }
 866+
 867+ // To support custom messages in metadata ignore rule methods titled "messages"
 868+ if (rules.messages) {
 869+ delete rules.messages;
 870+ }
 871+
 872+ return rules;
 873+ },
 874+
 875+ // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
 876+ normalizeRule: function(data) {
 877+ if( typeof data == "string" ) {
 878+ var transformed = {};
 879+ $.each(data.split(/\s/), function() {
 880+ transformed[this] = true;
 881+ });
 882+ data = transformed;
 883+ }
 884+ return data;
 885+ },
 886+
 887+ // http://docs.jquery.com/Plugins/Validation/Validator/addMethod
 888+ addMethod: function(name, method, message) {
 889+ $.validator.methods[name] = method;
 890+ $.validator.messages[name] = message != undefined ? message : $.validator.messages[name];
 891+ if (method.length < 3) {
 892+ $.validator.addClassRules(name, $.validator.normalizeRule(name));
 893+ }
 894+ },
 895+
 896+ methods: {
 897+
 898+ // http://docs.jquery.com/Plugins/Validation/Methods/required
 899+ required: function(value, element, param) {
 900+ // check if dependency is met
 901+ if ( !this.depend(param, element) )
 902+ return "dependency-mismatch";
 903+ switch( element.nodeName.toLowerCase() ) {
 904+ case 'select':
 905+ // could be an array for select-multiple or a string, both are fine this way
 906+ var val = $(element).val();
 907+ return val && val.length > 0;
 908+ case 'input':
 909+ if ( this.checkable(element) )
 910+ return this.getLength(value, element) > 0;
 911+ default:
 912+ return $.trim(value).length > 0;
 913+ }
 914+ },
 915+
 916+ // http://docs.jquery.com/Plugins/Validation/Methods/remote
 917+ remote: function(value, element, param) {
 918+ if ( this.optional(element) )
 919+ return "dependency-mismatch";
 920+
 921+ var previous = this.previousValue(element);
 922+ if (!this.settings.messages[element.name] )
 923+ this.settings.messages[element.name] = {};
 924+ previous.originalMessage = this.settings.messages[element.name].remote;
 925+ this.settings.messages[element.name].remote = previous.message;
 926+
 927+ param = typeof param == "string" && {url:param} || param;
 928+
 929+ if ( previous.old !== value ) {
 930+ previous.old = value;
 931+ var validator = this;
 932+ this.startRequest(element);
 933+ var data = {};
 934+ data[element.name] = value;
 935+ $.ajax($.extend(true, {
 936+ url: param,
 937+ mode: "abort",
 938+ port: "validate" + element.name,
 939+ dataType: "json",
 940+ data: data,
 941+ success: function(response) {
 942+ validator.settings.messages[element.name].remote = previous.originalMessage;
 943+ var valid = response === true;
 944+ if ( valid ) {
 945+ var submitted = validator.formSubmitted;
 946+ validator.prepareElement(element);
 947+ validator.formSubmitted = submitted;
 948+ validator.successList.push(element);
 949+ validator.showErrors();
 950+ } else {
 951+ var errors = {};
 952+ var message = (previous.message = response || validator.defaultMessage( element, "remote" ));
 953+ errors[element.name] = $.isFunction(message) ? message(value) : message;
 954+ validator.showErrors(errors);
 955+ }
 956+ previous.valid = valid;
 957+ validator.stopRequest(element, valid);
 958+ }
 959+ }, param));
 960+ return "pending";
 961+ } else if( this.pending[element.name] ) {
 962+ return "pending";
 963+ }
 964+ return previous.valid;
 965+ },
 966+
 967+ // http://docs.jquery.com/Plugins/Validation/Methods/minlength
 968+ minlength: function(value, element, param) {
 969+ return this.optional(element) || this.getLength($.trim(value), element) >= param;
 970+ },
 971+
 972+ // http://docs.jquery.com/Plugins/Validation/Methods/maxlength
 973+ maxlength: function(value, element, param) {
 974+ return this.optional(element) || this.getLength($.trim(value), element) <= param;
 975+ },
 976+
 977+ // http://docs.jquery.com/Plugins/Validation/Methods/rangelength
 978+ rangelength: function(value, element, param) {
 979+ var length = this.getLength($.trim(value), element);
 980+ return this.optional(element) || ( length >= param[0] && length <= param[1] );
 981+ },
 982+
 983+ // http://docs.jquery.com/Plugins/Validation/Methods/min
 984+ min: function( value, element, param ) {
 985+ return this.optional(element) || value >= param;
 986+ },
 987+
 988+ // http://docs.jquery.com/Plugins/Validation/Methods/max
 989+ max: function( value, element, param ) {
 990+ return this.optional(element) || value <= param;
 991+ },
 992+
 993+ // http://docs.jquery.com/Plugins/Validation/Methods/range
 994+ range: function( value, element, param ) {
 995+ return this.optional(element) || ( value >= param[0] && value <= param[1] );
 996+ },
 997+
 998+ // http://docs.jquery.com/Plugins/Validation/Methods/email
 999+ email: function(value, element) {
 1000+ // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
 1001+ 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);
 1002+ },
 1003+
 1004+ // http://docs.jquery.com/Plugins/Validation/Methods/url
 1005+ url: function(value, element) {
 1006+ // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
 1007+ 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);
 1008+ },
 1009+
 1010+ // http://docs.jquery.com/Plugins/Validation/Methods/date
 1011+ date: function(value, element) {
 1012+ return this.optional(element) || !/Invalid|NaN/.test(new Date(value));
 1013+ },
 1014+
 1015+ // http://docs.jquery.com/Plugins/Validation/Methods/dateISO
 1016+ dateISO: function(value, element) {
 1017+ return this.optional(element) || /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value);
 1018+ },
 1019+
 1020+ // http://docs.jquery.com/Plugins/Validation/Methods/number
 1021+ number: function(value, element) {
 1022+ return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value);
 1023+ },
 1024+
 1025+ // http://docs.jquery.com/Plugins/Validation/Methods/digits
 1026+ digits: function(value, element) {
 1027+ return this.optional(element) || /^\d+$/.test(value);
 1028+ },
 1029+
 1030+ // http://docs.jquery.com/Plugins/Validation/Methods/creditcard
 1031+ // based on http://en.wikipedia.org/wiki/Luhn
 1032+ creditcard: function(value, element) {
 1033+ if ( this.optional(element) )
 1034+ return "dependency-mismatch";
 1035+ // accept only digits and dashes
 1036+ if (/[^0-9-]+/.test(value))
 1037+ return false;
 1038+ var nCheck = 0,
 1039+ nDigit = 0,
 1040+ bEven = false;
 1041+
 1042+ value = value.replace(/\D/g, "");
 1043+
 1044+ for (var n = value.length - 1; n >= 0; n--) {
 1045+ var cDigit = value.charAt(n);
 1046+ var nDigit = parseInt(cDigit, 10);
 1047+ if (bEven) {
 1048+ if ((nDigit *= 2) > 9)
 1049+ nDigit -= 9;
 1050+ }
 1051+ nCheck += nDigit;
 1052+ bEven = !bEven;
 1053+ }
 1054+
 1055+ return (nCheck % 10) == 0;
 1056+ },
 1057+
 1058+ // http://docs.jquery.com/Plugins/Validation/Methods/accept
 1059+ accept: function(value, element, param) {
 1060+ param = typeof param == "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif";
 1061+ return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i"));
 1062+ },
 1063+
 1064+ // http://docs.jquery.com/Plugins/Validation/Methods/equalTo
 1065+ equalTo: function(value, element, param) {
 1066+ // bind to the blur event of the target in order to revalidate whenever the target field is updated
 1067+ // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
 1068+ var target = $(param).unbind(".validate-equalTo").bind("blur.validate-equalTo", function() {
 1069+ $(element).valid();
 1070+ });
 1071+ return value == target.val();
 1072+ }
 1073+
 1074+ }
 1075+
 1076+});
 1077+
 1078+// deprecated, use $.validator.format instead
 1079+$.format = $.validator.format;
 1080+
 1081+})(jQuery);
 1082+
 1083+// ajax mode: abort
 1084+// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
 1085+// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
 1086+;(function($) {
 1087+ var ajax = $.ajax;
 1088+ var pendingRequests = {};
 1089+ $.ajax = function(settings) {
 1090+ // create settings for compatibility with ajaxSetup
 1091+ settings = $.extend(settings, $.extend({}, $.ajaxSettings, settings));
 1092+ var port = settings.port;
 1093+ if (settings.mode == "abort") {
 1094+ if ( pendingRequests[port] ) {
 1095+ pendingRequests[port].abort();
 1096+ }
 1097+ return (pendingRequests[port] = ajax.apply(this, arguments));
 1098+ }
 1099+ return ajax.apply(this, arguments);
 1100+ };
 1101+})(jQuery);
 1102+
 1103+// provides cross-browser focusin and focusout events
 1104+// IE has native support, in other browsers, use event caputuring (neither bubbles)
 1105+
 1106+// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
 1107+// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target
 1108+;(function($) {
 1109+ // only implement if not provided by jQuery core (since 1.4)
 1110+ // TODO verify if jQuery 1.4's implementation is compatible with older jQuery special-event APIs
 1111+ if (!jQuery.event.special.focusin && !jQuery.event.special.focusout && document.addEventListener) {
 1112+ $.each({
 1113+ focus: 'focusin',
 1114+ blur: 'focusout'
 1115+ }, function( original, fix ){
 1116+ $.event.special[fix] = {
 1117+ setup:function() {
 1118+ this.addEventListener( original, handler, true );
 1119+ },
 1120+ teardown:function() {
 1121+ this.removeEventListener( original, handler, true );
 1122+ },
 1123+ handler: function(e) {
 1124+ arguments[0] = $.event.fix(e);
 1125+ arguments[0].type = fix;
 1126+ return $.event.handle.apply(this, arguments);
 1127+ }
 1128+ };
 1129+ function handler(e) {
 1130+ e = $.event.fix(e);
 1131+ e.type = fix;
 1132+ return $.event.handle.call(this, e);
 1133+ }
 1134+ });
 1135+ };
 1136+ $.extend($.fn, {
 1137+ validateDelegate: function(delegate, type, handler) {
 1138+ return this.bind(type, function(event) {
 1139+ var target = $(event.target);
 1140+ if (target.is(delegate)) {
 1141+ return handler.apply(target, arguments);
 1142+ }
 1143+ });
 1144+ }
 1145+ });
 1146+})(jQuery);
Property changes on: trunk/extensions/UploadWizard/js/jquery/plugins/jquery.validate.js
___________________________________________________________________
Name: svn:eol-style
11147 + native
Index: trunk/extensions/UploadWizard/js/jquery/plugins/jquery.validate.additional-methods.js
@@ -0,0 +1,259 @@
 2+(function() {
 3+
 4+ function stripHtml(value) {
 5+ // remove html tags and space chars
 6+ return value.replace(/<.[^<>]*?>/g, ' ').replace(/&nbsp;|&#160;/gi, ' ')
 7+ // remove numbers and punctuation
 8+ .replace(/[0-9.(),;:!?%#$'"_+=\/-]*/g,'');
 9+ }
 10+ jQuery.validator.addMethod("maxWords", function(value, element, params) {
 11+ return this.optional(element) || stripHtml(value).match(/\b\w+\b/g).length < params;
 12+ }, jQuery.validator.format("Please enter {0} words or less."));
 13+
 14+ jQuery.validator.addMethod("minWords", function(value, element, params) {
 15+ return this.optional(element) || stripHtml(value).match(/\b\w+\b/g).length >= params;
 16+ }, jQuery.validator.format("Please enter at least {0} words."));
 17+
 18+ jQuery.validator.addMethod("rangeWords", function(value, element, params) {
 19+ return this.optional(element) || stripHtml(value).match(/\b\w+\b/g).length >= params[0] && value.match(/bw+b/g).length < params[1];
 20+ }, jQuery.validator.format("Please enter between {0} and {1} words."));
 21+
 22+})();
 23+
 24+jQuery.validator.addMethod("letterswithbasicpunc", function(value, element) {
 25+ return this.optional(element) || /^[a-z-.,()'\"\s]+$/i.test(value);
 26+}, "Letters or punctuation only please");
 27+
 28+jQuery.validator.addMethod("alphanumeric", function(value, element) {
 29+ return this.optional(element) || /^\w+$/i.test(value);
 30+}, "Letters, numbers, spaces or underscores only please");
 31+
 32+jQuery.validator.addMethod("lettersonly", function(value, element) {
 33+ return this.optional(element) || /^[a-z]+$/i.test(value);
 34+}, "Letters only please");
 35+
 36+jQuery.validator.addMethod("nowhitespace", function(value, element) {
 37+ return this.optional(element) || /^\S+$/i.test(value);
 38+}, "No white space please");
 39+
 40+jQuery.validator.addMethod("ziprange", function(value, element) {
 41+ return this.optional(element) || /^90[2-5]\d\{2}-\d{4}$/.test(value);
 42+}, "Your ZIP-code must be in the range 902xx-xxxx to 905-xx-xxxx");
 43+
 44+jQuery.validator.addMethod("integer", function(value, element) {
 45+ return this.optional(element) || /^-?\d+$/.test(value);
 46+}, "A positive or negative non-decimal number please");
 47+
 48+/**
 49+* Return true, if the value is a valid vehicle identification number (VIN).
 50+*
 51+* Works with all kind of text inputs.
 52+*
 53+* @example <input type="text" size="20" name="VehicleID" class="{required:true,vinUS:true}" />
 54+* @desc Declares a required input element whose value must be a valid vehicle identification number.
 55+*
 56+* @name jQuery.validator.methods.vinUS
 57+* @type Boolean
 58+* @cat Plugins/Validate/Methods
 59+*/
 60+jQuery.validator.addMethod(
 61+ "vinUS",
 62+ function(v){
 63+ if (v.length != 17)
 64+ return false;
 65+ var i, n, d, f, cd, cdv;
 66+ var LL = ["A","B","C","D","E","F","G","H","J","K","L","M","N","P","R","S","T","U","V","W","X","Y","Z"];
 67+ var VL = [1,2,3,4,5,6,7,8,1,2,3,4,5,7,9,2,3,4,5,6,7,8,9];
 68+ var FL = [8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2];
 69+ var rs = 0;
 70+ for(i = 0; i < 17; i++){
 71+ f = FL[i];
 72+ d = v.slice(i,i+1);
 73+ if(i == 8){
 74+ cdv = d;
 75+ }
 76+ if(!isNaN(d)){
 77+ d *= f;
 78+ }
 79+ else{
 80+ for(n = 0; n < LL.length; n++){
 81+ if(d.toUpperCase() === LL[n]){
 82+ d = VL[n];
 83+ d *= f;
 84+ if(isNaN(cdv) && n == 8){
 85+ cdv = LL[n];
 86+ }
 87+ break;
 88+ }
 89+ }
 90+ }
 91+ rs += d;
 92+ }
 93+ cd = rs % 11;
 94+ if(cd == 10){cd = "X";}
 95+ if(cd == cdv){return true;}
 96+ return false;
 97+ },
 98+ "The specified vehicle identification number (VIN) is invalid."
 99+);
 100+
 101+/**
 102+ * Return true, if the value is a valid date, also making this formal check dd/mm/yyyy.
 103+ *
 104+ * @example jQuery.validator.methods.date("01/01/1900")
 105+ * @result true
 106+ *
 107+ * @example jQuery.validator.methods.date("01/13/1990")
 108+ * @result false
 109+ *
 110+ * @example jQuery.validator.methods.date("01.01.1900")
 111+ * @result false
 112+ *
 113+ * @example <input name="pippo" class="{dateITA:true}" />
 114+ * @desc Declares an optional input element whose value must be a valid date.
 115+ *
 116+ * @name jQuery.validator.methods.dateITA
 117+ * @type Boolean
 118+ * @cat Plugins/Validate/Methods
 119+ */
 120+jQuery.validator.addMethod(
 121+ "dateITA",
 122+ function(value, element) {
 123+ var check = false;
 124+ var re = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
 125+ if( re.test(value)){
 126+ var adata = value.split('/');
 127+ var gg = parseInt(adata[0],10);
 128+ var mm = parseInt(adata[1],10);
 129+ var aaaa = parseInt(adata[2],10);
 130+ var xdata = new Date(aaaa,mm-1,gg);
 131+ if ( ( xdata.getFullYear() == aaaa ) && ( xdata.getMonth () == mm - 1 ) && ( xdata.getDate() == gg ) )
 132+ check = true;
 133+ else
 134+ check = false;
 135+ } else
 136+ check = false;
 137+ return this.optional(element) || check;
 138+ },
 139+ "Please enter a correct date"
 140+);
 141+
 142+jQuery.validator.addMethod("dateNL", function(value, element) {
 143+ return this.optional(element) || /^\d\d?[\.\/-]\d\d?[\.\/-]\d\d\d?\d?$/.test(value);
 144+ }, "Vul hier een geldige datum in."
 145+);
 146+
 147+jQuery.validator.addMethod("time", function(value, element) {
 148+ return this.optional(element) || /^([01][0-9])|(2[0123]):([0-5])([0-9])$/.test(value);
 149+ }, "Please enter a valid time, between 00:00 and 23:59"
 150+);
 151+
 152+/**
 153+ * matches US phone number format
 154+ *
 155+ * where the area code may not start with 1 and the prefix may not start with 1
 156+ * allows '-' or ' ' as a separator and allows parens around area code
 157+ * some people may want to put a '1' in front of their number
 158+ *
 159+ * 1(212)-999-2345
 160+ * or
 161+ * 212 999 2344
 162+ * or
 163+ * 212-999-0983
 164+ *
 165+ * but not
 166+ * 111-123-5434
 167+ * and not
 168+ * 212 123 4567
 169+ */
 170+jQuery.validator.addMethod("phoneUS", function(phone_number, element) {
 171+ phone_number = phone_number.replace(/\s+/g, "");
 172+ return this.optional(element) || phone_number.length > 9 &&
 173+ phone_number.match(/^(1-?)?(\([2-9]\d{2}\)|[2-9]\d{2})-?[2-9]\d{2}-?\d{4}$/);
 174+}, "Please specify a valid phone number");
 175+
 176+jQuery.validator.addMethod('phoneUK', function(phone_number, element) {
 177+return this.optional(element) || phone_number.length > 9 &&
 178+phone_number.match(/^(\(?(0|\+44)[1-9]{1}\d{1,4}?\)?\s?\d{3,4}\s?\d{3,4})$/);
 179+}, 'Please specify a valid phone number');
 180+
 181+jQuery.validator.addMethod('mobileUK', function(phone_number, element) {
 182+return this.optional(element) || phone_number.length > 9 &&
 183+phone_number.match(/^((0|\+44)7(5|6|7|8|9){1}\d{2}\s?\d{6})$/);
 184+}, 'Please specify a valid mobile number');
 185+
 186+// TODO check if value starts with <, otherwise don't try stripping anything
 187+jQuery.validator.addMethod("strippedminlength", function(value, element, param) {
 188+ return jQuery(value).text().length >= param;
 189+}, jQuery.validator.format("Please enter at least {0} characters"));
 190+
 191+// same as email, but TLD is optional
 192+jQuery.validator.addMethod("email2", function(value, element, param) {
 193+ 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);
 194+}, jQuery.validator.messages.email);
 195+
 196+// same as url, but TLD is optional
 197+jQuery.validator.addMethod("url2", function(value, element, param) {
 198+ 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);
 199+}, jQuery.validator.messages.url);
 200+
 201+// NOTICE: Modified version of Castle.Components.Validator.CreditCardValidator
 202+// Redistributed under the the Apache License 2.0 at http://www.apache.org/licenses/LICENSE-2.0
 203+// Valid Types: mastercard, visa, amex, dinersclub, enroute, discover, jcb, unknown, all (overrides all other settings)
 204+jQuery.validator.addMethod("creditcardtypes", function(value, element, param) {
 205+
 206+ if (/[^0-9-]+/.test(value))
 207+ return false;
 208+
 209+ value = value.replace(/\D/g, "");
 210+
 211+ var validTypes = 0x0000;
 212+
 213+ if (param.mastercard)
 214+ validTypes |= 0x0001;
 215+ if (param.visa)
 216+ validTypes |= 0x0002;
 217+ if (param.amex)
 218+ validTypes |= 0x0004;
 219+ if (param.dinersclub)
 220+ validTypes |= 0x0008;
 221+ if (param.enroute)
 222+ validTypes |= 0x0010;
 223+ if (param.discover)
 224+ validTypes |= 0x0020;
 225+ if (param.jcb)
 226+ validTypes |= 0x0040;
 227+ if (param.unknown)
 228+ validTypes |= 0x0080;
 229+ if (param.all)
 230+ validTypes = 0x0001 | 0x0002 | 0x0004 | 0x0008 | 0x0010 | 0x0020 | 0x0040 | 0x0080;
 231+
 232+ if (validTypes & 0x0001 && /^(51|52|53|54|55)/.test(value)) { //mastercard
 233+ return value.length == 16;
 234+ }
 235+ if (validTypes & 0x0002 && /^(4)/.test(value)) { //visa
 236+ return value.length == 16;
 237+ }
 238+ if (validTypes & 0x0004 && /^(34|37)/.test(value)) { //amex
 239+ return value.length == 15;
 240+ }
 241+ if (validTypes & 0x0008 && /^(300|301|302|303|304|305|36|38)/.test(value)) { //dinersclub
 242+ return value.length == 14;
 243+ }
 244+ if (validTypes & 0x0010 && /^(2014|2149)/.test(value)) { //enroute
 245+ return value.length == 15;
 246+ }
 247+ if (validTypes & 0x0020 && /^(6011)/.test(value)) { //discover
 248+ return value.length == 16;
 249+ }
 250+ if (validTypes & 0x0040 && /^(3)/.test(value)) { //jcb
 251+ return value.length == 16;
 252+ }
 253+ if (validTypes & 0x0040 && /^(2131|1800)/.test(value)) { //jcb
 254+ return value.length == 15;
 255+ }
 256+ if (validTypes & 0x0080) { //unknown
 257+ return true;
 258+ }
 259+ return false;
 260+}, "Please enter a valid credit card number.");
Property changes on: trunk/extensions/UploadWizard/js/jquery/plugins/jquery.validate.additional-methods.js
___________________________________________________________________
Name: svn:eol-style
1261 + native
Index: trunk/extensions/UploadWizard/js/mw.UploadWizard.js
@@ -4,6 +4,12 @@
55
66 mw.includeAllModuleMessages();
77
 8+/**
 9+ * General configuration for the validator
 10+ */
 11+$j.validator.setDefaults( {
 12+ debug: true
 13+} );
814
915 /**
1016 * Sort of an abstract class for deeds
@@ -123,19 +129,16 @@
124130 }
125131
126132 if ( remainingTime !== null ) {
127 - var tm = mw.seconds2tm( parseInt( remainingTime / 1000, 10 ) );
128 - var seconds = tm[0];
129 - var minutes = tm[1];
130 - var hours = tm[2];
 133+ var t = mw.seconds2Measurements( parseInt( remainingTime / 1000, 10 ) );
131134 var timeString;
132 - if (hours == 0) {
133 - if (minutes == 0) {
134 - timeString = gM( 'mwe-upwiz-secs-remaining', seconds )
 135+ if (t.hours == 0) {
 136+ if (t.minutes == 0) {
 137+ timeString = gM( 'mwe-upwiz-secs-remaining', t.seconds )
135138 } else {
136 - timeString = gM( 'mwe-upwiz-mins-secs-remaining', minutes, seconds )
 139+ timeString = gM( 'mwe-upwiz-mins-secs-remaining', t.minutes, t.seconds )
137140 }
138141 } else {
139 - timeString = gM( 'mwe-upwiz-hrs-mins-secs-remaining', hours, minutes, seconds );
 142+ timeString = gM( 'mwe-upwiz-hrs-mins-secs-remaining', t.hours, t.minutes, t.seconds );
140143 }
141144 _this.$selector.find( '.mwe-upwiz-etr' ).html( timeString )
142145 }
@@ -216,7 +219,8 @@
217220 var id = 'license_' + key + '_' + c;
218221 var input = $j( '<input />' )
219222 .attr( { id: id, type: 'checkbox', value: key } )
220 - .click( function() { _this.change() } );
 223+ // we use the selector because events can't be unbound unless they're in the DOM.
 224+ .click( function() { _this.$selector.trigger( 'changeLicenses' ) } );
221225 data.input = input.get(0);
222226 _this.$selector.append(
223227 data.input,
@@ -243,7 +247,8 @@
244248 var checked = ~~!!licenseValues[key];
245249 $j( _this.licenses[key].input ).attr( { 'checked' : checked } );
246250 } );
247 - _this.change();
 251+ // we use the selector because events can't be unbound unless they're in the DOM.
 252+ _this.$selector.trigger( 'changeLicenses' );
248253 },
249254
250255 /**
@@ -252,14 +257,14 @@
253258 setDefaultValues: function() {
254259 var _this = this;
255260 var values = {};
256 - $j.each( mw.getConfig('defaultLicenses'), function( i, license ) {
 261+ $j.each( mw.getConfig( 'defaultLicenses' ), function( i, license ) {
257262 values[license] = true;
258263 } );
259264 _this.setValues( values );
260265 },
261266
262267 /**
263 - * Gets which values are set to true
 268+ * Gets which values are set to true.
264269 * @return object of object of license-key to boolean values, e.g. { cc_by_sa_30: true, gfdl: true }
265270 */
266271 getValues: function() {
@@ -287,27 +292,31 @@
288293 },
289294
290295 /**
291 - * Check if a valid value is set,
 296+ * Check if a valid value is set, also look for incompatible choices.
292297 * Side effect: if no valid value, add notes to the interface. Add listeners to interface, to revalidate and remove notes.
293298 * @return boolean; true if a value set, false otherwise
294299 */
295300 validate: function() {
 301+ var _this = this;
296302 var isValid = true;
297 - if ( ! this.isSet() ) {
 303+
 304+ if ( ! _this.isSet() ) {
298305 isValid = false;
299306 errorHtml = gM( 'mwe-upwiz-deeds-need-license' );
300307 }
301308
302 - var $errorEl = this.$selector.find( '.mwe-error' )
 309+ // XXX something goes here for licenses incompatible with each other
 310+
 311+ var $errorEl = this.$selector.find( '.mwe-error' );
303312 if (isValid) {
304 - var $inputs = _this.$selector.find( 'input[type=checkbox]' )
305 - $inputs.bind( 'click.revalidate', function() {
306 - $inputs.unbind( 'click.revalidate' );
 313+ $errorEl.fadeOut();
 314+ } else {
 315+ // we bind to $selector because unbind() doesn't work on non-DOM objects
 316+ _this.$selector.bind( 'changeLicenses.validate', function() {
 317+ _this.$selector.unbind( 'changeLicenses.validate' );
307318 _this.validate();
308319 } );
309 - errorHtml = $errorEl.html( gM( 'mwe-upwiz-deeds-need-license' ) ).show();
310 - } else {
311 - $errorEl.fadeOut();
 320+ $errorEl.html( errorHtml ).show();
312321 }
313322 },
314323
@@ -317,8 +326,7 @@
318327 * @return boolean
319328 */
320329 isSet: function() {
321 - var _this = this;
322 - return ( _this.getValues().length !== 0 );
 330+ return this.getTemplates().length > 0;
323331 }
324332
325333 };
@@ -2456,13 +2464,14 @@
24572465 var _this = new mw.UploadWizardDeed();
24582466
24592467 _this.authorInput = $j( '<input />')
2460 - .attr( { name: "author" } )
 2468+ .attr( { name: "author", type: "text" } )
24612469 .addClass( 'mwe-upwiz-sign' );
24622470
24632471 var licenseInputDiv = $j( '<div class="mwe-upwiz-deed-license"></div>' );
24642472 _this.licenseInput = new mw.UploadWizardLicenseInput( licenseInputDiv );
24652473 _this.licenseInput.setDefaultValues();
24662474
 2475+
24672476 return $j.extend( _this, {
24682477
24692478 name: 'ownwork',
@@ -2473,13 +2482,56 @@
24742483 */
24752484 validate: function() {
24762485 // we don't need to validate source because it's set by default
2477 - // authorInput should be non-blank
2478 - if ( _this.authorInput.val() )
 2486+ var authorValid = _this.$form.valid();
 2487+ var licenseValid = _this.licenseInput.validate();
 2488+ return authorValid & licenseValid;
 2489+ },
24792490
2480 - // licenseInput should have at least one value
2481 - _this.licenseInput.validate()
 2491+/*
 2492+ validateAuthor: function() {
 2493+ debugger;
 2494+ debugger;
 2495+ var _this = this;
 2496+ var signature = _this.authorInput.val().trim();
 2497+
 2498+ var authorErrorMsg = null;
 2499+ var maxAuthorLength = 50; // config?
 2500+ var minAuthorLength = 2; // config?
 2501+ if ( signature.length === 0 ) {
 2502+ authorErrorMsg = gM( 'mwe-upwiz-error-author-blank' );
 2503+ } else if ( signature.length < minAuthorLength ) {
 2504+ debugger;
 2505+ authorErrorMsg = gM( 'mwe-upwiz-error-author-too-short', minAuthorLength );
 2506+ } else if ( signature.length > maxAuthorLength ) {
 2507+ authorErrorMsg = gM( 'mwe-upwiz-error-author-too-long', maxAuthorLength );
 2508+ } else if ( signature.match(/[{}\[\]\(\)%$]/) ) {
 2509+ // XXX SECURITY we need to do a better job here
 2510+ authorErrorMsg = gM( 'mwe-upwiz-error-author-bad-chars' );
 2511+ }
 2512+
 2513+ if (authorErrorMsg) {
 2514+ _this.$selector
 2515+ .find( '.mwe-upwiz-author-error' )
 2516+ .html( authorErrorMsg )
 2517+ .show();
 2518+ _this.$selector
 2519+ .find( '.mwe-upwiz-sign' )
 2520+ .addClass( '.mwe-field-error' )
 2521+ .bind( 'keyup.revalidate', function() {
 2522+ $j( this ).unbind( 'keyup.revalidate' );
 2523+ _this.validateAuthor();
 2524+ } );
 2525+
 2526+ } else {
 2527+ _this.authorInput.removeClass( '.mwe-field-error' );
 2528+ _this.$selector.find( '.mwe-upwiz-author-error' ).fadeOut().empty();
 2529+ }
 2530+
 2531+ return (authorErrorMsg !== null)
 2532+
24822533 },
24832534
 2535+*/
24842536 getSourceWikiText: function() {
24852537 return '{{own}}';
24862538 },
@@ -2499,30 +2551,40 @@
25002552 },
25012553
25022554 setFormFields: function( $selector ) {
 2555+ _this.$selector = $selector;
 2556+
 2557+ _this.$form = $j( '<form/>' );
25032558 var $standardDiv, $customDiv;
25042559
25052560 var $standardDiv = $j( '<div />' ).append(
 2561+ $j( '<label for="blarg" generated="true" class="mwe-error" style="display:block;"/>' ),
25062562 $j( '<p>' )
25072563 .html( gM( 'mwe-upwiz-source-ownwork-assert',
25082564 uploadCount,
2509 - '<input name="author" class="mwe-upwiz-sign" />' )
 2565+ '<span class="mwe-standard-author-input"></span>' )
25102566 ),
2511 - $j( '<p class="mwe-small-print" />' ).append( gM( 'mwe-upwiz-source-ownwork-assert-note' ) )
2512 - );
 2567+ $j( '<p class="mwe-small-print" />' ).append( gM( 'mwe-upwiz-source-ownwork-assert-note' ) )
 2568+ );
 2569+ $standardDiv.find( '.mwe-standard-author-input' ).append( $j( '<input name="blarg" type="text" class="mwe-upwiz-sign" />' ) );
25132570
25142571 var $customDiv = $j('<div/>').append(
 2572+ $j( '<label for="author" generated="true" class="mwe-error" style="display:block;"/>' ),
25152573 $j( '<p>' )
25162574 .html( gM( 'mwe-upwiz-source-ownwork-assert-custom',
25172575 uploadCount,
25182576 '<span class="mwe-custom-author-input"></span>' ) ),
25192577 licenseInputDiv
25202578 );
 2579+ // have to add the author input this way -- gM() will flatten it to a string and we'll lose it as a dom object
 2580+ $customDiv.find( '.mwe-custom-author-input' ).append( _this.authorInput );
25212581
 2582+
25222583 var $crossfader = $j( '<div>' ).append( $standardDiv, $customDiv );
25232584 var $toggler = $j( '<p class="mwe-more-options" style="text-align: right" />' )
25242585 .append( $j( '<a />' )
25252586 .append( gM( 'mwe-upwiz-license-show-all' ) )
25262587 .click( function() {
 2588+ _this.formValidator.resetForm();
25272589 if ( $crossfader.data( 'crossfadeDisplay' ) === $customDiv ) {
25282590 _this.licenseInput.setDefaultValues();
25292591 $crossfader.morphCrossfade( $standardDiv );
@@ -2533,10 +2595,9 @@
25342596 }
25352597 } ) );
25362598
2537 - var $formFields = $j( '<div class="mwe-upwiz-deed-form-internal" />' ).append( $crossfader, $toggler );
 2599+ var $formFields = $j( '<div class="mwe-upwiz-deed-form-internal" />' )
 2600+ .append( $crossfader, $toggler );
25382601
2539 - // have to add the author input this way -- gM() will flatten it to a string and we'll lose it as a dom object
2540 - $formFields.find( '.mwe-custom-author-input' ).append( _this.authorInput );
25412602
25422603 // synchronize both username signatures
25432604 // set initial value to configured username
@@ -2559,10 +2620,46 @@
25602621 } );
25612622 } );
25622623
2563 - $selector.append( $formFields );
 2624+ _this.$form.append( $formFields );
 2625+ $selector.append( _this.$form );
 2626+
 2627+ // done after added to the DOM, so there are true heights
 2628+ $crossfader.morphCrossfader();
25642629
2565 - // done after append so there are true heights
2566 - $crossfader.morphCrossfader();
 2630+
 2631+ // and finally, validation
 2632+ _this.formValidator = _this.$form.validate( {
 2633+ debug: true,
 2634+ errorClass: 'mwe-error', // add to general config?
 2635+ rules: {
 2636+ blarg: {
 2637+ required: function( element ) {
 2638+ return $crossfader.data( 'crossfadeDisplay' ).get(0) === $standardDiv.get(0);
 2639+ },
 2640+ minlength: mw.getConfig( 'minAuthorLength' ),
 2641+ maxlength: mw.getConfig( 'maxAuthorLength' )
 2642+ },
 2643+ author: {
 2644+ required: function( element ) {
 2645+ return $crossfader.data( 'crossfadeDisplay' ).get(0) === $customDiv.get(0);
 2646+ },
 2647+ minlength: mw.getConfig( 'minAuthorLength' ),
 2648+ maxlength: mw.getConfig( 'maxAuthorLength' )
 2649+ }
 2650+ },
 2651+ messages: {
 2652+ blarg: {
 2653+ required: gM( 'mwe-upwiz-error-author-blank' ),
 2654+ minlength: gM( 'mwe-upwiz-error-author-too-long', mw.getConfig( 'minAuthorLength' ) ),
 2655+ maxlength: gM( 'mwe-upwiz-error-author-too-long', mw.getConfig( 'maxAuthorLength' ) )
 2656+ },
 2657+ author: {
 2658+ required: gM( 'mwe-upwiz-error-author-blank' ),
 2659+ minlength: gM( 'mwe-upwiz-error-author-too-long', mw.getConfig( 'minAuthorLength' ) ),
 2660+ maxlength: gM( 'mwe-upwiz-error-author-too-long', mw.getConfig( 'maxAuthorLength' ) )
 2661+ }
 2662+ }
 2663+ } );
25672664 }
25682665
25692666
Index: trunk/extensions/UploadWizard/UploadWizardPage.js
@@ -22,6 +22,8 @@
2323 token: wgEditToken,
2424 thumbnailWidth: 120,
2525 smallThumbnailWidth: 60,
 26+ maxAuthorLength: 50,
 27+ minAuthorLength: 2,
2628
2729 // not for use with all wikis.
2830 // The ISO 639 code for the language tagalog is "tl".

Status & tagging log