mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2024-11-18 11:28:23 -07:00
305 lines
8.9 KiB
JavaScript
305 lines
8.9 KiB
JavaScript
define(['browser', 'css!./navdrawer', 'scrollStyles'], function (browser) {
|
|
|
|
return function (options) {
|
|
|
|
var self,
|
|
defaults,
|
|
mask,
|
|
maskHammer,
|
|
menuHammer,
|
|
newPos = 0,
|
|
currentPos = 0,
|
|
startPoint = 0,
|
|
countStart = 0,
|
|
velocity = 0.0;
|
|
|
|
options.target.classList.add('transition');
|
|
var draggingX;
|
|
var draggingY;
|
|
|
|
var scrollContainer = options.target.querySelector('.scrollContainer');
|
|
scrollContainer.classList.add('smoothScrollY');
|
|
|
|
var TouchMenuLA = function () {
|
|
self = this;
|
|
|
|
defaults = {
|
|
width: 280,
|
|
handleSize: 30,
|
|
disableMask: false,
|
|
maxMaskOpacity: 0.5
|
|
};
|
|
|
|
this.isVisible = false;
|
|
|
|
this.initialize();
|
|
};
|
|
|
|
TouchMenuLA.prototype.initElements = function (Hammer) {
|
|
options.target.classList.add('touch-menu-la');
|
|
options.target.style.width = options.width + 'px';
|
|
options.target.style.left = -options.width + 'px';
|
|
|
|
if (!options.disableMask) {
|
|
mask = document.createElement('div');
|
|
mask.className = 'tmla-mask';
|
|
document.body.appendChild(mask);
|
|
|
|
if (Hammer) {
|
|
maskHammer = new Hammer(mask, null);
|
|
}
|
|
}
|
|
};
|
|
|
|
function onPanStart(ev) {
|
|
options.target.classList.remove('transition');
|
|
options.target.classList.add('open');
|
|
velocity = Math.abs(ev.velocity);
|
|
}
|
|
|
|
function onPanMove(ev) {
|
|
velocity = Math.abs(ev.velocity);
|
|
// Depending on the deltas, choose X or Y
|
|
|
|
var isOpen = self.visible;
|
|
|
|
// If it's already open, then treat any right-swipe as vertical pan
|
|
if (isOpen && !draggingX && ev.deltaX > 0) {
|
|
draggingY = true;
|
|
}
|
|
|
|
if (!draggingX && !draggingY && (!isOpen || Math.abs(ev.deltaX) >= 10)) {
|
|
draggingX = true;
|
|
scrollContainer.addEventListener('scroll', disableEvent);
|
|
self.showMask();
|
|
|
|
} else if (!draggingY) {
|
|
draggingY = true;
|
|
}
|
|
|
|
if (draggingX) {
|
|
newPos = currentPos + ev.deltaX;
|
|
self.changeMenuPos();
|
|
}
|
|
}
|
|
|
|
function onPanEnd(ev) {
|
|
options.target.classList.add('transition');
|
|
scrollContainer.removeEventListener('scroll', disableEvent);
|
|
draggingX = false;
|
|
draggingY = false;
|
|
currentPos = ev.deltaX;
|
|
self.checkMenuState(ev.deltaX, ev.deltaY);
|
|
}
|
|
|
|
function initEdgeSwipe(Hammer) {
|
|
if (options.disableEdgeSwipe) {
|
|
return;
|
|
}
|
|
|
|
var edgeHammer = new Hammer(options.edgeSwipeElement, null);
|
|
var isPeeking = false;
|
|
|
|
edgeHammer.on('panstart panmove', function (ev) {
|
|
|
|
if (isPeeking) {
|
|
onPanMove(ev);
|
|
} else {
|
|
var srcEvent = ev.srcEvent;
|
|
var clientX = srcEvent.clientX;
|
|
if (!clientX) {
|
|
var touches = srcEvent.touches;
|
|
if (touches && touches.length) {
|
|
clientX = touches[0].clientX;
|
|
}
|
|
}
|
|
if (clientX <= options.handleSize) {
|
|
isPeeking = true;
|
|
onPanStart(ev);
|
|
}
|
|
}
|
|
});
|
|
edgeHammer.on('panend pancancel', function (ev) {
|
|
if (isPeeking) {
|
|
isPeeking = false;
|
|
onPanEnd(ev);
|
|
}
|
|
});
|
|
|
|
self.edgeHammer = edgeHammer;
|
|
}
|
|
|
|
function disableEvent(e) {
|
|
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
|
|
TouchMenuLA.prototype.touchStartMenu = function () {
|
|
|
|
menuHammer.on('panstart', function (ev) {
|
|
onPanStart(ev);
|
|
});
|
|
menuHammer.on('panmove', function (ev) {
|
|
onPanMove(ev);
|
|
});
|
|
};
|
|
|
|
TouchMenuLA.prototype.animateToPosition = function (pos) {
|
|
|
|
requestAnimationFrame(function () {
|
|
if (pos) {
|
|
options.target.style.transform = 'translate3d(' + pos + 'px, 0, 0)';
|
|
options.target.style.WebkitTransform = 'translate3d(' + pos + 'px, 0, 0)';
|
|
options.target.style.MozTransform = 'translate3d(' + pos + 'px, 0, 0)';
|
|
} else {
|
|
options.target.style.transform = 'none';
|
|
options.target.style.WebkitTransform = 'none';
|
|
options.target.style.MozTransform = 'none';
|
|
}
|
|
});
|
|
};
|
|
|
|
TouchMenuLA.prototype.changeMenuPos = function () {
|
|
if (newPos <= options.width) {
|
|
this.animateToPosition(newPos);
|
|
}
|
|
};
|
|
|
|
TouchMenuLA.prototype.touchEndMenu = function () {
|
|
menuHammer.on('panend pancancel', onPanEnd);
|
|
};
|
|
|
|
TouchMenuLA.prototype.clickMaskClose = function () {
|
|
mask.addEventListener('click', function () {
|
|
self.close();
|
|
});
|
|
};
|
|
|
|
TouchMenuLA.prototype.checkMenuState = function (deltaX, deltaY) {
|
|
if (velocity >= 1.0) {
|
|
if (deltaX >= -80 || Math.abs(deltaY) >= 70) {
|
|
self.open();
|
|
} else {
|
|
self.close();
|
|
}
|
|
} else {
|
|
if (newPos >= 100) {
|
|
self.open();
|
|
} else {
|
|
self.close();
|
|
}
|
|
}
|
|
};
|
|
|
|
TouchMenuLA.prototype.open = function () {
|
|
this.animateToPosition(options.width);
|
|
|
|
currentPos = options.width;
|
|
this.isVisible = true;
|
|
options.target.classList.add('open');
|
|
|
|
self.showMask();
|
|
self.invoke(options.onChange);
|
|
};
|
|
|
|
TouchMenuLA.prototype.close = function () {
|
|
this.animateToPosition(0);
|
|
currentPos = 0;
|
|
self.isVisible = false;
|
|
options.target.classList.remove('open');
|
|
|
|
self.hideMask();
|
|
self.invoke(options.onChange);
|
|
};
|
|
|
|
TouchMenuLA.prototype.toggle = function () {
|
|
if (self.isVisible) {
|
|
self.close();
|
|
} else {
|
|
self.open();
|
|
}
|
|
};
|
|
|
|
TouchMenuLA.prototype.eventStartMask = function () {
|
|
maskHammer.on('panstart panmove', function (ev) {
|
|
if (ev.center.x <= options.width && self.isVisible) {
|
|
countStart++;
|
|
|
|
if (countStart == 1) {
|
|
startPoint = ev.deltaX;
|
|
}
|
|
|
|
if (ev.deltaX < 0) {
|
|
draggingX = true;
|
|
newPos = (ev.deltaX - startPoint) + options.width;
|
|
self.changeMenuPos();
|
|
velocity = Math.abs(ev.velocity);
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
TouchMenuLA.prototype.eventEndMask = function () {
|
|
maskHammer.on('panend pancancel', function (ev) {
|
|
self.checkMenuState(ev.deltaX);
|
|
countStart = 0;
|
|
});
|
|
};
|
|
|
|
TouchMenuLA.prototype.showMask = function () {
|
|
|
|
mask.classList.add('backdrop');
|
|
};
|
|
|
|
TouchMenuLA.prototype.hideMask = function () {
|
|
|
|
mask.classList.remove('backdrop');
|
|
};
|
|
|
|
TouchMenuLA.prototype.invoke = function (fn) {
|
|
if (fn) {
|
|
fn.apply(self);
|
|
}
|
|
};
|
|
|
|
function initWithHammer(Hammer) {
|
|
|
|
if (Hammer) {
|
|
menuHammer = Hammer(options.target, null);
|
|
}
|
|
|
|
self.initElements(Hammer);
|
|
|
|
if (Hammer) {
|
|
self.touchStartMenu();
|
|
self.touchEndMenu();
|
|
self.eventStartMask();
|
|
self.eventEndMask();
|
|
initEdgeSwipe(Hammer);
|
|
}
|
|
|
|
if (!options.disableMask) {
|
|
self.clickMaskClose();
|
|
}
|
|
}
|
|
|
|
TouchMenuLA.prototype.initialize = function () {
|
|
|
|
options = Object.assign(defaults, options || {});
|
|
|
|
// Not ready yet
|
|
if (browser.edge) {
|
|
options.disableEdgeSwipe = true;
|
|
}
|
|
|
|
if (browser.touch) {
|
|
require(['hammer'], initWithHammer);
|
|
} else {
|
|
initWithHammer();
|
|
}
|
|
};
|
|
|
|
return new TouchMenuLA();
|
|
};
|
|
}); |