Skip to content

Commit

Permalink
Fixes BoostIO#1827
Browse files Browse the repository at this point in the history
  • Loading branch information
ehhc committed Apr 21, 2018
1 parent d2163da commit e497190
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 44 deletions.
45 changes: 23 additions & 22 deletions browser/components/MarkdownEditor.js
Expand Up @@ -272,28 +272,29 @@ class MarkdownEditor extends React.Component {
? 'preview'
: 'preview--hide'
}
style={previewStyle}
theme={config.ui.theme}
keyMap={config.editor.keyMap}
fontSize={config.preview.fontSize}
fontFamily={config.preview.fontFamily}
codeBlockTheme={config.preview.codeBlockTheme}
codeBlockFontFamily={config.editor.fontFamily}
lineNumber={config.preview.lineNumber}
indentSize={editorIndentSize}
scrollPastEnd={config.preview.scrollPastEnd}
smartQuotes={config.preview.smartQuotes}
sanitize={config.preview.sanitize}
ref='preview'
onContextMenu={(e) => this.handleContextMenu(e)}
onDoubleClick={(e) => this.handleDoubleClick(e)}
tabIndex='0'
value={this.state.renderValue}
onMouseUp={(e) => this.handlePreviewMouseUp(e)}
onMouseDown={(e) => this.handlePreviewMouseDown(e)}
onCheckboxClick={(e) => this.handleCheckboxClick(e)}
showCopyNotification={config.ui.showCopyNotification}
storagePath={storage.path}
style={previewStyle}
theme={config.ui.theme}
keyMap={config.editor.keyMap}
fontSize={config.preview.fontSize}
fontFamily={config.preview.fontFamily}
codeBlockTheme={config.preview.codeBlockTheme}
codeBlockFontFamily={config.editor.fontFamily}
lineNumber={config.preview.lineNumber}
indentSize={editorIndentSize}
scrollPastEnd={config.preview.scrollPastEnd}
smartQuotes={config.preview.smartQuotes}
sanitize={config.preview.sanitize}
ref='preview'
onContextMenu={(e) => this.handleContextMenu(e)}
onDoubleClick={(e) => this.handleDoubleClick(e)}
tabIndex='0'
value={this.state.renderValue}
onMouseUp={(e) => this.handlePreviewMouseUp(e)}
onMouseDown={(e) => this.handlePreviewMouseDown(e)}
onCheckboxClick={(e) => this.handleCheckboxClick(e)}
showCopyNotification={config.ui.showCopyNotification}
storagePath={storage.path}
noteKey={noteKey}
/>
</div>
)
Expand Down
10 changes: 9 additions & 1 deletion browser/components/MarkdownPreview.js
Expand Up @@ -211,8 +211,9 @@ export default class MarkdownPreview extends React.Component {
const {fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme} = this.getStyleParams()

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

files.forEach((file) => {
file = file.replace('file://', '')
Expand All @@ -221,6 +222,13 @@ export default class MarkdownPreview extends React.Component {
dst: 'css'
})
})
attachmentsAbsolutePaths.forEach((attachment) => {
exportTasks.push({
src: attachment,
dst: attachmentManagement.DESTINATION_FOLDER
})
})
body = attachmentManagement.removeStorageAndNoteReferences(body, this.props.noteKey)

