$
This commit is contained in:
parent
2898565269
commit
7019a7e8ed
@ -322,7 +322,7 @@
|
|||||||
<span class="generalytics-stat-bac-progressbar-gen" style="width: 20%;">20% (Gen.)</span>
|
<span class="generalytics-stat-bac-progressbar-gen" style="width: 20%;">20% (Gen.)</span>
|
||||||
<span class="generalytics-stat-bac-progressbar-tech" style="width: 30%;">30% (Tech.)</span>
|
<span class="generalytics-stat-bac-progressbar-tech" style="width: 30%;">30% (Tech.)</span>
|
||||||
<span class="generalytics-stat-bac-progressbar-pro" style="width: 25%;">25% (Pro.)</span>
|
<span class="generalytics-stat-bac-progressbar-pro" style="width: 25%;">25% (Pro.)</span>
|
||||||
<span class="generalytics-stat-bac-progressbar-aut" style="width: 25%;">25% (Aut.)</span>
|
<span class="generalytics-stat-bac-progressbar-aut" style="width: 25%;">0% (Aut.)</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="generalytics-stat-bac-legend">
|
<div id="generalytics-stat-bac-legend">
|
||||||
|
46
src/components/global/selector/api/Controller.js
Normal file
46
src/components/global/selector/api/Controller.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import log from "./log";
|
||||||
|
|
||||||
|
export default class Controller {
|
||||||
|
constructor(model, view) {
|
||||||
|
this.model = model
|
||||||
|
this.view = view
|
||||||
|
window.updateModel = (selection, action) => {
|
||||||
|
if(this.model.getCurIndex() === 0) {
|
||||||
|
log("Selector->Controller", "Ajout d'une section pour refine")
|
||||||
|
this.model.setCat(selection)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(action === "next") {
|
||||||
|
this.model.nextPage()
|
||||||
|
} else if(action === "previous") {
|
||||||
|
this.model.previousPage()
|
||||||
|
} else {
|
||||||
|
log("Selector->Controller", "Action inconnue au bataillon (updateModel)")
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getData(this.model.getCurIndex()).then()
|
||||||
|
}
|
||||||
|
|
||||||
|
log("Selector", "Controller 3/3")
|
||||||
|
this.getData(0).then()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getData(n) {
|
||||||
|
if(n === 0) {
|
||||||
|
log("Selector->Controller", "Requete Section 0")
|
||||||
|
this.model.getModelData0().then((res) => {
|
||||||
|
this.view.renderMenu(res)
|
||||||
|
})
|
||||||
|
} else if(n === 1) {
|
||||||
|
log("Selector->Controller", "Requete Section 1")
|
||||||
|
this.model.getModelData1().then((res) => {
|
||||||
|
this.view.renderMenu(res)
|
||||||
|
})
|
||||||
|
} else if(n === 2) {
|
||||||
|
log("Selector->Controller", "Requete Section 2")
|
||||||
|
this.model.getModelData2().then((res) => {
|
||||||
|
this.view.renderMenu(res)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
120
src/components/global/selector/api/Model.js
Normal file
120
src/components/global/selector/api/Model.js
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import log from "./log"
|
||||||
|
|
||||||
|
export default class Model {
|
||||||
|
constructor() {
|
||||||
|
this.state = {
|
||||||
|
api: {
|
||||||
|
link: "https://data.enseignementsup-recherche.gouv.fr/api/records/1.0/search/?dataset=fr-esr-parcoursup&q=&lang=fr&rows=0&sort=tri",
|
||||||
|
facet: {
|
||||||
|
filiaire: "fili",
|
||||||
|
formation: "form_lib_voe_acc",
|
||||||
|
spec: "fil_lib_voe_acc"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
page: {
|
||||||
|
curIndex: 0, /* section n.0 -> n.2. */
|
||||||
|
cat: null,
|
||||||
|
path: ["", "", ""],
|
||||||
|
name: [
|
||||||
|
"formation",
|
||||||
|
"filière de formation",
|
||||||
|
"filière de formation détaillée"
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log("Selector", "Model 2/3")
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurIndex() {
|
||||||
|
return this.state.page.curIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
nextPage() {
|
||||||
|
if(this.state.page.curIndex+1 <= 2) {
|
||||||
|
this.state.page.curIndex++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
previousPage() {
|
||||||
|
if(this.state.page.curIndex-1 >= 0) {
|
||||||
|
this.state.page.curIndex--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setCat(v) {
|
||||||
|
this.state.page.cat = v
|
||||||
|
}
|
||||||
|
|
||||||
|
getModelData0() {
|
||||||
|
if(!localStorage.getItem(`sec0`)) {
|
||||||
|
const link = `${ this.state.api.link }` +
|
||||||
|
`&facet=${this.state.api.facet.filiaire}`
|
||||||
|
|
||||||
|
return fetch(link)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
if(data) {
|
||||||
|
localStorage.setItem(`sec0`, JSON.stringify(data.facet_groups[0].facets))
|
||||||
|
return data.facet_groups[0].facets
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
resolve(JSON.parse(localStorage.getItem(`sec0`)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getModelData1() {
|
||||||
|
if(!localStorage.getItem(`sec1-${this.state.page.cat}`)) {
|
||||||
|
const link = `${this.state.api.link}` +
|
||||||
|
`&facet=${this.state.api.facet.filiaire}` +
|
||||||
|
`&facet=${this.state.api.facet.formation}` +
|
||||||
|
`&facet=${this.state.api.facet.spec}` +
|
||||||
|
`&refine.${this.state.api.facet.filiaire}=${this.state.page.cat}`
|
||||||
|
|
||||||
|
return fetch(link)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
if(data) {
|
||||||
|
localStorage.setItem(`sec1-${this.state.page.cat}`, JSON.stringify(data.facet_groups[1].facets))
|
||||||
|
return data.facet_groups[1].facets
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
resolve(JSON.parse(localStorage.getItem(`sec1-${this.state.page.cat}`)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getModelData2() {
|
||||||
|
if(!localStorage.getItem(`sec2-${this.state.page.cat}`)) {
|
||||||
|
const link = `${this.state.api.link}` +
|
||||||
|
`&facet=${this.state.api.facet.filiaire}` +
|
||||||
|
`&facet=${this.state.api.facet.formation}` +
|
||||||
|
`&facet=${this.state.api.facet.spec}` +
|
||||||
|
`&refine.${this.state.api.facet.filiaire}=${this.state.page.cat}`
|
||||||
|
|
||||||
|
return fetch(link)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
if(data) {
|
||||||
|
localStorage.setItem(`sec2-${this.state.page.cat}`, JSON.stringify(data.facet_groups[2].facets))
|
||||||
|
return data.facet_groups[2].facets
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
resolve(JSON.parse(localStorage.getItem(`sec2-${this.state.page.cat}`)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
src/components/global/selector/api/View.js
Normal file
48
src/components/global/selector/api/View.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import log from "./log";
|
||||||
|
|
||||||
|
export default class View {
|
||||||
|
constructor() {
|
||||||
|
this.zone = document.getElementById("selector-list-zone")
|
||||||
|
this.btn = document.getElementById("selector-top-btn")
|
||||||
|
this.btn.onclick = () => {
|
||||||
|
this.updateMenu("", "previous")
|
||||||
|
}
|
||||||
|
|
||||||
|
log("Selector", "View 1/3")
|
||||||
|
}
|
||||||
|
|
||||||
|
renderMenu(data) {
|
||||||
|
this.zone.innerHTML = ""
|
||||||
|
|
||||||
|
data.forEach((e) => {
|
||||||
|
let li = document.createElement("li")
|
||||||
|
li.className = "selector-list-inner"
|
||||||
|
li.onclick = () => {
|
||||||
|
this.updateMenu(document.getElementById(`menu0-${e.name}`).innerText, "next")
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = document.createElement("a")
|
||||||
|
name.innerText = e.name
|
||||||
|
name.id = `menu0-${e.name}`
|
||||||
|
name.className = "selector-list-names"
|
||||||
|
|
||||||
|
let count = document.createElement("span")
|
||||||
|
count.innerText = e.count
|
||||||
|
count.className = "selector-list-counts"
|
||||||
|
|
||||||
|
li.appendChild(name)
|
||||||
|
li.appendChild(count)
|
||||||
|
this.zone.appendChild(li)
|
||||||
|
})
|
||||||
|
|
||||||
|
log("Selector->View", "Donnees recuperer OK !")
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMenu(selection, direction) {
|
||||||
|
if(direction) {
|
||||||
|
window.updateModel(selection, direction)
|
||||||
|
} else {
|
||||||
|
log("Selector->View", "Mince, le menu ne veut pas s'ouvrir :(")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
src/components/global/selector/api/log.js
Normal file
3
src/components/global/selector/api/log.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function log(mvc, msg) {
|
||||||
|
console.log(`${ mvc }:: ${ msg }`)
|
||||||
|
}
|
9
src/components/global/selector/api/selector.spec.js
Normal file
9
src/components/global/selector/api/selector.spec.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import Controller from "./Controller.js"
|
||||||
|
import View from "./View.js"
|
||||||
|
import Model from "./Model.js"
|
||||||
|
|
||||||
|
export default function start() {
|
||||||
|
const view = new View()
|
||||||
|
const model = new Model()
|
||||||
|
new Controller(model, view)
|
||||||
|
}
|
@ -56,7 +56,7 @@
|
|||||||
|
|
||||||
#selector
|
#selector
|
||||||
#selector-list-container
|
#selector-list-container
|
||||||
.selector-list
|
#selector-list-zone
|
||||||
.selector-list-inner {
|
.selector-list-inner {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -67,7 +67,8 @@
|
|||||||
|
|
||||||
#selector
|
#selector
|
||||||
#selector-list-container
|
#selector-list-container
|
||||||
.selector-list
|
#selector-list-zone
|
||||||
|
.selector-list-inner
|
||||||
.selector-list-names {
|
.selector-list-names {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: white;
|
color: white;
|
||||||
@ -77,7 +78,8 @@
|
|||||||
|
|
||||||
#selector
|
#selector
|
||||||
#selector-list-container
|
#selector-list-container
|
||||||
.selector-list
|
#selector-list-zone
|
||||||
|
.selector-list-inner
|
||||||
.selector-list-names:hover {
|
.selector-list-names:hover {
|
||||||
background: #344D59;
|
background: #344D59;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -87,7 +89,8 @@
|
|||||||
|
|
||||||
#selector
|
#selector
|
||||||
#selector-list-container
|
#selector-list-container
|
||||||
.selector-list
|
#selector-list-zone
|
||||||
|
.selector-list-inner
|
||||||
.selector-list-counts {
|
.selector-list-counts {
|
||||||
color: white;
|
color: white;
|
||||||
background: green;
|
background: green;
|
||||||
@ -98,218 +101,31 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<div id="selector">
|
||||||
export default {
|
|
||||||
/**
|
|
||||||
* state: Contenant
|
|
||||||
* state -> page: Contenant des données de la section actuel
|
|
||||||
* state -> page -> curIndex: Numero de la section actuel
|
|
||||||
* state -> page -> cat: Contenant des valeurs choisit ex: option1: "BUT"
|
|
||||||
* state -> page -> name: Contenant des titres de section en fonction de ..curIndex
|
|
||||||
*
|
|
||||||
* data: Contenant des facets etc...
|
|
||||||
* */
|
|
||||||
state: {
|
|
||||||
api: {
|
|
||||||
link: "https://data.enseignementsup-recherche.gouv.fr/api/records/1.0/search/?dataset=fr-esr-parcoursup&q=&lang=fr&rows=0&sort=tri",
|
|
||||||
facet: {
|
|
||||||
filiaire: "fili",
|
|
||||||
formation: "form_lib_voe_acc",
|
|
||||||
spec: "fil_lib_voe_acc"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
page: {
|
|
||||||
curIndex: 0, /* section n.0 -> n.2. */
|
|
||||||
cat: null,
|
|
||||||
path: ["", "", ""],
|
|
||||||
name: [
|
|
||||||
"formation",
|
|
||||||
"filière de formation",
|
|
||||||
"filière de formation détaillée"
|
|
||||||
],
|
|
||||||
},
|
|
||||||
data: null, /* JSON a traiter en fonction de la section choisit. */
|
|
||||||
path: null
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retourner a la section n-1.
|
|
||||||
* */
|
|
||||||
previousPage(){
|
|
||||||
try {
|
|
||||||
this.state.page.path[this.state.page.curIndex] = ""
|
|
||||||
document.querySelector("loc p").innerText = `${ this.state.page.path[0] } / ${ this.state.page.path[1] } / ${ this.state.page.path[2] }`
|
|
||||||
|
|
||||||
if(this.state.page.curIndex-1 >= 0) {
|
|
||||||
if(this.state.page.curIndex === 0) {
|
|
||||||
} else if(this.state.page.curIndex === 1) {
|
|
||||||
this.state.page.path[0] = ""
|
|
||||||
console.log(this.state.page.path)
|
|
||||||
this.getDataSection0()
|
|
||||||
} else if(this.state.page.curIndex === 2) {
|
|
||||||
this.getDataSection1()
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.state.page.curIndex !== 0) { /* Sinon ca va aller trop loin a la section 0. */
|
|
||||||
this.update({ curIndex: this.state.page.curIndex-- });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(e) {
|
|
||||||
console.error(e)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Aller a la section n+1.
|
|
||||||
* @param event Choix fait par l'utilisateur a la section n.
|
|
||||||
* todo: Faire en sorte de refaire des calls call en fonction de la section choisit (this.getSpecFor(nom_formation:String) et this.getSpecPlusFor(nom_formation:String).
|
|
||||||
* */
|
|
||||||
nextPage(event) {
|
|
||||||
try {
|
|
||||||
this.state.page.path[this.state.page.curIndex] = event.target.textContent
|
|
||||||
document.querySelector("loc p").innerText = `${ this.state.page.path[0] } / ${ this.state.page.path[1] } / ${ this.state.page.path[2] }`
|
|
||||||
|
|
||||||
if(this.state.page.curIndex+1 <= 3 ) {
|
|
||||||
if(this.state.page.curIndex === 0) {
|
|
||||||
this.state.page.cat = `${ event.target.textContent }`
|
|
||||||
this.getDataSection1()
|
|
||||||
} else if(this.state.page.curIndex === 1) {
|
|
||||||
this.getDataSection2(this.state.page.cat)
|
|
||||||
} else if(this.state.page.curIndex === 2) {}
|
|
||||||
|
|
||||||
if(this.state.page.curIndex !== 2) { /* Sinon ca va aller trop loin a la section 2. */
|
|
||||||
this.update({ curIndex: this.state.page.curIndex++ })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(e) {
|
|
||||||
console.error(e)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pour recuperer les données directement depuis l'API.
|
|
||||||
* Chaque getDataSectionN() sert a charge les donnees en fonction de la section choisit.
|
|
||||||
* */
|
|
||||||
async getDataSection0() {
|
|
||||||
if(!localStorage.getItem("sec0")) {
|
|
||||||
try {
|
|
||||||
const link = `${ this.state.api.link }` +
|
|
||||||
`&facet=${this.state.api.facet.filiaire}`
|
|
||||||
|
|
||||||
const response = await fetch(link)
|
|
||||||
const data = await response.json()
|
|
||||||
|
|
||||||
this.update({ data: data.facet_groups[0].facets })
|
|
||||||
localStorage.setItem("sec0", JSON.stringify(data.facet_groups[0].facets))
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
this.update({ data: JSON.parse(localStorage.getItem("sec0")) })
|
|
||||||
} catch(e) {
|
|
||||||
console.error(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async getDataSection1() {
|
|
||||||
if(!localStorage.getItem(`sec1-${this.state.page.cat}`)) {
|
|
||||||
try {
|
|
||||||
const link = `${this.state.api.link}` +
|
|
||||||
`&facet=${this.state.api.facet.filiaire}` +
|
|
||||||
`&facet=${this.state.api.facet.formation}` +
|
|
||||||
`&facet=${this.state.api.facet.spec}` +
|
|
||||||
`&refine.${this.state.api.facet.filiaire}=${this.state.page.cat}`
|
|
||||||
|
|
||||||
const response = await fetch(link)
|
|
||||||
const data = await response.json()
|
|
||||||
|
|
||||||
this.update({data: data.facet_groups[1].facets})
|
|
||||||
localStorage.setItem(`sec1-${this.state.page.cat}`, JSON.stringify(data.facet_groups[1].facets))
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
this.update({ data: JSON.parse(localStorage.getItem(`sec1-${this.state.page.cat}`)) })
|
|
||||||
} catch(e) {
|
|
||||||
console.error(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async getDataSection2() {
|
|
||||||
if(!localStorage.getItem(`sec2-${this.state.page.cat}`)) {
|
|
||||||
try {
|
|
||||||
const api = `${this.state.api.link}` +
|
|
||||||
`&facet=${this.state.api.facet.filiaire}` +
|
|
||||||
`&facet=${this.state.api.facet.formation}` +
|
|
||||||
`&facet=${this.state.api.facet.spec}` +
|
|
||||||
`&refine.${this.state.api.facet.filiaire}=${this.state.page.cat}`
|
|
||||||
|
|
||||||
const response = await fetch(api)
|
|
||||||
const data = await response.json()
|
|
||||||
|
|
||||||
this.update({data: data.facet_groups[2].facets})
|
|
||||||
localStorage.setItem(`sec2-${this.state.page.cat}`, JSON.stringify(data.facet_groups[2].facets))
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
this.update({ data: JSON.parse(localStorage.getItem(`sec2-${this.state.page.cat}`)) })
|
|
||||||
} catch(e) {
|
|
||||||
console.error(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onBeforeMount() {
|
|
||||||
this.getDataSection0()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<span if={ !this.state.data }>
|
|
||||||
Chargement des données... <br />
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div if={ this.state.data } id="selector">
|
|
||||||
<div id="selector-top-container">
|
<div id="selector-top-container">
|
||||||
<span id="selector-top-title">
|
<span id="selector-top-title">
|
||||||
{ this.state.page.name[this.state.page.curIndex] }
|
blabal
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
if={ this.state.page.curIndex > 0 }
|
|
||||||
onclick={ this.previousPage }
|
|
||||||
id="selector-top-btn">
|
id="selector-top-btn">
|
||||||
<
|
<
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="selector-list-container">
|
<div id="selector-list-container">
|
||||||
<ul if={ this.state.page.curIndex === 0 } class="selector-list">
|
<ul id="selector-list-zone">
|
||||||
<li each={ item in this.state.data } class="selector-list-inner">
|
|
||||||
<a onclick={ nextPage } class="selector-list-names">{ item.name }</a>
|
|
||||||
<span class="selector-list-counts">{ item.count }</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul if={ this.state.page.curIndex === 1 } class="selector-list">
|
|
||||||
<li each={ item in this.state.data } class="selector-list-inner">
|
|
||||||
<a onclick={ nextPage } class="selector-list-names">{ item.name }</a>
|
|
||||||
<span class="selector-list-counts">{ item.count }</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul if={ this.state.page.curIndex === 2 } class="selector-list">
|
|
||||||
<li each={ item in this.state.data } class="selector-list-inner">
|
|
||||||
<a onclick={ nextPage } class="selector-list-names">{ item.name }</a>
|
|
||||||
<span class="selector-list-counts">{ item.count }</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import start from "./api/selector.spec.js"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
onMounted() {
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</selector>
|
</selector>
|
Loading…
Reference in New Issue
Block a user