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.

884 lines
27 KiB

9 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
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 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
10 years ago
10 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
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
9 years ago
9 years ago
10 years ago
9 years ago
9 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
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
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
9 years ago
10 years ago
9 years ago
9 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
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 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
9 years ago
10 years ago
9 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
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
9 years ago
10 years ago
9 years ago
  1. /*!
  2. * # Semantic UI 2.0.4 - Sticky
  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. $.fn.sticky = 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.sticky.settings, parameters)
  29. : $.extend({}, $.fn.sticky.settings),
  30. className = settings.className,
  31. namespace = settings.namespace,
  32. error = settings.error,
  33. eventNamespace = '.' + namespace,
  34. moduleNamespace = 'module-' + namespace,
  35. $module = $(this),
  36. $window = $(window),
  37. $scroll = $(settings.scrollContext),
  38. $container,
  39. $context,
  40. selector = $module.selector || '',
  41. instance = $module.data(moduleNamespace),
  42. requestAnimationFrame = window.requestAnimationFrame
  43. || window.mozRequestAnimationFrame
  44. || window.webkitRequestAnimationFrame
  45. || window.msRequestAnimationFrame
  46. || function(callback) { setTimeout(callback, 0); },
  47. element = this,
  48. observer,
  49. module
  50. ;
  51. module = {
  52. initialize: function() {
  53. module.determineContainer();
  54. module.determineContext();
  55. module.verbose('Initializing sticky', settings, $container);
  56. module.save.positions();
  57. module.checkErrors();
  58. module.bind.events();
  59. if(settings.observeChanges) {
  60. module.observeChanges();
  61. }
  62. module.instantiate();
  63. },
  64. instantiate: function() {
  65. module.verbose('Storing instance of module', module);
  66. instance = module;
  67. $module
  68. .data(moduleNamespace, module)
  69. ;
  70. },
  71. destroy: function() {
  72. module.verbose('Destroying previous instance');
  73. module.reset();
  74. if(observer) {
  75. observer.disconnect();
  76. }
  77. $window
  78. .off('load' + eventNamespace, module.event.load)
  79. .off('resize' + eventNamespace, module.event.resize)
  80. ;
  81. $scroll
  82. .off('scrollchange' + eventNamespace, module.event.scrollchange)
  83. ;
  84. $module.removeData(moduleNamespace);
  85. },
  86. observeChanges: function() {
  87. var
  88. context = $context[0]
  89. ;
  90. if('MutationObserver' in window) {
  91. observer = new MutationObserver(function(mutations) {
  92. clearTimeout(module.timer);
  93. module.timer = setTimeout(function() {
  94. module.verbose('DOM tree modified, updating sticky menu', mutations);
  95. module.refresh();
  96. }, 100);
  97. });
  98. observer.observe(element, {
  99. childList : true,
  100. subtree : true
  101. });
  102. observer.observe(context, {
  103. childList : true,
  104. subtree : true
  105. });
  106. module.debug('Setting up mutation observer', observer);
  107. }
  108. },
  109. determineContainer: function() {
  110. $container = $module.offsetParent();
  111. },
  112. determineContext: function() {
  113. if(settings.context) {
  114. $context = $(settings.context);
  115. }
  116. else {
  117. $context = $container;
  118. }
  119. if($context.length === 0) {
  120. module.error(error.invalidContext, settings.context, $module);
  121. return;
  122. }
  123. },
  124. checkErrors: function() {
  125. if( module.is.hidden() ) {
  126. module.error(error.visible, $module);
  127. }
  128. if(module.cache.element.height > module.cache.context.height) {
  129. module.reset();
  130. module.error(error.elementSize, $module);
  131. return;
  132. }
  133. },
  134. bind: {
  135. events: function() {
  136. $window
  137. .on('load' + eventNamespace, module.event.load)
  138. .on('resize' + eventNamespace, module.event.resize)
  139. ;
  140. // pub/sub pattern
  141. $scroll
  142. .off('scroll' + eventNamespace)
  143. .on('scroll' + eventNamespace, module.event.scroll)
  144. .on('scrollchange' + eventNamespace, module.event.scrollchange)
  145. ;
  146. }
  147. },
  148. event: {
  149. load: function() {
  150. module.verbose('Page contents finished loading');
  151. requestAnimationFrame(module.refresh);
  152. },
  153. resize: function() {
  154. module.verbose('Window resized');
  155. requestAnimationFrame(module.refresh);
  156. },
  157. scroll: function() {
  158. requestAnimationFrame(function() {
  159. $scroll.triggerHandler('scrollchange' + eventNamespace, $scroll.scrollTop() );
  160. });
  161. },
  162. scrollchange: function(event, scrollPosition) {
  163. module.stick(scrollPosition);
  164. settings.onScroll.call(element);
  165. }
  166. },
  167. refresh: function(hardRefresh) {
  168. module.reset();
  169. if(!settings.context) {
  170. module.determineContext();
  171. }
  172. if(hardRefresh) {
  173. module.determineContainer();
  174. }
  175. module.save.positions();
  176. module.stick();
  177. settings.onReposition.call(element);
  178. },
  179. supports: {
  180. sticky: function() {
  181. var
  182. $element = $('<div/>'),
  183. element = $element[0]
  184. ;
  185. $element.addClass(className.supported);
  186. return($element.css('position').match('sticky'));
  187. }
  188. },
  189. save: {
  190. lastScroll: function(scroll) {
  191. module.lastScroll = scroll;
  192. },
  193. elementScroll: function(scroll) {
  194. module.elementScroll = scroll;
  195. },
  196. positions: function() {
  197. var
  198. window = {
  199. height: $window.height()
  200. },
  201. element = {
  202. margin: {
  203. top : parseInt($module.css('margin-top'), 10),
  204. bottom : parseInt($module.css('margin-bottom'), 10),
  205. },
  206. offset : $module.offset(),
  207. width : $module.outerWidth(),
  208. height : $module.outerHeight()
  209. },
  210. context = {
  211. offset : $context.offset(),
  212. height : $context.outerHeight()
  213. },
  214. container = {
  215. height: $container.outerHeight()
  216. }
  217. ;
  218. module.cache = {
  219. fits : ( element.height < window.height ),
  220. window: {
  221. height: window.height
  222. },
  223. element: {
  224. margin : element.margin,
  225. top : element.offset.top - element.margin.top,
  226. left : element.offset.left,
  227. width : element.width,
  228. height : element.height,
  229. bottom : element.offset.top + element.height
  230. },
  231. context: {
  232. top : context.offset.top,
  233. height : context.height,
  234. bottom : context.offset.top + context.height
  235. }
  236. };
  237. module.set.containerSize();
  238. module.set.size();
  239. module.stick();
  240. module.debug('Caching element positions', module.cache);
  241. }
  242. },
  243. get: {
  244. direction: function(scroll) {
  245. var
  246. direction = 'down'
  247. ;
  248. scroll = scroll || $scroll.scrollTop();
  249. if(module.lastScroll !== undefined) {
  250. if(module.lastScroll < scroll) {
  251. direction = 'down';
  252. }
  253. else if(module.lastScroll > scroll) {
  254. direction = 'up';
  255. }
  256. }
  257. return direction;
  258. },
  259. scrollChange: function(scroll) {
  260. scroll = scroll || $scroll.scrollTop();
  261. return (module.lastScroll)
  262. ? (scroll - module.lastScroll)
  263. : 0
  264. ;
  265. },
  266. currentElementScroll: function() {
  267. if(module.elementScroll) {
  268. return module.elementScroll;
  269. }
  270. return ( module.is.top() )
  271. ? Math.abs(parseInt($module.css('top'), 10)) || 0
  272. : Math.abs(parseInt($module.css('bottom'), 10)) || 0
  273. ;
  274. },
  275. elementScroll: function(scroll) {
  276. scroll = scroll || $scroll.scrollTop();
  277. var
  278. element = module.cache.element,
  279. window = module.cache.window,
  280. delta = module.get.scrollChange(scroll),
  281. maxScroll = (element.height - window.height + settings.offset),
  282. elementScroll = module.get.currentElementScroll(),
  283. possibleScroll = (elementScroll + delta)
  284. ;
  285. if(module.cache.fits || possibleScroll < 0) {
  286. elementScroll = 0;
  287. }
  288. else if(possibleScroll > maxScroll ) {
  289. elementScroll = maxScroll;
  290. }
  291. else {
  292. elementScroll = possibleScroll;
  293. }
  294. return elementScroll;
  295. }
  296. },
  297. remove: {
  298. lastScroll: function() {
  299. delete module.lastScroll;
  300. },
  301. elementScroll: function(scroll) {
  302. delete module.elementScroll;
  303. },
  304. offset: function() {
  305. $module.css('margin-top', '');
  306. }
  307. },
  308. set: {
  309. offset: function() {
  310. module.verbose('Setting offset on element', settings.offset);
  311. $module
  312. .css('margin-top', settings.offset)
  313. ;
  314. },
  315. containerSize: function() {
  316. var
  317. tagName = $container.get(0).tagName
  318. ;
  319. if(tagName === 'HTML' || tagName == 'body') {
  320. // this can trigger for too many reasons
  321. //module.error(error.container, tagName, $module);
  322. module.determineContainer();
  323. }
  324. else {
  325. if( Math.abs($container.outerHeight() - module.cache.context.height) > settings.jitter) {
  326. module.debug('Context has padding, specifying exact height for container', module.cache.context.height);
  327. $container.css({
  328. height: module.cache.context.height
  329. });
  330. }
  331. }
  332. },
  333. minimumSize: function() {
  334. var
  335. element = module.cache.element
  336. ;
  337. $container
  338. .css('min-height', element.height)
  339. ;
  340. },
  341. scroll: function(scroll) {
  342. module.debug('Setting scroll on element', scroll);
  343. if(module.elementScroll == scroll) {
  344. return;
  345. }
  346. if( module.is.top() ) {
  347. $module
  348. .css('bottom', '')
  349. .css('top', -scroll)
  350. ;
  351. }
  352. if( module.is.bottom() ) {
  353. $module
  354. .css('top', '')
  355. .css('bottom', scroll)
  356. ;
  357. }
  358. },
  359. size: function() {
  360. if(module.cache.element.height !== 0 && module.cache.element.width !== 0) {
  361. $module
  362. .css({
  363. width : module.cache.element.width,
  364. height : module.cache.element.height
  365. })
  366. ;
  367. }
  368. }
  369. },
  370. is: {
  371. top: function() {
  372. return $module.hasClass(className.top);
  373. },
  374. bottom: function() {
  375. return $module.hasClass(className.bottom);
  376. },
  377. initialPosition: function() {
  378. return (!module.is.fixed() && !module.is.bound());
  379. },
  380. hidden: function() {
  381. return (!$module.is(':visible'));
  382. },
  383. bound: function() {
  384. return $module.hasClass(className.bound);
  385. },
  386. fixed: function() {
  387. return $module.hasClass(className.fixed);
  388. }
  389. },
  390. stick: function(scroll) {
  391. var
  392. cachedPosition = scroll || $scroll.scrollTop(),
  393. cache = module.cache,
  394. fits = cache.fits,
  395. element = cache.element,
  396. window = cache.window,
  397. context = cache.context,
  398. offset = (module.is.bottom() && settings.pushing)
  399. ? settings.bottomOffset
  400. : settings.offset,
  401. scroll = {
  402. top : cachedPosition + offset,
  403. bottom : cachedPosition + offset + window.height
  404. },
  405. direction = module.get.direction(scroll.top),
  406. elementScroll = (fits)
  407. ? 0
  408. : module.get.elementScroll(scroll.top),
  409. // shorthand
  410. doesntFit = !fits,
  411. elementVisible = (element.height !== 0)
  412. ;
  413. if(elementVisible) {
  414. if( module.is.initialPosition() ) {
  415. if(scroll.top > context.bottom) {
  416. module.debug('Element bottom of container');
  417. module.bindBottom();
  418. }
  419. else if(scroll.top > element.top) {
  420. module.debug('Element passed, fixing element to page');
  421. if( (element.height + scroll.top - elementScroll) > context.bottom ) {
  422. module.bindBottom();
  423. }
  424. else {
  425. module.fixTop();
  426. }
  427. }
  428. }
  429. else if( module.is.fixed() ) {
  430. // currently fixed top
  431. if( module.is.top() ) {
  432. if( scroll.top < element.top ) {
  433. module.debug('Fixed element reached top of container');
  434. module.setInitialPosition();
  435. }
  436. else if( (element.height + scroll.top - elementScroll) > context.bottom ) {
  437. module.debug('Fixed element reached bottom of container');
  438. module.bindBottom();
  439. }
  440. // scroll element if larger than screen
  441. else if(doesntFit) {
  442. module.set.scroll(elementScroll);
  443. module.save.lastScroll(scroll.top);
  444. module.save.elementScroll(elementScroll);
  445. }
  446. }
  447. // currently fixed bottom
  448. else if(module.is.bottom() ) {
  449. // top edge
  450. if( (scroll.bottom - element.height) < element.top) {
  451. module.debug('Bottom fixed rail has reached top of container');
  452. module.setInitialPosition();
  453. }
  454. // bottom edge
  455. else if(scroll.bottom > context.bottom) {
  456. module.debug('Bottom fixed rail has reached bottom of container');
  457. module.bindBottom();
  458. }
  459. // scroll element if larger than screen
  460. else if(doesntFit) {
  461. module.set.scroll(elementScroll);
  462. module.save.lastScroll(scroll.top);
  463. module.save.elementScroll(elementScroll);
  464. }
  465. }
  466. }
  467. else if( module.is.bottom() ) {
  468. if(settings.pushing) {
  469. if(module.is.bound() && scroll.bottom < context.bottom ) {
  470. module.debug('Fixing bottom attached element to bottom of browser.');
  471. module.fixBottom();
  472. }
  473. }
  474. else {
  475. if(module.is.bound() && (scroll.top < context.bottom - element.height) ) {
  476. module.debug('Fixing bottom attached element to top of browser.');
  477. module.fixTop();
  478. }
  479. }
  480. }
  481. }
  482. },
  483. bindTop: function() {
  484. module.debug('Binding element to top of parent container');
  485. module.remove.offset();
  486. $module
  487. .css({
  488. left : '',
  489. top : '',
  490. marginBottom : ''
  491. })
  492. .removeClass(className.fixed)
  493. .removeClass(className.bottom)
  494. .addClass(className.bound)
  495. .addClass(className.top)
  496. ;
  497. settings.onTop.call(element);
  498. settings.onUnstick.call(element);
  499. },
  500. bindBottom: function() {
  501. module.debug('Binding element to bottom of parent container');
  502. module.remove.offset();
  503. $module
  504. .css({
  505. left : '',
  506. top : ''
  507. })
  508. .removeClass(className.fixed)
  509. .removeClass(className.top)
  510. .addClass(className.bound)
  511. .addClass(className.bottom)
  512. ;
  513. settings.onBottom.call(element);
  514. settings.onUnstick.call(element);
  515. },
  516. setInitialPosition: function() {
  517. module.unfix();
  518. module.unbind();
  519. },
  520. fixTop: function() {
  521. module.debug('Fixing element to top of page');
  522. module.set.minimumSize();
  523. module.set.offset();
  524. $module
  525. .css({
  526. left : module.cache.element.left,
  527. bottom : '',
  528. marginBottom : ''
  529. })
  530. .removeClass(className.bound)
  531. .removeClass(className.bottom)
  532. .addClass(className.fixed)
  533. .addClass(className.top)
  534. ;
  535. settings.onStick.call(element);
  536. },
  537. fixBottom: function() {
  538. module.debug('Sticking element to bottom of page');
  539. module.set.minimumSize();
  540. module.set.offset();
  541. $module
  542. .css({
  543. left : module.cache.element.left,
  544. bottom : '',
  545. marginBottom : ''
  546. })
  547. .removeClass(className.bound)
  548. .removeClass(className.top)
  549. .addClass(className.fixed)
  550. .addClass(className.bottom)
  551. ;
  552. settings.onStick.call(element);
  553. },
  554. unbind: function() {
  555. module.debug('Removing absolute position on element');
  556. module.remove.offset();
  557. $module
  558. .removeClass(className.bound)
  559. .removeClass(className.top)
  560. .removeClass(className.bottom)
  561. ;
  562. },
  563. unfix: function() {
  564. module.debug('Removing fixed position on element');
  565. module.remove.offset();
  566. $module
  567. .removeClass(className.fixed)
  568. .removeClass(className.top)
  569. .removeClass(className.bottom)
  570. ;
  571. settings.onUnstick.call(element);
  572. },
  573. reset: function() {
  574. module.debug('Reseting elements position');
  575. module.unbind();
  576. module.unfix();
  577. module.resetCSS();
  578. module.remove.offset();
  579. module.remove.lastScroll();
  580. },
  581. resetCSS: function() {
  582. $module
  583. .css({
  584. width : '',
  585. height : ''
  586. })
  587. ;
  588. $container
  589. .css({
  590. height: ''
  591. })
  592. ;
  593. },
  594. setting: function(name, value) {
  595. if( $.isPlainObject(name) ) {
  596. $.extend(true, settings, name);
  597. }
  598. else if(value !== undefined) {
  599. settings[name] = value;
  600. }
  601. else {
  602. return settings[name];
  603. }
  604. },
  605. internal: function(name, value) {
  606. if( $.isPlainObject(name) ) {
  607. $.extend(true, module, name);
  608. }
  609. else if(value !== undefined) {
  610. module[name] = value;
  611. }
  612. else {
  613. return module[name];
  614. }
  615. },
  616. debug: function() {
  617. if(settings.debug) {
  618. if(settings.performance) {
  619. module.performance.log(arguments);
  620. }
  621. else {
  622. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  623. module.debug.apply(console, arguments);
  624. }
  625. }
  626. },
  627. verbose: function() {
  628. if(settings.verbose && settings.debug) {
  629. if(settings.performance) {
  630. module.performance.log(arguments);
  631. }
  632. else {
  633. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  634. module.verbose.apply(console, arguments);
  635. }
  636. }
  637. },
  638. error: function() {
  639. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  640. module.error.apply(console, arguments);
  641. },
  642. performance: {
  643. log: function(message) {
  644. var
  645. currentTime,
  646. executionTime,
  647. previousTime
  648. ;
  649. if(settings.performance) {
  650. currentTime = new Date().getTime();
  651. previousTime = time || currentTime;
  652. executionTime = currentTime - previousTime;
  653. time = currentTime;
  654. performance.push({
  655. 'Name' : message[0],
  656. 'Arguments' : [].slice.call(message, 1) || '',
  657. 'Element' : element,
  658. 'Execution Time' : executionTime
  659. });
  660. }
  661. clearTimeout(module.performance.timer);
  662. module.performance.timer = setTimeout(module.performance.display, 0);
  663. },
  664. display: function() {
  665. var
  666. title = settings.name + ':',
  667. totalTime = 0
  668. ;
  669. time = false;
  670. clearTimeout(module.performance.timer);
  671. $.each(performance, function(index, data) {
  672. totalTime += data['Execution Time'];
  673. });
  674. title += ' ' + totalTime + 'ms';
  675. if(moduleSelector) {
  676. title += ' \'' + moduleSelector + '\'';
  677. }
  678. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  679. console.groupCollapsed(title);
  680. if(console.table) {
  681. console.table(performance);
  682. }
  683. else {
  684. $.each(performance, function(index, data) {
  685. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  686. });
  687. }
  688. console.groupEnd();
  689. }
  690. performance = [];
  691. }
  692. },
  693. invoke: function(query, passedArguments, context) {
  694. var
  695. object = instance,
  696. maxDepth,
  697. found,
  698. response
  699. ;
  700. passedArguments = passedArguments || queryArguments;
  701. context = element || context;
  702. if(typeof query == 'string' && object !== undefined) {
  703. query = query.split(/[\. ]/);
  704. maxDepth = query.length - 1;
  705. $.each(query, function(depth, value) {
  706. var camelCaseValue = (depth != maxDepth)
  707. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  708. : query
  709. ;
  710. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  711. object = object[camelCaseValue];
  712. }
  713. else if( object[camelCaseValue] !== undefined ) {
  714. found = object[camelCaseValue];
  715. return false;
  716. }
  717. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  718. object = object[value];
  719. }
  720. else if( object[value] !== undefined ) {
  721. found = object[value];
  722. return false;
  723. }
  724. else {
  725. return false;
  726. }
  727. });
  728. }
  729. if ( $.isFunction( found ) ) {
  730. response = found.apply(context, passedArguments);
  731. }
  732. else if(found !== undefined) {
  733. response = found;
  734. }
  735. if($.isArray(returnedValue)) {
  736. returnedValue.push(response);
  737. }
  738. else if(returnedValue !== undefined) {
  739. returnedValue = [returnedValue, response];
  740. }
  741. else if(response !== undefined) {
  742. returnedValue = response;
  743. }
  744. return found;
  745. }
  746. };
  747. if(methodInvoked) {
  748. if(instance === undefined) {
  749. module.initialize();
  750. }
  751. module.invoke(query);
  752. }
  753. else {
  754. if(instance !== undefined) {
  755. instance.invoke('destroy');
  756. }
  757. module.initialize();
  758. }
  759. })
  760. ;
  761. return (returnedValue !== undefined)
  762. ? returnedValue
  763. : this
  764. ;
  765. };
  766. $.fn.sticky.settings = {
  767. name : 'Sticky',
  768. namespace : 'sticky',
  769. debug : false,
  770. verbose : true,
  771. performance : true,
  772. // whether to stick in the opposite direction on scroll up
  773. pushing : false,
  774. context : false,
  775. // Context to watch scroll events
  776. scrollContext : window,
  777. // Offset to adjust scroll
  778. offset : 0,
  779. // Offset to adjust scroll when attached to bottom of screen
  780. bottomOffset : 0,
  781. jitter : 5, // will only set container height if difference between context and container is larger than this number
  782. // Whether to automatically observe changes with Mutation Observers
  783. observeChanges : false,
  784. // Called when position is recalculated
  785. onReposition : function(){},
  786. // Called on each scroll
  787. onScroll : function(){},
  788. // Called when element is stuck to viewport
  789. onStick : function(){},
  790. // Called when element is unstuck from viewport
  791. onUnstick : function(){},
  792. // Called when element reaches top of context
  793. onTop : function(){},
  794. // Called when element reaches bottom of context
  795. onBottom : function(){},
  796. error : {
  797. container : 'Sticky element must be inside a relative container',
  798. visible : 'Element is hidden, you must call refresh after element becomes visible',
  799. method : 'The method you called is not defined.',
  800. invalidContext : 'Context specified does not exist',
  801. elementSize : 'Sticky element is larger than its container, cannot create sticky.'
  802. },
  803. className : {
  804. bound : 'bound',
  805. fixed : 'fixed',
  806. supported : 'native',
  807. top : 'top',
  808. bottom : 'bottom'
  809. }
  810. };
  811. })( jQuery, window , document );