let styles = ''
files.forEach((file) => {
Expand Down
1 change: 1 addition & 0 deletions browser/components/MarkdownSplitEditor.js
Expand Up @@ -139,6 +139,7 @@ class MarkdownSplitEditor extends React.Component {
onScroll={this.handleScroll.bind(this)}
showCopyNotification={config.ui.showCopyNotification}
storagePath={storage.path}
noteKey={noteKey}
/>
</div>
)
Expand Down
40 changes: 40 additions & 0 deletions browser/main/lib/dataApi/attachmentManagement.js
Expand Up @@ -3,6 +3,7 @@ const fs = require('fs')
const path = require('path')
const findStorage = require('browser/lib/findStorage')
const mdurl = require('mdurl')
const escapeStringRegexp = require('escape-string-regexp')

const STORAGE_FOLDER_PLACEHOLDER = ':storage'
const DESTINATION_FOLDER = 'attachments'
Expand Down Expand Up @@ -153,12 +154,51 @@ function handlePastImageEvent (codeEditor, storageKey, noteKey, dataTransferItem
reader.readAsDataURL(blob)
}

/**
* @description Returns all attachment paths of the given markdown
* @param {String} markdownContent content in which the attachment paths should be found
* @returns {String[]} Array of the relativ paths (starting with :storage) of the attachments of the given markdown
*/
function getAttachmentsInContent (markdownContent) {
let preparedInput = markdownContent.replace(new RegExp(mdurl.encode(path.sep), 'g'), path.sep)
let 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')
return preparedInput.match(regexp)
}

/**
* @description Returns an array of the absolute paths of the attachments referenced in the given markdown code
* @param {String} markdownContent content in which the attachment paths should be found
* @param {String} storagePath path of the current storage
* @returns {String[]} Absolute paths of the referenced attachments
*/
function getAbsolutePathsOfAttachmentsInContent (markdownContent, storagePath) {
let temp = getAttachmentsInContent(markdownContent)
let result = []
for (let relativePath of temp) {
result.push(relativePath.replace(new RegExp(STORAGE_FOLDER_PLACEHOLDER, 'g'), path.join(storagePath, DESTINATION_FOLDER)))
}
return result
}

/**
* @description Deletes all :storage and noteKey references from the given input.
* @param input Input in which the references should be deleted
* @param noteKey Key of the current note
* @returns {String} Input without the references
*/
function removeStorageAndNoteReferences (input, noteKey) {
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)
}

module.exports = {
copyAttachment,
fixLocalURLS,
generateAttachmentMarkdown,
handleAttachmentDrop,
handlePastImageEvent,
getAttachmentsInContent,
getAbsolutePathsOfAttachmentsInContent,
removeStorageAndNoteReferences,
STORAGE_FOLDER_PLACEHOLDER,
DESTINATION_FOLDER
}
21 changes: 1 addition & 20 deletions browser/main/lib/dataApi/exportNote.js
@@ -1,14 +1,9 @@
import copyFile from 'browser/main/lib/dataApi/copyFile'
import { findStorage } from 'browser/lib/findStorage'
import filenamify from 'filenamify'

const fs = require('fs')
const path = require('path')

const LOCAL_STORED_REGEX = /!\[(.*?)]\(\s*?\/:storage\/(.*\.\S*?)\)/gi
//TODO: ehhc: check this -> attachmentManagement
const IMAGES_FOLDER_NAME = 'images'

/**
* Export note together with images
*
Expand All @@ -29,21 +24,7 @@ function exportNote (storageKey, noteContent, targetPath, outputFormatter) {
throw new Error('Storage path is not found')
}

let exportedData = noteContent.replace(LOCAL_STORED_REGEX, (match, dstFilename, srcFilename) => {
dstFilename = filenamify(dstFilename, {replacement: '_'})
if (!path.extname(dstFilename)) {
dstFilename += path.extname(srcFilename)
}

const dstRelativePath = path.join(IMAGES_FOLDER_NAME, dstFilename)

exportTasks.push({
src: path.join(IMAGES_FOLDER_NAME, srcFilename),
dst: dstRelativePath
})

return `![${dstFilename}](${dstRelativePath})`
})
let exportedData = noteContent

if (outputFormatter) {
exportedData = outputFormatter(exportedData, exportTasks)
Expand Down
97 changes: 96 additions & 1 deletion tests/dataApi/attachmentManagement.test.js
Expand Up @@ -165,4 +165,99 @@ it('should test that generateAttachmentMarkdown works correct both with previews
expected = `[${fileName}](${path})`
actual = systemUnderTest.generateAttachmentMarkdown(fileName, path, false)
expect(actual).toEqual(expected)
})
})

it('should test that getAttachmentsInContent finds all attachments', function () {
let testInput =
'<html>\n' +
' <head>\n' +
' //header\n' +
' </head>\n' +
' <body data-theme="default">\n' +
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
' <p data-line="2">\n' +
' <img src=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
' </p>\n' +
' <p data-line="4">\n' +
' <a href=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
' </p>\n' +
' <p data-line="6">\n' +
' <img src=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
' </p>\n' +
' </body>\n' +
'</html>'
let actual = systemUnderTest.getAttachmentsInContent(testInput)
let expected = [':storage\\9c9c4ba3-bc1e-441f-9866-c1e9a806e31c\\0.6r4zdgc22xp', ':storage\\9c9c4ba3-bc1e-441f-9866-c1e9a806e31c\\0.q2i4iw0fyx', ':storage\\9c9c4ba3-bc1e-441f-9866-c1e9a806e31c\\d6c5ee92.jpg']
expect(actual).toEqual(expect.arrayContaining(expected))
})

it('should test that getAbsolutePathsOfAttachmentsInContent returns all absolute paths', function () {
let dummyStoragePath = 'dummyStoragePath'
let testInput =
'<html>\n' +
' <head>\n' +
' //header\n' +
' </head>\n' +
' <body data-theme="default">\n' +
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
' <p data-line="2">\n' +
' <img src=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
' </p>\n' +
' <p data-line="4">\n' +
' <a href=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
' </p>\n' +
' <p data-line="6">\n' +
' <img src=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
' </p>\n' +
' </body>\n' +
'</html>'
let actual = systemUnderTest.getAbsolutePathsOfAttachmentsInContent(testInput, dummyStoragePath)
let expected = [dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.6r4zdgc22xp',
dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.q2i4iw0fyx',
dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + 'd6c5ee92.jpg']
expect(actual).toEqual(expect.arrayContaining(expected))
})

it('should remove the all ":storage" and noteKey references', function () {
let storageFolder = systemUnderTest.DESTINATION_FOLDER
let noteKey = 'noteKey'
let testInput =
'<html>\n' +
' <head>\n' +
' //header\n' +
' </head>\n' +
' <body data-theme="default">\n' +
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
' <p data-line="2">\n' +
' <img src=":storage' + mdurl.encode(path.sep) + noteKey + mdurl.encode(path.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
' </p>\n' +
' <p data-line="4">\n' +
' <a href=":storage' + mdurl.encode(path.sep) + noteKey + mdurl.encode(path.sep) + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
' </p>\n' +
' <p data-line="6">\n' +
' <img src=":storage' + mdurl.encode(path.sep) + noteKey + mdurl.encode(path.sep) + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
' </p>\n' +
' </body>\n' +
'</html>'
let storagePath = '<<dummyStoragePath>>'
let expectedOutput =
'<html>\n' +
' <head>\n' +
' //header\n' +
' </head>\n' +
' <body data-theme="default">\n' +
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
' <p data-line="2">\n' +
' <img src="' + storageFolder + '\\0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
' </p>\n' +
' <p data-line="4">\n' +
' <a href="' + storageFolder + '\\0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
' </p>\n' +
' <p data-line="6">\n' +
' <img src="' + storageFolder + '\\d6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
' </p>\n' +
' </body>\n' +
'</html>'
let actual = systemUnderTest.removeStorageAndNoteReferences(testInput, noteKey)
expect(actual).toEqual(expectedOutput)
})

0 comments on commit e497190

Please sign in to comment.