|
|
|
@@ -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,12 @@ export default class CodeEditor extends React.Component {
|
|
|
|
|
this.scrollToLineHandeler = this.scrollToLine.bind(this)
|
|
|
|
|
|
|
|
|
|
this.formatTable = () => this.handleFormatTable()
|
|
|
|
|
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()
|
|
|
|
@@ -232,6 +241,7 @@ 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)
|
|
|
|
|
this.editor.on('contextmenu', this.contextMenuHandler)
|
|
|
|
|
eventEmitter.on('top:search', this.searchHandler)
|
|
|
|
|
|
|
|
|
|
eventEmitter.emit('code:init')
|
|
|
|
@@ -248,6 +258,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 +409,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 +481,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 +504,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 +745,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 +774,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 +785,6 @@ CodeEditor.defaultProps = {
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
fontFamily: 'Monaco, Consolas',
|
|
|
|
|
indentSize: 4,
|
|
|
|
|
indentType: 'space'
|
|
|
|
|
indentType: 'space',
|
|
|
|
|
spellCheck: false
|
|
|
|
|
}
|
|
|
|
|