mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
feat(platforms): Android and iOS Specific Styles and Transitions
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
18
js/angular/directive/navBackButton.js
vendored
18
js/angular/directive/navBackButton.js
vendored
@@ -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');
|
||||
|
||||
13
js/angular/directive/navBar.js
vendored
13
js/angular/directive/navBar.js
vendored
@@ -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
|
||||
|
||||
4
js/angular/directive/navView.js
vendored
4
js/angular/directive/navView.js
vendored
@@ -1,3 +1,7 @@
|
||||
IonicModule.constant('$ionicNavViewConfig', {
|
||||
transition: 'slide-left-right-ios7'
|
||||
});
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ionNavView
|
||||
|
||||
4
js/angular/directive/tab.js
vendored
4
js/angular/directive/tab.js
vendored
@@ -1,3 +1,7 @@
|
||||
IonicModule.constant('$ionicTabConfig', {
|
||||
type: ''
|
||||
});
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ionTab
|
||||
|
||||
13
js/angular/directive/tabs.js
vendored
13
js/angular/directive/tabs.js
vendored
@@ -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) {
|
||||
|
||||
66
js/angular/service/platform.js
vendored
66
js/angular/service/platform.js
vendored
@@ -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
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
|
||||
9
js/angular/service/viewService.js
vendored
9
js/angular/service/viewService.js
vendored
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
114
test/html/nav.html
Normal 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>
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user