framework7
Version:
Full featured mobile HTML framework for building iOS & Android apps
615 lines (501 loc) • 19.6 kB
JavaScript
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
import $ from '../../shared/dom7';
import { deleteProps } from '../../shared/utils';
import Framework7Class from '../../shared/class';
import { getSupport } from '../../shared/get-support';
import { getDevice } from '../../shared/get-device';
var PullToRefresh = /*#__PURE__*/function (_Framework7Class) {
_inheritsLoose(PullToRefresh, _Framework7Class);
function PullToRefresh(app, el) {
var _this;
_this = _Framework7Class.call(this, {}, [app]) || this;
var ptr = _assertThisInitialized(_this);
var device = getDevice();
var support = getSupport();
var $el = $(el);
var $preloaderEl = $el.find('.ptr-preloader');
ptr.$el = $el;
ptr.el = $el[0];
ptr.app = app;
ptr.bottom = ptr.$el.hasClass('ptr-bottom'); // Extend defaults with modules params
ptr.useModulesParams({});
var isMaterial = app.theme === 'md';
var isIos = app.theme === 'ios';
var isAurora = app.theme === 'aurora'; // Done
ptr.done = function done() {
var $transitionTarget = isMaterial ? $preloaderEl : $el;
var onTranstionEnd = function onTranstionEnd(e) {
if ($(e.target).closest($preloaderEl).length) return;
$el.removeClass('ptr-transitioning ptr-pull-up ptr-pull-down ptr-closing');
$el.trigger('ptr:done');
ptr.emit('local::done ptrDone', $el[0]);
$transitionTarget.off('transitionend', onTranstionEnd);
};
$transitionTarget.on('transitionend', onTranstionEnd);
$el.removeClass('ptr-refreshing').addClass('ptr-transitioning ptr-closing');
return ptr;
};
ptr.refresh = function refresh() {
if ($el.hasClass('ptr-refreshing')) return ptr;
$el.addClass('ptr-transitioning ptr-refreshing');
$el.trigger('ptr:refresh', ptr.done);
ptr.emit('local::refresh ptrRefresh', $el[0], ptr.done);
return ptr;
}; // Mousewheel
ptr.mousewheel = $el.attr('data-ptr-mousewheel') === 'true'; // Events handling
var touchId;
var isTouched;
var isMoved;
var touchesStart = {};
var isScrolling;
var touchesDiff;
var refresh = false;
var useTranslate = false;
var forceUseTranslate = false;
var startTranslate = 0;
var translate;
var scrollTop;
var wasScrolled;
var triggerDistance;
var dynamicTriggerDistance;
var pullStarted;
var hasNavbar = false;
var scrollHeight;
var offsetHeight;
var maxScrollTop;
var $pageEl = $el.parents('.page');
if ($pageEl.find('.navbar').length > 0 || $pageEl.parents('.view').children('.navbars').length > 0) hasNavbar = true;
if ($pageEl.hasClass('no-navbar')) hasNavbar = false;
if (!ptr.bottom) {
var pageNavbarEl = app.navbar.getElByPage($pageEl[0]);
if (pageNavbarEl) {
var $pageNavbarEl = $(pageNavbarEl);
var isLargeTransparent = $pageNavbarEl.hasClass('navbar-large-transparent') || $pageNavbarEl.hasClass('navbar-large') && $pageNavbarEl.hasClass('navbar-transparent');
var isTransparent = $pageNavbarEl.hasClass('navbar-transparent') && !$pageNavbarEl.hasClass('navbar-large');
if (isLargeTransparent) {
$el.addClass('ptr-with-navbar-large-transparent');
} else if (isTransparent) {
$el.addClass('ptr-with-navbar-transparent');
}
}
}
if (!hasNavbar && !ptr.bottom) $el.addClass('ptr-no-navbar'); // Define trigger distance
if ($el.attr('data-ptr-distance')) {
dynamicTriggerDistance = true;
} else if (isMaterial) {
triggerDistance = 66;
} else if (isIos) {
triggerDistance = 44;
} else if (isAurora) {
triggerDistance = 38;
}
function setPreloaderProgress(progress) {
if (progress === void 0) {
progress = 0;
}
var $bars = $preloaderEl.find('.preloader-inner-line');
var perBarProgress = 1 / $bars.length;
$bars.forEach(function (barEl, barIndex) {
var barProgress = (progress - barIndex * perBarProgress) / perBarProgress;
barEl.style.opacity = Math.max(Math.min(barProgress, 1), 0) * 0.27;
});
}
function unsetPreloaderProgress() {
$preloaderEl.find('.preloader-inner-line').css('opacity', '');
}
function handleTouchStart(e) {
if (isTouched) {
if (device.os === 'android') {
if ('targetTouches' in e && e.targetTouches.length > 1) return;
} else return;
}
if ($el.hasClass('ptr-refreshing')) {
return;
}
if ($(e.target).closest('.sortable-handler, .ptr-ignore, .card-expandable.card-opened').length) 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;
}
function handleTouchMove(e) {
if (!isTouched) return;
var pageX;
var pageY;
var touch;
if (e.type === 'touchmove') {
if (touchId && e.touches) {
for (var i = 0; i < e.touches.length; i += 1) {
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 = $el[0].scrollTop;
if (!isMoved) {
$el.removeClass('ptr-transitioning');
if (isIos) {
setPreloaderProgress(0);
}
var targetIsScrollable;
scrollHeight = $el[0].scrollHeight;
offsetHeight = $el[0].offsetHeight;
if (ptr.bottom) {
maxScrollTop = scrollHeight - offsetHeight;
}
if (scrollTop > scrollHeight) {
isTouched = false;
return;
}
var $ptrWatchScrollable = $(e.target).closest('.ptr-watch-scroll');
if ($ptrWatchScrollable.length) {
$ptrWatchScrollable.each(function (ptrScrollableEl) {
if (ptrScrollableEl === el) return;
if (ptrScrollableEl.scrollHeight > ptrScrollableEl.offsetHeight && $(ptrScrollableEl).css('overflow') === 'auto' && (!ptr.bottom && ptrScrollableEl.scrollTop > 0 || ptr.bottom && ptrScrollableEl.scrollTop < ptrScrollableEl.scrollHeight - ptrScrollableEl.offsetHeight)) {
targetIsScrollable = true;
}
});
}
if (targetIsScrollable) {
isTouched = false;
return;
}
if (dynamicTriggerDistance) {
triggerDistance = $el.attr('data-ptr-distance');
if (triggerDistance.indexOf('%') >= 0) triggerDistance = scrollHeight * parseInt(triggerDistance, 10) / 100;
}
startTranslate = $el.hasClass('ptr-refreshing') ? triggerDistance : 0;
if (scrollHeight === offsetHeight || device.os !== 'ios' || isMaterial) {
useTranslate = true;
} else {
useTranslate = false;
}
forceUseTranslate = false;
}
isMoved = true;
touchesDiff = pageY - touchesStart.y;
if (typeof wasScrolled === 'undefined' && (ptr.bottom ? scrollTop !== maxScrollTop : scrollTop !== 0)) wasScrolled = true;
var ptrStarted = ptr.bottom ? touchesDiff < 0 && scrollTop >= maxScrollTop || scrollTop > maxScrollTop : touchesDiff > 0 && scrollTop <= 0 || scrollTop < 0;
if (ptrStarted) {
// iOS 8 fix
if (device.os === 'ios' && parseInt(device.osVersion.split('.')[0], 10) > 7) {
if (!ptr.bottom && scrollTop === 0 && !wasScrolled) useTranslate = true;
if (ptr.bottom && scrollTop === maxScrollTop && !wasScrolled) useTranslate = true;
}
if (!useTranslate && ptr.bottom && !isMaterial) {
$el.css('-webkit-overflow-scrolling', 'auto');
$el.scrollTop(maxScrollTop);
forceUseTranslate = true;
}
if (useTranslate || forceUseTranslate) {
if (e.cancelable) {
e.preventDefault();
}
translate = (ptr.bottom ? -1 * Math.pow(Math.abs(touchesDiff), 0.85) : Math.pow(touchesDiff, 0.85)) + startTranslate;
if (isMaterial) {
$preloaderEl.transform("translate3d(0," + translate + "px,0)").find('.ptr-arrow').transform("rotate(" + (180 * (Math.abs(touchesDiff) / 66) + 100) + "deg)");
} else {
// eslint-disable-next-line
if (ptr.bottom || isIos) {
$el.children().transform("translate3d(0," + translate + "px,0)");
} else {
// eslint-disable-next-line
$el.transform("translate3d(0," + translate + "px,0)");
}
if (isIos) {
$preloaderEl.transform("translate3d(0,0px,0)");
}
}
} else if (isIos && !ptr.bottom) {
$preloaderEl.transform("translate3d(0," + scrollTop + "px,0)");
}
var progress;
if (isIos && !refresh) {
progress = useTranslate || forceUseTranslate ? Math.pow(Math.abs(touchesDiff), 0.85) / triggerDistance : Math.abs(touchesDiff) / (triggerDistance * 2);
setPreloaderProgress(progress);
}
if ((useTranslate || forceUseTranslate) && Math.pow(Math.abs(touchesDiff), 0.85) > triggerDistance || !useTranslate && Math.abs(touchesDiff) >= triggerDistance * 2) {
refresh = true;
$el.addClass('ptr-pull-up').removeClass('ptr-pull-down');
unsetPreloaderProgress();
} else {
refresh = false;
$el.removeClass('ptr-pull-up').addClass('ptr-pull-down');
}
if (!pullStarted) {
$el.trigger('ptr:pullstart');
ptr.emit('local::pullStart ptrPullStart', $el[0]);
pullStarted = true;
}
$el.trigger('ptr:pullmove', {
event: e,
scrollTop: scrollTop,
translate: translate,
touchesDiff: touchesDiff
});
ptr.emit('local::pullMove ptrPullMove', $el[0], {
event: e,
scrollTop: scrollTop,
translate: translate,
touchesDiff: touchesDiff
});
} else {
pullStarted = false;
$el.removeClass('ptr-pull-up ptr-pull-down');
refresh = false;
}
}
function handleTouchEnd(e) {
if (e.type === 'touchend' && e.changedTouches && e.changedTouches.length > 0 && touchId) {
if (e.changedTouches[0].identifier !== touchId) {
isTouched = false;
isScrolling = false;
isMoved = false;
touchId = null;
return;
}
}
if (!isTouched || !isMoved) {
isTouched = false;
isMoved = false;
return;
}
if (translate) {
$el.addClass('ptr-transitioning');
translate = 0;
}
if (isMaterial) {
$preloaderEl.transform('').find('.ptr-arrow').transform('');
} else {
$preloaderEl.transform('');
if (ptr.bottom || isIos) {
$el.children().transform('');
} else {
$el.transform('');
}
}
if (!useTranslate && ptr.bottom && !isMaterial) {
$el.css('-webkit-overflow-scrolling', '');
}
if (refresh) {
$el.addClass('ptr-refreshing');
$el.trigger('ptr:refresh', ptr.done);
ptr.emit('local::refresh ptrRefresh', $el[0], ptr.done);
} else {
$el.removeClass('ptr-pull-down');
}
isTouched = false;
isMoved = false;
if (pullStarted) {
$el.trigger('ptr:pullend');
ptr.emit('local::pullEnd ptrPullEnd', $el[0]);
}
}
var mousewheelTimeout;
var mousewheelMoved;
var mousewheelAllow = true;
var mousewheelTranslate = 0;
function handleMouseWheelRelease() {
mousewheelAllow = true;
mousewheelMoved = false;
mousewheelTranslate = 0;
if (translate) {
$el.addClass('ptr-transitioning');
translate = 0;
}
if (isMaterial) {
$preloaderEl.transform('').find('.ptr-arrow').transform('');
} else {
$preloaderEl.transform('');
if (ptr.bottom) {
$el.children().transform('');
} else {
$el.transform('');
}
}
if (refresh) {
$el.addClass('ptr-refreshing');
$el.trigger('ptr:refresh', ptr.done);
ptr.emit('local::refresh ptrRefresh', $el[0], ptr.done);
} else {
$el.removeClass('ptr-pull-down');
}
if (pullStarted) {
$el.trigger('ptr:pullend');
ptr.emit('local::pullEnd ptrPullEnd', $el[0]);
}
}
function handleMouseWheel(e) {
if (!mousewheelAllow) return;
var deltaX = e.deltaX,
deltaY = e.deltaY;
if (Math.abs(deltaX) > Math.abs(deltaY)) return;
if ($el.hasClass('ptr-refreshing')) {
return;
}
if ($(e.target).closest('.sortable-handler, .ptr-ignore, .card-expandable.card-opened').length) return;
clearTimeout(mousewheelTimeout);
scrollTop = $el[0].scrollTop;
if (!mousewheelMoved) {
$el.removeClass('ptr-transitioning');
if (isIos) {
setPreloaderProgress(0);
}
var targetIsScrollable;
scrollHeight = $el[0].scrollHeight;
offsetHeight = $el[0].offsetHeight;
if (ptr.bottom) {
maxScrollTop = scrollHeight - offsetHeight;
}
if (scrollTop > scrollHeight) {
mousewheelAllow = false;
return;
}
var $ptrWatchScrollable = $(e.target).closest('.ptr-watch-scroll');
if ($ptrWatchScrollable.length) {
$ptrWatchScrollable.each(function (ptrScrollableEl) {
if (ptrScrollableEl === el) return;
if (ptrScrollableEl.scrollHeight > ptrScrollableEl.offsetHeight && $(ptrScrollableEl).css('overflow') === 'auto' && (!ptr.bottom && ptrScrollableEl.scrollTop > 0 || ptr.bottom && ptrScrollableEl.scrollTop < ptrScrollableEl.scrollHeight - ptrScrollableEl.offsetHeight)) {
targetIsScrollable = true;
}
});
}
if (targetIsScrollable) {
mousewheelAllow = false;
return;
}
if (dynamicTriggerDistance) {
triggerDistance = $el.attr('data-ptr-distance');
if (triggerDistance.indexOf('%') >= 0) triggerDistance = scrollHeight * parseInt(triggerDistance, 10) / 100;
}
}
isMoved = true;
mousewheelTranslate -= deltaY;
touchesDiff = mousewheelTranslate; // pageY - touchesStart.y;
if (typeof wasScrolled === 'undefined' && (ptr.bottom ? scrollTop !== maxScrollTop : scrollTop !== 0)) wasScrolled = true;
var ptrStarted = ptr.bottom ? touchesDiff < 0 && scrollTop >= maxScrollTop || scrollTop > maxScrollTop : touchesDiff > 0 && scrollTop <= 0 || scrollTop < 0;
if (ptrStarted) {
if (e.cancelable) {
e.preventDefault();
}
translate = touchesDiff;
if (Math.abs(translate) > triggerDistance) {
translate = triggerDistance + Math.pow(Math.abs(translate) - triggerDistance, 0.7);
if (ptr.bottom) translate = -translate;
}
if (isMaterial) {
$preloaderEl.transform("translate3d(0," + translate + "px,0)").find('.ptr-arrow').transform("rotate(" + (180 * (Math.abs(touchesDiff) / 66) + 100) + "deg)");
} else {
// eslint-disable-next-line
if (ptr.bottom) {
$el.children().transform("translate3d(0," + translate + "px,0)");
} else {
$el.transform("translate3d(0," + translate + "px,0)");
if (isIos) {
$preloaderEl.transform("translate3d(0," + -translate + "px,0)");
}
}
}
var progress;
if (isIos && !refresh) {
progress = Math.abs(translate) / triggerDistance;
setPreloaderProgress(progress);
}
if (Math.abs(translate) > triggerDistance) {
refresh = true;
$el.addClass('ptr-pull-up').removeClass('ptr-pull-down');
unsetPreloaderProgress();
} else {
refresh = false;
$el.removeClass('ptr-pull-up').addClass('ptr-pull-down');
}
if (!pullStarted) {
$el.trigger('ptr:pullstart');
ptr.emit('local::pullStart ptrPullStart', $el[0]);
pullStarted = true;
}
$el.trigger('ptr:pullmove', {
event: e,
scrollTop: scrollTop,
translate: translate,
touchesDiff: touchesDiff
});
ptr.emit('local::pullMove ptrPullMove', $el[0], {
event: e,
scrollTop: scrollTop,
translate: translate,
touchesDiff: touchesDiff
});
} else {
pullStarted = false;
$el.removeClass('ptr-pull-up ptr-pull-down');
refresh = false;
}
mousewheelTimeout = setTimeout(handleMouseWheelRelease, 300);
}
if (!$pageEl.length || !$el.length) return ptr || _assertThisInitialized(_this);
$el[0].f7PullToRefresh = ptr; // Events
ptr.attachEvents = function attachEvents() {
var passive = support.passiveListener ? {
passive: true
} : false;
$el.on(app.touchEvents.start, handleTouchStart, passive);
app.on('touchmove:active', handleTouchMove);
app.on('touchend:passive', handleTouchEnd);
if (ptr.mousewheel && !ptr.bottom) {
$el.on('wheel', handleMouseWheel);
}
};
ptr.detachEvents = function detachEvents() {
var passive = support.passiveListener ? {
passive: true
} : false;
$el.off(app.touchEvents.start, handleTouchStart, passive);
app.off('touchmove:active', handleTouchMove);
app.off('touchend:passive', handleTouchEnd);
if (ptr.mousewheel && !ptr.bottom) {
$el.off('wheel', handleMouseWheel);
}
}; // Install Modules
ptr.useModules(); // Init
ptr.init();
return ptr || _assertThisInitialized(_this);
}
var _proto = PullToRefresh.prototype;
_proto.init = function init() {
var ptr = this;
ptr.attachEvents();
};
_proto.destroy = function destroy() {
var ptr = this;
ptr.emit('local::beforeDestroy ptrBeforeDestroy', ptr);
ptr.$el.trigger('ptr:beforedestroy');
delete ptr.el.f7PullToRefresh;
ptr.detachEvents();
deleteProps(ptr);
ptr = null;
};
return PullToRefresh;
}(Framework7Class);
export default PullToRefresh;