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.

1032 lines
33 KiB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. /*!
  2. * # Semantic UI 1.11.3 - Visibility
  3. * http://github.com/semantic-org/semantic-ui/
  4. *
  5. *
  6. * Copyright 2014 Contributors
  7. * Released under the MIT license
  8. * http://opensource.org/licenses/MIT
  9. *
  10. */
  11. ;(function ( $, window, document, undefined ) {
  12. "use strict";
  13. $.fn.visibility = function(parameters) {
  14. var
  15. $allModules = $(this),
  16. moduleSelector = $allModules.selector || '',
  17. time = new Date().getTime(),
  18. performance = [],
  19. query = arguments[0],
  20. methodInvoked = (typeof query == 'string'),
  21. queryArguments = [].slice.call(arguments, 1),
  22. returnedValue
  23. ;
  24. $allModules
  25. .each(function() {
  26. var
  27. settings = ( $.isPlainObject(parameters) )
  28. ? $.extend(true, {}, $.fn.visibility.settings, parameters)
  29. : $.extend({}, $.fn.visibility.settings),
  30. className = settings.className,
  31. namespace = settings.namespace,
  32. error = settings.error,
  33. eventNamespace = '.' + namespace,
  34. moduleNamespace = 'module-' + namespace,
  35. $window = $(window),
  36. $module = $(this),
  37. $context = $(settings.context),
  38. $container = $module.offsetParent(),
  39. selector = $module.selector || '',
  40. instance = $module.data(moduleNamespace),
  41. requestAnimationFrame = window.requestAnimationFrame
  42. || window.mozRequestAnimationFrame
  43. || window.webkitRequestAnimationFrame
  44. || window.msRequestAnimationFrame
  45. || function(callback) { setTimeout(callback, 0); },
  46. element = this,
  47. observer,
  48. module
  49. ;
  50. module = {
  51. initialize: function() {
  52. module.debug('Initializing', settings);
  53. module.setup.cache();
  54. module.save.position();
  55. if( module.should.trackChanges() ) {
  56. module.bind.events();
  57. if(settings.type == 'image') {
  58. module.setup.image();
  59. }
  60. if(settings.type == 'fixed') {
  61. module.setup.fixed();
  62. }
  63. }
  64. if(settings.initialCheck) {
  65. module.checkVisibility();
  66. }
  67. if(settings.observeChanges) {
  68. module.observeChanges();
  69. }
  70. module.instantiate();
  71. },
  72. instantiate: function() {
  73. module.debug('Storing instance', module);
  74. $module
  75. .data(moduleNamespace, module)
  76. ;
  77. instance = module;
  78. },
  79. destroy: function() {
  80. module.verbose('Destroying previous module');
  81. $module
  82. .off(eventNamespace)
  83. .removeData(moduleNamespace)
  84. ;
  85. $window.off('resize' + eventNamespace, module.event.refresh);
  86. $context.off('scroll' + eventNamespace, module.event.scroll);
  87. },
  88. observeChanges: function() {
  89. var
  90. context = $context[0]
  91. ;
  92. if('MutationObserver' in window) {
  93. observer = new MutationObserver(function(mutations) {
  94. module.verbose('DOM tree modified, updating visibility calculations');
  95. module.refresh();
  96. });
  97. observer.observe(element, {
  98. childList : true,
  99. subtree : true
  100. });
  101. module.debug('Setting up mutation observer', observer);
  102. }
  103. },
  104. bind: {
  105. events: function() {
  106. module.verbose('Binding visibility events to scroll and resize');
  107. $window
  108. .on('resize' + eventNamespace, module.event.refresh)
  109. ;
  110. $context
  111. .on('scroll' + eventNamespace, module.event.scroll)
  112. ;
  113. }
  114. },
  115. event: {
  116. refresh: function() {
  117. requestAnimationFrame(module.refresh);
  118. },
  119. scroll: function() {
  120. module.verbose('Scroll position changed');
  121. if(settings.throttle) {
  122. clearTimeout(module.timer);
  123. module.timer = setTimeout(function() {
  124. module.checkVisibility();
  125. }, settings.throttle);
  126. }
  127. else {
  128. requestAnimationFrame(function() {
  129. module.checkVisibility();
  130. });
  131. }
  132. }
  133. },
  134. precache: function(images, callback) {
  135. if (!(images instanceof Array)) {
  136. images = [images];
  137. }
  138. var
  139. imagesLength = images.length,
  140. loadedCounter = 0,
  141. cache = [],
  142. cacheImage = document.createElement('img'),
  143. handleLoad = function() {
  144. loadedCounter++;
  145. if (loadedCounter >= images.length) {
  146. if ($.isFunction(callback)) {
  147. callback();
  148. }
  149. }
  150. }
  151. ;
  152. while (imagesLength--) {
  153. cacheImage = document.createElement('img');
  154. cacheImage.onload = handleLoad;
  155. cacheImage.onerror = handleLoad;
  156. cacheImage.src = images[imagesLength];
  157. cache.push(cacheImage);
  158. }
  159. },
  160. should: {
  161. trackChanges: function() {
  162. if(methodInvoked && queryArguments.length > 0) {
  163. module.debug('One time query, no need to bind events');
  164. return false;
  165. }
  166. module.debug('Callbacks being attached');
  167. return true;
  168. }
  169. },
  170. setup: {
  171. cache: function() {
  172. module.cache = {
  173. occurred : {},
  174. screen : {},
  175. element : {},
  176. };
  177. },
  178. image: function() {
  179. var
  180. src = $module.data('src')
  181. ;
  182. if(src) {
  183. module.verbose('Lazy loading image', src);
  184. settings.observeChanges = false;
  185. // show when top visible
  186. module.topVisible(function() {
  187. module.debug('Image top visible', element);
  188. module.precache(src, function() {
  189. module.set.image(src);
  190. settings.onTopVisible = false;
  191. });
  192. });
  193. }
  194. },
  195. fixed: function() {
  196. module.verbose('Setting up fixed on element pass');
  197. settings.once = false;
  198. settings.onTopPassed = function() {
  199. $module
  200. .addClass(className.fixed)
  201. .css({
  202. top: settings.offset + 'px'
  203. })
  204. ;
  205. if(settings.transition) {
  206. if($.fn.transition !== undefined) {
  207. $module.transition(settings.transition, settings.duration);
  208. }
  209. }
  210. };
  211. settings.onTopPassedReverse = function() {
  212. $module
  213. .removeClass(className.fixed)
  214. .css({
  215. position: '',
  216. top: ''
  217. })
  218. ;
  219. };
  220. }
  221. },
  222. set: {
  223. image: function(src) {
  224. var
  225. offScreen = (module.cache.screen.bottom < module.cache.element.top)
  226. ;
  227. $module
  228. .attr('src', src)
  229. ;
  230. if(offScreen) {
  231. module.verbose('Image outside browser, no show animation');
  232. $module.show();
  233. }
  234. else {
  235. if(settings.transition) {
  236. if( $.fn.transition !== undefined ) {
  237. $module.transition(settings.transition, settings.duration);
  238. }
  239. else {
  240. $module.fadeIn(settings.duration);
  241. }
  242. }
  243. else {
  244. $module.show();
  245. }
  246. }
  247. }
  248. },
  249. is: {
  250. visible: function() {
  251. if(module.cache && module.cache.element) {
  252. return (module.cache.element.width > 0);
  253. }
  254. return false;
  255. }
  256. },
  257. refresh: function() {
  258. module.debug('Refreshing constants (element width/height)');
  259. module.reset();
  260. module.save.position();
  261. module.checkVisibility();
  262. settings.onRefresh.call(element);
  263. },
  264. reset: function() {
  265. module.verbose('Reseting all cached values');
  266. if( $.isPlainObject(module.cache) ) {
  267. module.cache.screen = {};
  268. module.cache.element = {};
  269. }
  270. },
  271. checkVisibility: function() {
  272. module.verbose('Checking visibility of element', module.cache.element);
  273. if( module.is.visible() ) {
  274. // update calculations derived from scroll
  275. module.save.calculations();
  276. // percentage
  277. module.passed();
  278. // reverse (must be first)
  279. module.passingReverse();
  280. module.topVisibleReverse();
  281. module.bottomVisibleReverse();
  282. module.topPassedReverse();
  283. module.bottomPassedReverse();
  284. // one time
  285. module.passing();
  286. module.topVisible();
  287. module.bottomVisible();
  288. module.topPassed();
  289. module.bottomPassed();
  290. // on update callback
  291. if(settings.onUpdate) {
  292. settings.onUpdate.call(element, module.get.elementCalculations());
  293. }
  294. }
  295. },
  296. passed: function(amount, newCallback) {
  297. var
  298. calculations = module.get.elementCalculations(),
  299. amountInPixels
  300. ;
  301. // assign callback
  302. if(amount !== undefined && newCallback !== undefined) {
  303. settings.onPassed[amount] = newCallback;
  304. }
  305. else if(amount !== undefined) {
  306. return (module.get.pixelsPassed(amount) > calculations.pixelsPassed);
  307. }
  308. else if(calculations.passing) {
  309. $.each(settings.onPassed, function(amount, callback) {
  310. if(calculations.bottomVisible || calculations.pixelsPassed > module.get.pixelsPassed(amount)) {
  311. module.execute(callback, amount);
  312. }
  313. else if(!settings.once) {
  314. module.remove.occurred(callback);
  315. }
  316. });
  317. }
  318. },
  319. passing: function(newCallback) {
  320. var
  321. calculations = module.get.elementCalculations(),
  322. callback = newCallback || settings.onPassing,
  323. callbackName = 'passing'
  324. ;
  325. if(newCallback) {
  326. module.debug('Adding callback for passing', newCallback);
  327. settings.onPassing = newCallback;
  328. }
  329. if(calculations.passing) {
  330. module.execute(callback, callbackName);
  331. }
  332. else if(!settings.once) {
  333. module.remove.occurred(callbackName);
  334. }
  335. if(newCallback !== undefined) {
  336. return calculations.passing;
  337. }
  338. },
  339. topVisible: function(newCallback) {
  340. var
  341. calculations = module.get.elementCalculations(),
  342. callback = newCallback || settings.onTopVisible,
  343. callbackName = 'topVisible'
  344. ;
  345. if(newCallback) {
  346. module.debug('Adding callback for top visible', newCallback);
  347. settings.onTopVisible = newCallback;
  348. }
  349. if(calculations.topVisible) {
  350. module.execute(callback, callbackName);
  351. }
  352. else if(!settings.once) {
  353. module.remove.occurred(callbackName);
  354. }
  355. if(newCallback === undefined) {
  356. return calculations.topVisible;
  357. }
  358. },
  359. bottomVisible: function(newCallback) {
  360. var
  361. calculations = module.get.elementCalculations(),
  362. callback = newCallback || settings.onBottomVisible,
  363. callbackName = 'bottomVisible'
  364. ;
  365. if(newCallback) {
  366. module.debug('Adding callback for bottom visible', newCallback);
  367. settings.onBottomVisible = newCallback;
  368. }
  369. if(calculations.bottomVisible) {
  370. module.execute(callback, callbackName);
  371. }
  372. else if(!settings.once) {
  373. module.remove.occurred(callbackName);
  374. }
  375. if(newCallback === undefined) {
  376. return calculations.bottomVisible;
  377. }
  378. },
  379. topPassed: function(newCallback) {
  380. var
  381. calculations = module.get.elementCalculations(),
  382. callback = newCallback || settings.onTopPassed,
  383. callbackName = 'topPassed'
  384. ;
  385. if(newCallback) {
  386. module.debug('Adding callback for top passed', newCallback);
  387. settings.onTopPassed = newCallback;
  388. }
  389. if(calculations.topPassed) {
  390. module.execute(callback, callbackName);
  391. }
  392. else if(!settings.once) {
  393. module.remove.occurred(callbackName);
  394. }
  395. if(newCallback === undefined) {
  396. return calculations.topPassed;
  397. }
  398. },
  399. bottomPassed: function(newCallback) {
  400. var
  401. calculations = module.get.elementCalculations(),
  402. callback = newCallback || settings.onBottomPassed,
  403. callbackName = 'bottomPassed'
  404. ;
  405. if(newCallback) {
  406. module.debug('Adding callback for bottom passed', newCallback);
  407. settings.onBottomPassed = newCallback;
  408. }
  409. if(calculations.bottomPassed) {
  410. module.execute(callback, callbackName);
  411. }
  412. else if(!settings.once) {
  413. module.remove.occurred(callbackName);
  414. }
  415. if(newCallback === undefined) {
  416. return calculations.bottomPassed;
  417. }
  418. },
  419. passingReverse: function(newCallback) {
  420. var
  421. calculations = module.get.elementCalculations(),
  422. callback = newCallback || settings.onPassingReverse,
  423. callbackName = 'passingReverse'
  424. ;
  425. if(newCallback) {
  426. module.debug('Adding callback for passing reverse', newCallback);
  427. settings.onPassingReverse = newCallback;
  428. }
  429. if(!calculations.passing) {
  430. if(module.get.occurred('passing')) {
  431. module.execute(callback, callbackName);
  432. }
  433. }
  434. else if(!settings.once) {
  435. module.remove.occurred(callbackName);
  436. }
  437. if(newCallback !== undefined) {
  438. return !calculations.passing;
  439. }
  440. },
  441. topVisibleReverse: function(newCallback) {
  442. var
  443. calculations = module.get.elementCalculations(),
  444. callback = newCallback || settings.onTopVisibleReverse,
  445. callbackName = 'topVisibleReverse'
  446. ;
  447. if(newCallback) {
  448. module.debug('Adding callback for top visible reverse', newCallback);
  449. settings.onTopVisibleReverse = newCallback;
  450. }
  451. if(!calculations.topVisible) {
  452. if(module.get.occurred('topVisible')) {
  453. module.execute(callback, callbackName);
  454. }
  455. }
  456. else if(!settings.once) {
  457. module.remove.occurred(callbackName);
  458. }
  459. if(newCallback === undefined) {
  460. return !calculations.topVisible;
  461. }
  462. },
  463. bottomVisibleReverse: function(newCallback) {
  464. var
  465. calculations = module.get.elementCalculations(),
  466. callback = newCallback || settings.onBottomVisibleReverse,
  467. callbackName = 'bottomVisibleReverse'
  468. ;
  469. if(newCallback) {
  470. module.debug('Adding callback for bottom visible reverse', newCallback);
  471. settings.onBottomVisibleReverse = newCallback;
  472. }
  473. if(!calculations.bottomVisible) {
  474. if(module.get.occurred('bottomVisible')) {
  475. module.execute(callback, callbackName);
  476. }
  477. }
  478. else if(!settings.once) {
  479. module.remove.occurred(callbackName);
  480. }
  481. if(newCallback === undefined) {
  482. return !calculations.bottomVisible;
  483. }
  484. },
  485. topPassedReverse: function(newCallback) {
  486. var
  487. calculations = module.get.elementCalculations(),
  488. callback = newCallback || settings.onTopPassedReverse,
  489. callbackName = 'topPassedReverse'
  490. ;
  491. if(newCallback) {
  492. module.debug('Adding callback for top passed reverse', newCallback);
  493. settings.onTopPassedReverse = newCallback;
  494. }
  495. if(!calculations.topPassed) {
  496. if(module.get.occurred('topPassed')) {
  497. module.execute(callback, callbackName);
  498. }
  499. }
  500. else if(!settings.once) {
  501. module.remove.occurred(callbackName);
  502. }
  503. if(newCallback === undefined) {
  504. return !calculations.onTopPassed;
  505. }
  506. },
  507. bottomPassedReverse: function(newCallback) {
  508. var
  509. calculations = module.get.elementCalculations(),
  510. callback = newCallback || settings.onBottomPassedReverse,
  511. callbackName = 'bottomPassedReverse'
  512. ;
  513. if(newCallback) {
  514. module.debug('Adding callback for bottom passed reverse', newCallback);
  515. settings.onBottomPassedReverse = newCallback;
  516. }
  517. if(!calculations.bottomPassed) {
  518. if(module.get.occurred('bottomPassed')) {
  519. module.execute(callback, callbackName);
  520. }
  521. }
  522. else if(!settings.once) {
  523. module.remove.occurred(callbackName);
  524. }
  525. if(newCallback === undefined) {
  526. return !calculations.bottomPassed;
  527. }
  528. },
  529. execute: function(callback, callbackName) {
  530. var
  531. calculations = module.get.elementCalculations(),
  532. screen = module.get.screenCalculations()
  533. ;
  534. callback = callback || false;
  535. if(callback) {
  536. if(settings.continuous) {
  537. module.debug('Callback being called continuously', callbackName, calculations);
  538. callback.call(element, calculations, screen);
  539. }
  540. else if(!module.get.occurred(callbackName)) {
  541. module.debug('Conditions met', callbackName, calculations);
  542. callback.call(element, calculations, screen);
  543. }
  544. }
  545. module.save.occurred(callbackName);
  546. },
  547. remove: {
  548. occurred: function(callback) {
  549. if(callback) {
  550. if(module.cache.occurred[callback] !== undefined && module.cache.occurred[callback] === true) {
  551. module.debug('Callback can now be called again', callback);
  552. module.cache.occurred[callback] = false;
  553. }
  554. }
  555. else {
  556. module.cache.occurred = {};
  557. }
  558. }
  559. },
  560. save: {
  561. calculations: function() {
  562. module.verbose('Saving all calculations necessary to determine positioning');
  563. module.save.scroll();
  564. module.save.direction();
  565. module.save.screenCalculations();
  566. module.save.elementCalculations();
  567. },
  568. occurred: function(callback) {
  569. if(callback) {
  570. if(module.cache.occurred[callback] === undefined || (module.cache.occurred[callback] !== true)) {
  571. module.verbose('Saving callback occurred', callback);
  572. module.cache.occurred[callback] = true;
  573. }
  574. }
  575. },
  576. scroll: function() {
  577. module.cache.scroll = $context.scrollTop() + settings.offset;
  578. },
  579. direction: function() {
  580. var
  581. scroll = module.get.scroll(),
  582. lastScroll = module.get.lastScroll(),
  583. direction
  584. ;
  585. if(scroll > lastScroll && lastScroll) {
  586. direction = 'down';
  587. }
  588. else if(scroll < lastScroll && lastScroll) {
  589. direction = 'up';
  590. }
  591. else {
  592. direction = 'static';
  593. }
  594. module.cache.direction = direction;
  595. return module.cache.direction;
  596. },
  597. elementPosition: function() {
  598. var
  599. element = module.cache.element,
  600. screen = module.get.screenSize()
  601. ;
  602. module.verbose('Saving element position');
  603. // (quicker than $.extend)
  604. element.fits = (element.height < screen.height);
  605. element.offset = $module.offset();
  606. element.width = $module.outerWidth();
  607. element.height = $module.outerHeight();
  608. // store
  609. module.cache.element = element;
  610. return element;
  611. },
  612. elementCalculations: function() {
  613. var
  614. screen = module.get.screenCalculations(),
  615. element = module.get.elementPosition()
  616. ;
  617. // offset
  618. if(settings.includeMargin) {
  619. element.margin = {};
  620. element.margin.top = parseInt($module.css('margin-top'), 10);
  621. element.margin.bottom = parseInt($module.css('margin-bottom'), 10);
  622. element.top = element.offset.top - element.margin.top;
  623. element.bottom = element.offset.top + element.height + element.margin.bottom;
  624. }
  625. else {
  626. element.top = element.offset.top;
  627. element.bottom = element.offset.top + element.height;
  628. }
  629. // visibility
  630. element.topVisible = (screen.bottom >= element.top);
  631. element.topPassed = (screen.top >= element.top);
  632. element.bottomVisible = (screen.bottom >= element.bottom);
  633. element.bottomPassed = (screen.top >= element.bottom);
  634. element.pixelsPassed = 0;
  635. element.percentagePassed = 0;
  636. // meta calculations
  637. element.visible = (element.topVisible || element.bottomVisible);
  638. element.passing = (element.topPassed && !element.bottomPassed);
  639. element.hidden = (!element.topVisible && !element.bottomVisible);
  640. // passing calculations
  641. if(element.passing) {
  642. element.pixelsPassed = (screen.top - element.top);
  643. element.percentagePassed = (screen.top - element.top) / element.height;
  644. }
  645. module.cache.element = element;
  646. module.verbose('Updated element calculations', element);
  647. return element;
  648. },
  649. screenCalculations: function() {
  650. var
  651. scroll = module.get.scroll()
  652. ;
  653. module.save.direction();
  654. module.cache.screen.top = scroll;
  655. module.cache.screen.bottom = scroll + module.cache.screen.height;
  656. return module.cache.screen;
  657. },
  658. screenSize: function() {
  659. module.verbose('Saving window position');
  660. module.cache.screen = {
  661. height: $context.height()
  662. };
  663. },
  664. position: function() {
  665. module.save.screenSize();
  666. module.save.elementPosition();
  667. }
  668. },
  669. get: {
  670. pixelsPassed: function(amount) {
  671. var
  672. element = module.get.elementCalculations()
  673. ;
  674. if(amount.search('%') > -1) {
  675. return ( element.height * (parseInt(amount, 10) / 100) );
  676. }
  677. return parseInt(amount, 10);
  678. },
  679. occurred: function(callback) {
  680. return (module.cache.occurred !== undefined)
  681. ? module.cache.occurred[callback] || false
  682. : false
  683. ;
  684. },
  685. direction: function() {
  686. if(module.cache.direction === undefined) {
  687. module.save.direction();
  688. }
  689. return module.cache.direction;
  690. },
  691. elementPosition: function() {
  692. if(module.cache.element === undefined) {
  693. module.save.elementPosition();
  694. }
  695. return module.cache.element;
  696. },
  697. elementCalculations: function() {
  698. if(module.cache.element === undefined) {
  699. module.save.elementCalculations();
  700. }
  701. return module.cache.element;
  702. },
  703. screenCalculations: function() {
  704. if(module.cache.screen === undefined) {
  705. module.save.screenCalculations();
  706. }
  707. return module.cache.screen;
  708. },
  709. screenSize: function() {
  710. if(module.cache.screen === undefined) {
  711. module.save.screenSize();
  712. }
  713. return module.cache.screen;
  714. },
  715. scroll: function() {
  716. if(module.cache.scroll === undefined) {
  717. module.save.scroll();
  718. }
  719. return module.cache.scroll;
  720. },
  721. lastScroll: function() {
  722. if(module.cache.screen === undefined) {
  723. module.debug('First scroll event, no last scroll could be found');
  724. return false;
  725. }
  726. return module.cache.screen.top;
  727. }
  728. },
  729. setting: function(name, value) {
  730. if( $.isPlainObject(name) ) {
  731. $.extend(true, settings, name);
  732. }
  733. else if(value !== undefined) {
  734. settings[name] = value;
  735. }
  736. else {
  737. return settings[name];
  738. }
  739. },
  740. internal: function(name, value) {
  741. if( $.isPlainObject(name) ) {
  742. $.extend(true, module, name);
  743. }
  744. else if(value !== undefined) {
  745. module[name] = value;
  746. }
  747. else {
  748. return module[name];
  749. }
  750. },
  751. debug: function() {
  752. if(settings.debug) {
  753. if(settings.performance) {
  754. module.performance.log(arguments);
  755. }
  756. else {
  757. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  758. module.debug.apply(console, arguments);
  759. }
  760. }
  761. },
  762. verbose: function() {
  763. if(settings.verbose && settings.debug) {
  764. if(settings.performance) {
  765. module.performance.log(arguments);
  766. }
  767. else {
  768. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  769. module.verbose.apply(console, arguments);
  770. }
  771. }
  772. },
  773. error: function() {
  774. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  775. module.error.apply(console, arguments);
  776. },
  777. performance: {
  778. log: function(message) {
  779. var
  780. currentTime,
  781. executionTime,
  782. previousTime
  783. ;
  784. if(settings.performance) {
  785. currentTime = new Date().getTime();
  786. previousTime = time || currentTime;
  787. executionTime = currentTime - previousTime;
  788. time = currentTime;
  789. performance.push({
  790. 'Name' : message[0],
  791. 'Arguments' : [].slice.call(message, 1) || '',
  792. 'Element' : element,
  793. 'Execution Time' : executionTime
  794. });
  795. }
  796. clearTimeout(module.performance.timer);
  797. module.performance.timer = setTimeout(module.performance.display, 100);
  798. },
  799. display: function() {
  800. var
  801. title = settings.name + ':',
  802. totalTime = 0
  803. ;
  804. time = false;
  805. clearTimeout(module.performance.timer);
  806. $.each(performance, function(index, data) {
  807. totalTime += data['Execution Time'];
  808. });
  809. title += ' ' + totalTime + 'ms';
  810. if(moduleSelector) {
  811. title += ' \'' + moduleSelector + '\'';
  812. }
  813. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  814. console.groupCollapsed(title);
  815. if(console.table) {
  816. console.table(performance);
  817. }
  818. else {
  819. $.each(performance, function(index, data) {
  820. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  821. });
  822. }
  823. console.groupEnd();
  824. }
  825. performance = [];
  826. }
  827. },
  828. invoke: function(query, passedArguments, context) {
  829. var
  830. object = instance,
  831. maxDepth,
  832. found,
  833. response
  834. ;
  835. passedArguments = passedArguments || queryArguments;
  836. context = element || context;
  837. if(typeof query == 'string' && object !== undefined) {
  838. query = query.split(/[\. ]/);
  839. maxDepth = query.length - 1;
  840. $.each(query, function(depth, value) {
  841. var camelCaseValue = (depth != maxDepth)
  842. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  843. : query
  844. ;
  845. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  846. object = object[camelCaseValue];
  847. }
  848. else if( object[camelCaseValue] !== undefined ) {
  849. found = object[camelCaseValue];
  850. return false;
  851. }
  852. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  853. object = object[value];
  854. }
  855. else if( object[value] !== undefined ) {
  856. found = object[value];
  857. return false;
  858. }
  859. else {
  860. module.error(error.method, query);
  861. return false;
  862. }
  863. });
  864. }
  865. if ( $.isFunction( found ) ) {
  866. response = found.apply(context, passedArguments);
  867. }
  868. else if(found !== undefined) {
  869. response = found;
  870. }
  871. if($.isArray(returnedValue)) {
  872. returnedValue.push(response);
  873. }
  874. else if(returnedValue !== undefined) {
  875. returnedValue = [returnedValue, response];
  876. }
  877. else if(response !== undefined) {
  878. returnedValue = response;
  879. }
  880. return found;
  881. }
  882. };
  883. if(methodInvoked) {
  884. if(instance === undefined) {
  885. module.initialize();
  886. }
  887. module.invoke(query);
  888. }
  889. else {
  890. if(instance !== undefined) {
  891. instance.invoke('destroy');
  892. }
  893. module.initialize();
  894. }
  895. })
  896. ;
  897. return (returnedValue !== undefined)
  898. ? returnedValue
  899. : this
  900. ;
  901. };
  902. $.fn.visibility.settings = {
  903. name : 'Visibility',
  904. namespace : 'visibility',
  905. debug : false,
  906. verbose : false,
  907. performance : true,
  908. // whether to use mutation observers to follow changes
  909. observeChanges : true,
  910. // callback should only occur one time
  911. once : true,
  912. // callback should fire continuously whe evaluates to true
  913. continuous : false,
  914. // offset to use with scroll top
  915. offset : 0,
  916. // whether to include margin in elements position
  917. includeMargin : false,
  918. // scroll context for visibility checks
  919. context : window,
  920. // check position immediately on init
  921. initialCheck : true,
  922. // visibility check delay in ms (defaults to animationFrame)
  923. throttle : false,
  924. // special visibility type (image, fixed)
  925. type : false,
  926. // image only animation settings
  927. transition : false,
  928. duration : 1000,
  929. // array of callbacks for percentage
  930. onPassed : {},
  931. // standard callbacks
  932. onPassing : false,
  933. onTopVisible : false,
  934. onBottomVisible : false,
  935. onTopPassed : false,
  936. onBottomPassed : false,
  937. // reverse callbacks
  938. onPassingReverse : false,
  939. onTopVisibleReverse : false,
  940. onBottomVisibleReverse : false,
  941. onTopPassedReverse : false,
  942. onBottomPassedReverse : false,
  943. // utility callbacks
  944. onUpdate : false, // disabled by default for performance
  945. onRefresh : function(){},
  946. className: {
  947. fixed: 'fixed'
  948. },
  949. error : {
  950. method : 'The method you called is not defined.'
  951. }
  952. };
  953. })( jQuery, window , document );