diff --git a/browser/components/CodeEditor.js b/browser/components/CodeEditor.js index 59782e08..2a4ae71b 100644 --- a/browser/components/CodeEditor.js +++ b/browser/components/CodeEditor.js @@ -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 a407651e..e4c88de9 100755 --- a/browser/components/MarkdownPreview.js +++ b/browser/components/MarkdownPreview.js @@ -41,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, @@ -247,7 +248,11 @@ export default class MarkdownPreview extends React.Component { handleContextMenu (event) { const menu = buildMarkdownPreviewContextMenu(this, event) if (menu != null) { +<<<<<<< HEAD setTimeout(() => menu.popup(remote.getCurrentWindow()), 30) +======= + menu.popup(remote.getCurrentWindow()) +>>>>>>> upstream/master } } @@ -320,7 +325,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:///', '') @@ -555,6 +564,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 @@ -632,7 +642,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, @@ -645,14 +655,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 () { @@ -678,7 +686,8 @@ export default class MarkdownPreview extends React.Component { showCopyNotification, storagePath, noteKey, - sanitize + sanitize, + mermaidHTMLLabel } = this.props let { value, codeBlockTheme } = this.props @@ -820,7 +829,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) } ) @@ -870,6 +879,12 @@ export default class MarkdownPreview extends React.Component { this.setImgOnClickEventHelper(img, rect) imgObserver.observe(parentEl, config) } + + const aList = markdownPreviewIframe.contentWindow.document.body.querySelectorAll('a') + for (const a of aList) { + a.removeEventListener('click', this.linkClickHandler) + a.addEventListener('click', this.linkClickHandler) + } } setImgOnClickEventHelper (img, rect) { @@ -998,11 +1013,11 @@ export default class MarkdownPreview extends React.Component { if (!rawHref) return // not checked href because parser will create file://... string for [empty link]() - const regexNoteInternalLink = /.*[main.\w]*.html#/ - - if (regexNoteInternalLink.test(href)) { - const targetId = mdurl.encode(linkHash) - const targetElement = this.refs.root.contentWindow.document.querySelector( + const extractId = /(main.html)?#/ + const regexNoteInternalLink = new RegExp(`${extractId.source}(.+)`) + if (regexNoteInternalLink.test(linkHash)) { + const targetId = mdurl.encode(linkHash.replace(extractId, '')) + const targetElement = this.refs.root.contentWindow.document.getElementById( targetId ) 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 c46f0dc4..34f84789 100644 --- a/browser/lib/contextMenuBuilder.js +++ b/browser/lib/contextMenuBuilder.js @@ -81,12 +81,17 @@ const buildMarkdownPreviewContextMenu = function (markdownPreview, event) { // Default context menu inclusions const template = [{ +<<<<<<< HEAD role: 'cut' }, { role: 'copy' }, { role: 'paste' }, { +======= + role: 'copy' + }, { +>>>>>>> upstream/master role: 'selectall' }] 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-toc-generator.js b/browser/lib/markdown-toc-generator.js index 8f027247..7c76c1f3 100644 --- a/browser/lib/markdown-toc-generator.js +++ b/browser/lib/markdown-toc-generator.js @@ -21,7 +21,7 @@ function uniqueSlug (slug, slugs, opts) { } function linkify (token) { - token.content = mdlink(token.content, '#' + token.slug) + token.content = mdlink(token.content, `#${decodeURI(token.slug)}`) return token } 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/lib/slugify.js b/browser/lib/slugify.js index a3447a90..21c18e02 100644 --- a/browser/lib/slugify.js +++ b/browser/lib/slugify.js @@ -1,17 +1,11 @@ -import diacritics from 'diacritics-map' - -function replaceDiacritics (str) { - return str.replace(/[À-ž]/g, function (ch) { - return diacritics[ch] || ch - }) -} - module.exports = function slugify (title) { - let slug = title.trim() + const slug = encodeURI( + title.trim() + .replace(/^\s+/, '') + .replace(/\s+$/, '') + .replace(/\s+/g, '-') + .replace(/[\]\[\!\'\#\$\%\&\(\)\*\+\,\.\/\:\;\<\=\>\?\@\\\^\{\|\}\~\`]/g, '') + ) - slug = replaceDiacritics(slug) - - slug = slug.replace(/[^\w\s-]/g, '').replace(/\s+/g, '-') - - return encodeURI(slug).replace(/\-+$/, '') + return slug } 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 06fb91a5..45024751 100755 --- a/browser/main/Detail/MarkdownNoteDetail.js +++ b/browser/main/Detail/MarkdownNoteDetail.js @@ -67,9 +67,6 @@ class MarkdownNoteDetail extends React.Component { }) ee.on('hotkey:deletenote', this.handleDeleteNote.bind(this)) ee.on('code:generate-toc', this.generateToc) - - // Focus content if using blur or double click - if (this.state.switchPreview === 'BLUR' || this.state.switchPreview === 'DBL_CLICK') this.focus() } componentWillReceiveProps (nextProps) { @@ -84,6 +81,20 @@ class MarkdownNoteDetail extends React.Component { if (this.refs.tags) this.refs.tags.reset() }) } + + // Focus content if using blur or double click + // --> Moved here from componentDidMount so a re-render during search won't set focus to the editor + const {switchPreview} = nextProps.config.editor + + if (this.state.switchPreview !== switchPreview) { + this.setState({ + switchPreview + }) + if (switchPreview === 'BLUR' || switchPreview === 'DBL_CLICK') { + console.log('setting focus', switchPreview) + this.focus() + } + } } componentWillUnmount () { @@ -300,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) { @@ -439,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 (
{ this.handleOnSearchFocus() } this.codeInitHandler = this.handleCodeInit.bind(this) - this.updateKeyword = this.updateKeyword.bind(this) + this.handleKeyDown = this.handleKeyDown.bind(this) + this.handleSearchFocus = this.handleSearchFocus.bind(this) + this.handleSearchBlur = this.handleSearchBlur.bind(this) + this.handleSearchChange = this.handleSearchChange.bind(this) this.handleSearchClearButton = this.handleSearchClearButton.bind(this) - this.updateKeyword = debounce(this.updateKeyword, 1000 / 60, { + this.debouncedUpdateKeyword = debounce((keyword) => { + dispatch(push(`/searched/${encodeURIComponent(keyword)}`)) + this.setState({ + search: keyword + }) + ee.emit('top:search', keyword) + }, 1000 / 60, { maxWait: 1000 / 8 }) } @@ -63,14 +71,14 @@ class TopBar extends React.Component { this.refs.search.childNodes[0].blur dispatch(push('/searched')) e.preventDefault() + this.debouncedUpdateKeyword('') } handleKeyDown (e) { - // reset states - this.setState({ - isAlphabet: false, - isIME: false - }) + // Re-apply search field on ENTER key + if (e.keyCode === 13) { + this.debouncedUpdateKeyword(e.target.value) + } // Clear search on ESC if (e.keyCode === 27) { @@ -88,52 +96,11 @@ class TopBar extends React.Component { ee.emit('list:prior') e.preventDefault() } - - // When the key is an alphabet, del, enter or ctr - if (e.keyCode <= 90 || e.keyCode >= 186 && e.keyCode <= 222) { - this.setState({ - isAlphabet: true - }) - // When the key is an IME input (Japanese, Chinese) - } else if (e.keyCode === 229) { - this.setState({ - isIME: true - }) - } - } - - handleKeyUp (e) { - // reset states - this.setState({ - isConfirmTranslation: false - }) - - // When the key is translation confirmation (Enter, Space) - if (this.state.isIME && (e.keyCode === 32 || e.keyCode === 13)) { - this.setState({ - isConfirmTranslation: true - }) - const keyword = this.refs.searchInput.value - this.updateKeyword(keyword) - } } handleSearchChange (e) { - if (this.state.isAlphabet || this.state.isConfirmTranslation) { - const keyword = this.refs.searchInput.value - this.updateKeyword(keyword) - } else { - e.preventDefault() - } - } - - updateKeyword (keyword) { - const { dispatch } = this.props - dispatch(push(`/searched/${encodeURIComponent(keyword)}`)) - this.setState({ - search: keyword - }) - ee.emit('top:search', keyword) + const keyword = e.target.value + this.debouncedUpdateKeyword(keyword) } handleSearchFocus (e) { @@ -141,6 +108,7 @@ class TopBar extends React.Component { isSearching: true }) } + handleSearchBlur (e) { e.stopPropagation() @@ -170,7 +138,7 @@ class TopBar extends React.Component { } handleCodeInit () { - ee.emit('top:search', this.refs.searchInput.value) + ee.emit('top:search', this.refs.searchInput.value || '') } render () { @@ -183,24 +151,23 @@ class TopBar extends React.Component {
this.handleSearchFocus(e)} - onBlur={(e) => this.handleSearchBlur(e)} + onFocus={this.handleSearchFocus} + onBlur={this.handleSearchBlur} tabIndex='-1' ref='search' > - this.handleSearchChange(e)} - onKeyDown={(e) => this.handleKeyDown(e)} - onKeyUp={(e) => this.handleKeyUp(e)} + onInputChange={this.handleSearchChange} + onKeyDown={this.handleKeyDown} placeholder={i18n.__('Search')} type='text' className='searchInput' /> {this.state.search !== '' &&
+
+ +
+
+
+ +
{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 0893e681..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", @@ -105,6 +105,7 @@ "react-autosuggest": "^9.4.0", "react-codemirror": "^1.0.0", "react-color": "^2.2.2", + "react-composition-input": "^1.1.1", "react-debounce-render": "^4.0.1", "react-dom": "^16.8.6", "react-image-carousel": "^2.0.18", 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 e61d4b73..e3753aca 100644 --- a/tests/lib/contextMenuBuilder.test.js +++ b/tests/lib/contextMenuBuilder.test.js @@ -4,8 +4,13 @@ jest.mock('electron', () => { }) const spellcheck = require('browser/lib/spellcheck') +<<<<<<< HEAD const buildEditorContextMenu = require('browser/lib/contextMenuBuilder') const buildMarkdownPreviewContextMenu = require('browser/lib/contextMenuBuilder') +======= +const buildEditorContextMenu = require('browser/lib/contextMenuBuilder').buildEditorContextMenu +const buildMarkdownPreviewContextMenu = require('browser/lib/contextMenuBuilder').buildMarkdownPreviewContextMenu +>>>>>>> upstream/master beforeEach(() => { menuBuilderParameter = 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/slugify-test.js b/tests/lib/slugify-test.js new file mode 100644 index 00000000..0277bd10 --- /dev/null +++ b/tests/lib/slugify-test.js @@ -0,0 +1,58 @@ +import test from 'ava' +import slugify from 'browser/lib/slugify' + +test('alphabet and digit', t => { + const upperAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + const lowerAlphabet = 'abcdefghijklmnopqrstuvwxyz' + const digit = '0123456789' + const testCase = upperAlphabet + lowerAlphabet + digit + const decodeSlug = decodeURI(slugify(testCase)) + + t.true(decodeSlug === testCase) +}) + +test('should delete unavailable symbols', t => { + const availableSymbols = '_-' + const testCase = availableSymbols + '][!\'#$%&()*+,./:;<=>?@\\^{|}~`' + const decodeSlug = decodeURI(slugify(testCase)) + + t.true(decodeSlug === availableSymbols) +}) + +test('should convert from white spaces between words to hyphens', t => { + const testCase = 'This is one' + const expectedString = 'This-is-one' + const decodeSlug = decodeURI(slugify(testCase)) + + t.true(decodeSlug === expectedString) +}) + +test('should remove leading white spaces', t => { + const testCase = ' This is one' + const expectedString = 'This-is-one' + const decodeSlug = decodeURI(slugify(testCase)) + + t.true(decodeSlug === expectedString) +}) + +test('should remove trailing white spaces', t => { + const testCase = 'This is one ' + const expectedString = 'This-is-one' + const decodeSlug = decodeURI(slugify(testCase)) + + t.true(decodeSlug === expectedString) +}) + +test('2-byte charactor support', t => { + const testCase = '菠萝芒果テストÀžƁƵ' + const decodeSlug = decodeURI(slugify(testCase)) + + t.true(decodeSlug === testCase) +}) + +test('emoji', t => { + const testCase = '🌸' + const decodeSlug = decodeURI(slugify(testCase)) + + t.true(decodeSlug === testCase) +}) 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 diff --git a/yarn.lock b/yarn.lock index 30640d17..a10a0fc5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7746,6 +7746,13 @@ react-color@^2.2.2: reactcss "^1.2.0" tinycolor2 "^1.4.1" +react-composition-input@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/react-composition-input/-/react-composition-input-1.1.1.tgz#51fc711f8b1c7d11e39210639175f0b48de44aff" + integrity sha512-xzRAUvsrEdSjI1tQXu3ouPHkHVZnunx6OoAFsv4YxVV6fIBHc9XZuxkmJwoxSatPxJ6WN94k91PBWQTsL6h/ZA== + dependencies: + prop-types "^15.6.2" + react-css-modules@^4.7.9: version "4.7.9" resolved "https://registry.yarnpkg.com/react-css-modules/-/react-css-modules-4.7.9.tgz#459235e149a0df7a62b092ae079d53cb0b6154ee"