git ssb

2+

mixmix / ticktack



Tree: 9014dda813036162e40d60dc06a27061f9327d29

Files: 9014dda813036162e40d60dc06a27061f9327d29 / app / page / threadNew.js

4139 bytesRaw
1const nest = require('depnest')
2const { h, Struct, Value, Array: MutantArray, computed, map, resolve } = require('mutant')
3const suggestBox = require('suggest-box')
4
5exports.gives = nest('app.page.threadNew')
6
7exports.needs = nest({
8 'about.async.suggest': 'first',
9 'about.html.avatar': 'first',
10 'about.obs.name': 'first',
11 'app.html.sideNav': 'first',
12 'app.html.thread': 'first',
13 'history.sync.push': 'first',
14 'keys.sync.id': 'first',
15 'message.html.compose': 'first',
16 'message.sync.unbox': 'first',
17 'translations.sync.strings': 'first',
18})
19
20exports.create = (api) => {
21
22 return nest('app.page.threadNew', threadNew)
23
24 function threadNew (location) {
25 const { feed, channel } = location
26
27 if (feed) return threadNewFeed(location)
28 }
29
30 function threadNewFeed (location) {
31 const strings = api.translations.sync.strings()
32 const myId = api.keys.sync.id()
33
34 const { feed } = location
35
36 const meta = Struct({
37 type: 'post',
38 recps: MutantArray ([
39 myId,
40 { link: feed, name: resolve(api.about.obs.name(feed)) }
41 ]),
42 subject: Value()
43 })
44
45 return h('Page -threadNew', {title: strings.threadNew.pageTitle}, [
46 api.app.html.sideNav(location),
47 h('div.content', [
48 h('div.container', [
49 h('div.field -to', [
50 h('div.label', strings.threadNew.field.to),
51 h('div.recps', [
52 map(meta.recps, Recipient),
53 RecipientInput(meta.recps)
54 ])
55 ]),
56 h('div.field -subject', [
57 h('div.label', strings.threadNew.field.subject),
58 h('input', {
59 'ev-input': e => meta.subject.set(e.target.value),
60 placeholder: strings.optionalField
61 }),
62 ]),
63 Composer(meta)
64 ])
65 ])
66 ])
67
68 function Recipient (r) {
69 if (r === myId) return
70
71 return h('div.recp', [
72 api.about.html.avatar(r.link, 'tiny'),
73 h('div.name', r.name)
74 ])
75 }
76
77 function RecipientInput (recps) {
78 const getRecpSuggestions = api.about.async.suggest()
79 const input = h('input', {
80 placeholder: strings.threadNew.action.addMoreRecps
81 // 'ev-input': e => searchInput.set(e.target.value),
82 })
83
84 var boxActive = false
85 addSuggest()
86
87 input.addEventListener('suggestselect', (e) => {
88 const { id, title: name } = e.detail
89 if (!recps.find(r => r === id || r.link === id))
90 recps.push({ link: id, name })
91
92 boxActive = false
93 e.target.value = ''
94 e.target.placeholder = ''
95 })
96
97 input.addEventListener('keyup', (e) => {
98 // don't pop the previous entry if still entering a name!
99 if (boxActive) {
100 // if you delete a name you were typing completely, mark box inactive
101 // so that further deletes pop names
102 if (e.target.value === '') boxActive = false
103 return
104 }
105
106 if (e.code === 'Backspace' || e.key === 'Backspace' || e.keyCode == 8) {
107 if (recps.getLength() < 3) return // can only delete down to 2 recps (sender + 1 recp)
108
109 recps.pop()
110 }
111 })
112
113 return input
114
115 function addSuggest () {
116 if (!input.parentElement) return setTimeout(addSuggest, 100)
117
118 suggestBox(input, (inputText, cb) => {
119 if (recps.getLength() >= 7) return
120 // TODO - tell the user they're only allowed 6 (or 7?!) people in a message
121
122 boxActive = true
123 const suggestions = getRecpSuggestions(inputText)
124 cb(null, suggestions)
125 }, {cls: 'PatchSuggest'})
126 }
127 }
128
129 function Composer (meta) {
130 return api.message.html.compose(
131 { meta, shrink: false },
132 (err, msg) => {
133 if (err) return api.history.sync.push(err)
134
135 const someRecipient = meta.recps.get(1)
136 if (!someRecipient) return
137
138 api.history.sync.push(Object.assign(
139 api.message.sync.unbox(msg), // for consistency of message sideNav receives D:
140 { feed: someRecipient.link }
141 ))
142 }
143 )
144 }
145 }
146
147}
148
149

Built with git-ssb-web