1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-15 10:46:32 +00:00

merge from master

This commit is contained in:
Callum booth
2019-06-10 19:13:58 +01:00
96 changed files with 2248 additions and 1026 deletions

View File

@@ -11,6 +11,10 @@ const consts = require('browser/lib/consts')
let isInitialized = false
const DEFAULT_MARKDOWN_LINT_CONFIG = `{
"default": true
}`
export const DEFAULT_CONFIG = {
zoom: 1,
isSideNavFolded: false,
@@ -47,7 +51,7 @@ export const DEFAULT_CONFIG = {
enableRulers: false,
rulers: [80, 120],
displayLineNumbers: true,
matchingPairs: '()[]{}\'\'""$$**``',
matchingPairs: '()[]{}\'\'""$$**``~~__',
matchingTriples: '```"""\'\'\'',
explodingPairs: '[]{}``$$',
switchPreview: 'BLUR', // 'BLUR', 'DBL_CLICK', 'RIGHTCLICK'
@@ -60,7 +64,9 @@ export const DEFAULT_CONFIG = {
enableFrontMatterTitle: true,
frontMatterTitleField: 'title',
spellcheck: false,
enableSmartPaste: false
enableSmartPaste: false,
enableMarkdownLint: false,
customMarkdownLintConfig: DEFAULT_MARKDOWN_LINT_CONFIG
},
preview: {
fontSize: '14',
@@ -133,16 +139,12 @@ function get () {
document.head.appendChild(editorTheme)
}
config.editor.theme = consts.THEMES.some((theme) => theme === config.editor.theme)
? config.editor.theme
: 'default'
const theme = consts.THEMES.find(theme => theme.name === config.editor.theme)
if (config.editor.theme !== 'default') {
if (config.editor.theme.startsWith('solarized')) {
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/solarized.css')
} else {
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + config.editor.theme + '.css')
}
if (theme) {
editorTheme.setAttribute('href', `../${theme.path}`)
} else {
config.editor.theme = 'default'
}
}
@@ -178,16 +180,11 @@ function set (updates) {
editorTheme.setAttribute('rel', 'stylesheet')
document.head.appendChild(editorTheme)
}
const newTheme = consts.THEMES.some((theme) => theme === newConfig.editor.theme)
? newConfig.editor.theme
: 'default'
if (newTheme !== 'default') {
if (newTheme.startsWith('solarized')) {
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/solarized.css')
} else {
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + newTheme + '.css')
}
const newTheme = consts.THEMES.find(theme => theme.name === newConfig.editor.theme)
if (newTheme) {
editorTheme.setAttribute('href', `../${newTheme.path}`)
}
ipcRenderer.send('config-renew', {

View File

@@ -85,7 +85,7 @@ function getOrientation (file) {
return view.getUint16(offset + (i * 12) + 8, little)
}
}
} else if ((marker & 0xFF00) !== 0xFF00) { // If not start with 0xFF, not a Marker
} else if ((marker & 0xFF00) !== 0xFF00) { // If not start with 0xFF, not a Marker.
break
} else {
offset += view.getUint16(offset, false)
@@ -278,27 +278,40 @@ function handleAttachmentDrop (codeEditor, storageKey, noteKey, dropEvent) {
let promise
if (dropEvent.dataTransfer.files.length > 0) {
promise = Promise.all(Array.from(dropEvent.dataTransfer.files).map(file => {
if (file.type.startsWith('image')) {
if (file.type === 'image/gif' || file.type === 'image/svg+xml') {
return copyAttachment(file.path, storageKey, noteKey).then(fileName => ({
const filePath = file.path
const fileType = file.type // EX) 'image/gif' or 'text/html'
if (fileType.startsWith('image')) {
if (fileType === 'image/gif' || fileType === 'image/svg+xml') {
return copyAttachment(filePath, storageKey, noteKey).then(fileName => ({
fileName,
title: path.basename(file.path),
title: path.basename(filePath),
isImage: true
}))
} else {
return fixRotate(file)
.then(data => copyAttachment({type: 'base64', data: data, sourceFilePath: file.path}, storageKey, noteKey)
.then(fileName => ({
return getOrientation(file)
.then((orientation) => {
if (orientation === -1) { // The image rotation is correct and does not need adjustment
return copyAttachment(filePath, storageKey, noteKey)
} else {
return fixRotate(file).then(data => copyAttachment({
type: 'base64',
data: data,
sourceFilePath: filePath
}, storageKey, noteKey))
}
})
.then(fileName =>
({
fileName,
title: path.basename(file.path),
title: path.basename(filePath),
isImage: true
}))
})
)
}
} else {
return copyAttachment(file.path, storageKey, noteKey).then(fileName => ({
return copyAttachment(filePath, storageKey, noteKey).then(fileName => ({
fileName,
title: path.basename(file.path),
title: path.basename(filePath),
isImage: false
}))
}
@@ -325,13 +338,18 @@ function handleAttachmentDrop (codeEditor, storageKey, noteKey, dropEvent) {
canvas.height = image.height
context.drawImage(image, 0, 0)
return copyAttachment({type: 'base64', data: canvas.toDataURL(), sourceFilePath: imageURL}, storageKey, noteKey)
return copyAttachment({
type: 'base64',
data: canvas.toDataURL(),
sourceFilePath: imageURL
}, storageKey, noteKey)
})
.then(fileName => ({
fileName,
title: imageURL,
isImage: true
}))])
}))
])
}
promise.then(files => {
@@ -449,6 +467,54 @@ function getAbsolutePathsOfAttachmentsInContent (markdownContent, storagePath) {
return result
}
/**
* @description Copies the attachments to the storage folder and returns the mardown content it should be replaced with
* @param {String} markDownContent content in which the attachment paths should be found
* @param {String} filepath The path of the file with attachments to import
* @param {String} storageKey Storage key of the destination storage
* @param {String} noteKey Key of the current note. Will be used as subfolder in :storage
*/
function importAttachments (markDownContent, filepath, storageKey, noteKey) {
return new Promise((resolve, reject) => {
const nameRegex = /(!\[.*?]\()(.+?\..+?)(\))/g
let attachPath = nameRegex.exec(markDownContent)
const promiseArray = []
const attachmentPaths = []
const groupIndex = 2
while (attachPath) {
let attachmentPath = attachPath[groupIndex]
attachmentPaths.push(attachmentPath)
attachmentPath = path.isAbsolute(attachmentPath) ? attachmentPath : path.join(path.dirname(filepath), attachmentPath)
promiseArray.push(this.copyAttachment(attachmentPath, storageKey, noteKey))
attachPath = nameRegex.exec(markDownContent)
}
let numResolvedPromises = 0
if (promiseArray.length === 0) {
resolve(markDownContent)
}
for (let j = 0; j < promiseArray.length; j++) {
promiseArray[j]
.then((fileName) => {
const newPath = path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, fileName)
markDownContent = markDownContent.replace(attachmentPaths[j], newPath)
})
.catch((e) => {
console.error('File does not exist in path: ' + attachmentPaths[j])
})
.finally(() => {
numResolvedPromises++
if (numResolvedPromises === promiseArray.length) {
resolve(markDownContent)
}
})
}
})
}
/**
* @description Moves the attachments of the current note to the new location.
* Returns a modified version of the given content so that the links to the attachments point to the new note key.
@@ -656,6 +722,7 @@ module.exports = {
handlePasteNativeImage,
getAttachmentsInMarkdownContent,
getAbsolutePathsOfAttachmentsInContent,
importAttachments,
removeStorageAndNoteReferences,
deleteAttachmentFolder,
deleteAttachmentsNotPresentInNote,

View File

@@ -43,19 +43,18 @@ function exportFolder (storageKey, folderKey, fileType, exportDir) {
.then(function exportNotes (data) {
const { storage, notes } = data
notes
return Promise.all(notes
.filter(note => note.folder === folderKey && note.isTrashed === false && note.type === 'MARKDOWN_NOTE')
.forEach(note => {
.map(note => {
const notePath = path.join(exportDir, `${filenamify(note.title, {replacement: '_'})}.${fileType}`)
exportNote(note.key, storage.path, note.content, notePath, null)
return exportNote(note.key, storage.path, note.content, notePath, null)
})
return {
).then(() => ({
storage,
folderKey,
fileType,
exportDir
}
}))
})
}

View File

@@ -43,14 +43,17 @@ function exportNote (nodeKey, storageKey, noteContent, targetPath, outputFormatt
)
if (outputFormatter) {
exportedData = outputFormatter(exportedData, exportTasks)
exportedData = outputFormatter(exportedData, exportTasks, path.dirname(targetPath))
} else {
exportedData = Promise.resolve(exportedData)
}
const tasks = prepareTasks(exportTasks, storagePath, path.dirname(targetPath))
return Promise.all(tasks.map((task) => copyFile(task.src, task.dst)))
.then(() => {
return saveToFile(exportedData, targetPath)
.then(() => exportedData)
.then(data => {
return saveToFile(data, targetPath)
}).catch((err) => {
rollbackExport(tasks)
throw err

View File

@@ -1,7 +1,7 @@
import React from 'react'
import { Provider } from 'react-redux'
import ReactDOM from 'react-dom'
import store from '../store'
import { store } from '../store'
class ModalBase extends React.Component {
constructor (props) {