diff --git a/dist/jquery.sticky-sidebar.js b/dist/jquery.sticky-sidebar.js new file mode 100644 index 0000000..65294b1 --- /dev/null +++ b/dist/jquery.sticky-sidebar.js @@ -0,0 +1,886 @@ +(function () { +'use strict'; + +/* + * raf.js + * https://github.com/ngryman/raf.js + * + * original requestAnimationFrame polyfill by Erik Möller + * inspired from paul_irish gist and post + * + * Copyright (c) 2013 ngryman + * Licensed under the MIT license. + */ + +(function(window) { + var lastTime = 0, + vendors = ['webkit', 'moz'], + requestAnimationFrame = window.requestAnimationFrame, + cancelAnimationFrame = window.cancelAnimationFrame, + i = vendors.length; + + // try to un-prefix existing raf + while (--i >= 0 && !requestAnimationFrame) { + requestAnimationFrame = window[vendors[i] + 'RequestAnimationFrame']; + cancelAnimationFrame = window[vendors[i] + 'CancelAnimationFrame']; + } + + // polyfill with setTimeout fallback + // heavily inspired from @darius gist mod: https://gist.github.com/paulirish/1579671#comment-837945 + if (!requestAnimationFrame || !cancelAnimationFrame) { + requestAnimationFrame = function(callback) { + var now = +new Date(), nextTime = Math.max(lastTime + 16, now); + return setTimeout(function() { + callback(lastTime = nextTime); + }, nextTime - now); + }; + + cancelAnimationFrame = clearTimeout; + } + + // export to window + window.requestAnimationFrame = requestAnimationFrame; + window.cancelAnimationFrame = cancelAnimationFrame; +}(window)); + +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; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Sticky Sidebar JavaScript Plugin. + * @version 1.0.0 + * @author Ahmed Bouhuolia + * @license The MIT License (MIT) + */ +var StickySidebar = function () { + + // --------------------------------- + // # Define Constants + // --------------------------------- + // + var EVENT_KEY = '.stickySidebar'; + var VERSION = '2.0'; + + 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; + + // 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(_this.sidebar)) return; + _this.container = container; + }); + + if (!containers.length) throw new Error("The container does not contains on the sidebar."); + } + + // Current Affix Type of sidebar element. + this.affixedType = 'STATIC'; + this.direction = 'down'; + this.support = { + transform: false, + transform3d: false + }; + + this._initialized = false; + this._breakpoint = false; + this._resizeListeners = []; + + // Dimenstions of sidebar, container and screen viewport. + this.dimensions = { + translateY: 0, + topSpacing: 0, + bottomSpacing: 0, + sidebarHeight: 0, + sidebarWidth: 0, + containerTop: 0, + containerHeight: 0, + viewportHeight: 0, + viewportTop: 0, + lastViewportTop: 0 + }; + + // Bind event handlers for referencability. + ['_resizeListener'].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 dimenstions, adding helper classes and inline style. + * @private + */ + + + _createClass(StickySidebar, [{ + key: 'initialize', + value: function initialize() { + 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'); + } + + // If there's no specific container, user parent of sidebar as container. + if (null !== this.container) this.container = this.sidebar.parentElement; + + // 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; + } + + /** + * Bind all events of sticky sidebar plugin. + * @protected + */ + + }, { + key: 'bindEvents', + value: function bindEvents() { + window.addEventListener('resize', this, { passive: true }); + window.addEventListener('scroll', this, { passive: true }); + + this.sidebar.addEventListener('update' + EVENT_KEY, this); + + if (this.options.resizeSensor) { + this.addResizerListener(this.sidebarInner, this); + this.addResizerListener(this.container, this); + } + } + + /** + * Handles all events of the plugin. + * @param {Object} event - Event object passed from listener. + */ + + }, { + key: 'handleEvent', + value: function handleEvent(event) { + this.updateSticky(event); + } + + /** + * Calculates dimesntions of sidebar, container and screen viewpoint + * @public + */ + + }, { + 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.sidebar.offsetWidth; + + // Screen viewport dimensions. + dims.viewportHeight = window.innerHeight; + + this._calcDimensionsWithScroll(); + } + + /** + * Some dimensions values need to be up-to-date when scrolling the page. + * @private + */ + + }, { + 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; + } + + /** + * Detarmine wheather the sidebar is bigger than viewport. + * @public + * @return {Boolean} + */ + + }, { + key: 'isSidebarFitsViewport', + value: function isSidebarFitsViewport() { + return this.dimensions.sidebarHeight < this.dimensions.viewportHeight; + } + + /** + * Observe browser scrolling direction top and down. + */ + + }, { + 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'; + } + + /** + * Gets affix type of sidebar according to current scrollTop and scrollLeft. + * Holds all logical affix of the sidebar when scrolling up and down and when sidebar + * is bigger than viewport and vice versa. + * @public + * @return {String|False} - Proper affix type. + */ + + }, { + key: 'getAffixType', + value: function getAffixType() { + var dims = this.dimensions, + affixType = false; + + this._calcDimensionsWithScroll(); + + var sidebarBottom = dims.sidebarHeight + dims.containerTop; + var colliderTop = dims.viewportTop + dims.topSpacing; + var colliderBottom = dims.viewportBottom - dims.bottomSpacing; + + // When browser is scrolling top. + if ('up' === this.direction) { + if (colliderTop <= dims.containerTop) { + dims.translateY = 0; + affixType = 'STATIC'; + } else if (colliderTop <= dims.translateY + dims.containerTop) { + dims.translateY = colliderTop - dims.containerTop; + affixType = 'VIEWPORT-TOP'; + } else if (!this.isSidebarFitsViewport() && dims.containerTop <= colliderTop) { + affixType = 'VIEWPORT-UNBOTTOM'; + } + // When browser is scrolling up. + } else { + // When sidebar element is not bigger than screen viewport. + 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'; + } + // When sidebar element is bigger than screen viewport. + } 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) { + affixType = 'VIEWPORT-UNBOTTOM'; + } + } + } + + // 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.lastViewportTop = dims.viewportTop; + return affixType; + } + + /** + * Gets inline style of sticky sidebar wrapper and inner wrapper according + * to its affix type. + * @private + * @param {String} affixType - Affix type of sticky sidebar. + * @return {Object} + */ + + }, { + 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: this.options.topSpacing, + left: dims.sidebarLeft - dims.viewportLeft, width: dims.sidebarWidth }; + break; + case 'VIEWPORT-BOTTOM': + style.inner = { position: 'fixed', top: 'auto', left: dims.sidebarLeft, + bottom: this.options.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.containerTop + dims.translateY }; + 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: this._getTranslate() }, style.inner); + + return style; + } + + /** + * Cause the sidebar to be sticky according to affix type by adding inline + * style, adding helper class and trigger events. + * @function + * @protected + * @param {string} force - Update sticky sidebar position by force. + */ + + }, { + key: 'stickyPosition', + value: function stickyPosition(force) { + if (this._breakpoint) return; + + force = 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) this.sidebar.classList.remove(this.options.stickyClass);else this.sidebar.classList.add(this.options.stickyClass); + + for (var key in style.outer) { + var _unit = 'number' === typeof style.outer[key] ? 'px' : ''; + this.sidebar.style[key] = style.outer[key]; + } + + for (var _key in style.inner) { + var _unit2 = 'number' === typeof style.inner[_key] ? 'px' : ''; + this.sidebarInner.style[_key] = style.inner[_key] + _unit2; + } + + 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; + } + + /** + * Breakdown sticky sidebar when window width is below `options.minWidth` value. + * @protected + */ + + }, { + key: '_widthBreakpoint', + value: function _widthBreakpoint() { + + if (window.innerWidth <= this.options.minWidth) { + this._breakpoint = true; + this.affixedType = 'STATIC'; + + this.sidebar.removeAttribute('style'); + this.sidebar.classList.remove(this.options.stickyClass); + this.sidebarInner.removeAttribute('style'); + } else { + this._breakpoint = false; + } + } + + /** + * Switchs between functions stack for each event type, if there's no + * event, it will re-initialize sticky sidebar. + * @public + */ + + }, { + key: 'updateSticky', + value: function updateSticky() { + var _this2 = 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': + _this2._calcDimensionsWithScroll(); + _this2.observeScrollDir(); + _this2.stickyPosition(); + break; + + // When browser is resizing or there's no event, observe width + // breakpoint and re-calculate dimensions. + case 'resize': + default: + _this2._widthBreakpoint(); + _this2.calcDimensions(); + _this2.stickyPosition('resize' === eventType || false); + break; + } + _this2._running = false; + }); + })(event.type); + } + + /** + * Set browser support features to the public property. + * @private + */ + + }, { + key: '_setSupportFeatures', + value: function _setSupportFeatures() { + var support = this.support; + + support.transform = StickySidebar.supportTransform(); + support.transform3d = StickySidebar.supportTransform(true); + } + + /** + * Get translate value, if the browser supports transfrom3d, it will adopt it. + * and the same with translate. if browser doesn't support both return false. + * @param {Number} y - Value of Y-axis. + * @param {Number} x - Value of X-axis. + * @param {Number} z - Value of Z-axis. + * @return {String|False} + */ + + }, { + 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; + } + + /** + * Add resize sensor listener to specifc element. + * @public + * @param {DOMElement} element - + * @param {Function} callback - + */ + + }, { + key: 'addResizerListener', + value: function addResizerListener(element, callback) { + if (!element.resizeListeners) { + element.resizeListeners = []; + this._appendResizeSensor(element); + } + + element.resizeListeners.push(callback); + } + + /** + * Remove resize sonser listener from specific element. + * @function + * @public + * @param {DOMElement} element - + * @param {Function} callback - + */ + + }, { + key: 'removeResizeListener', + value: function removeResizeListener(element, callback) { + var resizeListeners = element.resizeListeners; + var index = resizeListeners.indexOf(callback); + + this._resizeListeners.splice(index, 1); + + if (null !== element.resizeListeners) { + var resizeTrigger = element.resizeTrigger; + var _window = resizeTrigger.contentDocument.defaultView; + + _window.removeEventListener('resize', this._resizeListener); + resizeTrigger = resizeTrigger.remove(); + } + } + + /** + * Append resize sensor object on DOM in specific element. + * @private + * @param {DOMElement} element - + */ + + }, { + key: '_appendResizeSensor', + value: function _appendResizeSensor(element) { + var _this3 = this; + + if ('static' === element.style.position) element.style.position = 'relative'; + + var wrapper = document.createElement('object'); + var style = 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%;' + 'overflow: hidden; pointer-events: none; z-index: -1;'; + + wrapper.setAttribute('style', style); + wrapper.resizeElement = element; + + wrapper.addEventListener('load', function (event) { + var target = event.currentTarget; + + target.contentDocument.defaultView.resizeTrigger = target.resizeElement; + target.contentDocument.defaultView.addEventListener('resize', _this3._resizeListener); + }); + + wrapper.type = 'text/html'; + + if (StickySidebar.isIE()) wrapper.data = 'about:blank'; + + element.resizeTrigger = wrapper; + element.appendChild(wrapper); + } + + /** + * Resize sensor listener to call callbacks of trigger. + * @private + * @param {Object} event - Event object passed from listener. + */ + + }, { + key: '_resizeListener', + value: function _resizeListener(event) { + var _this4 = this; + + var _window = event.target || event.srcElement; + var trigger = _window.resizeTrigger; + + trigger.resizeListeners.forEach(function (callback) { + if ('object' === typeof callback) { + callback = callback.handleEvent; + trigger = _this4; + } + callback.call(trigger, event); + }); + } + + /** + * Destroy sticky sidebar plugin. + * @public + */ + + }, { + key: 'destroy', + value: function destroy() { + window.removeEventListener('resize', this._onResize); + window.removeEventListener('scroll', this._onScroll); + + this.sidebar.classList.remove(this.options.stickyClass); + this.sidebar.style.minHeight = ''; + + this.removeEventListener('update' + EVENT_KEY, this.updateSticky); + + var styleReset = { position: '', top: '', left: '', bottom: '', width: '', transform: '' }; + for (var key in styleReset) { + this.sidebar.style[key] = styleReset[key]; + }if (this.options.resizeSensor) { + this.removeResizeListener(this.sidebarInner, this.updateSticky); + this.removeResizeListener(this.container, this.updateSticky); + } + } + + /** + * Detarmine if the browser is Internet Explorer. + * @function + * @static + */ + + }], [{ + key: 'isIE', + value: function isIE() { + return Boolean(navigator.userAgent.match(/Trident/)); + } + + /** + * Detarmine if the browser supports CSS transfrom feature. + * @function + * @static + * @param {Boolean} transform3d - Detect transform with translate3d. + * @return {String} + */ + + }, { + 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; + } + + /** + * Trigger custom event. + * @static + * @param {DOMObject} element - Target element on the DOM. + * @param {String} eventName - Event name. + * @param {Object} data - + */ + + }, { + key: 'eventTrigger', + value: function eventTrigger(element, eventName, data) { + if (window.CustomEvent) { + var event = new CustomEvent(eventName, { detail: data }); + } else { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent(eventName, true, true, data); + } + element.dispatchEvent(event); + } + + /** + * Extend options object with defaults. + * @function + * @static + */ + + }, { + 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; + } + + /** + * Get current coordinates left and top of specific element. + * @static + */ + + }, { + 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; + } while (element = element.offsetParent); + return result; + } + }]); + + return StickySidebar; + }(); + + return StickySidebar; +}(); + +// Global +// ------------------------- +window.StickySidebar = StickySidebar; + +(function () { + if ('undefined' === typeof widow) return; + + var plugin = window.$ || window.jQuery || window.Zepto; + var DATA_NAMESPACE = 'stickySidebar'; + + // Make sure the site has jquery or zepto plugin. + if (plugin) { + /** + * Sticky Sidebar Plugin Defintion. + * @param {Object|String} - config + */ + var jQueryPlugin = function (config) { + return this.each(function () { + var $this = plugin(this), + data = plugin(this).data(DATA_NAMESPACE); + + if (!data) { + data = new StickySidebar(this, typeof config == 'object' && config); + $this.data(DATA_NAMESPACE, data); + } + + if ('string' === typeof config) { + if (data[config] === undefined && ['destroy', 'updateSticky'].indexOf(config) === -1) throw new Error('No method named "' + config + '"'); + + data[config](); + } + }); + }; + + plugin.fn.stickySidebar = _jQueryPlugin; + plugin.fn.stickySidebar.Constructor = StickySidebar; + + var old = plugin.fn.stickySidebar; + + /** + * Sticky Sidebar No Conflict. + */ + plugin.fn.stickySidebar.noConflict = function () { + plugin.fn.stickySidebar = old; + return this; + }; + } +})(); + +}()); + +//# sourceMappingURL=jquery.sticky-sidebar.js.map diff --git a/dist/jquery.sticky-sidebar.js.map b/dist/jquery.sticky-sidebar.js.map new file mode 100644 index 0000000..17d6a9e --- /dev/null +++ b/dist/jquery.sticky-sidebar.js.map @@ -0,0 +1 @@ +{"version":3,"file":"jquery.sticky-sidebar.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/dist/jquery.sticky-sidebar.min.js b/dist/jquery.sticky-sidebar.min.js new file mode 100644 index 0000000..54d0e6d --- /dev/null +++ b/dist/jquery.sticky-sidebar.min.js @@ -0,0 +1,8 @@ +/** + * sticky-sidebar - A JavaScript plugin for making smart and high performance. + * @version v2.0 + * @link https://github.com/abouolia/sticky-sidebar + * @author Ahmed Bouhuolia + * @license The MIT License (MIT) +**/ +!function(){"use strict";function e(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}!function(e){for(var t=0,i=["webkit","moz"],n=e.requestAnimationFrame,s=e.cancelAnimationFrame,r=i.length;--r>=0&&!n;)n=e[i[r]+"RequestAnimationFrame"],s=e[i[r]+"CancelAnimationFrame"];n&&s||(n=function(e){var i=+new Date,n=Math.max(t+16,i);return setTimeout(function(){e(t=n)},n-i)},s=clearTimeout),e.requestAnimationFrame=n,e.cancelAnimationFrame=s}(window);var t=function(){function e(e,t){for(var i=0;i1&&void 0!==arguments[1]?arguments[1]:{};if(e(this,s),this.options=s.extend(n,r),this.sidebar="string"==typeof t?document.querySelector(t):t,void 0===this.sidebar)throw new Error("There is no specific sidebar element.");if(this.sidebarInner=!1,this.container=this.sidebar.parentElement,this.options.containerSelector){var o=document.querySelectorAll(this.options.containerSelector);if((o=Array.prototype.slice.call(o)).forEach(function(e,t){e.contains(i.sidebar)&&(i.container=e)}),!o.length)throw new Error("The container does not contains on the sidebar.")}this.affixedType="STATIC",this.direction="down",this.support={transform:!1,transform3d:!1},this._initialized=!1,this._breakpoint=!1,this._resizeListeners=[],this.dimensions={translateY:0,topSpacing:0,bottomSpacing:0,sidebarHeight:0,sidebarWidth:0,containerTop:0,containerHeight:0,viewportHeight:0,viewportTop:0,lastViewportTop:0},["_resizeListener"].forEach(function(e){i[e]=i[e].bind(i)}),this.initialize()}return t(s,[{key:"initialize",value:function(){if(this._setSupportFeatures(),this.options.innerWrapperSelector&&(this.sidebarInner=this.sidebar.querySelector(this.options.innerWrapperSelector),null!==this.sidebarInner&&(this.sidebarInner=!1)),!this.sidebarInner){var e=document.createElement("div");for(e.setAttribute("class","inner-wrapper-sticky"),this.sidebar.appendChild(e);this.sidebar.firstChild!=e;)e.appendChild(this.sidebar.firstChild);this.sidebarInner=this.sidebar.querySelector(".inner-wrapper-sticky")}null!==this.container&&(this.container=this.sidebar.parentElement),"function"!=typeof this.options.topSpacing&&(this.options.topSpacing=parseInt(this.options.topSpacing)||0),"function"!=typeof this.options.bottomSpacing&&(this.options.bottomSpacing=parseInt(this.options.bottomSpacing)||0),this._widthBreakpoint(),this.calcDimensions(),this.stickyPosition(),this.bindEvents(),this._initialized=!0}},{key:"bindEvents",value:function(){window.addEventListener("resize",this,{passive:!0}),window.addEventListener("scroll",this,{passive:!0}),this.sidebar.addEventListener("update"+i,this),this.options.resizeSensor&&(this.addResizerListener(this.sidebarInner,this),this.addResizerListener(this.container,this))}},{key:"handleEvent",value:function(e){this.updateSticky(e)}},{key:"calcDimensions",value:function(){if(!this._breakpoint){var e=this.dimensions;e.containerTop=s.offsetRelative(this.container).top,e.containerHeight=this.container.clientHeight,e.containerBottom=e.containerTop+e.containerHeight,e.sidebarHeight=this.sidebarInner.offsetHeight,e.sidebarWidth=this.sidebar.offsetWidth,e.viewportHeight=window.innerHeight,this._calcDimensionsWithScroll()}}},{key:"_calcDimensionsWithScroll",value:function(){var e=this.dimensions;e.sidebarLeft=s.offsetRelative(this.sidebar).left,e.viewportTop=document.documentElement.scrollTop||document.body.scrollTop,e.viewportBottom=e.viewportTop+e.viewportHeight,e.viewportLeft=document.documentElement.scrollLeft||document.body.scrollLeft,e.topSpacing=this.options.topSpacing,e.bottomSpacing=this.options.bottomSpacing,"function"==typeof e.topSpacing&&(e.topSpacing=parseInt(e.topSpacing(this.sidebar))||0),"function"==typeof e.bottomSpacing&&(e.bottomSpacing=parseInt(e.bottomSpacing(this.sidebar))||0)}},{key:"isSidebarFitsViewport",value:function(){return this.dimensions.sidebarHeight=e.containerBottom?(e.translateY=e.containerBottom-i,t="CONTAINER-BOTTOM"):n>=e.containerTop&&(e.translateY=n-e.containerTop,t="VIEWPORT-TOP"):e.containerBottom<=s?(e.translateY=e.containerBottom-i,t="CONTAINER-BOTTOM"):i+e.translateY<=s?(e.translateY=s-i,t="VIEWPORT-BOTTOM"):e.containerTop+e.translateY<=n&&(t="VIEWPORT-UNBOTTOM"),e.translateY=Math.max(0,e.translateY),e.translateY=Math.min(e.containerHeight,e.translateY),e.lastViewportTop=e.viewportTop,t}},{key:"_getStyle",value:function(e){if(void 0!==e){var t={inner:{},outer:{}},i=this.dimensions;switch(e){case"VIEWPORT-TOP":t.inner={position:"fixed",top:this.options.topSpacing,left:i.sidebarLeft-i.viewportLeft,width:i.sidebarWidth};break;case"VIEWPORT-BOTTOM":t.inner={position:"fixed",top:"auto",left:i.sidebarLeft,bottom:this.options.bottomSpacing,width:i.sidebarWidth};break;case"CONTAINER-BOTTOM":case"VIEWPORT-UNBOTTOM":var n=this._getTranslate(0,i.translateY+"px");t.inner=n?{transform:n}:{position:"absolute",top:i.containerTop+i.translateY}}switch(e){case"VIEWPORT-TOP":case"VIEWPORT-BOTTOM":case"VIEWPORT-UNBOTTOM":case"CONTAINER-BOTTOM":t.outer={height:i.sidebarHeight,position:"relative"}}return t.outer=s.extend({height:"",position:""},t.outer),t.inner=s.extend({position:"relative",top:"",left:"",bottom:"",width:"",transform:this._getTranslate()},t.inner),t}}},{key:"stickyPosition",value:function(e){if(!this._breakpoint){e=e||!1;this.options.topSpacing,this.options.bottomSpacing;var t=this.getAffixType(),n=this._getStyle(t);if((this.affixedType!=t||e)&&t){var r="affix."+t.toLowerCase().replace("viewport-","")+i;s.eventTrigger(this.sidebar,r),"STATIC"===t?this.sidebar.classList.remove(this.options.stickyClass):this.sidebar.classList.add(this.options.stickyClass);for(var o in n.outer){n.outer[o];this.sidebar.style[o]=n.outer[o]}for(var a in n.inner){var c="number"==typeof n.inner[a]?"px":"";this.sidebarInner.style[a]=n.inner[a]+c}var p="affixed."+t.toLowerCase().replace("viewport","")+i;s.eventTrigger(this.sidebar,p)}else this._initialized&&(this.sidebarInner.style.left=n.inner.left);this.affixedType=t}}},{key:"_widthBreakpoint",value:function(){window.innerWidth<=this.options.minWidth?(this._breakpoint=!0,this.affixedType="STATIC",this.sidebar.removeAttribute("style"),this.sidebar.classList.remove(this.options.stickyClass),this.sidebarInner.removeAttribute("style")):this._breakpoint=!1}},{key:"updateSticky",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this._running||(this._running=!0,function(t){requestAnimationFrame(function(){switch(t){case"scroll":e._calcDimensionsWithScroll(),e.observeScrollDir(),e.stickyPosition();break;case"resize":default:e._widthBreakpoint(),e.calcDimensions(),e.stickyPosition("resize"===t||!1)}e._running=!1})}(t.type))}},{key:"_setSupportFeatures",value:function(){var e=this.support;e.transform=s.supportTransform(),e.transform3d=s.supportTransform(!0)}},{key:"_getTranslate",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;return this.support.transform3d?"translate3d("+e+", "+t+", "+i+")":!!this.support.translate&&"translate("+e+", "+t+")"}},{key:"addResizerListener",value:function(e,t){e.resizeListeners||(e.resizeListeners=[],this._appendResizeSensor(e)),e.resizeListeners.push(t)}},{key:"removeResizeListener",value:function(e,t){var i=e.resizeListeners.indexOf(t);if(this._resizeListeners.splice(i,1),null!==e.resizeListeners){var n=e.resizeTrigger;n.contentDocument.defaultView.removeEventListener("resize",this._resizeListener),n=n.remove()}}},{key:"_appendResizeSensor",value:function(e){var t=this;"static"===e.style.position&&(e.style.position="relative");var i=document.createElement("object");i.setAttribute("style","display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%;overflow: hidden; pointer-events: none; z-index: -1;"),i.resizeElement=e,i.addEventListener("load",function(e){var i=e.currentTarget;i.contentDocument.defaultView.resizeTrigger=i.resizeElement,i.contentDocument.defaultView.addEventListener("resize",t._resizeListener)}),i.type="text/html",s.isIE()&&(i.data="about:blank"),e.resizeTrigger=i,e.appendChild(i)}},{key:"_resizeListener",value:function(e){var t=this,i=(e.target||e.srcElement).resizeTrigger;i.resizeListeners.forEach(function(n){"object"==typeof n&&(n=n.handleEvent,i=t),n.call(i,e)})}},{key:"destroy",value:function(){window.removeEventListener("resize",this._onResize),window.removeEventListener("scroll",this._onScroll),this.sidebar.classList.remove(this.options.stickyClass),this.sidebar.style.minHeight="",this.removeEventListener("update"+i,this.updateSticky);var e={position:"",top:"",left:"",bottom:"",width:"",transform:""};for(var t in e)this.sidebar.style[t]=e[t];this.options.resizeSensor&&(this.removeResizeListener(this.sidebarInner,this.updateSticky),this.removeResizeListener(this.container,this.updateSticky))}}],[{key:"isIE",value:function(){return Boolean(navigator.userAgent.match(/Trident/))}},{key:"supportTransform",value:function(e){var t=!1,i=e?"perspective":"transform",n=i.charAt(0).toUpperCase()+i.slice(1),s=["Webkit","Moz","O","ms"],r=document.createElement("support").style;return(i+" "+s.join(n+" ")+n).split(" ").forEach(function(e,i){if(void 0!==r[e])return t=e,!1}),t}},{key:"eventTrigger",value:function(e,t,i){if(window.CustomEvent)var n=new CustomEvent(t,{detail:i});else(n=document.createEvent("CustomEvent")).initCustomEvent(t,!0,!0,i);e.dispatchEvent(n)}},{key:"extend",value:function(e,t){var i={};for(var n in e)void 0!==t[n]?i[n]=t[n]:i[n]=e[n];return i}},{key:"offsetRelative",value:function(e){var t={left:0,top:0};do{var i=e.offsetTop,n=e.offsetLeft;isNaN(i)||(t.top+=i),isNaN(n)||(t.left+=n)}while(e=e.offsetParent);return t}}]),s}()}();window.StickySidebar=i,function(){if("undefined"!=typeof widow){var e=window.$||window.jQuery||window.Zepto;if(e){e.fn.stickySidebar=_jQueryPlugin,e.fn.stickySidebar.Constructor=i;var t=e.fn.stickySidebar;e.fn.stickySidebar.noConflict=function(){return e.fn.stickySidebar=t,this}}}}()}(); \ No newline at end of file diff --git a/dist/sticky-sidebar.js b/dist/sticky-sidebar.js index 2e19c05..ccffaff 100644 --- a/dist/sticky-sidebar.js +++ b/dist/sticky-sidebar.js @@ -1,3 +1,48 @@ +var stickySidebarModule = (function () { +'use strict'; + +/* + * raf.js + * https://github.com/ngryman/raf.js + * + * original requestAnimationFrame polyfill by Erik Möller + * inspired from paul_irish gist and post + * + * Copyright (c) 2013 ngryman + * Licensed under the MIT license. + */ + +(function(window) { + var lastTime = 0, + vendors = ['webkit', 'moz'], + requestAnimationFrame = window.requestAnimationFrame, + cancelAnimationFrame = window.cancelAnimationFrame, + i = vendors.length; + + // try to un-prefix existing raf + while (--i >= 0 && !requestAnimationFrame) { + requestAnimationFrame = window[vendors[i] + 'RequestAnimationFrame']; + cancelAnimationFrame = window[vendors[i] + 'CancelAnimationFrame']; + } + + // polyfill with setTimeout fallback + // heavily inspired from @darius gist mod: https://gist.github.com/paulirish/1579671#comment-837945 + if (!requestAnimationFrame || !cancelAnimationFrame) { + requestAnimationFrame = function(callback) { + var now = +new Date(), nextTime = Math.max(lastTime + 16, now); + return setTimeout(function() { + callback(lastTime = nextTime); + }, nextTime - now); + }; + + cancelAnimationFrame = clearTimeout; + } + + // export to window + window.requestAnimationFrame = requestAnimationFrame; + window.cancelAnimationFrame = cancelAnimationFrame; +}(window)); + 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; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -109,7 +154,7 @@ var StickySidebar = function () { } // Current Affix Type of sidebar element. - this.affixedType = 'static'; + this.affixedType = 'STATIC'; this.direction = 'down'; this.support = { transform: false, @@ -441,10 +486,10 @@ var StickySidebar = function () { var style = this._getStyle(affixType); if ((this.affixedType != affixType || force) && affixType) { - var affixEvent = 'affix.' + affixType.replace('viewport-', '') + EVENT_KEY; + var affixEvent = 'affix.' + affixType.toLowerCase().replace('viewport-', '') + EVENT_KEY; StickySidebar.eventTrigger(this.sidebar, affixEvent); - if ('static' === affixType) this.sidebar.classList.remove(this.options.stickyClass);else this.sidebar.classList.add(this.options.stickyClass); + if ('STATIC' === affixType) this.sidebar.classList.remove(this.options.stickyClass);else this.sidebar.classList.add(this.options.stickyClass); for (var key in style.outer) { var _unit = 'number' === typeof style.outer[key] ? 'px' : ''; @@ -456,7 +501,7 @@ var StickySidebar = function () { this.sidebarInner.style[_key] = style.inner[_key] + _unit2; } - var affixedEvent = 'affixed.' + affixType.replace('viewport', '') + EVENT_KEY; + 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; @@ -614,7 +659,7 @@ var StickySidebar = function () { value: function _appendResizeSensor(element) { var _this3 = this; - element.style.position = 'relative'; + if ('static' === element.style.position) element.style.position = 'relative'; var wrapper = document.createElement('object'); var style = 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%;' + 'overflow: hidden; pointer-events: none; z-index: -1;'; @@ -735,8 +780,6 @@ var StickySidebar = function () { }, { key: 'eventTrigger', value: function eventTrigger(element, eventName, data) { - data = 'object' === typeof data ? data : {}; - if (window.CustomEvent) { var event = new CustomEvent(eventName, { detail: data }); } else { @@ -786,12 +829,15 @@ var StickySidebar = function () { return StickySidebar; }(); - // Global - // ------------------------- + return StickySidebar; +}(); +// Global +// ------------------------- +window.StickySidebar = StickySidebar; - window.StickySidebar = StickySidebar; +return StickySidebar; + +}()); - return StickySidebar; -}(); //# sourceMappingURL=sticky-sidebar.js.map diff --git a/dist/sticky-sidebar.js.map b/dist/sticky-sidebar.js.map index c44aeb0..6cef6a7 100644 --- a/dist/sticky-sidebar.js.map +++ b/dist/sticky-sidebar.js.map @@ -1 +1 @@ -{"version":3,"sources":["sticky-sidebar.js"],"names":["StickySidebar","EVENT_KEY","VERSION","DEFAULTS","topSpacing","bottomSpacing","containerSelector","innerWrapperSelector","stickyClass","resizeSensor","minWidth","sidebar","options","extend","document","querySelector","Error","sidebarInner","container","parentElement","containers","querySelectorAll","Array","prototype","slice","call","forEach","item","contains","length","affixedType","direction","support","transform","transform3d","_initialized","_breakpoint","_resizeListeners","dimensions","translateY","sidebarHeight","sidebarWidth","containerTop","containerHeight","viewportHeight","viewportTop","lastViewportTop","method","bind","initialize","_setSupportFeatures","wrapper","createElement","setAttribute","appendChild","firstChild","parseInt","_widthBreakpoint","calcDimensions","stickyPosition","bindEvents","window","addEventListener","passive","addResizerListener","event","updateSticky","dims","offsetRelative","top","clientHeight","containerBottom","offsetHeight","offsetWidth","innerHeight","_calcDimensionsWithScroll","sidebarLeft","left","documentElement","scrollTop","body","viewportBottom","viewportLeft","scrollLeft","furthest","Math","min","max","affixType","sidebarBottom","colliderTop","colliderBottom","isSidebarFitsViewport","style","inner","outer","position","width","bottom","translate","_getTranslate","height","force","offsetTop","offsetBottom","getAffixType","_getStyle","affixEvent","replace","eventTrigger","classList","remove","add","key","_unit","affixedEvent","innerWidth","removeAttribute","_running","eventType","requestAnimationFrame","observeScrollDir","type","supportTransform","y","x","z","element","callback","resizeListeners","_appendResizeSensor","push","index","indexOf","splice","resizeTrigger","_window","contentDocument","defaultView","removeEventListener","_resizeListener","resizeElement","target","currentTarget","isIE","data","srcElement","trigger","handleEvent","_onResize","_onScroll","minHeight","styleReset","removeResizeListener","Boolean","navigator","userAgent","match","result","property","upper","charAt","toUpperCase","prefixes","join","split","i","undefined","eventName","CustomEvent","detail","createEvent","initCustomEvent","dispatchEvent","defaults","results","offsetLeft","isNaN","offsetParent"],"mappings":"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","file":"sticky-sidebar.js","sourcesContent":["/**\r\n * Sticky Sidebar JavaScript Plugin.\r\n * @version 1.0.0\r\n * @author Ahmed Bouhuolia \r\n * @license The MIT License (MIT)\r\n */\r\nconst StickySidebar = (() => {\r\n\r\n // ---------------------------------\r\n // # Define Constants\r\n // ---------------------------------\r\n //\r\n const EVENT_KEY = '.stickySidebar';\r\n const VERSION = '2.0';\r\n\r\n const DEFAULTS = {\r\n \r\n /**\r\n * Additional top spacing of the element when it becomes sticky.\r\n * @type {Numeric|Function}\r\n */\r\n topSpacing: 0,\r\n\r\n /**\r\n * Additional bottom spacing of the element when it becomes sticky.\r\n * @type {Numeric|Function}\r\n */\r\n bottomSpacing: 0,\r\n\r\n /**\r\n * Container sidebar selector to know what the beginning and end of sticky element.\r\n * @type {String|False}\r\n */\r\n containerSelector: false,\r\n\r\n /**\r\n * Inner wrapper selector.\r\n * @type {String}\r\n */\r\n innerWrapperSelector: '.inner-wrapper-sticky',\r\n\r\n /**\r\n * The name of CSS class to apply to elements when they have become stuck.\r\n * @type {String|False}\r\n */\r\n stickyClass: 'is-affixed',\r\n\r\n /**\r\n * Detect when sidebar and its container change height so re-calculate their dimensions.\r\n * @type {Boolean}\r\n */\r\n resizeSensor: true,\r\n\r\n /**\r\n * The sidebar returns to its normal position if its width below this value.\r\n * @type {Numeric}\r\n */\r\n minWidth: false\r\n };\r\n\r\n // ---------------------------------\r\n // # Class Definition\r\n // ---------------------------------\r\n //\r\n /**\r\n * Sticky Sidebar Class.\r\n * @public\r\n */\r\n class StickySidebar{\r\n\r\n /**\r\n * Sticky Sidebar Constructor.\r\n * @constructor\r\n * @param {HTMLElement|String} sidebar - The sidebar element or sidebar selector.\r\n * @param {Object} options - The options of sticky sidebar.\r\n */\r\n constructor(sidebar, options = {}){\r\n this.options = StickySidebar.extend(DEFAULTS, options);\r\n\r\n // Sidebar element query if there's no one, throw error.\r\n this.sidebar = ('string' === typeof sidebar ) ? document.querySelector(sidebar) : sidebar;\r\n if( 'undefined' === typeof this.sidebar )\r\n throw new Error(\"There is no specific sidebar element.\");\r\n\r\n this.sidebarInner = false;\r\n this.container = this.sidebar.parentElement;\r\n\r\n // Container wrapper of the sidebar.\r\n if( this.options.containerSelector ){\r\n let containers = document.querySelectorAll(this.options.containerSelector);\r\n containers = Array.prototype.slice.call(containers);\r\n\r\n containers.forEach((container, item) => {\r\n if( ! container.contains(this.sidebar) ) return;\r\n this.container = container;\r\n });\r\n\r\n if( ! containers.length )\r\n throw new Error(\"The container does not contains on the sidebar.\");\r\n }\r\n\r\n // Current Affix Type of sidebar element.\r\n this.affixedType = 'static';\r\n this.direction = 'down';\r\n this.support = {\r\n transform: false,\r\n transform3d: false\r\n };\r\n\r\n this._initialized = false;\r\n this._breakpoint = false;\r\n this._resizeListeners = [];\r\n \r\n // Dimenstions of sidebar, container and screen viewport.\r\n this.dimensions = {\r\n translateY: 0,\r\n topSpacing: 0,\r\n bottomSpacing: 0,\r\n sidebarHeight: 0,\r\n sidebarWidth: 0,\r\n containerTop: 0,\r\n containerHeight: 0,\r\n viewportHeight: 0,\r\n viewportTop: 0, \r\n lastViewportTop: 0,\r\n };\r\n\r\n // Bind event handlers for referencability.\r\n ['_resizeListener'].forEach( (method) => {\r\n this[method] = this[method].bind(this);\r\n });\r\n\r\n // Initialize sticky sidebar for first time.\r\n this.initialize();\r\n }\r\n\r\n /**\r\n * Initializes the sticky sidebar by adding inner wrapper, define its container, \r\n * min-width breakpoint, calculating dimenstions, adding helper classes and inline style.\r\n * @private\r\n */\r\n initialize(){\r\n this._setSupportFeatures();\r\n\r\n // Get sticky sidebar inner wrapper, if not found, will create one.\r\n if( this.options.innerWrapperSelector ){\r\n this.sidebarInner = this.sidebar.querySelector(this.options.innerWrapperSelector);\r\n\r\n if( null !== this.sidebarInner )\r\n this.sidebarInner = false;\r\n }\r\n \r\n if( ! this.sidebarInner ){\r\n let wrapper = document.createElement('div');\r\n wrapper.setAttribute('class', 'inner-wrapper-sticky');\r\n this.sidebar.appendChild(wrapper);\r\n\r\n while( this.sidebar.firstChild != wrapper )\r\n wrapper.appendChild(this.sidebar.firstChild);\r\n\r\n this.sidebarInner = this.sidebar.querySelector('.inner-wrapper-sticky');\r\n }\r\n\r\n // If there's no specific container, user parent of sidebar as container.\r\n if( null !== this.container )\r\n this.container = this.sidebar.parentElement;\r\n \r\n // If top/bottom spacing is not function parse value to integer.\r\n if( 'function' !== typeof this.options.topSpacing )\r\n this.options.topSpacing = parseInt(this.options.topSpacing) || 0;\r\n\r\n if( 'function' !== typeof this.options.bottomSpacing )\r\n this.options.bottomSpacing = parseInt(this.options.bottomSpacing) || 0;\r\n \r\n // Breakdown sticky sidebar if screen width below `options.minWidth`.\r\n this._widthBreakpoint();\r\n\r\n // Calculate dimensions of sidebar, container and viewport.\r\n this.calcDimensions();\r\n\r\n // Affix sidebar in proper position.\r\n this.stickyPosition();\r\n\r\n // Bind all events.\r\n this.bindEvents();\r\n \r\n // Inform other properties the sticky sidebar is initialized.\r\n this._initialized = true;\r\n }\r\n\r\n /**\r\n * Bind all events of sticky sidebar plugin.\r\n * @protected\r\n */\r\n bindEvents(){\r\n window.addEventListener('resize', this, {passive: true});\r\n window.addEventListener('scroll', this, {passive: true});\r\n\r\n this.sidebar.addEventListener('update' + EVENT_KEY, this);\r\n\r\n if( this.options.resizeSensor ){\r\n this.addResizerListener(this.sidebarInner, this);\r\n this.addResizerListener(this.container, this);\r\n }\r\n }\r\n\r\n /**\r\n * Handles all events of the plugin.\r\n * @param {Object} event - Event object passed from listener.\r\n */\r\n handleEvent(event){\r\n this.updateSticky(event);\r\n }\r\n\r\n /**\r\n * Calculates dimesntions of sidebar, container and screen viewpoint\r\n * @public\r\n */\r\n calcDimensions(){\r\n if( this._breakpoint ) return;\r\n var dims = this.dimensions;\r\n\r\n // Container of sticky sidebar dimensions.\r\n dims.containerTop = StickySidebar.offsetRelative(this.container).top;\r\n dims.containerHeight = this.container.clientHeight;\r\n dims.containerBottom = dims.containerTop + dims.containerHeight;\r\n\r\n // Sidebar dimensions.\r\n dims.sidebarHeight = this.sidebarInner.offsetHeight;\r\n dims.sidebarWidth = this.sidebar.offsetWidth;\r\n \r\n // Screen viewport dimensions.\r\n dims.viewportHeight = window.innerHeight;\r\n\r\n this._calcDimensionsWithScroll();\r\n }\r\n\r\n /**\r\n * Some dimensions values need to be up-to-date when scrolling the page.\r\n * @private\r\n */\r\n _calcDimensionsWithScroll(){\r\n var dims = this.dimensions;\r\n\r\n dims.sidebarLeft = StickySidebar.offsetRelative(this.sidebar).left;\r\n\r\n dims.viewportTop = document.documentElement.scrollTop || document.body.scrollTop;\r\n dims.viewportBottom = dims.viewportTop + dims.viewportHeight;\r\n dims.viewportLeft = document.documentElement.scrollLeft || document.body.scrollLeft;\r\n\r\n dims.topSpacing = this.options.topSpacing;\r\n dims.bottomSpacing = this.options.bottomSpacing;\r\n\r\n if( 'function' === typeof dims.topSpacing )\r\n dims.topSpacing = parseInt(dims.topSpacing(this.sidebar)) || 0;\r\n\r\n if( 'function' === typeof dims.bottomSpacing )\r\n dims.bottomSpacing = parseInt(dims.bottomSpacing(this.sidebar)) || 0;\r\n }\r\n \r\n /**\r\n * Detarmine wheather the sidebar is bigger than viewport.\r\n * @public\r\n * @return {Boolean}\r\n */\r\n isSidebarFitsViewport(){\r\n return this.dimensions.sidebarHeight < this.dimensions.viewportHeight;\r\n }\r\n\r\n /**\r\n * Observe browser scrolling direction top and down.\r\n */\r\n observeScrollDir(){\r\n var dims = this.dimensions;\r\n if( dims.lastViewportTop === dims.viewportTop ) return;\r\n\r\n var furthest = 'down' === this.direction ? Math.min : Math.max;\r\n \r\n // If the browser is scrolling not in the same direction.\r\n if( dims.viewportTop === furthest(dims.viewportTop, dims.lastViewportTop) )\r\n this.direction = 'down' === this.direction ? 'up' : 'down';\r\n }\r\n\r\n /**\r\n * Gets affix type of sidebar according to current scrollTop and scrollLeft.\r\n * Holds all logical affix of the sidebar when scrolling up and down and when sidebar \r\n * is bigger than viewport and vice versa.\r\n * @public\r\n * @return {String|False} - Proper affix type.\r\n */\r\n getAffixType(){\r\n var dims = this.dimensions, affixType = false;\r\n\r\n this._calcDimensionsWithScroll();\r\n\r\n var sidebarBottom = dims.sidebarHeight + dims.containerTop;\r\n var colliderTop = dims.viewportTop + dims.topSpacing;\r\n var colliderBottom = dims.viewportBottom - dims.bottomSpacing;\r\n\r\n // When browser is scrolling top.\r\n if( 'up' === this.direction ){\r\n if( colliderTop <= dims.containerTop ){\r\n dims.translateY = 0;\r\n affixType = 'STATIC';\r\n\r\n } else if( colliderTop <= dims.translateY + dims.containerTop ){\r\n dims.translateY = colliderTop - dims.containerTop;\r\n affixType = 'VIEWPORT-TOP';\r\n\r\n } else if( ! this.isSidebarFitsViewport() && dims.containerTop <= colliderTop ){\r\n affixType = 'VIEWPORT-UNBOTTOM';\r\n }\r\n // When browser is scrolling up.\r\n } else {\r\n // When sidebar element is not bigger than screen viewport.\r\n if( this.isSidebarFitsViewport() ){\r\n\r\n if( dims.sidebarHeight + colliderTop >= dims.containerBottom ){\r\n dims.translateY = dims.containerBottom - sidebarBottom;\r\n affixType = 'CONTAINER-BOTTOM'; \r\n\r\n } else if( colliderTop >= dims.containerTop ){\r\n dims.translateY = colliderTop - dims.containerTop;\r\n affixType = 'VIEWPORT-TOP';\r\n }\r\n // When sidebar element is bigger than screen viewport.\r\n } else {\r\n \r\n if( dims.containerBottom <= colliderBottom ){\r\n dims.translateY = dims.containerBottom - sidebarBottom; \r\n affixType = 'CONTAINER-BOTTOM'; \r\n\r\n } else if( sidebarBottom + dims.translateY <= colliderBottom ){\r\n dims.translateY = colliderBottom - sidebarBottom;\r\n affixType = 'VIEWPORT-BOTTOM';\r\n \r\n } else if( dims.containerTop + dims.translateY <= colliderTop ){\r\n affixType = 'VIEWPORT-UNBOTTOM';\r\n }\r\n }\r\n }\r\n\r\n // Make sure the translate Y is not bigger than container height.\r\n dims.translateY = Math.max(0, dims.translateY);\r\n dims.translateY = Math.min(dims.containerHeight, dims.translateY);\r\n\r\n dims.lastViewportTop = dims.viewportTop;\r\n return affixType;\r\n }\r\n\r\n /**\r\n * Gets inline style of sticky sidebar wrapper and inner wrapper according \r\n * to its affix type.\r\n * @private\r\n * @param {String} affixType - Affix type of sticky sidebar.\r\n * @return {Object}\r\n */\r\n _getStyle(affixType){\r\n if( 'undefined' === typeof affixType ) return;\r\n\r\n var style = {inner: {}, outer: {}};\r\n var dims = this.dimensions;\r\n\r\n switch( affixType ){\r\n case 'VIEWPORT-TOP':\r\n style.inner = {position: 'fixed', top: this.options.topSpacing,\r\n left: dims.sidebarLeft - dims.viewportLeft, width: dims.sidebarWidth};\r\n break;\r\n case 'VIEWPORT-BOTTOM':\r\n style.inner = {position: 'fixed', top: 'auto', left: dims.sidebarLeft,\r\n bottom: this.options.bottomSpacing, width: dims.sidebarWidth};\r\n break;\r\n case 'CONTAINER-BOTTOM':\r\n case 'VIEWPORT-UNBOTTOM':\r\n let translate = this._getTranslate(0, dims.translateY + 'px');\r\n \r\n if( translate )\r\n style.inner = {transform: translate};\r\n else \r\n style.inner = {position: 'absolute', top: dims.containerTop + dims.translateY};\r\n break;\r\n }\r\n \r\n switch( affixType ){\r\n case 'VIEWPORT-TOP':\r\n case 'VIEWPORT-BOTTOM':\r\n case 'VIEWPORT-UNBOTTOM':\r\n case 'CONTAINER-BOTTOM':\r\n style.outer = {height: dims.sidebarHeight, position: 'relative'};\r\n break;\r\n }\r\n\r\n style.outer = StickySidebar.extend({height: '', position: ''}, style.outer);\r\n style.inner = StickySidebar.extend({position: 'relative', top: '', left: '',\r\n bottom: '', width: '', transform: this._getTranslate()}, style.inner);\r\n\r\n return style;\r\n }\r\n \r\n /**\r\n * Cause the sidebar to be sticky according to affix type by adding inline\r\n * style, adding helper class and trigger events.\r\n * @function\r\n * @protected\r\n * @param {string} force - Update sticky sidebar position by force.\r\n */\r\n stickyPosition(force){\r\n if( this._breakpoint ) return;\r\n\r\n force = force || false;\r\n \r\n var offsetTop = this.options.topSpacing;\r\n var offsetBottom = this.options.bottomSpacing;\r\n\r\n var affixType = this.getAffixType();\r\n var style = this._getStyle(affixType);\r\n \r\n if( (this.affixedType != affixType || force) && affixType ){\r\n let affixEvent = 'affix.' + affixType.replace('viewport-', '') + EVENT_KEY;\r\n StickySidebar.eventTrigger(this.sidebar, affixEvent);\r\n\r\n if( 'static' === affixType )\r\n this.sidebar.classList.remove(this.options.stickyClass);\r\n else\r\n this.sidebar.classList.add(this.options.stickyClass);\r\n \r\n for( let key in style.outer ){\r\n let _unit = ('number' === typeof style.outer[key]) ? 'px' : '';\r\n this.sidebar.style[key] = style.outer[key];\r\n }\r\n\r\n for( let key in style.inner ){\r\n let _unit = ('number' === typeof style.inner[key]) ? 'px' : '';\r\n this.sidebarInner.style[key] = style.inner[key] + _unit;\r\n }\r\n\r\n let affixedEvent = 'affixed.'+ affixType.replace('viewport', '') + EVENT_KEY;\r\n StickySidebar.eventTrigger(this.sidebar, affixedEvent);\r\n } else {\r\n if( this._initialized ) this.sidebarInner.style.left = style.inner.left;\r\n }\r\n\r\n this.affixedType = affixType;\r\n }\r\n\r\n /**\r\n * Breakdown sticky sidebar when window width is below `options.minWidth` value.\r\n * @protected\r\n */\r\n _widthBreakpoint(){\r\n\r\n if( window.innerWidth <= this.options.minWidth ){\r\n this._breakpoint = true;\r\n this.affixedType = 'STATIC';\r\n\r\n this.sidebar.removeAttribute('style');\r\n this.sidebar.classList.remove(this.options.stickyClass);\r\n this.sidebarInner.removeAttribute('style');\r\n } else {\r\n this._breakpoint = false;\r\n }\r\n }\r\n\r\n /**\r\n * Switchs between functions stack for each event type, if there's no \r\n * event, it will re-initialize sticky sidebar.\r\n * @public\r\n */\r\n updateSticky(event = {}){\r\n if( this._running ) return;\r\n this._running = true;\r\n \r\n ((eventType) => {\r\n requestAnimationFrame(() => {\r\n switch( eventType ){\r\n // When browser is scrolling and re-calculate just dimensions\r\n // within scroll. \r\n case 'scroll':\r\n this._calcDimensionsWithScroll();\r\n this.observeScrollDir();\r\n this.stickyPosition();\r\n break;\r\n\r\n // When browser is resizing or there's no event, observe width\r\n // breakpoint and re-calculate dimensions.\r\n case 'resize':\r\n default: \r\n this._widthBreakpoint();\r\n this.calcDimensions();\r\n this.stickyPosition('resize' === eventType || false);\r\n break;\r\n }\r\n this._running = false;\r\n });\r\n })(event.type);\r\n }\r\n\r\n /**\r\n * Set browser support features to the public property.\r\n * @private\r\n */\r\n _setSupportFeatures(){\r\n var support = this.support;\r\n\r\n support.transform = StickySidebar.supportTransform();\r\n support.transform3d = StickySidebar.supportTransform(true);\r\n }\r\n\r\n /**\r\n * Get translate value, if the browser supports transfrom3d, it will adopt it.\r\n * and the same with translate. if browser doesn't support both return false.\r\n * @param {Number} y - Value of Y-axis.\r\n * @param {Number} x - Value of X-axis.\r\n * @param {Number} z - Value of Z-axis.\r\n * @return {String|False}\r\n */\r\n _getTranslate(y = 0, x = 0, z = 0){\r\n if( this.support.transform3d ) return 'translate3d(' + y +', '+ x +', '+ z +')';\r\n else if( this.support.translate ) return 'translate('+ y +', '+ x +')';\r\n else return false;\r\n }\r\n\r\n /**\r\n * Add resize sensor listener to specifc element.\r\n * @public\r\n * @param {DOMElement} element - \r\n * @param {Function} callback - \r\n */\r\n addResizerListener(element, callback){\r\n if( ! element.resizeListeners ){\r\n element.resizeListeners = [];\r\n this._appendResizeSensor(element);\r\n }\r\n \r\n element.resizeListeners.push(callback);\r\n }\r\n\r\n /**\r\n * Remove resize sonser listener from specific element.\r\n * @function\r\n * @public\r\n * @param {DOMElement} element - \r\n * @param {Function} callback - \r\n */\r\n removeResizeListener(element, callback){\r\n var resizeListeners = element.resizeListeners;\r\n var index = resizeListeners.indexOf(callback);\r\n\r\n this._resizeListeners.splice(index, 1);\r\n\r\n if( null !== element.resizeListeners){\r\n var resizeTrigger = element.resizeTrigger;\r\n var _window = resizeTrigger.contentDocument.defaultView;\r\n\r\n _window.removeEventListener('resize', this._resizeListener);\r\n resizeTrigger = resizeTrigger.remove();\r\n }\r\n }\r\n\r\n /**\r\n * Append resize sensor object on DOM in specific element.\r\n * @private\r\n * @param {DOMElement} element - \r\n */\r\n _appendResizeSensor(element){\r\n element.style.position = 'relative';\r\n\r\n var wrapper = document.createElement('object');\r\n var style = 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%;' + \r\n 'overflow: hidden; pointer-events: none; z-index: -1;';\r\n\r\n wrapper.setAttribute('style', style);\r\n wrapper.resizeElement = element;\r\n\r\n wrapper.addEventListener('load', (event) => {\r\n let target = event.currentTarget;\r\n\r\n target.contentDocument.defaultView.resizeTrigger = target.resizeElement;\r\n target.contentDocument.defaultView.addEventListener('resize', this._resizeListener);\r\n });\r\n\r\n wrapper.type = 'text/html';\r\n\r\n if( StickySidebar.isIE() ) wrapper.data = 'about:blank';\r\n \r\n element.resizeTrigger = wrapper;\r\n element.appendChild(wrapper);\r\n }\r\n\r\n /**\r\n * Resize sensor listener to call callbacks of trigger.\r\n * @private \r\n * @param {Object} event - Event object passed from listener.\r\n */\r\n _resizeListener(event){\r\n var _window = event.target || event.srcElement;\r\n var trigger = _window.resizeTrigger;\r\n \r\n trigger.resizeListeners.forEach((callback) => {\r\n if( 'object' === typeof callback ){\r\n callback = callback.handleEvent;\r\n trigger = this;\r\n }\r\n callback.call(trigger, event);\r\n });\r\n }\r\n\r\n /**\r\n * Destroy sticky sidebar plugin.\r\n * @public\r\n */\r\n destroy(){\r\n window.removeEventListener('resize', this._onResize);\r\n window.removeEventListener('scroll', this._onScroll);\r\n\r\n this.sidebar.classList.remove(this.options.stickyClass);\r\n this.sidebar.style.minHeight = '';\r\n\r\n this.removeEventListener('update' + EVENT_KEY, this.updateSticky);\r\n\r\n var styleReset = {position: '', top: '', left: '', bottom: '', width: '', transform: ''};\r\n for( let key in styleReset )\r\n this.sidebar.style[key] = styleReset[key];\r\n\r\n if( this.options.resizeSensor ){\r\n this.removeResizeListener(this.sidebarInner, this.updateSticky);\r\n this.removeResizeListener(this.container, this.updateSticky);\r\n }\r\n }\r\n\r\n /**\r\n * Detarmine if the browser is Internet Explorer.\r\n * @function\r\n * @static\r\n */\r\n static isIE(){\r\n return Boolean(navigator.userAgent.match(/Trident/));\r\n }\r\n\r\n /**\r\n * Detarmine if the browser supports CSS transfrom feature.\r\n * @function\r\n * @static\r\n * @param {Boolean} transform3d - Detect transform with translate3d.\r\n * @return {String}\r\n */\r\n static supportTransform(transform3d){\r\n var result = false,\r\n property = (transform3d) ? 'perspective' : 'transform',\r\n upper = property.charAt(0).toUpperCase() + property.slice(1),\r\n prefixes = ['Webkit', 'Moz', 'O', 'ms'],\r\n support = document.createElement('support'),\r\n style = support.style;\r\n\r\n (property + ' ' + prefixes.join(upper + ' ') + upper).split(' ').forEach(function(property, i) {\r\n if (style[property] !== undefined) {\r\n result = property;\r\n return false;\r\n }\r\n });\r\n return result;\r\n }\r\n\r\n /**\r\n * Trigger custom event.\r\n * @static\r\n * @param {DOMObject} element - Target element on the DOM.\r\n * @param {String} eventName - Event name.\r\n * @param {Object} data - \r\n */\r\n static eventTrigger(element, eventName, data){\r\n data = ( 'object' === typeof data ) ? data : {};\r\n\r\n if (window.CustomEvent) {\r\n var event = new CustomEvent(eventName, {detail: data});\r\n } else {\r\n var event = document.createEvent('CustomEvent');\r\n event.initCustomEvent(eventName, true, true, data);\r\n }\r\n element.dispatchEvent(event);\r\n }\r\n\r\n /**\r\n * Extend options object with defaults.\r\n * @function\r\n * @static\r\n */\r\n static extend(defaults, options){\r\n var results = {};\r\n for( let key in defaults ){\r\n if( 'undefined' !== typeof options[key] ) results[key] = options[key];\r\n else results[key] = defaults[key];\r\n }\r\n return results;\r\n }\r\n\r\n /**\r\n * Get current coordinates left and top of specific element.\r\n * @static\r\n */\r\n static offsetRelative(element){\r\n var result = {left: 0, top: 0};\r\n do{\r\n let offsetTop = element.offsetTop;\r\n let offsetLeft = element.offsetLeft;\r\n\r\n if( ! isNaN(offsetTop) )\r\n result.top += offsetTop;\r\n\r\n if( ! isNaN(offsetLeft) )\r\n result.left += offsetLeft;\r\n } while( element = element.offsetParent )\r\n return result;\r\n }\r\n }\r\n\r\n // Global\r\n // -------------------------\r\n window.StickySidebar = StickySidebar;\r\n\r\n return StickySidebar;\r\n})();"]} \ No newline at end of file +{"version":3,"file":"sticky-sidebar.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/dist/sticky-sidebar.min.js b/dist/sticky-sidebar.min.js index c164c0d..bc4686d 100644 --- a/dist/sticky-sidebar.min.js +++ b/dist/sticky-sidebar.min.js @@ -5,4 +5,4 @@ * @author Ahmed Bouhuolia * @license The MIT License (MIT) **/ -function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var _createClass=function(){function e(e,t){for(var i=0;i1&&void 0!==arguments[1]?arguments[1]:{};if(_classCallCheck(this,i),this.options=i.extend(t,s),this.sidebar="string"==typeof e?document.querySelector(e):e,void 0===this.sidebar)throw new Error("There is no specific sidebar element.");if(this.sidebarInner=!1,this.container=this.sidebar.parentElement,this.options.containerSelector){var r=document.querySelectorAll(this.options.containerSelector);if((r=Array.prototype.slice.call(r)).forEach(function(e,t){e.contains(n.sidebar)&&(n.container=e)}),!r.length)throw new Error("The container does not contains on the sidebar.")}this.affixedType="static",this.direction="down",this.support={transform:!1,transform3d:!1},this._initialized=!1,this._breakpoint=!1,this._resizeListeners=[],this.dimensions={translateY:0,topSpacing:0,bottomSpacing:0,sidebarHeight:0,sidebarWidth:0,containerTop:0,containerHeight:0,viewportHeight:0,viewportTop:0,lastViewportTop:0},["_resizeListener"].forEach(function(e){n[e]=n[e].bind(n)}),this.initialize()}return _createClass(i,[{key:"initialize",value:function(){if(this._setSupportFeatures(),this.options.innerWrapperSelector&&(this.sidebarInner=this.sidebar.querySelector(this.options.innerWrapperSelector),null!==this.sidebarInner&&(this.sidebarInner=!1)),!this.sidebarInner){var e=document.createElement("div");for(e.setAttribute("class","inner-wrapper-sticky"),this.sidebar.appendChild(e);this.sidebar.firstChild!=e;)e.appendChild(this.sidebar.firstChild);this.sidebarInner=this.sidebar.querySelector(".inner-wrapper-sticky")}null!==this.container&&(this.container=this.sidebar.parentElement),"function"!=typeof this.options.topSpacing&&(this.options.topSpacing=parseInt(this.options.topSpacing)||0),"function"!=typeof this.options.bottomSpacing&&(this.options.bottomSpacing=parseInt(this.options.bottomSpacing)||0),this._widthBreakpoint(),this.calcDimensions(),this.stickyPosition(),this.bindEvents(),this._initialized=!0}},{key:"bindEvents",value:function(){window.addEventListener("resize",this,{passive:!0}),window.addEventListener("scroll",this,{passive:!0}),this.sidebar.addEventListener("update"+e,this),this.options.resizeSensor&&(this.addResizerListener(this.sidebarInner,this),this.addResizerListener(this.container,this))}},{key:"handleEvent",value:function(e){this.updateSticky(e)}},{key:"calcDimensions",value:function(){if(!this._breakpoint){var e=this.dimensions;e.containerTop=i.offsetRelative(this.container).top,e.containerHeight=this.container.clientHeight,e.containerBottom=e.containerTop+e.containerHeight,e.sidebarHeight=this.sidebarInner.offsetHeight,e.sidebarWidth=this.sidebar.offsetWidth,e.viewportHeight=window.innerHeight,this._calcDimensionsWithScroll()}}},{key:"_calcDimensionsWithScroll",value:function(){var e=this.dimensions;e.sidebarLeft=i.offsetRelative(this.sidebar).left,e.viewportTop=document.documentElement.scrollTop||document.body.scrollTop,e.viewportBottom=e.viewportTop+e.viewportHeight,e.viewportLeft=document.documentElement.scrollLeft||document.body.scrollLeft,e.topSpacing=this.options.topSpacing,e.bottomSpacing=this.options.bottomSpacing,"function"==typeof e.topSpacing&&(e.topSpacing=parseInt(e.topSpacing(this.sidebar))||0),"function"==typeof e.bottomSpacing&&(e.bottomSpacing=parseInt(e.bottomSpacing(this.sidebar))||0)}},{key:"isSidebarFitsViewport",value:function(){return this.dimensions.sidebarHeight=e.containerBottom?(e.translateY=e.containerBottom-i,t="CONTAINER-BOTTOM"):n>=e.containerTop&&(e.translateY=n-e.containerTop,t="VIEWPORT-TOP"):e.containerBottom<=s?(e.translateY=e.containerBottom-i,t="CONTAINER-BOTTOM"):i+e.translateY<=s?(e.translateY=s-i,t="VIEWPORT-BOTTOM"):e.containerTop+e.translateY<=n&&(t="VIEWPORT-UNBOTTOM"),e.translateY=Math.max(0,e.translateY),e.translateY=Math.min(e.containerHeight,e.translateY),e.lastViewportTop=e.viewportTop,t}},{key:"_getStyle",value:function(e){if(void 0!==e){var t={inner:{},outer:{}},n=this.dimensions;switch(e){case"VIEWPORT-TOP":t.inner={position:"fixed",top:this.options.topSpacing,left:n.sidebarLeft-n.viewportLeft,width:n.sidebarWidth};break;case"VIEWPORT-BOTTOM":t.inner={position:"fixed",top:"auto",left:n.sidebarLeft,bottom:this.options.bottomSpacing,width:n.sidebarWidth};break;case"CONTAINER-BOTTOM":case"VIEWPORT-UNBOTTOM":var s=this._getTranslate(0,n.translateY+"px");t.inner=s?{transform:s}:{position:"absolute",top:n.containerTop+n.translateY}}switch(e){case"VIEWPORT-TOP":case"VIEWPORT-BOTTOM":case"VIEWPORT-UNBOTTOM":case"CONTAINER-BOTTOM":t.outer={height:n.sidebarHeight,position:"relative"}}return t.outer=i.extend({height:"",position:""},t.outer),t.inner=i.extend({position:"relative",top:"",left:"",bottom:"",width:"",transform:this._getTranslate()},t.inner),t}}},{key:"stickyPosition",value:function(t){if(!this._breakpoint){t=t||!1;this.options.topSpacing,this.options.bottomSpacing;var n=this.getAffixType(),s=this._getStyle(n);if((this.affixedType!=n||t)&&n){var r="affix."+n.replace("viewport-","")+e;i.eventTrigger(this.sidebar,r),"static"===n?this.sidebar.classList.remove(this.options.stickyClass):this.sidebar.classList.add(this.options.stickyClass);for(var o in s.outer){s.outer[o];this.sidebar.style[o]=s.outer[o]}for(var a in s.inner){var c="number"==typeof s.inner[a]?"px":"";this.sidebarInner.style[a]=s.inner[a]+c}var p="affixed."+n.replace("viewport","")+e;i.eventTrigger(this.sidebar,p)}else this._initialized&&(this.sidebarInner.style.left=s.inner.left);this.affixedType=n}}},{key:"_widthBreakpoint",value:function(){window.innerWidth<=this.options.minWidth?(this._breakpoint=!0,this.affixedType="STATIC",this.sidebar.removeAttribute("style"),this.sidebar.classList.remove(this.options.stickyClass),this.sidebarInner.removeAttribute("style")):this._breakpoint=!1}},{key:"updateSticky",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this._running||(this._running=!0,function(t){requestAnimationFrame(function(){switch(t){case"scroll":e._calcDimensionsWithScroll(),e.observeScrollDir(),e.stickyPosition();break;case"resize":default:e._widthBreakpoint(),e.calcDimensions(),e.stickyPosition("resize"===t||!1)}e._running=!1})}(t.type))}},{key:"_setSupportFeatures",value:function(){var e=this.support;e.transform=i.supportTransform(),e.transform3d=i.supportTransform(!0)}},{key:"_getTranslate",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;return this.support.transform3d?"translate3d("+e+", "+t+", "+i+")":!!this.support.translate&&"translate("+e+", "+t+")"}},{key:"addResizerListener",value:function(e,t){e.resizeListeners||(e.resizeListeners=[],this._appendResizeSensor(e)),e.resizeListeners.push(t)}},{key:"removeResizeListener",value:function(e,t){var i=e.resizeListeners.indexOf(t);if(this._resizeListeners.splice(i,1),null!==e.resizeListeners){var n=e.resizeTrigger;n.contentDocument.defaultView.removeEventListener("resize",this._resizeListener),n=n.remove()}}},{key:"_appendResizeSensor",value:function(e){var t=this;e.style.position="relative";var n=document.createElement("object");n.setAttribute("style","display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%;overflow: hidden; pointer-events: none; z-index: -1;"),n.resizeElement=e,n.addEventListener("load",function(e){var i=e.currentTarget;i.contentDocument.defaultView.resizeTrigger=i.resizeElement,i.contentDocument.defaultView.addEventListener("resize",t._resizeListener)}),n.type="text/html",i.isIE()&&(n.data="about:blank"),e.resizeTrigger=n,e.appendChild(n)}},{key:"_resizeListener",value:function(e){var t=this,i=(e.target||e.srcElement).resizeTrigger;i.resizeListeners.forEach(function(n){"object"==typeof n&&(n=n.handleEvent,i=t),n.call(i,e)})}},{key:"destroy",value:function(){window.removeEventListener("resize",this._onResize),window.removeEventListener("scroll",this._onScroll),this.sidebar.classList.remove(this.options.stickyClass),this.sidebar.style.minHeight="",this.removeEventListener("update"+e,this.updateSticky);var t={position:"",top:"",left:"",bottom:"",width:"",transform:""};for(var i in t)this.sidebar.style[i]=t[i];this.options.resizeSensor&&(this.removeResizeListener(this.sidebarInner,this.updateSticky),this.removeResizeListener(this.container,this.updateSticky))}}],[{key:"isIE",value:function(){return Boolean(navigator.userAgent.match(/Trident/))}},{key:"supportTransform",value:function(e){var t=!1,i=e?"perspective":"transform",n=i.charAt(0).toUpperCase()+i.slice(1),s=["Webkit","Moz","O","ms"],r=document.createElement("support").style;return(i+" "+s.join(n+" ")+n).split(" ").forEach(function(e,i){if(void 0!==r[e])return t=e,!1}),t}},{key:"eventTrigger",value:function(e,t,i){if(i="object"==typeof i?i:{},window.CustomEvent)var n=new CustomEvent(t,{detail:i});else(n=document.createEvent("CustomEvent")).initCustomEvent(t,!0,!0,i);e.dispatchEvent(n)}},{key:"extend",value:function(e,t){var i={};for(var n in e)void 0!==t[n]?i[n]=t[n]:i[n]=e[n];return i}},{key:"offsetRelative",value:function(e){var t={left:0,top:0};do{var i=e.offsetTop,n=e.offsetLeft;isNaN(i)||(t.top+=i),isNaN(n)||(t.left+=n)}while(e=e.offsetParent);return t}}]),i}();return window.StickySidebar=i,i}(); \ No newline at end of file +var stickySidebarModule=function(){"use strict";function e(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}!function(e){for(var t=0,i=["webkit","moz"],n=e.requestAnimationFrame,s=e.cancelAnimationFrame,r=i.length;--r>=0&&!n;)n=e[i[r]+"RequestAnimationFrame"],s=e[i[r]+"CancelAnimationFrame"];n&&s||(n=function(e){var i=+new Date,n=Math.max(t+16,i);return setTimeout(function(){e(t=n)},n-i)},s=clearTimeout),e.requestAnimationFrame=n,e.cancelAnimationFrame=s}(window);var t=function(){function e(e,t){for(var i=0;i1&&void 0!==arguments[1]?arguments[1]:{};if(e(this,s),this.options=s.extend(n,r),this.sidebar="string"==typeof t?document.querySelector(t):t,void 0===this.sidebar)throw new Error("There is no specific sidebar element.");if(this.sidebarInner=!1,this.container=this.sidebar.parentElement,this.options.containerSelector){var o=document.querySelectorAll(this.options.containerSelector);if((o=Array.prototype.slice.call(o)).forEach(function(e,t){e.contains(i.sidebar)&&(i.container=e)}),!o.length)throw new Error("The container does not contains on the sidebar.")}this.affixedType="STATIC",this.direction="down",this.support={transform:!1,transform3d:!1},this._initialized=!1,this._breakpoint=!1,this._resizeListeners=[],this.dimensions={translateY:0,topSpacing:0,bottomSpacing:0,sidebarHeight:0,sidebarWidth:0,containerTop:0,containerHeight:0,viewportHeight:0,viewportTop:0,lastViewportTop:0},["_resizeListener"].forEach(function(e){i[e]=i[e].bind(i)}),this.initialize()}return t(s,[{key:"initialize",value:function(){if(this._setSupportFeatures(),this.options.innerWrapperSelector&&(this.sidebarInner=this.sidebar.querySelector(this.options.innerWrapperSelector),null!==this.sidebarInner&&(this.sidebarInner=!1)),!this.sidebarInner){var e=document.createElement("div");for(e.setAttribute("class","inner-wrapper-sticky"),this.sidebar.appendChild(e);this.sidebar.firstChild!=e;)e.appendChild(this.sidebar.firstChild);this.sidebarInner=this.sidebar.querySelector(".inner-wrapper-sticky")}null!==this.container&&(this.container=this.sidebar.parentElement),"function"!=typeof this.options.topSpacing&&(this.options.topSpacing=parseInt(this.options.topSpacing)||0),"function"!=typeof this.options.bottomSpacing&&(this.options.bottomSpacing=parseInt(this.options.bottomSpacing)||0),this._widthBreakpoint(),this.calcDimensions(),this.stickyPosition(),this.bindEvents(),this._initialized=!0}},{key:"bindEvents",value:function(){window.addEventListener("resize",this,{passive:!0}),window.addEventListener("scroll",this,{passive:!0}),this.sidebar.addEventListener("update"+i,this),this.options.resizeSensor&&(this.addResizerListener(this.sidebarInner,this),this.addResizerListener(this.container,this))}},{key:"handleEvent",value:function(e){this.updateSticky(e)}},{key:"calcDimensions",value:function(){if(!this._breakpoint){var e=this.dimensions;e.containerTop=s.offsetRelative(this.container).top,e.containerHeight=this.container.clientHeight,e.containerBottom=e.containerTop+e.containerHeight,e.sidebarHeight=this.sidebarInner.offsetHeight,e.sidebarWidth=this.sidebar.offsetWidth,e.viewportHeight=window.innerHeight,this._calcDimensionsWithScroll()}}},{key:"_calcDimensionsWithScroll",value:function(){var e=this.dimensions;e.sidebarLeft=s.offsetRelative(this.sidebar).left,e.viewportTop=document.documentElement.scrollTop||document.body.scrollTop,e.viewportBottom=e.viewportTop+e.viewportHeight,e.viewportLeft=document.documentElement.scrollLeft||document.body.scrollLeft,e.topSpacing=this.options.topSpacing,e.bottomSpacing=this.options.bottomSpacing,"function"==typeof e.topSpacing&&(e.topSpacing=parseInt(e.topSpacing(this.sidebar))||0),"function"==typeof e.bottomSpacing&&(e.bottomSpacing=parseInt(e.bottomSpacing(this.sidebar))||0)}},{key:"isSidebarFitsViewport",value:function(){return this.dimensions.sidebarHeight=e.containerBottom?(e.translateY=e.containerBottom-i,t="CONTAINER-BOTTOM"):n>=e.containerTop&&(e.translateY=n-e.containerTop,t="VIEWPORT-TOP"):e.containerBottom<=s?(e.translateY=e.containerBottom-i,t="CONTAINER-BOTTOM"):i+e.translateY<=s?(e.translateY=s-i,t="VIEWPORT-BOTTOM"):e.containerTop+e.translateY<=n&&(t="VIEWPORT-UNBOTTOM"),e.translateY=Math.max(0,e.translateY),e.translateY=Math.min(e.containerHeight,e.translateY),e.lastViewportTop=e.viewportTop,t}},{key:"_getStyle",value:function(e){if(void 0!==e){var t={inner:{},outer:{}},i=this.dimensions;switch(e){case"VIEWPORT-TOP":t.inner={position:"fixed",top:this.options.topSpacing,left:i.sidebarLeft-i.viewportLeft,width:i.sidebarWidth};break;case"VIEWPORT-BOTTOM":t.inner={position:"fixed",top:"auto",left:i.sidebarLeft,bottom:this.options.bottomSpacing,width:i.sidebarWidth};break;case"CONTAINER-BOTTOM":case"VIEWPORT-UNBOTTOM":var n=this._getTranslate(0,i.translateY+"px");t.inner=n?{transform:n}:{position:"absolute",top:i.containerTop+i.translateY}}switch(e){case"VIEWPORT-TOP":case"VIEWPORT-BOTTOM":case"VIEWPORT-UNBOTTOM":case"CONTAINER-BOTTOM":t.outer={height:i.sidebarHeight,position:"relative"}}return t.outer=s.extend({height:"",position:""},t.outer),t.inner=s.extend({position:"relative",top:"",left:"",bottom:"",width:"",transform:this._getTranslate()},t.inner),t}}},{key:"stickyPosition",value:function(e){if(!this._breakpoint){e=e||!1;this.options.topSpacing,this.options.bottomSpacing;var t=this.getAffixType(),n=this._getStyle(t);if((this.affixedType!=t||e)&&t){var r="affix."+t.toLowerCase().replace("viewport-","")+i;s.eventTrigger(this.sidebar,r),"STATIC"===t?this.sidebar.classList.remove(this.options.stickyClass):this.sidebar.classList.add(this.options.stickyClass);for(var o in n.outer){n.outer[o];this.sidebar.style[o]=n.outer[o]}for(var a in n.inner){var c="number"==typeof n.inner[a]?"px":"";this.sidebarInner.style[a]=n.inner[a]+c}var p="affixed."+t.toLowerCase().replace("viewport","")+i;s.eventTrigger(this.sidebar,p)}else this._initialized&&(this.sidebarInner.style.left=n.inner.left);this.affixedType=t}}},{key:"_widthBreakpoint",value:function(){window.innerWidth<=this.options.minWidth?(this._breakpoint=!0,this.affixedType="STATIC",this.sidebar.removeAttribute("style"),this.sidebar.classList.remove(this.options.stickyClass),this.sidebarInner.removeAttribute("style")):this._breakpoint=!1}},{key:"updateSticky",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this._running||(this._running=!0,function(t){requestAnimationFrame(function(){switch(t){case"scroll":e._calcDimensionsWithScroll(),e.observeScrollDir(),e.stickyPosition();break;case"resize":default:e._widthBreakpoint(),e.calcDimensions(),e.stickyPosition("resize"===t||!1)}e._running=!1})}(t.type))}},{key:"_setSupportFeatures",value:function(){var e=this.support;e.transform=s.supportTransform(),e.transform3d=s.supportTransform(!0)}},{key:"_getTranslate",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;return this.support.transform3d?"translate3d("+e+", "+t+", "+i+")":!!this.support.translate&&"translate("+e+", "+t+")"}},{key:"addResizerListener",value:function(e,t){e.resizeListeners||(e.resizeListeners=[],this._appendResizeSensor(e)),e.resizeListeners.push(t)}},{key:"removeResizeListener",value:function(e,t){var i=e.resizeListeners.indexOf(t);if(this._resizeListeners.splice(i,1),null!==e.resizeListeners){var n=e.resizeTrigger;n.contentDocument.defaultView.removeEventListener("resize",this._resizeListener),n=n.remove()}}},{key:"_appendResizeSensor",value:function(e){var t=this;"static"===e.style.position&&(e.style.position="relative");var i=document.createElement("object");i.setAttribute("style","display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%;overflow: hidden; pointer-events: none; z-index: -1;"),i.resizeElement=e,i.addEventListener("load",function(e){var i=e.currentTarget;i.contentDocument.defaultView.resizeTrigger=i.resizeElement,i.contentDocument.defaultView.addEventListener("resize",t._resizeListener)}),i.type="text/html",s.isIE()&&(i.data="about:blank"),e.resizeTrigger=i,e.appendChild(i)}},{key:"_resizeListener",value:function(e){var t=this,i=(e.target||e.srcElement).resizeTrigger;i.resizeListeners.forEach(function(n){"object"==typeof n&&(n=n.handleEvent,i=t),n.call(i,e)})}},{key:"destroy",value:function(){window.removeEventListener("resize",this._onResize),window.removeEventListener("scroll",this._onScroll),this.sidebar.classList.remove(this.options.stickyClass),this.sidebar.style.minHeight="",this.removeEventListener("update"+i,this.updateSticky);var e={position:"",top:"",left:"",bottom:"",width:"",transform:""};for(var t in e)this.sidebar.style[t]=e[t];this.options.resizeSensor&&(this.removeResizeListener(this.sidebarInner,this.updateSticky),this.removeResizeListener(this.container,this.updateSticky))}}],[{key:"isIE",value:function(){return Boolean(navigator.userAgent.match(/Trident/))}},{key:"supportTransform",value:function(e){var t=!1,i=e?"perspective":"transform",n=i.charAt(0).toUpperCase()+i.slice(1),s=["Webkit","Moz","O","ms"],r=document.createElement("support").style;return(i+" "+s.join(n+" ")+n).split(" ").forEach(function(e,i){if(void 0!==r[e])return t=e,!1}),t}},{key:"eventTrigger",value:function(e,t,i){if(window.CustomEvent)var n=new CustomEvent(t,{detail:i});else(n=document.createEvent("CustomEvent")).initCustomEvent(t,!0,!0,i);e.dispatchEvent(n)}},{key:"extend",value:function(e,t){var i={};for(var n in e)void 0!==t[n]?i[n]=t[n]:i[n]=e[n];return i}},{key:"offsetRelative",value:function(e){var t={left:0,top:0};do{var i=e.offsetTop,n=e.offsetLeft;isNaN(i)||(t.top+=i),isNaN(n)||(t.left+=n)}while(e=e.offsetParent);return t}}]),s}()}();return window.StickySidebar=i,i}(); \ No newline at end of file