Skip to content

Commit d04048c

Browse files
authored
Merge pull request #1874 from ehhc/Issue_1827
Issue 1827
2 parents 9ff5cc5 + e9de8f4 commit d04048c

File tree

9 files changed

+158
-31
lines changed

9 files changed

+158
-31
lines changed

.eslintrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,8 @@
1919
"FileReader": true,
2020
"localStorage": true,
2121
"fetch": true
22+
},
23+
"env": {
24+
"jest": true
2225
}
2326
}

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ node_js:
33
- 6
44
script:
55
- npm run lint && npm run test
6+
- yarn jest
67
- 'if [[ ${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} = "master" ]]; then npm install -g grunt [email protected] && grunt pre-build; fi'
78
after_success:
89
- openssl aes-256-cbc -K $encrypted_440d7f9a3c38_key -iv $encrypted_440d7f9a3c38_iv

browser/components/MarkdownEditor.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ class MarkdownEditor extends React.Component {
294294
onCheckboxClick={(e) => this.handleCheckboxClick(e)}
295295
showCopyNotification={config.ui.showCopyNotification}
296296
storagePath={storage.path}
297+
noteKey={noteKey}
297298
/>
298299
</div>
299300
)

browser/components/MarkdownPreview.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,9 @@ export default class MarkdownPreview extends React.Component {
211211
const {fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme} = this.getStyleParams()
212212

213213
const inlineStyles = buildStyle(fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme, lineNumber)
214-
const body = this.markdown.render(escapeHtmlCharacters(noteContent))
214+
let body = this.markdown.render(escapeHtmlCharacters(noteContent))
215215
const files = [this.GetCodeThemeLink(codeBlockTheme), ...CSS_FILES]
216+
const attachmentsAbsolutePaths = attachmentManagement.getAbsolutePathsOfAttachmentsInContent(noteContent, this.props.storagePath)
216217

217218
files.forEach((file) => {
218219
file = file.replace('file://', '')
@@ -221,6 +222,13 @@ export default class MarkdownPreview extends React.Component {
221222
dst: 'css'
222223
})
223224
})
225+
attachmentsAbsolutePaths.forEach((attachment) => {
226+
exportTasks.push({
227+
src: attachment,
228+
dst: attachmentManagement.DESTINATION_FOLDER
229+
})
230+
})
231+
body = attachmentManagement.removeStorageAndNoteReferences(body, this.props.noteKey)
224232

225233
let styles = ''
226234
files.forEach((file) => {

browser/components/MarkdownSplitEditor.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ class MarkdownSplitEditor extends React.Component {
139139
onScroll={this.handleScroll.bind(this)}
140140
showCopyNotification={config.ui.showCopyNotification}
141141
storagePath={storage.path}
142+
noteKey={noteKey}
142143
/>
143144
</div>
144145
)

browser/main/lib/dataApi/attachmentManagement.js

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const fs = require('fs')
33
const path = require('path')
44
const findStorage = require('browser/lib/findStorage')
55
const mdurl = require('mdurl')
6+
const escapeStringRegexp = require('escape-string-regexp')
67

78
const STORAGE_FOLDER_PLACEHOLDER = ':storage'
89
const DESTINATION_FOLDER = 'attachments'
@@ -104,8 +105,8 @@ function handleAttachmentDrop (codeEditor, storageKey, noteKey, dropEvent) {
104105
const fileType = file['type']
105106

106107
copyAttachment(filePath, storageKey, noteKey).then((fileName) => {
107-
let showPreview = fileType.startsWith('image')
108-
let imageMd = generateAttachmentMarkdown(originalFileName, path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, fileName), showPreview)
108+
const showPreview = fileType.startsWith('image')
109+
const imageMd = generateAttachmentMarkdown(originalFileName, path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, fileName), showPreview)
109110
codeEditor.insertAttachmentMd(imageMd)
110111
})
111112
}
@@ -139,26 +140,65 @@ function handlePastImageEvent (codeEditor, storageKey, noteKey, dataTransferItem
139140
const destinationDir = path.join(targetStorage.path, DESTINATION_FOLDER, noteKey)
140141
createAttachmentDestinationFolder(targetStorage.path, noteKey)
141142

142-
let imageName = `${uniqueSlug()}.png`
143+
const imageName = `${uniqueSlug()}.png`
143144
const imagePath = path.join(destinationDir, imageName)
144145

145146
reader.onloadend = function () {
146147
base64data = reader.result.replace(/^data:image\/png;base64,/, '')
147148
base64data += base64data.replace('+', ' ')
148149
const binaryData = new Buffer(base64data, 'base64').toString('binary')
149150
fs.writeFile(imagePath, binaryData, 'binary')
150-
let imageMd = generateAttachmentMarkdown(imageName, imagePath, true)
151+
const imageMd = generateAttachmentMarkdown(imageName, imagePath, true)
151152
codeEditor.insertAttachmentMd(imageMd)
152153
}
153154
reader.readAsDataURL(blob)
154155
}
155156

