mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-22 14:11:42 +00:00
Merge branch 'master' of https://github.com/BoostIO/Boostnote into fix-2903
This commit is contained in:
@@ -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', {
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ const win = global.process.platform === 'win32'
|
||||
const electron = require('electron')
|
||||
const { ipcRenderer } = electron
|
||||
const consts = require('browser/lib/consts')
|
||||
const electronConfig = new (require('electron-config'))()
|
||||
|
||||
let isInitialized = false
|
||||
|
||||
@@ -15,6 +16,22 @@ const DEFAULT_MARKDOWN_LINT_CONFIG = `{
|
||||
"default": true
|
||||
}`
|
||||
|
||||
const DEFAULT_CSS_CONFIG = `
|
||||
/* Drop Your Custom CSS Code Here */
|
||||
[data-theme="default"] p code,
|
||||
[data-theme="default"] li code,
|
||||
[data-theme="default"] td code
|
||||
{
|
||||
padding: 2px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-radius: 5px;
|
||||
background-color: #F4F4F4;
|
||||
border-color: #d9d9d9;
|
||||
color: #03C588;
|
||||
}
|
||||
`
|
||||
|
||||
export const DEFAULT_CONFIG = {
|
||||
zoom: 1,
|
||||
isSideNavFolded: false,
|
||||
@@ -25,13 +42,19 @@ export const DEFAULT_CONFIG = {
|
||||
},
|
||||
sortTagsBy: 'ALPHABETICAL', // 'ALPHABETICAL', 'COUNTER'
|
||||
listStyle: 'DEFAULT', // 'DEFAULT', 'SMALL'
|
||||
listDirection: 'ASCENDING', // 'ASCENDING', 'DESCENDING'
|
||||
amaEnabled: true,
|
||||
autoUpdateEnabled: true,
|
||||
hotkey: {
|
||||
toggleMain: OSX ? 'Command + Alt + L' : 'Super + Alt + E',
|
||||
toggleMode: OSX ? 'Command + Alt + M' : 'Ctrl + M',
|
||||
deleteNote: OSX ? 'Command + Shift + Backspace' : 'Ctrl + Shift + Backspace',
|
||||
toggleDirection: OSX ? 'Command + Alt + Right' : 'Ctrl + Alt + Right',
|
||||
deleteNote: OSX
|
||||
? 'Command + Shift + Backspace'
|
||||
: 'Ctrl + Shift + Backspace',
|
||||
pasteSmartly: OSX ? 'Command + Shift + V' : 'Ctrl + Shift + V',
|
||||
prettifyMarkdown: 'Shift + F',
|
||||
prettifyMarkdown: OSX ? 'Command + Shift + F' : 'Ctrl + Shift + F',
|
||||
sortLines: OSX ? 'Command + Shift + S' : 'Ctrl + Shift + S',
|
||||
insertDate: OSX ? 'Command + /' : 'Ctrl + /',
|
||||
insertDateTime: OSX ? 'Command + Alt + /' : 'Ctrl + Shift + /',
|
||||
toggleMenuBar: 'Alt'
|
||||
@@ -39,8 +62,14 @@ export const DEFAULT_CONFIG = {
|
||||
ui: {
|
||||
language: 'en',
|
||||
theme: 'default',
|
||||
defaultTheme: 'default',
|
||||
enableScheduleTheme: false,
|
||||
scheduledTheme: 'monokai',
|
||||
scheduleStart: 1200,
|
||||
scheduleEnd: 360,
|
||||
showCopyNotification: true,
|
||||
disableDirectWrite: false,
|
||||
showScrollBar: true,
|
||||
defaultNote: 'ALWAYS_ASK', // 'ALWAYS_ASK', 'SNIPPET_NOTE', 'MARKDOWN_NOTE'
|
||||
showMenuBar: false,
|
||||
isStacking: false
|
||||
@@ -71,13 +100,14 @@ export const DEFAULT_CONFIG = {
|
||||
enableSmartPaste: false,
|
||||
enableMarkdownLint: false,
|
||||
customMarkdownLintConfig: DEFAULT_MARKDOWN_LINT_CONFIG,
|
||||
prettierConfig: ` {
|
||||
prettierConfig: `{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 4,
|
||||
"tabWidth": 2,
|
||||
"semi": false,
|
||||
"singleQuote": true
|
||||
}`,
|
||||
deleteUnusedAttachments: true
|
||||
deleteUnusedAttachments: true,
|
||||
rtlEnabled: false
|
||||
},
|
||||
preview: {
|
||||
fontSize: '14',
|
||||
@@ -95,8 +125,7 @@ export const DEFAULT_CONFIG = {
|
||||
breaks: true,
|
||||
smartArrows: false,
|
||||
allowCustomCSS: false,
|
||||
|
||||
customCSS: '/* Drop Your Custom CSS Code Here */',
|
||||
customCSS: DEFAULT_CSS_CONFIG,
|
||||
sanitize: 'STRICT', // 'STRICT', 'ALLOW_STYLES', 'NONE'
|
||||
mermaidHTMLLabel: false,
|
||||
lineThroughCheckbox: true
|
||||
@@ -112,7 +141,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
|
||||
@@ -121,13 +150,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 {
|
||||
@@ -141,6 +174,11 @@ function get () {
|
||||
_save(config)
|
||||
}
|
||||
|
||||
config.autoUpdateEnabled = electronConfig.get(
|
||||
'autoUpdateEnabled',
|
||||
config.autoUpdateEnabled
|
||||
)
|
||||
|
||||
if (!isInitialized) {
|
||||
isInitialized = true
|
||||
let editorTheme = document.getElementById('editorTheme')
|
||||
@@ -151,7 +189,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)
|
||||
@@ -163,7 +203,7 @@ function get () {
|
||||
return config
|
||||
}
|
||||
|
||||
function set (updates) {
|
||||
function set(updates) {
|
||||
const currentConfig = get()
|
||||
|
||||
const arrangedUpdates = updates
|
||||
@@ -171,24 +211,15 @@ 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)
|
||||
|
||||
if (newConfig.ui.theme === 'dark') {
|
||||
document.body.setAttribute('data-theme', 'dark')
|
||||
} else if (newConfig.ui.theme === 'white') {
|
||||
document.body.setAttribute('data-theme', 'white')
|
||||
} else if (newConfig.ui.theme === 'solarized-dark') {
|
||||
document.body.setAttribute('data-theme', 'solarized-dark')
|
||||
} else if (newConfig.ui.theme === 'monokai') {
|
||||
document.body.setAttribute('data-theme', 'monokai')
|
||||
} else if (newConfig.ui.theme === 'dracula') {
|
||||
document.body.setAttribute('data-theme', 'dracula')
|
||||
} else {
|
||||
document.body.setAttribute('data-theme', 'default')
|
||||
}
|
||||
|
||||
i18n.setLocale(newConfig.ui.language)
|
||||
|
||||
let editorTheme = document.getElementById('editorTheme')
|
||||
@@ -199,32 +230,61 @@ 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)
|
||||
}
|
||||
|
||||
electronConfig.set('autoUpdateEnabled', newConfig.autoUpdateEnabled)
|
||||
|
||||
ipcRenderer.send('config-renew', {
|
||||
config: get()
|
||||
})
|
||||
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 ')
|
||||
|
||||
65
browser/main/lib/ThemeManager.js
Normal file
65
browser/main/lib/ThemeManager.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||
|
||||
const saveChanges = newConfig => {
|
||||
ConfigManager.set(newConfig)
|
||||
}
|
||||
|
||||
const chooseTheme = config => {
|
||||
const { ui } = config
|
||||
if (!ui.enableScheduleTheme) {
|
||||
return
|
||||
}
|
||||
|
||||
const start = parseInt(ui.scheduleStart)
|
||||
const end = parseInt(ui.scheduleEnd)
|
||||
|
||||
const now = new Date()
|
||||
const minutes = now.getHours() * 60 + now.getMinutes()
|
||||
|
||||
const isEndAfterStart = end > start
|
||||
const isBetweenStartAndEnd = minutes >= start && minutes < end
|
||||
const isBetweenEndAndStart = minutes >= start || minutes < end
|
||||
|
||||
if (
|
||||
(isEndAfterStart && isBetweenStartAndEnd) ||
|
||||
(!isEndAfterStart && isBetweenEndAndStart)
|
||||
) {
|
||||
if (ui.theme !== ui.scheduledTheme) {
|
||||
ui.defaultTheme = ui.theme
|
||||
ui.theme = ui.scheduledTheme
|
||||
applyTheme(ui.theme)
|
||||
saveChanges(config)
|
||||
}
|
||||
} else {
|
||||
if (ui.theme !== ui.defaultTheme) {
|
||||
ui.theme = ui.defaultTheme
|
||||
applyTheme(ui.theme)
|
||||
saveChanges(config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const applyTheme = theme => {
|
||||
const supportedThemes = [
|
||||
'dark',
|
||||
'white',
|
||||
'solarized-dark',
|
||||
'monokai',
|
||||
'dracula'
|
||||
]
|
||||
if (supportedThemes.indexOf(theme) !== -1) {
|
||||
document.body.setAttribute('data-theme', theme)
|
||||
if (document.body.querySelector('.MarkdownPreview')) {
|
||||
document.body
|
||||
.querySelector('.MarkdownPreview')
|
||||
.contentDocument.body.setAttribute('data-theme', theme)
|
||||
}
|
||||
} else {
|
||||
document.body.setAttribute('data-theme', 'default')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
chooseTheme,
|
||||
applyTheme
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
})
|
||||
|
||||
@@ -6,28 +6,46 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
function createNoteFromUrl (url, storage, folder, dispatch = null, location = null) {
|
||||
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',
|
||||
UNEXPECTED: 'Unexpected error! Please check console for details!'
|
||||
}
|
||||
|
||||
function createNoteFromUrl(
|
||||
url,
|
||||
storage,
|
||||
folder,
|
||||
dispatch = null,
|
||||
location = null
|
||||
) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const td = createTurndownService()
|
||||
|
||||
if (!validateUrl(url)) {
|
||||
reject({result: false, error: 'Please check your URL is in correct format. (Example, https://www.google.com)'})
|
||||
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
|
||||
})
|
||||
|
||||
@@ -40,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, {
|
||||
@@ -61,17 +80,21 @@ 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: e})
|
||||
reject({
|
||||
result: false,
|
||||
error: ERROR_MESSAGES[e.code] || ERROR_MESSAGES.UNEXPECTED
|
||||
})
|
||||
})
|
||||
|
||||
req.end()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
})
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
<div className={'ModalBase' + (this.state.isHidden ? ' hide' : '')}>
|
||||
<div onClick={(e) => this.close(e)} className='modalBack' />
|
||||
<div onClick={e => this.close(e)} className='modalBack' />
|
||||
{this.state.component == null ? null : (
|
||||
<Provider store={store}>
|
||||
<this.state.component {...this.state.componentProps} close={this.close} />
|
||||
<this.state.component
|
||||
{...this.state.componentProps}
|
||||
close={this.close}
|
||||
/>
|
||||
</Provider>
|
||||
)}
|
||||
</div>
|
||||
@@ -38,21 +48,31 @@ const el = document.createElement('div')
|
||||
document.body.appendChild(el)
|
||||
const modalBase = ReactDOM.render(<ModalBase />, 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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import ee from 'browser/main/lib/eventEmitter'
|
||||
|
||||
module.exports = {
|
||||
'toggleMode': () => {
|
||||
toggleMode: () => {
|
||||
ee.emit('topbar:togglemodebutton')
|
||||
},
|
||||
'deleteNote': () => {
|
||||
toggleDirection: () => {
|
||||
ee.emit('topbar:toggledirectionbutton')
|
||||
},
|
||||
deleteNote: () => {
|
||||
ee.emit('hotkey:deletenote')
|
||||
},
|
||||
'toggleMenuBar': () => {
|
||||
toggleMenuBar: () => {
|
||||
ee.emit('menubar:togglemenubar')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user