VulpesOS/assets/webapps/mobile-wallet.gaiamobile.org/js/common/swipeable.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

209 lines
6.2 KiB
JavaScript

'use strict';
/* globals GestureDetector */
/* exported Swipeable */
(function(exports) {
var Swipeable = function(container, eltSelector, options) {
this._container = container.querySelector('.swipeable-container');
this._eltSelector = eltSelector;
this.updateElements();
this._createProgress();
this._gestureDetector = new GestureDetector(this._container,
{ holdEvents: false });
this._panHandler = e => this._handlePan(e);
this._swipeHandler = e => this._handleSwipe(e);
this._container.addEventListener('tap', (e) => {
if(this._tapCallback) {
this._tapCallback(this._elts[this._activeEltIdx].id);
}
});
options = options || {};
this._elWidth = options['element-width'] || this._elts[0].offsetWidth;
this._triggerPoint = options['auto-scroll-trigger'] || this._triggerPoint;
this._minSpeed = options['min-speed'] || this._minSpeed;
};
Swipeable.prototype = {
_gestureDetector: null,
_container: null,
_eltSelector: null,
_elts: [],
_progressElts: null,
_elWidth: 0,
_triggerPoint: 0.25,
_minSpeed: 1.0,
_inTransition: false,
_offset: 0,
_activeEltIdx: 0,
_tapCallback: null,
_swipeCallback: null,
_vertSwipeCallback: null,
set ontap(callback) {
this._tapCallback = callback;
},
set onswipe(callback) {
this._swipeCallback = callback;
},
set onvertswipe(callback) {
this._vertSwipeCallback = callback;
},
enable: function() {
this._gestureDetector.startDetecting();
this.unpauseSwipe();
},
disable: function() {
this._gestureDetector.stopDetecting();
},
pauseSwipe: function() {
this._container.removeEventListener('pan', this._panHandler);
this._container.removeEventListener('swipe', this._swipeHandler);
},
unpauseSwipe: function() {
this._container.addEventListener('pan', this._panHandler);
this._container.addEventListener('swipe', this._swipeHandler);
},
updateElements: function() {
var nodeList = this._container.querySelectorAll('.swipeable > ' + this._eltSelector);
this._elts = Array.prototype.slice.call(nodeList);
},
_createProgress: function() {
if(!this._elts || !this._elts.length) {
return;
}
var progressDiv = this._container.querySelector('.swipeable-progress');
if(!progressDiv) {
return;
}
var progressFragment = document.createDocumentFragment();
this._progressElts = this._elts.map(() => {
var div = document.createElement('div');
progressFragment.appendChild(div);
return div;
});
this._progressElts[0].classList.add('swipeable-progress-active');
progressDiv.innerHTML = '';
progressDiv.appendChild(progressFragment);
},
_updateProgress: function() {
this._progressElts.forEach((elt, idx) => {
if(idx === this._activeEltIdx) {
elt.classList.add('swipeable-progress-active');
} else if(elt.classList.contains('swipeable-progress-active')) {
elt.classList.remove('swipeable-progress-active');
}
});
},
progressSelect: function progressSelect(idx, select) {
var pElt = this._progressElts[idx];
if(!pElt) {
return;
}
if(select) {
pElt.classList.add('swipeable-progress-selected');
} else if(pElt.classList.contains('swipeable-progress-selected')) {
pElt.classList.remove('swipeable-progress-selected');
}
},
_handlePan: function(event) {
if(this._inTransition) {
return;
}
if (Math.abs(event.detail.relative.dx) > Math.abs(event.detail.relative.dy)) {
this._offset += event.detail.relative.dx;
this._animate();
}
},
_handleSwipe: function(event) {
if(this._vertSwipeCallback &&
['up', 'down'].indexOf(event.detail.direction) !== -1) {
var id = this._elts[this._activeEltIdx].id;
this._vertSwipeCallback(event.detail.direction, id);
}
var elPos = Math.abs(this._offset)%this._elWidth;
var triggerPassed = elPos > this._elWidth * this._triggerPoint;
var velocity = event.detail.vx;
var fastEnough = Math.abs(velocity) > this._minSpeed;
var direction = (event.detail.direction === 'left') ? 1 : -1;
var newIdx = this._computeNewIndex(direction);
// Make sure that that the speed and pan amount are in the same direction
//var samedirection = velocity === 0 || this._offset / velocity >= 0;
if((triggerPassed || fastEnough) && newIdx !== this._activeEltIdx) {
var speed = Math.max(Math.abs(velocity), this._minSpeed);
var time = (this._elWidth - Math.abs(this._offset%this._elWidth)) / speed;
this._activeEltIdx = newIdx;
this._performScroll(time);
this._updateProgress();
if (this._swipeCallback) {
this._swipeCallback(this._activeEltIdx);
}
} else if(this._offset !== 0){
var time = Math.abs(this._offset%this._elWidth) / this._minSpeed;
this._performScroll(time);
if (this._swipeCallback) {
this._swipeCallback(this._activeEltIdx);
}
}
},
_animate: function(time) {
var handler = (e) => {
e.target.style.transition = null;
e.target.removeEventListener('transitionend', handler);
};
this._elts.forEach((el) => {
if(time) {
el.style.transition = 'transform ' + time + 'ms ease';
el.addEventListener('transitionend', handler);
}
el.style.transform = 'translate3d('+this._offset+'px,0,0)';
});
},
_performScroll: function(time) {
this._inTransition = true;
this._offset = -1 * this._activeEltIdx * this._elWidth;
this._animate(time);
setTimeout(() => { this._inTransition = false; }, time);
},
_computeNewIndex: function(direction) {
var index = this._activeEltIdx + direction;
var offBounds = index < 0 || index >= this._elts.length;
return offBounds ? this._activeEltIdx : index;
}
};
exports.Swipeable = Swipeable;
}((typeof exports === 'undefined') ? window : exports));