filebrowser/frontend/src/components/Search.vue

310 lines
9.1 KiB
Vue
Raw Normal View History

2018-02-01 12:17:04 +00:00
<template>
2021-03-21 11:51:58 +00:00
<div id="search" @click="open" v-bind:class="{ active, ongoing }">
2018-02-01 12:17:04 +00:00
<div id="input">
2023-07-30 18:19:03 +00:00
<button
v-if="active"
class="action"
@click="close"
:aria-label="$t('buttons.close')"
:title="$t('buttons.close')"
>
<i class="material-icons">close</i>
2018-02-01 12:17:04 +00:00
</button>
<i v-else class="material-icons">search</i>
2023-07-30 18:19:03 +00:00
<input
type="text"
@keyup.exact="keyup"
@input="submit"
ref="input"
:autofocus="active"
v-model.trim="value"
:aria-label="$t('search.search')"
:placeholder="$t('search.search')"
/>
2018-02-01 12:17:04 +00:00
</div>
2023-07-30 18:19:03 +00:00
<div v-if="isMobile && active" id="result" :class="{ hidden: !active }" ref="result">
2023-07-13 02:23:29 +00:00
<div id="result-list">
2023-07-30 18:19:03 +00:00
<div class="button" style="width: 100%">
Search Context: {{ getContext(this.$route.path) }}
</div>
<ul v-show="results.length > 0">
<li
v-for="(s, k) in results"
:key="k"
@click.stop.prevent="navigateTo(s.url)"
style="cursor: pointer"
>
<router-link to="#" event="">
<i v-if="s.dir" class="material-icons folder-icons"> folder </i>
<i v-else-if="s.audio" class="material-icons audio-icons"> volume_up </i>
<i v-else-if="s.image" class="material-icons image-icons"> photo </i>
<i v-else-if="s.video" class="material-icons video-icons"> movie </i>
<i v-else-if="s.archive" class="material-icons archive-icons"> archive </i>
<i v-else class="material-icons file-icons"> insert_drive_file </i>
<span class="text-container">
{{ basePath(s.path) }}<b>{{ baseName(s.path) }}</b>
</span>
</router-link>
</li>
</ul>
<template v-if="isEmpty">
2018-02-01 12:17:04 +00:00
<p>{{ text }}</p>
<template v-if="value.length === 0">
<div class="boxes">
2021-03-21 11:51:58 +00:00
<h3>{{ $t("search.types") }}</h3>
2018-02-01 12:17:04 +00:00
<div>
2023-07-30 18:19:03 +00:00
<div
tabindex="0"
v-for="(v, k) in boxes"
:key="k"
role="button"
@click="init('type:' + k)"
:aria-label="v.label"
>
2021-03-21 11:51:58 +00:00
<i class="material-icons">{{ v.icon }}</i>
<p>{{ v.label }}</p>
2018-02-01 12:17:04 +00:00
</div>
</div>
</div>
</template>
</template>
2023-07-30 18:19:03 +00:00
</div>
</div>
<div v-if="!isMobile && active" id="result-desktop" ref="result">
<div id="result-list">
<div class="button" style="width: 100%">
Search Context: {{ getContext(this.$route.path) }}
</div>
<ul v-show="results.length > 0">
2023-07-30 18:19:03 +00:00
<li
v-for="(s, k) in results"
:key="k"
@click.stop.prevent="navigateTo(s.url)"
style="cursor: pointer"
>
<router-link to="#" event="">
<i v-if="s.dir" class="material-icons folder-icons"> folder </i>
<i v-else-if="s.audio" class="material-icons audio-icons"> volume_up </i>
<i v-else-if="s.image" class="material-icons image-icons"> photo </i>
<i v-else-if="s.video" class="material-icons video-icons"> movie </i>
<i v-else-if="s.archive" class="material-icons archive-icons"> archive </i>
<i v-else class="material-icons file-icons"> insert_drive_file </i>
<span class="text-container">
{{ basePath(s.path) }}<b>{{ baseName(s.path) }}</b>
</span>
2018-02-01 12:17:04 +00:00
</router-link>
</li>
</ul>
2023-07-30 18:19:03 +00:00
<template >
<p v-show="isEmpty" >{{ text }}</p>
<template >
<div v-show="results.length == 0" class="boxes">
<ButtonGroup
:buttons="folderSelect"
@button-clicked="init"
@remove-button-clicked="removeInit"
/>
<ButtonGroup
:buttons="typeSelect"
@button-clicked="init"
@remove-button-clicked="removeInit"
/>
<ButtonGroup
:buttons="sizeSelect"
@button-clicked="init"
@remove-button-clicked="removeInit"
/>
</div>
</template>
</template>
2018-02-01 12:17:04 +00:00
</div>
</div>
</div>
</template>
<script>
2023-07-30 18:19:03 +00:00
import ButtonGroup from "./ButtonGroup.vue";
2021-03-21 11:51:58 +00:00
import { mapState, mapGetters, mapMutations } from "vuex";
import { search } from "@/api";
var boxes = {
folder: { label: "folders", icon: "folder" },
file: { label: "files", icon: "insert_drive_file" },
archive: { label: "archives", icon: "archive" },
image: { label: "images", icon: "photo" },
audio: { label: "audio files", icon: "volume_up" },
video: { label: "videos", icon: "movie" },
doc: { label: "documents", icon: "picture_as_pdf" },
"larger=100": { label: "larger than 100MB", icon: "arrow_forward_ios" },
"smaller=100": { label: "smaller than 100MB ", icon: "arrow_back_ios" },
2021-03-21 11:51:58 +00:00
};
2018-02-01 12:17:04 +00:00
export default {
2023-07-30 18:19:03 +00:00
components: {
ButtonGroup,
},
name: "search",
2021-03-21 11:51:58 +00:00
data: function () {
2018-02-01 12:17:04 +00:00
return {
2023-07-30 18:19:03 +00:00
folderSelect: [
{ label: "Only Folders", value: "type:folder" },
{ label: "Only Files", value: "type:file" },
],
typeSelect: [
{ label: "Archives", value: "type:archive" },
{ label: "Audio Files", value: "type:audio" },
{ label: "Videos", value: "type:video" },
{ label: "Documents", value: "type:docs" },
],
sizeSelect: [
{ label: "Smaller than 100MB", value: "type:smaller=100" },
{ label: "Larger than 100MB", value: "type:larger=100" },
],
value: "",
2023-07-30 18:19:03 +00:00
width: window.innerWidth,
2018-02-01 12:17:04 +00:00
active: false,
ongoing: false,
results: [],
reload: false,
2021-03-21 11:51:58 +00:00
scrollable: null,
};
2018-02-01 12:17:04 +00:00
},
watch: {
2021-03-21 11:51:58 +00:00
show(val, old) {
this.active = val === "search";
if (old === "search" && !this.active) {
2018-02-01 12:17:04 +00:00
if (this.reload) {
2021-03-21 11:51:58 +00:00
this.setReload(true);
2018-02-01 12:17:04 +00:00
}
2021-03-21 11:51:58 +00:00
document.body.style.overflow = "auto";
this.reset();
this.value = "";
this.active = false;
this.$refs.input.blur();
} else if (this.active) {
2021-03-21 11:51:58 +00:00
this.reload = false;
this.$refs.input.focus();
document.body.style.overflow = "hidden";
2018-02-01 12:17:04 +00:00
}
},
2021-03-21 11:51:58 +00:00
value() {
if (this.results.length) {
2021-03-21 11:51:58 +00:00
this.reset();
}
2021-03-21 11:51:58 +00:00
},
2018-02-01 12:17:04 +00:00
},
computed: {
...mapState(["user", "show"]),
...mapGetters(["isListing"]),
boxes() {
2021-03-21 11:51:58 +00:00
return boxes;
},
isEmpty() {
2021-03-21 11:51:58 +00:00
return this.results.length === 0;
2018-02-01 12:17:04 +00:00
},
text() {
2018-02-01 12:17:04 +00:00
if (this.ongoing) {
2021-03-21 11:51:58 +00:00
return "";
2018-02-01 12:17:04 +00:00
}
2021-03-21 11:51:58 +00:00
return this.value === ""
? this.$t("search.typeToSearch")
: this.$t("search.pressToSearch");
},
2023-07-30 18:19:03 +00:00
isMobile() {
return this.width <= 800;
},
2018-02-01 12:17:04 +00:00
},
mounted() {
2023-07-30 18:19:03 +00:00
window.addEventListener("resize", this.handleResize);
this.handleResize(); // Call this once to set the initial width
2018-02-01 12:17:04 +00:00
},
methods: {
2023-07-30 18:19:03 +00:00
handleResize() {
this.width = window.innerWidth;
},
async navigateTo(url) {
this.closeHovers();
await this.$nextTick();
setTimeout(() => this.$router.push(url), 0);
},
getContext(url) {
2023-07-30 18:19:03 +00:00
url = url.slice(1);
let path = "./" + url.substring(url.indexOf("/") + 1);
return path.replace(/\/+$/, "") + "/";
},
basePath(str) {
2023-07-30 18:19:03 +00:00
if (!str.includes("/")) {
return "";
}
2023-07-30 18:19:03 +00:00
let parts = str.replace(/\/$/, "").split("/");
parts.pop();
return parts.join("/") + "/";
},
baseName(str) {
2023-07-30 18:19:03 +00:00
let parts = str.split("/");
if (str.endsWith("/")) {
2023-07-30 18:19:03 +00:00
return parts[parts.length - 2] + "/";
} else {
2023-07-30 18:19:03 +00:00
return parts[parts.length - 1];
}
},
...mapMutations(["showHover", "closeHovers", "setReload"]),
open() {
2021-03-21 11:51:58 +00:00
this.showHover("search");
2018-02-01 12:17:04 +00:00
},
close(event) {
2021-03-21 11:51:58 +00:00
event.stopPropagation();
this.closeHovers();
2018-02-01 12:17:04 +00:00
},
keyup(event) {
if (event.keyCode === 27) {
2021-03-21 11:51:58 +00:00
this.close(event);
return;
2018-02-01 12:17:04 +00:00
}
2023-06-16 17:29:43 +00:00
this.results.length === 0;
2018-02-01 12:17:04 +00:00
},
2021-03-21 11:51:58 +00:00
init(string) {
2023-07-30 18:19:03 +00:00
if (string == null || string == ""){
return false
}
this.value = `${string} ${this.value}`;
if (this.isMobile){
this.$refs.input.focus();
}
},
removeInit(string) {
if (string == null || string == ""){
return false
}
this.value = this.value.replace(string, "");
if (this.isMobile){
this.$refs.input.focus();
}
2018-02-01 12:17:04 +00:00
},
2021-03-21 11:51:58 +00:00
reset() {
this.ongoing = false;
this.resultsCount = 50;
this.results = [];
2018-02-01 12:17:04 +00:00
},
async submit(event) {
2021-03-21 11:51:58 +00:00
event.preventDefault();
2023-07-30 18:19:03 +00:00
const words = this.value.split(" ").filter((word) => word.length < 3);
if (this.value === "" || words.length > 0) {
2021-03-21 11:51:58 +00:00
return;
2018-02-01 12:17:04 +00:00
}
2021-03-21 11:51:58 +00:00
let path = this.$route.path;
this.ongoing = true;
2020-09-29 14:04:43 +00:00
try {
2021-03-21 11:51:58 +00:00
this.results = await search(path, this.value);
2020-09-29 14:04:43 +00:00
} catch (error) {
2021-03-21 11:51:58 +00:00
this.$showError(error);
2020-09-29 14:04:43 +00:00
}
2021-03-21 11:51:58 +00:00
this.ongoing = false;
},
},
};
2018-02-01 12:17:04 +00:00
</script>