UNPKG

framework7-vue

Version:

Build full featured iOS & Android apps using Framework7 & Vue

1,045 lines (963 loc) 814 kB
/** * 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'); }