Commit c31e472556bdb4d5a6a192709bcff72ce36f324a
Merge branch 'master' of github.com:ssbc/patchbay into dark_crystal
mixmix committed on 8/2/2018, 4:43:49 AMParent: 2ca0297e908c4698d545ebf83acc9644cdef00f8
Parent: 061795bee1aa4edbfd8a050dc27d10cc020a8360
Files changed
app/page/calendar.js | changed |
app/page/notifications.js | changed |
app/page/private.js | changed |
app/page/search.js | changed |
index.js | changed |
package-lock.json | changed |
package.json | changed |
app/page/calendar.js | ||
---|---|---|
@@ -1,20 +1,35 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | 2 … | const { h, Array: MutantArray, map, Struct, computed, watch, throttle, resolve } = require('mutant') |
3 … | + | |
3 | 4 … | const pull = require('pull-stream') |
4 | 5 … | const { isMsg } = require('ssb-ref') |
5 | 6 … | |
6 | -exports.gives = nest('app.page.calendar') | |
7 … | +exports.gives = nest({ | |
8 … | + 'app.page.calendar': true, | |
9 … | + 'app.html.menuItem': true | |
10 … | +}) | |
7 | 11 … | |
8 | 12 … | exports.needs = nest({ |
9 | 13 … | 'message.html.render': 'first', |
14 … | + 'app.sync.goTo': 'first', | |
10 | 15 … | 'sbot.async.get': 'first', |
11 | 16 … | 'sbot.pull.stream': 'first' |
12 | 17 … | }) |
13 | 18 … | |
14 | 19 … | exports.create = (api) => { |
15 | - return nest('app.page.calendar', calendarPage) | |
20 … | + return nest({ | |
21 … | + 'app.html.menuItem': menuItem, | |
22 … | + 'app.page.calendar': calendarPage | |
23 … | + }) | |
16 | 24 … | |
25 … | + function menuItem () { | |
26 … | + return h('a', { | |
27 … | + style: { order: 1 }, | |
28 … | + 'ev-click': () => api.app.sync.goTo({ page: 'calendar' }) | |
29 … | + }, '/calendar') | |
30 … | + } | |
31 … | + | |
17 | 32 … | function calendarPage (location) { |
18 | 33 … | const d = new Date() |
19 | 34 … | const state = Struct({ |
20 | 35 … | today: new Date(d.getFullYear(), d.getMonth(), d.getDate()), |
@@ -25,90 +40,122 @@ | ||
25 | 40 … | lt: new Date(d.getFullYear(), d.getMonth(), d.getDate() + 1) |
26 | 41 … | }) |
27 | 42 … | }) |
28 | 43 … | |
29 | - watch(state.year, year => getEvents(year, state.events)) | |
44 … | + watch(state.year, year => getEvents(year, state.events, api)) | |
30 | 45 … | |
31 | 46 … | const page = h('CalendarPage', { title: '/calendar' }, [ |
32 | 47 … | Calendar(state), |
33 | - Events(state) | |
48 … | + Events(state, api) | |
34 | 49 … | ]) |
35 | 50 … | |
36 | - page.scroll = i => { | |
37 | - const gte = resolve(state.range.gte) | |
38 | - state.range.gte.set(new Date(gte.getFullYear(), gte.getMonth(), gte.getDate() + i)) | |
39 | - const lt = resolve(state.range.lt) | |
40 | - state.range.lt.set(new Date(lt.getFullYear(), lt.getMonth(), lt.getDate() + i)) | |
41 | - } | |
51 … | + page.scroll = (i) => scroll(state.range, i) | |
42 | 52 … | |
43 | 53 … | return page |
44 | 54 … | } |
55 … | +} | |
45 | 56 … | |
46 | - function Events (state) { | |
47 | - return h('CalendarEvents', computed([state.events, state.range], (events, range) => { | |
48 | - const keys = events | |
49 | - .filter(ev => ev.date >= range.gte && ev.date < range.lt) | |
50 | - .sort((a, b) => a.date - b.date) | |
51 | - .map(ev => ev.data.key) | |
57 … | +function scroll (range, i) { | |
58 … | + const { gte, lt } = resolve(range) | |
52 | 59 … | |
53 | - const gatherings = MutantArray([]) | |
60 … | + if (isMonthInterval(gte, lt)) { | |
61 … | + range.gte.set(new Date(gte.getFullYear(), gte.getMonth() + i, gte.getDate())) | |
62 … | + range.lt.set(new Date(lt.getFullYear(), lt.getMonth() + i, lt.getDate())) | |
63 … | + return | |
64 … | + } | |
54 | 65 … | |
55 | - pull( | |
56 | - pull.values(keys), | |
57 | - pull.asyncMap((key, cb) => { | |
58 | - api.sbot.async.get(key, (err, value) => { | |
59 | - if (err) return cb(err) | |
60 | - cb(null, {key, value}) | |
61 | - }) | |
62 | - }), | |
63 | - pull.drain(msg => gatherings.push(msg)) | |
64 | - ) | |
66 … | + if (isWeekInterval(gte, lt)) { | |
67 … | + range.gte.set(new Date(gte.getFullYear(), gte.getMonth(), gte.getDate() + 7 * i)) | |
68 … | + range.lt.set(new Date(lt.getFullYear(), lt.getMonth(), lt.getDate() + 7 * i)) | |
69 … | + return | |
70 … | + } | |
65 | 71 … | |
66 | - return map(gatherings, g => api.message.html.render(g)) | |
67 | - })) | |
72 … | + range.gte.set(new Date(gte.getFullYear(), gte.getMonth(), gte.getDate() + i)) | |
73 … | + range.lt.set(new Date(lt.getFullYear(), lt.getMonth(), lt.getDate() + i)) | |
74 … | + | |
75 … | + function isMonthInterval (gte, lt) { | |
76 … | + return gte.getDate() === 1 && // 1st of month | |
77 … | + lt.getDate() === 1 && // to the 1st of the month | |
78 … | + gte.getMonth() + 1 === lt.getMonth() && // one month gap | |
79 … | + gte.getFullYear() === lt.getFullYear() | |
68 | 80 … | } |
69 | 81 … | |
70 | - function getEvents (year, events) { | |
71 | - const query = [{ | |
72 | - $filter: { | |
73 | - value: { | |
74 | - timestamp: {$gt: Number(new Date(year, 0, 1))}, // ordered by published time | |
75 | - content: { | |
76 | - type: 'about', | |
77 | - startDateTime: { | |
78 | - epoch: {$gt: 0} | |
79 | - } | |
82 … | + function isWeekInterval (gte, lt) { | |
83 … | + console.log( | |
84 … | + new Date(gte.getFullYear(), gte.getMonth(), gte.getDate() + 7).toISOString() === lt.toISOString(), | |
85 … | + new Date(gte.getFullYear(), gte.getMonth(), gte.getDate() + 7).toISOString(), | |
86 … | + lt.toISOString(), | |
87 … | + ) | |
88 … | + return gte.getDay() === 1 && // from monday | |
89 … | + lt.getDay() === 1 && // to just inside monday | |
90 … | + new Date(gte.getFullYear(), gte.getMonth(), gte.getDate() + 7).toISOString() === lt.toISOString() | |
91 … | + } | |
92 … | +} | |
93 … | + | |
94 … | +function Events (state, api) { | |
95 … | + return h('CalendarEvents', computed([state.events, state.range], (events, range) => { | |
96 … | + const keys = events | |
97 … | + .filter(ev => ev.date >= range.gte && ev.date < range.lt) | |
98 … | + .sort((a, b) => a.date - b.date) | |
99 … | + .map(ev => ev.data.key) | |
100 … | + | |
101 … | + const gatherings = MutantArray([]) | |
102 … | + | |
103 … | + pull( | |
104 … | + pull.values(keys), | |
105 … | + pull.asyncMap((key, cb) => { | |
106 … | + api.sbot.async.get(key, (err, value) => { | |
107 … | + if (err) return cb(err) | |
108 … | + cb(null, {key, value}) | |
109 … | + }) | |
110 … | + }), | |
111 … | + pull.drain(msg => gatherings.push(msg)) | |
112 … | + ) | |
113 … | + | |
114 … | + return map(gatherings, g => api.message.html.render(g)) | |
115 … | + })) | |
116 … | +} | |
117 … | + | |
118 … | +function getEvents (year, events, api) { | |
119 … | + const query = [{ | |
120 … | + $filter: { | |
121 … | + value: { | |
122 … | + timestamp: {$gt: Number(new Date(year, 0, 1))}, // ordered by published time | |
123 … | + content: { | |
124 … | + type: 'about', | |
125 … | + startDateTime: { | |
126 … | + epoch: {$gt: 0} | |
80 | 127 … | } |
81 | 128 … | } |
82 | 129 … | } |
83 | - }, { | |
84 | - $map: { | |
85 | - key: ['value', 'content', 'about'], // gathering | |
86 | - date: ['value', 'content', 'startDateTime', 'epoch'] | |
87 | - } | |
88 | - }] | |
89 | - | |
90 | - const opts = { | |
91 | - reverse: false, | |
92 | - live: true, | |
93 | - query | |
94 | 130 … | } |
131 … | + }, { | |
132 … | + $map: { | |
133 … | + key: ['value', 'content', 'about'], // gathering | |
134 … | + date: ['value', 'content', 'startDateTime', 'epoch'] | |
135 … | + } | |
136 … | + }] | |
95 | 137 … | |
96 | - pull( | |
97 | - api.sbot.pull.stream(server => server.query.read(opts)), | |
98 | - pull.filter(m => !m.sync), | |
99 | - pull.filter(r => isMsg(r.key) && Number.isInteger(r.date)), | |
100 | - pull.map(r => { | |
101 | - return { key: r.key, date: new Date(r.date) } | |
102 | - }), | |
103 | - pull.drain(({ key, date }) => { | |
104 | - var target = events.find(ev => ev.data.key === key) | |
105 | - if (target && target.date <= date) events.delete(target) | |
138 … | + const opts = { | |
139 … | + reverse: false, | |
140 … | + live: true, | |
141 … | + query | |
142 … | + } | |
106 | 143 … | |
107 | - events.push({ date, data: { key } }) | |
108 | - }) | |
109 | - ) | |
110 | - } | |
144 … | + pull( | |
145 … | + api.sbot.pull.stream(server => server.query.read(opts)), | |
146 … | + pull.filter(m => !m.sync), | |
147 … | + pull.filter(r => isMsg(r.key) && Number.isInteger(r.date)), | |
148 … | + pull.map(r => { | |
149 … | + return { key: r.key, date: new Date(r.date) } | |
150 … | + }), | |
151 … | + pull.drain(({ key, date }) => { | |
152 … | + var target = events.find(ev => ev.data.key === key) | |
153 … | + if (target && target.date <= date) events.delete(target) | |
154 … | + | |
155 … | + events.push({ date, data: { key } }) | |
156 … | + }) | |
157 … | + ) | |
111 | 158 … | } |
112 | 159 … | |
113 | 160 … | // ////////////////// extract below into a module /////////////////////// |
114 | 161 … | |
@@ -121,31 +168,27 @@ | ||
121 | 168 … | function Calendar (state) { |
122 | 169 … | // TODO assert events is an Array of object |
123 | 170 … | // of form { date, data } |
124 | 171 … | |
125 | - const setRange = state.range.set | |
172 … | + const { gte, lt } = state.range | |
126 | 173 … | |
127 | 174 … | return h('Calendar', [ |
128 | - Header(state.year), | |
175 … | + h('div.header', [ | |
176 … | + h('div.year', [ | |
177 … | + state.year, | |
178 … | + h('a', { 'ev-click': () => state.year.set(state.year() - 1) }, '-'), | |
179 … | + h('a', { 'ev-click': () => state.year.set(state.year() + 1) }, '+') | |
180 … | + ]) | |
181 … | + ]), | |
129 | 182 … | h('div.months', computed(throttle(state, 100), ({ today, year, events, range }) => { |
130 | 183 … | return MONTHS.map((month, monthIndex) => { |
131 | - return Month({ month, monthIndex, today, year, events, range, setRange }) | |
184 … | + return Month({ month, monthIndex, today, year, events, range, gte, lt }) | |
132 | 185 … | }) |
133 | 186 … | })) |
134 | 187 … | ]) |
135 | 188 … | } |
136 | 189 … | |
137 | -function Header (year) { | |
138 | - return h('div.header', [ | |
139 | - h('div.year', [ | |
140 | - year, | |
141 | - h('a', { 'ev-click': () => year.set(year() - 1) }, '-'), | |
142 | - h('a', { 'ev-click': () => year.set(year() + 1) }, '+') | |
143 | - ]) | |
144 | - ]) | |
145 | -} | |
146 | - | |
147 | -function Month ({ month, monthIndex, today, year, events, range, setRange }) { | |
190 … | +function Month ({ month, monthIndex, today, year, events, range, gte, lt }) { | |
148 | 191 … | const monthLength = new Date(year, monthIndex + 1, 0).getDate() |
149 | 192 … | // NOTE Date takes month as a monthIndex i.e. april = 3 |
150 | 193 … | // and day = 0 goes back a day |
151 | 194 … | const days = Array(monthLength).fill().map((_, i) => i + 1) |
@@ -153,12 +196,12 @@ | ||
153 | 196 … | var weekday |
154 | 197 … | var week |
155 | 198 … | var offset = getDay(new Date(year, monthIndex, 1)) - 1 |
156 | 199 … | |
157 | - const setMonthRange = () => setRange({ | |
158 | - gte: new Date(year, monthIndex, 1), | |
159 | - lt: new Date(year, monthIndex + 1, 1) | |
160 | - }) | |
200 … | + const setMonthRange = (ev) => { | |
201 … | + gte.set(new Date(year, monthIndex, 1)) | |
202 … | + lt.set(new Date(year, monthIndex + 1, 1)) | |
203 … | + } | |
161 | 204 … | |
162 | 205 … | return h('CalendarMonth', [ |
163 | 206 … | h('div.month-name', { 'ev-click': setMonthRange }, month.substr(0, 2)), |
164 | 207 … | h('div.days', { style: {display: 'grid'} }, [ |
@@ -190,19 +233,22 @@ | ||
190 | 233 … | classList: [ |
191 | 234 … | date < today ? '-past' : '-future', |
192 | 235 … | eventsOnDay.length ? '-events' : '', |
193 | 236 … | date >= range.gte && date < range.lt ? '-selected' : '' |
194 | - ] | |
237 … | + ], | |
238 … | + 'ev-click': (ev) => { | |
239 … | + if (ev.shiftKey) { | |
240 … | + dateEnd >= resolve(lt) ? lt.set(dateEnd) : gte.set(date) | |
241 … | + return | |
242 … | + } | |
243 … | + | |
244 … | + gte.set(date) | |
245 … | + lt.set(dateEnd) | |
246 … | + } | |
195 | 247 … | } |
196 | 248 … | |
197 | 249 … | if (!eventsOnDay.length) return h('CalendarDay', opts) |
198 | 250 … | |
199 | - opts['ev-click'] = () => setRange({ | |
200 | - gte: date, | |
201 | - lt: dateEnd | |
202 | - }) | |
203 | - opts['ev-hover'] = () => console.log(date) | |
204 | - | |
205 | 251 … | return h('CalendarDay', opts, [ |
206 | 252 … | // TODO add awareness of whether I'm going to events |
207 | 253 … | // TODO try a FontAwesome circle |
208 | 254 … | h('div.dot', [ |
app/page/notifications.js | ||
---|---|---|
@@ -1,9 +1,9 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | 2 … | const { h } = require('mutant') |
3 | 3 … | const pull = require('pull-stream') |
4 | 4 … | const Scroller = require('pull-scroll') |
5 | -const next = require('pull-next-step') | |
5 … | +const next = require('pull-next-query') | |
6 | 6 … | |
7 | 7 … | exports.gives = nest({ |
8 | 8 … | 'app.html.menuItem': true, |
9 | 9 … | 'app.page.notifications': true |
@@ -12,12 +12,13 @@ | ||
12 | 12 … | exports.needs = nest({ |
13 | 13 … | 'app.html.filter': 'first', |
14 | 14 … | 'app.html.scroller': 'first', |
15 | 15 … | 'app.sync.goTo': 'first', |
16 | - 'feed.pull.mentions': 'first', | |
17 | 16 … | 'feed.pull.public': 'first', |
18 | 17 … | 'keys.sync.id': 'first', |
19 | - 'message.html.render': 'first' | |
18 … | + 'message.html.render': 'first', | |
19 … | + 'message.sync.isBlocked': 'first', | |
20 … | + 'sbot.pull.stream': 'first' | |
20 | 21 … | }) |
21 | 22 … | |
22 | 23 … | exports.create = function (api) { |
23 | 24 … | return nest({ |
@@ -32,30 +33,22 @@ | ||
32 | 33 … | }, '/notifications') |
33 | 34 … | } |
34 | 35 … | |
35 | 36 … | function notificationsPage (location) { |
36 | - const id = api.keys.sync.id() | |
37 | - | |
38 | 37 … | const { filterMenu, filterDownThrough, filterUpThrough, resetFeed } = api.app.html.filter(draw) |
39 | 38 … | const { container, content } = api.app.html.scroller({ prepend: [ filterMenu ] }) |
40 | - const removeMyMessages = () => pull.filter(msg => msg.value.author !== id) | |
41 | - const removePrivateMessages = () => pull.filter(msg => msg.value.private !== true) | |
42 | 39 … | |
43 | 40 … | function draw () { |
44 | 41 … | resetFeed({ container, content }) |
45 | 42 … | |
46 | 43 … | pull( |
47 | - next(api.feed.pull.mentions(id), {old: false, limit: 100, property: ['timestamp']}), | |
48 | - removeMyMessages(), | |
49 | - removePrivateMessages(), | |
44 … | + pullMentions({old: false, live: true}), | |
50 | 45 … | filterDownThrough(), |
51 | 46 … | Scroller(container, content, api.message.html.render, true, false) |
52 | 47 … | ) |
53 | 48 … | |
54 | 49 … | pull( |
55 | - next(api.feed.pull.mentions(id), {reverse: true, limit: 100, live: false, property: ['timestamp']}), | |
56 | - removeMyMessages(), | |
57 | - removePrivateMessages(), | |
50 … | + pullMentions({reverse: true, live: false}), | |
58 | 51 … | filterUpThrough(), |
59 | 52 … | Scroller(container, content, api.message.html.render, false, false) |
60 | 53 … | ) |
61 | 54 … | } |
@@ -63,5 +56,32 @@ | ||
63 | 56 … | |
64 | 57 … | container.title = '/notifications' |
65 | 58 … | return container |
66 | 59 … | } |
60 … | + | |
61 … | + // NOTE - this currently hits mentions AND the patchwork message replies | |
62 … | + function pullMentions (opts) { | |
63 … | + const query = [{ | |
64 … | + $filter: { | |
65 … | + dest: api.keys.sync.id(), | |
66 … | + timestamp: {$gt: 0}, | |
67 … | + value: { | |
68 … | + author: {$ne: api.keys.sync.id()}, // not my messages! | |
69 … | + private: {$ne: true} // not private mentions | |
70 … | + } | |
71 … | + } | |
72 … | + }] | |
73 … | + | |
74 … | + const _opts = Object.assign({ | |
75 … | + query, | |
76 … | + limit: 100, | |
77 … | + index: 'DTA' | |
78 … | + }, opts) | |
79 … | + | |
80 … | + return api.sbot.pull.stream(server => { | |
81 … | + return pull( | |
82 … | + next(server.backlinks.read, _opts, ['timestamp']), | |
83 … | + pull.filter(m => !api.message.sync.isBlocked(m)) | |
84 … | + ) | |
85 … | + }) | |
86 … | + } | |
67 | 87 … | } |
app/page/private.js | ||
---|---|---|
@@ -2,9 +2,9 @@ | ||
2 | 2 … | const { h } = require('mutant') |
3 | 3 … | const pull = require('pull-stream') |
4 | 4 … | const Scroller = require('pull-scroll') |
5 | 5 … | const ref = require('ssb-ref') |
6 | -const next = require('pull-next-step') | |
6 … | +const next = require('pull-next-query') | |
7 | 7 … | |
8 | 8 … | exports.gives = nest({ |
9 | 9 … | 'app.html.menuItem': true, |
10 | 10 … | 'app.page.private': true |
@@ -56,15 +56,15 @@ | ||
56 | 56 … | function draw () { |
57 | 57 … | resetFeed({ container, content }) |
58 | 58 … | |
59 | 59 … | pull( |
60 | - next(api.feed.pull.private, {old: false, limit: 100}, ['value', 'timestamp']), | |
60 … | + pullPrivate({old: false, live: true}), | |
61 | 61 … | filterDownThrough(), |
62 | 62 … | Scroller(container, content, api.message.html.render, true, false) |
63 | 63 … | ) |
64 | 64 … | |
65 | 65 … | pull( |
66 | - next(api.feed.pull.private, {reverse: true, limit: 100, live: false}, ['value', 'timestamp']), | |
66 … | + pullPrivate({reverse: true}), | |
67 | 67 … | filterUpThrough(), |
68 | 68 … | Scroller(container, content, api.message.html.render, false, false) |
69 | 69 … | ) |
70 | 70 … | } |
@@ -72,5 +72,23 @@ | ||
72 | 72 … | |
73 | 73 … | container.title = '/private' |
74 | 74 … | return container |
75 | 75 … | } |
76 … | + | |
77 … | + function pullPrivate (opts) { | |
78 … | + const query = [{ | |
79 … | + $filter: { | |
80 … | + timestamp: {$gt: 0}, | |
81 … | + value: { | |
82 … | + content: { | |
83 … | + recps: {$truthy: true} | |
84 … | + } | |
85 … | + } | |
86 … | + } | |
87 … | + }] | |
88 … | + | |
89 … | + const _opts = Object.assign({ query, limit: 100 }, opts) | |
90 … | + | |
91 … | + return next(api.feed.pull.private, _opts, ['timestamp']) | |
92 … | + } | |
76 | 93 … | } |
94 … | + |
app/page/search.js | ||
---|---|---|
@@ -1,8 +1,8 @@ | ||
1 | 1 … | const nest = require('depnest') |
2 | -const { h, Struct, Value, when, computed } = require('mutant') | |
2 … | +const { h, Struct, Value } = require('mutant') | |
3 | 3 … | const pull = require('pull-stream') |
4 | -const next = require('pull-next-step') | |
4 … | +const next = require('pull-next-query') | |
5 | 5 … | const Scroller = require('pull-scroll') |
6 | 6 … | const TextNodeSearcher = require('text-node-searcher') |
7 | 7 … | |
8 | 8 … | exports.gives = nest('app.page.search') |
@@ -16,130 +16,42 @@ | ||
16 | 16 … | }) |
17 | 17 … | |
18 | 18 … | var whitespace = /\s+/ |
19 | 19 … | |
20 | -function 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 | - | |
32 | -function 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 | - | |
44 | -function createOrRegExp (ary) { | |
45 | - return new RegExp(ary.map(function (e) { | |
46 | - return '\\b' + e + '\\b' | |
47 | - }).join('|'), 'i') | |
48 | -} | |
49 | - | |
50 | -function highlight (el, query) { | |
51 | - var searcher = new TextNodeSearcher({container: el}) | |
52 | - searcher.query = query | |
53 | - searcher.highlight() | |
54 | - return el | |
55 | -} | |
56 | - | |
57 | -function 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 | - | |
74 | 20 … | exports.create = function (api) { |
75 | 21 … | return nest('app.page.search', searchPage) |
76 | 22 … | |
77 | 23 … | function searchPage (location) { |
78 | 24 … | const query = location.query.trim() |
79 | 25 … | |
80 | - var queryTerms = query.split(whitespace) | |
81 | - var matchesQuery = searchFilter(queryTerms) | |
82 | - | |
83 | 26 … | const search = Struct({ |
84 | - isLinear: Value(false), | |
85 | - linear: Struct({ | |
86 | - checked: Value(0) | |
87 | - }), | |
88 | 27 … | fulltext: Struct({ |
89 | 28 … | isDone: Value(false) |
90 | 29 … | }), |
91 | 30 … | matches: Value(0) |
92 | 31 … | }) |
93 | - const hasNoFulltextMatches = computed([search.fulltext.isDone, search.matches], | |
94 | - (done, matches) => done && matches === 0) | |
95 | 32 … | |
96 | 33 … | 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 | - ) | |
34 … | + h('header', h('h1', query)) | |
108 | 35 … | ]) |
109 | - const { filterMenu, filterDownThrough, filterUpThrough, resetFeed } = api.app.html.filter(draw) | |
36 … | + const { filterMenu, filterDownThrough, resetFeed } = api.app.html.filter(draw) | |
110 | 37 … | const { container, content } = api.app.html.scroller({ prepend: [searchHeader, filterMenu] }) |
111 | 38 … | |
112 | 39 … | function renderMsg (msg) { |
113 | 40 … | var el = api.message.html.render(msg) |
41 … | + var queryTerms = query.split(whitespace) | |
42 … | + | |
114 | 43 … | highlight(el, createOrRegExp(queryTerms)) |
115 | 44 … | return el |
116 | 45 … | } |
117 | 46 … | |
118 | 47 … | function draw () { |
119 | 48 … | resetFeed({ container, content }) |
120 | 49 … | |
50 … | + // TODO figure out how to step on kinda orderless search results | |
121 | 51 … | 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 | - }), | |
52 … | + // api.sbot.pull.stream(sbot => next(sbot.search.query, { query, limit: 500 })), | |
53 … | + api.sbot.pull.stream(sbot => sbot.search.query({ query, limit: 500 })), | |
142 | 54 … | filterDownThrough(), |
143 | 55 … | pull.through(() => search.matches.set(search.matches() + 1)), |
144 | 56 … | Scroller(container, content, renderMsg, false, false) |
145 | 57 … | ) |
@@ -150,4 +62,18 @@ | ||
150 | 62 … | container.title = '?' + query |
151 | 63 … | return container |
152 | 64 … | } |
153 | 65 … | } |
66 … | + | |
67 … | +function createOrRegExp (ary) { | |
68 … | + return new RegExp(ary.map(function (e) { | |
69 … | + return '\\b' + e + '\\b' | |
70 … | + }).join('|'), 'i') | |
71 … | +} | |
72 … | + | |
73 … | +function highlight (el, query) { | |
74 … | + var searcher = new TextNodeSearcher({container: el}) | |
75 … | + searcher.query = query | |
76 … | + searcher.highlight() | |
77 … | + return el | |
78 … | +} | |
79 … | + |
index.js | ||
---|---|---|
@@ -134,9 +134,9 @@ | ||
134 | 134 … | window.webContents.on('dom-ready', function () { |
135 | 135 … | window.webContents.executeJavaScript(` |
136 | 136 … | var electron = require('electron') |
137 | 137 … | var h = require('mutant/h') |
138 | - electron.webFrame.setZoomLevelLimits(1, 1) | |
138 … | + electron.webFrame.setVisualZoomLevelLimits(1, 1) | |
139 | 139 … | var title = ${JSON.stringify(opts.title || 'Patchbay')} |
140 | 140 … | document.documentElement.querySelector('head').appendChild( |
141 | 141 … | h('title', title) |
142 | 142 … | ) |
package-lock.json | ||
---|---|---|
The diff is too large to show. Use a local git client to view these changes. Old file size: 359968 bytes New file size: 329995 bytes |
package.json | ||
---|---|---|
@@ -62,13 +62,13 @@ | ||
62 | 62 … | "patch-context": "^2.0.1", |
63 | 63 … | "patch-drafts": "0.0.6", |
64 | 64 … | "patch-history": "^1.0.0", |
65 | 65 … | "patch-hub": "^1.1.0", |
66 | - "patch-inbox": "^1.1.5", | |
66 … | + "patch-inbox": "^1.1.6", | |
67 | 67 … | "patch-settings": "^1.1.2", |
68 | 68 … | "patch-suggest": "^2.0.2", |
69 | - "patchbay-book": "^1.0.7", | |
70 | 69 … | "patchbay-dark-crystal": "0.0.3", |
70 … | + "patchbay-book": "^1.0.8", | |
71 | 71 … | "patchbay-gatherings": "^2.0.2", |
72 | 72 … | "patchbay-poll": "^1.0.5", |
73 | 73 … | "patchcore": "^1.28.0", |
74 | 74 … | "pull-abortable": "^4.1.1", |
@@ -83,30 +83,30 @@ | ||
83 | 83 … | "setimmediate": "^1.0.5", |
84 | 84 … | "ssb-about": "^0.1.2", |
85 | 85 … | "ssb-backlinks": "^0.7.3", |
86 | 86 … | "ssb-blobs": "^1.1.5", |
87 | - "ssb-chess": "^2.2.8", | |
87 … | + "ssb-chess": "^2.2.9", | |
88 | 88 … | "ssb-chess-db": "^1.0.2", |
89 | 89 … | "ssb-client": "^4.5.7", |
90 | 90 … | "ssb-ebt": "^5.2.2", |
91 | 91 … | "ssb-friends": "^2.4.0", |
92 | 92 … | "ssb-horcrux": "^1.0.0", |
93 | 93 … | "ssb-keys": "^7.0.15", |
94 | 94 … | "ssb-meme": "^1.0.4", |
95 | - "ssb-mentions": "^0.4.1", | |
95 … | + "ssb-mentions": "^0.5.0", | |
96 | 96 … | "ssb-mutual": "^0.1.0", |
97 | 97 … | "ssb-private": "^0.2.2", |
98 | 98 … | "ssb-query": "^2.1.0", |
99 | 99 … | "ssb-search": "^1.1.2", |
100 | 100 … | "ssb-sort": "^1.1.0", |
101 | - "ssb-ws": "^1.0.3", | |
102 | - "style-resolve": "^1.1.0", | |
101 … | + "ssb-ws": "^2.1.1", | |
102 … | + "style-resolve": "^1.0.1", | |
103 | 103 … | "suggest-box": "^2.2.3", |
104 | 104 … | "text-node-searcher": "^1.1.1", |
105 | 105 … | "xtend": "^4.0.1" |
106 | 106 … | }, |
107 | 107 … | "devDependencies": { |
108 | 108 … | "electro": "^2.1.1", |
109 | - "electron": "^1.8.6", | |
109 … | + "electron": "^2.0.5", | |
110 | 110 … | "standard": "^8.6.0" |
111 | 111 … | } |
112 | 112 … | } |
Built with git-ssb-web