223 lines
8.4 KiB
JavaScript
223 lines
8.4 KiB
JavaScript
/*======================================================
|
|
************ Pull To Refresh ************
|
|
======================================================*/
|
|
app.initPullToRefresh = function (pageContainer) {
|
|
var eventsTarget = $(pageContainer);
|
|
if (!eventsTarget.hasClass('pull-to-refresh-content')) {
|
|
eventsTarget = eventsTarget.find('.pull-to-refresh-content');
|
|
}
|
|
if (!eventsTarget || eventsTarget.length === 0) return;
|
|
|
|
var touchId, isTouched, isMoved, touchesStart = {}, isScrolling, touchesDiff, touchStartTime, container, refresh = false, useTranslate = false, startTranslate = 0, translate, scrollTop, wasScrolled, layer, triggerDistance, dynamicTriggerDistance, pullStarted;
|
|
var page = eventsTarget.hasClass('page') ? eventsTarget : eventsTarget.parents('.page');
|
|
var hasNavbar = false;
|
|
if (page.find('.navbar').length > 0 || page.parents('.navbar-fixed, .navbar-through').length > 0 || page.hasClass('navbar-fixed') || page.hasClass('navbar-through')) hasNavbar = true;
|
|
if (page.hasClass('no-navbar')) hasNavbar = false;
|
|
if (!hasNavbar) eventsTarget.addClass('pull-to-refresh-no-navbar');
|
|
|
|
container = eventsTarget;
|
|
|
|
// Define trigger distance
|
|
if (container.attr('data-ptr-distance')) {
|
|
dynamicTriggerDistance = true;
|
|
}
|
|
else {
|
|
triggerDistance = 44;
|
|
}
|
|
|
|
function handleTouchStart(e) {
|
|
if (isTouched) {
|
|
if (app.device.os === 'android') {
|
|
if ('targetTouches' in e && e.targetTouches.length > 1) return;
|
|
}
|
|
else return;
|
|
}
|
|
|
|
/*jshint validthis:true */
|
|
container = $(this);
|
|
if (container.hasClass('refreshing')) {
|
|
return;
|
|
}
|
|
|
|
isMoved = false;
|
|
pullStarted = false;
|
|
isTouched = true;
|
|
isScrolling = undefined;
|
|
wasScrolled = undefined;
|
|
if (e.type === 'touchstart') touchId = e.targetTouches[0].identifier;
|
|
touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
|
|
touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
|
|
touchStartTime = (new Date()).getTime();
|
|
|
|
}
|
|
|
|
function handleTouchMove(e) {
|
|
if (!isTouched) return;
|
|
var pageX, pageY, touch;
|
|
if (e.type === 'touchmove') {
|
|
if (touchId && e.touches) {
|
|
for (var i = 0; i < e.touches.length; i++) {
|
|
if (e.touches[i].identifier === touchId) {
|
|
touch = e.touches[i];
|
|
}
|
|
}
|
|
}
|
|
if (!touch) touch = e.targetTouches[0];
|
|
pageX = touch.pageX;
|
|
pageY = touch.pageY;
|
|
}
|
|
else {
|
|
pageX = e.pageX;
|
|
pageY = e.pageY;
|
|
}
|
|
if (!pageX || !pageY) return;
|
|
|
|
|
|
if (typeof isScrolling === 'undefined') {
|
|
isScrolling = !!(isScrolling || Math.abs(pageY - touchesStart.y) > Math.abs(pageX - touchesStart.x));
|
|
}
|
|
if (!isScrolling) {
|
|
isTouched = false;
|
|
return;
|
|
}
|
|
|
|
scrollTop = container[0].scrollTop;
|
|
if (typeof wasScrolled === 'undefined' && scrollTop !== 0) wasScrolled = true;
|
|
|
|
if (!isMoved) {
|
|
/*jshint validthis:true */
|
|
container.removeClass('transitioning');
|
|
if (scrollTop > container[0].offsetHeight) {
|
|
isTouched = false;
|
|
return;
|
|
}
|
|
if (dynamicTriggerDistance) {
|
|
triggerDistance = container.attr('data-ptr-distance');
|
|
if (triggerDistance.indexOf('%') >= 0) triggerDistance = container[0].offsetHeight * parseInt(triggerDistance, 10) / 100;
|
|
}
|
|
startTranslate = container.hasClass('refreshing') ? triggerDistance : 0;
|
|
if (container[0].scrollHeight === container[0].offsetHeight || app.device.os !== 'ios') {
|
|
useTranslate = true;
|
|
}
|
|
else {
|
|
useTranslate = false;
|
|
}
|
|
}
|
|
isMoved = true;
|
|
touchesDiff = pageY - touchesStart.y;
|
|
|
|
if (touchesDiff > 0 && scrollTop <= 0 || scrollTop < 0) {
|
|
// iOS 8 fix
|
|
if (app.device.os === 'ios' && parseInt(app.device.osVersion.split('.')[0], 10) > 7 && scrollTop === 0 && !wasScrolled) useTranslate = true;
|
|
|
|
if (useTranslate) {
|
|
e.preventDefault();
|
|
translate = (Math.pow(touchesDiff, 0.85) + startTranslate);
|
|
container.transform('translate3d(0,' + translate + 'px,0)');
|
|
}
|
|
if ((useTranslate && Math.pow(touchesDiff, 0.85) > triggerDistance) || (!useTranslate && touchesDiff >= triggerDistance * 2)) {
|
|
refresh = true;
|
|
container.addClass('pull-up').removeClass('pull-down');
|
|
}
|
|
else {
|
|
refresh = false;
|
|
container.removeClass('pull-up').addClass('pull-down');
|
|
}
|
|
if (!pullStarted) {
|
|
container.trigger('pullstart');
|
|
pullStarted = true;
|
|
}
|
|
container.trigger('pullmove', {
|
|
event: e,
|
|
scrollTop: scrollTop,
|
|
translate: translate,
|
|
touchesDiff: touchesDiff
|
|
});
|
|
}
|
|
else {
|
|
pullStarted = false;
|
|
container.removeClass('pull-up pull-down');
|
|
refresh = false;
|
|
return;
|
|
}
|
|
}
|
|
function handleTouchEnd(e) {
|
|
if (e.type === 'touchend' && e.changedTouches && e.changedTouches.length > 0 && touchId) {
|
|
if (e.changedTouches[0].identifier !== touchId) return;
|
|
}
|
|
if (!isTouched || !isMoved) {
|
|
isTouched = false;
|
|
isMoved = false;
|
|
return;
|
|
}
|
|
if (translate) {
|
|
container.addClass('transitioning');
|
|
translate = 0;
|
|
}
|
|
container.transform('');
|
|
if (refresh) {
|
|
container.addClass('refreshing');
|
|
container.trigger('refresh', {
|
|
done: function () {
|
|
app.pullToRefreshDone(container);
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
container.removeClass('pull-down');
|
|
}
|
|
isTouched = false;
|
|
isMoved = false;
|
|
if (pullStarted) container.trigger('pullend');
|
|
}
|
|
|
|
// Attach Events
|
|
var passiveListener = app.touchEvents.start === 'touchstart' && app.support.passiveListener ? {passive: true, capture: false} : false;
|
|
eventsTarget.on(app.touchEvents.start, handleTouchStart, passiveListener);
|
|
eventsTarget.on(app.touchEvents.move, handleTouchMove);
|
|
eventsTarget.on(app.touchEvents.end, handleTouchEnd, passiveListener);
|
|
|
|
// Detach Events on page remove
|
|
if (page.length === 0) return;
|
|
function destroyPullToRefresh() {
|
|
eventsTarget.off(app.touchEvents.start, handleTouchStart);
|
|
eventsTarget.off(app.touchEvents.move, handleTouchMove);
|
|
eventsTarget.off(app.touchEvents.end, handleTouchEnd);
|
|
}
|
|
eventsTarget[0].f7DestroyPullToRefresh = destroyPullToRefresh;
|
|
function detachEvents() {
|
|
destroyPullToRefresh();
|
|
page.off('pageBeforeRemove', detachEvents);
|
|
}
|
|
page.on('pageBeforeRemove', detachEvents);
|
|
|
|
};
|
|
|
|
app.pullToRefreshDone = function (container) {
|
|
container = $(container);
|
|
if (container.length === 0) container = $('.pull-to-refresh-content.refreshing');
|
|
container.removeClass('refreshing').addClass('transitioning');
|
|
container.transitionEnd(function () {
|
|
container.removeClass('transitioning pull-up pull-down');
|
|
container.trigger('refreshdone');
|
|
});
|
|
};
|
|
app.pullToRefreshTrigger = function (container) {
|
|
container = $(container);
|
|
if (container.length === 0) container = $('.pull-to-refresh-content');
|
|
if (container.hasClass('refreshing')) return;
|
|
container.addClass('transitioning refreshing');
|
|
container.trigger('refresh', {
|
|
done: function () {
|
|
app.pullToRefreshDone(container);
|
|
}
|
|
});
|
|
};
|
|
|
|
app.destroyPullToRefresh = function (pageContainer) {
|
|
pageContainer = $(pageContainer);
|
|
var pullToRefreshContent = pageContainer.hasClass('pull-to-refresh-content') ? pageContainer : pageContainer.find('.pull-to-refresh-content');
|
|
if (pullToRefreshContent.length === 0) return;
|
|
if (pullToRefreshContent[0].f7DestroyPullToRefresh) pullToRefreshContent[0].f7DestroyPullToRefresh();
|
|
};
|