github.com/fanux/shipyard@v0.0.0-20161009071005-6515ce223235/controller/static/semantic/dist/components/tab.js (about)

     1  /*!
     2   * # Semantic UI x.x - Tab
     3   * http://github.com/semantic-org/semantic-ui/
     4   *
     5   *
     6   * Copyright 2014 Contributorss
     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.tab = function(parameters) {
    17  
    18    var
    19      // use window context if none specified
    20      $allModules     = $.isFunction(this)
    21          ? $(window)
    22          : $(this),
    23  
    24      settings        = ( $.isPlainObject(parameters) )
    25        ? $.extend(true, {}, $.fn.tab.settings, parameters)
    26        : $.extend({}, $.fn.tab.settings),
    27  
    28      moduleSelector  = $allModules.selector || '',
    29      time            = new Date().getTime(),
    30      performance     = [],
    31  
    32      query           = arguments[0],
    33      methodInvoked   = (typeof query == 'string'),
    34      queryArguments  = [].slice.call(arguments, 1),
    35  
    36      module,
    37      returnedValue
    38    ;
    39  
    40    $allModules
    41      .each(function() {
    42        var
    43  
    44          className          = settings.className,
    45          metadata           = settings.metadata,
    46          selector           = settings.selector,
    47          error              = settings.error,
    48  
    49          eventNamespace     = '.' + settings.namespace,
    50          moduleNamespace    = 'module-' + settings.namespace,
    51  
    52          $module            = $(this),
    53  
    54          cache              = {},
    55          firstLoad          = true,
    56          recursionDepth     = 0,
    57  
    58          $context,
    59          $tabs,
    60          activeTabPath,
    61          parameterArray,
    62          historyEvent,
    63  
    64          element         = this,
    65          instance        = $module.data(moduleNamespace)
    66        ;
    67  
    68        module = {
    69  
    70          initialize: function() {
    71            module.debug('Initializing tab menu item', $module);
    72  
    73            module.determineTabs();
    74            module.debug('Determining tabs', settings.context, $tabs);
    75  
    76            // set up automatic routing
    77            if(settings.auto) {
    78              module.set.auto();
    79            }
    80  
    81            // attach events if navigation wasn't set to window
    82            if( !$.isWindow( element ) ) {
    83              module.debug('Attaching tab activation events to element', $module);
    84              $module
    85                .on('click' + eventNamespace, module.event.click)
    86              ;
    87            }
    88            module.instantiate();
    89          },
    90  
    91          determineTabs: function() {
    92            var
    93              $reference
    94            ;
    95  
    96            // determine tab context
    97            if(settings.context === 'parent') {
    98              if($module.closest(selector.ui).length > 0) {
    99                $reference = $module.closest(selector.ui);
   100                module.verbose('Using closest UI element for determining parent', $reference);
   101              }
   102              else {
   103                $reference = $module;
   104              }
   105              $context = $reference.parent();
   106              module.verbose('Determined parent element for creating context', $context);
   107            }
   108            else if(settings.context) {
   109              $context = $(settings.context);
   110              module.verbose('Using selector for tab context', settings.context, $context);
   111            }
   112            else {
   113              $context = $('body');
   114            }
   115  
   116            // find tabs
   117            if(settings.childrenOnly) {
   118              $tabs = $context.children(selector.tabs);
   119              module.debug('Searching tab context children for tabs', $context, $tabs);
   120            }
   121            else {
   122              $tabs = $context.find(selector.tabs);
   123              module.debug('Searching tab context for tabs', $context, $tabs);
   124            }
   125          },
   126  
   127          initializeHistory: function() {
   128            if(settings.history) {
   129              module.debug('Initializing page state');
   130              if( $.address === undefined ) {
   131                module.error(error.state);
   132                return false;
   133              }
   134              else {
   135                if(settings.historyType == 'state') {
   136                  module.debug('Using HTML5 to manage state');
   137                  if(settings.path !== false) {
   138                    $.address
   139                      .history(true)
   140                      .state(settings.path)
   141                    ;
   142                  }
   143                  else {
   144                    module.error(error.path);
   145                    return false;
   146                  }
   147                }
   148                $.address
   149                  .bind('change', module.event.history.change)
   150                ;
   151              }
   152            }
   153          },
   154  
   155          instantiate: function () {
   156            module.verbose('Storing instance of module', module);
   157            instance = module;
   158            $module
   159              .data(moduleNamespace, module)
   160            ;
   161          },
   162  
   163          destroy: function() {
   164            module.debug('Destroying tabs', $module);
   165            $module
   166              .removeData(moduleNamespace)
   167              .off(eventNamespace)
   168            ;
   169          },
   170  
   171          event: {
   172            click: function(event) {
   173              var
   174                tabPath = $(this).data(metadata.tab)
   175              ;
   176              if(tabPath !== undefined) {
   177                if(settings.history) {
   178                  module.verbose('Updating page state', event);
   179                  $.address.value(tabPath);
   180                }
   181                else {
   182                  module.verbose('Changing tab', event);
   183                  module.changeTab(tabPath);
   184                }
   185                event.preventDefault();
   186              }
   187              else {
   188                module.debug('No tab specified');
   189              }
   190            },
   191            history: {
   192              change: function(event) {
   193                var
   194                  tabPath   = event.pathNames.join('/') || module.get.initialPath(),
   195                  pageTitle = settings.templates.determineTitle(tabPath) || false
   196                ;
   197                module.performance.display();
   198                module.debug('History change event', tabPath, event);
   199                historyEvent = event;
   200                if(tabPath !== undefined) {
   201                  module.changeTab(tabPath);
   202                }
   203                if(pageTitle) {
   204                  $.address.title(pageTitle);
   205                }
   206              }
   207            }
   208          },
   209  
   210          refresh: function() {
   211            if(activeTabPath) {
   212              module.debug('Refreshing tab', activeTabPath);
   213              module.changeTab(activeTabPath);
   214            }
   215          },
   216  
   217          cache: {
   218  
   219            read: function(cacheKey) {
   220              return (cacheKey !== undefined)
   221                ? cache[cacheKey]
   222                : false
   223              ;
   224            },
   225            add: function(cacheKey, content) {
   226              cacheKey = cacheKey || activeTabPath;
   227              module.debug('Adding cached content for', cacheKey);
   228              cache[cacheKey] = content;
   229            },
   230            remove: function(cacheKey) {
   231              cacheKey = cacheKey || activeTabPath;
   232              module.debug('Removing cached content for', cacheKey);
   233              delete cache[cacheKey];
   234            }
   235          },
   236  
   237          set: {
   238            auto: function() {
   239              var
   240                url = (typeof settings.path == 'string')
   241                  ? settings.path.replace(/\/$/, '') + '/{$tab}'
   242                  : '/{$tab}'
   243              ;
   244              module.verbose('Setting up automatic tab retrieval from server', url);
   245              if($.isPlainObject(settings.apiSettings)) {
   246                settings.apiSettings.url = url;
   247              }
   248              else {
   249                settings.apiSettings = {
   250                  url: url
   251                };
   252              }
   253            },
   254            state: function(state) {
   255              $.address.value(state);
   256            }
   257          },
   258  
   259          changeTab: function(tabPath) {
   260            var
   261              pushStateAvailable = (window.history && window.history.pushState),
   262              shouldIgnoreLoad   = (pushStateAvailable && settings.ignoreFirstLoad && firstLoad),
   263              remoteContent      = (settings.auto || $.isPlainObject(settings.apiSettings) ),
   264              // only get default path if not remote content
   265              pathArray = (remoteContent && !shouldIgnoreLoad)
   266                ? module.utilities.pathToArray(tabPath)
   267                : module.get.defaultPathArray(tabPath)
   268            ;
   269            tabPath = module.utilities.arrayToPath(pathArray);
   270            $.each(pathArray, function(index, tab) {
   271              var
   272                currentPathArray   = pathArray.slice(0, index + 1),
   273                currentPath        = module.utilities.arrayToPath(currentPathArray),
   274  
   275                isTab              = module.is.tab(currentPath),
   276                isLastIndex        = (index + 1 == pathArray.length),
   277  
   278                $tab               = module.get.tabElement(currentPath),
   279                $anchor,
   280                nextPathArray,
   281                nextPath,
   282                isLastTab
   283              ;
   284              module.verbose('Looking for tab', tab);
   285              if(isTab) {
   286  
   287                module.verbose('Tab was found', tab);
   288                // scope up
   289                activeTabPath  = currentPath;
   290                parameterArray = module.utilities.filterArray(pathArray, currentPathArray);
   291  
   292                if(isLastIndex) {
   293                  isLastTab = true;
   294                }
   295                else {
   296                  nextPathArray = pathArray.slice(0, index + 2);
   297                  nextPath      = module.utilities.arrayToPath(nextPathArray);
   298                  isLastTab     = ( !module.is.tab(nextPath) );
   299                  if(isLastTab) {
   300                    module.verbose('Tab parameters found', nextPathArray);
   301                  }
   302                }
   303                if(isLastTab && remoteContent) {
   304                  if(!shouldIgnoreLoad) {
   305                    module.activate.navigation(currentPath);
   306                    module.content.fetch(currentPath, tabPath);
   307                  }
   308                  else {
   309                    module.debug('Ignoring remote content on first tab load', currentPath);
   310                    firstLoad = false;
   311                    module.cache.add(tabPath, $tab.html());
   312                    module.activate.all(currentPath);
   313                    settings.onTabInit.call($tab, currentPath, parameterArray, historyEvent);
   314                    settings.onTabLoad.call($tab, currentPath, parameterArray, historyEvent);
   315                  }
   316                  return false;
   317                }
   318                else {
   319                  module.debug('Opened local tab', currentPath);
   320                  module.activate.all(currentPath);
   321                  if( !module.cache.read(currentPath) ) {
   322                    module.cache.add(currentPath, true);
   323                    module.debug('First time tab loaded calling tab init');
   324                    settings.onTabInit.call($tab, currentPath, parameterArray, historyEvent);
   325                  }
   326                  settings.onTabLoad.call($tab, currentPath, parameterArray, historyEvent);
   327                }
   328              }
   329              else if(tabPath.search('/') == -1 && tabPath !== '') {
   330                // look for in page anchor
   331                $anchor     = $('#' + tabPath + ', a[name="' + tabPath + '"]'),
   332                currentPath = $anchor.closest('[data-tab]').data('tab');
   333                $tab        = module.get.tabElement(currentPath);
   334                // if anchor exists use parent tab
   335                if($anchor && $anchor.length > 0 && currentPath) {
   336                  module.debug('No tab found, but deep anchor link present, opening parent tab');
   337                  module.activate.all(currentPath);
   338                  if( !module.cache.read(currentPath) ) {
   339                    module.cache.add(currentPath, true);
   340                    module.debug('First time tab loaded calling tab init');
   341                    settings.onTabInit.call($tab, currentPath, parameterArray, historyEvent);
   342                  }
   343                  return false;
   344                }
   345              }
   346              else {
   347                module.error(error.missingTab, $module, $context, currentPath);
   348                return false;
   349              }
   350            });
   351          },
   352  
   353          content: {
   354  
   355            fetch: function(tabPath, fullTabPath) {
   356              var
   357                $tab        = module.get.tabElement(tabPath),
   358                apiSettings = {
   359                  dataType : 'html',
   360                  on       : 'now',
   361                  onSuccess    : function(response) {
   362                    module.cache.add(fullTabPath, response);
   363                    module.content.update(tabPath, response);
   364                    if(tabPath == activeTabPath) {
   365                      module.debug('Content loaded', tabPath);
   366                      module.activate.tab(tabPath);
   367                    }
   368                    else {
   369                      module.debug('Content loaded in background', tabPath);
   370                    }
   371                    settings.onTabInit.call($tab, tabPath, parameterArray, historyEvent);
   372                    settings.onTabLoad.call($tab, tabPath, parameterArray, historyEvent);
   373                  },
   374                  urlData: { tab: fullTabPath }
   375                },
   376                request         = $tab.api('get request') || false,
   377                existingRequest = ( request && request.state() === 'pending' ),
   378                requestSettings,
   379                cachedContent
   380              ;
   381  
   382              fullTabPath   = fullTabPath || tabPath;
   383              cachedContent = module.cache.read(fullTabPath);
   384  
   385  
   386              module.activate.tab(tabPath);
   387  
   388              if(settings.cache && cachedContent) {
   389                module.debug('Showing existing content', fullTabPath);
   390                module.content.update(tabPath, cachedContent);
   391                settings.onTabLoad.call($tab, tabPath, parameterArray, historyEvent);
   392              }
   393              else if(existingRequest) {
   394                module.debug('Content is already loading', fullTabPath);
   395                $tab.addClass(className.loading);
   396              }
   397              else if($.api !== undefined) {
   398                requestSettings = $.extend(true, {
   399                  headers: { 'X-Remote': true }
   400                }, settings.apiSettings, apiSettings);
   401                module.debug('Retrieving remote content', fullTabPath, requestSettings);
   402                $tab.api( requestSettings );
   403              }
   404              else {
   405                module.error(error.api);
   406              }
   407            },
   408  
   409            update: function(tabPath, html) {
   410              module.debug('Updating html for', tabPath);
   411              var
   412                $tab = module.get.tabElement(tabPath)
   413              ;
   414              $tab
   415                .html(html)
   416              ;
   417            }
   418          },
   419  
   420          activate: {
   421            all: function(tabPath) {
   422              module.activate.tab(tabPath);
   423              module.activate.navigation(tabPath);
   424            },
   425            tab: function(tabPath) {
   426              var
   427                $tab = module.get.tabElement(tabPath)
   428              ;
   429              module.verbose('Showing tab content for', $tab);
   430              $tab
   431                .addClass(className.active)
   432                .siblings($tabs)
   433                  .removeClass(className.active + ' ' + className.loading)
   434              ;
   435            },
   436            navigation: function(tabPath) {
   437              var
   438                $navigation = module.get.navElement(tabPath)
   439              ;
   440              module.verbose('Activating tab navigation for', $navigation, tabPath);
   441              $navigation
   442                .addClass(className.active)
   443                .siblings($allModules)
   444                  .removeClass(className.active + ' ' + className.loading)
   445              ;
   446            }
   447          },
   448  
   449          deactivate: {
   450            all: function() {
   451              module.deactivate.navigation();
   452              module.deactivate.tabs();
   453            },
   454            navigation: function() {
   455              $allModules
   456                .removeClass(className.active)
   457              ;
   458            },
   459            tabs: function() {
   460              $tabs
   461                .removeClass(className.active + ' ' + className.loading)
   462              ;
   463            }
   464          },
   465  
   466          is: {
   467            tab: function(tabName) {
   468              return (tabName !== undefined)
   469                ? ( module.get.tabElement(tabName).length > 0 )
   470                : false
   471              ;
   472            }
   473          },
   474  
   475          get: {
   476            initialPath: function() {
   477              return $allModules.eq(0).data(metadata.tab) || $tabs.eq(0).data(metadata.tab);
   478            },
   479            path: function() {
   480              return $.address.value();
   481            },
   482            // adds default tabs to tab path
   483            defaultPathArray: function(tabPath) {
   484              return module.utilities.pathToArray( module.get.defaultPath(tabPath) );
   485            },
   486            defaultPath: function(tabPath) {
   487              var
   488                $defaultNav = $allModules.filter('[data-' + metadata.tab + '^="' + tabPath + '/"]').eq(0),
   489                defaultTab  = $defaultNav.data(metadata.tab) || false
   490              ;
   491              if( defaultTab ) {
   492                module.debug('Found default tab', defaultTab);
   493                if(recursionDepth < settings.maxDepth) {
   494                  recursionDepth++;
   495                  return module.get.defaultPath(defaultTab);
   496                }
   497                module.error(error.recursion);
   498              }
   499              else {
   500                module.debug('No default tabs found for', tabPath, $tabs);
   501              }
   502              recursionDepth = 0;
   503              return tabPath;
   504            },
   505            navElement: function(tabPath) {
   506              tabPath = tabPath || activeTabPath;
   507              return $allModules.filter('[data-' + metadata.tab + '="' + tabPath + '"]');
   508            },
   509            tabElement: function(tabPath) {
   510              var
   511                $fullPathTab,
   512                $simplePathTab,
   513                tabPathArray,
   514                lastTab
   515              ;
   516              tabPath        = tabPath || activeTabPath;
   517              tabPathArray   = module.utilities.pathToArray(tabPath);
   518              lastTab        = module.utilities.last(tabPathArray);
   519              $fullPathTab   = $tabs.filter('[data-' + metadata.tab + '="' + lastTab + '"]');
   520              $simplePathTab = $tabs.filter('[data-' + metadata.tab + '="' + tabPath + '"]');
   521              return ($fullPathTab.length > 0)
   522                ? $fullPathTab
   523                : $simplePathTab
   524              ;
   525            },
   526            tab: function() {
   527              return activeTabPath;
   528            }
   529          },
   530  
   531          utilities: {
   532            filterArray: function(keepArray, removeArray) {
   533              return $.grep(keepArray, function(keepValue) {
   534                return ( $.inArray(keepValue, removeArray) == -1);
   535              });
   536            },
   537            last: function(array) {
   538              return $.isArray(array)
   539                ? array[ array.length - 1]
   540                : false
   541              ;
   542            },
   543            pathToArray: function(pathName) {
   544              if(pathName === undefined) {
   545                pathName = activeTabPath;
   546              }
   547              return typeof pathName == 'string'
   548                ? pathName.split('/')
   549                : [pathName]
   550              ;
   551            },
   552            arrayToPath: function(pathArray) {
   553              return $.isArray(pathArray)
   554                ? pathArray.join('/')
   555                : false
   556              ;
   557            }
   558          },
   559  
   560          setting: function(name, value) {
   561            module.debug('Changing setting', name, value);
   562            if( $.isPlainObject(name) ) {
   563              $.extend(true, settings, name);
   564            }
   565            else if(value !== undefined) {
   566              settings[name] = value;
   567            }
   568            else {
   569              return settings[name];
   570            }
   571          },
   572          internal: function(name, value) {
   573            if( $.isPlainObject(name) ) {
   574              $.extend(true, module, name);
   575            }
   576            else if(value !== undefined) {
   577              module[name] = value;
   578            }
   579            else {
   580              return module[name];
   581            }
   582          },
   583          debug: function() {
   584            if(settings.debug) {
   585              if(settings.performance) {
   586                module.performance.log(arguments);
   587              }
   588              else {
   589                module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
   590                module.debug.apply(console, arguments);
   591              }
   592            }
   593          },
   594          verbose: function() {
   595            if(settings.verbose && settings.debug) {
   596              if(settings.performance) {
   597                module.performance.log(arguments);
   598              }
   599              else {
   600                module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
   601                module.verbose.apply(console, arguments);
   602              }
   603            }
   604          },
   605          error: function() {
   606            module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
   607            module.error.apply(console, arguments);
   608          },
   609          performance: {
   610            log: function(message) {
   611              var
   612                currentTime,
   613                executionTime,
   614                previousTime
   615              ;
   616              if(settings.performance) {
   617                currentTime   = new Date().getTime();
   618                previousTime  = time || currentTime;
   619                executionTime = currentTime - previousTime;
   620                time          = currentTime;
   621                performance.push({
   622                  'Name'           : message[0],
   623                  'Arguments'      : [].slice.call(message, 1) || '',
   624                  'Element'        : element,
   625                  'Execution Time' : executionTime
   626                });
   627              }
   628              clearTimeout(module.performance.timer);
   629              module.performance.timer = setTimeout(module.performance.display, 100);
   630            },
   631            display: function() {
   632              var
   633                title = settings.name + ':',
   634                totalTime = 0
   635              ;
   636              time = false;
   637              clearTimeout(module.performance.timer);
   638              $.each(performance, function(index, data) {
   639                totalTime += data['Execution Time'];
   640              });
   641              title += ' ' + totalTime + 'ms';
   642              if(moduleSelector) {
   643                title += ' \'' + moduleSelector + '\'';
   644              }
   645              if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
   646                console.groupCollapsed(title);
   647                if(console.table) {
   648                  console.table(performance);
   649                }
   650                else {
   651                  $.each(performance, function(index, data) {
   652                    console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
   653                  });
   654                }
   655                console.groupEnd();
   656              }
   657              performance = [];
   658            }
   659          },
   660          invoke: function(query, passedArguments, context) {
   661            var
   662              object = instance,
   663              maxDepth,
   664              found,
   665              response
   666            ;
   667            passedArguments = passedArguments || queryArguments;
   668            context         = element         || context;
   669            if(typeof query == 'string' && object !== undefined) {
   670              query    = query.split(/[\. ]/);
   671              maxDepth = query.length - 1;
   672              $.each(query, function(depth, value) {
   673                var camelCaseValue = (depth != maxDepth)
   674                  ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
   675                  : query
   676                ;
   677                if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
   678                  object = object[camelCaseValue];
   679                }
   680                else if( object[camelCaseValue] !== undefined ) {
   681                  found = object[camelCaseValue];
   682                  return false;
   683                }
   684                else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
   685                  object = object[value];
   686                }
   687                else if( object[value] !== undefined ) {
   688                  found = object[value];
   689                  return false;
   690                }
   691                else {
   692                  module.error(error.method, query);
   693                  return false;
   694                }
   695              });
   696            }
   697            if ( $.isFunction( found ) ) {
   698              response = found.apply(context, passedArguments);
   699            }
   700            else if(found !== undefined) {
   701              response = found;
   702            }
   703            if($.isArray(returnedValue)) {
   704              returnedValue.push(response);
   705            }
   706            else if(returnedValue !== undefined) {
   707              returnedValue = [returnedValue, response];
   708            }
   709            else if(response !== undefined) {
   710              returnedValue = response;
   711            }
   712            return found;
   713          }
   714        };
   715        if(methodInvoked) {
   716          if(instance === undefined) {
   717            module.initialize();
   718          }
   719          module.invoke(query);
   720        }
   721        else {
   722          if(instance !== undefined) {
   723            instance.invoke('destroy');
   724          }
   725          module.initialize();
   726        }
   727      })
   728    ;
   729    if(module && !methodInvoked) {
   730      module.initializeHistory();
   731    }
   732    return (returnedValue !== undefined)
   733      ? returnedValue
   734      : this
   735    ;
   736  
   737  };
   738  
   739  // shortcut for tabbed content with no defined navigation
   740  $.tab = function() {
   741    $(window).tab.apply(this, arguments);
   742  };
   743  
   744  $.fn.tab.settings = {
   745  
   746    name            : 'Tab',
   747    namespace       : 'tab',
   748  
   749    debug           : false,
   750    verbose         : true,
   751    performance     : true,
   752  
   753    auto            : false,  // uses pjax style endpoints fetching content from same url with remote-content headers
   754    history         : false,  // use browser history
   755    historyType     : 'hash', // #/ or html5 state
   756    path            : false,  // base path of url
   757  
   758    context         : false,  // specify a context that tabs must appear inside
   759    childrenOnly    : false,  // use only tabs that are children of context
   760    maxDepth        : 25,     // max depth a tab can be nested
   761  
   762    alwaysRefresh   : false,  // load tab content new every tab click
   763    cache           : true,   // cache the content requests to pull locally
   764    ignoreFirstLoad : false,  // don't load remote content on first load
   765    apiSettings     : false,  // settings for api call
   766  
   767    onTabInit    : function(tabPath, parameterArray, historyEvent) {}, // called first time loaded
   768    onTabLoad    : function(tabPath, parameterArray, historyEvent) {}, // called on every load
   769  
   770    templates    : {
   771      determineTitle: function(tabArray) {} // returns page title for path
   772    },
   773  
   774    error: {
   775      api        : 'You attempted to load content without API module',
   776      method     : 'The method you called is not defined',
   777      missingTab : 'Activated tab cannot be found for this context.',
   778      noContent  : 'The tab you specified is missing a content url.',
   779      path       : 'History enabled, but no path was specified',
   780      recursion  : 'Max recursive depth reached',
   781      state      : 'History requires Asual\'s Address library <https://github.com/asual/jquery-address>'
   782    },
   783  
   784    metadata : {
   785      tab    : 'tab',
   786      loaded : 'loaded',
   787      promise: 'promise'
   788    },
   789  
   790    className   : {
   791      loading : 'loading',
   792      active  : 'active'
   793    },
   794  
   795    selector    : {
   796      tabs : '.ui.tab',
   797      ui   : '.ui'
   798    }
   799  
   800  };
   801  
   802  })( jQuery, window , document );