From b72eaa24abb4797aade8a0ada7c45dfc63b46c48 Mon Sep 17 00:00:00 2001 From: Aron Duby Date: Tue, 29 Mar 2016 22:38:02 -0400 Subject: [PATCH] add the ability to turn off stopPropagation and preventDefault --- README.md | 10 ++++++++++ angular-scroll.js | 28 +++++++++++++++++++++------- angular-scroll.min.js | 2 +- angular-scroll.min.js.map | 2 +- src/directives/smooth-scroll.js | 6 +++--- src/module.js | 7 ++++++- 6 files changed, 42 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 3afcaea..3ce0378 100644 --- a/README.md +++ b/README.md @@ -248,6 +248,16 @@ Specify the active class name to apply to a link when it is active, default is ` angular.module('myApp', ['duScroll']).value('duScrollActiveClass', 'custom-class'); ``` +### stopPropagation and preventDefault +By default `duSmoothScroll` will call `stopPropagation` and `preventDefault` on the click event. To prevent this set these values to `false`. + +```js +angular.module('myApp', ['duScroll']) + .value('duStopPropagation', false) + .value('duPreventDefault', false); +``` + + Events ------ diff --git a/angular-scroll.js b/angular-scroll.js index 803e0e7..dbbc85e 100644 --- a/angular-scroll.js +++ b/angular-scroll.js @@ -21,6 +21,9 @@ var duScroll = angular.module('duScroll', [ .value('duScrollDuration', 350) //Scrollspy debounce interval, set to 0 to disable .value('duScrollSpyWait', 100) + //Scrollspy forced refresh interval, use if your content changes or reflows without scrolling. + //0 to disable + .value('duScrollSpyRefreshInterval', 0) //Wether or not multiple scrollspies can be active at once .value('duScrollGreedy', false) //Default offset for smoothScroll directive @@ -32,7 +35,12 @@ var duScroll = angular.module('duScroll', [ //Whether or not to activate the last scrollspy, when page/container bottom is reached .value('duScrollBottomSpy', false) //Active class name - .value('duScrollActiveClass', 'active'); + .value('duScrollActiveClass', 'active') + //Whether or not to stopPropagation on the click event + .value('duStopPropagation', true) + //Whether or not to preventDefault on the click event + .value('duPreventDefault', true); + if (typeof module !== 'undefined' && module && module.exports) { module.exports = duScroll; @@ -254,7 +262,7 @@ angular.module('duScroll.requestAnimation', ['duScroll.polyfill']) angular.module('duScroll.spyAPI', ['duScroll.scrollContainerAPI']) -.factory('spyAPI', ["$rootScope", "$timeout", "$window", "$document", "scrollContainerAPI", "duScrollGreedy", "duScrollSpyWait", "duScrollBottomSpy", "duScrollActiveClass", function($rootScope, $timeout, $window, $document, scrollContainerAPI, duScrollGreedy, duScrollSpyWait, duScrollBottomSpy, duScrollActiveClass) { +.factory('spyAPI', ["$rootScope", "$timeout", "$interval", "$window", "$document", "scrollContainerAPI", "duScrollGreedy", "duScrollSpyWait", "duScrollSpyRefreshInterval", "duScrollBottomSpy", "duScrollActiveClass", function($rootScope, $timeout, $interval, $window, $document, scrollContainerAPI, duScrollGreedy, duScrollSpyWait, duScrollSpyRefreshInterval, duScrollBottomSpy, duScrollActiveClass) { 'use strict'; var createScrollHandler = function(context) { @@ -283,7 +291,7 @@ angular.module('duScroll.spyAPI', ['duScroll.scrollContainerAPI']) for(i = 0; i < spies.length; i++) { spy = spies[i]; pos = spy.getTargetPosition(); - if (!pos) continue; + if (!pos || !spy.$element) continue; if((duScrollBottomSpy && bottomReached) || (pos.top + spy.offset - containerOffset < 20 && (duScrollGreedy || pos.top*-1 + containerOffset) < pos.height)) { //Find the one closest the viewport top or the page bottom if it's reached @@ -300,7 +308,7 @@ angular.module('duScroll.spyAPI', ['duScroll.scrollContainerAPI']) toBeActive = toBeActive.spy; } if(currentlyActive === toBeActive || (duScrollGreedy && !toBeActive)) return; - if(currentlyActive) { + if(currentlyActive && currentlyActive.$element) { currentlyActive.$element.removeClass(duScrollActiveClass); $rootScope.$broadcast( 'duScrollspy:becameInactive', @@ -360,6 +368,9 @@ angular.module('duScroll.spyAPI', ['duScroll.scrollContainerAPI']) var destroyContext = function($scope) { var id = $scope.$id; var context = contexts[id], container = context.container; + if(context.intervalPromise) { + $interval.cancel(context.intervalPromise); + } if(container) { container.off('scroll', context.handler); } @@ -411,6 +422,9 @@ angular.module('duScroll.spyAPI', ['duScroll.scrollContainerAPI']) context.container.off('scroll', context.handler); } context.container = scrollContainerAPI.getContainer(spy.$scope); + if (duScrollSpyRefreshInterval && !context.intervalPromise) { + context.intervalPromise = $interval(context.handler, duScrollSpyRefreshInterval, 0, false); + } context.container.on('scroll', context.handler).triggerHandler('scroll'); } }; @@ -482,7 +496,7 @@ angular.module('duScroll.scrollContainerAPI', []) angular.module('duScroll.smoothScroll', ['duScroll.scrollHelpers', 'duScroll.scrollContainerAPI']) -.directive('duSmoothScroll', ["duScrollDuration", "duScrollOffset", "scrollContainerAPI", function(duScrollDuration, duScrollOffset, scrollContainerAPI) { +.directive('duSmoothScroll', ["duScrollDuration", "duScrollOffset", "duStopPropagation", "duPreventDefault", "scrollContainerAPI", function(duScrollDuration, duScrollOffset, duStopPropagation, duPreventDefault, scrollContainerAPI) { 'use strict'; return { @@ -495,8 +509,8 @@ angular.module('duScroll.smoothScroll', ['duScroll.scrollHelpers', 'duScroll.scr var target = document.getElementById(id) || document.getElementsByName(id)[0]; if(!target || !target.getBoundingClientRect) return; - if (e.stopPropagation) e.stopPropagation(); - if (e.preventDefault) e.preventDefault(); + if (duStopPropagation && e.stopPropagation) e.stopPropagation(); + if (duPreventDefault && e.preventDefault) e.preventDefault(); var offset = $attr.offset ? parseInt($attr.offset, 10) : duScrollOffset; var duration = $attr.duration ? parseInt($attr.duration, 10) : duScrollDuration; diff --git a/angular-scroll.min.js b/angular-scroll.min.js index cace875..a90c5c1 100644 --- a/angular-scroll.min.js +++ b/angular-scroll.min.js @@ -1,2 +1,2 @@ -var duScrollDefaultEasing=function(e){"use strict";return.5>e?Math.pow(2*e,2)/2:1-Math.pow(2*(1-e),2)/2},duScroll=angular.module("duScroll",["duScroll.scrollspy","duScroll.smoothScroll","duScroll.scrollContainer","duScroll.spyContext","duScroll.scrollHelpers"]).value("duScrollDuration",350).value("duScrollSpyWait",100).value("duScrollGreedy",!1).value("duScrollOffset",0).value("duScrollEasing",duScrollDefaultEasing).value("duScrollCancelOnEvents","scroll mousedown mousewheel touchmove keydown").value("duScrollBottomSpy",!1).value("duScrollActiveClass","active");"undefined"!=typeof module&&module&&module.exports&&(module.exports=duScroll),angular.module("duScroll.scrollHelpers",["duScroll.requestAnimation"]).run(["$window","$q","cancelAnimation","requestAnimation","duScrollEasing","duScrollDuration","duScrollOffset","duScrollCancelOnEvents",function(e,t,n,r,o,l,u,c){"use strict";var i={},a=function(e){return"undefined"!=typeof HTMLDocument&&e instanceof HTMLDocument||e.nodeType&&e.nodeType===e.DOCUMENT_NODE},s=function(e){return"undefined"!=typeof HTMLElement&&e instanceof HTMLElement||e.nodeType&&e.nodeType===e.ELEMENT_NODE},d=function(e){return s(e)||a(e)?e:e[0]};i.duScrollTo=function(t,n,r,o){var l;if(angular.isElement(t)?l=this.duScrollToElement:angular.isDefined(r)&&(l=this.duScrollToAnimated),l)return l.apply(this,arguments);var u=d(this);return a(u)?e.scrollTo(t,n):(u.scrollLeft=t,void(u.scrollTop=n))};var f,m;i.duScrollToAnimated=function(e,l,u,i){u&&!i&&(i=o);var a=this.duScrollLeft(),s=this.duScrollTop(),d=Math.round(e-a),p=Math.round(l-s),S=null,g=0,v=this,h=function(e){(!e||g&&e.which>0)&&(c&&v.unbind(c,h),n(f),m.reject(),f=null)};if(f&&h(),m=t.defer(),0===u||!d&&!p)return 0===u&&v.duScrollTo(e,l),m.resolve(),m.promise;var y=function(e){null===S&&(S=e),g=e-S;var t=g>=u?1:i(g/u);v.scrollTo(a+Math.ceil(d*t),s+Math.ceil(p*t)),1>t?f=r(y):(c&&v.unbind(c,h),f=null,m.resolve())};return v.duScrollTo(a,s),c&&v.bind(c,h),f=r(y),m.promise},i.duScrollToElement=function(e,t,n,r){var o=d(this);(!angular.isNumber(t)||isNaN(t))&&(t=u);var l=this.duScrollTop()+d(e).getBoundingClientRect().top-t;return s(o)&&(l-=o.getBoundingClientRect().top),this.duScrollTo(0,l,n,r)},i.duScrollLeft=function(t,n,r){if(angular.isNumber(t))return this.duScrollTo(t,this.duScrollTop(),n,r);var o=d(this);return a(o)?e.scrollX||document.documentElement.scrollLeft||document.body.scrollLeft:o.scrollLeft},i.duScrollTop=function(t,n,r){if(angular.isNumber(t))return this.duScrollTo(this.duScrollLeft(),t,n,r);var o=d(this);return a(o)?e.scrollY||document.documentElement.scrollTop||document.body.scrollTop:o.scrollTop},i.duScrollToElementAnimated=function(e,t,n,r){return this.duScrollToElement(e,t,n||l,r)},i.duScrollTopAnimated=function(e,t,n){return this.duScrollTop(e,t||l,n)},i.duScrollLeftAnimated=function(e,t,n){return this.duScrollLeft(e,t||l,n)},angular.forEach(i,function(e,t){angular.element.prototype[t]=e;var n=t.replace(/^duScroll/,"scroll");angular.isUndefined(angular.element.prototype[n])&&(angular.element.prototype[n]=e)})}]),angular.module("duScroll.polyfill",[]).factory("polyfill",["$window",function(e){"use strict";var t=["webkit","moz","o","ms"];return function(n,r){if(e[n])return e[n];for(var o,l=n.substr(0,1).toUpperCase()+n.substr(1),u=0;u=a.scrollHeight;else{var f=r[0].body.scrollHeight||r[0].documentElement.scrollHeight;t=Math.round(n.pageYOffset+n.innerHeight)>=f}var m,p,S,g,v,h,y=c&&t?"bottom":"top";for(g=o.spies,p=o.currentlyActive,S=void 0,m=0;me?Math.pow(2*e,2)/2:1-Math.pow(2*(1-e),2)/2},duScroll=angular.module("duScroll",["duScroll.scrollspy","duScroll.smoothScroll","duScroll.scrollContainer","duScroll.spyContext","duScroll.scrollHelpers"]).value("duScrollDuration",350).value("duScrollSpyWait",100).value("duScrollSpyRefreshInterval",0).value("duScrollGreedy",!1).value("duScrollOffset",0).value("duScrollEasing",duScrollDefaultEasing).value("duScrollCancelOnEvents","scroll mousedown mousewheel touchmove keydown").value("duScrollBottomSpy",!1).value("duScrollActiveClass","active").value("duStopPropagation",!0).value("duPreventDefault",!0);"undefined"!=typeof module&&module&&module.exports&&(module.exports=duScroll),angular.module("duScroll.scrollHelpers",["duScroll.requestAnimation"]).run(["$window","$q","cancelAnimation","requestAnimation","duScrollEasing","duScrollDuration","duScrollOffset","duScrollCancelOnEvents",function(e,t,n,r,o,l,u,i){"use strict";var c={},a=function(e){return"undefined"!=typeof HTMLDocument&&e instanceof HTMLDocument||e.nodeType&&e.nodeType===e.DOCUMENT_NODE},s=function(e){return"undefined"!=typeof HTMLElement&&e instanceof HTMLElement||e.nodeType&&e.nodeType===e.ELEMENT_NODE},d=function(e){return s(e)||a(e)?e:e[0]};c.duScrollTo=function(t,n,r,o){var l;if(angular.isElement(t)?l=this.duScrollToElement:angular.isDefined(r)&&(l=this.duScrollToAnimated),l)return l.apply(this,arguments);var u=d(this);return a(u)?e.scrollTo(t,n):(u.scrollLeft=t,void(u.scrollTop=n))};var f,p;c.duScrollToAnimated=function(e,l,u,c){u&&!c&&(c=o);var a=this.duScrollLeft(),s=this.duScrollTop(),d=Math.round(e-a),m=Math.round(l-s),S=null,g=0,v=this,h=function(e){(!e||g&&e.which>0)&&(i&&v.unbind(i,h),n(f),p.reject(),f=null)};if(f&&h(),p=t.defer(),0===u||!d&&!m)return 0===u&&v.duScrollTo(e,l),p.resolve(),p.promise;var y=function(e){null===S&&(S=e),g=e-S;var t=g>=u?1:c(g/u);v.scrollTo(a+Math.ceil(d*t),s+Math.ceil(m*t)),1>t?f=r(y):(i&&v.unbind(i,h),f=null,p.resolve())};return v.duScrollTo(a,s),i&&v.bind(i,h),f=r(y),p.promise},c.duScrollToElement=function(e,t,n,r){var o=d(this);angular.isNumber(t)&&!isNaN(t)||(t=u);var l=this.duScrollTop()+d(e).getBoundingClientRect().top-t;return s(o)&&(l-=o.getBoundingClientRect().top),this.duScrollTo(0,l,n,r)},c.duScrollLeft=function(t,n,r){if(angular.isNumber(t))return this.duScrollTo(t,this.duScrollTop(),n,r);var o=d(this);return a(o)?e.scrollX||document.documentElement.scrollLeft||document.body.scrollLeft:o.scrollLeft},c.duScrollTop=function(t,n,r){if(angular.isNumber(t))return this.duScrollTo(this.duScrollLeft(),t,n,r);var o=d(this);return a(o)?e.scrollY||document.documentElement.scrollTop||document.body.scrollTop:o.scrollTop},c.duScrollToElementAnimated=function(e,t,n,r){return this.duScrollToElement(e,t,n||l,r)},c.duScrollTopAnimated=function(e,t,n){return this.duScrollTop(e,t||l,n)},c.duScrollLeftAnimated=function(e,t,n){return this.duScrollLeft(e,t||l,n)},angular.forEach(c,function(e,t){angular.element.prototype[t]=e;var n=t.replace(/^duScroll/,"scroll");angular.isUndefined(angular.element.prototype[n])&&(angular.element.prototype[n]=e)})}]),angular.module("duScroll.polyfill",[]).factory("polyfill",["$window",function(e){"use strict";var t=["webkit","moz","o","ms"];return function(n,r){if(e[n])return e[n];for(var o,l=n.substr(0,1).toUpperCase()+n.substr(1),u=0;u=i.scrollHeight;else{var f=o[0].body.scrollHeight||o[0].documentElement.scrollHeight;t=Math.round(r.pageYOffset+r.innerHeight)>=f}var p,m,S,g,v,h,y=a&&t?"bottom":"top";for(g=n.spies,m=n.currentlyActive,S=void 0,p=0;p 0)) {\n if(duScrollCancelOnEvents) {\n el.unbind(duScrollCancelOnEvents, cancelScrollAnimation);\n }\n cancelAnimation(scrollAnimation);\n deferred.reject();\n scrollAnimation = null;\n }\n };\n\n if(scrollAnimation) {\n cancelScrollAnimation();\n }\n deferred = $q.defer();\n\n if(duration === 0 || (!deltaLeft && !deltaTop)) {\n if(duration === 0) {\n el.duScrollTo(left, top);\n }\n deferred.resolve();\n return deferred.promise;\n }\n\n var animationStep = function(timestamp) {\n if (startTime === null) {\n startTime = timestamp;\n }\n\n progress = timestamp - startTime;\n var percent = (progress >= duration ? 1 : easing(progress/duration));\n\n el.scrollTo(\n startLeft + Math.ceil(deltaLeft * percent),\n startTop + Math.ceil(deltaTop * percent)\n );\n if(percent < 1) {\n scrollAnimation = requestAnimation(animationStep);\n } else {\n if(duScrollCancelOnEvents) {\n el.unbind(duScrollCancelOnEvents, cancelScrollAnimation);\n }\n scrollAnimation = null;\n deferred.resolve();\n }\n };\n\n //Fix random mobile safari bug when scrolling to top by hitting status bar\n el.duScrollTo(startLeft, startTop);\n\n if(duScrollCancelOnEvents) {\n el.bind(duScrollCancelOnEvents, cancelScrollAnimation);\n }\n\n scrollAnimation = requestAnimation(animationStep);\n return deferred.promise;\n };\n\n proto.duScrollToElement = function(target, offset, duration, easing) {\n var el = unwrap(this);\n if(!angular.isNumber(offset) || isNaN(offset)) {\n offset = duScrollOffset;\n }\n var top = this.duScrollTop() + unwrap(target).getBoundingClientRect().top - offset;\n if(isElement(el)) {\n top -= el.getBoundingClientRect().top;\n }\n return this.duScrollTo(0, top, duration, easing);\n };\n\n proto.duScrollLeft = function(value, duration, easing) {\n if(angular.isNumber(value)) {\n return this.duScrollTo(value, this.duScrollTop(), duration, easing);\n }\n var el = unwrap(this);\n if(isDocument(el)) {\n return $window.scrollX || document.documentElement.scrollLeft || document.body.scrollLeft;\n }\n return el.scrollLeft;\n };\n proto.duScrollTop = function(value, duration, easing) {\n if(angular.isNumber(value)) {\n return this.duScrollTo(this.duScrollLeft(), value, duration, easing);\n }\n var el = unwrap(this);\n if(isDocument(el)) {\n return $window.scrollY || document.documentElement.scrollTop || document.body.scrollTop;\n }\n return el.scrollTop;\n };\n\n proto.duScrollToElementAnimated = function(target, offset, duration, easing) {\n return this.duScrollToElement(target, offset, duration || duScrollDuration, easing);\n };\n\n proto.duScrollTopAnimated = function(top, duration, easing) {\n return this.duScrollTop(top, duration || duScrollDuration, easing);\n };\n\n proto.duScrollLeftAnimated = function(left, duration, easing) {\n return this.duScrollLeft(left, duration || duScrollDuration, easing);\n };\n\n angular.forEach(proto, function(fn, key) {\n angular.element.prototype[key] = fn;\n\n //Remove prefix if not already claimed by jQuery / ui.utils\n var unprefixed = key.replace(/^duScroll/, 'scroll');\n if(angular.isUndefined(angular.element.prototype[unprefixed])) {\n angular.element.prototype[unprefixed] = fn;\n }\n });\n\n});\n","//Adapted from https://gist.github.com/paulirish/1579671\nangular.module('duScroll.polyfill', [])\n.factory('polyfill', function($window) {\n 'use strict';\n\n var vendors = ['webkit', 'moz', 'o', 'ms'];\n\n return function(fnName, fallback) {\n if($window[fnName]) {\n return $window[fnName];\n }\n var suffix = fnName.substr(0, 1).toUpperCase() + fnName.substr(1);\n for(var key, i = 0; i < vendors.length; i++) {\n key = vendors[i]+suffix;\n if($window[key]) {\n return $window[key];\n }\n }\n return fallback;\n };\n});\n\nangular.module('duScroll.requestAnimation', ['duScroll.polyfill'])\n.factory('requestAnimation', function(polyfill, $timeout) {\n 'use strict';\n\n var lastTime = 0;\n var fallback = function(callback, element) {\n var currTime = new Date().getTime();\n var timeToCall = Math.max(0, 16 - (currTime - lastTime));\n var id = $timeout(function() { callback(currTime + timeToCall); },\n timeToCall);\n lastTime = currTime + timeToCall;\n return id;\n };\n\n return polyfill('requestAnimationFrame', fallback);\n})\n.factory('cancelAnimation', function(polyfill, $timeout) {\n 'use strict';\n\n var fallback = function(promise) {\n $timeout.cancel(promise);\n };\n\n return polyfill('cancelAnimationFrame', fallback);\n});\n","angular.module('duScroll.spyAPI', ['duScroll.scrollContainerAPI'])\n.factory('spyAPI', function($rootScope, $timeout, $window, $document, scrollContainerAPI, duScrollGreedy, duScrollSpyWait, duScrollBottomSpy, duScrollActiveClass) {\n 'use strict';\n\n var createScrollHandler = function(context) {\n var timer = false, queued = false;\n var handler = function() {\n queued = false;\n var container = context.container,\n containerEl = container[0],\n containerOffset = 0,\n bottomReached;\n\n if (typeof HTMLElement !== 'undefined' && containerEl instanceof HTMLElement || containerEl.nodeType && containerEl.nodeType === containerEl.ELEMENT_NODE) {\n containerOffset = containerEl.getBoundingClientRect().top;\n bottomReached = Math.round(containerEl.scrollTop + containerEl.clientHeight) >= containerEl.scrollHeight;\n } else {\n var documentScrollHeight = $document[0].body.scrollHeight || $document[0].documentElement.scrollHeight; // documentElement for IE11\n bottomReached = Math.round($window.pageYOffset + $window.innerHeight) >= documentScrollHeight;\n }\n var compareProperty = (duScrollBottomSpy && bottomReached ? 'bottom' : 'top');\n\n var i, currentlyActive, toBeActive, spies, spy, pos;\n spies = context.spies;\n currentlyActive = context.currentlyActive;\n toBeActive = undefined;\n\n for(i = 0; i < spies.length; i++) {\n spy = spies[i];\n pos = spy.getTargetPosition();\n if (!pos) continue;\n\n if((duScrollBottomSpy && bottomReached) || (pos.top + spy.offset - containerOffset < 20 && (duScrollGreedy || pos.top*-1 + containerOffset) < pos.height)) {\n //Find the one closest the viewport top or the page bottom if it's reached\n if(!toBeActive || toBeActive[compareProperty] < pos[compareProperty]) {\n toBeActive = {\n spy: spy\n };\n toBeActive[compareProperty] = pos[compareProperty];\n }\n }\n }\n\n if(toBeActive) {\n toBeActive = toBeActive.spy;\n }\n if(currentlyActive === toBeActive || (duScrollGreedy && !toBeActive)) return;\n if(currentlyActive) {\n currentlyActive.$element.removeClass(duScrollActiveClass);\n $rootScope.$broadcast(\n 'duScrollspy:becameInactive',\n currentlyActive.$element,\n angular.element(currentlyActive.getTargetElement())\n );\n }\n if(toBeActive) {\n toBeActive.$element.addClass(duScrollActiveClass);\n $rootScope.$broadcast(\n 'duScrollspy:becameActive',\n toBeActive.$element,\n angular.element(toBeActive.getTargetElement())\n );\n }\n context.currentlyActive = toBeActive;\n };\n\n if(!duScrollSpyWait) {\n return handler;\n }\n\n //Debounce for potential performance savings\n return function() {\n if(!timer) {\n handler();\n timer = $timeout(function() {\n timer = false;\n if(queued) {\n handler();\n }\n }, duScrollSpyWait, false);\n } else {\n queued = true;\n }\n };\n };\n\n var contexts = {};\n\n var createContext = function($scope) {\n var id = $scope.$id;\n var context = {\n spies: []\n };\n\n context.handler = createScrollHandler(context);\n contexts[id] = context;\n\n $scope.$on('$destroy', function() {\n destroyContext($scope);\n });\n\n return id;\n };\n\n var destroyContext = function($scope) {\n var id = $scope.$id;\n var context = contexts[id], container = context.container;\n if(container) {\n container.off('scroll', context.handler);\n }\n delete contexts[id];\n };\n\n var defaultContextId = createContext($rootScope);\n\n var getContextForScope = function(scope) {\n if(contexts[scope.$id]) {\n return contexts[scope.$id];\n }\n if(scope.$parent) {\n return getContextForScope(scope.$parent);\n }\n return contexts[defaultContextId];\n };\n\n var getContextForSpy = function(spy) {\n var context, contextId, scope = spy.$scope;\n if(scope) {\n return getContextForScope(scope);\n }\n //No scope, most likely destroyed\n for(contextId in contexts) {\n context = contexts[contextId];\n if(context.spies.indexOf(spy) !== -1) {\n return context;\n }\n }\n };\n\n var isElementInDocument = function(element) {\n while (element.parentNode) {\n element = element.parentNode;\n if (element === document) {\n return true;\n }\n }\n return false;\n };\n\n var addSpy = function(spy) {\n var context = getContextForSpy(spy);\n if (!context) return;\n context.spies.push(spy);\n if (!context.container || !isElementInDocument(context.container)) {\n if(context.container) {\n context.container.off('scroll', context.handler);\n }\n context.container = scrollContainerAPI.getContainer(spy.$scope);\n context.container.on('scroll', context.handler).triggerHandler('scroll');\n }\n };\n\n var removeSpy = function(spy) {\n var context = getContextForSpy(spy);\n if(spy === context.currentlyActive) {\n $rootScope.$broadcast('duScrollspy:becameInactive', context.currentlyActive.$element);\n context.currentlyActive = null;\n }\n var i = context.spies.indexOf(spy);\n if(i !== -1) {\n context.spies.splice(i, 1);\n }\n\t\tspy.$element = null;\n };\n\n return {\n addSpy: addSpy,\n removeSpy: removeSpy,\n createContext: createContext,\n destroyContext: destroyContext,\n getContextForScope: getContextForScope\n };\n});\n","angular.module('duScroll.scrollContainerAPI', [])\n.factory('scrollContainerAPI', function($document) {\n 'use strict';\n\n var containers = {};\n\n var setContainer = function(scope, element) {\n var id = scope.$id;\n containers[id] = element;\n return id;\n };\n\n var getContainerId = function(scope) {\n if(containers[scope.$id]) {\n return scope.$id;\n }\n if(scope.$parent) {\n return getContainerId(scope.$parent);\n }\n return;\n };\n\n var getContainer = function(scope) {\n var id = getContainerId(scope);\n return id ? containers[id] : $document;\n };\n\n var removeContainer = function(scope) {\n var id = getContainerId(scope);\n if(id) {\n delete containers[id];\n }\n };\n\n return {\n getContainerId: getContainerId,\n getContainer: getContainer,\n setContainer: setContainer,\n removeContainer: removeContainer\n };\n});\n","angular.module('duScroll.smoothScroll', ['duScroll.scrollHelpers', 'duScroll.scrollContainerAPI'])\n.directive('duSmoothScroll', function(duScrollDuration, duScrollOffset, scrollContainerAPI) {\n 'use strict';\n\n return {\n link : function($scope, $element, $attr) {\n $element.on('click', function(e) {\n if((!$attr.href || $attr.href.indexOf('#') === -1) && $attr.duSmoothScroll === '') return;\n\n var id = $attr.href ? $attr.href.replace(/.*(?=#[^\\s]+$)/, '').substring(1) : $attr.duSmoothScroll;\n\n var target = document.getElementById(id) || document.getElementsByName(id)[0];\n if(!target || !target.getBoundingClientRect) return;\n\n if (e.stopPropagation) e.stopPropagation();\n if (e.preventDefault) e.preventDefault();\n\n var offset = $attr.offset ? parseInt($attr.offset, 10) : duScrollOffset;\n var duration = $attr.duration ? parseInt($attr.duration, 10) : duScrollDuration;\n var container = scrollContainerAPI.getContainer($scope);\n\n container.duScrollToElement(\n angular.element(target),\n isNaN(offset) ? 0 : offset,\n isNaN(duration) ? 0 : duration\n );\n });\n }\n };\n});\n","angular.module('duScroll.spyContext', ['duScroll.spyAPI'])\n.directive('duSpyContext', function(spyAPI) {\n 'use strict';\n\n return {\n restrict: 'A',\n scope: true,\n compile: function compile(tElement, tAttrs, transclude) {\n return {\n pre: function preLink($scope, iElement, iAttrs, controller) {\n spyAPI.createContext($scope);\n }\n };\n }\n };\n});\n","angular.module('duScroll.scrollContainer', ['duScroll.scrollContainerAPI'])\n.directive('duScrollContainer', function(scrollContainerAPI){\n 'use strict';\n\n return {\n restrict: 'A',\n scope: true,\n compile: function compile(tElement, tAttrs, transclude) {\n return {\n pre: function preLink($scope, iElement, iAttrs, controller) {\n iAttrs.$observe('duScrollContainer', function(element) {\n if(angular.isString(element)) {\n element = document.getElementById(element);\n }\n\n element = (angular.isElement(element) ? angular.element(element) : iElement);\n scrollContainerAPI.setContainer($scope, element);\n $scope.$on('$destroy', function() {\n scrollContainerAPI.removeContainer($scope);\n });\n });\n }\n };\n }\n };\n});\n","angular.module('duScroll.scrollspy', ['duScroll.spyAPI'])\n.directive('duScrollspy', function(spyAPI, duScrollOffset, $timeout, $rootScope) {\n 'use strict';\n\n var Spy = function(targetElementOrId, $scope, $element, offset) {\n if(angular.isElement(targetElementOrId)) {\n this.target = targetElementOrId;\n } else if(angular.isString(targetElementOrId)) {\n this.targetId = targetElementOrId;\n }\n this.$scope = $scope;\n this.$element = $element;\n this.offset = offset;\n };\n\n Spy.prototype.getTargetElement = function() {\n if (!this.target && this.targetId) {\n this.target = document.getElementById(this.targetId) || document.getElementsByName(this.targetId)[0];\n }\n return this.target;\n };\n\n Spy.prototype.getTargetPosition = function() {\n var target = this.getTargetElement();\n if(target) {\n return target.getBoundingClientRect();\n }\n };\n\n Spy.prototype.flushTargetCache = function() {\n if(this.targetId) {\n this.target = undefined;\n }\n };\n\n return {\n link: function ($scope, $element, $attr) {\n var href = $attr.ngHref || $attr.href;\n var targetId;\n\n if (href && href.indexOf('#') !== -1) {\n targetId = href.replace(/.*(?=#[^\\s]+$)/, '').substring(1);\n } else if($attr.duScrollspy) {\n targetId = $attr.duScrollspy;\n } else if($attr.duSmoothScroll) {\n targetId = $attr.duSmoothScroll;\n }\n if(!targetId) return;\n\n // Run this in the next execution loop so that the scroll context has a chance\n // to initialize\n var timeoutPromise = $timeout(function() {\n var spy = new Spy(targetId, $scope, $element, -($attr.offset ? parseInt($attr.offset, 10) : duScrollOffset));\n spyAPI.addSpy(spy);\n\n $scope.$on('$locationChangeSuccess', spy.flushTargetCache.bind(spy));\n var deregisterOnStateChange = $rootScope.$on('$stateChangeSuccess', spy.flushTargetCache.bind(spy));\n $scope.$on('$destroy', function() {\n spyAPI.removeSpy(spy);\n deregisterOnStateChange();\n });\n }, 0, false);\n $scope.$on('$destroy', function() {$timeout.cancel(timeoutPromise);});\n }\n };\n});\n"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["module.js","helpers.js","request-animation.js","spy-api.js","scroll-container-api.js","smooth-scroll.js","spy-context.js","scroll-container.js","scrollspy.js"],"names":["duScrollDefaultEasing","x","Math","pow","duScroll","angular","module","value","exports","run","$window","$q","cancelAnimation","requestAnimation","duScrollEasing","duScrollDuration","duScrollOffset","duScrollCancelOnEvents","proto","isDocument","el","HTMLDocument","nodeType","DOCUMENT_NODE","isElement","HTMLElement","ELEMENT_NODE","unwrap","duScrollTo","left","top","duration","easing","aliasFn","this","duScrollToElement","isDefined","duScrollToAnimated","apply","arguments","scrollTo","scrollLeft","scrollTop","scrollAnimation","deferred","startLeft","duScrollLeft","startTop","duScrollTop","deltaLeft","round","deltaTop","startTime","progress","cancelScrollAnimation","$event","which","unbind","reject","defer","resolve","promise","animationStep","timestamp","percent","ceil","bind","target","offset","isNumber","isNaN","getBoundingClientRect","scrollX","document","documentElement","body","scrollY","duScrollToElementAnimated","duScrollTopAnimated","duScrollLeftAnimated","forEach","fn","key","element","prototype","unprefixed","replace","isUndefined","factory","vendors","fnName","fallback","suffix","substr","toUpperCase","i","length","polyfill","$timeout","lastTime","callback","currTime","Date","getTime","timeToCall","max","id","cancel","$rootScope","$interval","$document","scrollContainerAPI","duScrollGreedy","duScrollSpyWait","duScrollSpyRefreshInterval","duScrollBottomSpy","duScrollActiveClass","createScrollHandler","context","timer","queued","handler","bottomReached","container","containerEl","containerOffset","clientHeight","scrollHeight","documentScrollHeight","pageYOffset","innerHeight","currentlyActive","toBeActive","spies","spy","pos","compareProperty","undefined","getTargetPosition","$element","height","removeClass","$broadcast","getTargetElement","addClass","contexts","createContext","$scope","$id","$on","destroyContext","intervalPromise","off","defaultContextId","getContextForScope","scope","$parent","getContextForSpy","contextId","indexOf","isElementInDocument","parentNode","addSpy","push","getContainer","on","triggerHandler","removeSpy","splice","containers","setContainer","getContainerId","removeContainer","directive","duStopPropagation","duPreventDefault","link","$attr","e","href","duSmoothScroll","substring","getElementById","getElementsByName","stopPropagation","preventDefault","parseInt","spyAPI","restrict","compile","tElement","tAttrs","transclude","pre","iElement","iAttrs","controller","$observe","isString","Spy","targetElementOrId","targetId","flushTargetCache","ngHref","duScrollspy","timeoutPromise","deregisterOnStateChange"],"mappings":"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","file":"angular-scroll.min.js","sourcesContent":["/**\r\n * x is a value between 0 and 1, indicating where in the animation you are.\r\n */\r\nvar duScrollDefaultEasing = function (x) {\r\n 'use strict';\r\n\r\n if(x < 0.5) {\r\n return Math.pow(x*2, 2)/2;\r\n }\r\n return 1-Math.pow((1-x)*2, 2)/2;\r\n};\r\n\r\nvar duScroll = angular.module('duScroll', [\r\n 'duScroll.scrollspy',\r\n 'duScroll.smoothScroll',\r\n 'duScroll.scrollContainer',\r\n 'duScroll.spyContext',\r\n 'duScroll.scrollHelpers'\r\n])\r\n //Default animation duration for smoothScroll directive\r\n .value('duScrollDuration', 350)\r\n //Scrollspy debounce interval, set to 0 to disable\r\n .value('duScrollSpyWait', 100)\r\n //Scrollspy forced refresh interval, use if your content changes or reflows without scrolling.\r\n //0 to disable\r\n .value('duScrollSpyRefreshInterval', 0)\r\n //Wether or not multiple scrollspies can be active at once\r\n .value('duScrollGreedy', false)\r\n //Default offset for smoothScroll directive\r\n .value('duScrollOffset', 0)\r\n //Default easing function for scroll animation\r\n .value('duScrollEasing', duScrollDefaultEasing)\r\n //Which events on the container (such as body) should cancel scroll animations\r\n .value('duScrollCancelOnEvents', 'scroll mousedown mousewheel touchmove keydown')\r\n //Whether or not to activate the last scrollspy, when page/container bottom is reached\r\n .value('duScrollBottomSpy', false)\r\n //Active class name\r\n .value('duScrollActiveClass', 'active')\r\n //Whether or not to stopPropagation on the click event\r\n .value('duStopPropagation', true)\r\n //Whether or not to preventDefault on the click event\r\n .value('duPreventDefault', true);\r\n\r\n\r\nif (typeof module !== 'undefined' && module && module.exports) {\r\n module.exports = duScroll;\r\n}\r\n","angular.module('duScroll.scrollHelpers', ['duScroll.requestAnimation'])\r\n.run(function($window, $q, cancelAnimation, requestAnimation, duScrollEasing, duScrollDuration, duScrollOffset, duScrollCancelOnEvents) {\r\n 'use strict';\r\n\r\n var proto = {};\r\n\r\n var isDocument = function(el) {\r\n return (typeof HTMLDocument !== 'undefined' && el instanceof HTMLDocument) || (el.nodeType && el.nodeType === el.DOCUMENT_NODE);\r\n };\r\n\r\n var isElement = function(el) {\r\n return (typeof HTMLElement !== 'undefined' && el instanceof HTMLElement) || (el.nodeType && el.nodeType === el.ELEMENT_NODE);\r\n };\r\n\r\n var unwrap = function(el) {\r\n return isElement(el) || isDocument(el) ? el : el[0];\r\n };\r\n\r\n proto.duScrollTo = function(left, top, duration, easing) {\r\n var aliasFn;\r\n if(angular.isElement(left)) {\r\n aliasFn = this.duScrollToElement;\r\n } else if(angular.isDefined(duration)) {\r\n aliasFn = this.duScrollToAnimated;\r\n }\r\n if(aliasFn) {\r\n return aliasFn.apply(this, arguments);\r\n }\r\n var el = unwrap(this);\r\n if(isDocument(el)) {\r\n return $window.scrollTo(left, top);\r\n }\r\n el.scrollLeft = left;\r\n el.scrollTop = top;\r\n };\r\n\r\n var scrollAnimation, deferred;\r\n proto.duScrollToAnimated = function(left, top, duration, easing) {\r\n if(duration && !easing) {\r\n easing = duScrollEasing;\r\n }\r\n var startLeft = this.duScrollLeft(),\r\n startTop = this.duScrollTop(),\r\n deltaLeft = Math.round(left - startLeft),\r\n deltaTop = Math.round(top - startTop);\r\n\r\n var startTime = null, progress = 0;\r\n var el = this;\r\n\r\n var cancelScrollAnimation = function($event) {\r\n if (!$event || (progress && $event.which > 0)) {\r\n if(duScrollCancelOnEvents) {\r\n el.unbind(duScrollCancelOnEvents, cancelScrollAnimation);\r\n }\r\n cancelAnimation(scrollAnimation);\r\n deferred.reject();\r\n scrollAnimation = null;\r\n }\r\n };\r\n\r\n if(scrollAnimation) {\r\n cancelScrollAnimation();\r\n }\r\n deferred = $q.defer();\r\n\r\n if(duration === 0 || (!deltaLeft && !deltaTop)) {\r\n if(duration === 0) {\r\n el.duScrollTo(left, top);\r\n }\r\n deferred.resolve();\r\n return deferred.promise;\r\n }\r\n\r\n var animationStep = function(timestamp) {\r\n if (startTime === null) {\r\n startTime = timestamp;\r\n }\r\n\r\n progress = timestamp - startTime;\r\n var percent = (progress >= duration ? 1 : easing(progress/duration));\r\n\r\n el.scrollTo(\r\n startLeft + Math.ceil(deltaLeft * percent),\r\n startTop + Math.ceil(deltaTop * percent)\r\n );\r\n if(percent < 1) {\r\n scrollAnimation = requestAnimation(animationStep);\r\n } else {\r\n if(duScrollCancelOnEvents) {\r\n el.unbind(duScrollCancelOnEvents, cancelScrollAnimation);\r\n }\r\n scrollAnimation = null;\r\n deferred.resolve();\r\n }\r\n };\r\n\r\n //Fix random mobile safari bug when scrolling to top by hitting status bar\r\n el.duScrollTo(startLeft, startTop);\r\n\r\n if(duScrollCancelOnEvents) {\r\n el.bind(duScrollCancelOnEvents, cancelScrollAnimation);\r\n }\r\n\r\n scrollAnimation = requestAnimation(animationStep);\r\n return deferred.promise;\r\n };\r\n\r\n proto.duScrollToElement = function(target, offset, duration, easing) {\r\n var el = unwrap(this);\r\n if(!angular.isNumber(offset) || isNaN(offset)) {\r\n offset = duScrollOffset;\r\n }\r\n var top = this.duScrollTop() + unwrap(target).getBoundingClientRect().top - offset;\r\n if(isElement(el)) {\r\n top -= el.getBoundingClientRect().top;\r\n }\r\n return this.duScrollTo(0, top, duration, easing);\r\n };\r\n\r\n proto.duScrollLeft = function(value, duration, easing) {\r\n if(angular.isNumber(value)) {\r\n return this.duScrollTo(value, this.duScrollTop(), duration, easing);\r\n }\r\n var el = unwrap(this);\r\n if(isDocument(el)) {\r\n return $window.scrollX || document.documentElement.scrollLeft || document.body.scrollLeft;\r\n }\r\n return el.scrollLeft;\r\n };\r\n proto.duScrollTop = function(value, duration, easing) {\r\n if(angular.isNumber(value)) {\r\n return this.duScrollTo(this.duScrollLeft(), value, duration, easing);\r\n }\r\n var el = unwrap(this);\r\n if(isDocument(el)) {\r\n return $window.scrollY || document.documentElement.scrollTop || document.body.scrollTop;\r\n }\r\n return el.scrollTop;\r\n };\r\n\r\n proto.duScrollToElementAnimated = function(target, offset, duration, easing) {\r\n return this.duScrollToElement(target, offset, duration || duScrollDuration, easing);\r\n };\r\n\r\n proto.duScrollTopAnimated = function(top, duration, easing) {\r\n return this.duScrollTop(top, duration || duScrollDuration, easing);\r\n };\r\n\r\n proto.duScrollLeftAnimated = function(left, duration, easing) {\r\n return this.duScrollLeft(left, duration || duScrollDuration, easing);\r\n };\r\n\r\n angular.forEach(proto, function(fn, key) {\r\n angular.element.prototype[key] = fn;\r\n\r\n //Remove prefix if not already claimed by jQuery / ui.utils\r\n var unprefixed = key.replace(/^duScroll/, 'scroll');\r\n if(angular.isUndefined(angular.element.prototype[unprefixed])) {\r\n angular.element.prototype[unprefixed] = fn;\r\n }\r\n });\r\n\r\n});\r\n","//Adapted from https://gist.github.com/paulirish/1579671\r\nangular.module('duScroll.polyfill', [])\r\n.factory('polyfill', function($window) {\r\n 'use strict';\r\n\r\n var vendors = ['webkit', 'moz', 'o', 'ms'];\r\n\r\n return function(fnName, fallback) {\r\n if($window[fnName]) {\r\n return $window[fnName];\r\n }\r\n var suffix = fnName.substr(0, 1).toUpperCase() + fnName.substr(1);\r\n for(var key, i = 0; i < vendors.length; i++) {\r\n key = vendors[i]+suffix;\r\n if($window[key]) {\r\n return $window[key];\r\n }\r\n }\r\n return fallback;\r\n };\r\n});\r\n\r\nangular.module('duScroll.requestAnimation', ['duScroll.polyfill'])\r\n.factory('requestAnimation', function(polyfill, $timeout) {\r\n 'use strict';\r\n\r\n var lastTime = 0;\r\n var fallback = function(callback, element) {\r\n var currTime = new Date().getTime();\r\n var timeToCall = Math.max(0, 16 - (currTime - lastTime));\r\n var id = $timeout(function() { callback(currTime + timeToCall); },\r\n timeToCall);\r\n lastTime = currTime + timeToCall;\r\n return id;\r\n };\r\n\r\n return polyfill('requestAnimationFrame', fallback);\r\n})\r\n.factory('cancelAnimation', function(polyfill, $timeout) {\r\n 'use strict';\r\n\r\n var fallback = function(promise) {\r\n $timeout.cancel(promise);\r\n };\r\n\r\n return polyfill('cancelAnimationFrame', fallback);\r\n});\r\n","angular.module('duScroll.spyAPI', ['duScroll.scrollContainerAPI'])\r\n.factory('spyAPI', function($rootScope, $timeout, $interval, $window, $document, scrollContainerAPI, duScrollGreedy, duScrollSpyWait, duScrollSpyRefreshInterval, duScrollBottomSpy, duScrollActiveClass) {\r\n 'use strict';\r\n\r\n var createScrollHandler = function(context) {\r\n var timer = false, queued = false;\r\n var handler = function() {\r\n queued = false;\r\n var container = context.container,\r\n containerEl = container[0],\r\n containerOffset = 0,\r\n bottomReached;\r\n\r\n if (typeof HTMLElement !== 'undefined' && containerEl instanceof HTMLElement || containerEl.nodeType && containerEl.nodeType === containerEl.ELEMENT_NODE) {\r\n containerOffset = containerEl.getBoundingClientRect().top;\r\n bottomReached = Math.round(containerEl.scrollTop + containerEl.clientHeight) >= containerEl.scrollHeight;\r\n } else {\r\n var documentScrollHeight = $document[0].body.scrollHeight || $document[0].documentElement.scrollHeight; // documentElement for IE11\r\n bottomReached = Math.round($window.pageYOffset + $window.innerHeight) >= documentScrollHeight;\r\n }\r\n var compareProperty = (duScrollBottomSpy && bottomReached ? 'bottom' : 'top');\r\n\r\n var i, currentlyActive, toBeActive, spies, spy, pos;\r\n spies = context.spies;\r\n currentlyActive = context.currentlyActive;\r\n toBeActive = undefined;\r\n\r\n for(i = 0; i < spies.length; i++) {\r\n spy = spies[i];\r\n pos = spy.getTargetPosition();\r\n if (!pos || !spy.$element) continue;\r\n\r\n if((duScrollBottomSpy && bottomReached) || (pos.top + spy.offset - containerOffset < 20 && (duScrollGreedy || pos.top*-1 + containerOffset) < pos.height)) {\r\n //Find the one closest the viewport top or the page bottom if it's reached\r\n if(!toBeActive || toBeActive[compareProperty] < pos[compareProperty]) {\r\n toBeActive = {\r\n spy: spy\r\n };\r\n toBeActive[compareProperty] = pos[compareProperty];\r\n }\r\n }\r\n }\r\n\r\n if(toBeActive) {\r\n toBeActive = toBeActive.spy;\r\n }\r\n if(currentlyActive === toBeActive || (duScrollGreedy && !toBeActive)) return;\r\n if(currentlyActive && currentlyActive.$element) {\r\n currentlyActive.$element.removeClass(duScrollActiveClass);\r\n $rootScope.$broadcast(\r\n 'duScrollspy:becameInactive',\r\n currentlyActive.$element,\r\n angular.element(currentlyActive.getTargetElement())\r\n );\r\n }\r\n if(toBeActive) {\r\n toBeActive.$element.addClass(duScrollActiveClass);\r\n $rootScope.$broadcast(\r\n 'duScrollspy:becameActive',\r\n toBeActive.$element,\r\n angular.element(toBeActive.getTargetElement())\r\n );\r\n }\r\n context.currentlyActive = toBeActive;\r\n };\r\n\r\n if(!duScrollSpyWait) {\r\n return handler;\r\n }\r\n\r\n //Debounce for potential performance savings\r\n return function() {\r\n if(!timer) {\r\n handler();\r\n timer = $timeout(function() {\r\n timer = false;\r\n if(queued) {\r\n handler();\r\n }\r\n }, duScrollSpyWait, false);\r\n } else {\r\n queued = true;\r\n }\r\n };\r\n };\r\n\r\n var contexts = {};\r\n\r\n var createContext = function($scope) {\r\n var id = $scope.$id;\r\n var context = {\r\n spies: []\r\n };\r\n\r\n context.handler = createScrollHandler(context);\r\n contexts[id] = context;\r\n\r\n $scope.$on('$destroy', function() {\r\n destroyContext($scope);\r\n });\r\n\r\n return id;\r\n };\r\n\r\n var destroyContext = function($scope) {\r\n var id = $scope.$id;\r\n var context = contexts[id], container = context.container;\r\n if(context.intervalPromise) {\r\n $interval.cancel(context.intervalPromise);\r\n }\r\n if(container) {\r\n container.off('scroll', context.handler);\r\n }\r\n delete contexts[id];\r\n };\r\n\r\n var defaultContextId = createContext($rootScope);\r\n\r\n var getContextForScope = function(scope) {\r\n if(contexts[scope.$id]) {\r\n return contexts[scope.$id];\r\n }\r\n if(scope.$parent) {\r\n return getContextForScope(scope.$parent);\r\n }\r\n return contexts[defaultContextId];\r\n };\r\n\r\n var getContextForSpy = function(spy) {\r\n var context, contextId, scope = spy.$scope;\r\n if(scope) {\r\n return getContextForScope(scope);\r\n }\r\n //No scope, most likely destroyed\r\n for(contextId in contexts) {\r\n context = contexts[contextId];\r\n if(context.spies.indexOf(spy) !== -1) {\r\n return context;\r\n }\r\n }\r\n };\r\n\r\n var isElementInDocument = function(element) {\r\n while (element.parentNode) {\r\n element = element.parentNode;\r\n if (element === document) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n };\r\n\r\n var addSpy = function(spy) {\r\n var context = getContextForSpy(spy);\r\n if (!context) return;\r\n context.spies.push(spy);\r\n if (!context.container || !isElementInDocument(context.container)) {\r\n if(context.container) {\r\n context.container.off('scroll', context.handler);\r\n }\r\n context.container = scrollContainerAPI.getContainer(spy.$scope);\r\n if (duScrollSpyRefreshInterval && !context.intervalPromise) {\r\n context.intervalPromise = $interval(context.handler, duScrollSpyRefreshInterval, 0, false);\r\n }\r\n context.container.on('scroll', context.handler).triggerHandler('scroll');\r\n }\r\n };\r\n\r\n var removeSpy = function(spy) {\r\n var context = getContextForSpy(spy);\r\n if(spy === context.currentlyActive) {\r\n $rootScope.$broadcast('duScrollspy:becameInactive', context.currentlyActive.$element);\r\n context.currentlyActive = null;\r\n }\r\n var i = context.spies.indexOf(spy);\r\n if(i !== -1) {\r\n context.spies.splice(i, 1);\r\n }\r\n\t\tspy.$element = null;\r\n };\r\n\r\n return {\r\n addSpy: addSpy,\r\n removeSpy: removeSpy,\r\n createContext: createContext,\r\n destroyContext: destroyContext,\r\n getContextForScope: getContextForScope\r\n };\r\n});\r\n","angular.module('duScroll.scrollContainerAPI', [])\r\n.factory('scrollContainerAPI', function($document) {\r\n 'use strict';\r\n\r\n var containers = {};\r\n\r\n var setContainer = function(scope, element) {\r\n var id = scope.$id;\r\n containers[id] = element;\r\n return id;\r\n };\r\n\r\n var getContainerId = function(scope) {\r\n if(containers[scope.$id]) {\r\n return scope.$id;\r\n }\r\n if(scope.$parent) {\r\n return getContainerId(scope.$parent);\r\n }\r\n return;\r\n };\r\n\r\n var getContainer = function(scope) {\r\n var id = getContainerId(scope);\r\n return id ? containers[id] : $document;\r\n };\r\n\r\n var removeContainer = function(scope) {\r\n var id = getContainerId(scope);\r\n if(id) {\r\n delete containers[id];\r\n }\r\n };\r\n\r\n return {\r\n getContainerId: getContainerId,\r\n getContainer: getContainer,\r\n setContainer: setContainer,\r\n removeContainer: removeContainer\r\n };\r\n});\r\n","angular.module('duScroll.smoothScroll', ['duScroll.scrollHelpers', 'duScroll.scrollContainerAPI'])\r\n.directive('duSmoothScroll', function(duScrollDuration, duScrollOffset, duStopPropagation, duPreventDefault, scrollContainerAPI) {\r\n 'use strict';\r\n\r\n return {\r\n link : function($scope, $element, $attr) {\r\n $element.on('click', function(e) {\r\n if((!$attr.href || $attr.href.indexOf('#') === -1) && $attr.duSmoothScroll === '') return;\r\n\r\n var id = $attr.href ? $attr.href.replace(/.*(?=#[^\\s]+$)/, '').substring(1) : $attr.duSmoothScroll;\r\n\r\n var target = document.getElementById(id) || document.getElementsByName(id)[0];\r\n if(!target || !target.getBoundingClientRect) return;\r\n\r\n if (duStopPropagation && e.stopPropagation) e.stopPropagation();\r\n if (duPreventDefault && e.preventDefault) e.preventDefault();\r\n\r\n var offset = $attr.offset ? parseInt($attr.offset, 10) : duScrollOffset;\r\n var duration = $attr.duration ? parseInt($attr.duration, 10) : duScrollDuration;\r\n var container = scrollContainerAPI.getContainer($scope);\r\n\r\n container.duScrollToElement(\r\n angular.element(target),\r\n isNaN(offset) ? 0 : offset,\r\n isNaN(duration) ? 0 : duration\r\n );\r\n });\r\n }\r\n };\r\n});\r\n","angular.module('duScroll.spyContext', ['duScroll.spyAPI'])\r\n.directive('duSpyContext', function(spyAPI) {\r\n 'use strict';\r\n\r\n return {\r\n restrict: 'A',\r\n scope: true,\r\n compile: function compile(tElement, tAttrs, transclude) {\r\n return {\r\n pre: function preLink($scope, iElement, iAttrs, controller) {\r\n spyAPI.createContext($scope);\r\n }\r\n };\r\n }\r\n };\r\n});\r\n","angular.module('duScroll.scrollContainer', ['duScroll.scrollContainerAPI'])\r\n.directive('duScrollContainer', function(scrollContainerAPI){\r\n 'use strict';\r\n\r\n return {\r\n restrict: 'A',\r\n scope: true,\r\n compile: function compile(tElement, tAttrs, transclude) {\r\n return {\r\n pre: function preLink($scope, iElement, iAttrs, controller) {\r\n iAttrs.$observe('duScrollContainer', function(element) {\r\n if(angular.isString(element)) {\r\n element = document.getElementById(element);\r\n }\r\n\r\n element = (angular.isElement(element) ? angular.element(element) : iElement);\r\n scrollContainerAPI.setContainer($scope, element);\r\n $scope.$on('$destroy', function() {\r\n scrollContainerAPI.removeContainer($scope);\r\n });\r\n });\r\n }\r\n };\r\n }\r\n };\r\n});\r\n","angular.module('duScroll.scrollspy', ['duScroll.spyAPI'])\r\n.directive('duScrollspy', function(spyAPI, duScrollOffset, $timeout, $rootScope) {\r\n 'use strict';\r\n\r\n var Spy = function(targetElementOrId, $scope, $element, offset) {\r\n if(angular.isElement(targetElementOrId)) {\r\n this.target = targetElementOrId;\r\n } else if(angular.isString(targetElementOrId)) {\r\n this.targetId = targetElementOrId;\r\n }\r\n this.$scope = $scope;\r\n this.$element = $element;\r\n this.offset = offset;\r\n };\r\n\r\n Spy.prototype.getTargetElement = function() {\r\n if (!this.target && this.targetId) {\r\n this.target = document.getElementById(this.targetId) || document.getElementsByName(this.targetId)[0];\r\n }\r\n return this.target;\r\n };\r\n\r\n Spy.prototype.getTargetPosition = function() {\r\n var target = this.getTargetElement();\r\n if(target) {\r\n return target.getBoundingClientRect();\r\n }\r\n };\r\n\r\n Spy.prototype.flushTargetCache = function() {\r\n if(this.targetId) {\r\n this.target = undefined;\r\n }\r\n };\r\n\r\n return {\r\n link: function ($scope, $element, $attr) {\r\n var href = $attr.ngHref || $attr.href;\r\n var targetId;\r\n\r\n if (href && href.indexOf('#') !== -1) {\r\n targetId = href.replace(/.*(?=#[^\\s]+$)/, '').substring(1);\r\n } else if($attr.duScrollspy) {\r\n targetId = $attr.duScrollspy;\r\n } else if($attr.duSmoothScroll) {\r\n targetId = $attr.duSmoothScroll;\r\n }\r\n if(!targetId) return;\r\n\r\n // Run this in the next execution loop so that the scroll context has a chance\r\n // to initialize\r\n var timeoutPromise = $timeout(function() {\r\n var spy = new Spy(targetId, $scope, $element, -($attr.offset ? parseInt($attr.offset, 10) : duScrollOffset));\r\n spyAPI.addSpy(spy);\r\n\r\n $scope.$on('$locationChangeSuccess', spy.flushTargetCache.bind(spy));\r\n var deregisterOnStateChange = $rootScope.$on('$stateChangeSuccess', spy.flushTargetCache.bind(spy));\r\n $scope.$on('$destroy', function() {\r\n spyAPI.removeSpy(spy);\r\n deregisterOnStateChange();\r\n });\r\n }, 0, false);\r\n $scope.$on('$destroy', function() {$timeout.cancel(timeoutPromise);});\r\n }\r\n };\r\n});\r\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/src/directives/smooth-scroll.js b/src/directives/smooth-scroll.js index 1283171..de01d3a 100644 --- a/src/directives/smooth-scroll.js +++ b/src/directives/smooth-scroll.js @@ -1,5 +1,5 @@ angular.module('duScroll.smoothScroll', ['duScroll.scrollHelpers', 'duScroll.scrollContainerAPI']) -.directive('duSmoothScroll', function(duScrollDuration, duScrollOffset, scrollContainerAPI) { +.directive('duSmoothScroll', function(duScrollDuration, duScrollOffset, duStopPropagation, duPreventDefault, scrollContainerAPI) { 'use strict'; return { @@ -12,8 +12,8 @@ angular.module('duScroll.smoothScroll', ['duScroll.scrollHelpers', 'duScroll.scr var target = document.getElementById(id) || document.getElementsByName(id)[0]; if(!target || !target.getBoundingClientRect) return; - if (e.stopPropagation) e.stopPropagation(); - if (e.preventDefault) e.preventDefault(); + if (duStopPropagation && e.stopPropagation) e.stopPropagation(); + if (duPreventDefault && e.preventDefault) e.preventDefault(); var offset = $attr.offset ? parseInt($attr.offset, 10) : duScrollOffset; var duration = $attr.duration ? parseInt($attr.duration, 10) : duScrollDuration; diff --git a/src/module.js b/src/module.js index 754cd64..1c165b1 100644 --- a/src/module.js +++ b/src/module.js @@ -35,7 +35,12 @@ var duScroll = angular.module('duScroll', [ //Whether or not to activate the last scrollspy, when page/container bottom is reached .value('duScrollBottomSpy', false) //Active class name - .value('duScrollActiveClass', 'active'); + .value('duScrollActiveClass', 'active') + //Whether or not to stopPropagation on the click event + .value('duStopPropagation', true) + //Whether or not to preventDefault on the click event + .value('duPreventDefault', true); + if (typeof module !== 'undefined' && module && module.exports) { module.exports = duScroll;