/** * @private * TODO document */ IonicModule .factory('$ionicViewSwitcher',[ '$timeout', '$compile', '$controller', '$ionicClickBlock', '$ionicConfig', '$ionicNavBarDelegate', function($timeout, $compile, $controller, $ionicClickBlock, $ionicConfig, $ionicNavBarDelegate) { var TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend'; var DATA_NO_CACHE = '$noCache'; var DATA_ELE_IDENTIFIER = '$eleId'; var DATA_ACTIVE_ELE_IDENTIFIER = '$activeEleId'; var DATA_VIEW_ACCESSED = '$accessed'; var DATA_FALLBACK_TIMER = '$fallbackTimer'; var NAV_VIEW_ATTR = 'nav-view'; var HISTORY_CURSOR_ATTR = 'history-cursor'; var HISTORY_ROOT = 'root'; var HISTORY_AFTER_ROOT = 'after-root'; var VIEW_STATUS_ACTIVE = 'active'; var VIEW_STATUS_CACHED = 'cached'; var VIEW_STATUS_STAGED = 'stage'; var transitionCounter = 0; var nextTransition; var nextDirection; ionic.transition = ionic.transition || {}; ionic.transition.isActive = false; var isActiveTimer; function createViewElement(viewLocals) { var div = jqLite('
'); if (viewLocals && viewLocals.$template) { div.html(viewLocals.$template); var nodes = div.contents(); for (var i = 0; i < nodes.length; i++) { if (nodes[i].nodeType == 1) { // first try to get just a child element return nodes.eq(i); } } } // fallback to return the div so it has one parent element return div; } function getViewElementIdentifier(locals, view) { if ( viewState(locals).abstract ) return viewState(locals).name; if ( view ) return view.stateId || view.viewId; return ionic.Utils.nextUid(); } function viewState(locals) { return locals && locals.$$state && locals.$$state.self || {}; } function getTransitionData(viewLocals, enteringEle, direction, enteringView, showBack) { // Priority // 1) attribute directive on the button/link to this view // 2) entering element's attribute // 3) entering view's $state config property // 4) view registration data // 5) global config // 6) fallback value var state = viewState(viewLocals); enteringView = enteringView || {}; var transition = nextTransition || ionic.DomUtil.cachedAttr(enteringEle, 'view-transition') || state.viewTransition || $ionicConfig.views.transition() || 'none'; direction = nextDirection || ionic.DomUtil.cachedAttr(enteringEle, 'view-direction') || state.viewDirection || direction || 'none'; var shouldAnimate = (transition !== 'none' && direction !== 'none'); return { transition: transition, direction: direction, shouldAnimate: shouldAnimate, viewId: enteringView.viewId, stateId: enteringView.stateId, stateName: enteringView.stateName, stateParams: enteringView.stateParams, showBack: !!showBack }; } function navViewAttr(ele, value) { ionic.DomUtil.cachedAttr(ele, NAV_VIEW_ATTR, value); } function historyCursorAttr(ele, value) { ionic.DomUtil.cachedAttr(ele, HISTORY_CURSOR_ATTR, value); } var ionicViewSwitcher = { create: function(navViewScope, navViewElement, viewLocals, enteringView) { // get a reference to an entering/leaving element if they exist // loop through to see if the view is already in the navViewElement var enteringEle, leavingEle; var transitionId = ++transitionCounter; var alreadyInDom; var switcher = { init: function(registerData, callback) { ionicViewSwitcher.isTransitioning(true); $ionicClickBlock.show(); switcher.loadViewElements(); switcher.render(registerData, function(){ callback && callback(); }); }, loadViewElements: function() { var viewEle, viewElements = navViewElement.children(); var enteringEleIdentifier = getViewElementIdentifier(viewLocals, enteringView); var navViewActiveEleId = navViewElement.data(DATA_ACTIVE_ELE_IDENTIFIER); for (var x=0, l=viewElements.length; x $ionicConfig.views.maxCache() ) { // check to see if we have more cached views than we should // the total number of child elements has exceeded how many to keep in the DOM var oldestAccess = Date.now(); for (x=0; x