git ssb

16+

Dominic / patchbay



Tree: 945ca13b771f8b6d6af68122f85759e9f3eb3e9b

Files: 945ca13b771f8b6d6af68122f85759e9f3eb3e9b / app / page / search.js

4235 bytesRaw
1const nest = require('depnest')
2const { h, Struct, Value, when, computed } = require('mutant')
3const pull = require('pull-stream')
4const next = require('pull-next-step')
5const Scroller = require('pull-scroll')
6const TextNodeSearcher = require('text-node-searcher')
7
8exports.gives = nest('app.page.search')
9
10exports.needs = nest({
11 'app.html.filter': 'first',
12 'app.html.scroller': 'first',
13 'message.html.render': 'first',
14 'sbot.pull.log': 'first',
15 'sbot.pull.stream': 'first'
16})
17
18var whitespace = /\s+/
19
20function andSearch (terms, inputs) {
21 for (var i = 0; i < terms.length; i++) {
22 var match = false
23 for (var j = 0; j < inputs.length; j++) {
24 if (terms[i].test(inputs[j])) match = true
25 }
26 // if a term was not matched by anything, filter this one
27 if (!match) return false
28 }
29 return true
30}
31
32function searchFilter (terms) {
33 return function (msg) {
34 var c = msg && msg.value && msg.value.content
35 return c && (
36 msg.key === terms[0] ||
37 andSearch(terms.map(function (term) {
38 return new RegExp('\\b' + term + '\\b', 'i')
39 }), [c.text, c.name, c.title])
40 )
41 }
42}
43
44function createOrRegExp (ary) {
45 return new RegExp(ary.map(function (e) {
46 return '\\b' + e + '\\b'
47 }).join('|'), 'i')
48}
49
50function highlight (el, query) {
51 var searcher = new TextNodeSearcher({container: el})
52 searcher.query = query
53 searcher.highlight()
54 return el
55}
56
57function fallback (createReader) {
58 var fallbackRead
59 return function (read) {
60 return function (abort, cb) {
61 read(abort, function next (end, data) {
62 if (end && createReader && (fallbackRead = createReader(end))) {
63 createReader = null
64 read = fallbackRead
65 read(abort, next)
66 } else {
67 cb(end, data)
68 }
69 })
70 }
71 }
72}
73
74exports.create = function (api) {
75 return nest('app.page.search', searchPage)
76
77 function searchPage (location) {
78 const query = location.query.trim()
79
80 var queryTerms = query.split(whitespace)
81 var matchesQuery = searchFilter(queryTerms)
82
83 const search = Struct({
84 isLinear: Value(false),
85 linear: Struct({
86 checked: Value(0)
87 }),
88 fulltext: Struct({
89 isDone: Value(false)
90 }),
91 matches: Value(0)
92 })
93 const hasNoFulltextMatches = computed([search.fulltext.isDone, search.matches],
94 (done, matches) => done && matches === 0)
95
96 const searchHeader = h('Search', [
97 h('header', h('h1', query)),
98 when(search.isLinear,
99 h('section.details', [
100 h('div.searched', ['Searched: ', search.linear.checked]),
101 h('div.matches', [search.matches, ' matches'])
102 ]),
103 h('section.details', [
104 h('div.searched'),
105 when(hasNoFulltextMatches, h('div.matches', 'No matches'))
106 ])
107 )
108 ])
109 const { filterMenu, filterDownThrough, filterUpThrough, resetFeed } = api.app.html.filter(draw)
110 const { container, content } = api.app.html.scroller({ prepend: [searchHeader, filterMenu] })
111
112 function renderMsg (msg) {
113 var el = api.message.html.render(msg)
114 highlight(el, createOrRegExp(queryTerms))
115 return el
116 }
117
118 function draw () {
119 resetFeed({ container, content })
120
121 pull(
122 api.sbot.pull.log({old: false}),
123 pull.filter(matchesQuery),
124 filterUpThrough(),
125 Scroller(container, content, renderMsg, true, false)
126 )
127
128 pull(
129 api.sbot.pull.stream(sbot => next(sbot.search.query, { query, limit: 500 })),
130 fallback((err) => {
131 if (err === true) {
132 search.fulltext.isDone.set(true)
133 } else if (/^no source/.test(err.message)) {
134 search.isLinear.set(true)
135 return pull(
136 next(api.sbot.pull.log, {reverse: true, limit: 500, live: false}),
137 pull.through(() => search.linear.checked.set(search.linear.checked() + 1)),
138 pull.filter(matchesQuery)
139 )
140 }
141 }),
142 filterDownThrough(),
143 pull.through(() => search.matches.set(search.matches() + 1)),
144 Scroller(container, content, renderMsg, false, false)
145 )
146 }
147
148 draw()
149
150 container.title = '?' + query
151 return container
152 }
153}
154

Built with git-ssb-web