From 168e8390cccb948fa5c8ce1f5b06e1195b802f34 Mon Sep 17 00:00:00 2001 From: Matheus Bernardes Date: Thu, 22 Aug 2024 18:02:56 -0300 Subject: [PATCH 1/3] Adds active-slide event to emit for each active slide --- glider.js | 1110 +++++++++++++++++++++++++++-------------------------- 1 file changed, 562 insertions(+), 548 deletions(-) diff --git a/glider.js b/glider.js index 1fd819f..0d7007e 100644 --- a/glider.js +++ b/glider.js @@ -17,594 +17,608 @@ /* global define */ (function (factory) { - typeof define === 'function' && define.amd - ? define(factory) - : typeof exports === 'object' - ? (module.exports = factory()) - : factory() -})(function () { - ('use strict') // eslint-disable-line no-unused-expressions - - /* globals window:true */ - var _window = typeof window !== 'undefined' ? window : this - - var Glider = (_window.Glider = function (element, settings) { - var _ = this - - if (element._glider) return element._glider - - _.ele = element - _.ele.classList.add('glider') - - // expose glider object to its DOM element - _.ele._glider = _ - - // merge user setting with defaults - _.opt = Object.assign( - {}, - { - slidesToScroll: 1, - slidesToShow: 1, - resizeLock: true, - duration: 0.5, - passiveListeners: false, - // easeInQuad - easing: function (x, t, b, c, d) { - return c * (t /= d) * t + b + typeof define === 'function' && define.amd + ? define(factory) + : typeof exports === 'object' + ? (module.exports = factory()) + : factory() + })(function () { + ('use strict') // eslint-disable-line no-unused-expressions + + /* globals window:true */ + var _window = typeof window !== 'undefined' ? window : this + + var Glider = (_window.Glider = function (element, settings) { + var _ = this + + if (element._glider) return element._glider + + _.ele = element + _.ele.classList.add('glider') + + // used to make the slide-active event emit only once per active slide + _.lastEmittedActiveSlide = null + + // expose glider object to its DOM element + _.ele._glider = _ + + // merge user setting with defaults + _.opt = Object.assign( + {}, + { + slidesToScroll: 1, + slidesToShow: 1, + resizeLock: true, + duration: 0.5, + passiveListeners: false, + // easeInQuad + easing: function (x, t, b, c, d) { + return c * (t /= d) * t + b + } + }, + settings + ) + + // set defaults + _.animate_id = _.page = _.slide = 0 + _.arrows = {} + + // preserve original options to + // extend breakpoint settings + _._opt = _.opt + + if (_.opt.skipTrack) { + // first and only child is the track + _.track = _.ele.children[0] + } else { + // create track and wrap slides + _.track = document.createElement('div') + _.ele.appendChild(_.track) + while (_.ele.children.length !== 1) { + _.track.appendChild(_.ele.children[0]) } - }, - settings - ) - - // set defaults - _.animate_id = _.page = _.slide = 0 - _.arrows = {} - - // preserve original options to - // extend breakpoint settings - _._opt = _.opt - - if (_.opt.skipTrack) { - // first and only child is the track - _.track = _.ele.children[0] - } else { - // create track and wrap slides - _.track = document.createElement('div') - _.ele.appendChild(_.track) - while (_.ele.children.length !== 1) { - _.track.appendChild(_.ele.children[0]) } - } - - _.track.classList.add('glider-track') - - // start glider - _.init() - - // set events - _.resize = _.init.bind(_, true) - _.event( - _.ele, - 'add', - { - scroll: _.updateControls.bind(_) - }, - { passive: _.opt.passiveListeners } - ) - _.event(_window, 'add', { - resize: _.resize - }) - }) - - var gliderPrototype = Glider.prototype - gliderPrototype.init = function (refresh, paging) { - var _ = this - - var width = 0 - - var height = 0 - - _.slides = _.track.children; - - [].forEach.call(_.slides, function (_, i) { - _.classList.add('glider-slide') - _.setAttribute('data-gslide', i) - }) - - _.containerWidth = _.ele.clientWidth - - var breakpointChanged = _.settingsBreakpoint() - if (!paging) paging = breakpointChanged - - if ( - _.opt.slidesToShow === 'auto' || - typeof _.opt._autoSlide !== 'undefined' - ) { - var slideCount = _.containerWidth / _.opt.itemWidth - - _.opt._autoSlide = _.opt.slidesToShow = _.opt.exactWidth - ? slideCount - : Math.max(1, Math.floor(slideCount)) - } - if (_.opt.slidesToScroll === 'auto') { - _.opt.slidesToScroll = Math.floor(_.opt.slidesToShow) - } - - _.itemWidth = _.opt.exactWidth - ? _.opt.itemWidth - : _.containerWidth / _.opt.slidesToShow; - - // set slide dimensions - [].forEach.call(_.slides, function (__) { - __.style.height = 'auto' - __.style.width = _.itemWidth + 'px' - width += _.itemWidth - height = Math.max(__.offsetHeight, height) + + _.track.classList.add('glider-track') + + // start glider + _.init() + + // set events + _.resize = _.init.bind(_, true) + _.event( + _.ele, + 'add', + { + scroll: _.updateControls.bind(_) + }, + { passive: _.opt.passiveListeners } + ) + _.event(_window, 'add', { + resize: _.resize + }) }) - - _.track.style.width = width + 'px' - _.trackWidth = width - _.isDrag = false - _.preventClick = false - _.move = false - - _.opt.resizeLock && _.scrollTo(_.slide * _.itemWidth, 0) - - if (breakpointChanged || paging) { - _.bindArrows() - _.buildDots() - _.bindDrag() - } - - _.updateControls() - - _.emit(refresh ? 'refresh' : 'loaded') - } - - gliderPrototype.bindDrag = function () { - var _ = this - _.mouse = _.mouse || _.handleMouse.bind(_) - - var mouseup = function () { - _.mouseDown = undefined - _.ele.classList.remove('drag') - if (_.isDrag) { - _.preventClick = true + + var gliderPrototype = Glider.prototype + gliderPrototype.init = function (refresh, paging) { + var _ = this + + var width = 0 + + var height = 0 + + _.slides = _.track.children; + + [].forEach.call(_.slides, function (_, i) { + _.classList.add('glider-slide') + _.setAttribute('data-gslide', i) + }) + + _.containerWidth = _.ele.clientWidth + + var breakpointChanged = _.settingsBreakpoint() + if (!paging) paging = breakpointChanged + + if ( + _.opt.slidesToShow === 'auto' || + typeof _.opt._autoSlide !== 'undefined' + ) { + var slideCount = _.containerWidth / _.opt.itemWidth + + _.opt._autoSlide = _.opt.slidesToShow = _.opt.exactWidth + ? slideCount + : Math.max(1, Math.floor(slideCount)) + } + if (_.opt.slidesToScroll === 'auto') { + _.opt.slidesToScroll = Math.floor(_.opt.slidesToShow) } + + _.itemWidth = _.opt.exactWidth + ? _.opt.itemWidth + : _.containerWidth / _.opt.slidesToShow; + + // set slide dimensions + [].forEach.call(_.slides, function (__) { + __.style.height = 'auto' + __.style.width = _.itemWidth + 'px' + width += _.itemWidth + height = Math.max(__.offsetHeight, height) + }) + + _.track.style.width = width + 'px' + _.trackWidth = width _.isDrag = false + _.preventClick = false + _.move = false + + _.opt.resizeLock && _.scrollTo(_.slide * _.itemWidth, 0) + + if (breakpointChanged || paging) { + _.bindArrows() + _.buildDots() + _.bindDrag() + } + + _.updateControls() + + _.emit(refresh ? 'refresh' : 'loaded') } - - const move = function () { - _.move = true - } - - var events = { - mouseup: mouseup, - mouseleave: mouseup, - mousedown: function (e) { - e.preventDefault() - e.stopPropagation() - _.mouseDown = e.clientX - _.ele.classList.add('drag') - _.move = false - setTimeout(move, 300) - }, - touchstart: function (e) { - _.ele.classList.add('drag') - _.move = false - setTimeout(move, 300) - }, - mousemove: _.mouse, - click: function (e) { - if (_.preventClick && _.move) { + + gliderPrototype.bindDrag = function () { + var _ = this + _.mouse = _.mouse || _.handleMouse.bind(_) + + var mouseup = function () { + _.mouseDown = undefined + _.ele.classList.remove('drag') + if (_.isDrag) { + _.preventClick = true + } + _.isDrag = false + } + + const move = function () { + _.move = true + } + + var events = { + mouseup: mouseup, + mouseleave: mouseup, + mousedown: function (e) { e.preventDefault() e.stopPropagation() + _.mouseDown = e.clientX + _.ele.classList.add('drag') + _.move = false + setTimeout(move, 300) + }, + touchstart: function (e) { + _.ele.classList.add('drag') + _.move = false + setTimeout(move, 300) + }, + mousemove: _.mouse, + click: function (e) { + if (_.preventClick && _.move) { + e.preventDefault() + e.stopPropagation() + } + _.preventClick = false + _.move = false } - _.preventClick = false - _.move = false + } + + _.ele.classList.toggle('draggable', _.opt.draggable === true) + _.event(_.ele, 'remove', events) + if (_.opt.draggable) { + _.event(_.ele, 'add', events, { + passive: _.opt.passiveListeners + }) } } - - _.ele.classList.toggle('draggable', _.opt.draggable === true) - _.event(_.ele, 'remove', events) - if (_.opt.draggable) { - _.event(_.ele, 'add', events, { - passive: _.opt.passiveListeners - }) - } - } - - gliderPrototype.buildDots = function () { - var _ = this - - if (!_.opt.dots) { - if (_.dots) _.dots.innerHTML = '' - return - } - - if (typeof _.opt.dots === 'string') { - _.dots = document.querySelector(_.opt.dots) - } else _.dots = _.opt.dots - if (!_.dots) return - - _.dots.innerHTML = '' - _.dots.setAttribute('role', 'tablist') - _.dots.classList.add('glider-dots') - - for (var i = 0; i < Math.ceil(_.slides.length / _.opt.slidesToShow); ++i) { - var dot = document.createElement('button') - dot.dataset.index = i - dot.setAttribute('aria-label', 'Page ' + (i + 1)) - dot.setAttribute('role', 'tab') - dot.className = 'glider-dot ' + (i ? '' : 'active') - _.event(dot, 'add', { - click: _.scrollItem.bind(_, i, true) - }) - _.dots.appendChild(dot) + + gliderPrototype.buildDots = function () { + var _ = this + + if (!_.opt.dots) { + if (_.dots) _.dots.innerHTML = '' + return + } + + if (typeof _.opt.dots === 'string') { + _.dots = document.querySelector(_.opt.dots) + } else _.dots = _.opt.dots + if (!_.dots) return + + _.dots.innerHTML = '' + _.dots.setAttribute('role', 'tablist') + _.dots.classList.add('glider-dots') + + for (var i = 0; i < Math.ceil(_.slides.length / _.opt.slidesToShow); ++i) { + var dot = document.createElement('button') + dot.dataset.index = i + dot.setAttribute('aria-label', 'Page ' + (i + 1)) + dot.setAttribute('role', 'tab') + dot.className = 'glider-dot ' + (i ? '' : 'active') + _.event(dot, 'add', { + click: _.scrollItem.bind(_, i, true) + }) + _.dots.appendChild(dot) + } } - } - - gliderPrototype.bindArrows = function () { - var _ = this - if (!_.opt.arrows) { - Object.keys(_.arrows).forEach(function (direction) { - var element = _.arrows[direction] - _.event(element, 'remove', { click: element._func }) + + gliderPrototype.bindArrows = function () { + var _ = this + if (!_.opt.arrows) { + Object.keys(_.arrows).forEach(function (direction) { + var element = _.arrows[direction] + _.event(element, 'remove', { click: element._func }) + }) + return + } + ['prev', 'next'].forEach(function (direction) { + var arrow = _.opt.arrows[direction] + if (arrow) { + if (typeof arrow === 'string') arrow = document.querySelector(arrow) + if (arrow) { + arrow._func = arrow._func || _.scrollItem.bind(_, direction) + _.event(arrow, 'remove', { + click: arrow._func + }) + _.event(arrow, 'add', { + click: arrow._func + }) + _.arrows[direction] = arrow + } + } }) - return } - ['prev', 'next'].forEach(function (direction) { - var arrow = _.opt.arrows[direction] - if (arrow) { - if (typeof arrow === 'string') arrow = document.querySelector(arrow) - if (arrow) { - arrow._func = arrow._func || _.scrollItem.bind(_, direction) - _.event(arrow, 'remove', { - click: arrow._func - }) - _.event(arrow, 'add', { - click: arrow._func - }) - _.arrows[direction] = arrow + + gliderPrototype.updateControls = function (event) { + var _ = this + + if (event && !_.opt.scrollPropagate) { + event.stopPropagation() + } + + var disableArrows = _.containerWidth >= _.trackWidth + + if (!_.opt.rewind) { + if (_.arrows.prev) { + _.arrows.prev.classList.toggle( + 'disabled', + _.ele.scrollLeft <= 0 || disableArrows + ) + + _.arrows.prev.setAttribute( + 'aria-disabled', + _.arrows.prev.classList.contains('disabled') + ) + } + if (_.arrows.next) { + _.arrows.next.classList.toggle( + 'disabled', + Math.ceil(_.ele.scrollLeft + _.containerWidth) >= + Math.floor(_.trackWidth) || disableArrows + ) + + _.arrows.next.setAttribute( + 'aria-disabled', + _.arrows.next.classList.contains('disabled') + ) } } - }) - } - - gliderPrototype.updateControls = function (event) { - var _ = this - - if (event && !_.opt.scrollPropagate) { - event.stopPropagation() - } - - var disableArrows = _.containerWidth >= _.trackWidth - - if (!_.opt.rewind) { - if (_.arrows.prev) { - _.arrows.prev.classList.toggle( - 'disabled', - _.ele.scrollLeft <= 0 || disableArrows - ) - - _.arrows.prev.setAttribute( - 'aria-disabled', - _.arrows.prev.classList.contains('disabled') - ) + + _.slide = Math.round(_.ele.scrollLeft / _.itemWidth) + _.page = Math.round(_.ele.scrollLeft / _.containerWidth) + + var middle = _.slide + Math.floor(Math.floor(_.opt.slidesToShow) / 2) + + var extraMiddle = Math.floor(_.opt.slidesToShow) % 2 ? 0 : middle + 1 + if (Math.floor(_.opt.slidesToShow) === 1) { + extraMiddle = 0 } - if (_.arrows.next) { - _.arrows.next.classList.toggle( - 'disabled', - Math.ceil(_.ele.scrollLeft + _.containerWidth) >= - Math.floor(_.trackWidth) || disableArrows - ) - - _.arrows.next.setAttribute( - 'aria-disabled', - _.arrows.next.classList.contains('disabled') - ) + + // the last page may be less than one half of a normal page width so + // the page is rounded down. when at the end, force the page to turn + if (_.ele.scrollLeft + _.containerWidth >= Math.floor(_.trackWidth)) { + _.page = _.dots ? _.dots.children.length - 1 : 0 } - } - - _.slide = Math.round(_.ele.scrollLeft / _.itemWidth) - _.page = Math.round(_.ele.scrollLeft / _.containerWidth) - - var middle = _.slide + Math.floor(Math.floor(_.opt.slidesToShow) / 2) - - var extraMiddle = Math.floor(_.opt.slidesToShow) % 2 ? 0 : middle + 1 - if (Math.floor(_.opt.slidesToShow) === 1) { - extraMiddle = 0 - } - - // the last page may be less than one half of a normal page width so - // the page is rounded down. when at the end, force the page to turn - if (_.ele.scrollLeft + _.containerWidth >= Math.floor(_.trackWidth)) { - _.page = _.dots ? _.dots.children.length - 1 : 0 - } - - [].forEach.call(_.slides, function (slide, index) { - var slideClasses = slide.classList - - var wasVisible = slideClasses.contains('visible') - - var start = _.ele.scrollLeft - - var end = _.ele.scrollLeft + _.containerWidth - - var itemStart = _.itemWidth * index - - var itemEnd = itemStart + _.itemWidth; - - [].forEach.call(slideClasses, function (className) { - /^left|right/.test(className) && slideClasses.remove(className) + + [].forEach.call(_.slides, function (slide, index) { + var slideClasses = slide.classList + + var wasVisible = slideClasses.contains('visible') + + var start = _.ele.scrollLeft + + var end = _.ele.scrollLeft + _.containerWidth + + var itemStart = _.itemWidth * index + + var itemEnd = itemStart + _.itemWidth; + + [].forEach.call(slideClasses, function (className) { + /^left|right/.test(className) && slideClasses.remove(className) + }) + slideClasses.toggle('active', _.slide === index) + if (middle === index || (extraMiddle && extraMiddle === index)) { + slideClasses.add('center') + } else { + slideClasses.remove('center') + slideClasses.add( + [ + index < middle ? 'left' : 'right', + Math.abs(index - (index < middle ? middle : extraMiddle || middle)) + ].join('-') + ) + } + + var isVisible = + Math.ceil(itemStart) >= Math.floor(start) && + Math.floor(itemEnd) <= Math.ceil(end) + slideClasses.toggle('visible', isVisible) + if ( + isVisible && + index === _.slide && + _.lastEmittedActiveSlide !== _.slide + ) { + _.emit('slide-active', { + slide: index + }) + _.lastEmittedActiveSlide = index + } + if (isVisible !== wasVisible) { + _.emit('slide-' + (isVisible ? 'visible' : 'hidden'), { + slide: index + }) + } }) - slideClasses.toggle('active', _.slide === index) - if (middle === index || (extraMiddle && extraMiddle === index)) { - slideClasses.add('center') - } else { - slideClasses.remove('center') - slideClasses.add( - [ - index < middle ? 'left' : 'right', - Math.abs(index - (index < middle ? middle : extraMiddle || middle)) - ].join('-') - ) - } - - var isVisible = - Math.ceil(itemStart) >= Math.floor(start) && - Math.floor(itemEnd) <= Math.ceil(end) - slideClasses.toggle('visible', isVisible) - if (isVisible !== wasVisible) { - _.emit('slide-' + (isVisible ? 'visible' : 'hidden'), { - slide: index + if (_.dots) { + [].forEach.call(_.dots.children, function (dot, index) { + dot.classList.toggle('active', _.page === index) }) } - }) - if (_.dots) { - [].forEach.call(_.dots.children, function (dot, index) { - dot.classList.toggle('active', _.page === index) - }) - } - - if (event && _.opt.scrollLock) { - clearTimeout(_.scrollLock) - _.scrollLock = setTimeout(function () { + + if (event && _.opt.scrollLock) { clearTimeout(_.scrollLock) - // dont attempt to scroll less than a pixel fraction - causes looping - if (Math.abs(_.ele.scrollLeft / _.itemWidth - _.slide) > 0.02) { - if (!_.mouseDown) { - // Only scroll if not at the end (#94) - if (_.trackWidth > _.containerWidth + _.ele.scrollLeft) { - _.scrollItem(_.getCurrentSlide()) + _.scrollLock = setTimeout(function () { + clearTimeout(_.scrollLock) + // dont attempt to scroll less than a pixel fraction - causes looping + if (Math.abs(_.ele.scrollLeft / _.itemWidth - _.slide) > 0.02) { + if (!_.mouseDown) { + // Only scroll if not at the end (#94) + if (_.trackWidth > _.containerWidth + _.ele.scrollLeft) { + _.scrollItem(_.getCurrentSlide()) + } } } - } - }, _.opt.scrollLockDelay || 250) + }, _.opt.scrollLockDelay || 250) + } } - } - - gliderPrototype.getCurrentSlide = function () { - var _ = this - return _.round(_.ele.scrollLeft / _.itemWidth) - } - - gliderPrototype.scrollItem = function (slide, dot, e) { - if (e) e.preventDefault() - - var _ = this - - var originalSlide = slide - ++_.animate_id - - var prevSlide = _.slide - var position - - if (dot === true) { - slide = Math.round((slide * _.containerWidth) / _.itemWidth) - position = slide * _.itemWidth - } else { - if (typeof slide === 'string') { - var backwards = slide === 'prev' - - // use precise location if fractional slides are on - if (_.opt.slidesToScroll % 1 || _.opt.slidesToShow % 1) { - slide = _.getCurrentSlide() - } else { - slide = _.slide - } - - if (backwards) slide -= _.opt.slidesToScroll - else slide += _.opt.slidesToScroll - - if (_.opt.rewind) { - var scrollLeft = _.ele.scrollLeft - slide = - backwards && !scrollLeft - ? _.slides.length - : !backwards && - scrollLeft + _.containerWidth >= Math.floor(_.trackWidth) - ? 0 - : slide + + gliderPrototype.getCurrentSlide = function () { + var _ = this + return _.round(_.ele.scrollLeft / _.itemWidth) + } + + gliderPrototype.scrollItem = function (slide, dot, e) { + if (e) e.preventDefault() + + var _ = this + + var originalSlide = slide + ++_.animate_id + + var prevSlide = _.slide + var position + + if (dot === true) { + slide = Math.round((slide * _.containerWidth) / _.itemWidth) + position = slide * _.itemWidth + } else { + if (typeof slide === 'string') { + var backwards = slide === 'prev' + + // use precise location if fractional slides are on + if (_.opt.slidesToScroll % 1 || _.opt.slidesToShow % 1) { + slide = _.getCurrentSlide() + } else { + slide = _.slide + } + + if (backwards) slide -= _.opt.slidesToScroll + else slide += _.opt.slidesToScroll + + if (_.opt.rewind) { + var scrollLeft = _.ele.scrollLeft + slide = + backwards && !scrollLeft + ? _.slides.length + : !backwards && + scrollLeft + _.containerWidth >= Math.floor(_.trackWidth) + ? 0 + : slide + } } + + slide = Math.max(Math.min(slide, _.slides.length), 0) + + _.slide = slide + position = _.itemWidth * slide } - - slide = Math.max(Math.min(slide, _.slides.length), 0) - - _.slide = slide - position = _.itemWidth * slide + + _.emit('scroll-item', { prevSlide, slide }) + + _.scrollTo( + position, + _.opt.duration * Math.abs(_.ele.scrollLeft - position), + function () { + _.updateControls() + _.emit('animated', { + value: originalSlide, + type: + typeof originalSlide === 'string' ? 'arrow' : dot ? 'dot' : 'slide' + }) + } + ) + + return false } - - _.emit('scroll-item', { prevSlide, slide }) - - _.scrollTo( - position, - _.opt.duration * Math.abs(_.ele.scrollLeft - position), - function () { - _.updateControls() - _.emit('animated', { - value: originalSlide, - type: - typeof originalSlide === 'string' ? 'arrow' : dot ? 'dot' : 'slide' + + gliderPrototype.settingsBreakpoint = function () { + var _ = this + + var resp = _._opt.responsive + + if (resp) { + // Sort the breakpoints in mobile first order + resp.sort(function (a, b) { + return b.breakpoint - a.breakpoint }) - } - ) - - return false - } - - gliderPrototype.settingsBreakpoint = function () { - var _ = this - - var resp = _._opt.responsive - - if (resp) { - // Sort the breakpoints in mobile first order - resp.sort(function (a, b) { - return b.breakpoint - a.breakpoint - }) - - for (var i = 0; i < resp.length; ++i) { - var size = resp[i] - if (_window.innerWidth >= size.breakpoint) { - if (_.breakpoint !== size.breakpoint) { - _.opt = Object.assign({}, _._opt, size.settings) - _.breakpoint = size.breakpoint - return true + + for (var i = 0; i < resp.length; ++i) { + var size = resp[i] + if (_window.innerWidth >= size.breakpoint) { + if (_.breakpoint !== size.breakpoint) { + _.opt = Object.assign({}, _._opt, size.settings) + _.breakpoint = size.breakpoint + return true + } + return false } - return false } } + // set back to defaults in case they were overriden + var breakpointChanged = _.breakpoint !== 0 + _.opt = Object.assign({}, _._opt) + _.breakpoint = 0 + return breakpointChanged } - // set back to defaults in case they were overriden - var breakpointChanged = _.breakpoint !== 0 - _.opt = Object.assign({}, _._opt) - _.breakpoint = 0 - return breakpointChanged - } - - gliderPrototype.scrollTo = function (scrollTarget, scrollDuration, callback) { - var _ = this - - var start = new Date().getTime() - - var animateIndex = _.animate_id - - var animate = function () { - var now = new Date().getTime() - start - _.ele.scrollLeft = - _.ele.scrollLeft + - (scrollTarget - _.ele.scrollLeft) * - _.opt.easing(0, now, 0, 1, scrollDuration) - if (now < scrollDuration && animateIndex === _.animate_id) { - _window.requestAnimationFrame(animate) - } else { - _.ele.scrollLeft = scrollTarget - callback && callback.call(_) + + gliderPrototype.scrollTo = function (scrollTarget, scrollDuration, callback) { + var _ = this + + var start = new Date().getTime() + + var animateIndex = _.animate_id + + var animate = function () { + var now = new Date().getTime() - start + _.ele.scrollLeft = + _.ele.scrollLeft + + (scrollTarget - _.ele.scrollLeft) * + _.opt.easing(0, now, 0, 1, scrollDuration) + if (now < scrollDuration && animateIndex === _.animate_id) { + _window.requestAnimationFrame(animate) + } else { + _.ele.scrollLeft = scrollTarget + callback && callback.call(_) + } } + + _window.requestAnimationFrame(animate) } - - _window.requestAnimationFrame(animate) - } - - gliderPrototype.removeItem = function (index) { - var _ = this - - if (_.slides.length) { - _.track.removeChild(_.slides[index]) + + gliderPrototype.removeItem = function (index) { + var _ = this + + if (_.slides.length) { + _.track.removeChild(_.slides[index]) + _.refresh(true) + _.emit('remove') + } + } + + gliderPrototype.addItem = function (ele) { + var _ = this + + _.track.appendChild(ele) _.refresh(true) - _.emit('remove') + _.emit('add') } - } - - gliderPrototype.addItem = function (ele) { - var _ = this - - _.track.appendChild(ele) - _.refresh(true) - _.emit('add') - } - - gliderPrototype.handleMouse = function (e) { - var _ = this - if (_.mouseDown) { - _.isDrag = true - _.ele.scrollLeft += - (_.mouseDown - e.clientX) * (_.opt.dragVelocity || 3.3) - _.mouseDown = e.clientX + + gliderPrototype.handleMouse = function (e) { + var _ = this + if (_.mouseDown) { + _.isDrag = true + _.ele.scrollLeft += + (_.mouseDown - e.clientX) * (_.opt.dragVelocity || 3.3) + _.mouseDown = e.clientX + } } - } - - // used to round to the nearest 0.XX fraction - gliderPrototype.round = function (double) { - var _ = this - var step = _.opt.slidesToScroll % 1 || 1 - var inv = 1.0 / step - return Math.round(double * inv) / inv - } - - gliderPrototype.refresh = function (paging) { - var _ = this - _.init(true, paging) - } - - gliderPrototype.setOption = function (opt, global) { - var _ = this - - if (_.breakpoint && !global) { - _._opt.responsive.forEach(function (v) { - if (v.breakpoint === _.breakpoint) { - v.settings = Object.assign({}, v.settings, opt) - } + + // used to round to the nearest 0.XX fraction + gliderPrototype.round = function (double) { + var _ = this + var step = _.opt.slidesToScroll % 1 || 1 + var inv = 1.0 / step + return Math.round(double * inv) / inv + } + + gliderPrototype.refresh = function (paging) { + var _ = this + _.init(true, paging) + } + + gliderPrototype.setOption = function (opt, global) { + var _ = this + + if (_.breakpoint && !global) { + _._opt.responsive.forEach(function (v) { + if (v.breakpoint === _.breakpoint) { + v.settings = Object.assign({}, v.settings, opt) + } + }) + } else { + _._opt = Object.assign({}, _._opt, opt) + } + + _.breakpoint = 0 + _.settingsBreakpoint() + } + + gliderPrototype.destroy = function () { + var _ = this + + var replace = _.ele.cloneNode(true) + + var clear = function (ele) { + ele.removeAttribute('style'); + [].forEach.call(ele.classList, function (className) { + /^glider/.test(className) && ele.classList.remove(className) + }) + } + // remove track if it was created by glider + if (!_.opt.skipTrack) { + replace.children[0].outerHTML = replace.children[0].innerHTML + } + clear(replace); + [].forEach.call(replace.getElementsByTagName('*'), clear) + _.ele.parentNode.replaceChild(replace, _.ele) + _.event(_window, 'remove', { + resize: _.resize }) - } else { - _._opt = Object.assign({}, _._opt, opt) + _.emit('destroy') } - - _.breakpoint = 0 - _.settingsBreakpoint() - } - - gliderPrototype.destroy = function () { - var _ = this - - var replace = _.ele.cloneNode(true) - - var clear = function (ele) { - ele.removeAttribute('style'); - [].forEach.call(ele.classList, function (className) { - /^glider/.test(className) && ele.classList.remove(className) + + gliderPrototype.emit = function (name, arg) { + var _ = this + + var e = new _window.CustomEvent('glider-' + name, { + bubbles: !_.opt.eventPropagate, + detail: arg }) + _.ele.dispatchEvent(e) } - // remove track if it was created by glider - if (!_.opt.skipTrack) { - replace.children[0].outerHTML = replace.children[0].innerHTML + + gliderPrototype.event = function (ele, type, args) { + var eventHandler = ele[type + 'EventListener'].bind(ele) + Object.keys(args).forEach(function (k) { + eventHandler(k, args[k]) + }) } - clear(replace); - [].forEach.call(replace.getElementsByTagName('*'), clear) - _.ele.parentNode.replaceChild(replace, _.ele) - _.event(_window, 'remove', { - resize: _.resize - }) - _.emit('destroy') - } - - gliderPrototype.emit = function (name, arg) { - var _ = this - - var e = new _window.CustomEvent('glider-' + name, { - bubbles: !_.opt.eventPropagate, - detail: arg - }) - _.ele.dispatchEvent(e) - } - - gliderPrototype.event = function (ele, type, args) { - var eventHandler = ele[type + 'EventListener'].bind(ele) - Object.keys(args).forEach(function (k) { - eventHandler(k, args[k]) - }) - } - - return Glider -}) + + return Glider + }) + \ No newline at end of file From 74eb9c7a2c1f862a377db599c8327107f18f672f Mon Sep 17 00:00:00 2001 From: Matheus Bernardes Date: Thu, 22 Aug 2024 18:07:13 -0300 Subject: [PATCH 2/3] Adds active-slide event to emit for each active slide --- glider.js | 1119 +++++++++++++++++++++++++++-------------------------- 1 file changed, 561 insertions(+), 558 deletions(-) diff --git a/glider.js b/glider.js index 0d7007e..26f8d07 100644 --- a/glider.js +++ b/glider.js @@ -17,608 +17,611 @@ /* global define */ (function (factory) { - typeof define === 'function' && define.amd - ? define(factory) - : typeof exports === 'object' - ? (module.exports = factory()) - : factory() - })(function () { - ('use strict') // eslint-disable-line no-unused-expressions - - /* globals window:true */ - var _window = typeof window !== 'undefined' ? window : this - - var Glider = (_window.Glider = function (element, settings) { - var _ = this - - if (element._glider) return element._glider - - _.ele = element - _.ele.classList.add('glider') - - // used to make the slide-active event emit only once per active slide - _.lastEmittedActiveSlide = null - - // expose glider object to its DOM element - _.ele._glider = _ - - // merge user setting with defaults - _.opt = Object.assign( - {}, - { - slidesToScroll: 1, - slidesToShow: 1, - resizeLock: true, - duration: 0.5, - passiveListeners: false, - // easeInQuad - easing: function (x, t, b, c, d) { - return c * (t /= d) * t + b - } - }, - settings - ) - - // set defaults - _.animate_id = _.page = _.slide = 0 - _.arrows = {} - - // preserve original options to - // extend breakpoint settings - _._opt = _.opt - - if (_.opt.skipTrack) { - // first and only child is the track - _.track = _.ele.children[0] - } else { - // create track and wrap slides - _.track = document.createElement('div') - _.ele.appendChild(_.track) - while (_.ele.children.length !== 1) { - _.track.appendChild(_.ele.children[0]) + typeof define === 'function' && define.amd + ? define(factory) + : typeof exports === 'object' + ? (module.exports = factory()) + : factory() +})(function () { + ('use strict') // eslint-disable-line no-unused-expressions + + /* globals window:true */ + var _window = typeof window !== 'undefined' ? window : this + + var Glider = (_window.Glider = function (element, settings) { + var _ = this + + if (element._glider) return element._glider + + _.ele = element + _.ele.classList.add('glider') + + // used to make the slide-active event emit only once per active slide + _.lastEmittedActiveSlide = null + + // expose glider object to its DOM element + _.ele._glider = _ + + // merge user setting with defaults + _.opt = Object.assign( + {}, + { + slidesToScroll: 1, + slidesToShow: 1, + resizeLock: true, + duration: 0.5, + passiveListeners: false, + // easeInQuad + easing: function (x, t, b, c, d) { + return c * (t /= d) * t + b } + }, + settings + ) + + // set defaults + _.animate_id = _.page = _.slide = 0 + _.arrows = {} + + // preserve original options to + // extend breakpoint settings + _._opt = _.opt + + if (_.opt.skipTrack) { + // first and only child is the track + _.track = _.ele.children[0] + } else { + // create track and wrap slides + _.track = document.createElement('div') + _.ele.appendChild(_.track) + while (_.ele.children.length !== 1) { + _.track.appendChild(_.ele.children[0]) } - - _.track.classList.add('glider-track') - - // start glider - _.init() - - // set events - _.resize = _.init.bind(_, true) - _.event( - _.ele, - 'add', - { - scroll: _.updateControls.bind(_) - }, - { passive: _.opt.passiveListeners } - ) - _.event(_window, 'add', { - resize: _.resize - }) + } + + _.track.classList.add('glider-track') + + // start glider + _.init() + + // set events + _.resize = _.init.bind(_, true) + _.event( + _.ele, + 'add', + { + scroll: _.updateControls.bind(_) + }, + { passive: _.opt.passiveListeners } + ) + _.event(_window, 'add', { + resize: _.resize }) - - var gliderPrototype = Glider.prototype - gliderPrototype.init = function (refresh, paging) { - var _ = this - - var width = 0 - - var height = 0 - - _.slides = _.track.children; - - [].forEach.call(_.slides, function (_, i) { - _.classList.add('glider-slide') - _.setAttribute('data-gslide', i) - }) - - _.containerWidth = _.ele.clientWidth - - var breakpointChanged = _.settingsBreakpoint() - if (!paging) paging = breakpointChanged - - if ( - _.opt.slidesToShow === 'auto' || - typeof _.opt._autoSlide !== 'undefined' - ) { - var slideCount = _.containerWidth / _.opt.itemWidth - - _.opt._autoSlide = _.opt.slidesToShow = _.opt.exactWidth - ? slideCount - : Math.max(1, Math.floor(slideCount)) - } - if (_.opt.slidesToScroll === 'auto') { - _.opt.slidesToScroll = Math.floor(_.opt.slidesToShow) + }) + + var gliderPrototype = Glider.prototype + gliderPrototype.init = function (refresh, paging) { + var _ = this + + var width = 0 + + var height = 0 + + _.slides = _.track.children; + + [].forEach.call(_.slides, function (_, i) { + _.classList.add('glider-slide') + _.setAttribute('data-gslide', i) + }) + + _.containerWidth = _.ele.clientWidth + + var breakpointChanged = _.settingsBreakpoint() + if (!paging) paging = breakpointChanged + + if ( + _.opt.slidesToShow === 'auto' || + typeof _.opt._autoSlide !== 'undefined' + ) { + var slideCount = _.containerWidth / _.opt.itemWidth + + _.opt._autoSlide = _.opt.slidesToShow = _.opt.exactWidth + ? slideCount + : Math.max(1, Math.floor(slideCount)) + } + if (_.opt.slidesToScroll === 'auto') { + _.opt.slidesToScroll = Math.floor(_.opt.slidesToShow) + } + + _.itemWidth = _.opt.exactWidth + ? _.opt.itemWidth + : _.containerWidth / _.opt.slidesToShow; + + // set slide dimensions + [].forEach.call(_.slides, function (__) { + __.style.height = 'auto' + __.style.width = _.itemWidth + 'px' + width += _.itemWidth + height = Math.max(__.offsetHeight, height) + }) + + _.track.style.width = width + 'px' + _.trackWidth = width + _.isDrag = false + _.preventClick = false + _.move = false + + _.opt.resizeLock && _.scrollTo(_.slide * _.itemWidth, 0) + + if (breakpointChanged || paging) { + _.bindArrows() + _.buildDots() + _.bindDrag() + } + + _.updateControls() + + _.emit(refresh ? 'refresh' : 'loaded') + } + + gliderPrototype.bindDrag = function () { + var _ = this + _.mouse = _.mouse || _.handleMouse.bind(_) + + var mouseup = function () { + _.mouseDown = undefined + _.ele.classList.remove('drag') + if (_.isDrag) { + _.preventClick = true } - - _.itemWidth = _.opt.exactWidth - ? _.opt.itemWidth - : _.containerWidth / _.opt.slidesToShow; - - // set slide dimensions - [].forEach.call(_.slides, function (__) { - __.style.height = 'auto' - __.style.width = _.itemWidth + 'px' - width += _.itemWidth - height = Math.max(__.offsetHeight, height) - }) - - _.track.style.width = width + 'px' - _.trackWidth = width _.isDrag = false - _.preventClick = false - _.move = false - - _.opt.resizeLock && _.scrollTo(_.slide * _.itemWidth, 0) - - if (breakpointChanged || paging) { - _.bindArrows() - _.buildDots() - _.bindDrag() - } - - _.updateControls() - - _.emit(refresh ? 'refresh' : 'loaded') } - - gliderPrototype.bindDrag = function () { - var _ = this - _.mouse = _.mouse || _.handleMouse.bind(_) - - var mouseup = function () { - _.mouseDown = undefined - _.ele.classList.remove('drag') - if (_.isDrag) { - _.preventClick = true - } - _.isDrag = false - } - - const move = function () { - _.move = true - } - - var events = { - mouseup: mouseup, - mouseleave: mouseup, - mousedown: function (e) { + + const move = function () { + _.move = true + } + + var events = { + mouseup: mouseup, + mouseleave: mouseup, + mousedown: function (e) { + e.preventDefault() + e.stopPropagation() + _.mouseDown = e.clientX + _.ele.classList.add('drag') + _.move = false + setTimeout(move, 300) + }, + touchstart: function (e) { + _.ele.classList.add('drag') + _.move = false + setTimeout(move, 300) + }, + mousemove: _.mouse, + click: function (e) { + if (_.preventClick && _.move) { e.preventDefault() e.stopPropagation() - _.mouseDown = e.clientX - _.ele.classList.add('drag') - _.move = false - setTimeout(move, 300) - }, - touchstart: function (e) { - _.ele.classList.add('drag') - _.move = false - setTimeout(move, 300) - }, - mousemove: _.mouse, - click: function (e) { - if (_.preventClick && _.move) { - e.preventDefault() - e.stopPropagation() - } - _.preventClick = false - _.move = false } - } - - _.ele.classList.toggle('draggable', _.opt.draggable === true) - _.event(_.ele, 'remove', events) - if (_.opt.draggable) { - _.event(_.ele, 'add', events, { - passive: _.opt.passiveListeners - }) + _.preventClick = false + _.move = false } } - - gliderPrototype.buildDots = function () { - var _ = this - - if (!_.opt.dots) { - if (_.dots) _.dots.innerHTML = '' - return - } - - if (typeof _.opt.dots === 'string') { - _.dots = document.querySelector(_.opt.dots) - } else _.dots = _.opt.dots - if (!_.dots) return - - _.dots.innerHTML = '' - _.dots.setAttribute('role', 'tablist') - _.dots.classList.add('glider-dots') - - for (var i = 0; i < Math.ceil(_.slides.length / _.opt.slidesToShow); ++i) { - var dot = document.createElement('button') - dot.dataset.index = i - dot.setAttribute('aria-label', 'Page ' + (i + 1)) - dot.setAttribute('role', 'tab') - dot.className = 'glider-dot ' + (i ? '' : 'active') - _.event(dot, 'add', { - click: _.scrollItem.bind(_, i, true) - }) - _.dots.appendChild(dot) - } + + _.ele.classList.toggle('draggable', _.opt.draggable === true) + _.event(_.ele, 'remove', events) + if (_.opt.draggable) { + _.event(_.ele, 'add', events, { + passive: _.opt.passiveListeners + }) } - - gliderPrototype.bindArrows = function () { - var _ = this - if (!_.opt.arrows) { - Object.keys(_.arrows).forEach(function (direction) { - var element = _.arrows[direction] - _.event(element, 'remove', { click: element._func }) - }) - return - } - ['prev', 'next'].forEach(function (direction) { - var arrow = _.opt.arrows[direction] - if (arrow) { - if (typeof arrow === 'string') arrow = document.querySelector(arrow) - if (arrow) { - arrow._func = arrow._func || _.scrollItem.bind(_, direction) - _.event(arrow, 'remove', { - click: arrow._func - }) - _.event(arrow, 'add', { - click: arrow._func - }) - _.arrows[direction] = arrow - } - } + } + + gliderPrototype.buildDots = function () { + var _ = this + + if (!_.opt.dots) { + if (_.dots) _.dots.innerHTML = '' + return + } + + if (typeof _.opt.dots === 'string') { + _.dots = document.querySelector(_.opt.dots) + } else _.dots = _.opt.dots + if (!_.dots) return + + _.dots.innerHTML = '' + _.dots.setAttribute('role', 'tablist') + _.dots.classList.add('glider-dots') + + for (var i = 0; i < Math.ceil(_.slides.length / _.opt.slidesToShow); ++i) { + var dot = document.createElement('button') + dot.dataset.index = i + dot.setAttribute('aria-label', 'Page ' + (i + 1)) + dot.setAttribute('role', 'tab') + dot.className = 'glider-dot ' + (i ? '' : 'active') + _.event(dot, 'add', { + click: _.scrollItem.bind(_, i, true) }) + _.dots.appendChild(dot) } - - gliderPrototype.updateControls = function (event) { - var _ = this - - if (event && !_.opt.scrollPropagate) { - event.stopPropagation() - } - - var disableArrows = _.containerWidth >= _.trackWidth - - if (!_.opt.rewind) { - if (_.arrows.prev) { - _.arrows.prev.classList.toggle( - 'disabled', - _.ele.scrollLeft <= 0 || disableArrows - ) - - _.arrows.prev.setAttribute( - 'aria-disabled', - _.arrows.prev.classList.contains('disabled') - ) - } - if (_.arrows.next) { - _.arrows.next.classList.toggle( - 'disabled', - Math.ceil(_.ele.scrollLeft + _.containerWidth) >= - Math.floor(_.trackWidth) || disableArrows - ) - - _.arrows.next.setAttribute( - 'aria-disabled', - _.arrows.next.classList.contains('disabled') - ) + } + + gliderPrototype.bindArrows = function () { + var _ = this + if (!_.opt.arrows) { + Object.keys(_.arrows).forEach(function (direction) { + var element = _.arrows[direction] + _.event(element, 'remove', { click: element._func }) + }) + return + } + ['prev', 'next'].forEach(function (direction) { + var arrow = _.opt.arrows[direction] + if (arrow) { + if (typeof arrow === 'string') arrow = document.querySelector(arrow) + if (arrow) { + arrow._func = arrow._func || _.scrollItem.bind(_, direction) + _.event(arrow, 'remove', { + click: arrow._func + }) + _.event(arrow, 'add', { + click: arrow._func + }) + _.arrows[direction] = arrow } } - - _.slide = Math.round(_.ele.scrollLeft / _.itemWidth) - _.page = Math.round(_.ele.scrollLeft / _.containerWidth) - - var middle = _.slide + Math.floor(Math.floor(_.opt.slidesToShow) / 2) - - var extraMiddle = Math.floor(_.opt.slidesToShow) % 2 ? 0 : middle + 1 - if (Math.floor(_.opt.slidesToShow) === 1) { - extraMiddle = 0 + }) + } + + gliderPrototype.updateControls = function (event) { + var _ = this + + if (event && !_.opt.scrollPropagate) { + event.stopPropagation() + } + + var disableArrows = _.containerWidth >= _.trackWidth + + if (!_.opt.rewind) { + if (_.arrows.prev) { + _.arrows.prev.classList.toggle( + 'disabled', + _.ele.scrollLeft <= 0 || disableArrows + ) + + _.arrows.prev.setAttribute( + 'aria-disabled', + _.arrows.prev.classList.contains('disabled') + ) } - - // the last page may be less than one half of a normal page width so - // the page is rounded down. when at the end, force the page to turn - if (_.ele.scrollLeft + _.containerWidth >= Math.floor(_.trackWidth)) { - _.page = _.dots ? _.dots.children.length - 1 : 0 + if (_.arrows.next) { + _.arrows.next.classList.toggle( + 'disabled', + Math.ceil(_.ele.scrollLeft + _.containerWidth) >= + Math.floor(_.trackWidth) || disableArrows + ) + + _.arrows.next.setAttribute( + 'aria-disabled', + _.arrows.next.classList.contains('disabled') + ) } - - [].forEach.call(_.slides, function (slide, index) { - var slideClasses = slide.classList - - var wasVisible = slideClasses.contains('visible') - - var start = _.ele.scrollLeft - - var end = _.ele.scrollLeft + _.containerWidth - - var itemStart = _.itemWidth * index - - var itemEnd = itemStart + _.itemWidth; - - [].forEach.call(slideClasses, function (className) { - /^left|right/.test(className) && slideClasses.remove(className) - }) - slideClasses.toggle('active', _.slide === index) - if (middle === index || (extraMiddle && extraMiddle === index)) { - slideClasses.add('center') - } else { - slideClasses.remove('center') - slideClasses.add( - [ - index < middle ? 'left' : 'right', - Math.abs(index - (index < middle ? middle : extraMiddle || middle)) - ].join('-') - ) - } - - var isVisible = - Math.ceil(itemStart) >= Math.floor(start) && - Math.floor(itemEnd) <= Math.ceil(end) - slideClasses.toggle('visible', isVisible) - if ( - isVisible && - index === _.slide && - _.lastEmittedActiveSlide !== _.slide - ) { + } + + _.slide = Math.round(_.ele.scrollLeft / _.itemWidth) + _.page = Math.round(_.ele.scrollLeft / _.containerWidth) + + var middle = _.slide + Math.floor(Math.floor(_.opt.slidesToShow) / 2) + + var extraMiddle = Math.floor(_.opt.slidesToShow) % 2 ? 0 : middle + 1 + if (Math.floor(_.opt.slidesToShow) === 1) { + extraMiddle = 0 + } + + // the last page may be less than one half of a normal page width so + // the page is rounded down. when at the end, force the page to turn + if (_.ele.scrollLeft + _.containerWidth >= Math.floor(_.trackWidth)) { + _.page = _.dots ? _.dots.children.length - 1 : 0 + } + + [].forEach.call(_.slides, function (slide, index) { + var slideClasses = slide.classList + + var wasVisible = slideClasses.contains('visible') + + var start = _.ele.scrollLeft + + var end = _.ele.scrollLeft + _.containerWidth + + var itemStart = _.itemWidth * index + + var itemEnd = itemStart + _.itemWidth; + + [].forEach.call(slideClasses, function (className) { + /^left|right/.test(className) && slideClasses.remove(className) + }) + slideClasses.toggle('active', _.slide === index) + + if (isVisible && index === _.slide && _.lastEmittedActiveSlide !== _.slide) { _.emit('slide-active', { - slide: index + slide: index }) _.lastEmittedActiveSlide = index - } - if (isVisible !== wasVisible) { - _.emit('slide-' + (isVisible ? 'visible' : 'hidden'), { + } + + if (middle === index || (extraMiddle && extraMiddle === index)) { + slideClasses.add('center') + } else { + slideClasses.remove('center') + slideClasses.add( + [ + index < middle ? 'left' : 'right', + Math.abs(index - (index < middle ? middle : extraMiddle || middle)) + ].join('-') + ) + } + + var isVisible = + Math.ceil(itemStart) >= Math.floor(start) && + Math.floor(itemEnd) <= Math.ceil(end) + slideClasses.toggle('visible', isVisible) + if (isVisible && index === _.slide && _.lastEmittedActiveSlide !== _.slide) { + _.emit('slide-active', { slide: index }) - } - }) - if (_.dots) { - [].forEach.call(_.dots.children, function (dot, index) { - dot.classList.toggle('active', _.page === index) + _.lastEmittedActiveSlide = index + } + if (isVisible !== wasVisible) { + _.emit('slide-' + (isVisible ? 'visible' : 'hidden'), { + slide: index }) } - - if (event && _.opt.scrollLock) { + }) + if (_.dots) { + [].forEach.call(_.dots.children, function (dot, index) { + dot.classList.toggle('active', _.page === index) + }) + } + + if (event && _.opt.scrollLock) { + clearTimeout(_.scrollLock) + _.scrollLock = setTimeout(function () { clearTimeout(_.scrollLock) - _.scrollLock = setTimeout(function () { - clearTimeout(_.scrollLock) - // dont attempt to scroll less than a pixel fraction - causes looping - if (Math.abs(_.ele.scrollLeft / _.itemWidth - _.slide) > 0.02) { - if (!_.mouseDown) { - // Only scroll if not at the end (#94) - if (_.trackWidth > _.containerWidth + _.ele.scrollLeft) { - _.scrollItem(_.getCurrentSlide()) - } + // dont attempt to scroll less than a pixel fraction - causes looping + if (Math.abs(_.ele.scrollLeft / _.itemWidth - _.slide) > 0.02) { + if (!_.mouseDown) { + // Only scroll if not at the end (#94) + if (_.trackWidth > _.containerWidth + _.ele.scrollLeft) { + _.scrollItem(_.getCurrentSlide()) } } - }, _.opt.scrollLockDelay || 250) - } - } - - gliderPrototype.getCurrentSlide = function () { - var _ = this - return _.round(_.ele.scrollLeft / _.itemWidth) + } + }, _.opt.scrollLockDelay || 250) } - - gliderPrototype.scrollItem = function (slide, dot, e) { - if (e) e.preventDefault() - - var _ = this - - var originalSlide = slide - ++_.animate_id - - var prevSlide = _.slide - var position - - if (dot === true) { - slide = Math.round((slide * _.containerWidth) / _.itemWidth) - position = slide * _.itemWidth - } else { - if (typeof slide === 'string') { - var backwards = slide === 'prev' - - // use precise location if fractional slides are on - if (_.opt.slidesToScroll % 1 || _.opt.slidesToShow % 1) { - slide = _.getCurrentSlide() - } else { - slide = _.slide - } - - if (backwards) slide -= _.opt.slidesToScroll - else slide += _.opt.slidesToScroll - - if (_.opt.rewind) { - var scrollLeft = _.ele.scrollLeft - slide = - backwards && !scrollLeft - ? _.slides.length - : !backwards && - scrollLeft + _.containerWidth >= Math.floor(_.trackWidth) - ? 0 - : slide - } + } + + gliderPrototype.getCurrentSlide = function () { + var _ = this + return _.round(_.ele.scrollLeft / _.itemWidth) + } + + gliderPrototype.scrollItem = function (slide, dot, e) { + if (e) e.preventDefault() + + var _ = this + + var originalSlide = slide + ++_.animate_id + + var prevSlide = _.slide + var position + + if (dot === true) { + slide = Math.round((slide * _.containerWidth) / _.itemWidth) + position = slide * _.itemWidth + } else { + if (typeof slide === 'string') { + var backwards = slide === 'prev' + + // use precise location if fractional slides are on + if (_.opt.slidesToScroll % 1 || _.opt.slidesToShow % 1) { + slide = _.getCurrentSlide() + } else { + slide = _.slide } - - slide = Math.max(Math.min(slide, _.slides.length), 0) - - _.slide = slide - position = _.itemWidth * slide - } - - _.emit('scroll-item', { prevSlide, slide }) - - _.scrollTo( - position, - _.opt.duration * Math.abs(_.ele.scrollLeft - position), - function () { - _.updateControls() - _.emit('animated', { - value: originalSlide, - type: - typeof originalSlide === 'string' ? 'arrow' : dot ? 'dot' : 'slide' - }) + + if (backwards) slide -= _.opt.slidesToScroll + else slide += _.opt.slidesToScroll + + if (_.opt.rewind) { + var scrollLeft = _.ele.scrollLeft + slide = + backwards && !scrollLeft + ? _.slides.length + : !backwards && + scrollLeft + _.containerWidth >= Math.floor(_.trackWidth) + ? 0 + : slide } - ) - - return false + } + + slide = Math.max(Math.min(slide, _.slides.length), 0) + + _.slide = slide + position = _.itemWidth * slide } - - gliderPrototype.settingsBreakpoint = function () { - var _ = this - - var resp = _._opt.responsive - - if (resp) { - // Sort the breakpoints in mobile first order - resp.sort(function (a, b) { - return b.breakpoint - a.breakpoint + + _.emit('scroll-item', { prevSlide, slide }) + + _.scrollTo( + position, + _.opt.duration * Math.abs(_.ele.scrollLeft - position), + function () { + _.updateControls() + _.emit('animated', { + value: originalSlide, + type: + typeof originalSlide === 'string' ? 'arrow' : dot ? 'dot' : 'slide' }) - - for (var i = 0; i < resp.length; ++i) { - var size = resp[i] - if (_window.innerWidth >= size.breakpoint) { - if (_.breakpoint !== size.breakpoint) { - _.opt = Object.assign({}, _._opt, size.settings) - _.breakpoint = size.breakpoint - return true - } - return false - } - } } - // set back to defaults in case they were overriden - var breakpointChanged = _.breakpoint !== 0 - _.opt = Object.assign({}, _._opt) - _.breakpoint = 0 - return breakpointChanged - } - - gliderPrototype.scrollTo = function (scrollTarget, scrollDuration, callback) { - var _ = this - - var start = new Date().getTime() - - var animateIndex = _.animate_id - - var animate = function () { - var now = new Date().getTime() - start - _.ele.scrollLeft = - _.ele.scrollLeft + - (scrollTarget - _.ele.scrollLeft) * - _.opt.easing(0, now, 0, 1, scrollDuration) - if (now < scrollDuration && animateIndex === _.animate_id) { - _window.requestAnimationFrame(animate) - } else { - _.ele.scrollLeft = scrollTarget - callback && callback.call(_) + ) + + return false + } + + gliderPrototype.settingsBreakpoint = function () { + var _ = this + + var resp = _._opt.responsive + + if (resp) { + // Sort the breakpoints in mobile first order + resp.sort(function (a, b) { + return b.breakpoint - a.breakpoint + }) + + for (var i = 0; i < resp.length; ++i) { + var size = resp[i] + if (_window.innerWidth >= size.breakpoint) { + if (_.breakpoint !== size.breakpoint) { + _.opt = Object.assign({}, _._opt, size.settings) + _.breakpoint = size.breakpoint + return true + } + return false } } - - _window.requestAnimationFrame(animate) } - - gliderPrototype.removeItem = function (index) { - var _ = this - - if (_.slides.length) { - _.track.removeChild(_.slides[index]) - _.refresh(true) - _.emit('remove') + // set back to defaults in case they were overriden + var breakpointChanged = _.breakpoint !== 0 + _.opt = Object.assign({}, _._opt) + _.breakpoint = 0 + return breakpointChanged + } + + gliderPrototype.scrollTo = function (scrollTarget, scrollDuration, callback) { + var _ = this + + var start = new Date().getTime() + + var animateIndex = _.animate_id + + var animate = function () { + var now = new Date().getTime() - start + _.ele.scrollLeft = + _.ele.scrollLeft + + (scrollTarget - _.ele.scrollLeft) * + _.opt.easing(0, now, 0, 1, scrollDuration) + if (now < scrollDuration && animateIndex === _.animate_id) { + _window.requestAnimationFrame(animate) + } else { + _.ele.scrollLeft = scrollTarget + callback && callback.call(_) } } - - gliderPrototype.addItem = function (ele) { - var _ = this - - _.track.appendChild(ele) + + _window.requestAnimationFrame(animate) + } + + gliderPrototype.removeItem = function (index) { + var _ = this + + if (_.slides.length) { + _.track.removeChild(_.slides[index]) _.refresh(true) - _.emit('add') - } - - gliderPrototype.handleMouse = function (e) { - var _ = this - if (_.mouseDown) { - _.isDrag = true - _.ele.scrollLeft += - (_.mouseDown - e.clientX) * (_.opt.dragVelocity || 3.3) - _.mouseDown = e.clientX - } + _.emit('remove') } - - // used to round to the nearest 0.XX fraction - gliderPrototype.round = function (double) { - var _ = this - var step = _.opt.slidesToScroll % 1 || 1 - var inv = 1.0 / step - return Math.round(double * inv) / inv - } - - gliderPrototype.refresh = function (paging) { - var _ = this - _.init(true, paging) - } - - gliderPrototype.setOption = function (opt, global) { - var _ = this - - if (_.breakpoint && !global) { - _._opt.responsive.forEach(function (v) { - if (v.breakpoint === _.breakpoint) { - v.settings = Object.assign({}, v.settings, opt) - } - }) - } else { - _._opt = Object.assign({}, _._opt, opt) - } - - _.breakpoint = 0 - _.settingsBreakpoint() + } + + gliderPrototype.addItem = function (ele) { + var _ = this + + _.track.appendChild(ele) + _.refresh(true) + _.emit('add') + } + + gliderPrototype.handleMouse = function (e) { + var _ = this + if (_.mouseDown) { + _.isDrag = true + _.ele.scrollLeft += + (_.mouseDown - e.clientX) * (_.opt.dragVelocity || 3.3) + _.mouseDown = e.clientX } - - gliderPrototype.destroy = function () { - var _ = this - - var replace = _.ele.cloneNode(true) - - var clear = function (ele) { - ele.removeAttribute('style'); - [].forEach.call(ele.classList, function (className) { - /^glider/.test(className) && ele.classList.remove(className) - }) - } - // remove track if it was created by glider - if (!_.opt.skipTrack) { - replace.children[0].outerHTML = replace.children[0].innerHTML - } - clear(replace); - [].forEach.call(replace.getElementsByTagName('*'), clear) - _.ele.parentNode.replaceChild(replace, _.ele) - _.event(_window, 'remove', { - resize: _.resize + } + + // used to round to the nearest 0.XX fraction + gliderPrototype.round = function (double) { + var _ = this + var step = _.opt.slidesToScroll % 1 || 1 + var inv = 1.0 / step + return Math.round(double * inv) / inv + } + + gliderPrototype.refresh = function (paging) { + var _ = this + _.init(true, paging) + } + + gliderPrototype.setOption = function (opt, global) { + var _ = this + + if (_.breakpoint && !global) { + _._opt.responsive.forEach(function (v) { + if (v.breakpoint === _.breakpoint) { + v.settings = Object.assign({}, v.settings, opt) + } }) - _.emit('destroy') + } else { + _._opt = Object.assign({}, _._opt, opt) } - - gliderPrototype.emit = function (name, arg) { - var _ = this - - var e = new _window.CustomEvent('glider-' + name, { - bubbles: !_.opt.eventPropagate, - detail: arg + + _.breakpoint = 0 + _.settingsBreakpoint() + } + + gliderPrototype.destroy = function () { + var _ = this + + var replace = _.ele.cloneNode(true) + + var clear = function (ele) { + ele.removeAttribute('style'); + [].forEach.call(ele.classList, function (className) { + /^glider/.test(className) && ele.classList.remove(className) }) - _.ele.dispatchEvent(e) } - - gliderPrototype.event = function (ele, type, args) { - var eventHandler = ele[type + 'EventListener'].bind(ele) - Object.keys(args).forEach(function (k) { - eventHandler(k, args[k]) - }) + // remove track if it was created by glider + if (!_.opt.skipTrack) { + replace.children[0].outerHTML = replace.children[0].innerHTML } - - return Glider - }) - \ No newline at end of file + clear(replace); + [].forEach.call(replace.getElementsByTagName('*'), clear) + _.ele.parentNode.replaceChild(replace, _.ele) + _.event(_window, 'remove', { + resize: _.resize + }) + _.emit('destroy') + } + + gliderPrototype.emit = function (name, arg) { + var _ = this + + var e = new _window.CustomEvent('glider-' + name, { + bubbles: !_.opt.eventPropagate, + detail: arg + }) + _.ele.dispatchEvent(e) + } + + gliderPrototype.event = function (ele, type, args) { + var eventHandler = ele[type + 'EventListener'].bind(ele) + Object.keys(args).forEach(function (k) { + eventHandler(k, args[k]) + }) + } + + return Glider +}) From dfee57b71d13a977bea5464e8211dbb4227acf90 Mon Sep 17 00:00:00 2001 From: Matheus Bernardes Date: Thu, 22 Aug 2024 18:18:23 -0300 Subject: [PATCH 3/3] Removes duplicated code --- glider.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/glider.js b/glider.js index 26f8d07..a126e67 100644 --- a/glider.js +++ b/glider.js @@ -343,13 +343,6 @@ }) slideClasses.toggle('active', _.slide === index) - if (isVisible && index === _.slide && _.lastEmittedActiveSlide !== _.slide) { - _.emit('slide-active', { - slide: index - }) - _.lastEmittedActiveSlide = index - } - if (middle === index || (extraMiddle && extraMiddle === index)) { slideClasses.add('center') } else { @@ -366,12 +359,14 @@ Math.ceil(itemStart) >= Math.floor(start) && Math.floor(itemEnd) <= Math.ceil(end) slideClasses.toggle('visible', isVisible) + if (isVisible && index === _.slide && _.lastEmittedActiveSlide !== _.slide) { _.emit('slide-active', { slide: index }) _.lastEmittedActiveSlide = index } + if (isVisible !== wasVisible) { _.emit('slide-' + (isVisible ? 'visible' : 'hidden'), { slide: index