(function() { 'use strict'; /** * @description * The NavController is a navigation stack View Controller modelled off of * UINavigationController from Cocoa Touch. With the Nav Controller, you can * "push" new "pages" on to the navigation stack, and then pop them off to go * back. The NavController controls a navigation bar with a back button and title * which updates as the pages switch. * * The NavController makes sure to not recycle scopes of old pages * so that a pop will still show the same state that the user left. * * However, once a page is popped, its scope is destroyed and will have to be * recreated then next time it is pushed. * */ var actualLocation = null; angular.module('ionic.ui.navRouter', ['ionic.service.gesture']) .run(['$rootScope', function($rootScope) { $rootScope.stackCursorPosition = 0; }]) .directive('navRouter', ['$rootScope', '$timeout', '$location', '$window', '$route', function($rootScope, $timeout, $location, $window, $route) { return { restrict: 'AC', // So you can require being under this controller: ['$scope', '$element', function($scope, $element) { this.navBar = { isVisible: true }; $scope.navController = this; this.goBack = function() { $scope.direction = 'back'; }; }], link: function($scope, $element, $attr, ctrl) { if(!$element.length) return; $scope.animation = $attr.animation; $element[0].classList.add('noop-animation'); var isFirst = true; // Store whether we did an animation yet, to know if // we should let the first state animate var didAnimate = false; var initTransition = function() { //$element.addClass($scope.animation); }; var reverseTransition = function() { $element[0].classList.remove('noop-animation'); $element[0].classList.add($scope.animation); $element[0].classList.add('reverse'); }; var forwardTransition = function() { $element[0].classList.remove('noop-animation'); $element[0].classList.remove('reverse'); $element[0].classList.add($scope.animation); }; $scope.$on('$routeChangeSuccess', function(e, a) { }); $scope.$on('$routeChangeStart', function(e, next, current) { var back, historyState = $window.history.state; back = $scope.direction == 'back' || (!!(historyState && historyState.position <= $rootScope.stackCursorPosition)); if(isFirst || (next && next.$$route && next.$$route.originalPath === "")) { // Don't animate isFirst = false; return; } if(didAnimate || $rootScope.stackCursorPosition > 0) { didAnimate = true; if(back) { reverseTransition(); } else { forwardTransition(); } } }); $scope.$on('$locationChangeSuccess', function(a, b, c) { // Store the new location $rootScope.actualLocation = $location.path(); if(isFirst && $location.path() !== '/') { isFirst = false; } }); $scope.$on('navRouter.goBack', function(e) { ctrl.goBack(); }); // Keep track of location changes and update a stack pointer that tracks whether we are // going forwards or back $scope.$watch(function () { return $location.path(); }, function (newLocation, oldLocation) { if($rootScope.actualLocation === newLocation) { if(oldLocation === '') {// || newLocation == '/') { // initial route, skip this return; } var back, historyState = $window.history.state; back = $scope.direction == 'back' || (!!(historyState && historyState.position <= $rootScope.stackCursorPosition)); if (back) { //back button $rootScope.stackCursorPosition--; } else { //forward button $rootScope.stackCursorPosition++; } $scope.direction = 'forwards'; } else { var currentRouteBeforeChange = $route.current; if (currentRouteBeforeChange) { $window.history.replaceState({ position: $rootScope.stackCursorPosition }); $rootScope.stackCursorPosition++; } } }); } }; }]) /** * Our Nav Bar directive which updates as the controller state changes. */ .directive('navBar', ['$rootScope', '$animate', '$compile', function($rootScope, $animate, $compile) { /** * Perform an animation between one tab bar state and the next. * Right now this just animates the titles. */ var animate = function($scope, $element, oldTitle, data, cb) { var title, nTitle, oTitle, titles = $element[0].querySelectorAll('.title'); var newTitle = data.title; if(!oldTitle || oldTitle === newTitle) { cb(); return; } // Clone the old title and add a new one so we can show two animating in and out // add ng-leave and ng-enter during creation to prevent flickering when they are swapped during animation title = angular.element(titles[0]); oTitle = $compile('
')($scope); title.replaceWith(oTitle); nTitle = $compile('')($scope); var insert = $element[0].firstElementChild || null; // Insert the new title $animate.enter(nTitle, $element, insert && angular.element(insert), function() { cb(); }); // Remove the old title $animate.leave(angular.element(oTitle), function() { }); }; return { restrict: 'E', require: '^navRouter', replace: true, scope: { type: '@', backButtonType: '@', backButtonLabel: '@', backButtonIcon: '@', alignTitle: '@' }, template: '