mirror of
https://github.com/marktext/marktext.git
synced 2025-05-02 22:10:24 +08:00
fix: source code mode tab switching (#881)
This commit is contained in:
parent
e78bc8036c
commit
d12f4fab19
3
.github/CHANGELOG.md
vendored
3
.github/CHANGELOG.md
vendored
@ -41,6 +41,7 @@ foo<section>bar</section>zar
|
|||||||
- Add new themes: Ulysses Light, Graphite Light, Material Dark and One Dark.
|
- Add new themes: Ulysses Light, Graphite Light, Material Dark and One Dark.
|
||||||
- Watch file changed in tabs and show a notice(autoSave is `false`) or update the file(autoSave is `true`)
|
- Watch file changed in tabs and show a notice(autoSave is `false`) or update the file(autoSave is `true`)
|
||||||
- Support input inline Ruby charactors as raw html (#257)
|
- Support input inline Ruby charactors as raw html (#257)
|
||||||
|
- Added unsaved tab indicator
|
||||||
|
|
||||||
**:butterfly:Optimization**
|
**:butterfly:Optimization**
|
||||||
|
|
||||||
@ -109,6 +110,8 @@ foo<section>bar</section>zar
|
|||||||
- Fixed bug when combine pre list and next list into one when inline update #707
|
- Fixed bug when combine pre list and next list into one when inline update #707
|
||||||
- Fix renderer error when selection in sidebar (#625)
|
- Fix renderer error when selection in sidebar (#625)
|
||||||
- Fixed list parse error [more info](https://github.com/marktext/marktext/issues/831#issuecomment-477719256)
|
- Fixed list parse error [more info](https://github.com/marktext/marktext/issues/831#issuecomment-477719256)
|
||||||
|
- Fixed source code mode tab switching
|
||||||
|
- Fixed source code mode to preview switching
|
||||||
|
|
||||||
### 0.13.65
|
### 0.13.65
|
||||||
|
|
||||||
|
@ -218,6 +218,7 @@ class AppWindow {
|
|||||||
newTab (win, filePath) {
|
newTab (win, filePath) {
|
||||||
this.watcher.watch(win, filePath, 'file')
|
this.watcher.watch(win, filePath, 'file')
|
||||||
loadMarkdownFile(filePath).then(rawDocument => {
|
loadMarkdownFile(filePath).then(rawDocument => {
|
||||||
|
appMenu.addRecentlyUsedDocument(filePath)
|
||||||
newTab(win, rawDocument)
|
newTab(win, rawDocument)
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
// TODO: Handle error --> create a end-user error handler.
|
// TODO: Handle error --> create a end-user error handler.
|
||||||
|
@ -28,7 +28,7 @@ export const validEmoji = text => {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export const checkEditEmoji = node => {
|
export const checkEditEmoji = node => {
|
||||||
if (node.classList.contains(CLASS_OR_ID['AG_EMOJI_MARKED_TEXT'])) {
|
if (node && node.classList.contains(CLASS_OR_ID['AG_EMOJI_MARKED_TEXT'])) {
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -59,6 +59,10 @@
|
|||||||
background: #4d78cc !important;
|
background: #4d78cc !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.drop-container.active {
|
||||||
|
border: 1px dashed #4d78cc !important;
|
||||||
|
}
|
||||||
|
|
||||||
.title-bar .frameless-titlebar-button > div > svg {
|
.title-bar .frameless-titlebar-button > div > svg {
|
||||||
fill: #ffffff;
|
fill: #ffffff;
|
||||||
}
|
}
|
||||||
@ -84,6 +88,8 @@
|
|||||||
.side-bar-toc .no-data svg {
|
.side-bar-toc .no-data svg {
|
||||||
fill: #4d78cc !important;
|
fill: #4d78cc !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.recent-files-projects a,
|
||||||
.open-project a {
|
.open-project a {
|
||||||
color: #9da5b4 !important;
|
color: #9da5b4 !important;
|
||||||
border: 1px solid #181a1f !important;
|
border: 1px solid #181a1f !important;
|
||||||
@ -91,6 +97,11 @@
|
|||||||
background-image: linear-gradient(#3a3f4b, #353b45) !important;
|
background-image: linear-gradient(#3a3f4b, #353b45) !important;
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
}
|
}
|
||||||
|
.recent-files-projects a:hover,
|
||||||
|
.open-project a:hover {
|
||||||
|
color: #d7dae0 !important;
|
||||||
|
background-image: linear-gradient(#3e4451, #3a3f4b) !important;
|
||||||
|
}
|
||||||
|
|
||||||
.editor-tabs {
|
.editor-tabs {
|
||||||
border-bottom: 1px solid #181a1f;
|
border-bottom: 1px solid #181a1f;
|
||||||
@ -111,6 +122,9 @@
|
|||||||
height: auto !important;
|
height: auto !important;
|
||||||
background: #4d78cc !important;
|
background: #4d78cc !important;
|
||||||
}
|
}
|
||||||
|
.tabs-container svg.close-icon #unsaved-circle-icon {
|
||||||
|
fill: #4d78cc;
|
||||||
|
}
|
||||||
|
|
||||||
:not(pre) > code[class*="language-"],
|
:not(pre) > code[class*="language-"],
|
||||||
pre.ag-paragraph {
|
pre.ag-paragraph {
|
||||||
|
@ -261,7 +261,8 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
this.editor.on('change', changes => {
|
this.editor.on('change', changes => {
|
||||||
this.$store.dispatch('LISTEN_FOR_CONTENT_CHANGE', changes)
|
// WORKAROUND: "id: 'muya'"
|
||||||
|
this.$store.dispatch('LISTEN_FOR_CONTENT_CHANGE', Object.assign(changes, { id: 'muya' }))
|
||||||
})
|
})
|
||||||
|
|
||||||
this.editor.on('format-click', ({ event, formatType, data }) => {
|
this.editor.on('format-click', ({ event, formatType, data }) => {
|
||||||
@ -445,7 +446,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
// listen for `open-single-file` event, it will call this method only when open a new file.
|
// listen for `open-single-file` event, it will call this method only when open a new file.
|
||||||
setMarkdownToEditor (markdown) {
|
setMarkdownToEditor ({id, markdown}) {
|
||||||
const { editor } = this
|
const { editor } = this
|
||||||
if (editor) {
|
if (editor) {
|
||||||
editor.clearHistory()
|
editor.clearHistory()
|
||||||
@ -455,7 +456,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
// listen for markdown change form source mode or change tabs etc
|
// listen for markdown change form source mode or change tabs etc
|
||||||
handleMarkdownChange ({ markdown, cursor, renderCursor, history }) {
|
handleMarkdownChange ({ id, markdown, cursor, renderCursor, history }) {
|
||||||
const { editor } = this
|
const { editor } = this
|
||||||
if (editor) {
|
if (editor) {
|
||||||
if (history) {
|
if (history) {
|
||||||
@ -488,12 +489,15 @@
|
|||||||
bus.$off('undo', this.handleUndo)
|
bus.$off('undo', this.handleUndo)
|
||||||
bus.$off('redo', this.handleRedo)
|
bus.$off('redo', this.handleRedo)
|
||||||
bus.$off('export', this.handleExport)
|
bus.$off('export', this.handleExport)
|
||||||
|
bus.$off('print-service-clearup', this.handlePrintServiceClearup)
|
||||||
bus.$off('paragraph', this.handleEditParagraph)
|
bus.$off('paragraph', this.handleEditParagraph)
|
||||||
bus.$off('format', this.handleInlineFormat)
|
bus.$off('format', this.handleInlineFormat)
|
||||||
bus.$off('searchValue', this.handleSearch)
|
bus.$off('searchValue', this.handleSearch)
|
||||||
bus.$off('replaceValue', this.handReplace)
|
bus.$off('replaceValue', this.handReplace)
|
||||||
bus.$off('find', this.handleFind)
|
bus.$off('find', this.handleFind)
|
||||||
bus.$off('dotu-select', this.handleSelect)
|
bus.$off('insert-image', this.handleSelect)
|
||||||
|
bus.$off('image-uploaded', this.handleUploadedImage)
|
||||||
|
bus.$off('file-changed', this.handleMarkdownChange)
|
||||||
bus.$off('editor-blur', this.blurEditor)
|
bus.$off('editor-blur', this.blurEditor)
|
||||||
bus.$off('image-auto-path', this.handleImagePath)
|
bus.$off('image-auto-path', this.handleImagePath)
|
||||||
bus.$off('copyAsMarkdown', this.handleCopyPaste)
|
bus.$off('copyAsMarkdown', this.handleCopyPaste)
|
||||||
|
@ -26,14 +26,18 @@
|
|||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
'theme': state => state.preferences.theme
|
'theme': state => state.preferences.theme,
|
||||||
|
'currentTab': state => state.editor.currentFile,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
contentState: null,
|
contentState: null,
|
||||||
editor: null
|
editor: null,
|
||||||
|
commitTimer: null,
|
||||||
|
viewDestroyed: false,
|
||||||
|
tabId: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -48,6 +52,8 @@
|
|||||||
|
|
||||||
created () {
|
created () {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
// TODO: Should we load markdown from the tab or mapped vue property?
|
||||||
|
const { id } = this.currentTab
|
||||||
const { markdown = '', theme, cursor, textDirection } = this
|
const { markdown = '', theme, cursor, textDirection } = this
|
||||||
const container = this.$refs.sourceCode
|
const container = this.$refs.sourceCode
|
||||||
const codeMirrorConfig = {
|
const codeMirrorConfig = {
|
||||||
@ -71,6 +77,7 @@
|
|||||||
codeMirrorConfig.theme = 'one-dark'
|
codeMirrorConfig.theme = 'one-dark'
|
||||||
}
|
}
|
||||||
const editor = this.editor = codeMirror(container, codeMirrorConfig)
|
const editor = this.editor = codeMirror(container, codeMirrorConfig)
|
||||||
|
|
||||||
bus.$on('file-loaded', this.setMarkdown)
|
bus.$on('file-loaded', this.setMarkdown)
|
||||||
bus.$on('file-changed', this.handleMarkdownChange)
|
bus.$on('file-changed', this.handleMarkdownChange)
|
||||||
bus.$on('dotu-select', this.handleSelectDoutu)
|
bus.$on('dotu-select', this.handleSelectDoutu)
|
||||||
@ -82,13 +89,22 @@
|
|||||||
} else {
|
} else {
|
||||||
setCursorAtLastLine(editor)
|
setCursorAtLastLine(editor)
|
||||||
}
|
}
|
||||||
|
this.tabId = id
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
|
// NOTE: Clear timer and manually commit changes. After mode switching and cleanup may follow
|
||||||
|
// further key inputs, so ignore all inputs.
|
||||||
|
this.viewDestroyed = true
|
||||||
|
if (this.commitTimer) clearTimeout(this.commitTimer)
|
||||||
|
|
||||||
bus.$off('file-loaded', this.setMarkdown)
|
bus.$off('file-loaded', this.setMarkdown)
|
||||||
|
bus.$off('file-changed', this.handleMarkdownChange)
|
||||||
bus.$off('dotu-select', this.handleSelectDoutu)
|
bus.$off('dotu-select', this.handleSelectDoutu)
|
||||||
const { markdown, cursor } = this
|
|
||||||
bus.$emit('file-changed', { markdown, cursor, renderCursor: true })
|
const { editor } = this
|
||||||
|
const { cursor, markdown } = this.getMarkdownAndCursor(editor)
|
||||||
|
bus.$emit('file-changed', { id: this.tabId, markdown, cursor, renderCursor: true })
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleSelectDoutu (url) {
|
handleSelectDoutu (url) {
|
||||||
@ -99,29 +115,37 @@
|
|||||||
},
|
},
|
||||||
listenChange () {
|
listenChange () {
|
||||||
const { editor } = this
|
const { editor } = this
|
||||||
let timer = null
|
editor.on('cursorActivity', cm => {
|
||||||
editor.on('cursorActivity', (cm, event) => {
|
const { cursor, markdown } = this.getMarkdownAndCursor(cm)
|
||||||
let cursor = cm.getCursor()
|
|
||||||
const markdown = cm.getValue()
|
|
||||||
const wordCount = getWordCount(markdown)
|
const wordCount = getWordCount(markdown)
|
||||||
const line = cm.getLine(cursor.line)
|
if (this.commitTimer) clearTimeout(this.commitTimer)
|
||||||
const preLine = cm.getLine(cursor.line - 1)
|
this.commitTimer = setTimeout(() => {
|
||||||
const nextLine = cm.getLine(cursor.line + 1)
|
// See "beforeDestroy" note
|
||||||
cursor = adjustCursor(cursor, preLine, line, nextLine)
|
if (!this.viewDestroyed) {
|
||||||
if (timer) clearTimeout(timer)
|
if (this.tabId) {
|
||||||
timer = setTimeout(() => {
|
this.$store.dispatch('LISTEN_FOR_CONTENT_CHANGE', { id: this.tabId, markdown, wordCount, cursor })
|
||||||
this.$store.dispatch('LISTEN_FOR_CONTENT_CHANGE', { markdown, wordCount, cursor })
|
} else {
|
||||||
|
// This may occur during tab switching but should not occur otherwise.
|
||||||
|
console.warn(`LISTEN_FOR_CONTENT_CHANGE: Cannot commit changes because not tab id was set!`)
|
||||||
|
}
|
||||||
|
}
|
||||||
}, 1000)
|
}, 1000)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
setMarkdown (markdown) {
|
// A new file was opened or new tab was added.
|
||||||
|
setMarkdown ({ id, markdown }) {
|
||||||
|
this.prepareTabSwitch()
|
||||||
|
|
||||||
const { editor } = this
|
const { editor } = this
|
||||||
editor.setValue(markdown)
|
editor.setValue(markdown)
|
||||||
// // NOTE: Don't set the cursor because we load a new file - no tab switch.
|
// NOTE: Don't set the cursor because we load a new file.
|
||||||
setCursorAtLastLine(editor)
|
setCursorAtLastLine(editor)
|
||||||
|
this.tabId = id
|
||||||
},
|
},
|
||||||
// Only listen to get changes. Do not set history or other things.
|
// Another tab was selected - only listen to get changes but don't set history or other things.
|
||||||
handleMarkdownChange({ markdown, cursor, renderCursor, history }) {
|
handleMarkdownChange ({ id, markdown, cursor, renderCursor, history }) {
|
||||||
|
this.prepareTabSwitch()
|
||||||
|
|
||||||
const { editor } = this
|
const { editor } = this
|
||||||
editor.setValue(markdown)
|
editor.setValue(markdown)
|
||||||
// Cursor is null when loading a file or creating a new tab in source code mode.
|
// Cursor is null when loading a file or creating a new tab in source code mode.
|
||||||
@ -130,6 +154,27 @@
|
|||||||
} else {
|
} else {
|
||||||
setCursorAtLastLine(editor)
|
setCursorAtLastLine(editor)
|
||||||
}
|
}
|
||||||
|
this.tabId = id
|
||||||
|
},
|
||||||
|
// Get markdown and cursor from CodeMirror.
|
||||||
|
getMarkdownAndCursor (cm) {
|
||||||
|
let cursor = cm.getCursor()
|
||||||
|
const markdown = cm.getValue()
|
||||||
|
const line = cm.getLine(cursor.line)
|
||||||
|
const preLine = cm.getLine(cursor.line - 1)
|
||||||
|
const nextLine = cm.getLine(cursor.line + 1)
|
||||||
|
cursor = adjustCursor(cursor, preLine, line, nextLine)
|
||||||
|
return { cursor, markdown }
|
||||||
|
},
|
||||||
|
// Commit changes from old tab. Problem: tab was already switched, so commit changes with old tab id.
|
||||||
|
prepareTabSwitch () {
|
||||||
|
if (this.commitTimer) clearTimeout(this.commitTimer)
|
||||||
|
if (this.tabId) {
|
||||||
|
const { editor } = this
|
||||||
|
const { cursor, markdown } = this.getMarkdownAndCursor(editor)
|
||||||
|
this.$store.dispatch('LISTEN_FOR_CONTENT_CHANGE', { id: this.tabId, markdown, cursor })
|
||||||
|
this.tabId = null // invalidate tab id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,11 @@
|
|||||||
@click.stop="selectFile(file)"
|
@click.stop="selectFile(file)"
|
||||||
>
|
>
|
||||||
<span>{{ file.filename }}</span>
|
<span>{{ file.filename }}</span>
|
||||||
<svg class="icon" aria-hidden="true"
|
<svg class="close-icon icon" aria-hidden="true"
|
||||||
@click.stop="removeFileInTab(file)"
|
@click.stop="removeFileInTab(file)"
|
||||||
>
|
>
|
||||||
<use xlink:href="#icon-close-small"></use>
|
<circle id="unsaved-circle-icon" cx="6" cy="6" r="3"></circle>
|
||||||
|
<use id="default-close-icon" xlink:href="#icon-close-small"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</li>
|
</li>
|
||||||
<li class="new-file">
|
<li class="new-file">
|
||||||
@ -49,6 +50,9 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
svg.close-icon #unsaved-circle-icon {
|
||||||
|
fill: var(--themeColor);
|
||||||
|
}
|
||||||
.editor-tabs {
|
.editor-tabs {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 35px;
|
height: 35px;
|
||||||
@ -82,6 +86,12 @@
|
|||||||
&:hover > svg {
|
&:hover > svg {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
&:hover > svg.close-icon #default-close-icon {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
&:hover > svg.close-icon #unsaved-circle-icon {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
& > span {
|
& > span {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@ -89,6 +99,17 @@
|
|||||||
margin-right: 3px;
|
margin-right: 3px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
& > li.unsaved:not(.active) {
|
||||||
|
& > svg.close-icon {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
& > svg.close-icon #unsaved-circle-icon {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
& > svg.close-icon #default-close-icon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
& > li.active {
|
& > li.active {
|
||||||
background: var(--itemBgColor);
|
background: var(--itemBgColor);
|
||||||
&:not(:last-child):after {
|
&:not(:last-child):after {
|
||||||
@ -103,6 +124,9 @@
|
|||||||
& > svg {
|
& > svg {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
& > svg.close-icon #unsaved-circle-icon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& > li.new-file {
|
& > li.new-file {
|
||||||
|
@ -25,11 +25,11 @@ const mutations = {
|
|||||||
SET_CURRENT_FILE (state, currentFile) {
|
SET_CURRENT_FILE (state, currentFile) {
|
||||||
const oldCurrentFile = state.currentFile
|
const oldCurrentFile = state.currentFile
|
||||||
if (!oldCurrentFile.id || oldCurrentFile.id !== currentFile.id) {
|
if (!oldCurrentFile.id || oldCurrentFile.id !== currentFile.id) {
|
||||||
const { markdown, cursor, history, pathname } = currentFile
|
const { id, markdown, cursor, history, pathname } = currentFile
|
||||||
window.DIRNAME = pathname ? path.dirname(pathname) : ''
|
window.DIRNAME = pathname ? path.dirname(pathname) : ''
|
||||||
// set state first, then emit file changed event
|
// set state first, then emit file changed event
|
||||||
state.currentFile = currentFile
|
state.currentFile = currentFile
|
||||||
bus.$emit('file-changed', { markdown, cursor, renderCursor: true, history })
|
bus.$emit('file-changed', { id, markdown, cursor, renderCursor: true, history })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ADD_FILE_TO_TABS (state, currentFile) {
|
ADD_FILE_TO_TABS (state, currentFile) {
|
||||||
@ -41,12 +41,12 @@ const mutations = {
|
|||||||
tabs.splice(index, 1)
|
tabs.splice(index, 1)
|
||||||
state.tabs = tabs
|
state.tabs = tabs
|
||||||
if (file.id === currentFile.id) {
|
if (file.id === currentFile.id) {
|
||||||
const fileState = state.tabs[index] || state.tabs[index - 1] || {}
|
const fileState = state.tabs[index] || state.tabs[index - 1] || state.tabs[0] || {}
|
||||||
state.currentFile = fileState
|
state.currentFile = fileState
|
||||||
if (typeof fileState.markdown === 'string') {
|
if (typeof fileState.markdown === 'string') {
|
||||||
const { markdown, cursor, history, pathname } = fileState
|
const { id, markdown, cursor, history, pathname } = fileState
|
||||||
window.DIRNAME = pathname ? path.dirname(pathname) : ''
|
window.DIRNAME = pathname ? path.dirname(pathname) : ''
|
||||||
bus.$emit('file-changed', { markdown, cursor, renderCursor: true, history })
|
bus.$emit('file-changed', { id, markdown, cursor, renderCursor: true, history })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -55,7 +55,7 @@ const mutations = {
|
|||||||
const { data, pathname } = change
|
const { data, pathname } = change
|
||||||
const { isMixedLineEndings, lineEnding, adjustLineEndingOnSave, isUtf8BomEncoded, markdown, textDirection, filename } = data
|
const { isMixedLineEndings, lineEnding, adjustLineEndingOnSave, isUtf8BomEncoded, markdown, textDirection, filename } = data
|
||||||
const options = { isUtf8BomEncoded, lineEnding, adjustLineEndingOnSave, textDirection }
|
const options = { isUtf8BomEncoded, lineEnding, adjustLineEndingOnSave, textDirection }
|
||||||
const fileState = getSingleFileState({ markdown, filename, pathname, options })
|
const newFileState = getSingleFileState({ markdown, filename, pathname, options })
|
||||||
if (isMixedLineEndings) {
|
if (isMixedLineEndings) {
|
||||||
notice.notify({
|
notice.notify({
|
||||||
title: 'Line Ending',
|
title: 'Line Ending',
|
||||||
@ -65,18 +65,26 @@ const mutations = {
|
|||||||
showConfirm: false
|
showConfirm: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let fileState = null
|
||||||
for (const tab of tabs) {
|
for (const tab of tabs) {
|
||||||
if (tab.pathname === pathname) {
|
if (tab.pathname === pathname) {
|
||||||
Object.assign(tab, fileState)
|
const oldId = tab.id
|
||||||
|
Object.assign(tab, newFileState)
|
||||||
|
tab.id = oldId
|
||||||
|
fileState = tab
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.tabs = tabs
|
|
||||||
|
if (!fileState) {
|
||||||
|
throw new Error('LOAD_CHANGE: Cannot find tab in tab list.')
|
||||||
|
}
|
||||||
|
|
||||||
if (pathname === currentFile.pathname) {
|
if (pathname === currentFile.pathname) {
|
||||||
Object.assign(currentFile, fileState)
|
state.currentFile = fileState
|
||||||
state.currentFile = currentFile
|
const { id, cursor, history } = fileState
|
||||||
const { cursor, history } = currentFile
|
bus.$emit('file-changed', { id, markdown, cursor, renderCursor: true, history })
|
||||||
bus.$emit('file-changed', { markdown, cursor, renderCursor: true, history })
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SET_PATHNAME (state, file) {
|
SET_PATHNAME (state, file) {
|
||||||
@ -139,6 +147,7 @@ const mutations = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
CLOSE_TABS (state, arr) {
|
CLOSE_TABS (state, arr) {
|
||||||
|
let tabIndex = 0
|
||||||
arr.forEach(id => {
|
arr.forEach(id => {
|
||||||
const index = state.tabs.findIndex(f => f.id === id)
|
const index = state.tabs.findIndex(f => f.id === id)
|
||||||
const { pathname } = state.tabs.find(f => f.id === id)
|
const { pathname } = state.tabs.find(f => f.id === id)
|
||||||
@ -151,14 +160,17 @@ const mutations = {
|
|||||||
if (state.currentFile.id === id) {
|
if (state.currentFile.id === id) {
|
||||||
state.currentFile = {}
|
state.currentFile = {}
|
||||||
window.DIRNAME = ''
|
window.DIRNAME = ''
|
||||||
|
if (arr.length === 1) {
|
||||||
|
tabIndex = index
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (!state.currentFile.id && state.tabs.length) {
|
if (!state.currentFile.id && state.tabs.length) {
|
||||||
state.currentFile = state.tabs[0]
|
state.currentFile = state.tabs[tabIndex] || state.tabs[tabIndex - 1] || state.tabs[0] || {}
|
||||||
if (typeof state.currentFile.markdown === 'string') {
|
if (typeof state.currentFile.markdown === 'string') {
|
||||||
const { markdown, cursor, history, pathname } = state.currentFile
|
const { id, markdown, cursor, history, pathname } = state.currentFile
|
||||||
window.DIRNAME = pathname ? path.dirname(pathname) : ''
|
window.DIRNAME = pathname ? path.dirname(pathname) : ''
|
||||||
bus.$emit('file-changed', { markdown, cursor, renderCursor: true, history })
|
bus.$emit('file-changed', { id, markdown, cursor, renderCursor: true, history })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -383,11 +395,12 @@ const actions = {
|
|||||||
LISTEN_FOR_OPEN_SINGLE_FILE ({ commit, state, dispatch }) {
|
LISTEN_FOR_OPEN_SINGLE_FILE ({ commit, state, dispatch }) {
|
||||||
ipcRenderer.on('AGANI::open-single-file', (e, { markdown, filename, pathname, options }) => {
|
ipcRenderer.on('AGANI::open-single-file', (e, { markdown, filename, pathname, options }) => {
|
||||||
const fileState = getSingleFileState({ markdown, filename, pathname, options })
|
const fileState = getSingleFileState({ markdown, filename, pathname, options })
|
||||||
|
const { id } = fileState
|
||||||
const { lineEnding } = options
|
const { lineEnding } = options
|
||||||
commit('SET_GLOBAL_LINE_ENDING', lineEnding)
|
commit('SET_GLOBAL_LINE_ENDING', lineEnding)
|
||||||
dispatch('INIT_STATUS', true)
|
dispatch('INIT_STATUS', true)
|
||||||
dispatch('UPDATE_CURRENT_FILE', fileState)
|
dispatch('UPDATE_CURRENT_FILE', fileState)
|
||||||
bus.$emit('file-loaded', markdown)
|
bus.$emit('file-loaded', { id, markdown })
|
||||||
commit('SET_LAYOUT', {
|
commit('SET_LAYOUT', {
|
||||||
rightColumn: 'files',
|
rightColumn: 'files',
|
||||||
showSideBar: false,
|
showSideBar: false,
|
||||||
@ -424,12 +437,11 @@ const actions = {
|
|||||||
|
|
||||||
NEW_BLANK_FILE ({ commit, state, dispatch }) {
|
NEW_BLANK_FILE ({ commit, state, dispatch }) {
|
||||||
dispatch('SHOW_TAB_VIEW', false)
|
dispatch('SHOW_TAB_VIEW', false)
|
||||||
|
|
||||||
const { tabs, lineEnding } = state
|
const { tabs, lineEnding } = state
|
||||||
const fileState = getBlankFileState(tabs, lineEnding)
|
const fileState = getBlankFileState(tabs, lineEnding)
|
||||||
const { markdown } = fileState
|
const { id, markdown } = fileState
|
||||||
dispatch('UPDATE_CURRENT_FILE', fileState)
|
dispatch('UPDATE_CURRENT_FILE', fileState)
|
||||||
bus.$emit('file-loaded', markdown)
|
bus.$emit('file-loaded', { id, markdown })
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -449,8 +461,9 @@ const actions = {
|
|||||||
|
|
||||||
const { markdown, isMixedLineEndings } = markdownDocument
|
const { markdown, isMixedLineEndings } = markdownDocument
|
||||||
const docState = createDocumentState(markdownDocument)
|
const docState = createDocumentState(markdownDocument)
|
||||||
|
const { id } = docState
|
||||||
dispatch('UPDATE_CURRENT_FILE', docState)
|
dispatch('UPDATE_CURRENT_FILE', docState)
|
||||||
bus.$emit('file-loaded', markdown)
|
bus.$emit('file-loaded', { id, markdown })
|
||||||
|
|
||||||
if (isMixedLineEndings) {
|
if (isMixedLineEndings) {
|
||||||
const { filename, lineEnding } = markdownDocument
|
const { filename, lineEnding } = markdownDocument
|
||||||
@ -476,11 +489,11 @@ const actions = {
|
|||||||
ipcRenderer.on('AGANI::open-blank-window', (e, { lineEnding, markdown: source }) => {
|
ipcRenderer.on('AGANI::open-blank-window', (e, { lineEnding, markdown: source }) => {
|
||||||
const { tabs } = state
|
const { tabs } = state
|
||||||
const fileState = getBlankFileState(tabs, lineEnding, source)
|
const fileState = getBlankFileState(tabs, lineEnding, source)
|
||||||
const { markdown } = fileState
|
const { id, markdown } = fileState
|
||||||
commit('SET_GLOBAL_LINE_ENDING', lineEnding)
|
commit('SET_GLOBAL_LINE_ENDING', lineEnding)
|
||||||
dispatch('INIT_STATUS', true)
|
dispatch('INIT_STATUS', true)
|
||||||
dispatch('UPDATE_CURRENT_FILE', fileState)
|
dispatch('UPDATE_CURRENT_FILE', fileState)
|
||||||
bus.$emit('file-loaded', markdown)
|
bus.$emit('file-loaded', { id, markdown })
|
||||||
commit('SET_LAYOUT', {
|
commit('SET_LAYOUT', {
|
||||||
rightColumn: 'files',
|
rightColumn: 'files',
|
||||||
showSideBar: false,
|
showSideBar: false,
|
||||||
@ -490,24 +503,34 @@ const actions = {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// LISTEN_FOR_FILE_CHANGE ({ commit, state }) {
|
|
||||||
// ipcRenderer.on('AGANI::file-change', (e, { file, filename, pathname }) => {
|
|
||||||
// const { windowActive } = state
|
|
||||||
// commit('SET_FILENAME', filename)
|
|
||||||
// commit('SET_PATHNAME', pathname)
|
|
||||||
// commit('SET_MARKDOWN', file)
|
|
||||||
// commit('SET_SAVE_STATUS', true)
|
|
||||||
// if (!windowActive) {
|
|
||||||
// bus.$emit('file-loaded', file)
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// },
|
|
||||||
|
|
||||||
// Content change from realtime preview editor and source code editor
|
// Content change from realtime preview editor and source code editor
|
||||||
LISTEN_FOR_CONTENT_CHANGE ({ commit, state, rootState }, { markdown, wordCount, cursor, history, toc }) {
|
// WORKAROUND: id is "muya" if changes come from muya and not source code editor! So we don't have to apply the workaround.
|
||||||
|
LISTEN_FOR_CONTENT_CHANGE ({ commit, state, rootState }, { id, markdown, wordCount, cursor, history, toc }) {
|
||||||
const { autoSave } = rootState.preferences
|
const { autoSave } = rootState.preferences
|
||||||
const { projectTree } = rootState.project
|
const { projectTree } = rootState.project
|
||||||
const { pathname, markdown: oldMarkdown, id } = state.currentFile
|
const { id: currentId, pathname, markdown: oldMarkdown } = state.currentFile
|
||||||
|
|
||||||
|
if (!id) {
|
||||||
|
throw new Error(`Listen for document change but id was not set!`)
|
||||||
|
} else if (!currentId || state.tabs.length === 0) {
|
||||||
|
// Discard changes - this case should normally not occur.
|
||||||
|
return
|
||||||
|
} else if (id !== 'muya' && currentId !== id) {
|
||||||
|
// WORKAROUND: We commit changes after switching the tab in source code mode.
|
||||||
|
// Update old tab or discard changes
|
||||||
|
for (const tab of state.tabs) {
|
||||||
|
if (tab.id && tab.id === id) {
|
||||||
|
tab.markdown = markdown
|
||||||
|
// set cursor
|
||||||
|
if (cursor) tab.cursor = cursor
|
||||||
|
// set history
|
||||||
|
if (history) tab.history = history
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const options = getOptionsFromState(state.currentFile)
|
const options = getOptionsFromState(state.currentFile)
|
||||||
commit('SET_MARKDOWN', markdown)
|
commit('SET_MARKDOWN', markdown)
|
||||||
|
|
||||||
@ -531,7 +554,7 @@ const actions = {
|
|||||||
commit('UPDATE_PROJECT_CONTENT', { markdown, pathname })
|
commit('UPDATE_PROJECT_CONTENT', { markdown, pathname })
|
||||||
}
|
}
|
||||||
if (pathname && autoSave) {
|
if (pathname && autoSave) {
|
||||||
ipcRenderer.send('AGANI::response-file-save', { id, pathname, markdown, options })
|
ipcRenderer.send('AGANI::response-file-save', { id: currentId, pathname, markdown, options })
|
||||||
} else {
|
} else {
|
||||||
commit('SET_SAVE_STATUS', false)
|
commit('SET_SAVE_STATUS', false)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user