sticky.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  3. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  4. (factory((global.StickySidebar = {})));
  5. }(this, (function (exports) { 'use strict';
  6. var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
  7. function unwrapExports (x) {
  8. return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
  9. }
  10. function createCommonjsModule(fn, module) {
  11. return module = { exports: {} }, fn(module, module.exports), module.exports;
  12. }
  13. var stickySidebar = createCommonjsModule(function (module, exports) {
  14. (function (global, factory) {
  15. if (typeof undefined === "function" && undefined.amd) {
  16. undefined(['exports'], factory);
  17. } else {
  18. factory(exports);
  19. }
  20. })(commonjsGlobal, function (exports) {
  21. Object.defineProperty(exports, "__esModule", {
  22. value: true
  23. });
  24. function _classCallCheck(instance, Constructor) {
  25. if (!(instance instanceof Constructor)) {
  26. throw new TypeError("Cannot call a class as a function");
  27. }
  28. }
  29. var _createClass = function () {
  30. function defineProperties(target, props) {
  31. for (var i = 0; i < props.length; i++) {
  32. var descriptor = props[i];
  33. descriptor.enumerable = descriptor.enumerable || false;
  34. descriptor.configurable = true;
  35. if ("value" in descriptor) descriptor.writable = true;
  36. Object.defineProperty(target, descriptor.key, descriptor);
  37. }
  38. }
  39. return function (Constructor, protoProps, staticProps) {
  40. if (protoProps) defineProperties(Constructor.prototype, protoProps);
  41. if (staticProps) defineProperties(Constructor, staticProps);
  42. return Constructor;
  43. };
  44. }();
  45. /**
  46. * Sticky Sidebar JavaScript Plugin.
  47. * @version 3.3.4
  48. * @author Ahmed Bouhuolia <a.bouhuolia@gmail.com>
  49. * @license The MIT License (MIT)
  50. */
  51. var StickySidebar = function () {
  52. // ---------------------------------
  53. // # Define Constants
  54. // ---------------------------------
  55. //
  56. var EVENT_KEY = '.stickySidebar';
  57. var DEFAULTS = {
  58. /**
  59. * Additional top spacing of the element when it becomes sticky.
  60. * @type {Numeric|Function}
  61. */
  62. topSpacing: 0,
  63. /**
  64. * Additional bottom spacing of the element when it becomes sticky.
  65. * @type {Numeric|Function}
  66. */
  67. bottomSpacing: 0,
  68. /**
  69. * Container sidebar selector to know what the beginning and end of sticky element.
  70. * @type {String|False}
  71. */
  72. containerSelector: false,
  73. /**
  74. * Inner wrapper selector.
  75. * @type {String}
  76. */
  77. innerWrapperSelector: '.inner-wrapper-sticky',
  78. /**
  79. * The name of CSS class to apply to elements when they have become stuck.
  80. * @type {String|False}
  81. */
  82. stickyClass: 'is-affixed',
  83. /**
  84. * Detect when sidebar and its container change height so re-calculate their dimensions.
  85. * @type {Boolean}
  86. */
  87. resizeSensor: true,
  88. /**
  89. * The sidebar returns to its normal position if its width below this value.
  90. * @type {Numeric}
  91. */
  92. minWidth: false
  93. };
  94. // ---------------------------------
  95. // # Class Definition
  96. // ---------------------------------
  97. //
  98. /**
  99. * Sticky Sidebar Class.
  100. * @public
  101. */
  102. var StickySidebar = function () {
  103. /**
  104. * Sticky Sidebar Constructor.
  105. * @constructor
  106. * @param {HTMLElement|String} sidebar - The sidebar element or sidebar selector.
  107. * @param {Object} options - The options of sticky sidebar.
  108. */
  109. function StickySidebar(sidebar) {
  110. var _this = this;
  111. var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  112. _classCallCheck(this, StickySidebar);
  113. this.options = StickySidebar.extend(DEFAULTS, options);
  114. // Sidebar element query if there's no one, throw error.
  115. this.sidebar = 'string' === typeof sidebar ? document.querySelector(sidebar) : sidebar;
  116. if ('undefined' === typeof this.sidebar) throw new Error("There is no specific sidebar element.");
  117. this.sidebarInner = false;
  118. this.container = this.sidebar.parentElement;
  119. // Current Affix Type of sidebar element.
  120. this.affixedType = 'STATIC';
  121. this.direction = 'down';
  122. this.support = {
  123. transform: false,
  124. transform3d: false
  125. };
  126. this._initialized = false;
  127. this._reStyle = false;
  128. this._breakpoint = false;
  129. // Dimensions of sidebar, container and screen viewport.
  130. this.dimensions = {
  131. translateY: 0,
  132. maxTranslateY: 0,
  133. topSpacing: 0,
  134. lastTopSpacing: 0,
  135. bottomSpacing: 0,
  136. lastBottomSpacing: 0,
  137. sidebarHeight: 0,
  138. sidebarWidth: 0,
  139. containerTop: 0,
  140. containerHeight: 0,
  141. viewportHeight: 0,
  142. viewportTop: 0,
  143. lastViewportTop: 0
  144. };
  145. // Bind event handlers for referencability.
  146. ['handleEvent'].forEach(function (method) {
  147. _this[method] = _this[method].bind(_this);
  148. });
  149. // Initialize sticky sidebar for first time.
  150. this.initialize();
  151. }
  152. /**
  153. * Initializes the sticky sidebar by adding inner wrapper, define its container,
  154. * min-width breakpoint, calculating dimensions, adding helper classes and inline style.
  155. * @private
  156. */
  157. _createClass(StickySidebar, [{
  158. key: 'initialize',
  159. value: function initialize() {
  160. var _this2 = this;
  161. this._setSupportFeatures();
  162. // Get sticky sidebar inner wrapper, if not found, will create one.
  163. if (this.options.innerWrapperSelector) {
  164. this.sidebarInner = this.sidebar.querySelector(this.options.innerWrapperSelector);
  165. if (null === this.sidebarInner) this.sidebarInner = false;
  166. }
  167. if (!this.sidebarInner) {
  168. var wrapper = document.createElement('div');
  169. wrapper.setAttribute('class', 'inner-wrapper-sticky');
  170. this.sidebar.appendChild(wrapper);
  171. while (this.sidebar.firstChild != wrapper) {
  172. wrapper.appendChild(this.sidebar.firstChild);
  173. }this.sidebarInner = this.sidebar.querySelector('.inner-wrapper-sticky');
  174. }
  175. // Container wrapper of the sidebar.
  176. if (this.options.containerSelector) {
  177. var containers = document.querySelectorAll(this.options.containerSelector);
  178. containers = Array.prototype.slice.call(containers);
  179. containers.forEach(function (container, item) {
  180. if (!container.contains(_this2.sidebar)) return;
  181. _this2.container = container;
  182. });
  183. if (!containers.length) throw new Error("The container does not contains on the sidebar.");
  184. }
  185. // If top/bottom spacing is not function parse value to integer.
  186. if ('function' !== typeof this.options.topSpacing) this.options.topSpacing = parseInt(this.options.topSpacing) || 0;
  187. if ('function' !== typeof this.options.bottomSpacing) this.options.bottomSpacing = parseInt(this.options.bottomSpacing) || 0;
  188. // Breakdown sticky sidebar if screen width below `options.minWidth`.
  189. this._widthBreakpoint();
  190. // Calculate dimensions of sidebar, container and viewport.
  191. this.calcDimensions();
  192. // Affix sidebar in proper position.
  193. this.stickyPosition();
  194. // Bind all events.
  195. this.bindEvents();
  196. // Inform other properties the sticky sidebar is initialized.
  197. this._initialized = true;
  198. }
  199. }, {
  200. key: 'bindEvents',
  201. value: function bindEvents() {
  202. window.addEventListener('resize', this, { passive: true, capture: false });
  203. window.addEventListener('scroll', this, { passive: true, capture: false });
  204. this.sidebar.addEventListener('update' + EVENT_KEY, this);
  205. if (this.options.resizeSensor && 'undefined' !== typeof ResizeSensor) {
  206. new ResizeSensor(this.sidebarInner, this.handleEvent);
  207. new ResizeSensor(this.container, this.handleEvent);
  208. }
  209. }
  210. }, {
  211. key: 'handleEvent',
  212. value: function handleEvent(event) {
  213. this.updateSticky(event);
  214. }
  215. }, {
  216. key: 'calcDimensions',
  217. value: function calcDimensions() {
  218. if (this._breakpoint) return;
  219. var dims = this.dimensions;
  220. // Container of sticky sidebar dimensions.
  221. dims.containerTop = StickySidebar.offsetRelative(this.container).top;
  222. dims.containerHeight = this.container.clientHeight;
  223. dims.containerBottom = dims.containerTop + dims.containerHeight;
  224. // Sidebar dimensions.
  225. dims.sidebarHeight = this.sidebarInner.offsetHeight;
  226. dims.sidebarWidth = this.sidebarInner.offsetWidth;
  227. // Screen viewport dimensions.
  228. dims.viewportHeight = window.innerHeight;
  229. // Maximum sidebar translate Y.
  230. dims.maxTranslateY = dims.containerHeight - dims.sidebarHeight;
  231. this._calcDimensionsWithScroll();
  232. }
  233. }, {
  234. key: '_calcDimensionsWithScroll',
  235. value: function _calcDimensionsWithScroll() {
  236. var dims = this.dimensions;
  237. dims.sidebarLeft = StickySidebar.offsetRelative(this.sidebar).left;
  238. dims.viewportTop = document.documentElement.scrollTop || document.body.scrollTop;
  239. dims.viewportBottom = dims.viewportTop + dims.viewportHeight;
  240. dims.viewportLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
  241. dims.topSpacing = this.options.topSpacing;
  242. dims.bottomSpacing = this.options.bottomSpacing;
  243. if ('function' === typeof dims.topSpacing) dims.topSpacing = parseInt(dims.topSpacing(this.sidebar)) || 0;
  244. if ('function' === typeof dims.bottomSpacing) dims.bottomSpacing = parseInt(dims.bottomSpacing(this.sidebar)) || 0;
  245. if ('VIEWPORT-TOP' === this.affixedType) {
  246. // Adjust translate Y in the case decrease top spacing value.
  247. if (dims.topSpacing < dims.lastTopSpacing) {
  248. dims.translateY += dims.lastTopSpacing - dims.topSpacing;
  249. this._reStyle = true;
  250. }
  251. } else if ('VIEWPORT-BOTTOM' === this.affixedType) {
  252. // Adjust translate Y in the case decrease bottom spacing value.
  253. if (dims.bottomSpacing < dims.lastBottomSpacing) {
  254. dims.translateY += dims.lastBottomSpacing - dims.bottomSpacing;
  255. this._reStyle = true;
  256. }
  257. }
  258. dims.lastTopSpacing = dims.topSpacing;
  259. dims.lastBottomSpacing = dims.bottomSpacing;
  260. }
  261. }, {
  262. key: 'isSidebarFitsViewport',
  263. value: function isSidebarFitsViewport() {
  264. var dims = this.dimensions;
  265. var offset = this.scrollDirection === 'down' ? dims.lastBottomSpacing : dims.lastTopSpacing;
  266. return this.dimensions.sidebarHeight + offset < this.dimensions.viewportHeight;
  267. }
  268. }, {
  269. key: 'observeScrollDir',
  270. value: function observeScrollDir() {
  271. var dims = this.dimensions;
  272. if (dims.lastViewportTop === dims.viewportTop) return;
  273. var furthest = 'down' === this.direction ? Math.min : Math.max;
  274. // If the browser is scrolling not in the same direction.
  275. if (dims.viewportTop === furthest(dims.viewportTop, dims.lastViewportTop)) this.direction = 'down' === this.direction ? 'up' : 'down';
  276. }
  277. }, {
  278. key: 'getAffixType',
  279. value: function getAffixType() {
  280. this._calcDimensionsWithScroll();
  281. var dims = this.dimensions;
  282. var colliderTop = dims.viewportTop + dims.topSpacing;
  283. var affixType = this.affixedType;
  284. if (colliderTop <= dims.containerTop || dims.containerHeight <= dims.sidebarHeight) {
  285. dims.translateY = 0;
  286. affixType = 'STATIC';
  287. } else {
  288. affixType = 'up' === this.direction ? this._getAffixTypeScrollingUp() : this._getAffixTypeScrollingDown();
  289. }
  290. // Make sure the translate Y is not bigger than container height.
  291. dims.translateY = Math.max(0, dims.translateY);
  292. dims.translateY = Math.min(dims.containerHeight, dims.translateY);
  293. dims.translateY = Math.round(dims.translateY);
  294. dims.lastViewportTop = dims.viewportTop;
  295. return affixType;
  296. }
  297. }, {
  298. key: '_getAffixTypeScrollingDown',
  299. value: function _getAffixTypeScrollingDown() {
  300. var dims = this.dimensions;
  301. var sidebarBottom = dims.sidebarHeight + dims.containerTop;
  302. var colliderTop = dims.viewportTop + dims.topSpacing;
  303. var colliderBottom = dims.viewportBottom - dims.bottomSpacing;
  304. var affixType = this.affixedType;
  305. if (this.isSidebarFitsViewport()) {
  306. if (dims.sidebarHeight + colliderTop >= dims.containerBottom) {
  307. dims.translateY = dims.containerBottom - sidebarBottom;
  308. affixType = 'CONTAINER-BOTTOM';
  309. } else if (colliderTop >= dims.containerTop) {
  310. dims.translateY = colliderTop - dims.containerTop;
  311. affixType = 'VIEWPORT-TOP';
  312. }
  313. } else {
  314. if (dims.containerBottom <= colliderBottom) {
  315. dims.translateY = dims.containerBottom - sidebarBottom;
  316. affixType = 'CONTAINER-BOTTOM';
  317. } else if (sidebarBottom + dims.translateY <= colliderBottom) {
  318. dims.translateY = colliderBottom - sidebarBottom;
  319. affixType = 'VIEWPORT-BOTTOM';
  320. } else if (dims.containerTop + dims.translateY <= colliderTop && 0 !== dims.translateY && dims.maxTranslateY !== dims.translateY) {
  321. affixType = 'VIEWPORT-UNBOTTOM';
  322. }
  323. }
  324. return affixType;
  325. }
  326. }, {
  327. key: '_getAffixTypeScrollingUp',
  328. value: function _getAffixTypeScrollingUp() {
  329. var dims = this.dimensions;
  330. var sidebarBottom = dims.sidebarHeight + dims.containerTop;
  331. var colliderTop = dims.viewportTop + dims.topSpacing;
  332. var colliderBottom = dims.viewportBottom - dims.bottomSpacing;
  333. var affixType = this.affixedType;
  334. if (colliderTop <= dims.translateY + dims.containerTop) {
  335. dims.translateY = colliderTop - dims.containerTop;
  336. affixType = 'VIEWPORT-TOP';
  337. } else if (dims.containerBottom <= colliderBottom) {
  338. dims.translateY = dims.containerBottom - sidebarBottom;
  339. affixType = 'CONTAINER-BOTTOM';
  340. } else if (!this.isSidebarFitsViewport()) {
  341. if (dims.containerTop <= colliderTop && 0 !== dims.translateY && dims.maxTranslateY !== dims.translateY) {
  342. affixType = 'VIEWPORT-UNBOTTOM';
  343. }
  344. }
  345. return affixType;
  346. }
  347. }, {
  348. key: '_getStyle',
  349. value: function _getStyle(affixType) {
  350. if ('undefined' === typeof affixType) return;
  351. var style = { inner: {}, outer: {} };
  352. var dims = this.dimensions;
  353. switch (affixType) {
  354. case 'VIEWPORT-TOP':
  355. style.inner = { position: 'fixed', top: dims.topSpacing,
  356. left: dims.sidebarLeft - dims.viewportLeft, width: dims.sidebarWidth };
  357. break;
  358. case 'VIEWPORT-BOTTOM':
  359. style.inner = { position: 'fixed', top: 'auto', left: dims.sidebarLeft,
  360. bottom: dims.bottomSpacing, width: dims.sidebarWidth };
  361. break;
  362. case 'CONTAINER-BOTTOM':
  363. case 'VIEWPORT-UNBOTTOM':
  364. var translate = this._getTranslate(0, dims.translateY + 'px');
  365. if (translate) style.inner = { transform: translate };else style.inner = { position: 'absolute', top: dims.translateY, width: dims.sidebarWidth };
  366. break;
  367. }
  368. switch (affixType) {
  369. case 'VIEWPORT-TOP':
  370. case 'VIEWPORT-BOTTOM':
  371. case 'VIEWPORT-UNBOTTOM':
  372. case 'CONTAINER-BOTTOM':
  373. style.outer = { height: dims.sidebarHeight, position: 'relative' };
  374. break;
  375. }
  376. style.outer = StickySidebar.extend({ height: '', position: '' }, style.outer);
  377. style.inner = StickySidebar.extend({ position: 'relative', top: '', left: '',
  378. bottom: '', width: '', transform: '' }, style.inner);
  379. return style;
  380. }
  381. }, {
  382. key: 'stickyPosition',
  383. value: function stickyPosition(force) {
  384. if (this._breakpoint) return;
  385. force = this._reStyle || force || false;
  386. var offsetTop = this.options.topSpacing;
  387. var offsetBottom = this.options.bottomSpacing;
  388. var affixType = this.getAffixType();
  389. var style = this._getStyle(affixType);
  390. if ((this.affixedType != affixType || force) && affixType) {
  391. var affixEvent = 'affix.' + affixType.toLowerCase().replace('viewport-', '') + EVENT_KEY;
  392. StickySidebar.eventTrigger(this.sidebar, affixEvent);
  393. if ('STATIC' === affixType) StickySidebar.removeClass(this.sidebar, this.options.stickyClass);else StickySidebar.addClass(this.sidebar, this.options.stickyClass);
  394. for (var key in style.outer) {
  395. var unit = 'number' === typeof style.outer[key] ? 'px' : '';
  396. this.sidebar.style[key] = style.outer[key] + unit;
  397. }
  398. for (var _key in style.inner) {
  399. var _unit = 'number' === typeof style.inner[_key] ? 'px' : '';
  400. this.sidebarInner.style[_key] = style.inner[_key] + _unit;
  401. }
  402. var affixedEvent = 'affixed.' + affixType.toLowerCase().replace('viewport-', '') + EVENT_KEY;
  403. StickySidebar.eventTrigger(this.sidebar, affixedEvent);
  404. } else {
  405. if (this._initialized) this.sidebarInner.style.left = style.inner.left;
  406. }
  407. this.affixedType = affixType;
  408. }
  409. }, {
  410. key: '_widthBreakpoint',
  411. value: function _widthBreakpoint() {
  412. if (window.innerWidth <= this.options.minWidth) {
  413. this._breakpoint = true;
  414. this.affixedType = 'STATIC';
  415. this.sidebar.removeAttribute('style');
  416. StickySidebar.removeClass(this.sidebar, this.options.stickyClass);
  417. this.sidebarInner.removeAttribute('style');
  418. } else {
  419. this._breakpoint = false;
  420. }
  421. }
  422. }, {
  423. key: 'updateSticky',
  424. value: function updateSticky() {
  425. var _this3 = this;
  426. var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  427. if (this._running) return;
  428. this._running = true;
  429. (function (eventType) {
  430. requestAnimationFrame(function () {
  431. switch (eventType) {
  432. // When browser is scrolling and re-calculate just dimensions
  433. // within scroll.
  434. case 'scroll':
  435. _this3._calcDimensionsWithScroll();
  436. _this3.observeScrollDir();
  437. _this3.stickyPosition();
  438. break;
  439. // When browser is resizing or there's no event, observe width
  440. // breakpoint and re-calculate dimensions.
  441. case 'resize':
  442. default:
  443. _this3._widthBreakpoint();
  444. _this3.calcDimensions();
  445. _this3.stickyPosition(true);
  446. break;
  447. }
  448. _this3._running = false;
  449. });
  450. })(event.type);
  451. }
  452. }, {
  453. key: '_setSupportFeatures',
  454. value: function _setSupportFeatures() {
  455. var support = this.support;
  456. support.transform = StickySidebar.supportTransform();
  457. support.transform3d = StickySidebar.supportTransform(true);
  458. }
  459. }, {
  460. key: '_getTranslate',
  461. value: function _getTranslate() {
  462. var y = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
  463. var x = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
  464. var z = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
  465. if (this.support.transform3d) return 'translate3d(' + y + ', ' + x + ', ' + z + ')';else if (this.support.translate) return 'translate(' + y + ', ' + x + ')';else return false;
  466. }
  467. }, {
  468. key: 'destroy',
  469. value: function destroy() {
  470. window.removeEventListener('resize', this, { capture: false });
  471. window.removeEventListener('scroll', this, { capture: false });
  472. this.sidebar.classList.remove(this.options.stickyClass);
  473. this.sidebar.style.minHeight = '';
  474. this.sidebar.removeEventListener('update' + EVENT_KEY, this);
  475. var styleReset = { inner: {}, outer: {} };
  476. styleReset.inner = { position: '', top: '', left: '', bottom: '', width: '', transform: '' };
  477. styleReset.outer = { height: '', position: '' };
  478. for (var key in styleReset.outer) {
  479. this.sidebar.style[key] = styleReset.outer[key];
  480. }for (var _key2 in styleReset.inner) {
  481. this.sidebarInner.style[_key2] = styleReset.inner[_key2];
  482. }if (this.options.resizeSensor && 'undefined' !== typeof ResizeSensor) {
  483. ResizeSensor.detach(this.sidebarInner, this.handleEvent);
  484. ResizeSensor.detach(this.container, this.handleEvent);
  485. }
  486. }
  487. }], [{
  488. key: 'supportTransform',
  489. value: function supportTransform(transform3d) {
  490. var result = false,
  491. property = transform3d ? 'perspective' : 'transform',
  492. upper = property.charAt(0).toUpperCase() + property.slice(1),
  493. prefixes = ['Webkit', 'Moz', 'O', 'ms'],
  494. support = document.createElement('support'),
  495. style = support.style;
  496. (property + ' ' + prefixes.join(upper + ' ') + upper).split(' ').forEach(function (property, i) {
  497. if (style[property] !== undefined) {
  498. result = property;
  499. return false;
  500. }
  501. });
  502. return result;
  503. }
  504. }, {
  505. key: 'eventTrigger',
  506. value: function eventTrigger(element, eventName, data) {
  507. try {
  508. var event = new CustomEvent(eventName, { detail: data });
  509. } catch (e) {
  510. var event = document.createEvent('CustomEvent');
  511. event.initCustomEvent(eventName, true, true, data);
  512. }
  513. element.dispatchEvent(event);
  514. }
  515. }, {
  516. key: 'extend',
  517. value: function extend(defaults, options) {
  518. var results = {};
  519. for (var key in defaults) {
  520. if ('undefined' !== typeof options[key]) results[key] = options[key];else results[key] = defaults[key];
  521. }
  522. return results;
  523. }
  524. }, {
  525. key: 'offsetRelative',
  526. value: function offsetRelative(element) {
  527. var result = { left: 0, top: 0 };
  528. do {
  529. var offsetTop = element.offsetTop;
  530. var offsetLeft = element.offsetLeft;
  531. if (!isNaN(offsetTop)) result.top += offsetTop;
  532. if (!isNaN(offsetLeft)) result.left += offsetLeft;
  533. element = 'BODY' === element.tagName ? element.parentElement : element.offsetParent;
  534. } while (element);
  535. return result;
  536. }
  537. }, {
  538. key: 'addClass',
  539. value: function addClass(element, className) {
  540. if (!StickySidebar.hasClass(element, className)) {
  541. if (element.classList) element.classList.add(className);else element.className += ' ' + className;
  542. }
  543. }
  544. }, {
  545. key: 'removeClass',
  546. value: function removeClass(element, className) {
  547. if (StickySidebar.hasClass(element, className)) {
  548. if (element.classList) element.classList.remove(className);else element.className = element.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
  549. }
  550. }
  551. }, {
  552. key: 'hasClass',
  553. value: function hasClass(element, className) {
  554. if (element.classList) return element.classList.contains(className);else return new RegExp('(^| )' + className + '( |$)', 'gi').test(element.className);
  555. }
  556. }, {
  557. key: 'defaults',
  558. get: function () {
  559. return DEFAULTS;
  560. }
  561. }]);
  562. return StickySidebar;
  563. }();
  564. return StickySidebar;
  565. }();
  566. exports.default = StickySidebar;
  567. // Global
  568. // -------------------------
  569. window.StickySidebar = StickySidebar;
  570. });
  571. });
  572. var stickySidebar$1 = unwrapExports(stickySidebar);
  573. exports['default'] = stickySidebar$1;
  574. exports.__moduleExports = stickySidebar;
  575. Object.defineProperty(exports, '__esModule', { value: true });
  576. })));
  577. //# sourceMappingURL=sticky-sidebar.js.map