mirror of
https://github.com/marktext/marktext.git
synced 2025-05-04 00:52:19 +08:00
feat: source code mode
This commit is contained in:
parent
2ff0137b97
commit
a77cf47ea0
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
- Add Typewriter Mode, The current line will always in the center of the document. If you change the current line, it will be auto scroll to the new line.
|
- Add Typewriter Mode, The current line will always in the center of the document. If you change the current line, it will be auto scroll to the new line.
|
||||||
|
|
||||||
|
- Add Focus Mode, the current paragraph's will be focused.
|
||||||
|
|
||||||
**Optimization**
|
**Optimization**
|
||||||
|
|
||||||
- Optimize the display of path name and file name in title bar.
|
- Optimize the display of path name and file name in title bar.
|
||||||
|
@ -1,15 +1 @@
|
|||||||
wow
|
wowowo wowowow
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
owoww
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
owow
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
import 'codemirror/addon/edit/closebrackets'
|
import 'codemirror/addon/edit/closebrackets'
|
||||||
import 'codemirror/addon/edit/closetag'
|
import 'codemirror/addon/edit/closetag'
|
||||||
|
import 'codemirror/addon/selection/active-line'
|
||||||
import 'codemirror/mode/meta'
|
import 'codemirror/mode/meta'
|
||||||
import codeMirror from 'codemirror/lib/codemirror'
|
import codeMirror from 'codemirror/lib/codemirror'
|
||||||
|
|
||||||
import loadmode from './loadmode'
|
import loadmode from './loadmode'
|
||||||
|
import overlayMode from './overlayMode'
|
||||||
import languages from './modes'
|
import languages from './modes'
|
||||||
import 'codemirror/lib/codemirror.css'
|
import 'codemirror/lib/codemirror.css'
|
||||||
import './index.css'
|
import './index.css'
|
||||||
|
|
||||||
loadmode(codeMirror)
|
loadmode(codeMirror)
|
||||||
|
overlayMode(codeMirror)
|
||||||
window.CodeMirror = codeMirror
|
window.CodeMirror = codeMirror
|
||||||
|
|
||||||
const modes = codeMirror.modeInfo
|
const modes = codeMirror.modeInfo
|
||||||
|
98
src/editor/codeMirror/overlayMode.js
Normal file
98
src/editor/codeMirror/overlayMode.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||||
|
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||||
|
|
||||||
|
// Utility function that allows modes to be combined. The mode given
|
||||||
|
// as the base argument takes care of most of the normal mode
|
||||||
|
// functionality, but a second (typically simple) mode is used, which
|
||||||
|
// can override the style of text. Both modes get to parse all of the
|
||||||
|
// text, but when both assign a non-null style to a piece of code, the
|
||||||
|
// overlay wins, unless the combine argument was true and not overridden,
|
||||||
|
// or state.overlay.combineTokens was true, in which case the styles are
|
||||||
|
// combined.
|
||||||
|
|
||||||
|
const overlayMode = CodeMirror => {
|
||||||
|
CodeMirror.overlayMode = function (base, overlay, combine) {
|
||||||
|
return {
|
||||||
|
startState () {
|
||||||
|
return {
|
||||||
|
base: CodeMirror.startState(base),
|
||||||
|
overlay: CodeMirror.startState(overlay),
|
||||||
|
basePos: 0,
|
||||||
|
baseCur: null,
|
||||||
|
overlayPos: 0,
|
||||||
|
overlayCur: null,
|
||||||
|
streamSeen: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
copyState (state) {
|
||||||
|
return {
|
||||||
|
base: CodeMirror.copyState(base, state.base),
|
||||||
|
overlay: CodeMirror.copyState(overlay, state.overlay),
|
||||||
|
basePos: state.basePos,
|
||||||
|
baseCur: null,
|
||||||
|
overlayPos: state.overlayPos,
|
||||||
|
overlayCur: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
token (stream, state) {
|
||||||
|
if (stream !== state.streamSeen ||
|
||||||
|
Math.min(state.basePos, state.overlayPos) < stream.start) {
|
||||||
|
state.streamSeen = stream
|
||||||
|
state.basePos = state.overlayPos = stream.start
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream.start === state.basePos) {
|
||||||
|
state.baseCur = base.token(stream, state.base)
|
||||||
|
state.basePos = stream.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream.start === state.overlayPos) {
|
||||||
|
stream.pos = stream.start
|
||||||
|
state.overlayCur = overlay.token(stream, state.overlay)
|
||||||
|
state.overlayPos = stream.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.pos = Math.min(state.basePos, state.overlayPos)
|
||||||
|
|
||||||
|
// state.overlay.combineTokens always takes precedence over combine,
|
||||||
|
// unless set to null
|
||||||
|
if (state.overlayCur === null) {
|
||||||
|
return state.baseCur
|
||||||
|
} else if (
|
||||||
|
(state.baseCur !== null &&
|
||||||
|
state.overlay.combineTokens) ||
|
||||||
|
(combine && state.overlay.combineTokens === null)
|
||||||
|
) {
|
||||||
|
return state.baseCur + ' ' + state.overlayCur
|
||||||
|
} else return state.overlayCur
|
||||||
|
},
|
||||||
|
|
||||||
|
indent: base.indent && function (state, textAfter) {
|
||||||
|
return base.indent(state.base, textAfter)
|
||||||
|
},
|
||||||
|
|
||||||
|
electricChars: base.electricChars,
|
||||||
|
|
||||||
|
innerMode (state) {
|
||||||
|
return {
|
||||||
|
state: state.base,
|
||||||
|
mode: base
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
blankLine (state) {
|
||||||
|
var baseToken, overlayToken
|
||||||
|
if (base.blankLine) baseToken = base.blankLine(state.base)
|
||||||
|
if (overlay.blankLine) overlayToken = overlay.blankLine(state.overlay)
|
||||||
|
|
||||||
|
return overlayToken == null
|
||||||
|
? baseToken
|
||||||
|
: (combine && baseToken != null ? baseToken + ' ' + overlayToken : overlayToken)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default overlayMode
|
@ -135,8 +135,8 @@ li.ag-task-list-item > input[type=checkbox] {
|
|||||||
height: inherit;
|
height: inherit;
|
||||||
margin: 4px 0px 0px;
|
margin: 4px 0px 0px;
|
||||||
top: 1px;
|
top: 1px;
|
||||||
width: 19px;
|
width: 18px;
|
||||||
height: 19px;
|
height: 18px;
|
||||||
left: -20px;
|
left: -20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,8 +146,8 @@ li.ag-task-list-item > input.ag-checkbox-checked ~ p {
|
|||||||
|
|
||||||
li.ag-task-list-item > input[type=checkbox]::before {
|
li.ag-task-list-item > input[type=checkbox]::before {
|
||||||
content: '';
|
content: '';
|
||||||
width: 16px;
|
width: 14px;
|
||||||
height: 16px;
|
height: 14px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border: 2px solid #606266;
|
border: 2px solid #606266;
|
||||||
@ -174,7 +174,7 @@ li.ag-task-list-item > input.ag-checkbox-checked::after {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
top: 4px;
|
top: 4px;
|
||||||
left: 4px;
|
left: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
li p .ag-hide:first-child {
|
li p .ag-hide:first-child {
|
||||||
|
@ -390,10 +390,12 @@ class Aganippe {
|
|||||||
return this.contentState.wordCount()
|
return this.contentState.wordCount()
|
||||||
}
|
}
|
||||||
|
|
||||||
setMarkdown (text) {
|
setMarkdown (markdown, cursor) {
|
||||||
// if text is blank, dont need to import markdown
|
// if markdown is blank, dont need to import markdown
|
||||||
if (!text.trim()) return
|
if (!markdown.trim()) return
|
||||||
this.contentState.importMarkdown(text)
|
this.contentState.importMarkdown(markdown)
|
||||||
|
this.contentState.importCursor(cursor)
|
||||||
|
this.contentState.render()
|
||||||
this.dispatchChange()
|
this.dispatchChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,12 +226,10 @@ const importRegister = ContentState => {
|
|||||||
return this.getStateFragment(markdown)
|
return this.getStateFragment(markdown)
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentState.prototype.importMarkdown = function (markdown) {
|
ContentState.prototype.importCursor = function (cursor) {
|
||||||
// empty the blocks and codeBlocks
|
|
||||||
this.keys = new Set()
|
|
||||||
this.codeBlocks = new Map()
|
|
||||||
this.blocks = this.getStateFragment(markdown)
|
|
||||||
// set cursor
|
// set cursor
|
||||||
|
if (cursor) {
|
||||||
|
// TODO for codeMirror cursor to aganippe cursor
|
||||||
const lastBlock = this.getLastBlock()
|
const lastBlock = this.getLastBlock()
|
||||||
const key = lastBlock.key
|
const key = lastBlock.key
|
||||||
const offset = lastBlock.text.length
|
const offset = lastBlock.text.length
|
||||||
@ -239,8 +237,22 @@ const importRegister = ContentState => {
|
|||||||
start: { key, offset },
|
start: { key, offset },
|
||||||
end: { key, offset }
|
end: { key, offset }
|
||||||
}
|
}
|
||||||
// re-render
|
} else {
|
||||||
this.render()
|
const lastBlock = this.getLastBlock()
|
||||||
|
const key = lastBlock.key
|
||||||
|
const offset = lastBlock.text.length
|
||||||
|
this.cursor = {
|
||||||
|
start: { key, offset },
|
||||||
|
end: { key, offset }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentState.prototype.importMarkdown = function (markdown) {
|
||||||
|
// empty the blocks and codeBlocks
|
||||||
|
this.keys = new Set()
|
||||||
|
this.codeBlocks = new Map()
|
||||||
|
this.blocks = this.getStateFragment(markdown)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,15 @@ const HASH = {
|
|||||||
export const view = (win, item, type) => {
|
export const view = (win, item, type) => {
|
||||||
const { checked } = item
|
const { checked } = item
|
||||||
win.webContents.send('AGANI::view', { type, checked })
|
win.webContents.send('AGANI::view', { type, checked })
|
||||||
|
|
||||||
|
if (type === 'sourceCode') {
|
||||||
|
const viewMenuItem = getMenuItem('View')
|
||||||
|
viewMenuItem.submenu.items.forEach(item => {
|
||||||
|
if (/typewriter|focus/.test(HASH[item.label])) {
|
||||||
|
item.enabled = !checked
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.on('AGANI::ask-for-mode', e => {
|
ipcMain.on('AGANI::ask-for-mode', e => {
|
||||||
|
@ -9,8 +9,18 @@
|
|||||||
:typewriter="typewriter"
|
:typewriter="typewriter"
|
||||||
:focus="focus"
|
:focus="focus"
|
||||||
:source-code="sourceCode"
|
:source-code="sourceCode"
|
||||||
|
:markdown="markdown"
|
||||||
|
:cursor="cursor"
|
||||||
|
v-if="!sourceCode"
|
||||||
></editor>
|
></editor>
|
||||||
<search></search>
|
<source-code
|
||||||
|
v-else
|
||||||
|
:markdown="markdown"
|
||||||
|
:cursor="cursor"
|
||||||
|
></source-code>
|
||||||
|
<search
|
||||||
|
v-if="!sourceCode"
|
||||||
|
></search>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -18,6 +28,7 @@
|
|||||||
import Editor from '@/components/editor'
|
import Editor from '@/components/editor'
|
||||||
import TitleBar from '@/components/titleBar'
|
import TitleBar from '@/components/titleBar'
|
||||||
import Search from '@/components/search'
|
import Search from '@/components/search'
|
||||||
|
import SourceCode from '@/components/sourceCode'
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -25,13 +36,14 @@
|
|||||||
components: {
|
components: {
|
||||||
Editor,
|
Editor,
|
||||||
TitleBar,
|
TitleBar,
|
||||||
Search
|
Search,
|
||||||
|
SourceCode
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {}
|
return {}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['pathname', 'windowActive', 'wordCount', 'typewriter', 'focus', 'sourceCode'])
|
...mapState(['pathname', 'windowActive', 'wordCount', 'typewriter', 'focus', 'sourceCode', 'markdown', 'cursor'])
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
const { dispatch } = this.$store
|
const { dispatch } = this.$store
|
||||||
@ -56,4 +68,10 @@
|
|||||||
.editor-container {
|
.editor-container {
|
||||||
padding-top: 22px;
|
padding-top: 22px;
|
||||||
}
|
}
|
||||||
|
.editor-container .hide {
|
||||||
|
z-index: -1;
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
left: -10000px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="editor-wrapper"
|
class="editor-wrapper"
|
||||||
:class="{ 'typewriter': typewriter, 'focus': focus, 'source-code': sourceCode }"
|
:class="{ 'typewriter': typewriter, 'focus': focus, 'source': sourceCode }"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
ref="editor"
|
ref="editor"
|
||||||
@ -81,7 +81,9 @@
|
|||||||
sourceCode: {
|
sourceCode: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: true
|
required: true
|
||||||
}
|
},
|
||||||
|
markdown: String,
|
||||||
|
cursor: Object
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
@ -114,8 +116,14 @@
|
|||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const ele = this.$refs.editor
|
const ele = this.$refs.editor
|
||||||
this.editor = new Aganippe(ele)
|
this.editor = new Aganippe(ele)
|
||||||
|
const { container } = this.editor
|
||||||
|
const { markdown } = this
|
||||||
|
|
||||||
bus.$on('file-loaded', this.handleFileLoaded)
|
if (markdown.trim()) {
|
||||||
|
this.setMarkdownToEditor(markdown)
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.$on('file-loaded', this.setMarkdownToEditor)
|
||||||
bus.$on('undo', () => this.editor.undo())
|
bus.$on('undo', () => this.editor.undo())
|
||||||
bus.$on('redo', () => this.editor.redo())
|
bus.$on('redo', () => this.editor.redo())
|
||||||
bus.$on('export', this.handleExport)
|
bus.$on('export', this.handleExport)
|
||||||
@ -125,8 +133,6 @@
|
|||||||
bus.$on('replaceValue', this.handReplace)
|
bus.$on('replaceValue', this.handReplace)
|
||||||
bus.$on('find', this.handleFind)
|
bus.$on('find', this.handleFind)
|
||||||
|
|
||||||
const { container } = this.editor
|
|
||||||
|
|
||||||
this.editor.on('change', (markdown, wordCount) => {
|
this.editor.on('change', (markdown, wordCount) => {
|
||||||
this.$store.dispatch('SAVE_FILE', { markdown, wordCount })
|
this.$store.dispatch('SAVE_FILE', { markdown, wordCount })
|
||||||
})
|
})
|
||||||
@ -210,16 +216,23 @@
|
|||||||
this.dialogTableVisible = false
|
this.dialogTableVisible = false
|
||||||
this.editor && this.editor.createTable(this.tableChecker)
|
this.editor && this.editor.createTable(this.tableChecker)
|
||||||
},
|
},
|
||||||
handleFileLoaded (file) {
|
setMarkdownToEditor (markdown) {
|
||||||
this.editor && this.editor.setMarkdown(file)
|
const { cursor } = this
|
||||||
|
this.editor && this.editor.setMarkdown(markdown, cursor)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
bus.$off('file-loaded', this.handleFileLoaded)
|
bus.$off('file-loaded', this.setMarkdownToEditor)
|
||||||
bus.$off('export-styled-html', this.handleExport('styledHtml'))
|
bus.$off('undo', () => this.editor.undo())
|
||||||
|
bus.$off('redo', () => this.editor.redo())
|
||||||
|
bus.$off('export', this.handleExport)
|
||||||
bus.$off('paragraph', this.handleEditParagraph)
|
bus.$off('paragraph', this.handleEditParagraph)
|
||||||
|
bus.$off('format', this.handleInlineFormat)
|
||||||
bus.$off('searchValue', this.handleSearch)
|
bus.$off('searchValue', this.handleSearch)
|
||||||
|
bus.$off('replaceValue', this.handReplace)
|
||||||
bus.$off('find', this.handleFind)
|
bus.$off('find', this.handleFind)
|
||||||
|
|
||||||
|
// this.editor.destroy()
|
||||||
this.editor = null
|
this.editor = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,6 +244,12 @@
|
|||||||
.editor-wrapper {
|
.editor-wrapper {
|
||||||
height: calc(100vh - 22px);
|
height: calc(100vh - 22px);
|
||||||
}
|
}
|
||||||
|
.editor-wrapper.source {
|
||||||
|
position: absolute;
|
||||||
|
z-index: -1;
|
||||||
|
left: -10000px;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
.editor-component {
|
.editor-component {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
@ -136,31 +136,39 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
bus.$on('find', () => {
|
bus.$on('find', this.listenFind)
|
||||||
|
bus.$on('replace', this.listenReplace)
|
||||||
|
bus.$on('findNext', this.listenFindNext)
|
||||||
|
bus.$on('findPrev', this.listenFindPrev)
|
||||||
|
document.addEventListener('click', this.docClick)
|
||||||
|
document.addEventListener('keyup', this.docKeyup)
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
bus.$off('find', this.listenFind)
|
||||||
|
bus.$off('replace', this.listenReplace)
|
||||||
|
bus.$off('findNext', this.listenFindNext)
|
||||||
|
bus.$off('findPrev', this.listenFindPrev)
|
||||||
|
document.removeEventListener('click', this.docClick)
|
||||||
|
document.removeEventListener('keyup', this.docKeyup)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
listenFind () {
|
||||||
this.showSearch = true
|
this.showSearch = true
|
||||||
this.type = 'search'
|
this.type = 'search'
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.$refs.search.focus()
|
this.$refs.search.focus()
|
||||||
})
|
})
|
||||||
})
|
},
|
||||||
bus.$on('replace', () => {
|
listenReplace () {
|
||||||
this.showSearch = true
|
this.showSearch = true
|
||||||
this.type = 'replace'
|
this.type = 'replace'
|
||||||
})
|
},
|
||||||
bus.$on('findNext', () => {
|
listenFindNext () {
|
||||||
this.find('next')
|
this.find('next')
|
||||||
})
|
},
|
||||||
bus.$on('findPrev', () => {
|
listenFindPrev () {
|
||||||
this.find('prev')
|
this.find('prev')
|
||||||
})
|
|
||||||
document.addEventListener('click', this.docClick)
|
|
||||||
document.addEventListener('keyup', this.docKeyup)
|
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
|
||||||
document.removeEventListener('click', this.docClick)
|
|
||||||
document.removeEventListener('keyup', this.docKeyup)
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
docKeyup (event) {
|
docKeyup (event) {
|
||||||
if (event.key === 'Escape') {
|
if (event.key === 'Escape') {
|
||||||
this.emitSearch(true)
|
this.emitSearch(true)
|
||||||
|
86
src/renderer/components/sourceCode.vue
Normal file
86
src/renderer/components/sourceCode.vue
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<template>
|
||||||
|
<div class="source-code" ref="sourceCode">
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import codeMirror, { setMode, setCursorAtLastLine } from '../../editor/codeMirror'
|
||||||
|
import ContentState from '../../editor/contentState'
|
||||||
|
import bus from '../bus'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
markdown: String,
|
||||||
|
cursor: Object
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
contentState: null,
|
||||||
|
editor: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.contentState = new ContentState()
|
||||||
|
const container = this.$refs.sourceCode
|
||||||
|
const editor = this.editor = codeMirror(container, {
|
||||||
|
value: this.markdown || '',
|
||||||
|
lineNumbers: true,
|
||||||
|
autofocus: true,
|
||||||
|
lineWrapping: true,
|
||||||
|
styleActiveLine: true,
|
||||||
|
lineNumberFormatter (line) {
|
||||||
|
if (line % 10 === 0 || line === 1) {
|
||||||
|
return line
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
bus.$on('file-loaded', this.setMarkdown)
|
||||||
|
|
||||||
|
editor.on('cursorActivity', (cm, event) => {
|
||||||
|
const cursor = cm.getCursor()
|
||||||
|
const markdown = cm.getValue()
|
||||||
|
// get word count
|
||||||
|
this.contentState.importMarkdown(markdown, cursor)
|
||||||
|
const wordCount = this.contentState.wordCount()
|
||||||
|
this.$store.dispatch('SAVE_FILE', { markdown, cursor, wordCount })
|
||||||
|
})
|
||||||
|
|
||||||
|
setMode(editor, 'markdown')
|
||||||
|
this.setMarkdown(this.markdown || '')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
beforeDestory () {
|
||||||
|
bus.$off('file-loaded', this.setMarkdown)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setMarkdown (markdown) {
|
||||||
|
const { editor } = this
|
||||||
|
this.editor.setValue(markdown)
|
||||||
|
setCursorAtLastLine(editor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.source-code {
|
||||||
|
height: calc(100vh - 22px);
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.source-code .CodeMirror {
|
||||||
|
margin: 50px auto;
|
||||||
|
max-width: 860px;
|
||||||
|
}
|
||||||
|
.source-code .CodeMirror-gutters {
|
||||||
|
border-right: none;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.source-code .CodeMirror-activeline-background,
|
||||||
|
.source-code .CodeMirror-activeline-gutter {
|
||||||
|
background: #F2F6FC;
|
||||||
|
}
|
||||||
|
</style>
|
@ -34,6 +34,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
filename: String,
|
||||||
pathname: String,
|
pathname: String,
|
||||||
active: Boolean,
|
active: Boolean,
|
||||||
wordCount: Object
|
wordCount: Object
|
||||||
@ -42,10 +43,6 @@
|
|||||||
paths () {
|
paths () {
|
||||||
const pathnameToken = this.pathname.split('/').filter(i => i)
|
const pathnameToken = this.pathname.split('/').filter(i => i)
|
||||||
return pathnameToken.slice(0, pathnameToken.length - 1).slice(-3)
|
return pathnameToken.slice(0, pathnameToken.length - 1).slice(-3)
|
||||||
},
|
|
||||||
filename () {
|
|
||||||
const pathnameToken = this.pathname.split('/').filter(i => i)
|
|
||||||
return pathnameToken.pop()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -12,9 +12,10 @@ const state = {
|
|||||||
typewriter: false, // typewriter mode
|
typewriter: false, // typewriter mode
|
||||||
focus: false, // focus mode
|
focus: false, // focus mode
|
||||||
sourceCode: false, // source code mode
|
sourceCode: false, // source code mode
|
||||||
pathname: 'Untitled - unsaved',
|
pathname: '',
|
||||||
isSaved: true,
|
isSaved: true,
|
||||||
markdown: '',
|
markdown: '',
|
||||||
|
cursor: null,
|
||||||
windowActive: true,
|
windowActive: true,
|
||||||
wordCount: {
|
wordCount: {
|
||||||
paragraph: 0,
|
paragraph: 0,
|
||||||
@ -49,6 +50,9 @@ const mutations = {
|
|||||||
},
|
},
|
||||||
SET_WORD_COUNT (state, wordCount) {
|
SET_WORD_COUNT (state, wordCount) {
|
||||||
state.wordCount = wordCount
|
state.wordCount = wordCount
|
||||||
|
},
|
||||||
|
SET_CURSOR (state, cursor) {
|
||||||
|
state.cursor = cursor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,9 +123,10 @@ const actions = {
|
|||||||
const { filename, pathname } = state
|
const { filename, pathname } = state
|
||||||
ipcRenderer.send('AGANI::response-export', { type, content, filename, pathname })
|
ipcRenderer.send('AGANI::response-export', { type, content, filename, pathname })
|
||||||
},
|
},
|
||||||
SAVE_FILE ({ commit, state }, { markdown, wordCount }) {
|
SAVE_FILE ({ commit, state }, { markdown, wordCount, cursor }) {
|
||||||
commit('SET_MARKDOWN', markdown)
|
commit('SET_MARKDOWN', markdown)
|
||||||
commit('SET_WORD_COUNT', wordCount)
|
if (wordCount) commit('SET_WORD_COUNT', wordCount)
|
||||||
|
if (cursor) commit('SET_CURSOR', cursor)
|
||||||
const { pathname } = state
|
const { pathname } = state
|
||||||
if (pathname) {
|
if (pathname) {
|
||||||
commit('SET_STATUS', true)
|
commit('SET_STATUS', true)
|
||||||
|
Loading…
Reference in New Issue
Block a user