gamutable/js/gamutable.es6.js
tofulm 60483a2f84 Apres pas mal de tests, l'utilisation de regex pour récupérer un
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é
2020-05-08 14:46:07 +02:00

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);
},
},
});