diff --git a/hacking/SideMenuController.js b/hacking/SideMenuController.js new file mode 100644 index 0000000000..dc27973571 --- /dev/null +++ b/hacking/SideMenuController.js @@ -0,0 +1,180 @@ +(function(window, document, ionic) { + + SideMenuController = function(options) { + var _this = this; + + + this.left = options.left; + this.right = options.right; + this.content = options.content; + + this._rightShowing = false; + this._leftShowing = false; + + this.content.onDrag = function(e) { + _this._handleDrag(e); + }; + + this.content.endDrag = function(e) { + _this._endDrag(e); + }; + + }; + + SideMenuController.prototype = { + toggleLeft: function() { + var openAmount = this.getOpenAmount(); + if(openAmount > 0) { + this.openPercentage(0); + } else { + this.openPercentage(100); + } + }, + toggleRight: function() { + var openAmount = this.getOpenAmount(); + if(openAmount < 0) { + this.openPercentage(0); + } else { + this.openPercentage(-100); + } + }, + getOpenAmount: function() { + return this.content.getTranslateX() || 0; + }, + getOpenRatio: function() { + var amount = this.getOpenAmount(); + if(amount >= 0) { + return amount / this.left.width; + } + return amount / this.right.width; + }, + getOpenPercentage: function() { + return this.getOpenRatio() * 100; + }, + openPercentage: function(percentage) { + var p = percentage / 100; + var maxLeft = this.left.width; + var maxRight = this.right.width; + if(percentage >= 0) { + this.openAmount(maxLeft * p); + } else { + this.openAmount(maxRight * p); + } + }, + openAmount: function(amount) { + var maxLeft = this.left.width; + var maxRight = this.right.width; + + // Check if we can move to that side, depending if the left/right panel is enabled + if((!this.left.isEnabled && amount > 0) || (!this.right.isEnabled && amount < 0)) { + return; + } + + if((this._leftShowing && amount > maxLeft) || (this._rightShowing && amount < -maxRight)) { + return; + } + + this.content.setTranslateX(amount); + + if(amount >= 0) { + this._leftShowing = true; + this._rightShowing = false; + + // Push the z-index of the right menu down + this.right.pushDown(); + // Bring the z-index of the left menu up + this.left.bringUp(); + } else { + this._rightShowing = true; + this._leftShowing = false; + + // Bring the z-index of the right menu up + this.right.bringUp(); + // Push the z-index of the left menu down + this.left.pushDown(); + } + }, + snapToRest: function(e) { + // We want to animate at the end of this + this.content.enableAnimation(); + this._isDragging = false; + + // Check how much the panel is open after the drag, and + // what the drag velocity is + var ratio = this.getOpenRatio(); + + + if(ratio == 0) + return; + + var velocityThreshold = 0.3; + var velocityX = e.gesture.velocityX + var direction = e.gesture.direction; + + // Less than half, going left + //if(ratio > 0 && ratio < 0.5 && direction == 'left' && velocityX < velocityThreshold) { + //this.openPercentage(0); + //} + + var sign = ratio && ratio / Math.abs(ratio); + + // Left panel, More than positive half, too slow + if((ratio > 0.5 || ratio < -0.5) && velocityX < velocityThreshold) { + this.openPercentage(sign * 100); + } + // Left or Right Panel, Less than +/- half, too slow + else if(ratio <= 0.5 && ratio >= -0.5 && velocityX < velocityThreshold) { + this.openPercentage(0); + } + + // Left panel, Going left, quickly + else if(direction == 'left' && ratio >= 0 && velocityX >= velocityThreshold) { + this.openPercentage(0); + } + + // Left panel, Going right, quickly + else if(direction == 'right' && ratio >= 0 && velocityX >= velocityThreshold) { + this.openPercentage(100); + } + + // Right panel, Going left, quickly + else if(direction == 'left' && ratio <= 0 && velocityX >= velocityThreshold) { + this.openPercentage(-100); + } + + // Right panel, Going right, quickly + else if(direction == 'right' && ratio <= 0 && velocityX >= velocityThreshold) { + this.openPercentage(0); + } else { + this.openPercentage(0); + } + }, + _endDrag: function(e) { + this.snapToRest(e); + }, + _initDrag: function(e) { + this.content.disableAnimation(); + this._isDragging = true; + this._startX = 0; + this._offsetX = 0; + this._lastX = 0; + }, + _handleDrag: function(e) { + if(!this._isDragging) { + this._initDrag(e); + + this._startX = e.gesture.touches[0].pageX; + this._lastX = this._startX; + + this._offsetX = this.getOpenAmount(); + } + //console.log('Dragging page', this._startX, this._lastX, this._offsetX, e); + var newX = this._offsetX + (this._lastX - this._startX); + + this.openAmount(newX); + + this._lastX = e.gesture.touches[0].pageX; + } + }; + +})(this, document, ion = this.ionic || {}); diff --git a/hacking/SideMenuController.unit.js b/hacking/SideMenuController.unit.js new file mode 100644 index 0000000000..d5de171712 --- /dev/null +++ b/hacking/SideMenuController.unit.js @@ -0,0 +1,158 @@ +describe('SideMenuController', function() { + var ctrl, l, r, c; + + var Controller = function(opts) { + this.el = opts.el; + this.animateClass = opts.animateClass; + }; + Controller.prototype = { + getTranslateX: function() { + var r = /translate3d\((-?.+)px/; + var d = r.exec(this.el.style.webkitTransform); + + if(d && d.length > 0) { + return parseFloat(d[1]); + } + return 0; + }, + setTranslateX: function(amount) { + this.el.style.webkitTransform = 'translate3d(' + amount + 'px, 0, 0)'; + }, + enableAnimation: function() { + this.el.classList.add(this.animateClass); + }, + disableAnimation: function() { + this.el.classList.remove(this.animateClass); + } + }; + + beforeEach(function() { + l = new SideMenu({ el: document.createElement('div'), width: 270 }); + r = new SideMenu({ el: document.createElement('div'), width: 270 }); + c = new Controller({ el: document.createElement('div') }); + + ctrl = new SideMenuController({ + left: l, + right: r, + content: c + }); + }); + + // Init + it('Should init', function() { + expect(ctrl.left).toBe(l); + expect(ctrl.right).toBe(r); + expect(ctrl.content).toBe(c); + }); + + // Menu enable/disable + it('Should set enabled/disabled', function() { + var left = ctrl.left; + var right = ctrl.right; + left.setIsEnabled(false); + right.setIsEnabled(false); + expect(left.isEnabled).toEqual(false); + expect(right.isEnabled).toEqual(false); + left.setIsEnabled(true); + right.setIsEnabled(true); + expect(left.isEnabled).toEqual(true); + expect(right.isEnabled).toEqual(true); + }); + + // Menu widths + it('Should init widths', function() { + var left = ctrl.left; + var right = ctrl.right; + expect(left.width).toEqual(270); + expect(right.width).toEqual(270); + }); + + it('Should have amount and percentage correct', function() { + ctrl.openAmount(l.width/2); + expect(ctrl.getOpenAmount()).toEqual(l.width/2); + expect(ctrl.getOpenPercentage()).toEqual(50); + + ctrl.openAmount(l.width/4); + expect(ctrl.getOpenAmount()).toEqual(l.width/4); + expect(ctrl.getOpenPercentage()).toEqual(25); + + ctrl.openAmount(-r.width/2); + expect(ctrl.getOpenAmount()).toEqual(-r.width/2); + expect(ctrl.getOpenPercentage()).toEqual(-50); + }); + + // Open + it('Should toggle left and right', function() { + ctrl.toggleLeft(); + expect(ctrl.getOpenPercentage()).toEqual(100); + ctrl.toggleRight(); + expect(ctrl.getOpenPercentage()).toEqual(-100); + }); + + // Snap + it('Should snap', function() { + + // Center to right, Going right, less than half, too slow (snap back) + ctrl.openAmount(10); + ctrl.snapToRest({ + gesture: { + velocityX: 0, + direction: 'right' + } + }); + expect(ctrl.getOpenPercentage()).toEqual(0); + + // Right to left, Going left, more than half, too slow (snap back) + ctrl.openPercentage(51); + ctrl.snapToRest({ + gesture: { + velocityX: 0, + direction: 'left' + } + }); + expect(ctrl.getOpenPercentage()).toEqual(100); + + // Right to left, Going left, less than half, too slow (snap back) + ctrl.openAmount(10); + ctrl.snapToRest({ + gesture: { + velocityX: 0, + direction: 'left' + } + }); + expect(ctrl.getOpenPercentage()).toEqual(0); + + // Left to right, Going right, more than half, too slow (snap back) + ctrl.openPercentage(-51); + ctrl.snapToRest({ + gesture: { + velocityX: 0, + direction: 'right' + } + }); + expect(ctrl.getOpenPercentage()).toEqual(-100); + + // Going right, more than half, or quickly (snap open) + ctrl.openPercentage(-51); + ctrl.snapToRest({ + gesture: { + velocityX: 1, + direction: 'right' + } + }); + expect(ctrl.getOpenPercentage()).toEqual(0); + + // Going left, more than half, or quickly (snap open) + ctrl.openPercentage(-51); + ctrl.snapToRest({ + gesture: { + velocityX: 1, + direction: 'left' + } + }); + expect(ctrl.getOpenPercentage()).toEqual(-100); + }); + + it('Should test content drag events', function() { + }); +});