feat: rework preview and editor
fix filebrowser/filebrowser#750, fix filebrowser/filebrowser#553 Preview: - Opens and cycle all files types. - Support for text, mardown and html. - Added filename title, esc key shortcut and editor button. Editor: - Shows on full screen overlay. - Added esc key shortcut.
This commit is contained in:
parent
77eef5dc12
commit
b0693906eb
@ -13,6 +13,7 @@
|
|||||||
"clipboard": "^2.0.4",
|
"clipboard": "^2.0.4",
|
||||||
"js-base64": "^2.5.1",
|
"js-base64": "^2.5.1",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
|
"marked": "^0.8.0",
|
||||||
"material-design-icons": "^3.0.1",
|
"material-design-icons": "^3.0.1",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
|
|||||||
@ -124,6 +124,12 @@ nav > div {
|
|||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#previewer .text,
|
||||||
|
#previewer .markdown,
|
||||||
|
#previewer .html {
|
||||||
|
background: var(--surfacePrimary);
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 736px) {
|
@media (max-width: 736px) {
|
||||||
#file-selection {
|
#file-selection {
|
||||||
background: var(--surfaceSecondary) !important;
|
background: var(--surfaceSecondary) !important;
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
<search v-if="isLogged"></search>
|
<search v-if="isLogged"></search>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<template v-if="isLogged">
|
<template v-if="isLogged && isListing">
|
||||||
<button @click="openSearch" :aria-label="$t('buttons.search')" :title="$t('buttons.search')" class="search-button action">
|
<button @click="openSearch" :aria-label="$t('buttons.search')" :title="$t('buttons.search')" class="search-button action">
|
||||||
<i class="material-icons">search</i>
|
<i class="material-icons">search</i>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
17
frontend/src/components/buttons/Edit.vue
Normal file
17
frontend/src/components/buttons/Edit.vue
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<button @click="show" :aria-label="$t('buttons.edit')" :title="$t('buttons.edit')" class="action" id="edit-button">
|
||||||
|
<i class="material-icons">mode_edit</i>
|
||||||
|
<span>{{ $t('buttons.edit') }}</span>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'edit-button',
|
||||||
|
methods: {
|
||||||
|
show: function () {
|
||||||
|
this.$store.commit('toggleEditor')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<button @click="show" :aria-label="$t('buttons.rename')" :title="$t('buttons.rename')" class="action" id="rename-button">
|
<button @click="show" :aria-label="$t('buttons.rename')" :title="$t('buttons.rename')" class="action" id="rename-button">
|
||||||
<i class="material-icons">mode_edit</i>
|
<i class="material-icons">label</i>
|
||||||
<span>{{ $t('buttons.rename') }}</span>
|
<span>{{ $t('buttons.rename') }}</span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,5 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<form id="editor"></form>
|
<div id="previewer">
|
||||||
|
<div class="bar">
|
||||||
|
<button @click="back" class="action" :title="$t('files.closePreview')" :aria-label="$t('files.closePreview')" id="close">
|
||||||
|
<i class="material-icons">close</i>
|
||||||
|
</button>
|
||||||
|
<span class="title">{{ req.name + ((contentChanged) ? '*' : '') }}</span>
|
||||||
|
<button @click="save" v-show="user.perm.modify" :aria-label="$t('buttons.save')" :title="$t('buttons.save')" class="action" id="save-button">
|
||||||
|
<i class="material-icons">save</i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="editor">
|
||||||
|
<form id="editor"></form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -10,55 +23,50 @@ import buttons from '@/utils/buttons'
|
|||||||
import ace from 'ace-builds/src-min-noconflict/ace.js'
|
import ace from 'ace-builds/src-min-noconflict/ace.js'
|
||||||
import modelist from 'ace-builds/src-min-noconflict/ext-modelist.js'
|
import modelist from 'ace-builds/src-min-noconflict/ext-modelist.js'
|
||||||
import 'ace-builds/webpack-resolver'
|
import 'ace-builds/webpack-resolver'
|
||||||
import { theme } from '@/utils/constants'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'editor',
|
name: 'editor',
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['req'])
|
...mapState(['req', 'user', 'previewContent'])
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {}
|
return {
|
||||||
|
editor: null,
|
||||||
|
contentChanged: false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
window.addEventListener('keydown', this.keyEvent)
|
window.addEventListener('keydown', this.keyEvent)
|
||||||
document.getElementById('save-button').addEventListener('click', this.save)
|
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
window.removeEventListener('keydown', this.keyEvent)
|
window.removeEventListener('keydown', this.keyEvent)
|
||||||
document.getElementById('save-button').removeEventListener('click', this.save)
|
|
||||||
this.editor.destroy();
|
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
const fileContent = this.req.content || '';
|
|
||||||
|
|
||||||
this.editor = ace.edit('editor', {
|
this.editor = ace.edit('editor', {
|
||||||
maxLines: Infinity,
|
maxLines: Infinity,
|
||||||
minLines: 20,
|
minLines: 20,
|
||||||
value: fileContent,
|
value: this.previewContent,
|
||||||
showPrintMargin: false,
|
showPrintMargin: false,
|
||||||
readOnly: this.req.type === 'textImmutable',
|
readOnly: this.req.type === 'textImmutable',
|
||||||
theme: 'ace/theme/chrome',
|
theme: 'ace/theme/twilight',
|
||||||
mode: modelist.getModeForPath(this.req.name).mode,
|
mode: modelist.getModeForPath(this.req.name).mode,
|
||||||
wrap: true
|
wrap: true
|
||||||
})
|
})
|
||||||
|
|
||||||
if (theme == 'dark') {
|
this.editor.on('change', () => {
|
||||||
this.editor.setTheme("ace/theme/twilight");
|
this.contentChanged = true
|
||||||
}
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
keyEvent (event) {
|
keyEvent (event) {
|
||||||
if (!event.ctrlKey && !event.metaKey) {
|
let key = String.fromCharCode(event.which).toLowerCase()
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (String.fromCharCode(event.which).toLowerCase() !== 's') {
|
if ((event.ctrlKey || event.metaKey) && key == 's') {
|
||||||
return
|
event.preventDefault()
|
||||||
|
this.save()
|
||||||
|
} else if (event.which === 27) { // Esc
|
||||||
|
this.$store.commit('toggleEditor')
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault()
|
|
||||||
this.save()
|
|
||||||
},
|
},
|
||||||
async save () {
|
async save () {
|
||||||
const button = 'save'
|
const button = 'save'
|
||||||
@ -66,11 +74,18 @@ export default {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await api.put(this.$route.path, this.editor.getValue())
|
await api.put(this.$route.path, this.editor.getValue())
|
||||||
|
|
||||||
|
this.$store.commit('setPreviewContent', this.editor.getValue())
|
||||||
|
this.contentChanged = false
|
||||||
|
|
||||||
buttons.success(button)
|
buttons.success(button)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
buttons.done(button)
|
buttons.done(button)
|
||||||
this.$showError(e)
|
this.$showError(e)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
back () {
|
||||||
|
this.$store.commit('toggleEditor')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,8 @@
|
|||||||
<button @click="back" class="action" :title="$t('files.closePreview')" :aria-label="$t('files.closePreview')" id="close">
|
<button @click="back" class="action" :title="$t('files.closePreview')" :aria-label="$t('files.closePreview')" id="close">
|
||||||
<i class="material-icons">close</i>
|
<i class="material-icons">close</i>
|
||||||
</button>
|
</button>
|
||||||
|
<span class="title">{{ req.name }}</span>
|
||||||
|
<edit-button v-if="isFileEditable"></edit-button>
|
||||||
<rename-button v-if="user.perm.rename"></rename-button>
|
<rename-button v-if="user.perm.rename"></rename-button>
|
||||||
<delete-button v-if="user.perm.delete"></delete-button>
|
<delete-button v-if="user.perm.delete"></delete-button>
|
||||||
<download-button v-if="user.perm.download"></download-button>
|
<download-button v-if="user.perm.download"></download-button>
|
||||||
@ -33,29 +34,37 @@
|
|||||||
and watch it with your favorite video player!
|
and watch it with your favorite video player!
|
||||||
</video>
|
</video>
|
||||||
<object v-else-if="req.extension == '.pdf'" class="pdf" :data="raw"></object>
|
<object v-else-if="req.extension == '.pdf'" class="pdf" :data="raw"></object>
|
||||||
<a v-else-if="req.type == 'blob'" :href="download">
|
<div class="html" v-else-if="req.extension == '.html'"> <iframe :src="getHtmlContent()"></iframe> </div>
|
||||||
<h2 class="message">{{ $t('buttons.download') }} <i class="material-icons">file_download</i></h2>
|
<div class="markdown" v-else-if="isMarkdown" v-html="getMarkdownContent()"></div>
|
||||||
</a>
|
<div class="text" v-else-if="req.type == 'text'">{{ previewContent }}</div>
|
||||||
|
<div v-else>
|
||||||
|
<a :href="download">
|
||||||
|
<h2 class="message">{{ $t('buttons.download') }} <i class="material-icons">file_download</i></h2>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex'
|
import { mapGetters, mapState } from 'vuex'
|
||||||
import url from '@/utils/url'
|
import url from '@/utils/url'
|
||||||
import { baseURL } from '@/utils/constants'
|
import { baseURL } from '@/utils/constants'
|
||||||
import { files as api } from '@/api'
|
import { files as api } from '@/api'
|
||||||
|
import marked from 'marked'
|
||||||
import InfoButton from '@/components/buttons/Info'
|
import InfoButton from '@/components/buttons/Info'
|
||||||
import DeleteButton from '@/components/buttons/Delete'
|
import DeleteButton from '@/components/buttons/Delete'
|
||||||
import RenameButton from '@/components/buttons/Rename'
|
import RenameButton from '@/components/buttons/Rename'
|
||||||
import DownloadButton from '@/components/buttons/Download'
|
import DownloadButton from '@/components/buttons/Download'
|
||||||
|
import EditButton from '@/components/buttons/Edit'
|
||||||
import ExtendedImage from './ExtendedImage'
|
import ExtendedImage from './ExtendedImage'
|
||||||
|
|
||||||
const mediaTypes = [
|
const markdownExtesions = [
|
||||||
"image",
|
'.md',
|
||||||
"video",
|
'.mkdn',
|
||||||
"audio",
|
'.mdwn',
|
||||||
"blob"
|
'.mdown',
|
||||||
|
'.markdown'
|
||||||
]
|
]
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -65,6 +74,7 @@ export default {
|
|||||||
DeleteButton,
|
DeleteButton,
|
||||||
RenameButton,
|
RenameButton,
|
||||||
DownloadButton,
|
DownloadButton,
|
||||||
|
EditButton,
|
||||||
ExtendedImage
|
ExtendedImage
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
@ -76,7 +86,8 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['req', 'user', 'oldReq', 'jwt']),
|
...mapGetters(['isFileEditable']),
|
||||||
|
...mapState(['req', 'user', 'oldReq', 'jwt', 'previewContent']),
|
||||||
hasPrevious () {
|
hasPrevious () {
|
||||||
return (this.previousLink !== '')
|
return (this.previousLink !== '')
|
||||||
},
|
},
|
||||||
@ -88,10 +99,13 @@ export default {
|
|||||||
},
|
},
|
||||||
raw () {
|
raw () {
|
||||||
return `${this.download}&inline=true`
|
return `${this.download}&inline=true`
|
||||||
|
},
|
||||||
|
isMarkdown () {
|
||||||
|
return markdownExtesions.includes(this.req.extension)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted () {
|
async mounted () {
|
||||||
window.addEventListener('keyup', this.key)
|
window.addEventListener('keydown', this.key)
|
||||||
|
|
||||||
if (this.req.subtitles) {
|
if (this.req.subtitles) {
|
||||||
this.subtitles = this.req.subtitles.map(sub => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`)
|
this.subtitles = this.req.subtitles.map(sub => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`)
|
||||||
@ -110,7 +124,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
window.removeEventListener('keyup', this.key)
|
window.removeEventListener('keydown', this.key)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
back () {
|
back () {
|
||||||
@ -130,6 +144,8 @@ export default {
|
|||||||
if (this.hasNext) this.next()
|
if (this.hasNext) this.next()
|
||||||
} else if (event.which === 37) { // left arrow
|
} else if (event.which === 37) { // left arrow
|
||||||
if (this.hasPrevious) this.prev()
|
if (this.hasPrevious) this.prev()
|
||||||
|
} else if (event.which == 27) { // esc
|
||||||
|
this.back()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateLinks (items) {
|
updateLinks (items) {
|
||||||
@ -139,14 +155,14 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let j = i - 1; j >= 0; j--) {
|
for (let j = i - 1; j >= 0; j--) {
|
||||||
if (mediaTypes.includes(items[j].type)) {
|
if (!items[j].isDir) {
|
||||||
this.previousLink = items[j].url
|
this.previousLink = items[j].url
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let j = i + 1; j < items.length; j++) {
|
for (let j = i + 1; j < items.length; j++) {
|
||||||
if (mediaTypes.includes(items[j].type)) {
|
if (!items[j].isDir) {
|
||||||
this.nextLink = items[j].url
|
this.nextLink = items[j].url
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -154,6 +170,12 @@ export default {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
getHtmlContent () {
|
||||||
|
return 'data:text/html;base64,' + btoa(unescape(encodeURIComponent(this.previewContent)))
|
||||||
|
},
|
||||||
|
getMarkdownContent () {
|
||||||
|
return marked(this.previewContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -125,8 +125,13 @@
|
|||||||
height: 3.7em;
|
height: 3.7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#previewer .action:first-of-type {
|
#previewer .title {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 2.4;
|
||||||
|
padding: 0 8px;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#previewer .action i {
|
#previewer .action i {
|
||||||
@ -148,6 +153,40 @@
|
|||||||
height: calc(100vh - 9.7em);
|
height: calc(100vh - 9.7em);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#previewer .editor {
|
||||||
|
max-height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#previewer .text {
|
||||||
|
height: 100%;
|
||||||
|
padding: 16px;
|
||||||
|
overflow: auto;
|
||||||
|
background: white;
|
||||||
|
text-align: left;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
#previewer .markdown {
|
||||||
|
height: 100%;
|
||||||
|
padding: 16px;
|
||||||
|
overflow: auto;
|
||||||
|
background: white;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#previewer .html {
|
||||||
|
height: 100%;
|
||||||
|
background: white;
|
||||||
|
text-align: left;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
#previewer .html iframe {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
#previewer .preview pre {
|
#previewer .preview pre {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
"create": "Create",
|
"create": "Create",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"download": "Download",
|
"download": "Download",
|
||||||
|
"edit": "Edit",
|
||||||
"info": "Info",
|
"info": "Info",
|
||||||
"more": "More",
|
"more": "More",
|
||||||
"move": "Move",
|
"move": "Move",
|
||||||
|
|||||||
@ -2,7 +2,10 @@ const getters = {
|
|||||||
isLogged: state => state.user !== null,
|
isLogged: state => state.user !== null,
|
||||||
isFiles: state => !state.loading && state.route.name === 'Files',
|
isFiles: state => !state.loading && state.route.name === 'Files',
|
||||||
isListing: (state, getters) => getters.isFiles && state.req.isDir,
|
isListing: (state, getters) => getters.isFiles && state.req.isDir,
|
||||||
isEditor: (state, getters) => getters.isFiles && (state.req.type === 'text' || state.req.type === 'textImmutable'),
|
isPreview: (state, getters) => !state.loading && !getters.isListing && !getters.isEditor,
|
||||||
|
isEditor: (state, getters) => getters.isFiles && state.showEditor,
|
||||||
|
isFileEditable: (state) => state.req.type === 'text' || state.req.type === 'textImmutable',
|
||||||
|
getPreviewContent: state => state.previewContent,
|
||||||
selectedCount: state => state.selected.length
|
selectedCount: state => state.selected.length
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,9 @@ const state = {
|
|||||||
show: null,
|
show: null,
|
||||||
showShell: false,
|
showShell: false,
|
||||||
showMessage: null,
|
showMessage: null,
|
||||||
showConfirm: null
|
showConfirm: null,
|
||||||
|
showEditor: false,
|
||||||
|
previewContent: null
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
|
|||||||
@ -85,6 +85,12 @@ const mutations = {
|
|||||||
},
|
},
|
||||||
setProgress: (state, value) => {
|
setProgress: (state, value) => {
|
||||||
state.progress = value
|
state.progress = value
|
||||||
|
},
|
||||||
|
toggleEditor: (state) => (
|
||||||
|
state.showEditor = !state.showEditor
|
||||||
|
),
|
||||||
|
setPreviewContent: (state, value) => {
|
||||||
|
state.previewContent = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,6 @@ const logoURL = `/${staticURL}/img/logo.svg`
|
|||||||
const noAuth = window.FileBrowser.NoAuth
|
const noAuth = window.FileBrowser.NoAuth
|
||||||
const authMethod = window.FileBrowser.AuthMethod
|
const authMethod = window.FileBrowser.AuthMethod
|
||||||
const loginPage = window.FileBrowser.LoginPage
|
const loginPage = window.FileBrowser.LoginPage
|
||||||
const theme = window.FileBrowser.Theme
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
name,
|
name,
|
||||||
@ -23,6 +22,5 @@ export {
|
|||||||
version,
|
version,
|
||||||
noAuth,
|
noAuth,
|
||||||
authMethod,
|
authMethod,
|
||||||
loginPage,
|
loginPage
|
||||||
theme
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div id="breadcrumbs">
|
<div v-if="isListing" id="breadcrumbs">
|
||||||
<router-link to="/files/" :aria-label="$t('files.home')" :title="$t('files.home')">
|
<router-link to="/files/" :aria-label="$t('files.home')" :title="$t('files.home')">
|
||||||
<i class="material-icons">home</i>
|
<i class="material-icons">home</i>
|
||||||
</router-link>
|
</router-link>
|
||||||
@ -53,6 +53,7 @@ export default {
|
|||||||
...mapGetters([
|
...mapGetters([
|
||||||
'selectedCount',
|
'selectedCount',
|
||||||
'isListing',
|
'isListing',
|
||||||
|
'isPreview',
|
||||||
'isEditor',
|
'isEditor',
|
||||||
'isFiles'
|
'isFiles'
|
||||||
]),
|
]),
|
||||||
@ -63,9 +64,6 @@ export default {
|
|||||||
'multiple',
|
'multiple',
|
||||||
'loading'
|
'loading'
|
||||||
]),
|
]),
|
||||||
isPreview () {
|
|
||||||
return !this.loading && !this.isListing && !this.isEditor
|
|
||||||
},
|
|
||||||
breadcrumbs () {
|
breadcrumbs () {
|
||||||
let parts = this.$route.path.split('/')
|
let parts = this.$route.path.split('/')
|
||||||
|
|
||||||
@ -151,6 +149,9 @@ export default {
|
|||||||
|
|
||||||
this.$store.commit('updateRequest', res)
|
this.$store.commit('updateRequest', res)
|
||||||
document.title = res.name
|
document.title = res.name
|
||||||
|
|
||||||
|
if (res.content)
|
||||||
|
this.$store.commit('setPreviewContent', res.content)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.error = e
|
this.error = e
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user