From 51ed4f9001dffd9ec4886527fc7d382c6a313160 Mon Sep 17 00:00:00 2001 From: Wikiki Date: Mon, 14 May 2018 13:29:19 +0200 Subject: [PATCH] fix(swipe): Mouse enable swipe And fix #37 Consider marking event handler as 'passive'? --- dist/bulma-carousel.js | 38 ++++++++++++++++++++++++++----------- dist/bulma-carousel.min.js | 2 +- src/extension.js | 39 ++++++++++++++++++++++++++------------ 3 files changed, 55 insertions(+), 24 deletions(-) diff --git a/dist/bulma-carousel.js b/dist/bulma-carousel.js index 9077037..5dbc5ee 100644 --- a/dist/bulma-carousel.js +++ b/dist/bulma-carousel.js @@ -130,6 +130,17 @@ class EventEmitter { } } +var supportsPassive = false; +try { + var opts = Object.defineProperty({}, 'passive', { + get: function() { + supportsPassive = true; + } + }); + window.addEventListener("testPassive", null, opts); + window.removeEventListener("testPassive", null, opts); +} catch (e) {} + class Carousel extends EventEmitter { constructor(selector) { super(); @@ -281,7 +292,7 @@ class Carousel extends EventEmitter { clearInterval(this._autoPlayInterval); this._autoPlay(this.carousel.dataset.delay || 5000); } - }); + }, supportsPassive ? { passive: true } : false); }); } @@ -294,20 +305,22 @@ class Carousel extends EventEmitter { clearInterval(this._autoPlayInterval); this._autoPlay(this.carousel.dataset.delay || 5000); } - }); + }, supportsPassive ? { passive: true } : false); }); } // Bind swipe events this.carousel.addEventListener('touchstart', e => { this._swipeStart(e); - }); + }, supportsPassive ? { passive: true } : false); this.carousel.addEventListener('touchmove', e => { - e.preventDefault(); - }); + if (!supportsPassive) { + e.preventDefault(); + } + }, supportsPassive ? { passive: true } : false); this.carousel.addEventListener('touchend', e => { this._swipeEnd(e); - }); + }, supportsPassive ? { passive: true } : false); } /** @@ -371,11 +384,13 @@ class Carousel extends EventEmitter { _swipeStart(e) { e.preventDefault(); + e = e ? e : window.event; + e = ('changedTouches' in e) ? e.changedTouches[0] : e; this._touch = { start: { time: new Date().getTime(), // record time when finger first makes contact with surface - x: touchObj.pageX, - y: touchObj.pageY + x: e.pageX, + y: e.pageY }, dist: { x: 0, @@ -393,10 +408,11 @@ class Carousel extends EventEmitter { _swipeEnd(e) { e.preventDefault(); - const touchObj = e.changedTouches[0]; + e = e ? e : window.event; + e = ('changedTouches' in e) ? e.changedTouches[0] : e; this._touch.dist = { - x: touchObj.pageX - this._touch.start.x, // get horizontal dist traveled by finger while in contact with surface - y: touchObj.pageY - this._touch.start.y // get vertical dist traveled by finger while in contact with surface + x: e.pageX - this._touch.start.x, // get horizontal dist traveled by finger while in contact with surface + y: e.pageY - this._touch.start.y // get vertical dist traveled by finger while in contact with surface }; this._handleGesture(); diff --git a/dist/bulma-carousel.min.js b/dist/bulma-carousel.min.js index e568fc5..1cb7217 100644 --- a/dist/bulma-carousel.min.js +++ b/dist/bulma-carousel.min.js @@ -1 +1 @@ -(function(a,b){'object'==typeof exports&&'undefined'!=typeof module?module.exports=b():'function'==typeof define&&define.amd?define('bulmaCarousel',b):a.bulmaCarousel=b()})(this,function(){'use strict';var a=Math.abs;class b{constructor(a=[]){this._listeners=new Map(a),this._middlewares=new Map}listenerCount(a){if(!this._listeners.has(a))return 0;const b=this._listeners.get(a);return b.length}removeListeners(a=null,b=!1){null===a?this._listeners=new Map:Array.isArray(a)?name.forEach((a)=>this.removeListeners(a,b)):(this._listeners.delete(a),b&&this.removeMiddleware(a))}middleware(a,b){Array.isArray(a)?name.forEach((a)=>this.middleware(a,b)):(!Array.isArray(this._middlewares.get(a))&&this._middlewares.set(a,[]),this._middlewares.get(a).push(b))}removeMiddleware(a=null){null===a?this._middlewares=new Map:Array.isArray(a)?name.forEach((a)=>this.removeMiddleware(a)):this._middlewares.delete(a)}on(a,b,c=!1){if(Array.isArray(a))a.forEach((a)=>this.on(a,b));else{a=a.toString();const d=a.split(/,|, | /);1this.on(a,b)):(!Array.isArray(this._listeners.get(a))&&this._listeners.set(a,[]),this._listeners.get(a).push({once:c,callback:b}))}}once(a,b){this.on(a,b,!0)}emit(a,b,c=!1){a=a.toString();let d=this._listeners.get(a),e=null,f=0,g=c;if(Array.isArray(d))for(d.forEach((h,i)=>{c||(e=this._middlewares.get(a),Array.isArray(e)?(e.forEach((c)=>{c(b,(a=null)=>{null!==a&&(b=a),f++},a)}),f>=e.length&&(g=!0)):g=!0),g&&(h.once&&(d[i]=null),h.callback(b))});-1!==d.indexOf(null);)d.splice(d.indexOf(null),1)}}class c extends b{constructor(a){if(super(),this._clickEvents=['touchstart','click'],this.carousel='string'==typeof a?document.querySelector(a):a,!this.carousel)throw new Error('An invalid selector or non-DOM node has been provided.');this.options=Object.assign({},{threshold:50,restraint:100,allowedTime:500}),this.init()}static attach(a='.carousel, .hero-carousel'){let b=[];const d=document.querySelectorAll(a);return[].forEach.call(d,(a)=>{setTimeout(()=>{b.push(new c(a))},100)}),b}init(){let a=!1;if(this.computedStyle=window.getComputedStyle(this.carousel),this.carouselWidth=parseInt(this.computedStyle.getPropertyValue('width'),10),this.carouselContainer=this.carousel.querySelector('.carousel-container'),this.carouselItems=this.carousel.querySelectorAll('.carousel-item'),this.carouselItemsArray=Array.from(this.carouselItems),this.carousel.dataset.size&&!this.carousel.classList.contains('carousel-animate-fade')&&(this.carousel.dataset.size>=this.carouselItemsArray.length?(this.offset=0,a=!0):this.offset=this.carouselWidth/this.carousel.dataset.size,this.carouselContainer.style.left=0-this.offset+'px',this.carouselContainer.style.transform=`translateX(${this.offset}px)`,[].forEach.call(this.carouselItems,(a)=>{a.style.flexBasis=`${this.offset}px`})),this._initNavigation(a),this.carousel.classList.contains('carousel-animate-fade')&&this.carouselItems.length){let a=this.carouselItems[0].querySelector('img'),b=1;a.naturalWidth?(b=this.carouselWidth/a.naturalWidth,this.carouselContainer.style.height=a.naturalHeight*b+'px'):a.onload=()=>{b=this.carouselWidth/a.naturalWidth,this.carouselContainer.style.height=a.naturalHeight*b+'px'}}this.currentItem={carousel:this.carousel,node:null,pos:-1},this.currentItem.node=this.carousel.querySelector('.carousel-item.is-active'),this.currentItem.pos=this.currentItem.node?this.carouselItemsArray.indexOf(this.currentItem.node):-1,this.currentItem.node||(this.currentItem.node=this.carouselItems[0],this.currentItem.node.classList.add('is-active'),this.currentItem.pos=0),this._setOrder(),this.carousel.dataset.autoplay&&'true'==this.carousel.dataset.autoplay&&this._autoPlay(this.carousel.dataset.delay||5e3),this._bindEvents(),this.emit('carousel:ready',this.currentItem)}_initNavigation(a=!1){this.previousControl=this.carousel.querySelector('.carousel-nav-left'),this.nextControl=this.carousel.querySelector('.carousel-nav-right'),(1>=this.carouselItems.length||a)&&(this.carouselContainer&&(this.carouselContainer.style.left='0'),this.previousControl&&(this.previousControl.style.display='none'),this.nextControl&&(this.nextControl.style.display='none'))}_bindEvents(){this.previousControl&&this._clickEvents.forEach((a)=>{this.previousControl.addEventListener(a,(a)=>{a.preventDefault(),this._slide('previous'),this._autoPlayInterval&&(clearInterval(this._autoPlayInterval),this._autoPlay(this.carousel.dataset.delay||5e3))})}),this.nextControl&&this._clickEvents.forEach((a)=>{this.nextControl.addEventListener(a,(a)=>{a.preventDefault(),this._slide('next'),this._autoPlayInterval&&(clearInterval(this._autoPlayInterval),this._autoPlay(this.carousel.dataset.delay||5e3))})}),this.carousel.addEventListener('touchstart',(a)=>{this._swipeStart(a)}),this.carousel.addEventListener('touchmove',(a)=>{a.preventDefault()}),this.carousel.addEventListener('touchend',(a)=>{this._swipeEnd(a)})}_next(a){return a.nextElementSibling?a.nextElementSibling:this.carouselItems[0]}_previous(a){return a.previousElementSibling?a.previousElementSibling:this.carouselItems[this.carouselItems.length-1]}_setOrder(){this.currentItem.node.style.order='1',this.currentItem.node.style.zIndex='1';let a,b,c,d=this.currentItem.node;for(a=b=2,c=this.carouselItemsArray.length;2<=c?b<=c:b>=c;a=2<=c?++b:--b)d=this._next(d),d.style.order=''+a%this.carouselItemsArray.length,d.style.zIndex='0'}_swipeStart(a){a.preventDefault(),this._touch={start:{time:new Date().getTime(),x:touchObj.pageX,y:touchObj.pageY},dist:{x:0,y:0}}}_swipeEnd(a){a.preventDefault();const b=a.changedTouches[0];this._touch.dist={x:b.pageX-this._touch.start.x,y:b.pageY-this._touch.start.y},this._handleGesture()}_handleGesture(){const b=new Date().getTime()-this._touch.start.time;b<=this.options.allowedTime&&a(this._touch.dist.x)>=this.options.threshold&&a(this._touch.dist.y)<=this.options.restraint&&(0>this._touch.dist.x?this._slide('next'):this._slide('previous'))}_slide(b='next'){this.carouselItems.length&&(this.oldItemNode=this.currentItem.node,this.emit('carousel:slide:before',this.currentItem),'previous'===b?(this.currentItem.node=this._previous(this.currentItem.node),!this.carousel.classList.contains('carousel-animate-fade')&&(this.carousel.classList.add('is-reversing'),this.carouselContainer.style.transform=`translateX(${-a(this.offset)}px)`)):(this.currentItem.node=this._next(this.currentItem.node),this.carousel.classList.remove('is-reversing'),this.carouselContainer.style.transform=`translateX(${a(this.offset)}px)`),this.currentItem.node.classList.add('is-active'),this.oldItemNode.classList.remove('is-active'),this.carousel.classList.remove('carousel-animated'),setTimeout(()=>{this.carousel.classList.add('carousel-animated')},50),this._setOrder(),this.emit('carousel:slide:after',this.currentItem))}_autoPlay(a=5e3){this._autoPlayInterval=setInterval(()=>{this._slide('next')},a)}}return c}); \ No newline at end of file +(function(a,b){'object'==typeof exports&&'undefined'!=typeof module?module.exports=b():'function'==typeof define&&define.amd?define('bulmaCarousel',b):a.bulmaCarousel=b()})(this,function(){'use strict';var a=Math.abs;class b{constructor(a=[]){this._listeners=new Map(a),this._middlewares=new Map}listenerCount(a){if(!this._listeners.has(a))return 0;const b=this._listeners.get(a);return b.length}removeListeners(a=null,b=!1){null===a?this._listeners=new Map:Array.isArray(a)?name.forEach((a)=>this.removeListeners(a,b)):(this._listeners.delete(a),b&&this.removeMiddleware(a))}middleware(a,b){Array.isArray(a)?name.forEach((a)=>this.middleware(a,b)):(!Array.isArray(this._middlewares.get(a))&&this._middlewares.set(a,[]),this._middlewares.get(a).push(b))}removeMiddleware(a=null){null===a?this._middlewares=new Map:Array.isArray(a)?name.forEach((a)=>this.removeMiddleware(a)):this._middlewares.delete(a)}on(a,b,c=!1){if(Array.isArray(a))a.forEach((a)=>this.on(a,b));else{a=a.toString();const d=a.split(/,|, | /);1this.on(a,b)):(!Array.isArray(this._listeners.get(a))&&this._listeners.set(a,[]),this._listeners.get(a).push({once:c,callback:b}))}}once(a,b){this.on(a,b,!0)}emit(a,b,c=!1){a=a.toString();let d=this._listeners.get(a),e=null,f=0,g=c;if(Array.isArray(d))for(d.forEach((h,i)=>{c||(e=this._middlewares.get(a),Array.isArray(e)?(e.forEach((c)=>{c(b,(a=null)=>{null!==a&&(b=a),f++},a)}),f>=e.length&&(g=!0)):g=!0),g&&(h.once&&(d[i]=null),h.callback(b))});-1!==d.indexOf(null);)d.splice(d.indexOf(null),1)}}var c=!1;try{var d=Object.defineProperty({},'passive',{get:function(){c=!0}});window.addEventListener('testPassive',null,d),window.removeEventListener('testPassive',null,d)}catch(a){}class e extends b{constructor(a){if(super(),this._clickEvents=['touchstart','click'],this.carousel='string'==typeof a?document.querySelector(a):a,!this.carousel)throw new Error('An invalid selector or non-DOM node has been provided.');this.options=Object.assign({},{threshold:50,restraint:100,allowedTime:500}),this.init()}static attach(a='.carousel, .hero-carousel'){let b=[];const c=document.querySelectorAll(a);return[].forEach.call(c,(a)=>{setTimeout(()=>{b.push(new e(a))},100)}),b}init(){let a=!1;if(this.computedStyle=window.getComputedStyle(this.carousel),this.carouselWidth=parseInt(this.computedStyle.getPropertyValue('width'),10),this.carouselContainer=this.carousel.querySelector('.carousel-container'),this.carouselItems=this.carousel.querySelectorAll('.carousel-item'),this.carouselItemsArray=Array.from(this.carouselItems),this.carousel.dataset.size&&!this.carousel.classList.contains('carousel-animate-fade')&&(this.carousel.dataset.size>=this.carouselItemsArray.length?(this.offset=0,a=!0):this.offset=this.carouselWidth/this.carousel.dataset.size,this.carouselContainer.style.left=0-this.offset+'px',this.carouselContainer.style.transform=`translateX(${this.offset}px)`,[].forEach.call(this.carouselItems,(a)=>{a.style.flexBasis=`${this.offset}px`})),this._initNavigation(a),this.carousel.classList.contains('carousel-animate-fade')&&this.carouselItems.length){let a=this.carouselItems[0].querySelector('img'),b=1;a.naturalWidth?(b=this.carouselWidth/a.naturalWidth,this.carouselContainer.style.height=a.naturalHeight*b+'px'):a.onload=()=>{b=this.carouselWidth/a.naturalWidth,this.carouselContainer.style.height=a.naturalHeight*b+'px'}}this.currentItem={carousel:this.carousel,node:null,pos:-1},this.currentItem.node=this.carousel.querySelector('.carousel-item.is-active'),this.currentItem.pos=this.currentItem.node?this.carouselItemsArray.indexOf(this.currentItem.node):-1,this.currentItem.node||(this.currentItem.node=this.carouselItems[0],this.currentItem.node.classList.add('is-active'),this.currentItem.pos=0),this._setOrder(),this.carousel.dataset.autoplay&&'true'==this.carousel.dataset.autoplay&&this._autoPlay(this.carousel.dataset.delay||5e3),this._bindEvents(),this.emit('carousel:ready',this.currentItem)}_initNavigation(a=!1){this.previousControl=this.carousel.querySelector('.carousel-nav-left'),this.nextControl=this.carousel.querySelector('.carousel-nav-right'),(1>=this.carouselItems.length||a)&&(this.carouselContainer&&(this.carouselContainer.style.left='0'),this.previousControl&&(this.previousControl.style.display='none'),this.nextControl&&(this.nextControl.style.display='none'))}_bindEvents(){this.previousControl&&this._clickEvents.forEach((a)=>{this.previousControl.addEventListener(a,(a)=>{a.preventDefault(),this._slide('previous'),this._autoPlayInterval&&(clearInterval(this._autoPlayInterval),this._autoPlay(this.carousel.dataset.delay||5e3))},!!c&&{passive:!0})}),this.nextControl&&this._clickEvents.forEach((a)=>{this.nextControl.addEventListener(a,(a)=>{a.preventDefault(),this._slide('next'),this._autoPlayInterval&&(clearInterval(this._autoPlayInterval),this._autoPlay(this.carousel.dataset.delay||5e3))},!!c&&{passive:!0})}),this.carousel.addEventListener('touchstart',(a)=>{this._swipeStart(a)},!!c&&{passive:!0}),this.carousel.addEventListener('touchmove',(a)=>{c||a.preventDefault()},!!c&&{passive:!0}),this.carousel.addEventListener('touchend',(a)=>{this._swipeEnd(a)},!!c&&{passive:!0})}_next(a){return a.nextElementSibling?a.nextElementSibling:this.carouselItems[0]}_previous(a){return a.previousElementSibling?a.previousElementSibling:this.carouselItems[this.carouselItems.length-1]}_setOrder(){this.currentItem.node.style.order='1',this.currentItem.node.style.zIndex='1';let a,b,c,d=this.currentItem.node;for(a=b=2,c=this.carouselItemsArray.length;2<=c?b<=c:b>=c;a=2<=c?++b:--b)d=this._next(d),d.style.order=''+a%this.carouselItemsArray.length,d.style.zIndex='0'}_swipeStart(a){a.preventDefault(),a=a?a:window.event,a='changedTouches'in a?a.changedTouches[0]:a,this._touch={start:{time:new Date().getTime(),x:a.pageX,y:a.pageY},dist:{x:0,y:0}}}_swipeEnd(a){a.preventDefault(),a=a?a:window.event,a='changedTouches'in a?a.changedTouches[0]:a,this._touch.dist={x:a.pageX-this._touch.start.x,y:a.pageY-this._touch.start.y},this._handleGesture()}_handleGesture(){const b=new Date().getTime()-this._touch.start.time;b<=this.options.allowedTime&&a(this._touch.dist.x)>=this.options.threshold&&a(this._touch.dist.y)<=this.options.restraint&&(0>this._touch.dist.x?this._slide('next'):this._slide('previous'))}_slide(b='next'){this.carouselItems.length&&(this.oldItemNode=this.currentItem.node,this.emit('carousel:slide:before',this.currentItem),'previous'===b?(this.currentItem.node=this._previous(this.currentItem.node),!this.carousel.classList.contains('carousel-animate-fade')&&(this.carousel.classList.add('is-reversing'),this.carouselContainer.style.transform=`translateX(${-a(this.offset)}px)`)):(this.currentItem.node=this._next(this.currentItem.node),this.carousel.classList.remove('is-reversing'),this.carouselContainer.style.transform=`translateX(${a(this.offset)}px)`),this.currentItem.node.classList.add('is-active'),this.oldItemNode.classList.remove('is-active'),this.carousel.classList.remove('carousel-animated'),setTimeout(()=>{this.carousel.classList.add('carousel-animated')},50),this._setOrder(),this.emit('carousel:slide:after',this.currentItem))}_autoPlay(a=5e3){this._autoPlayInterval=setInterval(()=>{this._slide('next')},a)}}return e}); \ No newline at end of file diff --git a/src/extension.js b/src/extension.js index 8a28d8b..b28b3ed 100644 --- a/src/extension.js +++ b/src/extension.js @@ -1,5 +1,16 @@ import EventEmitter from './events'; +var supportsPassive = false; +try { + var opts = Object.defineProperty({}, 'passive', { + get: function() { + supportsPassive = true; + } + }); + window.addEventListener("testPassive", null, opts); + window.removeEventListener("testPassive", null, opts); +} catch (e) {} + export default class Carousel extends EventEmitter { constructor(selector) { super(); @@ -152,7 +163,7 @@ export default class Carousel extends EventEmitter { clearInterval(this._autoPlayInterval); this._autoPlay(this.carousel.dataset.delay || 5000); } - }); + }, supportsPassive ? { passive: true } : false); }); } @@ -165,20 +176,22 @@ export default class Carousel extends EventEmitter { clearInterval(this._autoPlayInterval); this._autoPlay(this.carousel.dataset.delay || 5000); } - }); + }, supportsPassive ? { passive: true } : false); }); } // Bind swipe events this.carousel.addEventListener('touchstart', e => { this._swipeStart(e); - }); + }, supportsPassive ? { passive: true } : false); this.carousel.addEventListener('touchmove', e => { - e.preventDefault(); - }); + if (!supportsPassive) { + e.preventDefault(); + } + }, supportsPassive ? { passive: true } : false); this.carousel.addEventListener('touchend', e => { this._swipeEnd(e); - }); + }, supportsPassive ? { passive: true } : false); } /** @@ -242,12 +255,13 @@ export default class Carousel extends EventEmitter { _swipeStart(e) { e.preventDefault(); - const touchobj = e.changedTouches[0]; + e = e ? e : window.event; + e = ('changedTouches' in e) ? e.changedTouches[0] : e; this._touch = { start: { time: new Date().getTime(), // record time when finger first makes contact with surface - x: touchObj.pageX, - y: touchObj.pageY + x: e.pageX, + y: e.pageY }, dist: { x: 0, @@ -265,10 +279,11 @@ export default class Carousel extends EventEmitter { _swipeEnd(e) { e.preventDefault(); - const touchObj = e.changedTouches[0]; + e = e ? e : window.event; + e = ('changedTouches' in e) ? e.changedTouches[0] : e; this._touch.dist = { - x: touchObj.pageX - this._touch.start.x, // get horizontal dist traveled by finger while in contact with surface - y: touchObj.pageY - this._touch.start.y // get vertical dist traveled by finger while in contact with surface + x: e.pageX - this._touch.start.x, // get horizontal dist traveled by finger while in contact with surface + y: e.pageY - this._touch.start.y // get vertical dist traveled by finger while in contact with surface }; this._handleGesture();