Skip to content

Commit 0b8c9b5

Browse files
committed
chore(split): SourceView from ViewerComponent
Signed-off-by: Max <[email protected]>
1 parent ab7ed54 commit 0b8c9b5

File tree

2 files changed

+164
-98
lines changed

2 files changed

+164
-98
lines changed

src/components/SourceView.vue

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
<!--
2+
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
3+
- SPDX-License-Identifier: AGPL-3.0-or-later
4+
-->
5+
6+
<template>
7+
<div
8+
id="editor-container"
9+
data-text-el="editor-container"
10+
class="text-editor source-viewer">
11+
<Component
12+
:is="readerComponent"
13+
:content="content"
14+
:file-id="fileid"
15+
:read-only="true"
16+
:show-menu-bar="false" />
17+
<NcButton
18+
v-if="isEmbedded"
19+
class="toggle-interactive"
20+
@click="$emit('edit')">
21+
{{ t('text', 'Edit') }}
22+
<template #icon>
23+
<PencilOutlineIcon />
24+
</template>
25+
</NcButton>
26+
</div>
27+
</template>
28+
29+
<script>
30+
import axios from '@nextcloud/axios'
31+
import { getClient, getRootPath } from '@nextcloud/files/dav'
32+
import { t } from '@nextcloud/l10n'
33+
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
34+
import Vue from 'vue'
35+
import PencilOutlineIcon from 'vue-material-design-icons/PencilOutline.vue'
36+
import MarkdownContentEditor from './Editor/MarkdownContentEditor.vue'
37+
import PlainTextReader from './PlainTextReader.vue'
38+
39+
export default {
40+
name: 'SourceView',
41+
components: {
42+
NcButton: Vue.extend(NcButton),
43+
PencilOutlineIcon: Vue.extend(PencilOutlineIcon),
44+
PlainTextReader: Vue.extend(PlainTextReader),
45+
MarkdownContentEditor: Vue.extend(MarkdownContentEditor),
46+
},
47+
inject: ['isEmbedded'],
48+
props: {
49+
filename: {
50+
type: String,
51+
default: null,
52+
},
53+
fileid: {
54+
type: Number,
55+
default: null,
56+
},
57+
mime: {
58+
type: String,
59+
default: null,
60+
},
61+
source: {
62+
type: String,
63+
default: undefined,
64+
},
65+
},
66+
data() {
67+
return {
68+
content: '',
69+
}
70+
},
71+
computed: {
72+
isEncrypted() {
73+
return this.$attrs.e2EeIsEncrypted || false
74+
},
75+
76+
isMarkdown() {
77+
return (
78+
this.mime === 'text/markdown' || this.mime === 'text/x-web-markdown'
79+
)
80+
},
81+
82+
/** @return {boolean} */
83+
readerComponent() {
84+
return this.isMarkdown ? MarkdownContentEditor : PlainTextReader
85+
},
86+
},
87+
88+
watch: {
89+
source() {
90+
this.loadFileContent()
91+
},
92+
},
93+
94+
mounted() {
95+
this.loadFileContent()
96+
},
97+
98+
methods: {
99+
async loadFileContent() {
100+
if (this.isEncrypted) {
101+
this.content = await this.fetchDecryptedContent()
102+
this.contentLoaded = true
103+
} else {
104+
const response = await axios.get(this.source)
105+
this.content = response.data
106+
this.contentLoaded = true
107+
}
108+
this.$emit('loaded', true)
109+
},
110+
async fetchDecryptedContent() {
111+
const client = getClient()
112+
const response = await client.getFileContents(
113+
`${getRootPath()}${this.filename}`,
114+
{ details: true },
115+
)
116+
const blob = new Blob([response.data], {
117+
type: response.headers['content-type'],
118+
})
119+
const reader = new FileReader()
120+
reader.readAsText(blob)
121+
return new Promise((resolve) => {
122+
reader.onload = () => {
123+
resolve(reader.result)
124+
}
125+
})
126+
},
127+
t,
128+
},
129+
}
130+
</script>
131+
<style lang="scss" scoped>
132+
.source-viewer {
133+
display: block;
134+
135+
.text-editor__content-wrapper {
136+
margin-top: var(--header-height);
137+
}
138+
139+
.toggle-interactive {
140+
position: sticky;
141+
bottom: 0;
142+
right: 0;
143+
z-index: 1;
144+
margin-left: auto;
145+
margin-right: 0;
146+
}
147+
}
148+
</style>

src/components/ViewerComponent.vue

