From 592aca1539166bb9a6d1eaf36a20203fff584c37 Mon Sep 17 00:00:00 2001 From: Nguyen Viet Hung Date: Wed, 5 Feb 2020 13:28:27 +1300 Subject: [PATCH] fixed eslint error & integrated with prettier as well as formatted the whole codebase (#3450) --- .eslintrc | 7 +- .prettierrc | 5 + browser/components/CodeEditor.js | 368 +++-- browser/components/ColorPicker.js | 27 +- browser/components/MarkdownEditor.js | 301 ++-- browser/components/MarkdownPreview.js | 217 +-- browser/components/MarkdownSplitEditor.js | 88 +- browser/components/ModalEscButton.js | 4 +- browser/components/NavToggleButton.js | 25 +- browser/components/NoteItem.js | 72 +- browser/components/NoteItemSimple.js | 46 +- browser/components/RealtimeNotification.js | 38 +- browser/components/SideNavFilter.js | 58 +- browser/components/SnippetTab.js | 117 +- browser/components/StorageItem.js | 16 +- browser/components/StorageList.js | 14 +- browser/components/TagListItem.js | 62 +- browser/components/TodoListPercentage.js | 15 +- browser/components/TodoProcess.js | 15 +- browser/components/render/MermaidRender.js | 12 +- browser/lib/CSSModules.js | 4 +- browser/lib/Languages.js | 6 +- browser/lib/Mutable.js | 40 +- browser/lib/RcParser.js | 4 +- browser/lib/SnippetManager.js | 11 +- browser/lib/TextEditorInterface.js | 28 +- browser/lib/confirmDeleteNote.js | 5 +- browser/lib/consts.js | 56 +- browser/lib/context.js | 4 +- browser/lib/contextMenuBuilder.js | 128 +- browser/lib/convertModeName.js | 2 +- browser/lib/customMeta.js | 15 +- browser/lib/date-formatter.js | 2 +- browser/lib/findNoteTitle.js | 25 +- browser/lib/findStorage.js | 9 +- browser/lib/getTodoStatus.js | 8 +- browser/lib/htmlTextHelper.js | 10 +- browser/lib/i18n.js | 7 +- browser/lib/keygen.js | 2 +- browser/lib/markdown-it-deflist.js | 124 +- browser/lib/markdown-it-fence.js | 17 +- browser/lib/markdown-it-frontmatter.js | 15 +- browser/lib/markdown-it-sanitize-html.js | 29 +- browser/lib/markdown-toc-generator.js | 25 +- browser/lib/markdown.js | 364 +++-- browser/lib/markdownTextHelper.js | 2 +- browser/lib/newNote.js | 53 +- browser/lib/normalizeEditorFontFamily.js | 2 +- browser/lib/search.js | 25 +- browser/lib/slugify.js | 10 +- browser/lib/spellcheck.js | 107 +- browser/lib/turndown.js | 2 +- browser/lib/utils.js | 14 +- browser/main/Detail/FolderSelect.js | 247 +-- browser/main/Detail/FromUrlButton.js | 40 +- browser/main/Detail/FullscreenButton.js | 14 +- browser/main/Detail/InfoButton.js | 8 +- browser/main/Detail/InfoPanel.js | 80 +- browser/main/Detail/InfoPanelTrashed.js | 40 +- browser/main/Detail/MarkdownNoteDetail.js | 541 ++++--- browser/main/Detail/PermanentDeleteButton.js | 8 +- browser/main/Detail/RestoreButton.js | 8 +- browser/main/Detail/SnippetNoteDetail.js | 848 +++++----- browser/main/Detail/StarButton.js | 44 +- browser/main/Detail/TagSelect.js | 174 +- browser/main/Detail/ToggleDirectionButton.js | 8 +- browser/main/Detail/ToggleModeButton.js | 34 +- browser/main/Detail/TrashButton.js | 12 +- browser/main/Detail/index.js | 50 +- browser/main/Main.js | 65 +- browser/main/NewNoteButton/index.js | 65 +- browser/main/NoteList/index.js | 726 +++++---- browser/main/SideNav/ListButton.js | 19 +- browser/main/SideNav/PreferenceButton.js | 6 +- browser/main/SideNav/StorageItem.js | 259 +-- browser/main/SideNav/TagButton.js | 19 +- browser/main/SideNav/index.js | 344 ++-- browser/main/StatusBar/index.js | 57 +- browser/main/TopBar/index.js | 88 +- browser/main/index.js | 78 +- browser/main/lib/AwsMobileAnalyticsConfig.js | 12 +- browser/main/lib/Commander.js | 13 +- browser/main/lib/ConfigManager.js | 77 +- browser/main/lib/ZoomManager.js | 10 +- browser/main/lib/dataApi/addStorage.js | 44 +- .../main/lib/dataApi/attachmentManagement.js | 692 +++++--- browser/main/lib/dataApi/copyFile.js | 2 +- browser/main/lib/dataApi/createFolder.js | 38 +- browser/main/lib/dataApi/createNote.js | 45 +- browser/main/lib/dataApi/createNoteFromUrl.js | 54 +- browser/main/lib/dataApi/createSnippet.js | 24 +- browser/main/lib/dataApi/deleteFolder.js | 47 +- browser/main/lib/dataApi/deleteNote.js | 11 +- browser/main/lib/dataApi/deleteSnippet.js | 20 +- browser/main/lib/dataApi/exportFolder.js | 46 +- browser/main/lib/dataApi/exportNote.js | 43 +- browser/main/lib/dataApi/exportStorage.js | 19 +- browser/main/lib/dataApi/fetchSnippet.js | 6 +- browser/main/lib/dataApi/init.js | 77 +- .../main/lib/dataApi/migrateFromV5Storage.js | 153 +- .../main/lib/dataApi/migrateFromV6Storage.js | 93 +- browser/main/lib/dataApi/moveNote.js | 154 +- browser/main/lib/dataApi/removeStorage.js | 9 +- browser/main/lib/dataApi/renameStorage.js | 7 +- browser/main/lib/dataApi/reorderFolder.js | 22 +- .../main/lib/dataApi/resolveStorageData.js | 12 +- .../main/lib/dataApi/resolveStorageNotes.js | 10 +- browser/main/lib/dataApi/toggleStorage.js | 4 +- browser/main/lib/dataApi/updateFolder.js | 26 +- browser/main/lib/dataApi/updateNote.js | 135 +- browser/main/lib/dataApi/updateSnippet.js | 20 +- browser/main/lib/eventEmitter.js | 8 +- browser/main/lib/ipcClient.js | 10 +- browser/main/lib/modal.js | 48 +- browser/main/lib/notify.js | 8 +- browser/main/lib/shortcut.js | 8 +- browser/main/lib/shortcutManager.js | 8 +- browser/main/modals/CreateFolderModal.js | 46 +- .../main/modals/CreateMarkdownFromURLModal.js | 64 +- browser/main/modals/NewNoteModal.js | 54 +- browser/main/modals/PreferencesModal/Blog.js | 124 +- .../modals/PreferencesModal/Crowdfunding.js | 81 +- .../modals/PreferencesModal/FolderItem.js | 206 +-- .../modals/PreferencesModal/FolderList.js | 46 +- .../main/modals/PreferencesModal/HotkeyTab.js | 225 ++- .../main/modals/PreferencesModal/InfoTab.js | 156 +- .../modals/PreferencesModal/SnippetEditor.js | 54 +- .../modals/PreferencesModal/SnippetList.js | 86 +- .../modals/PreferencesModal/SnippetTab.js | 61 +- .../modals/PreferencesModal/StorageItem.js | 133 +- .../modals/PreferencesModal/StoragesTab.js | 229 +-- browser/main/modals/PreferencesModal/UiTab.js | 592 ++++--- browser/main/modals/PreferencesModal/index.js | 109 +- browser/main/modals/RenameFolderModal.js | 41 +- browser/main/store.js | 345 ++-- dev-scripts/dev.js | 6 +- gruntfile.js | 201 ++- index.js | 18 +- lib/ipcServer.js | 10 +- lib/main-app.js | 19 +- lib/main-menu.js | 257 +-- lib/main-window.js | 19 +- lib/touchbar-menu.js | 7 +- package.json | 4 +- tests/components/TagListItem.snapshot.test.js | 4 +- tests/dataApi/addStorage.js | 23 +- tests/dataApi/attachmentManagement.test.js | 1412 +++++++++++++---- tests/dataApi/copyFile-test.js | 7 +- tests/dataApi/createFolder-test.js | 19 +- tests/dataApi/createNote-test.js | 51 +- tests/dataApi/createNoteFromUrl-test.js | 30 +- tests/dataApi/createSnippet-test.js | 16 +- tests/dataApi/deleteFolder-test.js | 67 +- tests/dataApi/deleteNote-test.js | 55 +- tests/dataApi/deleteSnippet-test.js | 12 +- tests/dataApi/exportFolder-test.js | 29 +- tests/dataApi/exportStorage-test.js | 43 +- tests/dataApi/init.js | 40 +- tests/dataApi/migrateFromV6Storage-test.js | 55 +- tests/dataApi/moveNote-test.js | 28 +- tests/dataApi/removeStorage-test.js | 15 +- tests/dataApi/renameStorage-test.js | 17 +- tests/dataApi/reorderFolder-test.js | 19 +- tests/dataApi/toggleStorage-test.js | 17 +- tests/dataApi/updateFolder-test.js | 19 +- tests/dataApi/updateNote-test.js | 91 +- tests/dataApi/updateSnippet-test.js | 16 +- tests/date-formatter-test.js | 5 +- tests/fixtures/TestDummy.js | 112 +- tests/helpers/setup-browser-env.js | 14 +- tests/jest.js | 2 +- tests/lib/contextMenuBuilder.test.js | 79 +- tests/lib/find-storage-test.js | 9 +- tests/lib/find-title-test.js | 29 +- tests/lib/get-todo-status-test.js | 13 +- tests/lib/html-text-helper-test.js | 46 +- tests/lib/markdown-text-helper-test.js | 6 +- tests/lib/markdown-toc-generator-test.js | 30 +- .../lib/normalize-editor-font-family-test.js | 5 +- tests/lib/rc-parser-test.js | 56 +- tests/lib/search-test.js | 15 +- tests/lib/slugify-test.js | 2 +- tests/lib/spellcheck.test.js | 269 ++-- webpack-production.config.js | 7 +- webpack.config.js | 4 +- yarn.lock | 258 ++- 186 files changed, 9233 insertions(+), 5565 deletions(-) create mode 100644 .prettierrc diff --git a/.eslintrc b/.eslintrc index be8cb903..67b6c8fe 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,6 +1,6 @@ { - "extends": ["standard", "standard-jsx", "plugin:react/recommended"], - "plugins": ["react"], + "extends": ["standard", "standard-jsx", "plugin:react/recommended", "prettier"], + "plugins": ["react", "prettier"], "rules": { "no-useless-escape": 0, "prefer-const": ["warn", { @@ -13,7 +13,8 @@ "react/no-string-refs": 0, "react/no-find-dom-node": "warn", "react/no-render-return-value": "warn", - "react/no-deprecated": "warn" + "react/no-deprecated": "warn", + "prettier/prettier": ["error"] }, "globals": { "FileReader": true, diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..515c6cd5 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "singleQuote": true, + "semi": false, + "jsxSingleQuote": true +} \ No newline at end of file diff --git a/browser/components/CodeEditor.js b/browser/components/CodeEditor.js index bc2719dc..a5bb009a 100644 --- a/browser/components/CodeEditor.js +++ b/browser/components/CodeEditor.js @@ -6,11 +6,7 @@ import hljs from 'highlight.js' import 'codemirror-mode-elixir' import attachmentManagement from 'browser/main/lib/dataApi/attachmentManagement' import convertModeName from 'browser/lib/convertModeName' -import { - options, - TableEditor, - Alignment -} from '@susisu/mte-kernel' +import { options, TableEditor, Alignment } from '@susisu/mte-kernel' import TextEditorInterface from 'browser/lib/TextEditorInterface' import eventEmitter from 'browser/main/lib/eventEmitter' import iconv from 'iconv-lite' @@ -20,11 +16,15 @@ 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').buildEditorContextMenu +const buildEditorContextMenu = require('browser/lib/contextMenuBuilder') + .buildEditorContextMenu import { createTurndownService } from '../lib/turndown' -import {languageMaps} from '../lib/CMLanguageList' +import { languageMaps } from '../lib/CMLanguageList' import snippetManager from '../lib/SnippetManager' -import {generateInEditor, tocExistsInEditor} from 'browser/lib/markdown-toc-generator' +import { + generateInEditor, + tocExistsInEditor +} from 'browser/lib/markdown-toc-generator' import markdownlint from 'markdownlint' import Jsonlint from 'jsonlint-mod' import { DEFAULT_CONFIG } from '../main/lib/ConfigManager' @@ -33,28 +33,38 @@ import prettier from 'prettier' CodeMirror.modeURL = '../node_modules/codemirror/mode/%N/%N.js' const buildCMRulers = (rulers, enableRulers) => - (enableRulers ? rulers.map(ruler => ({ - column: ruler - })) : []) + enableRulers + ? rulers.map(ruler => ({ + column: ruler + })) + : [] -function translateHotkey (hotkey) { - return hotkey.replace(/\s*\+\s*/g, '-').replace(/Command/g, 'Cmd').replace(/Control/g, 'Ctrl') +function translateHotkey(hotkey) { + return hotkey + .replace(/\s*\+\s*/g, '-') + .replace(/Command/g, 'Cmd') + .replace(/Control/g, 'Ctrl') } export default class CodeEditor extends React.Component { - constructor (props) { + constructor(props) { super(props) this.scrollHandler = _.debounce(this.handleScroll.bind(this), 100, { leading: false, trailing: true }) - this.changeHandler = (editor, changeObject) => this.handleChange(editor, changeObject) - this.highlightHandler = (editor, changeObject) => this.handleHighlight(editor, changeObject) + this.changeHandler = (editor, changeObject) => + this.handleChange(editor, changeObject) + this.highlightHandler = (editor, changeObject) => + this.handleHighlight(editor, changeObject) this.focusHandler = () => { ipcRenderer.send('editor:focused', true) } - const debouncedDeletionOfAttachments = _.debounce(attachmentManagement.deleteAttachmentsNotPresentInNote, 30000) + const debouncedDeletionOfAttachments = _.debounce( + attachmentManagement.deleteAttachmentsNotPresentInNote, + 30000 + ) this.blurHandler = (editor, e) => { ipcRenderer.send('editor:focused', false) if (e == null) return null @@ -66,12 +76,13 @@ export default class CodeEditor extends React.Component { el = el.parentNode } this.props.onBlur != null && this.props.onBlur(e) - const { - storageKey, - noteKey - } = this.props + const { storageKey, noteKey } = this.props if (this.props.deleteUnusedAttachments === true) { - debouncedDeletionOfAttachments(this.editor.getValue(), storageKey, noteKey) + debouncedDeletionOfAttachments( + this.editor.getValue(), + storageKey, + noteKey + ) } } this.pasteHandler = (editor, e) => { @@ -91,7 +102,7 @@ export default class CodeEditor extends React.Component { this.formatTable = () => this.handleFormatTable() if (props.switchPreview !== 'RIGHTCLICK') { - this.contextMenuHandler = function (editor, event) { + this.contextMenuHandler = function(editor, event) { const menu = buildEditorContextMenu(editor, event) if (menu != null) { setTimeout(() => menu.popup(remote.getCurrentWindow()), 30) @@ -104,24 +115,24 @@ export default class CodeEditor extends React.Component { this.turndownService = createTurndownService() } - handleSearch (msg) { + handleSearch(msg) { const cm = this.editor const component = this if (component.searchState) cm.removeOverlay(component.searchState) if (msg.length < 1) return - cm.operation(function () { + cm.operation(function() { component.searchState = makeOverlay(msg, 'searching') cm.addOverlay(component.searchState) - function makeOverlay (query, style) { + function makeOverlay(query, style) { query = new RegExp( query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'), 'gi' ) return { - token: function (stream) { + token: function(stream) { query.lastIndex = stream.pos var match = query.exec(stream.string) if (match && match.index === stream.pos) { @@ -138,25 +149,27 @@ export default class CodeEditor extends React.Component { }) } - handleFormatTable () { - this.tableEditor.formatAll(options({ - textWidthOptions: {} - })) + handleFormatTable() { + this.tableEditor.formatAll( + options({ + textWidthOptions: {} + }) + ) } - handleEditorActivity () { + handleEditorActivity() { if (!this.textEditorInterface.transaction) { this.updateTableEditorState() } } - updateDefaultKeyMap () { + updateDefaultKeyMap() { const { hotkey } = this.props const self = this const expandSnippet = snippetManager.expandSnippet this.defaultKeyMap = CodeMirror.normalizeKeyMap({ - Tab: function (cm) { + Tab: function(cm) { const cursor = cm.getCursor() const line = cm.getLine(cursor.line) const cursorPosition = cursor.ch @@ -198,17 +211,17 @@ export default class CodeEditor extends React.Component { } } }, - 'Cmd-Left': function (cm) { + 'Cmd-Left': function(cm) { cm.execCommand('goLineLeft') }, - 'Cmd-T': function (cm) { + 'Cmd-T': function(cm) { // Do nothing }, - [translateHotkey(hotkey.insertDate)]: function (cm) { + [translateHotkey(hotkey.insertDate)]: function(cm) { const dateNow = new Date() cm.replaceSelection(dateNow.toLocaleDateString()) }, - [translateHotkey(hotkey.insertDateTime)]: function (cm) { + [translateHotkey(hotkey.insertDateTime)]: function(cm) { const dateNow = new Date() cm.replaceSelection(dateNow.toLocaleString()) }, @@ -231,7 +244,10 @@ export default class CodeEditor extends React.Component { currentConfig.cursorOffset = cm.doc.indexFromPos(cursorPos) // Prettify contents of editor - const formattedTextDetails = prettier.formatWithCursor(cm.doc.getValue(), currentConfig) + const formattedTextDetails = prettier.formatWithCursor( + cm.doc.getValue(), + currentConfig + ) const formattedText = formattedTextDetails.formatted const formattedCursorPos = formattedTextDetails.cursorOffset @@ -246,7 +262,8 @@ export default class CodeEditor extends React.Component { const appendLineBreak = /\n$/.test(selection) const sorted = _.split(selection.trim(), '\n').sort() - const sortedString = _.join(sorted, '\n') + (appendLineBreak ? '\n' : '') + const sortedString = + _.join(sorted, '\n') + (appendLineBreak ? '\n' : '') cm.doc.replaceSelection(sortedString) }, @@ -256,7 +273,7 @@ export default class CodeEditor extends React.Component { }) } - updateTableEditorState () { + updateTableEditorState() { const active = this.tableEditor.cursorIsInTable(this.tableEditorOptions) if (active) { if (this.extraKeysMode !== 'editor') { @@ -272,7 +289,7 @@ export default class CodeEditor extends React.Component { } } - componentDidMount () { + componentDidMount() { const { rulers, enableRulers, enableMarkdownLint, RTL } = this.props eventEmitter.on('line:jump', this.scrollToLineHandeler) @@ -298,7 +315,11 @@ export default class CodeEditor extends React.Component { rtlMoveVisually: RTL, foldGutter: true, lint: enableMarkdownLint ? this.getCodeEditorLintConfig() : false, - gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers'], + gutters: [ + 'CodeMirror-linenumbers', + 'CodeMirror-foldgutter', + 'CodeMirror-lint-markers' + ], autoCloseBrackets: { pairs: this.props.matchingPairs, triples: this.props.matchingTriples, @@ -309,7 +330,9 @@ export default class CodeEditor extends React.Component { prettierConfig: this.props.prettierConfig }) - document.querySelector('.CodeMirror-lint-markers').style.display = enableMarkdownLint ? 'inline-block' : 'none' + document.querySelector( + '.CodeMirror-lint-markers' + ).style.display = enableMarkdownLint ? 'inline-block' : 'none' if (!this.props.mode && this.props.value && this.props.autoDetect) { this.autoDetectLanguage(this.props.value) @@ -342,7 +365,7 @@ export default class CodeEditor extends React.Component { this.textEditorInterface = new TextEditorInterface(this.editor) this.tableEditor = new TableEditor(this.textEditorInterface) if (this.props.spellCheck) { - this.editor.addPanel(this.createSpellCheckPanel(), {position: 'bottom'}) + this.editor.addPanel(this.createSpellCheckPanel(), { position: 'bottom' }) } eventEmitter.on('code:format-table', this.formatTable) @@ -352,13 +375,13 @@ export default class CodeEditor extends React.Component { }) this.editorKeyMap = CodeMirror.normalizeKeyMap({ - 'Tab': () => { + Tab: () => { this.tableEditor.nextCell(this.tableEditorOptions) }, 'Shift-Tab': () => { this.tableEditor.previousCell(this.tableEditorOptions) }, - 'Enter': () => { + Enter: () => { this.tableEditor.nextRow(this.tableEditorOptions) }, 'Ctrl-Enter': () => { @@ -477,7 +500,7 @@ export default class CodeEditor extends React.Component { this.initialHighlighting() } - getWordBeforeCursor (line, lineNumber, cursorPosition) { + getWordBeforeCursor(line, lineNumber, cursorPosition) { let wordBeforeCursor = '' const originCursorPosition = cursorPosition const emptyChars = /\t|\s|\r|\n|\$/ @@ -514,11 +537,11 @@ export default class CodeEditor extends React.Component { } } - quitEditor () { + quitEditor() { document.querySelector('textarea').blur() } - componentWillUnmount () { + componentWillUnmount() { this.editor.off('focus', this.focusHandler) this.editor.off('blur', this.blurHandler) this.editor.off('change', this.changeHandler) @@ -533,7 +556,7 @@ export default class CodeEditor extends React.Component { eventEmitter.off('code:format-table', this.formatTable) } - componentDidUpdate (prevProps, prevState) { + componentDidUpdate(prevProps, prevState) { let needRefresh = false const { rulers, @@ -561,13 +584,18 @@ export default class CodeEditor extends React.Component { this.editor.setOption('direction', this.props.RTL ? 'rtl' : 'ltr') this.editor.setOption('rtlMoveVisually', this.props.RTL) } - if (prevProps.enableMarkdownLint !== enableMarkdownLint || prevProps.customMarkdownLintConfig !== customMarkdownLintConfig) { + if ( + prevProps.enableMarkdownLint !== enableMarkdownLint || + prevProps.customMarkdownLintConfig !== customMarkdownLintConfig + ) { if (!enableMarkdownLint) { - this.editor.setOption('lint', {default: false}) - document.querySelector('.CodeMirror-lint-markers').style.display = 'none' + this.editor.setOption('lint', { default: false }) + document.querySelector('.CodeMirror-lint-markers').style.display = + 'none' } else { this.editor.setOption('lint', this.getCodeEditorLintConfig()) - document.querySelector('.CodeMirror-lint-markers').style.display = 'inline-block' + document.querySelector('.CodeMirror-lint-markers').style.display = + 'inline-block' } needRefresh = true } @@ -599,9 +627,11 @@ export default class CodeEditor extends React.Component { this.editor.setOption('scrollPastEnd', this.props.scrollPastEnd) } - if (prevProps.matchingPairs !== this.props.matchingPairs || + if ( + prevProps.matchingPairs !== this.props.matchingPairs || prevProps.matchingTriples !== this.props.matchingTriples || - prevProps.explodingPairs !== this.props.explodingPairs) { + prevProps.explodingPairs !== this.props.explodingPairs + ) { const bracketObject = { pairs: this.props.matchingPairs, triples: this.props.matchingTriples, @@ -646,11 +676,18 @@ export default class CodeEditor extends React.Component { const elem = document.getElementById('editor-bottom-panel') elem.parentNode.removeChild(elem) } else { - this.editor.addPanel(this.createSpellCheckPanel(), {position: 'bottom'}) + this.editor.addPanel(this.createSpellCheckPanel(), { + position: 'bottom' + }) } } - if (prevProps.deleteUnusedAttachments !== this.props.deleteUnusedAttachments) { - this.editor.setOption('deleteUnusedAttachments', this.props.deleteUnusedAttachments) + if ( + prevProps.deleteUnusedAttachments !== this.props.deleteUnusedAttachments + ) { + this.editor.setOption( + 'deleteUnusedAttachments', + this.props.deleteUnusedAttachments + ) } if (needRefresh) { @@ -658,17 +695,19 @@ export default class CodeEditor extends React.Component { } } - getCodeEditorLintConfig () { + getCodeEditorLintConfig() { const { mode } = this.props const checkMarkdownNoteIsOpen = mode === 'Boost Flavored Markdown' - return checkMarkdownNoteIsOpen ? { - getAnnotations: this.validatorOfMarkdown, - async: true - } : false + return checkMarkdownNoteIsOpen + ? { + getAnnotations: this.validatorOfMarkdown, + async: true + } + : false } - validatorOfMarkdown (text, updateLinting) { + validatorOfMarkdown(text, updateLinting) { const { customMarkdownLintConfig } = this.props let lintConfigJson try { @@ -693,7 +732,7 @@ export default class CodeEditor extends React.Component { let ruleNames = '' item.ruleNames.map((ruleName, index) => { ruleNames += ruleName - ruleNames += (index === item.ruleNames.length - 1) ? ': ' : '/' + ruleNames += index === item.ruleNames.length - 1 ? ': ' : '/' }) const lineNumber = item.lineNumber - 1 foundIssues.push({ @@ -708,7 +747,7 @@ export default class CodeEditor extends React.Component { }) } - setMode (mode) { + setMode(mode) { let syntax = CodeMirror.findModeByName(convertModeName(mode || 'text')) if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text') @@ -716,7 +755,7 @@ export default class CodeEditor extends React.Component { CodeMirror.autoLoadMode(this.editor, syntax.mode) } - handleChange (editor, changeObject) { + handleChange(editor, changeObject) { spellcheck.handleChange(editor, changeObject) // The current note contains an toc. We'll check for changes on headlines. @@ -726,7 +765,11 @@ export default class CodeEditor extends React.Component { // Check if one of the changed lines contains a headline for (let line = 0; line < changeObject.text.length; line++) { - if (this.linePossibleContainsHeadline(editor.getLine(changeObject.from.line + line))) { + if ( + this.linePossibleContainsHeadline( + editor.getLine(changeObject.from.line + line) + ) + ) { requireTocUpdate = true break } @@ -755,13 +798,13 @@ export default class CodeEditor extends React.Component { } } - linePossibleContainsHeadline (currentLine) { + linePossibleContainsHeadline(currentLine) { // We can't check if the line start with # because when some write text before // the # we also need to update the toc return currentLine.includes('# ') } - incrementLines (start, linesAdded, linesRemoved, editor) { + incrementLines(start, linesAdded, linesRemoved, editor) { const highlightedLines = editor.options.linesHighlighted const totalHighlightedLines = highlightedLines.length @@ -782,7 +825,7 @@ export default class CodeEditor extends React.Component { highlightedLines.splice(highlightedLines.indexOf(lineNumber), 1) // Lines that need to be relocated - if (lineNumber >= (start + linesRemoved)) { + if (lineNumber >= start + linesRemoved) { newLines.push(lineNumber + offset) } } @@ -796,22 +839,30 @@ export default class CodeEditor extends React.Component { } } - handleHighlight (editor, changeObject) { + handleHighlight(editor, changeObject) { const lines = editor.options.linesHighlighted if (!lines.includes(changeObject)) { lines.push(changeObject) - editor.addLineClass(changeObject, 'text', 'CodeMirror-activeline-background') + editor.addLineClass( + changeObject, + 'text', + 'CodeMirror-activeline-background' + ) } else { lines.splice(lines.indexOf(changeObject), 1) - editor.removeLineClass(changeObject, 'text', 'CodeMirror-activeline-background') + editor.removeLineClass( + changeObject, + 'text', + 'CodeMirror-activeline-background' + ) } if (this.props.onChange) { this.props.onChange(editor) } } - updateHighlight (editor, changeObject) { + updateHighlight(editor, changeObject) { const linesAdded = changeObject.text.length - 1 const linesRemoved = changeObject.removed.length - 1 @@ -842,28 +893,28 @@ export default class CodeEditor extends React.Component { this.incrementLines(start, linesAdded, linesRemoved, editor) } - moveCursorTo (row, col) {} + moveCursorTo(row, col) {} - scrollToLine (event, num) { + scrollToLine(event, num) { const cursor = { line: num, ch: 1 } this.editor.setCursor(cursor) - const top = this.editor.charCoords({line: num, ch: 0}, 'local').top + const top = this.editor.charCoords({ line: num, ch: 0 }, 'local').top const middleHeight = this.editor.getScrollerElement().offsetHeight / 2 this.editor.scrollTo(null, top - middleHeight - 5) } - focus () { + focus() { this.editor.focus() } - blur () { + blur() { this.editor.blur() } - reload () { + reload() { // Change event shouldn't be fired when switch note this.editor.off('change', this.changeHandler) this.value = this.props.value @@ -874,7 +925,7 @@ export default class CodeEditor extends React.Component { this.editor.refresh() } - setValue (value) { + setValue(value) { const cursor = this.editor.getCursor() this.editor.setValue(value) this.editor.setCursor(cursor) @@ -885,18 +936,19 @@ export default class CodeEditor extends React.Component { * @param {Number} lineNumber * @param {String} content */ - setLineContent (lineNumber, content) { + setLineContent(lineNumber, content) { const prevContent = this.editor.getLine(lineNumber) const prevContentLength = prevContent ? prevContent.length : 0 - this.editor.replaceRange(content, { line: lineNumber, ch: 0 }, { line: lineNumber, ch: prevContentLength }) + this.editor.replaceRange( + content, + { line: lineNumber, ch: 0 }, + { line: lineNumber, ch: prevContentLength } + ) } - handleDropImage (dropEvent) { + handleDropImage(dropEvent) { dropEvent.preventDefault() - const { - storageKey, - noteKey - } = this.props + const { storageKey, noteKey } = this.props attachmentManagement.handleAttachmentDrop( this, storageKey, @@ -905,37 +957,44 @@ export default class CodeEditor extends React.Component { ) } - insertAttachmentMd (imageMd) { + insertAttachmentMd(imageMd) { this.editor.replaceSelection(imageMd) } - autoDetectLanguage (content) { + autoDetectLanguage(content) { const res = hljs.highlightAuto(content, Object.keys(languageMaps)) this.setMode(languageMaps[res.language]) } - handlePaste (editor, forceSmartPaste) { + handlePaste(editor, forceSmartPaste) { const { storageKey, noteKey, fetchUrlTitle, enableSmartPaste } = this.props - const isURL = str => /(?:^\w+:|^)\/\/(?:[^\s\.]+\.\S{2}|localhost[\:?\d]*)/.test(str) + const isURL = str => + /(?:^\w+:|^)\/\/(?:[^\s\.]+\.\S{2}|localhost[\:?\d]*)/.test(str) const isInLinkTag = editor => { const startCursor = editor.getCursor('start') - const prevChar = editor.getRange({ - line: startCursor.line, - ch: startCursor.ch - 2 - }, { - line: startCursor.line, - ch: startCursor.ch - }) + const prevChar = editor.getRange( + { + line: startCursor.line, + ch: startCursor.ch - 2 + }, + { + line: startCursor.line, + ch: startCursor.ch + } + ) const endCursor = editor.getCursor('end') - const nextChar = editor.getRange({ - line: endCursor.line, - ch: endCursor.ch - }, { - line: endCursor.line, - ch: endCursor.ch + 1 - }) + const nextChar = editor.getRange( + { + line: endCursor.line, + ch: endCursor.ch + }, + { + line: endCursor.line, + ch: endCursor.ch + 1 + } + ) return prevChar === '](' && nextChar === ')' } @@ -947,7 +1006,7 @@ export default class CodeEditor extends React.Component { return true } - let line = line = cursor.line - 1 + let line = (line = cursor.line - 1) while (line >= 0) { token = editor.getTokenAt({ ch: 3, @@ -979,7 +1038,11 @@ export default class CodeEditor extends React.Component { if (isInFencedCodeBlock(editor)) { this.handlePasteText(editor, pastedTxt) - } else if (fetchUrlTitle && isMarkdownTitleURL(pastedTxt) && !isInLinkTag(editor)) { + } else if ( + fetchUrlTitle && + isMarkdownTitleURL(pastedTxt) && + !isInLinkTag(editor) + ) { this.handlePasteUrl(editor, pastedTxt) } else if (fetchUrlTitle && isURL(pastedTxt) && !isInLinkTag(editor)) { this.handlePasteUrl(editor, pastedTxt) @@ -1015,13 +1078,13 @@ export default class CodeEditor extends React.Component { } } - handleScroll (e) { + handleScroll(e) { if (this.props.onScroll) { this.props.onScroll(e) } } - handlePasteUrl (editor, pastedTxt) { + handlePasteUrl(editor, pastedTxt) { let taggedUrl = `<${pastedTxt}>` let urlToFetch = pastedTxt let titleMark = '' @@ -1071,16 +1134,16 @@ export default class CodeEditor extends React.Component { }) } - handlePasteHtml (editor, pastedHtml) { + handlePasteHtml(editor, pastedHtml) { const markdown = this.turndownService.turndown(pastedHtml) editor.replaceSelection(markdown) } - handlePasteText (editor, pastedTxt) { + handlePasteText(editor, pastedTxt) { editor.replaceSelection(pastedTxt) } - mapNormalResponse (response, pastedTxt) { + mapNormalResponse(response, pastedTxt) { return this.decodeResponse(response).then(body => { return new Promise((resolve, reject) => { try { @@ -1088,10 +1151,12 @@ export default class CodeEditor extends React.Component { body, 'text/html' ) - const escapePipe = (str) => { + const escapePipe = str => { return str.replace('|', '\\|') } - const linkWithTitle = `[${escapePipe(parsedBody.title)}](${pastedTxt})` + const linkWithTitle = `[${escapePipe( + parsedBody.title + )}](${pastedTxt})` resolve(linkWithTitle) } catch (e) { reject(e) @@ -1100,7 +1165,7 @@ export default class CodeEditor extends React.Component { }) } - initialHighlighting () { + initialHighlighting() { if (this.editor.options.linesHighlighted == null) { return } @@ -1114,16 +1179,20 @@ export default class CodeEditor extends React.Component { // make sure that we skip the invalid lines althrough this case should not be happened. continue } - this.editor.addLineClass(lineNumber, 'text', 'CodeMirror-activeline-background') + this.editor.addLineClass( + lineNumber, + 'text', + 'CodeMirror-activeline-background' + ) } } - restartHighlighting () { + restartHighlighting() { this.editor.options.linesHighlighted = this.props.linesHighlighted this.initialHighlighting() } - mapImageResponse (response, pastedTxt) { + mapImageResponse(response, pastedTxt) { return new Promise((resolve, reject) => { try { const url = response.url @@ -1136,7 +1205,7 @@ export default class CodeEditor extends React.Component { }) } - decodeResponse (response) { + decodeResponse(response) { const headers = response.headers const _charset = headers.has('content-type') ? this.extractContentTypeCharset(headers.get('content-type')) @@ -1144,10 +1213,10 @@ export default class CodeEditor extends React.Component { return response.arrayBuffer().then(buff => { return new Promise((resolve, reject) => { try { - const charset = _charset !== undefined && - iconv.encodingExists(_charset) - ? _charset - : 'utf-8' + const charset = + _charset !== undefined && iconv.encodingExists(_charset) + ? _charset + : 'utf-8' resolve(iconv.decode(Buffer.from(buff), charset).toString()) } catch (e) { reject(e) @@ -1156,50 +1225,49 @@ export default class CodeEditor extends React.Component { }) } - extractContentTypeCharset (contentType) { + extractContentTypeCharset(contentType) { return contentType .split(';') .filter(str => { - return str.trim().toLowerCase().startsWith('charset') + return str + .trim() + .toLowerCase() + .startsWith('charset') }) .map(str => { return str.replace(/['"]/g, '').split('=')[1] })[0] } - render () { - const { - className, - fontSize - } = this.props + render() { + const { className, fontSize } = this.props const fontFamily = normalizeEditorFontFamily(this.props.fontFamily) const width = this.props.width - return (< - div className={ - className == null ? 'CodeEditor' : `CodeEditor ${className}` - } - ref='root' - tabIndex='-1' - style={{ - fontFamily, - fontSize: fontSize, - width: width - }} - onDrop={ - e => this.handleDropImage(e) - } + return ( +
this.handleDropImage(e)} /> ) } - createSpellCheckPanel () { + createSpellCheckPanel() { const panel = document.createElement('div') panel.className = 'panel bottom' panel.id = 'editor-bottom-panel' const dropdown = document.createElement('select') dropdown.title = 'Spellcheck' dropdown.className = styles['spellcheck-select'] - dropdown.addEventListener('change', (e) => spellcheck.setLanguage(this.editor, dropdown.value)) + dropdown.addEventListener('change', e => + spellcheck.setLanguage(this.editor, dropdown.value) + ) const options = spellcheck.getAvailableDictionaries() for (const op of options) { const option = document.createElement('option') diff --git a/browser/components/ColorPicker.js b/browser/components/ColorPicker.js index 9e0199c2..4d4e80e4 100644 --- a/browser/components/ColorPicker.js +++ b/browser/components/ColorPicker.js @@ -7,7 +7,7 @@ import styles from './ColorPicker.styl' const componentHeight = 330 class ColorPicker extends React.Component { - constructor (props) { + constructor(props) { super(props) this.state = { @@ -18,21 +18,21 @@ class ColorPicker extends React.Component { this.handleConfirm = this.handleConfirm.bind(this) } - componentWillReceiveProps (nextProps) { + componentWillReceiveProps(nextProps) { this.onColorChange(nextProps.color) } - onColorChange (color) { + onColorChange(color) { this.setState({ color }) } - handleConfirm () { + handleConfirm() { this.props.onConfirm(this.state.color) } - render () { + render() { const { onReset, onCancel, targetRect } = this.props const { color } = this.state @@ -44,13 +44,22 @@ class ColorPicker extends React.Component { } return ( -
+
- - - + + +
) diff --git a/browser/components/MarkdownEditor.js b/browser/components/MarkdownEditor.js index a2265321..a8b88891 100644 --- a/browser/components/MarkdownEditor.js +++ b/browser/components/MarkdownEditor.js @@ -10,7 +10,7 @@ import ConfigManager from 'browser/main/lib/ConfigManager' import attachmentManagement from 'browser/main/lib/dataApi/attachmentManagement' class MarkdownEditor extends React.Component { - constructor (props) { + constructor(props) { super(props) // char codes for ctrl + w @@ -20,7 +20,10 @@ class MarkdownEditor extends React.Component { this.supportMdSelectionBold = [16, 17, 186] this.state = { - status: props.config.editor.switchPreview === 'RIGHTCLICK' ? props.config.editor.delfaultStatus : 'CODE', + status: + props.config.editor.switchPreview === 'RIGHTCLICK' + ? props.config.editor.delfaultStatus + : 'CODE', renderValue: props.value, keyPressed: new Set(), isLocked: props.isLocked @@ -29,133 +32,153 @@ class MarkdownEditor extends React.Component { this.lockEditorCode = () => this.handleLockEditor() } - componentDidMount () { + componentDidMount() { this.value = this.refs.code.value eventEmitter.on('editor:lock', this.lockEditorCode) eventEmitter.on('editor:focus', this.focusEditor.bind(this)) } - componentDidUpdate () { + componentDidUpdate() { this.value = this.refs.code.value } - componentWillReceiveProps (props) { + componentWillReceiveProps(props) { if (props.value !== this.props.value) { this.queueRendering(props.value) } } - componentWillUnmount () { + componentWillUnmount() { this.cancelQueue() eventEmitter.off('editor:lock', this.lockEditorCode) eventEmitter.off('editor:focus', this.focusEditor.bind(this)) } - focusEditor () { - this.setState({ - status: 'CODE' - }, () => { - this.refs.code.focus() - }) + focusEditor() { + this.setState( + { + status: 'CODE' + }, + () => { + this.refs.code.focus() + } + ) } - queueRendering (value) { + queueRendering(value) { clearTimeout(this.renderTimer) this.renderTimer = setTimeout(() => { this.renderPreview(value) }, 500) } - cancelQueue () { + cancelQueue() { clearTimeout(this.renderTimer) } - renderPreview (value) { + renderPreview(value) { this.setState({ renderValue: value }) } - setValue (value) { + setValue(value) { this.refs.code.setValue(value) } - handleChange (e) { + handleChange(e) { this.value = this.refs.code.value this.props.onChange(e) } - handleContextMenu (e) { + handleContextMenu(e) { if (this.state.isLocked) return const { config } = this.props if (config.editor.switchPreview === 'RIGHTCLICK') { const newStatus = this.state.status === 'PREVIEW' ? 'CODE' : 'PREVIEW' - this.setState({ - status: newStatus - }, () => { - if (newStatus === 'CODE') { - this.refs.code.focus() - } else { - this.refs.preview.focus() - } - eventEmitter.emit('topbar:togglelockbutton', this.state.status) + this.setState( + { + status: newStatus + }, + () => { + if (newStatus === 'CODE') { + this.refs.code.focus() + } else { + this.refs.preview.focus() + } + eventEmitter.emit('topbar:togglelockbutton', this.state.status) - const newConfig = Object.assign({}, config) - newConfig.editor.delfaultStatus = newStatus - ConfigManager.set(newConfig) - }) + const newConfig = Object.assign({}, config) + newConfig.editor.delfaultStatus = newStatus + ConfigManager.set(newConfig) + } + ) } } - handleBlur (e) { + handleBlur(e) { if (this.state.isLocked) return this.setState({ keyPressed: new Set() }) const { config } = this.props - if (config.editor.switchPreview === 'BLUR' || - (config.editor.switchPreview === 'DBL_CLICK' && this.state.status === 'CODE') + if ( + config.editor.switchPreview === 'BLUR' || + (config.editor.switchPreview === 'DBL_CLICK' && + this.state.status === 'CODE') ) { const cursorPosition = this.refs.code.editor.getCursor() - this.setState({ - status: 'PREVIEW' - }, () => { - this.refs.preview.focus() - this.refs.preview.scrollToRow(cursorPosition.line) - }) + this.setState( + { + status: 'PREVIEW' + }, + () => { + this.refs.preview.focus() + this.refs.preview.scrollToRow(cursorPosition.line) + } + ) eventEmitter.emit('topbar:togglelockbutton', this.state.status) } } - handleDoubleClick (e) { + handleDoubleClick(e) { if (this.state.isLocked) return - this.setState({keyPressed: new Set()}) + this.setState({ keyPressed: new Set() }) const { config } = this.props if (config.editor.switchPreview === 'DBL_CLICK') { - this.setState({ - status: 'CODE' - }, () => { - this.refs.code.focus() - eventEmitter.emit('topbar:togglelockbutton', this.state.status) - }) + this.setState( + { + status: 'CODE' + }, + () => { + this.refs.code.focus() + eventEmitter.emit('topbar:togglelockbutton', this.state.status) + } + ) } } - handlePreviewMouseDown (e) { + handlePreviewMouseDown(e) { this.previewMouseDownedAt = new Date() } - handlePreviewMouseUp (e) { + handlePreviewMouseUp(e) { const { config } = this.props - if (config.editor.switchPreview === 'BLUR' && new Date() - this.previewMouseDownedAt < 200) { - this.setState({ - status: 'CODE' - }, () => { - this.refs.code.focus() - }) + if ( + config.editor.switchPreview === 'BLUR' && + new Date() - this.previewMouseDownedAt < 200 + ) { + this.setState( + { + status: 'CODE' + }, + () => { + this.refs.code.focus() + } + ) eventEmitter.emit('topbar:togglelockbutton', this.state.status) } } - handleCheckboxClick (e) { + handleCheckboxClick(e) { e.preventDefault() e.stopPropagation() const idMatch = /checkbox-([0-9]+)/ @@ -164,9 +187,9 @@ class MarkdownEditor extends React.Component { const checkReplace = /\[x]/i const uncheckReplace = /\[ ]/ if (idMatch.test(e.target.getAttribute('id'))) { - const lineIndex = parseInt(e.target.getAttribute('id').match(idMatch)[1], 10) - 1 - const lines = this.refs.code.value - .split('\n') + const lineIndex = + parseInt(e.target.getAttribute('id').match(idMatch)[1], 10) - 1 + const lines = this.refs.code.value.split('\n') const targetLine = lines[lineIndex] let newLine = targetLine @@ -181,45 +204,56 @@ class MarkdownEditor extends React.Component { } } - focus () { + focus() { if (this.state.status === 'PREVIEW') { - this.setState({ - status: 'CODE' - }, () => { - this.refs.code.focus() - }) + this.setState( + { + status: 'CODE' + }, + () => { + this.refs.code.focus() + } + ) } else { this.refs.code.focus() } eventEmitter.emit('topbar:togglelockbutton', this.state.status) } - reload () { + reload() { this.refs.code.reload() this.cancelQueue() this.renderPreview(this.props.value) } - handleKeyDown (e) { + handleKeyDown(e) { const { config } = this.props if (this.state.status !== 'CODE') return false const keyPressed = this.state.keyPressed keyPressed.add(e.keyCode) this.setState({ keyPressed }) - const isNoteHandlerKey = (el) => { return keyPressed.has(el) } + const isNoteHandlerKey = el => { + return keyPressed.has(el) + } // These conditions are for ctrl-e and ctrl-w - if (keyPressed.size === this.escapeFromEditor.length && - !this.state.isLocked && this.state.status === 'CODE' && - this.escapeFromEditor.every(isNoteHandlerKey)) { + if ( + keyPressed.size === this.escapeFromEditor.length && + !this.state.isLocked && + this.state.status === 'CODE' && + this.escapeFromEditor.every(isNoteHandlerKey) + ) { this.handleContextMenu() if (config.editor.switchPreview === 'BLUR') document.activeElement.blur() } - if (keyPressed.size === this.supportMdSelectionBold.length && this.supportMdSelectionBold.every(isNoteHandlerKey)) { + if ( + keyPressed.size === this.supportMdSelectionBold.length && + this.supportMdSelectionBold.every(isNoteHandlerKey) + ) { this.addMdAroundWord('**') } } - addMdAroundWord (mdElement) { + addMdAroundWord(mdElement) { if (this.refs.code.editor.getSelection()) { return this.addMdAroundSelection(mdElement) } @@ -227,47 +261,63 @@ class MarkdownEditor extends React.Component { const word = this.refs.code.editor.findWordAt(currentCaret) const cmDoc = this.refs.code.editor.getDoc() cmDoc.replaceRange(mdElement, word.anchor) - cmDoc.replaceRange(mdElement, { line: word.head.line, ch: word.head.ch + mdElement.length }) - } - - addMdAroundSelection (mdElement) { - this.refs.code.editor.replaceSelection(`${mdElement}${this.refs.code.editor.getSelection()}${mdElement}`) - } - - handleDropImage (dropEvent) { - dropEvent.preventDefault() - const { storageKey, noteKey } = this.props - - this.setState({ - status: 'CODE' - }, () => { - this.refs.code.focus() - - this.refs.code.editor.execCommand('goDocEnd') - this.refs.code.editor.execCommand('goLineEnd') - this.refs.code.editor.execCommand('newlineAndIndent') - - attachmentManagement.handleAttachmentDrop( - this.refs.code, - storageKey, - noteKey, - dropEvent - ) + cmDoc.replaceRange(mdElement, { + line: word.head.line, + ch: word.head.ch + mdElement.length }) } - handleKeyUp (e) { + addMdAroundSelection(mdElement) { + this.refs.code.editor.replaceSelection( + `${mdElement}${this.refs.code.editor.getSelection()}${mdElement}` + ) + } + + handleDropImage(dropEvent) { + dropEvent.preventDefault() + const { storageKey, noteKey } = this.props + + this.setState( + { + status: 'CODE' + }, + () => { + this.refs.code.focus() + + this.refs.code.editor.execCommand('goDocEnd') + this.refs.code.editor.execCommand('goLineEnd') + this.refs.code.editor.execCommand('newlineAndIndent') + + attachmentManagement.handleAttachmentDrop( + this.refs.code, + storageKey, + noteKey, + dropEvent + ) + } + ) + } + + handleKeyUp(e) { const keyPressed = this.state.keyPressed keyPressed.delete(e.keyCode) this.setState({ keyPressed }) } - handleLockEditor () { + handleLockEditor() { this.setState({ isLocked: !this.state.isLocked }) } - render () { - const {className, value, config, storageKey, noteKey, linesHighlighted, RTL} = this.props + render() { + const { + className, + value, + config, + storageKey, + noteKey, + linesHighlighted, + RTL + } = this.props let editorFontSize = parseInt(config.editor.fontSize, 10) if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14 @@ -275,23 +325,24 @@ class MarkdownEditor extends React.Component { if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4 const previewStyle = {} - if (this.props.ignorePreviewPointerEvents) previewStyle.pointerEvents = 'none' + if (this.props.ignorePreviewPointerEvents) + previewStyle.pointerEvents = 'none' const storage = findStorage(storageKey) return ( -
this.handleContextMenu(e)} + onContextMenu={e => this.handleContextMenu(e)} tabIndex='-1' - onKeyDown={(e) => this.handleKeyDown(e)} - onKeyUp={(e) => this.handleKeyUp(e)} + onKeyDown={e => this.handleKeyDown(e)} + onKeyUp={e => this.handleKeyUp(e)} > - this.handleChange(e)} - onBlur={(e) => this.handleBlur(e)} + onChange={e => this.handleChange(e)} + onBlur={e => this.handleBlur(e)} spellCheck={config.editor.spellcheck} enableSmartPaste={config.editor.enableSmartPaste} hotkey={config.hotkey} @@ -327,9 +378,9 @@ class MarkdownEditor extends React.Component { deleteUnusedAttachments={config.editor.deleteUnusedAttachments} RTL={RTL} /> - this.handleContextMenu(e)} - onDoubleClick={(e) => this.handleDoubleClick(e)} + onContextMenu={e => this.handleContextMenu(e)} + onDoubleClick={e => this.handleDoubleClick(e)} tabIndex='0' value={this.state.renderValue} - onMouseUp={(e) => this.handlePreviewMouseUp(e)} - onMouseDown={(e) => this.handlePreviewMouseDown(e)} - onCheckboxClick={(e) => this.handleCheckboxClick(e)} + onMouseUp={e => this.handlePreviewMouseUp(e)} + onMouseDown={e => this.handlePreviewMouseDown(e)} + onCheckboxClick={e => this.handleCheckboxClick(e)} showCopyNotification={config.ui.showCopyNotification} storagePath={storage.path} noteKey={noteKey} customCSS={config.preview.customCSS} allowCustomCSS={config.preview.allowCustomCSS} lineThroughCheckbox={config.preview.lineThroughCheckbox} - onDrop={(e) => this.handleDropImage(e)} + onDrop={e => this.handleDropImage(e)} RTL={RTL} />
diff --git a/browser/components/MarkdownPreview.js b/browser/components/MarkdownPreview.js index fc5aa95c..75635c89 100755 --- a/browser/components/MarkdownPreview.js +++ b/browser/components/MarkdownPreview.js @@ -26,7 +26,8 @@ import i18n from 'browser/lib/i18n' const { remote, shell } = require('electron') const attachmentManagement = require('../main/lib/dataApi/attachmentManagement') -const buildMarkdownPreviewContextMenu = require('browser/lib/contextMenuBuilder').buildMarkdownPreviewContextMenu +const buildMarkdownPreviewContextMenu = require('browser/lib/contextMenuBuilder') + .buildMarkdownPreviewContextMenu const { app } = remote const path = require('path') @@ -56,7 +57,7 @@ const CSS_FILES = [ * @param {String} [opts.customCSS] Will be added to bottom, only if `opts.allowCustomCSS` is truthy * @returns {String} */ -function buildStyle (opts) { +function buildStyle(opts) { const { fontFamily, fontSize, @@ -104,11 +105,14 @@ body { font-family: '${fontFamily.join("','")}'; font-size: ${fontSize}px; - ${scrollPastEnd ? ` + ${ + scrollPastEnd + ? ` padding-bottom: 90vh; box-sizing: border-box; ` - : ''} + : '' + } ${RTL ? 'direction: rtl;' : ''} ${RTL ? 'text-align: right;' : ''} } @@ -225,7 +229,7 @@ const defaultCodeBlockFontFamily = [ // return the line number of the line that used to generate the specified element // return -1 if the line is not found -function getSourceLineNumberByElement (element) { +function getSourceLineNumberByElement(element) { let isHasLineNumber = element.dataset.line !== undefined let parent = element while (!isHasLineNumber && parent.parentElement !== null) { @@ -236,7 +240,7 @@ function getSourceLineNumberByElement (element) { } export default class MarkdownPreview extends React.Component { - constructor (props) { + constructor(props) { super(props) this.contextMenuHandler = e => this.handleContextMenu(e) @@ -260,7 +264,7 @@ export default class MarkdownPreview extends React.Component { this.initMarkdown() } - initMarkdown () { + initMarkdown() { const { smartQuotes, sanitize, breaks } = this.props this.markdown = new Markdown({ typographer: smartQuotes, @@ -269,17 +273,17 @@ export default class MarkdownPreview extends React.Component { }) } - handleCheckboxClick (e) { + handleCheckboxClick(e) { this.props.onCheckboxClick(e) } - handleScroll (e) { + handleScroll(e) { if (this.props.onScroll) { this.props.onScroll(e) } } - handleContextMenu (event) { + handleContextMenu(event) { const menu = buildMarkdownPreviewContextMenu(this, event) const switchPreview = ConfigManager.get().editor.switchPreview if (menu != null && switchPreview !== 'RIGHTCLICK') { @@ -289,17 +293,21 @@ export default class MarkdownPreview extends React.Component { } } - handleDoubleClick (e) { + handleDoubleClick(e) { if (this.props.onDoubleClick != null) this.props.onDoubleClick(e) } - handleMouseDown (e) { + handleMouseDown(e) { const config = ConfigManager.get() const clickElement = e.target const targetTag = clickElement.tagName // The direct parent HTML of where was clicked ie "BODY" or "DIV" const lineNumber = getSourceLineNumberByElement(clickElement) // Line location of element clicked. - if (config.editor.switchPreview === 'RIGHTCLICK' && e.buttons === 2 && config.editor.type === 'SPLIT') { + if ( + config.editor.switchPreview === 'RIGHTCLICK' && + e.buttons === 2 && + config.editor.type === 'SPLIT' + ) { eventEmitter.emit('topbar:togglemodebutton', 'CODE') } if (e.ctrlKey) { @@ -315,10 +323,11 @@ export default class MarkdownPreview extends React.Component { } } - if (this.props.onMouseDown != null && targetTag === 'BODY') this.props.onMouseDown(e) + if (this.props.onMouseDown != null && targetTag === 'BODY') + this.props.onMouseDown(e) } - handleMouseUp (e) { + handleMouseUp(e) { if (!this.props.onMouseUp) return if (e.target != null && e.target.tagName === 'A') { return null @@ -326,15 +335,15 @@ export default class MarkdownPreview extends React.Component { if (this.props.onMouseUp != null) this.props.onMouseUp(e) } - handleSaveAsText () { + handleSaveAsText() { this.exportAsDocument('txt') } - handleSaveAsMd () { + handleSaveAsMd() { this.exportAsDocument('md') } - htmlContentFormatter (noteContent, exportTasks, targetDir) { + htmlContentFormatter(noteContent, exportTasks, targetDir) { const { fontFamily, fontSize, @@ -360,10 +369,7 @@ export default class MarkdownPreview extends React.Component { RTL }) let body = this.refs.root.contentWindow.document.body.innerHTML - body = attachmentManagement.fixLocalURLS( - body, - this.props.storagePath - ) + body = attachmentManagement.fixLocalURLS(body, this.props.storagePath) const files = [this.getCodeThemeLink(codeBlockTheme), ...CSS_FILES] files.forEach(file => { if (global.process.platform === 'win32') { @@ -394,14 +400,24 @@ export default class MarkdownPreview extends React.Component { ` } - handleSaveAsHtml () { - this.exportAsDocument('html', (noteContent, exportTasks, targetDir) => Promise.resolve(this.htmlContentFormatter(noteContent, exportTasks, targetDir))) + handleSaveAsHtml() { + this.exportAsDocument('html', (noteContent, exportTasks, targetDir) => + Promise.resolve( + this.htmlContentFormatter(noteContent, exportTasks, targetDir) + ) + ) } - handleSaveAsPdf () { + handleSaveAsPdf() { this.exportAsDocument('pdf', (noteContent, exportTasks, targetDir) => { - const printout = new remote.BrowserWindow({show: false, webPreferences: {webSecurity: false, javascript: false}}) - printout.loadURL('data:text/html;charset=UTF-8,' + this.htmlContentFormatter(noteContent, exportTasks, targetDir)) + const printout = new remote.BrowserWindow({ + show: false, + webPreferences: { webSecurity: false, javascript: false } + }) + printout.loadURL( + 'data:text/html;charset=UTF-8,' + + this.htmlContentFormatter(noteContent, exportTasks, targetDir) + ) return new Promise((resolve, reject) => { printout.webContents.on('did-finish-load', () => { printout.webContents.printToPDF({}, (err, data) => { @@ -414,11 +430,11 @@ export default class MarkdownPreview extends React.Component { }) } - handlePrint () { + handlePrint() { this.refs.root.contentWindow.print() } - exportAsDocument (fileType, contentFormatter) { + exportAsDocument(fileType, contentFormatter) { const options = { filters: [{ name: 'Documents', extensions: [fileType] }], properties: ['openFile', 'createDirectory'] @@ -449,7 +465,7 @@ export default class MarkdownPreview extends React.Component { }) } - fixDecodedURI (node) { + fixDecodedURI(node) { if ( node && node.children.length === 1 && @@ -466,17 +482,18 @@ export default class MarkdownPreview extends React.Component { * @param {string[]} splitWithCodeTag Array of HTML strings separated by three ``` * @returns {string} HTML in which special characters between three ``` have been converted */ - escapeHtmlCharactersInCodeTag (splitWithCodeTag) { + escapeHtmlCharactersInCodeTag(splitWithCodeTag) { for (let index = 0; index < splitWithCodeTag.length; index++) { - const codeTagRequired = (splitWithCodeTag[index] !== '\`\`\`' && index < splitWithCodeTag.length - 1) + const codeTagRequired = + splitWithCodeTag[index] !== '```' && index < splitWithCodeTag.length - 1 if (codeTagRequired) { - splitWithCodeTag.splice((index + 1), 0, '\`\`\`') + splitWithCodeTag.splice(index + 1, 0, '```') } } let inCodeTag = false let result = '' for (let content of splitWithCodeTag) { - if (content === '\`\`\`') { + if (content === '```') { inCodeTag = !inCodeTag } else if (inCodeTag) { content = escapeHtmlCharacters(content) @@ -486,13 +503,15 @@ export default class MarkdownPreview extends React.Component { return result } - getScrollBarStyle () { + getScrollBarStyle() { const { theme } = this.props - return uiThemes.some(item => item.name === theme && item.isDark) ? scrollBarDarkStyle : scrollBarStyle + return uiThemes.some(item => item.name === theme && item.isDark) + ? scrollBarDarkStyle + : scrollBarStyle } - componentDidMount () { + componentDidMount() { const { onDrop } = this.props this.refs.root.setAttribute('sandbox', 'allow-scripts') @@ -542,10 +561,7 @@ export default class MarkdownPreview extends React.Component { 'scroll', this.scrollHandler ) - this.refs.root.contentWindow.addEventListener( - 'resize', - this.resizeHandler - ) + this.refs.root.contentWindow.addEventListener('resize', this.resizeHandler) eventEmitter.on('export:save-text', this.saveAsTextHandler) eventEmitter.on('export:save-md', this.saveAsMdHandler) eventEmitter.on('export:save-html', this.saveAsHtmlHandler) @@ -553,7 +569,7 @@ export default class MarkdownPreview extends React.Component { eventEmitter.on('print', this.printHandler) } - componentWillUnmount () { + componentWillUnmount() { const { onDrop } = this.props this.refs.root.contentWindow.document.body.removeEventListener( @@ -595,7 +611,7 @@ export default class MarkdownPreview extends React.Component { eventEmitter.off('print', this.printHandler) } - componentDidUpdate (prevProps) { + componentDidUpdate(prevProps) { // actual rewriteIframe function should be called only once let needsRewriteIframe = false if (prevProps.value !== this.props.value) needsRewriteIframe = true @@ -637,7 +653,7 @@ export default class MarkdownPreview extends React.Component { } } - getStyleParams () { + getStyleParams() { const { fontSize, lineNumber, @@ -649,19 +665,20 @@ export default class MarkdownPreview extends React.Component { RTL } = this.props let { fontFamily, codeBlockFontFamily } = this.props - fontFamily = _.isString(fontFamily) && fontFamily.trim().length > 0 - ? fontFamily - .split(',') - .map(fontName => fontName.trim()) - .concat(defaultFontFamily) - : defaultFontFamily - codeBlockFontFamily = _.isString(codeBlockFontFamily) && - codeBlockFontFamily.trim().length > 0 - ? codeBlockFontFamily - .split(',') - .map(fontName => fontName.trim()) - .concat(defaultCodeBlockFontFamily) - : defaultCodeBlockFontFamily + fontFamily = + _.isString(fontFamily) && fontFamily.trim().length > 0 + ? fontFamily + .split(',') + .map(fontName => fontName.trim()) + .concat(defaultFontFamily) + : defaultFontFamily + codeBlockFontFamily = + _.isString(codeBlockFontFamily) && codeBlockFontFamily.trim().length > 0 + ? codeBlockFontFamily + .split(',') + .map(fontName => fontName.trim()) + .concat(defaultCodeBlockFontFamily) + : defaultCodeBlockFontFamily return { fontFamily, @@ -677,7 +694,7 @@ export default class MarkdownPreview extends React.Component { } } - applyStyle () { + applyStyle() { const { fontFamily, fontSize, @@ -707,7 +724,7 @@ export default class MarkdownPreview extends React.Component { }) } - getCodeThemeLink (name) { + getCodeThemeLink(name) { const theme = consts.THEMES.find(theme => theme.name === name) return theme != null @@ -715,7 +732,7 @@ export default class MarkdownPreview extends React.Component { : `${appPath}/node_modules/codemirror/theme/elegant.css` } - rewriteIframe () { + rewriteIframe() { _.forEach( this.refs.root.contentWindow.document.querySelectorAll( 'input[type="checkbox"]' @@ -773,7 +790,9 @@ export default class MarkdownPreview extends React.Component { codeBlockTheme = consts.THEMES.find(theme => theme.name === codeBlockTheme) - const codeBlockThemeClassName = codeBlockTheme ? codeBlockTheme.className : 'cm-s-default' + const codeBlockThemeClassName = codeBlockTheme + ? codeBlockTheme.className + : 'cm-s-default' _.forEach( this.refs.root.contentWindow.document.querySelectorAll('.code code'), @@ -859,7 +878,10 @@ export default class MarkdownPreview extends React.Component { el => { try { const format = el.attributes.getNamedItem('data-format').value - const chartConfig = format === 'yaml' ? yaml.load(el.innerHTML) : JSON.parse(el.innerHTML) + const chartConfig = + format === 'yaml' + ? yaml.load(el.innerHTML) + : JSON.parse(el.innerHTML) el.innerHTML = '' const canvas = document.createElement('canvas') @@ -882,7 +904,12 @@ export default class MarkdownPreview extends React.Component { _.forEach( this.refs.root.contentWindow.document.querySelectorAll('.mermaid'), el => { - mermaidRender(el, htmlTextHelper.decodeEntities(el.innerHTML), theme, mermaidHTMLLabel) + mermaidRender( + el, + htmlTextHelper.decodeEntities(el.innerHTML), + theme, + mermaidHTMLLabel + ) } ) @@ -904,20 +931,14 @@ export default class MarkdownPreview extends React.Component { autoplay = 0 } - render( - , - el - ) + render(, el) } ) const markdownPreviewIframe = document.querySelector('.MarkdownPreview') const rect = markdownPreviewIframe.getBoundingClientRect() const config = { attributes: true, subtree: true } - const imgObserver = new MutationObserver((mutationList) => { + const imgObserver = new MutationObserver(mutationList => { for (const mu of mutationList) { if (mu.target.className === 'carouselContent-enter-done') { this.setImgOnClickEventHelper(mu.target, rect) @@ -926,26 +947,32 @@ export default class MarkdownPreview extends React.Component { } }) - const imgList = markdownPreviewIframe.contentWindow.document.body.querySelectorAll('img') + const imgList = markdownPreviewIframe.contentWindow.document.body.querySelectorAll( + 'img' + ) for (const img of imgList) { const parentEl = img.parentElement this.setImgOnClickEventHelper(img, rect) imgObserver.observe(parentEl, config) } - const aList = markdownPreviewIframe.contentWindow.document.body.querySelectorAll('a') + 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) { + setImgOnClickEventHelper(img, rect) { img.onclick = () => { const widthMagnification = document.body.clientWidth / img.width const heightMagnification = document.body.clientHeight / img.height const baseOnWidth = widthMagnification < heightMagnification - const magnification = baseOnWidth ? widthMagnification : heightMagnification + const magnification = baseOnWidth + ? widthMagnification + : heightMagnification const zoomImgWidth = img.width * magnification const zoomImgHeight = img.height * magnification @@ -976,10 +1003,7 @@ export default class MarkdownPreview extends React.Component { width: ${zoomImgWidth}; height: ${zoomImgHeight}px; ` - zoomImg.animate([ - originalImgRect, - zoomInImgRect - ], animationSpeed) + zoomImg.animate([originalImgRect, zoomInImgRect], animationSpeed) const overlay = document.createElement('div') overlay.style = ` @@ -1000,10 +1024,10 @@ export default class MarkdownPreview extends React.Component { width: ${img.width}px; height: ${img.height}px; ` - const zoomOutImgAnimation = zoomImg.animate([ - zoomInImgRect, - originalImgRect - ], animationSpeed) + const zoomOutImgAnimation = zoomImg.animate( + [zoomInImgRect, originalImgRect], + animationSpeed + ) zoomOutImgAnimation.onfinish = () => overlay.remove() } @@ -1012,7 +1036,7 @@ export default class MarkdownPreview extends React.Component { } } - handleResize () { + handleResize() { _.forEach( this.refs.root.contentWindow.document.querySelectorAll('svg[ratio]'), el => { @@ -1021,11 +1045,11 @@ export default class MarkdownPreview extends React.Component { ) } - focus () { + focus() { this.refs.root.focus() } - getWindow () { + getWindow() { return this.refs.root.contentWindow } @@ -1033,7 +1057,7 @@ export default class MarkdownPreview extends React.Component { * @public * @param {Number} targetRow */ - scrollToRow (targetRow) { + scrollToRow(targetRow) { const blocks = this.getWindow().document.querySelectorAll( 'body>[data-line]' ) @@ -1054,16 +1078,16 @@ export default class MarkdownPreview extends React.Component { * @param {Number} x * @param {Number} y */ - scrollTo (x, y) { + scrollTo(x, y) { this.getWindow().document.body.scrollTo(x, y) } - preventImageDroppedHandler (e) { + preventImageDroppedHandler(e) { e.preventDefault() e.stopPropagation() } - notify (title, options) { + notify(title, options) { if (global.process.platform === 'win32') { options.icon = path.join( 'file://', @@ -1074,7 +1098,7 @@ export default class MarkdownPreview extends React.Component { return new window.Notification(title, options) } - handleLinkClick (e) { + handleLinkClick(e) { e.preventDefault() e.stopPropagation() @@ -1095,9 +1119,7 @@ export default class MarkdownPreview extends React.Component { if (posOfHash > -1) { const extractedId = linkHash.slice(posOfHash + 1) const targetId = mdurl.encode(extractedId) - const targetElement = this.getWindow().document.getElementById( - targetId - ) + const targetElement = this.getWindow().document.getElementById(targetId) if (targetElement != null) { this.scrollTo(0, targetElement.offsetTop) @@ -1138,9 +1160,10 @@ export default class MarkdownPreview extends React.Component { this.openExternal(href) } - openExternal (href) { + openExternal(href) { try { - const success = shell.openExternal(href) || shell.openExternal(decodeURI(href)) + const success = + shell.openExternal(href) || shell.openExternal(decodeURI(href)) if (!success) console.error('failed to open url ' + href) } catch (e) { // URI Error threw from decodeURI @@ -1148,7 +1171,7 @@ export default class MarkdownPreview extends React.Component { } } - render () { + render() { const { className, style, tabIndex } = this.props return ( \n\n## Docs :memo:\n- [Boostnote | Boost your happiness, productivity and creativity.](https://hackernoon.com/boostnote-boost-your-happiness-productivity-and-creativity-315034efeebe)\n- [Cloud Syncing & Backups](https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup)\n- [How to sync your data across Desktop and Mobile apps](https://github.com/BoostIO/Boostnote/wiki/Sync-Data-Across-Desktop-and-Mobile-apps)\n- [Convert data from **Evernote** to Boostnote.](https://github.com/BoostIO/Boostnote/wiki/Evernote)\n- [Keyboard Shortcuts](https://github.com/BoostIO/Boostnote/wiki/Keyboard-Shortcuts)\n- [Keymaps in Editor mode](https://github.com/BoostIO/Boostnote/wiki/Keymaps-in-Editor-mode)\n- [How to set syntax highlight in Snippet note](https://github.com/BoostIO/Boostnote/wiki/Syntax-Highlighting)\n\n---\n\n## Article Archive :books:\n- [Reddit English](http://bit.ly/2mOJPu7)\n- [Reddit Spanish](https://www.reddit.com/r/boostnote_es/)\n- [Reddit Chinese](https://www.reddit.com/r/boostnote_cn/)\n- [Reddit Japanese](https://www.reddit.com/r/boostnote_jp/)\n\n---\n\n## Community :beers:\n- [GitHub](http://bit.ly/2AWWzkD)\n- [Twitter](http://bit.ly/2z8BUJZ)\n- [Facebook Group](http://bit.ly/2jcca8t)' + content: + '# Welcome to Boostnote!\n## Click here to edit markdown :wave:\n\n\n\n## Docs :memo:\n- [Boostnote | Boost your happiness, productivity and creativity.](https://hackernoon.com/boostnote-boost-your-happiness-productivity-and-creativity-315034efeebe)\n- [Cloud Syncing & Backups](https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup)\n- [How to sync your data across Desktop and Mobile apps](https://github.com/BoostIO/Boostnote/wiki/Sync-Data-Across-Desktop-and-Mobile-apps)\n- [Convert data from **Evernote** to Boostnote.](https://github.com/BoostIO/Boostnote/wiki/Evernote)\n- [Keyboard Shortcuts](https://github.com/BoostIO/Boostnote/wiki/Keyboard-Shortcuts)\n- [Keymaps in Editor mode](https://github.com/BoostIO/Boostnote/wiki/Keymaps-in-Editor-mode)\n- [How to set syntax highlight in Snippet note](https://github.com/BoostIO/Boostnote/wiki/Syntax-Highlighting)\n\n---\n\n## Article Archive :books:\n- [Reddit English](http://bit.ly/2mOJPu7)\n- [Reddit Spanish](https://www.reddit.com/r/boostnote_es/)\n- [Reddit Chinese](https://www.reddit.com/r/boostnote_cn/)\n- [Reddit Japanese](https://www.reddit.com/r/boostnote_jp/)\n\n---\n\n## Community :beers:\n- [GitHub](http://bit.ly/2AWWzkD)\n- [Twitter](http://bit.ly/2z8BUJZ)\n- [Facebook Group](http://bit.ly/2jcca8t)' }) .then(note => { store.dispatch({ @@ -141,7 +145,7 @@ class Main extends React.Component { }) } - componentDidMount () { + componentDidMount() { const { dispatch, config } = this.props if (uiThemes.some(theme => theme.name === config.ui.theme)) { @@ -173,38 +177,44 @@ class Main extends React.Component { delete CodeMirror.keyMap.emacs['Ctrl-V'] eventEmitter.on('editor:fullscreen', this.toggleFullScreen) - eventEmitter.on('menubar:togglemenubar', this.toggleMenuBarVisible.bind(this)) + eventEmitter.on( + 'menubar:togglemenubar', + this.toggleMenuBarVisible.bind(this) + ) } - componentWillUnmount () { + componentWillUnmount() { eventEmitter.off('editor:fullscreen', this.toggleFullScreen) - eventEmitter.off('menubar:togglemenubar', this.toggleMenuBarVisible.bind(this)) + eventEmitter.off( + 'menubar:togglemenubar', + this.toggleMenuBarVisible.bind(this) + ) } - toggleMenuBarVisible () { + toggleMenuBarVisible() { const { config } = this.props const { ui } = config - const newUI = Object.assign(ui, {showMenuBar: !ui.showMenuBar}) + const newUI = Object.assign(ui, { showMenuBar: !ui.showMenuBar }) const newConfig = Object.assign(config, newUI) ConfigManager.set(newConfig) } - handleLeftSlideMouseDown (e) { + handleLeftSlideMouseDown(e) { e.preventDefault() this.setState({ isLeftSliderFocused: true }) } - handleRightSlideMouseDown (e) { + handleRightSlideMouseDown(e) { e.preventDefault() this.setState({ isRightSliderFocused: true }) } - handleMouseUp (e) { + handleMouseUp(e) { // Change width of NoteList component. if (this.state.isRightSliderFocused) { this.setState( @@ -244,7 +254,7 @@ class Main extends React.Component { } } - handleMouseMove (e) { + handleMouseMove(e) { if (this.state.isRightSliderFocused) { const offset = this.refs.body.getBoundingClientRect().left let newListWidth = e.pageX - offset @@ -270,7 +280,7 @@ class Main extends React.Component { } } - handleFullScreenButton (e) { + handleFullScreenButton(e) { this.setState({ fullScreen: !this.state.fullScreen }, () => { const noteDetail = document.querySelector('.NoteDetail') const noteList = document.querySelector('.NoteList') @@ -284,7 +294,7 @@ class Main extends React.Component { }) } - hideLeftLists (noteDetail, noteList, mainBody) { + hideLeftLists(noteDetail, noteList, mainBody) { this.setState({ noteDetailWidth: noteDetail.style.left }) this.setState({ mainBodyWidth: mainBody.style.left }) noteDetail.style.left = '0px' @@ -292,13 +302,13 @@ class Main extends React.Component { noteList.style.display = 'none' } - showLeftLists (noteDetail, noteList, mainBody) { + showLeftLists(noteDetail, noteList, mainBody) { noteDetail.style.left = this.state.noteDetailWidth mainBody.style.left = this.state.mainBodyWidth noteList.style.display = 'inline' } - render () { + render() { const { config } = this.props // the width of the navigation bar when it is folded/collapsed @@ -312,10 +322,16 @@ class Main extends React.Component { onMouseUp={e => this.handleMouseUp(e)} > - {!config.isSideNavFolded && + {!config.isSideNavFolded && (
-
} +
+ )}
- -
-
this.handleNoteListKeyDown(e)} + onKeyDown={e => this.handleNoteListKeyDown(e)} onKeyUp={this.handleNoteListKeyUp} onBlur={this.handleNoteListBlur} > diff --git a/browser/main/SideNav/ListButton.js b/browser/main/SideNav/ListButton.js index b5bc1488..dc9ba1cc 100644 --- a/browser/main/SideNav/ListButton.js +++ b/browser/main/SideNav/ListButton.js @@ -4,14 +4,17 @@ import CSSModules from 'browser/lib/CSSModules' import styles from './SwitchButton.styl' import i18n from 'browser/lib/i18n' -const ListButton = ({ - onClick, isTagActive -}) => ( - diff --git a/browser/main/SideNav/PreferenceButton.js b/browser/main/SideNav/PreferenceButton.js index 187bc41a..25499463 100644 --- a/browser/main/SideNav/PreferenceButton.js +++ b/browser/main/SideNav/PreferenceButton.js @@ -4,10 +4,8 @@ import CSSModules from 'browser/lib/CSSModules' import styles from './PreferenceButton.styl' import i18n from 'browser/lib/i18n' -const PreferenceButton = ({ - onClick -}) => ( - diff --git a/browser/main/SideNav/StorageItem.js b/browser/main/SideNav/StorageItem.js index 5cd4a491..a20b0df1 100644 --- a/browser/main/SideNav/StorageItem.js +++ b/browser/main/SideNav/StorageItem.js @@ -19,7 +19,7 @@ const escapeStringRegexp = require('escape-string-regexp') const path = require('path') class StorageItem extends React.Component { - constructor (props) { + constructor(props) { super(props) const { storage } = this.props @@ -30,11 +30,11 @@ class StorageItem extends React.Component { } } - handleHeaderContextMenu (e) { + handleHeaderContextMenu(e) { context.popup([ { label: i18n.__('Add Folder'), - click: (e) => this.handleAddFolderButtonClick(e) + click: e => this.handleAddFolderButtonClick(e) }, { type: 'separator' @@ -44,11 +44,11 @@ class StorageItem extends React.Component { submenu: [ { label: i18n.__('Export as txt'), - click: (e) => this.handleExportStorageClick(e, 'txt') + click: e => this.handleExportStorageClick(e, 'txt') }, { label: i18n.__('Export as md'), - click: (e) => this.handleExportStorageClick(e, 'md') + click: e => this.handleExportStorageClick(e, 'md') } ] }, @@ -57,75 +57,74 @@ class StorageItem extends React.Component { }, { label: i18n.__('Unlink Storage'), - click: (e) => this.handleUnlinkStorageClick(e) + click: e => this.handleUnlinkStorageClick(e) } ]) } - handleUnlinkStorageClick (e) { + handleUnlinkStorageClick(e) { const index = dialog.showMessageBox(remote.getCurrentWindow(), { type: 'warning', message: i18n.__('Unlink Storage'), - detail: i18n.__('This work will just detatches a storage from Boostnote. (Any data won\'t be deleted.)'), + detail: i18n.__( + "This work will just detatches a storage from Boostnote. (Any data won't be deleted.)" + ), buttons: [i18n.__('Confirm'), i18n.__('Cancel')] }) if (index === 0) { const { storage, dispatch } = this.props - dataApi.removeStorage(storage.key) + dataApi + .removeStorage(storage.key) .then(() => { dispatch({ type: 'REMOVE_STORAGE', storageKey: storage.key }) }) - .catch((err) => { + .catch(err => { throw err }) } } - handleExportStorageClick (e, fileType) { + handleExportStorageClick(e, fileType) { const options = { properties: ['openDirectory', 'createDirectory'], buttonLabel: i18n.__('Select directory'), title: i18n.__('Select a folder to export the files to'), multiSelections: false } - dialog.showOpenDialog(remote.getCurrentWindow(), options, - (paths) => { - if (paths && paths.length === 1) { - const { storage, dispatch } = this.props - dataApi - .exportStorage(storage.key, fileType, paths[0]) - .then(data => { - dispatch({ - type: 'EXPORT_STORAGE', - storage: data.storage, - fileType: data.fileType - }) - }) - } - }) + dialog.showOpenDialog(remote.getCurrentWindow(), options, paths => { + if (paths && paths.length === 1) { + const { storage, dispatch } = this.props + dataApi.exportStorage(storage.key, fileType, paths[0]).then(data => { + dispatch({ + type: 'EXPORT_STORAGE', + storage: data.storage, + fileType: data.fileType + }) + }) + } + }) } - handleToggleButtonClick (e) { + handleToggleButtonClick(e) { const { storage, dispatch } = this.props const isOpen = !this.state.isOpen - dataApi.toggleStorage(storage.key, isOpen) - .then((storage) => { - dispatch({ - type: 'EXPAND_STORAGE', - storage, - isOpen - }) + dataApi.toggleStorage(storage.key, isOpen).then(storage => { + dispatch({ + type: 'EXPAND_STORAGE', + storage, + isOpen }) + }) this.setState({ isOpen: isOpen }) } - handleAddFolderButtonClick (e) { + handleAddFolderButtonClick(e) { const { storage } = this.props modal.open(CreateFolderModal, { @@ -133,23 +132,23 @@ class StorageItem extends React.Component { }) } - handleHeaderInfoClick (e) { + handleHeaderInfoClick(e) { const { storage, dispatch } = this.props dispatch(push('/storages/' + storage.key)) } - handleFolderButtonClick (folderKey) { - return (e) => { + handleFolderButtonClick(folderKey) { + return e => { const { storage, dispatch } = this.props dispatch(push('/storages/' + storage.key + '/folders/' + folderKey)) } } - handleFolderButtonContextMenu (e, folder) { + handleFolderButtonContextMenu(e, folder) { context.popup([ { label: i18n.__('Rename Folder'), - click: (e) => this.handleRenameFolderClick(e, folder) + click: e => this.handleRenameFolderClick(e, folder) }, { type: 'separator' @@ -159,11 +158,11 @@ class StorageItem extends React.Component { submenu: [ { label: i18n.__('Export as txt'), - click: (e) => this.handleExportFolderClick(e, folder, 'txt') + click: e => this.handleExportFolderClick(e, folder, 'txt') }, { label: i18n.__('Export as md'), - click: (e) => this.handleExportFolderClick(e, folder, 'md') + click: e => this.handleExportFolderClick(e, folder, 'md') } ] }, @@ -172,12 +171,12 @@ class StorageItem extends React.Component { }, { label: i18n.__('Delete Folder'), - click: (e) => this.handleFolderDeleteClick(e, folder) + click: e => this.handleFolderDeleteClick(e, folder) } ]) } - handleRenameFolderClick (e, folder) { + handleRenameFolderClick(e, folder) { const { storage } = this.props modal.open(RenameFolderModal, { storage, @@ -185,20 +184,19 @@ class StorageItem extends React.Component { }) } - handleExportFolderClick (e, folder, fileType) { + handleExportFolderClick(e, folder, fileType) { const options = { properties: ['openDirectory', 'createDirectory'], buttonLabel: i18n.__('Select directory'), title: i18n.__('Select a folder to export the files to'), multiSelections: false } - dialog.showOpenDialog(remote.getCurrentWindow(), options, - (paths) => { + dialog.showOpenDialog(remote.getCurrentWindow(), options, paths => { if (paths && paths.length === 1) { const { storage, dispatch } = this.props dataApi .exportFolder(storage.key, folder.key, fileType, paths[0]) - .then((data) => { + .then(data => { dispatch({ type: 'EXPORT_FOLDER', storage: data.storage, @@ -224,66 +222,74 @@ class StorageItem extends React.Component { }) } - handleFolderDeleteClick (e, folder) { + handleFolderDeleteClick(e, folder) { const index = dialog.showMessageBox(remote.getCurrentWindow(), { type: 'warning', message: i18n.__('Delete Folder'), - detail: i18n.__('This will delete all notes in the folder and can not be undone.'), + detail: i18n.__( + 'This will delete all notes in the folder and can not be undone.' + ), buttons: [i18n.__('Confirm'), i18n.__('Cancel')] }) if (index === 0) { const { storage, dispatch } = this.props - dataApi - .deleteFolder(storage.key, folder.key) - .then((data) => { - dispatch({ - type: 'DELETE_FOLDER', - storage: data.storage, - folderKey: data.folderKey - }) + dataApi.deleteFolder(storage.key, folder.key).then(data => { + dispatch({ + type: 'DELETE_FOLDER', + storage: data.storage, + folderKey: data.folderKey }) + }) } } - handleDragEnter (e, key) { + handleDragEnter(e, key) { e.preventDefault() - if (this.state.draggedOver === key) { return } + if (this.state.draggedOver === key) { + return + } this.setState({ draggedOver: key }) } - handleDragLeave (e) { + handleDragLeave(e) { e.preventDefault() - if (this.state.draggedOver === null) { return } + if (this.state.draggedOver === null) { + return + } this.setState({ draggedOver: null }) } - dropNote (storage, folder, dispatch, location, noteData) { - noteData = noteData.filter((note) => folder.key !== note.folder) + dropNote(storage, folder, dispatch, location, noteData) { + noteData = noteData.filter(note => folder.key !== note.folder) if (noteData.length === 0) return Promise.all( - noteData.map((note) => dataApi.moveNote(note.storage, note.key, storage.key, folder.key)) + noteData.map(note => + dataApi.moveNote(note.storage, note.key, storage.key, folder.key) + ) ) - .then((createdNoteData) => { - createdNoteData.forEach((newNote) => { - dispatch({ - type: 'MOVE_NOTE', - originNote: noteData.find((note) => note.content === newNote.oldContent), - note: newNote + .then(createdNoteData => { + createdNoteData.forEach(newNote => { + dispatch({ + type: 'MOVE_NOTE', + originNote: noteData.find( + note => note.content === newNote.oldContent + ), + note: newNote + }) }) }) - }) - .catch((err) => { - console.error(`error on delete notes: ${err}`) - }) + .catch(err => { + console.error(`error on delete notes: ${err}`) + }) } - handleDrop (e, storage, folder, dispatch, location) { + handleDrop(e, storage, folder, dispatch, location) { e.preventDefault() if (this.state.draggedOver !== null) { this.setState({ @@ -294,21 +300,37 @@ class StorageItem extends React.Component { this.dropNote(storage, folder, dispatch, location, noteData) } - render () { + render() { const { storage, location, isFolded, data, dispatch } = this.props const { folderNoteMap, trashedSet } = data const SortableStorageItemChild = SortableElement(StorageItemChild) const folderList = storage.folders.map((folder, index) => { - const folderRegex = new RegExp(escapeStringRegexp(path.sep) + 'storages' + escapeStringRegexp(path.sep) + storage.key + escapeStringRegexp(path.sep) + 'folders' + escapeStringRegexp(path.sep) + folder.key) - const isActive = !!(location.pathname.match(folderRegex)) + const folderRegex = new RegExp( + escapeStringRegexp(path.sep) + + 'storages' + + escapeStringRegexp(path.sep) + + storage.key + + escapeStringRegexp(path.sep) + + 'folders' + + escapeStringRegexp(path.sep) + + folder.key + ) + const isActive = !!location.pathname.match(folderRegex) const noteSet = folderNoteMap.get(storage.key + '-' + folder.key) let noteCount = 0 if (noteSet) { let trashedNoteCount = 0 - const noteKeys = noteSet.map(noteKey => { return noteKey }) + const noteKeys = noteSet.map(noteKey => { + return noteKey + }) trashedSet.toJS().forEach(trashedKey => { - if (noteKeys.some(noteKey => { return noteKey === trashedKey })) trashedNoteCount++ + if ( + noteKeys.some(noteKey => { + return noteKey === trashedKey + }) + ) + trashedNoteCount++ }) noteCount = noteSet.size - trashedNoteCount } @@ -317,73 +339,80 @@ class StorageItem extends React.Component { key={folder.key} index={index} isActive={isActive || folder.key === this.state.draggedOver} - handleButtonClick={(e) => this.handleFolderButtonClick(folder.key)(e)} - handleContextMenu={(e) => this.handleFolderButtonContextMenu(e, folder)} + handleButtonClick={e => this.handleFolderButtonClick(folder.key)(e)} + handleContextMenu={e => this.handleFolderButtonContextMenu(e, folder)} folderName={folder.name} folderColor={folder.color} isFolded={isFolded} noteCount={noteCount} - handleDrop={(e) => { + handleDrop={e => { this.handleDrop(e, storage, folder, dispatch, location) }} - handleDragEnter={(e) => { + handleDragEnter={e => { this.handleDragEnter(e, folder.key) }} - handleDragLeave={(e) => { + handleDragLeave={e => { this.handleDragLeave(e, folder) }} /> ) }) - const isActive = location.pathname.match(new RegExp(escapeStringRegexp(path.sep) + 'storages' + escapeStringRegexp(path.sep) + storage.key + '$')) + const isActive = location.pathname.match( + new RegExp( + escapeStringRegexp(path.sep) + + 'storages' + + escapeStringRegexp(path.sep) + + storage.key + + '$' + ) + ) return ( -
-
this.handleHeaderContextMenu(e)} +
+
this.handleHeaderContextMenu(e)} > - - {!isFolded && - - } + )} -
- {this.state.isOpen && -
- {folderList} -
- } + {this.state.isOpen &&
{folderList}
}
) } diff --git a/browser/main/SideNav/TagButton.js b/browser/main/SideNav/TagButton.js index d91ae2c4..268e0d7e 100644 --- a/browser/main/SideNav/TagButton.js +++ b/browser/main/SideNav/TagButton.js @@ -4,14 +4,17 @@ import CSSModules from 'browser/lib/CSSModules' import styles from './SwitchButton.styl' import i18n from 'browser/lib/i18n' -const TagButton = ({ - onClick, isTagActive -}) => ( - diff --git a/browser/main/SideNav/index.js b/browser/main/SideNav/index.js index 241d4151..dcda9a27 100644 --- a/browser/main/SideNav/index.js +++ b/browser/main/SideNav/index.js @@ -16,7 +16,7 @@ import EventEmitter from 'browser/main/lib/eventEmitter' import PreferenceButton from './PreferenceButton' import ListButton from './ListButton' import TagButton from './TagButton' -import {SortableContainer} from 'react-sortable-hoc' +import { SortableContainer } from 'react-sortable-hoc' import i18n from 'browser/lib/i18n' import context from 'browser/lib/context' import { remote } from 'electron' @@ -24,13 +24,13 @@ import { confirmDeleteNote } from 'browser/lib/confirmDeleteNote' import ColorPicker from 'browser/components/ColorPicker' import { every, sortBy } from 'lodash' -function matchActiveTags (tags, activeTags) { +function matchActiveTags(tags, activeTags) { return every(activeTags, v => tags.indexOf(v) >= 0) } class SideNav extends React.Component { // TODO: should not use electron stuff v0.7 - constructor (props) { + constructor(props) { super(props) this.state = { @@ -47,24 +47,32 @@ class SideNav extends React.Component { this.handleColorPickerReset = this.handleColorPickerReset.bind(this) } - componentDidMount () { + componentDidMount() { EventEmitter.on('side:preferences', this.handleMenuButtonClick) } - componentWillUnmount () { + componentWillUnmount() { EventEmitter.off('side:preferences', this.handleMenuButtonClick) } - deleteTag (tag) { - const selectedButton = remote.dialog.showMessageBox(remote.getCurrentWindow(), { - type: 'warning', - message: i18n.__('Confirm tag deletion'), - detail: i18n.__('This will permanently remove this tag.'), - buttons: [i18n.__('Confirm'), i18n.__('Cancel')] - }) + deleteTag(tag) { + const selectedButton = remote.dialog.showMessageBox( + remote.getCurrentWindow(), + { + type: 'warning', + message: i18n.__('Confirm tag deletion'), + detail: i18n.__('This will permanently remove this tag.'), + buttons: [i18n.__('Confirm'), i18n.__('Cancel')] + } + ) if (selectedButton === 0) { - const { data, dispatch, location, match: { params } } = this.props + const { + data, + dispatch, + location, + match: { params } + } = this.props const notes = data.noteMap .map(note => note) @@ -78,44 +86,48 @@ class SideNav extends React.Component { return note }) - Promise - .all(notes.map(note => dataApi.updateNote(note.storage, note.key, note))) - .then(updatedNotes => { - updatedNotes.forEach(note => { - dispatch({ - type: 'UPDATE_NOTE', - note - }) + Promise.all( + notes.map(note => dataApi.updateNote(note.storage, note.key, note)) + ).then(updatedNotes => { + updatedNotes.forEach(note => { + dispatch({ + type: 'UPDATE_NOTE', + note }) - - if (location.pathname.match('/tags')) { - const tags = params.tagname.split(' ') - const index = tags.indexOf(tag) - if (index !== -1) { - tags.splice(index, 1) - - dispatch(push(`/tags/${tags.map(tag => encodeURIComponent(tag)).join(' ')}`)) - } - } }) + + if (location.pathname.match('/tags')) { + const tags = params.tagname.split(' ') + const index = tags.indexOf(tag) + if (index !== -1) { + tags.splice(index, 1) + + dispatch( + push( + `/tags/${tags.map(tag => encodeURIComponent(tag)).join(' ')}` + ) + ) + } + } + }) } } - handleMenuButtonClick (e) { + handleMenuButtonClick(e) { openModal(PreferencesModal) } - handleHomeButtonClick (e) { + handleHomeButtonClick(e) { const { dispatch } = this.props dispatch(push('/home')) } - handleStarredButtonClick (e) { + handleStarredButtonClick(e) { const { dispatch } = this.props dispatch(push('/starred')) } - handleTagContextMenu (e, tag) { + handleTagContextMenu(e, tag) { const menu = [] menu.push({ @@ -125,13 +137,17 @@ class SideNav extends React.Component { menu.push({ label: i18n.__('Customize Color'), - click: this.displayColorPicker.bind(this, tag, e.target.getBoundingClientRect()) + click: this.displayColorPicker.bind( + this, + tag, + e.target.getBoundingClientRect() + ) }) context.popup(menu) } - dismissColorPicker () { + dismissColorPicker() { this.setState({ colorPicker: { show: false @@ -139,7 +155,7 @@ class SideNav extends React.Component { }) } - displayColorPicker (tagName, rect) { + displayColorPicker(tagName, rect) { const { config } = this.props this.setState({ colorPicker: { @@ -151,10 +167,17 @@ class SideNav extends React.Component { }) } - handleColorPickerConfirm (color) { - const { dispatch, config: {coloredTags} } = this.props - const { colorPicker: { tagName } } = this.state - const newColoredTags = Object.assign({}, coloredTags, {[tagName]: color.hex}) + handleColorPickerConfirm(color) { + const { + dispatch, + config: { coloredTags } + } = this.props + const { + colorPicker: { tagName } + } = this.state + const newColoredTags = Object.assign({}, coloredTags, { + [tagName]: color.hex + }) const config = { coloredTags: newColoredTags } ConfigManager.set(config) @@ -165,9 +188,14 @@ class SideNav extends React.Component { this.dismissColorPicker() } - handleColorPickerReset () { - const { dispatch, config: {coloredTags} } = this.props - const { colorPicker: { tagName } } = this.state + handleColorPickerReset() { + const { + dispatch, + config: { coloredTags } + } = this.props + const { + colorPicker: { tagName } + } = this.state const newColoredTags = Object.assign({}, coloredTags) delete newColoredTags[tagName] @@ -181,43 +209,41 @@ class SideNav extends React.Component { this.dismissColorPicker() } - handleToggleButtonClick (e) { + handleToggleButtonClick(e) { const { dispatch, config } = this.props - ConfigManager.set({isSideNavFolded: !config.isSideNavFolded}) + ConfigManager.set({ isSideNavFolded: !config.isSideNavFolded }) dispatch({ type: 'SET_IS_SIDENAV_FOLDED', isFolded: !config.isSideNavFolded }) } - handleTrashedButtonClick (e) { + handleTrashedButtonClick(e) { const { dispatch } = this.props dispatch(push('/trashed')) } - handleSwitchFoldersButtonClick () { + handleSwitchFoldersButtonClick() { const { dispatch } = this.props dispatch(push('/home')) } - handleSwitchTagsButtonClick () { + handleSwitchTagsButtonClick() { const { dispatch } = this.props dispatch(push('/alltags')) } - onSortEnd (storage) { - return ({oldIndex, newIndex}) => { + onSortEnd(storage) { + return ({ oldIndex, newIndex }) => { const { dispatch } = this.props - dataApi - .reorderFolder(storage.key, oldIndex, newIndex) - .then((data) => { - dispatch({ type: 'REORDER_FOLDER', storage: data.storage }) - }) + dataApi.reorderFolder(storage.key, oldIndex, newIndex).then(data => { + dispatch({ type: 'REORDER_FOLDER', storage: data.storage }) + }) } } - SideNavComponent (isFolded, storageList) { + SideNavComponent(isFolded, storageList) { const { location, data, config } = this.props const isHomeActive = !!location.pathname.match(/^\/home$/) @@ -227,25 +253,35 @@ class SideNav extends React.Component { let component // TagsMode is not selected - if (!location.pathname.match('/tags') && !location.pathname.match('/alltags')) { + if ( + !location.pathname.match('/tags') && + !location.pathname.match('/alltags') + ) { component = (
this.handleHomeButtonClick(e)} + handleAllNotesButtonClick={e => this.handleHomeButtonClick(e)} isStarredActive={isStarredActive} isTrashedActive={isTrashedActive} - handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)} - handleTrashedButtonClick={(e) => this.handleTrashedButtonClick(e)} - counterTotalNote={data.noteMap._map.size - data.trashedSet._set.size} + handleStarredButtonClick={e => this.handleStarredButtonClick(e)} + handleTrashedButtonClick={e => this.handleTrashedButtonClick(e)} + counterTotalNote={ + data.noteMap._map.size - data.trashedSet._set.size + } counterStarredNote={data.starredSet._set.size} counterDelNote={data.trashedSet._set.size} - handleFilterButtonContextMenu={this.handleFilterButtonContextMenu.bind(this)} + handleFilterButtonContextMenu={this.handleFilterButtonContextMenu.bind( + this + )} /> - +
) } else { @@ -257,22 +293,26 @@ class SideNav extends React.Component {
-
-
- {this.tagListComponent(data)} -
- +
{this.tagListComponent(data)}
+
) } @@ -280,82 +320,84 @@ class SideNav extends React.Component { return component } - tagListComponent () { + tagListComponent() { const { data, location, config } = this.props const { colorPicker } = this.state const activeTags = this.getActiveTags(location.pathname) const relatedTags = this.getRelatedTags(activeTags, data.noteMap) - let tagList = sortBy(data.tagNoteMap.map( - (tag, name) => ({ name, size: tag.size, related: relatedTags.has(name) }) - ).filter( - tag => tag.size > 0 - ), ['name']) + let tagList = sortBy( + data.tagNoteMap + .map((tag, name) => ({ + name, + size: tag.size, + related: relatedTags.has(name) + })) + .filter(tag => tag.size > 0), + ['name'] + ) if (config.ui.enableLiveNoteCounts && activeTags.length !== 0) { const notesTags = data.noteMap.map(note => note.tags) tagList = tagList.map(tag => { - tag.size = notesTags.filter(tags => tags.includes(tag.name) && matchActiveTags(tags, activeTags)).length + tag.size = notesTags.filter( + tags => tags.includes(tag.name) && matchActiveTags(tags, activeTags) + ).length return tag }) } if (config.sortTagsBy === 'COUNTER') { - tagList = sortBy(tagList, item => (0 - item.size)) + tagList = sortBy(tagList, item => 0 - item.size) } - if (config.ui.showOnlyRelatedTags && (relatedTags.size > 0)) { - tagList = tagList.filter( - tag => tag.related + if (config.ui.showOnlyRelatedTags && relatedTags.size > 0) { + tagList = tagList.filter(tag => tag.related) + } + return tagList.map(tag => { + return ( + ) - } - return ( - tagList.map(tag => { - return ( - - ) - }) - ) + }) } - getRelatedTags (activeTags, noteMap) { + getRelatedTags(activeTags, noteMap) { if (activeTags.length === 0) { return new Set() } - const relatedNotes = noteMap.map( - note => ({key: note.key, tags: note.tags}) - ).filter( - note => activeTags.every(tag => note.tags.includes(tag)) - ) + const relatedNotes = noteMap + .map(note => ({ key: note.key, tags: note.tags })) + .filter(note => activeTags.every(tag => note.tags.includes(tag))) const relatedTags = new Set() relatedNotes.forEach(note => note.tags.map(tag => relatedTags.add(tag))) return relatedTags } - getTagActive (path, tag) { + getTagActive(path, tag) { return this.getActiveTags(path).includes(tag) } - getActiveTags (path) { + getActiveTags(path) { const pathSegments = path.split('/') const tags = pathSegments[pathSegments.length - 1] - return (tags === 'alltags') - ? [] - : decodeURIComponent(tags).split(' ') + return tags === 'alltags' ? [] : decodeURIComponent(tags).split(' ') } - handleClickTagListItem (name) { + handleClickTagListItem(name) { const { dispatch } = this.props dispatch(push(`/tags/${encodeURIComponent(name)}`)) } - handleSortTagsByChange (e) { + handleSortTagsByChange(e) { const { dispatch } = this.props const config = { @@ -369,7 +411,7 @@ class SideNav extends React.Component { }) } - handleClickNarrowToTag (tag) { + handleClickNarrowToTag(tag) { const { dispatch, location } = this.props const listOfTags = this.getActiveTags(location.pathname) const indexOfTag = listOfTags.indexOf(tag) @@ -381,33 +423,38 @@ class SideNav extends React.Component { dispatch(push(`/tags/${encodeURIComponent(listOfTags.join(' '))}`)) } - emptyTrash (entries) { + emptyTrash(entries) { const { dispatch } = this.props - const deletionPromises = entries.map((note) => { + const deletionPromises = entries.map(note => { return dataApi.deleteNote(note.storage, note.key) }) const { confirmDeletion } = this.props.config.ui if (!confirmDeleteNote(confirmDeletion, true)) return Promise.all(deletionPromises) - .then((arrayOfStorageAndNoteKeys) => { - arrayOfStorageAndNoteKeys.forEach(({ storageKey, noteKey }) => { - dispatch({ type: 'DELETE_NOTE', storageKey, noteKey }) + .then(arrayOfStorageAndNoteKeys => { + arrayOfStorageAndNoteKeys.forEach(({ storageKey, noteKey }) => { + dispatch({ type: 'DELETE_NOTE', storageKey, noteKey }) + }) + }) + .catch(err => { + console.error('Cannot Delete note: ' + err) }) - }) - .catch((err) => { - console.error('Cannot Delete note: ' + err) - }) } - handleFilterButtonContextMenu (event) { + handleFilterButtonContextMenu(event) { const { data } = this.props - const trashedNotes = data.trashedSet.toJS().map((uniqueKey) => data.noteMap.get(uniqueKey)) + const trashedNotes = data.trashedSet + .toJS() + .map(uniqueKey => data.noteMap.get(uniqueKey)) context.popup([ - { label: i18n.__('Empty Trash'), click: () => this.emptyTrash(trashedNotes) } + { + label: i18n.__('Empty Trash'), + click: () => this.emptyTrash(trashedNotes) + } ]) } - render () { + render() { const { data, location, config, dispatch } = this.props const { colorPicker: colorPickerState } = this.state @@ -415,16 +462,18 @@ class SideNav extends React.Component { const storageList = data.storageMap.map((storage, key) => { const SortableStorageItem = SortableContainer(StorageItem) - return + return ( + + ) }) let colorPicker @@ -444,15 +493,22 @@ class SideNav extends React.Component { if (!isFolded) style.width = this.props.width const isTagActive = /tag/.test(location.pathname) return ( -
- - + +
diff --git a/browser/main/StatusBar/index.js b/browser/main/StatusBar/index.js index c99bf036..6b53f2d2 100644 --- a/browser/main/StatusBar/index.js +++ b/browser/main/StatusBar/index.js @@ -11,30 +11,43 @@ const electron = require('electron') const { remote, ipcRenderer } = electron const { dialog } = remote -const zoomOptions = [0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0] +const zoomOptions = [ + 0.8, + 0.9, + 1, + 1.1, + 1.2, + 1.3, + 1.4, + 1.5, + 1.6, + 1.7, + 1.8, + 1.9, + 2.0 +] class StatusBar extends React.Component { - - constructor (props) { + constructor(props) { super(props) this.handleZoomInMenuItem = this.handleZoomInMenuItem.bind(this) this.handleZoomOutMenuItem = this.handleZoomOutMenuItem.bind(this) this.handleZoomResetMenuItem = this.handleZoomResetMenuItem.bind(this) } - componentDidMount () { + componentDidMount() { EventEmitter.on('status:zoomin', this.handleZoomInMenuItem) EventEmitter.on('status:zoomout', this.handleZoomOutMenuItem) EventEmitter.on('status:zoomreset', this.handleZoomResetMenuItem) } - componentWillUnmount () { + componentWillUnmount() { EventEmitter.off('status:zoomin', this.handleZoomInMenuItem) EventEmitter.off('status:zoomout', this.handleZoomOutMenuItem) EventEmitter.off('status:zoomreset', this.handleZoomResetMenuItem) } - updateApp () { + updateApp() { const index = dialog.showMessageBox(remote.getCurrentWindow(), { type: 'warning', message: i18n.__('Update Boostnote'), @@ -47,10 +60,10 @@ class StatusBar extends React.Component { } } - handleZoomButtonClick (e) { + handleZoomButtonClick(e) { const templates = [] - zoomOptions.forEach((zoom) => { + zoomOptions.forEach(zoom => { templates.push({ label: Math.floor(zoom * 100) + '%', click: () => this.handleZoomMenuItemClick(zoom) @@ -60,7 +73,7 @@ class StatusBar extends React.Component { context.popup(templates) } - handleZoomMenuItemClick (zoomFactor) { + handleZoomMenuItemClick(zoomFactor) { const { dispatch } = this.props ZoomManager.setZoom(zoomFactor) dispatch({ @@ -69,40 +82,36 @@ class StatusBar extends React.Component { }) } - handleZoomInMenuItem () { + handleZoomInMenuItem() { const zoomFactor = ZoomManager.getZoom() + 0.1 this.handleZoomMenuItemClick(zoomFactor) } - handleZoomOutMenuItem () { + handleZoomOutMenuItem() { const zoomFactor = ZoomManager.getZoom() - 0.1 this.handleZoomMenuItemClick(zoomFactor) } - handleZoomResetMenuItem () { + handleZoomResetMenuItem() { this.handleZoomMenuItemClick(1.0) } - render () { + render() { const { config, status } = this.context return ( -
- - {status.updateReady - ? - : null - } + ) : null}
) } diff --git a/browser/main/TopBar/index.js b/browser/main/TopBar/index.js index 09fd56b2..e9554a67 100644 --- a/browser/main/TopBar/index.js +++ b/browser/main/TopBar/index.js @@ -11,7 +11,7 @@ import CInput from 'react-composition-input' import { push } from 'connected-react-router' class TopBar extends React.Component { - constructor (props) { + constructor(props) { super(props) this.state = { @@ -33,19 +33,25 @@ class TopBar extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this) this.handleSearchClearButton = this.handleSearchClearButton.bind(this) - this.debouncedUpdateKeyword = debounce((keyword) => { - dispatch(push(`/searched/${encodeURIComponent(keyword)}`)) - this.setState({ - search: keyword - }) - ee.emit('top:search', keyword) - }, 1000 / 60, { - maxWait: 1000 / 8 - }) + this.debouncedUpdateKeyword = debounce( + keyword => { + dispatch(push(`/searched/${encodeURIComponent(keyword)}`)) + this.setState({ + search: keyword + }) + ee.emit('top:search', keyword) + }, + 1000 / 60, + { + maxWait: 1000 / 8 + } + ) } - componentDidMount () { - const { match: { params } } = this.props + componentDidMount() { + const { + match: { params } + } = this.props const searchWord = params && params.searchword if (searchWord !== undefined) { this.setState({ @@ -57,12 +63,12 @@ class TopBar extends React.Component { ee.on('code:init', this.codeInitHandler) } - componentWillUnmount () { + componentWillUnmount() { ee.off('top:focus-search', this.focusSearchHandler) ee.off('code:init', this.codeInitHandler) } - handleSearchClearButton (e) { + handleSearchClearButton(e) { const { dispatch } = this.props this.setState({ search: '', @@ -74,7 +80,7 @@ class TopBar extends React.Component { this.debouncedUpdateKeyword('') } - handleKeyDown (e) { + handleKeyDown(e) { // Re-apply search field on ENTER key if (e.keyCode === 13) { this.debouncedUpdateKeyword(e.target.value) @@ -98,18 +104,18 @@ class TopBar extends React.Component { } } - handleSearchChange (e) { + handleSearchChange(e) { const keyword = e.target.value this.debouncedUpdateKeyword(keyword) } - handleSearchFocus (e) { + handleSearchFocus(e) { this.setState({ isSearching: true }) } - handleSearchBlur (e) { + handleSearchBlur(e) { e.stopPropagation() let el = e.relatedTarget @@ -128,7 +134,7 @@ class TopBar extends React.Component { } } - handleOnSearchFocus () { + handleOnSearchFocus() { const el = this.refs.search.childNodes[0] if (this.state.isSearching) { el.blur() @@ -137,20 +143,22 @@ class TopBar extends React.Component { } } - handleCodeInit () { + handleCodeInit() { ee.emit('top:search', this.refs.searchInput.value || '') } - render () { + render() { const { config, style, location } = this.props return ( -
-
- {this.state.search !== '' && - - } + )}
- {location.pathname === '/trashed' ? '' - : } + {location.pathname === '/trashed' ? ( + '' + ) : ( + + )}
) } diff --git a/browser/main/index.js b/browser/main/index.js index b3a909e5..727c4d0d 100644 --- a/browser/main/index.js +++ b/browser/main/index.js @@ -17,11 +17,11 @@ const electron = require('electron') const { remote, ipcRenderer } = electron const { dialog } = remote -document.addEventListener('drop', function (e) { +document.addEventListener('drop', function(e) { e.preventDefault() e.stopPropagation() }) -document.addEventListener('dragover', function (e) { +document.addEventListener('dragover', function(e) { e.preventDefault() e.stopPropagation() }) @@ -33,7 +33,7 @@ let isAltWithMouse = false let isAltWithOtherKey = false let isOtherKey = false -document.addEventListener('keydown', function (e) { +document.addEventListener('keydown', function(e) { if (e.key === 'Alt') { isAltPressing = true if (isOtherKey) { @@ -47,13 +47,13 @@ document.addEventListener('keydown', function (e) { } }) -document.addEventListener('mousedown', function (e) { +document.addEventListener('mousedown', function(e) { if (isAltPressing) { isAltWithMouse = true } }) -document.addEventListener('keyup', function (e) { +document.addEventListener('keyup', function(e) { if (e.key === 'Alt') { if (isAltWithMouse || isAltWithOtherKey) { e.preventDefault() @@ -65,14 +65,13 @@ document.addEventListener('keyup', function (e) { } }) -document.addEventListener('click', function (e) { +document.addEventListener('click', function(e) { const className = e.target.className - if (!className && typeof (className) !== 'string') return + if (!className && typeof className !== 'string') return const isInfoButton = className.includes('infoButton') const offsetParent = e.target.offsetParent - const isInfoPanel = offsetParent !== null - ? offsetParent.className.includes('infoPanel') - : false + const isInfoPanel = + offsetParent !== null ? offsetParent.className.includes('infoPanel') : false if (isInfoButton || isInfoPanel) return const infoPanel = document.querySelector('.infoPanel') if (infoPanel) infoPanel.style.display = 'none' @@ -80,11 +79,11 @@ document.addEventListener('click', function (e) { const el = document.getElementById('content') -function notify (...args) { +function notify(...args) { return new window.Notification(...args) } -function updateApp () { +function updateApp() { const index = dialog.showMessageBox(remote.getCurrentWindow(), { type: 'warning', message: i18n.__('Update Boostnote'), @@ -97,7 +96,7 @@ function updateApp () { } } -ReactDOM.render(( +ReactDOM.render( @@ -112,36 +111,41 @@ ReactDOM.render(( {/* storages */} - + - -), el, function () { - const loadingCover = document.getElementById('loadingCover') - loadingCover.parentNode.removeChild(loadingCover) + , + el, + function() { + const loadingCover = document.getElementById('loadingCover') + loadingCover.parentNode.removeChild(loadingCover) - ipcRenderer.on('update-ready', function () { - store.dispatch({ - type: 'UPDATE_AVAILABLE' + ipcRenderer.on('update-ready', function() { + store.dispatch({ + type: 'UPDATE_AVAILABLE' + }) + notify('Update ready!', { + body: 'New Boostnote is ready to be installed.' + }) + updateApp() }) - notify('Update ready!', { - body: 'New Boostnote is ready to be installed.' - }) - updateApp() - }) - ipcRenderer.on('update-found', function () { - notify('Update found!', { - body: 'Preparing to update...' + ipcRenderer.on('update-found', function() { + notify('Update found!', { + body: 'Preparing to update...' + }) }) - }) - ipcRenderer.send('update-check', 'check-update') - window.addEventListener('online', function () { - if (!store.getState().status.updateReady) { - ipcRenderer.send('update-check', 'check-update') - } - }) -}) + ipcRenderer.send('update-check', 'check-update') + window.addEventListener('online', function() { + if (!store.getState().status.updateReady) { + ipcRenderer.send('update-check', 'check-update') + } + }) + } +) diff --git a/browser/main/lib/AwsMobileAnalyticsConfig.js b/browser/main/lib/AwsMobileAnalyticsConfig.js index e4a21a92..ce7b03ef 100644 --- a/browser/main/lib/AwsMobileAnalyticsConfig.js +++ b/browser/main/lib/AwsMobileAnalyticsConfig.js @@ -22,7 +22,7 @@ if (!getSendEventCond()) { }) } -function convertPlatformName (platformName) { +function convertPlatformName(platformName) { if (platformName === 'darwin') { return 'MacOS' } else if (platformName === 'win32') { @@ -34,16 +34,16 @@ function convertPlatformName (platformName) { } } -function getSendEventCond () { +function getSendEventCond() { const isDev = process.env.NODE_ENV !== 'production' const isDisable = !ConfigManager.default.get().amaEnabled const isOffline = !window.navigator.onLine return isDev || isDisable || isOffline } -function initAwsMobileAnalytics () { +function initAwsMobileAnalytics() { if (getSendEventCond()) return - AWS.config.credentials.get((err) => { + AWS.config.credentials.get(err => { if (!err) { recordDynamicCustomEvent('APP_STARTED') recordStaticCustomEvent() @@ -51,7 +51,7 @@ function initAwsMobileAnalytics () { }) } -function recordDynamicCustomEvent (type, options = {}) { +function recordDynamicCustomEvent(type, options = {}) { if (getSendEventCond()) return try { mobileAnalyticsClient.recordEvent(type, options) @@ -62,7 +62,7 @@ function recordDynamicCustomEvent (type, options = {}) { } } -function recordStaticCustomEvent () { +function recordStaticCustomEvent() { if (getSendEventCond()) return try { mobileAnalyticsClient.recordEvent('UI_COLOR_THEME', { diff --git a/browser/main/lib/Commander.js b/browser/main/lib/Commander.js index 6eef62ee..de6aa27c 100644 --- a/browser/main/lib/Commander.js +++ b/browser/main/lib/Commander.js @@ -1,25 +1,24 @@ let callees = [] -function bind (name, el) { +function bind(name, el) { callees.push({ name: name, element: el }) } -function release (el) { - callees = callees.filter((callee) => callee.element !== el) +function release(el) { + callees = callees.filter(callee => callee.element !== el) } -function fire (command) { +function fire(command) { console.info('COMMAND >>', command) const splitted = command.split(':') const target = splitted[0] const targetCommand = splitted[1] - const targetCallees = callees - .filter((callee) => callee.name === target) + const targetCallees = callees.filter(callee => callee.name === target) - targetCallees.forEach((callee) => { + targetCallees.forEach(callee => { callee.element.fire(targetCommand) }) } diff --git a/browser/main/lib/ConfigManager.js b/browser/main/lib/ConfigManager.js index 26fda02b..6a950af1 100644 --- a/browser/main/lib/ConfigManager.js +++ b/browser/main/lib/ConfigManager.js @@ -33,7 +33,9 @@ export const DEFAULT_CONFIG = { toggleMain: OSX ? 'Command + Alt + L' : 'Super + Alt + E', toggleMode: OSX ? 'Command + Alt + M' : 'Ctrl + M', toggleDirection: OSX ? 'Command + Alt + Right' : 'Ctrl + Right', - deleteNote: OSX ? 'Command + Shift + Backspace' : 'Ctrl + Shift + Backspace', + deleteNote: OSX + ? 'Command + Shift + Backspace' + : 'Ctrl + Shift + Backspace', pasteSmartly: OSX ? 'Command + Shift + V' : 'Ctrl + Shift + V', prettifyMarkdown: OSX ? 'Command + Shift + F' : 'Ctrl + Shift + F', sortLines: OSX ? 'Command + Shift + S' : 'Ctrl + Shift + S', @@ -116,7 +118,7 @@ export const DEFAULT_CONFIG = { coloredTags: {} } -function validate (config) { +function validate(config) { if (!_.isObject(config)) return false if (!_.isNumber(config.zoom) || config.zoom < 0) return false if (!_.isBoolean(config.isSideNavFolded)) return false @@ -125,13 +127,17 @@ function validate (config) { return true } -function _save (config) { +function _save(config) { window.localStorage.setItem('config', JSON.stringify(config)) } -function get () { +function get() { const rawStoredConfig = window.localStorage.getItem('config') - const storedConfig = Object.assign({}, DEFAULT_CONFIG, JSON.parse(rawStoredConfig)) + const storedConfig = Object.assign( + {}, + DEFAULT_CONFIG, + JSON.parse(rawStoredConfig) + ) let config = storedConfig try { @@ -145,7 +151,10 @@ function get () { _save(config) } - config.autoUpdateEnabled = electronConfig.get('autoUpdateEnabled', config.autoUpdateEnabled) + config.autoUpdateEnabled = electronConfig.get( + 'autoUpdateEnabled', + config.autoUpdateEnabled + ) if (!isInitialized) { isInitialized = true @@ -157,7 +166,9 @@ function get () { document.head.appendChild(editorTheme) } - const theme = consts.THEMES.find(theme => theme.name === config.editor.theme) + const theme = consts.THEMES.find( + theme => theme.name === config.editor.theme + ) if (theme) { editorTheme.setAttribute('href', theme.path) @@ -169,7 +180,7 @@ function get () { return config } -function set (updates) { +function set(updates) { const currentConfig = get() const arrangedUpdates = updates @@ -177,7 +188,12 @@ function set (updates) { arrangedUpdates.preview.customCSS = DEFAULT_CONFIG.preview.customCSS } - const newConfig = Object.assign({}, DEFAULT_CONFIG, currentConfig, arrangedUpdates) + const newConfig = Object.assign( + {}, + DEFAULT_CONFIG, + currentConfig, + arrangedUpdates + ) if (!validate(newConfig)) throw new Error('INVALID CONFIG') _save(newConfig) @@ -197,7 +213,9 @@ function set (updates) { document.head.appendChild(editorTheme) } - const newTheme = consts.THEMES.find(theme => theme.name === newConfig.editor.theme) + const newTheme = consts.THEMES.find( + theme => theme.name === newConfig.editor.theme + ) if (newTheme) { editorTheme.setAttribute('href', newTheme.path) @@ -211,20 +229,45 @@ function set (updates) { ee.emit('config-renew') } -function assignConfigValues (originalConfig, rcConfig) { +function assignConfigValues(originalConfig, rcConfig) { const config = Object.assign({}, DEFAULT_CONFIG, originalConfig, rcConfig) - config.hotkey = Object.assign({}, DEFAULT_CONFIG.hotkey, originalConfig.hotkey, rcConfig.hotkey) - config.blog = Object.assign({}, DEFAULT_CONFIG.blog, originalConfig.blog, rcConfig.blog) - config.ui = Object.assign({}, DEFAULT_CONFIG.ui, originalConfig.ui, rcConfig.ui) - config.editor = Object.assign({}, DEFAULT_CONFIG.editor, originalConfig.editor, rcConfig.editor) - config.preview = Object.assign({}, DEFAULT_CONFIG.preview, originalConfig.preview, rcConfig.preview) + config.hotkey = Object.assign( + {}, + DEFAULT_CONFIG.hotkey, + originalConfig.hotkey, + rcConfig.hotkey + ) + config.blog = Object.assign( + {}, + DEFAULT_CONFIG.blog, + originalConfig.blog, + rcConfig.blog + ) + config.ui = Object.assign( + {}, + DEFAULT_CONFIG.ui, + originalConfig.ui, + rcConfig.ui + ) + config.editor = Object.assign( + {}, + DEFAULT_CONFIG.editor, + originalConfig.editor, + rcConfig.editor + ) + config.preview = Object.assign( + {}, + DEFAULT_CONFIG.preview, + originalConfig.preview, + rcConfig.preview + ) rewriteHotkey(config) return config } -function rewriteHotkey (config) { +function rewriteHotkey(config) { const keys = [...Object.keys(config.hotkey)] keys.forEach(key => { config.hotkey[key] = config.hotkey[key].replace(/Cmd\s/g, 'Command ') diff --git a/browser/main/lib/ZoomManager.js b/browser/main/lib/ZoomManager.js index a8903ca3..56bc9236 100644 --- a/browser/main/lib/ZoomManager.js +++ b/browser/main/lib/ZoomManager.js @@ -5,20 +5,20 @@ const { remote } = electron _init() -function _init () { +function _init() { setZoom(getZoom(), true) } -function _saveZoom (zoomFactor) { - ConfigManager.set({zoom: zoomFactor}) +function _saveZoom(zoomFactor) { + ConfigManager.set({ zoom: zoomFactor }) } -function setZoom (zoomFactor, noSave = false) { +function setZoom(zoomFactor, noSave = false) { if (!noSave) _saveZoom(zoomFactor) remote.getCurrentWebContents().setZoomFactor(zoomFactor) } -function getZoom () { +function getZoom() { const config = ConfigManager.get() return config.zoom diff --git a/browser/main/lib/dataApi/addStorage.js b/browser/main/lib/dataApi/addStorage.js index bfd6698a..370a07e0 100644 --- a/browser/main/lib/dataApi/addStorage.js +++ b/browser/main/lib/dataApi/addStorage.js @@ -16,7 +16,7 @@ const CSON = require('@rokt33r/season') * 3. fetch notes & folders * 4. return `{storage: {...} folders: [folder]}` */ -function addStorage (input) { +function addStorage(input) { if (!_.isString(input.path)) { return Promise.reject(new Error('Path must be a string.')) } @@ -29,7 +29,7 @@ function addStorage (input) { rawStorages = [] } let key = keygen() - while (rawStorages.some((storage) => storage.key === key)) { + while (rawStorages.some(storage => storage.key === key)) { key = keygen() } @@ -43,7 +43,7 @@ function addStorage (input) { return Promise.resolve(newStorage) .then(resolveStorageData) - .then(function saveMetadataToLocalStorage (resolvedStorage) { + .then(function saveMetadataToLocalStorage(resolvedStorage) { newStorage = resolvedStorage rawStorages.push({ key: newStorage.key, @@ -56,27 +56,29 @@ function addStorage (input) { localStorage.setItem('storages', JSON.stringify(rawStorages)) return newStorage }) - .then(function (storage) { - return resolveStorageNotes(storage) - .then((notes) => { - let unknownCount = 0 - notes.forEach((note) => { - if (!storage.folders.some((folder) => note.folder === folder.key)) { - unknownCount++ - storage.folders.push({ - key: note.folder, - color: consts.FOLDER_COLORS[(unknownCount - 1) % 7], - name: 'Unknown ' + unknownCount - }) - } - }) - if (unknownCount > 0) { - CSON.writeFileSync(path.join(storage.path, 'boostnote.json'), _.pick(storage, ['folders', 'version'])) + .then(function(storage) { + return resolveStorageNotes(storage).then(notes => { + let unknownCount = 0 + notes.forEach(note => { + if (!storage.folders.some(folder => note.folder === folder.key)) { + unknownCount++ + storage.folders.push({ + key: note.folder, + color: consts.FOLDER_COLORS[(unknownCount - 1) % 7], + name: 'Unknown ' + unknownCount + }) } - return notes }) + if (unknownCount > 0) { + CSON.writeFileSync( + path.join(storage.path, 'boostnote.json'), + _.pick(storage, ['folders', 'version']) + ) + } + return notes + }) }) - .then(function returnValue (notes) { + .then(function returnValue(notes) { return { storage: newStorage, notes diff --git a/browser/main/lib/dataApi/attachmentManagement.js b/browser/main/lib/dataApi/attachmentManagement.js index 971ae812..f3b11997 100644 --- a/browser/main/lib/dataApi/attachmentManagement.js +++ b/browser/main/lib/dataApi/attachmentManagement.js @@ -12,14 +12,15 @@ import { isString } from 'lodash' const STORAGE_FOLDER_PLACEHOLDER = ':storage' const DESTINATION_FOLDER = 'attachments' -const PATH_SEPARATORS = escapeStringRegexp(path.posix.sep) + escapeStringRegexp(path.win32.sep) +const PATH_SEPARATORS = + escapeStringRegexp(path.posix.sep) + escapeStringRegexp(path.win32.sep) /** * @description * Create a Image element to get the real size of image. * @param {File} file the File object dropped. * @returns {Promise} Image element created */ -function getImage (file) { +function getImage(file) { if (isString(file)) { return new Promise(resolve => { const img = new Image() @@ -55,38 +56,39 @@ function getImage (file) { * @param {File} file the File object dropped. * @returns {Promise} Orientation info */ -function getOrientation (file) { +function getOrientation(file) { const getData = arrayBuffer => { const view = new DataView(arrayBuffer) // Not start with SOI(Start of image) Marker return fail value - if (view.getUint16(0, false) !== 0xFFD8) return -2 + if (view.getUint16(0, false) !== 0xffd8) return -2 const length = view.byteLength let offset = 2 while (offset < length) { const marker = view.getUint16(offset, false) offset += 2 // Loop and seed for APP1 Marker - if (marker === 0xFFE1) { + if (marker === 0xffe1) { // return fail value if it isn't EXIF data - if (view.getUint32(offset += 2, false) !== 0x45786966) { + if (view.getUint32((offset += 2), false) !== 0x45786966) { return -1 } // Read TIFF header, // First 2bytes defines byte align of TIFF data. // If it is 0x4949="II", it means "Intel" type byte align. // If it is 0x4d4d="MM", it means "Motorola" type byte align - const little = view.getUint16(offset += 6, false) === 0x4949 + const little = view.getUint16((offset += 6), false) === 0x4949 offset += view.getUint32(offset + 4, little) const tags = view.getUint16(offset, little) // Get TAG number offset += 2 for (let i = 0; i < tags; i++) { // Loop to find Orientation TAG and return the value - if (view.getUint16(offset + (i * 12), little) === 0x0112) { - return view.getUint16(offset + (i * 12) + 8, little) + if (view.getUint16(offset + i * 12, little) === 0x0112) { + return view.getUint16(offset + i * 12 + 8, little) } } - } else if ((marker & 0xFF00) !== 0xFF00) { // If not start with 0xFF, not a Marker. + } else if ((marker & 0xff00) !== 0xff00) { + // If not start with 0xFF, not a Marker. break } else { offset += view.getUint16(offset, false) @@ -94,7 +96,7 @@ function getOrientation (file) { } return -1 } - return new Promise((resolve) => { + return new Promise(resolve => { const reader = new FileReader() reader.onload = event => resolve(getData(event.target.result)) reader.readAsArrayBuffer(file.slice(0, 64 * 1024)) @@ -107,31 +109,47 @@ function getOrientation (file) { * @param {*} file the File object dropped. * @return {String} Base64 encoded image. */ -function fixRotate (file) { - return Promise.all([getImage(file), getOrientation(file)]) - .then(([img, orientation]) => { - const canvas = document.createElement('canvas') - const ctx = canvas.getContext('2d') - if (orientation > 4 && orientation < 9) { - canvas.width = img.height - canvas.height = img.width - } else { - canvas.width = img.width - canvas.height = img.height +function fixRotate(file) { + return Promise.all([getImage(file), getOrientation(file)]).then( + ([img, orientation]) => { + const canvas = document.createElement('canvas') + const ctx = canvas.getContext('2d') + if (orientation > 4 && orientation < 9) { + canvas.width = img.height + canvas.height = img.width + } else { + canvas.width = img.width + canvas.height = img.height + } + switch (orientation) { + case 2: + ctx.transform(-1, 0, 0, 1, img.width, 0) + break + case 3: + ctx.transform(-1, 0, 0, -1, img.width, img.height) + break + case 4: + ctx.transform(1, 0, 0, -1, 0, img.height) + break + case 5: + ctx.transform(0, 1, 1, 0, 0, 0) + break + case 6: + ctx.transform(0, 1, -1, 0, img.height, 0) + break + case 7: + ctx.transform(0, -1, -1, 0, img.height, img.width) + break + case 8: + ctx.transform(0, -1, 1, 0, 0, img.width) + break + default: + break + } + ctx.drawImage(img, 0, 0) + return canvas.toDataURL() } - switch (orientation) { - case 2: ctx.transform(-1, 0, 0, 1, img.width, 0); break - case 3: ctx.transform(-1, 0, 0, -1, img.width, img.height); break - case 4: ctx.transform(1, 0, 0, -1, 0, img.height); break - case 5: ctx.transform(0, 1, 1, 0, 0, 0); break - case 6: ctx.transform(0, 1, -1, 0, img.height, 0); break - case 7: ctx.transform(0, -1, -1, 0, img.height, img.width); break - case 8: ctx.transform(0, -1, 1, 0, 0, img.width); break - default: break - } - ctx.drawImage(img, 0, 0) - return canvas.toDataURL() - }) + ) } /** @@ -145,7 +163,12 @@ function fixRotate (file) { * @param {boolean} useRandomName determines whether a random filename for the new file is used. If false the source file name is used * @return {Promise} name (inclusive extension) of the generated file */ -function copyAttachment (sourceFilePath, storageKey, noteKey, useRandomName = true) { +function copyAttachment( + sourceFilePath, + storageKey, + noteKey, + useRandomName = true +) { return new Promise((resolve, reject) => { if (!sourceFilePath) { reject('sourceFilePath has to be given') @@ -160,28 +183,41 @@ function copyAttachment (sourceFilePath, storageKey, noteKey, useRandomName = tr } try { - const isBase64 = typeof sourceFilePath === 'object' && sourceFilePath.type === 'base64' + const isBase64 = + typeof sourceFilePath === 'object' && sourceFilePath.type === 'base64' if (!isBase64 && !fs.existsSync(sourceFilePath)) { return reject('source file does not exist') } const sourcePath = sourceFilePath.sourceFilePath || sourceFilePath - const sourceURL = url.parse(/^\w+:\/\//.test(sourcePath) ? sourcePath : 'file:///' + sourcePath) + const sourceURL = url.parse( + /^\w+:\/\//.test(sourcePath) ? sourcePath : 'file:///' + sourcePath + ) let destinationName if (useRandomName) { - destinationName = `${uniqueSlug()}${path.extname(sourceURL.pathname) || '.png'}` + destinationName = `${uniqueSlug()}${path.extname(sourceURL.pathname) || + '.png'}` } else { destinationName = path.basename(sourceURL.pathname) } const targetStorage = findStorage.findStorage(storageKey) - const destinationDir = path.join(targetStorage.path, DESTINATION_FOLDER, noteKey) + const destinationDir = path.join( + targetStorage.path, + DESTINATION_FOLDER, + noteKey + ) createAttachmentDestinationFolder(targetStorage.path, noteKey) - const outputFile = fs.createWriteStream(path.join(destinationDir, destinationName)) + const outputFile = fs.createWriteStream( + path.join(destinationDir, destinationName) + ) if (isBase64) { - const base64Data = sourceFilePath.data.replace(/^data:image\/\w+;base64,/, '') + const base64Data = sourceFilePath.data.replace( + /^data:image\/\w+;base64,/, + '' + ) const dataBuffer = Buffer.from(base64Data, 'base64') outputFile.write(dataBuffer, () => { resolve(destinationName) @@ -199,12 +235,16 @@ function copyAttachment (sourceFilePath, storageKey, noteKey, useRandomName = tr }) } -function createAttachmentDestinationFolder (destinationStoragePath, noteKey) { +function createAttachmentDestinationFolder(destinationStoragePath, noteKey) { let destinationDir = path.join(destinationStoragePath, DESTINATION_FOLDER) if (!fs.existsSync(destinationDir)) { fs.mkdirSync(destinationDir) } - destinationDir = path.join(destinationStoragePath, DESTINATION_FOLDER, noteKey) + destinationDir = path.join( + destinationStoragePath, + DESTINATION_FOLDER, + noteKey + ) if (!fs.existsSync(destinationDir)) { fs.mkdirSync(destinationDir) } @@ -216,17 +256,28 @@ function createAttachmentDestinationFolder (destinationStoragePath, noteKey) { * @param storagePath Storage path of the current note * @param noteKey Key of the current note */ -function migrateAttachments (markdownContent, storagePath, noteKey) { - if (noteKey !== undefined && sander.existsSync(path.join(storagePath, 'images'))) { +function migrateAttachments(markdownContent, storagePath, noteKey) { + if ( + noteKey !== undefined && + sander.existsSync(path.join(storagePath, 'images')) + ) { const attachments = getAttachmentsInMarkdownContent(markdownContent) || [] if (attachments.length) { createAttachmentDestinationFolder(storagePath, noteKey) } for (const attachment of attachments) { const attachmentBaseName = path.basename(attachment) - const possibleLegacyPath = path.join(storagePath, 'images', attachmentBaseName) + const possibleLegacyPath = path.join( + storagePath, + 'images', + attachmentBaseName + ) if (sander.existsSync(possibleLegacyPath)) { - const destinationPath = path.join(storagePath, DESTINATION_FOLDER, attachmentBaseName) + const destinationPath = path.join( + storagePath, + DESTINATION_FOLDER, + attachmentBaseName + ) if (!sander.existsSync(destinationPath)) { sander.copyFileSync(possibleLegacyPath).to(destinationPath) } @@ -241,10 +292,11 @@ function migrateAttachments (markdownContent, storagePath, noteKey) { * @param {String} storagePath Path of the current storage * @returns {String} postprocessed HTML in which all :storage references are mapped to the actual paths. */ -function fixLocalURLS (renderedHTML, storagePath) { +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, '/') + const storageUrl = + 'file:///' + path.join(storagePath, DESTINATION_FOLDER).replace(/\\/g, '/') /* A :storage reference is like `:storage/3b6f8bd6-4edd-4b15-96e0-eadc4475b564/f939b2c3.jpg`. @@ -254,9 +306,17 @@ function fixLocalURLS (renderedHTML, storagePath) { - `(?:\\\/|%5C)[-.\\w]+` will either match `/3b6f8bd6-4edd-4b15-96e0-eadc4475b564` or `/f939b2c3.jpg` - `(?:\\\/|%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) { - return match.replace(encodedWin32SeparatorRegex, '/').replace(storageRegex, storageUrl) - }) + return renderedHTML.replace( + new RegExp( + '/?' + STORAGE_FOLDER_PLACEHOLDER + '(?:(?:\\/|%5C)[-.\\w]+)+', + 'g' + ), + function(match) { + return match + .replace(encodedWin32SeparatorRegex, '/') + .replace(storageRegex, storageUrl) + } + ) } /** @@ -266,7 +326,7 @@ function fixLocalURLS (renderedHTML, storagePath) { * @param {Boolean} showPreview Indicator whether the generated markdown should show a preview of the image. Note that at the moment only previews for images are supported * @returns {String} Generated markdown code */ -function generateAttachmentMarkdown (fileName, path, showPreview) { +function generateAttachmentMarkdown(fileName, path, showPreview) { return `${showPreview ? '!' : ''}[${fileName}](${path})` } @@ -278,53 +338,66 @@ function generateAttachmentMarkdown (fileName, path, showPreview) { * @param {String} noteKey Key of the current note * @param {Event} dropEvent DropEvent */ -function handleAttachmentDrop (codeEditor, storageKey, noteKey, dropEvent) { +function handleAttachmentDrop(codeEditor, storageKey, noteKey, dropEvent) { let promise if (dropEvent.dataTransfer.files.length > 0) { - promise = Promise.all(Array.from(dropEvent.dataTransfer.files).map(file => { - const filePath = file.path - const fileType = file.type // EX) 'image/gif' or 'text/html' - if (fileType.startsWith('image')) { - if (fileType === 'image/gif' || fileType === 'image/svg+xml') { - return copyAttachment(filePath, storageKey, noteKey).then(fileName => ({ - fileName, - title: path.basename(filePath), - isImage: true - })) - } else { - return getOrientation(file) - .then((orientation) => { - if (orientation === -1) { // The image rotation is correct and does not need adjustment - return copyAttachment(filePath, storageKey, noteKey) - } else { - return fixRotate(file).then(data => copyAttachment({ - type: 'base64', - data: data, - sourceFilePath: filePath - }, storageKey, noteKey)) - } - }) - .then(fileName => - ({ + promise = Promise.all( + Array.from(dropEvent.dataTransfer.files).map(file => { + const filePath = file.path + const fileType = file.type // EX) 'image/gif' or 'text/html' + if (fileType.startsWith('image')) { + if (fileType === 'image/gif' || fileType === 'image/svg+xml') { + return copyAttachment(filePath, storageKey, noteKey).then( + fileName => ({ fileName, title: path.basename(filePath), isImage: true }) ) + } else { + return getOrientation(file) + .then(orientation => { + if (orientation === -1) { + // The image rotation is correct and does not need adjustment + return copyAttachment(filePath, storageKey, noteKey) + } else { + return fixRotate(file).then(data => + copyAttachment( + { + type: 'base64', + data: data, + sourceFilePath: filePath + }, + storageKey, + noteKey + ) + ) + } + }) + .then(fileName => ({ + fileName, + title: path.basename(filePath), + isImage: true + })) + } + } else { + return copyAttachment(filePath, storageKey, noteKey).then( + fileName => ({ + fileName, + title: path.basename(filePath), + isImage: false + }) + ) } - } else { - return copyAttachment(filePath, storageKey, noteKey).then(fileName => ({ - fileName, - title: path.basename(filePath), - isImage: false - })) - } - })) + }) + ) } else { let imageURL = dropEvent.dataTransfer.getData('text/plain') if (!imageURL) { - const match = /]*[\s"']src="([^"]+)"/.exec(dropEvent.dataTransfer.getData('text/html')) + const match = /]*[\s"']src="([^"]+)"/.exec( + dropEvent.dataTransfer.getData('text/html') + ) if (match) { imageURL = match[1] } @@ -334,30 +407,43 @@ function handleAttachmentDrop (codeEditor, storageKey, noteKey, dropEvent) { return } - promise = Promise.all([getImage(imageURL) - .then(image => { - const canvas = document.createElement('canvas') - const context = canvas.getContext('2d') - canvas.width = image.width - canvas.height = image.height - context.drawImage(image, 0, 0) + promise = Promise.all([ + getImage(imageURL) + .then(image => { + const canvas = document.createElement('canvas') + const context = canvas.getContext('2d') + canvas.width = image.width + canvas.height = image.height + context.drawImage(image, 0, 0) - return copyAttachment({ - type: 'base64', - data: canvas.toDataURL(), - sourceFilePath: imageURL - }, storageKey, noteKey) - }) - .then(fileName => ({ - fileName, - title: imageURL, - isImage: true - })) + return copyAttachment( + { + type: 'base64', + data: canvas.toDataURL(), + sourceFilePath: imageURL + }, + storageKey, + noteKey + ) + }) + .then(fileName => ({ + fileName, + title: imageURL, + isImage: true + })) ]) } promise.then(files => { - const attachments = files.filter(file => !!file).map(file => generateAttachmentMarkdown(file.title, path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, file.fileName), file.isImage)) + const attachments = files + .filter(file => !!file) + .map(file => + generateAttachmentMarkdown( + file.title, + path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, file.fileName), + file.isImage + ) + ) codeEditor.insertAttachmentMd(attachments.join('\n')) }) @@ -370,7 +456,12 @@ function handleAttachmentDrop (codeEditor, storageKey, noteKey, dropEvent) { * @param {String} noteKey Key of the current note * @param {DataTransferItem} dataTransferItem Part of the past-event */ -function handlePasteImageEvent (codeEditor, storageKey, noteKey, dataTransferItem) { +function handlePasteImageEvent( + codeEditor, + storageKey, + noteKey, + dataTransferItem +) { if (!codeEditor) { throw new Error('codeEditor has to be given') } @@ -389,19 +480,31 @@ function handlePasteImageEvent (codeEditor, storageKey, noteKey, dataTransferIte const reader = new FileReader() let base64data const targetStorage = findStorage.findStorage(storageKey) - const destinationDir = path.join(targetStorage.path, DESTINATION_FOLDER, noteKey) + const destinationDir = path.join( + targetStorage.path, + DESTINATION_FOLDER, + noteKey + ) createAttachmentDestinationFolder(targetStorage.path, noteKey) const imageName = `${uniqueSlug()}.png` const imagePath = path.join(destinationDir, imageName) - reader.onloadend = function () { + reader.onloadend = function() { base64data = reader.result.replace(/^data:image\/png;base64,/, '') base64data += base64data.replace('+', ' ') const binaryData = new Buffer(base64data, 'base64').toString('binary') fs.writeFileSync(imagePath, binaryData, 'binary') - const imageReferencePath = path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, imageName) - const imageMd = generateAttachmentMarkdown(imageName, imageReferencePath, true) + const imageReferencePath = path.join( + STORAGE_FOLDER_PLACEHOLDER, + noteKey, + imageName + ) + const imageMd = generateAttachmentMarkdown( + imageName, + imageReferencePath, + true + ) codeEditor.insertAttachmentMd(imageMd) } reader.readAsDataURL(blob) @@ -414,7 +517,7 @@ function handlePasteImageEvent (codeEditor, storageKey, noteKey, dataTransferIte * @param {String} noteKey Key of the current note * @param {NativeImage} image The native image */ -function handlePasteNativeImage (codeEditor, storageKey, noteKey, image) { +function handlePasteNativeImage(codeEditor, storageKey, noteKey, image) { if (!codeEditor) { throw new Error('codeEditor has to be given') } @@ -430,7 +533,11 @@ function handlePasteNativeImage (codeEditor, storageKey, noteKey, image) { } const targetStorage = findStorage.findStorage(storageKey) - const destinationDir = path.join(targetStorage.path, DESTINATION_FOLDER, noteKey) + const destinationDir = path.join( + targetStorage.path, + DESTINATION_FOLDER, + noteKey + ) createAttachmentDestinationFolder(targetStorage.path, noteKey) @@ -440,19 +547,42 @@ function handlePasteNativeImage (codeEditor, storageKey, noteKey, image) { const binaryData = image.toPNG() fs.writeFileSync(imagePath, binaryData, 'binary') - const imageReferencePath = path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, imageName) - const imageMd = generateAttachmentMarkdown(imageName, imageReferencePath, true) + const imageReferencePath = path.join( + STORAGE_FOLDER_PLACEHOLDER, + noteKey, + imageName + ) + const imageMd = generateAttachmentMarkdown( + imageName, + imageReferencePath, + true + ) codeEditor.insertAttachmentMd(imageMd) } /** -* @description Returns all attachment paths of the given markdown -* @param {String} markdownContent content in which the attachment paths should be found -* @returns {String[]} Array of the relative paths (starting with :storage) of the attachments of the given markdown -*/ -function getAttachmentsInMarkdownContent (markdownContent) { - const preparedInput = markdownContent.replace(new RegExp('[' + PATH_SEPARATORS + ']', 'g'), path.sep) - const regexp = new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '(' + escapeStringRegexp(path.sep) + ')' + '?([a-zA-Z0-9]|-)*' + '(' + escapeStringRegexp(path.sep) + ')' + '([a-zA-Z0-9]|\\.)+(\\.[a-zA-Z0-9]+)?', 'g') + * @description Returns all attachment paths of the given markdown + * @param {String} markdownContent content in which the attachment paths should be found + * @returns {String[]} Array of the relative paths (starting with :storage) of the attachments of the given markdown + */ +function getAttachmentsInMarkdownContent(markdownContent) { + const preparedInput = markdownContent.replace( + new RegExp('[' + PATH_SEPARATORS + ']', 'g'), + path.sep + ) + const regexp = new RegExp( + '/?' + + STORAGE_FOLDER_PLACEHOLDER + + '(' + + escapeStringRegexp(path.sep) + + ')' + + '?([a-zA-Z0-9]|-)*' + + '(' + + escapeStringRegexp(path.sep) + + ')' + + '([a-zA-Z0-9]|\\.)+(\\.[a-zA-Z0-9]+)?', + 'g' + ) return preparedInput.match(regexp) } @@ -462,11 +592,16 @@ function getAttachmentsInMarkdownContent (markdownContent) { * @param {String} storagePath path of the current storage * @returns {String[]} Absolute paths of the referenced attachments */ -function getAbsolutePathsOfAttachmentsInContent (markdownContent, storagePath) { +function getAbsolutePathsOfAttachmentsInContent(markdownContent, storagePath) { const temp = getAttachmentsInMarkdownContent(markdownContent) || [] const result = [] for (const relativePath of temp) { - result.push(relativePath.replace(new RegExp(STORAGE_FOLDER_PLACEHOLDER, 'g'), path.join(storagePath, DESTINATION_FOLDER))) + result.push( + relativePath.replace( + new RegExp(STORAGE_FOLDER_PLACEHOLDER, 'g'), + path.join(storagePath, DESTINATION_FOLDER) + ) + ) } return result } @@ -478,7 +613,7 @@ function getAbsolutePathsOfAttachmentsInContent (markdownContent, storagePath) { * @param {String} storageKey Storage key of the destination storage * @param {String} noteKey Key of the current note. Will be used as subfolder in :storage */ -function importAttachments (markDownContent, filepath, storageKey, noteKey) { +function importAttachments(markDownContent, filepath, storageKey, noteKey) { return new Promise((resolve, reject) => { const nameRegex = /(!\[.*?]\()(.+?\..+?)(\))/g let attachPath = nameRegex.exec(markDownContent) @@ -489,8 +624,12 @@ function importAttachments (markDownContent, filepath, storageKey, noteKey) { while (attachPath) { let attachmentPath = attachPath[groupIndex] attachmentPaths.push(attachmentPath) - attachmentPath = path.isAbsolute(attachmentPath) ? attachmentPath : path.join(path.dirname(filepath), attachmentPath) - promiseArray.push(this.copyAttachment(attachmentPath, storageKey, noteKey)) + attachmentPath = path.isAbsolute(attachmentPath) + ? attachmentPath + : path.join(path.dirname(filepath), attachmentPath) + promiseArray.push( + this.copyAttachment(attachmentPath, storageKey, noteKey) + ) attachPath = nameRegex.exec(markDownContent) } @@ -502,19 +641,23 @@ function importAttachments (markDownContent, filepath, storageKey, noteKey) { for (let j = 0; j < promiseArray.length; j++) { promiseArray[j] - .then((fileName) => { - const newPath = path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, fileName) - markDownContent = markDownContent.replace(attachmentPaths[j], newPath) - }) - .catch((e) => { - console.error('File does not exist in path: ' + attachmentPaths[j]) - }) - .finally(() => { - numResolvedPromises++ - if (numResolvedPromises === promiseArray.length) { - resolve(markDownContent) - } - }) + .then(fileName => { + const newPath = path.join( + STORAGE_FOLDER_PLACEHOLDER, + noteKey, + fileName + ) + markDownContent = markDownContent.replace(attachmentPaths[j], newPath) + }) + .catch(e => { + console.error('File does not exist in path: ' + attachmentPaths[j]) + }) + .finally(() => { + numResolvedPromises++ + if (numResolvedPromises === promiseArray.length) { + resolve(markDownContent) + } + }) } }) } @@ -529,7 +672,7 @@ function importAttachments (markDownContent, filepath, storageKey, noteKey) { * @param {String} noteContent Content of the note to be moved * @returns {String} Modified version of noteContent in which the paths of the attachments are fixed */ -function moveAttachments (oldPath, newPath, noteKey, newNoteKey, noteContent) { +function moveAttachments(oldPath, newPath, noteKey, newNoteKey, noteContent) { const src = path.join(oldPath, DESTINATION_FOLDER, noteKey) const dest = path.join(newPath, DESTINATION_FOLDER, newNoteKey) if (fse.existsSync(src)) { @@ -545,10 +688,19 @@ function moveAttachments (oldPath, newPath, noteKey, newNoteKey, noteContent) { * @param newNoteKey note key serving as a replacement * @returns {String} modified note content */ -function replaceNoteKeyWithNewNoteKey (noteContent, oldNoteKey, newNoteKey) { +function replaceNoteKeyWithNewNoteKey(noteContent, oldNoteKey, newNoteKey) { if (noteContent) { - const preparedInput = noteContent.replace(new RegExp('[' + PATH_SEPARATORS + ']', 'g'), path.sep) - return preparedInput.replace(new RegExp(STORAGE_FOLDER_PLACEHOLDER + escapeStringRegexp(path.sep) + oldNoteKey, 'g'), path.join(STORAGE_FOLDER_PLACEHOLDER, newNoteKey)) + const preparedInput = noteContent.replace( + new RegExp('[' + PATH_SEPARATORS + ']', 'g'), + path.sep + ) + return preparedInput.replace( + new RegExp( + STORAGE_FOLDER_PLACEHOLDER + escapeStringRegexp(path.sep) + oldNoteKey, + 'g' + ), + path.join(STORAGE_FOLDER_PLACEHOLDER, newNoteKey) + ) } return noteContent } @@ -559,15 +711,28 @@ function replaceNoteKeyWithNewNoteKey (noteContent, oldNoteKey, newNoteKey) { * @param noteKey Key of the current note * @returns {String} Input without the references */ -function removeStorageAndNoteReferences (input, noteKey) { - return input.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '.*?("|])', 'g'), function (match) { - const temp = match - .replace(new RegExp(mdurl.encode(path.win32.sep), 'g'), path.sep) - .replace(new RegExp(mdurl.encode(path.posix.sep), 'g'), path.sep) - .replace(new RegExp(escapeStringRegexp(path.win32.sep), 'g'), path.sep) - .replace(new RegExp(escapeStringRegexp(path.posix.sep), 'g'), path.sep) - return temp.replace(new RegExp(STORAGE_FOLDER_PLACEHOLDER + '(' + escapeStringRegexp(path.sep) + noteKey + ')?', 'g'), DESTINATION_FOLDER) - }) +function removeStorageAndNoteReferences(input, noteKey) { + return input.replace( + new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '.*?("|])', 'g'), + function(match) { + const temp = match + .replace(new RegExp(mdurl.encode(path.win32.sep), 'g'), path.sep) + .replace(new RegExp(mdurl.encode(path.posix.sep), 'g'), path.sep) + .replace(new RegExp(escapeStringRegexp(path.win32.sep), 'g'), path.sep) + .replace(new RegExp(escapeStringRegexp(path.posix.sep), 'g'), path.sep) + return temp.replace( + new RegExp( + STORAGE_FOLDER_PLACEHOLDER + + '(' + + escapeStringRegexp(path.sep) + + noteKey + + ')?', + 'g' + ), + DESTINATION_FOLDER + ) + } + ) } /** @@ -575,9 +740,13 @@ function removeStorageAndNoteReferences (input, noteKey) { * @param storageKey Key of the storage of the note to be deleted * @param noteKey Key of the note to be deleted */ -function deleteAttachmentFolder (storageKey, noteKey) { +function deleteAttachmentFolder(storageKey, noteKey) { const storagePath = findStorage.findStorage(storageKey) - const noteAttachmentPath = path.join(storagePath.path, DESTINATION_FOLDER, noteKey) + const noteAttachmentPath = path.join( + storagePath.path, + DESTINATION_FOLDER, + noteKey + ) sander.rimrafSync(noteAttachmentPath) } @@ -587,36 +756,66 @@ function deleteAttachmentFolder (storageKey, noteKey) { * @param storageKey StorageKey of the current note. Is used to determine the belonging attachment folder. * @param noteKey NoteKey of the current note. Is used to determine the belonging attachment folder. */ -function deleteAttachmentsNotPresentInNote (markdownContent, storageKey, noteKey) { +function deleteAttachmentsNotPresentInNote( + markdownContent, + storageKey, + noteKey +) { if (storageKey == null || noteKey == null || markdownContent == null) { return } const targetStorage = findStorage.findStorage(storageKey) - const attachmentFolder = path.join(targetStorage.path, DESTINATION_FOLDER, noteKey) + const attachmentFolder = path.join( + targetStorage.path, + DESTINATION_FOLDER, + noteKey + ) const attachmentsInNote = getAttachmentsInMarkdownContent(markdownContent) const attachmentsInNoteOnlyFileNames = [] if (attachmentsInNote) { for (let i = 0; i < attachmentsInNote.length; i++) { - attachmentsInNoteOnlyFileNames.push(attachmentsInNote[i].replace(new RegExp(STORAGE_FOLDER_PLACEHOLDER + escapeStringRegexp(path.sep) + noteKey + escapeStringRegexp(path.sep), 'g'), '')) + attachmentsInNoteOnlyFileNames.push( + attachmentsInNote[i].replace( + new RegExp( + STORAGE_FOLDER_PLACEHOLDER + + escapeStringRegexp(path.sep) + + noteKey + + escapeStringRegexp(path.sep), + 'g' + ), + '' + ) + ) } } if (fs.existsSync(attachmentFolder)) { fs.readdir(attachmentFolder, (err, files) => { if (err) { - console.error('Error reading directory "' + attachmentFolder + '". Error:') + console.error( + 'Error reading directory "' + attachmentFolder + '". Error:' + ) console.error(err) return } files.forEach(file => { if (!attachmentsInNoteOnlyFileNames.includes(file)) { - const absolutePathOfFile = path.join(targetStorage.path, DESTINATION_FOLDER, noteKey, file) - fs.unlink(absolutePathOfFile, (err) => { + const absolutePathOfFile = path.join( + targetStorage.path, + DESTINATION_FOLDER, + noteKey, + file + ) + fs.unlink(absolutePathOfFile, err => { if (err) { console.error('Could not delete "%s"', absolutePathOfFile) console.error(err) return } - console.info('File "' + absolutePathOfFile + '" deleted because it was not included in the content of the note') + console.info( + 'File "' + + absolutePathOfFile + + '" deleted because it was not included in the content of the note' + ) }) } }) @@ -632,31 +831,53 @@ function deleteAttachmentsNotPresentInNote (markdownContent, storageKey, noteKey * @param noteKey NoteKey of the currentNote * @return {Promise>} Promise returning the list of attachments with their properties */ -function getAttachmentsPathAndStatus (markdownContent, storageKey, noteKey) { +function getAttachmentsPathAndStatus(markdownContent, storageKey, noteKey) { if (storageKey == null || noteKey == null || markdownContent == null) { return null } const targetStorage = findStorage.findStorage(storageKey) - const attachmentFolder = path.join(targetStorage.path, DESTINATION_FOLDER, noteKey) + const attachmentFolder = path.join( + targetStorage.path, + DESTINATION_FOLDER, + noteKey + ) const attachmentsInNote = getAttachmentsInMarkdownContent(markdownContent) const attachmentsInNoteOnlyFileNames = [] if (attachmentsInNote) { for (let i = 0; i < attachmentsInNote.length; i++) { - attachmentsInNoteOnlyFileNames.push(attachmentsInNote[i].replace(new RegExp(STORAGE_FOLDER_PLACEHOLDER + escapeStringRegexp(path.sep) + noteKey + escapeStringRegexp(path.sep), 'g'), '')) + attachmentsInNoteOnlyFileNames.push( + attachmentsInNote[i].replace( + new RegExp( + STORAGE_FOLDER_PLACEHOLDER + + escapeStringRegexp(path.sep) + + noteKey + + escapeStringRegexp(path.sep), + 'g' + ), + '' + ) + ) } } if (fs.existsSync(attachmentFolder)) { return new Promise((resolve, reject) => { fs.readdir(attachmentFolder, (err, files) => { if (err) { - console.error('Error reading directory "' + attachmentFolder + '". Error:') + console.error( + 'Error reading directory "' + attachmentFolder + '". Error:' + ) console.error(err) reject(err) return } const attachments = [] for (const file of files) { - const absolutePathOfFile = path.join(targetStorage.path, DESTINATION_FOLDER, noteKey, file) + const absolutePathOfFile = path.join( + targetStorage.path, + DESTINATION_FOLDER, + noteKey, + file + ) if (!attachmentsInNoteOnlyFileNames.includes(file)) { attachments.push({ path: absolutePathOfFile, isInUse: false }) } else { @@ -675,11 +896,11 @@ function getAttachmentsPathAndStatus (markdownContent, storageKey, noteKey) { * @description Remove all specified attachment paths * @param attachments attachment paths * @return {Promise} Promise after all attachments are removed */ -function removeAttachmentsByPaths (attachments) { +function removeAttachmentsByPaths(attachments) { const promises = [] for (const attachment of attachments) { const promise = new Promise((resolve, reject) => { - fs.unlink(attachment, (err) => { + fs.unlink(attachment, err => { if (err) { console.error('Could not delete "%s"', attachment) console.error(err) @@ -700,29 +921,54 @@ function removeAttachmentsByPaths (attachments) { * @param oldNote Note that is being cloned * @param newNote Clone of the note */ -function cloneAttachments (oldNote, newNote) { +function cloneAttachments(oldNote, newNote) { if (newNote.type === 'MARKDOWN_NOTE') { const oldStorage = findStorage.findStorage(oldNote.storage) const newStorage = findStorage.findStorage(newNote.storage) - const attachmentsPaths = getAbsolutePathsOfAttachmentsInContent(oldNote.content, oldStorage.path) || [] + const attachmentsPaths = + getAbsolutePathsOfAttachmentsInContent( + oldNote.content, + oldStorage.path + ) || [] - const destinationFolder = path.join(newStorage.path, DESTINATION_FOLDER, newNote.key) + const destinationFolder = path.join( + newStorage.path, + DESTINATION_FOLDER, + newNote.key + ) if (!sander.existsSync(destinationFolder)) { sander.mkdirSync(destinationFolder) } for (const attachment of attachmentsPaths) { - const destination = path.join(newStorage.path, DESTINATION_FOLDER, newNote.key, path.basename(attachment)) + const destination = path.join( + newStorage.path, + DESTINATION_FOLDER, + newNote.key, + path.basename(attachment) + ) sander.copyFileSync(attachment).to(destination) } - newNote.content = replaceNoteKeyWithNewNoteKey(newNote.content, oldNote.key, newNote.key) + newNote.content = replaceNoteKeyWithNewNoteKey( + newNote.content, + oldNote.key, + newNote.key + ) } else { - console.debug('Cloning of the attachment was skipped since it only works for MARKDOWN_NOTEs') + console.debug( + 'Cloning of the attachment was skipped since it only works for MARKDOWN_NOTEs' + ) } } -function generateFileNotFoundMarkdown () { - return '**' + i18n.__('⚠ 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! ⚠') + '**' +function generateFileNotFoundMarkdown() { + return ( + '**' + + i18n.__( + '⚠ 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! ⚠' + ) + + '**' + ) } /** @@ -730,9 +976,21 @@ function generateFileNotFoundMarkdown () { * @param text Text that might contain a attachment link * @return {Boolean} Result of the test */ -function isAttachmentLink (text) { +function isAttachmentLink(text) { if (text) { - return text.match(new RegExp('.*\\[.*\\]\\( *' + escapeStringRegexp(STORAGE_FOLDER_PLACEHOLDER) + '[' + PATH_SEPARATORS + ']' + '.*\\).*', 'gi')) != null + return ( + text.match( + new RegExp( + '.*\\[.*\\]\\( *' + + escapeStringRegexp(STORAGE_FOLDER_PLACEHOLDER) + + '[' + + PATH_SEPARATORS + + ']' + + '.*\\).*', + 'gi' + ) + ) != null + ) } return false } @@ -745,38 +1003,72 @@ function isAttachmentLink (text) { * @param linkText Text that was pasted * @return {Promise} Promise returning the modified text */ -function handleAttachmentLinkPaste (storageKey, noteKey, linkText) { +function handleAttachmentLinkPaste(storageKey, noteKey, linkText) { if (storageKey != null && noteKey != null && linkText != null) { const storagePath = findStorage.findStorage(storageKey).path const attachments = getAttachmentsInMarkdownContent(linkText) || [] const replaceInstructions = [] const copies = [] for (const attachment of attachments) { - const absPathOfAttachment = attachment.replace(new RegExp(STORAGE_FOLDER_PLACEHOLDER, 'g'), path.join(storagePath, DESTINATION_FOLDER)) + const absPathOfAttachment = attachment.replace( + new RegExp(STORAGE_FOLDER_PLACEHOLDER, 'g'), + path.join(storagePath, DESTINATION_FOLDER) + ) copies.push( - sander.exists(absPathOfAttachment) - .then((fileExists) => { - if (!fileExists) { - const fileNotFoundRegexp = new RegExp('!?' + escapeStringRegexp('[') + '[\\w|\\d|\\s|\\.]*\\]\\(\\s*' + STORAGE_FOLDER_PLACEHOLDER + '[\\w|\\d|\\-|' + PATH_SEPARATORS + ']*' + escapeStringRegexp(path.basename(absPathOfAttachment)) + escapeStringRegexp(')')) - replaceInstructions.push({regexp: fileNotFoundRegexp, replacement: this.generateFileNotFoundMarkdown()}) - return Promise.resolve() - } - return this.copyAttachment(absPathOfAttachment, storageKey, noteKey) - .then((fileName) => { - const replaceLinkRegExp = new RegExp(escapeStringRegexp('(') + ' *' + STORAGE_FOLDER_PLACEHOLDER + '[\\w|\\d|\\-|' + PATH_SEPARATORS + ']*' + escapeStringRegexp(path.basename(absPathOfAttachment)) + ' *' + escapeStringRegexp(')')) - replaceInstructions.push({ - regexp: replaceLinkRegExp, - replacement: '(' + path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, fileName) + ')' - }) - return Promise.resolve() - }) + sander.exists(absPathOfAttachment).then(fileExists => { + if (!fileExists) { + const fileNotFoundRegexp = new RegExp( + '!?' + + escapeStringRegexp('[') + + '[\\w|\\d|\\s|\\.]*\\]\\(\\s*' + + STORAGE_FOLDER_PLACEHOLDER + + '[\\w|\\d|\\-|' + + PATH_SEPARATORS + + ']*' + + escapeStringRegexp(path.basename(absPathOfAttachment)) + + escapeStringRegexp(')') + ) + replaceInstructions.push({ + regexp: fileNotFoundRegexp, + replacement: this.generateFileNotFoundMarkdown() + }) + return Promise.resolve() + } + return this.copyAttachment( + absPathOfAttachment, + storageKey, + noteKey + ).then(fileName => { + const replaceLinkRegExp = new RegExp( + escapeStringRegexp('(') + + ' *' + + STORAGE_FOLDER_PLACEHOLDER + + '[\\w|\\d|\\-|' + + PATH_SEPARATORS + + ']*' + + escapeStringRegexp(path.basename(absPathOfAttachment)) + + ' *' + + escapeStringRegexp(')') + ) + replaceInstructions.push({ + regexp: replaceLinkRegExp, + replacement: + '(' + + path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, fileName) + + ')' + }) + return Promise.resolve() }) + }) ) } return Promise.all(copies).then(() => { let modifiedLinkText = linkText for (const replaceInstruction of replaceInstructions) { - modifiedLinkText = modifiedLinkText.replace(replaceInstruction.regexp, replaceInstruction.replacement) + modifiedLinkText = modifiedLinkText.replace( + replaceInstruction.regexp, + replaceInstruction.replacement + ) } return modifiedLinkText }) diff --git a/browser/main/lib/dataApi/copyFile.js b/browser/main/lib/dataApi/copyFile.js index 6f23aae2..0b390b2a 100755 --- a/browser/main/lib/dataApi/copyFile.js +++ b/browser/main/lib/dataApi/copyFile.js @@ -7,7 +7,7 @@ const path = require('path') * @param {String} dstPath * @return {Promise} an image path */ -function copyFile (srcPath, dstPath) { +function copyFile(srcPath, dstPath) { if (!path.extname(dstPath)) { dstPath = path.join(dstPath, path.basename(srcPath)) } diff --git a/browser/main/lib/dataApi/createFolder.js b/browser/main/lib/dataApi/createFolder.js index 05fcea37..786d905b 100644 --- a/browser/main/lib/dataApi/createFolder.js +++ b/browser/main/lib/dataApi/createFolder.js @@ -22,7 +22,7 @@ const { findStorage } = require('browser/lib/findStorage') * } * ``` */ -function createFolder (storageKey, input) { +function createFolder(storageKey, input) { let targetStorage try { if (input == null) throw new Error('No input found.') @@ -34,26 +34,28 @@ function createFolder (storageKey, input) { return Promise.reject(e) } - return resolveStorageData(targetStorage) - .then(function createFolder (storage) { - let key = keygen() - while (storage.folders.some((folder) => folder.key === key)) { - key = keygen() - } - const newFolder = { - key, - color: input.color, - name: input.name - } + return resolveStorageData(targetStorage).then(function createFolder(storage) { + let key = keygen() + while (storage.folders.some(folder => folder.key === key)) { + key = keygen() + } + const newFolder = { + key, + color: input.color, + name: input.name + } - storage.folders.push(newFolder) + storage.folders.push(newFolder) - CSON.writeFileSync(path.join(storage.path, 'boostnote.json'), _.pick(storage, ['folders', 'version'])) + CSON.writeFileSync( + path.join(storage.path, 'boostnote.json'), + _.pick(storage, ['folders', 'version']) + ) - return { - storage - } - }) + return { + storage + } + }) } module.exports = createFolder diff --git a/browser/main/lib/dataApi/createNote.js b/browser/main/lib/dataApi/createNote.js index 5bfa2457..079a988b 100644 --- a/browser/main/lib/dataApi/createNote.js +++ b/browser/main/lib/dataApi/createNote.js @@ -6,9 +6,11 @@ const path = require('path') const CSON = require('@rokt33r/season') const { findStorage } = require('browser/lib/findStorage') -function validateInput (input) { +function validateInput(input) { if (!_.isArray(input.tags)) input.tags = [] - input.tags = input.tags.filter((tag) => _.isString(tag) && tag.trim().length > 0) + input.tags = input.tags.filter( + tag => _.isString(tag) && tag.trim().length > 0 + ) if (!_.isString(input.title)) input.title = '' input.isStarred = !!input.isStarred input.isTrashed = !!input.isTrashed @@ -21,20 +23,24 @@ function validateInput (input) { case 'SNIPPET_NOTE': if (!_.isString(input.description)) input.description = '' if (!_.isArray(input.snippets)) { - input.snippets = [{ - name: '', - mode: 'text', - content: '', - linesHighlighted: [] - }] + input.snippets = [ + { + name: '', + mode: 'text', + content: '', + linesHighlighted: [] + } + ] } break default: - throw new Error('Invalid type: only MARKDOWN_NOTE and SNIPPET_NOTE are available.') + throw new Error( + 'Invalid type: only MARKDOWN_NOTE and SNIPPET_NOTE are available.' + ) } } -function createNote (storageKey, input) { +function createNote(storageKey, input) { let targetStorage try { if (input == null) throw new Error('No input found.') @@ -47,13 +53,13 @@ function createNote (storageKey, input) { } return resolveStorageData(targetStorage) - .then(function checkFolderExists (storage) { - if (_.find(storage.folders, {key: input.folder}) == null) { - throw new Error('Target folder doesn\'t exist.') + .then(function checkFolderExists(storage) { + if (_.find(storage.folders, { key: input.folder }) == null) { + throw new Error("Target folder doesn't exist.") } return storage }) - .then(function saveNote (storage) { + .then(function saveNote(storage) { let key = keygen(true) let isUnique = false while (!isUnique) { @@ -68,7 +74,8 @@ function createNote (storageKey, input) { } } } - const noteData = Object.assign({}, + const noteData = Object.assign( + {}, { createdAt: new Date(), updatedAt: new Date() @@ -77,9 +84,13 @@ function createNote (storageKey, input) { { key, storage: storageKey - }) + } + ) - CSON.writeFileSync(path.join(storage.path, 'notes', key + '.cson'), _.omit(noteData, ['key', 'storage'])) + CSON.writeFileSync( + path.join(storage.path, 'notes', key + '.cson'), + _.omit(noteData, ['key', 'storage']) + ) return noteData }) diff --git a/browser/main/lib/dataApi/createNoteFromUrl.js b/browser/main/lib/dataApi/createNoteFromUrl.js index ead93f9e..2fd3bd9d 100644 --- a/browser/main/lib/dataApi/createNoteFromUrl.js +++ b/browser/main/lib/dataApi/createNoteFromUrl.js @@ -6,8 +6,12 @@ const createNote = require('./createNote') import { push } from 'connected-react-router' import ee from 'browser/main/lib/eventEmitter' -function validateUrl (str) { - if (/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(str)) { +function validateUrl(str) { + if ( + /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test( + str + ) + ) { return true } else { return false @@ -15,25 +19,33 @@ function validateUrl (str) { } const ERROR_MESSAGES = { - ENOTFOUND: 'URL not found. Please check the URL, or your internet connection and try again.', - VALIDATION_ERROR: 'Please check if the URL follows this format: https://www.google.com', + ENOTFOUND: + 'URL not found. Please check the URL, or your internet connection and try again.', + VALIDATION_ERROR: + 'Please check if the URL follows this format: https://www.google.com', UNEXPECTED: 'Unexpected error! Please check console for details!' } -function createNoteFromUrl (url, storage, folder, dispatch = null, location = null) { +function createNoteFromUrl( + url, + storage, + folder, + dispatch = null, + location = null +) { return new Promise((resolve, reject) => { const td = createTurndownService() if (!validateUrl(url)) { - reject({result: false, error: ERROR_MESSAGES.VALIDATION_ERROR}) + reject({ result: false, error: ERROR_MESSAGES.VALIDATION_ERROR }) } const request = url.startsWith('https') ? https : http - const req = request.request(url, (res) => { + const req = request.request(url, res => { let data = '' - res.on('data', (chunk) => { + res.on('data', chunk => { data += chunk }) @@ -46,20 +58,21 @@ function createNoteFromUrl (url, storage, folder, dispatch = null, location = nu folder: folder, title: '', content: markdownHTML - }) - .then((note) => { + }).then(note => { const noteHash = note.key dispatch({ type: 'UPDATE_NOTE', note: note }) - dispatch(push({ - pathname: location.pathname, - query: {key: noteHash} - })) + dispatch( + push({ + pathname: location.pathname, + query: { key: noteHash } + }) + ) ee.emit('list:jump', noteHash) ee.emit('detail:focus') - resolve({result: true, error: null}) + resolve({ result: true, error: null }) }) } else { createNote(storage, { @@ -67,16 +80,19 @@ function createNoteFromUrl (url, storage, folder, dispatch = null, location = nu folder: folder, title: '', content: markdownHTML - }).then((note) => { - resolve({result: true, note, error: null}) + }).then(note => { + resolve({ result: true, note, error: null }) }) } }) }) - req.on('error', (e) => { + req.on('error', e => { console.error('error in parsing URL', e) - reject({result: false, error: ERROR_MESSAGES[e.code] || ERROR_MESSAGES.UNEXPECTED}) + reject({ + result: false, + error: ERROR_MESSAGES[e.code] || ERROR_MESSAGES.UNEXPECTED + }) }) req.end() diff --git a/browser/main/lib/dataApi/createSnippet.js b/browser/main/lib/dataApi/createSnippet.js index 2e585c9f..48d6705d 100644 --- a/browser/main/lib/dataApi/createSnippet.js +++ b/browser/main/lib/dataApi/createSnippet.js @@ -3,7 +3,7 @@ import crypto from 'crypto' import consts from 'browser/lib/consts' import fetchSnippet from 'browser/main/lib/dataApi/fetchSnippet' -function createSnippet (snippetFile) { +function createSnippet(snippetFile) { return new Promise((resolve, reject) => { const newSnippet = { id: crypto.randomBytes(16).toString('hex'), @@ -12,15 +12,21 @@ function createSnippet (snippetFile) { content: '', linesHighlighted: [] } - fetchSnippet(null, snippetFile).then((snippets) => { - snippets.push(newSnippet) - fs.writeFile(snippetFile || consts.SNIPPET_FILE, JSON.stringify(snippets, null, 4), (err) => { - if (err) reject(err) - resolve(newSnippet) + fetchSnippet(null, snippetFile) + .then(snippets => { + snippets.push(newSnippet) + fs.writeFile( + snippetFile || consts.SNIPPET_FILE, + JSON.stringify(snippets, null, 4), + err => { + if (err) reject(err) + resolve(newSnippet) + } + ) + }) + .catch(err => { + reject(err) }) - }).catch((err) => { - reject(err) - }) }) } diff --git a/browser/main/lib/dataApi/deleteFolder.js b/browser/main/lib/dataApi/deleteFolder.js index 5ccc1414..f20078c8 100644 --- a/browser/main/lib/dataApi/deleteFolder.js +++ b/browser/main/lib/dataApi/deleteFolder.js @@ -18,7 +18,7 @@ const deleteSingleNote = require('./deleteNote') * } * ``` */ -function deleteFolder (storageKey, folderKey) { +function deleteFolder(storageKey, folderKey) { let targetStorage try { targetStorage = findStorage(storageKey) @@ -27,35 +27,36 @@ function deleteFolder (storageKey, folderKey) { } return resolveStorageData(targetStorage) - .then(function assignNotes (storage) { - return resolveStorageNotes(storage) - .then((notes) => { - return { - storage, - notes - } - }) + .then(function assignNotes(storage) { + return resolveStorageNotes(storage).then(notes => { + return { + storage, + notes + } + }) }) - .then(function deleteFolderAndNotes (data) { + .then(function deleteFolderAndNotes(data) { const { storage, notes } = data - storage.folders = storage.folders - .filter(function excludeTargetFolder (folder) { - return folder.key !== folderKey - }) + storage.folders = storage.folders.filter(function excludeTargetFolder( + folder + ) { + return folder.key !== folderKey + }) - const targetNotes = notes.filter(function filterTargetNotes (note) { + const targetNotes = notes.filter(function filterTargetNotes(note) { return note.folder === folderKey }) - const deleteAllNotes = targetNotes - .map(function deleteNote (note) { - return deleteSingleNote(storageKey, note.key) - }) - return Promise.all(deleteAllNotes) - .then(() => storage) + const deleteAllNotes = targetNotes.map(function deleteNote(note) { + return deleteSingleNote(storageKey, note.key) + }) + return Promise.all(deleteAllNotes).then(() => storage) }) - .then(function (storage) { - CSON.writeFileSync(path.join(storage.path, 'boostnote.json'), _.pick(storage, ['folders', 'version'])) + .then(function(storage) { + CSON.writeFileSync( + path.join(storage.path, 'boostnote.json'), + _.pick(storage, ['folders', 'version']) + ) return { storage, diff --git a/browser/main/lib/dataApi/deleteNote.js b/browser/main/lib/dataApi/deleteNote.js index 46ec2b55..b40fdfe5 100644 --- a/browser/main/lib/dataApi/deleteNote.js +++ b/browser/main/lib/dataApi/deleteNote.js @@ -4,7 +4,7 @@ const sander = require('sander') const attachmentManagement = require('./attachmentManagement') const { findStorage } = require('browser/lib/findStorage') -function deleteNote (storageKey, noteKey) { +function deleteNote(storageKey, noteKey) { let targetStorage try { targetStorage = findStorage(storageKey) @@ -13,7 +13,7 @@ function deleteNote (storageKey, noteKey) { } return resolveStorageData(targetStorage) - .then(function deleteNoteFile (storage) { + .then(function deleteNoteFile(storage) { const notePath = path.join(storage.path, 'notes', noteKey + '.cson') try { @@ -26,8 +26,11 @@ function deleteNote (storageKey, noteKey) { storageKey } }) - .then(function deleteAttachments (storageInfo) { - attachmentManagement.deleteAttachmentFolder(storageInfo.storageKey, storageInfo.noteKey) + .then(function deleteAttachments(storageInfo) { + attachmentManagement.deleteAttachmentFolder( + storageInfo.storageKey, + storageInfo.noteKey + ) return storageInfo }) } diff --git a/browser/main/lib/dataApi/deleteSnippet.js b/browser/main/lib/dataApi/deleteSnippet.js index 0e446886..bd7b1223 100644 --- a/browser/main/lib/dataApi/deleteSnippet.js +++ b/browser/main/lib/dataApi/deleteSnippet.js @@ -2,14 +2,20 @@ import fs from 'fs' import consts from 'browser/lib/consts' import fetchSnippet from 'browser/main/lib/dataApi/fetchSnippet' -function deleteSnippet (snippet, snippetFile) { +function deleteSnippet(snippet, snippetFile) { return new Promise((resolve, reject) => { - fetchSnippet(null, snippetFile).then((snippets) => { - snippets = snippets.filter(currentSnippet => currentSnippet.id !== snippet.id) - fs.writeFile(snippetFile || consts.SNIPPET_FILE, JSON.stringify(snippets, null, 4), (err) => { - if (err) reject(err) - resolve(snippet) - }) + fetchSnippet(null, snippetFile).then(snippets => { + snippets = snippets.filter( + currentSnippet => currentSnippet.id !== snippet.id + ) + fs.writeFile( + snippetFile || consts.SNIPPET_FILE, + JSON.stringify(snippets, null, 4), + err => { + if (err) reject(err) + resolve(snippet) + } + ) }) }) } diff --git a/browser/main/lib/dataApi/exportFolder.js b/browser/main/lib/dataApi/exportFolder.js index 8f15b147..a77ba29b 100644 --- a/browser/main/lib/dataApi/exportFolder.js +++ b/browser/main/lib/dataApi/exportFolder.js @@ -22,7 +22,7 @@ import * as path from 'path' * ``` */ -function exportFolder (storageKey, folderKey, fileType, exportDir) { +function exportFolder(storageKey, folderKey, fileType, exportDir) { let targetStorage try { targetStorage = findStorage(storageKey) @@ -31,24 +31,38 @@ function exportFolder (storageKey, folderKey, fileType, exportDir) { } return resolveStorageData(targetStorage) - .then(function assignNotes (storage) { - return resolveStorageNotes(storage) - .then((notes) => { - return { - storage, - notes - } - }) + .then(function assignNotes(storage) { + return resolveStorageNotes(storage).then(notes => { + return { + storage, + notes + } + }) }) - .then(function exportNotes (data) { + .then(function exportNotes(data) { const { storage, notes } = data - return Promise.all(notes - .filter(note => note.folder === folderKey && note.isTrashed === false && note.type === 'MARKDOWN_NOTE') - .map(note => { - const notePath = path.join(exportDir, `${filenamify(note.title, {replacement: '_'})}.${fileType}`) - return exportNote(note.key, storage.path, note.content, notePath, null) - }) + return Promise.all( + notes + .filter( + note => + note.folder === folderKey && + note.isTrashed === false && + note.type === 'MARKDOWN_NOTE' + ) + .map(note => { + const notePath = path.join( + exportDir, + `${filenamify(note.title, { replacement: '_' })}.${fileType}` + ) + return exportNote( + note.key, + storage.path, + note.content, + notePath, + null + ) + }) ).then(() => ({ storage, folderKey, diff --git a/browser/main/lib/dataApi/exportNote.js b/browser/main/lib/dataApi/exportNote.js index 42e1fa56..ffd45a1c 100755 --- a/browser/main/lib/dataApi/exportNote.js +++ b/browser/main/lib/dataApi/exportNote.js @@ -19,8 +19,16 @@ const attachmentManagement = require('./attachmentManagement') * @param {function} outputFormatter * @return {Promise.<*[]>} */ -function exportNote (nodeKey, storageKey, noteContent, targetPath, outputFormatter) { - const storagePath = path.isAbsolute(storageKey) ? storageKey : findStorage(storageKey).path +function exportNote( + nodeKey, + storageKey, + noteContent, + targetPath, + outputFormatter +) { + const storagePath = path.isAbsolute(storageKey) + ? storageKey + : findStorage(storageKey).path const exportTasks = [] if (!storagePath) { @@ -50,18 +58,19 @@ function exportNote (nodeKey, storageKey, noteContent, targetPath, outputFormatt const tasks = prepareTasks(exportTasks, storagePath, path.dirname(targetPath)) - return Promise.all(tasks.map((task) => copyFile(task.src, task.dst))) - .then(() => exportedData) - .then(data => { - return saveToFile(data, targetPath) - }).catch((err) => { - rollbackExport(tasks) - throw err - }) + return Promise.all(tasks.map(task => copyFile(task.src, task.dst))) + .then(() => exportedData) + .then(data => { + return saveToFile(data, targetPath) + }) + .catch(err => { + rollbackExport(tasks) + throw err + }) } -function prepareTasks (tasks, storagePath, targetPath) { - return tasks.map((task) => { +function prepareTasks(tasks, storagePath, targetPath) { + return tasks.map(task => { if (!path.isAbsolute(task.src)) { task.src = path.join(storagePath, task.src) } @@ -74,9 +83,9 @@ function prepareTasks (tasks, storagePath, targetPath) { }) } -function saveToFile (data, filename) { +function saveToFile(data, filename) { return new Promise((resolve, reject) => { - fs.writeFile(filename, data, (err) => { + fs.writeFile(filename, data, err => { if (err) return reject(err) resolve(filename) @@ -88,9 +97,9 @@ function saveToFile (data, filename) { * Remove exported files * @param tasks Array of copy task objects. Object consists of two mandatory fields – `src` and `dst` */ -function rollbackExport (tasks) { +function rollbackExport(tasks) { const folders = new Set() - tasks.forEach((task) => { + tasks.forEach(task => { let fullpath = task.dst if (!path.extname(task.dst)) { @@ -103,7 +112,7 @@ function rollbackExport (tasks) { } }) - folders.forEach((folder) => { + folders.forEach(folder => { if (fs.readdirSync(folder).length === 0) { fs.rmdir(folder) } diff --git a/browser/main/lib/dataApi/exportStorage.js b/browser/main/lib/dataApi/exportStorage.js index ce2c4573..2a7c725c 100644 --- a/browser/main/lib/dataApi/exportStorage.js +++ b/browser/main/lib/dataApi/exportStorage.js @@ -20,7 +20,7 @@ import * as fs from 'fs' * ``` */ -function exportStorage (storageKey, fileType, exportDir) { +function exportStorage(storageKey, fileType, exportDir) { let targetStorage try { targetStorage = findStorage(storageKey) @@ -29,14 +29,17 @@ function exportStorage (storageKey, fileType, exportDir) { } return resolveStorageData(targetStorage) - .then(storage => ( - resolveStorageNotes(storage).then(notes => ({storage, notes})) - )) - .then(function exportNotes (data) { + .then(storage => + resolveStorageNotes(storage).then(notes => ({ storage, notes })) + ) + .then(function exportNotes(data) { const { storage, notes } = data const folderNamesMapping = {} storage.folders.forEach(folder => { - const folderExportedDir = path.join(exportDir, filenamify(folder.name, {replacement: '_'})) + const folderExportedDir = path.join( + exportDir, + filenamify(folder.name, { replacement: '_' }) + ) folderNamesMapping[folder.key] = folderExportedDir // make sure directory exists try { @@ -47,7 +50,9 @@ function exportStorage (storageKey, fileType, exportDir) { .filter(note => !note.isTrashed && note.type === 'MARKDOWN_NOTE') .forEach(markdownNote => { const folderExportedDir = folderNamesMapping[markdownNote.folder] - const snippetName = `${filenamify(markdownNote.title, {replacement: '_'})}.${fileType}` + const snippetName = `${filenamify(markdownNote.title, { + replacement: '_' + })}.${fileType}` const notePath = path.join(folderExportedDir, snippetName) fs.writeFileSync(notePath, markdownNote.content) }) diff --git a/browser/main/lib/dataApi/fetchSnippet.js b/browser/main/lib/dataApi/fetchSnippet.js index 456a5090..8344eb5d 100644 --- a/browser/main/lib/dataApi/fetchSnippet.js +++ b/browser/main/lib/dataApi/fetchSnippet.js @@ -1,7 +1,7 @@ import fs from 'fs' import consts from 'browser/lib/consts' -function fetchSnippet (id, snippetFile) { +function fetchSnippet(id, snippetFile) { return new Promise((resolve, reject) => { fs.readFile(snippetFile || consts.SNIPPET_FILE, 'utf8', (err, data) => { if (err) { @@ -9,7 +9,9 @@ function fetchSnippet (id, snippetFile) { } const snippets = JSON.parse(data) if (id) { - const snippet = snippets.find(snippet => { return snippet.id === id }) + const snippet = snippets.find(snippet => { + return snippet.id === id + }) resolve(snippet) } resolve(snippets) diff --git a/browser/main/lib/dataApi/init.js b/browser/main/lib/dataApi/init.js index 0dbcc182..0ad35625 100644 --- a/browser/main/lib/dataApi/init.js +++ b/browser/main/lib/dataApi/init.js @@ -21,8 +21,8 @@ const CSON = require('@rokt33r/season') * 3. empty directory */ -function init () { - const fetchStorages = function () { +function init() { + const fetchStorages = function() { let rawStorages try { rawStorages = JSON.parse(window.localStorage.getItem('storages')) @@ -34,44 +34,50 @@ function init () { rawStorages = [] window.localStorage.setItem('storages', JSON.stringify(rawStorages)) } - return Promise.all(rawStorages - .map(resolveStorageData)) + return Promise.all(rawStorages.map(resolveStorageData)) } - const fetchNotes = function (storages) { + const fetchNotes = function(storages) { const findNotesFromEachStorage = storages - .filter(storage => fs.existsSync(storage.path)) - .map((storage) => { - return resolveStorageNotes(storage) - .then((notes) => { - let unknownCount = 0 - notes.forEach((note) => { - if (note && !storage.folders.some((folder) => note.folder === folder.key)) { - unknownCount++ - storage.folders.push({ - key: note.folder, - color: consts.FOLDER_COLORS[(unknownCount - 1) % 7], - name: 'Unknown ' + unknownCount - }) - } - }) - if (unknownCount > 0) { - try { - CSON.writeFileSync(path.join(storage.path, 'boostnote.json'), _.pick(storage, ['folders', 'version'])) - } catch (e) { - console.log('Error writting boostnote.json: ' + e + ' from init.js') - } + .filter(storage => fs.existsSync(storage.path)) + .map(storage => { + return resolveStorageNotes(storage).then(notes => { + let unknownCount = 0 + notes.forEach(note => { + if ( + note && + !storage.folders.some(folder => note.folder === folder.key) + ) { + unknownCount++ + storage.folders.push({ + key: note.folder, + color: consts.FOLDER_COLORS[(unknownCount - 1) % 7], + name: 'Unknown ' + unknownCount + }) } - return notes }) + if (unknownCount > 0) { + try { + CSON.writeFileSync( + path.join(storage.path, 'boostnote.json'), + _.pick(storage, ['folders', 'version']) + ) + } catch (e) { + console.log( + 'Error writting boostnote.json: ' + e + ' from init.js' + ) + } + } + return notes + }) }) return Promise.all(findNotesFromEachStorage) - .then(function concatNoteGroup (noteGroups) { - return noteGroups.reduce(function (sum, group) { + .then(function concatNoteGroup(noteGroups) { + return noteGroups.reduce(function(sum, group) { return sum.concat(group) }, []) }) - .then(function returnData (notes) { + .then(function returnData(notes) { return { storages, notes @@ -80,12 +86,11 @@ function init () { } return Promise.resolve(fetchStorages()) - .then((storages) => { - return storages - .filter((storage) => { - if (!_.isObject(storage)) return false - return true - }) + .then(storages => { + return storages.filter(storage => { + if (!_.isObject(storage)) return false + return true + }) }) .then(fetchNotes) } diff --git a/browser/main/lib/dataApi/migrateFromV5Storage.js b/browser/main/lib/dataApi/migrateFromV5Storage.js index 78d78746..abf57831 100644 --- a/browser/main/lib/dataApi/migrateFromV5Storage.js +++ b/browser/main/lib/dataApi/migrateFromV5Storage.js @@ -6,102 +6,111 @@ const CSON = require('@rokt33r/season') const path = require('path') const sander = require('sander') -function migrateFromV5Storage (storageKey, data) { +function migrateFromV5Storage(storageKey, data) { let targetStorage try { const cachedStorageList = JSON.parse(localStorage.getItem('storages')) - if (!_.isArray(cachedStorageList)) throw new Error('Target storage doesn\'t exist.') + if (!_.isArray(cachedStorageList)) + throw new Error("Target storage doesn't exist.") - targetStorage = _.find(cachedStorageList, {key: storageKey}) - if (targetStorage == null) throw new Error('Target storage doesn\'t exist.') + targetStorage = _.find(cachedStorageList, { key: storageKey }) + if (targetStorage == null) throw new Error("Target storage doesn't exist.") } catch (e) { return Promise.reject(e) } - return resolveStorageData(targetStorage) - .then(function (storage) { - return importAll(storage, data) - }) + return resolveStorageData(targetStorage).then(function(storage) { + return importAll(storage, data) + }) } -function importAll (storage, data) { +function importAll(storage, data) { const oldArticles = data.articles const notes = [] - data.folders - .forEach(function (oldFolder) { - let folderKey = keygen() - while (storage.folders.some((folder) => folder.key === folderKey)) { - folderKey = keygen() - } - const newFolder = { - key: folderKey, - name: oldFolder.name, - color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7] - } + data.folders.forEach(function(oldFolder) { + let folderKey = keygen() + while (storage.folders.some(folder => folder.key === folderKey)) { + folderKey = keygen() + } + const newFolder = { + key: folderKey, + name: oldFolder.name, + color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7] + } - storage.folders.push(newFolder) + storage.folders.push(newFolder) - const articles = oldArticles.filter((article) => article.FolderKey === oldFolder.key) - articles.forEach((article) => { - let noteKey = keygen() - let isUnique = false - while (!isUnique) { - try { - sander.statSync(path.join(storage.path, 'notes', noteKey + '.cson')) - noteKey = keygen() - } catch (err) { - if (err.code === 'ENOENT') { - isUnique = true - } else { - console.error('Failed to read `notes` directory.') - throw err - } + const articles = oldArticles.filter( + article => article.FolderKey === oldFolder.key + ) + articles.forEach(article => { + let noteKey = keygen() + let isUnique = false + while (!isUnique) { + try { + sander.statSync(path.join(storage.path, 'notes', noteKey + '.cson')) + noteKey = keygen() + } catch (err) { + if (err.code === 'ENOENT') { + isUnique = true + } else { + console.error('Failed to read `notes` directory.') + throw err } } + } - if (article.mode === 'markdown') { - const newNote = { - tags: article.tags, - createdAt: article.createdAt, - updatedAt: article.updatedAt, - folder: folderKey, - storage: storage.key, - type: 'MARKDOWN_NOTE', - isStarred: false, - title: article.title, - content: '# ' + article.title + '\n\n' + article.content, - key: noteKey, - linesHighlighted: article.linesHighlighted - } - notes.push(newNote) - } else { - const newNote = { - tags: article.tags, - createdAt: article.createdAt, - updatedAt: article.updatedAt, - folder: folderKey, - storage: storage.key, - type: 'SNIPPET_NOTE', - isStarred: false, - title: article.title, - description: article.title, - key: noteKey, - snippets: [{ + if (article.mode === 'markdown') { + const newNote = { + tags: article.tags, + createdAt: article.createdAt, + updatedAt: article.updatedAt, + folder: folderKey, + storage: storage.key, + type: 'MARKDOWN_NOTE', + isStarred: false, + title: article.title, + content: '# ' + article.title + '\n\n' + article.content, + key: noteKey, + linesHighlighted: article.linesHighlighted + } + notes.push(newNote) + } else { + const newNote = { + tags: article.tags, + createdAt: article.createdAt, + updatedAt: article.updatedAt, + folder: folderKey, + storage: storage.key, + type: 'SNIPPET_NOTE', + isStarred: false, + title: article.title, + description: article.title, + key: noteKey, + snippets: [ + { name: article.mode, mode: article.mode, content: article.content, linesHighlighted: article.linesHighlighted - }] - } - notes.push(newNote) + } + ] } - }) + notes.push(newNote) + } }) - - notes.forEach(function (note) { - CSON.writeFileSync(path.join(storage.path, 'notes', note.key + '.cson'), _.omit(note, ['storage', 'key'])) }) - CSON.writeFileSync(path.join(storage.path, 'boostnote.json'), _.pick(storage, ['version', 'folders'])) + notes.forEach(function(note) { + CSON.writeFileSync( + path.join(storage.path, 'notes', note.key + '.cson'), + _.omit(note, ['storage', 'key']) + ) + }) + + CSON.writeFileSync( + path.join(storage.path, 'boostnote.json'), + _.pick(storage, ['version', 'folders']) + ) return { storage, diff --git a/browser/main/lib/dataApi/migrateFromV6Storage.js b/browser/main/lib/dataApi/migrateFromV6Storage.js index af4d902f..8255a0de 100644 --- a/browser/main/lib/dataApi/migrateFromV6Storage.js +++ b/browser/main/lib/dataApi/migrateFromV6Storage.js @@ -4,86 +4,91 @@ const keygen = require('browser/lib/keygen') const _ = require('lodash') const CSON = require('@rokt33r/season') -function migrateFromV5Storage (storagePath) { +function migrateFromV5Storage(storagePath) { var boostnoteJSONPath = path.join(storagePath, 'boostnote.json') return Promise.resolve() - .then(function readBoostnoteJSON () { + .then(function readBoostnoteJSON() { return sander.readFile(boostnoteJSONPath, { encoding: 'utf-8' }) }) - .then(function verifyVersion (rawData) { + .then(function verifyVersion(rawData) { var boostnoteJSONData = JSON.parse(rawData) - if (boostnoteJSONData.version === '1.0') throw new Error('Target storage seems to be transformed already.') - if (!_.isArray(boostnoteJSONData.folders)) throw new Error('the value of folders is not an array.') + if (boostnoteJSONData.version === '1.0') + throw new Error('Target storage seems to be transformed already.') + if (!_.isArray(boostnoteJSONData.folders)) + throw new Error('the value of folders is not an array.') return boostnoteJSONData }) - .then(function setVersion (boostnoteJSONData) { + .then(function setVersion(boostnoteJSONData) { boostnoteJSONData.version = '1.0' - return sander.writeFile(boostnoteJSONPath, JSON.stringify(boostnoteJSONData)) + return sander + .writeFile(boostnoteJSONPath, JSON.stringify(boostnoteJSONData)) .then(() => boostnoteJSONData) }) - .then(function fetchNotes (boostnoteJSONData) { - var fetchNotesFromEachFolder = boostnoteJSONData.folders - .map(function (folder) { - const folderDataJSONPath = path.join(storagePath, folder.key, 'data.json') - return sander - .readFile(folderDataJSONPath, { - encoding: 'utf-8' + .then(function fetchNotes(boostnoteJSONData) { + var fetchNotesFromEachFolder = boostnoteJSONData.folders.map(function( + folder + ) { + const folderDataJSONPath = path.join( + storagePath, + folder.key, + 'data.json' + ) + return sander + .readFile(folderDataJSONPath, { + encoding: 'utf-8' + }) + .then(function(rawData) { + var data = JSON.parse(rawData) + if (!_.isArray(data.notes)) + throw new Error('value of notes is not an array.') + return data.notes.map(function setFolderToNote(note) { + note.folder = folder.key + return note }) - .then(function (rawData) { - var data = JSON.parse(rawData) - if (!_.isArray(data.notes)) throw new Error('value of notes is not an array.') - return data.notes - .map(function setFolderToNote (note) { - note.folder = folder.key - return note - }) - }) - .catch(function failedToReadDataJSON (err) { - console.warn('Failed to fetch notes from ', folderDataJSONPath, err) - return [] - }) - }) + }) + .catch(function failedToReadDataJSON(err) { + console.warn('Failed to fetch notes from ', folderDataJSONPath, err) + return [] + }) + }) return Promise.all(fetchNotesFromEachFolder) - .then(function flatten (folderNotes) { - return folderNotes - .reduce(function concatNotes (sum, notes) { - return sum.concat(notes) - }, []) + .then(function flatten(folderNotes) { + return folderNotes.reduce(function concatNotes(sum, notes) { + return sum.concat(notes) + }, []) }) - .then(function saveNotes (notes) { - notes.forEach(function renewKey (note) { + .then(function saveNotes(notes) { + notes.forEach(function renewKey(note) { var newKey = keygen() - while (notes.some((_note) => _note.key === newKey)) { + while (notes.some(_note => _note.key === newKey)) { newKey = keygen() } note.key = newKey }) const noteDirPath = path.join(storagePath, 'notes') - notes - .map(function saveNote (note) { - CSON.writeFileSync(path.join(noteDirPath, note.key) + '.cson', note) - }) + notes.map(function saveNote(note) { + CSON.writeFileSync(path.join(noteDirPath, note.key) + '.cson', note) + }) return true }) - .then(function deleteFolderDir (check) { + .then(function deleteFolderDir(check) { if (check) { - boostnoteJSONData.folders.forEach((folder) => { + boostnoteJSONData.folders.forEach(folder => { sander.rimrafSync(path.join(storagePath, folder.key)) }) } return check }) }) - .catch(function handleError (err) { + .catch(function handleError(err) { console.warn(err) return false }) } module.exports = migrateFromV5Storage - diff --git a/browser/main/lib/dataApi/moveNote.js b/browser/main/lib/dataApi/moveNote.js index c38968cb..b72db7aa 100644 --- a/browser/main/lib/dataApi/moveNote.js +++ b/browser/main/lib/dataApi/moveNote.js @@ -7,90 +7,104 @@ const sander = require('sander') const { findStorage } = require('browser/lib/findStorage') const attachmentManagement = require('./attachmentManagement') -function moveNote (storageKey, noteKey, newStorageKey, newFolderKey) { +function moveNote(storageKey, noteKey, newStorageKey, newFolderKey) { let oldStorage, newStorage try { oldStorage = findStorage(storageKey) newStorage = findStorage(newStorageKey) - if (newStorage == null) throw new Error('Target storage doesn\'t exist.') + if (newStorage == null) throw new Error("Target storage doesn't exist.") } catch (e) { return Promise.reject(e) } - return resolveStorageData(oldStorage) - .then(function saveNote (_oldStorage) { - oldStorage = _oldStorage - let noteData - const notePath = path.join(oldStorage.path, 'notes', noteKey + '.cson') - try { - noteData = CSON.readFileSync(notePath) - } catch (err) { - console.warn('Failed to find note cson', err) - throw err - } - let newNoteKey - return Promise.resolve() - .then(function resolveNewStorage () { - if (storageKey === newStorageKey) { - newNoteKey = noteKey - return oldStorage - } - return resolveStorageData(newStorage) - .then(function findNewNoteKey (_newStorage) { - newStorage = _newStorage - newNoteKey = keygen(true) - let isUnique = false - while (!isUnique) { - try { - sander.statSync(path.join(newStorage.path, 'notes', newNoteKey + '.cson')) - newNoteKey = keygen(true) - } catch (err) { - if (err.code === 'ENOENT') { - isUnique = true - } else { - throw err - } - } - } - - return newStorage - }) - }) - .then(function checkFolderExistsAndPrepareNoteData (newStorage) { - if (_.find(newStorage.folders, {key: newFolderKey}) == null) throw new Error('Target folder doesn\'t exist.') - - noteData.folder = newFolderKey - noteData.key = newNoteKey - noteData.storage = newStorageKey - noteData.updatedAt = new Date() - noteData.oldContent = noteData.content - - return noteData - }) - .then(function moveAttachments (noteData) { - if (oldStorage.path === newStorage.path) { - return noteData - } - - noteData.content = attachmentManagement.moveAttachments(oldStorage.path, newStorage.path, noteKey, newNoteKey, noteData.content) - return noteData - }) - .then(function writeAndReturn (noteData) { - CSON.writeFileSync(path.join(newStorage.path, 'notes', noteData.key + '.cson'), _.omit(noteData, ['key', 'storage', 'oldContent'])) - return noteData - }) - .then(function deleteOldNote (data) { - if (storageKey !== newStorageKey) { + return resolveStorageData(oldStorage).then(function saveNote(_oldStorage) { + oldStorage = _oldStorage + let noteData + const notePath = path.join(oldStorage.path, 'notes', noteKey + '.cson') + try { + noteData = CSON.readFileSync(notePath) + } catch (err) { + console.warn('Failed to find note cson', err) + throw err + } + let newNoteKey + return Promise.resolve() + .then(function resolveNewStorage() { + if (storageKey === newStorageKey) { + newNoteKey = noteKey + return oldStorage + } + return resolveStorageData(newStorage).then(function findNewNoteKey( + _newStorage + ) { + newStorage = _newStorage + newNoteKey = keygen(true) + let isUnique = false + while (!isUnique) { try { - sander.unlinkSync(path.join(oldStorage.path, 'notes', noteKey + '.cson')) + sander.statSync( + path.join(newStorage.path, 'notes', newNoteKey + '.cson') + ) + newNoteKey = keygen(true) } catch (err) { - console.warn(err) + if (err.code === 'ENOENT') { + isUnique = true + } else { + throw err + } } } - return data + return newStorage }) - }) + }) + .then(function checkFolderExistsAndPrepareNoteData(newStorage) { + if (_.find(newStorage.folders, { key: newFolderKey }) == null) + throw new Error("Target folder doesn't exist.") + + noteData.folder = newFolderKey + noteData.key = newNoteKey + noteData.storage = newStorageKey + noteData.updatedAt = new Date() + noteData.oldContent = noteData.content + + return noteData + }) + .then(function moveAttachments(noteData) { + if (oldStorage.path === newStorage.path) { + return noteData + } + + noteData.content = attachmentManagement.moveAttachments( + oldStorage.path, + newStorage.path, + noteKey, + newNoteKey, + noteData.content + ) + return noteData + }) + .then(function writeAndReturn(noteData) { + CSON.writeFileSync( + path.join(newStorage.path, 'notes', noteData.key + '.cson'), + _.omit(noteData, ['key', 'storage', 'oldContent']) + ) + return noteData + }) + .then(function deleteOldNote(data) { + if (storageKey !== newStorageKey) { + try { + sander.unlinkSync( + path.join(oldStorage.path, 'notes', noteKey + '.cson') + ) + } catch (err) { + console.warn(err) + } + } + + return data + }) + }) } module.exports = moveNote diff --git a/browser/main/lib/dataApi/removeStorage.js b/browser/main/lib/dataApi/removeStorage.js index c50bbd12..3f957ab2 100644 --- a/browser/main/lib/dataApi/removeStorage.js +++ b/browser/main/lib/dataApi/removeStorage.js @@ -4,7 +4,7 @@ const _ = require('lodash') * @param {String} key * @return {key} */ -function removeStorage (key) { +function removeStorage(key) { let rawStorages try { @@ -15,10 +15,9 @@ function removeStorage (key) { rawStorages = [] } - rawStorages = rawStorages - .filter(function excludeTargetStorage (rawStorage) { - return rawStorage.key !== key - }) + rawStorages = rawStorages.filter(function excludeTargetStorage(rawStorage) { + return rawStorage.key !== key + }) localStorage.setItem('storages', JSON.stringify(rawStorages)) diff --git a/browser/main/lib/dataApi/renameStorage.js b/browser/main/lib/dataApi/renameStorage.js index 3b806d1c..165a5ab3 100644 --- a/browser/main/lib/dataApi/renameStorage.js +++ b/browser/main/lib/dataApi/renameStorage.js @@ -6,8 +6,9 @@ const resolveStorageData = require('./resolveStorageData') * @param {String} name * @return {Object} Storage meta data */ -function renameStorage (key, name) { - if (!_.isString(name)) return Promise.reject(new Error('Name must be a string.')) +function renameStorage(key, name) { + if (!_.isString(name)) + return Promise.reject(new Error('Name must be a string.')) let cachedStorageList try { @@ -17,7 +18,7 @@ function renameStorage (key, name) { console.error(err) return Promise.reject(err) } - const targetStorage = _.find(cachedStorageList, {key: key}) + const targetStorage = _.find(cachedStorageList, { key: key }) if (targetStorage == null) return Promise.reject('Storage') targetStorage.name = name diff --git a/browser/main/lib/dataApi/reorderFolder.js b/browser/main/lib/dataApi/reorderFolder.js index 9102438e..e86ac838 100644 --- a/browser/main/lib/dataApi/reorderFolder.js +++ b/browser/main/lib/dataApi/reorderFolder.js @@ -17,7 +17,7 @@ const { findStorage } = require('browser/lib/findStorage') * } * ``` */ -function reorderFolder (storageKey, oldIndex, newIndex) { +function reorderFolder(storageKey, oldIndex, newIndex) { let targetStorage try { if (!_.isNumber(oldIndex)) throw new Error('oldIndex must be a number.') @@ -28,15 +28,19 @@ function reorderFolder (storageKey, oldIndex, newIndex) { return Promise.reject(e) } - return resolveStorageData(targetStorage) - .then(function reorderFolder (storage) { - storage.folders = _.move(storage.folders, oldIndex, newIndex) - CSON.writeFileSync(path.join(storage.path, 'boostnote.json'), _.pick(storage, ['folders', 'version'])) + return resolveStorageData(targetStorage).then(function reorderFolder( + storage + ) { + storage.folders = _.move(storage.folders, oldIndex, newIndex) + CSON.writeFileSync( + path.join(storage.path, 'boostnote.json'), + _.pick(storage, ['folders', 'version']) + ) - return { - storage - } - }) + return { + storage + } + }) } module.exports = reorderFolder diff --git a/browser/main/lib/dataApi/resolveStorageData.js b/browser/main/lib/dataApi/resolveStorageData.js index da41f3d0..3476ec7d 100644 --- a/browser/main/lib/dataApi/resolveStorageData.js +++ b/browser/main/lib/dataApi/resolveStorageData.js @@ -3,7 +3,7 @@ const path = require('path') const CSON = require('@rokt33r/season') const migrateFromV6Storage = require('./migrateFromV6Storage') -function resolveStorageData (storageCache) { +function resolveStorageData(storageCache) { const storage = { key: storageCache.key, name: storageCache.name, @@ -15,13 +15,14 @@ function resolveStorageData (storageCache) { const boostnoteJSONPath = path.join(storageCache.path, 'boostnote.json') try { const jsonData = CSON.readFileSync(boostnoteJSONPath) - if (!_.isArray(jsonData.folders)) throw new Error('folders should be an array.') + if (!_.isArray(jsonData.folders)) + throw new Error('folders should be an array.') storage.folders = jsonData.folders storage.version = jsonData.version } catch (err) { if (err.code === 'ENOENT') { - console.warn('boostnote.json file doesn\'t exist the given path') - CSON.writeFileSync(boostnoteJSONPath, {folders: [], version: '1.0'}) + console.warn("boostnote.json file doesn't exist the given path") + CSON.writeFileSync(boostnoteJSONPath, { folders: [], version: '1.0' }) } else { console.error(err) } @@ -34,8 +35,7 @@ function resolveStorageData (storageCache) { return Promise.resolve(storage) } - return migrateFromV6Storage(storage.path) - .then(() => storage) + return migrateFromV6Storage(storage.path).then(() => storage) } module.exports = resolveStorageData diff --git a/browser/main/lib/dataApi/resolveStorageNotes.js b/browser/main/lib/dataApi/resolveStorageNotes.js index 9da27248..e86ecc26 100644 --- a/browser/main/lib/dataApi/resolveStorageNotes.js +++ b/browser/main/lib/dataApi/resolveStorageNotes.js @@ -2,14 +2,14 @@ const sander = require('sander') const path = require('path') const CSON = require('@rokt33r/season') -function resolveStorageNotes (storage) { +function resolveStorageNotes(storage) { const notesDirPath = path.join(storage.path, 'notes') let notePathList try { notePathList = sander.readdirSync(notesDirPath) } catch (err) { if (err.code === 'ENOENT') { - console.error(notesDirPath, ' doesn\'t exist.') + console.error(notesDirPath, " doesn't exist.") sander.mkdirSync(notesDirPath) } else { console.warn('Failed to find note dir', notesDirPath, err) @@ -17,10 +17,10 @@ function resolveStorageNotes (storage) { notePathList = [] } const notes = notePathList - .filter(function filterOnlyCSONFile (notePath) { + .filter(function filterOnlyCSONFile(notePath) { return /\.cson$/.test(notePath) }) - .map(function parseCSONFile (notePath) { + .map(function parseCSONFile(notePath) { try { const data = CSON.readFileSync(path.join(notesDirPath, notePath)) data.key = path.basename(notePath, '.cson') @@ -30,7 +30,7 @@ function resolveStorageNotes (storage) { console.error(`error on note path: ${notePath}, error: ${err}`) } }) - .filter(function filterOnlyNoteObject (noteObj) { + .filter(function filterOnlyNoteObject(noteObj) { return typeof noteObj === 'object' }) diff --git a/browser/main/lib/dataApi/toggleStorage.js b/browser/main/lib/dataApi/toggleStorage.js index 246d85ef..013c15d4 100644 --- a/browser/main/lib/dataApi/toggleStorage.js +++ b/browser/main/lib/dataApi/toggleStorage.js @@ -6,7 +6,7 @@ const resolveStorageData = require('./resolveStorageData') * @param {Boolean} isOpen * @return {Object} Storage meta data */ -function toggleStorage (key, isOpen) { +function toggleStorage(key, isOpen) { let cachedStorageList try { cachedStorageList = JSON.parse(localStorage.getItem('storages')) @@ -15,7 +15,7 @@ function toggleStorage (key, isOpen) { console.error(err) return Promise.reject(err) } - const targetStorage = _.find(cachedStorageList, {key: key}) + const targetStorage = _.find(cachedStorageList, { key: key }) if (targetStorage == null) return Promise.reject('Storage') targetStorage.isOpen = isOpen diff --git a/browser/main/lib/dataApi/updateFolder.js b/browser/main/lib/dataApi/updateFolder.js index 2a325c60..84658ffc 100644 --- a/browser/main/lib/dataApi/updateFolder.js +++ b/browser/main/lib/dataApi/updateFolder.js @@ -22,7 +22,7 @@ const { findStorage } = require('browser/lib/findStorage') * } * ``` */ -function updateFolder (storageKey, folderKey, input) { +function updateFolder(storageKey, folderKey, input) { let targetStorage try { if (input == null) throw new Error('No input found.') @@ -34,19 +34,21 @@ function updateFolder (storageKey, folderKey, input) { return Promise.reject(e) } - return resolveStorageData(targetStorage) - .then(function updateFolder (storage) { - const targetFolder = _.find(storage.folders, {key: folderKey}) - if (targetFolder == null) throw new Error('Target folder doesn\'t exist.') - targetFolder.name = input.name - targetFolder.color = input.color + return resolveStorageData(targetStorage).then(function updateFolder(storage) { + const targetFolder = _.find(storage.folders, { key: folderKey }) + if (targetFolder == null) throw new Error("Target folder doesn't exist.") + targetFolder.name = input.name + targetFolder.color = input.color - CSON.writeFileSync(path.join(storage.path, 'boostnote.json'), _.pick(storage, ['folders', 'version'])) + CSON.writeFileSync( + path.join(storage.path, 'boostnote.json'), + _.pick(storage, ['folders', 'version']) + ) - return { - storage - } - }) + return { + storage + } + }) } module.exports = updateFolder diff --git a/browser/main/lib/dataApi/updateNote.js b/browser/main/lib/dataApi/updateNote.js index ce9fabcf..775888a6 100644 --- a/browser/main/lib/dataApi/updateNote.js +++ b/browser/main/lib/dataApi/updateNote.js @@ -4,13 +4,14 @@ const path = require('path') const CSON = require('@rokt33r/season') const { findStorage } = require('browser/lib/findStorage') -function validateInput (input) { +function validateInput(input) { const validatedInput = {} if (input.tags != null) { if (!_.isArray(input.tags)) validatedInput.tags = [] - validatedInput.tags = input.tags - .filter((tag) => _.isString(tag) && tag.trim().length > 0) + validatedInput.tags = input.tags.filter( + tag => _.isString(tag) && tag.trim().length > 0 + ) } if (input.title != null) { @@ -40,7 +41,8 @@ function validateInput (input) { if (!_.isString(input.content)) validatedInput.content = '' else validatedInput.content = input.content - if (!_.isArray(input.linesHighlighted)) validatedInput.linesHighlighted = [] + if (!_.isArray(input.linesHighlighted)) + validatedInput.linesHighlighted = [] else validatedInput.linesHighlighted = input.linesHighlighted } return validatedInput @@ -51,30 +53,33 @@ function validateInput (input) { } if (input.snippets != null) { if (!_.isArray(input.snippets)) { - validatedInput.snippets = [{ - name: '', - mode: 'text', - content: '', - linesHighlighted: [] - }] + validatedInput.snippets = [ + { + name: '', + mode: 'text', + content: '', + linesHighlighted: [] + } + ] } else { validatedInput.snippets = input.snippets } - validatedInput.snippets - .filter((snippet) => { - if (!_.isString(snippet.name)) return false - if (!_.isString(snippet.mode)) return false - if (!_.isString(snippet.content)) return false - return true - }) + validatedInput.snippets.filter(snippet => { + if (!_.isString(snippet.name)) return false + if (!_.isString(snippet.mode)) return false + if (!_.isString(snippet.content)) return false + return true + }) } return validatedInput default: - throw new Error('Invalid type: only MARKDOWN_NOTE and SNIPPET_NOTE are available.') + throw new Error( + 'Invalid type: only MARKDOWN_NOTE and SNIPPET_NOTE are available.' + ) } } -function updateNote (storageKey, noteKey, input) { +function updateNote(storageKey, noteKey, input) { let targetStorage try { if (input == null) throw new Error('No input found.') @@ -85,55 +90,61 @@ function updateNote (storageKey, noteKey, input) { return Promise.reject(e) } - return resolveStorageData(targetStorage) - .then(function saveNote (storage) { - let noteData - const notePath = path.join(storage.path, 'notes', noteKey + '.cson') - try { - noteData = CSON.readFileSync(notePath) - } catch (err) { - console.warn('Failed to find note cson', err) - noteData = input.type === 'SNIPPET_NOTE' + return resolveStorageData(targetStorage).then(function saveNote(storage) { + let noteData + const notePath = path.join(storage.path, 'notes', noteKey + '.cson') + try { + noteData = CSON.readFileSync(notePath) + } catch (err) { + console.warn('Failed to find note cson', err) + noteData = + input.type === 'SNIPPET_NOTE' ? { - type: 'SNIPPET_NOTE', - description: [], - snippets: [{ - name: '', - mode: 'text', + type: 'SNIPPET_NOTE', + description: [], + snippets: [ + { + name: '', + mode: 'text', + content: '', + linesHighlighted: [] + } + ] + } + : { + type: 'MARKDOWN_NOTE', content: '', linesHighlighted: [] - }] - } - : { - type: 'MARKDOWN_NOTE', - content: '', - linesHighlighted: [] - } - noteData.title = '' - if (storage.folders.length === 0) throw new Error('Failed to restore note: No folder exists.') - noteData.folder = storage.folders[0].key - noteData.createdAt = new Date() - noteData.updatedAt = new Date() - noteData.isStarred = false - noteData.isTrashed = false - noteData.tags = [] - noteData.isPinned = false - } + } + noteData.title = '' + if (storage.folders.length === 0) + throw new Error('Failed to restore note: No folder exists.') + noteData.folder = storage.folders[0].key + noteData.createdAt = new Date() + noteData.updatedAt = new Date() + noteData.isStarred = false + noteData.isTrashed = false + noteData.tags = [] + noteData.isPinned = false + } - if (noteData.type === 'SNIPPET_NOTE') { - noteData.title - } + if (noteData.type === 'SNIPPET_NOTE') { + noteData.title + } - Object.assign(noteData, input, { - key: noteKey, - updatedAt: new Date(), - storage: storageKey - }) - - CSON.writeFileSync(path.join(storage.path, 'notes', noteKey + '.cson'), _.omit(noteData, ['key', 'storage'])) - - return noteData + Object.assign(noteData, input, { + key: noteKey, + updatedAt: new Date(), + storage: storageKey }) + + CSON.writeFileSync( + path.join(storage.path, 'notes', noteKey + '.cson'), + _.omit(noteData, ['key', 'storage']) + ) + + return noteData + }) } module.exports = updateNote diff --git a/browser/main/lib/dataApi/updateSnippet.js b/browser/main/lib/dataApi/updateSnippet.js index f132d83f..95acf053 100644 --- a/browser/main/lib/dataApi/updateSnippet.js +++ b/browser/main/lib/dataApi/updateSnippet.js @@ -1,9 +1,11 @@ import fs from 'fs' import consts from 'browser/lib/consts' -function updateSnippet (snippet, snippetFile) { +function updateSnippet(snippet, snippetFile) { return new Promise((resolve, reject) => { - const snippets = JSON.parse(fs.readFileSync(snippetFile || consts.SNIPPET_FILE, 'utf-8')) + const snippets = JSON.parse( + fs.readFileSync(snippetFile || consts.SNIPPET_FILE, 'utf-8') + ) for (let i = 0; i < snippets.length; i++) { const currentSnippet = snippets[i] @@ -21,11 +23,15 @@ function updateSnippet (snippet, snippetFile) { currentSnippet.name = snippet.name currentSnippet.prefix = snippet.prefix currentSnippet.content = snippet.content - currentSnippet.linesHighlighted = (snippet.linesHighlighted) - fs.writeFile(snippetFile || consts.SNIPPET_FILE, JSON.stringify(snippets, null, 4), (err) => { - if (err) reject(err) - resolve(snippets) - }) + currentSnippet.linesHighlighted = snippet.linesHighlighted + fs.writeFile( + snippetFile || consts.SNIPPET_FILE, + JSON.stringify(snippets, null, 4), + err => { + if (err) reject(err) + resolve(snippets) + } + ) } } } diff --git a/browser/main/lib/eventEmitter.js b/browser/main/lib/eventEmitter.js index 1276545b..370ea3a9 100644 --- a/browser/main/lib/eventEmitter.js +++ b/browser/main/lib/eventEmitter.js @@ -1,19 +1,19 @@ const electron = require('electron') const { ipcRenderer, remote } = electron -function on (name, listener) { +function on(name, listener) { ipcRenderer.on(name, listener) } -function off (name, listener) { +function off(name, listener) { ipcRenderer.removeListener(name, listener) } -function once (name, listener) { +function once(name, listener) { ipcRenderer.once(name, listener) } -function emit (name, ...args) { +function emit(name, ...args) { remote.getCurrentWindow().webContents.send(name, ...args) } diff --git a/browser/main/lib/ipcClient.js b/browser/main/lib/ipcClient.js index c06296b5..4c25d52c 100644 --- a/browser/main/lib/ipcClient.js +++ b/browser/main/lib/ipcClient.js @@ -12,14 +12,14 @@ nodeIpc.config.silent = true nodeIpc.connectTo( 'node', path.join(app.getPath('userData'), 'boostnote.service'), - function () { - nodeIpc.of.node.on('error', function (err) { + function() { + nodeIpc.of.node.on('error', function(err) { console.error(err) }) - nodeIpc.of.node.on('connect', function () { - ipcRenderer.send('config-renew', {config: ConfigManager.get()}) + nodeIpc.of.node.on('connect', function() { + ipcRenderer.send('config-renew', { config: ConfigManager.get() }) }) - nodeIpc.of.node.on('disconnect', function () { + nodeIpc.of.node.on('disconnect', function() { return }) } diff --git a/browser/main/lib/modal.js b/browser/main/lib/modal.js index 955cb5c8..08d8c7f1 100644 --- a/browser/main/lib/modal.js +++ b/browser/main/lib/modal.js @@ -4,7 +4,7 @@ import ReactDOM from 'react-dom' import { store } from '../store' class ModalBase extends React.Component { - constructor (props) { + constructor(props) { super(props) this.state = { component: null, @@ -13,20 +13,30 @@ class ModalBase extends React.Component { } } - close () { - if (modalBase != null) modalBase.setState({component: null, componentProps: null, isHidden: true}) + close() { + if (modalBase != null) + modalBase.setState({ + component: null, + componentProps: null, + isHidden: true + }) // Toggle overflow style on NoteList - const list = document.querySelector('.NoteList__list___browser-main-NoteList-') + const list = document.querySelector( + '.NoteList__list___browser-main-NoteList-' + ) list.style.overflow = 'auto' } - render () { + render() { return (
-
this.close(e)} className='modalBack' /> +
this.close(e)} className='modalBack' /> {this.state.component == null ? null : ( - + )}
@@ -38,21 +48,31 @@ const el = document.createElement('div') document.body.appendChild(el) const modalBase = ReactDOM.render(, el) -export function openModal (component, props) { - if (modalBase == null) { return } +export function openModal(component, props) { + if (modalBase == null) { + return + } // Hide scrollbar by removing overflow when modal opens - const list = document.querySelector('.NoteList__list___browser-main-NoteList-') + const list = document.querySelector( + '.NoteList__list___browser-main-NoteList-' + ) list.style.overflow = 'hidden' document.body.setAttribute('data-modal', 'open') - modalBase.setState({component: component, componentProps: props, isHidden: false}) + modalBase.setState({ + component: component, + componentProps: props, + isHidden: false + }) } -export function closeModal () { - if (modalBase == null) { return } +export function closeModal() { + if (modalBase == null) { + return + } modalBase.close() } -export function isModalOpen () { +export function isModalOpen() { return !modalBase.state.isHidden } diff --git a/browser/main/lib/notify.js b/browser/main/lib/notify.js index 458a784d..6054cb36 100644 --- a/browser/main/lib/notify.js +++ b/browser/main/lib/notify.js @@ -1,8 +1,12 @@ const path = require('path') -function notify (title, options) { +function notify(title, options) { if (process.platform === 'win32') { - options.icon = path.join('file://', global.__dirname, '../../resources/app.png') + options.icon = path.join( + 'file://', + global.__dirname, + '../../resources/app.png' + ) options.silent = false } return new window.Notification(title, options) diff --git a/browser/main/lib/shortcut.js b/browser/main/lib/shortcut.js index 98e26e06..aab644d7 100644 --- a/browser/main/lib/shortcut.js +++ b/browser/main/lib/shortcut.js @@ -1,16 +1,16 @@ import ee from 'browser/main/lib/eventEmitter' module.exports = { - 'toggleMode': () => { + toggleMode: () => { ee.emit('topbar:togglemodebutton') }, - 'toggleDirection': () => { + toggleDirection: () => { ee.emit('topbar:toggledirectionbutton') }, - 'deleteNote': () => { + deleteNote: () => { ee.emit('hotkey:deletenote') }, - 'toggleMenuBar': () => { + toggleMenuBar: () => { ee.emit('menubar:togglemenubar') } } diff --git a/browser/main/lib/shortcutManager.js b/browser/main/lib/shortcutManager.js index ac2a3a08..7575bb99 100644 --- a/browser/main/lib/shortcutManager.js +++ b/browser/main/lib/shortcutManager.js @@ -7,7 +7,7 @@ import functions from './shortcut' let shortcuts = CM.get().hotkey -ee.on('config-renew', function () { +ee.on('config-renew', function() { // only update if hotkey changed ! const newHotkey = CM.get().hotkey if (!isObjectEqual(newHotkey, shortcuts)) { @@ -15,17 +15,17 @@ ee.on('config-renew', function () { } }) -function updateShortcut (newHotkey) { +function updateShortcut(newHotkey) { Mousetrap.reset() shortcuts = newHotkey applyShortcuts(newHotkey) } -function formatShortcut (shortcut) { +function formatShortcut(shortcut) { return shortcut.toLowerCase().replace(/ /g, '') } -function applyShortcuts (shortcuts) { +function applyShortcuts(shortcuts) { for (const shortcut in shortcuts) { const toggler = formatShortcut(shortcuts[shortcut]) // only bind if the function for that shortcut exists diff --git a/browser/main/modals/CreateFolderModal.js b/browser/main/modals/CreateFolderModal.js index b48d6e42..26b5a245 100644 --- a/browser/main/modals/CreateFolderModal.js +++ b/browser/main/modals/CreateFolderModal.js @@ -10,7 +10,7 @@ import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig' import i18n from 'browser/lib/i18n' class CreateFolderModal extends React.Component { - constructor (props) { + constructor(props) { super(props) this.state = { @@ -18,39 +18,39 @@ class CreateFolderModal extends React.Component { } } - componentDidMount () { + componentDidMount() { this.refs.name.focus() this.refs.name.select() } - handleCloseButtonClick (e) { + handleCloseButtonClick(e) { this.props.close() } - handleChange (e) { + handleChange(e) { this.setState({ name: this.refs.name.value }) } - handleKeyDown (e) { + handleKeyDown(e) { if (e.keyCode === 27) { this.props.close() } } - handleInputKeyDown (e) { + handleInputKeyDown(e) { switch (e.keyCode) { case 13: this.confirm() } } - handleConfirmButtonClick (e) { + handleConfirmButtonClick(e) { this.confirm() } - confirm () { + confirm() { AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_FOLDER') if (this.state.name.trim().length > 0) { const { storage } = this.props @@ -59,42 +59,48 @@ class CreateFolderModal extends React.Component { color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7] } - dataApi.createFolder(storage.key, input) - .then((data) => { + dataApi + .createFolder(storage.key, input) + .then(data => { store.dispatch({ type: 'UPDATE_FOLDER', storage: data.storage }) this.props.close() }) - .catch((err) => { + .catch(err => { console.error(err) }) } } - render () { + render() { return ( -
this.handleKeyDown(e)} + onKeyDown={e => this.handleKeyDown(e)} >
{i18n.__('Create new folder')}
- this.handleCloseButtonClick(e)} /> + this.handleCloseButtonClick(e)} + />
{i18n.__('Folder name')}
- this.handleChange(e)} - onKeyDown={(e) => this.handleInputKeyDown(e)} + onChange={e => this.handleChange(e)} + onKeyDown={e => this.handleInputKeyDown(e)} />
- diff --git a/browser/main/modals/CreateMarkdownFromURLModal.js b/browser/main/modals/CreateMarkdownFromURLModal.js index 31988059..090fe5a4 100644 --- a/browser/main/modals/CreateMarkdownFromURLModal.js +++ b/browser/main/modals/CreateMarkdownFromURLModal.js @@ -7,7 +7,7 @@ import ModalEscButton from 'browser/components/ModalEscButton' import i18n from 'browser/lib/i18n' class CreateMarkdownFromURLModal extends React.Component { - constructor (props) { + constructor(props) { super(props) this.state = { @@ -17,89 +17,101 @@ class CreateMarkdownFromURLModal extends React.Component { } } - componentDidMount () { + componentDidMount() { this.refs.name.focus() this.refs.name.select() } - handleCloseButtonClick (e) { + handleCloseButtonClick(e) { this.props.close() } - handleChange (e) { + handleChange(e) { this.setState({ name: this.refs.name.value }) } - handleKeyDown (e) { + handleKeyDown(e) { if (e.keyCode === 27) { this.props.close() } } - handleInputKeyDown (e) { + handleInputKeyDown(e) { switch (e.keyCode) { case 13: this.confirm() } } - handleConfirmButtonClick (e) { + handleConfirmButtonClick(e) { this.confirm() } - showError (message) { + showError(message) { this.setState({ showerror: true, errormessage: message }) } - hideError () { + hideError() { this.setState({ showerror: false, errormessage: '' }) } - confirm () { + confirm() { this.hideError() const { storage, folder, dispatch, location } = this.props - dataApi.createNoteFromUrl(this.state.name, storage, folder, dispatch, location).then((result) => { - this.props.close() - }).catch((result) => { - this.showError(result.error) - }) + dataApi + .createNoteFromUrl(this.state.name, storage, folder, dispatch, location) + .then(result => { + this.props.close() + }) + .catch(result => { + this.showError(result.error) + }) } - render () { + render() { return ( -
this.handleKeyDown(e)} + onKeyDown={e => this.handleKeyDown(e)} >
{i18n.__('Import Markdown From URL')}
- this.handleCloseButtonClick(e)} /> + this.handleCloseButtonClick(e)} + />
-
{i18n.__('Insert URL Here')}
- + {i18n.__('Insert URL Here')} +
+ this.handleChange(e)} - onKeyDown={(e) => this.handleInputKeyDown(e)} + onChange={e => this.handleChange(e)} + onKeyDown={e => this.handleInputKeyDown(e)} />
- -
{this.state.errormessage}
+
+ {this.state.errormessage} +
) diff --git a/browser/main/modals/NewNoteModal.js b/browser/main/modals/NewNoteModal.js index 476fa252..c06e91e3 100644 --- a/browser/main/modals/NewNoteModal.js +++ b/browser/main/modals/NewNoteModal.js @@ -9,21 +9,21 @@ import { createMarkdownNote, createSnippetNote } from 'browser/lib/newNote' import queryString from 'query-string' class NewNoteModal extends React.Component { - constructor (props) { + constructor(props) { super(props) this.lock = false this.state = {} } - componentDidMount () { + componentDidMount() { this.refs.markdownButton.focus() } - handleCloseButtonClick (e) { + handleCloseButtonClick(e) { this.props.close() } - handleCreateMarkdownFromUrlClick (e) { + handleCreateMarkdownFromUrlClick(e) { this.props.close() const { storage, folder, dispatch, location } = this.props @@ -35,49 +35,63 @@ class NewNoteModal extends React.Component { }) } - handleMarkdownNoteButtonClick (e) { + handleMarkdownNoteButtonClick(e) { const { storage, folder, dispatch, location, config } = this.props const params = location.search !== '' && queryString.parse(location.search) if (!this.lock) { this.lock = true - createMarkdownNote(storage, folder, dispatch, location, params, config).then(() => { + createMarkdownNote( + storage, + folder, + dispatch, + location, + params, + config + ).then(() => { setTimeout(this.props.close, 200) }) } } - handleMarkdownNoteButtonKeyDown (e) { + handleMarkdownNoteButtonKeyDown(e) { if (e.keyCode === 9) { e.preventDefault() this.refs.snippetButton.focus() } } - handleSnippetNoteButtonClick (e) { + handleSnippetNoteButtonClick(e) { const { storage, folder, dispatch, location, config } = this.props const params = location.search !== '' && queryString.parse(location.search) if (!this.lock) { this.lock = true - createSnippetNote(storage, folder, dispatch, location, params, config).then(() => { + createSnippetNote( + storage, + folder, + dispatch, + location, + params, + config + ).then(() => { setTimeout(this.props.close, 200) }) } } - handleSnippetNoteButtonKeyDown (e) { + handleSnippetNoteButtonKeyDown(e) { if (e.keyCode === 9) { e.preventDefault() this.refs.markdownButton.focus() } } - handleKeyDown (e) { + handleKeyDown(e) { if (e.keyCode === 27) { this.props.close() } } - render () { + render() { return (
this.handleSnippetNoteButtonKeyDown(e)} ref='snippetButton' > -
+ +
{i18n.__('Snippet Note')} @@ -127,10 +142,17 @@ class NewNoteModal extends React.Component { )} -
-
{i18n.__('Tab to switch format')}
-
this.handleCreateMarkdownFromUrlClick(e)}>Or, create a new markdown note from a URL
+
+ + {i18n.__('Tab to switch format')} +
+
this.handleCreateMarkdownFromUrlClick(e)} + > + Or, create a new markdown note from a URL +
) } diff --git a/browser/main/modals/PreferencesModal/Blog.js b/browser/main/modals/PreferencesModal/Blog.js index 4d59bea1..26b4839d 100644 --- a/browser/main/modals/PreferencesModal/Blog.js +++ b/browser/main/modals/PreferencesModal/Blog.js @@ -11,7 +11,7 @@ const electron = require('electron') const { shell } = electron const ipc = electron.ipcRenderer class Blog extends React.Component { - constructor (props) { + constructor(props) { super(props) this.state = { @@ -20,12 +20,12 @@ class Blog extends React.Component { } } - handleLinkClick (e) { + handleLinkClick(e) { shell.openExternal(e.currentTarget.href) e.preventDefault() } - clearMessage () { + clearMessage() { _.debounce(() => { this.setState({ BlogAlert: null @@ -33,30 +33,41 @@ class Blog extends React.Component { }, 2000)() } - componentDidMount () { + componentDidMount() { this.handleSettingDone = () => { - this.setState({BlogAlert: { - type: 'success', - message: i18n.__('Successfully applied!') - }}) + this.setState({ + BlogAlert: { + type: 'success', + message: i18n.__('Successfully applied!') + } + }) } - this.handleSettingError = (err) => { - this.setState({BlogAlert: { - type: 'error', - message: err.message != null ? err.message : i18n.__('An error occurred!') - }}) + this.handleSettingError = err => { + this.setState({ + BlogAlert: { + type: 'error', + message: + err.message != null ? err.message : i18n.__('An error occurred!') + } + }) } this.oldBlog = this.state.config.blog ipc.addListener('APP_SETTING_DONE', this.handleSettingDone) ipc.addListener('APP_SETTING_ERROR', this.handleSettingError) } - handleBlogChange (e) { + handleBlogChange(e) { const { config } = this.state config.blog = { - password: !_.isNil(this.refs.passwordInput) ? this.refs.passwordInput.value : config.blog.password, - username: !_.isNil(this.refs.usernameInput) ? this.refs.usernameInput.value : config.blog.username, - token: !_.isNil(this.refs.tokenInput) ? this.refs.tokenInput.value : config.blog.token, + password: !_.isNil(this.refs.passwordInput) + ? this.refs.passwordInput.value + : config.blog.password, + username: !_.isNil(this.refs.usernameInput) + ? this.refs.usernameInput.value + : config.blog.username, + token: !_.isNil(this.refs.tokenInput) + ? this.refs.tokenInput.value + : config.blog.token, authMethod: this.refs.authMethodDropdown.value, address: this.refs.addressInput.value, type: this.refs.typeDropdown.value @@ -75,7 +86,7 @@ class Blog extends React.Component { } } - handleSaveButtonClick (e) { + handleSaveButtonClick(e) { const newConfig = { blog: this.state.config.blog } @@ -90,36 +101,36 @@ class Blog extends React.Component { this.props.haveToSave() } - render () { - const {config, BlogAlert} = this.state - const blogAlertElement = BlogAlert != null - ?

- {BlogAlert.message} -

- : null + render() { + const { config, BlogAlert } = this.state + const blogAlertElement = + BlogAlert != null ? ( +

{BlogAlert.message}

+ ) : null return (
{i18n.__('Blog')}
-
- {i18n.__('Blog Type')} -
+
{i18n.__('Blog Type')}
{i18n.__('Blog Address')}
- this.handleBlogChange(e)} + this.handleBlogChange(e)} ref='addressInput' value={config.blog.address} type='text' @@ -127,8 +138,11 @@ class Blog extends React.Component {
- {blogAlertElement}
@@ -143,49 +157,59 @@ class Blog extends React.Component {
- { config.blog.authMethod === 'JWT' && + {config.blog.authMethod === 'JWT' && (
{i18n.__('Token')}
- this.handleBlogChange(e)} + this.handleBlogChange(e)} ref='tokenInput' value={config.blog.token} - type='text' /> + type='text' + />
- } - { config.blog.authMethod === 'USER' && + )} + {config.blog.authMethod === 'USER' && (
{i18n.__('UserName')}
- this.handleBlogChange(e)} + this.handleBlogChange(e)} ref='usernameInput' value={config.blog.username} - type='text' /> + type='text' + />
{i18n.__('Password')}
- this.handleBlogChange(e)} + this.handleBlogChange(e)} ref='passwordInput' value={config.blog.password} - type='password' /> + type='password' + />
- } + )}
) } diff --git a/browser/main/modals/PreferencesModal/Crowdfunding.js b/browser/main/modals/PreferencesModal/Crowdfunding.js index 56bb6e34..a5d37718 100644 --- a/browser/main/modals/PreferencesModal/Crowdfunding.js +++ b/browser/main/modals/PreferencesModal/Crowdfunding.js @@ -7,50 +7,93 @@ const electron = require('electron') const { shell } = electron class Crowdfunding extends React.Component { - constructor (props) { + constructor(props) { super(props) - this.state = { - } + this.state = {} } - handleLinkClick (e) { + handleLinkClick(e) { shell.openExternal(e.currentTarget.href) e.preventDefault() } - render () { + render() { return (
{i18n.__('Crowdfunding')}

{i18n.__('Thank you for using Boostnote!')}


-

{i18n.__('We launched IssueHunt which is an issue-based crowdfunding / sourcing platform for open source projects.')}

-

{i18n.__('Anyone can put a bounty on not only a bug but also on OSS feature requests listed on IssueHunt. Collected funds will be distributed to project owners and contributors.')}

-
{i18n.__('Sustainable Open Source Ecosystem')}
-

{i18n.__('We discussed about open-source ecosystem and IssueHunt concept with the Boostnote team repeatedly. We actually also discussed with Matz who father of Ruby.')}

-

{i18n.__('The original reason why we made IssueHunt was to reward our contributors of Boostnote project. We’ve got tons of Github stars and hundred of contributors in two years.')}

-

{i18n.__('We thought that it will be nice if we can pay reward for our contributors.')}

-
{i18n.__('We believe Meritocracy')}
-

{i18n.__('We think developers who have skills and do great things must be rewarded properly.')}

-

{i18n.__('OSS projects are used in everywhere on the internet, but no matter how they great, most of owners of those projects need to have another job to sustain their living.')}

+

+ {i18n.__( + 'We launched IssueHunt which is an issue-based crowdfunding / sourcing platform for open source projects.' + )} +

+

+ {i18n.__( + 'Anyone can put a bounty on not only a bug but also on OSS feature requests listed on IssueHunt. Collected funds will be distributed to project owners and contributors.' + )} +

+
+ {i18n.__('Sustainable Open Source Ecosystem')} +
+

+ {i18n.__( + 'We discussed about open-source ecosystem and IssueHunt concept with the Boostnote team repeatedly. We actually also discussed with Matz who father of Ruby.' + )} +

+

+ {i18n.__( + 'The original reason why we made IssueHunt was to reward our contributors of Boostnote project. We’ve got tons of Github stars and hundred of contributors in two years.' + )} +

+

+ {i18n.__( + 'We thought that it will be nice if we can pay reward for our contributors.' + )} +

+
+ {i18n.__('We believe Meritocracy')} +
+

+ {i18n.__( + 'We think developers who have skills and do great things must be rewarded properly.' + )} +

+

+ {i18n.__( + 'OSS projects are used in everywhere on the internet, but no matter how they great, most of owners of those projects need to have another job to sustain their living.' + )} +

{i18n.__('It sometimes looks like exploitation.')}

-

{i18n.__('We’ve realized IssueHunt could enhance sustainability of open-source ecosystem.')}

+

+ {i18n.__( + 'We’ve realized IssueHunt could enhance sustainability of open-source ecosystem.' + )} +


-

{i18n.__('As same as issues of Boostnote are already funded on IssueHunt, your open-source projects can be also started funding from now.')}

+

+ {i18n.__( + 'As same as issues of Boostnote are already funded on IssueHunt, your open-source projects can be also started funding from now.' + )} +


{i18n.__('Thank you,')}

{i18n.__('The Boostnote Team')}


) } } -Crowdfunding.propTypes = { -} +Crowdfunding.propTypes = {} export default CSSModules(Crowdfunding, styles) diff --git a/browser/main/modals/PreferencesModal/FolderItem.js b/browser/main/modals/PreferencesModal/FolderItem.js index 648db4e6..6418bb6a 100644 --- a/browser/main/modals/PreferencesModal/FolderItem.js +++ b/browser/main/modals/PreferencesModal/FolderItem.js @@ -10,7 +10,7 @@ import { SortableElement, SortableHandle } from 'react-sortable-hoc' import i18n from 'browser/lib/i18n' class FolderItem extends React.Component { - constructor (props) { + constructor(props) { super(props) this.state = { @@ -24,7 +24,7 @@ class FolderItem extends React.Component { } } - handleEditChange (e) { + handleEditChange(e) { const { folder } = this.state folder.name = this.refs.nameInput.value @@ -33,18 +33,18 @@ class FolderItem extends React.Component { }) } - handleConfirmButtonClick (e) { + handleConfirmButtonClick(e) { this.confirm() } - confirm () { + confirm() { const { storage, folder } = this.props dataApi .updateFolder(storage.key, folder.key, { color: this.state.folder.color, name: this.state.folder.name }) - .then((data) => { + .then(data => { store.dispatch({ type: 'UPDATE_FOLDER', storage: data.storage @@ -55,9 +55,12 @@ class FolderItem extends React.Component { }) } - handleColorButtonClick (e) { - const folder = Object.assign({}, this.state.folder, { showColumnPicker: true, colorPickerPos: { left: 0, top: 0 } }) - this.setState({ folder }, function () { + handleColorButtonClick(e) { + const folder = Object.assign({}, this.state.folder, { + showColumnPicker: true, + colorPickerPos: { left: 0, top: 0 } + }) + this.setState({ folder }, function() { // After the color picker has been painted, re-calculate its position // by comparing its dimensions to the host dimensions. const { hostBoundingBox } = this.props @@ -67,30 +70,32 @@ class FolderItem extends React.Component { const folder = Object.assign({}, this.state.folder, { colorPickerPos: { left: 25, - top: offsetTop < 0 ? offsetTop - 5 : 0 // subtract 5px for aestetics + top: offsetTop < 0 ? offsetTop - 5 : 0 // subtract 5px for aestetics } }) this.setState({ folder }) }) } - handleColorChange (color) { + handleColorChange(color) { const folder = Object.assign({}, this.state.folder, { color: color.hex }) this.setState({ folder }) } - handleColorPickerClose (event) { - const folder = Object.assign({}, this.state.folder, { showColumnPicker: false }) + handleColorPickerClose(event) { + const folder = Object.assign({}, this.state.folder, { + showColumnPicker: false + }) this.setState({ folder }) } - handleCancelButtonClick (e) { + handleCancelButtonClick(e) { this.setState({ status: 'IDLE' }) } - handleFolderItemBlur (e) { + handleFolderItemBlur(e) { let el = e.relatedTarget while (el != null) { if (el === this.refs.root) { @@ -101,7 +106,7 @@ class FolderItem extends React.Component { this.confirm() } - renderEdit (e) { + renderEdit(e) { const popover = { position: 'absolute', zIndex: 2 } const cover = { position: 'fixed', @@ -110,51 +115,64 @@ class FolderItem extends React.Component { bottom: 0, left: 0 } - const pickerStyle = Object.assign({}, { - position: 'absolute' - }, this.state.folder.colorPickerPos) + const pickerStyle = Object.assign( + {}, + { + position: 'absolute' + }, + this.state.folder.colorPickerPos + ) return ( -
this.handleFolderItemBlur(e)} +
this.handleFolderItemBlur(e)} tabIndex='-1' ref='root' >
- - this.handleEditChange(e)} + onChange={e => this.handleEditChange(e)} />
- - @@ -163,79 +181,85 @@ class FolderItem extends React.Component { ) } - handleDeleteConfirmButtonClick (e) { + handleDeleteConfirmButtonClick(e) { const { storage, folder } = this.props - dataApi - .deleteFolder(storage.key, folder.key) - .then((data) => { - store.dispatch({ - type: 'DELETE_FOLDER', - storage: data.storage, - folderKey: data.folderKey - }) + dataApi.deleteFolder(storage.key, folder.key).then(data => { + store.dispatch({ + type: 'DELETE_FOLDER', + storage: data.storage, + folderKey: data.folderKey }) - } - - renderDelete () { - return ( -
-
- {i18n.__('Are you sure to ')} {i18n.__(' delete')} {i18n.__('this folder?')} -
-
- - -
-
- ) - } - - handleEditButtonClick (e) { - const { folder: propsFolder } = this.props - const { folder: stateFolder } = this.state - const folder = Object.assign({}, stateFolder, propsFolder) - this.setState({ - status: 'EDIT', - folder - }, () => { - this.refs.nameInput.select() }) } - handleDeleteButtonClick (e) { + renderDelete() { + return ( +
+
+ {i18n.__('Are you sure to ')}{' '} + {i18n.__(' delete')}{' '} + {i18n.__('this folder?')} +
+
+ + +
+
+ ) + } + + handleEditButtonClick(e) { + const { folder: propsFolder } = this.props + const { folder: stateFolder } = this.state + const folder = Object.assign({}, stateFolder, propsFolder) + this.setState( + { + status: 'EDIT', + folder + }, + () => { + this.refs.nameInput.select() + } + ) + } + + handleDeleteButtonClick(e) { this.setState({ status: 'DELETE' }) } - renderIdle () { + renderIdle() { const { folder } = this.props return ( -
this.handleEditButtonClick(e)} +
this.handleEditButtonClick(e)} > -
+
{folder.name} ({folder.key})
- - @@ -244,7 +268,7 @@ class FolderItem extends React.Component { ) } - render () { + render() { switch (this.state.status) { case 'DELETE': return this.renderDelete() @@ -277,7 +301,7 @@ FolderItem.propTypes = { } class Handle extends React.Component { - render () { + render() { return (
@@ -287,7 +311,7 @@ class Handle extends React.Component { } class SortableFolderItemComponent extends React.Component { - render () { + render() { const StyledHandle = CSSModules(Handle, styles) const DragHandle = SortableHandle(StyledHandle) diff --git a/browser/main/modals/PreferencesModal/FolderList.js b/browser/main/modals/PreferencesModal/FolderList.js index 674026c5..f751d250 100644 --- a/browser/main/modals/PreferencesModal/FolderList.js +++ b/browser/main/modals/PreferencesModal/FolderList.js @@ -9,24 +9,28 @@ import { SortableContainer } from 'react-sortable-hoc' import i18n from 'browser/lib/i18n' class FolderList extends React.Component { - render () { + render() { const { storage, hostBoundingBox } = this.props const folderList = storage.folders.map((folder, index) => { - return + return ( + + ) }) return (
- {folderList.length > 0 - ? folderList - :
{i18n.__('No Folders')}
- } + {folderList.length > 0 ? ( + folderList + ) : ( +
{i18n.__('No Folders')}
+ )}
) } @@ -52,23 +56,21 @@ FolderList.propTypes = { } class SortableFolderListComponent extends React.Component { - constructor (props) { + constructor(props) { super(props) - this.onSortEnd = ({oldIndex, newIndex}) => { + this.onSortEnd = ({ oldIndex, newIndex }) => { const { storage } = this.props - dataApi - .reorderFolder(storage.key, oldIndex, newIndex) - .then((data) => { - store.dispatch({ - type: 'REORDER_FOLDER', - storage: data.storage - }) - this.setState() + dataApi.reorderFolder(storage.key, oldIndex, newIndex).then(data => { + store.dispatch({ + type: 'REORDER_FOLDER', + storage: data.storage }) + this.setState() + }) } } - render () { + render() { const StyledFolderList = CSSModules(FolderList, this.props.styles) const SortableFolderList = SortableContainer(StyledFolderList) diff --git a/browser/main/modals/PreferencesModal/HotkeyTab.js b/browser/main/modals/PreferencesModal/HotkeyTab.js index 00fea4f0..1bba78e3 100644 --- a/browser/main/modals/PreferencesModal/HotkeyTab.js +++ b/browser/main/modals/PreferencesModal/HotkeyTab.js @@ -11,7 +11,7 @@ const electron = require('electron') const ipc = electron.ipcRenderer class HotkeyTab extends React.Component { - constructor (props) { + constructor(props) { super(props) this.state = { @@ -20,28 +20,35 @@ class HotkeyTab extends React.Component { } } - componentDidMount () { + componentDidMount() { this.handleSettingDone = () => { - this.setState({keymapAlert: { - type: 'success', - message: i18n.__('Successfully applied!') - }}) + this.setState({ + keymapAlert: { + type: 'success', + message: i18n.__('Successfully applied!') + } + }) } - this.handleSettingError = (err) => { + this.handleSettingError = err => { if ( this.state.config.hotkey.toggleMain === '' || this.state.config.hotkey.toggleMode === '' || this.state.config.hotkey.toggleDirection === '' ) { - this.setState({keymapAlert: { - type: 'success', - message: i18n.__('Successfully applied!') - }}) + this.setState({ + keymapAlert: { + type: 'success', + message: i18n.__('Successfully applied!') + } + }) } else { - this.setState({keymapAlert: { - type: 'error', - message: err.message != null ? err.message : i18n.__('An error occurred!') - }}) + this.setState({ + keymapAlert: { + type: 'error', + message: + err.message != null ? err.message : i18n.__('An error occurred!') + } + }) } } this.oldHotkey = this.state.config.hotkey @@ -49,12 +56,12 @@ class HotkeyTab extends React.Component { ipc.addListener('APP_SETTING_ERROR', this.handleSettingError) } - componentWillUnmount () { + componentWillUnmount() { ipc.removeListener('APP_SETTING_DONE', this.handleSettingDone) ipc.removeListener('APP_SETTING_ERROR', this.handleSettingError) } - handleSaveButtonClick (e) { + handleSaveButtonClick(e) { const newConfig = { hotkey: this.state.config.hotkey } @@ -69,13 +76,13 @@ class HotkeyTab extends React.Component { this.props.haveToSave() } - handleHintToggleButtonClick (e) { + handleHintToggleButtonClick(e) { this.setState({ isHotkeyHintOpen: !this.state.isHotkeyHintOpen }) } - handleHotkeyChange (e) { + handleHotkeyChange(e) { const { config } = this.state config.hotkey = Object.assign({}, config.hotkey, { toggleMain: this.refs.toggleMain.value, @@ -102,7 +109,7 @@ class HotkeyTab extends React.Component { } } - clearMessage () { + clearMessage() { _.debounce(() => { this.setState({ keymapAlert: null @@ -110,13 +117,12 @@ class HotkeyTab extends React.Component { }, 2000)() } - render () { + render() { const keymapAlert = this.state.keymapAlert - const keymapAlertElement = keymapAlert != null - ?

- {keymapAlert.message} -

- : null + const keymapAlertElement = + keymapAlert != null ? ( +

{keymapAlert.message}

+ ) : null const { config } = this.state return ( @@ -124,10 +130,13 @@ class HotkeyTab extends React.Component {
{i18n.__('Hotkeys')}
-
{i18n.__('Show/Hide Boostnote')}
+
+ {i18n.__('Show/Hide Boostnote')} +
- this.handleHotkeyChange(e)} + this.handleHotkeyChange(e)} ref='toggleMain' value={config.hotkey.toggleMain} type='text' @@ -135,10 +144,13 @@ class HotkeyTab extends React.Component {
-
{i18n.__('Show/Hide Menu Bar')}
+
+ {i18n.__('Show/Hide Menu Bar')} +
- this.handleHotkeyChange(e)} + this.handleHotkeyChange(e)} ref='toggleMenuBar' value={config.hotkey.toggleMenuBar} type='text' @@ -146,10 +158,13 @@ class HotkeyTab extends React.Component {
-
{i18n.__('Toggle Editor Mode')}
+
+ {i18n.__('Toggle Editor Mode')} +
- this.handleHotkeyChange(e)} + this.handleHotkeyChange(e)} ref='toggleMode' value={config.hotkey.toggleMode} type='text' @@ -157,10 +172,13 @@ class HotkeyTab extends React.Component {
-
{i18n.__('Toggle Direction')}
+
+ {i18n.__('Toggle Direction')} +
- this.handleHotkeyChange(e)} + this.handleHotkeyChange(e)} ref='toggleDirection' value={config.hotkey.toggleDirection} type='text' @@ -170,8 +188,9 @@ class HotkeyTab extends React.Component {
{i18n.__('Delete Note')}
- this.handleHotkeyChange(e)} + this.handleHotkeyChange(e)} ref='deleteNote' value={config.hotkey.deleteNote} type='text' @@ -181,8 +200,9 @@ class HotkeyTab extends React.Component {
{i18n.__('Paste HTML')}
- this.handleHotkeyChange(e)} + this.handleHotkeyChange(e)} ref='pasteSmartly' value={config.hotkey.pasteSmartly} type='text' @@ -190,19 +210,26 @@ class HotkeyTab extends React.Component {
-
{i18n.__('Prettify Markdown')}
+
+ {i18n.__('Prettify Markdown')} +
- this.handleHotkeyChange(e)} + this.handleHotkeyChange(e)} ref='prettifyMarkdown' value={config.hotkey.prettifyMarkdown} - type='text' /> + type='text' + />
-
{i18n.__('Insert Current Date')}
+
+ {i18n.__('Insert Current Date')} +
-
-
{i18n.__('Insert Current Date and Time')}
+
+ {i18n.__('Insert Current Date and Time')} +
-
- - {keymapAlertElement}
- {this.state.isHotkeyHintOpen && + {this.state.isHotkeyHintOpen && (

{i18n.__('Available Keys')}

    -
  • 0 to 9
  • -
  • A to Z
  • -
  • F1 to F24
  • -
  • Punctuations like ~, !, @, #, $, etc.
  • -
  • Plus
  • -
  • Space
  • -
  • Backspace
  • -
  • Delete
  • -
  • Insert
  • -
  • Return (or Enter as alias)
  • -
  • Up, Down, Left and Right
  • -
  • Home and End
  • -
  • PageUp and PageDown
  • -
  • Escape (or Esc for short)
  • -
  • VolumeUp, VolumeDown and VolumeMute
  • -
  • MediaNextTrack, MediaPreviousTrack, MediaStop and MediaPlayPause
  • -
  • Control (or Ctrl for short)
  • -
  • Shift
  • +
  • + 0 to 9 +
  • +
  • + A to Z +
  • +
  • + F1 to F24 +
  • +
  • + Punctuations like ~, !,{' '} + @, #, $, etc. +
  • +
  • + Plus +
  • +
  • + Space +
  • +
  • + Backspace +
  • +
  • + Delete +
  • +
  • + Insert +
  • +
  • + Return (or Enter as alias) +
  • +
  • + Up, Down, Left and{' '} + Right +
  • +
  • + Home and End +
  • +
  • + PageUp and PageDown +
  • +
  • + Escape (or Esc for short) +
  • +
  • + VolumeUp, VolumeDown and{' '} + VolumeMute +
  • +
  • + MediaNextTrack, MediaPreviousTrack,{' '} + MediaStop and MediaPlayPause +
  • +
  • + Control (or Ctrl for short) +
  • +
  • + Shift +
- } + )}
) diff --git a/browser/main/modals/PreferencesModal/InfoTab.js b/browser/main/modals/PreferencesModal/InfoTab.js index 97f06f7b..fa49025f 100644 --- a/browser/main/modals/PreferencesModal/InfoTab.js +++ b/browser/main/modals/PreferencesModal/InfoTab.js @@ -12,7 +12,7 @@ const { shell, remote } = electron const appVersion = remote.app.getVersion() class InfoTab extends React.Component { - constructor (props) { + constructor(props) { super(props) this.state = { @@ -20,18 +20,18 @@ class InfoTab extends React.Component { } } - handleLinkClick (e) { + handleLinkClick(e) { shell.openExternal(e.currentTarget.href) e.preventDefault() } - handleConfigChange (e) { + handleConfigChange(e) { const newConfig = { amaEnabled: this.refs.amaEnabled.checked } this.setState({ config: newConfig }) } - handleSaveButtonClick (e) { + handleSaveButtonClick(e) { const newConfig = { amaEnabled: this.state.config.amaEnabled } @@ -43,7 +43,7 @@ class InfoTab extends React.Component { }) } else { this.setState({ - amaMessage: i18n.__('Thank\'s for trusting us') + amaMessage: i18n.__("Thank's for trusting us") }) } @@ -61,7 +61,7 @@ class InfoTab extends React.Component { }) } - toggleAutoUpdate () { + toggleAutoUpdate() { const newConfig = { autoUpdateEnabled: !this.state.config.autoUpdateEnabled } @@ -70,46 +70,64 @@ class InfoTab extends React.Component { ConfigManager.set(newConfig) } - infoMessage () { + infoMessage() { const { amaMessage } = this.state return amaMessage ?

{amaMessage}

: null } - render () { + render() { return (
{i18n.__('Community')}
@@ -120,11 +138,20 @@ class InfoTab extends React.Component {
- +
-
{i18n.__('Boostnote')} {appVersion}
+
+ {i18n.__('Boostnote')} {appVersion} +
- {i18n.__('An open source note-taking app made for programmers just like you.')} + {i18n.__( + 'An open source note-taking app made for programmers just like you.' + )}
@@ -132,39 +159,71 @@ class InfoTab extends React.Component { -
+
+ +

{i18n.__('Analytics')}
-
{i18n.__('Boostnote collects anonymous data for the sole purpose of improving the application, and strictly does not collect any personal information such the contents of your notes.')}
-
{i18n.__('You can see how it works on ')} this.handleLinkClick(e)}>GitHub.
+
+ {i18n.__( + 'Boostnote collects anonymous data for the sole purpose of improving the application, and strictly does not collect any personal information such the contents of your notes.' + )} +
+
+ {i18n.__('You can see how it works on ')} + this.handleLinkClick(e)} + > + GitHub + + . +

{i18n.__('You can choose to enable or disable this option.')}
- this.handleConfigChange(e)} + this.handleConfigChange(e)} checked={this.state.config.amaEnabled} ref='amaEnabled' type='checkbox' /> - {i18n.__('Enable analytics to help improve Boostnote')}
- + {i18n.__('Enable analytics to help improve Boostnote')} +
+
{this.infoMessage()}
@@ -172,7 +231,6 @@ class InfoTab extends React.Component { } } -InfoTab.propTypes = { -} +InfoTab.propTypes = {} export default CSSModules(InfoTab, styles) diff --git a/browser/main/modals/PreferencesModal/SnippetEditor.js b/browser/main/modals/PreferencesModal/SnippetEditor.js index e95afdcf..f748924c 100644 --- a/browser/main/modals/PreferencesModal/SnippetEditor.js +++ b/browser/main/modals/PreferencesModal/SnippetEditor.js @@ -6,13 +6,19 @@ import CSSModules from 'browser/lib/CSSModules' import dataApi from 'browser/main/lib/dataApi' import snippetManager from '../../../lib/SnippetManager' -const defaultEditorFontFamily = ['Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'monospace'] +const defaultEditorFontFamily = [ + 'Monaco', + 'Menlo', + 'Ubuntu Mono', + 'Consolas', + 'source-code-pro', + 'monospace' +] const buildCMRulers = (rulers, enableRulers) => enableRulers ? rulers.map(ruler => ({ column: ruler })) : [] class SnippetEditor extends React.Component { - - componentDidMount () { + componentDidMount() { this.props.onRef(this) const { rulers, enableRulers } = this.props this.cm = CodeMirror(this.refs.root, { @@ -49,38 +55,50 @@ class SnippetEditor extends React.Component { }) } - componentWillUnmount () { + componentWillUnmount() { this.props.onRef(undefined) } - onSnippetChanged (newSnippet) { + onSnippetChanged(newSnippet) { this.snippet = newSnippet this.cm.setValue(this.snippet.content) } - onSnippetNameOrPrefixChanged (newSnippet) { + onSnippetNameOrPrefixChanged(newSnippet) { this.snippet.name = newSnippet.name - this.snippet.prefix = newSnippet.prefix.toString().replace(/\s/g, '').split(',') + this.snippet.prefix = newSnippet.prefix + .toString() + .replace(/\s/g, '') + .split(',') this.saveSnippet() } - saveSnippet () { - dataApi.updateSnippet(this.snippet) + saveSnippet() { + dataApi + .updateSnippet(this.snippet) .then(snippets => snippetManager.assignSnippets(snippets)) - .catch((err) => { throw err }) + .catch(err => { + throw err + }) } - render () { + render() { const { fontSize } = this.props let fontFamily = this.props.fontFamily - fontFamily = _.isString(fontFamily) && fontFamily.length > 0 - ? [fontFamily].concat(defaultEditorFontFamily) - : defaultEditorFontFamily + fontFamily = + _.isString(fontFamily) && fontFamily.length > 0 + ? [fontFamily].concat(defaultEditorFontFamily) + : defaultEditorFontFamily return ( -
+
) } } diff --git a/browser/main/modals/PreferencesModal/SnippetList.js b/browser/main/modals/PreferencesModal/SnippetList.js index 3790eb3f..145cfb75 100644 --- a/browser/main/modals/PreferencesModal/SnippetList.js +++ b/browser/main/modals/PreferencesModal/SnippetList.js @@ -7,53 +7,65 @@ import eventEmitter from 'browser/main/lib/eventEmitter' import context from 'browser/lib/context' class SnippetList extends React.Component { - constructor (props) { + constructor(props) { super(props) this.state = { snippets: [] } } - componentDidMount () { + componentDidMount() { this.reloadSnippetList() eventEmitter.on('snippetList:reload', this.reloadSnippetList.bind(this)) } - reloadSnippetList () { + reloadSnippetList() { dataApi.fetchSnippet().then(snippets => { - this.setState({snippets}) + this.setState({ snippets }) this.props.onSnippetSelect(this.props.currentSnippet) }) } - handleSnippetContextMenu (snippet) { - context.popup([{ - label: i18n.__('Delete snippet'), - click: () => this.deleteSnippet(snippet) - }]) + handleSnippetContextMenu(snippet) { + context.popup([ + { + label: i18n.__('Delete snippet'), + click: () => this.deleteSnippet(snippet) + } + ]) } - deleteSnippet (snippet) { - dataApi.deleteSnippet(snippet).then(() => { - this.reloadSnippetList() - this.props.onSnippetDeleted(snippet) - }).catch(err => { throw err }) + deleteSnippet(snippet) { + dataApi + .deleteSnippet(snippet) + .then(() => { + this.reloadSnippetList() + this.props.onSnippetDeleted(snippet) + }) + .catch(err => { + throw err + }) } - handleSnippetClick (snippet) { + handleSnippetClick(snippet) { this.props.onSnippetSelect(snippet) } - createSnippet () { - dataApi.createSnippet().then(() => { - this.reloadSnippetList() - // scroll to end of list when added new snippet - const snippetList = document.getElementById('snippets') - snippetList.scrollTop = snippetList.scrollHeight - }).catch(err => { throw err }) + createSnippet() { + dataApi + .createSnippet() + .then(() => { + this.reloadSnippetList() + // scroll to end of list when added new snippet + const snippetList = document.getElementById('snippets') + snippetList.scrollTop = snippetList.scrollHeight + }) + .catch(err => { + throw err + }) } - defineSnippetStyleName (snippet) { + defineSnippetStyleName(snippet) { const { currentSnippet } = this.props if (currentSnippet == null) { @@ -67,29 +79,31 @@ class SnippetList extends React.Component { } } - render () { + render() { const { snippets } = this.state return (
-
    - { - snippets.map((snippet) => ( -
  • this.handleSnippetContextMenu(snippet)} - onClick={() => this.handleSnippetClick(snippet)}> - {snippet.name} -
  • - )) - } + {snippets.map(snippet => ( +
  • this.handleSnippetContextMenu(snippet)} + onClick={() => this.handleSnippetClick(snippet)} + > + {snippet.name} +
  • + ))}
) diff --git a/browser/main/modals/PreferencesModal/SnippetTab.js b/browser/main/modals/PreferencesModal/SnippetTab.js index df338d7f..0476c5c2 100644 --- a/browser/main/modals/PreferencesModal/SnippetTab.js +++ b/browser/main/modals/PreferencesModal/SnippetTab.js @@ -11,7 +11,7 @@ import copy from 'copy-to-clipboard' const path = require('path') class SnippetTab extends React.Component { - constructor (props) { + constructor(props) { super(props) this.state = { currentSnippet: null @@ -19,7 +19,7 @@ class SnippetTab extends React.Component { this.changeDelay = null } - notify (title, options) { + notify(title, options) { if (global.process.platform === 'win32') { options.icon = path.join( 'file://', @@ -30,7 +30,7 @@ class SnippetTab extends React.Component { return new window.Notification(title, options) } - handleSnippetNameOrPrefixChange () { + handleSnippetNameOrPrefixChange() { clearTimeout(this.changeDelay) this.changeDelay = setTimeout(() => { // notify the snippet editor that the name or prefix of snippet has been changed @@ -39,20 +39,20 @@ class SnippetTab extends React.Component { }, 500) } - handleSnippetSelect (snippet) { + handleSnippetSelect(snippet) { const { currentSnippet } = this.state if (snippet !== null) { if (currentSnippet === null || currentSnippet.id !== snippet.id) { dataApi.fetchSnippet(snippet.id).then(changedSnippet => { // notify the snippet editor to load the content of the new snippet this.snippetEditor.onSnippetChanged(changedSnippet) - this.setState({currentSnippet: changedSnippet}) + this.setState({ currentSnippet: changedSnippet }) }) } } } - onSnippetNameOrPrefixChanged (e, type) { + onSnippetNameOrPrefixChanged(e, type) { const newSnippet = Object.assign({}, this.state.currentSnippet) if (type === 'name') { newSnippet.name = e.target.value @@ -63,14 +63,14 @@ class SnippetTab extends React.Component { this.handleSnippetNameOrPrefixChange() } - handleDeleteSnippet (snippet) { + handleDeleteSnippet(snippet) { // prevent old snippet still display when deleted if (snippet.id === this.state.currentSnippet.id) { - this.setState({currentSnippet: null}) + this.setState({ currentSnippet: null }) } } - handleCopySnippet (e) { + handleCopySnippet(e) { const showCopyNotification = this.props.config.ui.showCopyNotification copy(this.state.currentSnippet.content) if (showCopyNotification) { @@ -81,7 +81,7 @@ class SnippetTab extends React.Component { } } - render () { + render() { const { config, storageKey } = this.props const { currentSnippet } = this.state @@ -95,12 +95,19 @@ class SnippetTab extends React.Component { -
+ currentSnippet={currentSnippet} + /> +
-
@@ -110,18 +117,26 @@ class SnippetTab extends React.Component { { this.onSnippetNameOrPrefixChanged(e, 'name') }} - type='text' /> + onChange={e => { + this.onSnippetNameOrPrefixChanged(e, 'name') + }} + type='text' + />
-
{i18n.__('Snippet prefix')}
+
+ {i18n.__('Snippet prefix')} +
{ this.onSnippetNameOrPrefixChanged(e, 'prefix') }} - type='text' /> + onChange={e => { + this.onSnippetNameOrPrefixChanged(e, 'prefix') + }} + type='text' + />
@@ -140,7 +155,10 @@ class SnippetTab extends React.Component { matchingTriples={config.editor.matchingTriples} explodingPairs={config.editor.explodingPairs} scrollPastEnd={config.editor.scrollPastEnd} - onRef={ref => { this.snippetEditor = ref }} /> + onRef={ref => { + this.snippetEditor = ref + }} + />
@@ -148,7 +166,6 @@ class SnippetTab extends React.Component { } } -SnippetTab.PropTypes = { -} +SnippetTab.PropTypes = {} export default CSSModules(SnippetTab, styles) diff --git a/browser/main/modals/PreferencesModal/StorageItem.js b/browser/main/modals/PreferencesModal/StorageItem.js index 9af02962..3cb18e30 100644 --- a/browser/main/modals/PreferencesModal/StorageItem.js +++ b/browser/main/modals/PreferencesModal/StorageItem.js @@ -12,7 +12,7 @@ const { shell, remote } = require('electron') const { dialog } = remote class StorageItem extends React.Component { - constructor (props) { + constructor(props) { super(props) this.state = { @@ -20,137 +20,156 @@ class StorageItem extends React.Component { } } - handleNewFolderButtonClick (e) { + handleNewFolderButtonClick(e) { const { storage } = this.props const input = { name: i18n.__('New Folder'), color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7] } - dataApi.createFolder(storage.key, input) - .then((data) => { + dataApi + .createFolder(storage.key, input) + .then(data => { store.dispatch({ type: 'UPDATE_FOLDER', storage: data.storage }) }) - .catch((err) => { + .catch(err => { console.error(err) }) } - handleExternalButtonClick () { + handleExternalButtonClick() { const { storage } = this.props shell.showItemInFolder(storage.path) } - handleUnlinkButtonClick (e) { + handleUnlinkButtonClick(e) { const index = dialog.showMessageBox(remote.getCurrentWindow(), { type: 'warning', message: i18n.__('Unlink Storage'), - detail: i18n.__('Unlinking removes this linked storage from Boostnote. No data is removed, please manually delete the folder from your hard drive if needed.'), + detail: i18n.__( + 'Unlinking removes this linked storage from Boostnote. No data is removed, please manually delete the folder from your hard drive if needed.' + ), buttons: [i18n.__('Unlink'), i18n.__('Cancel')] }) if (index === 0) { const { storage } = this.props - dataApi.removeStorage(storage.key) + dataApi + .removeStorage(storage.key) .then(() => { store.dispatch({ type: 'REMOVE_STORAGE', storageKey: storage.key }) }) - .catch((err) => { + .catch(err => { throw err }) } } - handleLabelClick (e) { + handleLabelClick(e) { const { storage } = this.props - this.setState({ - isLabelEditing: true, - name: storage.name - }, () => { - this.refs.label.focus() - }) + this.setState( + { + isLabelEditing: true, + name: storage.name + }, + () => { + this.refs.label.focus() + } + ) } - handleLabelChange (e) { + handleLabelChange(e) { this.setState({ name: this.refs.label.value }) } - handleLabelBlur (e) { + handleLabelBlur(e) { const { storage } = this.props - dataApi - .renameStorage(storage.key, this.state.name) - .then((_storage) => { - store.dispatch({ - type: 'RENAME_STORAGE', - storage: _storage - }) - this.setState({ - isLabelEditing: false - }) + dataApi.renameStorage(storage.key, this.state.name).then(_storage => { + store.dispatch({ + type: 'RENAME_STORAGE', + storage: _storage }) + this.setState({ + isLabelEditing: false + }) + }) } - render () { + render() { const { storage, hostBoundingBox } = this.props return (
- {this.state.isLabelEditing - ?
- + this.handleLabelChange(e)} - onBlur={(e) => this.handleLabelBlur(e)} + onChange={e => this.handleLabelChange(e)} + onBlur={e => this.handleLabelBlur(e)} />
- :
this.handleLabelClick(e)} + ) : ( +
this.handleLabelClick(e)} > -   + +   {storage.name}  ({storage.path}) 
- } + )}
- - -
- +
) } diff --git a/browser/main/modals/PreferencesModal/StoragesTab.js b/browser/main/modals/PreferencesModal/StoragesTab.js index e84fa88c..9df1a153 100644 --- a/browser/main/modals/PreferencesModal/StoragesTab.js +++ b/browser/main/modals/PreferencesModal/StoragesTab.js @@ -12,24 +12,27 @@ import fs from 'fs' const electron = require('electron') const { shell, remote } = electron -function browseFolder () { +function browseFolder() { const dialog = remote.dialog const defaultPath = remote.app.getPath('home') return new Promise((resolve, reject) => { - dialog.showOpenDialog({ - title: i18n.__('Select Directory'), - defaultPath, - properties: ['openDirectory', 'createDirectory'] - }, function (targetPaths) { - if (targetPaths == null) return resolve('') - resolve(targetPaths[0]) - }) + dialog.showOpenDialog( + { + title: i18n.__('Select Directory'), + defaultPath, + properties: ['openDirectory', 'createDirectory'] + }, + function(targetPaths) { + if (targetPaths == null) return resolve('') + resolve(targetPaths[0]) + } + ) }) } class StoragesTab extends React.Component { - constructor (props) { + constructor(props) { super(props) this.state = { @@ -44,7 +47,7 @@ class StoragesTab extends React.Component { this.loadAttachmentStorage() } - loadAttachmentStorage () { + loadAttachmentStorage() { const promises = [] this.props.data.noteMap.map(note => { const promise = attachmentManagement.getAttachmentsPathAndStatus( @@ -58,106 +61,128 @@ class StoragesTab extends React.Component { Promise.all(promises) .then(data => { const result = data.reduce((acc, curr) => acc.concat(curr), []) - this.setState({attachments: result}) + this.setState({ attachments: result }) }) .catch(console.error) } - handleAddStorageButton (e) { - this.setState({ - page: 'ADD_STORAGE', - newStorage: { - name: 'Unnamed', - type: 'FILESYSTEM', - path: '' + handleAddStorageButton(e) { + this.setState( + { + page: 'ADD_STORAGE', + newStorage: { + name: 'Unnamed', + type: 'FILESYSTEM', + path: '' + } + }, + () => { + this.refs.addStorageName.select() } - }, () => { - this.refs.addStorageName.select() - }) + ) } - handleLinkClick (e) { + handleLinkClick(e) { shell.openExternal(e.currentTarget.href) e.preventDefault() } - handleRemoveUnusedAttachments (attachments) { - attachmentManagement.removeAttachmentsByPaths(attachments) + handleRemoveUnusedAttachments(attachments) { + attachmentManagement + .removeAttachmentsByPaths(attachments) .then(() => this.loadAttachmentStorage()) .catch(console.error) } - renderList () { + renderList() { const { data, boundingBox } = this.props const { attachments } = this.state - const unusedAttachments = attachments.filter(attachment => !attachment.isInUse) - const inUseAttachments = attachments.filter(attachment => attachment.isInUse) + const unusedAttachments = attachments.filter( + attachment => !attachment.isInUse + ) + const inUseAttachments = attachments.filter( + attachment => attachment.isInUse + ) const totalUnusedAttachments = unusedAttachments.length const totalInuseAttachments = inUseAttachments.length const totalAttachments = totalUnusedAttachments + totalInuseAttachments - const totalUnusedAttachmentsSize = unusedAttachments - .reduce((acc, curr) => { - const stats = fs.statSync(curr.path) - const fileSizeInBytes = stats.size - return acc + fileSizeInBytes - }, 0) - const totalInuseAttachmentsSize = inUseAttachments - .reduce((acc, curr) => { - const stats = fs.statSync(curr.path) - const fileSizeInBytes = stats.size - return acc + fileSizeInBytes - }, 0) - const totalAttachmentsSize = totalUnusedAttachmentsSize + totalInuseAttachmentsSize + const totalUnusedAttachmentsSize = unusedAttachments.reduce((acc, curr) => { + const stats = fs.statSync(curr.path) + const fileSizeInBytes = stats.size + return acc + fileSizeInBytes + }, 0) + const totalInuseAttachmentsSize = inUseAttachments.reduce((acc, curr) => { + const stats = fs.statSync(curr.path) + const fileSizeInBytes = stats.size + return acc + fileSizeInBytes + }, 0) + const totalAttachmentsSize = + totalUnusedAttachmentsSize + totalInuseAttachmentsSize - const unusedAttachmentPaths = unusedAttachments - .reduce((acc, curr) => acc.concat(curr.path), []) + const unusedAttachmentPaths = unusedAttachments.reduce( + (acc, curr) => acc.concat(curr.path), + [] + ) - if (!boundingBox) { return null } - const storageList = data.storageMap.map((storage) => { - return + if (!boundingBox) { + return null + } + const storageList = data.storageMap.map(storage => { + return ( + + ) }) return (
{i18n.__('Storage Locations')}
- {storageList.length > 0 - ? storageList - :
{i18n.__('No storage found.')}
- } + {storageList.length > 0 ? ( + storageList + ) : ( +
{i18n.__('No storage found.')}
+ )}
-
{i18n.__('Attachment storage')}

- Unused attachments size: {humanFileSize(totalUnusedAttachmentsSize)} ({totalUnusedAttachments} items) + Unused attachments size: {humanFileSize(totalUnusedAttachmentsSize)} ( + {totalUnusedAttachments} items)

- In use attachments size: {humanFileSize(totalInuseAttachmentsSize)} ({totalInuseAttachments} items) + In use attachments size: {humanFileSize(totalInuseAttachmentsSize)} ( + {totalInuseAttachments} items)

- Total attachments size: {humanFileSize(totalAttachmentsSize)} ({totalAttachments} items) + Total attachments size: {humanFileSize(totalAttachmentsSize)} ( + {totalAttachments} items)

-
) } - handleAddStorageBrowseButtonClick (e) { + handleAddStorageBrowseButtonClick(e) { browseFolder() - .then((targetPath) => { + .then(targetPath => { if (targetPath.length > 0) { const { newStorage } = this.state newStorage.path = targetPath @@ -166,13 +191,13 @@ class StoragesTab extends React.Component { }) } }) - .catch((err) => { + .catch(err => { console.error('BrowseFAILED') console.error(err) }) } - handleAddStorageChange (e) { + handleAddStorageChange(e) { const { newStorage } = this.state newStorage.name = this.refs.addStorageName.value newStorage.path = this.refs.addStoragePath.value @@ -181,13 +206,13 @@ class StoragesTab extends React.Component { }) } - handleAddStorageCreateButton (e) { + handleAddStorageCreateButton(e) { dataApi .addStorage({ name: this.state.newStorage.name, path: this.state.newStorage.path }) - .then((data) => { + .then(data => { const { dispatch } = this.props dispatch({ type: 'ADD_STORAGE', @@ -200,37 +225,39 @@ class StoragesTab extends React.Component { }) } - handleAddStorageCancelButton (e) { + handleAddStorageCancelButton(e) { this.setState({ page: 'LIST' }) } - renderAddStorage () { + renderAddStorage() { return (
-
{i18n.__('Add Storage')}
-
{i18n.__('Name')}
- this.handleAddStorageChange(e)} + onChange={e => this.handleAddStorageChange(e)} />
-
{i18n.__('Type')}
+
+ {i18n.__('Type')} +
-
-
{i18n.__('Location')} +
+ {i18n.__('Location')}
- this.handleAddStorageChange(e)} + onChange={e => this.handleAddStorageChange(e)} /> - @@ -264,21 +297,25 @@ class StoragesTab extends React.Component {
- - + +
-
-
) } - renderContent () { + renderContent() { switch (this.state.page) { case 'ADD_STORAGE': case 'ADD_FOLDER': @@ -289,12 +326,8 @@ class StoragesTab extends React.Component { } } - render () { - return ( -
- {this.renderContent()} -
- ) + render() { + return
{this.renderContent()}
} } diff --git a/browser/main/modals/PreferencesModal/UiTab.js b/browser/main/modals/PreferencesModal/UiTab.js index c54ed098..e043397d 100644 --- a/browser/main/modals/PreferencesModal/UiTab.js +++ b/browser/main/modals/PreferencesModal/UiTab.js @@ -20,7 +20,7 @@ const electron = require('electron') const ipc = electron.ipcRenderer class UiTab extends React.Component { - constructor (props) { + constructor(props) { super(props) this.state = { config: props.config, @@ -28,10 +28,16 @@ class UiTab extends React.Component { } } - componentDidMount () { - CodeMirror.autoLoadMode(this.codeMirrorInstance.getCodeMirror(), 'javascript') + componentDidMount() { + CodeMirror.autoLoadMode( + this.codeMirrorInstance.getCodeMirror(), + 'javascript' + ) CodeMirror.autoLoadMode(this.customCSSCM.getCodeMirror(), 'css') - CodeMirror.autoLoadMode(this.customMarkdownLintConfigCM.getCodeMirror(), 'javascript') + CodeMirror.autoLoadMode( + this.customMarkdownLintConfigCM.getCodeMirror(), + 'javascript' + ) CodeMirror.autoLoadMode(this.prettierConfigCM.getCodeMirror(), 'javascript') // Set CM editor Sizes this.customCSSCM.getCodeMirror().setSize('400px', '400px') @@ -39,27 +45,32 @@ class UiTab extends React.Component { this.customMarkdownLintConfigCM.getCodeMirror().setSize('400px', '200px') this.handleSettingDone = () => { - this.setState({UiAlert: { - type: 'success', - message: i18n.__('Successfully applied!') - }}) + this.setState({ + UiAlert: { + type: 'success', + message: i18n.__('Successfully applied!') + } + }) } - this.handleSettingError = (err) => { - this.setState({UiAlert: { - type: 'error', - message: err.message != null ? err.message : i18n.__('An error occurred!') - }}) + this.handleSettingError = err => { + this.setState({ + UiAlert: { + type: 'error', + message: + err.message != null ? err.message : i18n.__('An error occurred!') + } + }) } ipc.addListener('APP_SETTING_DONE', this.handleSettingDone) ipc.addListener('APP_SETTING_ERROR', this.handleSettingError) } - componentWillUnmount () { + componentWillUnmount() { ipc.removeListener('APP_SETTING_DONE', this.handleSettingDone) ipc.removeListener('APP_SETTING_ERROR', this.handleSettingError) } - handleUIChange (e) { + handleUIChange(e) { const { codemirrorTheme } = this.state let checkHighLight = document.getElementById('checkHighLight') @@ -75,7 +86,8 @@ class UiTab extends React.Component { theme: this.refs.uiTheme.value, language: this.refs.uiLanguage.value, defaultNote: this.refs.defaultNote.value, - tagNewNoteWithFilteringTags: this.refs.tagNewNoteWithFilteringTags.checked, + tagNewNoteWithFilteringTags: this.refs.tagNewNoteWithFilteringTags + .checked, showCopyNotification: this.refs.showCopyNotification.checked, confirmDeletion: this.refs.confirmDeletion.checked, showOnlyRelatedTags: this.refs.showOnlyRelatedTags.checked, @@ -83,9 +95,8 @@ class UiTab extends React.Component { saveTagsAlphabetically: this.refs.saveTagsAlphabetically.checked, enableLiveNoteCounts: this.refs.enableLiveNoteCounts.checked, showMenuBar: this.refs.showMenuBar.checked, - disableDirectWrite: this.refs.uiD2w != null - ? this.refs.uiD2w.checked - : false + disableDirectWrite: + this.refs.uiD2w != null ? this.refs.uiD2w.checked : false }, editor: { theme: this.refs.editorTheme.value, @@ -111,7 +122,9 @@ class UiTab extends React.Component { spellcheck: this.refs.spellcheck.checked, enableSmartPaste: this.refs.enableSmartPaste.checked, enableMarkdownLint: this.refs.enableMarkdownLint.checked, - customMarkdownLintConfig: this.customMarkdownLintConfigCM.getCodeMirror().getValue(), + customMarkdownLintConfig: this.customMarkdownLintConfigCM + .getCodeMirror() + .getValue(), prettierConfig: this.prettierConfigCM.getCodeMirror().getValue(), deleteUnusedAttachments: this.refs.deleteUnusedAttachments.checked }, @@ -141,29 +154,34 @@ class UiTab extends React.Component { const newCodemirrorTheme = this.refs.editorTheme.value if (newCodemirrorTheme !== codemirrorTheme) { - const theme = consts.THEMES.find(theme => theme.name === newCodemirrorTheme) + const theme = consts.THEMES.find( + theme => theme.name === newCodemirrorTheme + ) if (theme) { checkHighLight.setAttribute('href', theme.path) } } - this.setState({ config: newConfig, codemirrorTheme: newCodemirrorTheme }, () => { - const {ui, editor, preview} = this.props.config - this.currentConfig = {ui, editor, preview} - if (_.isEqual(this.currentConfig, this.state.config)) { - this.props.haveToSave() - } else { - this.props.haveToSave({ - tab: 'UI', - type: 'warning', - message: i18n.__('Unsaved Changes!') - }) + this.setState( + { config: newConfig, codemirrorTheme: newCodemirrorTheme }, + () => { + const { ui, editor, preview } = this.props.config + this.currentConfig = { ui, editor, preview } + if (_.isEqual(this.currentConfig, this.state.config)) { + this.props.haveToSave() + } else { + this.props.haveToSave({ + tab: 'UI', + type: 'warning', + message: i18n.__('Unsaved Changes!') + }) + } } - }) + ) } - handleSaveUIClick (e) { + handleSaveUIClick(e) { const newConfig = { ui: this.state.config.ui, editor: this.state.config.editor, @@ -180,7 +198,7 @@ class UiTab extends React.Component { this.props.haveToSave() } - clearMessage () { + clearMessage() { _.debounce(() => { this.setState({ UiAlert: null @@ -188,17 +206,17 @@ class UiTab extends React.Component { }, 2000)() } - render () { + render() { const UiAlert = this.state.UiAlert - const UiAlertElement = UiAlert != null - ?

- {UiAlert.message} -

- : null + const UiAlertElement = + UiAlert != null ? ( +

{UiAlert.message}

+ ) : null const themes = consts.THEMES const { config, codemirrorTheme } = this.state - const codemirrorSampleCode = 'function iamHappy (happy) {\n\tif (happy) {\n\t console.log("I am Happy!")\n\t} else {\n\t console.log("I am not Happy!")\n\t}\n};' + const codemirrorSampleCode = + 'function iamHappy (happy) {\n\tif (happy) {\n\t console.log("I am Happy!")\n\t} else {\n\t console.log("I am not Happy!")\n\t}\n};' const enableEditRulersStyle = config.editor.enableRulers ? 'block' : 'none' const fontFamily = normalizeEditorFontFamily(config.editor.fontFamily) return ( @@ -211,40 +229,52 @@ class UiTab extends React.Component { {i18n.__('Interface Theme')}
- this.handleUIChange(e)} ref='uiTheme' > - { - uiThemes.filter(theme => !theme.isDark).sort((a, b) => a.label.localeCompare(b.label)).map(theme => { - return () - }) - } + {uiThemes + .filter(theme => !theme.isDark) + .sort((a, b) => a.label.localeCompare(b.label)) + .map(theme => { + return ( + + ) + })} - { - uiThemes.filter(theme => theme.isDark).sort((a, b) => a.label.localeCompare(b.label)).map(theme => { - return () - }) - } + {uiThemes + .filter(theme => theme.isDark) + .sort((a, b) => a.label.localeCompare(b.label)) + .map(theme => { + return ( + + ) + })}
-
- {i18n.__('Language')} -
+
{i18n.__('Language')}
- this.handleUIChange(e)} ref='uiLanguage' > - { - getLanguages().map((language) => ) - } + {getLanguages().map(language => ( + + ))}
@@ -254,12 +284,15 @@ class UiTab extends React.Component { {i18n.__('Default New Note')}
- this.handleUIChange(e)} ref='defaultNote' > - +
@@ -267,103 +300,121 @@ class UiTab extends React.Component {
- { - global.process.platform === 'win32' - ?
+ {global.process.platform === 'win32' ? ( +
- : null - } + ) : null}
Tags
@@ -371,21 +422,22 @@ class UiTab extends React.Component {
Editor
-
- {i18n.__('Editor Theme')} -
+
{i18n.__('Editor Theme')}
- -
+
(this.codeMirrorInstance = e)} value={codemirrorSampleCode} @@ -394,7 +446,8 @@ class UiTab extends React.Component { readOnly: true, mode: 'javascript', theme: codemirrorTheme - }} /> + }} + />
@@ -403,10 +456,11 @@ class UiTab extends React.Component { {i18n.__('Editor Font Size')}
- this.handleUIChange(e)} + onChange={e => this.handleUIChange(e)} type='text' />
@@ -416,10 +470,11 @@ class UiTab extends React.Component { {i18n.__('Editor Font Family')}
- this.handleUIChange(e)} + onChange={e => this.handleUIChange(e)} type='text' />
@@ -429,18 +484,21 @@ class UiTab extends React.Component { {i18n.__('Editor Indent Style')}
-   - this.handleUIChange(e)} + onChange={e => this.handleUIChange(e)} > @@ -454,23 +512,21 @@ class UiTab extends React.Component {
-
- this.handleUIChange(e)} + onChange={e => this.handleUIChange(e)} type='text' />
@@ -481,12 +537,15 @@ class UiTab extends React.Component { {i18n.__('Switch to Preview')}
-
@@ -497,15 +556,20 @@ class UiTab extends React.Component { {i18n.__('Editor Keymap')}
- -

{i18n.__('⚠️ Please restart boostnote after you change the keymap')}

+

+ {i18n.__( + '⚠️ Please restart boostnote after you change the keymap' + )} +

@@ -514,14 +578,21 @@ class UiTab extends React.Component { {i18n.__('Snippet Default Language')}
-
@@ -531,10 +602,11 @@ class UiTab extends React.Component { {i18n.__('Front matter title field')}
- this.handleUIChange(e)} + onChange={e => this.handleUIChange(e)} type='text' />
@@ -542,99 +614,119 @@ class UiTab extends React.Component {
@@ -643,10 +735,11 @@ class UiTab extends React.Component { {i18n.__('Matching character pairs')}
- this.handleUIChange(e)} + onChange={e => this.handleUIChange(e)} type='text' />
@@ -657,10 +750,11 @@ class UiTab extends React.Component { {i18n.__('Matching character triples')}
- this.handleUIChange(e)} + onChange={e => this.handleUIChange(e)} type='text' />
@@ -671,10 +765,11 @@ class UiTab extends React.Component { {i18n.__('Exploding character pairs')}
- this.handleUIChange(e)} + onChange={e => this.handleUIChange(e)} type='text' />
@@ -684,13 +779,22 @@ class UiTab extends React.Component { {i18n.__('Custom MarkdownLint Rules')}
- this.handleUIChange(e)} + this.handleUIChange(e)} checked={this.state.config.editor.enableMarkdownLint} ref='enableMarkdownLint' type='checkbox' - />  + /> +   {i18n.__('Enable MarkdownLint')} -
+
+ gutters: [ + 'CodeMirror-linenumbers', + 'CodeMirror-foldgutter', + 'CodeMirror-lint-markers' + ] + }} + />
@@ -714,10 +823,11 @@ class UiTab extends React.Component { {i18n.__('Preview Font Size')}
- this.handleUIChange(e)} + onChange={e => this.handleUIChange(e)} type='text' />
@@ -727,124 +837,152 @@ class UiTab extends React.Component { {i18n.__('Preview Font Family')}
- this.handleUIChange(e)} + onChange={e => this.handleUIChange(e)} type='text' />
-
{i18n.__('Code Block Theme')}
+
+ {i18n.__('Code Block Theme')} +
-
-
- {i18n.__('Sanitization')} -
+
{i18n.__('Sanitization')}
-
@@ -853,10 +991,11 @@ class UiTab extends React.Component { {i18n.__('LaTeX Inline Open Delimiter')}
- this.handleUIChange(e)} + onChange={e => this.handleUIChange(e)} type='text' />
@@ -866,10 +1005,11 @@ class UiTab extends React.Component { {i18n.__('LaTeX Inline Close Delimiter')}
- this.handleUIChange(e)} + onChange={e => this.handleUIChange(e)} type='text' />
@@ -879,10 +1019,11 @@ class UiTab extends React.Component { {i18n.__('LaTeX Block Open Delimiter')}
- this.handleUIChange(e)} + onChange={e => this.handleUIChange(e)} type='text' />
@@ -892,10 +1033,11 @@ class UiTab extends React.Component { {i18n.__('LaTeX Block Close Delimiter')}
- this.handleUIChange(e)} + onChange={e => this.handleUIChange(e)} type='text' />
@@ -905,26 +1047,27 @@ class UiTab extends React.Component { {i18n.__('PlantUML Server')}
- this.handleUIChange(e)} + onChange={e => this.handleUIChange(e)} type='text' />
-
- {i18n.__('Custom CSS')} -
+
{i18n.__('Custom CSS')}
- this.handleUIChange(e)} + this.handleUIChange(e)} checked={config.preview.allowCustomCSS} ref='previewAllowCustomCSS' type='checkbox' - />  + /> +   {i18n.__('Allow custom CSS for preview')} -
+
+ }} + />
@@ -944,7 +1088,7 @@ class UiTab extends React.Component { {i18n.__('Prettier Config')}
-
+
+ }} + />
- {UiAlertElement}
diff --git a/browser/main/modals/PreferencesModal/index.js b/browser/main/modals/PreferencesModal/index.js index 86957083..2c14e6c7 100644 --- a/browser/main/modals/PreferencesModal/index.js +++ b/browser/main/modals/PreferencesModal/index.js @@ -16,7 +16,7 @@ import _ from 'lodash' import i18n from 'browser/lib/i18n' class Preferences extends React.Component { - constructor (props) { + constructor(props) { super(props) this.state = { @@ -27,44 +27,39 @@ class Preferences extends React.Component { } } - componentDidMount () { + componentDidMount() { this.refs.root.focus() const boundingBox = this.getContentBoundingBox() this.setState({ boundingBox }) } - switchTeam (teamId) { - this.setState({currentTeamId: teamId}) + switchTeam(teamId) { + this.setState({ currentTeamId: teamId }) } - handleNavButtonClick (tab) { - return (e) => { - this.setState({currentTab: tab}) + handleNavButtonClick(tab) { + return e => { + this.setState({ currentTab: tab }) } } - handleEscButtonClick () { + handleEscButtonClick() { this.props.close() } - renderContent () { + renderContent() { const { boundingBox } = this.state const { dispatch, config, data } = this.props switch (this.state.currentTab) { case 'INFO': - return ( - - ) + return case 'HOTKEY': return ( this.setState({HotkeyAlert: alert})} + haveToSave={alert => this.setState({ HotkeyAlert: alert })} /> ) case 'UI': @@ -72,29 +67,21 @@ class Preferences extends React.Component { this.setState({UIAlert: alert})} + haveToSave={alert => this.setState({ UIAlert: alert })} /> ) case 'CROWDFUNDING': - return ( - - ) + return case 'BLOG': return ( this.setState({BlogAlert: alert})} + haveToSave={alert => this.setState({ BlogAlert: alert })} /> ) case 'SNIPPET': - return ( - - ) + return case 'STORAGES': default: return ( @@ -107,67 +94,69 @@ class Preferences extends React.Component { } } - handleKeyDown (e) { + handleKeyDown(e) { if (e.keyCode === 27) { this.props.close() } } - getContentBoundingBox () { + getContentBoundingBox() { return this.refs.content.getBoundingClientRect() } - haveToSaveNotif (type, message) { - return ( -

{message}

- ) + haveToSaveNotif(type, message) { + return

{message}

} - render () { + render() { const content = this.renderContent() const tabs = [ - {target: 'STORAGES', label: i18n.__('Storage')}, - {target: 'HOTKEY', label: i18n.__('Hotkeys'), Hotkey: this.state.HotkeyAlert}, - {target: 'UI', label: i18n.__('Interface'), UI: this.state.UIAlert}, - {target: 'INFO', label: i18n.__('About')}, - {target: 'CROWDFUNDING', label: i18n.__('Crowdfunding')}, - {target: 'BLOG', label: i18n.__('Blog'), Blog: this.state.BlogAlert}, - {target: 'SNIPPET', label: i18n.__('Snippets')} + { target: 'STORAGES', label: i18n.__('Storage') }, + { + target: 'HOTKEY', + label: i18n.__('Hotkeys'), + Hotkey: this.state.HotkeyAlert + }, + { target: 'UI', label: i18n.__('Interface'), UI: this.state.UIAlert }, + { target: 'INFO', label: i18n.__('About') }, + { target: 'CROWDFUNDING', label: i18n.__('Crowdfunding') }, + { target: 'BLOG', label: i18n.__('Blog'), Blog: this.state.BlogAlert }, + { target: 'SNIPPET', label: i18n.__('Snippets') } ] - const navButtons = tabs.map((tab) => { + const navButtons = tabs.map(tab => { const isActive = this.state.currentTab === tab.target - const isUiHotkeyTab = _.isObject(tab[tab.label]) && tab.label === tab[tab.label].tab + const isUiHotkeyTab = + _.isObject(tab[tab.label]) && tab.label === tab[tab.label].tab return ( - ) }) return ( -
this.handleKeyDown(e)} + onKeyDown={e => this.handleKeyDown(e)} >

{i18n.__('Your preferences for Boostnote')}

- this.handleEscButtonClick(e)} /> -
- {navButtons} -
+ this.handleEscButtonClick(e)} + /> +
{navButtons}
{content}
@@ -181,4 +170,4 @@ Preferences.propTypes = { dispatch: PropTypes.func } -export default connect((x) => x)(CSSModules(Preferences, styles)) +export default connect(x => x)(CSSModules(Preferences, styles)) diff --git a/browser/main/modals/RenameFolderModal.js b/browser/main/modals/RenameFolderModal.js index 9fdd70c8..a8d6f386 100644 --- a/browser/main/modals/RenameFolderModal.js +++ b/browser/main/modals/RenameFolderModal.js @@ -8,7 +8,7 @@ import ModalEscButton from 'browser/components/ModalEscButton' import i18n from 'browser/lib/i18n' class RenameFolderModal extends React.Component { - constructor (props) { + constructor(props) { super(props) this.state = { @@ -16,39 +16,39 @@ class RenameFolderModal extends React.Component { } } - componentDidMount () { + componentDidMount() { this.refs.name.focus() this.refs.name.select() } - handleCloseButtonClick (e) { + handleCloseButtonClick(e) { this.props.close() } - handleChange (e) { + handleChange(e) { this.setState({ name: this.refs.name.value }) } - handleKeyDown (e) { + handleKeyDown(e) { if (e.keyCode === 27) { this.props.close() } } - handleInputKeyDown (e) { + handleInputKeyDown(e) { switch (e.keyCode) { case 13: this.confirm() } } - handleConfirmButtonClick (e) { + handleConfirmButtonClick(e) { this.confirm() } - confirm () { + confirm() { if (this.state.name.trim().length > 0) { const { storage, folder } = this.props dataApi @@ -56,7 +56,7 @@ class RenameFolderModal extends React.Component { name: this.state.name, color: folder.color }) - .then((data) => { + .then(data => { store.dispatch({ type: 'UPDATE_FOLDER', storage: data.storage @@ -66,27 +66,32 @@ class RenameFolderModal extends React.Component { } } - render () { + render() { return ( -
this.handleKeyDown(e)} + onKeyDown={e => this.handleKeyDown(e)} >
{i18n.__('Rename Folder')}
- this.handleCloseButtonClick(e)} /> + this.handleCloseButtonClick(e)} + />
- this.handleChange(e)} - onKeyDown={(e) => this.handleInputKeyDown(e)} + onChange={e => this.handleChange(e)} + onKeyDown={e => this.handleInputKeyDown(e)} /> - diff --git a/browser/main/store.js b/browser/main/store.js index d48198a7..d48946a6 100644 --- a/browser/main/store.js +++ b/browser/main/store.js @@ -6,7 +6,7 @@ import { Map, Set } from 'browser/lib/Mutable' import _ from 'lodash' import DevTools from './DevTools' -function defaultDataMap () { +function defaultDataMap() { return { storageMap: new Map(), noteMap: new Map(), @@ -18,16 +18,16 @@ function defaultDataMap () { } } -function data (state = defaultDataMap(), action) { +function data(state = defaultDataMap(), action) { switch (action.type) { case 'INIT_ALL': state = defaultDataMap() - action.storages.forEach((storage) => { + action.storages.forEach(storage => { state.storageMap.set(storage.key, storage) }) - action.notes.some((note) => { + action.notes.some(note => { if (note === undefined) return true const uniqueKey = note.key const folderKey = note.storage + '-' + note.folder @@ -40,7 +40,10 @@ function data (state = defaultDataMap(), action) { if (note.isTrashed) { state.trashedSet.add(uniqueKey) } - const storageNoteList = getOrInitItem(state.storageNoteMap, note.storage) + const storageNoteList = getOrInitItem( + state.storageNoteMap, + note.storage + ) storageNoteList.add(uniqueKey) const folderNoteSet = getOrInitItem(state.folderNoteMap, folderKey) @@ -51,173 +54,170 @@ function data (state = defaultDataMap(), action) { } }) return state - case 'UPDATE_NOTE': - { - const note = action.note - const uniqueKey = note.key - const folderKey = note.storage + '-' + note.folder - const oldNote = state.noteMap.get(uniqueKey) + case 'UPDATE_NOTE': { + const note = action.note + const uniqueKey = note.key + const folderKey = note.storage + '-' + note.folder + const oldNote = state.noteMap.get(uniqueKey) - state = Object.assign({}, state) - state.noteMap = new Map(state.noteMap) - state.noteMap.set(uniqueKey, note) + state = Object.assign({}, state) + state.noteMap = new Map(state.noteMap) + state.noteMap.set(uniqueKey, note) - updateStarredChange(oldNote, note, state, uniqueKey) + updateStarredChange(oldNote, note, state, uniqueKey) - if (oldNote == null || oldNote.isTrashed !== note.isTrashed) { - state.trashedSet = new Set(state.trashedSet) - if (note.isTrashed) { - state.trashedSet.add(uniqueKey) - state.starredSet.delete(uniqueKey) - removeFromTags(note.tags, state, uniqueKey) - } else { - state.trashedSet.delete(uniqueKey) - - assignToTags(note.tags, state, uniqueKey) - - if (note.isStarred) { - state.starredSet.add(uniqueKey) - } - } - } - - // Update storageNoteMap if oldNote doesn't exist - if (oldNote == null) { - state.storageNoteMap = new Map(state.storageNoteMap) - let storageNoteSet = state.storageNoteMap.get(note.storage) - storageNoteSet = new Set(storageNoteSet) - storageNoteSet.add(uniqueKey) - state.storageNoteMap.set(note.storage, storageNoteSet) - } - - // Update foldermap if folder changed or post created - updateFolderChange(oldNote, note, state, folderKey, uniqueKey) - - if (oldNote != null) { - updateTagChanges(oldNote, note, state, uniqueKey) + if (oldNote == null || oldNote.isTrashed !== note.isTrashed) { + state.trashedSet = new Set(state.trashedSet) + if (note.isTrashed) { + state.trashedSet.add(uniqueKey) + state.starredSet.delete(uniqueKey) + removeFromTags(note.tags, state, uniqueKey) } else { + state.trashedSet.delete(uniqueKey) + assignToTags(note.tags, state, uniqueKey) - } - return state + if (note.isStarred) { + state.starredSet.add(uniqueKey) + } + } } - case 'MOVE_NOTE': - { - const originNote = action.originNote - const originKey = originNote.key - const note = action.note - const uniqueKey = note.key - const folderKey = note.storage + '-' + note.folder - const oldNote = state.noteMap.get(uniqueKey) - state = Object.assign({}, state) - state.noteMap = new Map(state.noteMap) - state.noteMap.delete(originKey) - state.noteMap.set(uniqueKey, note) + // Update storageNoteMap if oldNote doesn't exist + if (oldNote == null) { + state.storageNoteMap = new Map(state.storageNoteMap) + let storageNoteSet = state.storageNoteMap.get(note.storage) + storageNoteSet = new Set(storageNoteSet) + storageNoteSet.add(uniqueKey) + state.storageNoteMap.set(note.storage, storageNoteSet) + } - // If storage chanced, origin key must be discarded - if (originKey !== uniqueKey) { - // From isStarred - if (originNote.isStarred) { - state.starredSet = new Set(state.starredSet) - state.starredSet.delete(originKey) - } + // Update foldermap if folder changed or post created + updateFolderChange(oldNote, note, state, folderKey, uniqueKey) - if (originNote.isTrashed) { - state.trashedSet = new Set(state.trashedSet) - state.trashedSet.delete(originKey) - } + if (oldNote != null) { + updateTagChanges(oldNote, note, state, uniqueKey) + } else { + assignToTags(note.tags, state, uniqueKey) + } - // From storageNoteMap - state.storageNoteMap = new Map(state.storageNoteMap) - let noteSet = state.storageNoteMap.get(originNote.storage) - noteSet = new Set(noteSet) - noteSet.delete(originKey) - state.storageNoteMap.set(originNote.storage, noteSet) + return state + } + case 'MOVE_NOTE': { + const originNote = action.originNote + const originKey = originNote.key + const note = action.note + const uniqueKey = note.key + const folderKey = note.storage + '-' + note.folder + const oldNote = state.noteMap.get(uniqueKey) - // From folderNoteMap - state.folderNoteMap = new Map(state.folderNoteMap) - const originFolderKey = originNote.storage + '-' + originNote.folder - let originFolderList = state.folderNoteMap.get(originFolderKey) - originFolderList = new Set(originFolderList) - originFolderList.delete(originKey) - state.folderNoteMap.set(originFolderKey, originFolderList) + state = Object.assign({}, state) + state.noteMap = new Map(state.noteMap) + state.noteMap.delete(originKey) + state.noteMap.set(uniqueKey, note) - removeFromTags(originNote.tags, state, originKey) + // If storage chanced, origin key must be discarded + if (originKey !== uniqueKey) { + // From isStarred + if (originNote.isStarred) { + state.starredSet = new Set(state.starredSet) + state.starredSet.delete(originKey) } - updateStarredChange(oldNote, note, state, uniqueKey) - - if (oldNote == null || oldNote.isTrashed !== note.isTrashed) { + if (originNote.isTrashed) { state.trashedSet = new Set(state.trashedSet) - if (note.isTrashed) { - state.trashedSet.add(uniqueKey) - } else { - state.trashedSet.delete(uniqueKey) - } + state.trashedSet.delete(originKey) } - // Update storageNoteMap if oldNote doesn't exist - if (oldNote == null) { - state.storageNoteMap = new Map(state.storageNoteMap) - let noteSet = state.storageNoteMap.get(note.storage) - noteSet = new Set(noteSet) - noteSet.add(uniqueKey) - state.storageNoteMap.set(folderKey, noteSet) - } - - // Update foldermap if folder changed or post created - updateFolderChange(oldNote, note, state, folderKey, uniqueKey) - - // Remove from old folder map - if (oldNote != null) { - updateTagChanges(oldNote, note, state, uniqueKey) - } else { - assignToTags(note.tags, state, uniqueKey) - } - - return state - } - case 'DELETE_NOTE': - { - const uniqueKey = action.noteKey - const targetNote = state.noteMap.get(uniqueKey) - - state = Object.assign({}, state) - // From storageNoteMap state.storageNoteMap = new Map(state.storageNoteMap) - let noteSet = state.storageNoteMap.get(targetNote.storage) + let noteSet = state.storageNoteMap.get(originNote.storage) noteSet = new Set(noteSet) - noteSet.delete(uniqueKey) - state.storageNoteMap.set(targetNote.storage, noteSet) + noteSet.delete(originKey) + state.storageNoteMap.set(originNote.storage, noteSet) - if (targetNote != null) { - // From isStarred - if (targetNote.isStarred) { - state.starredSet = new Set(state.starredSet) - state.starredSet.delete(uniqueKey) - } + // From folderNoteMap + state.folderNoteMap = new Map(state.folderNoteMap) + const originFolderKey = originNote.storage + '-' + originNote.folder + let originFolderList = state.folderNoteMap.get(originFolderKey) + originFolderList = new Set(originFolderList) + originFolderList.delete(originKey) + state.folderNoteMap.set(originFolderKey, originFolderList) - if (targetNote.isTrashed) { - state.trashedSet = new Set(state.trashedSet) - state.trashedSet.delete(uniqueKey) - } - - // From folderNoteMap - const folderKey = targetNote.storage + '-' + targetNote.folder - state.folderNoteMap = new Map(state.folderNoteMap) - let folderSet = state.folderNoteMap.get(folderKey) - folderSet = new Set(folderSet) - folderSet.delete(uniqueKey) - state.folderNoteMap.set(folderKey, folderSet) - - removeFromTags(targetNote.tags, state, uniqueKey) - } - state.noteMap = new Map(state.noteMap) - state.noteMap.delete(uniqueKey) - return state + removeFromTags(originNote.tags, state, originKey) } + + updateStarredChange(oldNote, note, state, uniqueKey) + + if (oldNote == null || oldNote.isTrashed !== note.isTrashed) { + state.trashedSet = new Set(state.trashedSet) + if (note.isTrashed) { + state.trashedSet.add(uniqueKey) + } else { + state.trashedSet.delete(uniqueKey) + } + } + + // Update storageNoteMap if oldNote doesn't exist + if (oldNote == null) { + state.storageNoteMap = new Map(state.storageNoteMap) + let noteSet = state.storageNoteMap.get(note.storage) + noteSet = new Set(noteSet) + noteSet.add(uniqueKey) + state.storageNoteMap.set(folderKey, noteSet) + } + + // Update foldermap if folder changed or post created + updateFolderChange(oldNote, note, state, folderKey, uniqueKey) + + // Remove from old folder map + if (oldNote != null) { + updateTagChanges(oldNote, note, state, uniqueKey) + } else { + assignToTags(note.tags, state, uniqueKey) + } + + return state + } + case 'DELETE_NOTE': { + const uniqueKey = action.noteKey + const targetNote = state.noteMap.get(uniqueKey) + + state = Object.assign({}, state) + + // From storageNoteMap + state.storageNoteMap = new Map(state.storageNoteMap) + let noteSet = state.storageNoteMap.get(targetNote.storage) + noteSet = new Set(noteSet) + noteSet.delete(uniqueKey) + state.storageNoteMap.set(targetNote.storage, noteSet) + + if (targetNote != null) { + // From isStarred + if (targetNote.isStarred) { + state.starredSet = new Set(state.starredSet) + state.starredSet.delete(uniqueKey) + } + + if (targetNote.isTrashed) { + state.trashedSet = new Set(state.trashedSet) + state.trashedSet.delete(uniqueKey) + } + + // From folderNoteMap + const folderKey = targetNote.storage + '-' + targetNote.folder + state.folderNoteMap = new Map(state.folderNoteMap) + let folderSet = state.folderNoteMap.get(folderKey) + folderSet = new Set(folderSet) + folderSet.delete(uniqueKey) + state.folderNoteMap.set(folderKey, folderSet) + + removeFromTags(targetNote.tags, state, uniqueKey) + } + state.noteMap = new Map(state.noteMap) + state.noteMap.delete(uniqueKey) + return state + } case 'UPDATE_FOLDER': case 'REORDER_FOLDER': case 'EXPORT_FOLDER': @@ -247,7 +247,7 @@ function data (state = defaultDataMap(), action) { state.storageNoteMap.set(action.storage.key, storageNoteSet) if (noteSet != null) { - noteSet.forEach(function handleNoteKey (noteKey) { + noteSet.forEach(function handleNoteKey(noteKey) { // Get note from noteMap const note = state.noteMap.get(noteKey) if (note != null) { @@ -269,7 +269,7 @@ function data (state = defaultDataMap(), action) { // Delete key from tag map state.tagNoteMap = new Map(state.tagNoteMap) - note.tags.forEach((tag) => { + note.tags.forEach(tag => { const tagNoteSet = getOrInitItem(state.tagNoteMap, tag) tagNoteSet.delete(noteKey) }) @@ -288,7 +288,7 @@ function data (state = defaultDataMap(), action) { state.storageNoteMap.set(action.storage.key, new Set()) state.folderNoteMap = new Map(state.folderNoteMap) state.tagNoteMap = new Map(state.tagNoteMap) - action.notes.forEach((note) => { + action.notes.forEach(note => { const uniqueKey = note.key const folderKey = note.storage + '-' + note.folder state.noteMap.set(uniqueKey, note) @@ -307,7 +307,7 @@ function data (state = defaultDataMap(), action) { } folderNoteSet.add(uniqueKey) - note.tags.forEach((tag) => { + note.tags.forEach(tag => { const tagNoteSet = getOrInitItem(state.tagNoteMap, tag) tagNoteSet.add(uniqueKey) }) @@ -322,7 +322,7 @@ function data (state = defaultDataMap(), action) { // Remove folders from folderMap if (storage != null) { state.folderMap = new Map(state.folderMap) - storage.folders.forEach((folder) => { + storage.folders.forEach(folder => { const folderKey = storage.key + '-' + folder.key state.folderMap.delete(folderKey) }) @@ -334,17 +334,17 @@ function data (state = defaultDataMap(), action) { state.storageNoteMap.delete(action.storageKey) if (storageNoteSet != null) { const notes = storageNoteSet - .map((noteKey) => state.noteMap.get(noteKey)) - .filter((note) => note != null) + .map(noteKey => state.noteMap.get(noteKey)) + .filter(note => note != null) state.noteMap = new Map(state.noteMap) state.tagNoteMap = new Map(state.tagNoteMap) state.starredSet = new Set(state.starredSet) - notes.forEach((note) => { + notes.forEach(note => { const noteKey = note.key state.noteMap.delete(noteKey) state.starredSet.delete(noteKey) - note.tags.forEach((tag) => { + note.tags.forEach(tag => { let tagNoteSet = state.tagNoteMap.get(tag) tagNoteSet = new Set(tagNoteSet) tagNoteSet.delete(noteKey) @@ -364,7 +364,7 @@ function data (state = defaultDataMap(), action) { const defaultConfig = ConfigManager.get() -function config (state = defaultConfig, action) { +function config(state = defaultConfig, action) { switch (action.type) { case 'SET_IS_SIDENAV_FOLDED': state.isSideNavFolded = action.isFolded @@ -390,7 +390,7 @@ const defaultStatus = { updateReady: false } -function status (state = defaultStatus, action) { +function status(state = defaultStatus, action) { switch (action.type) { case 'UPDATE_AVAILABLE': return Object.assign({}, defaultStatus, { @@ -400,7 +400,7 @@ function status (state = defaultStatus, action) { return state } -function updateStarredChange (oldNote, note, state, uniqueKey) { +function updateStarredChange(oldNote, note, state, uniqueKey) { if (oldNote == null || oldNote.isStarred !== note.isStarred) { state.starredSet = new Set(state.starredSet) if (note.isStarred) { @@ -411,7 +411,7 @@ function updateStarredChange (oldNote, note, state, uniqueKey) { } } -function updateFolderChange (oldNote, note, state, folderKey, uniqueKey) { +function updateFolderChange(oldNote, note, state, folderKey, uniqueKey) { if (oldNote == null || oldNote.folder !== note.folder) { state.folderNoteMap = new Map(state.folderNoteMap) let folderNoteList = state.folderNoteMap.get(folderKey) @@ -429,7 +429,7 @@ function updateFolderChange (oldNote, note, state, folderKey, uniqueKey) { } } -function updateTagChanges (oldNote, note, state, uniqueKey) { +function updateTagChanges(oldNote, note, state, uniqueKey) { const discardedTags = _.difference(oldNote.tags, note.tags) const addedTags = _.difference(note.tags, oldNote.tags) if (discardedTags.length + addedTags.length > 0) { @@ -438,15 +438,15 @@ function updateTagChanges (oldNote, note, state, uniqueKey) { } } -function assignToTags (tags, state, uniqueKey) { +function assignToTags(tags, state, uniqueKey) { state.tagNoteMap = new Map(state.tagNoteMap) - tags.forEach((tag) => { + tags.forEach(tag => { const tagNoteList = getOrInitItem(state.tagNoteMap, tag) tagNoteList.add(uniqueKey) }) } -function removeFromTags (tags, state, uniqueKey) { +function removeFromTags(tags, state, uniqueKey) { state.tagNoteMap = new Map(state.tagNoteMap) tags.forEach(tag => { let tagNoteList = state.tagNoteMap.get(tag) @@ -458,7 +458,7 @@ function removeFromTags (tags, state, uniqueKey) { }) } -function getOrInitItem (target, key) { +function getOrInitItem(target, key) { let results = target.get(key) if (results == null) { results = new Set() @@ -476,8 +476,15 @@ const reducer = combineReducers({ router: connectRouter(history) }) -const store = createStore(reducer, undefined, process.env.NODE_ENV === 'development' - ? compose(applyMiddleware(routerMiddleware(history)), DevTools.instrument()) - : applyMiddleware(routerMiddleware(history))) +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/dev-scripts/dev.js b/dev-scripts/dev.js index 9698a2fe..4cff0ca2 100644 --- a/dev-scripts/dev.js +++ b/dev-scripts/dev.js @@ -15,7 +15,7 @@ const options = { quiet: true } -function startServer () { +function startServer() { config.plugins.push(new webpack.HotModuleReplacementPlugin()) config.entry.main.unshift( `webpack-dev-server/client?http://localhost:${port}/`, @@ -25,7 +25,7 @@ function startServer () { server = new WebpackDevServer(compiler, options) return new Promise((resolve, reject) => { - server.listen(port, 'localhost', function (err) { + server.listen(port, 'localhost', function(err) { if (err) { reject(err) } @@ -48,7 +48,7 @@ function startServer () { }) } -function startElectron () { +function startElectron() { spawn(electron, ['--hot', './index.js'], { stdio: 'inherit' }) .on('close', () => { server.close() diff --git a/gruntfile.js b/gruntfile.js index 207f8685..f235ceaa 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -5,13 +5,15 @@ const packager = require('electron-packager') const WIN = process.platform === 'win32' -module.exports = function (grunt) { +module.exports = function(grunt) { var authCode try { authCode = grunt.file.readJSON('secret/auth_code.json') } catch (e) { if (e.origError.code === 'ENOENT') { - console.warn('secret/auth_code.json is not found. CodeSigning is not available.') + console.warn( + 'secret/auth_code.json is not found. CodeSigning is not available.' + ) } } const OSX_COMMON_NAME = authCode != null ? authCode.OSX_COMMON_NAME : '' @@ -41,10 +43,7 @@ module.exports = function (grunt) { genericName: 'Boostnote', productDescription: 'The opensource note app for developers.', arch: 'amd64', - categories: [ - 'Development', - 'Utility' - ], + categories: ['Development', 'Utility'], icon: path.join(__dirname, 'resources/app.png'), bin: 'Boostnote' }, @@ -60,10 +59,7 @@ module.exports = function (grunt) { genericName: 'Boostnote', productDescription: 'The opensource note app for developers.', arch: 'x86_64', - categories: [ - 'Development', - 'Utility' - ], + categories: ['Development', 'Utility'], icon: path.join(__dirname, 'resources/app.png'), bin: 'Boostnote' }, @@ -80,18 +76,21 @@ module.exports = function (grunt) { grunt.loadNpmTasks('grunt-electron-installer-redhat') } - grunt.registerTask('compile', function () { + grunt.registerTask('compile', function() { var done = this.async() - var execPath = path.join('node_modules', '.bin', 'webpack') + ' --config webpack-production.config.js' + var execPath = + path.join('node_modules', '.bin', 'webpack') + + ' --config webpack-production.config.js' grunt.log.writeln(execPath) - ChildProcess.exec(execPath, + ChildProcess.exec( + execPath, { env: Object.assign({}, process.env, { BABEL_ENV: 'production', NODE_ENV: 'production' }) }, - function (err, stdout, stderr) { + function(err, stdout, stderr) { grunt.log.writeln(stdout) if (err) { @@ -105,7 +104,7 @@ module.exports = function (grunt) { ) }) - grunt.registerTask('pack', function (platform) { + grunt.registerTask('pack', function(platform) { grunt.log.writeln(path.join(__dirname, 'dist')) var done = this.async() var opts = { @@ -137,7 +136,7 @@ module.exports = function (grunt) { InternalName: 'Boostnote' } }) - packager(opts, function (err, appPath) { + packager(opts, function(err, appPath) { if (err) { grunt.log.writeln(err) done(err) @@ -153,7 +152,7 @@ module.exports = function (grunt) { icon: path.join(__dirname, 'resources/app.icns'), 'app-category-type': 'public.app-category.developer-tools' }) - packager(opts, function (err, appPath) { + packager(opts, function(err, appPath) { if (err) { grunt.log.writeln(err) done(err) @@ -168,7 +167,7 @@ module.exports = function (grunt) { icon: path.join(__dirname, 'resources/app.icns'), 'app-category-type': 'public.app-category.developer-tools' }) - packager(opts, function (err, appPath) { + packager(opts, function(err, appPath) { if (err) { grunt.log.writeln(err) done(err) @@ -180,15 +179,16 @@ module.exports = function (grunt) { } }) - grunt.registerTask('codesign', function (platform) { + grunt.registerTask('codesign', function(platform) { var done = this.async() if (process.platform !== 'darwin') { done(false) return } - ChildProcess.exec(`codesign --verbose --deep --force --sign \"${OSX_COMMON_NAME}\" dist/Boostnote-darwin-x64/Boostnote.app`, - function (err, stdout, stderr) { + ChildProcess.exec( + `codesign --verbose --deep --force --sign \"${OSX_COMMON_NAME}\" dist/Boostnote-darwin-x64/Boostnote.app`, + function(err, stdout, stderr) { grunt.log.writeln(stdout) if (err) { grunt.log.writeln(err) @@ -197,44 +197,43 @@ module.exports = function (grunt) { return } done() - }) + } + ) }) - grunt.registerTask('create-osx-installer', function () { + grunt.registerTask('create-osx-installer', function() { var done = this.async() var execPath = 'appdmg appdmg.json dist/Boostnote-mac.dmg' grunt.log.writeln(execPath) - ChildProcess.exec(execPath, - function (err, stdout, stderr) { - grunt.log.writeln(stdout) - if (err) { - grunt.log.writeln(err) - grunt.log.writeln(stderr) - done(false) - return - } - done() - }) + ChildProcess.exec(execPath, function(err, stdout, stderr) { + grunt.log.writeln(stdout) + if (err) { + grunt.log.writeln(err) + grunt.log.writeln(stderr) + done(false) + return + } + done() + }) }) - grunt.registerTask('zip', function (platform) { + grunt.registerTask('zip', function(platform) { var done = this.async() switch (platform) { case 'osx': - var execPath = 'cd dist/Boostnote-darwin-x64 && zip -r -y -q ../Boostnote-mac.zip Boostnote.app' + var execPath = + 'cd dist/Boostnote-darwin-x64 && zip -r -y -q ../Boostnote-mac.zip Boostnote.app' grunt.log.writeln(execPath) - ChildProcess.exec(execPath, - function (err, stdout, stderr) { - grunt.log.writeln(stdout) - if (err) { - grunt.log.writeln(err) - grunt.log.writeln(stderr) - done(false) - return - } - done() + ChildProcess.exec(execPath, function(err, stdout, stderr) { + grunt.log.writeln(stdout) + if (err) { + grunt.log.writeln(err) + grunt.log.writeln(stderr) + done(false) + return } - ) + done() + }) break default: done() @@ -242,7 +241,7 @@ module.exports = function (grunt) { } }) - function getTarget () { + function getTarget() { switch (process.platform) { case 'darwin': return 'osx' @@ -255,7 +254,7 @@ module.exports = function (grunt) { } } - grunt.registerTask('build', function (platform) { + grunt.registerTask('build', function(platform) { if (platform == null) platform = getTarget() switch (platform) { @@ -263,15 +262,26 @@ module.exports = function (grunt) { grunt.task.run(['compile', 'pack:win', 'create-windows-installer']) break case 'osx': - grunt.task.run(['compile', 'pack:osx', 'codesign', 'create-osx-installer', 'zip:osx']) + grunt.task.run([ + 'compile', + 'pack:osx', + 'codesign', + 'create-osx-installer', + 'zip:osx' + ]) break case 'linux': - grunt.task.run(['compile', 'pack:linux', 'electron-installer-debian', 'electron-installer-redhat']) + grunt.task.run([ + 'compile', + 'pack:linux', + 'electron-installer-debian', + 'electron-installer-redhat' + ]) break } }) - grunt.registerTask('pre-build', function (platform) { + grunt.registerTask('pre-build', function(platform) { if (platform == null) platform = getTarget() switch (platform) { @@ -286,11 +296,11 @@ module.exports = function (grunt) { } }) - grunt.registerTask('bfm', function () { + grunt.registerTask('bfm', function() { const Color = require('color') const parseCSS = require('css').parse - function generateRule (selector, bgColor, fgColor) { + function generateRule(selector, bgColor, fgColor) { if (bgColor.isLight()) { bgColor = bgColor.mix(fgColor, 0.05) } else { @@ -298,48 +308,79 @@ module.exports = function (grunt) { } if (selector && selector.length > 0) { - return `${selector} .cm-table-row-even { background-color: ${bgColor.rgb().string()}; }` + return `${selector} .cm-table-row-even { background-color: ${bgColor + .rgb() + .string()}; }` } else { - return `.cm-table-row-even { background-color: ${bgColor.rgb().string()}; }` + return `.cm-table-row-even { background-color: ${bgColor + .rgb() + .string()}; }` } } const root = path.join(__dirname, 'node_modules/codemirror/theme/') - const colors = fs.readdirSync(root).filter(file => file !== 'solarized.css').map(file => { - const css = parseCSS(fs.readFileSync(path.join(root, file), 'utf8')) + const colors = fs + .readdirSync(root) + .filter(file => file !== 'solarized.css') + .map(file => { + const css = parseCSS(fs.readFileSync(path.join(root, file), 'utf8')) - const rules = css.stylesheet.rules.filter(rule => rule.selectors && /\b\.CodeMirror$/.test(rule.selectors[0])) - if (rules.length === 1) { - let bgColor = Color('white') - let fgColor = Color('black') + const rules = css.stylesheet.rules.filter( + rule => rule.selectors && /\b\.CodeMirror$/.test(rule.selectors[0]) + ) + if (rules.length === 1) { + let bgColor = Color('white') + let fgColor = Color('black') - rules[0].declarations.forEach(declaration => { - if (declaration.property === 'background-color' || declaration.property === 'background') { - bgColor = Color(declaration.value.split(' ')[0]) - } else if (declaration.property === 'color') { - const value = /^(.*?)(?:\s*!important)?$/.exec(declaration.value)[1] - const match = /^rgba\((.*?),\s*1\)$/.exec(value) - if (match) { - fgColor = Color(`rgb(${match[1]})`) - } else { - fgColor = Color(value) + rules[0].declarations.forEach(declaration => { + if ( + declaration.property === 'background-color' || + declaration.property === 'background' + ) { + bgColor = Color(declaration.value.split(' ')[0]) + } else if (declaration.property === 'color') { + const value = /^(.*?)(?:\s*!important)?$/.exec( + declaration.value + )[1] + const match = /^rgba\((.*?),\s*1\)$/.exec(value) + if (match) { + fgColor = Color(`rgb(${match[1]})`) + } else { + fgColor = Color(value) + } } - } - }) + }) - return generateRule(rules[0].selectors[0], bgColor, fgColor) - } - }).filter(value => !!value) + return generateRule(rules[0].selectors[0], bgColor, fgColor) + } + }) + .filter(value => !!value) // default colors.unshift(generateRule(null, Color('white'), Color('black'))) // solarized dark - colors.push(generateRule('.cm-s-solarized.cm-s-dark', Color('#002b36'), Color('#839496'))) + colors.push( + generateRule( + '.cm-s-solarized.cm-s-dark', + Color('#002b36'), + Color('#839496') + ) + ) // solarized light - colors.push(generateRule('.cm-s-solarized.cm-s-light', Color('#fdf6e3'), Color('#657b83'))) + colors.push( + generateRule( + '.cm-s-solarized.cm-s-light', + Color('#fdf6e3'), + Color('#657b83') + ) + ) - fs.writeFileSync(path.join(__dirname, 'extra_scripts/codemirror/mode/bfm/bfm.css'), colors.join('\n'), 'utf8') + fs.writeFileSync( + path.join(__dirname, 'extra_scripts/codemirror/mode/bfm/bfm.css'), + colors.join('\n'), + 'utf8' + ) }) grunt.registerTask('default', ['build']) diff --git a/index.js b/index.js index 96f98e73..bcc4e879 100644 --- a/index.js +++ b/index.js @@ -4,30 +4,30 @@ const path = require('path') var error = null -function execMainApp () { +function execMainApp() { const appRootPath = path.join(process.execPath, '../..') const updateDotExePath = path.join(appRootPath, 'Update.exe') const exeName = path.basename(process.execPath) - function spawnUpdate (args, cb) { + function spawnUpdate(args, cb) { var stdout = '' var updateProcess = null try { updateProcess = ChildProcess.spawn(updateDotExePath, args) } catch (e) { - process.nextTick(function () { + process.nextTick(function() { cb(e) }) } - updateProcess.stdout.on('data', function (data) { + updateProcess.stdout.on('data', function(data) { stdout += data }) - updateProcess.on('error', function (_error) { + updateProcess.on('error', function(_error) { error = _error }) - updateProcess.on('close', function (code, signal) { + updateProcess.on('close', function(code, signal) { if (code !== 0) { error = new Error('Command failed: #{signal ? code}') error.code = code @@ -38,7 +38,7 @@ function execMainApp () { }) } - var handleStartupEvent = function () { + var handleStartupEvent = function() { if (process.platform !== 'win32') { return false } @@ -46,7 +46,7 @@ function execMainApp () { var squirrelCommand = process.argv[1] switch (squirrelCommand) { case '--squirrel-install': - spawnUpdate(['--createShortcut', exeName], function (err) { + spawnUpdate(['--createShortcut', exeName], function(err) { if (err) console.error(err) app.quit() }) @@ -55,7 +55,7 @@ function execMainApp () { app.quit() return true case '--squirrel-uninstall': - spawnUpdate(['--removeShortcut', exeName], function (err) { + spawnUpdate(['--removeShortcut', exeName], function(err) { if (err) console.error(err) app.quit() }) diff --git a/lib/ipcServer.js b/lib/ipcServer.js index 42e229d3..41d3ea7b 100644 --- a/lib/ipcServer.js +++ b/lib/ipcServer.js @@ -7,7 +7,7 @@ nodeIpc.config.id = 'node' nodeIpc.config.retry = 1500 nodeIpc.config.silent = true -function toggleMainWindow () { +function toggleMainWindow() { switch (global.process.platform) { case 'darwin': if (mainWindow.isFocused()) { @@ -52,14 +52,14 @@ ipcMain.on('config-renew', (e, payload) => { nodeIpc.serve( path.join(app.getPath('userData'), 'boostnote.service'), - function () { - nodeIpc.server.on('connect', function (socket) { + function() { + nodeIpc.server.on('connect', function(socket) { nodeIpc.log('ipc server >> socket joinned'.rainbow) - socket.on('close', function () { + socket.on('close', function() { nodeIpc.log('ipc server >> socket closed'.rainbow) }) }) - nodeIpc.server.on('error', function (err) { + nodeIpc.server.on('error', function(err) { nodeIpc.log('Node IPC error'.rainbow, err) }) } diff --git a/lib/main-app.js b/lib/main-app.js index f8ee1ecf..2293fd58 100644 --- a/lib/main-app.js +++ b/lib/main-app.js @@ -36,8 +36,9 @@ const updater = new GhReleases(ghReleasesOpts) // Check for updates // `status` returns true if there is a new update available -function checkUpdate () { - if (!isPackaged) { // Prevents app from attempting to update when in dev mode. +function checkUpdate() { + if (!isPackaged) { + // Prevents app from attempting to update when in dev mode. console.log('Updates are disabled in Development mode, see main-app.js') return true } @@ -58,29 +59,29 @@ function checkUpdate () { }) } -updater.on('update-downloaded', (info) => { +updater.on('update-downloaded', info => { if (mainWindow != null) { mainWindow.webContents.send('update-ready', 'Update available!') isUpdateReady = true } }) -updater.autoUpdater.on('error', (err) => { +updater.autoUpdater.on('error', err => { console.error(err) }) -ipc.on('update-app-confirm', function (event, msg) { +ipc.on('update-app-confirm', function(event, msg) { if (isUpdateReady) { mainWindow.removeAllListeners() updater.install() } }) -app.on('window-all-closed', function () { +app.on('window-all-closed', function() { app.quit() }) -app.on('ready', function () { +app.on('ready', function() { mainWindow = require('./main-window') var template = require('./main-menu') @@ -100,7 +101,7 @@ app.on('ready', function () { } // Check update every day - setInterval(function () { + setInterval(function() { if (isPackaged) checkUpdate() }, 1000 * 60 * 60 * 24) @@ -108,7 +109,7 @@ app.on('ready', function () { setTimeout(() => { if (isPackaged) checkUpdate() - ipc.on('update-check', function (event, msg) { + ipc.on('update-check', function(event, msg) { if (isUpdateReady) { mainWindow.webContents.send('update-ready', 'Update available!') } else { diff --git a/lib/main-menu.js b/lib/main-menu.js index 308a716c..7caef0bf 100644 --- a/lib/main-menu.js +++ b/lib/main-menu.js @@ -11,68 +11,68 @@ const LINUX = process.platform === 'linux' const boost = macOS ? { - label: 'Boostnote', - submenu: [ - { - label: 'About Boostnote', - selector: 'orderFrontStandardAboutPanel:' - }, - { - type: 'separator' - }, - { - label: 'Preferences', - accelerator: 'Command+,', - click () { - mainWindow.webContents.send('side:preferences') + label: 'Boostnote', + submenu: [ + { + label: 'About Boostnote', + selector: 'orderFrontStandardAboutPanel:' + }, + { + type: 'separator' + }, + { + label: 'Preferences', + accelerator: 'Command+,', + click() { + mainWindow.webContents.send('side:preferences') + } + }, + { + type: 'separator' + }, + { + label: 'Hide Boostnote', + accelerator: 'Command+H', + selector: 'hide:' + }, + { + label: 'Hide Others', + accelerator: 'Command+Shift+H', + selector: 'hideOtherApplications:' + }, + { + label: 'Show All', + selector: 'unhideAllApplications:' + }, + { + type: 'separator' + }, + { + label: 'Quit Boostnote', + role: 'quit', + accelerator: 'CommandOrControl+Q' } - }, - { - type: 'separator' - }, - { - label: 'Hide Boostnote', - accelerator: 'Command+H', - selector: 'hide:' - }, - { - label: 'Hide Others', - accelerator: 'Command+Shift+H', - selector: 'hideOtherApplications:' - }, - { - label: 'Show All', - selector: 'unhideAllApplications:' - }, - { - type: 'separator' - }, - { - label: 'Quit Boostnote', - role: 'quit', - accelerator: 'CommandOrControl+Q' - } - ] - } + ] + } : { - label: 'Boostnote', - submenu: [ - { - label: 'Preferences', - accelerator: 'Control+,', - click () { - mainWindow.webContents.send('side:preferences') + label: 'Boostnote', + submenu: [ + { + label: 'Preferences', + accelerator: 'Control+,', + click() { + mainWindow.webContents.send('side:preferences') + } + }, + { + type: 'separator' + }, + { + role: 'quit', + accelerator: 'Control+Q' } - }, - { - type: 'separator' - }, - { - role: 'quit', - accelerator: 'Control+Q' - } - ] - } + ] + } const file = { label: 'File', @@ -80,28 +80,28 @@ const file = { { label: 'New Note', accelerator: 'CommandOrControl+N', - click () { + click() { mainWindow.webContents.send('top:new-note') } }, { label: 'Focus Note', accelerator: 'CommandOrControl+E', - click () { + click() { mainWindow.webContents.send('detail:focus') } }, { label: 'Delete Note', accelerator: 'CommandOrControl+Shift+Backspace', - click () { + click() { mainWindow.webContents.send('detail:delete') } }, { label: 'Clone Note', accelerator: 'CommandOrControl+D', - click () { + click() { mainWindow.webContents.send('list:clone') } }, @@ -113,7 +113,7 @@ const file = { submenu: [ { label: 'Plain Text, MarkDown (.txt, .md)', - click () { + click() { mainWindow.webContents.send('import:file') } } @@ -124,28 +124,28 @@ const file = { submenu: [ { label: 'Plain Text (.txt)', - click () { + click() { mainWindow.webContents.send('list:isMarkdownNote', 'export-txt') mainWindow.webContents.send('export:save-text') } }, { label: 'MarkDown (.md)', - click () { + click() { mainWindow.webContents.send('list:isMarkdownNote', 'export-md') mainWindow.webContents.send('export:save-md') } }, { label: 'HTML (.html)', - click () { + click() { mainWindow.webContents.send('list:isMarkdownNote', 'export-html') mainWindow.webContents.send('export:save-html') } }, { label: 'PDF (.pdf)', - click () { + click() { mainWindow.webContents.send('list:isMarkdownNote', 'export-pdf') mainWindow.webContents.send('export:save-pdf') } @@ -158,13 +158,13 @@ const file = { { label: 'Generate/Update Markdown TOC', accelerator: 'Shift+Ctrl+T', - click () { + click() { mainWindow.webContents.send('code:generate-toc') } }, { label: 'Format Table', - click () { + click() { mainWindow.webContents.send('code:format-table') } }, @@ -174,7 +174,7 @@ const file = { { label: 'Print', accelerator: 'CommandOrControl+P', - click () { + click() { mainWindow.webContents.send('list:isMarkdownNote', 'print') mainWindow.webContents.send('print') } @@ -183,20 +183,25 @@ const file = { } if (LINUX) { - file.submenu.push({ - type: 'separator' - }, { - label: 'Preferences', - accelerator: 'Control+,', - click () { - mainWindow.webContents.send('side:preferences') + file.submenu.push( + { + type: 'separator' + }, + { + label: 'Preferences', + accelerator: 'Control+,', + click() { + mainWindow.webContents.send('side:preferences') + } + }, + { + type: 'separator' + }, + { + role: 'quit', + accelerator: 'Control+Q' } - }, { - type: 'separator' - }, { - role: 'quit', - accelerator: 'Control+Q' - }) + ) } const edit = { @@ -241,7 +246,7 @@ const edit = { { label: 'Add Tag', accelerator: 'CommandOrControl+Shift+T', - click () { + click() { mainWindow.webContents.send('editor:add-tag') } } @@ -254,14 +259,14 @@ const view = { { label: 'Reload', accelerator: 'CommandOrControl+R', - click () { + click() { BrowserWindow.getFocusedWindow().reload() } }, { label: 'Toggle Developer Tools', accelerator: 'CommandOrControl+Alt+I', - click () { + click() { BrowserWindow.getFocusedWindow().toggleDevTools() } }, @@ -271,14 +276,14 @@ const view = { { label: 'Next Note', accelerator: 'CommandOrControl+]', - click () { + click() { mainWindow.webContents.send('list:next') } }, { label: 'Previous Note', accelerator: 'CommandOrControl+[', - click () { + click() { mainWindow.webContents.send('list:prior') } }, @@ -288,7 +293,7 @@ const view = { { label: 'Focus Search', accelerator: 'CommandOrControl+Shift+L', - click () { + click() { mainWindow.webContents.send('top:focus-search') } }, @@ -298,14 +303,14 @@ const view = { { label: 'Toggle Full Screen', accelerator: macOS ? 'Command+Control+F' : 'F11', - click () { + click() { mainWindow.setFullScreen(!mainWindow.isFullScreen()) } }, { label: 'Toggle Side Bar', accelerator: 'CommandOrControl+B', - click () { + click() { mainWindow.webContents.send('editor:fullscreen') } }, @@ -315,21 +320,21 @@ const view = { { label: 'Actual Size', accelerator: 'CommandOrControl+0', - click () { + click() { mainWindow.webContents.send('status:zoomreset') } }, { label: 'Zoom In', accelerator: 'CommandOrControl+=', - click () { + click() { mainWindow.webContents.send('status:zoomin') } }, { label: 'Zoom Out', accelerator: 'CommandOrControl+-', - click () { + click() { mainWindow.webContents.send('status:zoomout') } } @@ -382,38 +387,58 @@ const help = { submenu: [ { label: 'Boostnote official site', - click () { shell.openExternal('https://boostnote.io/') } + click() { + shell.openExternal('https://boostnote.io/') + } }, { label: 'Wiki', - click () { shell.openExternal('https://github.com/BoostIO/Boostnote/wiki') } + click() { + shell.openExternal('https://github.com/BoostIO/Boostnote/wiki') + } }, { label: 'Issue Tracker', - click () { shell.openExternal('https://github.com/BoostIO/Boostnote/issues') } + click() { + shell.openExternal('https://github.com/BoostIO/Boostnote/issues') + } }, { label: 'Changelog', - click () { shell.openExternal('https://github.com/BoostIO/boost-releases') } + click() { + shell.openExternal('https://github.com/BoostIO/boost-releases') + } }, { label: 'Cheatsheets', submenu: [ { label: 'Markdown', - click () { shell.openExternal('https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet') } + click() { + shell.openExternal( + 'https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet' + ) + } }, { label: 'Latex', - click () { shell.openExternal('https://katex.org/docs/supported.html') } + click() { + shell.openExternal('https://katex.org/docs/supported.html') + } }, { label: 'HTML', - click () { shell.openExternal('https://htmlcheatsheet.com/') } + click() { + shell.openExternal('https://htmlcheatsheet.com/') + } }, { label: 'Boostnote', - click () { shell.openExternal('https://github.com/TobseF/boostnote-markdown-cheatsheet/blob/master/BOOSTNOTE_MARKDOWN_CHEAT_SHEET.md') } + click() { + shell.openExternal( + 'https://github.com/TobseF/boostnote-markdown-cheatsheet/blob/master/BOOSTNOTE_MARKDOWN_CHEAT_SHEET.md' + ) + } } ] }, @@ -422,7 +447,7 @@ const help = { }, { label: 'About', - click () { + click() { const version = electron.app.getVersion() const electronVersion = process.versions.electron const chromeVersion = process.versions.chrome @@ -430,20 +455,20 @@ const help = { 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}` - }) + electron.dialog.showMessageBox(BrowserWindow.getFocusedWindow(), { + title: 'BoostNote', + message: 'BoostNote', + type: 'info', + detail: `\n${detail}` + }) } } ] } -module.exports = process.platform === 'darwin' - ? [boost, file, edit, view, window, help] - : process.platform === 'win32' - ? [boost, file, view, help] - : [file, view, help] +module.exports = + process.platform === 'darwin' + ? [boost, file, edit, view, window, help] + : process.platform === 'win32' + ? [boost, file, view, help] + : [file, view, help] diff --git a/lib/main-window.js b/lib/main-window.js index 515dc8b4..e6b0cb29 100644 --- a/lib/main-window.js +++ b/lib/main-window.js @@ -54,12 +54,17 @@ const mainWindow = new BrowserWindow({ }, icon: path.resolve(__dirname, '../resources/app.png') }) -const url = path.resolve(__dirname, process.env.NODE_ENV === 'development' ? './main.development.html' : './main.production.html') +const url = path.resolve( + __dirname, + process.env.NODE_ENV === 'development' + ? './main.development.html' + : './main.production.html' +) mainWindow.loadURL('file://' + url) mainWindow.setMenuBarVisibility(false) -mainWindow.webContents.on('new-window', function (e) { +mainWindow.webContents.on('new-window', function(e) { e.preventDefault() }) @@ -74,10 +79,10 @@ mainWindow.webContents.sendInputEvent({ }) if (process.platform === 'darwin') { - mainWindow.on('close', function (e) { + mainWindow.on('close', function(e) { e.preventDefault() if (mainWindow.isFullScreen()) { - mainWindow.once('leave-full-screen', function () { + mainWindow.once('leave-full-screen', function() { mainWindow.hide() }) mainWindow.setFullScreen(false) @@ -86,7 +91,7 @@ if (process.platform === 'darwin') { } }) - app.on('before-quit', function (e) { + app.on('before-quit', function(e) { mainWindow.removeAllListeners() }) } @@ -94,7 +99,7 @@ if (process.platform === 'darwin') { mainWindow.on('resize', _.throttle(storeWindowSize, 500)) mainWindow.on('move', _.throttle(storeWindowSize, 500)) -function storeWindowSize () { +function storeWindowSize() { try { config.set('windowsize', mainWindow.getBounds()) } catch (e) { @@ -103,7 +108,7 @@ function storeWindowSize () { } } -app.on('activate', function () { +app.on('activate', function() { if (mainWindow == null) return null mainWindow.show() }) diff --git a/lib/touchbar-menu.js b/lib/touchbar-menu.js index 90a64410..b3696e13 100644 --- a/lib/touchbar-menu.js +++ b/lib/touchbar-menu.js @@ -1,5 +1,5 @@ -const {TouchBar} = require('electron') -const {TouchBarButton, TouchBarSpacer} = TouchBar +const { TouchBar } = require('electron') +const { TouchBarButton, TouchBarSpacer } = TouchBar const mainWindow = require('./main-window') const allNotes = new TouchBarButton({ @@ -35,7 +35,6 @@ module.exports = new TouchBar([ allNotes, starredNotes, trash, - new TouchBarSpacer({size: 'small'}), + new TouchBarSpacer({ size: 'small' }), newNote ]) - diff --git a/package.json b/package.json index acec8d5d..36a27c1d 100644 --- a/package.json +++ b/package.json @@ -152,9 +152,11 @@ "electron-debug": "^2.2.0", "electron-devtools-installer": "^2.2.4", "electron-packager": "^12.2.0", - "eslint": "^3.13.1", + "eslint": "^4.18.2", + "eslint-config-prettier": "^6.10.0", "eslint-config-standard": "^6.2.1", "eslint-config-standard-jsx": "^3.2.0", + "eslint-plugin-prettier": "^3.1.2", "eslint-plugin-react": "^7.8.2", "eslint-plugin-standard": "^3.0.1", "faker": "^3.1.0", diff --git a/tests/components/TagListItem.snapshot.test.js b/tests/components/TagListItem.snapshot.test.js index 637844e6..e128978d 100644 --- a/tests/components/TagListItem.snapshot.test.js +++ b/tests/components/TagListItem.snapshot.test.js @@ -3,7 +3,9 @@ import renderer from 'react-test-renderer' import TagListItem from 'browser/components/TagListItem' it('TagListItem renders correctly', () => { - const tagListItem = renderer.create() + const tagListItem = renderer.create( + + ) expect(tagListItem.toJSON()).toMatchSnapshot() }) diff --git a/tests/dataApi/addStorage.js b/tests/dataApi/addStorage.js index da39a993..81ddd5b3 100644 --- a/tests/dataApi/addStorage.js +++ b/tests/dataApi/addStorage.js @@ -6,7 +6,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const TestDummy = require('../fixtures/TestDummy') const sander = require('sander') @@ -18,24 +21,24 @@ const v1StoragePath = path.join(os.tmpdir(), 'test/addStorage-v1-storage') // const legacyStoragePath = path.join(os.tmpdir(), 'test/addStorage-legacy-storage') // const emptyDirPath = path.join(os.tmpdir(), 'test/addStorage-empty-storage') -test.beforeEach((t) => { +test.beforeEach(t => { t.context.v1StorageData = TestDummy.dummyStorage(v1StoragePath) // t.context.legacyStorageData = TestDummy.dummyLegacyStorage(legacyStoragePath) localStorage.setItem('storages', JSON.stringify([])) }) -test.serial('Add Storage', (t) => { +test.serial('Add Storage', t => { const input = { type: 'FILESYSTEM', name: 'add-storage1', path: v1StoragePath } return Promise.resolve() - .then(function doTest () { + .then(function doTest() { return addStorage(input) }) - .then(function validateResult (data) { + .then(function validateResult(data) { const { storage, notes } = data // Check data.storage @@ -48,18 +51,22 @@ test.serial('Add Storage', (t) => { // Check data.notes t.is(notes.length, t.context.v1StorageData.notes.length) - notes.forEach(function validateNote (note) { + notes.forEach(function validateNote(note) { t.is(note.storage, storage.key) }) // Check localStorage - const cacheData = _.find(JSON.parse(localStorage.getItem('storages')), {key: data.storage.key}) + const cacheData = _.find(JSON.parse(localStorage.getItem('storages')), { + key: data.storage.key + }) t.is(cacheData.name, input.name) t.is(cacheData.type, input.type) t.is(cacheData.path, input.path) // Check boostnote.json - const jsonData = CSON.readFileSync(path.join(storage.path, 'boostnote.json')) + const jsonData = CSON.readFileSync( + path.join(storage.path, 'boostnote.json') + ) t.true(_.isArray(jsonData.folders)) t.is(jsonData.version, '1.0') t.is(jsonData.folders.length, t.context.v1StorageData.json.folders.length) diff --git a/tests/dataApi/attachmentManagement.test.js b/tests/dataApi/attachmentManagement.test.js index 13dcedca..e49556ca 100644 --- a/tests/dataApi/attachmentManagement.test.js +++ b/tests/dataApi/attachmentManagement.test.js @@ -13,48 +13,71 @@ const sander = require('sander') const systemUnderTest = require('browser/main/lib/dataApi/attachmentManagement') -it('should test that copyAttachment should throw an error if sourcePath or storageKey or noteKey are undefined', function () { - systemUnderTest.copyAttachment(undefined, 'storageKey').then(() => {}, error => { - expect(error).toBe('sourceFilePath has to be given') - }) - systemUnderTest.copyAttachment(null, 'storageKey', 'noteKey').then(() => {}, error => { - expect(error).toBe('sourceFilePath has to be given') - }) - systemUnderTest.copyAttachment('source', undefined, 'noteKey').then(() => {}, error => { - expect(error).toBe('storageKey has to be given') - }) - systemUnderTest.copyAttachment('source', null, 'noteKey').then(() => {}, error => { - expect(error).toBe('storageKey has to be given') - }) - systemUnderTest.copyAttachment('source', 'storageKey', null).then(() => {}, error => { - expect(error).toBe('noteKey has to be given') - }) - systemUnderTest.copyAttachment('source', 'storageKey', undefined).then(() => {}, error => { - expect(error).toBe('noteKey has to be given') - }) +it('should test that copyAttachment should throw an error if sourcePath or storageKey or noteKey are undefined', function() { + systemUnderTest.copyAttachment(undefined, 'storageKey').then( + () => {}, + error => { + expect(error).toBe('sourceFilePath has to be given') + } + ) + systemUnderTest.copyAttachment(null, 'storageKey', 'noteKey').then( + () => {}, + error => { + expect(error).toBe('sourceFilePath has to be given') + } + ) + systemUnderTest.copyAttachment('source', undefined, 'noteKey').then( + () => {}, + error => { + expect(error).toBe('storageKey has to be given') + } + ) + systemUnderTest.copyAttachment('source', null, 'noteKey').then( + () => {}, + error => { + expect(error).toBe('storageKey has to be given') + } + ) + systemUnderTest.copyAttachment('source', 'storageKey', null).then( + () => {}, + error => { + expect(error).toBe('noteKey has to be given') + } + ) + systemUnderTest.copyAttachment('source', 'storageKey', undefined).then( + () => {}, + error => { + expect(error).toBe('noteKey has to be given') + } + ) }) -it('should test that copyAttachment should throw an error if sourcePath dosen\'t exists', function () { +it("should test that copyAttachment should throw an error if sourcePath dosen't exists", function() { fs.existsSync = jest.fn() fs.existsSync.mockReturnValue(false) - return systemUnderTest.copyAttachment('path', 'storageKey', 'noteKey').then(() => {}, error => { - expect(error).toBe('source file does not exist') - expect(fs.existsSync).toHaveBeenCalledWith('path') - }) + return systemUnderTest.copyAttachment('path', 'storageKey', 'noteKey').then( + () => {}, + error => { + expect(error).toBe('source file does not exist') + expect(fs.existsSync).toHaveBeenCalledWith('path') + } + ) }) -it('should test that copyAttachment works correctly assuming correct working of fs', function () { +it('should test that copyAttachment works correctly assuming correct working of fs', function() { const dummyExtension = '.ext' const sourcePath = 'path' + dummyExtension const storageKey = 'storageKey' const noteKey = 'noteKey' const dummyUniquePath = 'dummyPath' - const dummyStorage = {path: 'dummyStoragePath'} + const dummyStorage = { path: 'dummyStoragePath' } const dummyReadStream = {} dummyReadStream.pipe = jest.fn() - dummyReadStream.on = jest.fn((event, callback) => { callback() }) + dummyReadStream.on = jest.fn((event, callback) => { + callback() + }) fs.existsSync = jest.fn() fs.existsSync.mockReturnValue(true) fs.createReadStream = jest.fn(() => dummyReadStream) @@ -64,26 +87,43 @@ it('should test that copyAttachment works correctly assuming correct working of findStorage.findStorage.mockReturnValue(dummyStorage) uniqueSlug.mockReturnValue(dummyUniquePath) - return systemUnderTest.copyAttachment(sourcePath, storageKey, noteKey).then( - function (newFileName) { + return systemUnderTest + .copyAttachment(sourcePath, storageKey, noteKey) + .then(function(newFileName) { expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey) expect(fs.createReadStream).toHaveBeenCalledWith(sourcePath) expect(fs.existsSync).toHaveBeenCalledWith(sourcePath) expect(fs.createReadStream().pipe).toHaveBeenCalled() - expect(fs.createWriteStream).toHaveBeenCalledWith(path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, noteKey, dummyUniquePath + dummyExtension)) + expect(fs.createWriteStream).toHaveBeenCalledWith( + path.join( + dummyStorage.path, + systemUnderTest.DESTINATION_FOLDER, + noteKey, + dummyUniquePath + dummyExtension + ) + ) expect(newFileName).toBe(dummyUniquePath + dummyExtension) }) }) -it('should test that copyAttachment creates a new folder if the attachment folder doesn\'t exist', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it("should test that copyAttachment creates a new folder if the attachment folder doesn't exist", function() { + const dummyStorage = { path: 'dummyStoragePath' } const noteKey = 'noteKey' - const attachmentFolderPath = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER) - const attachmentFolderNoteKyPath = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, noteKey) + const attachmentFolderPath = path.join( + dummyStorage.path, + systemUnderTest.DESTINATION_FOLDER + ) + const attachmentFolderNoteKyPath = path.join( + dummyStorage.path, + systemUnderTest.DESTINATION_FOLDER, + noteKey + ) const dummyReadStream = {} dummyReadStream.pipe = jest.fn() - dummyReadStream.on = jest.fn((event, callback) => { callback() }) + dummyReadStream.on = jest.fn((event, callback) => { + callback() + }) fs.createReadStream = jest.fn(() => dummyReadStream) fs.existsSync = jest.fn() fs.existsSync.mockReturnValueOnce(true) @@ -95,8 +135,9 @@ it('should test that copyAttachment creates a new folder if the attachment folde findStorage.findStorage.mockReturnValue(dummyStorage) uniqueSlug.mockReturnValue('dummyPath') - return systemUnderTest.copyAttachment('path', 'storageKey', 'noteKey').then( - function () { + return systemUnderTest + .copyAttachment('path', 'storageKey', 'noteKey') + .then(function() { expect(fs.existsSync).toHaveBeenCalledWith(attachmentFolderPath) expect(fs.mkdirSync).toHaveBeenCalledWith(attachmentFolderPath) expect(fs.existsSync).toHaveBeenLastCalledWith(attachmentFolderNoteKyPath) @@ -104,12 +145,14 @@ it('should test that copyAttachment creates a new folder if the attachment folde }) }) -it('should test that copyAttachment don\'t uses a random file name if not intended ', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it("should test that copyAttachment don't uses a random file name if not intended ", function() { + const dummyStorage = { path: 'dummyStoragePath' } const dummyReadStream = {} dummyReadStream.pipe = jest.fn() - dummyReadStream.on = jest.fn((event, callback) => { callback() }) + dummyReadStream.on = jest.fn((event, callback) => { + callback() + }) fs.createReadStream = jest.fn(() => dummyReadStream) fs.existsSync = jest.fn() fs.existsSync.mockReturnValueOnce(true) @@ -120,23 +163,28 @@ it('should test that copyAttachment don\'t uses a random file name if not intend findStorage.findStorage.mockReturnValue(dummyStorage) uniqueSlug.mockReturnValue('dummyPath') - return systemUnderTest.copyAttachment('path', 'storageKey', 'noteKey', false).then( - function (newFileName) { + return systemUnderTest + .copyAttachment('path', 'storageKey', 'noteKey', false) + .then(function(newFileName) { expect(newFileName).toBe('path') }) }) -it('should test that copyAttachment with url (with extension, without query)', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that copyAttachment with url (with extension, without query)', function() { + const dummyStorage = { path: 'dummyStoragePath' } const dummyReadStream = { pipe: jest.fn(), - on: jest.fn((event, callback) => { callback() }) + on: jest.fn((event, callback) => { + callback() + }) } fs.createReadStream = jest.fn(() => dummyReadStream) const dummyWriteStream = { - write: jest.fn((data, callback) => { callback() }) + write: jest.fn((data, callback) => { + callback() + }) } fs.createWriteStream = jest.fn(() => dummyWriteStream) @@ -155,23 +203,28 @@ it('should test that copyAttachment with url (with extension, without query)', f data: 'data:image/jpeg;base64,Ym9vc3Rub3Rl' } - return systemUnderTest.copyAttachment(sourcePath, 'storageKey', 'noteKey').then( - function (newFileName) { + return systemUnderTest + .copyAttachment(sourcePath, 'storageKey', 'noteKey') + .then(function(newFileName) { expect(newFileName).toBe('dummyPath.jpg') }) }) -it('should test that copyAttachment with url (with extension, with query)', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that copyAttachment with url (with extension, with query)', function() { + const dummyStorage = { path: 'dummyStoragePath' } const dummyReadStream = { pipe: jest.fn(), - on: jest.fn((event, callback) => { callback() }) + on: jest.fn((event, callback) => { + callback() + }) } fs.createReadStream = jest.fn(() => dummyReadStream) const dummyWriteStream = { - write: jest.fn((data, callback) => { callback() }) + write: jest.fn((data, callback) => { + callback() + }) } fs.createWriteStream = jest.fn(() => dummyWriteStream) @@ -190,23 +243,28 @@ it('should test that copyAttachment with url (with extension, with query)', func data: 'data:image/jpeg;base64,Ym9vc3Rub3Rl' } - return systemUnderTest.copyAttachment(sourcePath, 'storageKey', 'noteKey').then( - function (newFileName) { + return systemUnderTest + .copyAttachment(sourcePath, 'storageKey', 'noteKey') + .then(function(newFileName) { expect(newFileName).toBe('dummyPath.jpg') }) }) -it('should test that copyAttachment with url (without extension, without query)', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that copyAttachment with url (without extension, without query)', function() { + const dummyStorage = { path: 'dummyStoragePath' } const dummyReadStream = { pipe: jest.fn(), - on: jest.fn((event, callback) => { callback() }) + on: jest.fn((event, callback) => { + callback() + }) } fs.createReadStream = jest.fn(() => dummyReadStream) const dummyWriteStream = { - write: jest.fn((data, callback) => { callback() }) + write: jest.fn((data, callback) => { + callback() + }) } fs.createWriteStream = jest.fn(() => dummyWriteStream) @@ -225,23 +283,28 @@ it('should test that copyAttachment with url (without extension, without query)' data: 'data:image/jpeg;base64,Ym9vc3Rub3Rl' } - return systemUnderTest.copyAttachment(sourcePath, 'storageKey', 'noteKey').then( - function (newFileName) { + return systemUnderTest + .copyAttachment(sourcePath, 'storageKey', 'noteKey') + .then(function(newFileName) { expect(newFileName).toBe('dummyPath.png') }) }) -it('should test that copyAttachment with url (without extension, with query)', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that copyAttachment with url (without extension, with query)', function() { + const dummyStorage = { path: 'dummyStoragePath' } const dummyReadStream = { pipe: jest.fn(), - on: jest.fn((event, callback) => { callback() }) + on: jest.fn((event, callback) => { + callback() + }) } fs.createReadStream = jest.fn(() => dummyReadStream) const dummyWriteStream = { - write: jest.fn((data, callback) => { callback() }) + write: jest.fn((data, callback) => { + callback() + }) } fs.createWriteStream = jest.fn(() => dummyWriteStream) @@ -260,13 +323,14 @@ it('should test that copyAttachment with url (without extension, with query)', f data: 'data:image/jpeg;base64,Ym9vc3Rub3Rl' } - return systemUnderTest.copyAttachment(sourcePath, 'storageKey', 'noteKey').then( - function (newFileName) { + return systemUnderTest + .copyAttachment(sourcePath, 'storageKey', 'noteKey') + .then(function(newFileName) { expect(newFileName).toBe('dummyPath.png') }) }) -it('should replace the all ":storage" path with the actual storage path', function () { +it('should replace the all ":storage" path with the actual storage path', function() { const storageFolder = systemUnderTest.DESTINATION_FOLDER const noteKey = '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' const testInput = @@ -277,21 +341,41 @@ 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' + ' \n' + '' @@ -304,21 +388,56 @@ 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' + ' \n' + '' @@ -326,7 +445,7 @@ it('should replace the all ":storage" path with the actual storage path', functi expect(actual).toEqual(expectedOutput) }) -it('should replace the ":storage" path with the actual storage path when they have different path separators', function () { +it('should replace the ":storage" path with the actual storage path when they have different path separators', function() { const storageFolder = systemUnderTest.DESTINATION_FOLDER const noteKey = '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' const testInput = @@ -337,10 +456,18 @@ 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' + '' @@ -353,10 +480,24 @@ 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' + '' @@ -364,7 +505,7 @@ it('should replace the ":storage" path with the actual storage path when they ha expect(actual).toEqual(expectedOutput) }) -it('should test that generateAttachmentMarkdown works correct both with previews and without', function () { +it('should test that generateAttachmentMarkdown works correct both with previews and without', function() { const fileName = 'fileName' const path = 'path' let expected = `![${fileName}](${path})` @@ -375,55 +516,133 @@ it('should test that generateAttachmentMarkdown works correct both with previews expect(actual).toEqual(expected) }) -it('should test that migrateAttachments work when they have different path separators', function () { +it('should test that migrateAttachments work when they have different path separators', function() { sander.existsSync = jest.fn(() => true) const dummyStoragePath = 'dummyStoragePath' const imagesPath = path.join(dummyStoragePath, 'images') const attachmentsPath = path.join(dummyStoragePath, 'attachments') const noteKey = 'noteKey' - const testInput = '"# Test\n' + - '\n' + - '![Screenshot1](:storage' + path.win32.sep + '0.3b88d0dc.png)\n' + - '![Screenshot2](:storage' + path.posix.sep + '0.2cb8875c.pdf)"' + const testInput = + '"# Test\n' + + '\n' + + '![Screenshot1](:storage' + + path.win32.sep + + '0.3b88d0dc.png)\n' + + '![Screenshot2](:storage' + + path.posix.sep + + '0.2cb8875c.pdf)"' systemUnderTest.migrateAttachments(testInput, dummyStoragePath, noteKey) expect(sander.existsSync.mock.calls[0][0]).toBe(imagesPath) - expect(sander.existsSync.mock.calls[1][0]).toBe(path.join(imagesPath, '0.3b88d0dc.png')) - expect(sander.existsSync.mock.calls[2][0]).toBe(path.join(attachmentsPath, '0.3b88d0dc.png')) - expect(sander.existsSync.mock.calls[3][0]).toBe(path.join(imagesPath, '0.2cb8875c.pdf')) - expect(sander.existsSync.mock.calls[4][0]).toBe(path.join(attachmentsPath, '0.2cb8875c.pdf')) + expect(sander.existsSync.mock.calls[1][0]).toBe( + path.join(imagesPath, '0.3b88d0dc.png') + ) + expect(sander.existsSync.mock.calls[2][0]).toBe( + path.join(attachmentsPath, '0.3b88d0dc.png') + ) + expect(sander.existsSync.mock.calls[3][0]).toBe( + path.join(imagesPath, '0.2cb8875c.pdf') + ) + expect(sander.existsSync.mock.calls[4][0]).toBe( + path.join(attachmentsPath, '0.2cb8875c.pdf') + ) }) -it('should test that getAttachmentsInMarkdownContent finds all attachments when they have different path separators', function () { - const testInput = '"# Test\n' + +it('should test that getAttachmentsInMarkdownContent finds all attachments when they have different path separators', function() { + const testInput = + '"# Test\n' + '\n' + - '![Screenshot1](:storage' + path.win32.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.win32.sep + '0.3b88d0dc.png)\n' + - '![Screenshot2](:storage' + path.posix.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.posix.sep + '2cb8875c.pdf)\n' + - '![Screenshot3](:storage' + path.win32.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.posix.sep + 'bbf49b02.jpg)"' + '![Screenshot1](:storage' + + path.win32.sep + + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + + path.win32.sep + + '0.3b88d0dc.png)\n' + + '![Screenshot2](:storage' + + path.posix.sep + + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + + path.posix.sep + + '2cb8875c.pdf)\n' + + '![Screenshot3](:storage' + + path.win32.sep + + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + + path.posix.sep + + 'bbf49b02.jpg)"' const actual = systemUnderTest.getAttachmentsInMarkdownContent(testInput) - const expected = [':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.3b88d0dc.png', ':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '2cb8875c.pdf', ':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + 'bbf49b02.jpg'] + const expected = [ + ':storage' + + path.sep + + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + + path.sep + + '0.3b88d0dc.png', + ':storage' + + path.sep + + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + + path.sep + + '2cb8875c.pdf', + ':storage' + + path.sep + + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + + path.sep + + 'bbf49b02.jpg' + ] expect(actual).toEqual(expect.arrayContaining(expected)) }) -it('should test that getAbsolutePathsOfAttachmentsInContent returns all absolute paths', function () { +it('should test that getAbsolutePathsOfAttachmentsInContent returns all absolute paths', function() { const dummyStoragePath = 'dummyStoragePath' const noteKey = '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' - const testInput = '"# Test\n' + + const testInput = + '"# Test\n' + '\n' + - '![Screenshot1](:storage' + path.win32.sep + noteKey + path.win32.sep + '0.6r4zdgc22xp.png)\n' + - '![Screenshot2](:storage' + path.posix.sep + noteKey + path.posix.sep + '0.q2i4iw0fyx.pdf)\n' + - '![Screenshot3](:storage' + path.win32.sep + noteKey + path.posix.sep + 'd6c5ee92.jpg)"' + '![Screenshot1](:storage' + + path.win32.sep + + noteKey + + path.win32.sep + + '0.6r4zdgc22xp.png)\n' + + '![Screenshot2](:storage' + + path.posix.sep + + noteKey + + path.posix.sep + + '0.q2i4iw0fyx.pdf)\n' + + '![Screenshot3](:storage' + + path.win32.sep + + noteKey + + path.posix.sep + + 'd6c5ee92.jpg)"' - const actual = systemUnderTest.getAbsolutePathsOfAttachmentsInContent(testInput, dummyStoragePath) - const expected = [dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + noteKey + path.sep + '0.6r4zdgc22xp.png', - dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + noteKey + path.sep + '0.q2i4iw0fyx.pdf', - dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + noteKey + path.sep + 'd6c5ee92.jpg'] + const actual = systemUnderTest.getAbsolutePathsOfAttachmentsInContent( + testInput, + dummyStoragePath + ) + const expected = [ + dummyStoragePath + + path.sep + + systemUnderTest.DESTINATION_FOLDER + + path.sep + + noteKey + + path.sep + + '0.6r4zdgc22xp.png', + dummyStoragePath + + path.sep + + systemUnderTest.DESTINATION_FOLDER + + path.sep + + noteKey + + path.sep + + '0.q2i4iw0fyx.pdf', + dummyStoragePath + + path.sep + + systemUnderTest.DESTINATION_FOLDER + + path.sep + + noteKey + + path.sep + + 'd6c5ee92.jpg' + ] expect(actual).toEqual(expect.arrayContaining(expected)) }) -it('should remove the all ":storage" and noteKey references', function () { +it('should remove the all ":storage" and noteKey references', function() { const storageFolder = systemUnderTest.DESTINATION_FOLDER const noteKey = 'noteKey' const testInput = @@ -434,13 +653,25 @@ it('should remove the all ":storage" and noteKey references', function () { ' \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' + '' @@ -452,62 +683,107 @@ it('should remove the all ":storage" and noteKey references', function () { ' \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' + '' - const actual = systemUnderTest.removeStorageAndNoteReferences(testInput, noteKey) + const actual = systemUnderTest.removeStorageAndNoteReferences( + testInput, + noteKey + ) expect(actual).toEqual(expectedOutput) }) -it('should make sure that "removeStorageAndNoteReferences" works with markdown content as well', function () { +it('should make sure that "removeStorageAndNoteReferences" works with markdown content as well', function() { const noteKey = 'noteKey' const testInput = 'Test input' + - '![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + noteKey + path.win32.sep + 'image.jpg](imageName}) \n' + - '[' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + noteKey + path.posix.sep + 'pdf.pdf](pdf})' + '![' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + noteKey + + path.win32.sep + + 'image.jpg](imageName}) \n' + + '[' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + noteKey + + path.posix.sep + + 'pdf.pdf](pdf})' const expectedOutput = 'Test input' + - '![' + systemUnderTest.DESTINATION_FOLDER + path.sep + 'image.jpg](imageName}) \n' + - '[' + systemUnderTest.DESTINATION_FOLDER + path.sep + 'pdf.pdf](pdf})' - const actual = systemUnderTest.removeStorageAndNoteReferences(testInput, noteKey) + '![' + + systemUnderTest.DESTINATION_FOLDER + + path.sep + + 'image.jpg](imageName}) \n' + + '[' + + systemUnderTest.DESTINATION_FOLDER + + path.sep + + 'pdf.pdf](pdf})' + const actual = systemUnderTest.removeStorageAndNoteReferences( + testInput, + noteKey + ) expect(actual).toEqual(expectedOutput) }) -it('should delete the correct attachment folder if a note is deleted', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should delete the correct attachment folder if a note is deleted', function() { + const dummyStorage = { path: 'dummyStoragePath' } const storageKey = 'storageKey' const noteKey = 'noteKey' findStorage.findStorage = jest.fn(() => dummyStorage) sander.rimrafSync = jest.fn() - const expectedPathToBeDeleted = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, noteKey) + const expectedPathToBeDeleted = path.join( + dummyStorage.path, + systemUnderTest.DESTINATION_FOLDER, + noteKey + ) systemUnderTest.deleteAttachmentFolder(storageKey, noteKey) expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey) expect(sander.rimrafSync).toHaveBeenCalledWith(expectedPathToBeDeleted) }) -it('should test that deleteAttachmentsNotPresentInNote deletes all unreferenced attachments ', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that deleteAttachmentsNotPresentInNote deletes all unreferenced attachments ', function() { + const dummyStorage = { path: 'dummyStoragePath' } const noteKey = 'noteKey' const storageKey = 'storageKey' const markdownContent = '' const dummyFilesInFolder = ['file1.txt', 'file2.pdf', 'file3.jpg'] - const attachmentFolderPath = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, noteKey) + const attachmentFolderPath = path.join( + dummyStorage.path, + systemUnderTest.DESTINATION_FOLDER, + noteKey + ) findStorage.findStorage = jest.fn(() => dummyStorage) fs.existsSync = jest.fn(() => true) - fs.readdir = jest.fn((paht, callback) => callback(undefined, dummyFilesInFolder)) + fs.readdir = jest.fn((paht, callback) => + callback(undefined, dummyFilesInFolder) + ) fs.unlink = jest.fn() - systemUnderTest.deleteAttachmentsNotPresentInNote(markdownContent, storageKey, noteKey) + systemUnderTest.deleteAttachmentsNotPresentInNote( + markdownContent, + storageKey, + noteKey + ) expect(fs.existsSync).toHaveBeenLastCalledWith(attachmentFolderPath) expect(fs.readdir).toHaveBeenCalledTimes(1) expect(fs.readdir.mock.calls[0][0]).toBe(attachmentFolderPath) @@ -518,35 +794,59 @@ it('should test that deleteAttachmentsNotPresentInNote deletes all unreferenced fsUnlinkCallArguments.push(fs.unlink.mock.calls[i][0]) } - dummyFilesInFolder.forEach(function (file) { - expect(fsUnlinkCallArguments.includes(path.join(attachmentFolderPath, file))).toBe(true) + dummyFilesInFolder.forEach(function(file) { + expect( + fsUnlinkCallArguments.includes(path.join(attachmentFolderPath, file)) + ).toBe(true) }) }) -it('should test that deleteAttachmentsNotPresentInNote does not delete referenced attachments', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that deleteAttachmentsNotPresentInNote does not delete referenced attachments', function() { + const dummyStorage = { path: 'dummyStoragePath' } const noteKey = 'noteKey' const storageKey = 'storageKey' const dummyFilesInFolder = ['file1.txt', 'file2.pdf', 'file3.jpg'] - const markdownContent = systemUnderTest.generateAttachmentMarkdown('fileLabel', path.join(systemUnderTest.STORAGE_FOLDER_PLACEHOLDER, noteKey, dummyFilesInFolder[0]), false) - const attachmentFolderPath = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, noteKey) + const markdownContent = systemUnderTest.generateAttachmentMarkdown( + 'fileLabel', + path.join( + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER, + noteKey, + dummyFilesInFolder[0] + ), + false + ) + const attachmentFolderPath = path.join( + dummyStorage.path, + systemUnderTest.DESTINATION_FOLDER, + noteKey + ) findStorage.findStorage = jest.fn(() => dummyStorage) fs.existsSync = jest.fn(() => true) - fs.readdir = jest.fn((paht, callback) => callback(undefined, dummyFilesInFolder)) + fs.readdir = jest.fn((paht, callback) => + callback(undefined, dummyFilesInFolder) + ) fs.unlink = jest.fn() - systemUnderTest.deleteAttachmentsNotPresentInNote(markdownContent, storageKey, noteKey) + systemUnderTest.deleteAttachmentsNotPresentInNote( + markdownContent, + storageKey, + noteKey + ) expect(fs.unlink).toHaveBeenCalledTimes(dummyFilesInFolder.length - 1) const fsUnlinkCallArguments = [] for (let i = 0; i < dummyFilesInFolder.length - 1; i++) { fsUnlinkCallArguments.push(fs.unlink.mock.calls[i][0]) } - expect(fsUnlinkCallArguments.includes(path.join(attachmentFolderPath, dummyFilesInFolder[0]))).toBe(false) + expect( + fsUnlinkCallArguments.includes( + path.join(attachmentFolderPath, dummyFilesInFolder[0]) + ) + ).toBe(false) }) -it('should test that deleteAttachmentsNotPresentInNote does nothing if noteKey, storageKey or noteContent was null', function () { +it('should test that deleteAttachmentsNotPresentInNote does nothing if noteKey, storageKey or noteContent was null', function() { const noteKey = null const storageKey = null const markdownContent = '' @@ -556,13 +856,17 @@ it('should test that deleteAttachmentsNotPresentInNote does nothing if noteKey, fs.readdir = jest.fn() fs.unlink = jest.fn() - systemUnderTest.deleteAttachmentsNotPresentInNote(markdownContent, storageKey, noteKey) + systemUnderTest.deleteAttachmentsNotPresentInNote( + markdownContent, + storageKey, + noteKey + ) expect(fs.existsSync).not.toHaveBeenCalled() expect(fs.readdir).not.toHaveBeenCalled() expect(fs.unlink).not.toHaveBeenCalled() }) -it('should test that deleteAttachmentsNotPresentInNote does nothing if noteKey, storageKey or noteContent was undefined', function () { +it('should test that deleteAttachmentsNotPresentInNote does nothing if noteKey, storageKey or noteContent was undefined', function() { const noteKey = undefined const storageKey = undefined const markdownContent = '' @@ -572,47 +876,70 @@ it('should test that deleteAttachmentsNotPresentInNote does nothing if noteKey, fs.readdir = jest.fn() fs.unlink = jest.fn() - systemUnderTest.deleteAttachmentsNotPresentInNote(markdownContent, storageKey, noteKey) + systemUnderTest.deleteAttachmentsNotPresentInNote( + markdownContent, + storageKey, + noteKey + ) expect(fs.existsSync).not.toHaveBeenCalled() expect(fs.readdir).not.toHaveBeenCalled() expect(fs.unlink).not.toHaveBeenCalled() }) -it('should test that getAttachmentsPathAndStatus return null if noteKey, storageKey or noteContent was undefined', function () { +it('should test that getAttachmentsPathAndStatus return null if noteKey, storageKey or noteContent was undefined', function() { const noteKey = undefined const storageKey = undefined const markdownContent = '' - const result = systemUnderTest.getAttachmentsPathAndStatus(markdownContent, storageKey, noteKey) + const result = systemUnderTest.getAttachmentsPathAndStatus( + markdownContent, + storageKey, + noteKey + ) expect(result).toBeNull() }) -it('should test that getAttachmentsPathAndStatus return null if noteKey, storageKey or noteContent was null', function () { +it('should test that getAttachmentsPathAndStatus return null if noteKey, storageKey or noteContent was null', function() { const noteKey = null const storageKey = null const markdownContent = '' - const result = systemUnderTest.getAttachmentsPathAndStatus(markdownContent, storageKey, noteKey) + const result = systemUnderTest.getAttachmentsPathAndStatus( + markdownContent, + storageKey, + noteKey + ) expect(result).toBeNull() }) -it('should test that getAttachmentsPathAndStatus return the correct path and status for attachments', async function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that getAttachmentsPathAndStatus return the correct path and status for attachments', async function() { + const dummyStorage = { path: 'dummyStoragePath' } const noteKey = 'noteKey' const storageKey = 'storageKey' const markdownContent = 'Test input' + - '![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + noteKey + path.win32.sep + 'file2.pdf](file2.pdf) \n' + '![' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + noteKey + + path.win32.sep + + 'file2.pdf](file2.pdf) \n' const dummyFilesInFolder = ['file1.txt', 'file2.pdf', 'file3.jpg'] findStorage.findStorage = jest.fn(() => dummyStorage) fs.existsSync = jest.fn(() => true) - fs.readdir = jest.fn((paht, callback) => callback(undefined, dummyFilesInFolder)) + fs.readdir = jest.fn((paht, callback) => + callback(undefined, dummyFilesInFolder) + ) fs.unlink = jest.fn() const targetStorage = findStorage.findStorage(storageKey) - const attachments = await systemUnderTest.getAttachmentsPathAndStatus(markdownContent, storageKey, noteKey) + const attachments = await systemUnderTest.getAttachmentsPathAndStatus( + markdownContent, + storageKey, + noteKey + ) expect(attachments.length).toBe(3) expect(attachments[0].isInUse).toBe(false) expect(attachments[1].isInUse).toBe(true) @@ -644,7 +971,7 @@ it('should test that getAttachmentsPathAndStatus return the correct path and sta ) }) -it('should test that moveAttachments moves attachments only if the source folder existed', function () { +it('should test that moveAttachments moves attachments only if the source folder existed', function() { fse.existsSync = jest.fn(() => false) fse.moveSync = jest.fn() @@ -654,14 +981,24 @@ it('should test that moveAttachments moves attachments only if the source folder const newNoteKey = 'newNoteKey' const content = '' - const expectedSource = path.join(oldPath, systemUnderTest.DESTINATION_FOLDER, oldNoteKey) + const expectedSource = path.join( + oldPath, + systemUnderTest.DESTINATION_FOLDER, + oldNoteKey + ) - systemUnderTest.moveAttachments(oldPath, newPath, oldNoteKey, newNoteKey, content) + systemUnderTest.moveAttachments( + oldPath, + newPath, + oldNoteKey, + newNoteKey, + content + ) expect(fse.existsSync).toHaveBeenCalledWith(expectedSource) expect(fse.moveSync).not.toHaveBeenCalled() }) -it('should test that moveAttachments moves attachments to the right destination', function () { +it('should test that moveAttachments moves attachments to the right destination', function() { fse.existsSync = jest.fn(() => true) fse.moveSync = jest.fn() @@ -671,15 +1008,29 @@ it('should test that moveAttachments moves attachments to the right destination' const newNoteKey = 'newNoteKey' const content = '' - const expectedSource = path.join(oldPath, systemUnderTest.DESTINATION_FOLDER, oldNoteKey) - const expectedDestination = path.join(newPath, systemUnderTest.DESTINATION_FOLDER, newNoteKey) + const expectedSource = path.join( + oldPath, + systemUnderTest.DESTINATION_FOLDER, + oldNoteKey + ) + const expectedDestination = path.join( + newPath, + systemUnderTest.DESTINATION_FOLDER, + newNoteKey + ) - systemUnderTest.moveAttachments(oldPath, newPath, oldNoteKey, newNoteKey, content) + systemUnderTest.moveAttachments( + oldPath, + newPath, + oldNoteKey, + newNoteKey, + content + ) expect(fse.existsSync).toHaveBeenCalledWith(expectedSource) expect(fse.moveSync).toHaveBeenCalledWith(expectedSource, expectedDestination) }) -it('should test that moveAttachments returns a correct modified content version', function () { +it('should test that moveAttachments returns a correct modified content version', function() { fse.existsSync = jest.fn() fse.moveSync = jest.fn() @@ -689,63 +1040,159 @@ it('should test that moveAttachments returns a correct modified content version' const newNoteKey = 'newNoteKey' const testInput = 'Test input' + - '![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + oldNoteKey + path.win32.sep + 'image.jpg](imageName}) \n' + - '[' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + oldNoteKey + path.posix.sep + 'pdf.pdf](pdf})' + '![' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + oldNoteKey + + path.win32.sep + + 'image.jpg](imageName}) \n' + + '[' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + oldNoteKey + + path.posix.sep + + 'pdf.pdf](pdf})' const expectedOutput = 'Test input' + - '![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNoteKey + path.sep + 'image.jpg](imageName}) \n' + - '[' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNoteKey + path.sep + 'pdf.pdf](pdf})' + '![' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.sep + + newNoteKey + + path.sep + + 'image.jpg](imageName}) \n' + + '[' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.sep + + newNoteKey + + path.sep + + 'pdf.pdf](pdf})' - const actualContent = systemUnderTest.moveAttachments(oldPath, newPath, oldNoteKey, newNoteKey, testInput) + const actualContent = systemUnderTest.moveAttachments( + oldPath, + newPath, + oldNoteKey, + newNoteKey, + testInput + ) expect(actualContent).toBe(expectedOutput) }) -it('should test that cloneAttachments modifies the content of the new note correctly', function () { - const oldNote = {key: 'oldNoteKey', content: 'oldNoteContent', storage: 'storageKey', type: 'MARKDOWN_NOTE'} - const newNote = {key: 'newNoteKey', content: 'oldNoteContent', storage: 'storageKey', type: 'MARKDOWN_NOTE'} +it('should test that cloneAttachments modifies the content of the new note correctly', function() { + const oldNote = { + key: 'oldNoteKey', + content: 'oldNoteContent', + storage: 'storageKey', + type: 'MARKDOWN_NOTE' + } + const newNote = { + key: 'newNoteKey', + content: 'oldNoteContent', + storage: 'storageKey', + type: 'MARKDOWN_NOTE' + } const testInput = 'Test input' + - '![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + oldNote.key + path.win32.sep + 'image.jpg](imageName}) \n' + - '[' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + oldNote.key + path.posix.sep + 'pdf.pdf](pdf})' + '![' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + oldNote.key + + path.win32.sep + + 'image.jpg](imageName}) \n' + + '[' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + oldNote.key + + path.posix.sep + + 'pdf.pdf](pdf})' newNote.content = testInput findStorage.findStorage = jest.fn() - findStorage.findStorage.mockReturnValue({path: 'dummyStoragePath'}) + findStorage.findStorage.mockReturnValue({ path: 'dummyStoragePath' }) const expectedOutput = 'Test input' + - '![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNote.key + path.sep + 'image.jpg](imageName}) \n' + - '[' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNote.key + path.sep + 'pdf.pdf](pdf})' + '![' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.sep + + newNote.key + + path.sep + + 'image.jpg](imageName}) \n' + + '[' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.sep + + newNote.key + + path.sep + + 'pdf.pdf](pdf})' systemUnderTest.cloneAttachments(oldNote, newNote) expect(newNote.content).toBe(expectedOutput) }) -it('should test that cloneAttachments finds all attachments and copies them to the new location', function () { +it('should test that cloneAttachments finds all attachments and copies them to the new location', function() { const storagePathOld = 'storagePathOld' const storagePathNew = 'storagePathNew' - const dummyStorageOld = {path: storagePathOld} - const dummyStorageNew = {path: storagePathNew} - const oldNote = {key: 'oldNoteKey', content: 'oldNoteContent', storage: 'storageKeyOldNote', type: 'MARKDOWN_NOTE'} - const newNote = {key: 'newNoteKey', content: 'oldNoteContent', storage: 'storageKeyNewNote', type: 'MARKDOWN_NOTE'} + const dummyStorageOld = { path: storagePathOld } + const dummyStorageNew = { path: storagePathNew } + const oldNote = { + key: 'oldNoteKey', + content: 'oldNoteContent', + storage: 'storageKeyOldNote', + type: 'MARKDOWN_NOTE' + } + const newNote = { + key: 'newNoteKey', + content: 'oldNoteContent', + storage: 'storageKeyNewNote', + type: 'MARKDOWN_NOTE' + } const testInput = 'Test input' + - '![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + oldNote.key + path.win32.sep + 'image.jpg](imageName}) \n' + - '[' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + oldNote.key + path.posix.sep + 'pdf.pdf](pdf})' + '![' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + oldNote.key + + path.win32.sep + + 'image.jpg](imageName}) \n' + + '[' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + oldNote.key + + path.posix.sep + + 'pdf.pdf](pdf})' oldNote.content = testInput newNote.content = testInput - const copyFileSyncResp = {to: jest.fn()} + const copyFileSyncResp = { to: jest.fn() } sander.copyFileSync = jest.fn() sander.copyFileSync.mockReturnValue(copyFileSyncResp) findStorage.findStorage = jest.fn() findStorage.findStorage.mockReturnValueOnce(dummyStorageOld) findStorage.findStorage.mockReturnValue(dummyStorageNew) - const pathAttachmentOneFrom = path.join(storagePathOld, systemUnderTest.DESTINATION_FOLDER, oldNote.key, 'image.jpg') - const pathAttachmentOneTo = path.join(storagePathNew, systemUnderTest.DESTINATION_FOLDER, newNote.key, 'image.jpg') + const pathAttachmentOneFrom = path.join( + storagePathOld, + systemUnderTest.DESTINATION_FOLDER, + oldNote.key, + 'image.jpg' + ) + const pathAttachmentOneTo = path.join( + storagePathNew, + systemUnderTest.DESTINATION_FOLDER, + newNote.key, + 'image.jpg' + ) - const pathAttachmentTwoFrom = path.join(storagePathOld, systemUnderTest.DESTINATION_FOLDER, oldNote.key, 'pdf.pdf') - const pathAttachmentTwoTo = path.join(storagePathNew, systemUnderTest.DESTINATION_FOLDER, newNote.key, 'pdf.pdf') + const pathAttachmentTwoFrom = path.join( + storagePathOld, + systemUnderTest.DESTINATION_FOLDER, + oldNote.key, + 'pdf.pdf' + ) + const pathAttachmentTwoTo = path.join( + storagePathNew, + systemUnderTest.DESTINATION_FOLDER, + newNote.key, + 'pdf.pdf' + ) systemUnderTest.cloneAttachments(oldNote, newNote) @@ -759,9 +1206,19 @@ it('should test that cloneAttachments finds all attachments and copies them to t expect(copyFileSyncResp.to.mock.calls[1][0]).toBe(pathAttachmentTwoTo) }) -it('should test that cloneAttachments finds all attachments and copies them to the new location', function () { - const oldNote = {key: 'oldNoteKey', content: 'oldNoteContent', storage: 'storageKeyOldNote', type: 'SOMETHING_ELSE'} - const newNote = {key: 'newNoteKey', content: 'oldNoteContent', storage: 'storageKeyNewNote', type: 'SOMETHING_ELSE'} +it('should test that cloneAttachments finds all attachments and copies them to the new location', function() { + const oldNote = { + key: 'oldNoteKey', + content: 'oldNoteContent', + storage: 'storageKeyOldNote', + type: 'SOMETHING_ELSE' + } + const newNote = { + key: 'newNoteKey', + content: 'oldNoteContent', + storage: 'storageKeyNewNote', + type: 'SOMETHING_ELSE' + } const testInput = 'Test input' oldNote.content = testInput newNote.content = testInput @@ -775,82 +1232,274 @@ it('should test that cloneAttachments finds all attachments and copies them to t expect(sander.copyFileSync).not.toHaveBeenCalled() }) -it('should test that isAttachmentLink works correctly', function () { +it('should test that isAttachmentLink works correctly', function() { expect(systemUnderTest.isAttachmentLink('text')).toBe(false) expect(systemUnderTest.isAttachmentLink('text [linkText](link)')).toBe(false) expect(systemUnderTest.isAttachmentLink('text ![linkText](link)')).toBe(false) - expect(systemUnderTest.isAttachmentLink('[linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + 'noteKey' + path.win32.sep + 'pdf.pdf)')).toBe(true) - expect(systemUnderTest.isAttachmentLink('![linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + 'noteKey' + path.win32.sep + 'pdf.pdf )')).toBe(true) - expect(systemUnderTest.isAttachmentLink('text [ linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + 'noteKey' + path.win32.sep + 'pdf.pdf)')).toBe(true) - expect(systemUnderTest.isAttachmentLink('text ![linkText ](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + 'noteKey' + path.win32.sep + 'pdf.pdf)')).toBe(true) - expect(systemUnderTest.isAttachmentLink('[linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + 'noteKey' + path.win32.sep + 'pdf.pdf) test')).toBe(true) - expect(systemUnderTest.isAttachmentLink('![linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + 'noteKey' + path.win32.sep + 'pdf.pdf) test')).toBe(true) - expect(systemUnderTest.isAttachmentLink('text [linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + 'noteKey' + path.win32.sep + 'pdf.pdf) test')).toBe(true) - expect(systemUnderTest.isAttachmentLink('text ![linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + 'noteKey' + path.win32.sep + 'pdf.pdf) test')).toBe(true) - expect(systemUnderTest.isAttachmentLink('[linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + 'noteKey' + path.posix.sep + 'pdf.pdf)')).toBe(true) - expect(systemUnderTest.isAttachmentLink('![linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + 'noteKey' + path.posix.sep + 'pdf.pdf )')).toBe(true) - expect(systemUnderTest.isAttachmentLink('text [ linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + 'noteKey' + path.posix.sep + 'pdf.pdf)')).toBe(true) - expect(systemUnderTest.isAttachmentLink('text ![linkText ](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + 'noteKey' + path.posix.sep + 'pdf.pdf)')).toBe(true) - expect(systemUnderTest.isAttachmentLink('[linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + 'noteKey' + path.posix.sep + 'pdf.pdf) test')).toBe(true) - expect(systemUnderTest.isAttachmentLink('![linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + 'noteKey' + path.posix.sep + 'pdf.pdf) test')).toBe(true) - expect(systemUnderTest.isAttachmentLink('text [linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + 'noteKey' + path.posix.sep + 'pdf.pdf) test')).toBe(true) - expect(systemUnderTest.isAttachmentLink('text ![linkText](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + 'noteKey' + path.posix.sep + 'pdf.pdf) test')).toBe(true) + expect( + systemUnderTest.isAttachmentLink( + '[linkText](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + 'noteKey' + + path.win32.sep + + 'pdf.pdf)' + ) + ).toBe(true) + expect( + systemUnderTest.isAttachmentLink( + '![linkText](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + 'noteKey' + + path.win32.sep + + 'pdf.pdf )' + ) + ).toBe(true) + expect( + systemUnderTest.isAttachmentLink( + 'text [ linkText](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + 'noteKey' + + path.win32.sep + + 'pdf.pdf)' + ) + ).toBe(true) + expect( + systemUnderTest.isAttachmentLink( + 'text ![linkText ](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + 'noteKey' + + path.win32.sep + + 'pdf.pdf)' + ) + ).toBe(true) + expect( + systemUnderTest.isAttachmentLink( + '[linkText](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + 'noteKey' + + path.win32.sep + + 'pdf.pdf) test' + ) + ).toBe(true) + expect( + systemUnderTest.isAttachmentLink( + '![linkText](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + 'noteKey' + + path.win32.sep + + 'pdf.pdf) test' + ) + ).toBe(true) + expect( + systemUnderTest.isAttachmentLink( + 'text [linkText](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + 'noteKey' + + path.win32.sep + + 'pdf.pdf) test' + ) + ).toBe(true) + expect( + systemUnderTest.isAttachmentLink( + 'text ![linkText](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + 'noteKey' + + path.win32.sep + + 'pdf.pdf) test' + ) + ).toBe(true) + expect( + systemUnderTest.isAttachmentLink( + '[linkText](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + 'noteKey' + + path.posix.sep + + 'pdf.pdf)' + ) + ).toBe(true) + expect( + systemUnderTest.isAttachmentLink( + '![linkText](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + 'noteKey' + + path.posix.sep + + 'pdf.pdf )' + ) + ).toBe(true) + expect( + systemUnderTest.isAttachmentLink( + 'text [ linkText](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + 'noteKey' + + path.posix.sep + + 'pdf.pdf)' + ) + ).toBe(true) + expect( + systemUnderTest.isAttachmentLink( + 'text ![linkText ](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + 'noteKey' + + path.posix.sep + + 'pdf.pdf)' + ) + ).toBe(true) + expect( + systemUnderTest.isAttachmentLink( + '[linkText](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + 'noteKey' + + path.posix.sep + + 'pdf.pdf) test' + ) + ).toBe(true) + expect( + systemUnderTest.isAttachmentLink( + '![linkText](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + 'noteKey' + + path.posix.sep + + 'pdf.pdf) test' + ) + ).toBe(true) + expect( + systemUnderTest.isAttachmentLink( + 'text [linkText](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + 'noteKey' + + path.posix.sep + + 'pdf.pdf) test' + ) + ).toBe(true) + expect( + systemUnderTest.isAttachmentLink( + 'text ![linkText](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + 'noteKey' + + path.posix.sep + + 'pdf.pdf) test' + ) + ).toBe(true) }) -it('should test that handleAttachmentLinkPaste copies the attachments to the new location', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that handleAttachmentLinkPaste copies the attachments to the new location', function() { + const dummyStorage = { path: 'dummyStoragePath' } findStorage.findStorage = jest.fn(() => dummyStorage) const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723' const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723' - const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.posix.sep + 'pdf.pdf)' + const pasteText = + 'text ![alt](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + pastedNoteKey + + path.posix.sep + + 'pdf.pdf)' const storageKey = 'storageKey' - const expectedSourceFilePath = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, pastedNoteKey, 'pdf.pdf') + const expectedSourceFilePath = path.join( + dummyStorage.path, + systemUnderTest.DESTINATION_FOLDER, + pastedNoteKey, + 'pdf.pdf' + ) sander.exists = jest.fn(() => Promise.resolve(true)) - systemUnderTest.copyAttachment = jest.fn(() => Promise.resolve('dummyNewFileName')) + systemUnderTest.copyAttachment = jest.fn(() => + Promise.resolve('dummyNewFileName') + ) - return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) + return systemUnderTest + .handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) .then(() => { expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey) expect(sander.exists).toHaveBeenCalledWith(expectedSourceFilePath) - expect(systemUnderTest.copyAttachment).toHaveBeenCalledWith(expectedSourceFilePath, storageKey, newNoteKey) + expect(systemUnderTest.copyAttachment).toHaveBeenCalledWith( + expectedSourceFilePath, + storageKey, + newNoteKey + ) }) }) -it('should test that handleAttachmentLinkPaste copies the attachments to the new location - win32 path', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that handleAttachmentLinkPaste copies the attachments to the new location - win32 path', function() { + const dummyStorage = { path: 'dummyStoragePath' } findStorage.findStorage = jest.fn(() => dummyStorage) const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723' const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723' - const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.win32.sep + 'pdf.pdf)' + const pasteText = + 'text ![alt](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + pastedNoteKey + + path.win32.sep + + 'pdf.pdf)' const storageKey = 'storageKey' - const expectedSourceFilePath = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, pastedNoteKey, 'pdf.pdf') + const expectedSourceFilePath = path.join( + dummyStorage.path, + systemUnderTest.DESTINATION_FOLDER, + pastedNoteKey, + 'pdf.pdf' + ) sander.exists = jest.fn(() => Promise.resolve(true)) - systemUnderTest.copyAttachment = jest.fn(() => Promise.resolve('dummyNewFileName')) + systemUnderTest.copyAttachment = jest.fn(() => + Promise.resolve('dummyNewFileName') + ) - return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) + return systemUnderTest + .handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) .then(() => { expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey) expect(sander.exists).toHaveBeenCalledWith(expectedSourceFilePath) - expect(systemUnderTest.copyAttachment).toHaveBeenCalledWith(expectedSourceFilePath, storageKey, newNoteKey) + expect(systemUnderTest.copyAttachment).toHaveBeenCalledWith( + expectedSourceFilePath, + storageKey, + newNoteKey + ) }) }) -it('should test that handleAttachmentLinkPaste don\'t try to copy the file if it does not exist - win32 path', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it("should test that handleAttachmentLinkPaste don't try to copy the file if it does not exist - win32 path", function() { + const dummyStorage = { path: 'dummyStoragePath' } findStorage.findStorage = jest.fn(() => dummyStorage) const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723' const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723' - const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.win32.sep + 'pdf.pdf)' + const pasteText = + 'text ![alt](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + pastedNoteKey + + path.win32.sep + + 'pdf.pdf)' const storageKey = 'storageKey' - const expectedSourceFilePath = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, pastedNoteKey, 'pdf.pdf') + const expectedSourceFilePath = path.join( + dummyStorage.path, + systemUnderTest.DESTINATION_FOLDER, + pastedNoteKey, + 'pdf.pdf' + ) sander.exists = jest.fn(() => Promise.resolve(false)) systemUnderTest.copyAttachment = jest.fn() systemUnderTest.generateFileNotFoundMarkdown = jest.fn() - return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) + return systemUnderTest + .handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) .then(() => { expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey) expect(sander.exists).toHaveBeenCalledWith(expectedSourceFilePath) @@ -858,20 +1507,32 @@ it('should test that handleAttachmentLinkPaste don\'t try to copy the file if it }) }) -it('should test that handleAttachmentLinkPaste don\'t try to copy the file if it does not exist -- posix', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it("should test that handleAttachmentLinkPaste don't try to copy the file if it does not exist -- posix", function() { + const dummyStorage = { path: 'dummyStoragePath' } findStorage.findStorage = jest.fn(() => dummyStorage) const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723' const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723' - const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.posix.sep + 'pdf.pdf)' + const pasteText = + 'text ![alt](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + pastedNoteKey + + path.posix.sep + + 'pdf.pdf)' const storageKey = 'storageKey' - const expectedSourceFilePath = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, pastedNoteKey, 'pdf.pdf') + const expectedSourceFilePath = path.join( + dummyStorage.path, + systemUnderTest.DESTINATION_FOLDER, + pastedNoteKey, + 'pdf.pdf' + ) sander.exists = jest.fn(() => Promise.resolve(false)) systemUnderTest.copyAttachment = jest.fn() systemUnderTest.generateFileNotFoundMarkdown = jest.fn() - return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) + return systemUnderTest + .handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) .then(() => { expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey) expect(sander.exists).toHaveBeenCalledWith(expectedSourceFilePath) @@ -879,106 +1540,217 @@ it('should test that handleAttachmentLinkPaste don\'t try to copy the file if it }) }) -it('should test that handleAttachmentLinkPaste copies multiple attachments if multiple were pasted', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that handleAttachmentLinkPaste copies multiple attachments if multiple were pasted', function() { + const dummyStorage = { path: 'dummyStoragePath' } findStorage.findStorage = jest.fn(() => dummyStorage) const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723' const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723' - const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.posix.sep + 'pdf.pdf) ..' + - '![secondAttachment](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.win32.sep + 'img.jpg)' + const pasteText = + 'text ![alt](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + pastedNoteKey + + path.posix.sep + + 'pdf.pdf) ..' + + '![secondAttachment](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + pastedNoteKey + + path.win32.sep + + 'img.jpg)' const storageKey = 'storageKey' - const expectedSourceFilePathOne = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, pastedNoteKey, 'pdf.pdf') - const expectedSourceFilePathTwo = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, pastedNoteKey, 'img.jpg') + const expectedSourceFilePathOne = path.join( + dummyStorage.path, + systemUnderTest.DESTINATION_FOLDER, + pastedNoteKey, + 'pdf.pdf' + ) + const expectedSourceFilePathTwo = path.join( + dummyStorage.path, + systemUnderTest.DESTINATION_FOLDER, + pastedNoteKey, + 'img.jpg' + ) sander.exists = jest.fn(() => Promise.resolve(true)) - systemUnderTest.copyAttachment = jest.fn(() => Promise.resolve('dummyNewFileName')) + systemUnderTest.copyAttachment = jest.fn(() => + Promise.resolve('dummyNewFileName') + ) - return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) + return systemUnderTest + .handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) .then(() => { expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey) expect(sander.exists).toHaveBeenCalledWith(expectedSourceFilePathOne) expect(sander.exists).toHaveBeenCalledWith(expectedSourceFilePathTwo) - expect(systemUnderTest.copyAttachment).toHaveBeenCalledWith(expectedSourceFilePathOne, storageKey, newNoteKey) - expect(systemUnderTest.copyAttachment).toHaveBeenCalledWith(expectedSourceFilePathTwo, storageKey, newNoteKey) + expect(systemUnderTest.copyAttachment).toHaveBeenCalledWith( + expectedSourceFilePathOne, + storageKey, + newNoteKey + ) + expect(systemUnderTest.copyAttachment).toHaveBeenCalledWith( + expectedSourceFilePathTwo, + storageKey, + newNoteKey + ) }) }) -it('should test that handleAttachmentLinkPaste returns the correct modified paste text', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that handleAttachmentLinkPaste returns the correct modified paste text', function() { + const dummyStorage = { path: 'dummyStoragePath' } findStorage.findStorage = jest.fn(() => dummyStorage) const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723' const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723' const dummyNewFileName = 'dummyNewFileName' - const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.win32.sep + 'pdf.pdf)' - const expectedText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNoteKey + path.sep + dummyNewFileName + ')' + const pasteText = + 'text ![alt](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + pastedNoteKey + + path.win32.sep + + 'pdf.pdf)' + const expectedText = + 'text ![alt](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.sep + + newNoteKey + + path.sep + + dummyNewFileName + + ')' const storageKey = 'storageKey' sander.exists = jest.fn(() => Promise.resolve(true)) - systemUnderTest.copyAttachment = jest.fn(() => Promise.resolve(dummyNewFileName)) + systemUnderTest.copyAttachment = jest.fn(() => + Promise.resolve(dummyNewFileName) + ) - return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) - .then((returnedPastedText) => { + return systemUnderTest + .handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) + .then(returnedPastedText => { expect(returnedPastedText).toBe(expectedText) }) }) -it('should test that handleAttachmentLinkPaste returns the correct modified paste text if multiple links are posted', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that handleAttachmentLinkPaste returns the correct modified paste text if multiple links are posted', function() { + const dummyStorage = { path: 'dummyStoragePath' } findStorage.findStorage = jest.fn(() => dummyStorage) const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723' const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723' const dummyNewFileNameOne = 'dummyNewFileName' const dummyNewFileNameTwo = 'dummyNewFileNameTwo' - const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.win32.sep + 'pdf.pdf) ' + - '![secondImage](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.posix.sep + 'img.jpg)' - const expectedText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNoteKey + path.sep + dummyNewFileNameOne + ') ' + - '![secondImage](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNoteKey + path.sep + dummyNewFileNameTwo + ')' + const pasteText = + 'text ![alt](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + pastedNoteKey + + path.win32.sep + + 'pdf.pdf) ' + + '![secondImage](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + pastedNoteKey + + path.posix.sep + + 'img.jpg)' + const expectedText = + 'text ![alt](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.sep + + newNoteKey + + path.sep + + dummyNewFileNameOne + + ') ' + + '![secondImage](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.sep + + newNoteKey + + path.sep + + dummyNewFileNameTwo + + ')' const storageKey = 'storageKey' sander.exists = jest.fn(() => Promise.resolve(true)) systemUnderTest.copyAttachment = jest.fn() - systemUnderTest.copyAttachment.mockReturnValueOnce(Promise.resolve(dummyNewFileNameOne)) - systemUnderTest.copyAttachment.mockReturnValue(Promise.resolve(dummyNewFileNameTwo)) + systemUnderTest.copyAttachment.mockReturnValueOnce( + Promise.resolve(dummyNewFileNameOne) + ) + systemUnderTest.copyAttachment.mockReturnValue( + Promise.resolve(dummyNewFileNameTwo) + ) - return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) - .then((returnedPastedText) => { + return systemUnderTest + .handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) + .then(returnedPastedText => { expect(returnedPastedText).toBe(expectedText) }) }) -it('should test that handleAttachmentLinkPaste calls the copy method correct if multiple links are posted where one file was found and one was not', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that handleAttachmentLinkPaste calls the copy method correct if multiple links are posted where one file was found and one was not', function() { + const dummyStorage = { path: 'dummyStoragePath' } findStorage.findStorage = jest.fn(() => dummyStorage) const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723' const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723' - const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.posix.sep + 'pdf.pdf) ..' + - '![secondAttachment](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.win32.sep + 'img.jpg)' + const pasteText = + 'text ![alt](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + pastedNoteKey + + path.posix.sep + + 'pdf.pdf) ..' + + '![secondAttachment](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + pastedNoteKey + + path.win32.sep + + 'img.jpg)' const storageKey = 'storageKey' - const expectedSourceFilePathOne = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, pastedNoteKey, 'pdf.pdf') - const expectedSourceFilePathTwo = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, pastedNoteKey, 'img.jpg') + const expectedSourceFilePathOne = path.join( + dummyStorage.path, + systemUnderTest.DESTINATION_FOLDER, + pastedNoteKey, + 'pdf.pdf' + ) + const expectedSourceFilePathTwo = path.join( + dummyStorage.path, + systemUnderTest.DESTINATION_FOLDER, + pastedNoteKey, + 'img.jpg' + ) sander.exists = jest.fn() sander.exists.mockReturnValueOnce(Promise.resolve(false)) sander.exists.mockReturnValue(Promise.resolve(true)) - systemUnderTest.copyAttachment = jest.fn(() => Promise.resolve('dummyNewFileName')) + systemUnderTest.copyAttachment = jest.fn(() => + Promise.resolve('dummyNewFileName') + ) systemUnderTest.generateFileNotFoundMarkdown = jest.fn() - return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) + return systemUnderTest + .handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) .then(() => { expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey) expect(sander.exists).toHaveBeenCalledWith(expectedSourceFilePathOne) expect(sander.exists).toHaveBeenCalledWith(expectedSourceFilePathTwo) expect(systemUnderTest.copyAttachment).toHaveBeenCalledTimes(1) - expect(systemUnderTest.copyAttachment).toHaveBeenCalledWith(expectedSourceFilePathTwo, storageKey, newNoteKey) + expect(systemUnderTest.copyAttachment).toHaveBeenCalledWith( + expectedSourceFilePathTwo, + storageKey, + newNoteKey + ) }) }) -it('should test that handleAttachmentLinkPaste returns the correct modified paste text if the file was not found', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that handleAttachmentLinkPaste returns the correct modified paste text if the file was not found', function() { + const dummyStorage = { path: 'dummyStoragePath' } findStorage.findStorage = jest.fn(() => dummyStorage) const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723' const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723' - const pasteText = 'text ![alt.png](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.posix.sep + 'pdf.pdf)' + const pasteText = + 'text ![alt.png](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + pastedNoteKey + + path.posix.sep + + 'pdf.pdf)' const storageKey = 'storageKey' const fileNotFoundMD = 'file not found' const expectedPastText = 'text ' + fileNotFoundMD @@ -986,19 +1758,31 @@ it('should test that handleAttachmentLinkPaste returns the correct modified past systemUnderTest.generateFileNotFoundMarkdown = jest.fn(() => fileNotFoundMD) sander.exists = jest.fn(() => Promise.resolve(false)) - return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) - .then((returnedPastedText) => { + return systemUnderTest + .handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) + .then(returnedPastedText => { expect(returnedPastedText).toBe(expectedPastText) }) }) -it('should test that handleAttachmentLinkPaste returns the correct modified paste text if multiple files were not found', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that handleAttachmentLinkPaste returns the correct modified paste text if multiple files were not found', function() { + const dummyStorage = { path: 'dummyStoragePath' } findStorage.findStorage = jest.fn(() => dummyStorage) const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723' const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723' - const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.win32.sep + 'pdf.pdf) ' + - '![secondImage](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.posix.sep + 'img.jpg)' + const pasteText = + 'text ![alt](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + pastedNoteKey + + path.win32.sep + + 'pdf.pdf) ' + + '![secondImage](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + pastedNoteKey + + path.posix.sep + + 'img.jpg)' const storageKey = 'storageKey' const fileNotFoundMD = 'file not found' const expectedPastText = 'text ' + fileNotFoundMD + ' ' + fileNotFoundMD @@ -1006,56 +1790,102 @@ it('should test that handleAttachmentLinkPaste returns the correct modified past sander.exists = jest.fn(() => Promise.resolve(false)) - return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) - .then((returnedPastedText) => { + return systemUnderTest + .handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) + .then(returnedPastedText => { expect(returnedPastedText).toBe(expectedPastText) }) }) -it('should test that handleAttachmentLinkPaste returns the correct modified paste text if one file was found and one was not found', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that handleAttachmentLinkPaste returns the correct modified paste text if one file was found and one was not found', function() { + const dummyStorage = { path: 'dummyStoragePath' } findStorage.findStorage = jest.fn(() => dummyStorage) const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723' const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723' const dummyFoundFileName = 'dummyFileName' const fileNotFoundMD = 'file not found' - const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.win32.sep + 'pdf.pdf) .. ' + - '![secondAttachment](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.posix.sep + 'img.jpg)' + const pasteText = + 'text ![alt](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + pastedNoteKey + + path.win32.sep + + 'pdf.pdf) .. ' + + '![secondAttachment](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + pastedNoteKey + + path.posix.sep + + 'img.jpg)' const storageKey = 'storageKey' - const expectedPastText = 'text ' + fileNotFoundMD + ' .. ![secondAttachment](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNoteKey + path.sep + dummyFoundFileName + ')' + const expectedPastText = + 'text ' + + fileNotFoundMD + + ' .. ![secondAttachment](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.sep + + newNoteKey + + path.sep + + dummyFoundFileName + + ')' sander.exists = jest.fn() sander.exists.mockReturnValueOnce(Promise.resolve(false)) sander.exists.mockReturnValue(Promise.resolve(true)) - systemUnderTest.copyAttachment = jest.fn(() => Promise.resolve(dummyFoundFileName)) + systemUnderTest.copyAttachment = jest.fn(() => + Promise.resolve(dummyFoundFileName) + ) systemUnderTest.generateFileNotFoundMarkdown = jest.fn(() => fileNotFoundMD) - return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) - .then((returnedPastedText) => { + return systemUnderTest + .handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) + .then(returnedPastedText => { expect(returnedPastedText).toBe(expectedPastText) }) }) -it('should test that handleAttachmentLinkPaste returns the correct modified paste text if one file was found and one was not found', function () { - const dummyStorage = {path: 'dummyStoragePath'} +it('should test that handleAttachmentLinkPaste returns the correct modified paste text if one file was found and one was not found', function() { + const dummyStorage = { path: 'dummyStoragePath' } findStorage.findStorage = jest.fn(() => dummyStorage) const pastedNoteKey = 'b1e06f81-8266-49b9-b438-084003c2e723' const newNoteKey = 'abc234-8266-49b9-b438-084003c2e723' const dummyFoundFileName = 'dummyFileName' const fileNotFoundMD = 'file not found' - const pasteText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.posix.sep + pastedNoteKey + path.posix.sep + 'pdf.pdf) .. ' + - '![secondAttachment](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.win32.sep + pastedNoteKey + path.win32.sep + 'img.jpg)' + const pasteText = + 'text ![alt](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.posix.sep + + pastedNoteKey + + path.posix.sep + + 'pdf.pdf) .. ' + + '![secondAttachment](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.win32.sep + + pastedNoteKey + + path.win32.sep + + 'img.jpg)' const storageKey = 'storageKey' - const expectedPastText = 'text ![alt](' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNoteKey + path.sep + dummyFoundFileName + ') .. ' + fileNotFoundMD + const expectedPastText = + 'text ![alt](' + + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + + path.sep + + newNoteKey + + path.sep + + dummyFoundFileName + + ') .. ' + + fileNotFoundMD sander.exists = jest.fn() sander.exists.mockReturnValueOnce(Promise.resolve(true)) sander.exists.mockReturnValue(Promise.resolve(false)) - systemUnderTest.copyAttachment = jest.fn(() => Promise.resolve(dummyFoundFileName)) + systemUnderTest.copyAttachment = jest.fn(() => + Promise.resolve(dummyFoundFileName) + ) systemUnderTest.generateFileNotFoundMarkdown = jest.fn(() => fileNotFoundMD) - return systemUnderTest.handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) - .then((returnedPastedText) => { + return systemUnderTest + .handleAttachmentLinkPaste(storageKey, newNoteKey, pasteText) + .then(returnedPastedText => { expect(returnedPastedText).toBe(expectedPastText) }) }) diff --git a/tests/dataApi/copyFile-test.js b/tests/dataApi/copyFile-test.js index 533b1354..f38f1ed2 100644 --- a/tests/dataApi/copyFile-test.js +++ b/tests/dataApi/copyFile-test.js @@ -13,13 +13,13 @@ const srcPath = path.join(srcFolder, testFile) const dstFolder = path.join(__dirname, '😇') const dstPath = path.join(dstFolder, testFile) -test.before((t) => { +test.before(t => { if (!fs.existsSync(srcFolder)) fs.mkdirSync(srcFolder) fs.writeFileSync(srcPath, 'test') }) -test('`copyFile` should handle encoded URI on src path', (t) => { +test('`copyFile` should handle encoded URI on src path', t => { return copyFile(encodeURI(srcPath), dstPath) .then(() => { t.true(true) @@ -29,10 +29,9 @@ test('`copyFile` should handle encoded URI on src path', (t) => { }) }) -test.after((t) => { +test.after(t => { fs.unlinkSync(srcPath) fs.unlinkSync(dstPath) execSync(removeDirCommand + '"' + srcFolder + '"') execSync(removeDirCommand + '"' + dstFolder + '"') }) - diff --git a/tests/dataApi/createFolder-test.js b/tests/dataApi/createFolder-test.js index 1b9a1c83..fd54ba27 100644 --- a/tests/dataApi/createFolder-test.js +++ b/tests/dataApi/createFolder-test.js @@ -6,7 +6,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const _ = require('lodash') const TestDummy = require('../fixtures/TestDummy') @@ -16,30 +19,32 @@ const CSON = require('@rokt33r/season') const storagePath = path.join(os.tmpdir(), 'test/create-folder') -test.beforeEach((t) => { +test.beforeEach(t => { t.context.storage = TestDummy.dummyStorage(storagePath) localStorage.setItem('storages', JSON.stringify([t.context.storage.cache])) }) -test.serial('Create a folder', (t) => { +test.serial('Create a folder', t => { const storageKey = t.context.storage.cache.key const input = { name: 'created', color: '#ff5555' } return Promise.resolve() - .then(function doTest () { + .then(function doTest() { return createFolder(storageKey, input) }) - .then(function assert (data) { + .then(function assert(data) { t.true(_.find(data.storage.folders, input) != null) - const jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json')) + const jsonData = CSON.readFileSync( + path.join(data.storage.path, 'boostnote.json') + ) console.log(path.join(data.storage.path, 'boostnote.json')) t.true(_.find(jsonData.folders, input) != null) }) }) -test.after(function after () { +test.after(function after() { localStorage.clear() sander.rimrafSync(storagePath) }) diff --git a/tests/dataApi/createNote-test.js b/tests/dataApi/createNote-test.js index 3606dfd4..2c3af348 100644 --- a/tests/dataApi/createNote-test.js +++ b/tests/dataApi/createNote-test.js @@ -6,7 +6,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const TestDummy = require('../fixtures/TestDummy') const sander = require('sander') @@ -16,26 +19,30 @@ const faker = require('faker') const storagePath = path.join(os.tmpdir(), 'test/create-note') -test.beforeEach((t) => { +test.beforeEach(t => { t.context.storage = TestDummy.dummyStorage(storagePath) localStorage.setItem('storages', JSON.stringify([t.context.storage.cache])) }) -test.serial('Create a note', (t) => { +test.serial('Create a note', t => { const storageKey = t.context.storage.cache.key const folderKey = t.context.storage.json.folders[0].key - const randLinesHighlightedArray = new Array(10).fill().map(() => Math.round(Math.random() * 10)) + const randLinesHighlightedArray = new Array(10) + .fill() + .map(() => Math.round(Math.random() * 10)) const input1 = { type: 'SNIPPET_NOTE', description: faker.lorem.lines(), - snippets: [{ - name: faker.system.fileName(), - mode: 'text', - content: faker.lorem.lines(), - linesHighlighted: randLinesHighlightedArray - }], + snippets: [ + { + name: faker.system.fileName(), + mode: 'text', + content: faker.lorem.lines(), + linesHighlighted: randLinesHighlightedArray + } + ], tags: faker.lorem.words().split(' '), folder: folderKey } @@ -51,18 +58,20 @@ test.serial('Create a note', (t) => { input2.title = input2.content.split('\n').shift() return Promise.resolve() - .then(function doTest () { + .then(function doTest() { return Promise.all([ createNote(storageKey, input1), createNote(storageKey, input2) ]) }) - .then(function assert (data) { + .then(function assert(data) { const data1 = data[0] const data2 = data[1] t.is(storageKey, data1.storage) - const jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson')) + const jsonData1 = CSON.readFileSync( + path.join(storagePath, 'notes', data1.key + '.cson') + ) t.is(input1.title, data1.title) t.is(input1.title, jsonData1.title) @@ -76,11 +85,19 @@ test.serial('Create a note', (t) => { t.is(input1.snippets[0].content, jsonData1.snippets[0].content) t.is(input1.snippets[0].name, data1.snippets[0].name) t.is(input1.snippets[0].name, jsonData1.snippets[0].name) - t.deepEqual(input1.snippets[0].linesHighlighted, data1.snippets[0].linesHighlighted) - t.deepEqual(input1.snippets[0].linesHighlighted, jsonData1.snippets[0].linesHighlighted) + t.deepEqual( + input1.snippets[0].linesHighlighted, + data1.snippets[0].linesHighlighted + ) + t.deepEqual( + input1.snippets[0].linesHighlighted, + jsonData1.snippets[0].linesHighlighted + ) t.is(storageKey, data2.storage) - const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson')) + const jsonData2 = CSON.readFileSync( + path.join(storagePath, 'notes', data2.key + '.cson') + ) t.is(input2.title, data2.title) t.is(input2.title, jsonData2.title) t.is(input2.content, data2.content) @@ -92,7 +109,7 @@ test.serial('Create a note', (t) => { }) }) -test.after(function after () { +test.after(function after() { localStorage.clear() sander.rimrafSync(storagePath) }) diff --git a/tests/dataApi/createNoteFromUrl-test.js b/tests/dataApi/createNoteFromUrl-test.js index a324a3e5..83b8d4e8 100644 --- a/tests/dataApi/createNoteFromUrl-test.js +++ b/tests/dataApi/createNoteFromUrl-test.js @@ -6,7 +6,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const TestDummy = require('../fixtures/TestDummy') const sander = require('sander') @@ -15,29 +18,32 @@ const CSON = require('@rokt33r/season') const storagePath = path.join(os.tmpdir(), 'test/create-note-from-url') -test.beforeEach((t) => { +test.beforeEach(t => { t.context.storage = TestDummy.dummyStorage(storagePath) localStorage.setItem('storages', JSON.stringify([t.context.storage.cache])) }) -test.serial('Create a note from URL', (t) => { +test.serial('Create a note from URL', t => { const storageKey = t.context.storage.cache.key const folderKey = t.context.storage.json.folders[0].key const url = 'https://shapeshed.com/writing-cross-platform-node/' - return createNoteFromUrl(url, storageKey, folderKey) - .then(function assert ({ note }) { - t.is(storageKey, note.storage) - const jsonData = CSON.readFileSync(path.join(storagePath, 'notes', note.key + '.cson')) + return createNoteFromUrl(url, storageKey, folderKey).then(function assert({ + note + }) { + t.is(storageKey, note.storage) + const jsonData = CSON.readFileSync( + path.join(storagePath, 'notes', note.key + '.cson') + ) - // Test if saved content is matching the created in memory note - t.is(note.content, jsonData.content) - t.is(note.tags.length, jsonData.tags.length) - }) + // Test if saved content is matching the created in memory note + t.is(note.content, jsonData.content) + t.is(note.tags.length, jsonData.tags.length) + }) }) -test.after(function after () { +test.after(function after() { localStorage.clear() sander.rimrafSync(storagePath) }) diff --git a/tests/dataApi/createSnippet-test.js b/tests/dataApi/createSnippet-test.js index 638b76ca..e1b9a570 100644 --- a/tests/dataApi/createSnippet-test.js +++ b/tests/dataApi/createSnippet-test.js @@ -7,21 +7,21 @@ const path = require('path') const snippetFilePath = path.join(os.tmpdir(), 'test', 'create-snippet') const snippetFile = path.join(snippetFilePath, 'snippets.json') -test.beforeEach((t) => { +test.beforeEach(t => { sander.writeFileSync(snippetFile, '[]') }) -test.serial('Create a snippet', (t) => { +test.serial('Create a snippet', t => { return Promise.resolve() - .then(function doTest () { - return Promise.all([ - createSnippet(snippetFile) - ]) + .then(function doTest() { + return Promise.all([createSnippet(snippetFile)]) }) - .then(function assert (data) { + .then(function assert(data) { data = data[0] const snippets = JSON.parse(sander.readFileSync(snippetFile)) - const snippet = snippets.find(currentSnippet => currentSnippet.id === data.id) + const snippet = snippets.find( + currentSnippet => currentSnippet.id === data.id + ) t.not(snippet, undefined) t.is(snippet.name, data.name) t.deepEqual(snippet.prefix, data.prefix) diff --git a/tests/dataApi/deleteFolder-test.js b/tests/dataApi/deleteFolder-test.js index af901896..8b930e48 100644 --- a/tests/dataApi/deleteFolder-test.js +++ b/tests/dataApi/deleteFolder-test.js @@ -10,7 +10,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const _ = require('lodash') const TestDummy = require('../fixtures/TestDummy') @@ -20,12 +23,12 @@ const CSON = require('@rokt33r/season') const storagePath = path.join(os.tmpdir(), 'test/delete-folder') -test.beforeEach((t) => { +test.beforeEach(t => { t.context.storage = TestDummy.dummyStorage(storagePath) localStorage.setItem('storages', JSON.stringify([t.context.storage.cache])) }) -test.serial('Delete a folder', (t) => { +test.serial('Delete a folder', t => { const storageKey = t.context.storage.cache.key const folderKey = t.context.storage.json.folders[0].key let noteKey @@ -33,44 +36,64 @@ test.serial('Delete a folder', (t) => { const input1 = { type: 'SNIPPET_NOTE', description: faker.lorem.lines(), - snippets: [{ - name: faker.system.fileName(), - mode: 'text', - content: faker.lorem.lines() - }], + snippets: [ + { + name: faker.system.fileName(), + mode: 'text', + content: faker.lorem.lines() + } + ], tags: faker.lorem.words().split(' '), folder: folderKey } input1.title = input1.description.split('\n').shift() return Promise.resolve() - .then(function prepare () { - return createNote(storageKey, input1) - .then(function createAttachmentFolder (data) { - fs.mkdirSync(path.join(storagePath, attachmentManagement.DESTINATION_FOLDER)) - fs.mkdirSync(path.join(storagePath, attachmentManagement.DESTINATION_FOLDER, data.key)) + .then(function prepare() { + return createNote(storageKey, input1).then( + function createAttachmentFolder(data) { + fs.mkdirSync( + path.join(storagePath, attachmentManagement.DESTINATION_FOLDER) + ) + fs.mkdirSync( + path.join( + storagePath, + attachmentManagement.DESTINATION_FOLDER, + data.key + ) + ) noteKey = data.key return data - }) + } + ) }) - .then(function doTest () { + .then(function doTest() { return deleteFolder(storageKey, folderKey) }) - .then(function assert (data) { - t.true(_.find(data.storage.folders, {key: folderKey}) == null) - const jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json')) + .then(function assert(data) { + t.true(_.find(data.storage.folders, { key: folderKey }) == null) + const jsonData = CSON.readFileSync( + path.join(data.storage.path, 'boostnote.json') + ) - t.true(_.find(jsonData.folders, {key: folderKey}) == null) + t.true(_.find(jsonData.folders, { key: folderKey }) == null) const notePaths = sander.readdirSync(data.storage.path, 'notes') - t.is(notePaths.length, t.context.storage.notes.filter((note) => note.folder !== folderKey).length) + t.is( + notePaths.length, + t.context.storage.notes.filter(note => note.folder !== folderKey).length + ) - const attachmentFolderPath = path.join(storagePath, attachmentManagement.DESTINATION_FOLDER, noteKey) + const attachmentFolderPath = path.join( + storagePath, + attachmentManagement.DESTINATION_FOLDER, + noteKey + ) t.false(fs.existsSync(attachmentFolderPath)) }) }) -test.after.always(function after () { +test.after.always(function after() { localStorage.clear() sander.rimrafSync(storagePath) }) diff --git a/tests/dataApi/deleteNote-test.js b/tests/dataApi/deleteNote-test.js index 9c809dcf..27ea478b 100644 --- a/tests/dataApi/deleteNote-test.js +++ b/tests/dataApi/deleteNote-test.js @@ -7,7 +7,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const TestDummy = require('../fixtures/TestDummy') const sander = require('sander') @@ -19,56 +22,72 @@ const attachmentManagement = require('browser/main/lib/dataApi/attachmentManagem const storagePath = path.join(os.tmpdir(), 'test/delete-note') -test.beforeEach((t) => { +test.beforeEach(t => { t.context.storage = TestDummy.dummyStorage(storagePath) localStorage.setItem('storages', JSON.stringify([t.context.storage.cache])) }) -test.serial('Delete a note', (t) => { +test.serial('Delete a note', t => { const storageKey = t.context.storage.cache.key const folderKey = t.context.storage.json.folders[0].key const input1 = { type: 'SNIPPET_NOTE', description: faker.lorem.lines(), - snippets: [{ - name: faker.system.fileName(), - mode: 'text', - content: faker.lorem.lines() - }], + snippets: [ + { + name: faker.system.fileName(), + mode: 'text', + content: faker.lorem.lines() + } + ], tags: faker.lorem.words().split(' '), folder: folderKey } input1.title = input1.description.split('\n').shift() return Promise.resolve() - .then(function doTest () { + .then(function doTest() { return createNote(storageKey, input1) - .then(function createAttachmentFolder (data) { - fs.mkdirSync(path.join(storagePath, attachmentManagement.DESTINATION_FOLDER)) - fs.mkdirSync(path.join(storagePath, attachmentManagement.DESTINATION_FOLDER, data.key)) + .then(function createAttachmentFolder(data) { + fs.mkdirSync( + path.join(storagePath, attachmentManagement.DESTINATION_FOLDER) + ) + fs.mkdirSync( + path.join( + storagePath, + attachmentManagement.DESTINATION_FOLDER, + data.key + ) + ) return data }) - .then(function (data) { + .then(function(data) { return deleteNote(storageKey, data.key) }) }) - .then(function assert (data) { + .then(function assert(data) { try { - CSON.readFileSync(path.join(storagePath, 'notes', data.noteKey + '.cson')) + CSON.readFileSync( + path.join(storagePath, 'notes', data.noteKey + '.cson') + ) t.fail('note cson must be deleted.') } catch (err) { t.is(err.code, 'ENOENT') return data } }) - .then(function assertAttachmentFolderDeleted (data) { - const attachmentFolderPath = path.join(storagePath, attachmentManagement.DESTINATION_FOLDER, data.noteKey) + .then(function assertAttachmentFolderDeleted(data) { + const attachmentFolderPath = path.join( + storagePath, + attachmentManagement.DESTINATION_FOLDER, + data.noteKey + ) t.is(fs.existsSync(attachmentFolderPath), false) }) }) -test.after(function after () { +test.after(function after() { localStorage.clear() sander.rimrafSync(storagePath) }) diff --git a/tests/dataApi/deleteSnippet-test.js b/tests/dataApi/deleteSnippet-test.js index 9d13249b..52ec2875 100644 --- a/tests/dataApi/deleteSnippet-test.js +++ b/tests/dataApi/deleteSnippet-test.js @@ -14,18 +14,16 @@ const newSnippet = { content: '' } -test.beforeEach((t) => { +test.beforeEach(t => { sander.writeFileSync(snippetFile, JSON.stringify([newSnippet])) }) -test.serial('Delete a snippet', (t) => { +test.serial('Delete a snippet', t => { return Promise.resolve() - .then(function doTest () { - return Promise.all([ - deleteSnippet(newSnippet, snippetFile) - ]) + .then(function doTest() { + return Promise.all([deleteSnippet(newSnippet, snippetFile)]) }) - .then(function assert (data) { + .then(function assert(data) { data = data[0] const snippets = JSON.parse(sander.readFileSync(snippetFile)) t.is(snippets.length, 0) diff --git a/tests/dataApi/exportFolder-test.js b/tests/dataApi/exportFolder-test.js index fb4aaa7b..d0aef186 100644 --- a/tests/dataApi/exportFolder-test.js +++ b/tests/dataApi/exportFolder-test.js @@ -7,7 +7,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const TestDummy = require('../fixtures/TestDummy') const os = require('os') @@ -17,12 +20,12 @@ const sander = require('sander') const storagePath = path.join(os.tmpdir(), 'test/export-note') -test.beforeEach((t) => { +test.beforeEach(t => { t.context.storage = TestDummy.dummyStorage(storagePath) localStorage.setItem('storages', JSON.stringify([t.context.storage.cache])) }) -test.serial('Export a folder', (t) => { +test.serial('Export a folder', t => { const storageKey = t.context.storage.cache.key const folderKey = t.context.storage.json.folders[0].key @@ -37,24 +40,26 @@ test.serial('Export a folder', (t) => { const input2 = { type: 'SNIPPET_NOTE', description: 'Some normal text', - snippets: [{ - name: faker.system.fileName(), - mode: 'text', - content: faker.lorem.lines() - }], + snippets: [ + { + name: faker.system.fileName(), + mode: 'text', + content: faker.lorem.lines() + } + ], tags: faker.lorem.words().split(' '), folder: folderKey } input2.title = 'input2' return createNote(storageKey, input1) - .then(function () { + .then(function() { return createNote(storageKey, input2) }) - .then(function () { + .then(function() { return exportFolder(storageKey, folderKey, 'md', storagePath) }) - .then(function assert () { + .then(function assert() { let filePath = path.join(storagePath, 'input1.md') t.true(fs.existsSync(filePath)) filePath = path.join(storagePath, 'input2.md') @@ -62,7 +67,7 @@ test.serial('Export a folder', (t) => { }) }) -test.after.always(function after () { +test.after.always(function after() { localStorage.clear() sander.rimrafSync(storagePath) }) diff --git a/tests/dataApi/exportStorage-test.js b/tests/dataApi/exportStorage-test.js index e5594329..1ee26f19 100644 --- a/tests/dataApi/exportStorage-test.js +++ b/tests/dataApi/exportStorage-test.js @@ -6,7 +6,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const TestDummy = require('../fixtures/TestDummy') const os = require('os') @@ -17,7 +20,9 @@ test.beforeEach(t => { t.context.storageDir = path.join(os.tmpdir(), 'test/export-storage') t.context.storage = TestDummy.dummyStorage(t.context.storageDir) t.context.exportDir = path.join(os.tmpdir(), 'test/export-storage-output') - try { fs.mkdirSync(t.context.exportDir) } catch (e) {} + try { + fs.mkdirSync(t.context.exportDir) + } catch (e) {} localStorage.setItem('storages', JSON.stringify([t.context.storage.cache])) }) @@ -26,23 +31,25 @@ test.serial('Export a storage', t => { const folders = t.context.storage.json.folders const notes = t.context.storage.notes const exportDir = t.context.exportDir - const folderKeyToName = folders.reduce( - (acc, folder) => { - acc[folder.key] = folder.name - return acc - }, {}) - return exportStorage(storageKey, 'md', exportDir) - .then(() => { - notes.forEach(note => { - const noteDir = path.join(exportDir, folderKeyToName[note.folder], `${note.title}.md`) - if (note.type === 'MARKDOWN_NOTE') { - t.true(fs.existsSync(noteDir)) - t.is(fs.readFileSync(noteDir, 'utf8'), note.content) - } else if (note.type === 'SNIPPET_NOTE') { - t.false(fs.existsSync(noteDir)) - } - }) + const folderKeyToName = folders.reduce((acc, folder) => { + acc[folder.key] = folder.name + return acc + }, {}) + return exportStorage(storageKey, 'md', exportDir).then(() => { + notes.forEach(note => { + const noteDir = path.join( + exportDir, + folderKeyToName[note.folder], + `${note.title}.md` + ) + if (note.type === 'MARKDOWN_NOTE') { + t.true(fs.existsSync(noteDir)) + t.is(fs.readFileSync(noteDir, 'utf8'), note.content) + } else if (note.type === 'SNIPPET_NOTE') { + t.false(fs.existsSync(noteDir)) + } }) + }) }) test.afterEach.always(t => { diff --git a/tests/dataApi/init.js b/tests/dataApi/init.js index cacc2b2a..989e4969 100644 --- a/tests/dataApi/init.js +++ b/tests/dataApi/init.js @@ -6,7 +6,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const TestDummy = require('../fixtures/TestDummy') const keygen = require('browser/lib/keygen') @@ -18,11 +21,16 @@ const v1StoragePath = path.join(os.tmpdir(), 'test/init-v1-storage') const legacyStoragePath = path.join(os.tmpdir(), 'test/init-legacy-storage') const emptyDirPath = path.join(os.tmpdir(), 'test/init-empty-storage') -test.beforeEach((t) => { +test.beforeEach(t => { localStorage.clear() // Prepare 3 types of dir - t.context.v1StorageData = TestDummy.dummyStorage(v1StoragePath, {cache: {name: 'v1'}}) - t.context.legacyStorageData = TestDummy.dummyLegacyStorage(legacyStoragePath, {cache: {name: 'legacy'}}) + t.context.v1StorageData = TestDummy.dummyStorage(v1StoragePath, { + cache: { name: 'v1' } + }) + t.context.legacyStorageData = TestDummy.dummyLegacyStorage( + legacyStoragePath, + { cache: { name: 'legacy' } } + ) t.context.emptyStorageData = { cache: { type: 'FILESYSTEM', @@ -32,27 +40,37 @@ test.beforeEach((t) => { } } - localStorage.setItem('storages', JSON.stringify([t.context.v1StorageData.cache, t.context.legacyStorageData.cache, t.context.emptyStorageData.cache])) + localStorage.setItem( + 'storages', + JSON.stringify([ + t.context.v1StorageData.cache, + t.context.legacyStorageData.cache, + t.context.emptyStorageData.cache + ]) + ) }) -test.serial('Initialize All Storages', (t) => { +test.serial('Initialize All Storages', t => { const { v1StorageData, legacyStorageData } = t.context return Promise.resolve() - .then(function test () { + .then(function test() { return init() }) - .then(function assert (data) { + .then(function assert(data) { t.true(Array.isArray(data.storages)) - t.is(data.notes.length, v1StorageData.notes.length + legacyStorageData.notes.length) + t.is( + data.notes.length, + v1StorageData.notes.length + legacyStorageData.notes.length + ) t.is(data.storages.length, 3) - data.storages.forEach(function assertStorage (storage) { + data.storages.forEach(function assertStorage(storage) { t.true(_.isString(storage.key)) t.true(_.isString(storage.name)) t.true(storage.type === 'FILESYSTEM') t.true(_.isString(storage.path)) }) }) - .then(function after () { + .then(function after() { localStorage.clear() }) }) diff --git a/tests/dataApi/migrateFromV6Storage-test.js b/tests/dataApi/migrateFromV6Storage-test.js index 7cdcdb71..92b87cec 100644 --- a/tests/dataApi/migrateFromV6Storage-test.js +++ b/tests/dataApi/migrateFromV6Storage-test.js @@ -6,7 +6,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const TestDummy = require('../fixtures/TestDummy') const sander = require('sander') @@ -16,18 +19,20 @@ const os = require('os') const dummyStoragePath = path.join(os.tmpdir(), 'test/migrate-test-storage') -test.beforeEach((t) => { - const dummyData = t.context.dummyData = TestDummy.dummyLegacyStorage(dummyStoragePath) +test.beforeEach(t => { + const dummyData = (t.context.dummyData = TestDummy.dummyLegacyStorage( + dummyStoragePath + )) console.log('init count', dummyData.notes.length) localStorage.setItem('storages', JSON.stringify([dummyData.cache])) }) -test.serial('Migrate legacy storage into v1 storage', (t) => { +test.serial('Migrate legacy storage into v1 storage', t => { return Promise.resolve() - .then(function test () { + .then(function test() { return migrateFromV6Storage(dummyStoragePath) }) - .then(function assert (data) { + .then(function assert(data) { // Check the result. It must be true if succeed. t.true(data) @@ -36,29 +41,31 @@ test.serial('Migrate legacy storage into v1 storage', (t) => { const noteDirPath = path.join(dummyStoragePath, 'notes') const fileList = sander.readdirSync(noteDirPath) t.is(dummyData.notes.length, fileList.length) - const noteMap = fileList - .map((filePath) => { - return CSON.readFileSync(path.join(noteDirPath, filePath)) - }) - dummyData.notes - .forEach(function (targetNote) { - t.true(_.find(noteMap, {title: targetNote.title, folder: targetNote.folder}) != null) - }) + const noteMap = fileList.map(filePath => { + return CSON.readFileSync(path.join(noteDirPath, filePath)) + }) + dummyData.notes.forEach(function(targetNote) { + t.true( + _.find(noteMap, { + title: targetNote.title, + folder: targetNote.folder + }) != null + ) + }) // Check legacy folder directory is removed - dummyData.json.folders - .forEach(function (folder) { - try { - sander.statSync(dummyStoragePath, folder.key) - t.fail('Folder still remains. ENOENT error must be occured.') - } catch (err) { - t.is(err.code, 'ENOENT') - } - }) + dummyData.json.folders.forEach(function(folder) { + try { + sander.statSync(dummyStoragePath, folder.key) + t.fail('Folder still remains. ENOENT error must be occured.') + } catch (err) { + t.is(err.code, 'ENOENT') + } + }) }) }) -test.after.always(function () { +test.after.always(function() { localStorage.clear() sander.rimrafSync(dummyStoragePath) }) diff --git a/tests/dataApi/moveNote-test.js b/tests/dataApi/moveNote-test.js index 3fe31c58..6718af37 100644 --- a/tests/dataApi/moveNote-test.js +++ b/tests/dataApi/moveNote-test.js @@ -6,7 +6,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const TestDummy = require('../fixtures/TestDummy') const sander = require('sander') @@ -16,13 +19,16 @@ const CSON = require('@rokt33r/season') const storagePath = path.join(os.tmpdir(), 'test/move-note') const storagePath2 = path.join(os.tmpdir(), 'test/move-note2') -test.beforeEach((t) => { +test.beforeEach(t => { t.context.storage1 = TestDummy.dummyStorage(storagePath) t.context.storage2 = TestDummy.dummyStorage(storagePath2) - localStorage.setItem('storages', JSON.stringify([t.context.storage1.cache, t.context.storage2.cache])) + localStorage.setItem( + 'storages', + JSON.stringify([t.context.storage1.cache, t.context.storage2.cache]) + ) }) -test.serial('Move a note', (t) => { +test.serial('Move a note', t => { const storageKey1 = t.context.storage1.cache.key const folderKey1 = t.context.storage1.json.folders[0].key const note1 = t.context.storage1.notes[0] @@ -31,22 +37,26 @@ test.serial('Move a note', (t) => { const folderKey2 = t.context.storage2.json.folders[0].key return Promise.resolve() - .then(function doTest () { + .then(function doTest() { return Promise.all([ moveNote(storageKey1, note1.key, storageKey1, folderKey1), moveNote(storageKey1, note2.key, storageKey2, folderKey2) ]) }) - .then(function assert (data) { + .then(function assert(data) { const data1 = data[0] const data2 = data[1] - const jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson')) + const jsonData1 = CSON.readFileSync( + path.join(storagePath, 'notes', data1.key + '.cson') + ) t.is(jsonData1.folder, folderKey1) t.is(jsonData1.title, note1.title) - const jsonData2 = CSON.readFileSync(path.join(storagePath2, 'notes', data2.key + '.cson')) + const jsonData2 = CSON.readFileSync( + path.join(storagePath2, 'notes', data2.key + '.cson') + ) t.is(jsonData2.folder, folderKey2) t.is(jsonData2.title, note2.title) try { @@ -58,7 +68,7 @@ test.serial('Move a note', (t) => { }) }) -test.after(function after () { +test.after(function after() { localStorage.clear() sander.rimrafSync(storagePath) sander.rimrafSync(storagePath2) diff --git a/tests/dataApi/removeStorage-test.js b/tests/dataApi/removeStorage-test.js index 33541df1..e5ac2c8f 100644 --- a/tests/dataApi/removeStorage-test.js +++ b/tests/dataApi/removeStorage-test.js @@ -6,7 +6,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const TestDummy = require('../fixtures/TestDummy') const sander = require('sander') @@ -14,23 +17,23 @@ const os = require('os') const storagePath = path.join(os.tmpdir(), 'test/remove-storage') -test.beforeEach((t) => { +test.beforeEach(t => { t.context.storage = TestDummy.dummyStorage(storagePath) localStorage.setItem('storages', JSON.stringify([t.context.storage.cache])) }) -test('Remove a storage', (t) => { +test('Remove a storage', t => { const storageKey = t.context.storage.cache.key return Promise.resolve() - .then(function doTest () { + .then(function doTest() { return removeStorage(storageKey) }) - .then(function assert (data) { + .then(function assert(data) { t.is(JSON.parse(localStorage.getItem('storages')).length, 0) }) }) -test.after(function after () { +test.after(function after() { localStorage.clear() sander.rimrafSync(storagePath) }) diff --git a/tests/dataApi/renameStorage-test.js b/tests/dataApi/renameStorage-test.js index f5c64cb6..46be9827 100644 --- a/tests/dataApi/renameStorage-test.js +++ b/tests/dataApi/renameStorage-test.js @@ -6,7 +6,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const _ = require('lodash') const TestDummy = require('../fixtures/TestDummy') @@ -15,24 +18,24 @@ const os = require('os') const storagePath = path.join(os.tmpdir(), 'test/rename-storage') -test.beforeEach((t) => { +test.beforeEach(t => { t.context.storage = TestDummy.dummyStorage(storagePath) localStorage.setItem('storages', JSON.stringify([t.context.storage.cache])) }) -test.serial('Rename a storage', (t) => { +test.serial('Rename a storage', t => { const storageKey = t.context.storage.cache.key return Promise.resolve() - .then(function doTest () { + .then(function doTest() { return renameStorage(storageKey, 'changed') }) - .then(function assert (data) { + .then(function assert(data) { const cachedStorageList = JSON.parse(localStorage.getItem('storages')) - t.true(_.find(cachedStorageList, {key: storageKey}).name === 'changed') + t.true(_.find(cachedStorageList, { key: storageKey }).name === 'changed') }) }) -test.after(function after () { +test.after(function after() { localStorage.clear() sander.rimrafSync(storagePath) }) diff --git a/tests/dataApi/reorderFolder-test.js b/tests/dataApi/reorderFolder-test.js index 55bff0eb..01694b8c 100644 --- a/tests/dataApi/reorderFolder-test.js +++ b/tests/dataApi/reorderFolder-test.js @@ -6,7 +6,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const _ = require('lodash') const TestDummy = require('../fixtures/TestDummy') @@ -16,32 +19,34 @@ const CSON = require('@rokt33r/season') const storagePath = path.join(os.tmpdir(), 'test/reorder-folder') -test.beforeEach((t) => { +test.beforeEach(t => { t.context.storage = TestDummy.dummyStorage(storagePath) localStorage.setItem('storages', JSON.stringify([t.context.storage.cache])) }) -test.serial('Reorder a folder', (t) => { +test.serial('Reorder a folder', t => { const storageKey = t.context.storage.cache.key const firstFolderKey = t.context.storage.json.folders[0].key const secondFolderKey = t.context.storage.json.folders[1].key return Promise.resolve() - .then(function doTest () { + .then(function doTest() { return reorderFolder(storageKey, 0, 1) }) - .then(function assert (data) { + .then(function assert(data) { t.true(_.nth(data.storage.folders, 0).key === secondFolderKey) t.true(_.nth(data.storage.folders, 1).key === firstFolderKey) - const jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json')) + const jsonData = CSON.readFileSync( + path.join(data.storage.path, 'boostnote.json') + ) t.true(_.nth(jsonData.folders, 0).key === secondFolderKey) t.true(_.nth(jsonData.folders, 1).key === firstFolderKey) }) }) -test.after(function after () { +test.after(function after() { localStorage.clear() sander.rimrafSync(storagePath) }) diff --git a/tests/dataApi/toggleStorage-test.js b/tests/dataApi/toggleStorage-test.js index 5169a4f4..87ed0059 100644 --- a/tests/dataApi/toggleStorage-test.js +++ b/tests/dataApi/toggleStorage-test.js @@ -6,7 +6,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const _ = require('lodash') const TestDummy = require('../fixtures/TestDummy') @@ -15,24 +18,24 @@ const os = require('os') const storagePath = path.join(os.tmpdir(), 'test/toggle-storage') -test.beforeEach((t) => { +test.beforeEach(t => { t.context.storage = TestDummy.dummyStorage(storagePath) localStorage.setItem('storages', JSON.stringify([t.context.storage.cache])) }) -test.serial('Toggle a storage location', (t) => { +test.serial('Toggle a storage location', t => { const storageKey = t.context.storage.cache.key return Promise.resolve() - .then(function doTest () { + .then(function doTest() { return toggleStorage(storageKey, true) }) - .then(function assert (data) { + .then(function assert(data) { const cachedStorageList = JSON.parse(localStorage.getItem('storages')) - t.true(_.find(cachedStorageList, {key: storageKey}).isOpen === true) + t.true(_.find(cachedStorageList, { key: storageKey }).isOpen === true) }) }) -test.after(function after () { +test.after(function after() { localStorage.clear() sander.rimrafSync(storagePath) }) diff --git a/tests/dataApi/updateFolder-test.js b/tests/dataApi/updateFolder-test.js index ca9fcf99..75ad71eb 100644 --- a/tests/dataApi/updateFolder-test.js +++ b/tests/dataApi/updateFolder-test.js @@ -6,7 +6,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const _ = require('lodash') const TestDummy = require('../fixtures/TestDummy') @@ -16,12 +19,12 @@ const CSON = require('@rokt33r/season') const storagePath = path.join(os.tmpdir(), 'test/update-folder') -test.beforeEach((t) => { +test.beforeEach(t => { t.context.storage = TestDummy.dummyStorage(storagePath) localStorage.setItem('storages', JSON.stringify([t.context.storage.cache])) }) -test.serial('Update a folder', (t) => { +test.serial('Update a folder', t => { const storageKey = t.context.storage.cache.key const folderKey = t.context.storage.json.folders[0].key const input = { @@ -29,18 +32,20 @@ test.serial('Update a folder', (t) => { color: '#FF0000' } return Promise.resolve() - .then(function doTest () { + .then(function doTest() { return updateFolder(storageKey, folderKey, input) }) - .then(function assert (data) { + .then(function assert(data) { t.true(_.find(data.storage.folders, input) != null) - const jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json')) + const jsonData = CSON.readFileSync( + path.join(data.storage.path, 'boostnote.json') + ) console.log(path.join(data.storage.path, 'boostnote.json')) t.true(_.find(jsonData.folders, input) != null) }) }) -test.after(function after () { +test.after(function after() { localStorage.clear() sander.rimrafSync(storagePath) }) diff --git a/tests/dataApi/updateNote-test.js b/tests/dataApi/updateNote-test.js index da47c30c..40e60b64 100644 --- a/tests/dataApi/updateNote-test.js +++ b/tests/dataApi/updateNote-test.js @@ -7,7 +7,10 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const TestDummy = require('../fixtures/TestDummy') const sander = require('sander') @@ -17,27 +20,33 @@ const faker = require('faker') const storagePath = path.join(os.tmpdir(), 'test/update-note') -test.beforeEach((t) => { +test.beforeEach(t => { t.context.storage = TestDummy.dummyStorage(storagePath) localStorage.setItem('storages', JSON.stringify([t.context.storage.cache])) }) -test.serial('Update a note', (t) => { +test.serial('Update a note', t => { const storageKey = t.context.storage.cache.key const folderKey = t.context.storage.json.folders[0].key - const randLinesHighlightedArray = new Array(10).fill().map(() => Math.round(Math.random() * 10)) - const randLinesHighlightedArray2 = new Array(15).fill().map(() => Math.round(Math.random() * 15)) + const randLinesHighlightedArray = new Array(10) + .fill() + .map(() => Math.round(Math.random() * 10)) + const randLinesHighlightedArray2 = new Array(15) + .fill() + .map(() => Math.round(Math.random() * 15)) const input1 = { type: 'SNIPPET_NOTE', description: faker.lorem.lines(), - snippets: [{ - name: faker.system.fileName(), - mode: 'text', - content: faker.lorem.lines(), - linesHighlighted: randLinesHighlightedArray - }], + snippets: [ + { + name: faker.system.fileName(), + mode: 'text', + content: faker.lorem.lines(), + linesHighlighted: randLinesHighlightedArray + } + ], tags: faker.lorem.words().split(' '), folder: folderKey } @@ -55,12 +64,14 @@ test.serial('Update a note', (t) => { const input3 = { type: 'SNIPPET_NOTE', description: faker.lorem.lines(), - snippets: [{ - name: faker.system.fileName(), - mode: 'text', - content: faker.lorem.lines(), - linesHighlighted: randLinesHighlightedArray2 - }], + snippets: [ + { + name: faker.system.fileName(), + mode: 'text', + content: faker.lorem.lines(), + linesHighlighted: randLinesHighlightedArray2 + } + ], tags: faker.lorem.words().split(' ') } input3.title = input3.description.split('\n').shift() @@ -74,26 +85,26 @@ test.serial('Update a note', (t) => { input4.title = input4.content.split('\n').shift() return Promise.resolve() - .then(function doTest () { - return Promise - .all([ - createNote(storageKey, input1), - createNote(storageKey, input2) + .then(function doTest() { + return Promise.all([ + createNote(storageKey, input1), + createNote(storageKey, input2) + ]).then(function updateNotes(data) { + const data1 = data[0] + const data2 = data[1] + return Promise.all([ + updateNote(data1.storage, data1.key, input3), + updateNote(data1.storage, data2.key, input4) ]) - .then(function updateNotes (data) { - const data1 = data[0] - const data2 = data[1] - return Promise.all([ - updateNote(data1.storage, data1.key, input3), - updateNote(data1.storage, data2.key, input4) - ]) - }) + }) }) - .then(function assert (data) { + .then(function assert(data) { const data1 = data[0] const data2 = data[1] - const jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson')) + const jsonData1 = CSON.readFileSync( + path.join(storagePath, 'notes', data1.key + '.cson') + ) t.is(input3.title, data1.title) t.is(input3.title, jsonData1.title) t.is(input3.description, data1.description) @@ -106,10 +117,18 @@ test.serial('Update a note', (t) => { t.is(input3.snippets[0].content, jsonData1.snippets[0].content) t.is(input3.snippets[0].name, data1.snippets[0].name) t.is(input3.snippets[0].name, jsonData1.snippets[0].name) - t.deepEqual(input3.snippets[0].linesHighlighted, data1.snippets[0].linesHighlighted) - t.deepEqual(input3.snippets[0].linesHighlighted, jsonData1.snippets[0].linesHighlighted) + t.deepEqual( + input3.snippets[0].linesHighlighted, + data1.snippets[0].linesHighlighted + ) + t.deepEqual( + input3.snippets[0].linesHighlighted, + jsonData1.snippets[0].linesHighlighted + ) - const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson')) + const jsonData2 = CSON.readFileSync( + path.join(storagePath, 'notes', data2.key + '.cson') + ) t.is(input4.title, data2.title) t.is(input4.title, jsonData2.title) t.is(input4.content, data2.content) @@ -121,7 +140,7 @@ test.serial('Update a note', (t) => { }) }) -test.after(function after () { +test.after(function after() { localStorage.clear() sander.rimrafSync(storagePath) }) diff --git a/tests/dataApi/updateSnippet-test.js b/tests/dataApi/updateSnippet-test.js index 662548bd..5e8fb3a9 100644 --- a/tests/dataApi/updateSnippet-test.js +++ b/tests/dataApi/updateSnippet-test.js @@ -21,20 +21,20 @@ const newSnippet = { content: 'new content' } -test.beforeEach((t) => { +test.beforeEach(t => { sander.writeFileSync(snippetFile, JSON.stringify([oldSnippet])) }) -test.serial('Update a snippet', (t) => { +test.serial('Update a snippet', t => { return Promise.resolve() - .then(function doTest () { - return Promise.all([ - updateSnippet(newSnippet, snippetFile) - ]) + .then(function doTest() { + return Promise.all([updateSnippet(newSnippet, snippetFile)]) }) - .then(function assert () { + .then(function assert() { const snippets = JSON.parse(sander.readFileSync(snippetFile)) - const snippet = snippets.find(currentSnippet => currentSnippet.id === newSnippet.id) + const snippet = snippets.find( + currentSnippet => currentSnippet.id === newSnippet.id + ) t.not(snippet, undefined) t.is(snippet.name, newSnippet.name) t.deepEqual(snippet.prefix, newSnippet.prefix) diff --git a/tests/date-formatter-test.js b/tests/date-formatter-test.js index 265ca4c4..c6de28c6 100644 --- a/tests/date-formatter-test.js +++ b/tests/date-formatter-test.js @@ -5,8 +5,5 @@ const test = require('ava') const { formatDate } = require('browser/lib/date-formatter') test(t => { - t.throws( - () => formatDate('invalid argument'), - 'Invalid argument.' - ) + t.throws(() => formatDate('invalid argument'), 'Invalid argument.') }) diff --git a/tests/fixtures/TestDummy.js b/tests/fixtures/TestDummy.js index 62cae846..0c0a95d5 100644 --- a/tests/fixtures/TestDummy.js +++ b/tests/fixtures/TestDummy.js @@ -5,7 +5,7 @@ const sander = require('sander') const CSON = require('@rokt33r/season') const path = require('path') -function dummyFolder (override = {}) { +function dummyFolder(override = {}) { var data = { name: faker.lorem.word(), color: faker.internet.color() @@ -17,21 +17,23 @@ function dummyFolder (override = {}) { return data } -function dummyBoostnoteJSONData (override = {}, isLegacy = false) { +function dummyBoostnoteJSONData(override = {}, isLegacy = false) { var data = {} if (override.folders == null) { data.folders = [] - var folderCount = Math.floor((Math.random() * 5)) + 2 + var folderCount = Math.floor(Math.random() * 5) + 2 for (var i = 0; i < folderCount; i++) { var key = keygen() - while (data.folders.some((folder) => folder.key === key)) { + while (data.folders.some(folder => folder.key === key)) { key = keygen() } - data.folders.push(dummyFolder({ - key - })) + data.folders.push( + dummyFolder({ + key + }) + ) } } if (!isLegacy) data.version = '1.0' @@ -41,24 +43,28 @@ function dummyBoostnoteJSONData (override = {}, isLegacy = false) { return data } -function dummyNote (override = {}) { - var data = Math.random() > 0.5 - ? { - type: 'MARKDOWN_NOTE', - content: faker.lorem.lines() - } - : { - type: 'SNIPPET_NOTE', - description: faker.lorem.lines(), - snippets: [{ - name: faker.system.fileName(), - mode: 'text', - content: faker.lorem.lines() - }] - } - data.title = data.type === 'MARKDOWN_NOTE' - ? data.content.split('\n').shift() - : data.description.split('\n').shift() +function dummyNote(override = {}) { + var data = + Math.random() > 0.5 + ? { + type: 'MARKDOWN_NOTE', + content: faker.lorem.lines() + } + : { + type: 'SNIPPET_NOTE', + description: faker.lorem.lines(), + snippets: [ + { + name: faker.system.fileName(), + mode: 'text', + content: faker.lorem.lines() + } + ] + } + data.title = + data.type === 'MARKDOWN_NOTE' + ? data.content.split('\n').shift() + : data.description.split('\n').shift() data.createdAt = faker.date.past() data.updatedAt = faker.date.recent() data.isStarred = false @@ -91,36 +97,41 @@ function dummyNote (override = {}) { * ``` * @return {[type]} */ -function dummyStorage (storagePath, override = {}) { - var jsonData = override.json != null - ? override.json - : dummyBoostnoteJSONData() - var cacheData = override.cache != null - ? override.cache - : {} +function dummyStorage(storagePath, override = {}) { + var jsonData = + override.json != null ? override.json : dummyBoostnoteJSONData() + var cacheData = override.cache != null ? override.cache : {} if (cacheData.key == null) cacheData.key = keygen() if (cacheData.name == null) cacheData.name = faker.random.word() if (cacheData.type == null) cacheData.type = 'FILESYSTEM' cacheData.path = storagePath - sander.writeFileSync(path.join(storagePath, 'boostnote.json'), JSON.stringify(jsonData)) + sander.writeFileSync( + path.join(storagePath, 'boostnote.json'), + JSON.stringify(jsonData) + ) var notesData = [] - var noteCount = Math.floor((Math.random() * 15)) + 2 + var noteCount = Math.floor(Math.random() * 15) + 2 for (var i = 0; i < noteCount; i++) { var key = keygen(true) - while (notesData.some((note) => note.key === key)) { + while (notesData.some(note => note.key === key)) { key = keygen(true) } var noteData = dummyNote({ key, - folder: jsonData.folders[Math.floor(Math.random() * jsonData.folders.length)].key + folder: + jsonData.folders[Math.floor(Math.random() * jsonData.folders.length)] + .key }) notesData.push(noteData) } - notesData.forEach(function saveNoteCSON (note) { - CSON.writeFileSync(path.join(storagePath, 'notes', note.key + '.cson'), _.omit(note, ['key'])) + notesData.forEach(function saveNoteCSON(note) { + CSON.writeFileSync( + path.join(storagePath, 'notes', note.key + '.cson'), + _.omit(note, ['key']) + ) }) return { @@ -130,27 +141,27 @@ function dummyStorage (storagePath, override = {}) { } } -function dummyLegacyStorage (storagePath, override = {}) { - var jsonData = override.json != null - ? override.json - : dummyBoostnoteJSONData({}, true) - var cacheData = override.cache != null - ? override.cache - : {} +function dummyLegacyStorage(storagePath, override = {}) { + var jsonData = + override.json != null ? override.json : dummyBoostnoteJSONData({}, true) + var cacheData = override.cache != null ? override.cache : {} if (cacheData.key == null) cacheData.key = keygen() if (cacheData.name == null) cacheData.name = faker.random.word() if (cacheData.type == null) cacheData.type = 'FILESYSTEM' cacheData.path = storagePath - sander.writeFileSync(path.join(storagePath, 'boostnote.json'), JSON.stringify(jsonData)) + sander.writeFileSync( + path.join(storagePath, 'boostnote.json'), + JSON.stringify(jsonData) + ) var notesData = [] for (var j = 0; j < jsonData.folders.length; j++) { var folderNotes = [] - var noteCount = Math.floor((Math.random() * 5)) + 1 + var noteCount = Math.floor(Math.random() * 5) + 1 for (var i = 0; i < noteCount; i++) { var key = keygen(true) - while (folderNotes.some((note) => note.key === key)) { + while (folderNotes.some(note => note.key === key)) { key = keygen(true) } @@ -161,7 +172,10 @@ function dummyLegacyStorage (storagePath, override = {}) { folderNotes.push(noteData) } notesData = notesData.concat(folderNotes) - CSON.writeFileSync(path.join(storagePath, jsonData.folders[j].key, 'data.json'), {notes: folderNotes.map((note) => _.omit(note, ['folder']))}) + CSON.writeFileSync( + path.join(storagePath, jsonData.folders[j].key, 'data.json'), + { notes: folderNotes.map(note => _.omit(note, ['folder'])) } + ) } return { diff --git a/tests/helpers/setup-browser-env.js b/tests/helpers/setup-browser-env.js index 3e3232b7..81237b82 100644 --- a/tests/helpers/setup-browser-env.js +++ b/tests/helpers/setup-browser-env.js @@ -2,14 +2,14 @@ import browserEnv from 'browser-env' browserEnv(['window', 'document', 'navigator']) // for CodeMirror mockup -document.body.createTextRange = function () { +document.body.createTextRange = function() { return { - setEnd: function () {}, - setStart: function () {}, - getBoundingClientRect: function () { - return {right: 0} + setEnd: function() {}, + setStart: function() {}, + getBoundingClientRect: function() { + return { right: 0 } }, - getClientRects: function () { + getClientRects: function() { return { length: 0, left: 0, @@ -21,7 +21,7 @@ document.body.createTextRange = function () { window.localStorage = { // polyfill - getItem () { + getItem() { return '{}' } } diff --git a/tests/jest.js b/tests/jest.js index 6f830c67..9e59fab6 100644 --- a/tests/jest.js +++ b/tests/jest.js @@ -2,7 +2,7 @@ global.Raphael = { setWindow: jest.fn(), registerFont: jest.fn(), - fn: function () { + fn: function() { return {} } } diff --git a/tests/lib/contextMenuBuilder.test.js b/tests/lib/contextMenuBuilder.test.js index b7009bf1..689fb5f4 100644 --- a/tests/lib/contextMenuBuilder.test.js +++ b/tests/lib/contextMenuBuilder.test.js @@ -1,18 +1,32 @@ let menuBuilderParameter jest.mock('electron', () => { - return {remote: {require: jest.fn(() => { return {Menu: {buildFromTemplate: jest.fn((param) => { menuBuilderParameter = param })}} })}} + return { + remote: { + require: jest.fn(() => { + return { + Menu: { + buildFromTemplate: jest.fn(param => { + menuBuilderParameter = param + }) + } + } + }) + } + } }) const spellcheck = require('browser/lib/spellcheck') -const buildEditorContextMenu = require('browser/lib/contextMenuBuilder').buildEditorContextMenu -const buildMarkdownPreviewContextMenu = require('browser/lib/contextMenuBuilder').buildMarkdownPreviewContextMenu +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 () { +it('should make sure that no context menu is build if the passed editor instance was null', function() { const event = { pageX: 12, pageY: 12 @@ -21,89 +35,96 @@ it('should make sure that no context menu is build if the passed editor instance expect(menuBuilderParameter).toEqual(null) }) -it('should make sure that word suggestions are only requested if the word contained a typo', function () { +it('should make sure that word suggestions are only requested if the word contained a typo', function() { spellcheck.getSpellingSuggestion = jest.fn() const editor = jest.fn() editor.coordsChar = jest.fn() - editor.findWordAt = jest.fn(() => { return {anchor: {}, head: {}} }) + editor.findWordAt = jest.fn(() => { + return { anchor: {}, head: {} } + }) editor.getRange = jest.fn() editor.findMarks = jest.fn(() => []) const event = { pageX: 12, pageY: 12 } - const expectedMenuParameter = [ { role: 'cut' }, + const expectedMenuParameter = [ + { role: 'cut' }, { role: 'copy' }, { role: 'paste' }, - { role: 'selectall' } ] + { role: 'selectall' } + ] buildEditorContextMenu(editor, event) expect(menuBuilderParameter).toEqual(expectedMenuParameter) expect(spellcheck.getSpellingSuggestion).not.toHaveBeenCalled() }) -it('should make sure that word suggestions are only requested if the word contained a typo and no other mark', function () { +it('should make sure that word suggestions are only requested if the word contained a typo and no other mark', function() { spellcheck.getSpellingSuggestion = jest.fn() spellcheck.getCSSClassName = jest.fn(() => 'dummyErrorClassName') const editor = jest.fn() editor.coordsChar = jest.fn() - editor.findWordAt = jest.fn(() => { return {anchor: {}, head: {}} }) + editor.findWordAt = jest.fn(() => { + return { anchor: {}, head: {} } + }) editor.getRange = jest.fn() - const dummyMarks = [ - {className: 'someStupidClassName'} - ] + const dummyMarks = [{ className: 'someStupidClassName' }] editor.findMarks = jest.fn(() => dummyMarks) const event = { pageX: 12, pageY: 12 } - const expectedMenuParameter = [ { role: 'cut' }, + const expectedMenuParameter = [ + { role: 'cut' }, { role: 'copy' }, { role: 'paste' }, - { role: 'selectall' } ] + { role: 'selectall' } + ] buildEditorContextMenu(editor, event) expect(menuBuilderParameter).toEqual(expectedMenuParameter) expect(spellcheck.getSpellingSuggestion).not.toHaveBeenCalled() }) -it('should make sure that word suggestions calls the right editor functions', function () { +it('should make sure that word suggestions calls the right editor functions', function() { spellcheck.getSpellingSuggestion = jest.fn() spellcheck.getCSSClassName = jest.fn(() => 'dummyErrorClassName') - const dummyCursor = {dummy: 'dummy'} - const dummyRange = {anchor: {test: 'test'}, head: {test2: 'test2'}} + const dummyCursor = { dummy: 'dummy' } + const dummyRange = { anchor: { test: 'test' }, head: { test2: 'test2' } } const editor = jest.fn() editor.coordsChar = jest.fn(() => dummyCursor) editor.findWordAt = jest.fn(() => dummyRange) editor.getRange = jest.fn() - const dummyMarks = [ - {className: 'someStupidClassName'} - ] + const dummyMarks = [{ className: 'someStupidClassName' }] editor.findMarks = jest.fn(() => dummyMarks) const event = { pageX: 12, pageY: 21 } - const expectedCoordsCharCall = {left: event.pageX, top: event.pageY} + const expectedCoordsCharCall = { left: event.pageX, top: event.pageY } buildEditorContextMenu(editor, event) expect(editor.coordsChar).toHaveBeenCalledWith(expectedCoordsCharCall) expect(editor.findWordAt).toHaveBeenCalledWith(dummyCursor) - expect(editor.getRange).toHaveBeenCalledWith(dummyRange.anchor, dummyRange.head) + expect(editor.getRange).toHaveBeenCalledWith( + dummyRange.anchor, + dummyRange.head + ) }) -it('should make sure that word suggestions creates a correct menu if there was an error', function () { +it('should make sure that word suggestions creates a correct menu if there was an error', function() { const suggestions = ['test1', 'test2', 'Pustekuchen'] const errorClassName = 'errorCSS' const wordToCorrect = 'pustekuchen' - const dummyMarks = [ - {className: errorClassName} - ] + const dummyMarks = [{ className: errorClassName }] spellcheck.getSpellingSuggestion = jest.fn(() => suggestions) spellcheck.getCSSClassName = jest.fn(() => errorClassName) const editor = jest.fn() editor.coordsChar = jest.fn() - editor.findWordAt = jest.fn(() => { return {anchor: {}, head: {}} }) + editor.findWordAt = jest.fn(() => { + return { anchor: {}, head: {} } + }) editor.getRange = jest.fn(() => wordToCorrect) editor.findMarks = jest.fn(() => []) @@ -128,7 +149,7 @@ it('should make sure that word suggestions creates a correct menu if there was a }) // Markdown Preview Context Menu -it('should make sure that no context menu is built if the Markdown Preview instance was null', function () { +it('should make sure that no context menu is built if the Markdown Preview instance was null', function() { const event = { pageX: 12, pageY: 12 diff --git a/tests/lib/find-storage-test.js b/tests/lib/find-storage-test.js index 3d7fdc63..ab3b07a6 100644 --- a/tests/lib/find-storage-test.js +++ b/tests/lib/find-storage-test.js @@ -6,14 +6,17 @@ global.window = document.defaultView global.navigator = window.navigator const Storage = require('dom-storage') -const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const localStorage = (window.localStorage = global.localStorage = new Storage( + null, + { strict: true } +)) const path = require('path') const TestDummy = require('../fixtures/TestDummy') const sander = require('sander') const os = require('os') const storagePath = path.join(os.tmpdir(), 'test/find-storage') -test.beforeEach((t) => { +test.beforeEach(t => { t.context.storage = TestDummy.dummyStorage(storagePath) localStorage.setItem('storages', JSON.stringify([t.context.storage.cache])) }) @@ -26,7 +29,7 @@ test('findStorage() should return a correct storage path(string)', t => { t.is(findStorage(storageKey).path, storagePath) }) -test.after(function after () { +test.after(function after() { localStorage.clear() sander.rimrafSync(storagePath) }) diff --git a/tests/lib/find-title-test.js b/tests/lib/find-title-test.js index 103b8774..2498cdc0 100644 --- a/tests/lib/find-title-test.js +++ b/tests/lib/find-title-test.js @@ -20,7 +20,11 @@ test('findNoteTitle#find should return a correct title (string)', t => { testCases.forEach(testCase => { const [input, expected] = testCase - t.is(findNoteTitle(input, false), expected, `Test for find() input: ${input} expected: ${expected}`) + t.is( + findNoteTitle(input, false), + expected, + `Test for find() input: ${input} expected: ${expected}` + ) }) }) @@ -34,21 +38,32 @@ test('findNoteTitle#find should ignore front matter when enableFrontMatterTitle testCases.forEach(testCase => { const [input, expected] = testCase - t.is(findNoteTitle(input, false), expected, `Test for find() input: ${input} expected: ${expected}`) + t.is( + findNoteTitle(input, false), + expected, + `Test for find() input: ${input} expected: ${expected}` + ) }) }) test('findNoteTitle#find should respect front matter when enableFrontMatterTitle=true', t => { // [input, expected] const testCases = [ - ['---\nlayout: test\ntitle: hoge hoge hoge \n---\n# fuga', 'hoge hoge hoge'], + [ + '---\nlayout: test\ntitle: hoge hoge hoge \n---\n# fuga', + 'hoge hoge hoge' + ], ['---\ntitle:hoge\n---\n# fuga', 'hoge'], ['title: fuga\n# hoge', '# hoge'] ] testCases.forEach(testCase => { const [input, expected] = testCase - t.is(findNoteTitle(input, true), expected, `Test for find() input: ${input} expected: ${expected}`) + t.is( + findNoteTitle(input, true), + expected, + `Test for find() input: ${input} expected: ${expected}` + ) }) }) @@ -61,6 +76,10 @@ test('findNoteTitle#find should respect frontMatterTitleField when provided', t testCases.forEach(testCase => { const [input, expected] = testCase - t.is(findNoteTitle(input, true, 'custom'), expected, `Test for find() input: ${input} expected: ${expected}`) + t.is( + findNoteTitle(input, true, 'custom'), + expected, + `Test for find() input: ${input} expected: ${expected}` + ) }) }) diff --git a/tests/lib/get-todo-status-test.js b/tests/lib/get-todo-status-test.js index db74ec56..52c57cfe 100644 --- a/tests/lib/get-todo-status-test.js +++ b/tests/lib/get-todo-status-test.js @@ -40,8 +40,15 @@ test('getTodoStatus should return a correct hash object', t => { testCases.forEach(testCase => { const [input, expected] = testCase - t.is(getTodoStatus(input).total, expected.total, `Test for getTodoStatus() input: ${input} expected: ${expected.total}`) - t.is(getTodoStatus(input).completed, expected.completed, `Test for getTodoStatus() input: ${input} expected: ${expected.completed}`) + t.is( + getTodoStatus(input).total, + expected.total, + `Test for getTodoStatus() input: ${input} expected: ${expected.total}` + ) + t.is( + getTodoStatus(input).completed, + expected.completed, + `Test for getTodoStatus() input: ${input} expected: ${expected.completed}` + ) }) }) - diff --git a/tests/lib/html-text-helper-test.js b/tests/lib/html-text-helper-test.js index 538b8757..9e6eb083 100644 --- a/tests/lib/html-text-helper-test.js +++ b/tests/lib/html-text-helper-test.js @@ -9,16 +9,23 @@ test('htmlTextHelper#decodeEntities should return encoded text (string)', t => { // [input, expected] const testCases = [ ['<a href=', 'Boostnote'], - ['<\\\\?php\n var = 'hoge';', '<\\\\?php\n var = \'hoge\';'], + ['var test = 'test'', "var test = 'test'"], + [ + '<a href='https://boostnote.io'>Boostnote', + "Boostnote" + ], + ['<\\\\?php\n var = 'hoge';', "<\\\\?php\n var = 'hoge';"], ['&', '&'], - ['a$'', 'a\\$\''] + ['a$'', "a\\$'"] ] testCases.forEach(testCase => { const [input, expected] = testCase - t.is(htmlTextHelper.decodeEntities(input), expected, `Test for decodeEntities() input: ${input} expected: ${expected}`) + t.is( + htmlTextHelper.decodeEntities(input), + expected, + `Test for decodeEntities() input: ${input} expected: ${expected}` + ) }) }) @@ -26,29 +33,40 @@ test('htmlTextHelper#decodeEntities() should return decoded text (string)', t => // [input, expected] const testCases = [ ['Boostnote', '<a href='https://boostnote.io'>Boostnote'], - ['Boostnote", + '<a href='https://boostnote.io'>Boostnote' + ], + [" { const [input, expected] = testCase - t.is(htmlTextHelper.encodeEntities(input), expected, `Test for encodeEntities() input: ${input} expected: ${expected}`) + t.is( + htmlTextHelper.encodeEntities(input), + expected, + `Test for encodeEntities() input: ${input} expected: ${expected}` + ) }) }) // Integration test test(t => { const testCases = [ - 'var test = \'test\'', - 'Boostnote', - '' + "var test = 'test'", + "Boostnote", + "" ] testCases.forEach(testCase => { const encodedText = htmlTextHelper.encodeEntities(testCase) const decodedText = htmlTextHelper.decodeEntities(encodedText) - t.is(decodedText, testCase, 'Integration test through encodedText() and decodedText()') + t.is( + decodedText, + testCase, + 'Integration test through encodedText() and decodedText()' + ) }) }) diff --git a/tests/lib/markdown-text-helper-test.js b/tests/lib/markdown-text-helper-test.js index 38ee3136..07d05dde 100644 --- a/tests/lib/markdown-text-helper-test.js +++ b/tests/lib/markdown-text-helper-test.js @@ -42,6 +42,10 @@ test(t => { testCases.forEach(testCase => { const [input, expected] = testCase - t.is(markdown.strip(input), expected, `Test for strip() input: ${input} expected: ${expected}`) + t.is( + markdown.strip(input), + expected, + `Test for strip() input: ${input} expected: ${expected}` + ) }) }) diff --git a/tests/lib/markdown-toc-generator-test.js b/tests/lib/markdown-toc-generator-test.js index 60568741..def2bcf8 100644 --- a/tests/lib/markdown-toc-generator-test.js +++ b/tests/lib/markdown-toc-generator-test.js @@ -261,7 +261,11 @@ this is a text const expectedToc = testCase[2].trim() const generatedToc = markdownToc.generate(inputMd) - t.is(generatedToc, expectedToc, `generate test : ${title} , generated : ${EOL}${generatedToc}, expected : ${EOL}${expectedToc}`) + t.is( + generatedToc, + expectedToc, + `generate test : ${title} , generated : ${EOL}${generatedToc}, expected : ${EOL}${expectedToc}` + ) }) }) @@ -279,7 +283,7 @@ test(t => { const testCases = [ [ `***************************** Empty note, cursor at the top`, - {line: 0, ch: 0}, + { line: 0, ch: 0 }, ``, ` @@ -291,7 +295,7 @@ test(t => { ], [ `***************************** Two level note,TOC at the beginning `, - {line: 0, ch: 0}, + { line: 0, ch: 0 }, ` # one this is a level one text @@ -329,7 +333,7 @@ this is a level one text ], [ `***************************** Two level note, cursor just after 'header text' `, - {line: 1, ch: 12}, + { line: 1, ch: 12 }, ` # header header text @@ -373,7 +377,7 @@ this is a level one text ], [ `***************************** Two level note, cursor at empty line under 'header text' `, - {line: 2, ch: 0}, + { line: 2, ch: 0 }, ` # header header text @@ -416,7 +420,7 @@ this is a level one text ], [ `***************************** Two level note, cursor just before 'text' word`, - {line: 1, ch: 8}, + { line: 1, ch: 8 }, ` # header header text @@ -461,7 +465,7 @@ this is a level one text ], [ `***************************** Already generated TOC without header file, regenerate TOC in place, no changes`, - {line: 13, ch: 0}, + { line: 13, ch: 0 }, ` # header header text @@ -511,7 +515,7 @@ this is a level one text ], [ `***************************** Already generated TOC, needs updating in place`, - {line: 0, ch: 0}, + { line: 0, ch: 0 }, ` # header header text @@ -561,7 +565,7 @@ this is a level one text ], [ `***************************** Document with cursor at the last line, expecting empty TOC `, - {line: 13, ch: 30}, + { line: 13, ch: 30 }, ` # header header text @@ -602,7 +606,7 @@ this is a level one text ], [ `***************************** Empty, not actual TOC , should be supplemented with two new points beneath`, - {line: 0, ch: 0}, + { line: 0, ch: 0 }, ` # header header text @@ -663,6 +667,10 @@ this is a level one text editor.setCursor(cursor) markdownToc.generateInEditor(editor) - t.is(expectedMd, editor.getValue(), `generateInEditor test : ${title} , generated : ${EOL}${editor.getValue()}, expected : ${EOL}${expectedMd}`) + t.is( + expectedMd, + editor.getValue(), + `generateInEditor test : ${title} , generated : ${EOL}${editor.getValue()}, expected : ${EOL}${expectedMd}` + ) }) }) diff --git a/tests/lib/normalize-editor-font-family-test.js b/tests/lib/normalize-editor-font-family-test.js index aacd03ac..beb2b765 100644 --- a/tests/lib/normalize-editor-font-family-test.js +++ b/tests/lib/normalize-editor-font-family-test.js @@ -12,5 +12,8 @@ test('normalizeEditorFontFamily() should return default font family (string[])', test('normalizeEditorFontFamily(["hoge", "huga"]) should return default font family connected with arg.', t => { const arg = 'font1, font2' - t.is(normalizeEditorFontFamily(arg), `${arg}, ${defaultEditorFontFamily.join(', ')}`) + t.is( + normalizeEditorFontFamily(arg), + `${arg}, ${defaultEditorFontFamily.join(', ')}` + ) }) diff --git a/tests/lib/rc-parser-test.js b/tests/lib/rc-parser-test.js index 024a2d36..2c8213ea 100644 --- a/tests/lib/rc-parser-test.js +++ b/tests/lib/rc-parser-test.js @@ -4,8 +4,42 @@ const { parse } = require('browser/lib/RcParser') // Unit test test('RcParser should return a json object', t => { - const validJson = { 'editor': { 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleMain': 'Control + L' }, 'listWidth': 135, 'navWidth': 135 } - const allJson = { 'amaEnabled': true, 'editor': { 'fontFamily': 'Monaco, Consolas', 'fontSize': '14', 'indentSize': '2', 'indentType': 'space', 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleMain': 'Cmd + Alt + L' }, 'isSideNavFolded': false, 'listStyle': 'DEFAULT', 'listWidth': 174, 'navWidth': 200, 'preview': { 'codeBlockTheme': 'dracula', 'fontFamily': 'Lato', 'fontSize': '14', 'lineNumber': true }, 'sortBy': { 'default': 'UPDATED_AT' }, 'ui': { 'defaultNote': 'ALWAYS_ASK', 'disableDirectWrite': false, 'theme': 'default' }, 'zoom': 1 } + const validJson = { + editor: { keyMap: 'vim', switchPreview: 'BLUR', theme: 'monokai' }, + hotkey: { toggleMain: 'Control + L' }, + listWidth: 135, + navWidth: 135 + } + const allJson = { + amaEnabled: true, + editor: { + fontFamily: 'Monaco, Consolas', + fontSize: '14', + indentSize: '2', + indentType: 'space', + keyMap: 'vim', + switchPreview: 'BLUR', + theme: 'monokai' + }, + hotkey: { toggleMain: 'Cmd + Alt + L' }, + isSideNavFolded: false, + listStyle: 'DEFAULT', + listWidth: 174, + navWidth: 200, + preview: { + codeBlockTheme: 'dracula', + fontFamily: 'Lato', + fontSize: '14', + lineNumber: true + }, + sortBy: { default: 'UPDATED_AT' }, + ui: { + defaultNote: 'ALWAYS_ASK', + disableDirectWrite: false, + theme: 'default' + }, + zoom: 1 + } // [input, expected] const validTestCases = [ @@ -13,21 +47,27 @@ test('RcParser should return a json object', t => { ['.boostnoterc.all', allJson] ] - const invalidTestCases = [ - ['.boostnoterc.invalid', {}] - ] + const invalidTestCases = [['.boostnoterc.invalid', {}]] validTestCases.forEach(validTestCase => { const [input, expected] = validTestCase - t.is(parse(filePath(input)).editor.keyMap, expected.editor.keyMap, `Test for getTodoStatus() input: ${input} expected: ${expected.keyMap}`) + t.is( + parse(filePath(input)).editor.keyMap, + expected.editor.keyMap, + `Test for getTodoStatus() input: ${input} expected: ${expected.keyMap}` + ) }) invalidTestCases.forEach(invalidTestCase => { const [input, expected] = invalidTestCase - t.is(parse(filePath(input)).editor, expected.editor, `Test for getTodoStatus() input: ${input} expected: ${expected.editor}`) + t.is( + parse(filePath(input)).editor, + expected.editor, + `Test for getTodoStatus() input: ${input} expected: ${expected.editor}` + ) }) }) -function filePath (filename) { +function filePath(filename) { return path.join(`${__dirname}/boostnoterc`, filename) } diff --git a/tests/lib/search-test.js b/tests/lib/search-test.js index 2e288d26..75180d9e 100644 --- a/tests/lib/search-test.js +++ b/tests/lib/search-test.js @@ -3,14 +3,21 @@ import searchFromNotes from 'browser/lib/search' import { dummyNote } from '../fixtures/TestDummy' import _ from 'lodash' -const pickContents = (notes) => notes.map((note) => { return note.content }) +const pickContents = notes => + notes.map(note => { + return note.content + }) let notes = [] let note1, note2, note3 test.before(t => { const data1 = { type: 'MARKDOWN_NOTE', content: 'content1', tags: ['tag1'] } - const data2 = { type: 'MARKDOWN_NOTE', content: 'content1\ncontent2', tags: ['tag1', 'tag2'] } + const data2 = { + type: 'MARKDOWN_NOTE', + content: 'content1\ncontent2', + tags: ['tag1', 'tag2'] + } const data3 = { type: 'MARKDOWN_NOTE', content: '#content4', tags: ['tag1'] } note1 = dummyNote(data1) @@ -34,12 +41,12 @@ test('it can find notes by tags and words', t => { ['#tag2 content1', [note2.content]], ['content1 #tag2', [note2.content]] ] - const testWithTagsWithoutHash = testWithTags.map(function (testCase) { + const testWithTagsWithoutHash = testWithTags.map(function(testCase) { return [testCase[0].replace(/#/g, ''), testCase[1]] }) const testCases = testWithTags.concat(testWithTagsWithoutHash) - testCases.forEach((testCase) => { + testCases.forEach(testCase => { const [input, expectedContents] = testCase const results = searchFromNotes(notes, input) t.true(_.isEqual(pickContents(results).sort(), expectedContents.sort())) diff --git a/tests/lib/slugify-test.js b/tests/lib/slugify-test.js index 0277bd10..39991bca 100644 --- a/tests/lib/slugify-test.js +++ b/tests/lib/slugify-test.js @@ -13,7 +13,7 @@ test('alphabet and digit', t => { test('should delete unavailable symbols', t => { const availableSymbols = '_-' - const testCase = availableSymbols + '][!\'#$%&()*+,./:;<=>?@\\^{|}~`' + const testCase = availableSymbols + "][!'#$%&()*+,./:;<=>?@\\^{|}~`" const decodeSlug = decodeURI(slugify(testCase)) t.true(decodeSlug === availableSymbols) diff --git a/tests/lib/spellcheck.test.js b/tests/lib/spellcheck.test.js index 6ebaaf3b..c3fc0b52 100644 --- a/tests/lib/spellcheck.test.js +++ b/tests/lib/spellcheck.test.js @@ -9,12 +9,12 @@ beforeEach(() => { Typo.mockClear() }) -it('should test that checkWord does not marks words that do not contain a typo', function () { +it('should test that checkWord does not marks words that do not contain a typo', function() { const testWord = 'testWord' const editor = jest.fn() editor.getRange = jest.fn(() => testWord) editor.markText = jest.fn() - const range = {anchor: {line: 1, ch: 0}, head: {line: 1, ch: 10}} + const range = { anchor: { line: 1, ch: 0 }, head: { line: 1, ch: 10 } } const mockDictionary = jest.fn() mockDictionary.check = jest.fn(() => true) systemUnderTest.setDictionaryForTestsOnly(mockDictionary) @@ -26,12 +26,12 @@ it('should test that checkWord does not marks words that do not contain a typo', expect(editor.markText).not.toHaveBeenCalled() }) -it('should test that checkWord should marks words that contain a typo', function () { +it('should test that checkWord should marks words that contain a typo', function() { const testWord = 'testWord' const editor = jest.fn() editor.getRange = jest.fn(() => testWord) editor.markText = jest.fn() - const range = {anchor: {line: 1, ch: 0}, head: {line: 1, ch: 10}} + const range = { anchor: { line: 1, ch: 0 }, head: { line: 1, ch: 10 } } const mockDictionary = jest.fn() mockDictionary.check = jest.fn(() => false) systemUnderTest.setDictionaryForTestsOnly(mockDictionary) @@ -40,14 +40,16 @@ it('should test that checkWord should marks words that contain a typo', function expect(editor.getRange).toHaveBeenCalledWith(range.anchor, range.head) expect(mockDictionary.check).toHaveBeenCalledWith(testWord) - expect(editor.markText).toHaveBeenCalledWith(range.anchor, range.head, {'className': systemUnderTest.CSS_ERROR_CLASS}) + expect(editor.markText).toHaveBeenCalledWith(range.anchor, range.head, { + className: systemUnderTest.CSS_ERROR_CLASS + }) }) -it('should test that setLanguage clears all marks', function () { +it('should test that setLanguage clears all marks', function() { const dummyMarks = [ - {clear: jest.fn()}, - {clear: jest.fn()}, - {clear: jest.fn()} + { clear: jest.fn() }, + { clear: jest.fn() }, + { clear: jest.fn() } ] const editor = jest.fn() editor.getAllMarks = jest.fn(() => dummyMarks) @@ -60,10 +62,12 @@ it('should test that setLanguage clears all marks', function () { } }) -it('should test that setLanguage with DISABLED as a lang argument should not load any dictionary and not check the whole document', function () { +it('should test that setLanguage with DISABLED as a lang argument should not load any dictionary and not check the whole document', function() { const editor = jest.fn() editor.getAllMarks = jest.fn(() => []) - const checkWholeDocumentSpy = jest.spyOn(systemUnderTest, 'checkWholeDocument').mockImplementation() + const checkWholeDocumentSpy = jest + .spyOn(systemUnderTest, 'checkWholeDocument') + .mockImplementation() systemUnderTest.setLanguage(editor, systemUnderTest.SPELLCHECK_DISABLED) @@ -72,38 +76,45 @@ it('should test that setLanguage with DISABLED as a lang argument should not loa checkWholeDocumentSpy.mockRestore() }) -it('should test that setLanguage loads the correct dictionary', function () { +it('should test that setLanguage loads the correct dictionary', function() { const editor = jest.fn() editor.getAllMarks = jest.fn(() => []) const lang = 'de_DE' - const checkWholeDocumentSpy = jest.spyOn(systemUnderTest, 'checkWholeDocument').mockImplementation() + const checkWholeDocumentSpy = jest + .spyOn(systemUnderTest, 'checkWholeDocument') + .mockImplementation() expect(Typo).not.toHaveBeenCalled() systemUnderTest.setLanguage(editor, lang) expect(Typo).toHaveBeenCalledWith(lang, false, false, expect.anything()) - expect(Typo.mock.calls[0][3].dictionaryPath).toEqual(systemUnderTest.DICTIONARY_PATH) + expect(Typo.mock.calls[0][3].dictionaryPath).toEqual( + systemUnderTest.DICTIONARY_PATH + ) expect(Typo.mock.calls[0][3].asyncLoad).toBe(true) checkWholeDocumentSpy.mockRestore() }) -it('should test that checkMultiLineRange performs checks for each word in the stated range', function () { +it('should test that checkMultiLineRange performs checks for each word in the stated range', function() { const dic = jest.fn() dic.check = jest.fn() systemUnderTest.setDictionaryForTestsOnly(dic) - document.body.createTextRange = jest.fn(() => document.createElement('textArea')) + document.body.createTextRange = jest.fn(() => + document.createElement('textArea') + ) const editor = new CodeMirror(jest.fn()) editor.setValue( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vehicula sem id tempor sollicitudin. Sed eu sagittis ligula. Maecenas sit amet velit enim. Etiam massa urna, elementum et sapien sit amet, vestibulum pharetra lectus. Nulla consequat malesuada nunc in aliquam. Vivamus faucibus orci et faucibus maximus. Pellentesque at dolor ac mi mollis molestie in facilisis nisl.\n' + - '\n' + - 'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' + - 'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' + - '\n' + - 'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' + - '\n' + - 'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ') - const rangeFrom = {line: 2, ch: 4} - const rangeTo = {line: 3, ch: 36} + '\n' + + 'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' + + 'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' + + '\n' + + 'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' + + '\n' + + 'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ' + ) + const rangeFrom = { line: 2, ch: 4 } + const rangeTo = { line: 3, ch: 36 } systemUnderTest.checkMultiLineRange(editor, rangeFrom, rangeTo) @@ -121,23 +132,26 @@ it('should test that checkMultiLineRange performs checks for each word in the st expect(dic.check.mock.calls[10][0]).toEqual('tristique') }) -it('should test that checkMultiLineRange works correct even when the range is inverted (from is the later position and to the lower)', function () { +it('should test that checkMultiLineRange works correct even when the range is inverted (from is the later position and to the lower)', function() { const dic = jest.fn() dic.check = jest.fn() systemUnderTest.setDictionaryForTestsOnly(dic) - document.body.createTextRange = jest.fn(() => document.createElement('textArea')) + document.body.createTextRange = jest.fn(() => + document.createElement('textArea') + ) const editor = new CodeMirror(jest.fn()) editor.setValue( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vehicula sem id tempor sollicitudin. Sed eu sagittis ligula. Maecenas sit amet velit enim. Etiam massa urna, elementum et sapien sit amet, vestibulum pharetra lectus. Nulla consequat malesuada nunc in aliquam. Vivamus faucibus orci et faucibus maximus. Pellentesque at dolor ac mi mollis molestie in facilisis nisl.\n' + - '\n' + - 'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' + - 'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' + - '\n' + - 'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' + - '\n' + - 'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ') - const rangeFrom = {line: 3, ch: 36} - const rangeTo = {line: 2, ch: 4} + '\n' + + 'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' + + 'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' + + '\n' + + 'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' + + '\n' + + 'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ' + ) + const rangeFrom = { line: 3, ch: 36 } + const rangeTo = { line: 2, ch: 4 } systemUnderTest.checkMultiLineRange(editor, rangeFrom, rangeTo) @@ -155,23 +169,26 @@ it('should test that checkMultiLineRange works correct even when the range is in expect(dic.check.mock.calls[10][0]).toEqual('tristique') }) -it('should test that checkMultiLineRange works for single line', function () { +it('should test that checkMultiLineRange works for single line', function() { const dic = jest.fn() dic.check = jest.fn() systemUnderTest.setDictionaryForTestsOnly(dic) - document.body.createTextRange = jest.fn(() => document.createElement('textArea')) + document.body.createTextRange = jest.fn(() => + document.createElement('textArea') + ) const editor = new CodeMirror(jest.fn()) editor.setValue( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vehicula sem id tempor sollicitudin. Sed eu sagittis ligula. Maecenas sit amet velit enim. Etiam massa urna, elementum et sapien sit amet, vestibulum pharetra lectus. Nulla consequat malesuada nunc in aliquam. Vivamus faucibus orci et faucibus maximus. Pellentesque at dolor ac mi mollis molestie in facilisis nisl.\n' + - '\n' + - 'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' + - 'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' + - '\n' + - 'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' + - '\n' + - 'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ') - const rangeFrom = {line: 5, ch: 14} - const rangeTo = {line: 5, ch: 39} + '\n' + + 'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' + + 'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' + + '\n' + + 'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' + + '\n' + + 'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ' + ) + const rangeFrom = { line: 5, ch: 14 } + const rangeTo = { line: 5, ch: 39 } systemUnderTest.checkMultiLineRange(editor, rangeFrom, rangeTo) @@ -181,23 +198,26 @@ it('should test that checkMultiLineRange works for single line', function () { expect(dic.check.mock.calls[2][0]).toEqual('ullamcorper') }) -it('should test that checkMultiLineRange works for single word', function () { +it('should test that checkMultiLineRange works for single word', function() { const dic = jest.fn() dic.check = jest.fn() systemUnderTest.setDictionaryForTestsOnly(dic) - document.body.createTextRange = jest.fn(() => document.createElement('textArea')) + document.body.createTextRange = jest.fn(() => + document.createElement('textArea') + ) const editor = new CodeMirror(jest.fn()) editor.setValue( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vehicula sem id tempor sollicitudin. Sed eu sagittis ligula. Maecenas sit amet velit enim. Etiam massa urna, elementum et sapien sit amet, vestibulum pharetra lectus. Nulla consequat malesuada nunc in aliquam. Vivamus faucibus orci et faucibus maximus. Pellentesque at dolor ac mi mollis molestie in facilisis nisl.\n' + - '\n' + - 'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' + - 'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' + - '\n' + - 'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' + - '\n' + - 'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ') - const rangeFrom = {line: 7, ch: 6} - const rangeTo = {line: 7, ch: 6} + '\n' + + 'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' + + 'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' + + '\n' + + 'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' + + '\n' + + 'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ' + ) + const rangeFrom = { line: 7, ch: 6 } + const rangeTo = { line: 7, ch: 6 } systemUnderTest.checkMultiLineRange(editor, rangeFrom, rangeTo) @@ -205,8 +225,10 @@ it('should test that checkMultiLineRange works for single word', function () { expect(dic.check.mock.calls[0][0]).toEqual('molestie') }) -it('should make sure that liveSpellcheck don\'t work if the spellcheck is not enabled', function () { - const checkMultiLineRangeSpy = jest.spyOn(systemUnderTest, 'checkMultiLineRange').mockImplementation() +it("should make sure that liveSpellcheck don't work if the spellcheck is not enabled", function() { + const checkMultiLineRangeSpy = jest + .spyOn(systemUnderTest, 'checkMultiLineRange') + .mockImplementation() const editor = jest.fn() editor.findMarks = jest.fn() @@ -219,61 +241,88 @@ it('should make sure that liveSpellcheck don\'t work if the spellcheck is not en checkMultiLineRangeSpy.mockRestore() }) -it('should make sure that liveSpellcheck works for a range of changes', function () { +it('should make sure that liveSpellcheck works for a range of changes', function() { const editor = jest.fn() - const marks = [{clear: jest.fn()}, {clear: jest.fn()}] + const marks = [{ clear: jest.fn() }, { clear: jest.fn() }] editor.findMarks = jest.fn(() => marks) - const checkMultiLineRangeSpy = jest.spyOn(systemUnderTest, 'checkMultiLineRange').mockImplementation() + const checkMultiLineRangeSpy = jest + .spyOn(systemUnderTest, 'checkMultiLineRange') + .mockImplementation() - const inputChangeRange = {from: {line: 0, ch: 2}, to: {line: 1, ch: 1}} - const inputChangeRangeTo = {from: {line: 0, ch: 2}, to: {line: 1, ch: 2}} + const inputChangeRange = { from: { line: 0, ch: 2 }, to: { line: 1, ch: 1 } } + const inputChangeRangeTo = { + from: { line: 0, ch: 2 }, + to: { line: 1, ch: 2 } + } systemUnderTest.setDictionaryForTestsOnly({}) systemUnderTest.checkChangeRange(editor, inputChangeRange, inputChangeRangeTo) - expect(checkMultiLineRangeSpy).toHaveBeenCalledWith(editor, {line: 0, ch: 1}, {line: 1, ch: 3}) - expect(editor.findMarks).toHaveBeenCalledWith({line: 0, ch: 1}, {line: 1, ch: 3}) + expect(checkMultiLineRangeSpy).toHaveBeenCalledWith( + editor, + { line: 0, ch: 1 }, + { line: 1, ch: 3 } + ) + expect(editor.findMarks).toHaveBeenCalledWith( + { line: 0, ch: 1 }, + { line: 1, ch: 3 } + ) expect(marks[0].clear).toHaveBeenCalled() expect(marks[1].clear).toHaveBeenCalled() checkMultiLineRangeSpy.mockRestore() }) -it('should make sure that liveSpellcheck works if ranges are inverted', function () { +it('should make sure that liveSpellcheck works if ranges are inverted', function() { const editor = jest.fn() - const marks = [{clear: jest.fn()}, {clear: jest.fn()}] + const marks = [{ clear: jest.fn() }, { clear: jest.fn() }] editor.findMarks = jest.fn(() => marks) - const checkMultiLineRangeSpy = jest.spyOn(systemUnderTest, 'checkMultiLineRange').mockImplementation() + const checkMultiLineRangeSpy = jest + .spyOn(systemUnderTest, 'checkMultiLineRange') + .mockImplementation() - const inputChangeRange = {from: {line: 0, ch: 2}, to: {line: 1, ch: 2}} - const inputChangeRangeTo = {from: {line: 0, ch: 2}, to: {line: 1, ch: 1}} + const inputChangeRange = { from: { line: 0, ch: 2 }, to: { line: 1, ch: 2 } } + const inputChangeRangeTo = { + from: { line: 0, ch: 2 }, + to: { line: 1, ch: 1 } + } systemUnderTest.setDictionaryForTestsOnly({}) systemUnderTest.checkChangeRange(editor, inputChangeRange, inputChangeRangeTo) - expect(checkMultiLineRangeSpy).toHaveBeenCalledWith(editor, {line: 0, ch: 1}, {line: 1, ch: 3}) - expect(editor.findMarks).toHaveBeenCalledWith({line: 0, ch: 1}, {line: 1, ch: 3}) + expect(checkMultiLineRangeSpy).toHaveBeenCalledWith( + editor, + { line: 0, ch: 1 }, + { line: 1, ch: 3 } + ) + expect(editor.findMarks).toHaveBeenCalledWith( + { line: 0, ch: 1 }, + { line: 1, ch: 3 } + ) expect(marks[0].clear).toHaveBeenCalled() expect(marks[1].clear).toHaveBeenCalled() checkMultiLineRangeSpy.mockRestore() }) -it('should make sure that liveSpellcheck works for a single word with change at the beginning', function () { +it('should make sure that liveSpellcheck works for a single word with change at the beginning', function() { const dic = jest.fn() dic.check = jest.fn() systemUnderTest.setDictionaryForTestsOnly(dic) - document.body.createTextRange = jest.fn(() => document.createElement('textArea')) + document.body.createTextRange = jest.fn(() => + document.createElement('textArea') + ) const editor = new CodeMirror(jest.fn()) editor.setValue( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vehicula sem id tempor sollicitudin. Sed eu sagittis ligula. Maecenas sit amet velit enim. Etiam massa urna, elementum et sapien sit amet, vestibulum pharetra lectus. Nulla consequat malesuada nunc in aliquam. Vivamus faucibus orci et faucibus maximus. Pellentesque at dolor ac mi mollis molestie in facilisis nisl.\n' + - '\n' + - 'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' + - 'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' + - '\n' + - 'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' + - '\n' + - 'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ') - const rangeFrom = {from: {line: 7, ch: 6}, to: {line: 7, ch: 6}} - const rangeTo = {from: {line: 7, ch: 6}, to: {line: 7, ch: 6}} + '\n' + + 'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' + + 'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' + + '\n' + + 'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' + + '\n' + + 'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ' + ) + const rangeFrom = { from: { line: 7, ch: 6 }, to: { line: 7, ch: 6 } } + const rangeTo = { from: { line: 7, ch: 6 }, to: { line: 7, ch: 6 } } systemUnderTest.checkChangeRange(editor, rangeFrom, rangeTo) @@ -281,23 +330,26 @@ it('should make sure that liveSpellcheck works for a single word with change at expect(dic.check.mock.calls[0][0]).toEqual('molestie') }) -it('should make sure that liveSpellcheck works for a single word with change in the middle', function () { +it('should make sure that liveSpellcheck works for a single word with change in the middle', function() { const dic = jest.fn() dic.check = jest.fn() systemUnderTest.setDictionaryForTestsOnly(dic) - document.body.createTextRange = jest.fn(() => document.createElement('textArea')) + document.body.createTextRange = jest.fn(() => + document.createElement('textArea') + ) const editor = new CodeMirror(jest.fn()) editor.setValue( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vehicula sem id tempor sollicitudin. Sed eu sagittis ligula. Maecenas sit amet velit enim. Etiam massa urna, elementum et sapien sit amet, vestibulum pharetra lectus. Nulla consequat malesuada nunc in aliquam. Vivamus faucibus orci et faucibus maximus. Pellentesque at dolor ac mi mollis molestie in facilisis nisl.\n' + - '\n' + - 'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' + - 'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' + - '\n' + - 'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' + - '\n' + - 'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ') - const rangeFrom = {from: {line: 7, ch: 9}, to: {line: 7, ch: 9}} - const rangeTo = {from: {line: 7, ch: 9}, to: {line: 7, ch: 9}} + '\n' + + 'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' + + 'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' + + '\n' + + 'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' + + '\n' + + 'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ' + ) + const rangeFrom = { from: { line: 7, ch: 9 }, to: { line: 7, ch: 9 } } + const rangeTo = { from: { line: 7, ch: 9 }, to: { line: 7, ch: 9 } } systemUnderTest.checkChangeRange(editor, rangeFrom, rangeTo) @@ -305,23 +357,26 @@ it('should make sure that liveSpellcheck works for a single word with change in expect(dic.check.mock.calls[0][0]).toEqual('molestie') }) -it('should make sure that liveSpellcheck works for a single word with change at the end', function () { +it('should make sure that liveSpellcheck works for a single word with change at the end', function() { const dic = jest.fn() dic.check = jest.fn() systemUnderTest.setDictionaryForTestsOnly(dic) - document.body.createTextRange = jest.fn(() => document.createElement('textArea')) + document.body.createTextRange = jest.fn(() => + document.createElement('textArea') + ) const editor = new CodeMirror(jest.fn()) editor.setValue( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vehicula sem id tempor sollicitudin. Sed eu sagittis ligula. Maecenas sit amet velit enim. Etiam massa urna, elementum et sapien sit amet, vestibulum pharetra lectus. Nulla consequat malesuada nunc in aliquam. Vivamus faucibus orci et faucibus maximus. Pellentesque at dolor ac mi mollis molestie in facilisis nisl.\n' + - '\n' + - 'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' + - 'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' + - '\n' + - 'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' + - '\n' + - 'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ') - const rangeFrom = {from: {line: 7, ch: 14}, to: {line: 7, ch: 14}} - const rangeTo = {from: {line: 7, ch: 14}, to: {line: 7, ch: 14}} + '\n' + + 'Nam id lacus et elit sollicitudin vestibulum. Phasellus blandit laoreet odio \n' + + 'Ut tristique risus et mi tristique, in aliquam odio laoreet. Curabitur nunc felis, mollis ut laoreet quis, finibus in nibh. Proin urna risus, rhoncus at diam interdum, maximus vestibulum nulla. Maecenas ut rutrum nulla, vel finibus est. Etiam placerat mi et libero volutpat, tristique rhoncus felis volutpat. Donec quam erat, congue quis ligula eget, mollis aliquet elit. Vestibulum feugiat odio sit amet ex dignissim, sit amet vulputate lectus iaculis. Sed tempus id enim at eleifend. Nullam bibendum eleifend congue. Pellentesque varius arcu elit, at accumsan dolor ultrices vitae. Etiam condimentum lectus id dolor fringilla tempor. Aliquam nec fringilla sem. Fusce ac quam porta, molestie nunc sed, semper nisl. Curabitur luctus sem in dapibus gravida. Suspendisse scelerisque mollis rutrum. Proin lacinia dolor sit amet ornare condimentum.\n' + + '\n' + + 'In ex neque, volutpat quis ullamcorper in, vestibulum vel ligula. Quisque lobortis eget neque quis ullamcorper. Nunc purus lorem, scelerisque in malesuada id, congue a magna. Donec rutrum maximus egestas. Nulla ornare libero quis odio ultricies iaculis. Suspendisse consectetur bibendum purus ac blandit. Donec et neque quis dolor eleifend tempus. Fusce fringilla risus id venenatis rutrum. Mauris commodo posuere ipsum, sit amet hendrerit risus lacinia quis. Aenean placerat ultricies ante id dapibus. Donec imperdiet eros quis porttitor accumsan. Vestibulum ut nulla luctus velit feugiat elementum. Nam vel pharetra nisl. Nullam risus tellus, tempor quis ipsum et, pretium rutrum ipsum.\n' + + '\n' + + 'Fusce molestie leo at facilisis mollis. Vivamus iaculis facilisis fermentum. Vivamus blandit id nisi sit amet porta. Nunc luctus porta blandit. Sed ac consequat eros, eu fringilla lorem. In blandit pharetra sollicitudin. Vivamus placerat risus ut ex faucibus, nec vehicula sapien imperdiet. Praesent luctus, leo eget ultrices cursus, neque ante porttitor mauris, id tempus tellus urna at ex. Curabitur elementum id quam vitae condimentum. Proin sit amet magna vel metus blandit iaculis. Phasellus viverra libero in lacus gravida, id laoreet ligula dapibus. Cras commodo arcu eget mi dignissim, et lobortis elit faucibus. Suspendisse potenti. ' + ) + const rangeFrom = { from: { line: 7, ch: 14 }, to: { line: 7, ch: 14 } } + const rangeTo = { from: { line: 7, ch: 14 }, to: { line: 7, ch: 14 } } systemUnderTest.checkChangeRange(editor, rangeFrom, rangeTo) diff --git a/webpack-production.config.js b/webpack-production.config.js index bcfb2a42..9c5a0b42 100644 --- a/webpack-production.config.js +++ b/webpack-production.config.js @@ -14,7 +14,8 @@ var config = Object.assign({}, skeleton, { { test: /\.styl$/, exclude: /(node_modules|bower_components)/, - loader: 'style!css?modules&importLoaders=1&localIdentName=[name]__[local]___[path]!stylus?sourceMap' + loader: + 'style!css?modules&importLoaders=1&localIdentName=[name]__[local]___[path]!stylus?sourceMap' }, { test: /\.json$/, @@ -35,8 +36,8 @@ var config = Object.assign({}, skeleton, { new webpack.optimize.OccurenceOrderPlugin(), new webpack.DefinePlugin({ 'process.env': { - 'NODE_ENV': JSON.stringify('production'), - 'BABEL_ENV': JSON.stringify('production') + NODE_ENV: JSON.stringify('production'), + BABEL_ENV: JSON.stringify('production') } }) ] diff --git a/webpack.config.js b/webpack.config.js index ad3c4f8b..ac0b91db 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -12,7 +12,8 @@ var config = Object.assign({}, skeleton, { { test: /\.styl$/, exclude: /(node_modules|bower_components)/, - loader: 'style!css?modules&importLoaders=1&localIdentName=[name]__[local]___[path]!stylus?sourceMap' + loader: + 'style!css?modules&importLoaders=1&localIdentName=[name]__[local]___[path]!stylus?sourceMap' }, { test: /\.json$/, @@ -39,4 +40,3 @@ var config = Object.assign({}, skeleton, { }) module.exports = config - diff --git a/yarn.lock b/yarn.lock index 2d153615..7a2f8985 100644 --- a/yarn.lock +++ b/yarn.lock @@ -193,6 +193,11 @@ ajv-keywords@^1.0.0: version "1.5.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" +ajv-keywords@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" + integrity sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I= + ajv@^4.7.0: version "4.11.8" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" @@ -200,7 +205,7 @@ ajv@^4.7.0: co "^4.6.0" json-stable-stringify "^1.0.1" -ajv@^5.1.0: +ajv@^5.1.0, ajv@^5.2.3, ajv@^5.3.0: version "5.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" dependencies: @@ -665,7 +670,7 @@ aws4@^1.6.0: version "1.7.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" -babel-code-frame@^6.16.0, babel-code-frame@^6.26.0: +babel-code-frame@^6.16.0, babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: @@ -1691,6 +1696,20 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.3.2, chalk@^2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^2.1.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chardet@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" + integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I= + chart.js@^2.7.2: version "2.7.2" resolved "http://registry.npm.taobao.org/chart.js/download/chart.js-2.7.2.tgz#3c9fde4dc5b95608211bdefeda7e5d33dffa5714" @@ -2051,7 +2070,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@1.6.2, concat-stream@^1.4.6, concat-stream@^1.5.2: +concat-stream@1.6.2, concat-stream@^1.4.6, concat-stream@^1.5.2, concat-stream@^1.6.0: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" dependencies: @@ -2232,7 +2251,7 @@ cross-env@^5.2.0: cross-spawn "^6.0.5" is-windows "^1.0.0" -cross-spawn@^5.0.1: +cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -2905,7 +2924,7 @@ doctrine@^1.2.2: esutils "^2.0.2" isarray "^1.0.0" -doctrine@^2.0.0, doctrine@^2.0.2: +doctrine@^2.0.2, doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" dependencies: @@ -3329,6 +3348,13 @@ escope@^3.6.0: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-config-prettier@^6.10.0: + version "6.10.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.10.0.tgz#7b15e303bf9c956875c948f6b21500e48ded6a7f" + integrity sha512-AtndijGte1rPILInUdHjvKEGbIV06NuvPrqlIEaEaWtbtvJh464mDeyGMdZEQMsGvC0ZVkiex1fSNcC4HAbRGg== + dependencies: + get-stdin "^6.0.0" + eslint-config-standard-jsx@3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-3.2.0.tgz#c240e26ed919a11a42aa4de8059472b38268d620" @@ -3341,6 +3367,13 @@ eslint-config-standard@6.2.1, eslint-config-standard@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-6.2.1.tgz#d3a68aafc7191639e7ee441e7348739026354292" +eslint-plugin-prettier@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz#432e5a667666ab84ce72f945c72f77d996a5c9ba" + integrity sha512-GlolCC9y3XZfv3RQfwGew7NnuFDKsfI4lbvRK+PIIo23SFH+LemGs4cKwzAaRa+Mdb+lQO/STaIayno8T5sJJA== + dependencies: + prettier-linter-helpers "^1.0.0" + eslint-plugin-promise@~3.4.0: version "3.4.2" resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.4.2.tgz#1be2793eafe2d18b5b123b8136c269f804fe7122" @@ -3369,45 +3402,62 @@ eslint-plugin-standard@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-2.0.1.tgz#3589699ff9c917f2c25f76a916687f641c369ff3" -eslint@^3.13.1: - version "3.19.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.19.0.tgz#c8fc6201c7f40dd08941b87c085767386a679acc" +eslint-scope@^3.7.1: + version "3.7.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535" + integrity sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA== dependencies: - babel-code-frame "^6.16.0" - chalk "^1.1.3" - concat-stream "^1.5.2" - debug "^2.1.1" - doctrine "^2.0.0" - escope "^3.6.0" - espree "^3.4.0" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-visitor-keys@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" + integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== + +eslint@^4.18.2: + version "4.19.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" + integrity sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ== + dependencies: + ajv "^5.3.0" + babel-code-frame "^6.22.0" + chalk "^2.1.0" + concat-stream "^1.6.0" + cross-spawn "^5.1.0" + debug "^3.1.0" + doctrine "^2.1.0" + eslint-scope "^3.7.1" + eslint-visitor-keys "^1.0.0" + espree "^3.5.4" esquery "^1.0.0" - estraverse "^4.2.0" esutils "^2.0.2" file-entry-cache "^2.0.0" - glob "^7.0.3" - globals "^9.14.0" - ignore "^3.2.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.0.1" + ignore "^3.3.3" imurmurhash "^0.1.4" - inquirer "^0.12.0" - is-my-json-valid "^2.10.0" + inquirer "^3.0.6" is-resolvable "^1.0.0" - js-yaml "^3.5.1" - json-stable-stringify "^1.0.0" + js-yaml "^3.9.1" + json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" - lodash "^4.0.0" - mkdirp "^0.5.0" + lodash "^4.17.4" + minimatch "^3.0.2" + mkdirp "^0.5.1" natural-compare "^1.4.0" optionator "^0.8.2" - path-is-inside "^1.0.1" - pluralize "^1.2.1" - progress "^1.1.8" - require-uncached "^1.0.2" - shelljs "^0.7.5" - strip-bom "^3.0.0" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + regexpp "^1.0.1" + require-uncached "^1.0.3" + semver "^5.3.0" + strip-ansi "^4.0.0" strip-json-comments "~2.0.1" - table "^3.7.8" + table "4.0.2" text-table "~0.2.0" - user-home "^2.0.0" eslint@~3.10.2: version "3.10.2" @@ -3457,7 +3507,7 @@ espower-location-detector@^1.0.0: source-map "^0.5.0" xtend "^4.0.0" -espree@^3.3.1, espree@^3.4.0: +espree@^3.3.1, espree@^3.5.4: version "3.5.4" resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" dependencies: @@ -3673,6 +3723,15 @@ extend@~3.0.1: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== +external-editor@^2.0.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" + integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A== + dependencies: + chardet "^0.4.0" + iconv-lite "^0.4.17" + tmp "^0.0.33" + extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" @@ -3721,6 +3780,11 @@ fast-diff@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" @@ -4075,6 +4139,11 @@ function-name-support@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/function-name-support/-/function-name-support-0.2.0.tgz#55d3bfaa6eafd505a50f9bc81fdf57564a0bb071" +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + galactus@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/galactus/-/galactus-0.2.1.tgz#cbed2d20a40c1f5679a35908e2b9415733e78db9" @@ -4247,7 +4316,12 @@ global@^4.3.0: min-document "^2.19.0" process "~0.5.1" -globals@^9.14.0, globals@^9.18.0, globals@^9.2.0: +globals@^11.0.1: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^9.18.0, globals@^9.2.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -4739,6 +4813,13 @@ iconv-lite@0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" +iconv-lite@^0.4.17: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + iconv-lite@~0.2.11: version "0.2.11" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8" @@ -4771,6 +4852,11 @@ ignore@^3.0.9, ignore@^3.2.0: version "3.3.8" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.8.tgz#3f8e9c35d38708a3a7e0e9abb6c73e7ee7707b2b" +ignore@^3.3.3: + version "3.3.10" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" + integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== + immutable@^3.8.1: version "3.8.2" resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3" @@ -4856,6 +4942,26 @@ inquirer@^0.12.0: strip-ansi "^3.0.0" through "^2.3.6" +inquirer@^3.0.6: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" + integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ== + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.0.4" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + interpret@^0.6.4: version "0.6.6" resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b" @@ -5614,7 +5720,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" -js-yaml@^3.10.0, js-yaml@^3.13.1, js-yaml@^3.5.1, js-yaml@^3.7.0, js-yaml@^3.8.1, js-yaml@^3.9.0: +js-yaml@^3.10.0, js-yaml@^3.13.1, js-yaml@^3.5.1, js-yaml@^3.7.0, js-yaml@^3.8.1, js-yaml@^3.9.0, js-yaml@^3.9.1: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== @@ -5781,6 +5887,11 @@ json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" @@ -6663,6 +6774,11 @@ mute-stream@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= + nan@^2.9.2: version "2.10.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" @@ -7088,7 +7204,7 @@ os-locale@^2.0.0: lcid "^1.0.0" mem "^1.1.0" -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -7245,7 +7361,7 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" -path-is-inside@^1.0.1: +path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" @@ -7385,6 +7501,11 @@ pluralize@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" +pluralize@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow== + pn@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" @@ -7643,6 +7764,13 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + prettier@^1.18.2: version "1.18.2" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" @@ -7701,6 +7829,11 @@ progress@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" @@ -8333,6 +8466,11 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" +regexpp@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" + integrity sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw== + regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" @@ -8474,7 +8612,7 @@ require-precompiled@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/require-precompiled/-/require-precompiled-0.1.0.tgz#5a1b52eb70ebed43eb982e974c85ab59571e56fa" -require-uncached@^1.0.2: +require-uncached@^1.0.2, require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" dependencies: @@ -8566,6 +8704,13 @@ run-async@^0.1.0: dependencies: once "^1.3.0" +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= + dependencies: + is-promise "^2.1.0" + run-node@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/run-node/-/run-node-1.0.0.tgz#46b50b946a2aa2d4947ae1d886e9856fd9cabe5e" @@ -8578,6 +8723,18 @@ rw@1: version "1.3.3" resolved "http://registry.npm.taobao.org/rw/download/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74= + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ= + rx-lite@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" @@ -8863,7 +9020,7 @@ slice-ansi@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" -slice-ansi@^1.0.0: +slice-ansi@1.0.0, slice-ansi@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" dependencies: @@ -9184,7 +9341,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: @@ -9378,6 +9535,18 @@ symbol-tree@^3.2.1, symbol-tree@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" +table@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" + integrity sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA== + dependencies: + ajv "^5.2.3" + ajv-keywords "^2.1.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" + string-width "^2.1.1" + table@^3.7.8: version "3.8.3" resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" @@ -9509,6 +9678,13 @@ tmp@0.0.28: dependencies: os-tmpdir "~1.0.1" +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"