Files: ed0d0518717fe16a686399588766fb35b3e6e37a / app / html / scroller.js
2312 bytesRaw
1 | const nest = require('depnest') |
2 | const { h } = require('mutant') |
3 | |
4 | exports.gives = nest('app.html.scroller') |
5 | |
6 | exports.create = function (api) { |
7 | return nest('app.html.scroller', Scroller) |
8 | |
9 | function Scroller (opts = {}) { |
10 | const { prepend, content = null, append, classList = [], className = '', title = '', scrollIntoView } = opts |
11 | |
12 | const contentSection = h('section.content', { |
13 | title: '', |
14 | intersectionBindingViewport: { rootMargin: '1000px' } // mutant magic |
15 | }, content) |
16 | |
17 | const container = h('Scroller', |
18 | { |
19 | classList, |
20 | className, |
21 | title, |
22 | style: { 'overflow-y': 'scroll', 'overflow-x': 'auto' } |
23 | // TODO (watch for breaks e.g. stuff stops updating after scrolling) |
24 | }, |
25 | [ |
26 | prepend ? h('section.top', prepend) : null, |
27 | contentSection, |
28 | append ? h('section.bottom', append) : null |
29 | ] |
30 | ) |
31 | |
32 | container.keyboardScroll = KeyboardScroll(contentSection, scrollIntoView) |
33 | |
34 | return { |
35 | content: contentSection, |
36 | container |
37 | } |
38 | } |
39 | } |
40 | |
41 | function KeyboardScroll (content, scrollIntoView = false) { |
42 | var curMsgEl |
43 | |
44 | if (!content) return () => {} |
45 | |
46 | content.addEventListener('click', onActivateChild, false) |
47 | content.addEventListener('focus', onActivateChild, true) |
48 | |
49 | function onActivateChild (ev) { |
50 | for (var el = ev.target; el; el = el.parentNode) { |
51 | if (el.parentNode === content) { |
52 | curMsgEl = el |
53 | return |
54 | } |
55 | } |
56 | } |
57 | |
58 | return function scroll (d) { |
59 | const child = (!curMsgEl || d === 'first') ? content.firstChild |
60 | : (!curMsgEl || d === 'last') ? content.lastChild |
61 | : d < 0 ? curMsgEl.previousElementSibling || content.firstChild |
62 | : d > 0 ? curMsgEl.nextElementSibling || content.lastChild |
63 | : curMsgEl |
64 | |
65 | selectChild(child) |
66 | curMsgEl = child |
67 | |
68 | return curMsgEl |
69 | } |
70 | |
71 | function selectChild (el) { |
72 | if (!el) { return } |
73 | |
74 | if (scrollIntoView) { |
75 | if (!el.scrollIntoViewIfNeeded && !el.scrollIntoView) return |
76 | ;(el.scrollIntoViewIfNeeded || el.scrollIntoView).call(el) |
77 | } else { |
78 | const height = el.offsetTop - content.parentElement.offsetTop - 10 |
79 | // content.parentElement.scroll({ top: height, behavior: 'smooth' }) |
80 | content.parentElement.scrollTop = height |
81 | } |
82 | |
83 | if (el.focus) el.focus() |
84 | } |
85 | } |
86 |
Built with git-ssb-web