feat(platforms): Android and iOS Specific Styles and Transitions

This commit is contained in:
Max Lynch
2014-06-11 16:48:53 -05:00
parent 8476f0cb3a
commit c30be67f65
19 changed files with 823 additions and 107 deletions

View File

@@ -38,5 +38,20 @@ var TestUtil = {
}
};
return timeout;
},
setPlatform: function(platformName) {
switch(platformName) {
case 'ios':
ionic.Platform.ua = 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25';
ionic.Platform.setPlatform('ios');
ionic.Platform.setVersion(null);
break;
case 'android':
ionic.Platform.ua = 'Mozilla/5.0 (Linux; U; Android 2.2.1; fr-ch; A43 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1';
ionic.Platform.setPlatform('android');
ionic.Platform.setVersion(undefined);
break;
}
}
};

View File

@@ -64,7 +64,11 @@ IonicModule
.directive('ionNavBackButton', [
'$animate',
'$rootScope',
function($animate, $rootScope) {
'$sanitize',
'$ionicNavBarConfig',
function($animate, $rootScope, $sanitize, $ionicNavBarConfig) {
var backIsShown = false;
//If the current viewstate does not allow a back button,
//always hide it.
@@ -76,7 +80,15 @@ function($animate, $rootScope) {
require: '^ionNavBar',
compile: function(tElement, tAttrs) {
tElement.addClass('button back-button ng-hide');
return function($scope, $element, $attr, navBarCtrl) {
console.log($attr.textFromTitle);
// Add a default back button icon based on the nav config, unless one is set
if($element[0].className.indexOf('ion-') < 0) {
$element.addClass($ionicNavBarConfig.backButtonIcon);
}
if (!$attr.ngClick) {
$scope.$navBack = navBarCtrl.back;
$element.on('click', function(event){
@@ -85,10 +97,12 @@ function($animate, $rootScope) {
});
});
}
//Make sure both that a backButton is allowed in the first place,
//and that it is shown by the current view.
$scope.$watch(function() {
if(isDefined($attr.fromTitle)) {
$element[0].innerHTML = '<span class="back-button-title">' + $sanitize($scope.oldTitle) + '</span>';
}
return !!(backIsShown && $scope.backButtonShown);
}, ionic.animationFrameThrottle(function(show) {
if (show) $animate.removeClass($element, 'ng-hide');

View File

@@ -1,4 +1,10 @@
IonicModule.constant('$ionicNavBarConfig', {
transition: 'nav-title-slide-ios7',
alignTitle: 'center',
backButtonIcon: 'ion-ios7-arrow-back'
});
/**
* @ngdoc directive
* @name ionNavBar
@@ -78,7 +84,8 @@ IonicModule
'$rootScope',
'$animate',
'$compile',
function($ionicViewService, $rootScope, $animate, $compile) {
'$ionicNavBarConfig',
function($ionicViewService, $rootScope, $animate, $compile, $ionicNavBarConfig) {
return {
restrict: 'E',
@@ -87,7 +94,7 @@ function($ionicViewService, $rootScope, $animate, $compile) {
compile: function(tElement, tAttrs) {
//We cannot transclude here because it breaks element.data() inheritance on compile
tElement
.addClass('bar bar-header nav-bar')
.addClass('bar bar-header nav-bar ' + $ionicNavBarConfig.transition)
.append(
'<div class="buttons left-buttons"> ' +
'</div>' +
@@ -100,7 +107,7 @@ function($ionicViewService, $rootScope, $animate, $compile) {
function prelink($scope, $element, $attr, navBarCtrl) {
navBarCtrl._headerBarView = new ionic.views.HeaderBar({
el: $element[0],
alignTitle: $attr.alignTitle || 'center'
alignTitle: $attr.alignTitle || $ionicNavBarConfig.alignTitle || 'center'
});
//defaults

View File

@@ -1,3 +1,7 @@
IonicModule.constant('$ionicNavViewConfig', {
transition: 'slide-left-right-ios7'
});
/**
* @ngdoc directive
* @name ionNavView

View File

@@ -1,3 +1,7 @@
IonicModule.constant('$ionicTabConfig', {
type: ''
});
/**
* @ngdoc directive
* @name ionTab

View File

@@ -1,3 +1,7 @@
IonicModule.constant('$ionicTabsConfig', {
position: '',
type: ''
});
/**
* @ngdoc directive
@@ -46,9 +50,10 @@
IonicModule
.directive('ionTabs', [
'$ionicViewService',
'$ionicTabsDelegate',
function($ionicViewService, $ionicTabsDelegate) {
'$ionicViewService',
'$ionicTabsDelegate',
'$ionicTabsConfig',
function($ionicViewService, $ionicTabsDelegate, $ionicTabsConfig) {
return {
restrict: 'E',
scope: true,
@@ -60,6 +65,8 @@ function($ionicViewService, $ionicTabsDelegate) {
var innerElement = jqLite('<div class="tabs"></div>');
innerElement.append(element.contents());
element.append(innerElement);
element.addClass($ionicTabsConfig.position);
element.addClass($ionicTabsConfig.type);
return { pre: prelink };
function prelink($scope, $element, $attr, tabsCtrl) {

View File

@@ -4,6 +4,69 @@ var PLATFORM_BACK_BUTTON_PRIORITY_MODAL = 200;
var PLATFORM_BACK_BUTTON_PRIORITY_ACTION_SHEET = 300;
var PLATFORM_BACK_BUTTON_PRIORITY_POPUP = 400;
var PLATFORM_BACK_BUTTON_PRIORITY_LOADING = 500;
function componentConfig(defaults) {
defaults.$get = function() { return defaults; }
return defaults;
}
IonicModule
.constant('$ionicPlatformDefaults', {
'ios': {
'$ionicNavBarConfig': {
transition: 'nav-title-slide-ios7',
alignTitle: 'center',
backButtonIcon: 'ion-ios7-arrow-back'
},
'$ionicNavViewConfig': {
transition: 'slide-left-right-ios7'
},
'$ionicTabsConfig': {
type: '',
position: ''
}
},
'android': {
'$ionicNavBarConfig': {
transition: 'no-animation',
alignTitle: 'left',
backButtonIcon: 'ion-android-arrow-back'
},
'$ionicNavViewConfig': {
transition: 'fade-implode'
},
'$ionicTabsConfig': {
type: 'tabs-striped',
position: ''
}
}
})
IonicModule.config([
'$ionicPlatformDefaults',
'$injector',
function($ionicPlatformDefaults, $injector) {
var platform = ionic.Platform.platform();
var applyConfig = function(platformDefaults) {
forEach(platformDefaults, function(defaults, constantName) {
extend($injector.get(constantName), defaults);
});
};
switch(platform) {
case 'ios':
applyConfig($ionicPlatformDefaults.ios);
break;
case 'android':
applyConfig($ionicPlatformDefaults.android);
break;
}
}]);
/**
* @ngdoc service
* @name $ionicPlatform
@@ -16,10 +79,10 @@ var PLATFORM_BACK_BUTTON_PRIORITY_LOADING = 500;
*/
IonicModule
.provider('$ionicPlatform', function() {
return {
$get: ['$q', '$rootScope', function($q, $rootScope) {
var self = {
/**
* @ngdoc method
* @name $ionicPlatform#onHardwareBackButton
@@ -138,3 +201,4 @@ IonicModule
};
});

View File

@@ -93,7 +93,8 @@ function($rootScope, $state, $location, $document, $animate, $ionicPlatform, $io
'$window',
'$injector',
'$animate',
function($rootScope, $state, $location, $window, $injector, $animate) {
'$ionicNavViewConfig',
function($rootScope, $state, $location, $window, $injector, $animate, $ionicNavViewConfig) {
var View = function(){};
View.prototype.initialize = function(data) {
@@ -440,6 +441,12 @@ function($rootScope, $state, $location, $window, $injector, $animate) {
className = el.getAttribute('animation');
el = el.parentElement;
}
// If they don't have an animation set explicitly, use the value in the config
if(!className) {
return $ionicNavViewConfig.transition;
}
return className;
}

View File

@@ -334,6 +334,8 @@ $slide-in-up-function: cubic-bezier(.1, .7, .1, 1);
*/
$ios7-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1);
$ios7-transition-duration: 340ms;
$ios-transition-box-shadow-start: -500px 0px 500px rgba(0,0,0,0), -5px 0px 5px rgba(0,0,0,0);
$ios-transition-box-shadow-end: -500px 0px 500px rgba(0,0,0,0.10), -5px 0px 5px rgba(0,0,0,0.2);
.slide-left-right-ios7,
.slide-right-left-ios7.reverse {
@@ -347,9 +349,11 @@ $ios7-transition-duration: 340ms;
left: -1px;
width: auto;
&:not(.bar) {
border-right: 1px solid #ddd;
border-left: 1px solid #ddd;
border-right: 1px solid transparent;
border-left: 1px solid transparent;
}
border-right: none;
border-left: none;
}
> .ng-enter, &.ng-enter {
/* NEW content placed far RIGHT BEFORE it slides IN from the RIGHT */
@@ -377,8 +381,8 @@ $ios7-transition-duration: 340ms;
bottom: 0;
left: -1px;
width: auto;
border-right: 1px solid #ddd;
border-left: 1px solid #ddd;
border-right: 1px solid transparent;
border-left: 1px solid transparent;
}
> .ng-enter, &.ng-enter {
/* NEW content placed far LEFT BEFORE it slides IN from the LEFT */
@@ -396,9 +400,169 @@ $ios7-transition-duration: 340ms;
@include translate3d(100%, 0, 0);
}
}
.grade-a {
.slide-left-right-ios7, .slide-right-left-ios7.reverse {
> .ng-enter, &.ng-enter {
box-shadow: $ios-transition-box-shadow-start;
}
> .ng-enter.ng-enter-active, &.ng-enter.ng-enter-active {
box-shadow: $ios-transition-box-shadow-end;
}
}
.slide-left-right-ios7.reverse, .slide-right-left-ios7 {
> .ng-leave, &.ng-leave {
box-shadow: $ios-transition-box-shadow-end;
}
> .ng-leave.ng-leave-active, &.ng-leave.ng-leave-active {
box-shadow: $ios-transition-box-shadow-start;
}
}
}
/**
* Android style "pop in" with fade and scale
*/
.fade-explode {
> .ng-enter, &.ng-enter,
> .ng-leave, &.ng-leave {
@include transition(all ease-out 300ms);
position: absolute;
top: 0;
right: -1px;
bottom: 0;
left: -1px;
width: auto;
&:not(.bar) {
border-right: 1px solid #ddd;
border-left: 1px solid #ddd;
}
}
> .ng-enter, &.ng-enter {
/* NEW content placed far RIGHT BEFORE it slides IN from the RIGHT */
@include scale(1.6);
opacity: 0;
z-index: 2;
}
> .ng-leave, &.ng-leave {
z-index: 1;
}
> .ng-enter.ng-enter-active, &.ng-enter.ng-enter-active {
/* NEW content ACTIVELY sliding IN from the RIGHT */
@include scale(1);
opacity: 1;
}
> .ng-leave.ng-leave-active, &.ng-leave.ng-leave-active {
/* OLD content ACTIVELY sliding OUT to the LEFT */
@include scale(0.95);
}
}
.fade-explode.reverse {
> .ng-enter, &.ng-enter, > .ng-leave, &.ng-leave {
@include transition(all ease-out 300ms);
position: absolute;
top: 0;
right: -1px;
bottom: 0;
left: -1px;
width: auto;
&:not(.bar) {
border-right: 1px solid #ddd;
border-left: 1px solid #ddd;
}
}
> .ng-enter, &.ng-enter {
/* NEW content placed far LEFT BEFORE it slides IN from the LEFT */
@include scale(0.95);
opacity: 0;
z-index: 1;
}
> .ng-leave, &.ng-leave {
@include scale(1);
opacity: 1;
z-index: 2;
}
> .ng-enter.ng-enter-active, &.ng-enter.ng-enter-active {
@include scale(1);
opacity: 1;
}
> .ng-leave.ng-leave-active, &.ng-leave.ng-leave-active {
@include scale(1.6);
opacity: 0;
}
}
/**
* Android style "pop in" with fade and scale
*/
.fade-implode {
> .ng-enter, &.ng-enter,
> .ng-leave, &.ng-leave {
@include transition(all ease-out 200ms);
position: absolute;
top: 0;
right: -1px;
bottom: 0;
left: -1px;
width: auto;
&:not(.bar) {
border-right: 1px solid #ddd;
border-left: 1px solid #ddd;
}
}
> .ng-enter, &.ng-enter {
/* NEW content placed far RIGHT BEFORE it slides IN from the RIGHT */
@include scale(0.8);
opacity: 0;
z-index: 2;
}
> .ng-leave, &.ng-leave {
z-index: 1;
}
> .ng-enter.ng-enter-active, &.ng-enter.ng-enter-active {
/* NEW content */
@include scale(1);
opacity: 1;
}
> .ng-leave.ng-leave-active, &.ng-leave.ng-leave-active {
}
}
.fade-implode.reverse {
> .ng-enter, &.ng-enter, > .ng-leave, &.ng-leave {
@include transition(all ease-out 200ms);
position: absolute;
top: 0;
right: -1px;
bottom: 0;
left: -1px;
width: auto;
border-right: 1px solid #ddd;
border-left: 1px solid #ddd;
}
> .ng-enter, &.ng-enter {
@include scale(1);
opacity: 1;
z-index: 1;
}
> .ng-leave, &.ng-leave {
@include scale(1);
opacity: 1;
z-index: 2;
}
> .ng-enter.ng-enter-active, &.ng-enter.ng-enter-active {
opacity: 1;
}
> .ng-leave.ng-leave-active, &.ng-leave.ng-leave-active {
@include scale(0.8);
opacity: 0;
}
}
/**
* Simple slide-in animation
*/
.slide-in-left {
@include translate3d(0%,0,0);
&.ng-enter, > .ng-enter {
@@ -619,3 +783,5 @@ $nav-title-slide-ios7-delay: $ios7-transition-duration;
}
}
}

View File

@@ -177,6 +177,16 @@
}
}
&.back-button {
padding: 0;
opacity: 0.8;
.back-button-title {
display: inline-block;
vertical-align: middle;
margin-left: 4px;
}
}
&.back-button.active,
&.back-button.activated {
opacity: 1;

View File

@@ -5,6 +5,96 @@
* Platform specific tweaks
*/
/**
* Apply roboto font
*/
.roboto {
font-family: "Roboto", $font-family-base;
input {
font-family: "Roboto", $font-family-base;
}
}
.platform-android {
.bar {
padding: 0;
line-height: 40px;
.button {
line-height: 40px;
}
.button-icon:before {
font-size: 24px;
}
}
.back-button {
&.button-icon:before {
line-height: 40px;
}
margin-left: -3px;
padding: 0px 2px !important;
&.ion-android-arrow-back:before {
font-size: 12px;
}
&.back-button.active,
&.back-button.activated {
background-color: rgba(0,0,0,0.1);
}
}
.item-divider {
background: none;
border-top-width: 0;
border-bottom-width: 2px;
text-transform: uppercase;
margin-top: 10px;
font-size: 14px;
}
.item {
border-left-width: 0;
border-right-width: 0;
}
.item-divider ~ .item:not(.item-divider) {
border-bottom-width: 0;
}
.back-button:not(.ng-hide) + .left-buttons + .title {
// Don't allow normal titles in this mode
display: none;
}
.bar .title {
text-align: left;
font-weight: normal;
}
/*
font-family: 'Roboto';
h1, h2, h3, h4, h5 {
font-family: 'Roboto', $font-family-base;
}
.tab-item {
font-family: 'Roboto', $font-family-base;
}
input, button, select, textarea {
font-family: 'Roboto', $font-family-base;
}
*/
}
.platform-ios7.platform-cordova {
// iOS7 has a status bar which sits on top of the header.
// Bump down everything to make room for it. However, if

View File

@@ -1,4 +1,3 @@
/**
* Tabs
* --------------------------------------------------
@@ -89,6 +88,69 @@
@include tab-badge-style($tabs-dark-text, $tabs-dark-bg);
}
@mixin tabs-striped($style, $color) {
&.#{$style} {
.tab-item.tab-item-active,
.tab-item.active,
.tab-item.activated {
margin-top: -4px;
color: $color;
border-style: solid;
border-width: $tabs-striped-border-width 0 0 0;
border-color: $color;
}
}
}
.tabs-striped {
.tabs {
background-color: white;
background-image: none;
border: none;
}
@include tabs-striped('tabs-light', $light);
@include tabs-striped('tabs-stable', $stable);
@include tabs-striped('tabs-positive', $positive);
@include tabs-striped('tabs-calm', $calm);
@include tabs-striped('tabs-assertive', $assertive);
@include tabs-striped('tabs-balanced', $balanced);
@include tabs-striped('tabs-energized', $energized);
@include tabs-striped('tabs-royal', $royal);
@include tabs-striped('tabs-dark', $dark);
&.tabs-icon-only .icon {
}
.tab-item {
color: $tabs-striped-off-color;
opacity: $tabs-striped-off-opacity;
}
.tab-item + .tab-item:before {
border-left: 1px solid #ccc;
display: block;
float: left;
width: 2px;
height: 26px;
margin: 11px auto;
content: " ";
}
}
.tabs-top {
&.tabs-striped {
.tab-item.tab-item-active,
.tab-item.active,
.tab-item.activated {
margin-top: 0;
margin-bottom: -4px;
border-width: 0px 0px $tabs-striped-border-width 0px !important;
}
}
}
/* Allow parent element to have tabs-top */
/* If you change this, change platform.scss as well */
.tabs-top > .tabs,
@@ -97,6 +159,7 @@
padding-top: 0;
padding-bottom: 2px;
background-position: bottom;
}
.tab-item {
@@ -176,6 +239,7 @@
line-height: inherit;
}
.tab-item.has-badge {
position: relative;
}
@@ -191,6 +255,7 @@
line-height: $tabs-badge-font-size + 4;
}
/* Navigational tab */
/* Active state for tab */
@@ -243,3 +308,11 @@
cursor: default;
pointer-events: none;
}
/** Platform styles **/
.tab-item.tab-item-ios {
}
.tab-item.tab-item-android {
border-top: 2px solid inherit;
}

View File

@@ -276,6 +276,10 @@ $tabs-default-text: $tabs-stable-text !default;
$tab-item-max-width: 150px !default;
$tabs-striped-off-color: #000;
$tabs-striped-off-opacity: 0.4;
$tabs-striped-border-width: 4px;
// Items
// -------------------------------

114
test/html/nav.html Normal file
View File

@@ -0,0 +1,114 @@
<html ng-app="nav">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
<title>navViews and ion-tabs w/ nested navViews</title>
<link rel="stylesheet" href="../../../../dist/css/ionic.css">
<script src="../../../../dist/js/ionic.bundle.js"></script>
<script src="dom-trace.js"></script>
</head>
<body>
<div>
<ion-nav-bar class="bar-positive">
<ion-nav-back-button class="button-icon" from-title>
</ion-nav-back-button>
</ion-nav-bar>
<ion-nav-view></ion-nav-view>
</div>
<script id="page1.html" type="text/ng-template">
<ion-view title="Page 1">
<ion-nav-buttons side="right">
<button class="button button-icon ion-android-search"></button>
<button class="button button-icon ion-android-information"></button>
<button class="button button-icon ion-android-share"></button>
</ion-nav-buttons>
<ion-content padding="true">
<ion-list>
<div class="item item-divider">
Things
</div>
<ion-item ng-repeat="item in items" href="#/page2">
Item {{$index}}
</ion-item>
<div class="item item-divider">
Stuff
</div>
<ion-item ng-repeat="item in items2" href="#/page2">
Item {{$index}}
</ion-item>
</ion-list>
</ion-content>
</ion-view>
</script>
<script id="page2.html" type="text/ng-template">
<ion-view title="Page 2">
<ion-content padding="true">
<a ng-click="goBack()" class="button button-positive">Back</a>
<a href="#/page3" class="button button-positive">Page 3</a>
</ion-content>
</ion-view>
</script>
<script id="page3.html" type="text/ng-template">
<ion-view title="Page 3">
<ion-content padding="true">
<a ng-click="goBack()" class="button button-positive">Back</a>
<a href="#/page1" class="button button-positive">Page 1</a>
</ion-content>
</ion-view>
</script>
<script>
angular.module('nav', ['ionic'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('page1', {
url: "/page1",
templateUrl: "page1.html",
controller: 'Page1Ctrl'
})
.state('page2', {
url: "/page2",
templateUrl: "page2.html",
controller: 'Page2Ctrl'
})
.state('page3', {
url: "/page3",
templateUrl: "page3.html",
controller: 'Page3Ctrl'
})
$urlRouterProvider.otherwise("/page1");
})
.controller('Page1Ctrl', function($scope) {
$scope.items = [];
for(var i = 0; i < 4; i++) {
$scope.items.push({});
}
$scope.items2 = [];
for(var i = 0; i < 4; i++) {
$scope.items2.push({});
}
})
.controller('Page2Ctrl', function($scope, $ionicNavBarDelegate) {
$scope.goBack = function() {
$ionicNavBarDelegate.back();
};
})
.controller('Page3Ctrl', function($scope, $ionicNavBarDelegate) {
$scope.goBack = function() {
$ionicNavBarDelegate.back();
};
})
</script>
</body>
</html>

View File

@@ -8,130 +8,155 @@
<link rel="stylesheet" href="../../../../dist/css/ionic.css">
<script src="../../../../dist/js/ionic.bundle.js"></script>
<link href='http://fonts.googleapis.com/css?family=Roboto:400,100,100italic,300,300italic,400italic,500,500italic,700,700italic,900,900italic' rel='stylesheet' type='text/css'>
<style>
/**
* Some component specific animations
*/
.nav-title-fade-only:not(.no-animation) .button.back-button {
-webkit-transition: all 340ms;
-moz-transition: all 340ms;
transition: all 340ms;
-webkit-transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1);
-moz-transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1);
transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1);
opacity: 1; }
.nav-title-fade-only:not(.no-animation) .button.back-button.active, .nav-title-fade-only:not(.no-animation) .button.back-button.activated {
opacity: 0.5; }
.nav-title-fade-only:not(.no-animation) .button.back-button.ng-hide {
opacity: 0; }
.nav-title-fade-only:not(.no-animation) .button.back-button.ng-hide-add, .nav-title-fade-only:not(.no-animation) .button.back-button.ng-hide-remove {
display: block !important; }
.nav-title-fade-only:not(.no-animation) .button.back-button.ng-hide-add {
position: absolute; }
.nav-title-fade-only > .ng-enter, .nav-title-fade-only.ng-enter, .nav-title-fade-only > .ng-leave, .nav-title-fade-only.ng-leave {
-webkit-transition: all 340ms;
-moz-transition: all 340ms;
transition: all 340ms;
-webkit-transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1);
-moz-transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1);
transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1);
opacity: 1; }
.nav-title-fade-only > .ng-enter, .nav-title-fade-only.ng-enter {
opacity: 0; }
.nav-title-fade-only > .ng-enter.ng-enter-active, .nav-title-fade-only.ng-enter.ng-enter-active {
opacity: 1; }
.nav-title-fade-only > .ng-leave.ng-leave-active, .nav-title-fade-only.ng-leave.ng-leave-active {
opacity: 0; }
.nav-title-fade-only.reverse > .ng-enter, .nav-title-fade-only.reverse.ng-enter, .nav-title-fade-only.reverse > .ng-leave, .nav-title-fade-only.reverse.ng-leave {
-webkit-transition: all 340ms;
-moz-transition: all 340ms;
transition: all 340ms;
-webkit-transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1);
-moz-transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1);
transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1);
opacity: 1; }
.nav-title-fade-only.reverse > .ng-enter, .nav-title-fade-only.reverse.ng-enter {
opacity: 0; }
.nav-title-fade-only.reverse > .ng-enter.ng-enter-active, .nav-title-fade-only.reverse.ng-enter.ng-enter-active {
opacity: 1; }
.nav-title-fade-only.reverse > .ng-leave.ng-leave-active, .nav-title-fade-only.reverse.ng-leave.ng-leave-active {
opacity: 0; }
</style>
</head>
<body>
<div ng-controller="AppCtrl">
<ion-nav-bar class="nav-title-slide-ios7 bar-positive">
<ion-nav-back-button class="button-icon icon ion-ios7-arrow-back">
Back
</ion-nav-back-button>
</ion-nav-bar>
<ion-nav-view animation="slide-left-right-ios7"></ion-nav-view>
<ion-nav-view></ion-nav-view>
</div>
<script id="home.html" type="text/ng-template">
<ion-view title="Home">
<!--
<ion-nav-buttons side="left">
<button
class="button button-icon icon ion-navicon"
menu-toggle="left">
</button>
</ion-nav-buttons>
<ion-nav-buttons side="right">
<button
class="button button-icon icon ion-close-circled"
ng-click="requestClearNotifications()">
</button>
<button
class="button button-icon icon ion-alert-circled"
ng-show="$root.showButton">
</button>
</ion-nav-buttons>
-->
<ion-nav-bar class="bar-positive">
<ion-nav-back-button class="button-icon icon ion-ios7-arrow-back">
Back
</ion-nav-back-button>
</ion-nav-bar>
<ion-content>
<a href="#/friends" class="button button-block button-primary">Friends</a>
<div class="list">
<a href="#/about" class="button button-block button-primary">Friends</a>
<div class="list">
<label class="item item-input item-select">
<div class="input-label">
Lightsaber
</div>
<select>
<option>Blue</option>
<option selected>Green</option>
<option>Red</option>
</select>
</label>
<label class="item item-input item-select">
<div class="input-label">
Lightsaber
</div>
<select>
<option>Blue</option>
<option selected>Green</option>
<option>Red</option>
</select>
</label>
</div>
</div>
</ion-content>
</ion-view>
</script>
<script id="friends.html" type="text/ng-template">
<ion-view title="Friends">
<!--
<ion-nav-buttons side="left">
<button
class="button button-icon icon ion-navicon"
menu-toggle="left">
</button>
</ion-nav-buttons>
<ion-nav-buttons side="right">
<button
class="button button-icon icon ion-close-circled"
ng-click="requestClearNotifications()">
</button>
<button
class="button button-icon icon ion-alert-circled"
ng-show="$root.showButton">
</button>
</ion-nav-buttons>
-->
<ion-nav-bar class="bar-positive">
<ion-nav-back-button class="button-icon icon ion-ios7-arrow-back">
Back
</ion-nav-back-button>
</ion-nav-bar>
<ion-content>
<div class="list">
<div class="list">
<label class="item item-input item-select">
<div class="input-label">
Lightsaber
</div>
<select>
<option>Blue</option>
<option selected>Green</option>
<option>Red</option>
</select>
</label>
<label class="item item-input item-select">
<div class="input-label">
Lightsaber
</div>
<select>
<option>Blue</option>
<option selected>Green</option>
<option>Red</option>
</select>
</label>
</div>
</div>
</ion-content>
</ion-view>
</script>
<script id="about.html" type="text/ng-template">
<ion-view title="Home">
<!--
<ion-nav-buttons side="left">
<button
class="button button-icon icon ion-navicon"
menu-toggle="left">
</button>
</ion-nav-buttons>
<ion-nav-buttons side="right">
<button
class="button button-icon icon ion-close-circled"
ng-click="requestClearNotifications()">
</button>
<button
class="button button-icon icon ion-alert-circled"
ng-show="$root.showButton">
</button>
</ion-nav-buttons>
-->
<ion-tabs
class="tabs-icon-only tabs-positive"
animation="fade-in-out"
controller-changed="onControllerChanged(oldController, oldIndex, newController, newIndex)">
<ion-content>
<h1>About</h1>
</ion-content>
<ion-tab title="Home" icon="ion-home">
<header class="bar bar-header bar-positive">
<h1 class="title"><i class="icon ion-android-book"></i> Read Now</h1>
</header>
<ion-content class="has-header has-subheader" on-refresh="onRefresh()" on-scroll="scroll(scrollTop, scrollLeft)">
</ion-content>
</ion-tab>
<ion-tab title="Friends" icon="ion-search">
<header class="bar bar-header bar-positive">
<h1 class="title">Friends</h1>
</header>
<ion-content class="has-header has-subheader" on-refresh="onRefresh()" on-scroll="scroll(scrollTop, scrollLeft)">
</ion-content>
</ion-tab>
<ion-tab title="About" icon="ion-heart">
<header class="bar bar-header bar-positive">
<h1 class="title">About</h1>
</header>
<ion-content class="has-header has-subheader" on-refresh="onRefresh()" on-scroll="scroll(scrollTop, scrollLeft)">
</ion-content>
</ion-tab>
</ion-tabs>
</ion-view>
</script>
<script>
angular.module('navState', ['ionic'])
.config(function($ionicTabsConfig) {
$ionicTabsConfig.tabsPosition = '';
//$ionicNavBarConfig.transition = 'nav-title-fade-only';
})
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider

