Files: 23773bc1942c218dddfed2ed303a71256b50710e / about / async / suggest.js
3772 bytesRaw
1 | var nest = require('depnest') |
2 | var { h, Struct, map, concat, dictToCollection, computed, lookup, watch, keys, resolve } = require('mutant') |
3 | |
4 | var KEY_SAMPLE_LENGTH = 10 // includes @ |
5 | |
6 | exports.gives = nest('about.async.suggest') |
7 | |
8 | exports.needs = nest({ |
9 | 'about.obs.groupedValues': 'first', |
10 | 'about.obs.name': 'first', |
11 | 'about.obs.imageUrl': 'first', |
12 | 'contact.obs.following': 'first', |
13 | 'feed.obs.recent': 'first', |
14 | 'keys.sync.id': 'first' |
15 | }) |
16 | |
17 | exports.create = function (api) { |
18 | var suggestions = null |
19 | var recentSuggestions = null |
20 | |
21 | return nest('about.async.suggest', suggest) |
22 | |
23 | function suggest () { |
24 | loadSuggestions() |
25 | return function (word) { |
26 | if (!word) return recentSuggestions() |
27 | |
28 | wordLower = word.toLowerCase() |
29 | return suggestions() |
30 | .filter(item => ~item.title.toLowerCase().indexOf(wordLower)) |
31 | .sort((a, b) => { |
32 | // where name is matching exactly so far |
33 | if (a.title.indexOf(word) === 0) return -1 |
34 | if (b.title.indexOf(word) === 0) return +1 |
35 | |
36 | // where name is matching exactly so far (case insensitive) |
37 | if (a.title.toLowerCase().indexOf(wordLower) === 0) return -1 |
38 | if (b.title.toLowerCase().indexOf(wordLower) === 0) return +1 |
39 | }) |
40 | .reduce((sofar, match) => { |
41 | // prune down to the first instance of each id |
42 | // this presumes if you were typing e.g. "dino" you don't need "ahdinosaur" as well |
43 | if (sofar.find(el => el.id === match.id)) return sofar |
44 | |
45 | return [...sofar, match] |
46 | }, []) |
47 | .sort((a, b) => { |
48 | // bubble up names where typed word matches our name for them |
49 | if (a._isPrefered) return -1 |
50 | if (b._isPrefered) return +1 |
51 | }) |
52 | } |
53 | } |
54 | |
55 | function loadSuggestions () { |
56 | if (suggestions) return |
57 | |
58 | var id = api.keys.sync.id() |
59 | var following = api.contact.obs.following(id) |
60 | var recentlyUpdated = api.feed.obs.recent() |
61 | var contacts = computed([following, recentlyUpdated], (a, b) => { |
62 | var result = new Set(a) |
63 | b.forEach(item => result.add(item)) |
64 | |
65 | return Array.from(result) |
66 | }) |
67 | |
68 | recentSuggestions = map( |
69 | computed(recentlyUpdated, (items) => Array.from(items).slice(0, 10)), |
70 | suggestion, |
71 | {idle: true} |
72 | ) |
73 | |
74 | const suggestionsRecord = lookup(contacts, contact => { |
75 | return [contact, keys(api.about.obs.groupedValues(contact, 'name'))] |
76 | }) |
77 | |
78 | suggestions = concat( |
79 | map(dictToCollection(suggestionsRecord), pluralSuggestions, {idle: true}) |
80 | ) |
81 | |
82 | watch(recentSuggestions) |
83 | watch(suggestions) |
84 | } |
85 | |
86 | function pluralSuggestions (item) { |
87 | const id = resolve(item.key) |
88 | |
89 | return computed([api.about.obs.name(id)], myNameForThem => { |
90 | return map(item.value, name => { |
91 | const names = item.value() |
92 | |
93 | const aliases = names |
94 | .filter(n => n != name) |
95 | .map(name => h('div.alias', |
96 | { className: name === myNameForThem ? '-bold' : '' }, |
97 | name |
98 | )) |
99 | |
100 | return Struct({ |
101 | id, |
102 | title: name, |
103 | subtitle: [ |
104 | h('div.aliases', aliases), |
105 | h('div.key', id.substring(0, KEY_SAMPLE_LENGTH)) |
106 | ], |
107 | value: mention(name, id), |
108 | image: api.about.obs.imageUrl(id), |
109 | showBoth: true, |
110 | _isPrefered: name === myNameForThem |
111 | }) |
112 | }) |
113 | }) |
114 | |
115 | } |
116 | |
117 | // feeds recentSuggestions |
118 | function suggestion (id) { |
119 | var name = api.about.obs.name(id) |
120 | return Struct({ |
121 | id, |
122 | title: name, |
123 | subtitle: h('div.key', id.substring(0, KEY_SAMPLE_LENGTH)), |
124 | value: computed([name, id], mention), |
125 | image: api.about.obs.imageUrl(id), |
126 | showBoth: true |
127 | }) |
128 | } |
129 | } |
130 | |
131 | function mention (name, id) { |
132 | return `[@${name}](${id})` |
133 | } |
134 |
Built with git-ssb-web