github.com/fanux/shipyard@v0.0.0-20161009071005-6515ce223235/controller/static/semantic/src/definitions/modules/dropdown.js (about)

     1  /*!
     2   * # Semantic UI - Dropdown
     3   * http://github.com/semantic-org/semantic-ui/
     4   *
     5   *
     6   * Copyright 2014 Contributors
     7   * Released under the MIT license
     8   * http://opensource.org/licenses/MIT
     9   *
    10   */
    11  
    12  ;(function ( $, window, document, undefined ) {
    13  
    14  "use strict";
    15  
    16  $.fn.dropdown = function(parameters) {
    17    var
    18      $allModules    = $(this),
    19      $document      = $(document),
    20  
    21      moduleSelector = $allModules.selector || '',
    22  
    23      hasTouch       = ('ontouchstart' in document.documentElement),
    24      time           = new Date().getTime(),
    25      performance    = [],
    26  
    27      query          = arguments[0],
    28      methodInvoked  = (typeof query == 'string'),
    29      queryArguments = [].slice.call(arguments, 1),
    30      returnedValue
    31    ;
    32  
    33    $allModules
    34      .each(function() {
    35        var
    36          settings          = ( $.isPlainObject(parameters) )
    37            ? $.extend(true, {}, $.fn.dropdown.settings, parameters)
    38            : $.extend({}, $.fn.dropdown.settings),
    39  
    40          className       = settings.className,
    41          metadata        = settings.metadata,
    42          namespace       = settings.namespace,
    43          selector        = settings.selector,
    44          error           = settings.error,
    45  
    46          eventNamespace  = '.' + namespace,
    47          moduleNamespace = 'module-' + namespace,
    48  
    49          $module         = $(this),
    50          $text           = $module.find(selector.text),
    51          $search         = $module.find(selector.search),
    52          $input          = $module.find(selector.input),
    53  
    54          $combo = ($module.prev().find(selector.text).length > 0)
    55            ? $module.prev().find(selector.text)
    56            : $module.prev(),
    57  
    58          $menu           = $module.children(selector.menu),
    59          $item           = $menu.find(selector.item),
    60  
    61          activated       = false,
    62          itemActivated   = false,
    63          element         = this,
    64          instance        = $module.data(moduleNamespace),
    65  
    66          elementNamespace,
    67          id,
    68          observer,
    69          module
    70        ;
    71  
    72        module = {
    73  
    74          initialize: function() {
    75            module.debug('Initializing dropdown', settings);
    76  
    77            if( module.is.alreadySetup() ) {
    78              module.setup.reference();
    79            }
    80            else {
    81              module.setup.layout();
    82  
    83              module.save.defaults();
    84              module.set.selected();
    85  
    86              module.create.id();
    87  
    88              if(hasTouch) {
    89                module.bind.touchEvents();
    90              }
    91              module.bind.mouseEvents();
    92              module.bind.keyboardEvents();
    93  
    94              module.observeChanges();
    95              module.instantiate();
    96            }
    97          },
    98  
    99          instantiate: function() {
   100            module.verbose('Storing instance of dropdown', module);
   101            instance = module;
   102            $module
   103              .data(moduleNamespace, module)
   104            ;
   105          },
   106  
   107          destroy: function() {
   108            module.verbose('Destroying previous dropdown for', $module);
   109            module.remove.tabbable();
   110            $module
   111              .off(eventNamespace)
   112              .removeData(moduleNamespace)
   113            ;
   114            $menu
   115              .off(eventNamespace)
   116            ;
   117            $document
   118              .off(elementNamespace)
   119            ;
   120          },
   121  
   122          observeChanges: function() {
   123            if('MutationObserver' in window) {
   124              observer = new MutationObserver(function(mutations) {
   125                if( module.is.selectMutation(mutations) ) {
   126                  module.debug('<select> modified, recreating menu');
   127                  module.setup.select();
   128                }
   129                else {
   130                  module.debug('DOM tree modified, updating selector cache');
   131                  module.refresh();
   132                }
   133              });
   134              observer.observe(element, {
   135                childList : true,
   136                subtree   : true
   137              });
   138              module.debug('Setting up mutation observer', observer);
   139            }
   140          },
   141  
   142          create: {
   143            id: function() {
   144              id = (Math.random().toString(16) + '000000000').substr(2,8);
   145              elementNamespace = '.' + id;
   146              module.verbose('Creating unique id for element', id);
   147            }
   148          },
   149  
   150          search: function() {
   151            var
   152              query
   153            ;
   154            query = $search.val();
   155  
   156            module.verbose('Searching for query', query);
   157            module.filter(query);
   158            if(module.is.searchSelection() && module.can.show() ) {
   159              module.show();
   160            }
   161          },
   162  
   163          setup: {
   164            layout: function() {
   165              if( $module.is('select') ) {
   166                module.setup.select();
   167              }
   168              if( module.is.search() && !module.is.searchable() ) {
   169                $search = $('<input />')
   170                  .addClass(className.search)
   171                  .insertBefore($text)
   172                ;
   173              }
   174              if(settings.allowTab) {
   175                module.set.tabbable();
   176              }
   177            },
   178            select: function() {
   179              var
   180                selectValues  = module.get.selectValues()
   181              ;
   182              module.debug('Dropdown initialized on a select', selectValues);
   183              if( $module.is('select') ) {
   184                $input = $module;
   185              }
   186              // see if select is placed correctly already
   187              if($input.parent(selector.dropdown).length > 0) {
   188                module.debug('UI dropdown already exists. Creating dropdown menu only');
   189                $module = $input.closest(selector.dropdown);
   190                $menu   = $module.children(selector.menu);
   191                if($menu.length === 0) {
   192                  $menu = $('<div />')
   193                    .addClass(className.menu)
   194                    .appendTo($module)
   195                  ;
   196                }
   197                $menu.html( settings.templates.menu( selectValues ));
   198              }
   199              else {
   200                module.debug('Creating entire dropdown from select');
   201                $module = $('<div />')
   202                  .attr('class', $input.attr('class') )
   203                  .addClass(className.selection)
   204                  .addClass(className.dropdown)
   205                  .html( settings.templates.dropdown(selectValues) )
   206                  .insertBefore($input)
   207                ;
   208                $input
   209                  .removeAttr('class')
   210                  .prependTo($module)
   211                ;
   212              }
   213              module.refresh();
   214            },
   215            reference: function() {
   216              var
   217                index = $allModules.index($module),
   218                $firstModules,
   219                $lastModules
   220              ;
   221              module.debug('Dropdown behavior was called on select, replacing with closest dropdown');
   222              // replace module reference
   223              $module = $module.parent(selector.dropdown);
   224              module.refresh();
   225              // adjust all modules
   226              $firstModules = $allModules.slice(0, index);
   227              $lastModules = $allModules.slice(index + 1);
   228              $allModules = $firstModules.add($module).add($lastModules);
   229            }
   230          },
   231  
   232          refresh: function() {
   233            module.verbose('Refreshing selector cache');
   234            $text   = $module.find(selector.text);
   235            $search = $module.find(selector.search);
   236            $input  = $module.find(selector.input);
   237            $combo  = ($module.prev().find(selector.text).length > 0)
   238              ? $module.prev().find(selector.text)
   239              : $module.prev()
   240            ;
   241            $menu   = $module.children(selector.menu);
   242            $item   = $menu.find(selector.item);
   243          },
   244  
   245          toggle: function() {
   246            module.verbose('Toggling menu visibility');
   247            if( !module.is.active() ) {
   248              module.show();
   249            }
   250            else {
   251              module.hide();
   252            }
   253          },
   254  
   255          show: function(callback) {
   256            callback = $.isFunction(callback)
   257              ? callback
   258              : function(){}
   259            ;
   260            if( module.is.searchSelection() && module.is.allFiltered() ) {
   261              return;
   262            }
   263            if( module.can.show() && !module.is.active() ) {
   264              module.debug('Showing dropdown');
   265              module.animate.show(function() {
   266                if( module.can.click() ) {
   267                  module.bind.intent();
   268                }
   269                module.set.visible();
   270                callback.call(element);
   271              });
   272              settings.onShow.call(element);
   273            }
   274          },
   275  
   276          hide: function(callback) {
   277            callback = $.isFunction(callback)
   278              ? callback
   279              : function(){}
   280            ;
   281            if( module.is.active() ) {
   282              module.debug('Hiding dropdown');
   283              module.animate.hide(function() {
   284                module.remove.visible();
   285                callback.call(element);
   286              });
   287              settings.onHide.call(element);
   288            }
   289          },
   290  
   291          hideOthers: function() {
   292            module.verbose('Finding other dropdowns to hide');
   293            $allModules
   294              .not($module)
   295                .has(selector.menu + ':visible:not(.' + className.animating + ')')
   296                  .dropdown('hide')
   297            ;
   298          },
   299  
   300          hideSubMenus: function() {
   301            var
   302              $subMenus = $menu.find(selector.menu)
   303            ;
   304            $subMenus.transition('hide');
   305          },
   306  
   307          bind: {
   308            keyboardEvents: function() {
   309              module.debug('Binding keyboard events');
   310              $module
   311                .on('keydown' + eventNamespace, module.event.keydown)
   312              ;
   313              if( module.is.searchable() ) {
   314                $module
   315                  .on(module.get.inputEvent(), selector.search, module.event.input)
   316                ;
   317              }
   318            },
   319            touchEvents: function() {
   320              module.debug('Touch device detected binding additional touch events');
   321              if( module.is.searchSelection() ) {
   322                // do nothing special yet
   323              }
   324              else {
   325                $module
   326                  .on('touchstart' + eventNamespace, module.event.test.toggle)
   327                ;
   328              }
   329              $menu
   330                .on('touchstart' + eventNamespace, selector.item, module.event.item.mouseenter)
   331              ;
   332            },
   333            mouseEvents: function() {
   334              module.verbose('Mouse detected binding mouse events');
   335              if( module.is.searchSelection() ) {
   336                $module
   337                  .on('mousedown' + eventNamespace, selector.menu, module.event.menu.activate)
   338                  .on('mouseup'   + eventNamespace, selector.menu, module.event.menu.deactivate)
   339                  .on('click'     + eventNamespace, selector.search, module.show)
   340                  .on('focus'     + eventNamespace, selector.search, module.event.searchFocus)
   341                  .on('blur'      + eventNamespace, selector.search, module.event.searchBlur)
   342                  .on('click'     + eventNamespace, selector.text, module.event.searchTextFocus)
   343                ;
   344              }
   345              else {
   346                if(settings.on == 'click') {
   347                  $module
   348                    .on('click' + eventNamespace, module.event.test.toggle)
   349                  ;
   350                }
   351                else if(settings.on == 'hover') {
   352                  $module
   353                    .on('mouseenter' + eventNamespace, module.delay.show)
   354                    .on('mouseleave' + eventNamespace, module.delay.hide)
   355                  ;
   356                }
   357                else {
   358                  $module
   359                    .on(settings.on + eventNamespace, module.toggle)
   360                  ;
   361                }
   362                $module
   363                  .on('mousedown' + eventNamespace, module.event.mousedown)
   364                  .on('mouseup'   + eventNamespace, module.event.mouseup)
   365                  .on('focus'     + eventNamespace, module.event.focus)
   366                  .on('blur'      + eventNamespace, module.event.blur)
   367                ;
   368              }
   369              $menu
   370                .on('mouseenter' + eventNamespace, selector.item, module.event.item.mouseenter)
   371                .on('mouseleave' + eventNamespace, selector.item, module.event.item.mouseleave)
   372                .on('click'      + eventNamespace, selector.item, module.event.item.click)
   373              ;
   374            },
   375            intent: function() {
   376              module.verbose('Binding hide intent event to document');
   377              if(hasTouch) {
   378                $document
   379                  .on('touchstart' + elementNamespace, module.event.test.touch)
   380                  .on('touchmove'  + elementNamespace, module.event.test.touch)
   381                ;
   382              }
   383              $document
   384                .on('click' + elementNamespace, module.event.test.hide)
   385              ;
   386            }
   387          },
   388  
   389          unbind: {
   390            intent: function() {
   391              module.verbose('Removing hide intent event from document');
   392              if(hasTouch) {
   393                $document
   394                  .off('touchstart' + elementNamespace)
   395                  .off('touchmove' + elementNamespace)
   396                ;
   397              }
   398              $document
   399                .off('click' + elementNamespace)
   400              ;
   401            }
   402          },
   403  
   404          filter: function(searchTerm) {
   405            var
   406              $results       = $(),
   407              escapedTerm    = module.escape.regExp(searchTerm),
   408              exactRegExp    = new RegExp('^' + escapedTerm, 'igm'),
   409              fullTextRegExp = new RegExp(escapedTerm, 'ig'),
   410              allItemsFiltered
   411            ;
   412            module.verbose('Searching for matching values');
   413            $item
   414              .each(function(){
   415                var
   416                  $choice = $(this),
   417                  text    = String(module.get.choiceText($choice, false)),
   418                  value   = String(module.get.choiceValue($choice, text))
   419                ;
   420                if( text.match(exactRegExp) || value.match(exactRegExp) ) {
   421                  $results = $results.add($choice);
   422                }
   423                else if(settings.fullTextSearch) {
   424                  if( text.match(fullTextRegExp) || value.match(fullTextRegExp) ) {
   425                    $results = $results.add($choice);
   426                  }
   427                }
   428              })
   429            ;
   430  
   431            module.debug('Setting filter', searchTerm);
   432            module.remove.filteredItem();
   433            $item
   434              .not($results)
   435              .addClass(className.filtered)
   436            ;
   437  
   438            module.verbose('Selecting first non-filtered element');
   439            module.remove.selectedItem();
   440            $item
   441              .not('.' + className.filtered)
   442                .eq(0)
   443                .addClass(className.selected)
   444            ;
   445            if( module.is.allFiltered() ) {
   446              module.debug('All items filtered, hiding dropdown', searchTerm);
   447              if(module.is.searchSelection()) {
   448                module.hide();
   449              }
   450              settings.onNoResults.call(element, searchTerm);
   451            }
   452          },
   453  
   454          focusSearch: function() {
   455            if( module.is.search() ) {
   456              $search
   457                .focus()
   458              ;
   459            }
   460          },
   461  
   462          forceSelection: function() {
   463            var
   464              $currentlySelected = $item.not(className.filtered).filter('.' + className.selected).eq(0),
   465              $activeItem        = $item.filter('.' + className.active).eq(0),
   466              $selectedItem      = ($currentlySelected.length > 0)
   467                ? $currentlySelected
   468                : $activeItem,
   469              hasSelected = ($selectedItem.size() > 0)
   470            ;
   471            if(hasSelected) {
   472              module.event.item.click.call($selectedItem);
   473              module.remove.filteredItem();
   474            }
   475            else {
   476              module.hide();
   477            }
   478          },
   479  
   480          event: {
   481            // prevents focus callback from occuring on mousedown
   482            mousedown: function() {
   483              activated = true;
   484            },
   485            mouseup: function() {
   486              activated = false;
   487            },
   488            focus: function() {
   489              if(!activated && module.is.hidden()) {
   490                module.show();
   491              }
   492            },
   493            blur: function(event) {
   494              var
   495                pageLostFocus = (document.activeElement === this)
   496              ;
   497              if(!activated && !pageLostFocus) {
   498                module.hide();
   499              }
   500            },
   501            searchFocus: function() {
   502              activated = true;
   503              module.show();
   504            },
   505            searchBlur: function(event) {
   506              var
   507                pageLostFocus = (document.activeElement === this)
   508              ;
   509              if(!itemActivated && !pageLostFocus) {
   510                if(settings.forceSelection) {
   511                  module.forceSelection();
   512                }
   513                else {
   514                  module.hide();
   515                }
   516              }
   517            },
   518            searchTextFocus: function(event) {
   519              activated = true;
   520              $search.focus();
   521            },
   522            input: function(event) {
   523              if(module.is.searchSelection()) {
   524                module.set.filtered();
   525              }
   526              clearTimeout(module.timer);
   527              module.timer = setTimeout(module.search, settings.delay.search);
   528            },
   529            keydown: function(event) {
   530              var
   531                $currentlySelected = $item.not(className.filtered).filter('.' + className.selected).eq(0),
   532                $activeItem        = $menu.children('.' + className.active).eq(0),
   533                $selectedItem      = ($currentlySelected.length > 0)
   534                  ? $currentlySelected
   535                  : $activeItem,
   536                $visibleItems = ($selectedItem.length > 0)
   537                  ? $selectedItem.siblings(':not(.' + className.filtered +')').andSelf()
   538                  : $menu.children(':not(.' + className.filtered +')'),
   539                $subMenu      = $selectedItem.children(selector.menu),
   540                $parentMenu   = $selectedItem.closest(selector.menu),
   541                isSubMenuItem = $parentMenu[0] !== $menu[0],
   542                inVisibleMenu = $parentMenu.is(':visible'),
   543                pressedKey    = event.which,
   544                keys          = {
   545                  enter      : 13,
   546                  escape     : 27,
   547                  leftArrow  : 37,
   548                  upArrow    : 38,
   549                  rightArrow : 39,
   550                  downArrow  : 40
   551                },
   552                hasSubMenu       = ($subMenu.length> 0),
   553                hasSelectedItem  = ($selectedItem.length > 0),
   554                lastVisibleIndex = ($visibleItems.size() - 1),
   555                $nextItem,
   556                newIndex
   557              ;
   558              // visible menu keyboard shortcuts
   559              if(module.is.visible()) {
   560                // enter (select or sub-menu)
   561                if(pressedKey == keys.enter && hasSelectedItem) {
   562                  if(hasSubMenu && !settings.allowCategorySelection) {
   563                    module.verbose('Pressed enter on unselectable category, opening sub menu');
   564                    pressedKey = keys.rightArrow;
   565                  }
   566                  else {
   567                    module.verbose('Enter key pressed, choosing selected item');
   568                    module.event.item.click.call($selectedItem, event);
   569                  }
   570                }
   571                // left arrow (hide sub-menu)
   572                if(pressedKey == keys.leftArrow) {
   573                  if(isSubMenuItem) {
   574                    module.verbose('Left key pressed, closing sub-menu');
   575                    module.animate.hide(false,  $parentMenu);
   576                    $selectedItem
   577                      .removeClass(className.selected)
   578                    ;
   579                    $parentMenu
   580                      .closest(selector.item)
   581                        .addClass(className.selected)
   582                    ;
   583                  }
   584                  event.preventDefault();
   585                }
   586                // right arrow (show sub-menu)
   587                if(pressedKey == keys.rightArrow) {
   588                  if(hasSubMenu) {
   589                    module.verbose('Right key pressed, opening sub-menu');
   590                    module.animate.show(false,  $subMenu);
   591                    $selectedItem
   592                      .removeClass(className.selected)
   593                    ;
   594                    $subMenu
   595                      .find(selector.item).eq(0)
   596                        .addClass(className.selected)
   597                    ;
   598                  }
   599                  event.preventDefault();
   600                }
   601                // up arrow (traverse menu up)
   602                if(pressedKey == keys.upArrow) {
   603                  $nextItem = (hasSelectedItem && inVisibleMenu)
   604                    ? $selectedItem.prevAll(selector.item + ':not(.' + className.filtered + ')').eq(0)
   605                    : $item.eq(0)
   606                  ;
   607                  if($visibleItems.index( $nextItem ) < 0) {
   608                    module.verbose('Up key pressed but reached top of current menu');
   609                    return;
   610                  }
   611                  else {
   612                    module.verbose('Up key pressed, changing active item');
   613                    $selectedItem
   614                      .removeClass(className.selected)
   615                    ;
   616                    $nextItem
   617                      .addClass(className.selected)
   618                    ;
   619                    module.set.scrollPosition($nextItem);
   620                  }
   621                  event.preventDefault();
   622                }
   623                // down arrow (traverse menu down)
   624                if(pressedKey == keys.downArrow) {
   625                  $nextItem = (hasSelectedItem && inVisibleMenu)
   626                    ? $nextItem = $selectedItem.nextAll(selector.item + ':not(.' + className.filtered + ')').eq(0)
   627                    : $item.eq(0)
   628                  ;
   629                  if($nextItem.length === 0) {
   630                    module.verbose('Down key pressed but reached bottom of current menu');
   631                    return;
   632                  }
   633                  else {
   634                    module.verbose('Down key pressed, changing active item');
   635                    $item
   636                      .removeClass(className.selected)
   637                    ;
   638                    $nextItem
   639                      .addClass(className.selected)
   640                    ;
   641                    module.set.scrollPosition($nextItem);
   642                  }
   643                  event.preventDefault();
   644                }
   645              }
   646              else {
   647                // enter (open menu)
   648                if(pressedKey == keys.enter) {
   649                  module.verbose('Enter key pressed, showing dropdown');
   650                  module.show();
   651                }
   652                // escape (close menu)
   653                if(pressedKey == keys.escape) {
   654                  module.verbose('Escape key pressed, closing dropdown');
   655                  module.hide();
   656                }
   657                // down arrow (open menu)
   658                if(pressedKey == keys.downArrow) {
   659                  module.verbose('Down key pressed, showing dropdown');
   660                  module.show();
   661                }
   662              }
   663            },
   664            test: {
   665              toggle: function(event) {
   666                if( module.determine.eventInMenu(event, module.toggle) ) {
   667                  event.preventDefault();
   668                }
   669              },
   670              touch: function(event) {
   671                module.determine.eventInMenu(event, function() {
   672                  if(event.type == 'touchstart') {
   673                    module.timer = setTimeout(module.hide, settings.delay.touch);
   674                  }
   675                  else if(event.type == 'touchmove') {
   676                    clearTimeout(module.timer);
   677                  }
   678                });
   679                event.stopPropagation();
   680              },
   681              hide: function(event) {
   682                module.determine.eventInModule(event, module.hide);
   683              }
   684            },
   685  
   686            menu: {
   687              activate: function() {
   688                itemActivated = true;
   689              },
   690              deactivate: function() {
   691                itemActivated = false;
   692              }
   693            },
   694            item: {
   695              mouseenter: function(event) {
   696                var
   697                  $subMenu    = $(this).children(selector.menu),
   698                  $otherMenus = $(this).siblings(selector.item).children(selector.menu)
   699                ;
   700                if( $subMenu.length > 0 ) {
   701                  clearTimeout(module.itemTimer);
   702                  module.itemTimer = setTimeout(function() {
   703                    module.verbose('Showing sub-menu', $subMenu);
   704                    $.each($otherMenus, function() {
   705                      module.animate.hide(false, $(this));
   706                    });
   707                    module.animate.show(false,  $subMenu);
   708                  }, settings.delay.show);
   709                  event.preventDefault();
   710                }
   711              },
   712              mouseleave: function(event) {
   713                var
   714                  $subMenu = $(this).children(selector.menu)
   715                ;
   716                if($subMenu.length > 0) {
   717                  clearTimeout(module.itemTimer);
   718                  module.itemTimer = setTimeout(function() {
   719                    module.verbose('Hiding sub-menu', $subMenu);
   720                    module.animate.hide(false,  $subMenu);
   721                  }, settings.delay.hide);
   722                }
   723              },
   724              click: function (event) {
   725                var
   726                  $choice  = $(this),
   727                  $target  = (event)
   728                    ? $(event.target)
   729                    : $(''),
   730                  $subMenu = $choice.find(selector.menu),
   731                  text     = module.get.choiceText($choice),
   732                  value    = module.get.choiceValue($choice, text),
   733                  callback = function() {
   734                    module.remove.searchTerm();
   735                    module.determine.selectAction(text, value);
   736                  },
   737                  hasSubMenu     = ($subMenu.length > 0),
   738                  isBubbledEvent = ($subMenu.find($target).length > 0)
   739                ;
   740                if(!isBubbledEvent && (!hasSubMenu || settings.allowCategorySelection)) {
   741                  callback();
   742                }
   743              }
   744            },
   745            resetStyle: function() {
   746              $(this).removeAttr('style');
   747            }
   748          },
   749  
   750          determine: {
   751            selectAction: function(text, value) {
   752              module.verbose('Determining action', settings.action);
   753              if( $.isFunction( module.action[settings.action] ) ) {
   754                module.verbose('Triggering preset action', settings.action, text, value);
   755                module.action[ settings.action ](text, value);
   756              }
   757              else if( $.isFunction(settings.action) ) {
   758                module.verbose('Triggering user action', settings.action, text, value);
   759                settings.action(text, value);
   760              }
   761              else {
   762                module.error(error.action, settings.action);
   763              }
   764            },
   765            eventInModule: function(event, callback) {
   766              callback = $.isFunction(callback)
   767                ? callback
   768                : function(){}
   769              ;
   770              if( $(event.target).closest($module).length === 0 ) {
   771                module.verbose('Triggering event', callback);
   772                callback();
   773                return true;
   774              }
   775              else {
   776                module.verbose('Event occurred in dropdown, canceling callback');
   777                return false;
   778              }
   779            },
   780            eventInMenu: function(event, callback) {
   781              callback = $.isFunction(callback)
   782                ? callback
   783                : function(){}
   784              ;
   785              if( $(event.target).closest($menu).length === 0 ) {
   786                module.verbose('Triggering event', callback);
   787                callback();
   788                return true;
   789              }
   790              else {
   791                module.verbose('Event occurred in dropdown menu, canceling callback');
   792                return false;
   793              }
   794            }
   795          },
   796  
   797          action: {
   798  
   799            nothing: function() {},
   800  
   801            activate: function(text, value) {
   802              value = (value !== undefined)
   803                ? value
   804                : text
   805              ;
   806              module.set.selected(value);
   807              module.hide(function() {
   808                module.remove.filteredItem();
   809              });
   810            },
   811  
   812            select: function(text, value) {
   813              value = (value !== undefined)
   814                ? value
   815                : text
   816              ;
   817              module.set.selected(value);
   818              module.hide(function() {
   819                module.remove.filteredItem();
   820              });
   821            },
   822  
   823            combo: function(text, value) {
   824              value = (value !== undefined)
   825                ? value
   826                : text
   827              ;
   828              module.set.selected(value);
   829              module.hide(function() {
   830                module.remove.filteredItem();
   831              });
   832            },
   833  
   834            hide: function() {
   835              module.hide(function() {
   836                module.remove.filteredItem();
   837              });
   838            }
   839  
   840          },
   841  
   842          get: {
   843            id: function() {
   844              return id;
   845            },
   846            text: function() {
   847              return $text.text();
   848            },
   849            value: function() {
   850              return ($input.length > 0)
   851                ? $input.val()
   852                : $module.data(metadata.value)
   853              ;
   854            },
   855            choiceText: function($choice, preserveHTML) {
   856              preserveHTML = (preserveHTML !== undefined)
   857                ? preserveHTML
   858                : settings.preserveHTML
   859              ;
   860              if($choice !== undefined) {
   861                if($choice.find(selector.menu).length > 0) {
   862                  module.verbose('Retreiving text of element with sub-menu');
   863                  $choice = $choice.clone();
   864                  $choice.find(selector.menu).remove();
   865                  $choice.find(selector.menuIcon).remove();
   866                }
   867                return ($choice.data(metadata.text) !== undefined)
   868                  ? $choice.data(metadata.text)
   869                  : (preserveHTML)
   870                    ? $choice.html().trim()
   871                    : $choice.text().trim()
   872                ;
   873              }
   874            },
   875            choiceValue: function($choice, choiceText) {
   876              choiceText = choiceText || module.get.choiceText($choice);
   877              return ($choice.data(metadata.value) !== undefined)
   878                ? $choice.data(metadata.value)
   879                : (typeof choiceText === 'string')
   880                  ? choiceText.toLowerCase().trim()
   881                  : choiceText.trim()
   882              ;
   883            },
   884            inputEvent: function() {
   885              var
   886                input = $search[0]
   887              ;
   888              if(input) {
   889                return (input.oninput !== undefined)
   890                  ? 'input'
   891                  : (input.onpropertychange !== undefined)
   892                    ? 'propertychange'
   893                    : 'keyup'
   894                ;
   895              }
   896              return false;
   897            },
   898            selectValues: function() {
   899              var
   900                select = {}
   901              ;
   902              select.values = (settings.sortSelect)
   903                ? {} // properties will be sorted in object when re-accessed
   904                : [] // properties will keep original order in array
   905              ;
   906              $module
   907                .find('option')
   908                  .each(function() {
   909                    var
   910                      name  = $(this).html(),
   911                      value = ( $(this).attr('value') !== undefined )
   912                        ? $(this).attr('value')
   913                        : name
   914                    ;
   915                    if(value === '') {
   916                      select.placeholder = name;
   917                    }
   918                    else {
   919                      if(settings.sortSelect) {
   920                        select.values[value] = {
   921                          name  : name,
   922                          value : value
   923                        };
   924                      }
   925                      else {
   926                        select.values.push({
   927                          name: name,
   928                          value: value
   929                        });
   930                      }
   931                    }
   932                  })
   933              ;
   934              if(settings.sortSelect) {
   935                module.debug('Retrieved and sorted values from select', select);
   936              }
   937              else {
   938                module.debug('Retreived values from select', select);
   939              }
   940              return select;
   941            },
   942            activeItem: function() {
   943              return $item.filter('.'  + className.active);
   944            },
   945            item: function(value, strict) {
   946              var
   947                $selectedItem = false
   948              ;
   949              value = (value !== undefined)
   950                ? value
   951                : ( module.get.value() !== undefined)
   952                  ? module.get.value()
   953                  : module.get.text()
   954              ;
   955              strict = (value === '' || value === 0)
   956                ? true
   957                : strict || false
   958              ;
   959              if(value !== undefined) {
   960                $item
   961                  .each(function() {
   962                    var
   963                      $choice       = $(this),
   964                      optionText    = module.get.choiceText($choice),
   965                      optionValue   = module.get.choiceValue($choice, optionText)
   966                    ;
   967                    if(strict) {
   968                      module.verbose('Ambiguous dropdown value using strict type check', $choice, value);
   969                      if( optionValue === value ) {
   970                        $selectedItem = $(this);
   971                        return true;
   972                      }
   973                      else if( !$selectedItem && optionText === value ) {
   974                        $selectedItem = $(this);
   975                        return true;
   976                      }
   977                    }
   978                    else {
   979                      if( optionValue == value ) {
   980                        module.verbose('Found select item by value', optionValue, value);
   981                        $selectedItem = $(this);
   982                        return true;
   983                      }
   984                      else if( !$selectedItem && optionText == value ) {
   985                        module.verbose('Found select item by text', optionText, value);
   986                        $selectedItem = $(this);
   987                        return true;
   988                      }
   989                    }
   990                  })
   991                ;
   992              }
   993              else {
   994                value = module.get.text();
   995              }
   996              return $selectedItem || false;
   997            }
   998          },
   999  
  1000          restore: {
  1001            defaults: function() {
  1002              module.restore.defaultText();
  1003              module.restore.defaultValue();
  1004            },
  1005            defaultText: function() {
  1006              var
  1007                defaultText = $module.data(metadata.defaultText)
  1008              ;
  1009              module.debug('Restoring default text', defaultText);
  1010              module.set.text(defaultText);
  1011              $text.addClass(className.placeholder);
  1012            },
  1013            defaultValue: function() {
  1014              var
  1015                defaultValue = $module.data(metadata.defaultValue)
  1016              ;
  1017              if(defaultValue !== undefined) {
  1018                module.debug('Restoring default value', defaultValue);
  1019                if(defaultValue.length) {
  1020                  module.set.selected(defaultValue);
  1021                }
  1022                else {
  1023                  module.remove.activeItem();
  1024                  module.remove.selectedItem();
  1025                }
  1026              }
  1027            }
  1028          },
  1029  
  1030          save: {
  1031            defaults: function() {
  1032              module.save.defaultText();
  1033              module.save.placeholderText();
  1034              module.save.defaultValue();
  1035            },
  1036            defaultValue: function() {
  1037              $module.data(metadata.defaultValue, module.get.value() );
  1038            },
  1039            defaultText: function() {
  1040              $module.data(metadata.defaultText, $text.text() );
  1041            },
  1042            placeholderText: function() {
  1043              if($text.hasClass(className.placeholder)) {
  1044                $module.data(metadata.placeholderText, $text.text());
  1045              }
  1046            }
  1047          },
  1048  
  1049          clear: function() {
  1050            var
  1051              placeholderText = $module.data(metadata.placeholderText)
  1052            ;
  1053            module.set.text(placeholderText);
  1054            module.set.value('');
  1055            module.remove.activeItem();
  1056            module.remove.selectedItem();
  1057            $text.addClass(className.placeholder);
  1058          },
  1059  
  1060          set: {
  1061            filtered: function() {
  1062              var
  1063                searchValue    = $search.val(),
  1064                hasSearchValue = (typeof searchValue === 'string' && searchValue.length > 0)
  1065              ;
  1066              if(hasSearchValue) {
  1067                $text.addClass(className.filtered);
  1068              }
  1069              else {
  1070                $text.removeClass(className.filtered);
  1071              }
  1072            },
  1073            tabbable: function() {
  1074              if( module.is.searchable() ) {
  1075                module.debug('Searchable dropdown initialized');
  1076                $search
  1077                  .val('')
  1078                  .attr('tabindex', 0)
  1079                ;
  1080                $menu
  1081                  .attr('tabindex', '-1')
  1082                ;
  1083              }
  1084              else {
  1085                module.debug('Simple selection dropdown initialized');
  1086                if(!$module.attr('tabindex') ) {
  1087                  $module
  1088                    .attr('tabindex', 0)
  1089                  ;
  1090                  $menu
  1091                    .attr('tabindex', '-1')
  1092                  ;
  1093                }
  1094              }
  1095            },
  1096            scrollPosition: function($item, forceScroll) {
  1097              var
  1098                edgeTolerance = 5,
  1099                hasActive,
  1100                offset,
  1101                itemHeight,
  1102                itemOffset,
  1103                menuOffset,
  1104                menuScroll,
  1105                menuHeight,
  1106                abovePage,
  1107                belowPage
  1108              ;
  1109  
  1110              $item       = $item || module.get.activeItem();
  1111              hasActive   = ($item && $item.length > 0);
  1112              forceScroll = (forceScroll !== undefined)
  1113                ? forceScroll
  1114                : false
  1115              ;
  1116  
  1117              if($item && hasActive) {
  1118  
  1119                if(!$menu.hasClass(className.visible)) {
  1120                  $menu.addClass(className.loading);
  1121                }
  1122  
  1123                menuHeight = $menu.height();
  1124                itemHeight = $item.height();
  1125                menuScroll = $menu.scrollTop();
  1126                menuOffset = $menu.offset().top;
  1127                itemOffset = $item.offset().top;
  1128                offset     = menuScroll - menuOffset + itemOffset;
  1129                belowPage  = menuScroll + menuHeight < (offset + edgeTolerance);
  1130                abovePage  = ((offset - edgeTolerance) < menuScroll);
  1131                module.debug('Scrolling to active item', offset);
  1132                if(abovePage || belowPage || forceScroll) {
  1133                  $menu
  1134                    .scrollTop(offset)
  1135                    .removeClass(className.loading)
  1136                  ;
  1137                }
  1138              }
  1139            },
  1140            text: function(text) {
  1141              if(settings.action == 'combo') {
  1142                module.debug('Changing combo button text', text, $combo);
  1143                if(settings.preserveHTML) {
  1144                  $combo.html(text);
  1145                }
  1146                else {
  1147                  $combo.text(text);
  1148                }
  1149              }
  1150              else if(settings.action !== 'select') {
  1151                module.debug('Changing text', text, $text);
  1152                $text
  1153                  .removeClass(className.filtered)
  1154                  .removeClass(className.placeholder)
  1155                ;
  1156                if(settings.preserveHTML) {
  1157                  $text.html(text);
  1158                }
  1159                else {
  1160                  $text.text(text);
  1161                }
  1162              }
  1163            },
  1164            value: function(value) {
  1165              module.debug('Adding selected value to hidden input', value, $input);
  1166              if($input.length > 0) {
  1167                $input
  1168                  .val(value)
  1169                  .trigger('change')
  1170                ;
  1171              }
  1172              else {
  1173                $module.data(metadata.value, value);
  1174              }
  1175            },
  1176            active: function() {
  1177              $module
  1178                .addClass(className.active)
  1179              ;
  1180            },
  1181            visible: function() {
  1182              $module.addClass(className.visible);
  1183            },
  1184            selected: function(value) {
  1185              var
  1186                $selectedItem = module.get.item(value),
  1187                selectedText,
  1188                selectedValue
  1189              ;
  1190              if($selectedItem && !$selectedItem.hasClass(className.active) ) {
  1191                module.debug('Setting selected menu item to', $selectedItem);
  1192                module.remove.activeItem();
  1193                module.remove.selectedItem();
  1194                $selectedItem
  1195                  .addClass(className.active)
  1196                  .addClass(className.selected)
  1197                ;
  1198                selectedText  = module.get.choiceText($selectedItem);
  1199                selectedValue = module.get.choiceValue($selectedItem, selectedText);
  1200                module.set.text(selectedText);
  1201                module.set.value(selectedValue);
  1202                settings.onChange.call(element, value, selectedText, $selectedItem);
  1203              }
  1204            }
  1205          },
  1206  
  1207          remove: {
  1208            active: function() {
  1209              $module.removeClass(className.active);
  1210            },
  1211            visible: function() {
  1212              $module.removeClass(className.visible);
  1213            },
  1214            activeItem: function() {
  1215              $item.removeClass(className.active);
  1216            },
  1217            filteredItem: function() {
  1218              $item.removeClass(className.filtered);
  1219            },
  1220            searchTerm: function() {
  1221              $search.val('');
  1222            },
  1223            selectedItem: function() {
  1224              $item.removeClass(className.selected);
  1225            },
  1226            tabbable: function() {
  1227              if( module.is.searchable() ) {
  1228                module.debug('Searchable dropdown initialized');
  1229                $search
  1230                  .attr('tabindex', '-1')
  1231                ;
  1232                $menu
  1233                  .attr('tabindex', '-1')
  1234                ;
  1235              }
  1236              else {
  1237                module.debug('Simple selection dropdown initialized');
  1238                $module
  1239                  .attr('tabindex', '-1')
  1240                ;
  1241                $menu
  1242                  .attr('tabindex', '-1')
  1243                ;
  1244              }
  1245            }
  1246          },
  1247  
  1248          is: {
  1249            active: function() {
  1250              return $module.hasClass(className.active);
  1251            },
  1252            alreadySetup: function() {
  1253              return ($module.is('select') && $module.parent(selector.dropdown).length > 0);
  1254            },
  1255            animating: function($subMenu) {
  1256              return ($subMenu)
  1257                ? $subMenu.is(':animated') || $subMenu.transition && $subMenu.transition('is animating')
  1258                : $menu.is(':animated') || $menu.transition && $menu.transition('is animating')
  1259              ;
  1260            },
  1261            allFiltered: function() {
  1262              return ($item.filter('.' + className.filtered).length === $item.length);
  1263            },
  1264            hidden: function($subMenu) {
  1265              return ($subMenu)
  1266                ? $subMenu.is(':hidden')
  1267                : $menu.is(':hidden')
  1268              ;
  1269            },
  1270            selectMutation: function(mutations) {
  1271              var
  1272                selectChanged = false
  1273              ;
  1274              $.each(mutations, function(index, mutation) {
  1275                if(mutation.target && $(mutation.target).is('select')) {
  1276                  selectChanged = true;
  1277                  return true;
  1278                }
  1279              });
  1280              return selectChanged;
  1281            },
  1282            search: function() {
  1283              return $module.hasClass(className.search);
  1284            },
  1285            searchable: function() {
  1286              return ($search.length > 0);
  1287            },
  1288            searchSelection: function() {
  1289              return ( module.is.searchable() && $search.parent().is($module) );
  1290            },
  1291            selection: function() {
  1292              return $module.hasClass(className.selection);
  1293            },
  1294            upward: function() {
  1295              return $module.hasClass(className.upward);
  1296            },
  1297            visible: function($subMenu) {
  1298              return ($subMenu)
  1299                ? $subMenu.is(':visible')
  1300                : $menu.is(':visible')
  1301              ;
  1302            }
  1303          },
  1304  
  1305          can: {
  1306            click: function() {
  1307              return (hasTouch || settings.on == 'click');
  1308            },
  1309            show: function() {
  1310              return !$module.hasClass(className.disabled);
  1311            }
  1312          },
  1313  
  1314          animate: {
  1315            show: function(callback, $subMenu) {
  1316              var
  1317                $currentMenu = $subMenu || $menu,
  1318                start = ($subMenu)
  1319                  ? function() {}
  1320                  : function() {
  1321                    module.hideSubMenus();
  1322                    module.hideOthers();
  1323                    module.set.active();
  1324                  }
  1325              ;
  1326              callback = $.isFunction(callback)
  1327                ? callback
  1328                : function(){}
  1329              ;
  1330              module.set.scrollPosition(module.get.activeItem(), true);
  1331              module.verbose('Doing menu show animation', $currentMenu);
  1332              if( module.is.hidden($currentMenu) || module.is.animating($currentMenu) ) {
  1333  
  1334                if(settings.transition == 'auto') {
  1335                  settings.transition = module.is.upward()
  1336                    ? 'slide up'
  1337                    : 'slide down'
  1338                  ;
  1339                  module.verbose('Automatically determining animation based on animation direction', settings.transition);
  1340                }
  1341                if(settings.transition == 'none') {
  1342                  callback.call(element);
  1343                }
  1344                else if($.fn.transition !== undefined && $module.transition('is supported')) {
  1345                  $currentMenu
  1346                    .transition({
  1347                      animation  : settings.transition + ' in',
  1348                      debug      : settings.debug,
  1349                      verbose    : settings.verbose,
  1350                      duration   : settings.duration,
  1351                      queue      : true,
  1352                      onStart    : start,
  1353                      onComplete : function() {
  1354                        callback.call(element);
  1355                      }
  1356                    })
  1357                  ;
  1358                }
  1359                else if(settings.transition == 'slide down') {
  1360                  start();
  1361                  $currentMenu
  1362                    .hide()
  1363                    .clearQueue()
  1364                    .children()
  1365                      .clearQueue()
  1366                      .css('opacity', 0)
  1367                      .delay(50)
  1368                      .animate({
  1369                        opacity : 1
  1370                      }, settings.duration, 'easeOutQuad', module.event.resetStyle)
  1371                      .end()
  1372                    .slideDown(100, 'easeOutQuad', function() {
  1373                      module.event.resetStyle.call(this);
  1374                      callback.call(element);
  1375                    })
  1376                  ;
  1377                }
  1378                else if(settings.transition == 'fade') {
  1379                  start();
  1380                  $currentMenu
  1381                    .hide()
  1382                    .clearQueue()
  1383                    .fadeIn(settings.duration, function() {
  1384                      module.event.resetStyle.call(this);
  1385                      callback.call(element);
  1386                    })
  1387                  ;
  1388                }
  1389                else {
  1390                  module.error(error.transition, settings.transition);
  1391                }
  1392              }
  1393            },
  1394            hide: function(callback, $subMenu) {
  1395              var
  1396                $currentMenu = $subMenu || $menu,
  1397                duration = ($subMenu)
  1398                  ? (settings.duration * 0.9)
  1399                  : settings.duration,
  1400                start = ($subMenu)
  1401                  ? function() {}
  1402                  : function() {
  1403                    if( module.can.click() ) {
  1404                      module.unbind.intent();
  1405                    }
  1406                    module.focusSearch();
  1407                    module.remove.active();
  1408                  }
  1409              ;
  1410              callback = $.isFunction(callback)
  1411                ? callback
  1412                : function(){}
  1413              ;
  1414              if( module.is.visible($currentMenu) || module.is.animating($currentMenu) ) {
  1415                module.verbose('Doing menu hide animation', $currentMenu);
  1416  
  1417                if(settings.transition == 'auto') {
  1418                  settings.transition = module.is.upward()
  1419                    ? 'slide up'
  1420                    : 'slide down'
  1421                  ;
  1422                }
  1423  
  1424                $input.trigger('blur');
  1425  
  1426                if(settings.transition == 'none') {
  1427                  callback.call(element);
  1428                }
  1429                else if($.fn.transition !== undefined && $module.transition('is supported')) {
  1430                  $currentMenu
  1431                    .transition({
  1432                      animation  : settings.transition + ' out',
  1433                      duration   : settings.duration,
  1434                      debug      : settings.debug,
  1435                      verbose    : settings.verbose,
  1436                      queue      : true,
  1437                      onStart    : start,
  1438                      onComplete : function() {
  1439                        callback.call(element);
  1440                      }
  1441                    })
  1442                  ;
  1443                }
  1444                else if(settings.transition == 'slide down') {
  1445                  start();
  1446                  $currentMenu
  1447                    .show()
  1448                    .clearQueue()
  1449                    .children()
  1450                      .clearQueue()
  1451                      .css('opacity', 1)
  1452                      .animate({
  1453                        opacity : 0
  1454                      }, 100, 'easeOutQuad', module.event.resetStyle)
  1455                      .end()
  1456                    .delay(50)
  1457                    .slideUp(100, 'easeOutQuad', function() {
  1458                      module.event.resetStyle.call(this);
  1459                      callback.call(element);
  1460                    })
  1461                  ;
  1462                }
  1463                else if(settings.transition == 'fade') {
  1464                  start();
  1465                  $currentMenu
  1466                    .show()
  1467                    .clearQueue()
  1468                    .fadeOut(150, function() {
  1469                      module.event.resetStyle.call(this);
  1470                      callback.call(element);
  1471                    })
  1472                  ;
  1473                }
  1474                else {
  1475                  module.error(error.transition);
  1476                }
  1477              }
  1478            }
  1479          },
  1480  
  1481          delay: {
  1482            show: function() {
  1483              module.verbose('Delaying show event to ensure user intent');
  1484              clearTimeout(module.timer);
  1485              module.timer = setTimeout(module.show, settings.delay.show);
  1486            },
  1487            hide: function() {
  1488              module.verbose('Delaying hide event to ensure user intent');
  1489              clearTimeout(module.timer);
  1490              module.timer = setTimeout(module.hide, settings.delay.hide);
  1491            }
  1492          },
  1493  
  1494          escape: {
  1495            regExp: function(text) {
  1496              text =  String(text);
  1497              return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
  1498            }
  1499          },
  1500  
  1501          setting: function(name, value) {
  1502            module.debug('Changing setting', name, value);
  1503            if( $.isPlainObject(name) ) {
  1504              $.extend(true, settings, name);
  1505            }
  1506            else if(value !== undefined) {
  1507              settings[name] = value;
  1508            }
  1509            else {
  1510              return settings[name];
  1511            }
  1512          },
  1513          internal: function(name, value) {
  1514            if( $.isPlainObject(name) ) {
  1515              $.extend(true, module, name);
  1516            }
  1517            else if(value !== undefined) {
  1518              module[name] = value;
  1519            }
  1520            else {
  1521              return module[name];
  1522            }
  1523          },
  1524          debug: function() {
  1525            if(settings.debug) {
  1526              if(settings.performance) {
  1527                module.performance.log(arguments);
  1528              }
  1529              else {
  1530                module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  1531                module.debug.apply(console, arguments);
  1532              }
  1533            }
  1534          },
  1535          verbose: function() {
  1536            if(settings.verbose && settings.debug) {
  1537              if(settings.performance) {
  1538                module.performance.log(arguments);
  1539              }
  1540              else {
  1541                module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  1542                module.verbose.apply(console, arguments);
  1543              }
  1544            }
  1545          },
  1546          error: function() {
  1547            module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  1548            module.error.apply(console, arguments);
  1549          },
  1550          performance: {
  1551            log: function(message) {
  1552              var
  1553                currentTime,
  1554                executionTime,
  1555                previousTime
  1556              ;
  1557              if(settings.performance) {
  1558                currentTime   = new Date().getTime();
  1559                previousTime  = time || currentTime;
  1560                executionTime = currentTime - previousTime;
  1561                time          = currentTime;
  1562                performance.push({
  1563                  'Name'           : message[0],
  1564                  'Arguments'      : [].slice.call(message, 1) || '',
  1565                  'Element'        : element,
  1566                  'Execution Time' : executionTime
  1567                });
  1568              }
  1569              clearTimeout(module.performance.timer);
  1570              module.performance.timer = setTimeout(module.performance.display, 500);
  1571            },
  1572            display: function() {
  1573              var
  1574                title = settings.name + ':',
  1575                totalTime = 0
  1576              ;
  1577              time = false;
  1578              clearTimeout(module.performance.timer);
  1579              $.each(performance, function(index, data) {
  1580                totalTime += data['Execution Time'];
  1581              });
  1582              title += ' ' + totalTime + 'ms';
  1583              if(moduleSelector) {
  1584                title += ' \'' + moduleSelector + '\'';
  1585              }
  1586              if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  1587                console.groupCollapsed(title);
  1588                if(console.table) {
  1589                  console.table(performance);
  1590                }
  1591                else {
  1592                  $.each(performance, function(index, data) {
  1593                    console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  1594                  });
  1595                }
  1596                console.groupEnd();
  1597              }
  1598              performance = [];
  1599            }
  1600          },
  1601          invoke: function(query, passedArguments, context) {
  1602            var
  1603              object = instance,
  1604              maxDepth,
  1605              found,
  1606              response
  1607            ;
  1608            passedArguments = passedArguments || queryArguments;
  1609            context         = element         || context;
  1610            if(typeof query == 'string' && object !== undefined) {
  1611              query    = query.split(/[\. ]/);
  1612              maxDepth = query.length - 1;
  1613              $.each(query, function(depth, value) {
  1614                var camelCaseValue = (depth != maxDepth)
  1615                  ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  1616                  : query
  1617                ;
  1618                if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  1619                  object = object[camelCaseValue];
  1620                }
  1621                else if( object[camelCaseValue] !== undefined ) {
  1622                  found = object[camelCaseValue];
  1623                  return false;
  1624                }
  1625                else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  1626                  object = object[value];
  1627                }
  1628                else if( object[value] !== undefined ) {
  1629                  found = object[value];
  1630                  return false;
  1631                }
  1632                else {
  1633                  module.error(error.method, query);
  1634                  return false;
  1635                }
  1636              });
  1637            }
  1638            if ( $.isFunction( found ) ) {
  1639              response = found.apply(context, passedArguments);
  1640            }
  1641            else if(found !== undefined) {
  1642              response = found;
  1643            }
  1644            if($.isArray(returnedValue)) {
  1645              returnedValue.push(response);
  1646            }
  1647            else if(returnedValue !== undefined) {
  1648              returnedValue = [returnedValue, response];
  1649            }
  1650            else if(response !== undefined) {
  1651              returnedValue = response;
  1652            }
  1653            return found;
  1654          }
  1655        };
  1656  
  1657        if(methodInvoked) {
  1658          if(instance === undefined) {
  1659            module.initialize();
  1660          }
  1661          module.invoke(query);
  1662        }
  1663        else {
  1664          if(instance !== undefined) {
  1665            instance.invoke('destroy');
  1666          }
  1667          module.initialize();
  1668        }
  1669      })
  1670    ;
  1671    return (returnedValue !== undefined)
  1672      ? returnedValue
  1673      : $allModules
  1674    ;
  1675  };
  1676  
  1677  $.fn.dropdown.settings = {
  1678  
  1679    debug                  : false,
  1680    verbose                : true,
  1681    performance            : true,
  1682  
  1683    on                     : 'click',
  1684    action                 : 'activate',
  1685  
  1686    allowTab               : true,
  1687    fullTextSearch         : false,
  1688    preserveHTML           : true,
  1689    sortSelect             : false,
  1690  
  1691    allowCategorySelection : false,
  1692  
  1693    delay                  : {
  1694      hide   : 300,
  1695      show   : 200,
  1696      search : 50,
  1697      touch  : 50
  1698    },
  1699  
  1700    forceSelection: true,
  1701  
  1702    transition : 'auto',
  1703    duration   : 250,
  1704  
  1705    /* Callbacks */
  1706    onNoResults : function(searchTerm){},
  1707    onChange    : function(value, text){},
  1708    onShow      : function(){},
  1709    onHide      : function(){},
  1710  
  1711    /* Component */
  1712  
  1713    name           : 'Dropdown',
  1714    namespace      : 'dropdown',
  1715  
  1716    error   : {
  1717      action       : 'You called a dropdown action that was not defined',
  1718      alreadySetup : 'Once a select has been initialized behaviors must be called on the created ui dropdown',
  1719      method       : 'The method you called is not defined.',
  1720      transition   : 'The requested transition was not found'
  1721    },
  1722  
  1723    metadata: {
  1724      defaultText     : 'defaultText',
  1725      defaultValue    : 'defaultValue',
  1726      placeholderText : 'placeholderText',
  1727      text            : 'text',
  1728      value           : 'value'
  1729    },
  1730  
  1731    selector : {
  1732      dropdown : '.ui.dropdown',
  1733      input    : '> input[type="hidden"], > select',
  1734      item     : '.item',
  1735      menu     : '.menu',
  1736      menuIcon : '.dropdown.icon',
  1737      search   : '> input.search, .menu > .search > input, .menu > input.search',
  1738      text     : '> .text:not(.icon)'
  1739    },
  1740  
  1741    className : {
  1742      active      : 'active',
  1743      animating   : 'animating',
  1744      disabled    : 'disabled',
  1745      dropdown    : 'ui dropdown',
  1746      filtered    : 'filtered',
  1747      loading     : 'loading',
  1748      menu        : 'menu',
  1749      placeholder : 'default',
  1750      search      : 'search',
  1751      selected    : 'selected',
  1752      selection   : 'selection',
  1753      upward      : 'upward',
  1754      visible     : 'visible'
  1755    }
  1756  
  1757  };
  1758  
  1759  /* Templates */
  1760  $.fn.dropdown.settings.templates = {
  1761    menu: function(select) {
  1762      var
  1763        placeholder = select.placeholder || false,
  1764        values      = select.values || {},
  1765        html        = ''
  1766      ;
  1767      $.each(select.values, function(index, option) {
  1768        html += '<div class="item" data-value="' + option.value + '">' + option.name + '</div>';
  1769      });
  1770      return html;
  1771    },
  1772    dropdown: function(select) {
  1773      var
  1774        placeholder = select.placeholder || false,
  1775        values      = select.values || {},
  1776        html        = ''
  1777      ;
  1778      html +=  '<i class="dropdown icon"></i>';
  1779      if(select.placeholder) {
  1780        html += '<div class="default text">' + placeholder + '</div>';
  1781      }
  1782      else {
  1783        html += '<div class="text"></div>';
  1784      }
  1785      html += '<div class="menu">';
  1786      $.each(select.values, function(index, option) {
  1787        html += '<div class="item" data-value="' + option.value + '">' + option.name + '</div>';
  1788      });
  1789      html += '</div>';
  1790      return html;
  1791    }
  1792  };
  1793  
  1794  
  1795  /* Dependencies */
  1796  $.extend( $.easing, {
  1797    easeOutQuad: function (x, t, b, c, d) {
  1798      return -c *(t/=d)*(t-2) + b;
  1799    },
  1800  });
  1801  
  1802  
  1803  })( jQuery, window , document );