data-search="toto" n'est pas jouable, gros pb de performance sur un gros tableau. les regex OUI mais si pas beaucoup ;-) Il semble indispensable de pouvoir gerer finemement les elements que l'on veut rechercher, dans etre polué par les balises html. Notre json, pour la partie corps du tableau, on ajoute un subdivision : "html" : { mes champs}, comme cela, on peut ajouter une nouvelle cle : "search" : {la valeur des champs qui seront recherchés et filtrés}. Cela alourdit un peu le html, et seulement son poids. La partie html/js est toujours aussi rapide, et meme plus si on utilise cette nouvelle cle. ATTENTION : cela casse la compatibilité
278 lines
7 KiB
JavaScript
278 lines
7 KiB
JavaScript
jQuery(function () {
|
|
$('#app').on('click', '.url_action', function (e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
let url = $(this).attr('href');
|
|
let id = $(this).data('id');
|
|
console.time('Chargement de VueJs APRES Ajax');
|
|
$.ajax({
|
|
url: url,
|
|
async: true,
|
|
}).done(function () {
|
|
if (parseInt(id) > 0) {
|
|
app.rechargerJson(id);
|
|
} else {
|
|
app.rechargerJson();
|
|
}
|
|
});
|
|
});
|
|
|
|
$('#app').on('click', '.modalbox', function (e) {
|
|
e.preventDefault();
|
|
let url = $(this).attr('href');
|
|
url += '&var_zajax=content';
|
|
$.modalbox(url);
|
|
});
|
|
|
|
$('#app').on('click', '.mediabox', function (e) {
|
|
e.preventDefault();
|
|
let href = $(this).attr('href');
|
|
$.fn.mediabox({ href });
|
|
});
|
|
});
|
|
function recupJson(d) {
|
|
try {
|
|
return JSON.parse(d);
|
|
} catch (e) {
|
|
return [];
|
|
}
|
|
}
|
|
const orderBy = (arr, props, orders, champ) =>
|
|
arr.sort((a, b) =>
|
|
props.reduce((acc, prop, i) => {
|
|
if (acc === 0) {
|
|
let [p1, p2] =
|
|
orders && orders[i] === 'desc'
|
|
? [b[champ][prop], a[champ][prop]]
|
|
: [a[champ][prop], b[champ][prop]];
|
|
// passe en lowercase les String
|
|
p1 = typeof p1 === 'string' ? p1.toLowerCase() : p1;
|
|
p2 = typeof p2 === 'string' ? p2.toLowerCase() : p2;
|
|
|
|
// Gestion du format de date
|
|
// transforme 03/11/2000 en 20001103
|
|
let re = /^(\d{2})\/(\d{2})\/(\d{2,4})$/;
|
|
|
|
if (typeof p1 !== 'number') {
|
|
let r1 = p1.match(re);
|
|
if (Array.isArray(r1)) {
|
|
p1 = r1[3] + r1[2] + r1[1];
|
|
}
|
|
|
|
let r2 = p2.match(re);
|
|
if (Array.isArray(r2)) {
|
|
p2 = r2[3] + r2[2] + r2[1];
|
|
}
|
|
}
|
|
|
|
acc = p1 > p2 ? 1 : p1 < p2 ? -1 : 0;
|
|
}
|
|
return acc;
|
|
}, 0)
|
|
);
|
|
console.time('Chargement de VueJS AVANT Ajax');
|
|
console.time('Chargement de VueJs APRES Ajax');
|
|
Vue.nextTick(function () {
|
|
console.timeEnd('Chargement de VueJS AVANT Ajax');
|
|
});
|
|
|
|
let monTableau = {
|
|
props: {
|
|
tparpage: {
|
|
type: Array,
|
|
default: function () {
|
|
return [10, 20, 50, 'Tous'];
|
|
},
|
|
},
|
|
apiuri: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
objet: {
|
|
type: String,
|
|
},
|
|
},
|
|
data: function () {
|
|
return {
|
|
table: [],
|
|
header: [],
|
|
crayons: [],
|
|
search: '',
|
|
page: 1,
|
|
parPage: this.tparpage[0],
|
|
parPageSelect: this.tparpage[0],
|
|
pages: [],
|
|
triOrders: [],
|
|
triProps: [],
|
|
selectTr: [],
|
|
champ_search: 'html',
|
|
};
|
|
},
|
|
mounted() {
|
|
this.chargerJson();
|
|
},
|
|
computed: {
|
|
tableau: function () {
|
|
if (!this.search) {
|
|
return this.pagination(this.table);
|
|
}
|
|
return this.pagination(
|
|
this.table.filter((ligne) =>
|
|
Object.values(ligne[this.champ_search])
|
|
.toString()
|
|
.toLowerCase()
|
|
.indexOf(this.search.toLowerCase()) < 0
|
|
? false
|
|
: true
|
|
)
|
|
);
|
|
},
|
|
},
|
|
watch: {
|
|
tableau() {
|
|
this.setPages();
|
|
},
|
|
parPageSelect(e) {
|
|
if (!parseInt(e)) {
|
|
this.parPage = this.table.length;
|
|
} else {
|
|
this.parPage = e;
|
|
}
|
|
},
|
|
},
|
|
methods: {
|
|
chargerJson(id) {
|
|
let url = this.apiuri;
|
|
if (parseInt(id) > 0) {
|
|
url += '&id=' + id;
|
|
}
|
|
fetch(url)
|
|
.then((response) => response.json())
|
|
.then((data) => {
|
|
let config = data.shift();
|
|
this.header = config.header;
|
|
this.crayons = config.crayons;
|
|
if (parseInt(id) > 0) {
|
|
let i = this.table.findIndex((ligne) => ligne.id === parseInt(id));
|
|
Vue.set(this.table, i, data[0]);
|
|
} else {
|
|
this.table = data;
|
|
if (data[0].search) {
|
|
this.champ_search = 'search';
|
|
}
|
|
}
|
|
Vue.nextTick(function () {
|
|
console.timeEnd('Chargement de VueJs APRES Ajax');
|
|
});
|
|
})
|
|
.catch((error) => console.log(error));
|
|
},
|
|
setPages() {
|
|
let nombreDePages = Math.ceil(this.table.length / this.parPage);
|
|
this.pages = [];
|
|
for (let index = 1; index <= nombreDePages; index++) {
|
|
this.pages.push(index);
|
|
}
|
|
},
|
|
pagination(tableau) {
|
|
let page = this.page;
|
|
let parPage = this.parPage;
|
|
let from = page * parPage - parPage;
|
|
let to = page * parPage;
|
|
return tableau.slice(from, to);
|
|
},
|
|
afficher_crayons(name, id) {
|
|
if (Object.keys(this.crayons).indexOf(name) !== -1) {
|
|
return `crayon ${this.crayons[name]}-${name}-${id}`;
|
|
}
|
|
},
|
|
tri(col, sens) {
|
|
const i = this.triProps.indexOf(col);
|
|
if (i !== -1) {
|
|
this.triOrders[i] = sens;
|
|
} else {
|
|
this.triProps.push(col);
|
|
this.triOrders.push(sens);
|
|
}
|
|
this.table = orderBy(this.table, this.triProps, this.triOrders, this.champ_search);
|
|
},
|
|
ordreActif(col, sens) {
|
|
const i = this.triProps.indexOf(col);
|
|
if (i !== -1) {
|
|
if (this.triOrders[i] === sens) {
|
|
return 'active';
|
|
}
|
|
}
|
|
},
|
|
resetTri() {
|
|
this.table = orderBy(this.table, ['id'], '', this.champ_search);
|
|
this.triOrders = [];
|
|
this.triProps = [];
|
|
},
|
|
selectLigne(id, col) {
|
|
if (col === 'id' && parseInt(id)) {
|
|
let i = this.selectTr.indexOf(id);
|
|
if (i !== -1) {
|
|
this.selectTr.splice(i, 1);
|
|
} else {
|
|
this.selectTr.push(id);
|
|
}
|
|
}
|
|
},
|
|
},
|
|
template: `
|
|
<div class="gamutable">
|
|
<div class="gamutable--surTable">
|
|
<select id="parPage" v-model="parPageSelect">
|
|
<option v-for="v in tparpage" :key="v">{{v}}</option>
|
|
</select>
|
|
<input class="gamutable--rechercher" type="text" v-model="search" placeholder="Rechercher">
|
|
<button class="btn gamutable--resetOrderBy" type="button" @click.stop="resetTri()">Réinitialiser les tris des colonnes</button>
|
|
</div>
|
|
<table class="table table--zebra">
|
|
<thead>
|
|
<tr>
|
|
<th v-for="(label,head,i) in header" :key="'head_'+i" :class="head">
|
|
<span v-html="label"></span>
|
|
<span class="iconeTri">
|
|
<i class="fa fa-sort-asc" :class="ordreActif(head, 'asc')" aria-hidden="true" @click.stop="tri(head,'asc')"></i>
|
|
<i class="fa fa-sort-desc":class="ordreActif(head, 'desc')" aria-hidden="true" @click.stop="tri(head,'desc')" ></i>
|
|
</span>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="l in tableau" :key="l.html.id" :class="selectTr.indexOf(l.html.id) !== -1 ? 'select' : ''" >
|
|
<td v-for="(td,name, i) in l.html" :key="'td_'+i" :class="[afficher_crayons(name,l.html.id), name]" v-html="td" @click="selectLigne(l.html.id,name)">
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<div class="gamutable--sousTable">
|
|
<div class="gamutable-nbrMax">{{table.length}} éléments</div>
|
|
<div class="gamutable--pagination">
|
|
<div class="page-item">
|
|
<button type="button" class="page-link" v-if="page != 1" @click="page=1"> Start </button>
|
|
<button type="button" class="page-link" v-if="page != 1" @click="page--"> Previous </button>
|
|
</div>
|
|
<div class="page-item">
|
|
<button type="button" class="page-link" v-for="pageNumber in pages.slice(page-1, page+5)" @click="page = pageNumber"> {{pageNumber}} </button>
|
|
</div>
|
|
<div class="page-item">
|
|
<button type="button" @click="page++" v-if="page < pages.length" class="page-link"> Next </button>
|
|
<button type="button" @click="page=pages.length" v-if="page < pages.length" class="page-link"> Last </button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>`,
|
|
};
|
|
|
|
let app = new Vue({
|
|
el: '#app',
|
|
components: { monTableau },
|
|
methods: {
|
|
rechargerJson(id) {
|
|
this.$refs.montableau.chargerJson(id);
|
|
},
|
|
},
|
|
});
|