157+
/**
158+
* @description Returns all attachment paths of the given markdown
159+
* @param {String} markdownContent content in which the attachment paths should be found
160+
* @returns {String[]} Array of the relativ paths (starting with :storage) of the attachments of the given markdown
161+
*/
162+
function getAttachmentsInContent (markdownContent) {
163+
const preparedInput = markdownContent.replace(new RegExp(mdurl.encode(path.sep), 'g'), path.sep)
164+
const regexp = new RegExp(STORAGE_FOLDER_PLACEHOLDER + escapeStringRegexp(path.sep) + '([a-zA-Z0-9]|-)+' + escapeStringRegexp(path.sep) + '[a-zA-Z0-9]+(\\.[a-zA-Z0-9]+)?', 'g')
165+
return preparedInput.match(regexp)
166+
}
167+
168+
/**
169+
* @description Returns an array of the absolute paths of the attachments referenced in the given markdown code
170+
* @param {String} markdownContent content in which the attachment paths should be found
171+
* @param {String} storagePath path of the current storage
172+
* @returns {String[]} Absolute paths of the referenced attachments
173+
*/
174+
function getAbsolutePathsOfAttachmentsInContent (markdownContent, storagePath) {
175+
const temp = getAttachmentsInContent(markdownContent)
176+
const result = []
177+
for (const relativePath of temp) {
178+
result.push(relativePath.replace(new RegExp(STORAGE_FOLDER_PLACEHOLDER, 'g'), path.join(storagePath, DESTINATION_FOLDER)))
179+
}
180+
return result
181+
}
182+
183+
/**
184+
* @description Deletes all :storage and noteKey references from the given input.
185+
* @param input Input in which the references should be deleted
186+
* @param noteKey Key of the current note
187+
* @returns {String} Input without the references
188+
*/
189+
function removeStorageAndNoteReferences (input, noteKey) {
190+
return input.replace(new RegExp(mdurl.encode(path.sep), 'g'), path.sep).replace(new RegExp(STORAGE_FOLDER_PLACEHOLDER + escapeStringRegexp(path.sep) + noteKey, 'g'), DESTINATION_FOLDER)
191+
}
192+
156193
module.exports = {
157194
copyAttachment,
158195
fixLocalURLS,
159196
generateAttachmentMarkdown,
160197
handleAttachmentDrop,
161198
handlePastImageEvent,
199+
getAttachmentsInContent,
200+
getAbsolutePathsOfAttachmentsInContent,
201+
removeStorageAndNoteReferences,
162202
STORAGE_FOLDER_PLACEHOLDER,
163203
DESTINATION_FOLDER
164204
}

browser/main/lib/dataApi/exportNote.js

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
import copyFile from 'browser/main/lib/dataApi/copyFile'
22
import { findStorage } from 'browser/lib/findStorage'
3-
import filenamify from 'filenamify'
43

54
const fs = require('fs')
65
const path = require('path')
76

