You've already forked filebrowser
mirror of
https://github.com/filebrowser/filebrowser.git
synced 2025-11-26 14:25:26 +08:00
feat: migrate to vue 3 (#2689)
--------- Co-authored-by: Joep <jcbuhre@gmail.com> Co-authored-by: Omar Hussein <omarmohammad1951@gmail.com> Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
This commit is contained in:
@@ -1,156 +1,129 @@
|
||||
<template>
|
||||
<div
|
||||
id="editor-container"
|
||||
@touchmove.prevent.stop
|
||||
@wheel.prevent.stop
|
||||
>
|
||||
<div id="editor-container" @touchmove.prevent.stop @wheel.prevent.stop>
|
||||
<header-bar>
|
||||
<action icon="close" :label="$t('buttons.close')" @action="close()" />
|
||||
<title>{{ req.name }}</title>
|
||||
<action icon="close" :label="t('buttons.close')" @action="close()" />
|
||||
<title>{{ fileStore.req?.name ?? "" }}</title>
|
||||
|
||||
<action
|
||||
v-if="user.perm.modify"
|
||||
v-if="authStore.user?.perm.modify"
|
||||
id="save-button"
|
||||
icon="save"
|
||||
:label="$t('buttons.save')"
|
||||
:label="t('buttons.save')"
|
||||
@action="save()"
|
||||
/>
|
||||
</header-bar>
|
||||
|
||||
<breadcrumbs base="/files" noLink />
|
||||
<Breadcrumbs base="/files" noLink />
|
||||
|
||||
<form id="editor"></form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from "vuex";
|
||||
<script setup lang="ts">
|
||||
import { files as api } from "@/api";
|
||||
import { theme } from "@/utils/constants";
|
||||
import buttons from "@/utils/buttons";
|
||||
import url from "@/utils/url";
|
||||
|
||||
import { version as ace_version } from "ace-builds";
|
||||
import ace from "ace-builds/src-min-noconflict/ace.js";
|
||||
import modelist from "ace-builds/src-min-noconflict/ext-modelist.js";
|
||||
import ace, { Ace, version as ace_version } from "ace-builds";
|
||||
import modelist from "ace-builds/src-noconflict/ext-modelist";
|
||||
import "ace-builds/src-noconflict/ext-language_tools";
|
||||
|
||||
import HeaderBar from "@/components/header/HeaderBar.vue";
|
||||
import Action from "@/components/header/Action.vue";
|
||||
import Breadcrumbs from "@/components/Breadcrumbs.vue";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import { useFileStore } from "@/stores/file";
|
||||
import { useLayoutStore } from "@/stores/layout";
|
||||
import { inject, onBeforeUnmount, onMounted, ref } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { getTheme } from "@/utils/theme";
|
||||
|
||||
export default {
|
||||
name: "editor",
|
||||
components: {
|
||||
HeaderBar,
|
||||
Action,
|
||||
Breadcrumbs,
|
||||
},
|
||||
data: function () {
|
||||
return {};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["req", "user"]),
|
||||
breadcrumbs() {
|
||||
let parts = this.$route.path.split("/");
|
||||
const $showError = inject<IToastError>("$showError")!;
|
||||
|
||||
if (parts[0] === "") {
|
||||
parts.shift();
|
||||
}
|
||||
const fileStore = useFileStore();
|
||||
const authStore = useAuthStore();
|
||||
const layoutStore = useLayoutStore();
|
||||
|
||||
if (parts[parts.length - 1] === "") {
|
||||
parts.pop();
|
||||
}
|
||||
const { t } = useI18n();
|
||||
|
||||
let breadcrumbs = [];
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
breadcrumbs.push({ name: decodeURIComponent(parts[i]) });
|
||||
}
|
||||
const editor = ref<Ace.Editor | null>(null);
|
||||
|
||||
breadcrumbs.shift();
|
||||
onMounted(() => {
|
||||
window.addEventListener("keydown", keyEvent);
|
||||
|
||||
if (breadcrumbs.length > 3) {
|
||||
while (breadcrumbs.length !== 4) {
|
||||
breadcrumbs.shift();
|
||||
}
|
||||
const fileContent = fileStore.req?.content || "";
|
||||
|
||||
breadcrumbs[0].name = "...";
|
||||
}
|
||||
ace.config.set(
|
||||
"basePath",
|
||||
`https://cdn.jsdelivr.net/npm/ace-builds@${ace_version}/src-min-noconflict/`
|
||||
);
|
||||
|
||||
return breadcrumbs;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
window.addEventListener("keydown", this.keyEvent);
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener("keydown", this.keyEvent);
|
||||
this.editor.destroy();
|
||||
},
|
||||
mounted: function () {
|
||||
const fileContent = this.req.content || "";
|
||||
editor.value = ace.edit("editor", {
|
||||
value: fileContent,
|
||||
showPrintMargin: false,
|
||||
readOnly: fileStore.req?.type === "textImmutable",
|
||||
theme: "ace/theme/chrome",
|
||||
mode: modelist.getModeForPath(fileStore.req?.name).mode,
|
||||
wrap: true,
|
||||
enableBasicAutocompletion: true,
|
||||
enableLiveAutocompletion: true,
|
||||
enableSnippets: true,
|
||||
});
|
||||
|
||||
ace.config.set(
|
||||
"basePath",
|
||||
`https://cdn.jsdelivr.net/npm/ace-builds@${ace_version}/src-min-noconflict/`
|
||||
);
|
||||
if (getTheme() === "dark") {
|
||||
editor.value!.setTheme("ace/theme/twilight");
|
||||
}
|
||||
|
||||
this.editor = ace.edit("editor", {
|
||||
value: fileContent,
|
||||
showPrintMargin: false,
|
||||
readOnly: this.req.type === "textImmutable",
|
||||
theme: "ace/theme/chrome",
|
||||
mode: modelist.getModeForPath(this.req.name).mode,
|
||||
wrap: true,
|
||||
});
|
||||
editor.value.focus();
|
||||
});
|
||||
|
||||
if (theme == "dark") {
|
||||
this.editor.setTheme("ace/theme/twilight");
|
||||
}
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener("keydown", keyEvent);
|
||||
editor.value?.destroy();
|
||||
});
|
||||
|
||||
this.editor.focus();
|
||||
},
|
||||
methods: {
|
||||
keyEvent(event) {
|
||||
if (event.code === "Escape") {
|
||||
this.close();
|
||||
}
|
||||
const keyEvent = (event: KeyboardEvent) => {
|
||||
if (event.code === "Escape") {
|
||||
close();
|
||||
}
|
||||
|
||||
if (!event.ctrlKey && !event.metaKey) {
|
||||
return;
|
||||
}
|
||||
if (!event.ctrlKey && !event.metaKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (String.fromCharCode(event.which).toLowerCase() !== "s") {
|
||||
return;
|
||||
}
|
||||
if (event.key !== "s") {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
this.save();
|
||||
},
|
||||
async save() {
|
||||
const button = "save";
|
||||
buttons.loading("save");
|
||||
event.preventDefault();
|
||||
save();
|
||||
};
|
||||
|
||||
try {
|
||||
await api.put(this.$route.path, this.editor.getValue());
|
||||
this.editor.session.getUndoManager().markClean();
|
||||
buttons.success(button);
|
||||
} catch (e) {
|
||||
buttons.done(button);
|
||||
this.$showError(e);
|
||||
}
|
||||
},
|
||||
close() {
|
||||
if (!this.editor.session.getUndoManager().isClean()) {
|
||||
this.$store.commit("showHover", "discardEditorChanges");
|
||||
return;
|
||||
}
|
||||
const save = async () => {
|
||||
const button = "save";
|
||||
buttons.loading("save");
|
||||
|
||||
this.$store.commit("updateRequest", {});
|
||||
try {
|
||||
await api.put(route.path, editor.value?.getValue());
|
||||
editor.value?.session.getUndoManager().markClean();
|
||||
buttons.success(button);
|
||||
} catch (e: any) {
|
||||
buttons.done(button);
|
||||
$showError(e);
|
||||
}
|
||||
};
|
||||
const close = () => {
|
||||
if (!editor.value?.session.getUndoManager().isClean()) {
|
||||
layoutStore.showHover("discardEditorChanges");
|
||||
return;
|
||||
}
|
||||
|
||||
let uri = url.removeLastDir(this.$route.path) + "/";
|
||||
this.$router.push({ path: uri });
|
||||
},
|
||||
},
|
||||
fileStore.updateRequest(null);
|
||||
|
||||
let uri = url.removeLastDir(route.path) + "/";
|
||||
router.push({ path: uri });
|
||||
};
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user