git ssb

10+

Matt McKegg / patchwork



Tree: f815ce842a77e397cb805d2045e8e7033e54da31

Files: f815ce842a77e397cb805d2045e8e7033e54da31 / modules / message / html / compose.js

4395 bytesRaw
1var h = require('mutant/h')
2var when = require('mutant/when')
3var send = require('mutant/send')
4var resolve = require('mutant/resolve')
5var Value = require('mutant/value')
6var computed = require('mutant/computed')
7var nest = require('depnest')
8var mentions = require('ssb-mentions')
9var extend = require('xtend')
10var addSuggest = require('suggest-box')
11
12exports.needs = nest({
13 'blob.html.input': 'first',
14 'profile.async.suggest': 'first',
15 'channel.async.suggest': 'first',
16 'message.async.publish': 'first',
17 'emoji.sync.names': 'first',
18 'emoji.sync.url': 'first'
19})
20
21exports.gives = nest('message.html.compose')
22
23exports.create = function (api) {
24 return nest('message.html.compose', function ({shrink = true, meta, prepublish, placeholder = 'Write a message'}, cb) {
25 var files = []
26 var filesById = {}
27 var focused = Value(false)
28 var hasContent = Value(false)
29 var publishing = Value(false)
30 var getProfileSuggestions = api.profile.async.suggest()
31 var getChannelSuggestions = api.channel.async.suggest()
32
33 var blurTimeout = null
34
35 var expanded = computed([shrink, focused, hasContent], (shrink, focused, hasContent) => {
36 if (!shrink || hasContent) {
37 return true
38 } else {
39 return focused
40 }
41 })
42
43 var textArea = h('textarea', {
44 'ev-input': function () {
45 hasContent.set(!!textArea.value)
46 },
47 'ev-blur': () => {
48 clearTimeout(blurTimeout)
49 blurTimeout = setTimeout(() => focused.set(false), 200)
50 },
51 'ev-focus': send(focused.set, true),
52 disabled: publishing,
53 placeholder
54 })
55
56 var fileInput = api.blob.html.input(file => {
57 files.push(file)
58 filesById[file.link] = file
59
60 var embed = file.type.indexOf('image/') === 0 ? '!' : ''
61 var spacer = embed ? '\n' : ' '
62 var insertLink = `${spacer}${embed}[${file.name}](${file.link})${spacer}`
63
64 var pos = textArea.selectionStart
65 textArea.value = `${textArea.value.slice(0, pos)}${insertLink}${textArea.value.slice(pos)}`
66 console.log('added:', file)
67 })
68
69 fileInput.onclick = function () {
70 hasContent.set(true)
71 }
72
73 var publishBtn = h('button', {
74 'ev-click': publish,
75 disabled: publishing
76 }, when(publishing, 'Publishing...', 'Publish'))
77
78 var actions = h('section.actions', [
79 fileInput,
80 publishBtn
81 ])
82
83 var composer = h('Compose', {
84 classList: [
85 when(expanded, '-expanded', '-contracted')
86 ]
87 }, [
88 textArea,
89 actions
90 ])
91
92 addSuggest(textArea, (inputText, cb) => {
93 if (inputText[0] === '@') {
94 cb(null, getProfileSuggestions(inputText.slice(1)))
95 } else if (inputText[0] === '#') {
96 cb(null, getChannelSuggestions(inputText.slice(1)))
97 } else if (inputText[0] === ':') {
98 // suggest emojis
99 var word = inputText.slice(1)
100 if (word[word.length - 1] === ':') {
101 word = word.slice(0, -1)
102 }
103 // TODO: when no emoji typed, list some default ones
104 cb(null, api.emoji.sync.names().filter(function (name) {
105 return name.slice(0, word.length) === word
106 }).slice(0, 100).map(function (emoji) {
107 return {
108 image: api.emoji.sync.url(emoji),
109 title: emoji,
110 subtitle: emoji,
111 value: ':' + emoji + ':'
112 }
113 }))
114 }
115 }, {cls: 'SuggestBox'})
116
117 return composer
118
119 // scoped
120
121 function publish () {
122 publishing.set(true)
123
124 var content = extend(resolve(meta), {
125 text: textArea.value,
126 mentions: mentions(textArea.value).map(mention => {
127 // merge markdown-detected mention with file info
128 var file = filesById[mention.link]
129 if (file) {
130 if (file.type) mention.type = file.type
131 if (file.size) mention.size = file.size
132 }
133 return mention
134 })
135 })
136
137 try {
138 if (typeof prepublish === 'function') {
139 content = prepublish(content)
140 }
141 } catch (err) {
142 publishing.set(false)
143 if (cb) cb(err)
144 else throw err
145 }
146
147 return api.message.async.publish(content, done)
148
149 function done (err, msg) {
150 publishing.set(false)
151 if (err) throw err
152 else if (msg) textArea.value = ''
153 if (cb) cb(err, msg)
154 }
155 }
156 })
157}
158

Built with git-ssb-web