8-
const LOCAL_STORED_REGEX = /!\[(.*?)]\(\s*?\/:storage\/(.*\.\S*?)\)/gi
9-
// TODO: ehhc: check this -> attachmentManagement
10-
const IMAGES_FOLDER_NAME = 'images'
11-
127
/**
138
* Export note together with images
149
*
@@ -29,21 +24,7 @@ function exportNote (storageKey, noteContent, targetPath, outputFormatter) {
2924
throw new Error('Storage path is not found')
3025
}
3126

32-
let exportedData = noteContent.replace(LOCAL_STORED_REGEX, (match, dstFilename, srcFilename) => {
33-
dstFilename = filenamify(dstFilename, {replacement: '_'})
34-
if (!path.extname(dstFilename)) {
35-
dstFilename += path.extname(srcFilename)
36-
}
37-
38-
const dstRelativePath = path.join(IMAGES_FOLDER_NAME, dstFilename)
39-
40-
exportTasks.push({
41-
src: path.join(IMAGES_FOLDER_NAME, srcFilename),
42-
dst: dstRelativePath
43-
})
44-
45-
return `![${dstFilename}](${dstRelativePath})`
46-
})
27+
let exportedData = noteContent
4728

4829
if (outputFormatter) {
4930
exportedData = outputFormatter(exportedData, exportTasks)

tests/components/__snapshots__/TagListItem.snapshot.test.js.snap

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@ exports[`TagListItem renders correctly 1`] = `
1717
# Test
1818
<span
1919
className="tagList-item-count"
20-
>
21-
22-
</span>
20+
/>
2321
</span>
2422
</button>
2523
</div>

tests/dataApi/attachmentManagement.test.js

Lines changed: 97 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,13 @@ it('should replace the all ":storage" path with the actual storage path', functi
142142
' <body data-theme="default">\n' +
143143
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
144144
' <p data-line="2">\n' +
145-
' <img src="file:///' + storagePath + '\\' + storageFolder + '\\0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
145+
' <img src="file:///' + storagePath + path.sep + storageFolder + path.sep + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
146146
' </p>\n' +
147147
' <p data-line="4">\n' +
148-
' <a href="file:///' + storagePath + '\\' + storageFolder + '\\0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
148+
' <a href="file:///' + storagePath + path.sep + storageFolder + path.sep + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
149149
' </p>\n' +
150150
' <p data-line="6">\n' +
151-
' <img src="file:///' + storagePath + '\\' + storageFolder + '\\d6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
151+
' <img src="file:///' + storagePath + path.sep + storageFolder + path.sep + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
152152
' </p>\n' +
153153
' </body>\n' +
154154
'</html>'
@@ -166,3 +166,97 @@ it('should test that generateAttachmentMarkdown works correct both with previews
166166
actual = systemUnderTest.generateAttachmentMarkdown(fileName, path, false)
167167
expect(actual).toEqual(expected)
168168
})
169+
170+
it('should test that getAttachmentsInContent finds all attachments', function () {
171+
const testInput =
172+
'<html>\n' +
173+
' <head>\n' +
174+
' //header\n' +
175+
' </head>\n' +
176+
' <body data-theme="default">\n' +
177+
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
178+
' <p data-line="2">\n' +
179+
' <img src=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
180+
' </p>\n' +
181+
' <p data-line="4">\n' +
182+
' <a href=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
183+
' </p>\n' +
184+
' <p data-line="6">\n' +
185+
' <img src=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
186+
' </p>\n' +
187+
' </body>\n' +
188+
'</html>'
189+
const actual = systemUnderTest.getAttachmentsInContent(testInput)
190+
const expected = [':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.6r4zdgc22xp', ':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.q2i4iw0fyx', ':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + 'd6c5ee92.jpg']
191+
expect(actual).toEqual(expect.arrayContaining(expected))
192+
})
193+
194+
it('should test that getAbsolutePathsOfAttachmentsInContent returns all absolute paths', function () {
195+
const dummyStoragePath = 'dummyStoragePath'
196+
const testInput =
197+
'<html>\n' +
198+
' <head>\n' +
199+
' //header\n' +
200+
' </head>\n' +
201+
' <body data-theme="default">\n' +
202+
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
203+
' <p data-line="2">\n' +
204+
' <img src=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
205+
' </p>\n' +
206+
' <p data-line="4">\n' +
207+
' <a href=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
208+
' </p>\n' +
209+
' <p data-line="6">\n' +
210+
' <img src=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
211+
' </p>\n' +
212+
' </body>\n' +
213+
'</html>'
214+
const actual = systemUnderTest.getAbsolutePathsOfAttachmentsInContent(testInput, dummyStoragePath)
215+
const expected = [dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.6r4zdgc22xp',
216+
dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.q2i4iw0fyx',
217+
dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + 'd6c5ee92.jpg']
218+
expect(actual).toEqual(expect.arrayContaining(expected))
219+
})
220+
221+
it('should remove the all ":storage" and noteKey references', function () {
222+
const storageFolder = systemUnderTest.DESTINATION_FOLDER
223+
const noteKey = 'noteKey'
224+
const testInput =
225+
'<html>\n' +
226+
' <head>\n' +
227+
' //header\n' +
228+
' </head>\n' +
229+
' <body data-theme="default">\n' +
230+
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
231+
' <p data-line="2">\n' +
232+
' <img src=":storage' + mdurl.encode(path.sep) + noteKey + mdurl.encode(path.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
233+
' </p>\n' +
234+
' <p data-line="4">\n' +
235+
' <a href=":storage' + mdurl.encode(path.sep) + noteKey + mdurl.encode(path.sep) + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
236+
' </p>\n' +
237+
' <p data-line="6">\n' +
238+
' <img src=":storage' + mdurl.encode(path.sep) + noteKey + mdurl.encode(path.sep) + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
239+
' </p>\n' +
240+
' </body>\n' +
241+
'</html>'
242+
const expectedOutput =
243+
'<html>\n' +
244+
' <head>\n' +
245+
' //header\n' +
246+
' </head>\n' +
247+
' <body data-theme="default">\n' +
248+
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
249+
' <p data-line="2">\n' +
250+
' <img src="' + storageFolder + path.sep + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
251+
' </p>\n' +
252+
' <p data-line="4">\n' +
253+
' <a href="' + storageFolder + path.sep + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
254+
' </p>\n' +
255+
' <p data-line="6">\n' +
256+
' <img src="' + storageFolder + path.sep + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
257+
' </p>\n' +
258+
' </body>\n' +
259+
'</html>'
260+
const actual = systemUnderTest.removeStorageAndNoteReferences(testInput, noteKey)
261+
expect(actual).toEqual(expectedOutput)
262+
})

0 commit comments

Comments
 (0)