View File

@@ -92,7 +92,8 @@ describe('bar directives', function() {
function setup(attrs) {
var el;
ionic.views.HeaderBar = function(opts) {
this.opts = opts;
this.alignTitle = opts.alignTitle;
this.el = opts.el;
this.align = jasmine.createSpy('align');
};
inject(function($compile, $rootScope) {

View File

@@ -1,3 +1,4 @@
describe('ionNavBackButton directive', function() {
beforeEach(module('ionic'));
@@ -76,4 +77,29 @@ describe('ionNavBackButton directive', function() {
expect(el.scope().$navBack).not.toHaveBeenCalled();
expect(el.scope().doSomething).toHaveBeenCalled();
});
describe('ionNavBackButton directive: Platforms', function() {
describe('ionNavBackButton directive: iOS Platform', function() {
beforeEach(function($provide) {
TestUtil.setPlatform('ios');
});
it('Should set default back button icon from ionicNavBarConfig ', inject(function($ionicNavBarConfig) {
var el = setup();
expect(el.hasClass('ion-ios7-arrow-back')).toBe(true);
}));
});
describe('ionNavBackButton directive: Android Platform', function() {
beforeEach(function($provide) {
TestUtil.setPlatform('android');
});
it('Should set default back button icon from ionicNavBarConfig ', inject(function($ionicNavBarConfig) {
var el = setup();
expect(el.hasClass('ion-android-arrow-back')).toBe(true);
}));
});
});
});

View File

@@ -294,4 +294,60 @@ describe('ionNavBar', function() {
expect(el.hasClass('reverse')).toBe(false);
});
});
describe('platforms', function() {
function setup(attrs, content) {
var el;
inject(function($compile, $rootScope) {
el = $compile('<ion-nav-bar '+(attrs||'')+'>'+(content||'')+'</ion-nav-bar>')($rootScope.$new());
$rootScope.$apply();
});
return el;
}
describe('iOS', function() {
beforeEach(module('ionic', function($provide) {
TestUtil.setPlatform('ios');
$provide.constant('$ionicNavBarConfig', {
alignTitle: 'center',
transition: 'nav-title-slide-ios7',
backButtonIcon: 'ion-ios7-arrow-back'
});
}));
it('should have correct title align', function() {
var el = setup();
var controller = el.controller('ionNavBar');
expect(controller._headerBarView.alignTitle).toBe('center');
});
it('Should have correct transition', function() {
var el = setup();
expect(el.hasClass('nav-title-slide-ios7')).toBe(true);
});
});
describe('Android', function() {
beforeEach(module('ionic', function($provide) {
TestUtil.setPlatform('android');
$provide.constant('$ionicNavBarConfig', {
alignTitle: 'left',
transition: 'no-animation',
backButtonIcon: 'ion-android-back'
});
}));
it('should have correct title align', function() {
var el = setup();
var controller = el.controller('ionNavBar');
expect(controller._headerBarView.alignTitle).toBe('left');
});
it('Should have correct transition', function() {
var el = setup();
// Nav bar titles don't animation by default on Android
expect(el.hasClass('no-animation')).toBe(true);
});
});
});
});

View File

@@ -260,6 +260,35 @@ describe('tabs', function() {
var el = setup('', '<div class="content"></div>');
expect(el[0].querySelector('.tabs .content')).toBeTruthy();
});
describe('platform Styles', function() {
describe('iOS', function() {
beforeEach(module('ionic', function($provide) {
TestUtil.setPlatform('ios');
$provide.constant('$ionicTabsConfig', {
type: ''
});
}));
it('should set iOS style', function() {
var el = setup();
expect(el.hasClass('tabs-striped')).not.toBe(true);
});
});
describe('android', function() {
beforeEach(module('ionic', function($provide) {
TestUtil.setPlatform('android');
$provide.constant('$ionicTabsConfig', {
type: 'tabs-striped'
});
}));
it('should set Android style', function() {
var el = setup();
expect(el.hasClass('tabs-striped')).toBe(true);
});
});
});
});
describe('ionicTab controller', function() {