diff --git a/browser/components/CodeEditor.js b/browser/components/CodeEditor.js index 31361b9b..7719ed90 100644 --- a/browser/components/CodeEditor.js +++ b/browser/components/CodeEditor.js @@ -73,12 +73,16 @@ export default class CodeEditor extends React.Component { this.scrollToLineHandeler = this.scrollToLine.bind(this) this.formatTable = () => this.handleFormatTable() - this.contextMenuHandler = function (editor, event) { - const menu = buildEditorContextMenu(editor, event) - if (menu != null) { - setTimeout(() => menu.popup(remote.getCurrentWindow()), 30) + + if (props.switchPreview !== 'RIGHTCLICK') { + this.contextMenuHandler = function (editor, event) { + const menu = buildEditorContextMenu(editor, event) + if (menu != null) { + setTimeout(() => menu.popup(remote.getCurrentWindow()), 30) + } } } + this.editorActivityHandler = () => this.handleEditorActivity() this.turndownService = new TurndownService() @@ -258,7 +262,9 @@ export default class CodeEditor extends React.Component { this.editor.on('blur', this.blurHandler) this.editor.on('change', this.changeHandler) this.editor.on('paste', this.pasteHandler) - this.editor.on('contextmenu', this.contextMenuHandler) + if (this.props.switchPreview !== 'RIGHTCLICK') { + this.editor.on('contextmenu', this.contextMenuHandler) + } eventEmitter.on('top:search', this.searchHandler) eventEmitter.emit('code:init') diff --git a/browser/components/MarkdownEditor.js b/browser/components/MarkdownEditor.js index f1aa8d73..d3270c18 100644 --- a/browser/components/MarkdownEditor.js +++ b/browser/components/MarkdownEditor.js @@ -280,6 +280,7 @@ class MarkdownEditor extends React.Component { spellCheck={config.editor.spellcheck} enableSmartPaste={config.editor.enableSmartPaste} hotkey={config.hotkey} + switchPreview={config.editor.switchPreview} /> { - let result = noteContent - if (this.props && this.props.storagePath && this.props.noteKey) { - const attachmentsAbsolutePaths = attachmentManagement.getAbsolutePathsOfAttachmentsInContent( - noteContent, - this.props.storagePath - ) - attachmentsAbsolutePaths.forEach(attachment => { - exportTasks.push({ - src: attachment, - dst: attachmentManagement.DESTINATION_FOLDER - }) - }) - result = attachmentManagement.removeStorageAndNoteReferences( - noteContent, - this.props.noteKey - ) - } - return result - }) + this.exportAsDocument('md') } handleSaveAsHtml () { @@ -339,11 +320,6 @@ export default class MarkdownPreview extends React.Component { ) let body = this.markdown.render(noteContent) const files = [this.GetCodeThemeLink(codeBlockTheme), ...CSS_FILES] - const attachmentsAbsolutePaths = attachmentManagement.getAbsolutePathsOfAttachmentsInContent( - noteContent, - this.props.storagePath - ) - files.forEach(file => { if (global.process.platform === 'win32') { file = file.replace('file:///', '') @@ -355,16 +331,6 @@ export default class MarkdownPreview extends React.Component { dst: 'css' }) }) - attachmentsAbsolutePaths.forEach(attachment => { - exportTasks.push({ - src: attachment, - dst: attachmentManagement.DESTINATION_FOLDER - }) - }) - body = attachmentManagement.removeStorageAndNoteReferences( - body, - this.props.noteKey - ) let styles = '' files.forEach(file => { @@ -397,8 +363,9 @@ export default class MarkdownPreview extends React.Component { if (filename) { const content = this.props.value const storage = this.props.storagePath + const nodeKey = this.props.noteKey - exportNote(storage, content, filename, contentFormatter) + exportNote(nodeKey, storage, content, filename, contentFormatter) .then(res => { dialog.showMessageBox(remote.getCurrentWindow(), { type: 'info', diff --git a/browser/components/MarkdownSplitEditor.js b/browser/components/MarkdownSplitEditor.js index fb7b21f5..bd79bc24 100644 --- a/browser/components/MarkdownSplitEditor.js +++ b/browser/components/MarkdownSplitEditor.js @@ -174,6 +174,7 @@ class MarkdownSplitEditor extends React.Component { spellCheck={config.editor.spellcheck} enableSmartPaste={config.editor.enableSmartPaste} hotkey={config.hotkey} + switchPreview={config.editor.switchPreview} />
this.handleMouseDown(e)} >
diff --git a/browser/main/Detail/InfoPanel.js b/browser/main/Detail/InfoPanel.js index 4ce610fa..15535186 100644 --- a/browser/main/Detail/InfoPanel.js +++ b/browser/main/Detail/InfoPanel.js @@ -70,22 +70,22 @@ class InfoPanel extends React.Component {
- - - - diff --git a/browser/main/Detail/InfoPanelTrashed.js b/browser/main/Detail/InfoPanelTrashed.js index db64a284..d4c8045d 100644 --- a/browser/main/Detail/InfoPanelTrashed.js +++ b/browser/main/Detail/InfoPanelTrashed.js @@ -31,17 +31,17 @@ const InfoPanelTrashed = ({
- - - diff --git a/browser/main/Detail/SnippetNoteDetail.js b/browser/main/Detail/SnippetNoteDetail.js index c839fb94..887e5237 100644 --- a/browser/main/Detail/SnippetNoteDetail.js +++ b/browser/main/Detail/SnippetNoteDetail.js @@ -645,11 +645,18 @@ class SnippetNoteDetail extends React.Component { if (infoPanel.style) infoPanel.style.display = infoPanel.style.display === 'none' ? 'inline' : 'none' } - showWarning () { + showWarning (e, msg) { + const warningMessage = (msg) => ({ + 'export-txt': 'Text export', + 'export-md': 'Markdown export', + 'export-html': 'HTML export', + 'print': 'Print' + })[msg] + dialog.showMessageBox(remote.getCurrentWindow(), { type: 'warning', message: i18n.__('Sorry!'), - detail: i18n.__('md/text import is available only a markdown note.'), + detail: i18n.__(warningMessage(msg) + ' is available only in markdown notes.'), buttons: [i18n.__('OK')] }) } @@ -802,7 +809,9 @@ class SnippetNoteDetail extends React.Component { createdAt={formatDate(note.createdAt)} exportAsMd={this.showWarning} exportAsTxt={this.showWarning} + exportAsHtml={this.showWarning} type={note.type} + print={this.showWarning} />
diff --git a/browser/main/NoteList/index.js b/browser/main/NoteList/index.js index 7bb52ccd..d1c8d14a 100644 --- a/browser/main/NoteList/index.js +++ b/browser/main/NoteList/index.js @@ -64,13 +64,14 @@ class NoteList extends React.Component { this.focusHandler = () => { this.refs.list.focus() } - this.alertIfSnippetHandler = () => { - this.alertIfSnippet() + this.alertIfSnippetHandler = (event, msg) => { + this.alertIfSnippet(msg) } this.importFromFileHandler = this.importFromFile.bind(this) this.jumpNoteByHash = this.jumpNoteByHashHandler.bind(this) this.handleNoteListKeyUp = this.handleNoteListKeyUp.bind(this) this.getNoteKeyFromTargetIndex = this.getNoteKeyFromTargetIndex.bind(this) + this.cloneNote = this.cloneNote.bind(this) this.deleteNote = this.deleteNote.bind(this) this.focusNote = this.focusNote.bind(this) this.pinToTop = this.pinToTop.bind(this) @@ -96,6 +97,7 @@ class NoteList extends React.Component { this.refreshTimer = setInterval(() => this.forceUpdate(), 60 * 1000) ee.on('list:next', this.selectNextNoteHandler) ee.on('list:prior', this.selectPriorNoteHandler) + ee.on('list:clone', this.cloneNote) ee.on('list:focus', this.focusHandler) ee.on('list:isMarkdownNote', this.alertIfSnippetHandler) ee.on('import:file', this.importFromFileHandler) @@ -118,6 +120,7 @@ class NoteList extends React.Component { ee.off('list:next', this.selectNextNoteHandler) ee.off('list:prior', this.selectPriorNoteHandler) + ee.off('list:clone', this.cloneNote) ee.off('list:focus', this.focusHandler) ee.off('list:isMarkdownNote', this.alertIfSnippetHandler) ee.off('import:file', this.importFromFileHandler) @@ -173,16 +176,15 @@ class NoteList extends React.Component { } } - focusNote (selectedNoteKeys, noteKey) { + focusNote (selectedNoteKeys, noteKey, pathname) { const { router } = this.context - const { location } = this.props this.setState({ selectedNoteKeys }) router.push({ - pathname: location.pathname, + pathname, query: { key: noteKey } @@ -201,6 +203,7 @@ class NoteList extends React.Component { } let { selectedNoteKeys } = this.state const { shiftKeyDown } = this.state + const { location } = this.props let targetIndex = this.getTargetIndex() @@ -217,7 +220,7 @@ class NoteList extends React.Component { selectedNoteKeys.push(priorNoteKey) } - this.focusNote(selectedNoteKeys, priorNoteKey) + this.focusNote(selectedNoteKeys, priorNoteKey, location.pathname) ee.emit('list:moved') } @@ -228,6 +231,7 @@ class NoteList extends React.Component { } let { selectedNoteKeys } = this.state const { shiftKeyDown } = this.state + const { location } = this.props let targetIndex = this.getTargetIndex() const isTargetLastNote = targetIndex === this.notes.length - 1 @@ -250,7 +254,7 @@ class NoteList extends React.Component { selectedNoteKeys.push(nextNoteKey) } - this.focusNote(selectedNoteKeys, nextNoteKey) + this.focusNote(selectedNoteKeys, nextNoteKey, location.pathname) ee.emit('list:moved') } @@ -262,7 +266,7 @@ class NoteList extends React.Component { } const selectedNoteKeys = [noteHash] - this.focusNote(selectedNoteKeys, noteHash) + this.focusNote(selectedNoteKeys, noteHash, '/home') ee.emit('list:moved') } @@ -276,12 +280,6 @@ class NoteList extends React.Component { ee.emit('top:new-note') } - // D key - if (e.keyCode === 68) { - e.preventDefault() - this.deleteNote() - } - // E key if (e.keyCode === 69) { e.preventDefault() @@ -494,14 +492,21 @@ class NoteList extends React.Component { }) } - alertIfSnippet () { + alertIfSnippet (msg) { + const warningMessage = (msg) => ({ + 'export-txt': 'Text export', + 'export-md': 'Markdown export', + 'export-html': 'HTML export', + 'print': 'Print' + })[msg] + const targetIndex = this.getTargetIndex() if (this.notes[targetIndex].type === 'SNIPPET_NOTE') { dialog.showMessageBox(remote.getCurrentWindow(), { type: 'warning', message: i18n.__('Sorry!'), - detail: i18n.__('md/text import is available only a markdown note.'), - buttons: [i18n.__('OK'), i18n.__('Cancel')] + detail: i18n.__(warningMessage(msg) + ' is available only in markdown notes.'), + buttons: [i18n.__('OK')] }) } } diff --git a/browser/main/SideNav/StorageItem.js b/browser/main/SideNav/StorageItem.js index 7b5caf72..e336f3ce 100644 --- a/browser/main/SideNav/StorageItem.js +++ b/browser/main/SideNav/StorageItem.js @@ -25,7 +25,8 @@ class StorageItem extends React.Component { const { storage } = this.props this.state = { - isOpen: !!storage.isOpen + isOpen: !!storage.isOpen, + draggedOver: null } } @@ -204,6 +205,20 @@ class StorageItem extends React.Component { folderKey: data.folderKey, fileType: data.fileType }) + return data + }) + .then(data => { + dialog.showMessageBox(remote.getCurrentWindow(), { + type: 'info', + message: 'Exported to "' + data.exportDir + '"' + }) + }) + .catch(err => { + dialog.showErrorBox( + 'Export error', + err ? err.message || err : 'Unexpected error during export' + ) + throw err }) } }) @@ -231,14 +246,20 @@ class StorageItem extends React.Component { } } - handleDragEnter (e) { - e.dataTransfer.setData('defaultColor', e.target.style.backgroundColor) - e.target.style.backgroundColor = 'rgba(129, 130, 131, 0.08)' + handleDragEnter (e, key) { + e.preventDefault() + if (this.state.draggedOver === key) { return } + this.setState({ + draggedOver: key + }) } handleDragLeave (e) { - e.target.style.opacity = '1' - e.target.style.backgroundColor = e.dataTransfer.getData('defaultColor') + e.preventDefault() + if (this.state.draggedOver === null) { return } + this.setState({ + draggedOver: null + }) } dropNote (storage, folder, dispatch, location, noteData) { @@ -263,8 +284,12 @@ class StorageItem extends React.Component { } handleDrop (e, storage, folder, dispatch, location) { - e.target.style.opacity = '1' - e.target.style.backgroundColor = e.dataTransfer.getData('defaultColor') + e.preventDefault() + if (this.state.draggedOver !== null) { + this.setState({ + draggedOver: null + }) + } const noteData = JSON.parse(e.dataTransfer.getData('note')) this.dropNote(storage, folder, dispatch, location, noteData) } @@ -291,16 +316,22 @@ class StorageItem extends React.Component { this.handleFolderButtonClick(folder.key)(e)} handleContextMenu={(e) => this.handleFolderButtonContextMenu(e, folder)} folderName={folder.name} folderColor={folder.color} isFolded={isFolded} noteCount={noteCount} - handleDrop={(e) => this.handleDrop(e, storage, folder, dispatch, location)} - handleDragEnter={this.handleDragEnter} - handleDragLeave={this.handleDragLeave} + handleDrop={(e) => { + this.handleDrop(e, storage, folder, dispatch, location) + }} + handleDragEnter={(e) => { + this.handleDragEnter(e, folder.key) + }} + handleDragLeave={(e) => { + this.handleDragLeave(e, folder) + }} /> ) }) diff --git a/browser/main/lib/dataApi/copyFile.js b/browser/main/lib/dataApi/copyFile.js index 2dc66309..6f23aae2 100755 --- a/browser/main/lib/dataApi/copyFile.js +++ b/browser/main/lib/dataApi/copyFile.js @@ -16,7 +16,7 @@ function copyFile (srcPath, dstPath) { const dstFolder = path.dirname(dstPath) if (!fs.existsSync(dstFolder)) fs.mkdirSync(dstFolder) - const input = fs.createReadStream(srcPath) + const input = fs.createReadStream(decodeURI(srcPath)) const output = fs.createWriteStream(dstPath) output.on('error', reject) diff --git a/browser/main/lib/dataApi/exportFolder.js b/browser/main/lib/dataApi/exportFolder.js index 3e998f15..771f77dc 100644 --- a/browser/main/lib/dataApi/exportFolder.js +++ b/browser/main/lib/dataApi/exportFolder.js @@ -1,9 +1,9 @@ import { findStorage } from 'browser/lib/findStorage' import resolveStorageData from './resolveStorageData' import resolveStorageNotes from './resolveStorageNotes' +import exportNote from './exportNote' import filenamify from 'filenamify' import * as path from 'path' -import * as fs from 'fs' /** * @param {String} storageKey @@ -45,9 +45,9 @@ function exportFolder (storageKey, folderKey, fileType, exportDir) { notes .filter(note => note.folder === folderKey && note.isTrashed === false && note.type === 'MARKDOWN_NOTE') - .forEach(snippet => { - const notePath = path.join(exportDir, `${filenamify(snippet.title, {replacement: '_'})}.${fileType}`) - fs.writeFileSync(notePath, snippet.content) + .forEach(note => { + const notePath = path.join(exportDir, `${filenamify(note.title, {replacement: '_'})}.${fileType}`) + exportNote(note.key, storage.path, note.content, notePath, null) }) return { diff --git a/browser/main/lib/dataApi/exportNote.js b/browser/main/lib/dataApi/exportNote.js index e4fec5f4..b358e548 100755 --- a/browser/main/lib/dataApi/exportNote.js +++ b/browser/main/lib/dataApi/exportNote.js @@ -4,27 +4,43 @@ import { findStorage } from 'browser/lib/findStorage' const fs = require('fs') const path = require('path') +const attachmentManagement = require('./attachmentManagement') + /** - * Export note together with images + * Export note together with attachments * - * If images is stored in the storage, creates 'images' subfolder in target directory - * and copies images to it. Changes links to images in the content of the note + * If attachments are stored in the storage, creates 'attachments' subfolder in target directory + * and copies attachments to it. Changes links to images in the content of the note * + * @param {String} nodeKey key of the node that should be exported * @param {String} storageKey or storage path * @param {String} noteContent Content to export * @param {String} targetPath Path to exported file * @param {function} outputFormatter * @return {Promise.<*[]>} */ -function exportNote (storageKey, noteContent, targetPath, outputFormatter) { +function exportNote (nodeKey, storageKey, noteContent, targetPath, outputFormatter) { const storagePath = path.isAbsolute(storageKey) ? storageKey : findStorage(storageKey).path const exportTasks = [] if (!storagePath) { throw new Error('Storage path is not found') } + const attachmentsAbsolutePaths = attachmentManagement.getAbsolutePathsOfAttachmentsInContent( + noteContent, + storagePath + ) + attachmentsAbsolutePaths.forEach(attachment => { + exportTasks.push({ + src: attachment, + dst: attachmentManagement.DESTINATION_FOLDER + }) + }) - let exportedData = noteContent + let exportedData = attachmentManagement.removeStorageAndNoteReferences( + noteContent, + nodeKey + ) if (outputFormatter) { exportedData = outputFormatter(exportedData, exportTasks) diff --git a/lib/main-menu.js b/lib/main-menu.js index 91f3c8c6..05921347 100644 --- a/lib/main-menu.js +++ b/lib/main-menu.js @@ -85,39 +85,24 @@ const file = { }, { label: 'Focus Note', - accelerator: 'Control+E', + accelerator: macOS ? 'Command+E' : 'Control+E', click () { mainWindow.webContents.send('detail:focus') } }, { - type: 'separator' + label: 'Delete Note', + accelerator: macOS ? 'Command+Shift+Backspace' : 'Control+Shift+Backspace', + click () { + mainWindow.webContents.send('detail:delete') + } }, { - label: 'Export as', - submenu: [ - { - label: 'Plain Text (.txt)', - click () { - mainWindow.webContents.send('list:isMarkdownNote') - mainWindow.webContents.send('export:save-text') - } - }, - { - label: 'MarkDown (.md)', - click () { - mainWindow.webContents.send('list:isMarkdownNote') - mainWindow.webContents.send('export:save-md') - } - }, - { - label: 'HTML (.html)', - click () { - mainWindow.webContents.send('list:isMarkdownNote') - mainWindow.webContents.send('export:save-html') - } - } - ] + label: 'Clone Note', + accelerator: macOS ? 'Command+D' : 'Control+D', + click () { + mainWindow.webContents.send('list:clone') + } }, { type: 'separator' @@ -134,13 +119,30 @@ const file = { ] }, { - type: 'separator' - }, - { - label: 'Format Table', - click () { - mainWindow.webContents.send('code:format-table') - } + label: 'Export as', + submenu: [ + { + label: 'Plain Text (.txt)', + click () { + mainWindow.webContents.send('list:isMarkdownNote', 'export-txt') + mainWindow.webContents.send('export:save-text') + } + }, + { + label: 'MarkDown (.md)', + click () { + mainWindow.webContents.send('list:isMarkdownNote', 'export-md') + mainWindow.webContents.send('export:save-md') + } + }, + { + label: 'HTML (.html)', + click () { + mainWindow.webContents.send('list:isMarkdownNote', 'export-html') + mainWindow.webContents.send('export:save-html') + } + } + ] }, { type: 'separator' @@ -153,24 +155,20 @@ const file = { } }, { - type: 'separator' - }, - { - label: 'Print', - accelerator: 'CommandOrControl+P', + label: 'Format Table', click () { - mainWindow.webContents.send('list:isMarkdownNote') - mainWindow.webContents.send('print') + mainWindow.webContents.send('code:format-table') } }, { type: 'separator' }, { - label: 'Delete Note', - accelerator: macOS ? 'Control+Backspace' : 'Control+Delete', + label: 'Print', + accelerator: 'CommandOrControl+P', click () { - mainWindow.webContents.send('detail:delete') + mainWindow.webContents.send('list:isMarkdownNote', 'print') + mainWindow.webContents.send('print') } } ] @@ -296,9 +294,6 @@ const view = { mainWindow.setFullScreen(!mainWindow.isFullScreen()) } }, - { - type: 'separator' - }, { label: 'Toggle Side Bar', accelerator: 'CommandOrControl+B', diff --git a/locales/ja.json b/locales/ja.json index e33bbaa6..9cfc2986 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -37,9 +37,15 @@ "White": "白", "Solarized Dark": "明灰", "Dark": "暗灰", + "Default New Note": "新規ノートの形式", + "Always Ask": "作成時に聞く", "Show a confirmation dialog when deleting notes": "ノートを削除する時に確認ダイアログを表示する", "Disable Direct Write (It will be applied after restarting)": "Disable Direct Write (It will be applied after restarting)", + "Save tags of a note in alphabetical order": "ノートのタグをアルファベット順に保存する", + "Show tags of a note in alphabetical order": "ノートのタグをアルファベット順に表示する", "Show only related tags": "関連するタグのみ表示する", + "Enable live count of notes": "タグ選択時にノート数を再計算して表示する", + "New notes are tagged with the filtering tags": "新規ノートに選択中のタグを付与する", "Editor Theme": "エディタのテーマ", "Editor Font Size": "エディタのフォントサイズ", "Editor Font Family": "エディタのフォント", @@ -55,21 +61,28 @@ "vim": "vim", "emacs": "emacs", "⚠️ Please restart boostnote after you change the keymap": "⚠️ キーマップ変更後は Boostnote を再起動してください", + "Snippet Default Language": "スニペットのデフォルト言語", + "Extract title from front matter": "Front matterからタイトルを抽出する", "Show line numbers in the editor": "エディタ内に行番号を表示", "Allow editor to scroll past the last line": "エディタが最終行以降にスクロールできるようにする", "Enable smart quotes": "スマートクォートを有効にする", "Bring in web page title when pasting URL on editor": "URLを貼り付けた時にWebページのタイトルを取得する", + "Enable smart table editor": "スマートテーブルエディタを有効にする", "Preview": "プレビュー", "Preview Font Size": "プレビュー時フォントサイズ", "Preview Font Family": "プレビュー時フォント", "Code Block Theme": "コードブロックのテーマ", + "Allow line through checkbox": "チェック済みチェックボックスのテキストに取り消し線を付与する", "Allow preview to scroll past the last line": "プレビュー時に最終行以降にスクロールできるようにする", + "When scrolling, synchronize preview with editor": "エディタとプレビューのスクロールを同期する", "Show line numbers for preview code blocks": "プレビュー時のコードブロック内に行番号を表示する", "LaTeX Inline Open Delimiter": "LaTeX 開始デリミタ(インライン)", "LaTeX Inline Close Delimiter": "LaTeX 終了デリミタ(インライン)", "LaTeX Block Open Delimiter": "LaTeX 開始デリミタ(ブロック)", "LaTeX Block Close Delimiter": "LaTeX 終了デリミタ(ブロック)", "PlantUML Server": "PlantUML サーバー", + "Custom CSS": "カスタムCSS", + "Allow custom CSS for preview": "プレビュー用のカスタムCSSを許可する", "Community": "コミュニティ", "Subscribe to Newsletter": "ニュースレターを購読する", "GitHub": "GitHub", @@ -135,6 +148,7 @@ "Hotkeys": "ホットキー", "Show/Hide Boostnote": "Boostnote の表示/非表示", "Toggle Editor Mode": "エディタモードの切替", + "Delete Note": "ノート削除", "Restore": "リストア", "Permanent Delete": "永久に削除", "Confirm note deletion": "ノート削除確認", diff --git a/package.json b/package.json index 1fb8e380..128a21af 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "escape-string-regexp": "^1.0.5", "file-uri-to-path": "^1.0.0", "file-url": "^2.0.2", - "filenamify": "^2.0.0", + "filenamify": "^2.1.0", "flowchart.js": "^1.6.5", "font-awesome": "^4.3.0", "fs-extra": "^5.0.0", diff --git a/readme.md b/readme.md index b3f2ec46..ef90dfcc 100644 --- a/readme.md +++ b/readme.md @@ -5,8 +5,11 @@

Note-taking app for programmers.

Apps available for Mac, Windows, Linux, Android, and iOS.
Built with Electron, React + Redux, Webpack, and CSSModules.
- -[![Build Status](https://travis-ci.org/BoostIO/Boostnote.svg?branch=master)](https://travis-ci.org/BoostIO/Boostnote) +

+ + Build Status + +

## Authors & Maintainers - [Rokt33r](https://github.com/rokt33r) diff --git a/tests/dataApi/copyFile-test.js b/tests/dataApi/copyFile-test.js new file mode 100644 index 00000000..412d510a --- /dev/null +++ b/tests/dataApi/copyFile-test.js @@ -0,0 +1,35 @@ +const test = require('ava') +const copyFile = require('browser/main/lib/dataApi/copyFile') + +const path = require('path') +const fs = require('fs') + +const testFile = 'test.txt' +const srcFolder = path.join(__dirname, '🤔') +const srcPath = path.join(srcFolder, testFile) +const dstFolder = path.join(__dirname, '😇') +const dstPath = path.join(dstFolder, testFile) + +test.before((t) => { + if (!fs.existsSync(srcFolder)) fs.mkdirSync(srcFolder) + + fs.writeFileSync(srcPath, 'test') +}) + +test('`copyFile` should handle encoded URI on src path', (t) => { + return copyFile(encodeURI(srcPath), dstPath) + .then(() => { + t.true(true) + }) + .catch(() => { + t.true(false) + }) +}) + +test.after((t) => { + fs.unlinkSync(srcPath) + fs.unlinkSync(dstPath) + fs.rmdirSync(srcFolder) + fs.rmdirSync(dstFolder) +}) + diff --git a/yarn.lock b/yarn.lock index 4b24d45d..48dd9056 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3591,9 +3591,9 @@ filename-reserved-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" -filenamify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-2.0.0.tgz#bd162262c0b6e94bfbcdcf19a3bbb3764f785695" +filenamify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-2.1.0.tgz#88faf495fb1b47abfd612300002a16228c677ee9" dependencies: filename-reserved-regex "^2.0.0" strip-outer "^1.0.0"