{this.SideNavComponent(isFolded, storageList)}
+ {colorPicker}
)
}
diff --git a/browser/main/StatusBar/StatusBar.styl b/browser/main/StatusBar/StatusBar.styl
index 83cf2088..23dec208 100644
--- a/browser/main/StatusBar/StatusBar.styl
+++ b/browser/main/StatusBar/StatusBar.styl
@@ -47,6 +47,14 @@
.update-icon
color $brand-color
+body[data-theme="default"]
+ .zoom
+ color $ui-text-color
+
+body[data-theme="white"]
+ .zoom
+ color $ui-text-color
+
body[data-theme="dark"]
.root
border-color $ui-dark-borderColor
diff --git a/browser/main/StatusBar/index.js b/browser/main/StatusBar/index.js
index 8b48e3d3..c99bf036 100644
--- a/browser/main/StatusBar/index.js
+++ b/browser/main/StatusBar/index.js
@@ -5,6 +5,7 @@ import styles from './StatusBar.styl'
import ZoomManager from 'browser/main/lib/ZoomManager'
import i18n from 'browser/lib/i18n'
import context from 'browser/lib/context'
+import EventEmitter from 'browser/main/lib/eventEmitter'
const electron = require('electron')
const { remote, ipcRenderer } = electron
@@ -13,6 +14,26 @@ 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]
class StatusBar extends React.Component {
+
+ constructor (props) {
+ super(props)
+ this.handleZoomInMenuItem = this.handleZoomInMenuItem.bind(this)
+ this.handleZoomOutMenuItem = this.handleZoomOutMenuItem.bind(this)
+ this.handleZoomResetMenuItem = this.handleZoomResetMenuItem.bind(this)
+ }
+
+ componentDidMount () {
+ EventEmitter.on('status:zoomin', this.handleZoomInMenuItem)
+ EventEmitter.on('status:zoomout', this.handleZoomOutMenuItem)
+ EventEmitter.on('status:zoomreset', this.handleZoomResetMenuItem)
+ }
+
+ componentWillUnmount () {
+ EventEmitter.off('status:zoomin', this.handleZoomInMenuItem)
+ EventEmitter.off('status:zoomout', this.handleZoomOutMenuItem)
+ EventEmitter.off('status:zoomreset', this.handleZoomResetMenuItem)
+ }
+
updateApp () {
const index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
@@ -48,6 +69,20 @@ class StatusBar extends React.Component {
})
}
+ handleZoomInMenuItem () {
+ const zoomFactor = ZoomManager.getZoom() + 0.1
+ this.handleZoomMenuItemClick(zoomFactor)
+ }
+
+ handleZoomOutMenuItem () {
+ const zoomFactor = ZoomManager.getZoom() - 0.1
+ this.handleZoomMenuItemClick(zoomFactor)
+ }
+
+ handleZoomResetMenuItem () {
+ this.handleZoomMenuItemClick(1.0)
+ }
+
render () {
const { config, status } = this.context
diff --git a/browser/main/TopBar/index.js b/browser/main/TopBar/index.js
index a5687ecb..91256daf 100644
--- a/browser/main/TopBar/index.js
+++ b/browser/main/TopBar/index.js
@@ -6,6 +6,7 @@ import _ from 'lodash'
import ee from 'browser/main/lib/eventEmitter'
import NewNoteButton from 'browser/main/NewNoteButton'
import i18n from 'browser/lib/i18n'
+import debounce from 'lodash/debounce'
class TopBar extends React.Component {
constructor (props) {
@@ -25,6 +26,10 @@ class TopBar extends React.Component {
}
this.codeInitHandler = this.handleCodeInit.bind(this)
+
+ this.updateKeyword = debounce(this.updateKeyword, 1000 / 60, {
+ maxWait: 1000 / 8
+ })
}
componentDidMount () {
@@ -94,7 +99,6 @@ class TopBar extends React.Component {
}
handleKeyUp (e) {
- const { router } = this.context
// reset states
this.setState({
isConfirmTranslation: false
@@ -106,21 +110,21 @@ class TopBar extends React.Component {
isConfirmTranslation: true
})
const keyword = this.refs.searchInput.value
- router.push(`/searched/${encodeURIComponent(keyword)}`)
- this.setState({
- search: keyword
- })
+ this.updateKeyword(keyword)
}
}
handleSearchChange (e) {
- const { router } = this.context
- const keyword = this.refs.searchInput.value
if (this.state.isAlphabet || this.state.isConfirmTranslation) {
- router.push(`/searched/${encodeURIComponent(keyword)}`)
+ const keyword = this.refs.searchInput.value
+ this.updateKeyword(keyword)
} else {
e.preventDefault()
}
+ }
+
+ updateKeyword (keyword) {
+ this.context.router.push(`/searched/${encodeURIComponent(keyword)}`)
this.setState({
search: keyword
})
diff --git a/browser/main/global.styl b/browser/main/global.styl
index e04060c2..d864993d 100644
--- a/browser/main/global.styl
+++ b/browser/main/global.styl
@@ -97,6 +97,7 @@ modalBackColor = white
body[data-theme="dark"]
+ background-color $ui-dark-backgroundColor
::-webkit-scrollbar-thumb
background-color rgba(0, 0, 0, 0.3)
.ModalBase
@@ -148,6 +149,7 @@ body[data-theme="dark"]
z-index modalZIndex + 5
body[data-theme="solarized-dark"]
+ background-color $ui-solarized-dark-backgroundColor
::-webkit-scrollbar-thumb
background-color rgba(0, 0, 0, 0.3)
.ModalBase
@@ -157,6 +159,7 @@ body[data-theme="solarized-dark"]
color: $ui-solarized-dark-text-color
body[data-theme="monokai"]
+ background-color $ui-monokai-backgroundColor
::-webkit-scrollbar-thumb
background-color rgba(0, 0, 0, 0.3)
.ModalBase
@@ -166,6 +169,7 @@ body[data-theme="monokai"]
color: $ui-monokai-text-color
body[data-theme="dracula"]
+ background-color $ui-dracula-backgroundColor
::-webkit-scrollbar-thumb
background-color rgba(0, 0, 0, 0.3)
.ModalBase
diff --git a/browser/main/lib/AwsMobileAnalyticsConfig.js b/browser/main/lib/AwsMobileAnalyticsConfig.js
index 1ef4f8da..e4a21a92 100644
--- a/browser/main/lib/AwsMobileAnalyticsConfig.js
+++ b/browser/main/lib/AwsMobileAnalyticsConfig.js
@@ -45,7 +45,6 @@ function initAwsMobileAnalytics () {
if (getSendEventCond()) return
AWS.config.credentials.get((err) => {
if (!err) {
- console.log('Cognito Identity ID: ' + AWS.config.credentials.identityId)
recordDynamicCustomEvent('APP_STARTED')
recordStaticCustomEvent()
}
@@ -58,7 +57,7 @@ function recordDynamicCustomEvent (type, options = {}) {
mobileAnalyticsClient.recordEvent(type, options)
} catch (analyticsError) {
if (analyticsError instanceof ReferenceError) {
- console.log(analyticsError.name + ': ' + analyticsError.message)
+ console.error(analyticsError.name + ': ' + analyticsError.message)
}
}
}
@@ -71,7 +70,7 @@ function recordStaticCustomEvent () {
})
} catch (analyticsError) {
if (analyticsError instanceof ReferenceError) {
- console.log(analyticsError.name + ': ' + analyticsError.message)
+ console.error(analyticsError.name + ': ' + analyticsError.message)
}
}
}
diff --git a/browser/main/lib/ConfigManager.js b/browser/main/lib/ConfigManager.js
index 1727deb8..8a89c9a9 100644
--- a/browser/main/lib/ConfigManager.js
+++ b/browser/main/lib/ConfigManager.js
@@ -24,14 +24,18 @@ export const DEFAULT_CONFIG = {
amaEnabled: true,
hotkey: {
toggleMain: OSX ? 'Command + Alt + L' : 'Super + Alt + E',
- toggleMode: OSX ? 'Command + Option + M' : 'Ctrl + M'
+ toggleMode: OSX ? 'Command + Alt + M' : 'Ctrl + M',
+ deleteNote: OSX ? 'Command + Shift + Backspace' : 'Ctrl + Shift + Backspace',
+ pasteSmartly: OSX ? 'Command + Shift + V' : 'Ctrl + Shift + V',
+ toggleMenuBar: 'Alt'
},
ui: {
language: 'en',
theme: 'default',
showCopyNotification: true,
disableDirectWrite: false,
- defaultNote: 'ALWAYS_ASK' // 'ALWAYS_ASK', 'SNIPPET_NOTE', 'MARKDOWN_NOTE'
+ defaultNote: 'ALWAYS_ASK', // 'ALWAYS_ASK', 'SNIPPET_NOTE', 'MARKDOWN_NOTE'
+ showMenuBar: false
},
editor: {
theme: 'base16-light',
@@ -43,11 +47,19 @@ export const DEFAULT_CONFIG = {
enableRulers: false,
rulers: [80, 120],
displayLineNumbers: true,
- switchPreview: 'BLUR', // Available value: RIGHTCLICK, BLUR
+ matchingPairs: '()[]{}\'\'""$$**``',
+ matchingTriples: '```"""\'\'\'',
+ explodingPairs: '[]{}``$$',
+ switchPreview: 'BLUR', // 'BLUR', 'DBL_CLICK', 'RIGHTCLICK'
+ delfaultStatus: 'PREVIEW', // 'PREVIEW', 'CODE'
scrollPastEnd: false,
- type: 'SPLIT',
+ type: 'SPLIT', // 'SPLIT', 'EDITOR_PREVIEW'
fetchUrlTitle: true,
- enableTableEditor: false
+ enableTableEditor: false,
+ enableFrontMatterTitle: true,
+ frontMatterTitleField: 'title',
+ spellcheck: false,
+ enableSmartPaste: false
},
preview: {
fontSize: '14',
@@ -60,6 +72,7 @@ export const DEFAULT_CONFIG = {
latexBlockClose: '$$',
plantUMLServerAddress: 'http://www.plantuml.com/plantuml',
scrollPastEnd: false,
+ scrollSync: true,
smartQuotes: true,
breaks: true,
smartArrows: false,
@@ -75,7 +88,8 @@ export const DEFAULT_CONFIG = {
token: '',
username: '',
password: ''
- }
+ },
+ coloredTags: {}
}
function validate (config) {
@@ -197,8 +211,8 @@ function assignConfigValues (originalConfig, rcConfig) {
function rewriteHotkey (config) {
const keys = [...Object.keys(config.hotkey)]
keys.forEach(key => {
- config.hotkey[key] = config.hotkey[key].replace(/Cmd/g, 'Command')
- config.hotkey[key] = config.hotkey[key].replace(/Opt/g, 'Alt')
+ config.hotkey[key] = config.hotkey[key].replace(/Cmd\s/g, 'Command ')
+ config.hotkey[key] = config.hotkey[key].replace(/Opt\s/g, 'Option ')
})
return config
}
diff --git a/browser/main/lib/dataApi/attachmentManagement.js b/browser/main/lib/dataApi/attachmentManagement.js
index 912450c1..6a0315f7 100644
--- a/browser/main/lib/dataApi/attachmentManagement.js
+++ b/browser/main/lib/dataApi/attachmentManagement.js
@@ -227,7 +227,15 @@ function migrateAttachments (markdownContent, storagePath, noteKey) {
* @returns {String} postprocessed HTML in which all :storage references are mapped to the actual paths.
*/
function fixLocalURLS (renderedHTML, storagePath) {
- return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '.*?"', 'g'), function (match) {
+ /*
+ A :storage reference is like `:storage/3b6f8bd6-4edd-4b15-96e0-eadc4475b564/f939b2c3.jpg`.
+
+ - `STORAGE_FOLDER_PLACEHOLDER` will match `:storage`
+ - `(?:(?:\\\/|%5C)[\\w.]+)+` will match `/3b6f8bd6-4edd-4b15-96e0-eadc4475b564/f939b2c3.jpg`
+ - `(?:\\\/|%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) {
var encodedPathSeparators = new RegExp(mdurl.encode(path.win32.sep) + '|' + mdurl.encode(path.posix.sep), 'g')
return match.replace(encodedPathSeparators, path.sep).replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER, 'g'), 'file:///' + path.join(storagePath, DESTINATION_FOLDER))
})
@@ -316,6 +324,44 @@ function handlePastImageEvent (codeEditor, storageKey, noteKey, dataTransferItem
reader.readAsDataURL(blob)
}
+/**
+ * @description Creates a new file in the storage folder belonging to the current note and inserts the correct markdown code
+ * @param {CodeEditor} codeEditor Markdown editor. Its insertAttachmentMd() method will be called to include the markdown code
+ * @param {String} storageKey Key of the current storage
+ * @param {String} noteKey Key of the current note
+ * @param {NativeImage} image The native image
+ */
+function handlePastNativeImage (codeEditor, storageKey, noteKey, image) {
+ if (!codeEditor) {
+ throw new Error('codeEditor has to be given')
+ }
+ if (!storageKey) {
+ throw new Error('storageKey has to be given')
+ }
+
+ if (!noteKey) {
+ throw new Error('noteKey has to be given')
+ }
+ if (!image) {
+ throw new Error('image has to be given')
+ }
+
+ const targetStorage = findStorage.findStorage(storageKey)
+ const destinationDir = path.join(targetStorage.path, DESTINATION_FOLDER, noteKey)
+
+ createAttachmentDestinationFolder(targetStorage.path, noteKey)
+
+ const imageName = `${uniqueSlug()}.png`
+ const imagePath = path.join(destinationDir, imageName)
+
+ const binaryData = image.toPNG()
+ fs.writeFileSync(imagePath, binaryData, 'binary')
+
+ 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
@@ -529,7 +575,6 @@ function handleAttachmentLinkPaste (storageKey, noteKey, linkText) {
return modifiedLinkText
})
} else {
- console.log('One if the parameters was null -> Do nothing..')
return Promise.resolve(linkText)
}
}
@@ -540,6 +585,7 @@ module.exports = {
generateAttachmentMarkdown,
handleAttachmentDrop,
handlePastImageEvent,
+ handlePastNativeImage,
getAttachmentsInMarkdownContent,
getAbsolutePathsOfAttachmentsInContent,
removeStorageAndNoteReferences,
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/createNote.js b/browser/main/lib/dataApi/createNote.js
index e5d44489..5bfa2457 100644
--- a/browser/main/lib/dataApi/createNote.js
+++ b/browser/main/lib/dataApi/createNote.js
@@ -16,6 +16,7 @@ function validateInput (input) {
switch (input.type) {
case 'MARKDOWN_NOTE':
if (!_.isString(input.content)) input.content = ''
+ if (!_.isArray(input.linesHighlighted)) input.linesHighlighted = []
break
case 'SNIPPET_NOTE':
if (!_.isString(input.description)) input.description = ''
@@ -23,7 +24,8 @@ function validateInput (input) {
input.snippets = [{
name: '',
mode: 'text',
- content: ''
+ content: '',
+ linesHighlighted: []
}]
}
break
diff --git a/browser/main/lib/dataApi/createSnippet.js b/browser/main/lib/dataApi/createSnippet.js
index 5d189217..2e585c9f 100644
--- a/browser/main/lib/dataApi/createSnippet.js
+++ b/browser/main/lib/dataApi/createSnippet.js
@@ -9,7 +9,8 @@ function createSnippet (snippetFile) {
id: crypto.randomBytes(16).toString('hex'),
name: 'Unnamed snippet',
prefix: [],
- content: ''
+ content: '',
+ linesHighlighted: []
}
fetchSnippet(null, snippetFile).then((snippets) => {
snippets.push(newSnippet)
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/browser/main/lib/dataApi/init.js b/browser/main/lib/dataApi/init.js
index 7f81e90b..0dbcc182 100644
--- a/browser/main/lib/dataApi/init.js
+++ b/browser/main/lib/dataApi/init.js
@@ -4,6 +4,7 @@ const resolveStorageData = require('./resolveStorageData')
const resolveStorageNotes = require('./resolveStorageNotes')
const consts = require('browser/lib/consts')
const path = require('path')
+const fs = require('fs')
const CSON = require('@rokt33r/season')
/**
* @return {Object} all storages and notes
@@ -19,11 +20,14 @@ const CSON = require('@rokt33r/season')
* 2. legacy
* 3. empty directory
*/
+
function init () {
const fetchStorages = function () {
let rawStorages
try {
rawStorages = JSON.parse(window.localStorage.getItem('storages'))
+ // Remove storages who's location is inaccesible.
+ rawStorages = rawStorages.filter(storage => fs.existsSync(storage.path))
if (!_.isArray(rawStorages)) throw new Error('Cached data is not valid.')
} catch (e) {
console.warn('Failed to parse cached data from localStorage', e)
@@ -36,6 +40,7 @@ function init () {
const fetchNotes = function (storages) {
const findNotesFromEachStorage = storages
+ .filter(storage => fs.existsSync(storage.path))
.map((storage) => {
return resolveStorageNotes(storage)
.then((notes) => {
@@ -51,7 +56,11 @@ function init () {
}
})
if (unknownCount > 0) {
- CSON.writeFileSync(path.join(storage.path, 'boostnote.json'), _.pick(storage, ['folders', 'version']))
+ 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
})
diff --git a/browser/main/lib/dataApi/migrateFromV5Storage.js b/browser/main/lib/dataApi/migrateFromV5Storage.js
index b11e66e9..78d78746 100644
--- a/browser/main/lib/dataApi/migrateFromV5Storage.js
+++ b/browser/main/lib/dataApi/migrateFromV5Storage.js
@@ -69,7 +69,8 @@ function importAll (storage, data) {
isStarred: false,
title: article.title,
content: '# ' + article.title + '\n\n' + article.content,
- key: noteKey
+ key: noteKey,
+ linesHighlighted: article.linesHighlighted
}
notes.push(newNote)
} else {
@@ -87,7 +88,8 @@ function importAll (storage, data) {
snippets: [{
name: article.mode,
mode: article.mode,
- content: article.content
+ content: article.content,
+ linesHighlighted: article.linesHighlighted
}]
}
notes.push(newNote)
diff --git a/browser/main/lib/dataApi/renameStorage.js b/browser/main/lib/dataApi/renameStorage.js
index 78242bed..3b806d1c 100644
--- a/browser/main/lib/dataApi/renameStorage.js
+++ b/browser/main/lib/dataApi/renameStorage.js
@@ -14,7 +14,6 @@ function renameStorage (key, name) {
cachedStorageList = JSON.parse(localStorage.getItem('storages'))
if (!_.isArray(cachedStorageList)) throw new Error('invalid storages')
} catch (err) {
- console.log('error got')
console.error(err)
return Promise.reject(err)
}
diff --git a/browser/main/lib/dataApi/resolveStorageData.js b/browser/main/lib/dataApi/resolveStorageData.js
index 681a102e..da41f3d0 100644
--- a/browser/main/lib/dataApi/resolveStorageData.js
+++ b/browser/main/lib/dataApi/resolveStorageData.js
@@ -31,13 +31,9 @@ function resolveStorageData (storageCache) {
const version = parseInt(storage.version, 10)
if (version >= 1) {
- if (version > 1) {
- console.log('The repository version is newer than one of current app.')
- }
return Promise.resolve(storage)
}
- console.log('Transform Legacy storage', storage.path)
return migrateFromV6Storage(storage.path)
.then(() => storage)
}
diff --git a/browser/main/lib/dataApi/resolveStorageNotes.js b/browser/main/lib/dataApi/resolveStorageNotes.js
index fa3f19ae..9da27248 100644
--- a/browser/main/lib/dataApi/resolveStorageNotes.js
+++ b/browser/main/lib/dataApi/resolveStorageNotes.js
@@ -9,7 +9,7 @@ function resolveStorageNotes (storage) {
notePathList = sander.readdirSync(notesDirPath)
} catch (err) {
if (err.code === 'ENOENT') {
- console.log(notesDirPath, ' doesn\'t exist.')
+ console.error(notesDirPath, ' doesn\'t exist.')
sander.mkdirSync(notesDirPath)
} else {
console.warn('Failed to find note dir', notesDirPath, err)
diff --git a/browser/main/lib/dataApi/toggleStorage.js b/browser/main/lib/dataApi/toggleStorage.js
index dbb625c3..246d85ef 100644
--- a/browser/main/lib/dataApi/toggleStorage.js
+++ b/browser/main/lib/dataApi/toggleStorage.js
@@ -12,7 +12,6 @@ function toggleStorage (key, isOpen) {
cachedStorageList = JSON.parse(localStorage.getItem('storages'))
if (!_.isArray(cachedStorageList)) throw new Error('invalid storages')
} catch (err) {
- console.log('error got')
console.error(err)
return Promise.reject(err)
}
diff --git a/browser/main/lib/dataApi/updateNote.js b/browser/main/lib/dataApi/updateNote.js
index 147fbc06..ce9fabcf 100644
--- a/browser/main/lib/dataApi/updateNote.js
+++ b/browser/main/lib/dataApi/updateNote.js
@@ -39,6 +39,9 @@ function validateInput (input) {
if (input.content != null) {
if (!_.isString(input.content)) validatedInput.content = ''
else validatedInput.content = input.content
+
+ if (!_.isArray(input.linesHighlighted)) validatedInput.linesHighlighted = []
+ else validatedInput.linesHighlighted = input.linesHighlighted
}
return validatedInput
case 'SNIPPET_NOTE':
@@ -51,7 +54,8 @@ function validateInput (input) {
validatedInput.snippets = [{
name: '',
mode: 'text',
- content: ''
+ content: '',
+ linesHighlighted: []
}]
} else {
validatedInput.snippets = input.snippets
@@ -96,12 +100,14 @@ function updateNote (storageKey, noteKey, input) {
snippets: [{
name: '',
mode: 'text',
- content: ''
+ content: '',
+ linesHighlighted: []
}]
}
: {
type: 'MARKDOWN_NOTE',
- content: ''
+ content: '',
+ linesHighlighted: []
}
noteData.title = ''
if (storage.folders.length === 0) throw new Error('Failed to restore note: No folder exists.')
diff --git a/browser/main/lib/dataApi/updateSnippet.js b/browser/main/lib/dataApi/updateSnippet.js
index f2310b8e..f132d83f 100644
--- a/browser/main/lib/dataApi/updateSnippet.js
+++ b/browser/main/lib/dataApi/updateSnippet.js
@@ -12,7 +12,8 @@ function updateSnippet (snippet, snippetFile) {
if (
currentSnippet.name === snippet.name &&
currentSnippet.prefix === snippet.prefix &&
- currentSnippet.content === snippet.content
+ currentSnippet.content === snippet.content &&
+ currentSnippet.linesHighlighted === snippet.linesHighlighted
) {
// if everything is the same then don't write to disk
resolve(snippets)
@@ -20,6 +21,7 @@ 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)
diff --git a/browser/main/lib/eventEmitter.js b/browser/main/lib/eventEmitter.js
index de08f078..1276545b 100644
--- a/browser/main/lib/eventEmitter.js
+++ b/browser/main/lib/eventEmitter.js
@@ -14,7 +14,6 @@ function once (name, listener) {
}
function emit (name, ...args) {
- console.log(name)
remote.getCurrentWindow().webContents.send(name, ...args)
}
diff --git a/browser/main/lib/ipcClient.js b/browser/main/lib/ipcClient.js
index 0c916617..c06296b5 100644
--- a/browser/main/lib/ipcClient.js
+++ b/browser/main/lib/ipcClient.js
@@ -14,14 +14,13 @@ nodeIpc.connectTo(
path.join(app.getPath('userData'), 'boostnote.service'),
function () {
nodeIpc.of.node.on('error', function (err) {
- console.log(err)
+ console.error(err)
})
nodeIpc.of.node.on('connect', function () {
- console.log('Connected successfully')
ipcRenderer.send('config-renew', {config: ConfigManager.get()})
})
nodeIpc.of.node.on('disconnect', function () {
- console.log('disconnected')
+ return
})
}
)
diff --git a/browser/main/lib/shortcut.js b/browser/main/lib/shortcut.js
index a6f33196..3165606a 100644
--- a/browser/main/lib/shortcut.js
+++ b/browser/main/lib/shortcut.js
@@ -3,5 +3,11 @@ import ee from 'browser/main/lib/eventEmitter'
module.exports = {
'toggleMode': () => {
ee.emit('topbar:togglemodebutton')
+ },
+ 'deleteNote': () => {
+ ee.emit('hotkey:deletenote')
+ },
+ 'toggleMenuBar': () => {
+ ee.emit('menubar:togglemenubar')
}
}
diff --git a/browser/main/modals/NewNoteModal.js b/browser/main/modals/NewNoteModal.js
index 8b16f2a2..a190602c 100644
--- a/browser/main/modals/NewNoteModal.js
+++ b/browser/main/modals/NewNoteModal.js
@@ -21,8 +21,8 @@ class NewNoteModal extends React.Component {
}
handleMarkdownNoteButtonClick (e) {
- const { storage, folder, dispatch, location } = this.props
- createMarkdownNote(storage, folder, dispatch, location).then(() => {
+ const { storage, folder, dispatch, location, params, config } = this.props
+ createMarkdownNote(storage, folder, dispatch, location, params, config).then(() => {
setTimeout(this.props.close, 200)
})
}
@@ -35,8 +35,8 @@ class NewNoteModal extends React.Component {
}
handleSnippetNoteButtonClick (e) {
- const { storage, folder, dispatch, location, config } = this.props
- createSnippetNote(storage, folder, dispatch, location, config).then(() => {
+ const { storage, folder, dispatch, location, params, config } = this.props
+ createSnippetNote(storage, folder, dispatch, location, params, config).then(() => {
setTimeout(this.props.close, 200)
})
}
diff --git a/browser/main/modals/PreferencesModal/Crowdfunding.js b/browser/main/modals/PreferencesModal/Crowdfunding.js
index f342fb76..f6389cd8 100644
--- a/browser/main/modals/PreferencesModal/Crowdfunding.js
+++ b/browser/main/modals/PreferencesModal/Crowdfunding.js
@@ -23,21 +23,29 @@ class Crowdfunding extends React.Component {
return (
{i18n.__('Crowdfunding')}
-
{i18n.__('Dear Boostnote users,')}
-
{i18n.__('Thank you for using Boostnote!')}
-
{i18n.__('Boostnote is used in about 200 different countries and regions by an awesome community of developers.')}
-
{i18n.__('To support our growing userbase, and satisfy community expectations,')}
-
{i18n.__('we would like to invest more time and resources in this project.')}
+
{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.__('If you use Boostnote and see its potential, help us out by supporting the project on OpenCollective!')}
+
{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.__('Thanks,')}
+
{i18n.__('### We believe Meritocracy')}
+
{i18n.__('We think developers who has skill and did 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.__('As same as issues of Boostnote are already funded on IssueHunt, your open-source projects can be also started funding from now.')}