mirror of
https://github.com/BoostIo/Boostnote
synced 2026-01-07 05:59:20 +00:00
Merge branch '0.6.0'
This commit is contained in:
31
browser/main/lib/Commander.js
Normal file
31
browser/main/lib/Commander.js
Normal file
@@ -0,0 +1,31 @@
|
||||
let callees = []
|
||||
|
||||
function bind (name, el) {
|
||||
callees.push({
|
||||
name: name,
|
||||
element: el
|
||||
})
|
||||
}
|
||||
|
||||
function release (el) {
|
||||
callees = callees.filter((callee) => callee.element !== el)
|
||||
}
|
||||
|
||||
function fire (command) {
|
||||
console.info('COMMAND >>', command)
|
||||
let splitted = command.split(':')
|
||||
let target = splitted[0]
|
||||
let targetCommand = splitted[1]
|
||||
let targetCallees = callees
|
||||
.filter((callee) => callee.name === target)
|
||||
|
||||
targetCallees.forEach((callee) => {
|
||||
callee.element.fire(targetCommand)
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
bind,
|
||||
release,
|
||||
fire
|
||||
}
|
||||
84
browser/main/lib/ConfigManager.js
Normal file
84
browser/main/lib/ConfigManager.js
Normal file
@@ -0,0 +1,84 @@
|
||||
import _ from 'lodash'
|
||||
|
||||
const OSX = global.process.platform === 'darwin'
|
||||
const electron = require('electron')
|
||||
const { ipcRenderer } = electron
|
||||
|
||||
const defaultConfig = {
|
||||
zoom: 1,
|
||||
isSideNavFolded: false,
|
||||
listWidth: 250,
|
||||
hotkey: {
|
||||
toggleFinder: OSX ? 'Cmd + Alt + S' : 'Super + Alt + S',
|
||||
toggleMain: OSX ? 'Cmd + Alt + L' : 'Super + Alt + E'
|
||||
},
|
||||
ui: {
|
||||
theme: 'default',
|
||||
disableDirectWrite: false
|
||||
},
|
||||
editor: {
|
||||
theme: 'xcode',
|
||||
fontSize: '14',
|
||||
fontFamily: 'Monaco, Consolas',
|
||||
indentType: 'space',
|
||||
indentSize: '4',
|
||||
switchPreview: 'BLUR' // Available value: RIGHTCLICK, BLUR
|
||||
},
|
||||
preview: {
|
||||
fontSize: '14',
|
||||
fontFamily: 'Lato',
|
||||
codeBlockTheme: 'xcode',
|
||||
lineNumber: true
|
||||
}
|
||||
}
|
||||
|
||||
function validate (config) {
|
||||
if (!_.isObject(config)) return false
|
||||
if (!_.isNumber(config.zoom) || config.zoom < 0) return false
|
||||
if (!_.isBoolean(config.isSideNavFolded)) return false
|
||||
if (!_.isNumber(config.listWidth) || config.listWidth <= 0) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
function _save (config) {
|
||||
console.log(config)
|
||||
window.localStorage.setItem('config', JSON.stringify(config))
|
||||
}
|
||||
|
||||
function get () {
|
||||
let config = window.localStorage.getItem('config')
|
||||
|
||||
try {
|
||||
config = Object.assign({}, defaultConfig, JSON.parse(config))
|
||||
if (!validate(config)) throw new Error('INVALID CONFIG')
|
||||
} catch (err) {
|
||||
console.warn('Boostnote resets the malformed configuration.')
|
||||
config = defaultConfig
|
||||
_save(config)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
function set (updates) {
|
||||
let currentConfig = get()
|
||||
let newConfig = Object.assign({}, defaultConfig, currentConfig, updates)
|
||||
if (!validate(newConfig)) throw new Error('INVALID CONFIG')
|
||||
_save(newConfig)
|
||||
ipcRenderer.send('CONFIG_RENEW', {
|
||||
config: get(),
|
||||
silent: false
|
||||
})
|
||||
}
|
||||
|
||||
ipcRenderer.send('CONFIG_RENEW', {
|
||||
config: get(),
|
||||
silent: true
|
||||
})
|
||||
|
||||
export default {
|
||||
get,
|
||||
set,
|
||||
validate
|
||||
}
|
||||
30
browser/main/lib/ZoomManager.js
Normal file
30
browser/main/lib/ZoomManager.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import ConfigManager from './ConfigManager'
|
||||
|
||||
const electron = require('electron')
|
||||
const { remote } = electron
|
||||
|
||||
_init()
|
||||
|
||||
function _init () {
|
||||
setZoom(getZoom(), true)
|
||||
}
|
||||
|
||||
function _saveZoom (zoomFactor) {
|
||||
ConfigManager.set({zoom: zoomFactor})
|
||||
}
|
||||
|
||||
function setZoom (zoomFactor, noSave = false) {
|
||||
if (!noSave) _saveZoom(zoomFactor)
|
||||
remote.getCurrentWebContents().setZoomFactor(zoomFactor)
|
||||
}
|
||||
|
||||
function getZoom () {
|
||||
let config = ConfigManager.get()
|
||||
|
||||
return config.zoom
|
||||
}
|
||||
|
||||
export default {
|
||||
setZoom,
|
||||
getZoom
|
||||
}
|
||||
565
browser/main/lib/dataApi.js
Normal file
565
browser/main/lib/dataApi.js
Normal file
@@ -0,0 +1,565 @@
|
||||
const keygen = require('browser/lib/keygen')
|
||||
const CSON = require('season')
|
||||
const path = require('path')
|
||||
const _ = require('lodash')
|
||||
const sander = require('sander')
|
||||
const consts = require('browser/lib/consts')
|
||||
|
||||
let storages = []
|
||||
let notes = []
|
||||
|
||||
let queuedTasks = []
|
||||
|
||||
function queueSaveFolder (storageKey, folderKey) {
|
||||
let storage = _.find(storages, {key: storageKey})
|
||||
if (storage == null) throw new Error('Failed to queue: Storage doesn\'t exist.')
|
||||
|
||||
let targetTasks = queuedTasks.filter((task) => task.storage === storageKey && task.folder === folderKey)
|
||||
targetTasks.forEach((task) => {
|
||||
clearTimeout(task.timer)
|
||||
})
|
||||
queuedTasks = queuedTasks.filter((task) => task.storage !== storageKey || task.folder !== folderKey)
|
||||
let newTimer = setTimeout(() => {
|
||||
let folderNotes = notes.filter((note) => note.storage === storageKey && note.folder === folderKey)
|
||||
sander
|
||||
.writeFile(path.join(storage.cache.path, folderKey, 'data.json'), JSON.stringify({
|
||||
notes: folderNotes.map((note) => {
|
||||
let json = note.toJSON()
|
||||
delete json.storage
|
||||
return json
|
||||
})
|
||||
}))
|
||||
}, 1500)
|
||||
|
||||
queuedTasks.push({
|
||||
storage: storageKey,
|
||||
folder: folderKey,
|
||||
timer: newTimer
|
||||
})
|
||||
}
|
||||
|
||||
class Storage {
|
||||
constructor (cache) {
|
||||
this.key = cache.key
|
||||
this.cache = cache
|
||||
}
|
||||
|
||||
loadJSONData () {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
let data = CSON.readFileSync(path.join(this.cache.path, 'boostnote.json'))
|
||||
this.data = data
|
||||
resolve(this)
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
toJSON () {
|
||||
return Object.assign({}, this.cache, this.data)
|
||||
}
|
||||
|
||||
initStorage () {
|
||||
return this.loadJSONData()
|
||||
.catch((err) => {
|
||||
console.error(err.code)
|
||||
if (err.code === 'ENOENT') {
|
||||
let initialStorage = {
|
||||
folders: []
|
||||
}
|
||||
|
||||
return sander.writeFile(path.join(this.cache.path, 'boostnote.json'), JSON.stringify(initialStorage))
|
||||
} else throw err
|
||||
})
|
||||
.then(() => this.loadJSONData())
|
||||
}
|
||||
|
||||
saveData () {
|
||||
return sander
|
||||
.writeFile(path.join(this.cache.path, 'boostnote.json'), JSON.stringify(this.data))
|
||||
.then(() => this)
|
||||
}
|
||||
|
||||
saveCache () {
|
||||
_saveCaches()
|
||||
}
|
||||
|
||||
static forge (cache) {
|
||||
let instance = new this(cache)
|
||||
return instance
|
||||
}
|
||||
}
|
||||
|
||||
class Note {
|
||||
constructor (note) {
|
||||
this.storage = note.storage
|
||||
this.folder = note.folder
|
||||
this.key = note.key
|
||||
this.uniqueKey = `${note.storage}-${note.folder}-${note.key}`
|
||||
this.data = note
|
||||
}
|
||||
|
||||
toJSON () {
|
||||
return Object.assign({}, this.data, {
|
||||
uniqueKey: this.uniqueKey
|
||||
})
|
||||
}
|
||||
|
||||
save () {
|
||||
let storage = _.find(storages, {key: this.storage})
|
||||
if (storage == null) return Promise.reject(new Error('Storage doesn\'t exist.'))
|
||||
let folder = _.find(storage.data.folders, {key: this.folder})
|
||||
if (folder == null) return Promise.reject(new Error('Storage doesn\'t exist.'))
|
||||
|
||||
// FS MUST BE MANIPULATED BY ASYNC METHOD
|
||||
queueSaveFolder(storage.key, folder.key)
|
||||
return Promise.resolve(this)
|
||||
}
|
||||
|
||||
static forge (note) {
|
||||
let instance = new this(note)
|
||||
|
||||
return Promise.resolve(instance)
|
||||
}
|
||||
}
|
||||
|
||||
function init () {
|
||||
let fetchStorages = function () {
|
||||
let caches
|
||||
try {
|
||||
caches = JSON.parse(localStorage.getItem('storages'))
|
||||
if (!_.isArray(caches)) throw new Error('Cached data is not valid.')
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
caches = []
|
||||
localStorage.setItem('storages', JSON.stringify(caches))
|
||||
}
|
||||
|
||||
return caches.map((cache) => {
|
||||
return Storage
|
||||
.forge(cache)
|
||||
.loadJSONData()
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
console.error('Failed to load a storage JSON File: %s', cache)
|
||||
return null
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
let fetchNotes = function (storages) {
|
||||
let notes = []
|
||||
let modifiedStorages = []
|
||||
storages
|
||||
.forEach((storage) => {
|
||||
storage.data.folders.forEach((folder) => {
|
||||
let dataPath = path.join(storage.cache.path, folder.key, 'data.json')
|
||||
let data
|
||||
try {
|
||||
data = CSON.readFileSync(dataPath)
|
||||
} catch (e) {
|
||||
// Remove folder if fetching failed.
|
||||
console.error('Failed to load data: %s', dataPath)
|
||||
storage.data.folders = storage.data.folders.filter((_folder) => _folder.key !== folder.key)
|
||||
if (modifiedStorages.some((modified) => modified.key === storage.key)) modifiedStorages.push(storage)
|
||||
return
|
||||
}
|
||||
data.notes.forEach((note) => {
|
||||
note.storage = storage.key
|
||||
note.folder = folder.key
|
||||
notes.push(Note.forge(note))
|
||||
})
|
||||
})
|
||||
}, [])
|
||||
return Promise
|
||||
.all(modifiedStorages.map((storage) => storage.saveData()))
|
||||
.then(() => Promise.all(notes))
|
||||
}
|
||||
|
||||
return Promise.all(fetchStorages())
|
||||
.then((_storages) => {
|
||||
storages = _storages.filter((storage) => {
|
||||
if (!_.isObject(storage)) return false
|
||||
return true
|
||||
})
|
||||
_saveCaches()
|
||||
|
||||
return storages
|
||||
})
|
||||
.then(fetchNotes)
|
||||
.then((_notes) => {
|
||||
notes = _notes
|
||||
return {
|
||||
storages: storages.map((storage) => storage.toJSON()),
|
||||
notes: notes.map((note) => note.toJSON())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function _saveCaches () {
|
||||
localStorage.setItem('storages', JSON.stringify(storages.map((storage) => storage.cache)))
|
||||
}
|
||||
|
||||
function addStorage (input) {
|
||||
if (!_.isString(input.path) || !input.path.match(/^\//)) {
|
||||
return Promise.reject(new Error('Path must be absolute.'))
|
||||
}
|
||||
|
||||
let key = keygen()
|
||||
while (storages.some((storage) => storage.key === key)) {
|
||||
key = keygen()
|
||||
}
|
||||
|
||||
return Storage
|
||||
.forge({
|
||||
name: input.name,
|
||||
key: key,
|
||||
type: input.type,
|
||||
path: input.path
|
||||
})
|
||||
.initStorage()
|
||||
.then((storage) => {
|
||||
let _notes = []
|
||||
let isFolderRemoved = false
|
||||
storage.data.folders.forEach((folder) => {
|
||||
let dataPath = path.join(storage.cache.path, folder.key, 'data.json')
|
||||
let data
|
||||
try {
|
||||
data = CSON.readFileSync(dataPath)
|
||||
} catch (e) {
|
||||
// Remove folder if fetching failed.
|
||||
console.error('Failed to load data: %s', dataPath)
|
||||
storage.data.folders = storage.data.folders.filter((_folder) => _folder.key !== folder.key)
|
||||
isFolderRemoved = true
|
||||
return true
|
||||
}
|
||||
data.notes.forEach((note) => {
|
||||
note.storage = storage.key
|
||||
note.folder = folder.key
|
||||
_notes.push(Note.forge(note))
|
||||
})
|
||||
})
|
||||
|
||||
return Promise.all(_notes)
|
||||
.then((_notes) => {
|
||||
notes = notes.concat(_notes)
|
||||
let data = {
|
||||
storage: storage,
|
||||
notes: _notes
|
||||
}
|
||||
return isFolderRemoved
|
||||
? storage.saveData().then(() => data)
|
||||
: data
|
||||
})
|
||||
})
|
||||
.then((data) => {
|
||||
storages = storages.filter((storage) => storage.key !== data.storage.key)
|
||||
storages.push(data.storage)
|
||||
_saveCaches()
|
||||
|
||||
if (data.storage.data.folders.length < 1) {
|
||||
return createFolder(data.storage.key, {
|
||||
name: 'Default',
|
||||
color: consts.FOLDER_COLORS[0]
|
||||
}).then(() => data)
|
||||
}
|
||||
|
||||
return data
|
||||
})
|
||||
.then((data) => {
|
||||
return {
|
||||
storage: data.storage.toJSON(),
|
||||
notes: data.notes.map((note) => note.toJSON())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function removeStorage (key) {
|
||||
storages = storages.filter((storage) => storage.key !== key)
|
||||
_saveCaches()
|
||||
notes = notes.filter((note) => note.storage !== key)
|
||||
return Promise.resolve(true)
|
||||
}
|
||||
|
||||
function renameStorage (key, name) {
|
||||
let storage = _.find(storages, {key: key})
|
||||
if (storage == null) throw new Error('Storage doesn\'t exist.')
|
||||
storage.cache.name = name
|
||||
storage.saveCache()
|
||||
|
||||
return Promise.resolve(storage.toJSON())
|
||||
}
|
||||
|
||||
function migrateFromV5 (key, data) {
|
||||
let oldFolders = data.folders
|
||||
let oldArticles = data.articles
|
||||
let storage = _.find(storages, {key: key})
|
||||
if (storage == null) throw new Error('Storage doesn\'t exist.')
|
||||
|
||||
let migrateFolders = oldFolders.map((oldFolder) => {
|
||||
let folderKey = keygen()
|
||||
while (storage.data.folders.some((folder) => folder.key === folderKey)) {
|
||||
folderKey = keygen()
|
||||
}
|
||||
let newFolder = {
|
||||
key: folderKey,
|
||||
name: oldFolder.name,
|
||||
color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7]
|
||||
}
|
||||
storage.data.folders.push(newFolder)
|
||||
let articles = oldArticles.filter((article) => article.FolderKey === oldFolder.key)
|
||||
let folderNotes = []
|
||||
articles.forEach((article) => {
|
||||
let noteKey = keygen()
|
||||
while (notes.some((note) => note.storage === key && note.folder === folderKey && note.key === noteKey)) {
|
||||
key = keygen()
|
||||
}
|
||||
if (article.mode === 'markdown') {
|
||||
let newNote = new Note({
|
||||
tags: article.tags,
|
||||
createdAt: article.createdAt,
|
||||
updatedAt: article.updatedAt,
|
||||
folder: folderKey,
|
||||
storage: key,
|
||||
type: 'MARKDOWN_NOTE',
|
||||
isStarred: false,
|
||||
title: article.title,
|
||||
content: '# ' + article.title + '\n\n' + article.content,
|
||||
key: noteKey
|
||||
})
|
||||
notes.push(newNote)
|
||||
folderNotes.push(newNote)
|
||||
} else {
|
||||
let newNote = new Note({
|
||||
tags: article.tags,
|
||||
createdAt: article.createdAt,
|
||||
updatedAt: article.updatedAt,
|
||||
folder: folderKey,
|
||||
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
|
||||
}]
|
||||
})
|
||||
notes.push(newNote)
|
||||
folderNotes.push(newNote)
|
||||
}
|
||||
})
|
||||
|
||||
return sander
|
||||
.writeFile(path.join(storage.cache.path, folderKey, 'data.json'), JSON.stringify({
|
||||
notes: folderNotes.map((note) => {
|
||||
let json = note.toJSON()
|
||||
delete json.storage
|
||||
return json
|
||||
})
|
||||
}))
|
||||
})
|
||||
return Promise.all(migrateFolders)
|
||||
.then(() => storage.saveData())
|
||||
.then(() => {
|
||||
return {
|
||||
storage: storage.toJSON(),
|
||||
notes: notes.filter((note) => note.storage === key)
|
||||
.map((note) => note.toJSON())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function createFolder (key, input) {
|
||||
let storage = _.find(storages, {key: key})
|
||||
if (storage == null) throw new Error('Storage doesn\'t exist.')
|
||||
|
||||
let folderKey = keygen()
|
||||
while (storage.data.folders.some((folder) => folder.key === folderKey)) {
|
||||
folderKey = keygen()
|
||||
}
|
||||
|
||||
let newFolder = {
|
||||
key: folderKey,
|
||||
name: input.name,
|
||||
color: input.color
|
||||
}
|
||||
|
||||
const defaultData = {notes: []}
|
||||
// FS MUST BE MANIPULATED BY ASYNC METHOD
|
||||
return sander
|
||||
.writeFile(path.join(storage.cache.path, folderKey, 'data.json'), JSON.stringify(defaultData))
|
||||
.then(() => {
|
||||
storage.data.folders.push(newFolder)
|
||||
return storage
|
||||
.saveData()
|
||||
.then((storage) => storage.toJSON())
|
||||
})
|
||||
}
|
||||
|
||||
function updateFolder (storageKey, folderKey, input) {
|
||||
let storage = _.find(storages, {key: storageKey})
|
||||
if (storage == null) throw new Error('Storage doesn\'t exist.')
|
||||
let folder = _.find(storage.data.folders, {key: folderKey})
|
||||
folder.color = input.color
|
||||
folder.name = input.name
|
||||
|
||||
return storage
|
||||
.saveData()
|
||||
.then((storage) => storage.toJSON())
|
||||
}
|
||||
|
||||
function removeFolder (storageKey, folderKey) {
|
||||
let storage = _.find(storages, {key: storageKey})
|
||||
if (storage == null) throw new Error('Storage doesn\'t exist.')
|
||||
storage.data.folders = storage.data.folders.filter((folder) => folder.key !== folderKey)
|
||||
notes = notes.filter((note) => note.storage !== storageKey || note.folder !== folderKey)
|
||||
|
||||
// FS MUST BE MANIPULATED BY ASYNC METHOD
|
||||
return sander
|
||||
.rimraf(path.join(storage.cache.path, folderKey))
|
||||
.catch((err) => {
|
||||
if (err.code === 'ENOENT') return true
|
||||
else throw err
|
||||
})
|
||||
.then(() => storage.saveData())
|
||||
.then((storage) => storage.toJSON())
|
||||
}
|
||||
|
||||
function createMarkdownNote (storageKey, folderKey, input) {
|
||||
let key = keygen()
|
||||
while (notes.some((note) => note.storage === storageKey && note.folder === folderKey && note.key === key)) {
|
||||
key = keygen()
|
||||
}
|
||||
|
||||
let newNote = new Note(Object.assign({
|
||||
tags: [],
|
||||
title: '',
|
||||
content: ''
|
||||
}, input, {
|
||||
type: 'MARKDOWN_NOTE',
|
||||
storage: storageKey,
|
||||
folder: folderKey,
|
||||
key: key,
|
||||
isStarred: false,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
}))
|
||||
notes.push(newNote)
|
||||
|
||||
return newNote
|
||||
.save()
|
||||
.then(() => newNote.toJSON())
|
||||
}
|
||||
|
||||
function createSnippetNote (storageKey, folderKey, input) {
|
||||
let key = keygen()
|
||||
while (notes.some((note) => note.storage === storageKey && note.folder === folderKey && note.key === key)) {
|
||||
key = keygen()
|
||||
}
|
||||
|
||||
let newNote = new Note(Object.assign({
|
||||
tags: [],
|
||||
title: '',
|
||||
description: '',
|
||||
snippets: [{
|
||||
name: '',
|
||||
mode: 'text',
|
||||
content: ''
|
||||
}]
|
||||
}, input, {
|
||||
type: 'SNIPPET_NOTE',
|
||||
storage: storageKey,
|
||||
folder: folderKey,
|
||||
key: key,
|
||||
isStarred: false,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
}))
|
||||
notes.push(newNote)
|
||||
|
||||
return newNote
|
||||
.save()
|
||||
.then(() => newNote.toJSON())
|
||||
}
|
||||
|
||||
function updateNote (storageKey, folderKey, noteKey, input) {
|
||||
let note = _.find(notes, {
|
||||
key: noteKey,
|
||||
storage: storageKey,
|
||||
folder: folderKey
|
||||
})
|
||||
|
||||
switch (note.data.type) {
|
||||
case 'MARKDOWN_NOTE':
|
||||
note.data.title = input.title
|
||||
note.data.tags = input.tags
|
||||
note.data.content = input.content
|
||||
note.data.updatedAt = input.updatedAt
|
||||
break
|
||||
case 'SNIPPET_NOTE':
|
||||
note.data.title = input.title
|
||||
note.data.tags = input.tags
|
||||
note.data.description = input.description
|
||||
note.data.snippets = input.snippets
|
||||
note.data.updatedAt = input.updatedAt
|
||||
}
|
||||
|
||||
return note.save()
|
||||
.then(() => note.toJSON())
|
||||
}
|
||||
|
||||
function removeNote (storageKey, folderKey, noteKey) {
|
||||
notes = notes.filter((note) => note.storage !== storageKey || note.folder !== folderKey || note.key !== noteKey)
|
||||
queueSaveFolder(storageKey, folderKey)
|
||||
|
||||
return Promise.resolve(null)
|
||||
}
|
||||
|
||||
function moveNote (storageKey, folderKey, noteKey, newStorageKey, newFolderKey) {
|
||||
let note = _.find(notes, {
|
||||
key: noteKey,
|
||||
storage: storageKey,
|
||||
folder: folderKey
|
||||
})
|
||||
if (note == null) throw new Error('Note doesn\'t exist.')
|
||||
|
||||
let storage = _.find(storages, {key: newStorageKey})
|
||||
if (storage == null) throw new Error('Storage doesn\'t exist.')
|
||||
let folder = _.find(storage.data.folders, {key: newFolderKey})
|
||||
if (folder == null) throw new Error('Folder doesn\'t exist.')
|
||||
note.storage = storage.key
|
||||
note.data.storage = storage.key
|
||||
note.folder = folder.key
|
||||
note.data.folder = folder.key
|
||||
let key = note.key
|
||||
while (notes.some((note) => note.storage === storage.key && note.folder === folder.key && note.key === key)) {
|
||||
key = keygen()
|
||||
}
|
||||
note.key = key
|
||||
note.data.key = key
|
||||
note.uniqueKey = `${note.storage}-${note.folder}-${note.key}`
|
||||
console.log(note.uniqueKey)
|
||||
queueSaveFolder(storageKey, folderKey)
|
||||
return note.save()
|
||||
.then(() => note.toJSON())
|
||||
}
|
||||
|
||||
export default {
|
||||
init,
|
||||
addStorage,
|
||||
removeStorage,
|
||||
renameStorage,
|
||||
createFolder,
|
||||
updateFolder,
|
||||
removeFolder,
|
||||
createMarkdownNote,
|
||||
createSnippetNote,
|
||||
updateNote,
|
||||
removeNote,
|
||||
moveNote,
|
||||
migrateFromV5
|
||||
}
|
||||
26
browser/main/lib/eventEmitter.js
Normal file
26
browser/main/lib/eventEmitter.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const electron = require('electron')
|
||||
const { ipcRenderer, remote } = electron
|
||||
|
||||
function on (name, listener) {
|
||||
ipcRenderer.on(name, listener)
|
||||
}
|
||||
|
||||
function off (name, listener) {
|
||||
ipcRenderer.removeListener(name, listener)
|
||||
}
|
||||
|
||||
function once (name, listener) {
|
||||
ipcRenderer.once(name, listener)
|
||||
}
|
||||
|
||||
function emit (name, ...args) {
|
||||
console.log(name)
|
||||
remote.getCurrentWindow().webContents.send(name, ...args)
|
||||
}
|
||||
|
||||
export default {
|
||||
emit,
|
||||
on,
|
||||
off,
|
||||
once
|
||||
}
|
||||
58
browser/main/lib/modal.js
Normal file
58
browser/main/lib/modal.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import React from 'react'
|
||||
import { Provider } from 'react-redux'
|
||||
import ReactDOM from 'react-dom'
|
||||
import store from '../store'
|
||||
|
||||
class ModalBase extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
component: null,
|
||||
componentProps: {},
|
||||
isHidden: true
|
||||
}
|
||||
}
|
||||
|
||||
close () {
|
||||
if (modalBase != null) modalBase.setState({component: null, componentProps: null, isHidden: true})
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className={'ModalBase' + (this.state.isHidden ? ' hide' : '')}>
|
||||
<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}/>
|
||||
</Provider>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let el = document.createElement('div')
|
||||
document.body.appendChild(el)
|
||||
let modalBase = ReactDOM.render(<ModalBase/>, el)
|
||||
|
||||
export function openModal (component, props) {
|
||||
if (modalBase == null) { return }
|
||||
|
||||
document.body.setAttribute('data-modal', 'open')
|
||||
modalBase.setState({component: component, componentProps: props, isHidden: false})
|
||||
}
|
||||
|
||||
export function closeModal () {
|
||||
if (modalBase == null) { return }
|
||||
modalBase.close()
|
||||
}
|
||||
|
||||
export function isModalOpen () {
|
||||
return !modalBase.state.isHidden
|
||||
}
|
||||
|
||||
export default {
|
||||
open: openModal,
|
||||
close: closeModal,
|
||||
isOpen: isModalOpen
|
||||
}
|
||||
Reference in New Issue
Block a user