Index: trunk/phase3/resources/mediawiki.util/mediawiki.util.js |
— | — | @@ -40,8 +40,8 @@ |
41 | 41 | // (but not Safari on Windows) |
42 | 42 | } else if ( !( profile.platform == 'win' && profile.name == 'safari' ) |
43 | 43 | && ( profile.name == 'safari' |
44 | | - || profile.platform == 'mac' |
45 | | - || profile.name == 'konqueror' ) ) { |
| 44 | + || profile.platform == 'mac' |
| 45 | + || profile.name == 'konqueror' ) ) { |
46 | 46 | mw.util.tooltipAccessKeyPrefix = 'ctrl-'; |
47 | 47 | |
48 | 48 | // Firefox 2.x |
— | — | @@ -263,26 +263,26 @@ |
264 | 264 | * ( '#foobar' ) of that item. |
265 | 265 | * |
266 | 266 | * @example mw.util.addPortletLink( |
267 | | - * 'p-tb', 'http://mediawiki.org/', |
268 | | - * 'MediaWiki.org', 't-mworg', 'Go to MediaWiki.org ', 'm', '#t-print' |
269 | | - * ) |
| 267 | + * 'p-tb', 'http://mediawiki.org/', |
| 268 | + * 'MediaWiki.org', 't-mworg', 'Go to MediaWiki.org ', 'm', '#t-print' |
| 269 | + * ) |
270 | 270 | * |
271 | 271 | * @param portlet ID of the target portlet ( 'p-cactions' or 'p-personal' etc.) |
272 | 272 | * @param href Link URL |
273 | 273 | * @param text Link text (will be automatically converted to lower |
274 | | - * case by CSS for p-cactions in Monobook) |
| 274 | + * case by CSS for p-cactions in Monobook) |
275 | 275 | * @param id ID of the new item, should be unique and preferably have |
276 | | - * the appropriate prefix ( 'ca-', 'pt-', 'n-' or 't-' ) |
| 276 | + * the appropriate prefix ( 'ca-', 'pt-', 'n-' or 't-' ) |
277 | 277 | * @param tooltip Text to show when hovering over the link, without accesskey suffix |
278 | 278 | * @param accesskey Access key to activate this link (one character, try |
279 | | - * to avoid conflicts. Use $( '[accesskey=x' ).get() in the console to |
280 | | - * see if 'x' is already used. |
| 279 | + * to avoid conflicts. Use $( '[accesskey=x' ).get() in the console to |
| 280 | + * see if 'x' is already used. |
281 | 281 | * @param nextnode DOM node or jQuery-selector of the item that the new |
282 | | - * item should be added before, should be another item in the same |
283 | | - * list will be ignored if not the so |
| 282 | + * item should be added before, should be another item in the same |
| 283 | + * list will be ignored if not the so |
284 | 284 | * |
285 | 285 | * @return The DOM node of the new item (a LI element, or A element for |
286 | | - * older skins) or null. |
| 286 | + * older skins) or null. |
287 | 287 | */ |
288 | 288 | 'addPortletLink' : function( portlet, href, text, id, tooltip, accesskey, nextnode ) { |
289 | 289 | |
— | — | @@ -376,10 +376,10 @@ |
377 | 377 | * something, replacing any previous message. |
378 | 378 | * |
379 | 379 | * @param message mixed The DOM-element or HTML-string to be put inside the message box] |
380 | | - * Calling with no arguments, with an empty string or null will hide the message |
| 380 | + * Calling with no arguments, with an empty string or null will hide the message |
381 | 381 | * @param className string Used in adding a class; should be different for each |
382 | | - * call to allow CSS/JS to hide different boxes. null = no class used. |
383 | | - * @return Boolean True on success, false on failure |
| 382 | + * call to allow CSS/JS to hide different boxes. null = no class used. |
| 383 | + * @return Boolean True on success, false on failure |
384 | 384 | */ |
385 | 385 | 'jsMessage' : function( message, className ) { |
386 | 386 | |
— | — | @@ -389,13 +389,13 @@ |
390 | 390 | return true; // Emptying and hiding message is intended behaviour, return true |
391 | 391 | |
392 | 392 | } else { |
393 | | - // We special-case skin structures provided by the software. Skins that |
| 393 | + // We special-case skin structures provided by the software. Skins that |
394 | 394 | // choose to abandon or significantly modify our formatting can just define |
395 | 395 | // an mw-js-message div to start with. |
396 | 396 | var $messageDiv = $( '#mw-js-message' ); |
397 | 397 | if ( !$messageDiv.length ) { |
398 | 398 | $messageDiv = $( '<div id="mw-js-message">' ); |
399 | | - if ( mw.util.$content.parent().length ) { |
| 399 | + if ( mw.util.$content.parent().length ) { |
400 | 400 | mw.util.$content.parent().prepend( $messageDiv ); |
401 | 401 | } else { |
402 | 402 | return false; |
— | — | @@ -416,6 +416,80 @@ |
417 | 417 | $messageDiv.slideDown(); |
418 | 418 | return true; |
419 | 419 | } |
| 420 | + }, |
| 421 | + |
| 422 | + /** |
| 423 | + * Validate a string as representing a valid e-mail address |
| 424 | + * according to HTML5 specification. Please note the specification |
| 425 | + * does not validate a domain with one character. |
| 426 | + * |
| 427 | + * FIXME: should be moved to a JavaScript validation module. |
| 428 | + */ |
| 429 | + 'validateEmail' : function( mailtxt ) { |
| 430 | + if( mailtxt === '' ) { |
| 431 | + return null; |
| 432 | + } |
| 433 | + |
| 434 | + /** |
| 435 | + * HTML5 defines a string as valid e-mail address if it matches |
| 436 | + * the ABNF: |
| 437 | + * 1 * ( atext / "." ) "@" ldh-str 1*( "." ldh-str ) |
| 438 | + * With: |
| 439 | + * - atext : defined in RFC 5322 section 3.2.3 |
| 440 | + * - ldh-str : defined in RFC 1034 section 3.5 |
| 441 | + * |
| 442 | + * (see STD 68 / RFC 5234 http://tools.ietf.org/html/std68): |
| 443 | + */ |
| 444 | + |
| 445 | + /** |
| 446 | + * First, define the RFC 5322 'atext' which is pretty easy : |
| 447 | + * atext = ALPHA / DIGIT / ; Printable US-ASCII |
| 448 | + "!" / "#" / ; characters not including |
| 449 | + "$" / "%" / ; specials. Used for atoms. |
| 450 | + "&" / "'" / |
| 451 | + "*" / "+" / |
| 452 | + "-" / "/" / |
| 453 | + "=" / "?" / |
| 454 | + "^" / "_" / |
| 455 | + "`" / "{" / |
| 456 | + "|" / "}" / |
| 457 | + "~" |
| 458 | + */ |
| 459 | + var rfc5322_atext = "a-z0-9!#$%&'*+-/=?^_`{|}�~", |
| 460 | + |
| 461 | + /** |
| 462 | + * Next define the RFC 1034 'ldh-str' |
| 463 | + * <domain> ::= <subdomain> | " " |
| 464 | + * <subdomain> ::= <label> | <subdomain> "." <label> |
| 465 | + * <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ] |
| 466 | + * <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str> |
| 467 | + * <let-dig-hyp> ::= <let-dig> | "-" |
| 468 | + * <let-dig> ::= <letter> | <digit> |
| 469 | + */ |
| 470 | + rfc1034_ldh_str = "a-z0-9-", |
| 471 | + |
| 472 | + HTML5_email_regexp = new RegExp( |
| 473 | + // start of string |
| 474 | + '^' |
| 475 | + + |
| 476 | + // User part which is liberal :p |
| 477 | + '[' + rfc5322_atext + '\\.' + ']' + '+' |
| 478 | + + |
| 479 | + // "at" |
| 480 | + '@' |
| 481 | + + |
| 482 | + // Domain first part |
| 483 | + '[' + rfc1034_ldh_str + ']+' |
| 484 | + + |
| 485 | + // Second part and following are separated by a dot |
| 486 | + '(?:\\.[' + rfc1034_ldh_str + ']+)+' |
| 487 | + + |
| 488 | + // End of string |
| 489 | + '$', |
| 490 | + // RegExp is case insensitive |
| 491 | + 'i' |
| 492 | + ); |
| 493 | + return (null !== mailtxt.match( HTML5_email_regexp ) ); |
420 | 494 | } |
421 | 495 | |
422 | 496 | }; |
Index: trunk/phase3/resources/Resources.php |
— | — | @@ -358,9 +358,9 @@ |
359 | 359 | 'dependencies' => 'mediawiki.util', |
360 | 360 | ), |
361 | 361 | 'mediawiki.special.preferences' => array( |
362 | | - 'messages' => array( 'email-address-validity-valid', 'email-address-validity-invalid' ), |
363 | 362 | 'scripts' => 'resources/mediawiki.special/mediawiki.special.preferences.js', |
364 | 363 | 'styles' => 'resources/mediawiki.special/mediawiki.special.preferences.css', |
| 364 | + 'messages' => array( 'email-address-validity-valid', 'email-address-validity-invalid' ), |
365 | 365 | ), |
366 | 366 | 'mediawiki.special.changeslist' => array( |
367 | 367 | 'styles' => 'resources/mediawiki.special/mediawiki.special.changeslist.css', |
Index: trunk/phase3/resources/mediawiki.special/mediawiki.special.preferences.css |
— | — | @@ -2,12 +2,12 @@ |
3 | 3 | padding: 2px 1em; |
4 | 4 | } |
5 | 5 | body.ltr #mw-emailaddress-validity { |
6 | | - border-bottom-right-radius:0.8em; |
7 | | - border-top-right-radius:0.8em; |
| 6 | + border-bottom-right-radius: 0.8em; |
| 7 | + border-top-right-radius: 0.8em; |
8 | 8 | } |
9 | 9 | body.rtl #mw-emailaddress-validity { |
10 | | - border-bottom-left-radius:0.8em; |
11 | | - border-top-left-radius:0.8em; |
| 10 | + border-bottom-left-radius: 0.8em; |
| 11 | + border-top-left-radius: 0.8em; |
12 | 12 | } |
13 | 13 | #mw-emailaddress-validity.valid { |
14 | 14 | border: 1px solid #80FF80; |
Index: trunk/phase3/resources/mediawiki.special/mediawiki.special.preferences.js |
— | — | @@ -39,119 +39,36 @@ |
40 | 40 | ); |
41 | 41 | } ); |
42 | 42 | |
43 | | -// User preference form validation |
44 | | -$( '#mw-prefs-form' ) |
45 | | - .submit( function () { |
46 | | - var isValid = wfValidateEmail( $('#mw-input-wpemailaddress').val() ); |
47 | | - wfUpdateMailValidityLabel( isValid ); |
48 | | - if(isValid == false ) { |
49 | | - $('#mw-input-wpemailaddress').focus(); |
50 | | - return false; |
51 | | - } |
52 | | - } |
53 | | -); |
54 | | - |
55 | | -// Lame tip to let user know if its email is valid. See bug 22449 |
56 | | -$( '#mw-input-wpemailaddress' ) |
57 | | - .blur( function () { |
58 | | - if( $( "#mw-emailaddress-validity" ).length == 0 ) { |
59 | | - $(this).after( '<label for="mw-input-wpemailaddress" id="mw-emailaddress-validity"></label>' ); |
60 | | - } |
61 | | - var isValid = wfValidateEmail( $(this).val() ); |
62 | | - wfUpdateMailValidityLabel( isValid ); |
63 | | - } ); |
64 | | - |
65 | 43 | /** |
66 | 44 | * Given an email validity status (true, false, null) update the label CSS class |
67 | 45 | */ |
68 | | -wfUpdateMailValidityLabel = function( isValid ) { |
69 | | - var class_to_add = isValid ? 'valid' : 'invalid'; |
70 | | - var class_to_remove = isValid ? 'invalid' : 'valid'; |
| 46 | +var updateMailValidityLabel = function( mail ) { |
| 47 | + var isValid = mw.util.validateEmail( mail ), |
| 48 | + $label = $( '#mw-emailaddress-validity' ); |
71 | 49 | |
72 | | - // We allow null address |
73 | | - if( isValid == null ) { |
74 | | - $( '#mw-emailaddress-validity' ).text( '' ) |
75 | | - .removeClass( 'valid invalid'); |
76 | | - } else { |
77 | | - $( '#mw-emailaddress-validity' ) |
78 | | - .text( |
79 | | - isValid ? |
80 | | - mediaWiki.msg( 'email-address-validity-valid' ) |
81 | | - : mediaWiki.msg( 'email-address-validity-invalid' ) |
82 | | - ) |
83 | | - .addClass( class_to_add ) |
84 | | - .removeClass( class_to_remove ); |
85 | | - } |
86 | | -} |
| 50 | + // We allow empty address |
| 51 | + if( isValid === null ) { |
| 52 | + $label.text( '' ).removeClass( 'valid invalid' ); |
87 | 53 | |
88 | | -/** |
89 | | - * Validate a string as representing a valid e-mail address |
90 | | - * according to HTML5 specification. Please note the specification |
91 | | - * does not validate a domain with one character. |
92 | | - * |
93 | | - * FIXME: should be moved to a JavaScript validation module. |
94 | | - */ |
95 | | -wfValidateEmail = function( mailtxt ) { |
96 | | - if( mailtxt == '' ) { return null; } |
| 54 | + // Valid |
| 55 | + } else if ( isValid ) { |
| 56 | + $label.text( mw.msg( 'email-address-validity-valid' ) ).addClass( 'valid' ).removeClass( 'invalid' ); |
97 | 57 | |
98 | | - /** |
99 | | - * HTML 5 define a string as valid e-mail address if it matches |
100 | | - * the ABNF : |
101 | | - * 1 * ( atext / "." ) "@" ldh-str 1*( "." ldh-str ) |
102 | | - * With: |
103 | | - * - atext : defined in RFC 5322 section 3.2.3 |
104 | | - * - ldh-str : defined in RFC 1034 section 3.5 |
105 | | - * |
106 | | - * (see STD 68 / RFC 5234 http://tools.ietf.org/html/std68): |
107 | | - */ |
108 | | - |
109 | | - /** |
110 | | - * First, define the RFC 5322 'atext' which is pretty easy : |
111 | | - * atext = ALPHA / DIGIT / ; Printable US-ASCII |
112 | | - "!" / "#" / ; characters not including |
113 | | - "$" / "%" / ; specials. Used for atoms. |
114 | | - "&" / "'" / |
115 | | - "*" / "+" / |
116 | | - "-" / "/" / |
117 | | - "=" / "?" / |
118 | | - "^" / "_" / |
119 | | - "`" / "{" / |
120 | | - "|" / "}" / |
121 | | - "~" |
122 | | - */ |
123 | | - var rfc5322_atext = "a-z0-9!#$%&'*+-/=?^_`{|}—~" ; |
124 | | - |
125 | | - /** |
126 | | - * Next define the RFC 1034 'ldh-str' |
127 | | - * <domain> ::= <subdomain> | " " |
128 | | - * <subdomain> ::= <label> | <subdomain> "." <label> |
129 | | - * <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ] |
130 | | - * <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str> |
131 | | - * <let-dig-hyp> ::= <let-dig> | "-" |
132 | | - * <let-dig> ::= <letter> | <digit> |
133 | | - */ |
134 | | - var rfc1034_ldh_str = "a-z0-9-" ; |
135 | | - |
136 | | - var HTML5_email_regexp = new RegExp( |
137 | | - // start of string |
138 | | - '^' |
139 | | - + |
140 | | - // User part which is liberal :p |
141 | | - '[' + rfc5322_atext + '\\.' + ']' + '+' |
142 | | - + |
143 | | - // "apostrophe" |
144 | | - '@' |
145 | | - + |
146 | | - // Domain first part |
147 | | - '[' + rfc1034_ldh_str + ']+' |
148 | | - + |
149 | | - // Second part and following are separated by a dot |
150 | | - '(?:\\.[' + rfc1034_ldh_str + ']+)+' |
151 | | - + |
152 | | - // End of string |
153 | | - '$', |
154 | | - // RegExp is case insensitive |
155 | | - 'i' |
156 | | - ); |
157 | | - return (null != mailtxt.match( HTML5_email_regexp ) ); |
| 58 | + // Not valid |
| 59 | + } else { |
| 60 | + $label.text( mw.msg( 'email-address-validity-invalid' ) ).addClass( 'invalid' ).removeClass( 'valid' ); |
| 61 | + } |
158 | 62 | }; |
| 63 | + |
| 64 | +// Lame tip to let user know if its email is valid. See bug 22449 |
| 65 | +// Only bind once for 'blur' so that the user can fill it in without errors |
| 66 | +// After that look at every keypress for direct feedback if it was invalid onblur |
| 67 | +$( '#mw-input-wpemailaddress' ).one( 'blur', function() { |
| 68 | + if ( $( '#mw-emailaddress-validity' ).length === 0 ) { |
| 69 | + $(this).after( '<label for="mw-input-wpemailaddress" id="mw-emailaddress-validity"></label>' ); |
| 70 | + } |
| 71 | + updateMailValidityLabel( $(this).val() ); |
| 72 | + $(this).keyup( function() { |
| 73 | + updateMailValidityLabel( $(this).val() ); |
| 74 | + } ); |
| 75 | +} ); |