gamutable/js/gamutable.es6.js
tofulm 34671bcf40 on supprime les 2 methodes Vue.set et Vue.delete, car vue3 les mutations
des array sont reactives.
Par contre, la methode findIndex semble ne pas fonctionner dans tous les
cas, pour palier j'ai creer une methode trouver_index. a tester
2020-10-19 21:05:00 +02:00

462 lines
12 KiB
JavaScript

jQuery(function () {
// pour les #URL_ACTION_AUTEUR
// il faut ajouter une class : url_action
$('#app').on('click', '.url_action', function (e) {
e.preventDefault();
e.stopPropagation();
let confirmation = $(this).data('confirm');
if (confirmation !== undefined) {
if (!confirm(confirmation)) {
return;
}
}
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();
}
if (nomBlocAjaxReload !== undefined) {
ajaxReload(nomBlocAjaxReload, {
args: { id },
callback: function () {
console.log('couco reload');
},
});
}
});
});
// lancement d'une modalbox
$('#app').on('click', '.modalbox', function (e) {
e.stopPropagation();
e.preventDefault();
let confirmation = $(this).data('confirm');
if (confirmation !== undefined) {
if (!confirm(confirmation)) {
return;
}
}
let url = $(this).attr('href');
url += '&var_zajax=content';
let data = {};
let minHeight = $(this).data('minheight');
if (minHeight !== undefined) {
data.minHeight = minHeight;
}
let minWidth = $(this).data('minwidth');
if (minWidth !== undefined) {
data.minWidth = minWidth;
}
let width = $(this).data('width');
if (width !== undefined) {
data.width = width;
}
$.modalbox(url, data);
});
// lancement d'une médiabox
$('#app').on('click', '.mediabox', function (e) {
e.preventDefault();
let confirmation = $(this).data('confirm');
if (confirmation !== undefined) {
if (!confirm(confirmation)) {
return;
}
}
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');
});
function exporterCSV(json, delimitercsv, name) {
let csv = '';
if (delimitercsv) {
csv = Papa.unparse(json, { delimiter: delimitercsv });
} else {
csv = Papa.unparse(json);
}
//Download the file as CSV
let link = document.createElement('a');
link.setAttribute('href', 'data:text/csv;charset=utf-8,%EF%BB%BF' + encodeURIComponent(csv));
link.setAttribute('download', name);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
function trouver_index(table, id) {
let i = -1;
table.forEach((ligne, index) => {
if (ligne.html.id === parseInt(id)) {
i = index;
}
});
return i;
}
let monTableau = {
props: {
tparpage: {
type: Array,
default: function () {
return [10, 20, 50, 'Tous'];
},
},
apiuri: {
type: String,
required: true,
},
champcsv: {
type: String,
},
delimitercsv: {
type: String,
},
namecsv: {
type: String,
},
url_sort_asc: {
type: String,
},
url_sort_desc: {
type: String,
},
},
data: function () {
return {
table: [],
header: [],
crayons: [],
classes: [],
search: '',
page: 1,
parPage: sessionStorage.getItem('nbItems') ? sessionStorage.getItem('nbItems') : this.tparpage[0],
parPageSelect: sessionStorage.getItem('nbItems') ? sessionStorage.getItem('nbItems') : this.tparpage[0],
pages: [],
triOrders: [],
triProps: [],
selectTr: [],
champ_search: 'html',
chargement: true,
nameLocalStorage: this.calculer_nameLocalStorage(),
};
},
mounted() {
this.chargerJson();
},
computed: {
tableau: function () {
this.setPages();
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: {
parPageSelect(e) {
if (!parseInt(e)) {
this.parPage = this.table.length;
} else {
this.parPage = e;
}
sessionStorage.setItem('nbItems', this.parPage);
},
table() {
let $table = [];
$table = [
...[
{
header: this.header,
crayons: this.crayons,
classes: this.classes,
},
],
...this.table,
];
localStorage.setItem(this.nameLocalStorage, JSON.stringify($table));
},
},
methods: {
calculer_nameLocalStorage() {
return this.apiuri.match(/.*page=(.*)/)[1];
},
chargerJson(id) {
let url = this.apiuri;
if (parseInt(id) > 0) {
url += '&id=' + id;
} else {
let data = localStorage.getItem(this.nameLocalStorage);
data = recupJson(data);
if (data && data.length) {
let config = data.shift();
this.header = config.header;
if (config.crayons !== undefined) {
this.crayons = config.crayons;
}
if (config.classes !== undefined) {
this.classes = config.classes;
}
this.table = data;
if (data.length && data[0].search) {
this.champ_search = 'search';
}
console.log('fin chargement localStorage');
}
}
fetch(url)
.then((response) => response.json())
.then((data) => {
let config = data.shift();
this.header = config.header;
if (config.crayons !== undefined) {
this.crayons = config.crayons;
}
if (config.classes !== undefined) {
this.classes = config.classes;
}
if (parseInt(id) > 0) {
if (data.length > 0) {
let i = trouver_index(this.table, id);
this.table[i] = data[0];
} else {
let i = trouver_index(this.table, id);
console.log('index ', i);
this.table.splice(i, 1);
}
} else {
this.table = data;
if (data[0] && data[0].search) {
this.champ_search = 'search';
}
}
Vue.nextTick(() => {
this.chargement = false;
if ($_id > 0) {
this.selectLigne($_id, 'id');
let url = new URL(window.location);
url = url.href.replace('&_id=' + $_id, '');
history.pushState({}, null, url);
}
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 = false) {
const i = this.triProps.indexOf(col);
if (i !== -1) {
if (!sens) {
sens = 'asc';
if (this.triOrders[i] === 'asc') {
sens = 'desc';
}
}
this.triOrders[i] = sens;
} else {
if (!sens) {
sens = 'asc';
}
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);
}
}
},
exportCSV() {
let $csv = [];
let $header = [];
let $tableau = [];
Object.keys(this.header).forEach((k) => $header.push(k));
$tableau = this.tableau.reduce((acc, ligne) => {
let $uneLigne = [];
Object.values(ligne[this.champcsv]).forEach((l) => $uneLigne.push(l));
return [...acc, [...$uneLigne]];
}, []);
$csv = [[...$header], ...$tableau];
exporterCSV($csv, this.delimitercsv, this.namecsv);
},
},
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>
<button class="btn gamutable--exportCSV" type="button" @click.stop="exportCSV()"
title="Exporter le tableau affiché en csv"
>
<i class="fa fa-file-excel-o fas fa-file-csv" aria-hidden="true"></i>
</button>
<span v-show="chargement" class="rouge">
<i class="fa fa-refresh fa-spin fa-fw rouge fas fa-sync fa-spin"></i>
Mise à jour de la base de donnée
</span>
<span v-show="!chargement" class="verte">
<i class="fa fa-check"></i>
Base de données synchronisée
</span>
</div>
<table class="table table--zebra">
<thead>
<tr>
<th v-for="(label,head,i) in header" :key="'head_'+i" :class="[head,classes[head]]">
<div>
<div class="label_tete_colonne" v-html="label" @click.stop="tri(head)"></div>
<div class="iconeTri">
<svg class="tri_col" :class="ordreActif(head, 'asc')" width="1rem" height="1rem" @click.stop="tri(head,'asc')">
<title></title>
<use :xlink:href="url_sort_asc" />
</svg>
<svg class="tri_col" :class="ordreActif(head, 'desc')" width="1rem" height="1rem" @click.stop="tri(head,'desc')">
<title></title>
<use :xlink:href="url_sort_desc" />
</svg>
</div>
</div>
</th>
</tr>
</thead>
<tbody>
<tr v-for="l in tableau" :key="l.html.id" :id="'id_'+l.html.id" :data-id="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, classes[name], l.classes !== undefined ? l.classes[name] : '']" v-html="td" @click="selectLigne(l.html.id,name)">
</td>
</tr>
</tbody>
</table>
<div class="gamutable--sousTable">
<div class="gamutable-nbrMax">{{tableau.length}} / {{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>`,
};
const gamuTable = {
components: { monTableau },
methods: {
rechargerJson(id) {
this.$refs.montableau.chargerJson(id);
},
},
};
let app = Vue.createApp(gamuTable).mount('#app');