git ssb

0+

alanz / patchwork



forked from Matt McKegg / patchwork

Tree: 0e7c0899affc876a69d822ae746c7c358f8c2906

Files: 0e7c0899affc876a69d822ae746c7c358f8c2906 / modules / page / html / render / search.js

4111 bytesRaw
1var { h, Value, when, computed } = require('mutant')
2var pull = require('pull-stream')
3var TextNodeSearcher = require('text-node-searcher')
4var whitespace = /\s+/
5var pullAbortable = require('pull-abortable')
6var Scroller = require('../../../../lib/scroller')
7var nextStepper = require('../../../../lib/next-stepper')
8var nest = require('depnest')
9var Proxy = require('mutant/proxy')
10
11exports.needs = nest({
12 'sbot.pull.stream': 'first',
13 'keys.sync.id': 'first',
14 'message.html.render': 'first'
15})
16
17exports.gives = nest('page.html.render')
18
19exports.create = function (api) {
20 return nest('page.html.render', function channel (path) {
21 if (path[0] !== '?') return
22
23 var queryStr = path.substr(1).trim()
24 var query = queryStr.split(whitespace)
25 var done = Value(false)
26 var loading = Proxy(true)
27 var count = Value(0)
28 var updates = Value(0)
29 var aborter = null
30
31 const searchHeader = h('div', {className: 'PageHeading'}, [
32 h('h1', [h('strong', 'Search Results:'), ' ', query.join(' ')])
33 ])
34
35 var updateLoader = h('a Notifier -loader', { href: '#', 'ev-click': refresh }, [
36 'Show ', h('strong', [updates]), ' ', plural(updates, 'update', 'updates')
37 ])
38
39 var content = Proxy()
40 var container = h('Scroller', {
41 style: { overflow: 'auto' }
42 }, [
43 h('div.wrapper', [
44 h('SearchPage', [
45 searchHeader,
46 content,
47 when(loading, h('Loading -search'), h('div', {
48 style: {
49 'padding': '60px 0',
50 'font-size': '150%'
51 }
52 }, [h('strong', 'Search completed.'), ' ', count, ' ', plural(count, 'result', 'results'), ' found']))
53 ])
54 ])
55 ])
56
57 var realtimeAborter = pullAbortable()
58
59 pull(
60 api.sbot.pull.stream(sbot => sbot.patchwork.linearSearch({old: false, query})),
61 realtimeAborter,
62 pull.drain(msg => {
63 updates.set(updates() + 1)
64 })
65 )
66
67 refresh()
68
69 return h('SplitView', {
70 hooks: [
71 RemoveHook(() => {
72 // terminate search if removed from dom
73 // this is triggered whenever a new search is started
74 realtimeAborter.abort()
75 aborter && aborter.abort()
76 })
77 ],
78 uniqueKey: 'search'
79 }, [
80 h('div.main', [
81 when(updates, updateLoader),
82 container
83 ])
84 ])
85
86 // scoped
87
88 function refresh () {
89 if (aborter) {
90 aborter.abort()
91 }
92
93 aborter = pullAbortable()
94
95 updates.set(0)
96 content.set(h('section.content'))
97
98 var scroller = Scroller(container, content(), renderMsg, err => {
99 if (err) console.log(err)
100 done.set(true)
101 })
102
103 pull(
104 api.sbot.pull.stream(sbot => nextStepper(getStream, {
105 reverse: true,
106 limit: 5,
107 query
108 })),
109 pull.through(() => count.set(count() + 1)),
110 aborter,
111 pull.filter(msg => msg.value),
112 scroller
113 )
114
115 loading.set(computed([done, scroller.queue], (done, queue) => {
116 return !done && queue < 5
117 }))
118 }
119
120 function getStream (opts) {
121 if (opts.lt != null && !opts.lt.marker) {
122 // if an lt has been specified that is not a marker, assume stream is finished
123 return pull.empty()
124 } else {
125 return api.sbot.pull.stream(sbot => sbot.patchwork.linearSearch(opts))
126 }
127 }
128
129 function renderMsg (msg) {
130 var el = h('FeedEvent', api.message.html.render(msg))
131 highlight(el, createOrRegExp(query))
132 return el
133 }
134 })
135}
136
137function createOrRegExp (ary) {
138 return new RegExp(ary.map(function (e) {
139 return '\\b' + e + '\\b'
140 }).join('|'), 'i')
141}
142
143function highlight (el, query) {
144 if (el) {
145 var searcher = new TextNodeSearcher({container: el})
146 searcher.query = query
147 searcher.highlight()
148 return el
149 }
150}
151
152function RemoveHook (fn) {
153 return function (element) {
154 return fn
155 }
156}
157
158function plural (value, single, many) {
159 return computed(value, (value) => {
160 if (value === 1) {
161 return single
162 } else {
163 return many
164 }
165 })
166}
167

Built with git-ssb-web