git ssb

16+

Dominic / patchbay



Tree: 81408e3008723f4b30952d1e379525f80a8ddf6d

Files: 81408e3008723f4b30952d1e379525f80a8ddf6d / app / html / filter.js

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

Built with git-ssb-web