diff --git a/dist/css/ionic.css b/dist/css/ionic.css
index 8ca4caaa0a..44e17e2101 100644
--- a/dist/css/ionic.css
+++ b/dist/css/ionic.css
@@ -3811,7 +3811,7 @@ button.item-button-right:after {
* Nav
* --------------------------------------------------
*/
-.nav-content {
+.nav-page {
position: absolute;
width: 100%;
height: 100%;
@@ -4801,50 +4801,94 @@ a.button {
100% {
-webkit-transform: translate3d(100%, 0, 0); } }
-.slide-in-left.ng-enter, .slide-in-left > .ng-enter {
- -webkit-animation-duration: 250ms;
- -webkit-animation-fill-mode: both;
- -webkit-animation-timing-function: ease-in-out;
- -webkit-animation-name: slideInLeft; }
-.slide-in-left.ng-leave, .slide-in-left > .ng-leave {
- -webkit-animation-duration: 250ms;
- -webkit-animation-fill-mode: both;
- -webkit-animation-timing-function: ease-in-out;
- -webkit-animation-name: slideOutLeft; }
+.slide-in-left {
+ -webkit-transform: translate3d(0%, 0, 0); }
+ .slide-in-left.ng-enter, .slide-in-left > .ng-enter {
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out;
+ -webkit-animation-name: slideInLeft; }
+ .slide-in-left.ng-leave, .slide-in-left > .ng-leave {
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out;
+ -webkit-animation-name: slideOutLeft; }
-.slide-out-left.ng-enter, .slide-out-left > .ng-enter {
+.slide-in-left-add {
+ -webkit-transform: translate3d(100%, 0, 0);
-webkit-animation-duration: 250ms;
-webkit-animation-fill-mode: both;
- -webkit-animation-timing-function: ease-in-out;
- -webkit-animation-name: slideOutLeft; }
-.slide-out-left.ng-leave, .slide-out-left > .ng-leave {
- -webkit-animation-duration: 250ms;
- -webkit-animation-fill-mode: both;
- -webkit-animation-timing-function: ease-in-out;
+ -webkit-animation-timing-function: ease-in-out; }
+
+.slide-in-left-add-active {
-webkit-animation-name: slideInLeft; }
-.slide-in-right.ng-enter, .slide-in-right > .ng-enter {
- -webkit-animation-duration: 250ms;
- -webkit-animation-fill-mode: both;
- -webkit-animation-timing-function: ease-in-out;
- -webkit-animation-name: slideInRight; }
-.slide-in-right.ng-leave, .slide-in-right > .ng-leave {
- -webkit-animation-duration: 250ms;
- -webkit-animation-fill-mode: both;
- -webkit-animation-timing-function: ease-in-out;
- -webkit-animation-name: slideOutRight; }
+.slide-out-left {
+ -webkit-transform: translate3d(-100%, 0, 0); }
+ .slide-out-left.ng-enter, .slide-out-left > .ng-enter {
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out;
+ -webkit-animation-name: slideOutLeft; }
+ .slide-out-left.ng-leave, .slide-out-left > .ng-leave {
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out;
+ -webkit-animation-name: slideOutLeft; }
-.slide-out-right.ng-enter, .slide-out-right > .ng-enter {
+.slide-out-left-add {
+ -webkit-transform: translate3d(0, 0, 0);
-webkit-animation-duration: 250ms;
-webkit-animation-fill-mode: both;
- -webkit-animation-timing-function: ease-in-out;
- -webkit-animation-name: slideOutRight; }
-.slide-out-right.ng-leave, .slide-out-right > .ng-leave {
+ -webkit-animation-timing-function: ease-in-out; }
+
+.slide-out-left-add-active {
+ -webkit-animation-name: slideOutLeft; }
+
+.slide-in-right {
+ -webkit-transform: translate3d(0%, 0, 0); }
+ .slide-in-right.ng-enter, .slide-in-right > .ng-enter {
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out;
+ -webkit-animation-name: slideInRight; }
+ .slide-in-right.ng-leave, .slide-in-right > .ng-leave {
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out;
+ -webkit-animation-name: slideInRight; }
+
+.slide-in-right-add {
+ -webkit-transform: translate3d(-100%, 0, 0);
-webkit-animation-duration: 250ms;
-webkit-animation-fill-mode: both;
- -webkit-animation-timing-function: ease-in-out;
+ -webkit-animation-timing-function: ease-in-out; }
+
+.slide-in-right-add-active {
-webkit-animation-name: slideInRight; }
+.slide-out-right {
+ -webkit-transform: translate3d(100%, 0, 0); }
+ .slide-out-right.ng-enter, .slide-out-right > .ng-enter {
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out;
+ -webkit-animation-name: slideOutRight; }
+ .slide-out-right.ng-leave, .slide-out-right > .ng-leave {
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out;
+ -webkit-animation-name: slideOutRight; }
+
+.slide-out-right-add {
+ -webkit-transform: translate3d(0, 0, 0);
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out; }
+
+.slide-out-right-add-active {
+ -webkit-animation-name: slideOutRight; }
+
@-webkit-keyframes slideInUp {
0% {
-webkit-transform: translate3d(0, 100%, 0);
diff --git a/dist/js/ionic-angular.js b/dist/js/ionic-angular.js
index 8a381ac94e..b9af873332 100644
--- a/dist/js/ionic-angular.js
+++ b/dist/js/ionic-angular.js
@@ -23597,7 +23597,7 @@ angular.module('ionic.ui.content', [])
.directive('pane', function() {
return {
restrict: 'E',
- compile: function(element, attr) {
+ link: function(scope, element, attr) {
element.addClass('pane');
}
}
@@ -23877,28 +23877,78 @@ angular.module('ionic.ui.loading', [])
(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.
+ *
+ */
angular.module('ionic.ui.nav', ['ionic.service.templateLoad', 'ionic.service.gesture', 'ionic.service.platform', 'ngAnimate'])
-.controller('NavCtrl', ['$scope', '$element', '$animate', '$compile', 'TemplateLoader', 'Platform', function($scope, $element, $animate, $compile, TemplateLoader, Platform) {
+.controller('NavCtrl', ['$scope', '$element', '$animate', '$compile', '$timeout', 'TemplateLoader', 'Platform', function($scope, $element, $animate, $compile, $timeout, TemplateLoader, Platform) {
var _this = this;
angular.extend(this, ionic.controllers.NavController.prototype);
+ var pushInAnimation = $scope.pushInAnimation || 'slide-in-left';
+ var pushOutAnimation = $scope.pushOutAnimation || 'slide-out-left';
+ var popInAnimation = $scope.popInAnimation || 'slide-in-right';
+ var popOutAnimation = $scope.popOutAnimation || 'slide-out-right';
+
+ // Remove some push classnames
+ var cleanElementAnimations = function(el) {
+ el.removeClass(pushInAnimation);
+ el.removeClass(pushOutAnimation);
+ el.removeClass(popInAnimation);
+ el.removeClass(popOutAnimation);
+ }
+
/**
* Push a template onto the navigation stack.
* @param {string} templateUrl the URL of the template to load.
*/
this.pushFromTemplate = ionic.throttle(function(templateUrl) {
var childScope = $scope.$new();
- childScope.isVisible = true;
+ var last = _this.getTopController();
// Load the given template
TemplateLoader.load(templateUrl).then(function(templateString) {
- // Compile the template with the new scrope, and append it to the navigation's content area
+ // Compile the template with the new scope, and append
+ // it to the navigation's content area
var el = $compile(templateString)(childScope, function(cloned, scope) {
- var content = angular.element($element[0].querySelector('.content, .scroll'));
- $animate.enter(cloned, angular.element(content));
+
+ // If there was a last controller, remove it and mark the new
+ // one to animate
+ if(last) {
+ // Push animate
+ cleanElementAnimations(last.element);
+ $animate.addClass(last.element, pushOutAnimation, function() {
+ last.element[0].style.display = 'none';
+ last.element.removeClass(pushOutAnimation);
+ });
+
+ }
+
+
+ if(last) {
+ // We will need to animate in the new page since we have an old page
+ cloned.addClass(pushInAnimation);
+ $animate.addClass(cloned, pushInAnimation);
+ }
+
+ $animate.enter(cloned, $element, null, function() {
+ });
+
});
});
}, 300, {
@@ -23907,13 +23957,34 @@ angular.module('ionic.ui.nav', ['ionic.service.templateLoad', 'ionic.service.ges
// Pop function, throttled
this.popController = ionic.throttle(function() {
- _this.pop();
- $scope.$broadcast('navs.pop');
+ var last = _this.pop();
+
+ var next = _this.getTopController();
+
+ if(last) {
+
+ cleanElementAnimations(last.element);
+ $animate.addClass(last.element, popOutAnimation, function() {
+ last.scope.$destroy();
+ last.element.remove();
+ });
+ }
+
+ // Animate the next one in
+ if(next) {
+ cleanElementAnimations(next.element);
+ $animate.addClass(next.element, popInAnimation)
+ next.element[0].style.display = 'block';
+ }
+
+ $scope.$parent.$broadcast('navigation.pop');
}, 300, {
trailing: false
});
+ // Extend the low-level navigation controller
+ // for this angular controller
ionic.controllers.NavController.call(this, {
content: {
},
@@ -23955,8 +24026,19 @@ angular.module('ionic.ui.nav', ['ionic.service.templateLoad', 'ionic.service.ges
* nav-content directive when it is linked to a scope on the page.
*/
$scope.pushController = function(scope, element) {
- _this.push(scope);
- $scope.$broadcast('navs.push', scope);
+ _this.push({
+ scope: scope,
+ element: element
+ });
+ $scope.$parent.$broadcast('navigation.push', scope);
+ };
+
+ this.pushController = function(scope, element) {
+ _this.push({
+ scope: scope,
+ element: element
+ });
+ $scope.$parent.$broadcast('navigation.push', scope);
};
$scope.navController = this;
@@ -23967,7 +24049,10 @@ angular.module('ionic.ui.nav', ['ionic.service.templateLoad', 'ionic.service.ges
});
}])
-.directive('navs', function() {
+/**
+ * The main directive for the controller.
+ */
+.directive('navigation', function() {
return {
restrict: 'E',
replace: true,
@@ -23975,26 +24060,54 @@ angular.module('ionic.ui.nav', ['ionic.service.templateLoad', 'ionic.service.ges
controller: 'NavCtrl',
//templateUrl: 'ext/angular/tmpl/ionicTabBar.tmpl.html',
template: '
',
+ scope: {
+ first: '@',
+ pushAnimation: '@',
+ popAnimation: '@'
+ },
+ link: function($scope, $element, $attr, navCtrl) {
+ $scope.pushAnimation = $scope.pushAnimation || 'slide-in-left';
+ $scope.popAnimation = $scope.popAnimation || 'slide-out-left';
+
+ if($scope.first) {
+ navCtrl.pushFromTemplate($scope.first);
+ }
+ }
};
})
+/**
+ * Our Nav Bar directive which updates as the controller state changes.
+ */
.directive('navBar', function() {
return {
restrict: 'E',
- require: '^navs',
+ require: '^navigation',
replace: true,
scope: {
type: '@',
backButtonType: '@',
+ backButtonLabel: '@',
+ backButtonIcon: '@',
alignTitle: '@'
},
template: '',
link: function($scope, $element, $attr, navCtrl) {
var backButton;
+ $scope.backButtonContent = '';
+
+ if($scope.backButtonIcon) {
+ $scope.backButtonContent += '';
+ }
+ if($scope.backButtonLabel) {
+ $scope.backButtonContent += ' ' + $scope.backButtonLabel
+ }
+
+
$scope.navController = navCtrl;
$scope.goBack = function() {
@@ -24011,12 +24124,12 @@ angular.module('ionic.ui.nav', ['ionic.service.templateLoad', 'ionic.service.ges
$scope.headerBarView = hb;
- $scope.$parent.$on('navs.push', function() {
+ $scope.$parent.$on('navigation.push', function() {
backButton = angular.element($element[0].querySelector('.button'));
backButton.addClass($scope.backButtonType);
hb.align();
});
- $scope.$parent.$on('navs.pop', function() {
+ $scope.$parent.$on('navigation.pop', function() {
hb.align();
});
@@ -24027,141 +24140,79 @@ angular.module('ionic.ui.nav', ['ionic.service.templateLoad', 'ionic.service.ges
};
})
-.directive('navContent', ['Gesture', '$animate', '$compile', function(Gesture, $animate, $compile) {
-
- // We need to animate the new controller into view.
- var animatePushedController = function(childScope, clone, $element, isForward) {
- var parent = angular.element($element.parent().parent().parent());
-
- var title = angular.element(parent[0].querySelector('.title'));
-
- // Clone the old title and insert it so we can animate it back into place for the new controller
- var newTitle = angular.element(title.clone());
- $compile(newTitle)(childScope);
- title.after(newTitle);
- // Grab the button so we can slide it in
- var button = angular.element(parent[0].querySelector('.button'));
-
- if(isForward) {
-
- // Slide the button in
- $animate.addClass(button, childScope.slideButtonInAnimation, function() {
- $animate.removeClass(button, childScope.slideButtonInAnimation, function() {});
- })
-
- // Slide the new title in
- $animate.addClass(newTitle, childScope.slideTitleInAnimation, function() {
- $animate.removeClass(newTitle, childScope.slideTitleInAnimation, function() {
- newTitle.scope().$destroy();
- newTitle.remove();
- });
- });
-
- // Grab the old title and slide it out
- var title = $element.parent().parent().parent()[0].querySelector('.title');
- $animate.addClass(angular.element(title), childScope.slideTitleOutAnimation, function() {
- $animate.removeClass(angular.element(title), childScope.slideTitleOutAnimation, function() {
- });
- });
- } else {
- clone.addClass(childScope.slideBackInAnimation);
- }
- };
+.directive('navPage', ['Gesture', '$animate', '$compile', function(Gesture, $animate, $compile) {
return {
- restrict: 'ECA',
- require: '^navs',
- transclude: 'element',
- compile: function(element, attr, transclude) {
- return function($scope, $element, $attr, navCtrl) {
- var lastParent, lastIndex, childScope, childElement;
+ restrict: 'AC',
+ require: '^navigation',
+ link: function($scope, $element, $attr, navCtrl) {
+ var lastParent, lastIndex, childScope, childElement;
- // Store that we should go forwards on the animation. This toggles
- // based on the visibility sequence (to support reverse transitions)
- var lastDirection = null;
+ // Store that we should go forwards on the animation. This toggles
+ // based on the visibility sequence (to support reverse transitions)
+ var lastDirection = null;
- $scope.title = $attr.title;
- $scope.pushAnimation = $attr.pushAnimation || 'slide-in-left';
- $scope.popAnimation = $attr.popAnimation || 'slide-in-right';
- $scope.slideTitleInAnimation = $attr.slideTitleInAnimation || 'bar-title-in';
- $scope.slideTitleOutAnimation = $attr.slideTitleOutAnimation || 'bar-title-out';
- $scope.slideButtonInAnimation = $attr.slideButtonInAnimation || 'bar-button-in';
- $scope.slideButtonOutAnimation = $attr.slideButtonOutAnimation || 'bar-button-out';
+ $scope.title = $attr.title;
- if($attr.navBar === "false") {
- navCtrl.hideNavBar();
- } else {
- navCtrl.showNavBar();
- }
-
- $scope.visibilityChanged = function(direction) {
- lastDirection = direction;
-
- if($scope.isVisible) {
- $scope.$broadcast('navContent.shown');
- } else {
- $scope.$broadcast('navContent.hidden');
- }
-
- if(!childElement) {
- return;
- }
-
- var clone = childElement;
-
- if(direction == 'push') {
- clone.addClass(childScope.pushAnimation);
- clone.removeClass(childScope.popAnimation);
- } else if(direction == 'pop') {
- clone.addClass(childScope.popAnimation);
- clone.removeClass(childScope.pushAnimation);
- }
- };
-
- // Push this controller onto the stack
- $scope.pushController($scope, $element);
-
- $scope.$watch('isVisible', function(value) {
-
- if(value) {
- childScope = $scope.$new();
-
- transclude(childScope, function(clone) {
- childElement = clone;
-
- if(lastDirection == 'push') {
- clone.addClass(childScope.pushAnimation);
- } else if(lastDirection == 'pop') {
- clone.addClass(childScope.popAnimation);
- }
-
- $animate.enter(clone, $element.parent(), $element, function() {
- clone.removeClass(childScope.pushAnimation);
- clone.removeClass(childScope.popAnimation);
- });
- });
- } else {
- // Taken from ngIf
- if(childElement) {
- // Check if this is visible, and if so, create it and show it
- $animate.leave(childElement, function() {
- if(childScope) {
- childElement.removeClass(childScope.pushAnimation);
- childElement.removeClass(childScope.popAnimation);
- }
- });
- childElement = undefined;
- }
- if(childScope) {
- childScope.$destroy();
- childScope = undefined;
- }
- }
- });
+ if($attr.navBar === "false") {
+ navCtrl.hideNavBar();
+ } else {
+ navCtrl.showNavBar();
}
+
+ $scope.$on('$destroy', function() {
+ if(childElement) {
+ childElement.remove();
+ }
+ });
+
+ // Push this controller onto the stack
+ navCtrl.pushController($scope, $element);
}
- };
-}]);
+ }
+}])
+
+.directive('navPush', function() {
+ return {
+ restrict: 'A',
+ link: function($scope, $element, $attr) {
+ var templateUrl = $attr.navPush;
+
+ var pushTemplate = function(e) {
+ $scope.$apply(function() {
+ $scope.navController && $scope.navController.pushFromTemplate(templateUrl);
+ });
+ return false;
+ };
+
+ $element.bind('tap', pushTemplate);
+
+ $scope.$on('$destroy', function() {
+ $element.unbind('tap', pushTemplate);
+ });
+ }
+ }
+})
+
+.directive('navPop', function() {
+ return {
+ restrict: 'A',
+ link: function($scope, $element, $attr, navCtrl) {
+ var popTemplate = function(e) {
+ $scope.$apply(function() {
+ $scope.navController && navController.pop();
+ });
+ return false;
+ };
+
+ $element.bind('tap', popTemplate);
+
+ $scope.$on('$destroy', function() {
+ $element.unbind('tap', popTemplate);
+ });
+ }
+ }
+})
})();
;
diff --git a/js/ext/angular/src/directive/ionicContent.js b/js/ext/angular/src/directive/ionicContent.js
index 074324dd83..1cc395a36d 100644
--- a/js/ext/angular/src/directive/ionicContent.js
+++ b/js/ext/angular/src/directive/ionicContent.js
@@ -10,7 +10,7 @@ angular.module('ionic.ui.content', [])
.directive('pane', function() {
return {
restrict: 'E',
- compile: function(element, attr) {
+ link: function(scope, element, attr) {
element.addClass('pane');
}
}
diff --git a/js/ext/angular/src/directive/ionicNav.js b/js/ext/angular/src/directive/ionicNav.js
index efab4025d7..503d3fe602 100644
--- a/js/ext/angular/src/directive/ionicNav.js
+++ b/js/ext/angular/src/directive/ionicNav.js
@@ -1,28 +1,78 @@
(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.
+ *
+ */
angular.module('ionic.ui.nav', ['ionic.service.templateLoad', 'ionic.service.gesture', 'ionic.service.platform', 'ngAnimate'])
-.controller('NavCtrl', ['$scope', '$element', '$animate', '$compile', 'TemplateLoader', 'Platform', function($scope, $element, $animate, $compile, TemplateLoader, Platform) {
+.controller('NavCtrl', ['$scope', '$element', '$animate', '$compile', '$timeout', 'TemplateLoader', 'Platform', function($scope, $element, $animate, $compile, $timeout, TemplateLoader, Platform) {
var _this = this;
angular.extend(this, ionic.controllers.NavController.prototype);
+ var pushInAnimation = $scope.pushInAnimation || 'slide-in-left';
+ var pushOutAnimation = $scope.pushOutAnimation || 'slide-out-left';
+ var popInAnimation = $scope.popInAnimation || 'slide-in-right';
+ var popOutAnimation = $scope.popOutAnimation || 'slide-out-right';
+
+ // Remove some push classnames
+ var cleanElementAnimations = function(el) {
+ el.removeClass(pushInAnimation);
+ el.removeClass(pushOutAnimation);
+ el.removeClass(popInAnimation);
+ el.removeClass(popOutAnimation);
+ }
+
/**
* Push a template onto the navigation stack.
* @param {string} templateUrl the URL of the template to load.
*/
this.pushFromTemplate = ionic.throttle(function(templateUrl) {
var childScope = $scope.$new();
- childScope.isVisible = true;
+ var last = _this.getTopController();
// Load the given template
TemplateLoader.load(templateUrl).then(function(templateString) {
- // Compile the template with the new scrope, and append it to the navigation's content area
+ // Compile the template with the new scope, and append
+ // it to the navigation's content area
var el = $compile(templateString)(childScope, function(cloned, scope) {
- var content = angular.element($element[0].querySelector('.content, .scroll'));
- $animate.enter(cloned, angular.element(content));
+
+ // If there was a last controller, remove it and mark the new
+ // one to animate
+ if(last) {
+ // Push animate
+ cleanElementAnimations(last.element);
+ $animate.addClass(last.element, pushOutAnimation, function() {
+ last.element[0].style.display = 'none';
+ last.element.removeClass(pushOutAnimation);
+ });
+
+ }
+
+
+ if(last) {
+ // We will need to animate in the new page since we have an old page
+ cloned.addClass(pushInAnimation);
+ $animate.addClass(cloned, pushInAnimation);
+ }
+
+ $animate.enter(cloned, $element, null, function() {
+ });
+
});
});
}, 300, {
@@ -31,13 +81,34 @@ angular.module('ionic.ui.nav', ['ionic.service.templateLoad', 'ionic.service.ges
// Pop function, throttled
this.popController = ionic.throttle(function() {
- _this.pop();
- $scope.$broadcast('navs.pop');
+ var last = _this.pop();
+
+ var next = _this.getTopController();
+
+ if(last) {
+
+ cleanElementAnimations(last.element);
+ $animate.addClass(last.element, popOutAnimation, function() {
+ last.scope.$destroy();
+ last.element.remove();
+ });
+ }
+
+ // Animate the next one in
+ if(next) {
+ cleanElementAnimations(next.element);
+ $animate.addClass(next.element, popInAnimation)
+ next.element[0].style.display = 'block';
+ }
+
+ $scope.$parent.$broadcast('navigation.pop');
}, 300, {
trailing: false
});
+ // Extend the low-level navigation controller
+ // for this angular controller
ionic.controllers.NavController.call(this, {
content: {
},
@@ -79,8 +150,19 @@ angular.module('ionic.ui.nav', ['ionic.service.templateLoad', 'ionic.service.ges
* nav-content directive when it is linked to a scope on the page.
*/
$scope.pushController = function(scope, element) {
- _this.push(scope);
- $scope.$broadcast('navs.push', scope);
+ _this.push({
+ scope: scope,
+ element: element
+ });
+ $scope.$parent.$broadcast('navigation.push', scope);
+ };
+
+ this.pushController = function(scope, element) {
+ _this.push({
+ scope: scope,
+ element: element
+ });
+ $scope.$parent.$broadcast('navigation.push', scope);
};
$scope.navController = this;
@@ -91,7 +173,10 @@ angular.module('ionic.ui.nav', ['ionic.service.templateLoad', 'ionic.service.ges
});
}])
-.directive('navs', function() {
+/**
+ * The main directive for the controller.
+ */
+.directive('navigation', function() {
return {
restrict: 'E',
replace: true,
@@ -99,26 +184,54 @@ angular.module('ionic.ui.nav', ['ionic.service.templateLoad', 'ionic.service.ges
controller: 'NavCtrl',
//templateUrl: 'ext/angular/tmpl/ionicTabBar.tmpl.html',
template: '',
+ scope: {
+ first: '@',
+ pushAnimation: '@',
+ popAnimation: '@'
+ },
+ link: function($scope, $element, $attr, navCtrl) {
+ $scope.pushAnimation = $scope.pushAnimation || 'slide-in-left';
+ $scope.popAnimation = $scope.popAnimation || 'slide-out-left';
+
+ if($scope.first) {
+ navCtrl.pushFromTemplate($scope.first);
+ }
+ }
};
})
+/**
+ * Our Nav Bar directive which updates as the controller state changes.
+ */
.directive('navBar', function() {
return {
restrict: 'E',
- require: '^navs',
+ require: '^navigation',
replace: true,
scope: {
type: '@',
backButtonType: '@',
+ backButtonLabel: '@',
+ backButtonIcon: '@',
alignTitle: '@'
},
template: '',
link: function($scope, $element, $attr, navCtrl) {
var backButton;
+ $scope.backButtonContent = '';
+
+ if($scope.backButtonIcon) {
+ $scope.backButtonContent += '';
+ }
+ if($scope.backButtonLabel) {
+ $scope.backButtonContent += ' ' + $scope.backButtonLabel
+ }
+
+
$scope.navController = navCtrl;
$scope.goBack = function() {
@@ -135,12 +248,12 @@ angular.module('ionic.ui.nav', ['ionic.service.templateLoad', 'ionic.service.ges
$scope.headerBarView = hb;
- $scope.$parent.$on('navs.push', function() {
+ $scope.$parent.$on('navigation.push', function() {
backButton = angular.element($element[0].querySelector('.button'));
backButton.addClass($scope.backButtonType);
hb.align();
});
- $scope.$parent.$on('navs.pop', function() {
+ $scope.$parent.$on('navigation.pop', function() {
hb.align();
});
@@ -151,140 +264,78 @@ angular.module('ionic.ui.nav', ['ionic.service.templateLoad', 'ionic.service.ges
};
})
-.directive('navContent', ['Gesture', '$animate', '$compile', function(Gesture, $animate, $compile) {
-
- // We need to animate the new controller into view.
- var animatePushedController = function(childScope, clone, $element, isForward) {
- var parent = angular.element($element.parent().parent().parent());
-
- var title = angular.element(parent[0].querySelector('.title'));
-
- // Clone the old title and insert it so we can animate it back into place for the new controller
- var newTitle = angular.element(title.clone());
- $compile(newTitle)(childScope);
- title.after(newTitle);
- // Grab the button so we can slide it in
- var button = angular.element(parent[0].querySelector('.button'));
-
- if(isForward) {
-
- // Slide the button in
- $animate.addClass(button, childScope.slideButtonInAnimation, function() {
- $animate.removeClass(button, childScope.slideButtonInAnimation, function() {});
- })
-
- // Slide the new title in
- $animate.addClass(newTitle, childScope.slideTitleInAnimation, function() {
- $animate.removeClass(newTitle, childScope.slideTitleInAnimation, function() {
- newTitle.scope().$destroy();
- newTitle.remove();
- });
- });
-
- // Grab the old title and slide it out
- var title = $element.parent().parent().parent()[0].querySelector('.title');
- $animate.addClass(angular.element(title), childScope.slideTitleOutAnimation, function() {
- $animate.removeClass(angular.element(title), childScope.slideTitleOutAnimation, function() {
- });
- });
- } else {
- clone.addClass(childScope.slideBackInAnimation);
- }
- };
+.directive('navPage', ['Gesture', '$animate', '$compile', function(Gesture, $animate, $compile) {
return {
- restrict: 'ECA',
- require: '^navs',
- transclude: 'element',
- compile: function(element, attr, transclude) {
- return function($scope, $element, $attr, navCtrl) {
- var lastParent, lastIndex, childScope, childElement;
+ restrict: 'AC',
+ require: '^navigation',
+ link: function($scope, $element, $attr, navCtrl) {
+ var lastParent, lastIndex, childScope, childElement;
- // Store that we should go forwards on the animation. This toggles
- // based on the visibility sequence (to support reverse transitions)
- var lastDirection = null;
+ // Store that we should go forwards on the animation. This toggles
+ // based on the visibility sequence (to support reverse transitions)
+ var lastDirection = null;
- $scope.title = $attr.title;
- $scope.pushAnimation = $attr.pushAnimation || 'slide-in-left';
- $scope.popAnimation = $attr.popAnimation || 'slide-in-right';
- $scope.slideTitleInAnimation = $attr.slideTitleInAnimation || 'bar-title-in';
- $scope.slideTitleOutAnimation = $attr.slideTitleOutAnimation || 'bar-title-out';
- $scope.slideButtonInAnimation = $attr.slideButtonInAnimation || 'bar-button-in';
- $scope.slideButtonOutAnimation = $attr.slideButtonOutAnimation || 'bar-button-out';
+ $scope.title = $attr.title;
- if($attr.navBar === "false") {
- navCtrl.hideNavBar();
- } else {
- navCtrl.showNavBar();
- }
-
- $scope.visibilityChanged = function(direction) {
- lastDirection = direction;
-
- if($scope.isVisible) {
- $scope.$broadcast('navContent.shown');
- } else {
- $scope.$broadcast('navContent.hidden');
- }
-
- if(!childElement) {
- return;
- }
-
- var clone = childElement;
-
- if(direction == 'push') {
- clone.addClass(childScope.pushAnimation);
- clone.removeClass(childScope.popAnimation);
- } else if(direction == 'pop') {
- clone.addClass(childScope.popAnimation);
- clone.removeClass(childScope.pushAnimation);
- }
- };
-
- // Push this controller onto the stack
- $scope.pushController($scope, $element);
-
- $scope.$watch('isVisible', function(value) {
-
- if(value) {
- childScope = $scope.$new();
-
- transclude(childScope, function(clone) {
- childElement = clone;
-
- if(lastDirection == 'push') {
- clone.addClass(childScope.pushAnimation);
- } else if(lastDirection == 'pop') {
- clone.addClass(childScope.popAnimation);
- }
-
- $animate.enter(clone, $element.parent(), $element, function() {
- clone.removeClass(childScope.pushAnimation);
- clone.removeClass(childScope.popAnimation);
- });
- });
- } else {
- // Taken from ngIf
- if(childElement) {
- // Check if this is visible, and if so, create it and show it
- $animate.leave(childElement, function() {
- if(childScope) {
- childElement.removeClass(childScope.pushAnimation);
- childElement.removeClass(childScope.popAnimation);
- }
- });
- childElement = undefined;
- }
- if(childScope) {
- childScope.$destroy();
- childScope = undefined;
- }
- }
- });
+ if($attr.navBar === "false") {
+ navCtrl.hideNavBar();
+ } else {
+ navCtrl.showNavBar();
}
+
+ $scope.$on('$destroy', function() {
+ if(childElement) {
+ childElement.remove();
+ }
+ });
+
+ // Push this controller onto the stack
+ navCtrl.pushController($scope, $element);
}
- };
-}]);
+ }
+}])
+
+.directive('navPush', function() {
+ return {
+ restrict: 'A',
+ link: function($scope, $element, $attr) {
+ var templateUrl = $attr.navPush;
+
+ var pushTemplate = function(e) {
+ $scope.$apply(function() {
+ $scope.navController && $scope.navController.pushFromTemplate(templateUrl);
+ });
+ return false;
+ };
+
+ $element.bind('tap', pushTemplate);
+
+ $scope.$on('$destroy', function() {
+ $element.unbind('tap', pushTemplate);
+ });
+ }
+ }
+})
+
+.directive('navPop', function() {
+ return {
+ restrict: 'A',
+ link: function($scope, $element, $attr, navCtrl) {
+ var popTemplate = function(e) {
+ $scope.$apply(function() {
+ $scope.navController && navController.pop();
+ });
+ return false;
+ };
+
+ $element.bind('tap', popTemplate);
+
+ $scope.$on('$destroy', function() {
+ $element.unbind('tap', popTemplate);
+ });
+ }
+ }
+})
})();
diff --git a/js/ext/angular/test/nav.html b/js/ext/angular/test/nav.html
index 9289396f41..9a620fe50a 100644
--- a/js/ext/angular/test/nav.html
+++ b/js/ext/angular/test/nav.html
@@ -12,7 +12,6 @@
position: fixed;
width: 100%;
height: 100%;
- background-color: black;
}
.slide-in-slide-out {
/*
@@ -28,22 +27,21 @@
-
-
+
+
-
-
-
-
-
-
+
@@ -68,9 +66,6 @@
angular.module('navTest', ['ionic', 'ngAnimate'])
- .controller('AppCtrl', function($scope, $compile, $element) {
- $scope.navController.pushFromTemplate('page.html');
- })
.controller('CatsCtrl', function($scope, $compile, $element) {
$scope.$on('navContent.shown', function() {
diff --git a/js/ext/angular/test/navPush.html b/js/ext/angular/test/navPush.html
new file mode 100644
index 0000000000..94f620e5c6
--- /dev/null
+++ b/js/ext/angular/test/navPush.html
@@ -0,0 +1,83 @@
+
+
+
+ Nav Bars
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scss/_animations.scss b/scss/_animations.scss
index 07c97fb6de..77ff8b6ad3 100644
--- a/scss/_animations.scss
+++ b/scss/_animations.scss
@@ -41,6 +41,7 @@
}
.slide-in-left {
+ -webkit-transform: translate3d(0%,0,0);
&.ng-enter, > .ng-enter {
-webkit-animation-duration: 250ms;
-webkit-animation-fill-mode: both;
@@ -55,28 +56,80 @@
}
}
+
+.slide-in-left-add {
+ -webkit-transform: translate3d(100%,0,0);
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out;
+}
+.slide-in-left-add-active {
+ -webkit-animation-name: slideInLeft;
+}
+
+.slide-out-left {
+ -webkit-transform: translate3d(-100%,0,0);
+ &.ng-enter, > .ng-enter {
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out;
+ -webkit-animation-name: slideOutLeft;
+ }
+ &.ng-leave, > .ng-leave {
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out;
+ -webkit-animation-name: slideOutLeft;
+ }
+}
+
.slide-out-left {
- &.ng-enter, > .ng-enter {
- -webkit-animation-duration: 250ms;
- -webkit-animation-fill-mode: both;
- -webkit-animation-timing-function: ease-in-out;
- -webkit-animation-name: slideOutLeft;
- }
- &.ng-leave, > .ng-leave {
- -webkit-animation-duration: 250ms;
- -webkit-animation-fill-mode: both;
- -webkit-animation-timing-function: ease-in-out;
- -webkit-animation-name: slideInLeft;
- }
+}
+
+.slide-out-left-add {
+ -webkit-transform: translate3d(0,0,0);
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out;
+}
+.slide-out-left-add-active {
+ -webkit-animation-name: slideOutLeft;
}
.slide-in-right {
+ -webkit-transform: translate3d(0%,0,0);
&.ng-enter, > .ng-enter {
-webkit-animation-duration: 250ms;
-webkit-animation-fill-mode: both;
-webkit-animation-timing-function: ease-in-out;
-webkit-animation-name: slideInRight;
}
+ &.ng-leave, > .ng-leave {
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out;
+ -webkit-animation-name: slideInRight;
+ }
+}
+
+.slide-in-right-add {
+ -webkit-transform: translate3d(-100%,0,0);
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out;
+}
+.slide-in-right-add-active {
+ -webkit-animation-name: slideInRight;
+}
+
+.slide-out-right {
+ -webkit-transform: translate3d(100%,0,0);
+ &.ng-enter, > .ng-enter {
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out;
+ -webkit-animation-name: slideOutRight;
+ }
&.ng-leave, > .ng-leave {
-webkit-animation-duration: 250ms;
-webkit-animation-fill-mode: both;
@@ -86,18 +139,15 @@
}
.slide-out-right {
- &.ng-enter, > .ng-enter {
- -webkit-animation-duration: 250ms;
- -webkit-animation-fill-mode: both;
- -webkit-animation-timing-function: ease-in-out;
- -webkit-animation-name: slideOutRight;
- }
- &.ng-leave, > .ng-leave {
- -webkit-animation-duration: 250ms;
- -webkit-animation-fill-mode: both;
- -webkit-animation-timing-function: ease-in-out;
- -webkit-animation-name: slideInRight;
- }
+}
+.slide-out-right-add {
+ -webkit-transform: translate3d(0,0,0);
+ -webkit-animation-duration: 250ms;
+ -webkit-animation-fill-mode: both;
+ -webkit-animation-timing-function: ease-in-out;
+}
+.slide-out-right-add-active {
+ -webkit-animation-name: slideOutRight;
}
$slide-in-up-function: cubic-bezier(.1, .7, .1, 1);
diff --git a/scss/_nav.scss b/scss/_nav.scss
index 3f023ec375..163c55814a 100644
--- a/scss/_nav.scss
+++ b/scss/_nav.scss
@@ -4,7 +4,7 @@
* --------------------------------------------------
*/
- .nav-content {
+ .nav-page {
position: absolute;
width: 100%;
height: 100%;