framework7-vue
Version:
Build full featured iOS & Android apps using Framework7 & Vue
1,045 lines (963 loc) • 814 kB
JavaScript
/**
* Framework7 1.5.2
* Full featured mobile HTML framework for building iOS & Android apps
*
* http://framework7.io/
*
* Copyright 2016, Vladimir Kharlampidi
* The iDangero.us
* http://www.idangero.us/
*
* Licensed under MIT
*
* Released on: December 17, 2016
*/
(function () {
'use strict';
/*===========================
Framework 7
===========================*/
window.Framework7 = function (params) {
// App
var app = this;
// Version
app.version = '1.5.0';
// Default Parameters
app.params = {
//
root: 'body',
//
cache: true,
cacheIgnore: [],
cacheIgnoreGetParameters: false,
cacheDuration: 1000 * 60 * 10, // Ten minutes
preloadPreviousPage: true,
uniqueHistory: false,
uniqueHistoryIgnoreGetParameters: false,
dynamicPageUrl: 'content-{{index}}',
allowDuplicateUrls: false,
router: true,
routerRemoveTimeout: false,
routerRemoveWithTimeout: false,
// Push State
pushState: false,
pushStateRoot: undefined,
pushStateNoAnimation: false,
pushStateSeparator: '#!/',
pushStateOnLoad: true,
// Fast clicks
fastClicks: true,
fastClicksDistanceThreshold: 10,
fastClicksDelayBetweenClicks: 50,
fastClicksExclude: '', // CSS selector
// Tap Hold
tapHold: false,
tapHoldDelay: 750,
tapHoldPreventClicks: true,
// Active State
activeState: true,
activeStateElements: 'a, button, label, span',
// Animate Nav Back Icon
animateNavBackIcon: false,
// Swipe Back
swipeBackPage: true,
swipeBackPageThreshold: 0,
swipeBackPageActiveArea: 30,
swipeBackPageAnimateShadow: true,
swipeBackPageAnimateOpacity: true,
// Ajax
ajaxLinks: undefined, // or CSS selector
// External Links
externalLinks: '.external', // CSS selector
// Sortable
sortable: true,
// Scroll toolbars
hideNavbarOnPageScroll: false,
hideToolbarOnPageScroll: false,
hideTabbarOnPageScroll: false,
showBarsOnPageScrollEnd: true,
showBarsOnPageScrollTop: true,
// Swipeout
swipeout: true,
swipeoutActionsNoFold: false,
swipeoutNoFollow: false,
swipeoutRemoveWithTimeout: false,
// Smart Select Back link template
smartSelectOpenIn: 'page', // or 'popup' or 'picker'
smartSelectBackText: 'Back',
smartSelectPopupCloseText: 'Close',
smartSelectPickerCloseText: 'Done',
smartSelectSearchbar: false,
smartSelectBackOnSelect: false,
// Tap Navbar or Statusbar to scroll to top
scrollTopOnNavbarClick: false,
scrollTopOnStatusbarClick: false,
// Panels
swipePanel: false, // or 'left' or 'right'
swipePanelActiveArea: 0,
swipePanelCloseOpposite: true,
swipePanelOnlyClose: false,
swipePanelNoFollow: false,
swipePanelThreshold: 0,
panelsCloseByOutside: true,
// Modals
modalButtonOk: 'OK',
modalButtonCancel: 'Cancel',
modalUsernamePlaceholder: 'Username',
modalPasswordPlaceholder: 'Password',
modalTitle: 'Framework7',
modalCloseByOutside: false,
actionsCloseByOutside: true,
popupCloseByOutside: true,
modalPreloaderTitle: 'Loading... ',
modalStack: true,
// Lazy Load
imagesLazyLoadThreshold: 0,
imagesLazyLoadSequential: true,
// Name space
viewClass: 'view',
viewMainClass: 'view-main',
viewsClass: 'views',
// Notifications defaults
notificationCloseOnClick: false,
notificationCloseIcon: true,
notificationCloseButtonText: 'Close',
// Animate Pages
animatePages: true,
// Template7
templates: {},
template7Data: {},
template7Pages: false,
precompileTemplates: false,
// Material
material: false,
materialPageLoadDelay: 0,
materialPreloaderSvg: '<svg xmlns="http://www.w3.org/2000/svg" height="75" width="75" viewbox="0 0 75 75"><circle cx="37.5" cy="37.5" r="33.5" stroke-width="8"/></svg>',
materialPreloaderHtml:
'<span class="preloader-inner">' +
'<span class="preloader-inner-gap"></span>' +
'<span class="preloader-inner-left">' +
'<span class="preloader-inner-half-circle"></span>' +
'</span>' +
'<span class="preloader-inner-right">' +
'<span class="preloader-inner-half-circle"></span>' +
'</span>' +
'</span>',
materialRipple: true,
materialRippleElements: '.ripple, a.link, a.item-link, .button, .modal-button, .tab-link, .label-radio, .label-checkbox, .actions-modal-button, a.searchbar-clear, a.floating-button, .floating-button > a, .speed-dial-buttons a',
// Auto init
init: true,
};
// Extend defaults with parameters
for (var param in params) {
app.params[param] = params[param];
}
// DOM lib
var $ = Dom7;
// Template7 lib
var t7 = Template7;
app._compiledTemplates = {};
// App Root
app.root = $(app.params.root);
app.root.eq(0).addClass('framework7-root');
// Touch events
app.touchEvents = {
start: app.support.touch ? 'touchstart' : 'mousedown',
move: app.support.touch ? 'touchmove' : 'mousemove',
end: app.support.touch ? 'touchend' : 'mouseup'
};
// Link to local storage
app.ls = window.localStorage;
// RTL
app.rtl = $('body').css('direction') === 'rtl';
if (app.rtl) $('html').attr('dir', 'rtl');
// Overwrite statusbar overlay
if (typeof app.params.statusbarOverlay !== 'undefined') {
if (app.params.statusbarOverlay) $('html').addClass('with-statusbar-overlay');
else $('html').removeClass('with-statusbar-overlay');
}
else if (app.device.ios && (window.cordova || window.phonegap)) {
$(document).on('resume', function () {
if (app.device.needsStatusBar()) {
$('html').addClass('with-statusbar-overlay');
}
}, false);
}
/*======================================================
************ Views ************
======================================================*/
app.views = [];
var View = function (selector, params) {
var defaults = {
dynamicNavbar: false,
domCache: false,
linksView: undefined,
reloadPages: false,
uniqueHistory: app.params.uniqueHistory,
uniqueHistoryIgnoreGetParameters: app.params.uniqueHistoryIgnoreGetParameters,
allowDuplicateUrls: app.params.allowDuplicateUrls,
swipeBackPage: app.params.swipeBackPage,
swipeBackPageAnimateShadow: app.params.swipeBackPageAnimateShadow,
swipeBackPageAnimateOpacity: app.params.swipeBackPageAnimateOpacity,
swipeBackPageActiveArea: app.params.swipeBackPageActiveArea,
swipeBackPageThreshold: app.params.swipeBackPageThreshold,
animatePages: app.params.animatePages,
preloadPreviousPage: app.params.preloadPreviousPage
};
var i;
// Params
params = params || {};
// Disable dynamic navbar for material theme
if (params.dynamicNavbar && app.params.material) params.dynamicNavbar = false;
// Extend params with defaults
for (var def in defaults) {
if (typeof params[def] === 'undefined') {
params[def] = defaults[def];
}
}
// View
var view = this;
view.params = params;
// Selector
view.selector = selector;
// Container
var container = $(selector);
view.container = container[0];
// Fix Selector
if (typeof selector !== 'string') {
// Supposed to be HTMLElement or Dom7
selector = (container.attr('id') ? '#' + container.attr('id') : '') + (container.attr('class') ? '.' + container.attr('class').replace(/ /g, '.').replace('.active', '') : '');
view.selector = selector;
}
// Is main
view.main = container.hasClass(app.params.viewMainClass);
// Content cache
view.contentCache = {};
// Context cache
view.contextCache = {};
// Pages cache
view.pagesCache = {};
view.pageElementsCache = {};
// Store View in element for easy access
container[0].f7View = view;
// Pages
view.pagesContainer = container.find('.pages')[0];
view.initialPages = [];
view.initialPagesUrl = [];
view.initialNavbars = [];
if (view.params.domCache) {
var initialPages = container.find('.page');
for (i = 0; i < initialPages.length; i++) {
view.initialPages.push(initialPages[i]);
view.initialPagesUrl.push('#' + initialPages.eq(i).attr('data-page'));
}
if (view.params.dynamicNavbar) {
var initialNavbars = container.find('.navbar-inner');
for (i = 0; i < initialNavbars.length; i++) {
view.initialNavbars.push(initialNavbars[i]);
}
}
}
view.allowPageChange = true;
// Location
var docLocation = document.location.href;
// History
view.history = [];
var viewURL = docLocation;
var pushStateSeparator = app.params.pushStateSeparator;
var pushStateRoot = app.params.pushStateRoot;
if (app.params.pushState && view.main) {
if (pushStateRoot) {
viewURL = pushStateRoot;
}
else {
if (pushStateSeparator && viewURL.indexOf(pushStateSeparator) >= 0 && viewURL.indexOf(pushStateSeparator + '#') < 0) viewURL = viewURL.split(pushStateSeparator)[0];
}
}
// Active Page
var currentPage, currentPageData;
if (!view.activePage) {
currentPage = $(view.pagesContainer).find('.page-on-center');
if (currentPage.length === 0) {
currentPage = $(view.pagesContainer).find('.page:not(.cached)');
currentPage = currentPage.eq(currentPage.length - 1);
}
if (currentPage.length > 0) {
currentPageData = currentPage[0].f7PageData;
}
}
// View startup URL
if (view.params.domCache && currentPage) {
view.url = container.attr('data-url') || view.params.url || '#' + currentPage.attr('data-page');
view.pagesCache[view.url] = currentPage.attr('data-page');
}
else view.url = container.attr('data-url') || view.params.url || viewURL;
// Update current page Data
if (currentPageData) {
currentPageData.view = view;
currentPageData.url = view.url;
if (view.params.domCache && view.params.dynamicNavbar && !currentPageData.navbarInnerContainer) {
currentPageData.navbarInnerContainer = view.initialNavbars[view.initialPages.indexOf(currentPageData.container)];
}
view.activePage = currentPageData;
currentPage[0].f7PageData = currentPageData;
}
// Store to history main view's url
if (view.url) {
view.history.push(view.url);
}
// Touch events
var isTouched = false,
isMoved = false,
touchesStart = {},
isScrolling,
activePage = [],
previousPage = [],
viewContainerWidth,
touchesDiff,
allowViewTouchMove = true,
touchStartTime,
activeNavbar = [],
previousNavbar = [],
activeNavElements,
previousNavElements,
activeNavBackIcon,
previousNavBackIcon,
dynamicNavbar,
pageShadow,
el;
view.handleTouchStart = function (e) {
if (!allowViewTouchMove || !view.params.swipeBackPage || isTouched || app.swipeoutOpenedEl || !view.allowPageChange) return;
isMoved = false;
isTouched = true;
isScrolling = undefined;
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();
dynamicNavbar = view.params.dynamicNavbar && container.find('.navbar-inner').length > 1;
};
view.handleTouchMove = function (e) {
if (!isTouched) return;
var pageX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
var pageY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
if (typeof isScrolling === 'undefined') {
isScrolling = !!(isScrolling || Math.abs(pageY - touchesStart.y) > Math.abs(pageX - touchesStart.x));
}
if (isScrolling || e.f7PreventSwipeBack || app.preventSwipeBack) {
isTouched = false;
return;
}
if (!isMoved) {
var cancel = false;
// Calc values during first move fired
viewContainerWidth = container.width();
var target = $(e.target);
var swipeout = target.hasClass('swipeout') ? target : target.parents('.swipeout');
if (swipeout.length > 0) {
if (!app.rtl && swipeout.find('.swipeout-actions-left').length > 0) cancel = true;
if (app.rtl && swipeout.find('.swipeout-actions-right').length > 0) cancel = true;
}
activePage = target.is('.page') ? target : target.parents('.page');
if (activePage.hasClass('no-swipeback')) cancel = true;
previousPage = container.find('.page-on-left:not(.cached)');
var notFromBorder = touchesStart.x - container.offset().left > view.params.swipeBackPageActiveArea;
if (app.rtl) {
notFromBorder = touchesStart.x < container.offset().left - container[0].scrollLeft + viewContainerWidth - view.params.swipeBackPageActiveArea;
}
else {
notFromBorder = touchesStart.x - container.offset().left > view.params.swipeBackPageActiveArea;
}
if (notFromBorder) cancel = true;
if (previousPage.length === 0 || activePage.length === 0) cancel = true;
if (cancel) {
isTouched = false;
return;
}
if (view.params.swipeBackPageAnimateShadow && !app.device.android) {
pageShadow = activePage.find('.swipeback-page-shadow');
if (pageShadow.length === 0) {
pageShadow = $('<div class="swipeback-page-shadow"></div>');
activePage.append(pageShadow);
}
}
if (dynamicNavbar) {
activeNavbar = container.find('.navbar-on-center:not(.cached)');
previousNavbar = container.find('.navbar-on-left:not(.cached)');
activeNavElements = activeNavbar.find('.left, .center, .right, .subnavbar, .fading');
previousNavElements = previousNavbar.find('.left, .center, .right, .subnavbar, .fading');
if (app.params.animateNavBackIcon) {
activeNavBackIcon = activeNavbar.find('.left.sliding .back .icon');
previousNavBackIcon = previousNavbar.find('.left.sliding .back .icon');
}
}
// Close/Hide Any Picker
if ($('.picker-modal.modal-in').length > 0) {
app.closeModal($('.picker-modal.modal-in'));
}
}
e.f7PreventPanelSwipe = true;
isMoved = true;
e.preventDefault();
// RTL inverter
var inverter = app.rtl ? -1 : 1;
// Touches diff
touchesDiff = (pageX - touchesStart.x - view.params.swipeBackPageThreshold) * inverter;
if (touchesDiff < 0) touchesDiff = 0;
var percentage = touchesDiff / viewContainerWidth;
// Swipe Back Callback
var callbackData = {
percentage: percentage,
activePage: activePage[0],
previousPage: previousPage[0],
activeNavbar: activeNavbar[0],
previousNavbar: previousNavbar[0]
};
if (view.params.onSwipeBackMove) {
view.params.onSwipeBackMove(callbackData);
}
container.trigger('swipeBackMove swipeback:move', callbackData);
// Transform pages
var activePageTranslate = touchesDiff * inverter;
var previousPageTranslate = (touchesDiff / 5 - viewContainerWidth / 5) * inverter;
if (app.device.pixelRatio === 1) {
activePageTranslate = Math.round(activePageTranslate);
previousPageTranslate = Math.round(previousPageTranslate);
}
activePage.transform('translate3d(' + activePageTranslate + 'px,0,0)');
if (view.params.swipeBackPageAnimateShadow && !app.device.android) pageShadow[0].style.opacity = 1 - 1 * percentage;
previousPage.transform('translate3d(' + previousPageTranslate + 'px,0,0)');
if (view.params.swipeBackPageAnimateOpacity) previousPage[0].style.opacity = 0.9 + 0.1 * percentage;
// Dynamic Navbars Animation
if (dynamicNavbar) {
var i;
for (i = 0; i < activeNavElements.length; i++) {
el = $(activeNavElements[i]);
if (!el.is('.subnavbar.sliding')) el[0].style.opacity = (1 - percentage * 1.3);
if (el[0].className.indexOf('sliding') >= 0) {
var activeNavTranslate = percentage * el[0].f7NavbarRightOffset;
if (app.device.pixelRatio === 1) activeNavTranslate = Math.round(activeNavTranslate);
el.transform('translate3d(' + activeNavTranslate + 'px,0,0)');
if (app.params.animateNavBackIcon) {
if (el[0].className.indexOf('left') >= 0 && activeNavBackIcon.length > 0) {
activeNavBackIcon.transform('translate3d(' + -activeNavTranslate + 'px,0,0)');
}
}
}
}
for (i = 0; i < previousNavElements.length; i++) {
el = $(previousNavElements[i]);
if (!el.is('.subnavbar.sliding')) el[0].style.opacity = percentage * 1.3 - 0.3;
if (el[0].className.indexOf('sliding') >= 0) {
var previousNavTranslate = el[0].f7NavbarLeftOffset * (1 - percentage);
if (app.device.pixelRatio === 1) previousNavTranslate = Math.round(previousNavTranslate);
el.transform('translate3d(' + previousNavTranslate + 'px,0,0)');
if (app.params.animateNavBackIcon) {
if (el[0].className.indexOf('left') >= 0 && previousNavBackIcon.length > 0) {
previousNavBackIcon.transform('translate3d(' + -previousNavTranslate + 'px,0,0)');
}
}
}
}
}
};
view.handleTouchEnd = function (e) {
if (!isTouched || !isMoved) {
isTouched = false;
isMoved = false;
return;
}
isTouched = false;
isMoved = false;
if (touchesDiff === 0) {
$([activePage[0], previousPage[0]]).transform('').css({opacity: '', boxShadow: ''});
if (dynamicNavbar) {
activeNavElements.transform('').css({opacity: ''});
previousNavElements.transform('').css({opacity: ''});
if (activeNavBackIcon && activeNavBackIcon.length > 0) activeNavBackIcon.transform('');
if (previousNavBackIcon && activeNavBackIcon.length > 0) previousNavBackIcon.transform('');
}
return;
}
var timeDiff = (new Date()).getTime() - touchStartTime;
var pageChanged = false;
// Swipe back to previous page
if (
timeDiff < 300 && touchesDiff > 10 ||
timeDiff >= 300 && touchesDiff > viewContainerWidth / 2
) {
activePage.removeClass('page-on-center').addClass('page-on-right');
previousPage.removeClass('page-on-left').addClass('page-on-center');
if (dynamicNavbar) {
activeNavbar.removeClass('navbar-on-center').addClass('navbar-on-right');
previousNavbar.removeClass('navbar-on-left').addClass('navbar-on-center');
}
pageChanged = true;
}
// Reset custom styles
// Add transitioning class for transition-duration
$([activePage[0], previousPage[0]]).transform('').css({opacity: '', boxShadow: ''}).addClass('page-transitioning');
if (dynamicNavbar) {
activeNavElements.css({opacity: ''})
.each(function () {
var translate = pageChanged ? this.f7NavbarRightOffset : 0;
var sliding = $(this);
sliding.transform('translate3d(' + translate + 'px,0,0)');
if (app.params.animateNavBackIcon) {
if (sliding.hasClass('left') && activeNavBackIcon.length > 0) {
activeNavBackIcon.addClass('page-transitioning').transform('translate3d(' + -translate + 'px,0,0)');
}
}
}).addClass('page-transitioning');
previousNavElements.transform('').css({opacity: ''}).each(function () {
var translate = pageChanged ? 0 : this.f7NavbarLeftOffset;
var sliding = $(this);
sliding.transform('translate3d(' + translate + 'px,0,0)');
if (app.params.animateNavBackIcon) {
if (sliding.hasClass('left') && previousNavBackIcon.length > 0) {
previousNavBackIcon.addClass('page-transitioning').transform('translate3d(' + -translate + 'px,0,0)');
}
}
}).addClass('page-transitioning');
}
allowViewTouchMove = false;
view.allowPageChange = false;
// Swipe Back Callback
var callbackData = {
activePage: activePage[0],
previousPage: previousPage[0],
activeNavbar: activeNavbar[0],
previousNavbar: previousNavbar[0]
};
if (pageChanged) {
// Update View's URL
var url = view.history[view.history.length - 2];
view.url = url;
// Page before animation callback
app.pageBackCallback('before', view, {pageContainer: activePage[0], url: url, position: 'center', newPage: previousPage, oldPage: activePage, swipeBack: true});
app.pageAnimCallback('before', view, {pageContainer: previousPage[0], url: url, position: 'left', newPage: previousPage, oldPage: activePage, swipeBack: true});
if (view.params.onSwipeBackBeforeChange) {
view.params.onSwipeBackBeforeChange(callbackData);
}
container.trigger('swipeBackBeforeChange swipeback:beforechange', callbackData);
}
else {
if (view.params.onSwipeBackBeforeReset) {
view.params.onSwipeBackBeforeReset(callbackData);
}
container.trigger('swipeBackBeforeReset swipeback:beforereset', callbackData);
}
activePage.transitionEnd(function () {
$([activePage[0], previousPage[0]]).removeClass('page-transitioning');
if (dynamicNavbar) {
activeNavElements.removeClass('page-transitioning').css({opacity: ''});
previousNavElements.removeClass('page-transitioning').css({opacity: ''});
if (activeNavBackIcon && activeNavBackIcon.length > 0) activeNavBackIcon.removeClass('page-transitioning');
if (previousNavBackIcon && previousNavBackIcon.length > 0) previousNavBackIcon.removeClass('page-transitioning');
}
allowViewTouchMove = true;
view.allowPageChange = true;
if (pageChanged) {
if (app.params.pushState && view.main) history.back();
// Page after animation callback
app.pageBackCallback('after', view, {pageContainer: activePage[0], url: url, position: 'center', newPage: previousPage, oldPage: activePage, swipeBack: true});
app.pageAnimCallback('after', view, {pageContainer: previousPage[0], url: url, position: 'left', newPage: previousPage, oldPage: activePage, swipeBack: true});
app.router.afterBack(view, activePage, previousPage);
if (view.params.onSwipeBackAfterChange) {
view.params.onSwipeBackAfterChange(callbackData);
}
container.trigger('swipeBackAfterChange swipeback:afterchange', callbackData);
}
else {
if (view.params.onSwipeBackAfterReset) {
view.params.onSwipeBackAfterReset(callbackData);
}
container.trigger('swipeBackAfterReset swipeback:afterreset', callbackData);
}
if (pageShadow && pageShadow.length > 0) pageShadow.remove();
});
};
view.attachEvents = function (detach) {
var action = detach ? 'off' : 'on';
var passiveListener = app.touchEvents.start === 'touchstart' && app.support.passiveListener ? {passive: true, capture: false} : false;
container[action](app.touchEvents.start, view.handleTouchStart, passiveListener);
container[action](app.touchEvents.move, view.handleTouchMove);
container[action](app.touchEvents.end, view.handleTouchEnd, passiveListener);
};
view.detachEvents = function () {
view.attachEvents(true);
};
// Init
if (view.params.swipeBackPage && !app.params.material) {
view.attachEvents();
}
// Add view to app
app.views.push(view);
if (view.main) app.mainView = view;
// Router
view.router = {
load: function (options) {
return app.router.load(view, options);
},
back: function (options) {
return app.router.back(view, options);
},
// Shortcuts
loadPage: function (options) {
options = options || {};
if (typeof options === 'string') {
var url = options;
options = {};
if (url && url.indexOf('#') === 0 && view.params.domCache) {
options.pageName = url.split('#')[1];
}
else options.url = url;
}
return app.router.load(view, options);
},
loadContent: function (content) {
return app.router.load(view, {content: content});
},
reloadPage: function (url) {
return app.router.load(view, {url: url, reload: true});
},
reloadContent: function (content) {
return app.router.load(view, {content: content, reload: true});
},
reloadPreviousPage: function (url) {
return app.router.load(view, {url: url, reloadPrevious: true, reload: true});
},
reloadPreviousContent: function (content) {
return app.router.load(view, {content: content, reloadPrevious: true, reload: true});
},
refreshPage: function () {
var options = {
url: view.url,
reload: true,
ignoreCache: true
};
if (options.url && options.url.indexOf('#') === 0) {
if (view.params.domCache && view.pagesCache[options.url]) {
options.pageName = view.pagesCache[options.url];
options.url = undefined;
delete options.url;
}
else if (view.contentCache[options.url]) {
options.content = view.contentCache[options.url];
options.url = undefined;
delete options.url;
}
}
return app.router.load(view, options);
},
refreshPreviousPage: function () {
var options = {
url: view.history[view.history.length - 2],
reload: true,
reloadPrevious: true,
ignoreCache: true
};
if (options.url && options.url.indexOf('#') === 0 && view.params.domCache && view.pagesCache[options.url]) {
options.pageName = view.pagesCache[options.url];
options.url = undefined;
delete options.url;
}
return app.router.load(view, options);
}
};
// Aliases for temporary backward compatibility
view.loadPage = view.router.loadPage;
view.loadContent = view.router.loadContent;
view.reloadPage = view.router.reloadPage;
view.reloadContent = view.router.reloadContent;
view.reloadPreviousPage = view.router.reloadPreviousPage;
view.reloadPreviousContent = view.router.reloadPreviousContent;
view.refreshPage = view.router.refreshPage;
view.refreshPreviousPage = view.router.refreshPreviousPage;
view.back = view.router.back;
// Bars methods
view.hideNavbar = function () {
return app.hideNavbar(container.find('.navbar'));
};
view.showNavbar = function () {
return app.showNavbar(container.find('.navbar'));
};
view.hideToolbar = function () {
return app.hideToolbar(container.find('.toolbar'));
};
view.showToolbar = function () {
return app.showToolbar(container.find('.toolbar'));
};
// Push State on load
if (app.params.pushState && app.params.pushStateOnLoad && view.main) {
var pushStateUrl;
var pushStateUrlSplit = docLocation.split(pushStateSeparator)[1];
if (pushStateRoot) {
pushStateUrl = docLocation.split(app.params.pushStateRoot + pushStateSeparator)[1];
}
else if (pushStateSeparator && docLocation.indexOf(pushStateSeparator) >= 0 && docLocation.indexOf(pushStateSeparator + '#') < 0) {
pushStateUrl = pushStateUrlSplit;
}
var pushStateAnimatePages = app.params.pushStateNoAnimation ? false : undefined;
var historyState = history.state;
if (pushStateUrl) {
if (pushStateUrl.indexOf('#') >= 0 && view.params.domCache && historyState && historyState.pageName && 'viewIndex' in historyState) {
app.router.load(view, {pageName: historyState.pageName, url: historyState.url, animatePages: pushStateAnimatePages, pushState: false});
}
else if (pushStateUrl.indexOf('#') >= 0 && view.params.domCache && view.initialPagesUrl.indexOf(pushStateUrl) >= 0) {
app.router.load(view, {pageName: pushStateUrl.replace('#',''), animatePages: pushStateAnimatePages, pushState: false});
}
else app.router.load(view, {url: pushStateUrl, animatePages: pushStateAnimatePages, pushState: false});
}
else if (view.params.domCache && docLocation.indexOf(pushStateSeparator + '#') >= 0) {
if (historyState && historyState.pageName && 'viewIndex' in historyState) {
app.router.load(view, {pageName: historyState.pageName, url: historyState.url, animatePages: pushStateAnimatePages, pushState: false});
}
else if (pushStateSeparator && pushStateUrlSplit.indexOf('#') === 0) {
if (view.initialPagesUrl.indexOf(pushStateUrlSplit)) {
app.router.load(view, {pageName: pushStateUrlSplit.replace('#', ''), animatePages: pushStateAnimatePages, pushState: false});
}
}
}
}
// Destroy
view.destroy = function () {
view.detachEvents();
view = undefined;
};
// Plugin hook
app.pluginHook('addView', view);
// Return view
return view;
};
app.addView = function (selector, params) {
return new View(selector, params);
};
app.getCurrentView = function (index) {
var popoverView = $('.popover.modal-in .view');
var popupView = $('.popup.modal-in .view');
var panelView = $('.panel.active .view');
var appViews = $('.views');
// Find active view as tab
var appView = appViews.children('.view');
// Propably in tabs or split view
if (appView.length > 1) {
if (appView.hasClass('tab')) {
// Tabs
appView = appViews.children('.view.active');
}
else {
// Split View, leave appView intact
}
}
if (popoverView.length > 0 && popoverView[0].f7View) return popoverView[0].f7View;
if (popupView.length > 0 && popupView[0].f7View) return popupView[0].f7View;
if (panelView.length > 0 && panelView[0].f7View) return panelView[0].f7View;
if (appView.length > 0) {
if (appView.length === 1 && appView[0].f7View) return appView[0].f7View;
if (appView.length > 1) {
var currentViews = [];
for (var i = 0; i < appView.length; i++) {
if (appView[i].f7View) currentViews.push(appView[i].f7View);
}
if (currentViews.length > 0 && typeof index !== 'undefined') return currentViews[index];
if (currentViews.length > 1) return currentViews;
if (currentViews.length === 1) return currentViews[0];
return undefined;
}
}
return undefined;
};
/*======================================================
************ Navbars && Toolbars ************
======================================================*/
// On Navbar Init Callback
app.navbarInitCallback = function (view, pageContainer, navbarContainer, navbarInnerContainer) {
if (!navbarContainer && navbarInnerContainer) navbarContainer = $(navbarInnerContainer).parent('.navbar')[0];
if (!navbarInnerContainer || navbarInnerContainer.f7NavbarInitialized && view && !view.params.domCache) return;
var navbarData = {
container: navbarContainer,
innerContainer: navbarInnerContainer
};
var pageData = pageContainer && pageContainer.f7PageData;
var eventData = {
page: pageData,
navbar: navbarData
};
if (navbarInnerContainer.f7NavbarInitialized && ((view && view.params.domCache) || (!view && $(navbarContainer).parents('.popup, .popover, .login-screen, .modal, .actions-modal, .picker-modal').length > 0))) {
// Reinit Navbar
app.reinitNavbar(navbarContainer, navbarInnerContainer);
// Plugin hook
app.pluginHook('navbarReinit', eventData);
// Event
$(navbarInnerContainer).trigger('navbarReinit navbar:reinit', eventData);
return;
}
navbarInnerContainer.f7NavbarInitialized = true;
// Before Init
app.pluginHook('navbarBeforeInit', navbarData, pageData);
$(navbarInnerContainer).trigger('navbarBeforeInit navbar:beforeinit', eventData);
// Initialize Navbar
app.initNavbar(navbarContainer, navbarInnerContainer);
// On init
app.pluginHook('navbarInit', navbarData, pageData);
$(navbarInnerContainer).trigger('navbarInit navbar:init', eventData);
};
// Navbar Remove Callback
app.navbarRemoveCallback = function (view, pageContainer, navbarContainer, navbarInnerContainer) {
if (!navbarContainer && navbarInnerContainer) navbarContainer = $(navbarInnerContainer).parent('.navbar')[0];
var navbarData = {
container: navbarContainer,
innerContainer: navbarInnerContainer
};
var pageData;
if (pageContainer) {
pageData = pageContainer.f7PageData;
}
var eventData = {
page: pageData,
navbar: navbarData
};
app.pluginHook('navbarBeforeRemove', navbarData, pageData);
$(navbarInnerContainer).trigger('navbarBeforeRemove navbar:beforeremove', eventData);
navbarData = null;
pageData = null;
};
app.initNavbar = function (navbarContainer, navbarInnerContainer) {
// Init Subnavbar Searchbar
if (app.initSearchbar) app.initSearchbar(navbarInnerContainer);
};
app.reinitNavbar = function (navbarContainer, navbarInnerContainer) {
// Re init navbar methods
};
app.initNavbarWithCallback = function (navbarContainer) {
navbarContainer = $(navbarContainer);
var viewContainer = navbarContainer.parents('.' + app.params.viewClass);
var view;
if (viewContainer.length === 0) return;
if (navbarContainer.parents('.navbar-through').length === 0 && viewContainer.find('.navbar-through').length === 0) return;
view = viewContainer[0].f7View || undefined;
navbarContainer.find('.navbar-inner').each(function () {
var navbarInnerContainer = this;
var pageContainer;
if ($(navbarInnerContainer).attr('data-page')) {
// For dom cache
pageContainer = viewContainer.find('.page[data-page="' + $(navbarInnerContainer).attr('data-page') + '"]')[0];
}
if (!pageContainer) {
var pages = viewContainer.find('.page');
if (pages.length === 1) {
pageContainer = pages[0];
}
else {
viewContainer.find('.page').each(function () {
if (this.f7PageData && this.f7PageData.navbarInnerContainer === navbarInnerContainer) {
pageContainer = this;
}
});
}
}
app.navbarInitCallback(view, pageContainer, navbarContainer[0], navbarInnerContainer);
});
};
// Size Navbars
app.sizeNavbars = function (viewContainer) {
if (app.params.material) return;
var navbarInner = viewContainer ? $(viewContainer).find('.navbar .navbar-inner:not(.cached)') : $('.navbar .navbar-inner:not(.cached)');
navbarInner.each(function () {
var n = $(this);
if (n.hasClass('cached')) return;
var left = app.rtl ? n.find('.right') : n.find('.left'),
right = app.rtl ? n.find('.left') : n.find('.right'),
center = n.find('.center'),
subnavbar = n.find('.subnavbar'),
noLeft = left.length === 0,
noRight = right.length === 0,
leftWidth = noLeft ? 0 : left.outerWidth(true),
rightWidth = noRight ? 0 : right.outerWidth(true),
centerWidth = center.outerWidth(true),
navbarStyles = n.styles(),
navbarWidth = n[0].offsetWidth - parseInt(navbarStyles.paddingLeft, 10) - parseInt(navbarStyles.paddingRight, 10),
onLeft = n.hasClass('navbar-on-left'),
currLeft, diff;
if (noRight) {
currLeft = navbarWidth - centerWidth;
}
if (noLeft) {
currLeft = 0;
}
if (!noLeft && !noRight) {
currLeft = (navbarWidth - rightWidth - centerWidth + leftWidth) / 2;
}
var requiredLeft = (navbarWidth - centerWidth) / 2;
if (navbarWidth - leftWidth - rightWidth > centerWidth) {
if (requiredLeft < leftWidth) {
requiredLeft = leftWidth;
}
if (requiredLeft + centerWidth > navbarWidth - rightWidth) {
requiredLeft = navbarWidth - rightWidth - centerWidth;
}
diff = requiredLeft - currLeft;
}
else {
diff = 0;
}
// RTL inverter
var inverter = app.rtl ? -1 : 1;
if (center.hasClass('sliding')) {
center[0].f7NavbarLeftOffset = -(currLeft + diff) * inverter;
center[0].f7NavbarRightOffset = (navbarWidth - currLeft - diff - centerWidth) * inverter;
if (onLeft) {
if (app.params.animateNavBackIcon) {
var activeNavbarBackLink = n.parent().find('.navbar-on-center').find('.left.sliding .back .icon ~ span');
if (activeNavbarBackLink.length > 0) {
center[0].f7NavbarLeftOffset += activeNavbarBackLink[0].offsetLeft;
}
}
center.transform('translate3d(' + center[0].f7NavbarLeftOffset + 'px, 0, 0)');
}
}
if (!noLeft && left.hasClass('sliding')) {
if (app.rtl) {
left[0].f7NavbarLeftOffset = -(navbarWidth - left[0].offsetWidth) / 2 * inverter;
left[0].f7NavbarRightOffset = leftWidth * inverter;
}
else {
left[0].f7NavbarLeftOffset = -leftWidth;
left[0].f7NavbarRightOffset = (navbarWidth - left[0].offsetWidth) / 2;
if (app.params.animateNavBackIcon && left.find('.back .icon').length > 0) {
left[0].f7NavbarRightOffset -= left.find('.back .icon')[0].offsetWidth;
}
}
if (onLeft) left.transform('translate3d(' + left[0].f7NavbarLeftOffset + 'px, 0, 0)');
}
if (!noRight && right.hasClass('sliding')) {
if (app.rtl) {
right[0].f7NavbarLeftOffset = -rightWidth * inverter;
right[0].f7NavbarRightOffset = (navbarWidth - right[0].offsetWidth) / 2 * inverter;
}
else {
right[0].f7NavbarLeftOffset = -(navbarWidth - right[0].offsetWidth) / 2;
right[0].f7NavbarRightOffset = rightWidth;
}
if (onLeft) right.transform('translate3d(' + right[0].f7NavbarLeftOffset + 'px, 0, 0)');
}
if (subnavbar.length && subnavbar.hasClass('sliding')) {
subnavbar[0].f7NavbarLeftOffset = app.rtl ? subnavbar[0].offsetWidth : -subnavbar[0].offsetWidth;
subnavbar[0].f7NavbarRightOffset = -subnavbar[0].f7NavbarLeftOffset;
}
// Center left
var centerLeft = diff;
if (app.rtl && noLeft && noRight && center.length > 0) centerLeft = -centerLeft;
center.css({left: centerLeft + 'px'});
});
};
// Hide/Show Navbars/Toolbars
app.hideNavbar = function (navbarContainer) {
$(navbarContainer).addClass('navbar-hidden');
return true;
};
app.showNavbar = function (navbarContainer) {
var navbar = $(navbarContainer);
navbar.addClass('navbar-hiding').removeClass('navbar-hidden').transitionEnd(function () {
navbar.removeClass('navbar-hiding');
}