Files: 97eb203c6049b5a49935be9ffca99fe8fbd07188 / lib / pull-scroll.js
2999 bytesRaw
1 | // forked because of weird non-filling and over-resuming problems |
2 | // should really PR this, but Dominic might not accept it :D |
3 | |
4 | var pull = require('pull-stream') |
5 | var Pause = require('pull-pause') |
6 | var Obv = require('obv') |
7 | |
8 | var next = 'undefined' === typeof setImmediate ? setTimeout : setImmediate |
9 | var buffer = Math.max(window.innerHeight * 2, 1000) |
10 | |
11 | var u = require('pull-scroll/utils'), |
12 | assertScrollable = u.assertScrollable, |
13 | isEnd = u.isEnd, |
14 | isVisible = u.isVisible |
15 | |
16 | module.exports = Scroller |
17 | |
18 | |
19 | function Scroller(scroller, content, render, isPrepend, isSticky, cb) { |
20 | assertScrollable(scroller) |
21 | var obv = Obv() |
22 | |
23 | //if second argument is a function, |
24 | //it means the scroller and content elements are the same. |
25 | if('function' === typeof content) { |
26 | cb = isSticky |
27 | isPrepend = render |
28 | render = content |
29 | content = scroller |
30 | } |
31 | |
32 | if(!cb) cb = function (err) { if(err) throw err } |
33 | |
34 | scroller.addEventListener('scroll', scroll) |
35 | var pause = Pause(function () {}) |
36 | var queue = [] |
37 | |
38 | //apply some changes to the dom, but ensure that |
39 | //`element` is at the same place on screen afterwards. |
40 | |
41 | function add () { |
42 | if(queue.length) { |
43 | var m = queue.shift() |
44 | var r = render(m) |
45 | append(scroller, content, r, isPrepend, isSticky) |
46 | obv.set(queue.length) |
47 | } |
48 | } |
49 | |
50 | function scroll (ev) { |
51 | if(isEnd(scroller, buffer, isPrepend)) { |
52 | pause.resume() |
53 | } |
54 | } |
55 | |
56 | pause.pause() |
57 | |
58 | //wait until the scroller has been added to the document |
59 | next(function next () { |
60 | if(scroller.parentElement) pause.resume() |
61 | else setTimeout(next, 100) |
62 | }) |
63 | |
64 | var stream = pull( |
65 | pause, |
66 | pull.drain(function (e) { |
67 | queue.push(e) |
68 | obv.set(queue.length) |
69 | |
70 | if(content.clientHeight < window.innerHeight) |
71 | add() |
72 | |
73 | if (isVisible(content)) { |
74 | if (isEnd(scroller, buffer, isPrepend)) |
75 | add() |
76 | } |
77 | |
78 | if(queue.length > 5) |
79 | pause.pause() |
80 | |
81 | }, function (err) { |
82 | if(err) console.error(err) |
83 | cb ? cb(err) : console.error(err) |
84 | }) |
85 | ) |
86 | |
87 | stream.visible = add |
88 | stream.observ = obv |
89 | return stream |
90 | } |
91 | |
92 | |
93 | function append(scroller, list, el, isPrepend, isSticky) { |
94 | if(!el) return |
95 | var s = scroller.scrollHeight |
96 | var st = scroller.scrollTop |
97 | if(isPrepend && list.firstChild) |
98 | list.insertBefore(el, list.firstChild) |
99 | else |
100 | list.appendChild(el) |
101 | |
102 | //scroll down by the height of the thing added. |
103 | //if it added to the top (in non-sticky mode) |
104 | //or added it to the bottom (in sticky mode) |
105 | if(isPrepend !== isSticky) { |
106 | var d = (scroller.scrollHeight - s) |
107 | var before = scroller.scrollTop |
108 | //check whether the browser has moved the scrollTop for us. |
109 | //if you add an element that is not scrolled into view |
110 | //it no longer bumps the view down! but this check is still needed |
111 | //for firefox. |
112 | //this seems to be the behavior in recent chrome (also electron) |
113 | if(st === scroller.scrollTop) { |
114 | scroller.scrollTop = scroller.scrollTop + d |
115 | } |
116 | } |
117 | } |
118 |
Built with git-ssb-web