git ssb

16+

Dominic / patchbay



Tree: a8df0b8c646db057a533878f17a685053a3d282f

Files: a8df0b8c646db057a533878f17a685053a3d282f / app / html / filter.js

6610 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: 'chess' })
95 ]),
96 h('div.root-messages', [
97 toggle({ type: 'rootMessages', filterGroup: 'only', label: 'Root messages only' })
98 ])
99 ])
100 ])
101 ])
102
103 function toggle ({ type, filterGroup, label }) {
104 label = label || type
105 filterGroup = filterGroup || 'show'
106
107 const state = computed(filterSettings, settings => get(settings, [filterGroup, type]))
108 const handleClick = () => {
109 const currentState = state()
110
111 // TODO use some lodash tool ?
112 api.settings.sync.set({
113 filter: {
114 [filterGroup]: {
115 [type]: !currentState
116 }
117 }
118 })
119
120 draw()
121 }
122
123 return h('FilterToggle', { 'ev-click': handleClick }, [
124 h('label', label),
125 h('i', { classList: when(state, 'fa fa-check-square-o', 'fa fa-square-o') })
126 ])
127 }
128
129 const getChannelSuggestions = api.channel.async.suggest()
130 addSuggest(channelInput, (inputText, cb) => {
131 if (inputText[0] === '#') {
132 cb(null, getChannelSuggestions(inputText.slice(1)))
133 }
134 }, {cls: 'PatchSuggest'})
135 channelInput.addEventListener('suggestselect', ev => {
136 const channels = channelInput.value.trim()
137
138 api.settings.sync.set({ filter: { exclude: { channels: channels } } })
139
140 draw()
141 })
142
143 var userId
144 const getAboutSuggestions = api.about.async.suggest()
145 addSuggest(userInput, (inputText, cb) => {
146 inputText = inputText.replace(/^@/, '')
147 cb(null, getAboutSuggestions(inputText.slice(1)))
148 }, {cls: 'PatchSuggest'})
149 userInput.addEventListener('suggestselect', ev => {
150 userId = ev.detail.id
151 userInput.value = userId
152
153 draw()
154 })
155
156 function followFilter (msg) {
157 if (!filterSettings().only.peopleAndChannelsIFollow) return true
158
159 return Array.from(peopleIFollow()).concat(myId).includes(msg.value.author) ||
160 (msg.value.content && Array.from(channelsIFollow()).includes(msg.value.content.channel))
161 }
162
163 function userFilter (msg) {
164 if (!userId) return true
165
166 return msg.value.author === userId
167 }
168
169 function rootFilter (msg) {
170 if (!filterSettings().only.rootMessages) return true
171
172 return !msg.value.content.root
173 }
174
175 function channelFilter (msg) {
176 var filters = filterSettings().exclude.channels
177 if (!filters) return true
178 filters = filters.split(' ').map(c => c.slice(1))
179
180 return msg.value.content && !filters.includes(msg.value.content.channel)
181 }
182
183 function messageFilter (msg) {
184 var { type } = msg.value.content
185 if (/^chess/.test(type)) {
186 type = 'chess'
187 }
188
189 return get(filterSettings(), ['show', type], true)
190 }
191
192 var downScrollAborter
193
194 function filterDownThrough () {
195 return pull(
196 downScrollAborter,
197 pull.filter(followFilter),
198 pull.filter(userFilter),
199 pull.filter(rootFilter),
200 pull.filter(channelFilter),
201 pull.filter(messageFilter)
202 )
203 }
204
205 var upScrollAborter
206
207 function filterUpThrough () {
208 return pull(
209 upScrollAborter,
210 pull.filter(followFilter),
211 pull.filter(userFilter),
212 pull.filter(rootFilter),
213 pull.filter(channelFilter),
214 pull.filter(messageFilter)
215 )
216 }
217
218 function resetFeed ({ container, content }) {
219 if (typeof upScrollAborter === 'function') {
220 upScrollAborter.abort()
221 downScrollAborter.abort()
222 }
223 upScrollAborter = Abort()
224 downScrollAborter = Abort()
225
226 container.scroll(0)
227 content.innerHTML = ''
228 }
229
230 return {
231 filterMenu,
232 filterDownThrough,
233 filterUpThrough,
234 resetFeed
235 }
236 }
237}
238

Built with git-ssb-web