diff --git a/browser/components/MarkdownEditor.js b/browser/components/MarkdownEditor.js index 2c98f18e..2bd5d951 100644 --- a/browser/components/MarkdownEditor.js +++ b/browser/components/MarkdownEditor.js @@ -283,6 +283,7 @@ class MarkdownEditor extends React.Component { indentSize={editorIndentSize} scrollPastEnd={config.preview.scrollPastEnd} smartQuotes={config.preview.smartQuotes} + breaks={config.preview.breaks} sanitize={config.preview.sanitize} ref='preview' onContextMenu={(e) => this.handleContextMenu(e)} diff --git a/browser/components/MarkdownPreview.js b/browser/components/MarkdownPreview.js index 6646f749..ea5f11c0 100755 --- a/browser/components/MarkdownPreview.js +++ b/browser/components/MarkdownPreview.js @@ -145,10 +145,11 @@ export default class MarkdownPreview extends React.Component { } initMarkdown () { - const { smartQuotes, sanitize } = this.props + const { smartQuotes, sanitize, breaks } = this.props this.markdown = new Markdown({ typographer: smartQuotes, - sanitize + sanitize, + breaks }) } @@ -340,7 +341,9 @@ export default class MarkdownPreview extends React.Component { componentDidUpdate (prevProps) { if (prevProps.value !== this.props.value) this.rewriteIframe() - if (prevProps.smartQuotes !== this.props.smartQuotes || prevProps.sanitize !== this.props.sanitize) { + if (prevProps.smartQuotes !== this.props.smartQuotes || + prevProps.sanitize !== this.props.sanitize || + prevProps.breaks !== this.props.breaks) { this.initMarkdown() this.rewriteIframe() } @@ -599,5 +602,6 @@ MarkdownPreview.propTypes = { value: PropTypes.string, showCopyNotification: PropTypes.bool, storagePath: PropTypes.string, - smartQuotes: PropTypes.bool + smartQuotes: PropTypes.bool, + breaks: PropTypes.bool } diff --git a/browser/components/MarkdownSplitEditor.js b/browser/components/MarkdownSplitEditor.js index 27505a5a..2bee5c24 100644 --- a/browser/components/MarkdownSplitEditor.js +++ b/browser/components/MarkdownSplitEditor.js @@ -131,6 +131,7 @@ class MarkdownSplitEditor extends React.Component { lineNumber={config.preview.lineNumber} scrollPastEnd={config.preview.scrollPastEnd} smartQuotes={config.preview.smartQuotes} + breaks={config.preview.breaks} sanitize={config.preview.sanitize} ref='preview' tabInde='0' diff --git a/browser/lib/markdown.js b/browser/lib/markdown.js index 5848aeea..b9e1a3eb 100644 --- a/browser/lib/markdown.js +++ b/browser/lib/markdown.js @@ -25,7 +25,7 @@ class Markdown { linkify: true, html: true, xhtmlOut: true, - breaks: true, + breaks: config.preview.breaks, highlight: function (str, lang) { const delimiter = ':' const langInfo = lang.split(delimiter) diff --git a/browser/main/lib/ConfigManager.js b/browser/main/lib/ConfigManager.js index 79fe0f5f..8a46911e 100644 --- a/browser/main/lib/ConfigManager.js +++ b/browser/main/lib/ConfigManager.js @@ -56,6 +56,7 @@ export const DEFAULT_CONFIG = { plantUMLServerAddress: 'http://www.plantuml.com/plantuml', scrollPastEnd: false, smartQuotes: true, + breaks: true, sanitize: 'STRICT' // 'STRICT', 'ALLOW_STYLES', 'NONE' }, blog: { diff --git a/browser/main/lib/dataApi/attachmentManagement.js b/browser/main/lib/dataApi/attachmentManagement.js index d8d236b4..1373cf94 100644 --- a/browser/main/lib/dataApi/attachmentManagement.js +++ b/browser/main/lib/dataApi/attachmentManagement.js @@ -5,6 +5,7 @@ const findStorage = require('browser/lib/findStorage') const mdurl = require('mdurl') const fse = require('fs-extra') const escapeStringRegexp = require('escape-string-regexp') +const sander = require('sander') const STORAGE_FOLDER_PLACEHOLDER = ':storage' const DESTINATION_FOLDER = 'attachments' @@ -213,6 +214,17 @@ 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) } +/** + * @description Deletes the attachment folder specified by the given storageKey and noteKey + * @param storageKey Key of the storage of the note to be deleted + * @param noteKey Key of the note to be deleted + */ +function deleteAttachmentFolder (storageKey, noteKey) { + const storagePath = findStorage.findStorage(storageKey) + const noteAttachmentPath = path.join(storagePath.path, DESTINATION_FOLDER, noteKey) + sander.rimrafSync(noteAttachmentPath) +} + /** * @description Deletes all attachments stored in the attachment folder of the give not that are not referenced in the markdownContent * @param markdownContent Content of the note. All unreferenced notes will be deleted @@ -265,6 +277,7 @@ module.exports = { getAttachmentsInContent, getAbsolutePathsOfAttachmentsInContent, removeStorageAndNoteReferences, + deleteAttachmentFolder, deleteAttachmentsNotPresentInNote, moveAttachments, STORAGE_FOLDER_PLACEHOLDER, diff --git a/browser/main/lib/dataApi/deleteNote.js b/browser/main/lib/dataApi/deleteNote.js index 49498a30..46ec2b55 100644 --- a/browser/main/lib/dataApi/deleteNote.js +++ b/browser/main/lib/dataApi/deleteNote.js @@ -1,6 +1,7 @@ const resolveStorageData = require('./resolveStorageData') const path = require('path') const sander = require('sander') +const attachmentManagement = require('./attachmentManagement') const { findStorage } = require('browser/lib/findStorage') function deleteNote (storageKey, noteKey) { @@ -25,6 +26,10 @@ function deleteNote (storageKey, noteKey) { storageKey } }) + .then(function deleteAttachments (storageInfo) { + attachmentManagement.deleteAttachmentFolder(storageInfo.storageKey, storageInfo.noteKey) + return storageInfo + }) } module.exports = deleteNote diff --git a/browser/main/modals/PreferencesModal/UiTab.js b/browser/main/modals/PreferencesModal/UiTab.js index 1bbcb18d..d2a2f178 100644 --- a/browser/main/modals/PreferencesModal/UiTab.js +++ b/browser/main/modals/PreferencesModal/UiTab.js @@ -97,6 +97,7 @@ class UiTab extends React.Component { plantUMLServerAddress: this.refs.previewPlantUMLServerAddress.value, scrollPastEnd: this.refs.previewScrollPastEnd.checked, smartQuotes: this.refs.previewSmartQuotes.checked, + breaks: this.refs.previewBreaks.checked, sanitize: this.refs.previewSanitize.value } } @@ -476,6 +477,16 @@ class UiTab extends React.Component { Enable smart quotes +
+ +
diff --git a/package.json b/package.json index 7ee171d5..e3548431 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "@rokt33r/season": "^5.3.0", "aws-sdk": "^2.48.0", "aws-sdk-mobile-analytics": "^0.9.2", - "codemirror": "^5.19.0", + "codemirror": "^5.37.0", "codemirror-mode-elixir": "^1.1.1", "electron-config": "^0.2.1", "electron-gh-releases": "^2.0.2", diff --git a/tests/dataApi/attachmentManagement.test.js b/tests/dataApi/attachmentManagement.test.js index 9511f6d7..feb9207c 100644 --- a/tests/dataApi/attachmentManagement.test.js +++ b/tests/dataApi/attachmentManagement.test.js @@ -8,6 +8,7 @@ jest.mock('unique-slug') const uniqueSlug = require('unique-slug') const mdurl = require('mdurl') const fse = require('fs-extra') +const sander = require('sander') const systemUnderTest = require('browser/main/lib/dataApi/attachmentManagement') @@ -262,6 +263,19 @@ it('should remove the all ":storage" and noteKey references', function () { expect(actual).toEqual(expectedOutput) }) +it('should delete the correct attachment folder if a note is deleted', function () { + const dummyStorage = {path: 'dummyStoragePath'} + const storageKey = 'storageKey' + const noteKey = 'noteKey' + findStorage.findStorage = jest.fn(() => dummyStorage) + sander.rimrafSync = jest.fn() + + const expectedPathToBeDeleted = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, noteKey) + systemUnderTest.deleteAttachmentFolder(storageKey, noteKey) + expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey) + expect(sander.rimrafSync).toHaveBeenCalledWith(expectedPathToBeDeleted) +}) + it('should test that deleteAttachmentsNotPresentInNote deletes all unreferenced attachments ', function () { const dummyStorage = {path: 'dummyStoragePath'} const noteKey = 'noteKey' diff --git a/tests/dataApi/deleteNote-test.js b/tests/dataApi/deleteNote-test.js index 611022de..9c809dcf 100644 --- a/tests/dataApi/deleteNote-test.js +++ b/tests/dataApi/deleteNote-test.js @@ -14,6 +14,8 @@ const sander = require('sander') const os = require('os') const CSON = require('@rokt33r/season') const faker = require('faker') +const fs = require('fs') +const attachmentManagement = require('browser/main/lib/dataApi/attachmentManagement') const storagePath = path.join(os.tmpdir(), 'test/delete-note') @@ -42,6 +44,11 @@ test.serial('Delete a note', (t) => { return Promise.resolve() .then(function doTest () { return createNote(storageKey, input1) + .then(function createAttachmentFolder (data) { + fs.mkdirSync(path.join(storagePath, attachmentManagement.DESTINATION_FOLDER)) + fs.mkdirSync(path.join(storagePath, attachmentManagement.DESTINATION_FOLDER, data.key)) + return data + }) .then(function (data) { return deleteNote(storageKey, data.key) }) @@ -52,8 +59,13 @@ test.serial('Delete a note', (t) => { t.fail('note cson must be deleted.') } catch (err) { t.is(err.code, 'ENOENT') + return data } }) + .then(function assertAttachmentFolderDeleted (data) { + const attachmentFolderPath = path.join(storagePath, attachmentManagement.DESTINATION_FOLDER, data.noteKey) + t.is(fs.existsSync(attachmentFolderPath), false) + }) }) test.after(function after () { diff --git a/tests/fixtures/markdowns.js b/tests/fixtures/markdowns.js index 8db35485..69e335e0 100644 --- a/tests/fixtures/markdowns.js +++ b/tests/fixtures/markdowns.js @@ -48,10 +48,13 @@ const checkboxes = ` const smartQuotes = 'This is a "QUOTE".' +const breaks = 'This is the first line.\nThis is the second line.' + export default { basic, codeblock, katex, checkboxes, - smartQuotes + smartQuotes, + breaks } diff --git a/tests/lib/markdown-test.js b/tests/lib/markdown-test.js index b2a81fdf..73b68799 100644 --- a/tests/lib/markdown-test.js +++ b/tests/lib/markdown-test.js @@ -34,3 +34,12 @@ test('Markdown.render() should text with quotes correctly', t => { const renderedNonSmartQuotes = newmd.render(markdownFixtures.smartQuotes) t.snapshot(renderedNonSmartQuotes) }) + +test('Markdown.render() should render line breaks correctly', t => { + const renderedBreaks = md.render(markdownFixtures.breaks) + t.snapshot(renderedBreaks) + + const newmd = new Markdown({ breaks: false }) + const renderedNonBreaks = newmd.render(markdownFixtures.breaks) + t.snapshot(renderedNonBreaks) +}) diff --git a/tests/lib/snapshots/markdown-test.js.md b/tests/lib/snapshots/markdown-test.js.md index d4f0469e..ffc3d699 100644 --- a/tests/lib/snapshots/markdown-test.js.md +++ b/tests/lib/snapshots/markdown-test.js.md @@ -4,6 +4,20 @@ The actual snapshot is saved in `markdown-test.js.snap`. Generated by [AVA](https://ava.li). +## Markdown.render() should render line breaks correctly + +> Snapshot 1 + + `

This is the first line.
␊ + This is the second line.

␊ + ` + +> Snapshot 2 + + `

This is the first line.␊ + This is the second line.

␊ + ` + ## Markdown.render() should renders KaTeX correctly > Snapshot 1 diff --git a/tests/lib/snapshots/markdown-test.js.snap b/tests/lib/snapshots/markdown-test.js.snap index 71ff221d..fc310cfd 100644 Binary files a/tests/lib/snapshots/markdown-test.js.snap and b/tests/lib/snapshots/markdown-test.js.snap differ