From 405aab855313ff37d3741a96d42d76ce2e2ddef6 Mon Sep 17 00:00:00 2001 From: David DeSandro Date: Fri, 16 Mar 2018 11:49:51 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=B7=20build=20v2.1.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🔔 Added `lazyLoad` support for images with `srcset` 🔔 Added `draggable: '>1'` option setting (now default) to disable dragging if only one slide 🔔 Enabled `staticClick` event when not draggable 🔔 Added `change` event. Triggered when selected slide is changed 🔔 Added `ready` event . Added `on` option to capture initial events. 🔔 Added support for `hash` option. --- README.md | 2 +- css/flickity.css | 2 +- dist/flickity.css | 64 ++++---- dist/flickity.min.css | 6 +- dist/flickity.pkgd.js | 315 ++++++++++++++++++++++++-------------- dist/flickity.pkgd.min.js | 10 +- js/index.js | 4 +- package.json | 4 +- 8 files changed, 249 insertions(+), 158 deletions(-) diff --git a/README.md b/README.md index a5c67062..76de7cac 100644 --- a/README.md +++ b/README.md @@ -147,4 +147,4 @@ var flky = new Flickity( '.gallery', { --- -By [Metafizzy](https://metafizzy.co) +By [Metafizzy 🌈🐻](https://metafizzy.co) diff --git a/css/flickity.css b/css/flickity.css index e2b8eac4..e6687bc0 100644 --- a/css/flickity.css +++ b/css/flickity.css @@ -1,4 +1,4 @@ -/*! Flickity v2.0.11 +/*! Flickity v2.1.0 https://flickity.metafizzy.co ---------------------------------------------- */ diff --git a/dist/flickity.css b/dist/flickity.css index 27c0e4f8..e6687bc0 100644 --- a/dist/flickity.css +++ b/dist/flickity.css @@ -1,5 +1,5 @@ -/*! Flickity v2.0.11 -http://flickity.metafizzy.co +/*! Flickity v2.1.0 +https://flickity.metafizzy.co ---------------------------------------------- */ .flickity-enabled { @@ -42,34 +42,53 @@ http://flickity.metafizzy.co cursor: grabbing; } -/* ---- previous/next buttons ---- */ +/* ---- flickity-button ---- */ -.flickity-prev-next-button { +.flickity-button { position: absolute; - top: 50%; - width: 44px; - height: 44px; - border: none; - border-radius: 50%; background: white; background: hsla(0, 0%, 100%, 0.75); - cursor: pointer; - /* vertically center */ - -webkit-transform: translateY(-50%); - transform: translateY(-50%); + border: none; + color: #333; } -.flickity-prev-next-button:hover { background: white; } +.flickity-button:hover { + background: white; + cursor: pointer; +} -.flickity-prev-next-button:focus { +.flickity-button:focus { outline: none; - box-shadow: 0 0 0 5px #09F; + box-shadow: 0 0 0 5px #19F; } -.flickity-prev-next-button:active { +.flickity-button:active { opacity: 0.6; } +.flickity-button:disabled { + opacity: 0.3; + cursor: auto; + /* prevent disabled button from capturing pointer up event. #716 */ + pointer-events: none; +} + +.flickity-button-icon { + fill: #333; +} + +/* ---- previous/next buttons ---- */ + +.flickity-prev-next-button { + top: 50%; + width: 44px; + height: 44px; + border-radius: 50%; + /* vertically center */ + -webkit-transform: translateY(-50%); + transform: translateY(-50%); +} + .flickity-prev-next-button.previous { left: 10px; } .flickity-prev-next-button.next { right: 10px; } /* right to left */ @@ -82,12 +101,7 @@ http://flickity.metafizzy.co left: 10px; } -.flickity-prev-next-button:disabled { - opacity: 0.3; - cursor: auto; -} - -.flickity-prev-next-button svg { +.flickity-prev-next-button .flickity-button-icon { position: absolute; left: 20%; top: 20%; @@ -95,10 +109,6 @@ http://flickity.metafizzy.co height: 60%; } -.flickity-prev-next-button .arrow { - fill: #333; -} - /* ---- page dots ---- */ .flickity-page-dots { diff --git a/dist/flickity.min.css b/dist/flickity.min.css index 33c3c94a..2c9f687d 100644 --- a/dist/flickity.min.css +++ b/dist/flickity.min.css @@ -1,4 +1,4 @@ -/*! Flickity v2.0.11 -http://flickity.metafizzy.co +/*! Flickity v2.1.0 +https://flickity.metafizzy.co ---------------------------------------------- */ -.flickity-enabled{position:relative}.flickity-enabled:focus{outline:0}.flickity-viewport{overflow:hidden;position:relative;height:100%}.flickity-slider{position:absolute;width:100%;height:100%}.flickity-enabled.is-draggable{-webkit-tap-highlight-color:transparent;tap-highlight-color:transparent;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.flickity-enabled.is-draggable .flickity-viewport{cursor:move;cursor:-webkit-grab;cursor:grab}.flickity-enabled.is-draggable .flickity-viewport.is-pointer-down{cursor:-webkit-grabbing;cursor:grabbing}.flickity-prev-next-button{position:absolute;top:50%;width:44px;height:44px;border:none;border-radius:50%;background:#fff;background:hsla(0,0%,100%,.75);cursor:pointer;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.flickity-prev-next-button:hover{background:#fff}.flickity-prev-next-button:focus{outline:0;box-shadow:0 0 0 5px #09f}.flickity-prev-next-button:active{opacity:.6}.flickity-prev-next-button.previous{left:10px}.flickity-prev-next-button.next{right:10px}.flickity-rtl .flickity-prev-next-button.previous{left:auto;right:10px}.flickity-rtl .flickity-prev-next-button.next{right:auto;left:10px}.flickity-prev-next-button:disabled{opacity:.3;cursor:auto}.flickity-prev-next-button svg{position:absolute;left:20%;top:20%;width:60%;height:60%}.flickity-prev-next-button .arrow{fill:#333}.flickity-page-dots{position:absolute;width:100%;bottom:-25px;padding:0;margin:0;list-style:none;text-align:center;line-height:1}.flickity-rtl .flickity-page-dots{direction:rtl}.flickity-page-dots .dot{display:inline-block;width:10px;height:10px;margin:0 8px;background:#333;border-radius:50%;opacity:.25;cursor:pointer}.flickity-page-dots .dot.is-selected{opacity:1} \ No newline at end of file +.flickity-enabled{position:relative}.flickity-enabled:focus{outline:0}.flickity-viewport{overflow:hidden;position:relative;height:100%}.flickity-slider{position:absolute;width:100%;height:100%}.flickity-enabled.is-draggable{-webkit-tap-highlight-color:transparent;tap-highlight-color:transparent;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.flickity-enabled.is-draggable .flickity-viewport{cursor:move;cursor:-webkit-grab;cursor:grab}.flickity-enabled.is-draggable .flickity-viewport.is-pointer-down{cursor:-webkit-grabbing;cursor:grabbing}.flickity-button{position:absolute;background:#fff;background:hsla(0,0%,100%,.75);border:none;color:#333}.flickity-button:hover{background:#fff;cursor:pointer}.flickity-button:focus{outline:0;box-shadow:0 0 0 5px #19f}.flickity-button:active{opacity:.6}.flickity-button:disabled{opacity:.3;cursor:auto;pointer-events:none}.flickity-button-icon{fill:#333}.flickity-prev-next-button{top:50%;width:44px;height:44px;border-radius:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.flickity-prev-next-button.previous{left:10px}.flickity-prev-next-button.next{right:10px}.flickity-rtl .flickity-prev-next-button.previous{left:auto;right:10px}.flickity-rtl .flickity-prev-next-button.next{right:auto;left:10px}.flickity-prev-next-button .flickity-button-icon{position:absolute;left:20%;top:20%;width:60%;height:60%}.flickity-page-dots{position:absolute;width:100%;bottom:-25px;padding:0;margin:0;list-style:none;text-align:center;line-height:1}.flickity-rtl .flickity-page-dots{direction:rtl}.flickity-page-dots .dot{display:inline-block;width:10px;height:10px;margin:0 8px;background:#333;border-radius:50%;opacity:.25;cursor:pointer}.flickity-page-dots .dot.is-selected{opacity:1} \ No newline at end of file diff --git a/dist/flickity.pkgd.js b/dist/flickity.pkgd.js index faf7a521..1533405f 100644 --- a/dist/flickity.pkgd.js +++ b/dist/flickity.pkgd.js @@ -1,12 +1,12 @@ /*! - * Flickity PACKAGED v2.0.11 + * Flickity PACKAGED v2.1.0 * Touch, responsive, flickable carousels * * Licensed GPLv3 for open source use * or Flickity Commercial License for commercial use * - * http://flickity.metafizzy.co - * Copyright 2017 Metafizzy + * https://flickity.metafizzy.co + * Copyright 2015-2018 Metafizzy */ /** @@ -1065,6 +1065,7 @@ proto.positionSliderAtSelected = function() { return; } this.x = -this.selectedSlide.target; + this.velocity = 0; // stop wobble this.positionSlider(); }; @@ -1089,7 +1090,7 @@ proto.settle = function( previousX ) { delete this.isFreeScrolling; // render position with translateX when settled this.positionSlider(); - this.dispatchEvent('settle'); + this.dispatchEvent( 'settle', null, [ this.selectedIndex ] ); } }; @@ -1141,7 +1142,7 @@ proto.getRestingPosition = function() { }; proto.applyDragForce = function() { - if ( !this.isPointerDown ) { + if ( !this.isDraggable || !this.isPointerDown ) { return; } // change the position to drag position by applying force @@ -1151,8 +1152,9 @@ proto.applyDragForce = function() { }; proto.applySelectedAttraction = function() { - // do not attract if pointer down or no cells - if ( this.isPointerDown || this.isFreeScrolling || !this.cells.length ) { + // do not attract if pointer down or no slides + var dragDown = this.isDraggable && this.isPointerDown; + if ( dragDown || this.isFreeScrolling || !this.slides.length ) { return; } var distance = this.selectedSlide.target * -1 - this.x; @@ -1305,6 +1307,12 @@ proto._create = function() { window.addEventListener( 'resize', this ); } + // add listeners from on option + for ( var eventName in this.options.on ) { + var listener = this.options.on[ eventName ]; + this.on( eventName, listener ); + } + Flickity.createMethods.forEach( function( method ) { this[ method ](); }, this ); @@ -1366,6 +1374,8 @@ proto.activate = function() { this.select( index, false, true ); // flag for initial activation, for using initialIndex this.isInitActivated = true; + // ready event. #493 + this.dispatchEvent('ready'); }; // slider positions the cells @@ -1682,6 +1692,7 @@ proto.select = function( index, isWrap, isInstant ) { if ( !this.slides[ index ] ) { return; } + var prevIndex = this.selectedIndex; this.selectedIndex = index; this.updateSelectedSlide(); if ( isInstant ) { @@ -1692,8 +1703,12 @@ proto.select = function( index, isWrap, isInstant ) { if ( this.options.adaptiveHeight ) { this.setGallerySize(); } - - this.dispatchEvent('select'); + // events + this.dispatchEvent( 'select', null, [ index ] ); + // change event if new index + if ( index != prevIndex ) { + this.dispatchEvent( 'change', null, [ index ] ); + } // old v1 event name, remove in v3 this.dispatchEvent('cellSelect'); }; @@ -1762,24 +1777,22 @@ proto.unselectSelectedSlide = function() { */ proto.selectCell = function( value, isWrap, isInstant ) { // get cell - var cell; - if ( typeof value == 'number' ) { - cell = this.cells[ value ]; - } else { - // use string as selector - if ( typeof value == 'string' ) { - value = this.element.querySelector( value ); - } - // get cell from element - cell = this.getCell( value ); + var cell = this.queryCell( value ); + if ( !cell ) { + return; } - // select slide that has cell - for ( var i=0; cell && i < this.slides.length; i++ ) { + + var index = this.getCellSlideIndex( cell ); + this.select( index, isWrap, isInstant ); +}; + +proto.getCellSlideIndex = function( cell ) { + // get index of slides that has cell + for ( var i=0; i < this.slides.length; i++ ) { var slide = this.slides[i]; var index = slide.cells.indexOf( cell ); if ( index != -1 ) { - this.select( i, isWrap, isInstant ); - return; + return i; } } }; @@ -1872,6 +1885,23 @@ proto.getAdjacentCellElements = function( adjCount, index ) { return cellElems; }; +/** + * select slide from number or cell element + * @param {Element, Selector String, or Number} selector + */ +proto.queryCell = function( selector ) { + if ( typeof selector == 'number' ) { + // use number as index + return this.cells[ selector ]; + } + if ( typeof selector == 'string' ) { + // use string as selector, get element + selector = this.element.querySelector( selector ); + } + // get cell from element + return this.getCell( selector ); +}; + // -------------------------- events -------------------------- // proto.uiChange = function() { @@ -1931,21 +1961,40 @@ proto.watchCSS = function() { // go previous/next if left/right keys pressed proto.onkeydown = function( event ) { // only work if element is in focus - if ( !this.options.accessibility || - ( document.activeElement && document.activeElement != this.element ) ) { + var isNotFocused = document.activeElement && document.activeElement != this.element; + if ( !this.options.accessibility ||isNotFocused ) { return; } - if ( event.keyCode == 37 ) { - // go left + var handler = Flickity.keyboardHandlers[ event.keyCode ]; + if ( handler ) { + handler.call( this ); + } +}; + +Flickity.keyboardHandlers = { + // left arrow + 37: function() { var leftMethod = this.options.rightToLeft ? 'next' : 'previous'; this.uiChange(); this[ leftMethod ](); - } else if ( event.keyCode == 39 ) { - // go right + }, + // right arrow + 39: function() { var rightMethod = this.options.rightToLeft ? 'previous' : 'next'; this.uiChange(); this[ rightMethod ](); + }, +}; + +// ----- focus ----- // + +proto.focus = function() { + var prevScrollY = window.pageYOffset; + this.element.focus(); + // hack to fix scroll jump after focus, #76 + if ( window.pageYOffset != prevScrollY ) { + window.scrollTo( window.pageXOffset, prevScrollY ); } }; @@ -1958,11 +2007,11 @@ proto.deactivate = function() { } this.element.classList.remove('flickity-enabled'); this.element.classList.remove('flickity-rtl'); + this.unselectSelectedSlide(); // destroy cells this.cells.forEach( function( cell ) { cell.destroy(); }); - this.unselectSelectedSlide(); this.element.removeChild( this.viewport ); // move child elements back into element moveElements( this.slider.children, this.element ); @@ -2627,7 +2676,7 @@ return Unidragger; // ----- defaults ----- // utils.extend( Flickity.defaults, { - draggable: true, + draggable: '>1', dragThreshold: 3, }); @@ -2647,10 +2696,12 @@ var isTouch = 'createTouch' in document; var isTouchmoveScrollCanceled = false; proto._createDrag = function() { - this.on( 'activate', this.bindDrag ); + this.on( 'activate', this.onActivateDrag ); this.on( 'uiChange', this._uiChangeDrag ); this.on( 'childUIPointerDown', this._childUIPointerDownDrag ); this.on( 'deactivate', this.unbindDrag ); + this.on( 'cellChange', this.updateDraggable ); + // TODO updateDraggable on resize? if groupCells & slides change // HACK - add seemingly innocuous handler to fix iOS 10 scroll behavior // #457, RubaXa/Sortable#973 if ( isTouch && !isTouchmoveScrollCanceled ) { @@ -2659,23 +2710,40 @@ proto._createDrag = function() { } }; -proto.bindDrag = function() { - if ( !this.options.draggable || this.isDragBound ) { - return; - } - this.element.classList.add('is-draggable'); +proto.onActivateDrag = function() { this.handles = [ this.viewport ]; this.bindHandles(); - this.isDragBound = true; + this.updateDraggable(); }; -proto.unbindDrag = function() { - if ( !this.isDragBound ) { - return; - } - this.element.classList.remove('is-draggable'); +proto.onDeactivateDrag = function() { this.unbindHandles(); - delete this.isDragBound; + this.element.classList.remove('is-draggable'); +}; + +proto.updateDraggable = function() { + // disable dragging if less than 2 slides. #278 + if ( this.options.draggable == '>1' ) { + this.isDraggable = this.slides.length > 1; + } else { + this.isDraggable = this.options.draggable; + } + if ( this.isDraggable ) { + this.element.classList.add('is-draggable'); + } else { + this.element.classList.remove('is-draggable'); + } +}; + +// backwards compatibility +proto.bindDrag = function() { + this.options.draggable = true; + this.updateDraggable(); +}; + +proto.unbindDrag = function() { + this.options.draggable = false; + this.updateDraggable(); }; proto._uiChangeDrag = function() { @@ -2683,6 +2751,9 @@ proto._uiChangeDrag = function() { }; proto._childUIPointerDownDrag = function( event ) { + if ( !this.isDraggable ) { + return; + } event.preventDefault(); this.pointerDownFocus( event ); }; @@ -2707,6 +2778,10 @@ var clickTypes = { }; proto.pointerDown = function( event, pointer ) { + if ( !this.isDraggable ) { + this._pointerDownDefault( event, pointer ); + return; + } // dismiss inputs with text fields. #403, #404 var isCursorInput = cursorNodes[ event.target.nodeName ] && !clickTypes[ event.target.type ]; @@ -2717,39 +2792,37 @@ proto.pointerDown = function( event, pointer ) { return; } - this._dragPointerDown( event, pointer ); - // kludge to blur focused inputs in dragger var focused = document.activeElement; - if ( focused && focused.blur && focused != this.element && + var canBlur = focused && focused.blur && focused != this.element && // do not blur body for IE9 & 10, #117 - focused != document.body ) { + focused != document.body; + if ( canBlur ) { focused.blur(); } this.pointerDownFocus( event ); // stop if it was moving this.dragX = this.x; this.viewport.classList.add('is-pointer-down'); - // bind move and end events - this._bindPostStartEvents( event ); // track scrolling this.pointerDownScroll = getScrollPosition(); window.addEventListener( 'scroll', this ); + this._pointerDownDefault( event, pointer ); +}; + +proto._pointerDownDefault = function( event, pointer ) { + this._dragPointerDown( event, pointer ); + // bind move and end events + this._bindPostStartEvents( event ); this.dispatchEvent( 'pointerDown', event, [ pointer ] ); }; proto.pointerDownFocus = function( event ) { // focus element, if not touch, and its not an input or select var canPointerDown = getCanPointerDown( event ); - if ( !this.options.accessibility || canPointerDown ) { - return; - } - var prevScrollY = window.pageYOffset; - this.element.focus(); - // hack to fix scroll jump after focus, #76 - if ( window.pageYOffset != prevScrollY ) { - window.scrollTo( window.pageXOffset, prevScrollY ); + if ( !canPointerDown ) { + this.focus(); } }; @@ -2768,7 +2841,7 @@ function getCanPointerDown( event ) { proto.canPreventDefaultOnPointerDown = function( event ) { // prevent default, unless touchstart or input var canPointerDown = getCanPointerDown( event ); - return !canPointerDown; + return this.isDraggable && !canPointerDown; }; // ----- move ----- // @@ -2794,6 +2867,9 @@ proto.pointerDone = function() { // -------------------------- dragging -------------------------- // proto.dragStart = function( event, pointer ) { + if ( !this.isDraggable ) { + return; + } this.dragStartPosition = this.x; this.startAnimation(); window.removeEventListener( 'scroll', this ); @@ -2807,11 +2883,18 @@ proto.pointerMove = function( event, pointer ) { }; proto.dragMove = function( event, pointer, moveVector ) { + if ( !this.isDraggable ) { + return; + } event.preventDefault(); this.previousDragX = this.dragX; // reverse if right-to-left var direction = this.options.rightToLeft ? -1 : 1; + if ( this.options.wrapAround ) { + // wrap around move. #589 + moveVector.x = moveVector.x % this.slideableWidth; + } var dragX = this.dragStartPosition + moveVector.x * direction; if ( !this.options.wrapAround && this.slides.length ) { @@ -2829,6 +2912,9 @@ proto.dragMove = function( event, pointer, moveVector ) { }; proto.dragEnd = function( event, pointer ) { + if ( !this.isDraggable ) { + return; + } if ( this.options.freeScroll ) { this.isFreeScrolling = true; } @@ -3134,7 +3220,7 @@ function PrevNextButton( direction, parent ) { this._create(); } -PrevNextButton.prototype = new TapListener(); +PrevNextButton.prototype = Object.create( TapListener.prototype ); PrevNextButton.prototype._create = function() { // properties @@ -3144,14 +3230,14 @@ PrevNextButton.prototype._create = function() { this.isLeft = this.direction == leftDirection; var element = this.element = document.createElement('button'); - element.className = 'flickity-prev-next-button'; + element.className = 'flickity-button flickity-prev-next-button'; element.className += this.isPrevious ? ' previous' : ' next'; // prevent button from submitting form http://stackoverflow.com/a/10836076/182183 element.setAttribute( 'type', 'button' ); // init as disabled this.disable(); - element.setAttribute( 'aria-label', this.isPrevious ? 'previous' : 'next' ); + element.setAttribute( 'aria-label', this.isPrevious ? 'Previous' : 'Next' ); // create arrow var svg = this.createSVG(); @@ -3181,6 +3267,7 @@ PrevNextButton.prototype.deactivate = function() { PrevNextButton.prototype.createSVG = function() { var svg = document.createElementNS( svgURI, 'svg'); + svg.setAttribute( 'class', 'flickity-button-icon' ); svg.setAttribute( 'viewBox', '0 0 100 100' ); var path = document.createElementNS( svgURI, 'path'); var pathMovements = getArrowMovements( this.parent.options.arrowShape ); @@ -3792,9 +3879,7 @@ proto.insert = function( elems, index ) { } this._sizeCells( cells ); - - var selectedIndexDelta = index > this.selectedIndex ? 0 : cells.length; - this._cellAddedRemoved( index, selectedIndexDelta ); + this.cellChange( index, true ); }; proto.append = function( elems ) { @@ -3811,39 +3896,20 @@ proto.prepend = function( elems ) { */ proto.remove = function( elems ) { var cells = this.getCells( elems ); - var selectedIndexDelta = 0; - var len = cells.length; - var i, cell; - // calculate selectedIndexDelta, easier if done in seperate loop - for ( i=0; i < len; i++ ) { - cell = cells[i]; - var wasBefore = this.cells.indexOf( cell ) < this.selectedIndex; - selectedIndexDelta -= wasBefore ? 1 : 0; - } - - for ( i=0; i < len; i++ ) { - cell = cells[i]; - cell.remove(); - // remove item from collection - utils.removeFrom( this.cells, cell ); - } - - if ( cells.length ) { - // update stuff - this._cellAddedRemoved( 0, selectedIndexDelta ); + if ( !cells || !cells.length ) { + return; } -}; -// updates when cells are added or removed -proto._cellAddedRemoved = function( changedCellIndex, selectedIndexDelta ) { - // TODO this math isn't perfect with grouped slides - selectedIndexDelta = selectedIndexDelta || 0; - this.selectedIndex += selectedIndexDelta; - this.selectedIndex = Math.max( 0, Math.min( this.slides.length - 1, this.selectedIndex ) ); + var minCellIndex = this.cells.length - 1; + // remove cells from collection & DOM + cells.forEach( function( cell ) { + cell.remove(); + var index = this.cells.indexOf( cell ); + minCellIndex = Math.min( index, minCellIndex ); + utils.removeFrom( this.cells, cell ); + }, this ); - this.cellChange( changedCellIndex, true ); - // backwards compatibility - this.emitEvent( 'cellAddedRemoved', [ changedCellIndex, selectedIndexDelta ] ); + this.cellChange( minCellIndex, true ); }; /** @@ -3866,24 +3932,24 @@ proto.cellSizeChange = function( elem ) { * @param {Integer} changedCellIndex - index of the changed cell, optional */ proto.cellChange = function( changedCellIndex, isPositioningSlider ) { - var prevSlideableWidth = this.slideableWidth; + var prevSelectedElem = this.selectedElement; this._positionCells( changedCellIndex ); this._getWrapShiftCells(); this.setGallerySize(); + // update selectedIndex + // try to maintain position & select previous selected element + var cell = this.getCell( prevSelectedElem ); + if ( cell ) { + this.selectedIndex = this.getCellSlideIndex( cell ); + } + this.selectedIndex = Math.min( this.slides.length - 1, this.selectedIndex ); + this.emitEvent( 'cellChange', [ changedCellIndex ] ); // position slider - if ( this.options.freeScroll ) { - // shift x by change in slideableWidth - // TODO fix position shifts when prepending w/ freeScroll - var deltaX = prevSlideableWidth - this.slideableWidth; - this.x += deltaX * this.cellAlign; - this.positionSlider(); - } else { - // do not position slider after lazy load - if ( isPositioningSlider ) { - this.positionSliderAtSelected(); - } - this.select( this.selectedIndex ); + this.select( this.selectedIndex ); + // do not position slider after lazy load + if ( isPositioningSlider ) { + this.positionSliderAtSelected(); } }; @@ -3953,12 +4019,18 @@ proto.lazyLoad = function() { function getCellLazyImages( cellElem ) { // check if cell element is lazy image - if ( cellElem.nodeName == 'IMG' && - cellElem.getAttribute('data-flickity-lazyload') ) { - return [ cellElem ]; + if ( cellElem.nodeName == 'IMG' ) { + var lazyloadAttr = cellElem.getAttribute('data-flickity-lazyload'); + var srcAttr = cellElem.getAttribute('data-flickity-lazyload-src'); + var srcsetAttr = cellElem.getAttribute('data-flickity-lazyload-srcset'); + if ( lazyloadAttr || srcAttr || srcsetAttr ) { + return [ cellElem ]; + } } // select lazy images in cell - var imgs = cellElem.querySelectorAll('img[data-flickity-lazyload]'); + var lazySelector = 'img[data-flickity-lazyload], ' + + 'img[data-flickity-lazyload-src], img[data-flickity-lazyload-srcset]'; + var imgs = cellElem.querySelectorAll( lazySelector ); return utils.makeArray( imgs ); } @@ -3978,10 +4050,19 @@ LazyLoader.prototype.handleEvent = utils.handleEvent; LazyLoader.prototype.load = function() { this.img.addEventListener( 'load', this ); this.img.addEventListener( 'error', this ); - // load image - this.img.src = this.img.getAttribute('data-flickity-lazyload'); + // get src & srcset + var src = this.img.getAttribute('data-flickity-lazyload') || + this.img.getAttribute('data-flickity-lazyload-src'); + var srcset = this.img.getAttribute('data-flickity-lazyload-srcset'); + // set src & serset + this.img.src = src; + if ( srcset ) { + this.img.setAttribute( 'srcset', srcset ); + } // remove attr this.img.removeAttribute('data-flickity-lazyload'); + this.img.removeAttribute('data-flickity-lazyload-src'); + this.img.removeAttribute('data-flickity-lazyload-srcset'); }; LazyLoader.prototype.onload = function( event ) { @@ -4014,14 +4095,14 @@ return Flickity; })); /*! - * Flickity v2.0.11 + * Flickity v2.1.0 * Touch, responsive, flickable carousels * * Licensed GPLv3 for open source use * or Flickity Commercial License for commercial use * - * http://flickity.metafizzy.co - * Copyright 2017 Metafizzy + * https://flickity.metafizzy.co + * Copyright 2015-2018 Metafizzy */ ( function( window, factory ) { diff --git a/dist/flickity.pkgd.min.js b/dist/flickity.pkgd.min.js index 9b4d3538..647d2042 100644 --- a/dist/flickity.pkgd.min.js +++ b/dist/flickity.pkgd.min.js @@ -1,13 +1,13 @@ /*! - * Flickity PACKAGED v2.0.11 + * Flickity PACKAGED v2.1.0 * Touch, responsive, flickable carousels * * Licensed GPLv3 for open source use * or Flickity Commercial License for commercial use * - * http://flickity.metafizzy.co - * Copyright 2017 Metafizzy + * https://flickity.metafizzy.co + * Copyright 2015-2018 Metafizzy */ -!function(t,e){"function"==typeof define&&define.amd?define("jquery-bridget/jquery-bridget",["jquery"],function(i){return e(t,i)}):"object"==typeof module&&module.exports?module.exports=e(t,require("jquery")):t.jQueryBridget=e(t,t.jQuery)}(window,function(t,e){"use strict";function i(i,o,a){function l(t,e,n){var s,o="$()."+i+'("'+e+'")';return t.each(function(t,l){var h=a.data(l,i);if(!h)return void r(i+" not initialized. Cannot call methods, i.e. "+o);var c=h[e];if(!c||"_"==e.charAt(0))return void r(o+" is not a valid method");var d=c.apply(h,n);s=void 0===s?d:s}),void 0!==s?s:t}function h(t,e){t.each(function(t,n){var s=a.data(n,i);s?(s.option(e),s._init()):(s=new o(n,e),a.data(n,i,s))})}a=a||e||t.jQuery,a&&(o.prototype.option||(o.prototype.option=function(t){a.isPlainObject(t)&&(this.options=a.extend(!0,this.options,t))}),a.fn[i]=function(t){if("string"==typeof t){var e=s.call(arguments,1);return l(this,t,e)}return h(this,t),this},n(a))}function n(t){!t||t&&t.bridget||(t.bridget=i)}var s=Array.prototype.slice,o=t.console,r="undefined"==typeof o?function(){}:function(t){o.error(t)};return n(e||t.jQuery),i}),function(t,e){"function"==typeof define&&define.amd?define("ev-emitter/ev-emitter",e):"object"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}("undefined"!=typeof window?window:this,function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var i=this._events=this._events||{},n=i[t]=i[t]||[];return n.indexOf(e)==-1&&n.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var i=this._onceEvents=this._onceEvents||{},n=i[t]=i[t]||{};return n[e]=!0,this}},e.off=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=i.indexOf(e);return n!=-1&&i.splice(n,1),this}},e.emitEvent=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){i=i.slice(0),e=e||[];for(var n=this._onceEvents&&this._onceEvents[t],s=0;s