summaryrefslogtreecommitdiffstats
path: root/catalog-ui/app/third-party/ng-infinite-scroll/src/infinite-scroll.coffee
diff options
context:
space:
mode:
Diffstat (limited to 'catalog-ui/app/third-party/ng-infinite-scroll/src/infinite-scroll.coffee')
-rw-r--r--catalog-ui/app/third-party/ng-infinite-scroll/src/infinite-scroll.coffee209
1 files changed, 209 insertions, 0 deletions
diff --git a/catalog-ui/app/third-party/ng-infinite-scroll/src/infinite-scroll.coffee b/catalog-ui/app/third-party/ng-infinite-scroll/src/infinite-scroll.coffee
new file mode 100644
index 0000000000..cf2f90fc19
--- /dev/null
+++ b/catalog-ui/app/third-party/ng-infinite-scroll/src/infinite-scroll.coffee
@@ -0,0 +1,209 @@
+angular.module('infinite-scroll', [])
+ .value('THROTTLE_MILLISECONDS', null)
+ .directive 'infiniteScroll', [
+ '$rootScope', '$window', '$interval', 'THROTTLE_MILLISECONDS',
+($rootScope, $window, $interval, THROTTLE_MILLISECONDS) ->
+ scope:
+ infiniteScroll: '&'
+ infiniteScrollContainer: '='
+ infiniteScrollDistance: '='
+ infiniteScrollDisabled: '='
+ infiniteScrollUseDocumentBottom: '=',
+ infiniteScrollListenForEvent: '@'
+
+ link: (scope, elem, attrs) ->
+ windowElement = angular.element($window)
+
+ scrollDistance = null
+ scrollEnabled = null
+ checkWhenEnabled = null
+ container = null
+ immediateCheck = true
+ useDocumentBottom = false
+ unregisterEventListener = null
+ checkInterval = false
+
+ height = (elem) ->
+ elem = elem[0] or elem
+
+ if isNaN(elem.offsetHeight) then elem.document.documentElement.clientHeight else elem.offsetHeight
+
+ offsetTop = (elem) ->
+ if not elem[0].getBoundingClientRect or elem.css('none')
+ return
+
+ elem[0].getBoundingClientRect().top + pageYOffset(elem)
+
+ pageYOffset = (elem) ->
+ elem = elem[0] or elem
+
+ if isNaN(window.pageYOffset) then elem.document.documentElement.scrollTop else elem.ownerDocument.defaultView.pageYOffset
+
+ # infinite-scroll specifies a function to call when the window,
+ # or some other container specified by infinite-scroll-container,
+ # is scrolled within a certain range from the bottom of the
+ # document. It is recommended to use infinite-scroll-disabled
+ # with a boolean that is set to true when the function is
+ # called in order to throttle the function call.
+ handler = ->
+ if container == windowElement
+ containerBottom = height(container) + pageYOffset(container[0].document.documentElement)
+ elementBottom = offsetTop(elem) + height(elem)
+ else
+ containerBottom = height(container)
+ containerTopOffset = 0
+ if offsetTop(container) != undefined
+ containerTopOffset = offsetTop(container)
+ elementBottom = offsetTop(elem) - containerTopOffset + height(elem)
+
+ if(useDocumentBottom)
+ elementBottom = height((elem[0].ownerDocument || elem[0].document).documentElement)
+
+ remaining = elementBottom - containerBottom
+ shouldScroll = remaining <= height(container) * scrollDistance + 1
+
+ if shouldScroll
+ checkWhenEnabled = true
+
+ if scrollEnabled
+ if scope.$$phase || $rootScope.$$phase
+ scope.infiniteScroll()
+ else
+ scope.$apply(scope.infiniteScroll)
+ else
+ if checkInterval then $interval.cancel checkInterval
+ checkWhenEnabled = false
+
+ # The optional THROTTLE_MILLISECONDS configuration value specifies
+ # a minimum time that should elapse between each call to the
+ # handler. N.b. the first call the handler will be run
+ # immediately, and the final call will always result in the
+ # handler being called after the `wait` period elapses.
+ # A slimmed down version of underscore's implementation.
+ throttle = (func, wait) ->
+ timeout = null
+ previous = 0
+ later = ->
+ previous = new Date().getTime()
+ $interval.cancel(timeout)
+ timeout = null
+ func.call()
+
+ return ->
+ now = new Date().getTime()
+ remaining = wait - (now - previous)
+ if remaining <= 0
+ $interval.cancel(timeout)
+ timeout = null
+ previous = now
+ func.call()
+ else timeout = $interval(later, remaining, 1) unless timeout
+
+ if THROTTLE_MILLISECONDS?
+ handler = throttle(handler, THROTTLE_MILLISECONDS)
+
+ scope.$on '$destroy', ->
+ container.unbind 'scroll', handler
+ if unregisterEventListener?
+ unregisterEventListener()
+ unregisterEventListener = null
+ if checkInterval
+ $interval.cancel checkInterval
+
+ # infinite-scroll-distance specifies how close to the bottom of the page
+ # the window is allowed to be before we trigger a new scroll. The value
+ # provided is multiplied by the container height; for example, to load
+ # more when the bottom of the page is less than 3 container heights away,
+ # specify a value of 3. Defaults to 0.
+ handleInfiniteScrollDistance = (v) ->
+ scrollDistance = parseFloat(v) or 0
+
+ scope.$watch 'infiniteScrollDistance', handleInfiniteScrollDistance
+ # If I don't explicitly call the handler here, tests fail. Don't know why yet.
+ handleInfiniteScrollDistance scope.infiniteScrollDistance
+
+ # infinite-scroll-disabled specifies a boolean that will keep the
+ # infnite scroll function from being called; this is useful for
+ # debouncing or throttling the function call. If an infinite
+ # scroll is triggered but this value evaluates to true, then
+ # once it switches back to false the infinite scroll function
+ # will be triggered again.
+ handleInfiniteScrollDisabled = (v) ->
+ scrollEnabled = !v
+ if scrollEnabled && checkWhenEnabled
+ checkWhenEnabled = false
+ handler()
+
+ scope.$watch 'infiniteScrollDisabled', handleInfiniteScrollDisabled
+ # If I don't explicitly call the handler here, tests fail. Don't know why yet.
+ handleInfiniteScrollDisabled scope.infiniteScrollDisabled
+
+ # use the bottom of the document instead of the element's bottom.
+ # This useful when the element does not have a height due to its
+ # children being absolute positioned.
+ handleInfiniteScrollUseDocumentBottom = (v) ->
+ useDocumentBottom = v
+
+ scope.$watch 'infiniteScrollUseDocumentBottom', handleInfiniteScrollUseDocumentBottom
+ handleInfiniteScrollUseDocumentBottom scope.infiniteScrollUseDocumentBottom
+
+ # infinite-scroll-container sets the container which we want to be
+ # infinte scrolled, instead of the whole window. Must be an
+ # Angular or jQuery element, or, if jQuery is loaded,
+ # a jQuery selector as a string.
+ changeContainer = (newContainer) ->
+ if container?
+ container.unbind 'scroll', handler
+
+ container = newContainer
+ if newContainer?
+ container.bind 'scroll', handler
+
+ changeContainer windowElement
+
+ if scope.infiniteScrollListenForEvent
+ unregisterEventListener = $rootScope.$on scope.infiniteScrollListenForEvent, handler
+
+ handleInfiniteScrollContainer = (newContainer) ->
+ # TODO: For some reason newContainer is sometimes null instead
+ # of the empty array, which Angular is supposed to pass when the
+ # element is not defined
+ # (https://github.com/sroze/ngInfiniteScroll/pull/7#commitcomment-5748431).
+ # So I leave both checks.
+ if (not newContainer?) or newContainer.length == 0
+ return
+
+ if newContainer.nodeType && newContainer.nodeType == 1
+ newContainer = angular.element newContainer
+ else if typeof newContainer.append == 'function'
+ newContainer = angular.element newContainer[newContainer.length - 1]
+ else if typeof newContainer == 'string'
+ newContainer = angular.element document.querySelector newContainer
+
+ if newContainer?
+ changeContainer newContainer
+ else
+ throw new Error("invalid infinite-scroll-container attribute.")
+
+ scope.$watch 'infiniteScrollContainer', handleInfiniteScrollContainer
+ handleInfiniteScrollContainer(scope.infiniteScrollContainer or [])
+
+ # infinite-scroll-parent establishes this element's parent as the
+ # container infinitely scrolled instead of the whole window.
+ if attrs.infiniteScrollParent?
+ changeContainer angular.element elem.parent()
+
+ # infinte-scoll-immediate-check sets whether or not run the
+ # expression passed on infinite-scroll for the first time when the
+ # directive first loads, before any actual scroll.
+ if attrs.infiniteScrollImmediateCheck?
+ immediateCheck = scope.$eval(attrs.infiniteScrollImmediateCheck)
+
+ checkInterval = $interval (->
+ if immediateCheck
+ handler()
+ $interval.cancel checkInterval
+ )
+]
+if typeof module != "undefined" && typeof exports != "undefined" && module.exports == exports
+ module.exports = 'infinite-scroll'