r75670 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r75669‎ | r75670 | r75671 >
Date:20:44, 29 October 2010
Author:hashar
Status:resolved (Comments)
Tags:
Comment:
Follow up r75627 (code review comments):
* Replace background coloring with a label insertion on the right or left of input depending on language direction.
* User side validation of email according to an HTML5 specifications provided by Simetrical :
http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#e-mail-state
Code comments should be self explaining.

Possible follows up:
- use JQuery Validation plugin
- make the validation part a mediawiki validation module
- server side validation
Modified paths:
  • /trunk/phase3/resources/mediawiki.specials/mediawiki.specials.preferences.css (modified) (history)
  • /trunk/phase3/resources/mediawiki.specials/mediawiki.specials.preferences.js (modified) (history)

Diff [purge]

Index: trunk/phase3/resources/mediawiki.specials/mediawiki.specials.preferences.js
@@ -41,19 +41,87 @@
4242
4343 // Lame tip to let user know if its email is valid. See bug 22449
4444 $( '#mw-input-emailaddress' )
45 - .keyup( function() {
46 - var mailtxt = $(this).val();
47 - if( mailtxt == '' ) {
48 - // mail is optional !
49 - $(this).removeClass( "invalid" );
50 - $(this).removeClass( "valid" );
51 - return;
 45+ .keyup( function () {
 46+ if( $( "#mw-emailaddress-validity" ).length == 0 ) {
 47+ $(this).after( '<label for="mw-input-emailaddress" id="mw-emailaddress-validity"></label>' );
5248 }
53 - if( mailtxt.match( /.+@.+\..+/ ) ) {
54 - $(this).addClass( "valid" );
55 - $(this).removeClass( "invalid" );
56 - } else {
57 - $(this).addClass( "invalid" );
58 - $(this).removeClass( "valid" );
59 - }
 49+ var isValid = wfValidateEmail( $(this).val() );
 50+ var class_to_add = isValid ? 'valid' : 'invalid';
 51+ var class_to_remove = isValid ? 'invalid' : 'valid';
 52+ $( '#mw-emailaddress-validity' )
 53+ .text( isValid ? 'Looks valid' : 'Valid address required!' )
 54+ .addClass( class_to_add )
 55+ .removeClass( class_to_remove );
6056 } );
 57+
 58+/**
 59+ * Validate a string as representing a valid e-mail address
 60+ * according to HTML5 specification. Please note the specification
 61+ * does not validate a domain with one character.
 62+ *
 63+ * FIXME: should be moved to a JavaScript validation module.
 64+ */
 65+wfValidateEmail = function( mailtxt ) {
 66+ if( mailtxt == '' ) { return null; }
 67+
 68+ /**
 69+ * HTML 5 define a string as valid e-mail address if it matches
 70+ * the ABNF :
 71+ * 1 * ( atext / "." ) "@" ldh-str 1*( "." ldh-str )
 72+ * With:
 73+ * - atext : defined in RFC 5322 section 3.2.3
 74+ * - ldh-str : defined in RFC 1034 section 3.5
 75+ *
 76+ * (see STD 68 / RFC 5234 http://tools.ietf.org/html/std68):
 77+ */
 78+
 79+ /**
 80+ * First, define the RFC 5322 'atext' which is pretty easy :
 81+ * atext = ALPHA / DIGIT / ; Printable US-ASCII
 82+ "!" / "#" / ; characters not including
 83+ "$" / "%" / ; specials. Used for atoms.
 84+ "&" / "'" /
 85+ "*" / "+" /
 86+ "-" / "/" /
 87+ "=" / "?" /
 88+ "^" / "_" /
 89+ "`" / "{" /
 90+ "|" / "}" /
 91+ "~"
 92+ */
 93+ var rfc5322_atext = "a-z0-9!#$%&'*+-/=?^_`{|}—~" ;
 94+
 95+ /**
 96+ * Next define the RFC 1034 'ldh-str'
 97+ * <domain> ::= <subdomain> | " "
 98+ * <subdomain> ::= <label> | <subdomain> "." <label>
 99+ * <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
 100+ * <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
 101+ * <let-dig-hyp> ::= <let-dig> | "-"
 102+ * <let-dig> ::= <letter> | <digit>
 103+ */
 104+ var rfc1034_ldh_str = "a-z0-9-" ;
 105+
 106+ var HTML5_email_regexp = new RegExp(
 107+ // start of string
 108+ '^'
 109+ +
 110+ // User part which is liberal :p
 111+ '[' + rfc5322_atext + '\\.' + ']' + '+'
 112+ +
 113+ // "apostrophe"
 114+ '@'
 115+ +
 116+ // Domain first character
 117+ '[' + rfc1034_ldh_str + ']'
 118+ +
 119+ // second char and following can include dot
 120+ '[' + rfc1034_ldh_str + '\\.' + ']' + '+'
 121+ +
 122+ // End of string
 123+ '$',
 124+ // RegExp is case insensitive
 125+ 'i'
 126+ );
 127+ return mailtxt.match( HTML5_email_regexp );
 128+};
Index: trunk/phase3/resources/mediawiki.specials/mediawiki.specials.preferences.css
@@ -1,8 +1,21 @@
2 -input.valid {
 2+#mw-emailaddress-validity {
 3+ padding: 2px 1em;
 4+}
 5+body.ltr #mw-emailaddress-validity {
 6+ border-bottom-right-radius:0.8em;
 7+ border-top-right-radius:0.8em;
 8+}
 9+body.rtl #mw-emailaddress-validity {
 10+ border-bottom-left-radius:0.8em;
 11+ border-top-left-radius:0.8em;
 12+}
 13+#mw-emailaddress-validity.valid {
 14+ border: 1px solid #80FF80;
315 background-color: #C0FFC0;
416 color: black;
517 }
6 -input.invalid {
 18+#mw-emailaddress-validity.invalid {
 19+ border: 1px solid #FF8080;
720 background-color: #FFC0C0;
821 color: black;
922 }

