489 lines
12 KiB
Vue
489 lines
12 KiB
Vue
<template>
|
|
<UInput
|
|
v-model="value"
|
|
placeholder="هوشمند جستجو کنید..."
|
|
:ui="{
|
|
trailing: '',
|
|
|
|
root: ['hadith-search-root'],
|
|
base: ['hadith-search-input'],
|
|
}"
|
|
:loading="loading"
|
|
trailing-icon="i-lucide-search"
|
|
autocomplete="on"
|
|
autofocus
|
|
highlight
|
|
@blur="onBlur"
|
|
@change="onChange"
|
|
@update:modelValue="onUpdateModel"
|
|
>
|
|
</UInput>
|
|
</template>
|
|
|
|
<script>
|
|
import { mapState } from "pinia";
|
|
import searchApi from "../../apis/searchApi.js";
|
|
import { useCommonStore } from "@stores/commonStore";
|
|
|
|
export default {
|
|
props: {
|
|
placeholder: {
|
|
default: "جستجو در هزاران محتوای قوانین و مقرارت",
|
|
},
|
|
contentKey: {
|
|
default: "qasection",
|
|
},
|
|
entityTheme: {
|
|
default: false,
|
|
},
|
|
showAppendSearchButton: {
|
|
default: true,
|
|
},
|
|
showPrepend: {
|
|
default: false,
|
|
},
|
|
showAppend: {
|
|
default: true,
|
|
},
|
|
textSearch: {
|
|
default: "",
|
|
},
|
|
modeInit: {
|
|
default: 0,
|
|
},
|
|
searchDomain: {
|
|
default() {
|
|
return [];
|
|
},
|
|
},
|
|
listAutocomplate: {
|
|
default() {
|
|
return [];
|
|
},
|
|
},
|
|
},
|
|
emits: ["getAutoComplateList"],
|
|
watch: {
|
|
modeInit(newVal = 1) {
|
|
this.mode = newVal;
|
|
},
|
|
textSearch(newVal) {
|
|
this.localTextSearch = newVal;
|
|
},
|
|
},
|
|
beforeMount() {
|
|
// this.inputPopupState = this.inputPopupState;
|
|
},
|
|
mounted() {
|
|
this.localTextSearch = this.textSearch;
|
|
|
|
if (window.localStorage.getItem([this.historySearchRecent])) {
|
|
try {
|
|
this.historySearch = JSON.parse(
|
|
window.localStorage.getItem([this.historySearchRecent])
|
|
);
|
|
} catch (e) {
|
|
window.localStorage.removeItem([this.historySearchRecent]);
|
|
}
|
|
}
|
|
},
|
|
beforeDestroy() {
|
|
window.removeEventListener("resize", this.handleResize);
|
|
window.removeEventListener("load", this.handleResize);
|
|
document.removeEventListener("click", this.handleClickOutside);
|
|
},
|
|
data() {
|
|
return {
|
|
loading: false,
|
|
value: "",
|
|
localListAutocomplate: [],
|
|
typingTimer: undefined,
|
|
doneTypingInterval: 800,
|
|
localTextSearch: "",
|
|
historySearch: [],
|
|
|
|
inputPopupState: 0,
|
|
mode: 1,
|
|
tagLiSelected: null,
|
|
inputfocused: false,
|
|
isLastKeyCodeArrow: false,
|
|
historySearchRecent: "historysearchrecent",
|
|
};
|
|
},
|
|
computed: {
|
|
...mapState(useCommonStore, ["domainActiveGetter"]),
|
|
},
|
|
methods: {
|
|
// on input changed
|
|
onUpdateModel() {
|
|
console.info("onUpdateModel");
|
|
},
|
|
// on input blur
|
|
onBlur() {
|
|
// console.info("onblue");
|
|
},
|
|
// on button click
|
|
onChange() {
|
|
console.info("onChange");
|
|
},
|
|
/**
|
|
* تنظیم آیتم انتخاب شده و شروع جستجو.
|
|
* @param {Object} navItem - آیتم انتخابشده.
|
|
*/
|
|
setDomainField(navItem) {
|
|
this.$emit("onSetDomainField", navItem);
|
|
// this.prevSearchStart();
|
|
},
|
|
async getAutoComplateList() {
|
|
this.localListAutocomplate = [];
|
|
if (this.localTextSearch == "") return;
|
|
|
|
let index_key = this.contentKey;
|
|
if (!index_key) return;
|
|
|
|
let url = searchApi.search.autoComplate;
|
|
|
|
url = url.replace("{{appname}}", buildName());
|
|
url = url.replace("{{index_key}}", index_key);
|
|
url = url.replace("{{filter}}", "q=" + this.localTextSearch);
|
|
|
|
try {
|
|
const { $api } = useNuxtApp();
|
|
const response = await $api(url, {
|
|
baseURL: repoUrl(),
|
|
});
|
|
|
|
this.localListAutocomplate = response.hits?.hits;
|
|
this.inputPopupState = 3;
|
|
} catch (err) {}
|
|
},
|
|
|
|
onKeyDown() {
|
|
clearTimeout(this.typingTimer);
|
|
this.typingTimer = undefined;
|
|
},
|
|
/**
|
|
* کنترل تایمر تکمیل خودکار و ارسال کوئری.
|
|
* تایمر فعلی را پاک میکند و یک تایمر جدید با یک تاخیر مشخص تنظیم میکند تا کوئری را ارسال کند.
|
|
*/
|
|
toggleAutocomplete(event) {
|
|
// برای کلید حرکت پایین درخواست اضافی نرود
|
|
if (
|
|
event.keyCode === 40 ||
|
|
event.keyCode === 38 ||
|
|
event.keyCode === 13
|
|
) {
|
|
this.isLastKeyCodeArrow = event.keyCode === 40 || event.keyCode === 38;
|
|
return;
|
|
}
|
|
|
|
this.isLastKeyCodeArrow = false;
|
|
|
|
if (!this.inputfocused && this.inputPopupState === 3) {
|
|
return;
|
|
}
|
|
|
|
if (this.typingTimer) {
|
|
clearTimeout(this.typingTimer);
|
|
this.typingTimer = undefined;
|
|
} else {
|
|
this.typingTimer = setTimeout(() => {
|
|
this.getAutoComplateList();
|
|
this.typingTimer = undefined;
|
|
}, this.doneTypingInterval);
|
|
}
|
|
},
|
|
|
|
setInputFocus() {
|
|
this.inputfocused = true;
|
|
// this.inputPopupfocused=false
|
|
},
|
|
/**
|
|
* شروع جستجو را کنترل میکند.
|
|
* @event prevSearchStart
|
|
*/
|
|
prevSearchStart(event) {
|
|
if (
|
|
this.isLastKeyCodeArrow &&
|
|
event.keyCode === 13 &&
|
|
this.inputPopupState != 0
|
|
) {
|
|
this.selectAutocomplate2();
|
|
this.isLastKeyCodeArrow = false;
|
|
return;
|
|
}
|
|
|
|
this.tagLiSelected = null;
|
|
this.inputPopupState = 0;
|
|
this.addHistorySearch(this.localTextSearch);
|
|
|
|
let tt = myEncodeQuery(this.localTextSearch);
|
|
this.$emit("onSearchStart", tt);
|
|
// this.searchStart(tt);
|
|
},
|
|
/**
|
|
*نمایش سابقه جستجو.
|
|
*/
|
|
showHisory() {
|
|
setTimeout(() => {
|
|
if (this.localTextSearch == "") this.inputPopupState = 1;
|
|
else {
|
|
this.inputPopupState = 0;
|
|
this.tagLiSelected = null;
|
|
}
|
|
}, 100);
|
|
},
|
|
/**
|
|
* کنترل کلیکهای خارج از المان.
|
|
*/
|
|
keyupdiv(event) {
|
|
// 13:enter
|
|
// 8:backspace
|
|
if (this.inputfocused == false) return;
|
|
if (this.inputPopupState == 0 || this.inputPopupState == 2) return;
|
|
var el = "";
|
|
el =
|
|
this.inputPopupState == 1
|
|
? this.$refs["his_ul"]
|
|
: this.$refs["auto_complate_ul"];
|
|
|
|
if (!el || !el.firstChild) return;
|
|
|
|
const selectItem = (item) => {
|
|
this.tagLiSelected = item;
|
|
this.tagLiSelected?.classList.add("selected");
|
|
this.tagLiSelected?.focus();
|
|
};
|
|
|
|
// 40: arrow down
|
|
// 38: arrow up
|
|
if (this.inputfocused == true && event.keyCode === 40) {
|
|
if (this.tagLiSelected) {
|
|
this.tagLiSelected?.classList.remove("selected");
|
|
const next = this.tagLiSelected?.nextSibling || el.firstChild;
|
|
selectItem(next);
|
|
} else {
|
|
selectItem(el?.firstChild);
|
|
}
|
|
} else if (this.inputfocused == true && event.keyCode === 38) {
|
|
if (this.tagLiSelected) {
|
|
this.tagLiSelected?.classList.remove("selected");
|
|
const prev = this.tagLiSelected?.previousSibling || el.lastChild;
|
|
selectItem(prev);
|
|
} else {
|
|
selectItem(el?.lastChild);
|
|
}
|
|
}
|
|
// 46: delete
|
|
else if (this.inputfocused == true && event.keyCode === 46) {
|
|
let index = this.tagLiSelected?.getAttribute("data-key");
|
|
|
|
this.removeHistorySearch(index);
|
|
}
|
|
},
|
|
onClickOutside() {
|
|
if (this.inputPopupState == 1 || this.inputPopupState == 3) {
|
|
this.inputPopupState = 0;
|
|
this.tagLiSelected = null;
|
|
}
|
|
},
|
|
selectAutocomplate(item) {
|
|
this.tagLiSelected = null;
|
|
this.inputPopupState = 0;
|
|
this.localTextSearch = item;
|
|
|
|
this.$emit("onSearchStart", this.localTextSearch);
|
|
// this.$emit("onSearchStart", {
|
|
// textSearch: this.localTextSearch,
|
|
// searchItem: item,
|
|
// });
|
|
},
|
|
|
|
selectHistorySearch(item) {
|
|
this.localTextSearch = item;
|
|
this.$emit("onSearchStart", this.localTextSearch);
|
|
},
|
|
|
|
removeHistorySearch(x) {
|
|
this.tagLiSelected = null;
|
|
this.historySearch.splice(x, 1);
|
|
this.saveHistorySearch();
|
|
},
|
|
saveHistorySearch() {
|
|
const parsed = JSON.stringify(this.historySearch);
|
|
window.localStorage.setItem([this.historySearchRecent], parsed);
|
|
},
|
|
getHighlightAutocomplate(item) {
|
|
if (!item) return "";
|
|
|
|
let html = "";
|
|
|
|
let key = "title";
|
|
if (this.contentKey == "qasection" || this.contentKey == "rgsection") {
|
|
key = "qanon_title";
|
|
if (item?.highlight[key]) html = item.highlight[key][0];
|
|
if (!html) {
|
|
let key1 = key + ".ph";
|
|
if (item?.highlight[key1]) html = item.highlight[key1][0];
|
|
}
|
|
|
|
if (!html) {
|
|
let key1 = key + ".fa";
|
|
if (item?.highlight[key1]) html = item.highlight[key1][0];
|
|
}
|
|
|
|
let key2 = "ts_date";
|
|
if (item?._source[key2]) {
|
|
html += `<span style="color: #a7a098;"> - تاریخ: ${item._source[key2]}</span>`;
|
|
}
|
|
}
|
|
|
|
if (this.contentKey == "sanad") {
|
|
Object.values(item?.highlight).forEach((element, index) => {
|
|
html += element[0];
|
|
});
|
|
}
|
|
|
|
return html;
|
|
},
|
|
|
|
addHistorySearch(newSearch = "") {
|
|
if (newSearch == "") {
|
|
return;
|
|
}
|
|
var index = this.historySearch.indexOf(newSearch);
|
|
if (index != -1) {
|
|
this.historySearch.splice(index, 1);
|
|
}
|
|
|
|
this.historySearch.unshift(newSearch);
|
|
this.saveHistorySearch();
|
|
},
|
|
saveHistorySearch() {
|
|
const parsed = JSON.stringify(this.historySearch);
|
|
window.localStorage.setItem([this.historySearchRecent], parsed);
|
|
},
|
|
|
|
selectAutocomplate2(item) {
|
|
if (!item) {
|
|
if (this.localListAutocomplate.length) {
|
|
item = this.localListAutocomplate[this.tagLiSelected?.value];
|
|
}
|
|
}
|
|
|
|
let key = "title";
|
|
if (this.contentKey == "qasection" || this.contentKey == "rgsection")
|
|
key = "qanon_title";
|
|
|
|
this.inputfocused = false;
|
|
this.searchinput?.blur();
|
|
this.localTextSearch = item?._source[key];
|
|
|
|
this.$emit("onSearchStart", this.localTextSearch);
|
|
// this.$emit("onSearchStart", {
|
|
// textSearch: this.localTextSearch,
|
|
// searchItem: item,
|
|
// });
|
|
|
|
if (!item) {
|
|
this.localTextSearch = this.tagLiSelected?.innerText;
|
|
this.addHistorySearch(this.localTextSearch);
|
|
|
|
let tt = myEncodeQuery(this.localTextSearch);
|
|
|
|
this.$emit("onSearchStart", tt);
|
|
// this.$emit("onSearchStart", { textSearch: tt, searchItem: item });
|
|
}
|
|
|
|
this.inputPopupState = 0;
|
|
this.tagLiSelected = null;
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style>
|
|
.hadith-search-root {
|
|
width: 656px;
|
|
&::before {
|
|
content: "";
|
|
|
|
position: absolute;
|
|
left: 1em;
|
|
right: 1em;
|
|
top: 50%;
|
|
|
|
backdrop-filter: blur(60px);
|
|
background: linear-gradient(137.41deg, #ffffff -42.82%, #e5e0ff 87.9%);
|
|
filter: blur(60px);
|
|
/* transform: rotate(180deg); */
|
|
|
|
width: 626px;
|
|
height: 68px;
|
|
z-index: 1;
|
|
}
|
|
|
|
& > span {
|
|
z-index:3;
|
|
width: 48px;
|
|
height: 48px;
|
|
justify-content: center;
|
|
align-items: center;
|
|
|
|
padding: 0;
|
|
/* padding-bottom: 6px; */
|
|
border-radius: 50px;
|
|
/* border-bottom-width: 1px; */
|
|
background: linear-gradient(320.71deg, #b9fde0 6.56%, #e4f9f0 69.69%);
|
|
left: 12px;
|
|
top: 0;
|
|
bottom: 0;
|
|
margin: auto;
|
|
transition: all 0.2s ease-in-out;
|
|
|
|
&:hover {
|
|
transition: all 0.2s ease-in-out;
|
|
background: linear-gradient(320.71deg, #90ceb3 6.56%, #daf1e8 69.69%);
|
|
}
|
|
|
|
& > span {
|
|
width: 18px;
|
|
height: 18px;
|
|
/* border-width: 1.5px; */
|
|
/* border: 1.5px solid; */
|
|
|
|
/* border-image-source: linear-gradient(
|
|
102.02deg,
|
|
#4be8ae 7.38%,
|
|
#00a762 91.78%
|
|
); */
|
|
}
|
|
}
|
|
}
|
|
|
|
.hadith-search-input {
|
|
z-index: 2;
|
|
|
|
height: 72px;
|
|
justify-content: space-between;
|
|
padding-top: 12px;
|
|
padding-right: 24px;
|
|
padding-bottom: 12px;
|
|
padding-left: 12px;
|
|
border-radius: 12px;
|
|
border-width: 0.3px;
|
|
|
|
background-color: #fff;
|
|
border: 0.3px solid #e0e0e0;
|
|
box-shadow: 0px 1px 4px 0px #0000000d;
|
|
|
|
font-family: IRANSansX;
|
|
font-weight: 300;
|
|
font-size: 14px;
|
|
line-height: 21px;
|
|
letter-spacing: 0%;
|
|
text-align: right;
|
|
color: #a7acbe;
|
|
}
|
|
</style>
|