Skip to content

Commit b69aa54

Browse files
committed
feat(splitView): expose side menu on large viewport
Ability to keep a left menu exposed on larger viewports, such as a landscape tablet. Added the `expose-aside-menu` attribute directive.
1 parent 853fad1 commit b69aa54

File tree

11 files changed

+216
-47
lines changed

11 files changed

+216
-47
lines changed

Diff for: config/docs/templates/api_menu_version.template.html

+6
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,12 @@
469469
</a>
470470
</li>
471471

472+
<li>
473+
<a href="{{ page.versionHref }}/api/directive/exposeAsideWhen/">
474+
expose-aside-when
475+
</a>
476+
</li>
477+
472478
<li>
473479
<a href="{{ page.versionHref }}/api/directive/menuToggle/">
474480
menu-toggle

Diff for: js/angular/controller/sideMenuController.js

+30-4
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ IonicModule
44
'$attrs',
55
'$ionicSideMenuDelegate',
66
'$ionicPlatform',
7-
function($scope, $attrs, $ionicSideMenuDelegate, $ionicPlatform) {
7+
'$document',
8+
function($scope, $attrs, $ionicSideMenuDelegate, $ionicPlatform, $document) {
89
var self = this;
910
var rightShowing, leftShowing, isDragging;
10-
var startX, lastX, offsetX;
11+
var startX, lastX, offsetX, isAsideExposed;
1112

1213
self.$scope = $scope;
1314

@@ -132,9 +133,9 @@ function($scope, $attrs, $ionicSideMenuDelegate, $ionicPlatform) {
132133
}
133134

134135
if(percentage !== 0) {
135-
document.body.classList.add('menu-open');
136+
$document[0].body.classList.add('menu-open');
136137
} else {
137-
document.body.classList.remove('menu-open');
138+
$document[0].body.classList.remove('menu-open');
138139
}
139140
};
140141

@@ -253,8 +254,32 @@ function($scope, $attrs, $ionicSideMenuDelegate, $ionicPlatform) {
253254
}
254255
};
255256