Follow-up revisions

RevisionCommit summaryAuthorDate
r75682Follow up r75627. Implements r75670 in PHP to validate emails....hashar22:03, 29 October 2010
r75876Fix misinterpration of HTML5 specification for email validation....hashar20:39, 2 November 2010
r79904js email validation fixed + i18n support...hashar17:09, 9 January 2011
r79910js email validation improvment (onBlur)...hashar18:36, 9 January 2011
r79924* Consistent single quotes...krinkle04:40, 10 January 2011

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r75627Lame user side email validator using JQuery....hashar21:01, 28 October 2010

Comments

#Comment by Catrope (talk | contribs)   20:33, 31 October 2010
+wfValidateEmail = function( mailtxt ) {

Don't use the wf prefix for function names in JavaScript. Contrary to what you may think, it's also not a global function unless you happen to be in debug mode.

#Comment by Simetrical (talk | contribs)   00:22, 1 November 2010

+ * according to HTML5 specification. Please note the specification

+ * does not validate a domain with one character.

You mean it doesn't validate a TLD. Each part of the domain name can have only one character if you like.

+		// "apostrophe"
+		'@'

This is an at-sign, not an apostrophe.

#Comment by Simetrical (talk | contribs)   00:27, 1 November 2010

Also, this is wrong, you're misreading the spec:

+        // Domain first character
+        '[' + rfc1034_ldh_str + ']'
+        +
+		// second char and following can include dot
+		'[' + rfc1034_ldh_str + '\\.' + ']' + '+'

It should be

		// Domain first part
		'[' + rfc1034_ldh_str + ']+'
		+
		// second char and following can include dot
		'([.' + rfc1034_ldh_str + '])+'

Your version allows crazy domain names like "f.......", which is not what the spec says. It allows two or more dot-separated parts.

#Comment by Hashar (talk | contribs)   19:27, 2 November 2010

Acknowledged. I have missread the ABNF definition for ldh-str :-/ I will patch both the php and js. Thanks!

#Comment by Simetrical (talk | contribs)   01:27, 1 November 2010

Okay, the UI here could use a lot of improvement. Take a look at this study: http://www.alistapart.com/articles/inline-validation-in-web-forms/ Two major conclusions of relevance:

  1. Do not display success/failure onkeyup. Instead, display it onchange. That way the user isn't told their e-mail address is invalid just because they've only half-entered it ("well, of course it's not valid yet!"). This means they get no client-side message if they just hit enter right away, but that's okay, because
  2. Don't display success, only failure. People get confused when they see their answer to an obvious question marked "correct". From the study:

    Our participants knew we had no way to know their correct name or postal code, so they knew that the green check mark didn’t mean “correct.” But what did they think it meant? They weren’t sure—and that was the problem. Not knowing what the message meant, our participants stopped to ask questions of the moderator instead of confidently answering what were very easy questions.

Also, you seem to have hardcoded the message as English . . . ?

#Comment by Hashar (talk | contribs)   11:20, 1 November 2010

1) onChange is not useful when this part of the form only has one input. It is more about changing the email then either hitting enter or clicking submit, although one could just disable the submit button until the error is address. I found the onKey event makes it much more dynamic and fun to use.

2) An email might be obvious for us, not for everyone. I got friends and family members who do not even know how to do the @ sign ! They have to copy-paste it from another source. As for the correct postal code, I totally agree with the study, probably why I said "looks valid".

I have hardcoded the message since I am not sure yet how to handle i18n for javascript messages. It looks like a work in progress.

