4831: Add test methods.
[arvados.git] / apps / backstage / app / infinitescroll.js
1 // Call the content module's getMoreItems() action whenever the bottom
2 // edge of the content view is [within pxThreshold of being] visible.
3 //
4 // If getMoreItems() returns a promise, bottom edge visibility will be
5 // tested again when that promise is resolved. This should be used
6 // whenever getMoreItems() adds any new items, to cover the case where
7 // the bottom of the content view is still visible after a new page of
8 // items is rendered.
9 //
10 // It is the responsibility of getMoreItems() to ignore subsequent
11 // calls while it's busy retrieving or preparing additional content.
12 module.exports = InfiniteScroll;
13
14 var m = require('mithril')
15 , jQuery = require('jquery');
16
17 function InfiniteScroll(contentCtrl, contentView, opts) {
18     var scroller = {};
19     opts = opts || {};
20     scroller.controller = function() {
21         this.contentCtrl = contentCtrl;
22         this.getMoreItems = this.contentCtrl.getMoreItems.bind(this.contentCtrl);
23         this.pxThreshold = opts.pxThreshold || 0;
24         this.onunload = onunload.bind(this);
25         function onunload () {
26             var i=0;
27             InfiniteScroll.controllers().map(function(ctrl) {
28                 if (ctrl === this) {
29                     InfiniteScroll.elements().splice(i, 1);
30                     InfiniteScroll.controllers().splice(i, 1);
31                 } else {
32                     i++;
33                 }
34             }.bind(this));
35         };
36     };
37     scroller.view = function(ctrl) {
38         return m('.container', {config: function(el, isInit, ctx) {
39             return scroller.configEl(el, isInit, ctx, ctrl);
40         }}, [
41             contentView(ctrl.contentCtrl)
42         ]);
43     };
44     scroller.configEl = function(el, isInit, ctx, ctrl) {
45         if (isInit) return;
46         if (InfiniteScroll.elements().indexOf(el) < 0) {
47             InfiniteScroll.elements().push(el);
48             InfiniteScroll.controllers().push(ctrl);
49         }
50     };
51     return scroller;
52 }
53 InfiniteScroll.elements = m.prop([]);
54 InfiniteScroll.controllers = m.prop([]);
55
56 (function() {
57     function scrollHandler(event) {
58         InfiniteScroll.elements().map(function(el, i) {
59             var ctrl = InfiniteScroll.controllers()[i];
60             var pxBeforeEnd =
61                 el.getBoundingClientRect().bottom -
62                 document.documentElement.clientHeight;
63             var promised;
64             if (pxBeforeEnd > ctrl.pxThreshold)
65                 return;
66             if ((promised = ctrl.getMoreItems()) && promised.then)
67                 promised.then(scrollHandler);
68         });
69     }
70     jQuery(window).on('DOMContentLoaded load resize scroll', scrollHandler);
71 })();