| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692 |
- (function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
- (factory((global.StickySidebar = {})));
- }(this, (function (exports) { 'use strict';
- var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
- function unwrapExports (x) {
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
- }
- function createCommonjsModule(fn, module) {
- return module = { exports: {} }, fn(module, module.exports), module.exports;
- }
- var stickySidebar = createCommonjsModule(function (module, exports) {
- (function (global, factory) {
- if (typeof undefined === "function" && undefined.amd) {
- undefined(['exports'], factory);
- } else {
- factory(exports);
- }
- })(commonjsGlobal, function (exports) {
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- function _classCallCheck(instance, Constructor) {
- if (!(instance instanceof Constructor)) {
- throw new TypeError("Cannot call a class as a function");
- }
- }
- var _createClass = function () {
- function defineProperties(target, props) {
- for (var i = 0; i < props.length; i++) {
- var descriptor = props[i];
- descriptor.enumerable = descriptor.enumerable || false;
- descriptor.configurable = true;
- if ("value" in descriptor) descriptor.writable = true;
- Object.defineProperty(target, descriptor.key, descriptor);
- }
- }
- return function (Constructor, protoProps, staticProps) {
- if (protoProps) defineProperties(Constructor.prototype, protoProps);
- if (staticProps) defineProperties(Constructor, staticProps);
- return Constructor;
- };
- }();
- /**
- * Sticky Sidebar JavaScript Plugin.
- * @version 3.3.4
- * @author Ahmed Bouhuolia <a.bouhuolia@gmail.com>
- * @license The MIT License (MIT)
- */
- var StickySidebar = function () {
- // ---------------------------------
- // # Define Constants
- // ---------------------------------
- //
- var EVENT_KEY = '.stickySidebar';
- var DEFAULTS = {
- /**
- * Additional top spacing of the element when it becomes sticky.
- * @type {Numeric|Function}
- */
- topSpacing: 0,
- /**
- * Additional bottom spacing of the element when it becomes sticky.
- * @type {Numeric|Function}
- */
- bottomSpacing: 0,
- /**
- * Container sidebar selector to know what the beginning and end of sticky element.
- * @type {String|False}
- */
- containerSelector: false,
- /**
- * Inner wrapper selector.
- * @type {String}
- */
- innerWrapperSelector: '.inner-wrapper-sticky',
- /**
- * The name of CSS class to apply to elements when they have become stuck.
- * @type {String|False}
- */
- stickyClass: 'is-affixed',
- /**
- * Detect when sidebar and its container change height so re-calculate their dimensions.
- * @type {Boolean}
- */
- resizeSensor: true,
- /**
- * The sidebar returns to its normal position if its width below this value.
- * @type {Numeric}
- */
- minWidth: false
- };
- // ---------------------------------
- // # Class Definition
- // ---------------------------------
- //
- /**
- * Sticky Sidebar Class.
- * @public
- */
- var StickySidebar = function () {
- /**
- * Sticky Sidebar Constructor.
- * @constructor
- * @param {HTMLElement|String} sidebar - The sidebar element or sidebar selector.
- * @param {Object} options - The options of sticky sidebar.
- */
- function StickySidebar(sidebar) {
- var _this = this;
- var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
- _classCallCheck(this, StickySidebar);
- this.options = StickySidebar.extend(DEFAULTS, options);
- // Sidebar element query if there's no one, throw error.
- this.sidebar = 'string' === typeof sidebar ? document.querySelector(sidebar) : sidebar;
- if ('undefined' === typeof this.sidebar) throw new Error("There is no specific sidebar element.");
- this.sidebarInner = false;
- this.container = this.sidebar.parentElement;
- // Current Affix Type of sidebar element.
- this.affixedType = 'STATIC';
- this.direction = 'down';
- this.support = {
- transform: false,
- transform3d: false
- };
- this._initialized = false;
- this._reStyle = false;
- this._breakpoint = false;
- // Dimensions of sidebar, container and screen viewport.
- this.dimensions = {
- translateY: 0,
- maxTranslateY: 0,
- topSpacing: 0,
- lastTopSpacing: 0,
- bottomSpacing: 0,
- lastBottomSpacing: 0,
- sidebarHeight: 0,
- sidebarWidth: 0,
- containerTop: 0,
- containerHeight: 0,
- viewportHeight: 0,
- viewportTop: 0,
- lastViewportTop: 0
- };
- // Bind event handlers for referencability.
- ['handleEvent'].forEach(function (method) {
- _this[method] = _this[method].bind(_this);
- });
- // Initialize sticky sidebar for first time.
- this.initialize();
- }
- /**
- * Initializes the sticky sidebar by adding inner wrapper, define its container,
- * min-width breakpoint, calculating dimensions, adding helper classes and inline style.
- * @private
- */
- _createClass(StickySidebar, [{
- key: 'initialize',
- value: function initialize() {
- var _this2 = this;
- this._setSupportFeatures();
- // Get sticky sidebar inner wrapper, if not found, will create one.
- if (this.options.innerWrapperSelector) {
- this.sidebarInner = this.sidebar.querySelector(this.options.innerWrapperSelector);
- if (null === this.sidebarInner) this.sidebarInner = false;
- }
- if (!this.sidebarInner) {
- var wrapper = document.createElement('div');
- wrapper.setAttribute('class', 'inner-wrapper-sticky');
- this.sidebar.appendChild(wrapper);
- while (this.sidebar.firstChild != wrapper) {
- wrapper.appendChild(this.sidebar.firstChild);
- }this.sidebarInner = this.sidebar.querySelector('.inner-wrapper-sticky');
- }
- // Container wrapper of the sidebar.
- if (this.options.containerSelector) {
- var containers = document.querySelectorAll(this.options.containerSelector);
- containers = Array.prototype.slice.call(containers);
- containers.forEach(function (container, item) {
- if (!container.contains(_this2.sidebar)) return;
- _this2.container = container;
- });
- if (!containers.length) throw new Error("The container does not contains on the sidebar.");
- }
- // If top/bottom spacing is not function parse value to integer.
- if ('function' !== typeof this.options.topSpacing) this.options.topSpacing = parseInt(this.options.topSpacing) || 0;
- if ('function' !== typeof this.options.bottomSpacing) this.options.bottomSpacing = parseInt(this.options.bottomSpacing) || 0;
- // Breakdown sticky sidebar if screen width below `options.minWidth`.
- this._widthBreakpoint();
- // Calculate dimensions of sidebar, container and viewport.
- this.calcDimensions();
- // Affix sidebar in proper position.
- this.stickyPosition();
- // Bind all events.
- this.bindEvents();
- // Inform other properties the sticky sidebar is initialized.
- this._initialized = true;
- }
- }, {
- key: 'bindEvents',
- value: function bindEvents() {
- window.addEventListener('resize', this, { passive: true, capture: false });
- window.addEventListener('scroll', this, { passive: true, capture: false });
- this.sidebar.addEventListener('update' + EVENT_KEY, this);
- if (this.options.resizeSensor && 'undefined' !== typeof ResizeSensor) {
- new ResizeSensor(this.sidebarInner, this.handleEvent);
- new ResizeSensor(this.container, this.handleEvent);
- }
- }
- }, {
- key: 'handleEvent',
- value: function handleEvent(event) {
- this.updateSticky(event);
- }
- }, {
- key: 'calcDimensions',
- value: function calcDimensions() {
- if (this._breakpoint) return;
- var dims = this.dimensions;
- // Container of sticky sidebar dimensions.
- dims.containerTop = StickySidebar.offsetRelative(this.container).top;
- dims.containerHeight = this.container.clientHeight;
- dims.containerBottom = dims.containerTop + dims.containerHeight;
- // Sidebar dimensions.
- dims.sidebarHeight = this.sidebarInner.offsetHeight;
- dims.sidebarWidth = this.sidebarInner.offsetWidth;
- // Screen viewport dimensions.
- dims.viewportHeight = window.innerHeight;
- // Maximum sidebar translate Y.
- dims.maxTranslateY = dims.containerHeight - dims.sidebarHeight;
- this._calcDimensionsWithScroll();
- }
- }, {
- key: '_calcDimensionsWithScroll',
- value: function _calcDimensionsWithScroll() {
- var dims = this.dimensions;
- dims.sidebarLeft = StickySidebar.offsetRelative(this.sidebar).left;
- dims.viewportTop = document.documentElement.scrollTop || document.body.scrollTop;
- dims.viewportBottom = dims.viewportTop + dims.viewportHeight;
- dims.viewportLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
- dims.topSpacing = this.options.topSpacing;
- dims.bottomSpacing = this.options.bottomSpacing;
- if ('function' === typeof dims.topSpacing) dims.topSpacing = parseInt(dims.topSpacing(this.sidebar)) || 0;
- if ('function' === typeof dims.bottomSpacing) dims.bottomSpacing = parseInt(dims.bottomSpacing(this.sidebar)) || 0;
- if ('VIEWPORT-TOP' === this.affixedType) {
- // Adjust translate Y in the case decrease top spacing value.
- if (dims.topSpacing < dims.lastTopSpacing) {
- dims.translateY += dims.lastTopSpacing - dims.topSpacing;
- this._reStyle = true;
- }
- } else if ('VIEWPORT-BOTTOM' === this.affixedType) {
- // Adjust translate Y in the case decrease bottom spacing value.
- if (dims.bottomSpacing < dims.lastBottomSpacing) {
- dims.translateY += dims.lastBottomSpacing - dims.bottomSpacing;
- this._reStyle = true;
- }
- }
- dims.lastTopSpacing = dims.topSpacing;
- dims.lastBottomSpacing = dims.bottomSpacing;
- }
- }, {
- key: 'isSidebarFitsViewport',
- value: function isSidebarFitsViewport() {
- var dims = this.dimensions;
- var offset = this.scrollDirection === 'down' ? dims.lastBottomSpacing : dims.lastTopSpacing;
- return this.dimensions.sidebarHeight + offset < this.dimensions.viewportHeight;
- }
- }, {
- key: 'observeScrollDir',
- value: function observeScrollDir() {
- var dims = this.dimensions;
- if (dims.lastViewportTop === dims.viewportTop) return;
- var furthest = 'down' === this.direction ? Math.min : Math.max;
- // If the browser is scrolling not in the same direction.
- if (dims.viewportTop === furthest(dims.viewportTop, dims.lastViewportTop)) this.direction = 'down' === this.direction ? 'up' : 'down';
- }
- }, {
- key: 'getAffixType',
- value: function getAffixType() {
- this._calcDimensionsWithScroll();
- var dims = this.dimensions;
- var colliderTop = dims.viewportTop + dims.topSpacing;
- var affixType = this.affixedType;
- if (colliderTop <= dims.containerTop || dims.containerHeight <= dims.sidebarHeight) {
- dims.translateY = 0;
- affixType = 'STATIC';
- } else {
- affixType = 'up' === this.direction ? this._getAffixTypeScrollingUp() : this._getAffixTypeScrollingDown();
- }
- // Make sure the translate Y is not bigger than container height.
- dims.translateY = Math.max(0, dims.translateY);
- dims.translateY = Math.min(dims.containerHeight, dims.translateY);
- dims.translateY = Math.round(dims.translateY);
- dims.lastViewportTop = dims.viewportTop;
- return affixType;
- }
- }, {
- key: '_getAffixTypeScrollingDown',
- value: function _getAffixTypeScrollingDown() {
- var dims = this.dimensions;
- var sidebarBottom = dims.sidebarHeight + dims.containerTop;
- var colliderTop = dims.viewportTop + dims.topSpacing;
- var colliderBottom = dims.viewportBottom - dims.bottomSpacing;
- var affixType = this.affixedType;
- if (this.isSidebarFitsViewport()) {
- if (dims.sidebarHeight + colliderTop >= dims.containerBottom) {
- dims.translateY = dims.containerBottom - sidebarBottom;
- affixType = 'CONTAINER-BOTTOM';
- } else if (colliderTop >= dims.containerTop) {
- dims.translateY = colliderTop - dims.containerTop;
- affixType = 'VIEWPORT-TOP';
- }
- } else {
- if (dims.containerBottom <= colliderBottom) {
- dims.translateY = dims.containerBottom - sidebarBottom;
- affixType = 'CONTAINER-BOTTOM';
- } else if (sidebarBottom + dims.translateY <= colliderBottom) {
- dims.translateY = colliderBottom - sidebarBottom;
- affixType = 'VIEWPORT-BOTTOM';
- } else if (dims.containerTop + dims.translateY <= colliderTop && 0 !== dims.translateY && dims.maxTranslateY !== dims.translateY) {
- affixType = 'VIEWPORT-UNBOTTOM';
- }
- }
- return affixType;
- }
- }, {
- key: '_getAffixTypeScrollingUp',
- value: function _getAffixTypeScrollingUp() {
- var dims = this.dimensions;
- var sidebarBottom = dims.sidebarHeight + dims.containerTop;
- var colliderTop = dims.viewportTop + dims.topSpacing;
- var colliderBottom = dims.viewportBottom - dims.bottomSpacing;
- var affixType = this.affixedType;
- if (colliderTop <= dims.translateY + dims.containerTop) {
- dims.translateY = colliderTop - dims.containerTop;
- affixType = 'VIEWPORT-TOP';
- } else if (dims.containerBottom <= colliderBottom) {
- dims.translateY = dims.containerBottom - sidebarBottom;
- affixType = 'CONTAINER-BOTTOM';
- } else if (!this.isSidebarFitsViewport()) {
- if (dims.containerTop <= colliderTop && 0 !== dims.translateY && dims.maxTranslateY !== dims.translateY) {
- affixType = 'VIEWPORT-UNBOTTOM';
- }
- }
- return affixType;
- }
- }, {
- key: '_getStyle',
- value: function _getStyle(affixType) {
- if ('undefined' === typeof affixType) return;
- var style = { inner: {}, outer: {} };
- var dims = this.dimensions;
- switch (affixType) {
- case 'VIEWPORT-TOP':
- style.inner = { position: 'fixed', top: dims.topSpacing,
- left: dims.sidebarLeft - dims.viewportLeft, width: dims.sidebarWidth };
- break;
- case 'VIEWPORT-BOTTOM':
- style.inner = { position: 'fixed', top: 'auto', left: dims.sidebarLeft,
- bottom: dims.bottomSpacing, width: dims.sidebarWidth };
- break;
- case 'CONTAINER-BOTTOM':
- case 'VIEWPORT-UNBOTTOM':
- var translate = this._getTranslate(0, dims.translateY + 'px');
- if (translate) style.inner = { transform: translate };else style.inner = { position: 'absolute', top: dims.translateY, width: dims.sidebarWidth };
- break;
- }
- switch (affixType) {
- case 'VIEWPORT-TOP':
- case 'VIEWPORT-BOTTOM':
- case 'VIEWPORT-UNBOTTOM':
- case 'CONTAINER-BOTTOM':
- style.outer = { height: dims.sidebarHeight, position: 'relative' };
- break;
- }
- style.outer = StickySidebar.extend({ height: '', position: '' }, style.outer);
- style.inner = StickySidebar.extend({ position: 'relative', top: '', left: '',
- bottom: '', width: '', transform: '' }, style.inner);
- return style;
- }
- }, {
- key: 'stickyPosition',
- value: function stickyPosition(force) {
- if (this._breakpoint) return;
- force = this._reStyle || force || false;
- var offsetTop = this.options.topSpacing;
- var offsetBottom = this.options.bottomSpacing;
- var affixType = this.getAffixType();
- var style = this._getStyle(affixType);
- if ((this.affixedType != affixType || force) && affixType) {
- var affixEvent = 'affix.' + affixType.toLowerCase().replace('viewport-', '') + EVENT_KEY;
- StickySidebar.eventTrigger(this.sidebar, affixEvent);
- if ('STATIC' === affixType) StickySidebar.removeClass(this.sidebar, this.options.stickyClass);else StickySidebar.addClass(this.sidebar, this.options.stickyClass);
- for (var key in style.outer) {
- var unit = 'number' === typeof style.outer[key] ? 'px' : '';
- this.sidebar.style[key] = style.outer[key] + unit;
- }
- for (var _key in style.inner) {
- var _unit = 'number' === typeof style.inner[_key] ? 'px' : '';
- this.sidebarInner.style[_key] = style.inner[_key] + _unit;
- }
- var affixedEvent = 'affixed.' + affixType.toLowerCase().replace('viewport-', '') + EVENT_KEY;
- StickySidebar.eventTrigger(this.sidebar, affixedEvent);
- } else {
- if (this._initialized) this.sidebarInner.style.left = style.inner.left;
- }
- this.affixedType = affixType;
- }
- }, {
- key: '_widthBreakpoint',
- value: function _widthBreakpoint() {
- if (window.innerWidth <= this.options.minWidth) {
- this._breakpoint = true;
- this.affixedType = 'STATIC';
- this.sidebar.removeAttribute('style');
- StickySidebar.removeClass(this.sidebar, this.options.stickyClass);
- this.sidebarInner.removeAttribute('style');
- } else {
- this._breakpoint = false;
- }
- }
- }, {
- key: 'updateSticky',
- value: function updateSticky() {
- var _this3 = this;
- var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- if (this._running) return;
- this._running = true;
- (function (eventType) {
- requestAnimationFrame(function () {
- switch (eventType) {
- // When browser is scrolling and re-calculate just dimensions
- // within scroll.
- case 'scroll':
- _this3._calcDimensionsWithScroll();
- _this3.observeScrollDir();
- _this3.stickyPosition();
- break;
- // When browser is resizing or there's no event, observe width
- // breakpoint and re-calculate dimensions.
- case 'resize':
- default:
- _this3._widthBreakpoint();
- _this3.calcDimensions();
- _this3.stickyPosition(true);
- break;
- }
- _this3._running = false;
- });
- })(event.type);
- }
- }, {
- key: '_setSupportFeatures',
- value: function _setSupportFeatures() {
- var support = this.support;
- support.transform = StickySidebar.supportTransform();
- support.transform3d = StickySidebar.supportTransform(true);
- }
- }, {
- key: '_getTranslate',
- value: function _getTranslate() {
- var y = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
- var x = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
- var z = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
- if (this.support.transform3d) return 'translate3d(' + y + ', ' + x + ', ' + z + ')';else if (this.support.translate) return 'translate(' + y + ', ' + x + ')';else return false;
- }
- }, {
- key: 'destroy',
- value: function destroy() {
- window.removeEventListener('resize', this, { capture: false });
- window.removeEventListener('scroll', this, { capture: false });
- this.sidebar.classList.remove(this.options.stickyClass);
- this.sidebar.style.minHeight = '';
- this.sidebar.removeEventListener('update' + EVENT_KEY, this);
- var styleReset = { inner: {}, outer: {} };
- styleReset.inner = { position: '', top: '', left: '', bottom: '', width: '', transform: '' };
- styleReset.outer = { height: '', position: '' };
- for (var key in styleReset.outer) {
- this.sidebar.style[key] = styleReset.outer[key];
- }for (var _key2 in styleReset.inner) {
- this.sidebarInner.style[_key2] = styleReset.inner[_key2];
- }if (this.options.resizeSensor && 'undefined' !== typeof ResizeSensor) {
- ResizeSensor.detach(this.sidebarInner, this.handleEvent);
- ResizeSensor.detach(this.container, this.handleEvent);
- }
- }
- }], [{
- key: 'supportTransform',
- value: function supportTransform(transform3d) {
- var result = false,
- property = transform3d ? 'perspective' : 'transform',
- upper = property.charAt(0).toUpperCase() + property.slice(1),
- prefixes = ['Webkit', 'Moz', 'O', 'ms'],
- support = document.createElement('support'),
- style = support.style;
- (property + ' ' + prefixes.join(upper + ' ') + upper).split(' ').forEach(function (property, i) {
- if (style[property] !== undefined) {
- result = property;
- return false;
- }
- });
- return result;
- }
- }, {
- key: 'eventTrigger',
- value: function eventTrigger(element, eventName, data) {
- try {
- var event = new CustomEvent(eventName, { detail: data });
- } catch (e) {
- var event = document.createEvent('CustomEvent');
- event.initCustomEvent(eventName, true, true, data);
- }
- element.dispatchEvent(event);
- }
- }, {
- key: 'extend',
- value: function extend(defaults, options) {
- var results = {};
- for (var key in defaults) {
- if ('undefined' !== typeof options[key]) results[key] = options[key];else results[key] = defaults[key];
- }
- return results;
- }
- }, {
- key: 'offsetRelative',
- value: function offsetRelative(element) {
- var result = { left: 0, top: 0 };
- do {
- var offsetTop = element.offsetTop;
- var offsetLeft = element.offsetLeft;
- if (!isNaN(offsetTop)) result.top += offsetTop;
- if (!isNaN(offsetLeft)) result.left += offsetLeft;
- element = 'BODY' === element.tagName ? element.parentElement : element.offsetParent;
- } while (element);
- return result;
- }
- }, {
- key: 'addClass',
- value: function addClass(element, className) {
- if (!StickySidebar.hasClass(element, className)) {
- if (element.classList) element.classList.add(className);else element.className += ' ' + className;
- }
- }
- }, {
- key: 'removeClass',
- value: function removeClass(element, className) {
- if (StickySidebar.hasClass(element, className)) {
- if (element.classList) element.classList.remove(className);else element.className = element.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
- }
- }
- }, {
- key: 'hasClass',
- value: function hasClass(element, className) {
- if (element.classList) return element.classList.contains(className);else return new RegExp('(^| )' + className + '( |$)', 'gi').test(element.className);
- }
- }, {
- key: 'defaults',
- get: function () {
- return DEFAULTS;
- }
- }]);
- return StickySidebar;
- }();
- return StickySidebar;
- }();
- exports.default = StickySidebar;
- // Global
- // -------------------------
- window.StickySidebar = StickySidebar;
- });
- });
- var stickySidebar$1 = unwrapExports(stickySidebar);
- exports['default'] = stickySidebar$1;
- exports.__moduleExports = stickySidebar;
- Object.defineProperty(exports, '__esModule', { value: true });
- })));
- //# sourceMappingURL=sticky-sidebar.js.map
|