#Comment by Simetrical (talk | contribs)   19:31, 1 November 2010

1) Inline validation doesn't matter so much if the user submits right away. After all, then they get feedback in just a second regardless. It's most useful if the user is filling out several things at once. But if you think otherwise, add an onsubmit trigger too.

Your assessment of what's fun to use doesn't outweigh an actual usability study. The study found that users clearly preferred being told that their input is wrong only after they've finished filling in the particular input. You're going to have to bring actual evidence if you feel otherwise.

2) It's arguable whether it's comparable to the postal code example, particularly since you say "Looks valid". But I still don't think the notification of validity serves any purpose here. At best it's distracting.

#Comment by Hashar (talk | contribs)   19:59, 2 November 2010

1) Since the user will submits right away, I found the onKey event more useful. That save it a click. I am not willing to add the onSubmit trigger since we could get a bug and I would prefer having some feedback before.

I have read the study (interesting stuff indeed, thanks for it) which apply to a multiple input form. The video show how annoying and distracting it is to have instant validation when filling a multiple input form. In our case, I have the feeling that instant validation is not as distractive since there is only one input. As for the usability, I only have my girlfriend (and you) to test upon :-p The first preferred the changing background ;-b

2) The whole idea was to warn users about obvious errors. For example, someone copy pasting : "Ashar Voultoiz" <hashar at free dot fr>, or unintended text which might precede or follow an email when copy pasting.

#Comment by Simetrical (talk | contribs)   18:45, 3 November 2010

I suggest we ask the usability people for an opinion, since we have a whole bunch lying around.

#Comment by Trevor Parscal (WMF) (talk | contribs)   18:56, 3 November 2010

Validation needs to happen on the server, and optionally the client. The change event is very odd and in some browsers buggy, usually not working the way you expect. The correct way to perform this validation is on blur. Submitting the form would cause the submit button to be focused, blurring the text field, and thus validating the field. The submit handler should not allow the form to be submitted if the field is empty or marked as invalid.

#Comment by Hashar (talk | contribs)   20:37, 3 November 2010

I have added the server side check (includes/Preference.php) with r75682 and r75876 (the later fixes the regexp).

#Comment by Hashar (talk | contribs)   20:46, 3 November 2010

I do not like the blur event since it triggers on a focus change only. Thus, this event defeats the feature I want to implement : provide an "instant" tip about email state. This is much like the skins/common/mwsuggest.js script or the twitter signup page.

I know the keyup / keydown / keypress are not consistent between browsers, specially when you actually care about the key pressed. In this case, we just need to know that a key got pressed which usually happen when typing it or copy pasting (since it press the V or whatever key).


(Trevor, if you have any documentation from the usability project, I am HIGHLY interested!)

#Comment by Simetrical (talk | contribs)   21:02, 5 November 2010

"Submitting the form would cause the submit button to be focused, blurring the text field, and thus validating the field."

Is that true? This page seems to work otherwise:

data:text/html,<!doctype html>
<form>
<input name=foo onblur="alert(true)">
<input type=submit>
</form>

If you focus the input and hit enter, it submits but doesn't alert, at least in Firefox 4.

#Comment by Trevor Parscal (WMF) (talk | contribs)   21:03, 5 November 2010

Perhaps you would need to put a $( 'submit button id' ).focus() in the submit handler...

#Comment by Jorm (WMF) (talk | contribs)   18:57, 3 November 2010

It's okay to do client side validation as *suggestive* but never *canonical*; validation has to happen on the server.

I'd not use onKeyUp or onChange; do your stuff on onBlur.

#Comment by Krinkle (talk | contribs)   23:43, 7 January 2011

I agree, when using unkeyup it's impossible to do a valid form submission without seeing errors (since it would be invalid while typing), which is bad because it should always be possible to fill in a form and submit it without seeing any errors.

#Comment by Hashar (talk | contribs)   13:17, 8 January 2011

Should I just remove the whole thing ? The main reasons are :

It is not i18n compliant. One way would have been to add hidden messages in the HTML and display/hide them on purpose. The problem is that it needs some new exceptions in HTMLForm and non CSS browser users will complain.

Originally, I wanted to warn the user ASAP (by using onKeyUp) but it seems to be a bad practice. The consensus seems to be using onBlur and a validation function on the submit buttons. This was not really what I wanted to do.

#Comment by Catrope (talk | contribs)   15:31, 8 January 2011

This seems to be controversial, so let's back it out of 1.17 at least.

#Comment by Hashar (talk | contribs)   18:38, 9 January 2011

Marking new: r79904 adds i18n support (thanks Roan) r79910 use onBlur()

#Comment by Catrope (talk | contribs)   00:42, 26 January 2011

This can be marked resolved now.

Status & tagging log