git ssb

0+

alanz / patchwork



forked from Matt McKegg / patchwork

Tree: fc4bdfbe7e94b2507aba1991405f77aa19c43e3c

Files: fc4bdfbe7e94b2507aba1991405f77aa19c43e3c / lib / scroller.js

2209 bytesRaw
1var pull = require('pull-stream')
2var Pause = require('pull-pause')
3var Value = require('mutant/value')
4var onceIdle = require('mutant/once-idle')
5var computed = require('mutant/computed')
6
7module.exports = Scroller
8
9function Scroller (scroller, content, render, opts) {
10 if (typeof opts === 'function') {
11 opts = {onDone: opts}
12 } else if (!opts) {
13 opts = {}
14 }
15 var toRenderCount = Value(0)
16 var toAppendCount = Value(0)
17 var pendingVisible = new Set()
18
19 var queueLength = computed([toRenderCount, toAppendCount], (a, b) => a + b)
20
21 var pause = Pause(function () {})
22 var running = true
23 var appendQueue = []
24
25 function appendLoop () {
26 var distanceFromBottom = scroller.scrollHeight - (scroller.scrollTop + scroller.clientHeight)
27 if (distanceFromBottom < scroller.clientHeight) {
28 while (appendQueue.length) {
29 var element = appendQueue.shift()
30 content.appendChild(element)
31 pendingVisible.add(element)
32 }
33 }
34
35 toAppendCount.set(appendQueue.length)
36 if (queueLength() < 5) {
37 // queue running low, resume stream
38 pause.resume()
39 }
40
41 if (running || queueLength()) {
42 window.requestAnimationFrame(appendLoop)
43 }
44
45 }
46
47 var stream = pull(
48 pause,
49 pull.drain(function (msg) {
50 toRenderCount.set(toRenderCount() + 1)
51
52 onceIdle(() => {
53 var element = render(msg)
54 appendQueue.push(element)
55 toRenderCount.set(toRenderCount() - 1)
56 })
57
58 if (queueLength() > 5) {
59 pause.pause()
60 }
61 }, function (err) {
62 running = false
63 clearInterval(visibleInterval)
64 opts.onDone ? opts.onDone(err) : console.error(err)
65 })
66 )
67
68 var visibleInterval = setInterval(() => {
69 // check for visible items every 2 seconds
70 Array.from(pendingVisible).forEach(checkVisible)
71 }, 2000)
72
73 stream.queue = queueLength
74
75 appendLoop()
76 return stream
77
78 function checkVisible (element) {
79 var height = scroller.clientHeight
80 var rect = element.getBoundingClientRect()
81 if (height > 50 && rect.bottom < height) {
82 pendingVisible.delete(element)
83 if (opts.onItemVisible) {
84 onceIdle(() => opts.onItemVisible(element))
85 }
86 }
87 }
88}
89

Built with git-ssb-web