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.

1037 lines
33 KiB

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