diff --git a/browser/components/CodeEditor.js b/browser/components/CodeEditor.js index 7543e859..057d0cd8 100644 --- a/browser/components/CodeEditor.js +++ b/browser/components/CodeEditor.js @@ -20,7 +20,7 @@ import styles from '../components/CodeEditor.styl' const { ipcRenderer, remote, clipboard } = require('electron') import normalizeEditorFontFamily from 'browser/lib/normalizeEditorFontFamily' const spellcheck = require('browser/lib/spellcheck') -const buildEditorContextMenu = require('browser/lib/contextMenuBuilder') +const buildEditorContextMenu = require('browser/lib/contextMenuBuilder').buildEditorContextMenu import { createTurndownService } from '../lib/turndown' import {languageMaps} from '../lib/CMLanguageList' import snippetManager from '../lib/SnippetManager' @@ -53,6 +53,7 @@ export default class CodeEditor extends React.Component { this.focusHandler = () => { ipcRenderer.send('editor:focused', true) } + const debouncedDeletionOfAttachments = _.debounce(attachmentManagement.deleteAttachmentsNotPresentInNote, 30000) this.blurHandler = (editor, e) => { ipcRenderer.send('editor:focused', false) if (e == null) return null @@ -64,16 +65,11 @@ export default class CodeEditor extends React.Component { el = el.parentNode } this.props.onBlur != null && this.props.onBlur(e) - const { storageKey, noteKey } = this.props - attachmentManagement.deleteAttachmentsNotPresentInNote( - this.editor.getValue(), - storageKey, - noteKey - ) + debouncedDeletionOfAttachments(this.editor.getValue(), storageKey, noteKey) } this.pasteHandler = (editor, e) => { e.preventDefault() @@ -205,23 +201,11 @@ export default class CodeEditor extends React.Component { 'Cmd-T': function (cm) { // Do nothing }, - 'Ctrl-/': function (cm) { - if (global.process.platform === 'darwin') { return } + [translateHotkey(hotkey.insertDate)]: function (cm) { const dateNow = new Date() cm.replaceSelection(dateNow.toLocaleDateString()) }, - 'Cmd-/': function (cm) { - if (global.process.platform !== 'darwin') { return } - const dateNow = new Date() - cm.replaceSelection(dateNow.toLocaleDateString()) - }, - 'Shift-Ctrl-/': function (cm) { - if (global.process.platform === 'darwin') { return } - const dateNow = new Date() - cm.replaceSelection(dateNow.toLocaleString()) - }, - 'Shift-Cmd-/': function (cm) { - if (global.process.platform !== 'darwin') { return } + [translateHotkey(hotkey.insertDateTime)]: function (cm) { const dateNow = new Date() cm.replaceSelection(dateNow.toLocaleString()) }, @@ -267,7 +251,7 @@ export default class CodeEditor extends React.Component { value: this.props.value, linesHighlighted: this.props.linesHighlighted, lineNumbers: this.props.displayLineNumbers, - lineWrapping: true, + lineWrapping: this.props.lineWrapping, theme: this.props.theme, indentUnit: this.props.indentSize, tabSize: this.props.indentSize, @@ -566,6 +550,10 @@ export default class CodeEditor extends React.Component { this.editor.setOption('lineNumbers', this.props.displayLineNumbers) } + if (prevProps.lineWrapping !== this.props.lineWrapping) { + this.editor.setOption('lineWrapping', this.props.lineWrapping) + } + if (prevProps.scrollPastEnd !== this.props.scrollPastEnd) { this.editor.setOption('scrollPastEnd', this.props.scrollPastEnd) } diff --git a/browser/components/MarkdownEditor.js b/browser/components/MarkdownEditor.js index e956655c..3dd57f70 100644 --- a/browser/components/MarkdownEditor.js +++ b/browser/components/MarkdownEditor.js @@ -304,6 +304,7 @@ class MarkdownEditor extends React.Component { enableRulers={config.editor.enableRulers} rulers={config.editor.rulers} displayLineNumbers={config.editor.displayLineNumbers} + lineWrapping matchingPairs={config.editor.matchingPairs} matchingTriples={config.editor.matchingTriples} explodingPairs={config.editor.explodingPairs} @@ -340,6 +341,7 @@ class MarkdownEditor extends React.Component { smartArrows={config.preview.smartArrows} breaks={config.preview.breaks} sanitize={config.preview.sanitize} + mermaidHTMLLabel={config.preview.mermaidHTMLLabel} ref='preview' onContextMenu={(e) => this.handleContextMenu(e)} onDoubleClick={(e) => this.handleDoubleClick(e)} diff --git a/browser/components/MarkdownPreview.js b/browser/components/MarkdownPreview.js index 9d391125..0072e403 100755 --- a/browser/components/MarkdownPreview.js +++ b/browser/components/MarkdownPreview.js @@ -18,15 +18,13 @@ import mdurl from 'mdurl' import exportNote from 'browser/main/lib/dataApi/exportNote' import { escapeHtmlCharacters } from 'browser/lib/utils' import yaml from 'js-yaml' -import context from 'browser/lib/context' -import i18n from 'browser/lib/i18n' -import fs from 'fs' import { render } from 'react-dom' import Carousel from 'react-image-carousel' import ConfigManager from '../main/lib/ConfigManager' const { remote, shell } = require('electron') const attachmentManagement = require('../main/lib/dataApi/attachmentManagement') +const buildMarkdownPreviewContextMenu = require('browser/lib/contextMenuBuilder').buildMarkdownPreviewContextMenu const { app } = remote const path = require('path') @@ -34,8 +32,6 @@ const fileUrl = require('file-url') const dialog = remote.dialog -const uri2path = require('file-uri-to-path') - const markdownStyle = require('!!css!stylus?sourceMap!./markdown.styl')[0][1] const appPath = fileUrl( process.env.NODE_ENV === 'production' ? app.getAppPath() : path.resolve() @@ -45,6 +41,7 @@ const CSS_FILES = [ `${appPath}/node_modules/codemirror/lib/codemirror.css`, `${appPath}/node_modules/react-image-carousel/lib/css/main.min.css` ] +const win = global.process.platform === 'win32' function buildStyle ( fontFamily, @@ -249,30 +246,9 @@ export default class MarkdownPreview extends React.Component { } handleContextMenu (event) { - // If a contextMenu handler was passed to us, use it instead of the self-defined one -> return - if (_.isFunction(this.props.onContextMenu)) { - this.props.onContextMenu(event) - return - } - // No contextMenu was passed to us -> execute our own link-opener - if (event.target.tagName.toLowerCase() === 'a' && event.target.getAttribute('href')) { - const href = event.target.href - const isLocalFile = href.startsWith('file:') - if (isLocalFile) { - const absPath = uri2path(href) - try { - if (fs.lstatSync(absPath).isFile()) { - context.popup([ - { - label: i18n.__('Show in explorer'), - click: (e) => shell.showItemInFolder(absPath) - } - ]) - } - } catch (e) { - console.log('Error while evaluating if the file is locally available', e) - } - } + const menu = buildMarkdownPreviewContextMenu(this, event) + if (menu != null) { + menu.popup(remote.getCurrentWindow()) } } @@ -345,7 +321,11 @@ export default class MarkdownPreview extends React.Component { customCSS ) let body = this.markdown.render(noteContent) - const files = [this.GetCodeThemeLink(codeBlockTheme), ...CSS_FILES] + body = attachmentManagement.fixLocalURLS( + body, + this.props.storagePath + ) + const files = [this.getCodeThemeLink(codeBlockTheme), ...CSS_FILES] files.forEach(file => { if (global.process.platform === 'win32') { file = file.replace('file:///', '') @@ -580,6 +560,7 @@ export default class MarkdownPreview extends React.Component { if ( prevProps.smartQuotes !== this.props.smartQuotes || prevProps.sanitize !== this.props.sanitize || + prevProps.mermaidHTMLLabel !== this.props.mermaidHTMLLabel || prevProps.smartArrows !== this.props.smartArrows || prevProps.breaks !== this.props.breaks || prevProps.lineThroughCheckbox !== this.props.lineThroughCheckbox @@ -657,7 +638,7 @@ export default class MarkdownPreview extends React.Component { this.getWindow().document.getElementById( 'codeTheme' - ).href = this.GetCodeThemeLink(codeBlockTheme) + ).href = this.getCodeThemeLink(codeBlockTheme) this.getWindow().document.getElementById('style').innerHTML = buildStyle( fontFamily, fontSize, @@ -670,14 +651,12 @@ export default class MarkdownPreview extends React.Component { ) } - GetCodeThemeLink (name) { + getCodeThemeLink (name) { const theme = consts.THEMES.find(theme => theme.name === name) - if (theme) { - return `${appPath}/${theme.path}` - } else { - return `${appPath}/node_modules/codemirror/theme/elegant.css` - } + return theme != null + ? theme.path + : `${appPath}/node_modules/codemirror/theme/elegant.css` } rewriteIframe () { @@ -703,7 +682,8 @@ export default class MarkdownPreview extends React.Component { showCopyNotification, storagePath, noteKey, - sanitize + sanitize, + mermaidHTMLLabel } = this.props let { value, codeBlockTheme } = this.props @@ -845,7 +825,7 @@ export default class MarkdownPreview extends React.Component { _.forEach( this.refs.root.contentWindow.document.querySelectorAll('.mermaid'), el => { - mermaidRender(el, htmlTextHelper.decodeEntities(el.innerHTML), theme) + mermaidRender(el, htmlTextHelper.decodeEntities(el.innerHTML), theme, mermaidHTMLLabel) } ) diff --git a/browser/components/MarkdownSplitEditor.js b/browser/components/MarkdownSplitEditor.js index 2b63d345..b283228c 100644 --- a/browser/components/MarkdownSplitEditor.js +++ b/browser/components/MarkdownSplitEditor.js @@ -150,7 +150,6 @@ class MarkdownSplitEditor extends React.Component { onMouseMove={e => this.handleMouseMove(e)} onMouseUp={e => this.handleMouseUp(e)}> ( ) diff --git a/browser/components/NoteItem.js b/browser/components/NoteItem.js index 625bb38d..9ef691da 100644 --- a/browser/components/NoteItem.js +++ b/browser/components/NoteItem.js @@ -148,15 +148,14 @@ NoteItem.propTypes = { tags: PropTypes.array, isStarred: PropTypes.bool.isRequired, isTrashed: PropTypes.bool.isRequired, - blog: { + blog: PropTypes.shape({ blogLink: PropTypes.string, blogId: PropTypes.number - } + }) }), handleNoteClick: PropTypes.func.isRequired, handleNoteContextMenu: PropTypes.func.isRequired, - handleDragStart: PropTypes.func.isRequired, - handleDragEnd: PropTypes.func.isRequired + handleDragStart: PropTypes.func.isRequired } export default CSSModules(NoteItem, styles) diff --git a/browser/components/SideNavFilter.js b/browser/components/SideNavFilter.js index 3a259ce7..5d5d627f 100644 --- a/browser/components/SideNavFilter.js +++ b/browser/components/SideNavFilter.js @@ -74,7 +74,7 @@ SideNavFilter.propTypes = { isStarredActive: PropTypes.bool.isRequired, isTrashedActive: PropTypes.bool.isRequired, handleStarredButtonClick: PropTypes.func.isRequired, - handleTrashdButtonClick: PropTypes.func.isRequired + handleTrashedButtonClick: PropTypes.func.isRequired } export default CSSModules(SideNavFilter, styles) diff --git a/browser/components/SnippetTab.js b/browser/components/SnippetTab.js index c030351f..d29130c7 100644 --- a/browser/components/SnippetTab.js +++ b/browser/components/SnippetTab.js @@ -114,7 +114,7 @@ class SnippetTab extends React.Component { > {snippet.name.trim().length > 0 ? snippet.name - : + : {i18n.__('Unnamed')} } diff --git a/browser/components/TodoProcess.js b/browser/components/TodoProcess.js index 251fd5b9..9d1f93cf 100644 --- a/browser/components/TodoProcess.js +++ b/browser/components/TodoProcess.js @@ -25,10 +25,10 @@ const TodoProcess = ({ ) TodoProcess.propTypes = { - todoStatus: { + todoStatus: PropTypes.exact({ total: PropTypes.number.isRequired, completed: PropTypes.number.isRequired - } + }) } export default CSSModules(TodoProcess, styles) diff --git a/browser/components/render/MermaidRender.js b/browser/components/render/MermaidRender.js index e28e06ea..d9ea549b 100644 --- a/browser/components/render/MermaidRender.js +++ b/browser/components/render/MermaidRender.js @@ -19,7 +19,7 @@ function getId () { return id } -function render (element, content, theme) { +function render (element, content, theme, enableHTMLLabel) { try { const height = element.attributes.getNamedItem('data-height') if (height && height.value !== 'undefined') { @@ -29,7 +29,8 @@ function render (element, content, theme) { mermaidAPI.initialize({ theme: isDarkTheme ? 'dark' : 'default', themeCSS: isDarkTheme ? darkThemeStyling : '', - useMaxWidth: false + useMaxWidth: false, + flowchart: { htmlLabels: enableHTMLLabel } }) mermaidAPI.render(getId(), content, (svgGraph) => { element.innerHTML = svgGraph diff --git a/browser/lib/consts.js b/browser/lib/consts.js index 9c993055..ed497376 100644 --- a/browser/lib/consts.js +++ b/browser/lib/consts.js @@ -7,6 +7,7 @@ const CODEMIRROR_THEME_PATH = 'node_modules/codemirror/theme' const CODEMIRROR_EXTRA_THEME_PATH = 'extra_scripts/codemirror/theme' const isProduction = process.env.NODE_ENV === 'production' + const paths = [ isProduction ? path.join(app.getAppPath(), CODEMIRROR_THEME_PATH) : path.resolve(CODEMIRROR_THEME_PATH), isProduction ? path.join(app.getAppPath(), CODEMIRROR_EXTRA_THEME_PATH) : path.resolve(CODEMIRROR_EXTRA_THEME_PATH) @@ -18,7 +19,7 @@ const themes = paths return { name, - path: path.join(directory.split(/\//g).slice(-3).join('/'), file), + path: path.join(directory, file), className: `cm-s-${name}` } })) @@ -27,17 +28,16 @@ const themes = paths themes.splice(themes.findIndex(({ name }) => name === 'solarized'), 1, { name: 'solarized dark', - path: `${CODEMIRROR_THEME_PATH}/solarized.css`, + path: path.join(paths[0], 'solarized.css'), className: `cm-s-solarized cm-s-dark` }, { name: 'solarized light', - path: `${CODEMIRROR_THEME_PATH}/solarized.css`, + path: path.join(paths[0], 'solarized.css'), className: `cm-s-solarized cm-s-light` }) - themes.splice(0, 0, { name: 'default', - path: `${CODEMIRROR_THEME_PATH}/elegant.css`, + path: path.join(paths[0], 'elegant.css'), className: `cm-s-default` }) diff --git a/browser/lib/contextMenuBuilder.js b/browser/lib/contextMenuBuilder.js index cf92f52e..ff3349eb 100644 --- a/browser/lib/contextMenuBuilder.js +++ b/browser/lib/contextMenuBuilder.js @@ -1,6 +1,12 @@ +import i18n from 'browser/lib/i18n' +import fs from 'fs' + const {remote} = require('electron') const {Menu} = remote.require('electron') +const {clipboard} = remote.require('electron') +const {shell} = remote.require('electron') const spellcheck = require('./spellcheck') +const uri2path = require('file-uri-to-path') /** * Creates the context menu that is shown when there is a right click in the editor of a (not-snippet) note. @@ -62,4 +68,57 @@ const buildEditorContextMenu = function (editor, event) { return Menu.buildFromTemplate(template) } -module.exports = buildEditorContextMenu +/** + * Creates the context menu that is shown when there is a right click Markdown preview of a (not-snippet) note. + * @param {MarkdownPreview} markdownPreview + * @param {MouseEvent} event that has triggered the creation of the context menu + * @returns {Electron.Menu} The created electron context menu + */ +const buildMarkdownPreviewContextMenu = function (markdownPreview, event) { + if (markdownPreview == null || event == null || event.pageX == null || event.pageY == null) { + return null + } + + // Default context menu inclusions + const template = [{ + role: 'copy' + }, { + role: 'selectall' + }] + + if (event.target.tagName.toLowerCase() === 'a' && event.target.getAttribute('href')) { + // Link opener for files on the local system pointed to by href + const href = event.target.href + const isLocalFile = href.startsWith('file:') + if (isLocalFile) { + const absPath = uri2path(href) + try { + if (fs.lstatSync(absPath).isFile()) { + template.push( + { + label: i18n.__('Show in explorer'), + click: (e) => shell.showItemInFolder(absPath) + } + ) + } + } catch (e) { + console.log('Error while evaluating if the file is locally available', e) + } + } + + // Add option to context menu to copy url + template.push( + { + label: i18n.__('Copy Url'), + click: (e) => clipboard.writeText(href) + } + ) + } + return Menu.buildFromTemplate(template) +} + +module.exports = +{ + buildEditorContextMenu: buildEditorContextMenu, + buildMarkdownPreviewContextMenu: buildMarkdownPreviewContextMenu +} diff --git a/browser/lib/customMeta.js b/browser/lib/customMeta.js index 0d4ee1e3..b890cf55 100644 --- a/browser/lib/customMeta.js +++ b/browser/lib/customMeta.js @@ -1,5 +1,10 @@ import CodeMirror from 'codemirror' import 'codemirror-mode-elixir' -CodeMirror.modeInfo.push({name: 'Stylus', mime: 'text/x-styl', mode: 'stylus', ext: ['styl'], alias: ['styl']}) +const stylusCodeInfo = CodeMirror.modeInfo.find(info => info.name === 'Stylus') +if (stylusCodeInfo == null) { + CodeMirror.modeInfo.push({name: 'Stylus', mime: 'text/x-styl', mode: 'stylus', ext: ['styl'], alias: ['styl']}) +} else { + stylusCodeInfo.alias = ['styl'] +} CodeMirror.modeInfo.push({name: 'Elixir', mime: 'text/x-elixir', mode: 'elixir', ext: ['ex']}) diff --git a/browser/lib/markdown-it-sanitize-html.js b/browser/lib/markdown-it-sanitize-html.js index 8f6d86a8..3325604a 100644 --- a/browser/lib/markdown-it-sanitize-html.js +++ b/browser/lib/markdown-it-sanitize-html.js @@ -15,7 +15,7 @@ module.exports = function sanitizePlugin (md, options) { options ) } - if (state.tokens[tokenIdx].type === '_fence') { + if (state.tokens[tokenIdx].type.match(/.*_fence$/)) { // escapeHtmlCharacters has better performance state.tokens[tokenIdx].content = escapeHtmlCharacters( state.tokens[tokenIdx].content, diff --git a/browser/lib/markdown.js b/browser/lib/markdown.js index 5fd7c85c..49183442 100644 --- a/browser/lib/markdown.js +++ b/browser/lib/markdown.js @@ -2,6 +2,7 @@ import markdownit from 'markdown-it' import sanitize from './markdown-it-sanitize-html' import emoji from 'markdown-it-emoji' import math from '@rokt33r/markdown-it-math' +import mdurl from 'mdurl' import smartArrows from 'markdown-it-smartarrows' import _ from 'lodash' import ConfigManager from 'browser/main/lib/ConfigManager' @@ -150,9 +151,9 @@ class Markdown { const content = token.content.split('\n').slice(0, -1).map(line => { const match = /!\[[^\]]*]\(([^\)]*)\)/.exec(line) if (match) { - return match[1] + return mdurl.encode(match[1]) } else { - return line + return mdurl.encode(line) } }).join('\n') @@ -288,7 +289,9 @@ class Markdown { case 'list_item_open': case 'paragraph_open': case 'table_open': - token.attrPush(['data-line', token.map[0]]) + if (token.map) { + token.attrPush(['data-line', token.map[0]]) + } } }) const result = originalRender.call(this.md.renderer, tokens, options, env) diff --git a/browser/main/Detail/FullscreenButton.js b/browser/main/Detail/FullscreenButton.js index bd76447c..eb33165f 100644 --- a/browser/main/Detail/FullscreenButton.js +++ b/browser/main/Detail/FullscreenButton.js @@ -11,7 +11,7 @@ const FullscreenButton = ({ const hotkey = (OSX ? i18n.__('Command(⌘)') : i18n.__('Ctrl(^)')) + '+B' return ( ) diff --git a/browser/main/Detail/InfoPanel.js b/browser/main/Detail/InfoPanel.js index 8fe0a855..86b5ae86 100644 --- a/browser/main/Detail/InfoPanel.js +++ b/browser/main/Detail/InfoPanel.js @@ -60,7 +60,7 @@ class InfoPanel extends React.Component {
- { e.target.select() }} /> + { e.target.select() }} /> diff --git a/browser/main/Detail/MarkdownNoteDetail.js b/browser/main/Detail/MarkdownNoteDetail.js index 2e61b365..a826f3e8 100755 --- a/browser/main/Detail/MarkdownNoteDetail.js +++ b/browser/main/Detail/MarkdownNoteDetail.js @@ -311,7 +311,7 @@ class MarkdownNoteDetail extends React.Component { } getToggleLockButton () { - return this.state.isLocked ? '../resources/icon/icon-previewoff-on.svg' : '../resources/icon/icon-previewoff-off.svg' + return this.state.isLocked ? '../resources/icon/icon-lock.svg' : '../resources/icon/icon-unlock.svg' } handleDeleteKeyDown (e) { @@ -450,7 +450,7 @@ class MarkdownNoteDetail extends React.Component { const detailTopBar =
-
+
this.handleFocus(e)} onMouseDown={(e) => this.handleLockButtonMouseDown(e)} > - + {this.state.isLocked ? Unlock : Lock} diff --git a/browser/main/Detail/PermanentDeleteButton.js b/browser/main/Detail/PermanentDeleteButton.js index fa00ef17..7c27ede1 100644 --- a/browser/main/Detail/PermanentDeleteButton.js +++ b/browser/main/Detail/PermanentDeleteButton.js @@ -10,7 +10,7 @@ const PermanentDeleteButton = ({ ) diff --git a/browser/main/Detail/SnippetNoteDetail.js b/browser/main/Detail/SnippetNoteDetail.js index 7503addb..2ae01082 100644 --- a/browser/main/Detail/SnippetNoteDetail.js +++ b/browser/main/Detail/SnippetNoteDetail.js @@ -518,6 +518,19 @@ class SnippetNoteDetail extends React.Component { ]) } + handleWrapLineButtonClick (e) { + context.popup([ + { + label: 'on', + click: (e) => this.handleWrapLineItemClick(e, true) + }, + { + label: 'off', + click: (e) => this.handleWrapLineItemClick(e, false) + } + ]) + } + handleIndentSizeItemClick (e, indentSize) { const { config, dispatch } = this.props const editor = Object.assign({}, config.editor, { @@ -550,6 +563,22 @@ class SnippetNoteDetail extends React.Component { }) } + handleWrapLineItemClick (e, lineWrapping) { + const { config, dispatch } = this.props + const editor = Object.assign({}, config.editor, { + lineWrapping + }) + ConfigManager.set({ + editor + }) + dispatch({ + type: 'SET_CONFIG', + config: { + editor + } + }) + } + focus () { this.refs.description.focus() } @@ -720,6 +749,7 @@ class SnippetNoteDetail extends React.Component { mode={snippet.mode || (autoDetect ? null : config.editor.snippetDefaultLanguage)} value={snippet.content} linesHighlighted={snippet.linesHighlighted} + lineWrapping={config.editor.lineWrapping} theme={config.editor.theme} fontFamily={config.editor.fontFamily} fontSize={editorFontSize} @@ -778,7 +808,7 @@ class SnippetNoteDetail extends React.Component { const detailTopBar =
-
+
+
(
-
onClick('SPLIT')}> - +
onClick('SPLIT')}> +
-
onClick('EDITOR_PREVIEW')}> - +
onClick('EDITOR_PREVIEW')}> +
{i18n.__('Toggle Mode')}
@@ -20,7 +20,7 @@ const ToggleModeButton = ({ ToggleModeButton.propTypes = { onClick: PropTypes.func.isRequired, - editorType: PropTypes.string.Required + editorType: PropTypes.string.isRequired } export default CSSModules(ToggleModeButton, styles) diff --git a/browser/main/Detail/TrashButton.js b/browser/main/Detail/TrashButton.js index d26be66e..8ca27ce9 100644 --- a/browser/main/Detail/TrashButton.js +++ b/browser/main/Detail/TrashButton.js @@ -10,7 +10,7 @@ const TrashButton = ({ ) diff --git a/browser/main/DevTools/index.js b/browser/main/DevTools/index.js index 93d666a2..d39d5fbb 100644 --- a/browser/main/DevTools/index.js +++ b/browser/main/DevTools/index.js @@ -1,8 +1,8 @@ /* eslint-disable no-undef */ -if (process.env.NODE_ENV === 'production') { - // eslint-disable-next-line global-require - module.exports = require('./index.prod').default -} else { +if (process.env.NODE_ENV === 'development') { // eslint-disable-next-line global-require module.exports = require('./index.dev').default +} else { + // eslint-disable-next-line global-require + module.exports = require('./index.prod').default } diff --git a/browser/main/NewNoteButton/index.js b/browser/main/NewNoteButton/index.js index 115d9530..27e2baa5 100644 --- a/browser/main/NewNoteButton/index.js +++ b/browser/main/NewNoteButton/index.js @@ -90,7 +90,7 @@ class NewNoteButton extends React.Component {
diff --git a/browser/main/SideNav/PreferenceButton.js b/browser/main/SideNav/PreferenceButton.js index 187171f4..187bc41a 100644 --- a/browser/main/SideNav/PreferenceButton.js +++ b/browser/main/SideNav/PreferenceButton.js @@ -8,7 +8,7 @@ const PreferenceButton = ({ onClick }) => ( ) diff --git a/browser/main/SideNav/StorageItem.js b/browser/main/SideNav/StorageItem.js index 74881b9e..5cd4a491 100644 --- a/browser/main/SideNav/StorageItem.js +++ b/browser/main/SideNav/StorageItem.js @@ -362,14 +362,14 @@ class StorageItem extends React.Component { }
{this.state.isOpen && -
+
{folderList}
} diff --git a/browser/main/SideNav/index.js b/browser/main/SideNav/index.js index fc665052..9d18a72c 100644 --- a/browser/main/SideNav/index.js +++ b/browser/main/SideNav/index.js @@ -440,7 +440,7 @@ class SideNav extends React.Component { const style = {} if (!isFolded) style.width = this.props.width - const isTagActive = location.pathname.match(/tag/) + const isTagActive = /tag/.test(location.pathname) return (
theme.name === config.editor.theme) if (theme) { - editorTheme.setAttribute('href', `../${theme.path}`) + editorTheme.setAttribute('href', theme.path) } else { config.editor.theme = 'default' } @@ -152,7 +156,13 @@ function get () { function set (updates) { const currentConfig = get() - const newConfig = Object.assign({}, DEFAULT_CONFIG, currentConfig, updates) + + const arrangedUpdates = updates + if (updates.preview !== undefined && updates.preview.customCSS === '') { + arrangedUpdates.preview.customCSS = DEFAULT_CONFIG.preview.customCSS + } + + const newConfig = Object.assign({}, DEFAULT_CONFIG, currentConfig, arrangedUpdates) if (!validate(newConfig)) throw new Error('INVALID CONFIG') _save(newConfig) @@ -183,7 +193,7 @@ function set (updates) { const newTheme = consts.THEMES.find(theme => theme.name === newConfig.editor.theme) if (newTheme) { - editorTheme.setAttribute('href', `../${newTheme.path}`) + editorTheme.setAttribute('href', newTheme.path) } ipcRenderer.send('config-renew', { diff --git a/browser/main/lib/dataApi/attachmentManagement.js b/browser/main/lib/dataApi/attachmentManagement.js index d92a1eb4..725bdc11 100644 --- a/browser/main/lib/dataApi/attachmentManagement.js +++ b/browser/main/lib/dataApi/attachmentManagement.js @@ -241,6 +241,10 @@ function migrateAttachments (markdownContent, storagePath, noteKey) { * @returns {String} postprocessed HTML in which all :storage references are mapped to the actual paths. */ function fixLocalURLS (renderedHTML, storagePath) { + const encodedWin32SeparatorRegex = /%5C/g + const storageRegex = new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER, 'g') + const storageUrl = 'file:///' + path.join(storagePath, DESTINATION_FOLDER).replace(/\\/g, '/') + /* A :storage reference is like `:storage/3b6f8bd6-4edd-4b15-96e0-eadc4475b564/f939b2c3.jpg`. @@ -250,8 +254,7 @@ function fixLocalURLS (renderedHTML, storagePath) { - `(?:\\\/|%5C)` match the path seperator. `\\\/` for posix systems and `%5C` for windows. */ return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '(?:(?:\\\/|%5C)[-.\\w]+)+', 'g'), function (match) { - var encodedPathSeparators = new RegExp(mdurl.encode(path.win32.sep) + '|' + mdurl.encode(path.posix.sep), 'g') - return match.replace(encodedPathSeparators, path.sep).replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER, 'g'), 'file:///' + path.join(storagePath, DESTINATION_FOLDER)) + return match.replace(encodedWin32SeparatorRegex, '/').replace(storageRegex, storageUrl) }) } @@ -617,8 +620,6 @@ function deleteAttachmentsNotPresentInNote (markdownContent, storageKey, noteKey } }) }) - } else { - console.info('Attachment folder ("' + attachmentFolder + '") did not exist..') } } diff --git a/browser/main/modals/NewNoteModal.styl b/browser/main/modals/NewNoteModal.styl index b79c2501..ff0052bd 100644 --- a/browser/main/modals/NewNoteModal.styl +++ b/browser/main/modals/NewNoteModal.styl @@ -19,6 +19,7 @@ .control padding 25px 0px text-align center + display: flex .control-button width 240px diff --git a/browser/main/modals/PreferencesModal/FolderItem.js b/browser/main/modals/PreferencesModal/FolderItem.js index e6bd1e37..648db4e6 100644 --- a/browser/main/modals/PreferencesModal/FolderItem.js +++ b/browser/main/modals/PreferencesModal/FolderItem.js @@ -225,7 +225,7 @@ class FolderItem extends React.Component {
- {folder.name} + {folder.name} ({folder.key})
@@ -288,10 +288,10 @@ class Handle extends React.Component { class SortableFolderItemComponent extends React.Component { render () { - const StyledHandle = CSSModules(Handle, this.props.styles) + const StyledHandle = CSSModules(Handle, styles) const DragHandle = SortableHandle(StyledHandle) - const StyledFolderItem = CSSModules(FolderItem, this.props.styles) + const StyledFolderItem = CSSModules(FolderItem, styles) return (
diff --git a/browser/main/modals/PreferencesModal/FolderList.js b/browser/main/modals/PreferencesModal/FolderList.js index 02f5cee9..674026c5 100644 --- a/browser/main/modals/PreferencesModal/FolderList.js +++ b/browser/main/modals/PreferencesModal/FolderList.js @@ -22,7 +22,7 @@ class FolderList extends React.Component { }) return ( -
+
{folderList.length > 0 ? folderList :
{i18n.__('No Folders')}
diff --git a/browser/main/modals/PreferencesModal/HotkeyTab.js b/browser/main/modals/PreferencesModal/HotkeyTab.js index 713f6a65..2c528fba 100644 --- a/browser/main/modals/PreferencesModal/HotkeyTab.js +++ b/browser/main/modals/PreferencesModal/HotkeyTab.js @@ -173,6 +173,26 @@ class HotkeyTab extends React.Component { />
+
+
{i18n.__('Insert Current Date')}
+
+ +
+
+
+
{i18n.__('Insert Current Date and Time')}
+
+ +
+
+
+ +
+
+
+ +
{i18n.__('LaTeX Inline Open Delimiter')} @@ -883,7 +907,6 @@ class UiTab extends React.Component { onChange={e => this.handleUIChange(e)} ref={e => (this.customCSSCM = e)} value={config.preview.customCSS} - defaultValue={'/* Drop Your Custom CSS Code Here */\n'} options={{ lineNumbers: true, mode: 'css', diff --git a/browser/main/modals/PreferencesModal/index.js b/browser/main/modals/PreferencesModal/index.js index f3fc3751..86957083 100644 --- a/browser/main/modals/PreferencesModal/index.js +++ b/browser/main/modals/PreferencesModal/index.js @@ -147,7 +147,7 @@ class Preferences extends React.Component { key={tab.target} onClick={(e) => this.handleNavButtonClick(tab.target)(e)} > - + {tab.label} {isUiHotkeyTab ? this.haveToSaveNotif(tab[tab.label].type, tab[tab.label].message) : null} diff --git a/browser/main/store.js b/browser/main/store.js index c708c3ad..d48198a7 100644 --- a/browser/main/store.js +++ b/browser/main/store.js @@ -476,7 +476,8 @@ const reducer = combineReducers({ router: connectRouter(history) }) -const store = createStore(reducer, undefined, compose( - applyMiddleware(routerMiddleware(history)), DevTools.instrument())) +const store = createStore(reducer, undefined, process.env.NODE_ENV === 'development' + ? compose(applyMiddleware(routerMiddleware(history)), DevTools.instrument()) + : applyMiddleware(routerMiddleware(history))) export { store, history } diff --git a/lib/main-menu.js b/lib/main-menu.js index f20f1e90..124c6675 100644 --- a/lib/main-menu.js +++ b/lib/main-menu.js @@ -3,6 +3,7 @@ const BrowserWindow = electron.BrowserWindow const shell = electron.shell const ipc = electron.ipcMain const mainWindow = require('./main-window') +const os = require('os') const macOS = process.platform === 'darwin' // const WIN = process.platform === 'win32' @@ -411,6 +412,28 @@ const help = { click () { shell.openExternal('https://github.com/TobseF/boostnote-markdown-cheatsheet/blob/master/BOOSTNOTE_MARKDOWN_CHEAT_SHEET.md') } } ] + }, + { + type: 'separator' + }, + { + label: 'About', + click () { + const version = electron.app.getVersion() + const electronVersion = process.versions.electron + const chromeVersion = process.versions.chrome + const nodeVersion = process.versions.node + const v8Version = process.versions.v8 + const OSInfo = `${os.type()} ${os.arch()} ${os.release()}` + const detail = `Version: ${version}\nElectron: ${electronVersion}\nChrome: ${chromeVersion}\nNode.js: ${nodeVersion}\nV8: ${v8Version}\nOS: ${OSInfo}` + electron.dialog.showMessageBox(BrowserWindow.getFocusedWindow(), + { + title: 'BoostNote', + message: 'BoostNote', + type: 'info', + detail: `\n${detail}` + }) + } } ] } diff --git a/lib/main-window.js b/lib/main-window.js index e650cb92..515dc8b4 100644 --- a/lib/main-window.js +++ b/lib/main-window.js @@ -54,7 +54,7 @@ const mainWindow = new BrowserWindow({ }, icon: path.resolve(__dirname, '../resources/app.png') }) -const url = path.resolve(__dirname, process.env.NODE_ENV === 'production' ? './main.production.html' : './main.development.html') +const url = path.resolve(__dirname, process.env.NODE_ENV === 'development' ? './main.development.html' : './main.production.html') mainWindow.loadURL('file://' + url) mainWindow.setMenuBarVisibility(false) diff --git a/lib/main.development.html b/lib/main.development.html index 38e2cea9..cbcda295 100644 --- a/lib/main.development.html +++ b/lib/main.development.html @@ -110,7 +110,6 @@ - diff --git a/lib/main.production.html b/lib/main.production.html index ffd9eec3..cab38981 100644 --- a/lib/main.production.html +++ b/lib/main.production.html @@ -105,7 +105,6 @@ - diff --git a/locales/da.json b/locales/da.json index 79503ab3..38a8fbeb 100644 --- a/locales/da.json +++ b/locales/da.json @@ -156,5 +156,7 @@ "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠", "Spellcheck disabled": "Spellcheck disabled", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/de.json b/locales/de.json index 518a4e65..cac158c5 100644 --- a/locales/de.json +++ b/locales/de.json @@ -212,5 +212,7 @@ "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠", "Spellcheck disabled": "Spellcheck disabled", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/en.json b/locales/en.json index 1e09bfc7..a10f3be9 100644 --- a/locales/en.json +++ b/locales/en.json @@ -187,5 +187,7 @@ "Snippet Default Language": "Snippet Default Language", "New notes are tagged with the filtering tags": "New notes are tagged with the filtering tags", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/es-ES.json b/locales/es-ES.json index f8003088..56945819 100644 --- a/locales/es-ES.json +++ b/locales/es-ES.json @@ -158,5 +158,7 @@ "Spellcheck disabled": "Deshabilitar corrector ortográfico", "Show menu bar": "Mostrar barra del menú", "Auto Detect": "Detección automática", - "Snippet Default Language": "Lenguaje por defecto de los fragmentos de código" + "Snippet Default Language": "Lenguaje por defecto de los fragmentos de código", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/fa.json b/locales/fa.json index d29e0e75..784c4864 100644 --- a/locales/fa.json +++ b/locales/fa.json @@ -160,5 +160,7 @@ "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠", "Spellcheck disabled": "Spellcheck disabled", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/fr.json b/locales/fr.json index c44b057e..698d4791 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -172,5 +172,7 @@ "Snippet name": "Nom du snippet", "Snippet prefix": "Préfixe du snippet", "Delete Note": "Supprimer la note", - "New notes are tagged with the filtering tags": "Les nouvelles notes sont taggées avec les tags de filtrage" + "New notes are tagged with the filtering tags": "Les nouvelles notes sont taggées avec les tags de filtrage", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/hu.json b/locales/hu.json index 558770b9..97b92212 100644 --- a/locales/hu.json +++ b/locales/hu.json @@ -180,5 +180,7 @@ "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠", "Spellcheck disabled": "Spellcheck disabled", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/it.json b/locales/it.json index 3b070197..26eafff1 100644 --- a/locales/it.json +++ b/locales/it.json @@ -160,5 +160,7 @@ "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠", "Spellcheck disabled": "Spellcheck disabled", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/ja.json b/locales/ja.json index e1dc553b..390386d4 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -219,5 +219,7 @@ "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ このノートのストレージに存在しない添付ファイルへのリンクを貼り付けました。添付ファイルへのリンクの貼り付けは同一ストレージ内でのみサポートされています。代わりに添付ファイルをドラッグアンドドロップしてください! ⚠", "Spellcheck disabled": "スペルチェック無効", "Show menu bar": "メニューバーを表示", - "Auto Detect": "自動検出" + "Auto Detect": "自動検出", + "Enable HTML label in mermaid flowcharts": "mermaid flowchartでHTMLラベルを有効にする ⚠ このオプションには潜在的なXSSの危険性があります。", + "Wrap line in Snippet Note": "行を右端で折り返す(Snippet Note)" } diff --git a/locales/ko.json b/locales/ko.json index 3dbb1ada..b6bd75be 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -163,5 +163,7 @@ "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠", "Spellcheck disabled": "Spellcheck disabled", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/no.json b/locales/no.json index ff858153..fa018e86 100644 --- a/locales/no.json +++ b/locales/no.json @@ -156,5 +156,7 @@ "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠", "Spellcheck disabled": "Spellcheck disabled", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/pl.json b/locales/pl.json index ffdc14be..c289ef23 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -165,5 +165,7 @@ "Add tag...": "Dodaj tag...", "Spellcheck disabled": "Spellcheck disabled", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/pt-BR.json b/locales/pt-BR.json index ada02453..0005a44e 100644 --- a/locales/pt-BR.json +++ b/locales/pt-BR.json @@ -156,5 +156,7 @@ "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠", "Spellcheck disabled": "Spellcheck disabled", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/pt-PT.json b/locales/pt-PT.json index 159c2255..677cce4d 100644 --- a/locales/pt-PT.json +++ b/locales/pt-PT.json @@ -155,5 +155,7 @@ "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ Você colou um link referente a um anexo que não pôde ser encontrado no local de armazenamento desta nota. A vinculação de anexos de referência de links só é suportada se o local de origem e de destino for o mesmo de armazenamento. Por favor, arraste e solte o anexo na nota! ⚠", "Spellcheck disabled": "Spellcheck disabled", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/ru.json b/locales/ru.json index 70d140ce..990374ef 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -153,5 +153,7 @@ "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠", "Spellcheck disabled": "Spellcheck disabled", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/sq.json b/locales/sq.json index 33d8ec97..dec7402f 100644 --- a/locales/sq.json +++ b/locales/sq.json @@ -155,5 +155,7 @@ "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠", "Spellcheck disabled": "Spellcheck disabled", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/th.json b/locales/th.json index ade52990..1f06ceb6 100644 --- a/locales/th.json +++ b/locales/th.json @@ -182,5 +182,7 @@ "Snippet Default Language": "ทำการ Snippet ภาษาที่เป็นค่าเริ่มต้น", "Spellcheck disabled": "Spellcheck disabled", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/tr.json b/locales/tr.json index d9dd28f1..78038402 100644 --- a/locales/tr.json +++ b/locales/tr.json @@ -155,5 +155,7 @@ "Allow dangerous html tags": "Tehlikeli html etiketlerine izin ver", "Spellcheck disabled": "Spellcheck disabled", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/zh-CN.json b/locales/zh-CN.json old mode 100755 new mode 100644 index 76700a7f..581e38d6 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -220,5 +220,7 @@ "Render newlines in Markdown paragraphs as
":"在 Markdown 段落中使用
换行", "Spellcheck disabled": "Spellcheck disabled", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/locales/zh-TW.json b/locales/zh-TW.json old mode 100755 new mode 100644 index ec6fa80c..33b71699 --- a/locales/zh-TW.json +++ b/locales/zh-TW.json @@ -164,5 +164,7 @@ "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠", "Spellcheck disabled": "Spellcheck disabled", "Show menu bar": "Show menu bar", - "Auto Detect": "Auto Detect" + "Auto Detect": "Auto Detect", + "Enable HTML label in mermaid flowcharts": "Enable HTML label in mermaid flowcharts ⚠ This option potentially has a risk of XSS.", + "Wrap line in Snippet Note": "Wrap line in Snippet Note" } diff --git a/package.json b/package.json index 1f327874..e5c78247 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "boost", "productName": "Boostnote", - "version": "0.11.17", + "version": "0.12.1", "main": "index.js", "description": "Boostnote", "license": "GPL-3.0", diff --git a/tests/dataApi/attachmentManagement.test.js b/tests/dataApi/attachmentManagement.test.js index 800159b8..0f420bcc 100644 --- a/tests/dataApi/attachmentManagement.test.js +++ b/tests/dataApi/attachmentManagement.test.js @@ -287,7 +287,11 @@ it('should replace the all ":storage" path with the actual storage path', functi '

\n' + '
\n' +
     '            \n' +
-    '            \n' +
+    '            \n' +
+    '        
\n' + + '
\n' +
+    '            \n' +
+    '            \n' +
     '        
\n' + ' \n' + '' @@ -300,17 +304,21 @@ it('should replace the all ":storage" path with the actual storage path', functi ' \n' + '

Headline

\n' + '

\n' + - ' dummyImage.png\n' + + ' dummyImage.png\n' + '

\n' + '

\n' + - ' dummyPDF.pdf\n' + + ' dummyPDF.pdf\n' + '

\n' + '

\n' + - ' dummyImage2.jpg\n' + + ' dummyImage2.jpg\n' + '

\n' + '
\n' +
     '            \n' +
-    '            \n' +
+    '            \n' +
+    '        
\n' + + '
\n' +
+    '            \n' +
+    '            \n' +
     '        
\n' + ' \n' + '' @@ -345,10 +353,10 @@ it('should replace the ":storage" path with the actual storage path when they ha ' \n' + '

Headline

\n' + '

\n' + - ' dummyImage.png\n' + + ' dummyImage.png\n' + '

\n' + '

\n' + - ' dummyPDF.pdf\n' + + ' dummyPDF.pdf\n' + '

\n' + ' \n' + '' diff --git a/tests/dataApi/copyFile-test.js b/tests/dataApi/copyFile-test.js index 412d510a..533b1354 100644 --- a/tests/dataApi/copyFile-test.js +++ b/tests/dataApi/copyFile-test.js @@ -3,6 +3,9 @@ const copyFile = require('browser/main/lib/dataApi/copyFile') const path = require('path') const fs = require('fs') +const os = require('os') +const execSync = require('child_process').execSync +const removeDirCommand = os.platform() === 'win32' ? 'rmdir /s /q ' : 'rm -rf ' const testFile = 'test.txt' const srcFolder = path.join(__dirname, '🤔') @@ -29,7 +32,7 @@ test('`copyFile` should handle encoded URI on src path', (t) => { test.after((t) => { fs.unlinkSync(srcPath) fs.unlinkSync(dstPath) - fs.rmdirSync(srcFolder) - fs.rmdirSync(dstFolder) + execSync(removeDirCommand + '"' + srcFolder + '"') + execSync(removeDirCommand + '"' + dstFolder + '"') }) diff --git a/tests/fixtures/markdowns.js b/tests/fixtures/markdowns.js index 0ee80909..340f2ddd 100644 --- a/tests/fixtures/markdowns.js +++ b/tests/fixtures/markdowns.js @@ -104,6 +104,11 @@ Term 2 with *inline markup* ` const shortcuts = 'Ctrl\n\n[[Ctrl]]' +const footnote = ` +^[hello-world] +hello-world: https://github.com/BoostIO/Boostnote/ +` + export default { basic, codeblock, @@ -115,5 +120,6 @@ export default { subTexts, supTexts, deflists, - shortcuts + shortcuts, + footnote } diff --git a/tests/lib/contextMenuBuilder.test.js b/tests/lib/contextMenuBuilder.test.js index 12ed2c32..b7009bf1 100644 --- a/tests/lib/contextMenuBuilder.test.js +++ b/tests/lib/contextMenuBuilder.test.js @@ -4,12 +4,14 @@ jest.mock('electron', () => { }) const spellcheck = require('browser/lib/spellcheck') -const buildEditorContextMenu = require('browser/lib/contextMenuBuilder') +const buildEditorContextMenu = require('browser/lib/contextMenuBuilder').buildEditorContextMenu +const buildMarkdownPreviewContextMenu = require('browser/lib/contextMenuBuilder').buildMarkdownPreviewContextMenu beforeEach(() => { menuBuilderParameter = null }) +// Editor Context Menu it('should make sure that no context menu is build if the passed editor instance was null', function () { const event = { pageX: 12, @@ -124,3 +126,13 @@ it('should make sure that word suggestions creates a correct menu if there was a expect(menuBuilderParameter[7].role).toEqual('selectall') expect(spellcheck.getSpellingSuggestion).toHaveBeenCalledWith(wordToCorrect) }) + +// Markdown Preview Context Menu +it('should make sure that no context menu is built if the Markdown Preview instance was null', function () { + const event = { + pageX: 12, + pageY: 12 + } + buildMarkdownPreviewContextMenu(null, event) + expect(menuBuilderParameter).toEqual(null) +}) diff --git a/tests/lib/markdown-test.js b/tests/lib/markdown-test.js index 46ae5941..31ffc518 100644 --- a/tests/lib/markdown-test.js +++ b/tests/lib/markdown-test.js @@ -68,3 +68,8 @@ test('Markdown.render() should render shortcuts correctly', t => { const rendered = md.render(markdownFixtures.shortcuts) t.snapshot(rendered) }) + +test('Markdown.render() should render footnote correctly', t => { + const rendered = md.render(markdownFixtures.footnote) + t.snapshot(rendered) +}) diff --git a/tests/lib/snapshots/markdown-test.js.md b/tests/lib/snapshots/markdown-test.js.md index 56c4466f..4111c2f2 100644 --- a/tests/lib/snapshots/markdown-test.js.md +++ b/tests/lib/snapshots/markdown-test.js.md @@ -4,6 +4,21 @@ The actual snapshot is saved in `markdown-test.js.snap`. Generated by [AVA](https://ava.li). +## Markdown.render() should render footnote correctly + +> Snapshot 1 + + `

[1]
␊ + hello-world: https://github.com/BoostIO/Boostnote/

␊ +
␊ +
␊ +
    ␊ +
  1. hello-world ↩︎

    ␊ +
  2. ␊ +
␊ +
␊ + ` + ## Markdown.render() should render line breaks correctly > Snapshot 1 diff --git a/tests/lib/snapshots/markdown-test.js.snap b/tests/lib/snapshots/markdown-test.js.snap index 67d43616..3f5ec41c 100644 Binary files a/tests/lib/snapshots/markdown-test.js.snap and b/tests/lib/snapshots/markdown-test.js.snap differ