mirror of
https://github.com/Spythere/pojazdownik.git
synced 2026-05-03 05:18:10 +00:00
modal realnych zestawień: przerobiono wygląd; poprawiono performance
This commit is contained in:
+6
-4
@@ -7,10 +7,10 @@
|
|||||||
<div class="g-card-dimmer" v-if="store.isRealStockListCardOpen" @click="store.isRealStockListCardOpen = false"></div>
|
<div class="g-card-dimmer" v-if="store.isRealStockListCardOpen" @click="store.isRealStockListCardOpen = false"></div>
|
||||||
|
|
||||||
<keep-alive>
|
<keep-alive>
|
||||||
<transition name="card-appear">
|
<RealStockCard v-if="store.isRealStockListCardOpen" />
|
||||||
<RealStockCard />
|
|
||||||
</transition>
|
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
|
<!-- <transition name="card-appear"> -->
|
||||||
|
<!-- </transition> -->
|
||||||
|
|
||||||
<div class="app_container">
|
<div class="app_container">
|
||||||
<main>
|
<main>
|
||||||
@@ -34,7 +34,9 @@
|
|||||||
regulaminem symulatora Train Driver 2</a
|
regulaminem symulatora Train Driver 2</a
|
||||||
>!
|
>!
|
||||||
</div>
|
</div>
|
||||||
<div class="text--grayed" style="margin-bottom: 0.25em">Strona jest kompletna dla wersji 2022.2.2 symulatora TD2</div>
|
<div class="text--grayed" style="margin-bottom: 0.25em">
|
||||||
|
Strona jest kompletna dla wersji 2022.2.2 symulatora TD2
|
||||||
|
</div>
|
||||||
©
|
©
|
||||||
<a href="https://td2.info.pl/profile/?u=20777" target="_blank">Spythere</a>
|
<a href="https://td2.info.pl/profile/?u=20777" target="_blank">Spythere</a>
|
||||||
{{ new Date().getUTCFullYear() }} | v{{ VERSION }}
|
{{ new Date().getUTCFullYear() }} | v{{ VERSION }}
|
||||||
|
|||||||
@@ -1,54 +1,74 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="real-stock-card g-card" v-show="store.isRealStockListCardOpen">
|
<div class="real-stock-card g-card">
|
||||||
<div class="g-card_bg" @click="store.isRealStockListCardOpen = false"></div>
|
<div class="g-card_bg" @click="store.isRealStockListCardOpen = false"></div>
|
||||||
|
|
||||||
<div class="card_content">
|
<div class="card_content">
|
||||||
<div>
|
<div class="card_nav">
|
||||||
<button class="btn exit-btn" @click="store.isRealStockListCardOpen = false">< POWRÓT</button>
|
<div class="top-pane">
|
||||||
|
<h1>ZESTAWIENIA REALNE by <a href="https://td2.info.pl/profile/?u=17708" target="_blank">Railtrains997</a></h1>
|
||||||
|
<button class="btn exit-btn" @click="store.isRealStockListCardOpen = false">⨯</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="header">
|
<div class="filters">
|
||||||
<!-- <h1>
|
<input
|
||||||
REALNE ZESTAWIENIA
|
list="readyStockDataList"
|
||||||
<div>by <a href="https://td2.info.pl/profile/?u=17708" target="_blank">Railtrains997</a></div>
|
ref="search"
|
||||||
</h1>
|
v-model="searchedReadyStockName"
|
||||||
<p>
|
placeholder="Szukaj zestawienia po nazwie"
|
||||||
Pełne informacje o zestawieniach dostępne na stronie
|
/>
|
||||||
<a href="http://bocznica.eu/files/archiwum/2021r_2021-11-04.html" target="_blank">bocznica.eu</a> (stan na
|
|
||||||
listopad 2021r.)
|
|
||||||
</p> -->
|
|
||||||
|
|
||||||
<input type="text" tabindex="0" v-model="searchedReadyStockName" placeholder="Szukaj zestawienia..." />
|
<datalist id="readyStockDataList">
|
||||||
|
<option v-for="stock in store.readyStockList" :value="stock.name">
|
||||||
|
{{ stock.type }} {{ stock.number }} {{ stock.name }}
|
||||||
|
</option>
|
||||||
|
</datalist>
|
||||||
|
|
||||||
|
<input list="readyStockStringList" placeholder="Szukaj zestawienia po pojazdach" />
|
||||||
|
|
||||||
|
<datalist id="readyStockStringList">
|
||||||
|
<option v-for="stock in store.readyStockList" :value="stock.stockString">
|
||||||
|
{{ stock.type }} {{ stock.number }} {{ stock.name }}
|
||||||
|
</option>
|
||||||
|
</datalist>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="list" v-if="responseStatus == 'loaded'">
|
<ul class="card_list" ref="list" @scroll="onListScroll">
|
||||||
<li
|
<li v-for="(rStock, i) in computedReadyStockList" :key="i">
|
||||||
v-for="(rStock, key) in computedReadyStockList"
|
<div
|
||||||
:key="key"
|
class="desc"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@click="chooseStock(rStock.stockString)"
|
@click="chooseStock(rStock.stockString)"
|
||||||
@keydown.enter="chooseStock(rStock.stockString)"
|
@keydown.enter="chooseStock(rStock.stockString)"
|
||||||
>
|
>
|
||||||
<div class="desc">
|
|
||||||
<img :src="getIconURL(rStock.type)" :alt="rStock.type" />
|
<img :src="getIconURL(rStock.type)" :alt="rStock.type" />
|
||||||
|
<b class="text--accent" style="margin-left: 5px"> {{ rStock.name }}</b>
|
||||||
<b class="text--accent"> {{ rStock.name }}</b>
|
|
||||||
<div>{{ rStock.number }}</div>
|
<div>{{ rStock.number }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="thumbnails" ref="thumbnailsRef">
|
<div class="thumbnails" ref="thumbnailsRef">
|
||||||
<div v-for="stockItem in rStock.stockString.split(';')">
|
<div v-for="stockItem in rStock.stockString.split(';')">
|
||||||
<span>
|
<!-- rStock.stockString.split(';') -->
|
||||||
<!-- <span>{{ stockItem }}</span> -->
|
<!-- <span> -->
|
||||||
|
<!-- <span>{{ stockItem }}</span> -->
|
||||||
|
<div class="thumbnail_container">
|
||||||
<img
|
<img
|
||||||
:src="`https://rj.td2.info.pl/dist/img/thumbnails/${stockItem}.png`"
|
:src="`https://rj.td2.info.pl/dist/img/thumbnails/${stockItem}.png`"
|
||||||
:alt="rStock.type"
|
|
||||||
:title="rStock.type"
|
:title="rStock.type"
|
||||||
|
style="opacity: 0"
|
||||||
|
@error="onStockItemError"
|
||||||
|
@load="e => (e.target as HTMLElement).style.opacity = '1'"
|
||||||
/>
|
/>
|
||||||
</span>
|
|
||||||
|
<!-- <img src="images/car-passenger-unknown.png" alt=""> -->
|
||||||
|
</div>
|
||||||
|
<!-- <img @error="e => (e.target as HTMLImageElement).src = `images/car-passenger-unknown.png`" /> -->
|
||||||
|
<!-- </span> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<div ref="bottom"></div>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -56,7 +76,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { Vehicle, IReadyStockList } from '../../types';
|
|
||||||
|
|
||||||
import { useStore } from '../../store';
|
import { useStore } from '../../store';
|
||||||
import imageMixin from '../../mixins/imageMixin';
|
import imageMixin from '../../mixins/imageMixin';
|
||||||
@@ -69,35 +88,82 @@ interface ResponseJSONData {
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [imageMixin, stockMixin],
|
mixins: [imageMixin, stockMixin],
|
||||||
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
store: useStore(),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
responseStatus: 'loading',
|
responseStatus: 'loading',
|
||||||
isMobile: 'ontouchstart' in document.documentElement && navigator.userAgent.match(/Mobi/) ? true : false,
|
isMobile: 'ontouchstart' in document.documentElement && navigator.userAgent.match(/Mobi/) ? true : false,
|
||||||
|
observer: null as IntersectionObserver | null,
|
||||||
searchedReadyStockName: '',
|
searchedReadyStockName: '',
|
||||||
|
store: useStore(),
|
||||||
|
visibleIndexesTo: 0,
|
||||||
|
lastChecked: null,
|
||||||
|
scrollY: 0,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
async mounted() {
|
||||||
|
this.mountObserver();
|
||||||
|
this.fetchStockListData();
|
||||||
|
},
|
||||||
|
|
||||||
|
activated() {
|
||||||
|
(this.$refs['search'] as HTMLInputElement).focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
deactivated() {
|
||||||
|
console.log((this.$refs['list'] as HTMLElement).scrollTop);
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
computedReadyStockList() {
|
computedReadyStockList() {
|
||||||
if (this.searchedReadyStockName == null) return this.store.readyStockList;
|
if (this.searchedReadyStockName == null) return this.store.readyStockList;
|
||||||
|
|
||||||
let filtered: IReadyStockList = {};
|
return this.store.readyStockList
|
||||||
|
.filter((rs) => rs.name.toLocaleLowerCase().includes(this.searchedReadyStockName.toLocaleLowerCase()))
|
||||||
|
.filter((_, i) => i <= this.visibleIndexesTo);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
for (let key in this.store.readyStockList) {
|
watch: {
|
||||||
if (key.toLocaleLowerCase().includes(this.searchedReadyStockName.toLocaleLowerCase()))
|
computedReadyStockList(curr, prev) {
|
||||||
filtered[key] = this.store.readyStockList[key];
|
if (curr.length < prev.length) this.visibleIndexesTo = 20;
|
||||||
}
|
|
||||||
|
|
||||||
return filtered;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
async fetchStockListData() {
|
||||||
|
const readyStockJSONData: ResponseJSONData = await (
|
||||||
|
await fetch(`https://spythere.github.io/api/td2/data/readyStock.json?t=${Math.floor(Date.now() / 60000)}`)
|
||||||
|
).json();
|
||||||
|
|
||||||
|
if (!readyStockJSONData) {
|
||||||
|
this.responseStatus = 'error';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let stockKey in readyStockJSONData) {
|
||||||
|
const [type, number, ...name] = stockKey.split(' ');
|
||||||
|
|
||||||
|
this.store.readyStockList.push({
|
||||||
|
type,
|
||||||
|
number: number.replace(/_/g, '/'),
|
||||||
|
name: name.join(' '),
|
||||||
|
stockString: readyStockJSONData[stockKey],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.responseStatus = 'loaded';
|
||||||
|
},
|
||||||
|
|
||||||
|
mountObserver() {
|
||||||
|
this.observer = new IntersectionObserver((entries) => {
|
||||||
|
// Is the entry visible?
|
||||||
|
if (entries[0].intersectionRatio > 0) {
|
||||||
|
this.visibleIndexesTo += 20;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.observer.observe(this.$refs['bottom'] as HTMLElement);
|
||||||
|
},
|
||||||
|
|
||||||
getImageUrl(name: string) {
|
getImageUrl(name: string) {
|
||||||
return new URL(`./dir/${name}.png`, import.meta.url).href;
|
return new URL(`./dir/${name}.png`, import.meta.url).href;
|
||||||
},
|
},
|
||||||
@@ -106,35 +172,17 @@ export default defineComponent({
|
|||||||
this.loadStockFromString(stockString);
|
this.loadStockFromString(stockString);
|
||||||
this.store.isRealStockListCardOpen = false;
|
this.store.isRealStockListCardOpen = false;
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
async mounted() {
|
onStockItemError(e: Event) {
|
||||||
const readyStockJSONData: ResponseJSONData = await (
|
const imageEl = e.target as HTMLImageElement;
|
||||||
await fetch(`https://spythere.github.io/api/td2/data/readyStock.json?t=${Math.floor(Date.now() / 60000)}`)
|
imageEl.src = 'images/car-passenger-unknown.png';
|
||||||
).json();
|
imageEl.style.opacity = '1';
|
||||||
|
},
|
||||||
|
|
||||||
if (!readyStockJSONData) {
|
onListScroll(e: Event) {
|
||||||
this.responseStatus = 'error';
|
const listElement = e.target as HTMLElement;
|
||||||
return;
|
const scrollTop = listElement.scrollTop;
|
||||||
}
|
},
|
||||||
|
|
||||||
for (let stockKey in readyStockJSONData) {
|
|
||||||
const splittedKey = stockKey.split(' ');
|
|
||||||
|
|
||||||
let name = '';
|
|
||||||
for (let i = 2; i < splittedKey.length; i++) {
|
|
||||||
name += ' ' + splittedKey[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.store.readyStockList[stockKey] = {
|
|
||||||
type: splittedKey[0],
|
|
||||||
number: splittedKey[1].replace(/_/g, '/'),
|
|
||||||
name,
|
|
||||||
stockString: readyStockJSONData[stockKey],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
this.responseStatus = 'loaded';
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@@ -144,20 +192,14 @@ export default defineComponent({
|
|||||||
|
|
||||||
.exit-btn {
|
.exit-btn {
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
margin: 0.5em 0;
|
margin: 0.25em 0;
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 250px;
|
|
||||||
|
|
||||||
&::placeholder {
|
|
||||||
font-size: 0.9em;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card_content {
|
.card_content {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto 1fr auto;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
background-color: #1c1c1c;
|
background-color: #1c1c1c;
|
||||||
border-radius: 1em;
|
border-radius: 1em;
|
||||||
|
|
||||||
@@ -167,38 +209,30 @@ input {
|
|||||||
|
|
||||||
padding: 0 1em;
|
padding: 0 1em;
|
||||||
|
|
||||||
overflow-y: auto;
|
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.top-pane {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
}
|
||||||
.top-sticky {
|
.top-sticky {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
background: #1c1c1c;
|
background: #1c1c1c;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.filters {
|
||||||
padding-bottom: 1.5em;
|
display: flex;
|
||||||
padding-top: 0.5em;
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
text-align: center;
|
padding: 0.5em 0;
|
||||||
font-size: 1.3em;
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
line-height: 0.9em;
|
|
||||||
margin: 0.5em 0;
|
|
||||||
|
|
||||||
div {
|
|
||||||
font-size: 0.65em;
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 1em 0;
|
|
||||||
color: #999;
|
|
||||||
font-size: 0.95em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
@@ -206,32 +240,19 @@ ul {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
|
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 2fr;
|
grid-template-columns: 1fr 2fr;
|
||||||
|
background: #2b2b2b;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
.desc {
|
.desc {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thumbnails {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-end;
|
|
||||||
|
|
||||||
overflow: auto;
|
|
||||||
padding: 0.5em;
|
|
||||||
|
|
||||||
img {
|
|
||||||
// width: 150px;
|
|
||||||
height: 100%;
|
|
||||||
max-height: 20px;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
background: #2b2b2b;
|
|
||||||
|
|
||||||
img {
|
img {
|
||||||
height: 0.85em;
|
height: 0.85em;
|
||||||
}
|
}
|
||||||
@@ -250,5 +271,36 @@ ul {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.thumbnails {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0.5em;
|
||||||
|
|
||||||
|
// img {
|
||||||
|
// // width: 150px;
|
||||||
|
// height: 100%;
|
||||||
|
// max-height: 20px;
|
||||||
|
// vertical-align: middle;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
.thumbnail_container {
|
||||||
|
// position: relative;
|
||||||
|
// width: 100%;
|
||||||
|
// height: 0;
|
||||||
|
|
||||||
|
img {
|
||||||
|
// position: absolute;
|
||||||
|
// top: 0;
|
||||||
|
// left: 0;
|
||||||
|
// width: 100%;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -162,7 +162,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
store,
|
store,
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ export const useStore = defineStore({
|
|||||||
stockList: [],
|
stockList: [],
|
||||||
cargoOptions: [],
|
cargoOptions: [],
|
||||||
|
|
||||||
readyStockList: {},
|
readyStockList: [],
|
||||||
|
|
||||||
swapVehicles: false,
|
swapVehicles: false,
|
||||||
|
|
||||||
|
|||||||
+6
-7
@@ -15,7 +15,7 @@ export interface IStore {
|
|||||||
chosenCarUseType: string;
|
chosenCarUseType: string;
|
||||||
|
|
||||||
stockList: IStock[];
|
stockList: IStock[];
|
||||||
readyStockList: IReadyStockList;
|
readyStockList: IReadyStockItem[];
|
||||||
cargoOptions: any[][];
|
cargoOptions: any[][];
|
||||||
|
|
||||||
chosenStockListIndex: number;
|
chosenStockListIndex: number;
|
||||||
@@ -109,11 +109,10 @@ export interface IStock {
|
|||||||
imgSrc?: string;
|
imgSrc?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IReadyStockList {
|
export interface IReadyStockItem {
|
||||||
[key: string]: { stockString: string; type: string; number: string; name: string };
|
stockString: string;
|
||||||
|
type: string;
|
||||||
|
number: string;
|
||||||
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -152,9 +152,7 @@ export function chosenRealStock(state: IStore) {
|
|||||||
}, [] as string[])
|
}, [] as string[])
|
||||||
.join(';');
|
.join(';');
|
||||||
|
|
||||||
const realStockObj = Object.values(state.readyStockList).find(
|
const realStockObj = state.readyStockList.find((readyStock) => readyStock.stockString == currentStockString);
|
||||||
(readyStock) => readyStock.stockString == currentStockString
|
|
||||||
);
|
|
||||||
|
|
||||||
state.chosenRealStockName = realStockObj
|
state.chosenRealStockName = realStockObj
|
||||||
? `${realStockObj.type} ${realStockObj.number} ${realStockObj.name}`
|
? `${realStockObj.type} ${realStockObj.number} ${realStockObj.name}`
|
||||||
|
|||||||
+5
-5
@@ -12,11 +12,13 @@ export default defineConfig({
|
|||||||
vue(),
|
vue(),
|
||||||
VitePWA({
|
VitePWA({
|
||||||
registerType: 'autoUpdate',
|
registerType: 'autoUpdate',
|
||||||
|
|
||||||
workbox: {
|
workbox: {
|
||||||
globPatterns: ['**/*.{js,css,html,png,svg,img}'],
|
// globPatterns: ['**/*.{js,css,html,png,svg,img}'],
|
||||||
|
|
||||||
runtimeCaching: [
|
runtimeCaching: [
|
||||||
{
|
{
|
||||||
urlPattern: new RegExp(`^https://rj.td2.info.pl/dist/img/thumbnails/.*`),
|
urlPattern: /^https:\/\/rj.td2.info.pl\/dist\/img\/thumbnails\/.*/i,
|
||||||
handler: 'CacheFirst',
|
handler: 'CacheFirst',
|
||||||
options: {
|
options: {
|
||||||
cacheName: 'swdr-images-cache',
|
cacheName: 'swdr-images-cache',
|
||||||
@@ -31,10 +33,8 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
devOptions: {
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user