git ssb

16+

Dominic / patchbay



Tree: 6151ce3e3718887750c939a25d0dec1f7d140794

Files: 6151ce3e3718887750c939a25d0dec1f7d140794 / app / html / filter.js

6735 bytesRaw
1const nest = require('depnest')
2const { h, Value, when, computed } = require('mutant')
3const Abort = require('pull-abortable')
4const pull = require('pull-stream')
5const addSuggest = require('suggest-box')
6const { isFeed } = require('ssb-ref')
7const get = require('lodash/get')
8const isEqual = require('lodash/isEqual')
9
10exports.gives = nest('app.html.filter')
11
12exports.needs = nest({
13 'about.async.suggest': 'first',
14 'channel.async.suggest': 'first',
15 'contact.obs.following': 'first',
16 'channel.obs.subscribed': 'first',
17 'keys.sync.id': 'first',
18 'settings.obs.get': 'first',
19 'settings.sync.set': 'first'
20})
21
22exports.create = function (api) {
23 return nest({
24 'app.html.filter': Filter
25 })
26
27 function Filter (draw) {
28 const showFilters = Value(false)
29
30 const myId = api.keys.sync.id()
31 const peopleIFollow = api.contact.obs.following(myId)
32 const channelsIFollow = api.channel.obs.subscribed(myId)
33
34 const filterSettings = api.settings.obs.get('filter', {exclude: {}})
35
36 const channelInput = h('input', {
37 value: filterSettings().exclude.channels,
38 'ev-keyup': (ev) => {
39 var text = ev.target.value
40 if (text.length === 0 || ev.which === 13) {
41 api.settings.sync.set({
42 filter: {
43 exclude: {
44 channels: text
45 }
46 }
47 })
48 draw()
49 }
50 }
51 })
52
53 const userInput = h('input')
54
55 const isFiltered = computed(filterSettings, (filterSettings) => {
56 const _settings = Object.assign({}, filterSettings)
57 delete _settings.defaults
58
59 return !isEqual(_settings, filterSettings.defaults)
60 })
61
62 const filterMenu = h('Filter', [
63 when(isFiltered, h('i.custom')),
64 h('i.fa.fa-filter', {
65 classList: when(showFilters, '-active'),
66 'ev-click': () => showFilters.set(!showFilters())
67 }),
68 h('i.fa.fa-angle-up', { 'ev-click': draw }),
69 h('div.options', { className: when(showFilters, '', '-hidden') }, [
70 h('header', [
71 'Filter',
72 h('i.fa.fa-filter')
73 ]),
74 h('section', [
75 h('div.users', [
76 toggle({ type: 'peopleAndChannelsIFollow', filterGroup: 'only', label: 'Only people & channels I follow' }),
77 h('div.user-filter', [
78 h('label', 'Only this user (temporary filter):'),
79 userInput
80 ])
81 ]),
82 h('div.channels', [
83 h('label', 'Exclude channels'),
84 channelInput
85 ]),
86 h('div.message-types', [
87 h('header', 'Show messages'),
88 toggle({ type: 'post' }),
89 toggle({ type: 'like' }),
90 toggle({ type: 'about' }),
91 toggle({ type: 'contact' }),
92 toggle({ type: 'channel' }),
93 toggle({ type: 'pub' }),
94 toggle({ type: 'private' }),
95 toggle({ type: 'chess' })
96 ]),
97 h('div.root-messages', [
98 toggle({ type: 'rootMessages', filterGroup: 'only', label: 'Root messages only' })
99 ])
100 ])
101 ])
102 ])
103
104 function toggle ({ type, filterGroup, label }) {
105 label = label || type
106 filterGroup = filterGroup || 'show'
107
108 const state = computed(filterSettings, settings => get(settings, [filterGroup, type]))
109 const handleClick = () => {
110 const currentState = state()
111
112 // TODO use some lodash tool ?
113 api.settings.sync.set({
114 filter: {
115 [filterGroup]: {
116 [type]: !currentState
117 }
118 }
119 })
120
121 draw()
122 }
123
124 return h('FilterToggle', { 'ev-click': handleClick }, [
125 h('label', label),
126 h('i', { classList: when(state, 'fa fa-check-square-o', 'fa fa-square-o') })
127 ])
128 }
129
130 const getChannelSuggestions = api.channel.async.suggest()
131 addSuggest(channelInput, (inputText, cb) => {
132 if (inputText[0] === '#') {
133 cb(null, getChannelSuggestions(inputText.slice(1)))
134 }
135 }, {cls: 'PatchSuggest'})
136 channelInput.addEventListener('suggestselect', ev => {
137 const channels = channelInput.value.trim()
138
139 api.settings.sync.set({ filter: { exclude: { channels: channels } } })
140
141 draw()
142 })
143
144 var userId
145 const getAboutSuggestions = api.about.async.suggest()
146 addSuggest(userInput, (inputText, cb) => {
147 inputText = inputText.replace(/^@/, '')
148 cb(null, getAboutSuggestions(inputText.slice(1)))
149 }, {cls: 'PatchSuggest'})
150 userInput.addEventListener('suggestselect', ev => {
151 userId = ev.detail.id
152 userInput.value = userId
153
154 draw()
155 })
156
157 function followFilter (msg) {
158 if (!filterSettings().only.peopleAndChannelsIFollow) return true
159
160 return Array.from(peopleIFollow()).concat(myId).includes(msg.value.author) ||
161 (msg.value.content && Array.from(channelsIFollow()).includes(msg.value.content.channel))
162 }
163
164 function userFilter (msg) {
165 if (!userId) return true
166
167 return msg.value.author === userId
168 }
169
170 function rootFilter (msg) {
171 if (!filterSettings().only.rootMessages) return true
172
173 return !msg.value.content.root
174 }
175
176 function channelFilter (msg) {
177 var filters = filterSettings().exclude.channels
178 if (!filters) return true
179 filters = filters.split(' ').map(c => c.slice(1))
180
181 return msg.value.content && !filters.includes(msg.value.content.channel)
182 }
183
184 function messageFilter (msg) {
185 var { type } = msg.value.content
186 if (/^chess/.test(type)) {
187 type = 'chess'
188 }
189
190 if (typeof msg.value.content == 'string') {
191 type = 'private'
192 }
193
194 return get(filterSettings(), ['show', type], true)
195 }
196
197 var downScrollAborter
198
199 function filterDownThrough () {
200 return pull(
201 downScrollAborter,
202 pull.filter(followFilter),
203 pull.filter(userFilter),
204 pull.filter(rootFilter),
205 pull.filter(channelFilter),
206 pull.filter(messageFilter)
207 )
208 }
209
210 var upScrollAborter
211
212 function filterUpThrough () {
213 return pull(
214 upScrollAborter,
215 pull.filter(followFilter),
216 pull.filter(userFilter),
217 pull.filter(rootFilter),
218 pull.filter(channelFilter),
219 pull.filter(messageFilter)
220 )
221 }
222
223 function resetFeed ({ container, content }) {
224 if (typeof upScrollAborter === 'function') {
225 upScrollAborter.abort()
226 downScrollAborter.abort()
227 }
228 upScrollAborter = Abort()
229 downScrollAborter = Abort()
230
231 container.scroll(0)
232 content.innerHTML = ''
233 }
234
235 return {
236 filterMenu,
237 filterDownThrough,
238 filterUpThrough,
239 resetFeed
240 }
241 }
242}
243

Built with git-ssb-web