app/page/blogNew.jsView |
---|
10 | 10 … | exports.gives = nest('app.page.blogNew') |
11 | 11 … | |
12 | 12 … | exports.needs = nest({ |
13 | 13 … | 'app.html.sideNav': 'first', |
| 14 … | + 'blob.html.input': 'first', |
14 | 15 … | 'channel.async.suggest': 'first', |
15 | 16 … | 'history.sync.push': 'first', |
16 | 17 … | 'message.html.compose': 'first', |
17 | 18 … | 'translations.sync.strings': 'first', |
18 | 19 … | 'sbot.async.addBlob': 'first' |
19 | 20 … | }) |
20 | 21 … | |
21 | 22 … | exports.create = (api) => { |
22 | | - var contentHtmlObs |
23 | | - |
24 | 23 … | return nest('app.page.blogNew', blogNew) |
25 | 24 … | |
26 | 25 … | function blogNew (location) { |
27 | 26 … | const strings = api.translations.sync.strings() |
34 | 33 … | summary: Value(), |
35 | 34 … | text: Value('') |
36 | 35 … | }) |
37 | 36 … | |
38 | | - const mediumComposer = h('div.editor', { |
| 37 … | + const mediumComposer = h('div.editor.Markdown', { |
39 | 38 … | 'ev-input': e => { |
40 | 39 … | } |
41 | 40 … | }) |
42 | | - const composer = api.message.html.compose( |
43 | | - { |
44 | | - meta, |
45 | | - placeholder: strings.blogNew.actions.writeBlog, |
46 | | - shrink: false, |
47 | | - prepublish: function (content, cb) { |
48 | | - var m = /\!\[[^]+\]\(([^\)]+)\)/.exec(marksum.image(content.text)) |
49 | | - content.thumbnail = m && m[1] |
50 | | - |
| 41 … | + var filesById = {} |
| 42 … | + const composer = initialiseDummyComposer({ filesById, meta, api }) |
|
| 43 … | + |
| 44 … | + |
| 45 … | + |
| 46 … | + |
51 | 47 … | |
52 | | - var stream = pull.values([content.text]) |
53 | | - delete content.text |
54 | | - api.sbot.async.addBlob(stream, function (err, hash) { |
55 | | - if (err) return cb(err) |
56 | | - if (!hash) throw new Error('missing hash') |
57 | | - content.blog = hash |
58 | | - cb(null, content) |
59 | | - }) |
60 | | - } |
61 | | - }, |
62 | | - (err, msg) => api.history.sync.push(err || { page: 'blogIndex' }) |
63 | | - ) |
64 | | - |
65 | 48 … | const channelInput = h('input', { |
66 | 49 … | 'ev-input': e => meta.channel.set(e.target.value), |
67 | 50 … | value: meta.channel, |
68 | 51 … | placeholder: strings.channel |
90 | 73 … | placeholder: strings.blogNew.field.summary |
91 | 74 … | }) |
92 | 75 … | ]), |
93 | 76 … | mediumComposer, |
94 | | - h('Button', { |
95 | | - 'ev-click': () => { |
96 | | - var img = h('img', { src: 'http://localhost:8989/blobs/get/%264TKyoyZmjjtpPvwiSR%2BGQIgrJs8o6XmzfUDZ5p1PP30%3D.sha256' }) |
97 | | - |
98 | | - |
99 | | - mediumComposer.appendChild(img) |
100 | | - } |
101 | | - }, 'Add Image'), |
| 77 … | + AddFileButton({ api, filesById, meta, textArea: mediumComposer }), |
102 | 78 … | composer |
103 | 79 … | ]) |
104 | 80 … | ]) |
105 | 81 … | ]) |
106 | 82 … | |
107 | | - function initialiseMedium () { |
108 | | - new MediumEditor(mediumComposer, { |
109 | | - elementsContainer: page, |
110 | | - toolbar: { |
111 | | - allowMultiParagraphSelection: true, |
112 | | - buttons: ['bold', 'italic', 'underline', 'anchor', 'h2', 'h3', 'quote'], |
113 | | - diffLeft: 0, |
114 | | - diffTop: -10, |
115 | | - firstButtonClass: 'medium-editor-button-first', |
116 | | - lastButtonClass: 'medium-editor-button-last', |
117 | | - relativeContainer: null, |
118 | | - standardizeSelectionStart: false, |
119 | | - static: false, |
120 | | - |
121 | | - align: 'center', |
122 | | - sticky: false, |
123 | | - updateOnEmptySelection: false |
124 | | - }, |
125 | | - extensions: { |
126 | | - markdown: new MediumToMD ( |
127 | | - { |
128 | | - toMarkdownOptions: { |
129 | | - converters: [{ |
130 | | - filter: 'img', |
131 | | - replacement: (content, node) => { |
132 | | - var blob = decodeURIComponent(node.src.replace('http://localhost:8989/blobs/get/', '')) |
133 | | - return `![](${blob})` |
134 | | - } |
135 | | - }] |
136 | | - }, |
137 | | - events: ['input', 'change', 'DOMNodeInserted'] |
138 | | - }, |
139 | | - md => meta.text.set(md) |
140 | | - ) |
141 | | - } |
| 83 … | + initialiseMedium({ page, el: mediumComposer, meta }) |
| 84 … | + initialiseChannelSuggests({ input: channelInput, suggester: getChannelSuggestions, meta }) |
| 85 … | + |
| 86 … | + return page |
| 87 … | + } |
| 88 … | +} |
| 89 … | + |
| 90 … | +function AddFileButton ({ api, filesById, meta, textArea }) { |
| 91 … | + |
| 92 … | + |
| 93 … | + const fileInput = api.blob.html.input(file => { |
| 94 … | + filesById[file.link] = file |
| 95 … | + |
| 96 … | + const isImage = file.type.match(/^image/) |
| 97 … | + const imgPrefix = isImage ? '!' : '' |
| 98 … | + const spacer = isImage ? '\n' : ' ' |
| 99 … | + const insertLink = spacer + imgPrefix + '[' + file.name + ']' + '(' + file.link + ')' + spacer |
| 100 … | + |
| 101 … | + const pos = textArea.selectionStart |
| 102 … | + |
| 103 … | + |
| 104 … | + |
| 105 … | + |
| 106 … | + |
| 107 … | + const img = h('p', [ |
| 108 … | + h('img', { |
| 109 … | + src: `http://localhost:8989/blobs/get/${encodeURIComponent(file.link)}`, |
| 110 … | + alt: file.name |
142 | 111 … | }) |
143 | | - } |
144 | | - initialiseMedium() |
| 112 … | + ]) |
| 113 … | + |
| 114 … | + textArea.appendChild(img) |
145 | 115 … | |
146 | | - addSuggest(channelInput, (inputText, cb) => { |
147 | | - inputText = inputText.replace(/^#/, '') |
148 | | - var suggestions = getChannelSuggestions(inputText) |
149 | | - .map(s => { |
150 | | - s.value = s.value.replace(/^#/, '') |
151 | | - return s |
152 | | - }) |
153 | | - .map(s => { |
154 | | - if (s.subtitle === 'subscribed') { s.subtitle = h('i.fa.fa-heart') } |
155 | | - return s |
156 | | - }) |
| 116 … | + console.log('added:', file) |
| 117 … | + }) |
157 | 118 … | |
158 | | - |
159 | | - if (!suggestions.some(s => s.title === inputText)) { |
160 | | - suggestions.push({ |
161 | | - title: inputText, |
162 | | - subtitle: h('i.fa.fa-plus-circle'), |
163 | | - value: inputText |
| 119 … | + return fileInput |
| 120 … | +} |
| 121 … | + |
| 122 … | +function initialiseDummyComposer ({ meta, api, filesById }) { |
| 123 … | + return api.message.html.compose( |
| 124 … | + { |
| 125 … | + meta, |
| 126 … | + |
| 127 … | + shrink: false, |
| 128 … | + filesById, |
| 129 … | + prepublish: function (content, cb) { |
| 130 … | + var m = /\!\[[^]+\]\(([^\)]+)\)/.exec(marksum.image(content.text)) |
| 131 … | + content.thumbnail = m && m[1] |
| 132 … | + |
| 133 … | + |
| 134 … | + var stream = pull.values([content.text]) |
| 135 … | + api.sbot.async.addBlob(stream, function (err, hash) { |
| 136 … | + if (err) return cb(err) |
| 137 … | + if (!hash) throw new Error('missing hash') |
| 138 … | + content.blog = hash |
| 139 … | + delete content.text |
| 140 … | + cb(null, content) |
164 | 141 … | }) |
165 | 142 … | } |
| 143 … | + }, |
| 144 … | + (err, msg) => api.history.sync.push(err || { page: 'blogIndex' }) |
| 145 … | + ) |
| 146 … | +} |
166 | 147 … | |
167 | | - cb(null, suggestions) |
168 | | - }, {cls: 'PatchSuggest.-channelHorizontal'}) |
| 148 … | +function initialiseChannelSuggests ({ input, suggester, meta }) { |
| 149 … | + addSuggest(input, (inputText, cb) => { |
| 150 … | + inputText = inputText.replace(/^#/, '') |
| 151 … | + var suggestions = suggester(inputText) |
| 152 … | + .map(s => { |
| 153 … | + s.value = s.value.replace(/^#/, '') |
| 154 … | + return s |
| 155 … | + }) |
| 156 … | + .map(s => { |
| 157 … | + if (s.subtitle === 'subscribed') { s.subtitle = h('i.fa.fa-heart') } |
| 158 … | + return s |
| 159 … | + }) |
169 | 160 … | |
170 | | - channelInput.addEventListener('suggestselect', (e) => { |
171 | | - meta.channel.set(e.detail.value) |
172 | | - }) |
| 161 … | + |
| 162 … | + if (!suggestions.some(s => s.title === inputText)) { |
| 163 … | + suggestions.push({ |
| 164 … | + title: inputText, |
| 165 … | + subtitle: h('i.fa.fa-plus-circle'), |
| 166 … | + value: inputText |
| 167 … | + }) |
| 168 … | + } |
173 | 169 … | |
174 | | - return page |
175 | | - } |
| 170 … | + cb(null, suggestions) |
| 171 … | + }, {cls: 'PatchSuggest.-channelHorizontal'}) |
| 172 … | + |
| 173 … | + input.addEventListener('suggestselect', (e) => { |
| 174 … | + meta.channel.set(e.detail.value) |
| 175 … | + }) |
176 | 176 … | } |
| 177 … | + |
| 178 … | +function initialiseMedium ({ page, el, meta }) { |
| 179 … | + var editor = new MediumEditor(el, { |
| 180 … | + elementsContainer: page, |
| 181 … | + toolbar: { |
| 182 … | + allowMultiParagraphSelection: true, |
| 183 … | + buttons: ['bold', 'italic', 'underline', 'anchor', 'h2', 'h3', 'quote'], |
| 184 … | + diffLeft: 0, |
| 185 … | + diffTop: -10, |
| 186 … | + firstButtonClass: 'medium-editor-button-first', |
| 187 … | + lastButtonClass: 'medium-editor-button-last', |
| 188 … | + relativeContainer: null, |
| 189 … | + standardizeSelectionStart: false, |
| 190 … | + static: false, |
| 191 … | + |
| 192 … | + align: 'center', |
| 193 … | + sticky: false, |
| 194 … | + updateOnEmptySelection: false |
| 195 … | + }, |
| 196 … | + extensions: { |
| 197 … | + markdown: new MediumToMD( |
| 198 … | + { |
| 199 … | + toMarkdownOptions: { |
| 200 … | + converters: [{ |
| 201 … | + filter: 'img', |
| 202 … | + replacement: (content, node) => { |
| 203 … | + var blob = decodeURIComponent(node.src.replace('http://localhost:8989/blobs/get/', '')) |
| 204 … | + return `![${node.alt}](${blob})` |
| 205 … | + } |
| 206 … | + }] |
| 207 … | + }, |
| 208 … | + events: ['input', 'change', 'DOMNodeInserted'] |
| 209 … | + }, |
| 210 … | + md => meta.text.set(md) |
| 211 … | + ) |
| 212 … | + } |
| 213 … | + }) |
| 214 … | + |
| 215 … | + return editor |
| 216 … | +} |