|                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |  | /*! * # Semantic UI 2.1.6 - Tab * http://github.com/semantic-org/semantic-ui/
 * * * Copyright 2015 Contributors * Released under the MIT license * http://opensource.org/licenses/MIT
 * */
;(function ($, window, document, undefined) {
"use strict";
$.fn.tab = function(parameters) {
  var    // use window context if none specified
    $allModules     = $.isFunction(this)        ? $(window)        : $(this),
    moduleSelector  = $allModules.selector || '',    time            = new Date().getTime(),    performance     = [],
    query           = arguments[0],    methodInvoked   = (typeof query == 'string'),    queryArguments  = [].slice.call(arguments, 1),
    initializedHistory = false,    returnedValue  ;
  $allModules    .each(function() {      var
        settings        = ( $.isPlainObject(parameters) )          ? $.extend(true, {}, $.fn.tab.settings, parameters)          : $.extend({}, $.fn.tab.settings),
        className       = settings.className,        metadata        = settings.metadata,        selector        = settings.selector,        error           = settings.error,
        eventNamespace  = '.' + settings.namespace,        moduleNamespace = 'module-' + settings.namespace,
        $module         = $(this),        $context,        $tabs,
        cache           = {},        firstLoad       = true,        recursionDepth  = 0,        element         = this,        instance        = $module.data(moduleNamespace),
        activeTabPath,        parameterArray,        module,
        historyEvent
      ;
      module = {
        initialize: function() {          module.debug('Initializing tab menu item', $module);          module.fix.callbacks();          module.determineTabs();
          module.debug('Determining tabs', settings.context, $tabs);          // set up automatic routing
          if(settings.auto) {            module.set.auto();          }          module.bind.events();
          if(settings.history && !initializedHistory) {            module.initializeHistory();            initializedHistory = true;          }
          module.instantiate();        },
        instantiate: function () {          module.verbose('Storing instance of module', module);          instance = module;          $module            .data(moduleNamespace, module)          ;        },
        destroy: function() {          module.debug('Destroying tabs', $module);          $module            .removeData(moduleNamespace)            .off(eventNamespace)          ;        },
        bind: {          events: function() {            // if using $.tab don't add events
            if( !$.isWindow( element ) ) {              module.debug('Attaching tab activation events to element', $module);              $module                .on('click' + eventNamespace, module.event.click)              ;            }          }        },
        determineTabs: function() {          var            $reference          ;
          // determine tab context
          if(settings.context === 'parent') {            if($module.closest(selector.ui).length > 0) {              $reference = $module.closest(selector.ui);              module.verbose('Using closest UI element as parent', $reference);            }            else {              $reference = $module;            }            $context = $reference.parent();            module.verbose('Determined parent element for creating context', $context);          }          else if(settings.context) {            $context = $(settings.context);            module.verbose('Using selector for tab context', settings.context, $context);          }          else {            $context = $('body');          }          // find tabs
          if(settings.childrenOnly) {            $tabs = $context.children(selector.tabs);            module.debug('Searching tab context children for tabs', $context, $tabs);          }          else {            $tabs = $context.find(selector.tabs);            module.debug('Searching tab context for tabs', $context, $tabs);          }        },
        fix: {          callbacks: function() {            if( $.isPlainObject(parameters) && (parameters.onTabLoad || parameters.onTabInit) ) {              if(parameters.onTabLoad) {                parameters.onLoad = parameters.onTabLoad;                delete parameters.onTabLoad;                module.error(error.legacyLoad, parameters.onLoad);              }              if(parameters.onTabInit) {                parameters.onFirstLoad = parameters.onTabInit;                delete parameters.onTabInit;                module.error(error.legacyInit, parameters.onFirstLoad);              }              settings = $.extend(true, {}, $.fn.tab.settings, parameters);            }          }        },
        initializeHistory: function() {          module.debug('Initializing page state');          if( $.address === undefined ) {            module.error(error.state);            return false;          }          else {            if(settings.historyType == 'state') {              module.debug('Using HTML5 to manage state');              if(settings.path !== false) {                $.address                  .history(true)                  .state(settings.path)                ;              }              else {                module.error(error.path);                return false;              }            }            $.address              .bind('change', module.event.history.change)            ;          }        },
        event: {          click: function(event) {            var              tabPath = $(this).data(metadata.tab)            ;            if(tabPath !== undefined) {              if(settings.history) {                module.verbose('Updating page state', event);                $.address.value(tabPath);              }              else {                module.verbose('Changing tab', event);                module.changeTab(tabPath);              }              event.preventDefault();            }            else {              module.debug('No tab specified');            }          },          history: {            change: function(event) {              var                tabPath   = event.pathNames.join('/') || module.get.initialPath(),                pageTitle = settings.templates.determineTitle(tabPath) || false              ;              module.performance.display();              module.debug('History change event', tabPath, event);              historyEvent = event;              if(tabPath !== undefined) {                module.changeTab(tabPath);              }              if(pageTitle) {                $.address.title(pageTitle);              }            }          }        },
        refresh: function() {          if(activeTabPath) {            module.debug('Refreshing tab', activeTabPath);            module.changeTab(activeTabPath);          }        },
        cache: {
          read: function(cacheKey) {            return (cacheKey !== undefined)              ? cache[cacheKey]              : false            ;          },          add: function(cacheKey, content) {            cacheKey = cacheKey || activeTabPath;            module.debug('Adding cached content for', cacheKey);            cache[cacheKey] = content;          },          remove: function(cacheKey) {            cacheKey = cacheKey || activeTabPath;            module.debug('Removing cached content for', cacheKey);            delete cache[cacheKey];          }        },
        set: {          auto: function() {            var              url = (typeof settings.path == 'string')                ? settings.path.replace(/\/$/, '') + '/{$tab}'                : '/{$tab}'            ;            module.verbose('Setting up automatic tab retrieval from server', url);            if($.isPlainObject(settings.apiSettings)) {              settings.apiSettings.url = url;            }            else {              settings.apiSettings = {                url: url              };            }          },          loading: function(tabPath) {            var              $tab      = module.get.tabElement(tabPath),              isLoading = $tab.hasClass(className.loading)            ;            if(!isLoading) {              module.verbose('Setting loading state for', $tab);              $tab                .addClass(className.loading)                .siblings($tabs)                  .removeClass(className.active + ' ' + className.loading)              ;              if($tab.length > 0) {                settings.onRequest.call($tab[0], tabPath);              }            }          },          state: function(state) {            $.address.value(state);          }        },
        changeTab: function(tabPath) {          var            pushStateAvailable = (window.history && window.history.pushState),            shouldIgnoreLoad   = (pushStateAvailable && settings.ignoreFirstLoad && firstLoad),            remoteContent      = (settings.auto || $.isPlainObject(settings.apiSettings) ),            // only add default path if not remote content
            pathArray = (remoteContent && !shouldIgnoreLoad)              ? module.utilities.pathToArray(tabPath)              : module.get.defaultPathArray(tabPath)          ;          tabPath = module.utilities.arrayToPath(pathArray);          $.each(pathArray, function(index, tab) {            var              currentPathArray   = pathArray.slice(0, index + 1),              currentPath        = module.utilities.arrayToPath(currentPathArray),
              isTab              = module.is.tab(currentPath),              isLastIndex        = (index + 1 == pathArray.length),
              $tab               = module.get.tabElement(currentPath),              $anchor,              nextPathArray,              nextPath,              isLastTab            ;            module.verbose('Looking for tab', tab);            if(isTab) {              module.verbose('Tab was found', tab);              // scope up
              activeTabPath  = currentPath;              parameterArray = module.utilities.filterArray(pathArray, currentPathArray);
              if(isLastIndex) {                isLastTab = true;              }              else {                nextPathArray = pathArray.slice(0, index + 2);                nextPath      = module.utilities.arrayToPath(nextPathArray);                isLastTab     = ( !module.is.tab(nextPath) );                if(isLastTab) {                  module.verbose('Tab parameters found', nextPathArray);                }              }              if(isLastTab && remoteContent) {                if(!shouldIgnoreLoad) {                  module.activate.navigation(currentPath);                  module.fetch.content(currentPath, tabPath);                }                else {                  module.debug('Ignoring remote content on first tab load', currentPath);                  firstLoad = false;                  module.cache.add(tabPath, $tab.html());                  module.activate.all(currentPath);                  settings.onFirstLoad.call($tab[0], currentPath, parameterArray, historyEvent);                  settings.onLoad.call($tab[0], currentPath, parameterArray, historyEvent);                }                return false;              }              else {                module.debug('Opened local tab', currentPath);                module.activate.all(currentPath);                if( !module.cache.read(currentPath) ) {                  module.cache.add(currentPath, true);                  module.debug('First time tab loaded calling tab init');                  settings.onFirstLoad.call($tab[0], currentPath, parameterArray, historyEvent);                }                settings.onLoad.call($tab[0], currentPath, parameterArray, historyEvent);              }
            }            else if(tabPath.search('/') == -1 && tabPath !== '') {              // look for in page anchor
              $anchor     = $('#' + tabPath + ', a[name="' + tabPath + '"]');              currentPath = $anchor.closest('[data-tab]').data(metadata.tab);              $tab        = module.get.tabElement(currentPath);              // if anchor exists use parent tab
              if($anchor && $anchor.length > 0 && currentPath) {                module.debug('Anchor link used, opening parent tab', $tab, $anchor);                if( !$tab.hasClass(className.active) ) {                  setTimeout(function() {                    module.scrollTo($anchor);                  }, 0);                }                module.activate.all(currentPath);                if( !module.cache.read(currentPath) ) {                  module.cache.add(currentPath, true);                  module.debug('First time tab loaded calling tab init');                  settings.onFirstLoad.call($tab[0], currentPath, parameterArray, historyEvent);                }                settings.onLoad.call($tab[0], currentPath, parameterArray, historyEvent);                return false;              }            }            else {              module.error(error.missingTab, $module, $context, currentPath);              return false;            }          });        },
        scrollTo: function($element) {          var            scrollOffset = ($element && $element.length > 0)              ? $element.offset().top              : false          ;          if(scrollOffset !== false) {            module.debug('Forcing scroll to an in-page link in a hidden tab', scrollOffset, $element);            $(document).scrollTop(scrollOffset);          }        },
        update: {          content: function(tabPath, html, evaluateScripts) {            var              $tab = module.get.tabElement(tabPath),              tab  = $tab[0]            ;            evaluateScripts = (evaluateScripts !== undefined)              ? evaluateScripts              : settings.evaluateScripts            ;            if(evaluateScripts) {              module.debug('Updating HTML and evaluating inline scripts', tabPath, html);              $tab.html(html);            }            else {              module.debug('Updating HTML', tabPath, html);              tab.innerHTML = html;            }          }        },
        fetch: {
          content: function(tabPath, fullTabPath) {            var              $tab        = module.get.tabElement(tabPath),              apiSettings = {                dataType         : 'html',                encodeParameters : false,                on               : 'now',                cache            : settings.alwaysRefresh,                headers          : {                  'X-Remote': true                },                onSuccess : function(response) {                  module.cache.add(fullTabPath, response);                  module.update.content(tabPath, response);                  if(tabPath == activeTabPath) {                    module.debug('Content loaded', tabPath);                    module.activate.tab(tabPath);                  }                  else {                    module.debug('Content loaded in background', tabPath);                  }                  settings.onFirstLoad.call($tab[0], tabPath, parameterArray, historyEvent);                  settings.onLoad.call($tab[0], tabPath, parameterArray, historyEvent);                },                urlData: {                  tab: fullTabPath                }              },              request         = $tab.api('get request') || false,              existingRequest = ( request && request.state() === 'pending' ),              requestSettings,              cachedContent            ;
            fullTabPath   = fullTabPath || tabPath;            cachedContent = module.cache.read(fullTabPath);
            if(settings.cache && cachedContent) {              module.activate.tab(tabPath);              module.debug('Adding cached content', fullTabPath);              if(settings.evaluateScripts == 'once') {                module.update.content(tabPath, cachedContent, false);              }              else {                module.update.content(tabPath, cachedContent);              }              settings.onLoad.call($tab[0], tabPath, parameterArray, historyEvent);            }            else if(existingRequest) {              module.set.loading(tabPath);              module.debug('Content is already loading', fullTabPath);            }            else if($.api !== undefined) {              requestSettings = $.extend(true, {}, settings.apiSettings, apiSettings);              module.debug('Retrieving remote content', fullTabPath, requestSettings);              module.set.loading(tabPath);              $tab.api(requestSettings);            }            else {              module.error(error.api);            }          }        },
        activate: {          all: function(tabPath) {            module.activate.tab(tabPath);            module.activate.navigation(tabPath);          },          tab: function(tabPath) {            var              $tab     = module.get.tabElement(tabPath),              isActive = $tab.hasClass(className.active)            ;            module.verbose('Showing tab content for', $tab);            if(!isActive) {              $tab                .addClass(className.active)                .siblings($tabs)                  .removeClass(className.active + ' ' + className.loading)              ;              if($tab.length > 0) {                settings.onVisible.call($tab[0], tabPath);              }            }          },          navigation: function(tabPath) {            var              $navigation = module.get.navElement(tabPath),              isActive    = $navigation.hasClass(className.active)            ;            module.verbose('Activating tab navigation for', $navigation, tabPath);            if(!isActive) {              $navigation                .addClass(className.active)                .siblings($allModules)                  .removeClass(className.active + ' ' + className.loading)              ;            }          }        },
        deactivate: {          all: function() {            module.deactivate.navigation();            module.deactivate.tabs();          },          navigation: function() {            $allModules              .removeClass(className.active)            ;          },          tabs: function() {            $tabs              .removeClass(className.active + ' ' + className.loading)            ;          }        },
        is: {          tab: function(tabName) {            return (tabName !== undefined)              ? ( module.get.tabElement(tabName).length > 0 )              : false            ;          }        },
        get: {          initialPath: function() {            return $allModules.eq(0).data(metadata.tab) || $tabs.eq(0).data(metadata.tab);          },          path: function() {            return $.address.value();          },          // adds default tabs to tab path
          defaultPathArray: function(tabPath) {            return module.utilities.pathToArray( module.get.defaultPath(tabPath) );          },          defaultPath: function(tabPath) {            var              $defaultNav = $allModules.filter('[data-' + metadata.tab + '^="' + tabPath + '/"]').eq(0),              defaultTab  = $defaultNav.data(metadata.tab) || false            ;            if( defaultTab ) {              module.debug('Found default tab', defaultTab);              if(recursionDepth < settings.maxDepth) {                recursionDepth++;                return module.get.defaultPath(defaultTab);              }              module.error(error.recursion);            }            else {              module.debug('No default tabs found for', tabPath, $tabs);            }            recursionDepth = 0;            return tabPath;          },          navElement: function(tabPath) {            tabPath = tabPath || activeTabPath;            return $allModules.filter('[data-' + metadata.tab + '="' + tabPath + '"]');          },          tabElement: function(tabPath) {            var              $fullPathTab,              $simplePathTab,              tabPathArray,              lastTab            ;            tabPath        = tabPath || activeTabPath;            tabPathArray   = module.utilities.pathToArray(tabPath);            lastTab        = module.utilities.last(tabPathArray);            $fullPathTab   = $tabs.filter('[data-' + metadata.tab + '="' + tabPath + '"]');            $simplePathTab = $tabs.filter('[data-' + metadata.tab + '="' + lastTab + '"]');            return ($fullPathTab.length > 0)              ? $fullPathTab              : $simplePathTab            ;          },          tab: function() {            return activeTabPath;          }        },
        utilities: {          filterArray: function(keepArray, removeArray) {            return $.grep(keepArray, function(keepValue) {              return ( $.inArray(keepValue, removeArray) == -1);            });          },          last: function(array) {            return $.isArray(array)              ? array[ array.length - 1]              : false            ;          },          pathToArray: function(pathName) {            if(pathName === undefined) {              pathName = activeTabPath;            }            return typeof pathName == 'string'              ? pathName.split('/')              : [pathName]            ;          },          arrayToPath: function(pathArray) {            return $.isArray(pathArray)              ? pathArray.join('/')              : false            ;          }        },
        setting: function(name, value) {          module.debug('Changing setting', name, value);          if( $.isPlainObject(name) ) {            $.extend(true, settings, name);          }          else if(value !== undefined) {            settings[name] = value;          }          else {            return settings[name];          }        },        internal: function(name, value) {          if( $.isPlainObject(name) ) {            $.extend(true, module, name);          }          else if(value !== undefined) {            module[name] = value;          }          else {            return module[name];          }        },        debug: function() {          if(settings.debug) {            if(settings.performance) {              module.performance.log(arguments);            }            else {              module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');              module.debug.apply(console, arguments);            }          }        },        verbose: function() {          if(settings.verbose && settings.debug) {            if(settings.performance) {              module.performance.log(arguments);            }            else {              module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');              module.verbose.apply(console, arguments);            }          }        },        error: function() {          module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');          module.error.apply(console, arguments);        },        performance: {          log: function(message) {            var              currentTime,              executionTime,              previousTime            ;            if(settings.performance) {              currentTime   = new Date().getTime();              previousTime  = time || currentTime;              executionTime = currentTime - previousTime;              time          = currentTime;              performance.push({                'Name'           : message[0],                'Arguments'      : [].slice.call(message, 1) || '',                'Element'        : element,                'Execution Time' : executionTime              });            }            clearTimeout(module.performance.timer);            module.performance.timer = setTimeout(module.performance.display, 500);          },          display: function() {            var              title = settings.name + ':',              totalTime = 0            ;            time = false;            clearTimeout(module.performance.timer);            $.each(performance, function(index, data) {              totalTime += data['Execution Time'];            });            title += ' ' + totalTime + 'ms';            if(moduleSelector) {              title += ' \'' + moduleSelector + '\'';            }            if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {              console.groupCollapsed(title);              if(console.table) {                console.table(performance);              }              else {                $.each(performance, function(index, data) {                  console.log(data['Name'] + ': ' + data['Execution Time']+'ms');                });              }              console.groupEnd();            }            performance = [];          }        },        invoke: function(query, passedArguments, context) {          var            object = instance,            maxDepth,            found,            response          ;          passedArguments = passedArguments || queryArguments;          context         = element         || context;          if(typeof query == 'string' && object !== undefined) {            query    = query.split(/[\. ]/);            maxDepth = query.length - 1;            $.each(query, function(depth, value) {              var camelCaseValue = (depth != maxDepth)                ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)                : query              ;              if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {                object = object[camelCaseValue];              }              else if( object[camelCaseValue] !== undefined ) {                found = object[camelCaseValue];                return false;              }              else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {                object = object[value];              }              else if( object[value] !== undefined ) {                found = object[value];                return false;              }              else {                module.error(error.method, query);                return false;              }            });          }          if ( $.isFunction( found ) ) {            response = found.apply(context, passedArguments);          }          else if(found !== undefined) {            response = found;          }          if($.isArray(returnedValue)) {            returnedValue.push(response);          }          else if(returnedValue !== undefined) {            returnedValue = [returnedValue, response];          }          else if(response !== undefined) {            returnedValue = response;          }          return found;        }      };      if(methodInvoked) {        if(instance === undefined) {          module.initialize();        }        module.invoke(query);      }      else {        if(instance !== undefined) {          instance.invoke('destroy');        }        module.initialize();      }    })  ;  return (returnedValue !== undefined)    ? returnedValue    : this  ;
};
// shortcut for tabbed content with no defined navigation
$.tab = function() {  $(window).tab.apply(this, arguments);};
$.fn.tab.settings = {
  name            : 'Tab',  namespace       : 'tab',
  debug           : false,  verbose         : false,  performance     : true,
  auto            : false,  // uses pjax style endpoints fetching content from same url with remote-content headers
  history         : false,  // use browser history
  historyType     : 'hash', // #/ or html5 state
  path            : false,  // base path of url
  context         : false,  // specify a context that tabs must appear inside
  childrenOnly    : false,  // use only tabs that are children of context
  maxDepth        : 25,     // max depth a tab can be nested
  alwaysRefresh   : false,  // load tab content new every tab click
  cache           : true,   // cache the content requests to pull locally
  ignoreFirstLoad : false,  // don't load remote content on first load
  apiSettings     : false,  // settings for api call
  evaluateScripts : 'once', // whether inline scripts should be parsed (true/false/once). Once will not re-evaluate on cached content
  onFirstLoad : function(tabPath, parameterArray, historyEvent) {}, // called first time loaded
  onLoad      : function(tabPath, parameterArray, historyEvent) {}, // called on every load
  onVisible   : function(tabPath, parameterArray, historyEvent) {}, // called every time tab visible
  onRequest   : function(tabPath, parameterArray, historyEvent) {}, // called ever time a tab beings loading remote content
  templates    : {    determineTitle: function(tabArray) {} // returns page title for path
  },
  error: {    api        : 'You attempted to load content without API module',    method     : 'The method you called is not defined',    missingTab : 'Activated tab cannot be found. Tabs are case-sensitive.',    noContent  : 'The tab you specified is missing a content url.',    path       : 'History enabled, but no path was specified',    recursion  : 'Max recursive depth reached',    legacyInit : 'onTabInit has been renamed to onFirstLoad in 2.0, please adjust your code.',    legacyLoad : 'onTabLoad has been renamed to onLoad in 2.0. Please adjust your code',    state      : 'History requires Asual\'s Address library <https://github.com/asual/jquery-address>'  },
  metadata : {    tab    : 'tab',    loaded : 'loaded',    promise: 'promise'  },
  className   : {    loading : 'loading',    active  : 'active'  },
  selector    : {    tabs : '.ui.tab',    ui   : '.ui'  }
};
})( jQuery, window, document );
 |