diff --git a/bower.json b/bower.json index 0d2b77a..6905373 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "angular-snapscroll", - "version": "0.2.6", + "version": "0.3.0", "authors": [ "Joel Mukuthu " ], diff --git a/dist/angular-snapscroll.js b/dist/angular-snapscroll.js index e514944..1377f0a 100644 --- a/dist/angular-snapscroll.js +++ b/dist/angular-snapscroll.js @@ -1,9 +1,9 @@ /** * angular-snapscroll - * Version: 0.2.6 + * Version: 0.3.0 * (c) 2014-2016 Joel Mukuthu * MIT License - * Built on: 03-04-2016 19:47:50 GMT+0200 + * Built on: 16-07-2016 00:35:52 GMT+0200 **/ (function () { @@ -19,13 +19,14 @@ } angular - .module('snapscroll', []) + .module('snapscroll', ['wheelie']) .value('defaultSnapscrollScrollEasing', easeInOutQuad) .value('defaultSnapscrollScrollDelay', 250) .value('defaultSnapscrollSnapDuration', 800) .value('defaultSnapscrollResizeDelay', 400) .value('defaultSnapscrollBindScrollTimeout', 400); })(); + (function () { 'use strict'; @@ -103,14 +104,11 @@ var watchSnapHeight = function (scope, callback) { scope.$watch('snapHeight', function (snapHeight, previousSnapHeight) { if (angular.isUndefined(snapHeight)) { - scope.snapHeight = scope.defaultSnapHeight; return; } if (!isNumber(snapHeight)) { if (isNumber(previousSnapHeight)) { scope.snapHeight = previousSnapHeight; - } else { - scope.snapHeight = scope.defaultSnapHeight; } return; } @@ -145,7 +143,7 @@ if (!scope.isValid(snapIndex)) { scope.ignoreThisSnapIndexChange = true; scope.snapIndex = previousSnapIndex; - scope.snapDirection = 0; + scope.snapDirection = 'none'; return; } if (scope.beforeSnap({snapIndex: snapIndex}) === false) { @@ -155,82 +153,69 @@ } if (angular.isFunction(callback)) { if (snapIndex > previousSnapIndex) { - scope.snapDirection = 1; + scope.snapDirection = 'up'; } else if (snapIndex < previousSnapIndex) { - scope.snapDirection = -1; + scope.snapDirection = 'down'; } callback(snapIndex, function () { - scope.snapDirection = 0; + scope.snapDirection = 'none'; scope.afterSnap({snapIndex: snapIndex}); }); } }); }; - var initWheelEvents = function (scope, element) { - var onWheel, - bindWheel, - unbindWheel; - - onWheel = function (e) { - var bubbleUp, - delta; - - if (e.originalEvent) { - e = e.originalEvent; + var initWheelEvents = function (wheelie, scope, element) { + function maybePreventBubbling(e, bubbleUp) { + if (!bubbleUp) { + e.stopPropagation(); } + } - e.preventDefault(); - - delta = Math.max(-1, Math.min(1, (e.wheelDelta || -(e.deltaY || e.detail)))); - - if (isNaN(delta) || delta === 0) { - return; - } + wheelie.bind(element, { + up: function (e) { + e.preventDefault(); - if (delta < 0) { - if (scope.snapDirection !== 1) { - if (scope.snapIndex + 1 > scope.scopeIndexMax()) { + var bubbleUp; + if (scope.snapDirection !== 'down') { + if (scope.snapIndex - 1 < scope.snapIndexMin()) { bubbleUp = true; } else { bubbleUp = false; scope.$apply(function () { - scope.snapIndex += 1; + scope.snapIndex -= 1; }); } } - } else { - if (scope.snapDirection !== -1) { - if (scope.snapIndex - 1 < scope.snapIndexMin()) { + + maybePreventBubbling(e, bubbleUp); + }, + down: function (e) { + e.preventDefault(); + + var bubbleUp; + if (scope.snapDirection !== 'up') { + if (scope.snapIndex + 1 > scope.scopeIndexMax()) { bubbleUp = true; } else { bubbleUp = false; scope.$apply(function () { - scope.snapIndex -= 1; + scope.snapIndex += 1; }); } } - } - if (!bubbleUp) { - e.stopPropagation(); + maybePreventBubbling(e, bubbleUp); } - }; - - bindWheel = function () { - element.on('wheel mousewheel onmousewheel', onWheel); - }; - - unbindWheel = function () { - element.off('wheel mousewheel onmousewheel', onWheel); - }; + }); - bindWheel(); - scope.$on('$destroy', unbindWheel); + scope.$on('$destroy', function () { + wheelie.unbind(element); + }); }; - var snapscrollAsAnAttribute = ['$timeout', 'scroll', 'defaultSnapscrollScrollDelay', 'defaultSnapscrollSnapDuration', 'defaultSnapscrollBindScrollTimeout', - function ($timeout, scroll, defaultSnapscrollScrollDelay, defaultSnapscrollSnapDuration, defaultSnapscrollBindScrollTimeout) { + var snapscrollAsAnAttribute = ['$timeout', 'scroll', 'wheelie', 'defaultSnapscrollScrollDelay', 'defaultSnapscrollSnapDuration', 'defaultSnapscrollBindScrollTimeout', + function ($timeout, scroll, wheelie, defaultSnapscrollScrollDelay, defaultSnapscrollSnapDuration, defaultSnapscrollBindScrollTimeout) { return { restrict: 'A', scope: scopeObject, @@ -249,9 +234,18 @@ snapDuration = attributes.snapDuration, preventSnappingAfterManualScroll = angular.isDefined(attributes.preventSnappingAfterManualScroll); + function getScrollTop(index) { + var snaps = element.children(); + var combinedHeight = 0; + for (var i = 0; i < index; i++) { + combinedHeight += parseInt(snaps[i].offsetHeight, 10); + } + return combinedHeight; + } + snapTo = function (index, afterSnap) { var args, - top = index * scope.snapHeight; + top = getScrollTop(index); if (scope.snapAnimation) { if (angular.isDefined(snapEasing)) { args = [element, top, snapDuration, snapEasing]; @@ -276,10 +270,22 @@ }); }; + function getSnapIndex(scrollTop) { + var snapIndex = -1, + snaps = element.children(), + lastSnapHeight; + while (scrollTop > 0) { + scrollTop -= lastSnapHeight = snaps[++snapIndex].offsetHeight; + } + if ((lastSnapHeight / 2) >= -scrollTop) { + snapIndex += 1; + } + return snapIndex; + } + onScroll = function () { var snap = function () { - var top = element[0].scrollTop, - newSnapIndex = Math.round(top / scope.snapHeight); + var newSnapIndex = getSnapIndex(element[0].scrollTop); if (scope.snapIndex === newSnapIndex) { snapTo(newSnapIndex); } else { @@ -299,7 +305,7 @@ bindScroll = function () { // if the bindScroll timeout expires while snapping is ongoing, restart the timer - if (scope.snapDirection !== 0) { + if (scope.snapDirection !== 'none') { bindScrollPromise = $timeout(bindScroll, defaultSnapscrollBindScrollTimeout); return; } @@ -337,8 +343,6 @@ } }); - scope.defaultSnapHeight = element[0].offsetHeight; - scope.snapIndexMin = function () { return 0; }; @@ -351,14 +355,16 @@ return snapIndex >= scope.snapIndexMin() && snapIndex <= scope.scopeIndexMax(); }; - element.css('overflowY', 'auto'); + if (element.css('overflowY') !== 'scroll') { + element.css('overflowY', 'auto'); + } - watchSnapHeight(scope, function () { + watchSnapHeight(scope, function (snapHeight) { + element.css('height', snapHeight + 'px'); var snaps = element.children(); - element.css('height', scope.snapHeight + 'px'); if (snaps.length) { angular.forEach(snaps, function (snap) { - angular.element(snap).css('height', scope.snapHeight + 'px'); + angular.element(snap).css('height', snapHeight + 'px'); }); } snapTo(scope.snapIndex); @@ -371,7 +377,7 @@ scope.$on('$destroy', unbindScroll); } - initWheelEvents(scope, element); + initWheelEvents(wheelie, scope, element); }; init(); diff --git a/dist/angular-snapscroll.min.js b/dist/angular-snapscroll.min.js index e554fa7..fa7674b 100644 --- a/dist/angular-snapscroll.min.js +++ b/dist/angular-snapscroll.min.js @@ -1,2 +1,2 @@ -/* angular-snapscroll v0.2.6, (c) 2014-2016 Joel Mukuthu, MIT License, built: 03-04-2016 19:47:50 GMT+0200 */ -!function(){"use strict";function a(a,b,c,d){return a/=d/2,1>a?c/2*a*a+b:(a--,-c/2*(a*(a-2)-1)+b)}angular.module("snapscroll",[]).value("defaultSnapscrollScrollEasing",a).value("defaultSnapscrollScrollDelay",250).value("defaultSnapscrollSnapDuration",800).value("defaultSnapscrollResizeDelay",400).value("defaultSnapscrollBindScrollTimeout",400)}(),function(){"use strict";angular.module("snapscroll").directive("fitWindowHeight",["$window","$timeout","defaultSnapscrollResizeDelay",function(a,b,c){return{restrict:"A",require:"snapscroll",link:function(d,e,f,g){function h(){l===!1?g.setSnapHeight(a.innerHeight):(b.cancel(k),k=b(function(){g.setSnapHeight(a.innerHeight)},l))}function i(){"false"===l?l=!1:(l=parseInt(l,10),isNaN(l)&&(l=c)),g.setSnapHeight(a.innerHeight),j=angular.element(a),j.on("resize",h),d.$on("$destroy",function(){j.off("resize")})}var j,k,l=f.resizeDelay;i()}}}])}(),function(){"use strict";var a={snapIndex:"=?",snapHeight:"=?",beforeSnap:"&",afterSnap:"&",snapAnimation:"=?"},b=["$scope",function(a){this.setSnapHeight=function(b){a.snapHeight=b}}],c=function(a){return angular.isNumber(a)&&!isNaN(a)},d=function(a,b){a.$watch("snapHeight",function(d,e){return angular.isUndefined(d)?void(a.snapHeight=a.defaultSnapHeight):c(d)?void(angular.isFunction(b)&&b(d)):void(c(e)?a.snapHeight=e:a.snapHeight=a.defaultSnapHeight)})},e=function(a,b){a.$watch("snapIndex",function(d,e){return angular.isUndefined(d)?void(a.snapIndex=0):c(d)?d%1!==0?void(a.snapIndex=Math.round(d)):a.ignoreThisSnapIndexChange?void(a.ignoreThisSnapIndexChange=void 0):a.isValid(d)?a.beforeSnap({snapIndex:d})===!1?(a.ignoreThisSnapIndexChange=!0,void(a.snapIndex=e)):void(angular.isFunction(b)&&(d>e?a.snapDirection=1:e>d&&(a.snapDirection=-1),b(d,function(){a.snapDirection=0,a.afterSnap({snapIndex:d})}))):(a.ignoreThisSnapIndexChange=!0,a.snapIndex=e,void(a.snapDirection=0)):void(c(e)?a.snapIndex=e:a.snapIndex=0)})},f=function(a,b){var c,d,e;c=function(b){var c,d;b.originalEvent&&(b=b.originalEvent),b.preventDefault(),d=Math.max(-1,Math.min(1,b.wheelDelta||-(b.deltaY||b.detail))),isNaN(d)||0===d||(0>d?1!==a.snapDirection&&(a.snapIndex+1>a.scopeIndexMax()?c=!0:(c=!1,a.$apply(function(){a.snapIndex+=1}))):-1!==a.snapDirection&&(a.snapIndex-1=a.snapIndexMin()&&b<=a.scopeIndexMax()},b.css("overflowY","auto"),d(a,function(){var c=b.children();b.css("height",a.snapHeight+"px"),c.length&&angular.forEach(c,function(b){angular.element(b).css("height",a.snapHeight+"px")}),m(a.snapIndex)}),e(a,m),w||(o(),a.$on("$destroy",q)),f(a,b)})()}}}];angular.module("snapscroll").directive("snapscroll",g)}(),function(){"use strict";var a=function(a,b){for(var c,d=["webkit","moz"],e=0;ep?(n=b(l,o),f.data("snapscroll-animation",n)):(e(f,n),m.resolve())},angular.isElement(f)&&angular.isNumber(g)?(m=a.defer(),h=parseInt(h),n=f.data("snapscroll-animation"),n&&(c(n),e(f,n)),0===h||isNaN(h)?(f[0].scrollTop=g,m.resolve()):("function"!=typeof i&&(i=d),j=f[0].scrollTop,k=g-j,p=0,o=20,l()),f.data("snapscroll-animation-deferred",m),m.promise):void 0},stop:function(a){var b=a.data("snapscroll-animation");b&&(c(b),a.data("snapscroll-animation-deferred").reject(),e(a,b))}}}])}(); \ No newline at end of file +/* angular-snapscroll v0.3.0, (c) 2014-2016 Joel Mukuthu, MIT License, built: 16-07-2016 00:35:52 GMT+0200 */ +!function(){"use strict";function a(a,b,c,d){return a/=d/2,a<1?c/2*a*a+b:(a--,-c/2*(a*(a-2)-1)+b)}angular.module("snapscroll",["wheelie"]).value("defaultSnapscrollScrollEasing",a).value("defaultSnapscrollScrollDelay",250).value("defaultSnapscrollSnapDuration",800).value("defaultSnapscrollResizeDelay",400).value("defaultSnapscrollBindScrollTimeout",400)}(),function(){"use strict";angular.module("snapscroll").directive("fitWindowHeight",["$window","$timeout","defaultSnapscrollResizeDelay",function(a,b,c){return{restrict:"A",require:"snapscroll",link:function(d,e,f,g){function h(){l===!1?g.setSnapHeight(a.innerHeight):(b.cancel(k),k=b(function(){g.setSnapHeight(a.innerHeight)},l))}function i(){"false"===l?l=!1:(l=parseInt(l,10),isNaN(l)&&(l=c)),g.setSnapHeight(a.innerHeight),j=angular.element(a),j.on("resize",h),d.$on("$destroy",function(){j.off("resize")})}var j,k,l=f.resizeDelay;i()}}}])}(),function(){"use strict";var a={snapIndex:"=?",snapHeight:"=?",beforeSnap:"&",afterSnap:"&",snapAnimation:"=?"},b=["$scope",function(a){this.setSnapHeight=function(b){a.snapHeight=b}}],c=function(a){return angular.isNumber(a)&&!isNaN(a)},d=function(a,b){a.$watch("snapHeight",function(d,e){if(!angular.isUndefined(d))return c(d)?void(angular.isFunction(b)&&b(d)):void(c(e)&&(a.snapHeight=e))})},e=function(a,b){a.$watch("snapIndex",function(d,e){return angular.isUndefined(d)?void(a.snapIndex=0):c(d)?d%1!==0?void(a.snapIndex=Math.round(d)):a.ignoreThisSnapIndexChange?void(a.ignoreThisSnapIndexChange=void 0):a.isValid(d)?a.beforeSnap({snapIndex:d})===!1?(a.ignoreThisSnapIndexChange=!0,void(a.snapIndex=e)):void(angular.isFunction(b)&&(d>e?a.snapDirection="up":db.scopeIndexMax()?c=!0:(c=!1,b.$apply(function(){b.snapIndex+=1}))),d(a,c)}}),b.$on("$destroy",function(){a.unbind(c)})},g=["$timeout","scroll","wheelie","defaultSnapscrollScrollDelay","defaultSnapscrollSnapDuration","defaultSnapscrollBindScrollTimeout",function(c,g,h,i,j,k){return{restrict:"A",scope:a,controller:b,link:function(a,b,l){function m(a){for(var c=b.children(),d=0,e=0;e0;)a-=c=e[++d].offsetHeight;return c/2>=-a&&(d+=1),d}var o,p,q,r,s,t,u,v,w=l.snapEasing,x=l.scrollDelay,y=l.snapDuration,z=angular.isDefined(l.preventSnappingAfterManualScroll);p=function(d,e){var f,h=m(d);f=a.snapAnimation?angular.isDefined(w)?[b,h,y,w]:[b,h,y]:[b,h],!z&&s&&t(),g.to.apply(g,f).then(function(){angular.isFunction(e)&&e(),z||(c.cancel(v),v=c(r,k))})},q=function(){var d=function(){var c=n(b[0].scrollTop);a.snapIndex===c?p(c):a.$apply(function(){a.snapIndex=c})};g.stop(b),x===!1?d():(c.cancel(u),u=c(d,x))},r=function(){return"none"!==a.snapDirection?void(v=c(r,k)):(b.on("scroll",q),void(s=!0))},t=function(){b.off("scroll",q),s=!1},(o=function(){"false"===x?x=!1:(x=parseInt(x,10),isNaN(x)&&(x=i)),angular.isDefined(w)&&(w=a.$parent.$eval(w)),y=parseInt(y,10),isNaN(y)&&(y=j),a.$watch("snapAnimation",function(b){void 0===b&&(a.snapAnimation=!0)}),a.snapIndexMin=function(){return 0},a.scopeIndexMax=function(){return b.children().length-1},a.isValid=function(b){return b>=a.snapIndexMin()&&b<=a.scopeIndexMax()},"scroll"!==b.css("overflowY")&&b.css("overflowY","auto"),d(a,function(c){b.css("height",c+"px");var d=b.children();d.length&&angular.forEach(d,function(a){angular.element(a).css("height",c+"px")}),p(a.snapIndex)}),e(a,p),z||(r(),a.$on("$destroy",t)),f(h,a,b)})()}}}];angular.module("snapscroll").directive("snapscroll",g)}(),function(){"use strict";var a=function(a,b){for(var c,d=["webkit","moz"],e=0;e