Newer
Older
dmpopidor / lib / assets / javascripts / utils_es5 / ariatiseForm.js
/*
    dmproadmap.utils.ariatiseForm augmentates a HTML form by:
    - Associating help text with form controls
    - Adding validation state to each form group
    - Adding specific attributes for user with assistive technologies.

    For example the following form :
    <form>
        <div class="form-group">
            <label class="control-label" for="name">Name</label>
            <input type="text" class="form-control" id="name" aria-required="true">
        </div>
        <div class="form-group">
            <label class="control-label" for="email">Email</label>
            <input type="email" class="form-control" id="email" aria-required="true">
        </div>
        <div class="form-group">
            <label class="control-label" for="name">Subject</label>
            <input type="text" class="form-control" id="subject" aria-required="false">
        </div>
        <button name="button" type="submit" class="btn btn-default">Submit</button>
    </form>
    will be augmentated as follows:
    <form>
        <div class="form-group">
            <label class="control-label" for="name">Name</label>
            <input type="text" class="form-control" id="name" aria-required="true" aria-describedby="help0">
            <span id="help0" class="help-block" style="display:none;">Please fill out this field with a valid text.</span>
        </div>
        <div class="form-group">
            <label class="control-label" for="email">Email</label>
            <input type="email" class="form-control" id="email" aria-required="true" aria-describedby="help1">
            <span id="help1" class="help-block" style="display:none;">Please fill out this field with a valid email.</span>
        </div>
        <div class="form-group">
            <label class="control-label" for="name">Subject</label>
            <input type="text" class="form-control" id="subject" aria-required="false">
        </div>
        <button name="button" type="submit" class="btn btn-default">Submit</button>
    </form>
    and any time the buttton is clicked the validation according to each type (e.g. text, email) will be triggered. An invalid result for a form-control will:
    1. Add has-error class to its form-group parent and aria-invalid="true" to the form-control
    2. Show its help-block following sibling
    3. Prevent form to be submitted
*/
(function(ctx){
    var requiredFields=(function(selector){
        return $(selector).find('.form-control').filter('[aria-required="true"]');
    });
    var blockHelp=(function (id,type){
        var msg='Please fill out this field with a valid '+type+'.';    //TODO internationalisation
        return '<span id="'+id+'" class="help-block" style="display:none;">'+msg+'</span>';
    });
    var ariaDescribedBy=(function(value){
        return { 'aria-describedby': value };
    });
    var ariaInvalid=(function(value){
        return { 'aria-invalid': value };
    });
    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_<input>_types
        }
        else if($(el).is('select')){
            return 'select';
        }
        else if($(el).is('textarea')){
            return 'textarea';
        }
        else
            return 'unknown';
    });
    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 'email':
                return dmproadmap.utils.validate.email(value);
            default:
                return false;
        }
    });
    var valid=(function(el){
        $(el).parent().removeClass(validationStates.hasError);
        $(el).attr(ariaInvalid(false));
        $(el).next().hide();
    });
    var invalid=(function(el){
        $(el).parent().addClass(validationStates.hasError);
        $(el).attr(ariaInvalid(true));
        $(el).next().show();
    });
    ctx.init=ctx.init || (function(options){
        if($ && options && options.selector){
            requiredFields(options.selector).each(function(i,el){
                $(el).attr(ariaDescribedBy('help'+i));
                $(el).after(blockHelp('help'+i, getTypeForSubmittableElement(el)));
            });
            $(options.selector+' [type="submit"]').click(function(e){
                requiredFields(options.selector).each(function(i,el){
                    if(isValid(getTypeForSubmittableElement(el),$(el).val())){
                        valid(el);
                    }
                    else{
                        e.preventDefault();
                        invalid(el);
                    }
                });
            });
        }   
    });
})(define('dmproadmap.utils.ariatiseForm'));