git ssb

16+

Dominic / patchbay



Tree: d34b731ad8a333e287d614895dc8ee066f7a59da

Files: d34b731ad8a333e287d614895dc8ee066f7a59da / modules_basic / compose.js

4919 bytesRaw
1'use strict'
2const fs = require('fs')
3const h = require('../h')
4const { Value, when } = require('mutant')
5const mentions = require('ssb-mentions')
6
7exports.needs = {
8 suggest_mentions: 'map', //<-- THIS MUST BE REWRITTEN
9 suggest_channel: 'map',
10 build_suggest_box: 'first',
11 publish: 'first',
12 message_content: 'first',
13 message_confirm: 'first',
14 file_input: 'first'
15}
16
17exports.gives = {
18 'message_compose': true,
19 'mcss': true
20}
21
22exports.create = function (api) {
23 return {
24 message_compose,
25 mcss: () => fs.readFileSync(__filename.replace(/js$/, 'mcss'), 'utf8')
26 }
27
28 /*
29 opts can take
30
31 placeholder: string. placeholder text, defaults to "Write a message"
32 prepublish: function. called before publishing a message.
33 shrink: boolean. set to false, to make composer not shrink (or hide controls) when unfocused.
34 */
35
36 function message_compose (meta = {}, opts = {}, cb) {
37 if(!meta.type) throw new Error('message must have type')
38
39 if('function' === typeof cb) {
40 if('function' === typeof opts) {
41 opts = {prepublish: opts}
42 }
43 }
44 opts.prepublish = opts.prepublish || id
45
46 const isExpanded = Value(opts.shrink === false)
47
48 var textArea = h('textarea', {
49 placeholder: opts.placeholder || 'Write a message'
50 })
51
52 var channelInput = h('input.channel', {
53 placeholder: '#channel (optional)',
54 value: meta.channel ? `#${meta.channel}` : '',
55 disabled: meta.channel ? true : false,
56 title: meta.channel ? 'Reply is in same channel as original message' : '',
57 })
58
59 channelInput.addEventListener('keyup', (e) => {
60 e.target.value = e.target.value
61 .replace(/^#*([\w@%&])/, '#$1')
62 })
63
64 if(opts.shrink !== false) {
65 isExpanded.set(false)
66 var blur
67
68 textArea.addEventListener('focus', () => {
69 clearTimeout(blur)
70 if(!textArea.value) {
71 isExpanded.set(true)
72 }
73 })
74 textArea.addEventListener('blur', () => {
75 //don't shrink right away, so there is time
76 //to click the publish button.
77 clearTimeout(blur)
78 blur = setTimeout(() => {
79 if(textArea.value) return
80 isExpanded.set(false)
81 }, 300)
82 })
83 channelInput.addEventListener('focus', () => {
84 clearTimeout(blur)
85 if (!textArea.value) {
86 isExpanded.set(true)
87 }
88 })
89 channelInput.addEventListener('blur', () => {
90 clearTimeout(blur)
91 blur = setTimeout(() => {
92 if (textArea.value || channelInput.value) return
93 isExpanded.set(false)
94 }, 300)
95 })
96 }
97
98 textArea.addEventListener('keydown', ev => {
99 if(ev.keyCode === 13 && ev.ctrlKey) publish()
100 })
101
102 var files = []
103 var filesById = {}
104
105 function publish() {
106 publishBtn.disabled = true
107 var content
108 try {
109 content = JSON.parse(textArea.value)
110 } catch (err) {
111 meta.text = textArea.value
112 meta.channel = (channelInput.value.startsWith('#') ?
113 channelInput.value.substr(1).trim() : channelInput.value.trim()) || null
114 meta.mentions = mentions(textArea.value).map(mention => {
115 // merge markdown-detected mention with file info
116 var file = filesById[mention.link]
117 if (file) {
118 if (file.type) mention.type = file.type
119 if (file.size) mention.size = file.size
120 }
121 return mention
122 })
123 try {
124 meta = opts.prepublish(meta)
125 } catch (err) {
126 publishBtn.disabled = false
127 if (cb) cb(err)
128 else alert(err.message)
129 }
130 return api.message_confirm(meta, done)
131 }
132
133 api.message_confirm(content, done)
134
135 function done (err, msg) {
136 publishBtn.disabled = false
137 if(err) return alert(err.stack)
138 else if (msg) textArea.value = ''
139
140 if (cb) cb(err, msg)
141 }
142 }
143
144 var fileInput = api.file_input(file => {
145 files.push(file)
146 filesById[file.link] = file
147
148 var embed = file.type.indexOf('image/') === 0 ? '!' : ''
149 var spacer = embed ? '\n' : ' '
150 var insertLink = spacer + embed + '[' + file.name + ']' + '(' + file.link + ')' + spacer
151
152 var pos = textArea.selectionStart
153 textArea.value = textArea.value.slice(0, pos) + insertLink + textArea.value.slice(pos)
154
155 isExpanded.set(true)
156 console.log('added:', file)
157 })
158 var publishBtn = h('button', {'ev-click': publish}, 'Publish' )
159 var actions = h('section.actions', [ fileInput, publishBtn ])
160
161 api.build_suggest_box(textArea, api.suggest_mentions)
162 api.build_suggest_box(channelInput, api.suggest_channel)
163
164 var composer = h('Compose', {
165 classList: [ when(isExpanded, '-expanded', '-contracted') ]
166 }, [
167 channelInput,
168 textArea,
169 actions
170 ])
171
172 return composer
173 }
174
175}
176
177function id (e) { return e }
178

Built with git-ssb-web