diff --git a/.gitignore b/.gitignore
index 726c3ca..41b70a5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
.*.sw*
+/.idea
diff --git a/README.md b/README.md
index e28bdb6..a18a9dc 100644
--- a/README.md
+++ b/README.md
@@ -2,3 +2,59 @@ ionic-contrib-drawer
====================
A side menu drawer for Ionic apps
+
+#####Setting up:
+
+Clone the ionic-ion-drawer repo into the lib folder in your ionic project so it looks like:
+
+*yourProjectName/www/lib/ionic-ion-drawer*
+
+Add the ionic-contrib-drawer.js and ionic-contrib-drawer.css files to your index file
+
+
+
+
+Add ionic.contrib.drawer to your Angular app:
+
+ angular.module('App', [
+ 'ionic',
+ 'ionic.contrib.drawer'
+ ])
+
+#####Usage:
+
+ Add the `` directive to your ionic templates or index.html files.
+
+#####Example:
+
+
+
+
+
+
+
+ Menu
+ Close
+
+ Friends
+ Favorites
+ Search
+
+
+
+
+
+
+
+Change the 'side' attribute of the `` to either "right" or "left" to switch the side the drawer opens from.
+
+#####Credits:
+
+driftyco: https://github.com/driftyco (original build)
+
+vitalyrotari: https://github.com/vitalyrotari (bug fixes, improved performance, background fading
+transition)
+
+brybott: https://github.com/brybott (right side functionality)
diff --git a/index.html b/index.html
index 0382143..1df22ca 100644
--- a/index.html
+++ b/index.html
@@ -4,15 +4,10 @@
Ionic Seed App
-
-
-
-
+
-
-
-
+
-
diff --git a/ionic.contrib.drawer.css b/ionic.contrib.drawer.css
index 37a450c..635c2c4 100644
--- a/ionic.contrib.drawer.css
+++ b/ionic.contrib.drawer.css
@@ -8,8 +8,8 @@ drawer {
}
drawer.animate {
- -webkit-transition: 0.4s all ease-in-out;
- transition: 0.4s all ease-in-out;
+ -webkit-transition: -webkit-transform 0.4s ease-in-out;
+ transition: transform 0.4s ease-in-out;
}
drawer.left {
@@ -17,6 +17,7 @@ drawer.left {
transform: translate3d(-100%, 0, 0);
box-shadow: 1px 0px 10px rgba(0,0,0,0.3);
}
+
drawer.right {
right: 0;
top: 0;
@@ -24,3 +25,21 @@ drawer.right {
transform: translate3d(100%, 0, 0);
box-shadow: -1px 0px 10px rgba(0,0,0,0.3);
}
+
+.drawer-overlay {
+ background-color: rgba(0, 0, 0, 0.6);
+ opacity: 0;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 99;
+ -webkit-transform: translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0);
+}
+
+.drawer-overlay.animate {
+ -webkit-transition: 0.4s opacity ease-in-out;
+ transition: 0.4s opacity ease-in-out;
+}
diff --git a/ionic.contrib.drawer.js b/ionic.contrib.drawer.js
index b2f5815..c1e031e 100644
--- a/ionic.contrib.drawer.js
+++ b/ionic.contrib.drawer.js
@@ -9,179 +9,300 @@
*/
angular.module('ionic.contrib.drawer', ['ionic'])
-.controller('drawerCtrl', ['$element', '$attrs', '$ionicGesture', '$document', function($element, $attr, $ionicGesture, $document) {
+.controller('drawerCtrl', ['$element', '$attrs', '$ionicGesture', '$document', '$ionicPlatform', function($element, $attr, $ionicGesture, $document, $ionicPlatform) {
var el = $element[0];
var dragging = false;
var startX, lastX, offsetX, newX;
- var side;
// How far to drag before triggering
var thresholdX = 15;
// How far from edge before triggering
var edgeX = 40;
- var LEFT = 0;
- var RIGHT = 1;
+ var SIDE_LEFT = 'left';
+ var SIDE_RIGHT = 'right';
+ var STATE_CLOSE = 'close';
+ var STATE_OPEN = 'open';
var isTargetDrag = false;
- var width = $element[0].clientWidth;
+ var side = $attr.side === SIDE_LEFT ? SIDE_LEFT : SIDE_RIGHT;
+ var width = el.clientWidth;
+ var docWidth = $document[0].body.clientWidth;
+ console.log(docWidth)
+
+ // Handle back button
+ var unregisterBackAction;
+
+ // Current State of Drawer
+ var drawerState = STATE_CLOSE;
+
+ // Drawer overlay
+ var $overlay = angular.element('
');
+ var overlayEl = $overlay[0];
+ var overlayState = STATE_CLOSE;
+
+ $element.parent().prepend(overlayEl);
+
+ var toggleOverlay = function(state) {
+ if (overlayState !== state) {
+ ionic.requestAnimationFrame(function() {
+ var translateX = state === STATE_CLOSE ? '-100' : '0';
+ overlayEl.style[ionic.CSS.TRANSFORM] = 'translate3d(' + translateX + '%, 0, 0)';
+ });
+ overlayState = state;
+ }
+ };
var enableAnimation = function() {
$element.addClass('animate');
+ $overlay.addClass('animate');
};
+
var disableAnimation = function() {
$element.removeClass('animate');
+ $overlay.removeClass('animate');
};
// Check if this is on target or not
- var isTarget = function(el) {
- while(el) {
- if(el === $element[0]) {
+ var isTarget = function(targetEl) {
+ while (targetEl) {
+ if (targetEl === el) {
return true;
}
- el = el.parentNode;
+ targetEl = targetEl.parentNode;
}
};
+ var isOpen = function() {
+ return drawerState === STATE_OPEN;
+ };
+
var startDrag = function(e) {
disableAnimation();
+ toggleOverlay(STATE_OPEN);
dragging = true;
offsetX = lastX - startX;
- console.log('Starting drag');
- console.log('Offset:', offsetX);
};
var startTargetDrag = function(e) {
disableAnimation();
+ toggleOverlay(STATE_OPEN);
dragging = true;
isTargetDrag = true;
offsetX = lastX - startX;
- console.log('Starting target drag');
- console.log('Offset:', offsetX);
};
var doEndDrag = function(e) {
- startX = null;
- lastX = null;
- offsetX = null;
+ startX = lastX = offsetX = null;
isTargetDrag = false;
- if(!dragging) {
+ if (!dragging) {
return;
}
dragging = false;
- console.log('End drag');
enableAnimation();
- ionic.requestAnimationFrame(function() {
- if(newX < (-width / 2)) {
- el.style.transform = el.style.webkitTransform = 'translate3d(' + -width + 'px, 0, 0)';
+ var translateX = 0;
+ var opacity = 0;
+
+ if (side === SIDE_RIGHT){
+ if (newX > width / 2) {
+ translateX = width;
+ drawerState = STATE_CLOSE;
+ } else {
+ opacity = 1;
+ drawerState = STATE_OPEN;
+ }
+ } else if (side === SIDE_LEFT){
+ if (newX < (-width / 2)) {
+ translateX = -width;
+ drawerState = STATE_CLOSE;
} else {
- el.style.transform = el.style.webkitTransform = 'translate3d(0px, 0, 0)';
+ opacity = 1;
+ drawerState = STATE_OPEN;
}
+ }
+
+ toggleOverlay(drawerState);
+
+ ionic.requestAnimationFrame(function() {
+ overlayEl.style.opacity = opacity;
+ el.style[ionic.CSS.TRANSFORM] = 'translate3d(' + translateX + 'px, 0, 0)';
});
};
var doDrag = function(e) {
- if(e.defaultPrevented) {
+ if (e.defaultPrevented) {
return;
}
+
+ var finger = e.gesture.touches[0];
+ var dir = e.gesture.direction;
- if(!lastX) {
- startX = e.gesture.touches[0].pageX;
+ if (!lastX) {
+ startX = finger.pageX;
}
- lastX = e.gesture.touches[0].pageX;
-
- if(!dragging) {
+ lastX = finger.pageX;
+
+ if (dir === 'down' || dir === 'up') {
+ return;
+ }
+ if (!dragging) {
+ //here at just the beginning of drag
// Dragged 15 pixels and finger is by edge
- if(Math.abs(lastX - startX) > thresholdX) {
- if(isTarget(e.target)) {
+ if (Math.abs(lastX - startX) > thresholdX) {
+ if (side === SIDE_LEFT){
+ if (isOpen()) {
+ if (dir === SIDE_RIGHT) {
+ return;
+ }
+ } else {
+ if (dir === SIDE_LEFT) {
+ return;
+ }
+ }
+ } else if (side === SIDE_RIGHT){
+ if (isOpen()) {
+ if (dir === SIDE_LEFT) {
+ return;
+ }
+ } else {
+ if (dir === SIDE_RIGHT) {
+ return;
+ }
+ }
+ }
+
+ // Menu is open and drag has reached target
+ if (e.gesture.center.pageX < width && isOpen()) {
startTargetDrag(e);
- } else if(startX < edgeX) {
+ } else if((startX < edgeX && side === SIDE_LEFT) || (startX > docWidth-edgeX && side === SIDE_RIGHT)) {
startDrag(e);
}
}
} else {
- console.log(lastX, offsetX, lastX - offsetX);
- newX = Math.min(0, (-width + (lastX - offsetX)));
- ionic.requestAnimationFrame(function() {
- el.style.transform = el.style.webkitTransform = 'translate3d(' + newX + 'px, 0, 0)';
- });
+ //here when we are dragging
+ e.gesture.srcEvent.stopImmediatePropagation();
+
+ // if fast gesture
+ if (e.gesture.deltaTime < 200) {
+ if (side === SIDE_LEFT){
+ if (isOpen()) {
+ if (dir === SIDE_LEFT) {
+ return newX = -width;
+ }
+ } else {
+ if (dir === SIDE_RIGHT) {
+ return newX = 0;
+ }
+ }
+ } else if (side === SIDE_RIGHT){
+ if (isOpen()) {
+ if (dir === SIDE_RIGHT) {
+ return newX = width;
+ }
+ } else {
+ if (dir === SIDE_LEFT) {
+ return newX = 0;
+ }
+ }
+ }
+ }
+
+ if (side === SIDE_LEFT){
+ newX = Math.min(0, (-width + (lastX - offsetX)));
+ var opacity = 1 + (newX / width);
+ } else if (side === SIDE_RIGHT){
+ newX = Math.max(0, (width - (docWidth - lastX + offsetX)));
+ var opacity = 1 - (newX / width);
+ }
+
+ if (opacity < 0) {
+ opacity = 0;
+ }
+
+ ionic.requestAnimationFrame(function() {
+ overlayEl.style.opacity = opacity;
+ el.style[ionic.CSS.TRANSFORM] = 'translate3d(' + newX + 'px, 0, 0)';
+ });
}
- if(dragging) {
+ if (dragging) {
e.gesture.srcEvent.preventDefault();
}
};
-
- side = $attr.side == 'left' ? LEFT : RIGHT;
- console.log(side);
-
- $ionicGesture.on('drag', function(e) {
- doDrag(e);
- }, $document);
- $ionicGesture.on('dragend', function(e) {
- doEndDrag(e);
- }, $document);
-
-
+
+ var hardwareBackCallback = function() {
+ this.close();
+ }.bind(this);
+
this.close = function() {
+ drawerState = STATE_CLOSE;
enableAnimation();
+ toggleOverlay(STATE_CLOSE);
+
ionic.requestAnimationFrame(function() {
- if(side === LEFT) {
- el.style.transform = el.style.webkitTransform = 'translate3d(-100%, 0, 0)';
- } else {
- el.style.transform = el.style.webkitTransform = 'translate3d(100%, 0, 0)';
- }
+ overlayEl.style.opacity = 0;
+ el.style[ionic.CSS.TRANSFORM] = 'translate3d(' + (side === SIDE_LEFT ? '-' : '') + '100%, 0, 0)';
});
+
+ if (unregisterBackAction) {
+ unregisterBackAction();
+ }
};
this.open = function() {
+ drawerState = STATE_OPEN;
enableAnimation();
+ toggleOverlay(STATE_OPEN);
ionic.requestAnimationFrame(function() {
- if(side === LEFT) {
- el.style.transform = el.style.webkitTransform = 'translate3d(0%, 0, 0)';
- } else {
- el.style.transform = el.style.webkitTransform = 'translate3d(0%, 0, 0)';
- }
+ overlayEl.style.opacity = 1;
+ el.style[ionic.CSS.TRANSFORM] = 'translate3d(0, 0, 0)';
});
+
+ unregisterBackAction = $ionicPlatform.registerBackButtonAction(hardwareBackCallback, 100);
};
+
+ this.isOpen = isOpen;
+
+ $ionicGesture.on('drag', doDrag, $document);
+ $ionicGesture.on('dragend', doEndDrag, $document);
+ $overlay.on('click', this.close);
}])
.directive('drawer', ['$rootScope', '$ionicGesture', function($rootScope, $ionicGesture) {
return {
restrict: 'E',
controller: 'drawerCtrl',
+ scope: {
+ side: '=side'
+ },
link: function($scope, $element, $attr, ctrl) {
$element.addClass($attr.side);
+
$scope.openDrawer = function() {
- console.log('open');
ctrl.open();
};
+
$scope.closeDrawer = function() {
- console.log('close');
ctrl.close();
};
- }
- }
-}]);
-
-.directive('drawerClose', ['$rootScope', function($rootScope) {
- return {
- restrict: 'A',
- link: function($scope, $element) {
- $element.bind('click', function() {
- var drawerCtrl = $element.inheritedData('$drawerController');
- drawerCtrl.close();
- });
+
+ $scope.toggleDrawer = function() {
+ if (ctrl.isOpen()) {
+ ctrl.close();
+ } else {
+ ctrl.open();
+ }
+ };
}
}
}]);