Skip to content

Instantly share code, notes, and snippets.

@th3hunt
Created August 19, 2020 07:15
Show Gist options
  • Save th3hunt/68b14010f92e5cbb117b39249a3ed6d6 to your computer and use it in GitHub Desktop.
Save th3hunt/68b14010f92e5cbb117b39249a3ed6d6 to your computer and use it in GitHub Desktop.
import Marionette from 'backbone.marionette';
import Hammer from 'hammerjs';
import $ from 'jquery';
import _ from 'underscore';
export default Marionette.Behavior.extend({
defaults: {
threshold: 30
},
ui() {
return {
content: this.options.content || 'item__content',
actions: this.options.actions || 'item__actions'
};
},
events: {
'tap @ui.content': 'onTap'
},
initialize() {
_.bindAll(this, 'onPan', 'onPanEnd');
this.swipeEnabled = this.view.getOption('swipeEnabled');
this.view.swipeOpen = this.swipeOpen.bind(this);
this.view.swipeClose = this.swipeClose.bind(this);
},
isEnabled() {
return _.result(this, 'swipeEnabled');
},
onRender() {
this.contentEl = this.ui.content[0];
},
onAttach() {
this.hammer = new Hammer.Manager(this.contentEl, {
touchAction: 'auto',
inputClass: Hammer.SUPPORT_POINTER_EVENTS ? Hammer.PointerEventInput : Hammer.TouchInput
});
this.hammer.add(new Hammer.Pan({direction: Hammer.DIRECTION_HORIZONTAL, threshold: this.getOption('threshold')}));
this.hammer.on('panleft panright', this.onPan);
this.hammer.on('panend', this.onPanEnd);
},
onDestroy() {
this.hammer && this.hammer.off('panleft panright panend');
delete this.hammer;
},
onTap(e) {
if (e && (this.isOpen || this.isStarted)) {
e.stopPropagation();
}
_.delay(this.swipeClose.bind(this), 200);
},
swipeOpen() {
this.el.classList.add('swipe-animate');
this.transform(this.snapPoint);
this.isOpen = true;
this.isStarted = false;
this.view.isSwipedOpen = true;
this.view.triggerMethod('swipe:open');
},
swipeClose() {
this.el.classList.add('swipe-animate');
this.transform(null);
this.isOpen = false;
this.isStarted = false;
this.view.isSwipedOpen = false;
this.view.triggerMethod('swipe:close');
},
slide(distance) {
let snapOffset;
let transform;
snapOffset = distance - this.snapPoint;
if (snapOffset > 0) {
this.readyToSnap = true;
// add resistance as we move beyond the snap point
transform = this.snapPoint + (snapOffset * this.snapPoint / distance);
} else {
this.resetOnEnd = false;
this.readyToSnap = false;
transform = distance;
}
transform = Math.min(this.maxDistance, Math.max(transform, 0));
this.el.classList.remove('swipe-animate');
this.view.triggerMethod('swipe:slide');
this.transform(transform);
},
start(e) {
const threshold = this.getOption('threshold');
if (e && _.isNumber(threshold)) {
if (e.direction === Hammer.DIRECTION_LEFT) {
this.distanceFix = -threshold;
} else {
this.distanceFix = +threshold;
}
} else {
this.distanceFix = 0;
}
this.snapPoint = this.calculateSnapPoint();
this.maxDistance = this.getOption('maxDistance') || this.el.offsetWidth / 1.5;
this.initialDistance = this.isOpen ? this.snapPoint : 0;
this.readyToSnap = false;
this.resetOnEnd = this.isOpen;
this.isStarted = true;
this.view.triggerMethod('swipe:start');
},
onPan(e) {
if (!this.isEnabled()) {
return;
}
if (!this.isStarted) {
// start only if the movement has a direction < 45 degrees
if (Math.abs(e.deltaY) > 0 && (Math.abs(e.deltaX / e.deltaY)) < 1) {
return;
}
this.start(e);
}
const distance = this.initialDistance - e.deltaX + this.distanceFix;
if (distance < 0 || distance > this.maxDistance) {
return;
}
e.srcEvent.stopPropagation();
e.srcEvent.preventDefault();
this.slide(distance);
},
onPanEnd(e) {
e.srcEvent.preventDefault();
if (this.readyToSnap && !this.resetOnEnd) {
this.swipeOpen();
} else {
this.swipeClose();
}
this.view.triggerMethod('swipe:end');
},
calculateSnapPoint() {
return this.ui.actions.width() - this.ui.actions.find('>div:visible').last().offset().left;
},
transform(pixels) {
if (pixels === null) {
this.contentEl.style[$.support.transform] = '';
} else {
this.contentEl.style[$.support.transform] = 'translateX(-' + pixels + 'px)';
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment