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:
@@ -4,55 +4,56 @@
|
||||
<title />
|
||||
|
||||
<action
|
||||
v-if="selectedCount"
|
||||
v-if="fileStore.selectedCount"
|
||||
icon="file_download"
|
||||
:label="$t('buttons.download')"
|
||||
:label="t('buttons.download')"
|
||||
@action="download"
|
||||
:counter="selectedCount"
|
||||
:counter="fileStore.selectedCount"
|
||||
/>
|
||||
<button
|
||||
v-if="isSingleFile()"
|
||||
class="action copy-clipboard"
|
||||
:data-clipboard-text="linkSelected()"
|
||||
:aria-label="$t('buttons.copyDownloadLinkToClipboard')"
|
||||
:title="$t('buttons.copyDownloadLinkToClipboard')"
|
||||
:aria-label="t('buttons.copyDownloadLinkToClipboard')"
|
||||
:data-title="t('buttons.copyDownloadLinkToClipboard')"
|
||||
@click="copyToClipboard(linkSelected())"
|
||||
>
|
||||
<i class="material-icons">content_paste</i>
|
||||
</button>
|
||||
<action
|
||||
icon="check_circle"
|
||||
:label="$t('buttons.selectMultiple')"
|
||||
:label="t('buttons.selectMultiple')"
|
||||
@action="toggleMultipleSelection"
|
||||
/>
|
||||
</header-bar>
|
||||
|
||||
<breadcrumbs :base="'/share/' + hash" />
|
||||
|
||||
<div v-if="loading">
|
||||
<h2 class="message delayed" style="padding-top: 3em !important;">
|
||||
<div v-if="layoutStore.loading">
|
||||
<h2 class="message delayed" style="padding-top: 3em !important">
|
||||
<div class="spinner">
|
||||
<div class="bounce1"></div>
|
||||
<div class="bounce2"></div>
|
||||
<div class="bounce3"></div>
|
||||
</div>
|
||||
<span>{{ $t("files.loading") }}</span>
|
||||
<span>{{ t("files.loading") }}</span>
|
||||
</h2>
|
||||
</div>
|
||||
<div v-else-if="error">
|
||||
<div v-if="error.status === 401">
|
||||
<div class="card floating" id="password">
|
||||
<div class="card floating" id="password" style="z-index: 9999999">
|
||||
<div v-if="attemptedPasswordLogin" class="share__wrong__password">
|
||||
{{ $t("login.wrongCredentials") }}
|
||||
{{ t("login.wrongCredentials") }}
|
||||
</div>
|
||||
<div class="card-title">
|
||||
<h2>{{ $t("login.password") }}</h2>
|
||||
<h2>{{ t("login.password") }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
<input
|
||||
v-focus
|
||||
class="input input--block"
|
||||
type="password"
|
||||
:placeholder="$t('login.password')"
|
||||
:placeholder="t('login.password')"
|
||||
v-model="password"
|
||||
@keyup.enter="fetchData"
|
||||
/>
|
||||
@@ -61,49 +62,60 @@
|
||||
<button
|
||||
class="button button--flat"
|
||||
@click="fetchData"
|
||||
:aria-label="$t('buttons.submit')"
|
||||
:title="$t('buttons.submit')"
|
||||
:aria-label="t('buttons.submit')"
|
||||
:data-title="t('buttons.submit')"
|
||||
>
|
||||
{{ $t("buttons.submit") }}
|
||||
{{ t("buttons.submit") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overlay" />
|
||||
</div>
|
||||
<errors v-else :errorCode="error.status" />
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-else-if="req !== null">
|
||||
<div class="share">
|
||||
<div class="share__box share__box__info"
|
||||
<div
|
||||
class="share__box share__box__info"
|
||||
style="
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top:-20.6em;
|
||||
z-index:999;"
|
||||
top: -20.6em;
|
||||
z-index: 999;
|
||||
"
|
||||
>
|
||||
<div class="share__box__header" style="height:3em">
|
||||
<div class="share__box__header" style="height: 3em">
|
||||
{{
|
||||
req.isDir
|
||||
? $t("download.downloadFolder")
|
||||
: $t("download.downloadFile")
|
||||
? t("download.downloadFolder")
|
||||
: t("download.downloadFile")
|
||||
}}
|
||||
</div>
|
||||
<div v-if="!this.req.isDir" class="share__box__element share__box__center share__box__icon">
|
||||
<div
|
||||
v-if="!req.isDir"
|
||||
class="share__box__element share__box__center share__box__icon"
|
||||
>
|
||||
<i class="material-icons">{{ icon }}</i>
|
||||
</div>
|
||||
<div class="share__box__element" style="height:3em">
|
||||
<div class="share__box__element" style="height: 3em">
|
||||
<strong>{{ $t("prompts.displayName") }}</strong> {{ req.name }}
|
||||
</div>
|
||||
<div v-if="!this.req.isDir" class="share__box__element" :title="modTime">
|
||||
<div v-if="!req.isDir" class="share__box__element" :title="modTime">
|
||||
<strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }}
|
||||
</div>
|
||||
<div class="share__box__element" style="height:3em">
|
||||
<div class="share__box__element" style="height: 3em">
|
||||
<strong>{{ $t("prompts.size") }}:</strong> {{ humanSize }}
|
||||
</div>
|
||||
<div class="share__box__element share__box__center">
|
||||
<a target="_blank" :href="link" class="button button--flat" style="height:4em">
|
||||
<a
|
||||
target="_blank"
|
||||
:href="link"
|
||||
class="button button--flat"
|
||||
style="height: 4em"
|
||||
>
|
||||
<div>
|
||||
<i class="material-icons">file_download</i
|
||||
>{{ $t("buttons.download") }}
|
||||
>{{ t("buttons.download") }}
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
@@ -114,85 +126,123 @@
|
||||
>
|
||||
<div>
|
||||
<i class="material-icons">open_in_new</i
|
||||
>{{ $t("buttons.openFile") }}
|
||||
>{{ t("buttons.openFile") }}
|
||||
</div>
|
||||
</a>
|
||||
<qrcode-vue v-if="this.req.isDir" :value="fullLink" size="100" level="M"></qrcode-vue>
|
||||
<qrcode-vue
|
||||
v-if="req.isDir"
|
||||
:value="link"
|
||||
:size="100"
|
||||
level="M"
|
||||
></qrcode-vue>
|
||||
</div>
|
||||
<div v-if="!this.req.isDir" class="share__box__element share__box__center">
|
||||
<qrcode-vue :value="link" size="200" level="M"></qrcode-vue>
|
||||
<div v-if="!req.isDir" class="share__box__element share__box__center">
|
||||
<qrcode-vue :value="link" :size="200" level="M"></qrcode-vue>
|
||||
</div>
|
||||
<div v-if="this.req.isDir" class="share__box__element share__box__header" style="height:3em">
|
||||
<div
|
||||
v-if="req.isDir"
|
||||
class="share__box__element share__box__header"
|
||||
style="height: 3em"
|
||||
>
|
||||
{{ $t("sidebar.preview") }}
|
||||
</div>
|
||||
<div
|
||||
v-if="this.req.isDir"
|
||||
class="share__box__element share__box__center share__box__icon"
|
||||
style="padding:0em !important;height:12em !important;"
|
||||
>
|
||||
<a
|
||||
v-if="req.isDir"
|
||||
class="share__box__element share__box__center share__box__icon"
|
||||
style="padding: 0em !important; height: 12em !important"
|
||||
>
|
||||
<a
|
||||
target="_blank"
|
||||
:href="raw"
|
||||
class="button button--flat"
|
||||
v-if= "!this.$store.state.multiple &&
|
||||
selectedCount === 1 &&
|
||||
req.items[this.selected[0]].type === 'image'"
|
||||
style="height: 12em; padding:0; margin:0;"
|
||||
v-if="
|
||||
!fileStore.multiple &&
|
||||
fileStore.selectedCount === 1 &&
|
||||
req.items[fileStore.selected[0]].type === 'image'
|
||||
"
|
||||
style="height: 12em; padding: 0; margin: 0"
|
||||
>
|
||||
<img
|
||||
style="height: 12em;"
|
||||
:src="raw"
|
||||
>
|
||||
<img style="height: 12em" :src="raw" />
|
||||
</a>
|
||||
<div
|
||||
v-else-if= "
|
||||
!this.$store.state.multiple &&
|
||||
selectedCount === 1 &&
|
||||
req.items[this.selected[0]].type === 'audio'"
|
||||
style="height: 12em; paddingTop:1em; margin:0;"
|
||||
>
|
||||
<button @click="play" v-if="!this.tag" style="fontSize:6em !important; border:0px;outline:none; background: white;" class="material-icons">play_circle_filled</button>
|
||||
<button @click="play" v-if="this.tag" style="fontSize:6em !important; border:0px;outline:none; background: white;" class="material-icons">pause_circle_filled</button>
|
||||
<audio id="myaudio"
|
||||
:src="raw"
|
||||
controls="controls"
|
||||
v-else-if="
|
||||
fileStore.multiple &&
|
||||
fileStore.selectedCount === 1 &&
|
||||
req.items[fileStore.selected[0]].type === 'audio'
|
||||
"
|
||||
style="height: 12em; padding-top: 1em; margin: 0"
|
||||
>
|
||||
<button
|
||||
@click="play"
|
||||
v-if="!tag"
|
||||
style="
|
||||
font-size: 6em !important;
|
||||
border: 0px;
|
||||
outline: none;
|
||||
background: white;
|
||||
"
|
||||
class="material-icons"
|
||||
>
|
||||
play_circle_filled
|
||||
</button>
|
||||
<button
|
||||
@click="play"
|
||||
v-if="tag"
|
||||
style="
|
||||
font-size: 6em !important;
|
||||
border: 0px;
|
||||
outline: none;
|
||||
background: white;
|
||||
"
|
||||
class="material-icons"
|
||||
>
|
||||
pause_circle_filled
|
||||
</button>
|
||||
<audio
|
||||
id="myaudio"
|
||||
ref="audio"
|
||||
:src="raw"
|
||||
controls
|
||||
:autoplay="tag"
|
||||
>
|
||||
</audio>
|
||||
></audio>
|
||||
</div>
|
||||
<video
|
||||
v-else-if= "
|
||||
!this.$store.state.multiple &&
|
||||
selectedCount === 1 &&
|
||||
req.items[this.selected[0]].type === 'video'"
|
||||
style="height: 12em; padding:0; margin:0;"
|
||||
:src="raw"
|
||||
controls="controls"
|
||||
>
|
||||
Sorry, your browser doesn't support embedded videos, but don't worry,
|
||||
you can <a :href="raw">download it</a>
|
||||
and watch it with your favorite video player!
|
||||
</video>
|
||||
<i
|
||||
v-else-if= "
|
||||
!this.$store.state.multiple &&
|
||||
selectedCount === 1 &&
|
||||
req.items[this.selected[0]].isDir"
|
||||
class="material-icons">folder
|
||||
<video
|
||||
v-else-if="
|
||||
!fileStore.multiple &&
|
||||
fileStore.selectedCount === 1 &&
|
||||
req.items[fileStore.selected[0]].type === 'video'
|
||||
"
|
||||
style="height: 12em; padding: 0; margin: 0"
|
||||
:src="raw"
|
||||
controls
|
||||
>
|
||||
Sorry, your browser doesn't support embedded videos, but don't
|
||||
worry, you can <a :href="raw">download it</a>
|
||||
and watch it with your favorite video player!
|
||||
</video>
|
||||
<i
|
||||
v-else-if="
|
||||
!fileStore.multiple &&
|
||||
fileStore.selectedCount === 1 &&
|
||||
req.items[fileStore.selected[0]].isDir
|
||||
"
|
||||
class="material-icons"
|
||||
>folder
|
||||
</i>
|
||||
<i v-else class="material-icons">call_to_action</i>
|
||||
</div>
|
||||
</div>
|
||||
<div id="shareList"
|
||||
<div
|
||||
id="shareList"
|
||||
v-if="req.isDir && req.items.length > 0"
|
||||
class="share__box share__box__items"
|
||||
>
|
||||
<div class="share__box__header" v-if="req.isDir">
|
||||
{{ $t("files.files") }}
|
||||
{{ t("files.files") }}
|
||||
</div>
|
||||
<div id="listing" class="list file-icons">
|
||||
<item
|
||||
v-for="item in req.items.slice(0, this.showLimit)"
|
||||
v-for="item in req.items.slice(0, showLimit)"
|
||||
:key="base64(item.name)"
|
||||
v-bind:index="item.index"
|
||||
v-bind:name="item.name"
|
||||
@@ -215,16 +265,16 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
:class="{ active: $store.state.multiple }"
|
||||
:class="{ active: fileStore.multiple }"
|
||||
id="multiple-selection"
|
||||
>
|
||||
<p>{{ $t("files.multipleSelectionEnabled") }}</p>
|
||||
<p>{{ t("files.multipleSelectionEnabled") }}</p>
|
||||
<div
|
||||
@click="$store.commit('multiple', false)"
|
||||
@click="() => (fileStore.multiple = false)"
|
||||
tabindex="0"
|
||||
role="button"
|
||||
:title="$t('files.clear')"
|
||||
:aria-label="$t('files.clear')"
|
||||
:data-title="t('buttons.clear')"
|
||||
:aria-label="t('buttons.clear')"
|
||||
class="action"
|
||||
>
|
||||
<i class="material-icons">clear</i>
|
||||
@@ -238,7 +288,7 @@
|
||||
>
|
||||
<h2 class="message">
|
||||
<i class="material-icons">sentiment_dissatisfied</i>
|
||||
<span>{{ $t("files.lonely") }}</span>
|
||||
<span>{{ t("files.lonely") }}</span>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
@@ -246,11 +296,11 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations, mapGetters } from "vuex";
|
||||
<script setup lang="ts">
|
||||
import { pub as api } from "@/api";
|
||||
import { filesize } from "@/utils";
|
||||
import moment from "moment/min/moment-with-locales";
|
||||
import dayjs from "dayjs";
|
||||
import { Base64 } from "js-base64";
|
||||
|
||||
import HeaderBar from "@/components/header/HeaderBar.vue";
|
||||
import Action from "@/components/header/Action.vue";
|
||||
@@ -258,198 +308,223 @@ import Breadcrumbs from "@/components/Breadcrumbs.vue";
|
||||
import Errors from "@/views/Errors.vue";
|
||||
import QrcodeVue from "qrcode.vue";
|
||||
import Item from "@/components/files/ListingItem.vue";
|
||||
import Clipboard from "clipboard";
|
||||
import { useFileStore } from "@/stores/file";
|
||||
import { useLayoutStore } from "@/stores/layout";
|
||||
import { computed, inject, onMounted, onBeforeUnmount, ref, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { StatusError } from "@/api/utils";
|
||||
import { copy } from "@/utils/clipboard";
|
||||
|
||||
export default {
|
||||
name: "share",
|
||||
components: {
|
||||
HeaderBar,
|
||||
Action,
|
||||
Breadcrumbs,
|
||||
Item,
|
||||
QrcodeVue,
|
||||
Errors,
|
||||
},
|
||||
data: () => ({
|
||||
error: null,
|
||||
showLimit: 100,
|
||||
password: "",
|
||||
attemptedPasswordLogin: false,
|
||||
hash: null,
|
||||
token: null,
|
||||
clip: null,
|
||||
tag: false,
|
||||
}),
|
||||
watch: {
|
||||
$route: function () {
|
||||
this.showLimit = 100;
|
||||
const error = ref<StatusError | null>(null);
|
||||
const showLimit = ref<number>(100);
|
||||
const password = ref<string>("");
|
||||
const attemptedPasswordLogin = ref<boolean>(false);
|
||||
const hash = ref<string>("");
|
||||
const token = ref<string>("");
|
||||
const audio = ref<HTMLAudioElement>();
|
||||
const tag = ref<boolean>(false);
|
||||
|
||||
this.fetchData();
|
||||
},
|
||||
},
|
||||
created: async function () {
|
||||
const hash = this.$route.params.pathMatch.split("/")[0];
|
||||
this.hash = hash;
|
||||
await this.fetchData();
|
||||
},
|
||||
mounted() {
|
||||
window.addEventListener("keydown", this.keyEvent);
|
||||
this.clip = new Clipboard(".copy-clipboard");
|
||||
this.clip.on("success", () => {
|
||||
this.$showSuccess(this.$t("success.linkCopied"));
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener("keydown", this.keyEvent);
|
||||
this.clip.destroy();
|
||||
},
|
||||
computed: {
|
||||
...mapState(["req", "loading", "multiple", "selected"]),
|
||||
...mapGetters(["selectedCount"]),
|
||||
icon: function () {
|
||||
if (this.req.isDir) return "folder";
|
||||
if (this.req.type === "image") return "insert_photo";
|
||||
if (this.req.type === "audio") return "volume_up";
|
||||
if (this.req.type === "video") return "movie";
|
||||
return "insert_drive_file";
|
||||
},
|
||||
link: function () {
|
||||
return api.getDownloadURL(this.req);
|
||||
},
|
||||
raw: function () {
|
||||
return this.req.items[this.selected[0]].url.replace(/share/, 'api/public/dl')+'?token='+this.token;
|
||||
},
|
||||
inlineLink: function () {
|
||||
return api.getDownloadURL(this.req, true);
|
||||
},
|
||||
humanSize: function () {
|
||||
if (this.req.isDir) {
|
||||
return this.req.items.length;
|
||||
}
|
||||
const $showSuccess = inject<IToastSuccess>("$showSuccess")!;
|
||||
|
||||
return filesize(this.req.size);
|
||||
},
|
||||
humanTime: function () {
|
||||
return moment(this.req.modified).fromNow();
|
||||
},
|
||||
modTime: function () {
|
||||
return new Date(Date.parse(this.req.modified)).toLocaleString();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(["resetSelected", "updateRequest", "setLoading"]),
|
||||
base64: function (name) {
|
||||
return window.btoa(unescape(encodeURIComponent(name)));
|
||||
},
|
||||
play() {
|
||||
var audio = document.getElementById('myaudio');
|
||||
if(this.tag){
|
||||
audio.pause();
|
||||
this.tag = false;
|
||||
} else {
|
||||
audio.play();
|
||||
this.tag = true;
|
||||
}
|
||||
},
|
||||
fetchData: async function () {
|
||||
// Reset view information.
|
||||
this.$store.commit("setReload", false);
|
||||
this.$store.commit("resetSelected");
|
||||
this.$store.commit("multiple", false);
|
||||
this.$store.commit("closeHovers");
|
||||
const { t } = useI18n({});
|
||||
|
||||
// Set loading to true and reset the error.
|
||||
this.setLoading(true);
|
||||
this.error = null;
|
||||
const route = useRoute();
|
||||
const fileStore = useFileStore();
|
||||
const layoutStore = useLayoutStore();
|
||||
|
||||
if (this.password !== "") {
|
||||
this.attemptedPasswordLogin = true;
|
||||
}
|
||||
watch(route, () => {
|
||||
showLimit.value = 100;
|
||||
fetchData();
|
||||
});
|
||||
|
||||
let url = this.$route.path;
|
||||
if (url === "") url = "/";
|
||||
if (url[0] !== "/") url = "/" + url;
|
||||
const req = computed(() => fileStore.req);
|
||||
|
||||
try {
|
||||
let file = await api.fetch(url, this.password);
|
||||
file.hash = this.hash;
|
||||
// Define computes
|
||||
|
||||
this.token = file.token || "";
|
||||
const icon = computed(() => {
|
||||
if (req.value === null) return "insert_drive_file";
|
||||
if (req.value.isDir) return "folder";
|
||||
if (req.value.type === "image") return "insert_photo";
|
||||
if (req.value.type === "audio") return "volume_up";
|
||||
if (req.value.type === "video") return "movie";
|
||||
return "insert_drive_file";
|
||||
});
|
||||
|
||||
this.updateRequest(file);
|
||||
document.title = `${file.name} - ${document.title}`;
|
||||
} catch (e) {
|
||||
this.error = e;
|
||||
} finally {
|
||||
this.setLoading(false);
|
||||
}
|
||||
},
|
||||
keyEvent(event) {
|
||||
// Esc!
|
||||
if (event.keyCode === 27) {
|
||||
// If we're on a listing, unselect all
|
||||
// files and folders.
|
||||
if (this.selectedCount > 0) {
|
||||
this.resetSelected();
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleMultipleSelection() {
|
||||
this.$store.commit("multiple", !this.multiple);
|
||||
},
|
||||
isSingleFile: function () {
|
||||
return (
|
||||
this.selectedCount === 1 && !this.req.items[this.selected[0]].isDir
|
||||
);
|
||||
},
|
||||
download() {
|
||||
if (this.isSingleFile()) {
|
||||
api.download(
|
||||
null,
|
||||
this.hash,
|
||||
this.token,
|
||||
this.req.items[this.selected[0]].path
|
||||
);
|
||||
return;
|
||||
}
|
||||
const link = computed(() => (req.value ? api.getDownloadURL(req.value) : ""));
|
||||
const raw = computed(() => {
|
||||
return req.value
|
||||
? req.value.items[fileStore.selected[0]].url.replace(
|
||||
/share/,
|
||||
"api/public/dl"
|
||||
) +
|
||||
"?token=" +
|
||||
token.value
|
||||
: "";
|
||||
});
|
||||
const inlineLink = computed(() =>
|
||||
req.value ? api.getDownloadURL(req.value, true) : ""
|
||||
);
|
||||
const humanSize = computed(() => {
|
||||
if (req.value) {
|
||||
return req.value.isDir
|
||||
? req.value.items.length
|
||||
: filesize(req.value.size ?? 0);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
const humanTime = computed(() => dayjs(req.value?.modified).fromNow());
|
||||
const modTime = computed(() =>
|
||||
req.value
|
||||
? new Date(Date.parse(req.value.modified)).toLocaleString()
|
||||
: new Date().toLocaleString()
|
||||
);
|
||||
|
||||
this.$store.commit("showHover", {
|
||||
prompt: "download",
|
||||
confirm: (format) => {
|
||||
this.$store.commit("closeHovers");
|
||||
|
||||
let files = [];
|
||||
|
||||
for (let i of this.selected) {
|
||||
files.push(this.req.items[i].path);
|
||||
}
|
||||
|
||||
api.download(format, this.hash, this.token, ...files);
|
||||
},
|
||||
});
|
||||
},
|
||||
linkSelected: function () {
|
||||
return this.isSingleFile()
|
||||
? api.getDownloadURL({
|
||||
hash: this.hash,
|
||||
path: this.req.items[this.selected[0]].path,
|
||||
})
|
||||
: "";
|
||||
},
|
||||
},
|
||||
// Functions
|
||||
const base64 = (name: any) => Base64.encodeURI(name);
|
||||
const play = () => {
|
||||
if (tag.value) {
|
||||
audio.value?.pause();
|
||||
tag.value = false;
|
||||
} else {
|
||||
audio.value?.play();
|
||||
tag.value = true;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
#listing.list{
|
||||
height: auto;
|
||||
const fetchData = async () => {
|
||||
fileStore.reload = false;
|
||||
fileStore.selected = [];
|
||||
fileStore.multiple = false;
|
||||
layoutStore.closeHovers();
|
||||
|
||||
// Set loading to true and reset the error.
|
||||
layoutStore.loading = true;
|
||||
error.value = null;
|
||||
if (password.value !== "") {
|
||||
attemptedPasswordLogin.value = true;
|
||||
}
|
||||
#shareList{
|
||||
overflow-y: scroll;
|
||||
|
||||
let url = route.path;
|
||||
if (url === "") url = "/";
|
||||
if (url[0] !== "/") url = "/" + url;
|
||||
|
||||
try {
|
||||
const file = await api.fetch(url, password.value);
|
||||
file.hash = hash.value;
|
||||
|
||||
token.value = file.token || "";
|
||||
|
||||
fileStore.updateRequest(file);
|
||||
document.title = `${file.name} - ${document.title}`;
|
||||
} catch (err) {
|
||||
if (err instanceof Error) {
|
||||
error.value = err;
|
||||
}
|
||||
} finally {
|
||||
layoutStore.loading = false;
|
||||
}
|
||||
@media (min-width: 930px) {
|
||||
#shareList{
|
||||
height: calc(100vh - 9.8em);
|
||||
overflow-y: auto;
|
||||
};
|
||||
|
||||
const keyEvent = (event: KeyboardEvent) => {
|
||||
if (event.key === "Escape") {
|
||||
// If we're on a listing, unselect all
|
||||
// files and folders.
|
||||
if (fileStore.selectedCount > 0) {
|
||||
fileStore.selected = [];
|
||||
}
|
||||
}
|
||||
</style>
|
||||
};
|
||||
|
||||
const toggleMultipleSelection = () => {
|
||||
fileStore.toggleMultiple();
|
||||
};
|
||||
|
||||
const isSingleFile = () =>
|
||||
fileStore.selectedCount === 1 &&
|
||||
!req.value?.items[fileStore.selected[0]].isDir;
|
||||
|
||||
const download = () => {
|
||||
if (!req.value) return false;
|
||||
|
||||
if (isSingleFile()) {
|
||||
api.download(
|
||||
null,
|
||||
hash.value,
|
||||
token.value,
|
||||
req.value.items[fileStore.selected[0]].path
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
layoutStore.showHover({
|
||||
prompt: "download",
|
||||
confirm: (format: DownloadFormat) => {
|
||||
if (req.value === null) return false;
|
||||
layoutStore.closeHovers();
|
||||
|
||||
let files: string[] = [];
|
||||
|
||||
for (let i of fileStore.selected) {
|
||||
files.push(req.value.items[i].path);
|
||||
}
|
||||
|
||||
api.download(format, hash.value, token.value, ...files);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const linkSelected = () => {
|
||||
return isSingleFile() && req.value
|
||||
? api.getDownloadURL({
|
||||
...req.value,
|
||||
hash: hash.value,
|
||||
path: req.value.items[fileStore.selected[0]].path,
|
||||
})
|
||||
: "";
|
||||
};
|
||||
|
||||
const copyToClipboard = (text: string) => {
|
||||
copy(text).then(
|
||||
() => {
|
||||
// clipboard successfully set
|
||||
$showSuccess(t("success.linkCopied"));
|
||||
},
|
||||
() => {
|
||||
// clipboard write failed
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
// Created
|
||||
hash.value = route.params.path[0];
|
||||
window.addEventListener("keydown", keyEvent);
|
||||
await fetchData();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
// Destroyed
|
||||
window.removeEventListener("keydown", keyEvent);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#listing.list {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#shareList {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
@media (min-width: 930px) {
|
||||
#shareList {
|
||||
height: calc(100vh - 9.8em);
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user