git ssb

2+

mixmix / ticktack



Tree: 9ad3a2e414cf22e0069c0a3d4d06a02090503ad2

Files: 9ad3a2e414cf22e0069c0a3d4d06a02090503ad2 / message / html / compose.js

5184 bytesRaw
1const nest = require('depnest')
2const { h, when, send, resolve, Value, computed } = require('mutant')
3const assign = require('lodash/assign')
4const ssbMentions = require('ssb-mentions')
5const addSuggest = require('suggest-box')
6
7exports.gives = nest('message.html.compose')
8
9exports.needs = nest({
10 'about.async.suggest': 'first',
11 'blob.html.input': 'first',
12 'channel.async.suggest': 'first',
13 'emoji.async.suggest': 'first',
14 'emoji.sync.names': 'first',
15 'emoji.sync.url': 'first',
16 'message.async.publish': 'first',
17 'message.html.markdown': 'first',
18 // 'message.html.confirm': 'first'
19 'translations.sync.strings': 'first'
20})
21
22exports.create = function (api) {
23 return nest('message.html.compose', compose)
24
25 function compose ({ shrink = true, meta, prepublish, placeholder }, cb) {
26 const strings = api.translations.sync.strings()
27 const getProfileSuggestions = api.about.async.suggest()
28 const getChannelSuggestions = api.channel.async.suggest()
29 const getEmojiSuggestions = api.emoji.async.suggest()
30
31 placeholder = placeholder || strings.writeMessage
32
33 var files = []
34 var filesById = {}
35 var textAreaFocused = Value(false)
36 var focused = textAreaFocused
37 var hasContent = Value(false)
38
39 var blurTimeout = null
40
41 var expanded = computed([shrink, focused, hasContent], (shrink, focused, hasContent) => {
42 if (!shrink || hasContent) return true
43
44 return focused
45 })
46
47 var textRaw = Value('')
48 var textArea = h('textarea', {
49 'ev-input': () => textRaw.set(textArea.value),
50 'ev-blur': () => {
51 clearTimeout(blurTimeout)
52 blurTimeout = setTimeout(() => textAreaFocused.set(false), 200)
53 },
54 'ev-focus': send(textAreaFocused.set, true),
55 placeholder
56 })
57 textRaw(text => hasContent.set(!!text))
58
59 textArea.publish = publish // TODO: fix - clunky api for the keyboard shortcut to target
60
61 var fileInput
62 if(!meta.recps) {
63 fileInput = api.blob.html.input(file => {
64 files.push(file)
65 filesById[file.link] = file
66
67 var embed = file.type.match(/^image/) ? '!' : ''
68 var spacer = embed ? '\n' : ' '
69 var insertLink = spacer + embed + '[' + file.name + ']' + '(' + file.link + ')' + spacer
70
71 var pos = textArea.selectionStart
72 var newText = textRaw().slice(0, pos) + insertLink + textRaw().slice(pos)
73 textArea.value = newText
74 textRaw.set(newText)
75
76 console.log('added:', file)
77 })
78
79 fileInput.onclick = () => hasContent.set(true)
80 }
81 // if fileInput is null, send button moves to the left side
82 // and we don't want that.
83 else
84 fileInput = h('input', { style: {visibility: 'hidden'}})
85
86 var showPreview = Value(false)
87 var previewBtn = h('Button',
88 {
89 className: when(showPreview, '-primary'),
90 'ev-click': () => showPreview.set(!showPreview())
91 },
92 when(showPreview, strings.blogNew.actions.edit, strings.blogNew.actions.preview)
93 )
94 var preview = computed(textRaw, text => api.message.html.markdown(text))
95
96 var publishBtn = h('Button -primary', { 'ev-click': publish }, strings.sendMessage)
97
98 var actions = h('section.actions', [
99 fileInput,
100 previewBtn,
101 publishBtn
102 ])
103
104 var composer = h('Compose', {
105 classList: when(expanded, '-expanded', '-contracted')
106 }, [
107 when(showPreview, preview, textArea),
108 actions
109 ])
110
111 addSuggest(textArea, (inputText, cb) => {
112 const char = inputText[0]
113 const wordFragment = inputText.slice(1)
114
115 if (char === '@') cb(null, getProfileSuggestions(wordFragment))
116 if (char === '#') cb(null, getChannelSuggestions(wordFragment))
117 if (char === ':') cb(null, getEmojiSuggestions(wordFragment))
118 }, {cls: 'PatchSuggest'})
119
120 return composer
121
122 // scoped
123
124 function publish () {
125 publishBtn.disabled = true
126 const text = resolve(textRaw)
127
128 const mentions = ssbMentions(text).map(mention => {
129 // merge markdown-detected mention with file info
130 var file = filesById[mention.link]
131 if (file) {
132 if (file.type) mention.type = file.type
133 if (file.size) mention.size = file.size
134 }
135 return mention
136 })
137
138 var content = assign({}, resolve(meta), {
139 text,
140 mentions
141 })
142
143 if (!content.channel) delete content.channel
144 if (!mentions.length) delete content.mentions
145 if (content.recps && content.recps.length === 0) delete content.recps
146
147 try {
148 if (typeof prepublish === 'function') {
149 content = prepublish(content)
150 }
151 } catch (err) {
152 publishBtn.disabled = false
153 handleErr(err)
154 }
155
156 // debugger
157 return api.message.async.publish(content, done)
158 // return api.message.html.confirm(content, done)
159
160 function done (err, msg) {
161 publishBtn.disabled = false
162 if (err) handleErr(err)
163 else if (msg) {
164 textRaw.set('')
165 textArea.value = ''
166 }
167 if (cb) cb(err, msg)
168 }
169
170 function handleErr (err) {
171 if (cb) cb(err)
172 else throw err
173 }
174 }
175 }
176}
177
178

Built with git-ssb-web