Lines changed: 16 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -14,46 +14,27 @@
1414
:class="{ 'text-editor--embedding': isEmbedded }"
1515
:mime="mime"
1616
:show-outline-outside="showOutlineOutside" />
17-
<div
17+
<SourceView
1818
v-else
19-
id="editor-container"
20-
data-text-el="editor-container"
21-
class="text-editor source-viewer">
22-
<Component
23-
:is="readerComponent"
24-
:content="content"
25-
:file-id="fileid"
26-
:read-only="true"
27-
:show-menu-bar="false" />
28-
<NcButton v-if="isEmbedded" class="toggle-interactive" @click="toggleEdit">
29-
{{ t('text', 'Edit') }}
30-
<template #icon>
31-
<PencilOutlineIcon />
32-
</template>
33-
</NcButton>
34-
</div>
19+
:fileid="fileid"
20+
:filename="filename"
21+
:mime="mime"
22+
:source="source"
23+
v-bind="$attrs"
24+
@loaded="onLoaded">
25+
@edit="toggleEdit">
26+
</SourceView>
3527
</template>
3628

3729
<script>
38-
import axios from '@nextcloud/axios'
39-
import { getClient, getRootPath } from '@nextcloud/files/dav'
40-
import { t } from '@nextcloud/l10n'
4130
import { getSharingToken } from '@nextcloud/sharing/public'
42-
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
43-
import Vue from 'vue'
44-
import PencilOutlineIcon from 'vue-material-design-icons/PencilOutline.vue'
45-
import MarkdownContentEditor from './Editor/MarkdownContentEditor.vue'
46-
import PlainTextReader from './PlainTextReader.vue'
47-
4831
import getEditorInstance from './Editor.singleton.js'
32+
import SourceView from './SourceView.vue'
4933
5034
export default {
5135
name: 'ViewerComponent',
5236
components: {
53-
NcButton: Vue.extend(NcButton),
54-
PencilOutlineIcon: Vue.extend(PencilOutlineIcon),
55-
PlainTextReader: Vue.extend(PlainTextReader),
56-
MarkdownContentEditor: Vue.extend(MarkdownContentEditor),
37+
SourceView,
5738
Editor: getEditorInstance,
5839
},
5940
provide() {
@@ -105,7 +86,6 @@ export default {
10586
},
10687
data() {
10788
return {
108-
content: '',
10989
hasToggledInteractiveEmbedding: false,
11090
}
11191
},
@@ -121,66 +101,21 @@ export default {
121101
&& !this.hasToggledInteractiveEmbedding
122102
)
123103
},
124-
125-
isEncrypted() {
126-
return this.$attrs.e2EeIsEncrypted || false
127-
},
128-
129-
isMarkdown() {
130-
return (
131-
this.mime === 'text/markdown' || this.mime === 'text/x-web-markdown'
132-
)
133-
},
134-
135-
/** @return {boolean} */
136-
readerComponent() {
137-
return this.isMarkdown ? MarkdownContentEditor : PlainTextReader
138-
},
139-
},
140-
141-
watch: {
142-
source() {
143-
this.loadFileContent()
144-
},
145104
},
146105
147106
mounted() {
148-
this.loadFileContent()
107+
if (!this.useSourceView) {
108+
this.onLoaded()
109+
}
149110
},
150111
151112
methods: {
152-
async loadFileContent() {
153-
if (this.useSourceView) {
154-
if (this.isEncrypted) {
155-
this.content = await this.fetchDecryptedContent()
156-
this.contentLoaded = true
157-
} else {
158-
const response = await axios.get(this.source)
159-
this.content = response.data
160-
this.contentLoaded = true
161-
}
162-
}
113+
async onLoaded() {
163114
this.$emit('update:loaded', true)
164115
},
165116
toggleEdit() {
166117
this.hasToggledInteractiveEmbedding = true
167-
},
168-
async fetchDecryptedContent() {
169-
const client = getClient()
170-
const response = await client.getFileContents(
171-
`${getRootPath()}${this.filename}`,
172-
{ details: true },
173-
)
174-
const blob = new Blob([response.data], {
175-
type: response.headers['content-type'],
176-
})
177-
const reader = new FileReader()
178-
reader.readAsText(blob)
179-
return new Promise((resolve) => {
180-
reader.onload = () => {
181-
resolve(reader.result)
182-
}
183-
})
118+
this.onLoaded()
184119
},
185120
t,
186121
},
@@ -197,23 +132,6 @@ export default {
197132
position: relative;
198133
background-color: var(--color-main-background);
199134
200-
&.source-viewer {
201-
display: block;
202-
203-
.text-editor__content-wrapper {
204-
margin-top: var(--header-height);
205-
}
206-
207-
.toggle-interactive {
208-
position: sticky;
209-
bottom: 0;
210-
right: 0;
211-
z-index: 1;
212-
margin-left: auto;
213-
margin-right: 0;
214-
}
215-
}
216-
217135
&.text-editor--embedding {
218136
min-height: 400px;
219137
}

0 commit comments

Comments
 (0)