257+
self.isAsideExposed = function() {
258+
return !!isAsideExposed;
259+
};
260+
261+
self.exposeAside = function(shouldExposeAside) {
262+
isAsideExposed = shouldExposeAside;
263+
264+
// set the left marget width if it should be exposed
265+
// otherwise set false so there's no left margin
266+
self.content.setMarginLeft( isAsideExposed ? self.left.width : 0 );
267+
268+
self.$scope.$emit('$ionicExposeAside', isAsideExposed);
269+
};
270+
271+
self.activeAsideResizing = function(isResizing) {
272+
if(isResizing) {
273+
$document[0].body.classList.add('aside-resizing');
274+
} else {
275+
$document[0].body.classList.remove('aside-resizing');
276+
}
277+
};
278+
256279
// End a drag with the given event
257280
self._endDrag = function(e) {
281+
if(isAsideExposed) return;
282+
258283
if(isDragging) {
259284
self.snapToRest(e);
260285
}
@@ -265,6 +290,7 @@ function($scope, $attrs, $ionicSideMenuDelegate, $ionicPlatform) {
265290

266291
// Handle a drag event
267292
self._handleDrag = function(e) {
293+
if(isAsideExposed) return;
268294

269295
// If we don't have start coords, grab and store them
270296
if(!startX) {

Diff for: js/angular/directive/exposeAsideWhen.js

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* @ngdoc directive
3+
* @name exposeAsideWhen
4+
* @module ionic
5+
* @restrict A
6+
* @parent ionic.directive:ionSideMenus
7+
*
8+
* @description
9+
* It is common for a tablet application to hide a menu when in portrait mode, but to show the
10+
* same menu on the left side when the tablet is in landscape mode. The `exposeAsideWhen` attribute
11+
* directive can be used to accomplish a similar interface.
12+
*
13+
* By default, side menus are hidden underneath its side menu content, and can be opened by either
14+
* swiping the content left or right, or toggling a button to show the side menu. However, by adding the
15+
* `exposeAsideWhen` attribute directive to an {@link ionic.directive:ionSideMenu} element directive,
16+
* a side menu can be given instructions on "when" the menu should be exposed (always viewable). For
17+
* example, the `expose-aside-when="large"` attribute will keep the side menu hidden when the viewport's
18+
* width is less than `768px`, but when the viewport's width is `768px` or greater, the menu will then
19+
* always be shown and can no longer be opened or closed like it could when it was hidden for smaller
20+
* viewports.
21+
*
22+
* Using `large` as the attribute's value is a shortcut value to `(min-width:768px)` since it is
23+
* the most common use-case. However, for added flexibility, any valid media query could be added
24+
* as the value, such as `(min-width:600px)` or even multiple queries such as
25+
* `(min-width:750px) and (max-width:1200px)`.
26+
27+
* @usage
28+
* ```html
29+
* <ion-side-menus>
30+
* <!-- Center content -->
31+
* <ion-side-menu-content>
32+
* </ion-side-menu-content>
33+
*
34+
* <!-- Left menu -->
35+
* <ion-side-menu expose-aside-when="large">
36+
* </ion-side-menu>
37+
* </ion-side-menus>
38+
* ```
39+
* For a complete side menu example, see the
40+
* {@link ionic.directive:ionSideMenus} documentation.
41+
*/
42+
IonicModule
43+
.directive('exposeAsideWhen', ['$window', function($window) {
44+
return {
45+
restrict: 'A',
46+
require: '^ionSideMenus',
47+
link: function($scope, $element, $attr, sideMenuCtrl) {
48+
49+
function checkAsideExpose() {
50+
var mq = $attr.exposeAsideWhen == 'large' ? '(min-width:768px)' : $attr.exposeAsideWhen;
51+
sideMenuCtrl.exposeAside( $window.matchMedia(mq).matches );
52+
sideMenuCtrl.activeAsideResizing(false);
53+
}
54+
55+
function onResize() {
56+
sideMenuCtrl.activeAsideResizing(true);
57+
debouncedCheck();
58+
}
59+
60+
var debouncedCheck = ionic.debounce(function() {
61+
$scope.$apply(function(){
62+
checkAsideExpose();
63+
});
64+
}, 300, false);
65+
66+
checkAsideExpose();
67+
68+
ionic.on('resize', onResize, $window);
69+
70+
$scope.$on('$destroy', function(){
71+
ionic.off('resize', onResize, $window);
72+
});
73+
74+
}
75+
};
76+
}]);
77+

Diff for: js/angular/directive/sideMenuContent.js

+21-5
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ IonicModule
3030
.directive('ionSideMenuContent', [
3131
'$timeout',
3232
'$ionicGesture',
33-
function($timeout, $ionicGesture) {
33+
'$window',
34+
function($timeout, $ionicGesture, $window) {
3435

3536
return {
3637
restrict: 'EA', //DEPRECATED 'A'
@@ -126,28 +127,43 @@ function($timeout, $ionicGesture) {
126127
}
127128
}
128129

129-
sideMenuCtrl.setContent({
130+
var content = {
130131
element: element[0],
131132
onDrag: function(e) {},
132133
endDrag: function(e) {},
133134
getTranslateX: function() {
134135
return $scope.sideMenuContentTranslateX || 0;
135136
},
136137
setTranslateX: ionic.animationFrameThrottle(function(amount) {
137-
$element[0].style[ionic.CSS.TRANSFORM] = 'translate3d(' + amount + 'px, 0, 0)';
138+
var xTransform = content.offsetX + amount;
139+
$element[0].style[ionic.CSS.TRANSFORM] = 'translate3d(' + xTransform + 'px,0,0)';
138140
$timeout(function() {
139141
$scope.sideMenuContentTranslateX = amount;
140142
});
141143
}),
144+
setMarginLeft: ionic.animationFrameThrottle(function(amount) {
145+
if(amount) {
146+
$element[0].style[ionic.CSS.TRANSFORM] = 'translate3d(' + amount + 'px,0,0)';
147+
$element[0].style.width = ($window.innerWidth - amount) + 'px';
148+
content.offsetX = amount;
149+
} else {
150+
$element[0].style[ionic.CSS.TRANSFORM] = 'translate3d(0,0,0)';
151+
$element[0].style.width = '';
152+
content.offsetX = 0;
153+
}
154+
}),
142155
enableAnimation: function() {
143156
$scope.animationEnabled = true;
144157
$element[0].classList.add('menu-animated');
145158
},
146159
disableAnimation: function() {
147160
$scope.animationEnabled = false;
148161
$element[0].classList.remove('menu-animated');
149-
}
150-
});
162+
},
163+
offsetX: 0
164+
};
165+
166+
sideMenuCtrl.setContent(content);
151167

152168
// add gesture handlers
153169
var dragRightGesture = $ionicGesture.on('dragright', onDragX, $element);

Diff for: js/angular/directive/sideMenus.js

+27-3
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,20 @@ IonicModule
1717
* links and buttons within `ion-side-menu` content, so that when the element is
1818
* clicked then the opened side menu will automatically close.
1919
*
20+
* By default, side menus are hidden underneath its side menu content, and can be opened by
21+
* either swiping the content left or right, or toggling a button to show the side menu. However,
22+
* by adding the {@link ionic.directive:exposeAsideWhen} attribute directive to an
23+
* {@link ionic.directive:ionSideMenu} element directive, a side menu can be given instructions
24+
* on "when" the menu should be exposed (always viewable).
25+
*
2026
* ![Side Menu](http://ionicframework.com.s3.amazonaws.com/docs/controllers/sidemenu.gif)
2127
*
2228
* For more information on side menus, check out:
2329
*
2430
* - {@link ionic.directive:ionSideMenuContent}
2531
* - {@link ionic.directive:ionSideMenu}
2632
* - {@link ionic.directive:menuClose}
33+
* - {@link ionic.directive:exposeAsideWhen}
2734
*
2835
* @usage
2936
* To use side menus, add an `<ion-side-menus>` parent element,
@@ -58,18 +65,35 @@ IonicModule
5865
*
5966
*/
6067
.directive('ionSideMenus', ['$document', function($document) {
68+
69+
var ASIDE_OPEN_CSS = 'aside-open';
70+
6171
return {
6272
restrict: 'ECA',
6373
controller: '$ionicSideMenus',
6474
compile: function(element, attr) {
6575
attr.$set('class', (attr['class'] || '') + ' view');
6676

67-
return function($scope) {
77+
return { pre: prelink };
78+
function prelink($scope) {
79+
var bodyClassList = $document[0].body.classList;
80+
81+
$scope.$on('$ionicExposeAside', function(evt, isAsideExposed){
82+
if(!$scope.$exposeAside) $scope.$exposeAside = {};
83+
$scope.$exposeAside.active = isAsideExposed;
84+
if(isAsideExposed) {
85+
bodyClassList.add(ASIDE_OPEN_CSS);
86+
} else {
87+
bodyClassList.remove(ASIDE_OPEN_CSS);
88+
}
89+
});
90+
6891
$scope.$on('$destroy', function(){
69-
$document[0].body.classList.remove('menu-open');
92+
bodyClassList.remove('menu-open');
93+
bodyClassList.remove(ASIDE_OPEN_CSS);
7094
});
7195

72-
};
96+
}
7397
}
7498
};
7599
}]);

Diff for: scss/_menu.scss

+4
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@
5555
right: 0;
5656
}
5757

58+
.aside-open.aside-resizing .menu-right {
59+
display: none;
60+
}
61+
5862
.menu-animated {
5963
@include transition-transform($menu-animation-speed ease);
6064
}

Diff for: scss/_split-pane.scss

-29
This file was deleted.

Diff for: scss/_variables.scss

-3
Original file line numberDiff line numberDiff line change
@@ -543,9 +543,6 @@ $menu-animation-speed: 200ms !default;
543543

544544
$menu-side-shadow: -1px 0px 2px rgba(0, 0, 0, 0.2), 1px 0px 2px rgba(0,0,0,0.2) !default;
545545

546-
$split-pane-menu-width: 320px !default;
547-
$split-pane-menu-border-color: #eee !default;
548-
549546

550547
// Modals
551548
// -------------------------------

Diff for: scss/ionic.scss

-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
"list",
2828
"badge",
2929
"slide-box",
30-
"split-pane",
3130

3231
// Forms
3332
"form",

Diff for: test/html/sideMenu.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
<ion-side-menu-content edge-drag-threshold="true" drag-content="!$root.disableDrag">
1717
<header class="bar bar-header bar-positive">
18-
<button class="button button-icon ion-navicon" ng-click="toggleLeft()"></button>
18+
<button class="button button-icon ion-navicon" ng-click="toggleLeft()" ng-hide="$exposeAside.active"></button>
1919
<h1 class="title">Slide me</h1>
2020
<button class="button button-icon ion-navicon" ng-click="toggleRight()"></button>
2121
</header>
@@ -32,7 +32,7 @@ <h1>Content</h1>
3232
</ion-content>
3333
</ion-side-menu-content>
3434

35-
<ion-side-menu side="left" width="$root.menuWidth || 270" ng-controller="LeftCtrl">
35+
<ion-side-menu side="left" width="$root.menuWidth || 275" ng-controller="LeftCtrl" expose-aside-when="(min-width:750px) and (max-width:1200px)">
3636
<header class="bar bar-header bar-assertive">
3737
<h1 class="title">Left</h1>
3838
</header>

0 commit comments

Comments
 (0)