git ssb

16+

Dominic / patchbay



Tree: 6b5fd322755eecdeebda31ed6090e626cebdc243

Files: 6b5fd322755eecdeebda31ed6090e626cebdc243 / modules_extra / search.js

3482 bytesRaw
1const h = require('../h')
2const fs = require('fs')
3const { Value, when } = require('@mmckegg/mutant')
4const u = require('../util')
5const pull = require('pull-stream')
6const Scroller = require('pull-scroll')
7const TextNodeSearcher = require('text-node-searcher')
8
9exports.needs = {
10 build_scroller: 'first',
11 message_render: 'first',
12 sbot_log: 'first',
13 sbot_fulltext_search: 'first'
14}
15
16exports.gives = {
17 screen_view: true,
18 mcss: true
19}
20
21var whitespace = /\s+/
22
23function andSearch(terms, inputs) {
24 for(var i = 0; i < terms.length; i++) {
25 var match = false
26 for(var j = 0; j < inputs.length; j++) {
27 if(terms[i].test(inputs[j])) match = true
28 }
29 //if a term was not matched by anything, filter this one
30 if(!match) return false
31 }
32 return true
33}
34
35function searchFilter(terms) {
36 return function (msg) {
37 var c = msg && msg.value && msg.value.content
38 return c && (
39 msg.key == terms[0] ||
40 andSearch(terms.map(function (term) {
41 return new RegExp('\\b'+term+'\\b', 'i')
42 }), [c.text, c.name, c.title])
43 )
44 }
45}
46
47function createOrRegExp(ary) {
48 return new RegExp(ary.map(function (e) {
49 return '\\b'+e+'\\b'
50 }).join('|'), 'i')
51}
52
53function highlight(el, query) {
54 var searcher = new TextNodeSearcher({container: el})
55 searcher.query = query
56 searcher.highlight()
57 return el
58}
59
60function fallback(reader) {
61 var fallbackRead
62 return function (read) {
63 return function (abort, cb) {
64 read(abort, function next(end, data) {
65 if (end && reader && (fallbackRead = reader(end))) {
66 reader = null
67 read = fallbackRead
68 read(abort, next)
69 } else {
70 cb(end, data)
71 }
72 })
73 }
74 }
75}
76
77exports.create = function (api) {
78
79 return {
80 screen_view,
81 mcss: () => fs.readFileSync(__filename.replace(/js$/, 'mcss'), 'utf8')
82 }
83
84 function screen_view (path) {
85 if (path[0] !== '?') return
86
87 var queryStr = path.substr(1).trim()
88 var query = queryStr.split(whitespace)
89 var _matches = searchFilter(query)
90
91 const isLinearSearch = Value(false)
92 const searched = Value(0)
93 const matches = Value(0)
94 const searchHeader = h('Search', [
95 h('header', h('h1', query.join(' '))),
96 when(isLinearSearch,
97 h('section.details', [
98 h('div.searched', ['Searched: ', searched]),
99 h('div.matches', [matches, ' matches'])
100 ])
101 )
102 ])
103 var { container, content } = api.build_scroller({ prepend: searchHeader })
104 container.id = path // helps tabs find this tab
105
106 function matchesQuery (data) {
107 searched.set(searched() + 1)
108 var m = _matches(data)
109 if(m) matches.set(matches() +1 )
110
111 return m
112 }
113
114 function renderMsg(msg) {
115 var el = api.message_render(msg)
116 highlight(el, createOrRegExp(query))
117 return el
118 }
119
120 pull(
121 api.sbot_log({old: false}),
122 pull.filter(matchesQuery),
123 Scroller(container, content, renderMsg, true, false)
124 )
125
126 pull(
127 u.next(api.sbot_fulltext_search, {query: queryStr, reverse: true, limit: 500, live: false}),
128 fallback((err) => {
129 if (/^no source/.test(err.message)) {
130 isLinearSearch.set(true)
131 return pull(
132 u.next(api.sbot_log, {reverse: true, limit: 500, live: false}),
133 pull.filter(matchesQuery)
134 )
135 }
136 }),
137 Scroller(container, content, renderMsg, false, false)
138 )
139
140 return container
141 }
142}
143
144

Built with git-ssb-web