Files: 7495ba504a750013427db3c17cf79911bdbe5106 / lib / pull-scroll.js
3035 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 Value = require('mutant/value') |
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 obs = Value(0) |
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 | obs.set(queue.length) |
47 | } |
48 | } |
49 | |
50 | function scroll (ev) { |
51 | if (isEnd(scroller, buffer, isPrepend)) { |
52 | add() |
53 | pause.resume() |
54 | } |
55 | } |
56 | |
57 | pause.pause() |
58 | |
59 | //wait until the scroller has been added to the document |
60 | next(function next () { |
61 | if(scroller.parentElement) pause.resume() |
62 | else setTimeout(next, 100) |
63 | }) |
64 | |
65 | var stream = pull( |
66 | pause, |
67 | pull.drain(function (e) { |
68 | queue.push(e) |
69 | obs.set(queue.length) |
70 | |
71 | if(content.clientHeight < window.innerHeight) |
72 | add() |
73 | |
74 | if (isVisible(content)) { |
75 | if (isEnd(scroller, buffer, isPrepend)) |
76 | add() |
77 | } |
78 | |
79 | if(queue.length > 5) { |
80 | pause.pause() |
81 | } |
82 | |
83 | }, function (err) { |
84 | if(err) console.error(err) |
85 | cb ? cb(err) : console.error(err) |
86 | }) |
87 | ) |
88 | |
89 | stream.visible = add |
90 | stream.queue = obs |
91 | return stream |
92 | } |
93 | |
94 | |
95 | function append(scroller, list, el, isPrepend, isSticky) { |
96 | if(!el) return |
97 | var s = scroller.scrollHeight |
98 | var st = scroller.scrollTop |
99 | if(isPrepend && list.firstChild) |
100 | list.insertBefore(el, list.firstChild) |
101 | else |
102 | list.appendChild(el) |
103 | |
104 | //scroll down by the height of the thing added. |
105 | //if it added to the top (in non-sticky mode) |
106 | //or added it to the bottom (in sticky mode) |
107 | if(isPrepend !== isSticky) { |
108 | var d = (scroller.scrollHeight - s) |
109 | var before = scroller.scrollTop |
110 | //check whether the browser has moved the scrollTop for us. |
111 | //if you add an element that is not scrolled into view |
112 | //it no longer bumps the view down! but this check is still needed |
113 | //for firefox. |
114 | //this seems to be the behavior in recent chrome (also electron) |
115 | if(st === scroller.scrollTop) { |
116 | scroller.scrollTop = scroller.scrollTop + d |
117 | } |
118 | } |
119 | } |
120 |
Built with git-ssb-web