if(typeof(initModuleDropdown) == 'undefined')
{
    function getEventTarget(e) {
        e = e || window.event;
        return e.target || e.srcElement;
    }
    
    /**
     * custom dropdown module.
     * 
     * @param $dd jQuery object containing 1,n div.dropdown elements.
     * 
     */
    var initModuleDropdown = function($module, opts){
        opts = opts || {};
        opts = merge({
            onChange: function(){}
        }, opts);
        
        $module.find('span').click(function(ev){
        
            var $span = $(this); // clicked span element
            var $div = $span.closest('.dropdown').find('div').eq(0); // the first div within the .dropdown
            var $input = $span.closest('.dropdown').find(':input:hidden'); // the hidden form element
            var $vis = $span.closest('.dropdown').find('span.value'); // the visible span 
            var changed = false;
            var el = getEventTarget(ev);
            
            if(el.tagName == 'LI') el = $(el).find('span').eq(0);
            
            if($div.hasClass('selected')){
                // choose new item
                $(el).closest('li').addClass('selected').siblings('li:not(.value)').removeClass('selected');
                changed = $input.attr('value') != $(el).attr('value');
                $input.attr('value', $(el).attr('value'));
                $vis.html($(el).html()).closest('li').addClass('selected');
            }
            
            $div.toggleClass('selected');
            if(changed){
                try {
                    $input.each(opts.onChange);
                } catch(e) {
                    console.log(e);
                }
            }

            
            return false;
        });
        $(document).click(function(e){
            var $e = $(e.target);
            if($e.closest('.dropdown').length < 1 && !$e.hasClass('dropdown')){
                $module.find('div').eq(0).removeClass('selected');
            }
        });
        return $module;
    };
}