Source: main.js

(function(global) {

    /**
     * @namespace
     * @name customformsjs
     * @example
     * // You can overwrite defaults by passing an object with some options, when an option is passed
     * // without a module name as namespace it will be a global option, module namespaced options will
     * // overwrite global options, also modules will have some options that are particular for that module,
     * // please refer to the documentation page to see all possible options for each module.
     *  var options = { active: true, lowercasemodulename: { active: false } };
     *
     *  // All supported elements inside container, will recurse to find all elements
     *  $('#container').cstmForm( options )
     *
     *  // All Form elements
     *  $('form').cstmForm( options )
     *
     *  // target a certain group of element
     *  $('input[type=file]').cstmForm( options )
     *
     *  // You can target specific groups of elements
     *  $('input[type=radio], input[type=checkbox], select').cstmForm( options )
     */
    var APP = global.customformsjs = global.customformsjs || {},

        fieldFactory = (function() {

            var SUPPORTED_ELEMENTS = {},
                GLOBAL_OPTIONS = {},
                capitaliseFirstLetter = function(string) {
                    return string.charAt(0).toUpperCase() + string.slice(1);
                },
                callModule = function(moduleName, element, options) {
                    var opt = options || {},
                        settings = $.extend(true, {}, GLOBAL_OPTIONS, opt);

                    settings.element = element;

                    APP.module[moduleName](settings);
                },
                setGlobalOptions = function(options) {
                    // Global options are options that are 
                    // not namespaced by a module name

                    // Reset on each call
                    GLOBAL_OPTIONS = {};

                    for (var option in options) {
                        if (!APP.module[capitaliseFirstLetter(option)]) {
                            GLOBAL_OPTIONS[option] = options[option];
                        }
                    }
                },
                getTag = function(element) {
                    return SUPPORTED_ELEMENTS[element.nodeName.toLowerCase()];
                },
                assertFilter = function(matchvalue, match) {
                    var lookupTable = {
                        array: function() {
                            return $.inArray(matchvalue, match) !== -1;
                        },
                        string: function() {
                            return matchvalue === match;
                        }
                    };

                    return lookupTable[typeof match === 'string' ? 'string' :
                        'array']();
                },
                checkFilter = function(filter, $element) {

                    var ret = false;

                    $.each(filter, function(key, filter) {

                        ret = assertFilter($element.attr(key), filter);

                        if (ret) {
                            return false;
                        }
                    });

                    return ret;
                },
                getModule = function($element, options) {

                    var element = $element[0],
                        tag = getTag(element);

                    for (var i = 0, len = tag.length; i < len; i++) {
                        var _tag = tag[i],
                            _modulename = _tag.module || _tag,
                            _options = options[_modulename.toLowerCase()];


                        if (typeof _tag === 'string' || checkFilter(_tag.filter,
                            $element)) {
                            callModule(_modulename, element, _options);
                        }
                    }
                },
                getSupportedChildren = function($parent, options) {
                    $.each($parent.children(), function() {
                        var lookupTable = {
                            getModule: getModule,
                            getSupportedChildren: getSupportedChildren
                        };

                        lookupTable[getTag($(this)[0]) ? 'getModule' :
                            'getSupportedChildren']($(this), options);
                    });
                },
                addSupportedElement = function(module, tag) {

                    var filter = APP.module[module].blueprint.filter || {},
                        item;

                    // if we dont have element on the hash add it
                    SUPPORTED_ELEMENTS[tag] = SUPPORTED_ELEMENTS[tag] || [];

                    // if module has a filter add it, else just add input
                    // with module reference.
                    item = filter[tag] ? {
                        filter: filter[tag],
                        module: module
                    } : module;

                    // push item to supported hash
                    SUPPORTED_ELEMENTS[tag].push(item);
                },
                buildSupportedElementsList = function() {
                    $.each(APP.module, function(key) {
                        var _tag = APP.module[key].blueprint.tagName,
                            lookupTable = {
                                array: function(module, tag) {
                                    $.each(tag, function(key, value) {
                                        addSupportedElement(module, value);
                                    });
                                },
                                string: addSupportedElement
                            };

                        lookupTable[$.isArray(_tag) ? 'array' : 'string'](key,
                            _tag);
                    });
                };

            // Build list of supported modules on the following format:
            //
            //SUPPORTED_ELEMENTS = {
            //    tagName: [
            //        {
            //            filter: { 'attrname': ['arrval'] },
            //            module: "moduleName"
            //        },
            //        {
            //            filter: { 'attrname2': 'strval' }
            //            module: "moduleName"
            //        },
            //        "strmodulename"
            //    ]
            //};
            buildSupportedElementsList();

            //return function()
            return function(options) {
                setGlobalOptions(options);

                $(this).each(function() {
                    var lookupTable = {
                        validTag: getModule,
                        checkChildrenForValidTag: getSupportedChildren
                    };

                    lookupTable[getTag($(this)[0]) ? "validTag" :
                        "checkChildrenForValidTag"]($(this), options);
                });
            };

        })();

    // assign to jquery as a pluggin
    $.fn.cstmForm = fieldFactory;

}(this));