You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
xshop/resources/js/components/MetaSearch.vue

377 lines
12 KiB
Vue

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<form ref="filter">
<div :class="cls">
<!--Only code you need is this label-->
<label class="switch">
<input name="ext" @change="apply" v-model="ext" type="checkbox">
<div class="slider round"></div>
</label>
فقط کالا‌های موجود
</div>
<div :class="cls">
<h2 id="fon">
مرتب سازی بر اساس:
</h2>
<input type="hidden" name="sort" value="sale" id="sort">
<span class="badge p-2 mb-1 bg-secondary" id="sale" @click="changeSort('sale',$event)">
پرفروشترین
</span>
<span class="badge p-2 mb-1 bg-secondary" id="new" @click="changeSort('new',$event)">
جدیدترین
</span>
<span class="badge p-2 mb-1 bg-secondary" id="fav" @click="changeSort('fav',$event)">
محبوبترین
</span>
<span class="badge p-2 mb-1 bg-secondary" id="cheap" @click="changeSort('cheap',$event)">
ارزانترین
</span>
<span class="badge p-2 mb-1 bg-secondary" id="expensive" @click="changeSort('expensive',$event)">
گرانترین
</span>
</div>
<div :class="cls" v-if="minm < maxm">
<label>
{{ t.priceRange }}
</label>
<VueSimpleRangeSlider
style="width: 95%;margin: auto"
:min="minm"
dir="rtl"
@input="price()"
:max="maxm"
active-bar-color="#1d68a7"
v-model="state.range"
>
<template #prefix="{ value }">ت</template>
</VueSimpleRangeSlider>
<input type="hidden" name="from" v-model="state.range[0]">
<input type="hidden" name="to" v-model="state.range[1]">
</div>
<div v-for="d in elms" :class="cls" v-if="d.searchable">
<template v-if="d.type !== 'checkbox'">
<label :for="d.name" >
{{ makeLabel(d.label) }}
</label>
</template>
<div v-if="d.type === 'text'">
<input v-model="defaults[d.name]" type="text" :id="d.name" :name="'meta['+d.name+']'"
class="form-control">
</div>
<div v-else-if="d.type === 'number'">
<input type="number" v-model="defaults[d.name]" :placeholder="makeLabel(d.label)" :id="d.name"
:name="'meta['+d.name+']'" class="form-control">
</div>
<div v-else-if="d.type === 'color'" :id="d.name" :name="'meta['+d.name+']'">
<select v-model="defaults[d.name]" :name="'meta['+d.name+']'" :id="d.name" class="form-control">
<option value=""> {{ makeLabel(d.label) }}</option>
<option :style="'background-color:' + o.value " :value="o.value" v-for="o in d.options">
{{ o.title }}
</option>
</select>
</div>
<div v-else-if="d.type === 'checkbox'">
<!--Only code you need is this label-->
<label class="switch">
<input :name="'meta['+d.name+']'" v-model="defaults[d.name]" type="checkbox">
<div class="slider round"></div>
</label>
<span >
</span>
{{ makeLabel(d.label) }}
</div>
<div v-else-if="d.type === 'select'">
<select v-model="defaults[d.name]" :name="'meta['+d.name+']'" :id="d.name" class="form-control">
<option value=""> {{ t.all }}</option>
<option :value="o.value" v-for="o in d.options"> {{ o.title }}</option>
</select>
</div>
<div v-else-if="d.type === 'multi'">
<multiselect :multiple="true" :taggable="true" label="title" v-model="defaults[d.name]"
:placeholder="makeLabel(d.label)" :options="d.options"></multiselect>
<input :id="d.label" type="hidden" :name="'meta['+d.name+']'" :value="makeVal(defaults[d.name])">
</div>
<div v-else-if="d.type === 'singlemulti'">
<multiselect @remove="rem(d.name,$event)" @select="upd(d.name,defaults[d.name])"
v-model="defaults[d.name]" :multiple="true" :taggable="true" label="title"
:placeholder="makeLabel(d.label)" :options="d.options"></multiselect>
<input type="hidden" :name="'meta['+d.name+']'" :value="makeVal(defaults[d.name])">
</div>
</div>
<button class="btn btn-primary w-100">
<i class="fa fa-check float-start mt-1"></i>
اعمال
</button>
</form>
</template>
<script>
import multiselect from 'vue-multiselect';
import VueSimpleRangeSlider from "vue-simple-range-slider/vue2";
import "vue-simple-range-slider/vue2/css";
function getParameterByName(name, url = window.location.href) {
name = name.replace(/[\[\]]/g, '\\$&');
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
function getURLParam(key, target = window.location.href) {
var values = [];
if (!target) target = location.href;
key = key.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var pattern = key + '=([^&#]+)';
var o_reg = new RegExp(pattern, 'ig');
while (true) {
console.log('x1');
var matches = o_reg.exec(target);
if (matches && matches[1]) {
values.push(matches[1]);
} else {
break;
}
}
if (!values.length) {
return null;
} else {
return values.length == 1 ? values[0] : values;
}
}
export default {
name: "MetaElement",
components: {multiselect, VueSimpleRangeSlider},
data: function () {
return {
b: true,
content: this.value,
value: '',
t: window.translate,
classes: 'form-control',
elms: [],
defaults: {},
ext: false,
state: {range: [parseInt(this.minm), parseInt(this.maxm)], number: 1000}
}
},
props: ['jdata', 'searchable', 'defz', 'cls', 'minm', 'maxm','langg'],
mounted() {
this.updateJdata(this.jdata, this.defz);
if (getParameterByName('to') !== null) {
this.state.range[1] = getParameterByName('to');
}
if (getParameterByName('from') !== null) {
this.state.range[0] = getParameterByName('from');
}
if (getParameterByName('ext') !== null) {
this.ext = true;
}
if (getParameterByName('sort') !== null) {
document.querySelector('#' + getParameterByName('sort')).click();
}
},
methods: {
makeLabel(lbl){
if ( typeof lbl == 'object'){
return lbl[this.langg];
}else{
return lbl;
}
},
apply: function () {
this.$refs.filter.submit();
},
changeSort: function (val, e) {
let x = document.querySelector('.badge.bg-primary');
x.classList.remove('bg-primary');
x.classList.add('bg-secondary');
document.querySelector('#sort').value = val;
e.target.classList.remove('bg-secondary');
e.target.classList.add('bg-primary');
},
price: function () {
console.log(this.state);
},
upd: function (name, data) {
this.defaults[name] = data;
this.$forceUpdate();
},
rem: function (name, value) {
for (const x in this.defaults[name]) {
let val = this.defaults[name][x];
if (val.value === value.value) {
this.defaults[name].splice(x, 1);
this.$forceUpdate();
return;
}
}
},
makeVal: function (ob) {
return JSON.stringify(ob);
},
updateJdata: function (e, def = []) {
try {
const params = new URL(window.location.href).searchParams;
// make defaults
for (const d of this.elms) {
switch (d.type) {
case 'checkbox':
if (params.get('meta[' + d.name + ']') !== null) {
this.defaults[d.name] = true;
} else {
this.defaults[d.name] = false;
}
break;
case 'select':
if (params.get('meta[' + d.name + ']') !== null) {
this.defaults[d.name] = params.get('meta[' + d.name + ']');
} else {
this.defaults[d.name] = '';
}
break;
case 'multi':
case 'singlemulti':
if (params.get('meta[' + d.name + ']') !== null) {
try {
this.defaults[d.name] = JSON.parse(params.get('meta[' + d.name + ']'));
} catch {
}
} else {
this.defaults[d.name] = [];
}
break;
default:
if (params.get('meta[' + d.name + ']') !== null) {
this.defaults[d.name] = params.get('meta[' + d.name + ']');
} else {
this.defaults[d.name] = '';
}
}
}
if (typeof e == 'string') {
this.elms = JSON.parse(e);
} else {
this.elms = e;
}
for (const e of this.elms) {
try {
e.options = JSON.parse(e.options);
// fix for multi select object
if (e.type === 'multi' || (e.type === '' && this.searchable)) {
this.defaults[e.name] = JSON.parse(this.defaults[e.name]);
}
// console.log(JSON.parse(e.options));
} catch {
}
}
} catch (e) {
this.elms = [];
console.log('no meta ele', e.message);
}
},
handleInput(e) {
this.$emit('input', this.content);
},
}
}
</script>
<style scoped>
.switch {
margin-top: 0px;
position: relative;
display: inline-block;
width: 35px;
height: 20px;
float: left;
}
.switch input {
display: none;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: 0.4s;
transition: 0.4s;
}
.slider:before {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 2px;
bottom: 2px;
background-color: white;
-webkit-transition: 0.4s;
transition: 0.4s;
}
input:checked + .slider {
background-color: #1d68a7;
}
input:focus + .slider {
box-shadow: 0 0 1px #1d68a7;
}
input:checked + .slider:before {
-webkit-transform: translateX(16px);
-ms-transform: translateX(16px);
transform: translateX(16px);
}
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
.scroll {
height: 150px;
overflow-y: scroll;
}
label {
margin-bottom: 4px;
}
select {
padding: 3px;
text-align: center;
}
</style>