You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

923 lines
31 KiB

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