diff --git a/browser/components/MarkdownPreview.js b/browser/components/MarkdownPreview.js index c5fbc949..7a376470 100644 --- a/browser/components/MarkdownPreview.js +++ b/browser/components/MarkdownPreview.js @@ -6,6 +6,8 @@ import consts from 'browser/lib/consts' import Raphael from 'raphael' import flowchart from 'flowchart' import SequenceDiagram from 'js-sequence-diagrams' +import eventEmitter from 'browser/main/lib/eventEmitter' +import fs from 'fs' function decodeHTMLEntities (text) { var entities = [ @@ -25,6 +27,7 @@ function decodeHTMLEntities (text) { const { remote } = require('electron') const { app } = remote const path = require('path') +const dialog = remote.dialog const markdownStyle = require('!!css!stylus?sourceMap!./markdown.styl')[0][1] const appPath = 'file://' + (process.env.NODE_ENV === 'production' @@ -90,6 +93,8 @@ export default class MarkdownPreview extends React.Component { this.mouseUpHandler = (e) => this.handleMouseUp(e) this.anchorClickHandler = (e) => this.handlePreviewAnchorClick(e) this.checkboxClickHandler = (e) => this.handleCheckboxClick(e) + this.saveAsTextHandler = () => this.handleSaveAsText() + this.saveAsMdHandler = () => this.handleSaveAsMd() } handlePreviewAnchorClick (e) { @@ -134,6 +139,31 @@ export default class MarkdownPreview extends React.Component { if (this.props.onMouseUp != null) this.props.onMouseUp(e) } + handleSaveAsText () { + this.exportAsDocument('txt') + } + + handleSaveAsMd () { + this.exportAsDocument('md') + } + + exportAsDocument (fileType) { + const options = { + filters: [ + { name: 'Documents', extensions: [fileType]} + ], + properties: ['openFile', 'createDirectory'] + } + dialog.showSaveDialog(remote.getCurrentWindow(), options, + (filename) => { + if (filename) { + fs.writeFile(filename, this.props.value, (err) => { + if (err) throw err + }) + } + }) + } + componentDidMount () { this.refs.root.setAttribute('sandbox', 'allow-scripts') this.refs.root.contentWindow.document.body.addEventListener('contextmenu', this.contextMenuHandler) @@ -149,12 +179,16 @@ export default class MarkdownPreview extends React.Component { this.refs.root.contentWindow.document.addEventListener('mousedown', this.mouseDownHandler) this.refs.root.contentWindow.document.addEventListener('mouseup', this.mouseUpHandler) + eventEmitter.on('export:save-text', this.saveAsTextHandler) + eventEmitter.on('export:save-md', this.saveAsMdHandler) } componentWillUnmount () { this.refs.root.contentWindow.document.body.removeEventListener('contextmenu', this.contextMenuHandler) this.refs.root.contentWindow.document.removeEventListener('mousedown', this.mouseDownHandler) this.refs.root.contentWindow.document.removeEventListener('mouseup', this.mouseUpHandler) + eventEmitter.off('export:save-text', this.saveAsTextHandler) + eventEmitter.off('export:save-md', this.saveAsMdHandler) } componentDidUpdate (prevProps) { diff --git a/browser/main/NoteList/index.js b/browser/main/NoteList/index.js index 1edb2fb2..82c0bbc3 100644 --- a/browser/main/NoteList/index.js +++ b/browser/main/NoteList/index.js @@ -38,6 +38,9 @@ class NoteList extends React.Component { this.focusHandler = () => { this.refs.list.focus() } + this.alertIfSnippetHnalder = () => { + this.alertIfSnippet() + } this.state = { } @@ -48,6 +51,7 @@ class NoteList extends React.Component { ee.on('list:next', this.selectNextNoteHandler) ee.on('list:prior', this.selectPriorNoteHandler) ee.on('list:focus', this.focusHandler) + ee.on('list:isMarkdownNote', this.alertIfSnippetHnalder) } componentWillReceiveProps (nextProps) { @@ -66,6 +70,7 @@ class NoteList extends React.Component { ee.off('list:next', this.selectNextNoteHandler) ee.off('list:prior', this.selectPriorNoteHandler) ee.off('list:focus', this.focusHandler) + ee.off('list:isMarkdownNote', this.alertIfSnippetHnalder) } componentDidUpdate (prevProps) { @@ -305,6 +310,20 @@ class NoteList extends React.Component { }) } + alertIfSnippet() { + let { location } = this.props + const targetIndex = _.findIndex(this.notes, (note) => { + return `${note.storage}-${note.key}` === location.query.key + }) + if (this.notes[targetIndex].type === 'SNIPPET_NOTE') { + dialog.showMessageBox(remote.getCurrentWindow(), { + type: 'warning', + message: 'Sorry!', + detail: 'md/text import is available only a markdown note.' + }) + } + } + render () { let { location, notes, config } = this.props let sortFunc = config.sortBy === 'CREATED_AT' diff --git a/lib/main-menu.js b/lib/main-menu.js index 482c8b07..9a95fe1d 100644 --- a/lib/main-menu.js +++ b/lib/main-menu.js @@ -62,6 +62,28 @@ var file = { { type: 'separator' }, + { + 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') + } + } + ] + }, + { + type: 'separator' + }, { label: 'Delete Note', accelerator: OSX ? 'Control + Backspace' : 'Control + Delete',