diff --git a/app/views/devise/invitations/edit.html.erb b/app/views/devise/invitations/edit.html.erb index 7720b7f..d8910f8 100644 --- a/app/views/devise/invitations/edit.html.erb +++ b/app/views/devise/invitations/edit.html.erb @@ -1,22 +1,26 @@
-

<%= t "devise.invitations.edit.header" %>

+

<%= _("Create an account to view the plan") %>

+

<%= _("You will need to create an account in order to accept your invitation to view the data management plan (DMP).") %>

- <%= form_for resource, :as => resource_name, :url => invitation_path(resource_name), :html => { :method => :put } do |f| %> + <%= form_for resource, as: resource_name, url: invitation_path(resource_name), html: {method: :put, id: "invitation_create_account"} do |f| %> <%= devise_error_messages! %> <%= f.hidden_field :invitation_token %> - -

<%= f.label :password %>
- <%= f.password_field :password %>

- -

<%= f.label :password_confirmation %>
- <%= f.password_field :password_confirmation %>

- -

<%= f.submit t("devise.invitations.edit.submit_button") %>

+ +
+ <%= f.label(:password, _('New password'), class: 'control-label') %> + <%= f.password_field(:password, class: 'form-control', "aria-required": true, "data-validation": "password") %> +
+
+ <%= f.label(:password_confirmation, _('Password confirmation'), class: 'control-label') %> + <%= f.password_field(:password_confirmation, class: 'form-control', "aria-required": true, "data-validation": "password") %> +
+ + <%= f.button(_('Create account'), class: "btn btn-default", type: "submit") %> <% end %>
diff --git a/app/views/devise/passwords/edit.html.erb b/app/views/devise/passwords/edit.html.erb index eb06aab..6cc47d0 100644 --- a/app/views/devise/passwords/edit.html.erb +++ b/app/views/devise/passwords/edit.html.erb @@ -11,12 +11,12 @@ <%= f.hidden_field :reset_password_token %>
- <%= f.label(:email, _('New password'), class: 'control-label') %> - <%= f.password_field(:password, class: 'form-control', "aria-required": true) %> + <%= f.label(:password, _('New password'), class: 'control-label') %> + <%= f.password_field(:password, class: 'form-control', "aria-required": true, "data-validation": "password") %>
- <%= f.label(:email, _('Confirm password'), class: 'control-label') %> - <%= f.password_field(:password_confirmation, class: 'form-control', "aria-required": true) %> + <%= f.label(:password_confirmation, _('Password confirmation'), class: 'control-label') %> + <%= f.password_field(:password_confirmation, class: 'form-control', "aria-required": true, "data-validation": "password") %>
<%= f.button(_('Save'), class: "btn btn-default", type: "submit") %> diff --git a/app/views/shared/_login_form.html.erb b/app/views/shared/_login_form.html.erb index fb56a41..eabb69f 100644 --- a/app/views/shared/_login_form.html.erb +++ b/app/views/shared/_login_form.html.erb @@ -1,6 +1,6 @@

<%= _('Sign in') %>

-<%= form_for resource, as: 'user', url: user_session_path, html: {class: "login-form roadmap-form"} do |f| %> +<%= form_for resource, as: 'user', url: user_session_path, html: {class: "login-form roadmap-form", id: "sign_in"} do |f| %>
<% if Rails.application.config.shibboleth_enabled %>

<%= _('Sign in with') %>

diff --git a/app/views/shared/_register_form.html.erb b/app/views/shared/_register_form.html.erb index fc26824..d2f1862 100644 --- a/app/views/shared/_register_form.html.erb +++ b/app/views/shared/_register_form.html.erb @@ -1,6 +1,6 @@

<%= _('Create account') %>

