1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-16 03:06:27 +00:00

Merge branch 'master' into export-yfm

This commit is contained in:
Baptiste Augrain
2018-12-13 14:35:25 +01:00
66 changed files with 220175 additions and 179 deletions

View File

@@ -11,9 +11,12 @@ import eventEmitter from 'browser/main/lib/eventEmitter'
import iconv from 'iconv-lite'
import crypto from 'crypto'
import consts from 'browser/lib/consts'
import styles from '../components/CodeEditor.styl'
import fs from 'fs'
const { ipcRenderer } = require('electron')
const { ipcRenderer, remote } = require('electron')
import normalizeEditorFontFamily from 'browser/lib/normalizeEditorFontFamily'
const spellcheck = require('browser/lib/spellcheck')
const buildEditorContextMenu = require('browser/lib/contextMenuBuilder')
import TurndownService from 'turndown'
import { gfm } from 'turndown-plugin-gfm'
@@ -30,7 +33,7 @@ export default class CodeEditor extends React.Component {
leading: false,
trailing: true
})
this.changeHandler = e => this.handleChange(e)
this.changeHandler = (editor, changeObject) => this.handleChange(editor, changeObject)
this.focusHandler = () => {
ipcRenderer.send('editor:focused', true)
}
@@ -62,6 +65,16 @@ export default class CodeEditor extends React.Component {
this.scrollToLineHandeler = this.scrollToLine.bind(this)
this.formatTable = () => this.handleFormatTable()
if (props.switchPreview !== 'RIGHTCLICK') {
this.contextMenuHandler = function (editor, event) {
const menu = buildEditorContextMenu(editor, event)
if (menu != null) {
setTimeout(() => menu.popup(remote.getCurrentWindow()), 30)
}
}
}
this.editorActivityHandler = () => this.handleEditorActivity()
this.turndownService = new TurndownService()
@@ -128,7 +141,7 @@ export default class CodeEditor extends React.Component {
}
componentDidMount () {
const { rulers, enableRulers } = this.props
const { rulers, enableRulers, switchPreview } = this.props
const expandSnippet = this.expandSnippet.bind(this)
eventEmitter.on('line:jump', this.scrollToLineHandeler)
@@ -232,6 +245,9 @@ export default class CodeEditor extends React.Component {
this.editor.on('blur', this.blurHandler)
this.editor.on('change', this.changeHandler)
this.editor.on('paste', this.pasteHandler)
if (switchPreview !== 'RIGHTCLICK') {
this.editor.on('contextmenu', this.contextMenuHandler)
}
eventEmitter.on('top:search', this.searchHandler)
eventEmitter.emit('code:init')
@@ -248,6 +264,10 @@ export default class CodeEditor extends React.Component {
this.textEditorInterface = new TextEditorInterface(this.editor)
this.tableEditor = new TableEditor(this.textEditorInterface)
if (this.props.spellCheck) {
this.editor.addPanel(this.createSpellCheckPanel(), {position: 'bottom'})
}
eventEmitter.on('code:format-table', this.formatTable)
this.tableEditorOptions = options({
@@ -395,9 +415,11 @@ export default class CodeEditor extends React.Component {
this.editor.off('paste', this.pasteHandler)
eventEmitter.off('top:search', this.searchHandler)
this.editor.off('scroll', this.scrollHandler)
this.editor.off('contextmenu', this.contextMenuHandler)
const editorTheme = document.getElementById('editorTheme')
editorTheme.removeEventListener('load', this.loadStyleHandler)
spellcheck.setLanguage(null, spellcheck.SPELLCHECK_DISABLED)
eventEmitter.off('code:format-table', this.formatTable)
}
@@ -465,6 +487,16 @@ export default class CodeEditor extends React.Component {
needRefresh = true
}
if (prevProps.spellCheck !== this.props.spellCheck) {
if (this.props.spellCheck === false) {
spellcheck.setLanguage(this.editor, spellcheck.SPELLCHECK_DISABLED)
let elem = document.getElementById('editor-bottom-panel')
elem.parentNode.removeChild(elem)
} else {
this.editor.addPanel(this.createSpellCheckPanel(), {position: 'bottom'})
}
}
if (needRefresh) {
this.editor.refresh()
}
@@ -478,10 +510,11 @@ export default class CodeEditor extends React.Component {
CodeMirror.autoLoadMode(this.editor, syntax.mode)
}
handleChange (e) {
this.value = this.editor.getValue()
handleChange (editor, changeObject) {
spellcheck.handleChange(editor, changeObject)
this.value = editor.getValue()
if (this.props.onChange) {
this.props.onChange(e)
this.props.onChange(editor)
}
}
@@ -718,6 +751,25 @@ export default class CodeEditor extends React.Component {
/>
)
}
createSpellCheckPanel () {
const panel = document.createElement('div')
panel.className = 'panel bottom'
panel.id = 'editor-bottom-panel'
const dropdown = document.createElement('select')
dropdown.title = 'Spellcheck'
dropdown.className = styles['spellcheck-select']
dropdown.addEventListener('change', (e) => spellcheck.setLanguage(this.editor, dropdown.value))
const options = spellcheck.getAvailableDictionaries()
for (const op of options) {
const option = document.createElement('option')
option.value = op.value
option.innerHTML = op.label
dropdown.appendChild(option)
}
panel.appendChild(dropdown)
return panel
}
}
CodeEditor.propTypes = {
@@ -728,7 +780,8 @@ CodeEditor.propTypes = {
className: PropTypes.string,
onBlur: PropTypes.func,
onChange: PropTypes.func,
readOnly: PropTypes.bool
readOnly: PropTypes.bool,
spellCheck: PropTypes.bool
}
CodeEditor.defaultProps = {
@@ -738,5 +791,6 @@ CodeEditor.defaultProps = {
fontSize: 14,
fontFamily: 'Monaco, Consolas',
indentSize: 4,
indentType: 'space'
indentType: 'space',
spellCheck: false
}

View File

@@ -0,0 +1,6 @@
.codeEditor-typo
text-decoration underline wavy red
.spellcheck-select
border: none
text-decoration underline wavy red

View File

@@ -149,6 +149,8 @@ class MarkdownEditor extends React.Component {
const idMatch = /checkbox-([0-9]+)/
const checkedMatch = /^\s*[\+\-\*] \[x\]/i
const uncheckedMatch = /^\s*[\+\-\*] \[ \]/
const checkReplace = /\[x\]/i
const uncheckReplace = /\[ \]/
if (idMatch.test(e.target.getAttribute('id'))) {
const lineIndex = parseInt(e.target.getAttribute('id').match(idMatch)[1], 10) - 1
const lines = this.refs.code.value
@@ -157,10 +159,10 @@ class MarkdownEditor extends React.Component {
const targetLine = lines[lineIndex]
if (targetLine.match(checkedMatch)) {
lines[lineIndex] = targetLine.replace(checkedMatch, '- [ ]')
lines[lineIndex] = targetLine.replace(checkReplace, '[ ]')
}
if (targetLine.match(uncheckedMatch)) {
lines[lineIndex] = targetLine.replace(uncheckedMatch, '- [x]')
lines[lineIndex] = targetLine.replace(uncheckReplace, '[x]')
}
this.refs.code.setValue(lines.join('\n'))
}
@@ -275,6 +277,8 @@ class MarkdownEditor extends React.Component {
enableTableEditor={config.editor.enableTableEditor}
onChange={(e) => this.handleChange(e)}
onBlur={(e) => this.handleBlur(e)}
spellCheck={config.editor.spellcheck}
switchPreview={config.editor.switchPreview}
/>
<MarkdownPreview styleName={this.state.status === 'PREVIEW'
? 'preview'

View File

@@ -28,6 +28,7 @@ import uri2path from 'file-uri-to-path'
import { remote, shell } from 'electron'
import attachmentManagement from '../main/lib/dataApi/attachmentManagement'
import filenamify from 'filenamify'
import ConfigManager from '../main/lib/ConfigManager'
const dialog = remote.dialog
@@ -125,6 +126,10 @@ export default class MarkdownPreview extends React.Component {
}
handleMouseDown (e) {
const config = ConfigManager.get()
if (config.editor.switchPreview === 'RIGHTCLICK' && e.buttons === 2 && config.editor.type === 'SPLIT') {
eventEmitter.emit('topbar:togglemodebutton', 'CODE')
}
if (e.target != null) {
switch (e.target.tagName) {
case 'A':

View File

@@ -80,6 +80,8 @@ class MarkdownSplitEditor extends React.Component {
const idMatch = /checkbox-([0-9]+)/
const checkedMatch = /^\s*[\+\-\*] \[x\]/i
const uncheckedMatch = /^\s*[\+\-\*] \[ \]/
const checkReplace = /\[x\]/i
const uncheckReplace = /\[ \]/
if (idMatch.test(e.target.getAttribute('id'))) {
const lineIndex = parseInt(e.target.getAttribute('id').match(idMatch)[1], 10) - 1
const lines = this.refs.code.value
@@ -88,10 +90,10 @@ class MarkdownSplitEditor extends React.Component {
const targetLine = lines[lineIndex]
if (targetLine.match(checkedMatch)) {
lines[lineIndex] = targetLine.replace(checkedMatch, '- [ ]')
lines[lineIndex] = targetLine.replace(checkReplace, '[ ]')
}
if (targetLine.match(uncheckedMatch)) {
lines[lineIndex] = targetLine.replace(uncheckedMatch, '- [x]')
lines[lineIndex] = targetLine.replace(uncheckReplace, '[x]')
}
this.refs.code.setValue(lines.join('\n'))
}
@@ -169,6 +171,8 @@ class MarkdownSplitEditor extends React.Component {
noteKey={noteKey}
onChange={this.handleOnChange.bind(this)}
onScroll={this.handleScroll.bind(this)}
spellCheck={config.editor.spellcheck}
switchPreview={config.editor.switchPreview}
/>
<div styleName='slider' style={{left: this.state.codeEditorWidthInPercent + '%'}} onMouseDown={e => this.handleMouseDown(e)} >
<div styleName='slider-hitbox' />

View File

@@ -25,7 +25,7 @@ function render (element, content, theme) {
if (height && height.value !== 'undefined') {
element.style.height = height.value + 'vh'
}
let isDarkTheme = theme === 'dark' || theme === 'solarized-dark' || theme === 'monokai' || theme === 'dracula'
const isDarkTheme = theme === 'dark' || theme === 'solarized-dark' || theme === 'monokai' || theme === 'dracula'
mermaidAPI.initialize({
theme: isDarkTheme ? 'dark' : 'default',
themeCSS: isDarkTheme ? darkThemeStyling : '',