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.

906 lines
28 KiB

  1. /*!
  2. * # Semantic UI 2.1.6 - 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. scrollContext = {
  199. height : $scroll.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. if( !module.is.standardScroll() ) {
  219. module.debug('Non-standard scroll. Removing scroll offset from element offset');
  220. scrollContext.top = $scroll.scrollTop();
  221. scrollContext.left = $scroll.scrollLeft();
  222. element.offset.top += scrollContext.top;
  223. context.offset.top += scrollContext.top;
  224. element.offset.left += scrollContext.left;
  225. context.offset.left += scrollContext.left;
  226. }
  227. module.cache = {
  228. fits : ( element.height < scrollContext.height ),
  229. scrollContext : {
  230. height : scrollContext.height
  231. },
  232. element: {
  233. margin : element.margin,
  234. top : element.offset.top - element.margin.top,
  235. left : element.offset.left,
  236. width : element.width,
  237. height : element.height,
  238. bottom : element.offset.top + element.height
  239. },
  240. context: {
  241. top : context.offset.top,
  242. height : context.height,
  243. bottom : context.offset.top + context.height
  244. }
  245. };
  246. module.set.containerSize();
  247. module.set.size();
  248. module.stick();
  249. module.debug('Caching element positions', module.cache);
  250. }
  251. },
  252. get: {
  253. direction: function(scroll) {
  254. var
  255. direction = 'down'
  256. ;
  257. scroll = scroll || $scroll.scrollTop();
  258. if(module.lastScroll !== undefined) {
  259. if(module.lastScroll < scroll) {
  260. direction = 'down';
  261. }
  262. else if(module.lastScroll > scroll) {
  263. direction = 'up';
  264. }
  265. }
  266. return direction;
  267. },
  268. scrollChange: function(scroll) {
  269. scroll = scroll || $scroll.scrollTop();
  270. return (module.lastScroll)
  271. ? (scroll - module.lastScroll)
  272. : 0
  273. ;
  274. },
  275. currentElementScroll: function() {
  276. if(module.elementScroll) {
  277. return module.elementScroll;
  278. }
  279. return ( module.is.top() )
  280. ? Math.abs(parseInt($module.css('top'), 10)) || 0
  281. : Math.abs(parseInt($module.css('bottom'), 10)) || 0
  282. ;
  283. },
  284. elementScroll: function(scroll) {
  285. scroll = scroll || $scroll.scrollTop();
  286. var
  287. element = module.cache.element,
  288. scrollContext = module.cache.scrollContext,
  289. delta = module.get.scrollChange(scroll),
  290. maxScroll = (element.height - scrollContext.height + settings.offset),
  291. elementScroll = module.get.currentElementScroll(),
  292. possibleScroll = (elementScroll + delta)
  293. ;
  294. if(module.cache.fits || possibleScroll < 0) {
  295. elementScroll = 0;
  296. }
  297. else if(possibleScroll > maxScroll ) {
  298. elementScroll = maxScroll;
  299. }
  300. else {
  301. elementScroll = possibleScroll;
  302. }
  303. return elementScroll;
  304. }
  305. },
  306. remove: {
  307. lastScroll: function() {
  308. delete module.lastScroll;
  309. },
  310. elementScroll: function(scroll) {
  311. delete module.elementScroll;
  312. },
  313. offset: function() {
  314. $module.css('margin-top', '');
  315. }
  316. },
  317. set: {
  318. offset: function() {
  319. module.verbose('Setting offset on element', settings.offset);
  320. $module
  321. .css('margin-top', settings.offset)
  322. ;
  323. },
  324. containerSize: function() {
  325. var
  326. tagName = $container.get(0).tagName
  327. ;
  328. if(tagName === 'HTML' || tagName == 'body') {
  329. // this can trigger for too many reasons
  330. //module.error(error.container, tagName, $module);
  331. module.determineContainer();
  332. }
  333. else {
  334. if( Math.abs($container.outerHeight() - module.cache.context.height) > settings.jitter) {
  335. module.debug('Context has padding, specifying exact height for container', module.cache.context.height);
  336. $container.css({
  337. height: module.cache.context.height
  338. });
  339. }
  340. }
  341. },
  342. minimumSize: function() {
  343. var
  344. element = module.cache.element
  345. ;
  346. $container
  347. .css('min-height', element.height)
  348. ;
  349. },
  350. scroll: function(scroll) {
  351. module.debug('Setting scroll on element', scroll);
  352. if(module.elementScroll == scroll) {
  353. return;
  354. }
  355. if( module.is.top() ) {
  356. $module
  357. .css('bottom', '')
  358. .css('top', -scroll)
  359. ;
  360. }
  361. if( module.is.bottom() ) {
  362. $module
  363. .css('top', '')
  364. .css('bottom', scroll)
  365. ;
  366. }
  367. },
  368. size: function() {
  369. if(module.cache.element.height !== 0 && module.cache.element.width !== 0) {
  370. element.style.setProperty('width', module.cache.element.width + 'px', 'important');
  371. element.style.setProperty('height', module.cache.element.height + 'px', 'important');
  372. }
  373. }
  374. },
  375. is: {
  376. standardScroll: function() {
  377. return ($scroll[0] == window);
  378. },
  379. top: function() {
  380. return $module.hasClass(className.top);
  381. },
  382. bottom: function() {
  383. return $module.hasClass(className.bottom);
  384. },
  385. initialPosition: function() {
  386. return (!module.is.fixed() && !module.is.bound());
  387. },
  388. hidden: function() {
  389. return (!$module.is(':visible'));
  390. },
  391. bound: function() {
  392. return $module.hasClass(className.bound);
  393. },
  394. fixed: function() {
  395. return $module.hasClass(className.fixed);
  396. }
  397. },
  398. stick: function(scroll) {
  399. var
  400. cachedPosition = scroll || $scroll.scrollTop(),
  401. cache = module.cache,
  402. fits = cache.fits,
  403. element = cache.element,
  404. scrollContext = cache.scrollContext,
  405. context = cache.context,
  406. offset = (module.is.bottom() && settings.pushing)
  407. ? settings.bottomOffset
  408. : settings.offset,
  409. scroll = {
  410. top : cachedPosition + offset,
  411. bottom : cachedPosition + offset + scrollContext.height
  412. },
  413. direction = module.get.direction(scroll.top),
  414. elementScroll = (fits)
  415. ? 0
  416. : module.get.elementScroll(scroll.top),
  417. // shorthand
  418. doesntFit = !fits,
  419. elementVisible = (element.height !== 0)
  420. ;
  421. if(elementVisible) {
  422. if( module.is.initialPosition() ) {
  423. if(scroll.top >= context.bottom) {
  424. module.debug('Initial element position is bottom of container');
  425. module.bindBottom();
  426. }
  427. else if(scroll.top > element.top) {
  428. if( (element.height + scroll.top - elementScroll) >= context.bottom ) {
  429. module.debug('Initial element position is bottom of container');
  430. module.bindBottom();
  431. }
  432. else {
  433. module.debug('Initial element position is fixed');
  434. module.fixTop();
  435. }
  436. }
  437. }
  438. else if( module.is.fixed() ) {
  439. // currently fixed top
  440. if( module.is.top() ) {
  441. if( scroll.top <= element.top ) {
  442. module.debug('Fixed element reached top of container');
  443. module.setInitialPosition();
  444. }
  445. else if( (element.height + scroll.top - elementScroll) >= context.bottom ) {
  446. module.debug('Fixed element reached bottom of container');
  447. module.bindBottom();
  448. }
  449. // scroll element if larger than screen
  450. else if(doesntFit) {
  451. module.set.scroll(elementScroll);
  452. module.save.lastScroll(scroll.top);
  453. module.save.elementScroll(elementScroll);
  454. }
  455. }
  456. // currently fixed bottom
  457. else if(module.is.bottom() ) {
  458. // top edge
  459. if( (scroll.bottom - element.height) <= element.top) {
  460. module.debug('Bottom fixed rail has reached top of container');
  461. module.setInitialPosition();
  462. }
  463. // bottom edge
  464. else if(scroll.bottom >= context.bottom) {
  465. module.debug('Bottom fixed rail has reached bottom of container');
  466. module.bindBottom();
  467. }
  468. // scroll element if larger than screen
  469. else if(doesntFit) {
  470. module.set.scroll(elementScroll);
  471. module.save.lastScroll(scroll.top);
  472. module.save.elementScroll(elementScroll);
  473. }
  474. }
  475. }
  476. else if( module.is.bottom() ) {
  477. if( scroll.top <= element.top ) {
  478. module.debug('Jumped from bottom fixed to top fixed, most likely used home/end button');
  479. module.setInitialPosition();
  480. }
  481. else {
  482. if(settings.pushing) {
  483. if(module.is.bound() && scroll.bottom <= context.bottom ) {
  484. module.debug('Fixing bottom attached element to bottom of browser.');
  485. module.fixBottom();
  486. }
  487. }
  488. else {
  489. if(module.is.bound() && (scroll.top <= context.bottom - element.height) ) {
  490. module.debug('Fixing bottom attached element to top of browser.');
  491. module.fixTop();
  492. }
  493. }
  494. }
  495. }
  496. }
  497. },
  498. bindTop: function() {
  499. module.debug('Binding element to top of parent container');
  500. module.remove.offset();
  501. $module
  502. .css({
  503. left : '',
  504. top : '',
  505. marginBottom : ''
  506. })
  507. .removeClass(className.fixed)
  508. .removeClass(className.bottom)
  509. .addClass(className.bound)
  510. .addClass(className.top)
  511. ;
  512. settings.onTop.call(element);
  513. settings.onUnstick.call(element);
  514. },
  515. bindBottom: function() {
  516. module.debug('Binding element to bottom of parent container');
  517. module.remove.offset();
  518. $module
  519. .css({
  520. left : '',
  521. top : ''
  522. })
  523. .removeClass(className.fixed)
  524. .removeClass(className.top)
  525. .addClass(className.bound)
  526. .addClass(className.bottom)
  527. ;
  528. settings.onBottom.call(element);
  529. settings.onUnstick.call(element);
  530. },
  531. setInitialPosition: function() {
  532. module.debug('Returning to initial position');
  533. module.unfix();
  534. module.unbind();
  535. },
  536. fixTop: function() {
  537. module.debug('Fixing element to top of page');
  538. module.set.minimumSize();
  539. module.set.offset();
  540. $module
  541. .css({
  542. left : module.cache.element.left,
  543. bottom : '',
  544. marginBottom : ''
  545. })
  546. .removeClass(className.bound)
  547. .removeClass(className.bottom)
  548. .addClass(className.fixed)
  549. .addClass(className.top)
  550. ;
  551. settings.onStick.call(element);
  552. },
  553. fixBottom: function() {
  554. module.debug('Sticking element to bottom of page');
  555. module.set.minimumSize();
  556. module.set.offset();
  557. $module
  558. .css({
  559. left : module.cache.element.left,
  560. bottom : '',
  561. marginBottom : ''
  562. })
  563. .removeClass(className.bound)
  564. .removeClass(className.top)
  565. .addClass(className.fixed)
  566. .addClass(className.bottom)
  567. ;
  568. settings.onStick.call(element);
  569. },
  570. unbind: function() {
  571. if( module.is.bound() ) {
  572. module.debug('Removing container bound position on element');
  573. module.remove.offset();
  574. $module
  575. .removeClass(className.bound)
  576. .removeClass(className.top)
  577. .removeClass(className.bottom)
  578. ;
  579. }
  580. },
  581. unfix: function() {
  582. if( module.is.fixed() ) {
  583. module.debug('Removing fixed position on element');
  584. module.remove.offset();
  585. $module
  586. .removeClass(className.fixed)
  587. .removeClass(className.top)
  588. .removeClass(className.bottom)
  589. ;
  590. settings.onUnstick.call(element);
  591. }
  592. },
  593. reset: function() {
  594. module.debug('Reseting elements position');
  595. module.unbind();
  596. module.unfix();
  597. module.resetCSS();
  598. module.remove.offset();
  599. module.remove.lastScroll();
  600. },
  601. resetCSS: function() {
  602. $module
  603. .css({
  604. width : '',
  605. height : ''
  606. })
  607. ;
  608. $container
  609. .css({
  610. height: ''
  611. })
  612. ;
  613. },
  614. setting: function(name, value) {
  615. if( $.isPlainObject(name) ) {
  616. $.extend(true, settings, name);
  617. }
  618. else if(value !== undefined) {
  619. settings[name] = value;
  620. }
  621. else {
  622. return settings[name];
  623. }
  624. },
  625. internal: function(name, value) {
  626. if( $.isPlainObject(name) ) {
  627. $.extend(true, module, name);
  628. }
  629. else if(value !== undefined) {
  630. module[name] = value;
  631. }
  632. else {
  633. return module[name];
  634. }
  635. },
  636. debug: function() {
  637. if(settings.debug) {
  638. if(settings.performance) {
  639. module.performance.log(arguments);
  640. }
  641. else {
  642. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  643. module.debug.apply(console, arguments);
  644. }
  645. }
  646. },
  647. verbose: function() {
  648. if(settings.verbose && settings.debug) {
  649. if(settings.performance) {
  650. module.performance.log(arguments);
  651. }
  652. else {
  653. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  654. module.verbose.apply(console, arguments);
  655. }
  656. }
  657. },
  658. error: function() {
  659. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  660. module.error.apply(console, arguments);
  661. },
  662. performance: {
  663. log: function(message) {
  664. var
  665. currentTime,
  666. executionTime,
  667. previousTime
  668. ;
  669. if(settings.performance) {
  670. currentTime = new Date().getTime();
  671. previousTime = time || currentTime;
  672. executionTime = currentTime - previousTime;
  673. time = currentTime;
  674. performance.push({
  675. 'Name' : message[0],
  676. 'Arguments' : [].slice.call(message, 1) || '',
  677. 'Element' : element,
  678. 'Execution Time' : executionTime
  679. });
  680. }
  681. clearTimeout(module.performance.timer);
  682. module.performance.timer = setTimeout(module.performance.display, 0);
  683. },
  684. display: function() {
  685. var
  686. title = settings.name + ':',
  687. totalTime = 0
  688. ;
  689. time = false;
  690. clearTimeout(module.performance.timer);
  691. $.each(performance, function(index, data) {
  692. totalTime += data['Execution Time'];
  693. });
  694. title += ' ' + totalTime + 'ms';
  695. if(moduleSelector) {
  696. title += ' \'' + moduleSelector + '\'';
  697. }
  698. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  699. console.groupCollapsed(title);
  700. if(console.table) {
  701. console.table(performance);
  702. }
  703. else {
  704. $.each(performance, function(index, data) {
  705. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  706. });
  707. }
  708. console.groupEnd();
  709. }
  710. performance = [];
  711. }
  712. },
  713. invoke: function(query, passedArguments, context) {
  714. var
  715. object = instance,
  716. maxDepth,
  717. found,
  718. response
  719. ;
  720. passedArguments = passedArguments || queryArguments;
  721. context = element || context;
  722. if(typeof query == 'string' && object !== undefined) {
  723. query = query.split(/[\. ]/);
  724. maxDepth = query.length - 1;
  725. $.each(query, function(depth, value) {
  726. var camelCaseValue = (depth != maxDepth)
  727. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  728. : query
  729. ;
  730. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  731. object = object[camelCaseValue];
  732. }
  733. else if( object[camelCaseValue] !== undefined ) {
  734. found = object[camelCaseValue];
  735. return false;
  736. }
  737. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  738. object = object[value];
  739. }
  740. else if( object[value] !== undefined ) {
  741. found = object[value];
  742. return false;
  743. }
  744. else {
  745. return false;
  746. }
  747. });
  748. }
  749. if ( $.isFunction( found ) ) {
  750. response = found.apply(context, passedArguments);
  751. }
  752. else if(found !== undefined) {
  753. response = found;
  754. }
  755. if($.isArray(returnedValue)) {
  756. returnedValue.push(response);
  757. }
  758. else if(returnedValue !== undefined) {
  759. returnedValue = [returnedValue, response];
  760. }
  761. else if(response !== undefined) {
  762. returnedValue = response;
  763. }
  764. return found;
  765. }
  766. };
  767. if(methodInvoked) {
  768. if(instance === undefined) {
  769. module.initialize();
  770. }
  771. module.invoke(query);
  772. }
  773. else {
  774. if(instance !== undefined) {
  775. instance.invoke('destroy');
  776. }
  777. module.initialize();
  778. }
  779. })
  780. ;
  781. return (returnedValue !== undefined)
  782. ? returnedValue
  783. : this
  784. ;
  785. };
  786. $.fn.sticky.settings = {
  787. name : 'Sticky',
  788. namespace : 'sticky',
  789. debug : false,
  790. verbose : true,
  791. performance : true,
  792. // whether to stick in the opposite direction on scroll up
  793. pushing : false,
  794. context : false,
  795. // Context to watch scroll events
  796. scrollContext : window,
  797. // Offset to adjust scroll
  798. offset : 0,
  799. // Offset to adjust scroll when attached to bottom of screen
  800. bottomOffset : 0,
  801. jitter : 5, // will only set container height if difference between context and container is larger than this number
  802. // Whether to automatically observe changes with Mutation Observers
  803. observeChanges : false,
  804. // Called when position is recalculated
  805. onReposition : function(){},
  806. // Called on each scroll
  807. onScroll : function(){},
  808. // Called when element is stuck to viewport
  809. onStick : function(){},
  810. // Called when element is unstuck from viewport
  811. onUnstick : function(){},
  812. // Called when element reaches top of context
  813. onTop : function(){},
  814. // Called when element reaches bottom of context
  815. onBottom : function(){},
  816. error : {
  817. container : 'Sticky element must be inside a relative container',
  818. visible : 'Element is hidden, you must call refresh after element becomes visible',
  819. method : 'The method you called is not defined.',
  820. invalidContext : 'Context specified does not exist',
  821. elementSize : 'Sticky element is larger than its container, cannot create sticky.'
  822. },
  823. className : {
  824. bound : 'bound',
  825. fixed : 'fixed',
  826. supported : 'native',
  827. top : 'top',
  828. bottom : 'bottom'
  829. }
  830. };
  831. })( jQuery, window, document );