git ssb

16+

Dominic / patchbay



Tree: 2a4eeba5ccbec9f2d17acc87b9ca095593a0bf7b

Files: 2a4eeba5ccbec9f2d17acc87b9ca095593a0bf7b / app / page / search.js

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

Built with git-ssb-web