diff --git a/ionic.contrib.drawer.css b/ionic.contrib.drawer.css index 635c2c4..244e041 100644 --- a/ionic.contrib.drawer.css +++ b/ionic.contrib.drawer.css @@ -13,6 +13,8 @@ drawer.animate { } drawer.left { + left: 0; + top: 0; -webkit-transform: translate3d(-100%, 0, 0); transform: translate3d(-100%, 0, 0); box-shadow: 1px 0px 10px rgba(0,0,0,0.3); diff --git a/ionic.contrib.drawer.js b/ionic.contrib.drawer.js index c1e031e..9bad3a7 100644 --- a/ionic.contrib.drawer.js +++ b/ionic.contrib.drawer.js @@ -9,302 +9,308 @@ */ angular.module('ionic.contrib.drawer', ['ionic']) -.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; - - // How far to drag before triggering - var thresholdX = 15; - // How far from edge before triggering - var edgeX = 40; - - var SIDE_LEFT = 'left'; - var SIDE_RIGHT = 'right'; - var STATE_CLOSE = 'close'; - var STATE_OPEN = 'open'; - - var isTargetDrag = false; - - 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(targetEl) { - while (targetEl) { - if (targetEl === el) { - return true; + .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; + + // How far to drag before triggering + var thresholdX = 15; + // How far from edge before triggering + var edgeX = 40; + + var SIDE_LEFT = 'left'; + var SIDE_RIGHT = 'right'; + var STATE_CLOSE = 'close'; + var STATE_OPEN = 'open'; + + var isTargetDrag = false; + + var side = $attr.side === SIDE_LEFT ? SIDE_LEFT : SIDE_RIGHT; + var width = el.clientWidth; + var docWidth = $document[0].body.clientWidth; + + // 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; } - targetEl = targetEl.parentNode; - } - }; + }; + + 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(targetEl) { + while (targetEl) { + if (targetEl === el) { + return true; + } + targetEl = targetEl.parentNode; + } + }; - var isOpen = function() { - return drawerState === STATE_OPEN; - }; + var isOpen = function() { + return drawerState === STATE_OPEN; + }; - var startDrag = function(e) { - disableAnimation(); - toggleOverlay(STATE_OPEN); + var startDrag = function(e) { + disableAnimation(); + toggleOverlay(STATE_OPEN); - dragging = true; - offsetX = lastX - startX; - }; + dragging = true; + offsetX = lastX - startX; + }; - var startTargetDrag = function(e) { - disableAnimation(); - toggleOverlay(STATE_OPEN); + var startTargetDrag = function(e) { + disableAnimation(); + toggleOverlay(STATE_OPEN); - dragging = true; - isTargetDrag = true; - offsetX = lastX - startX; - }; + dragging = true; + isTargetDrag = true; + offsetX = lastX - startX; + }; - var doEndDrag = function(e) { - startX = lastX = offsetX = null; - isTargetDrag = false; + var doEndDrag = function(e) { + startX = lastX = offsetX = null; + isTargetDrag = false; - if (!dragging) { - return; - } + if (!dragging) { + return; + } - dragging = false; + dragging = false; - enableAnimation(); + enableAnimation(); - 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 { - opacity = 1; - drawerState = STATE_OPEN; + 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 { + opacity = 1; + drawerState = STATE_OPEN; + } } - } - toggleOverlay(drawerState); + 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) { + return; + } - ionic.requestAnimationFrame(function() { - overlayEl.style.opacity = opacity; - el.style[ionic.CSS.TRANSFORM] = 'translate3d(' + translateX + 'px, 0, 0)'; - }); - }; + var finger = e.gesture.touches[0]; + var dir = e.gesture.direction; - var doDrag = function(e) { - if (e.defaultPrevented) { - return; - } - - var finger = e.gesture.touches[0]; - var dir = e.gesture.direction; + if (!lastX) { + startX = finger.pageX; + } - if (!lastX) { - startX = finger.pageX; - } + lastX = finger.pageX; - lastX = finger.pageX; - - if (dir === 'down' || dir === 'up') { - return; - } + 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 (side === SIDE_LEFT){ - if (isOpen()) { - if (dir === SIDE_RIGHT) { - 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 (side === SIDE_LEFT){ + if (isOpen()) { + if (dir === SIDE_RIGHT) { + return; + } + } else { + if (dir === SIDE_LEFT) { + 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; + } } } - } else if (side === SIDE_RIGHT){ - if (isOpen()) { - if (dir === SIDE_LEFT) { - return; + + // Menu is open and drag has reached target + if (e.gesture.center.pageX < width && isOpen()) { + startTargetDrag(e); + } else if((startX < edgeX && side === SIDE_LEFT) || (startX > docWidth-edgeX && side === SIDE_RIGHT)) { + startDrag(e); + } + } + } else { + //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 (dir === SIDE_RIGHT) { - return; + } else if (side === SIDE_RIGHT){ + if (isOpen()) { + if (dir === SIDE_RIGHT) { + return newX = width; + } + } else { + if (dir === SIDE_LEFT) { + return newX = 0; + } } } } - // Menu is open and drag has reached target - if (e.gesture.center.pageX < width && isOpen()) { - startTargetDrag(e); - } else if((startX < edgeX && side === SIDE_LEFT) || (startX > docWidth-edgeX && side === SIDE_RIGHT)) { - startDrag(e); - } - } - } else { - //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; - } - } + newX = Math.min(0, (-width + (lastX - offsetX))); + var opacity = 1 + (newX / width); } else if (side === SIDE_RIGHT){ - if (isOpen()) { - if (dir === SIDE_RIGHT) { - return newX = width; - } - } else { - if (dir === SIDE_LEFT) { - return newX = 0; - } - } + 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 (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 (dragging) { + e.gesture.srcEvent.preventDefault(); } + }; + + var hardwareBackCallback = function() { + this.close(); + }.bind(this); + + this.close = function() { + drawerState = STATE_CLOSE; + enableAnimation(); + toggleOverlay(STATE_CLOSE); - - if (opacity < 0) { - opacity = 0; + ionic.requestAnimationFrame(function() { + 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() { - overlayEl.style.opacity = opacity; - el.style[ionic.CSS.TRANSFORM] = 'translate3d(' + newX + 'px, 0, 0)'; - }); - } + overlayEl.style.opacity = 1; + el.style[ionic.CSS.TRANSFORM] = 'translate3d(0, 0, 0)'; + }); - if (dragging) { - e.gesture.srcEvent.preventDefault(); - } - }; - - var hardwareBackCallback = function() { - this.close(); - }.bind(this); - - this.close = function() { - drawerState = STATE_CLOSE; - enableAnimation(); - toggleOverlay(STATE_CLOSE); - - ionic.requestAnimationFrame(function() { - 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() { - 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() { - ctrl.open(); - }; - - $scope.closeDrawer = function() { - ctrl.close(); - }; - - $scope.toggleDrawer = function() { - if (ctrl.isOpen()) { - ctrl.close(); - } else { + 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', function($rootScope) { + return { + restrict: 'E', + controller: 'drawerCtrl', + link: function($scope, $element, $attr, ctrl) { + $element.addClass($attr.side); + + var drawerCtrl = { + openDrawer: openDrawer, + closeDrawer: closeDrawer, + toggleDrawer: toggleDrawer + }; + + ($scope.vm) ? angular.merge($scope.vm, drawerCtrl) : angular.merge($scope, drawerCtrl); + + function openDrawer() { ctrl.open(); + $scope.$emit('drawer-opened'); } - }; + + function closeDrawer() { + ctrl.close(); + $scope.$emit('drawer-closed'); + } + + function toggleDrawer() { + if (ctrl.isOpen()) { + ctrl.close(); + } else { + ctrl.open(); + } + } + } } - } -}]); + }]); })();