-<%= form_for resource, as: 'user', url: registration_path("user"), html: {autocomplete: "off", class: "roadmap-form register-form"} do |f| %> +<%= form_for resource, as: 'user', url: registration_path("user"), html: {autocomplete: "off", class: "roadmap-form register-form", id: "create_account"} do |f| %>
diff --git a/lib/assets/javascripts/constants.js b/lib/assets/javascripts/constants.js index e364441..6ce5d0c 100644 --- a/lib/assets/javascripts/constants.js +++ b/lib/assets/javascripts/constants.js @@ -1,7 +1,12 @@ (function(ctx){ var vals = { PASSWORD_MIN_LENGTH: 8, - PASSWORD_MAX_LENGTH: 128 + PASSWORD_MAX_LENGTH: 128, + + VALIDATION_MESSAGE_PASSWORD: "The password must be between 8 and 128 characters.", + VALIDATION_MESSAGE_EMAIL: "You must enter a valid email address.", + VALIDATION_MESSAGE_REQUIRED: "This field is required.", + VALIDATION_MESSAGE_PASSWORDS_MATCH: "The passwords must match." }; for(var key in vals){ diff --git a/lib/assets/javascripts/utils/ariatiseForm.js b/lib/assets/javascripts/utils/ariatiseForm.js index c787d77..69f571c 100644 --- a/lib/assets/javascripts/utils/ariatiseForm.js +++ b/lib/assets/javascripts/utils/ariatiseForm.js @@ -44,12 +44,12 @@ 3. Prevent form to be submitted */ (function(ctx){ - var requiredFields=(function(selector){ - return $(selector).find('.form-control').filter('[aria-required="true"]'); + // Collect all elements that are either required or have data-validation defined + var validatableFields=(function(selector){ + return $(selector).find('.form-control').filter('[data-validation],[aria-required="true"]'); }); var blockHelp=(function (id,type){ - var msg='Please fill out this field with a valid '+type+'.'; //TODO internationalisation - return ''; + return ''; }); var ariaDescribedBy=(function(value){ return { 'aria-describedby': value }; @@ -57,33 +57,35 @@ var ariaInvalid=(function(value){ return { 'aria-invalid': value }; }); + var defaultValidationError=(function(type){ + if(dmproadmap.utils.validate[type] && dmproadmap.utils.validate[type].message){ + return dmproadmap.utils.validate[type].message; + } + return ''; + }); var validationStates={ hasWarning: 'has-warning', hasError: 'has-error', hasSuccess: 'has-success' }; - var getTypeForSubmittableElement=(function(el){ - // Reference from https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories#Form-associated_content - if($(el).is('input')){ - return $(el).attr('type'); // available types at https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#Form__types - } - else if($(el).is('select')){ - return 'select'; - } - else if($(el).is('textarea')){ - return 'textarea'; - } - else - return 'unknown'; + var getValidationTypeForElement=(function(el){ + var validation = $(el).attr('data-validation'); + // if the specified validation type is defined + if(validation && dmproadmap.utils.validate[validation]){ + return $(el).attr('data-validation'); + + }else if($(el).attr('aria-required') === 'true'){ + return 'required'; + } + return false; }); var isValid=(function(type, value){ // TODO add more validation for each new type coming along by: // 1. defining a function at dmproadmap.utils.validate // 2. adding the case in the switch below switch(type){ - case 'text': - case 'textarea': - return dmproadmap.utils.validate.text(value); + case 'required': + return dmproadmap.utils.validate.required(value); case 'email': return dmproadmap.utils.validate.email(value); case 'password': @@ -97,28 +99,49 @@ $(el).attr(ariaInvalid(false)); $(el).next().hide(); }); - var invalid=(function(el){ + var invalid=(function(el,msg){ + if(!msg){ + msg = defaultValidationError(getValidationTypeForElement(el)); + } $(el).parent().addClass(validationStates.hasError); $(el).attr(ariaInvalid(true)); - $(el).next().show(); + $(el).next().text(msg).show(); + }); + + ctx.displayValidationError=ctx.displayValidationError || (function(el,msg){ + // Updates the validation error message for the element. If no msg is provided it will revert to the default message + if($(el)){ + invalid(el,msg); + } }); ctx.init=ctx.init || (function(options){ if($ && options && options.selector){ - requiredFields(options.selector).each(function(i,el){ + validatableFields(options.selector).each(function(i,el){ $(el).attr(ariaDescribedBy('help'+i)); - $(el).after(blockHelp('help'+i, getTypeForSubmittableElement(el))); + $(el).after(blockHelp('help'+i, getValidationTypeForElement(el))); }); + $(options.selector+' [type="submit"]').click(function(e){ - requiredFields(options.selector).each(function(i,el){ - if(isValid(getTypeForSubmittableElement(el),$(el).val())){ - valid(el); + validatableFields(options.selector).each(function(i,el){ + // If the element has a data-validation defined and the value is not blank + if($(el).attr('data-validation') && $(el).val().trim().length > 0){ + if(isValid($(el).attr('data-validation'), $(el).val())){ + valid(el); + }else{ + e.preventDefault(); + invalid(el); } - else{ - e.preventDefault(); - invalid(el); + // If the element is a required field make sure its not blank + }else if($(el).attr('aria-required') === "true"){ + if(isValid('required', $(el).val())){ + valid(el); + }else{ + e.preventDefault(); + invalid(el); } + } }); }); - } + } }); })(define('dmproadmap.utils.ariatiseForm')); \ No newline at end of file diff --git a/lib/assets/javascripts/utils/validate.js b/lib/assets/javascripts/utils/validate.js index 4d061c0..55af11c 100644 --- a/lib/assets/javascripts/utils/validate.js +++ b/lib/assets/javascripts/utils/validate.js @@ -5,7 +5,8 @@ @param value String to verify its length @return true if it has a length greater than zero; otherwise, false. */ - ctx.text = ctx.text || (function(value){ + ctx.required = ctx.required || (function(value){ +console.log("required: "+value); if(Object.prototype.toString.call(value) === '[object String]') return value.trim().length > 0; return false; @@ -31,10 +32,12 @@ value.trim().length <= dmproadmap.constants.PASSWORD_MAX_LENGTH); return false; }); + /* - validates whether the two values match (e.g. password and password_confirmation) + default error messages */ - ctx.matches = ctx.matches || (function(valueA, valueB){ - return valueA === valueB; - }); + ctx.required.message=ctx.required.message || dmproadmap.constants.VALIDATION_MESSAGE_REQUIRED; + ctx.email.message=ctx.email.message || dmproadmap.constants.VALIDATION_MESSAGE_EMAIL; + ctx.password.message=ctx.password.message || dmproadmap.constants.VALIDATION_MESSAGE_PASSWORD;; + })(define('dmproadmap.utils.validate')); \ No newline at end of file diff --git a/lib/assets/javascripts/views/devise/devise.js b/lib/assets/javascripts/views/devise/devise.js index 3d8f845..2b5c775 100644 --- a/lib/assets/javascripts/views/devise/devise.js +++ b/lib/assets/javascripts/views/devise/devise.js @@ -2,6 +2,21 @@ // Password reset dmproadmap.utils.ariatiseForm.init({ selector: '#user_request_reset_password' }); dmproadmap.utils.ariatiseForm.init({ selector: '#user_reset_password' }); + dmproadmap.utils.ariatiseForm.init({ selector: '#invitation_create_account' }); - + $("[type='submit']").click(function(e){ + // We have to specifically include the form name in the selectors here in case there are multiple + // devise forms (e.g. sign-in modal and the forgot password forms) + var frm = $(this).closest('form').attr('id'), + pwd = $("#"+frm+" #user_password"), + cnf = $("#"+frm+" #user_password_confirmation"); + + // If the password and password_confirmation are present and do not match display an error + if(pwd.val() && cnf.val()){ + if(pwd.val() != cnf.val()){ + e.preventDefault(); + dmproadmap.utils.ariatiseForm.displayValidationError(cnf, dmproadmap.constants.VALIDATION_MESSAGE_PASSWORDS_MATCH); + } + } + }); }); \ No newline at end of file