Compare commits

...

4 Commits

16 changed files with 843 additions and 653 deletions

View File

@ -17,7 +17,7 @@ De même l'idée est de rester libre du rendu des données en n'imposant pas de
## La première version
La première version se contente de récupérer et parser des données présentes dans un fichier CSV via un appel Ajax.
Les données trouvées sont affichées dans un tableau. En option, des colonnes peuvent être indiquées par filtrer les données et/ou les classer.
Les données trouvées sont affichées dans un tableau. En option, des colonnes peuvent être indiquées pour filtrer les données et/ou les classer.
Il est possible de fournir des fonctions spécifiques pour classer les données de certaines colonnes.
Il est également possible de paginer les résultats.
@ -27,10 +27,6 @@ Il reste à ajouter :
- la possibilité d'utiliser des sources/formats différents qu'un fichier CSV pour extraire les données.
- la possibilité de spécifier un code HTML autre qu'un tableau pour lister/récupérer les données.
Mais avant toute chose, il me faut maintenant **remanier le code, le script approchant les 500 lignes** !
Bref, il reste beaucoup de choses à faire !
## Tests et exemples
L'utilisation de TypeScript élimine déjà pas mal d'erreurs.

View File

@ -1,6 +1,6 @@
{
"name": "freedatas2html",
"version": "0.3.6",
"version": "0.4.0",
"description": "Visualization of data from various sources (CSV, API, HTML...) with filters, classification, pagination, etc.",
"main": "index.js",
"scripts": {
@ -42,4 +42,4 @@
"natural-orderby": "^2.0.3",
"papaparse": "^5.3.1"
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -34,16 +34,13 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
import { freeDatas2HTML } from "./freeDatas2HTML";
import { FreeDatas2HTML, Pagination, Selector, SortingField } from "./freeDatas2HTML";
var initialise = function () { return __awaiter(void 0, void 0, void 0, function () {
var converter, mySort, e_1;
var mySort, converter, pagination, filtre1, filtre2, filtre3, sortingField1, sortingField2, sortingField3, sortingField4, e_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 3]);
converter = new freeDatas2HTML();
converter.datasViewElt = { id: "datas" };
converter.datasSelectors = [{ datasFieldNb: 3, id: "filtre1" }, { datasFieldNb: 4, id: "filtre2" }, { datasFieldNb: 5, id: "filtre3", separator: "," }];
_a.trys.push([0, 3, , 4]);
mySort = function (a, b, order) {
if (order === void 0) { order = "asc"; }
var values = ["> 100000", "> 1 et < 100 000", "≤ 1", "Traces", "Inexistant"];
@ -56,33 +53,56 @@ var initialise = function () { return __awaiter(void 0, void 0, void 0, function
else
return 0;
};
converter.datasSortingColumns = [{ datasFieldNb: 0 }, { datasFieldNb: 1 }, { datasFieldNb: 2 }, { datasFieldNb: 4 }];
converter.datasSortingFunctions = [{ datasFieldNb: 4, sort: mySort }];
converter.pagination =
{
selectedValue: 10,
options: {
displayElement: { id: "paginationOptions" },
values: [10, 20, 50, 500],
name: "Choix de pagination :"
},
pages: {
displayElement: { id: "pages" },
name: "Page à afficher :"
}
};
converter = new FreeDatas2HTML();
converter.datasViewElt = { id: "datas" };
converter.datasSourceUrl = "http://localhost:8080/datas/elements-chimiques.csv";
return [4, converter.run()];
return [4, converter.parse()];
case 1:
_a.sent();
return [3, 3];
converter.datasSortingFunctions = [{ datasFieldNb: 4, sort: mySort }];
pagination = new Pagination(converter, { id: "pages" }, "Page à afficher :");
pagination.options = { displayElement: { id: "paginationOptions" }, values: [10, 20, 50, 500], name: "Choix de pagination :" };
pagination.selectedValue = 10;
converter.pagination = pagination;
pagination.rend2HTML();
return [4, converter.run()];
case 2:
_a.sent();
filtre1 = new Selector(converter);
filtre1.datasViewElt = { id: "filtre1" };
filtre1.datasFieldNb = 3;
filtre1.selector2HTML();
filtre2 = new Selector(converter);
filtre2.datasViewElt = { id: "filtre2" };
filtre2.datasFieldNb = 4;
filtre2.selector2HTML();
filtre3 = new Selector(converter);
filtre3.datasViewElt = { id: "filtre3" };
filtre3.datasFieldNb = 5;
filtre3.separator = ",";
filtre3.selector2HTML();
converter.datasSelectors = [filtre1, filtre2, filtre3];
sortingField1 = new SortingField(converter);
sortingField1.datasFieldNb = 0;
sortingField1.field2HTML();
sortingField2 = new SortingField(converter);
sortingField2.datasFieldNb = 1;
sortingField2.field2HTML();
sortingField3 = new SortingField(converter);
sortingField3.datasFieldNb = 2;
sortingField3.field2HTML();
sortingField4 = new SortingField(converter);
sortingField4.datasFieldNb = 4;
sortingField4.field2HTML();
converter.datasSortingFields = [sortingField1, sortingField2, sortingField3, sortingField4];
return [3, 4];
case 3:
e_1 = _a.sent();
console.error(e_1);
if (document.getElementById("datas") !== null)
document.getElementById("datas").innerHTML = "<strong>Désolé, mais un problème technique empêche l'affichage des données.</strong>";
return [3, 3];
case 3: return [2];
return [3, 4];
case 4: return [2];
}
});
}); };

View File

@ -37,26 +37,20 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
var Papa = require("papaparse");
var errors = require("./errors.js");
var compare = require('natural-orderby').compare;
var freeDatas2HTML = (function () {
function freeDatas2HTML() {
var FreeDatas2HTML = (function () {
function FreeDatas2HTML() {
this._datasViewElt = { id: "", eltDOM: undefined };
this.datasHTML = "";
this._datasSelectors = [];
this._datasSortingColumns = [];
this._datasSortingFunctions = [];
this._datasSourceUrl = "";
this.parseMeta = undefined;
this._datasSortingFunctions = [];
this.parseMetas = undefined;
this.parseDatas = [];
this.parseErrors = [];
this.stopIfParseErrors = false;
this.datasSelectors = [];
this.datasSortingFields = [];
}
freeDatas2HTML.isPositiveInteger = function (nb) {
return (Number.isInteger(nb) === false || nb <= 0) ? false : true;
};
freeDatas2HTML.isNaturalNumber = function (nb) {
return (Number.isInteger(nb) === false || nb < 0) ? false : true;
};
Object.defineProperty(freeDatas2HTML.prototype, "datasViewElt", {
Object.defineProperty(FreeDatas2HTML.prototype, "datasViewElt", {
set: function (elt) {
var checkContainerExist = document.getElementById(elt.id);
if (checkContainerExist === null)
@ -69,7 +63,7 @@ var freeDatas2HTML = (function () {
enumerable: true,
configurable: true
});
Object.defineProperty(freeDatas2HTML.prototype, "datasSourceUrl", {
Object.defineProperty(FreeDatas2HTML.prototype, "datasSourceUrl", {
set: function (url) {
if (url.trim().length === 0)
throw new Error(errors.needUrl);
@ -79,122 +73,24 @@ var freeDatas2HTML = (function () {
enumerable: true,
configurable: true
});
Object.defineProperty(freeDatas2HTML.prototype, "datasSelectors", {
get: function () {
return this._datasSelectors;
},
set: function (selectionElts) {
this._datasSelectors = [];
var checkContainerExist;
for (var i in selectionElts) {
checkContainerExist = document.getElementById(selectionElts[i].id);
if (checkContainerExist === null)
console.error(errors.elementNotFound + selectionElts[i].id);
else if (freeDatas2HTML.isNaturalNumber(selectionElts[i].datasFieldNb) === false)
console.error(errors.needNaturalNumber);
else {
selectionElts[i].eltDOM = checkContainerExist;
if (selectionElts[i].separator !== undefined && selectionElts[i].separator === "")
selectionElts[i].separator = undefined;
this._datasSelectors.push(selectionElts[i]);
}
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(freeDatas2HTML.prototype, "datasSortingColumns", {
get: function () {
return this._datasSortingColumns;
},
set: function (sortingColumns) {
this._datasSortingColumns = [];
for (var i = 0; i < sortingColumns.length; i++) {
if (freeDatas2HTML.isNaturalNumber(sortingColumns[i].datasFieldNb) === false)
console.error(errors.needNaturalNumber);
else {
sortingColumns[i].order = undefined;
this._datasSortingColumns.push(sortingColumns[i]);
}
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(freeDatas2HTML.prototype, "datasSortingFunctions", {
set: function (sortingFunctions) {
Object.defineProperty(FreeDatas2HTML.prototype, "datasSortingFunctions", {
set: function (SortingFunctions) {
this._datasSortingFunctions = [];
for (var i = 0; i < sortingFunctions.length; i++) {
if (freeDatas2HTML.isNaturalNumber(sortingFunctions[i].datasFieldNb) === false)
console.error(errors.needNaturalNumber);
else
this._datasSortingFunctions.push(sortingFunctions[i]);
for (var i = 0; i < SortingFunctions.length; i++) {
this._datasSortingFunctions.push(SortingFunctions[i]);
}
},
enumerable: true,
configurable: true
});
freeDatas2HTML.prototype.getSortingFunctionForField = function (datasFieldNb) {
FreeDatas2HTML.prototype.getSortingFunctionForField = function (datasFieldNb) {
for (var i in this._datasSortingFunctions) {
if (this._datasSortingFunctions[i].datasFieldNb === datasFieldNb)
return this._datasSortingFunctions[i];
}
return undefined;
};
Object.defineProperty(freeDatas2HTML.prototype, "pagination", {
get: function () {
return this._pagination;
},
set: function (config) {
this._pagination = {};
if (config.selectedValue !== undefined || config.options !== undefined) {
if (config.pages === undefined)
throw new Error(errors.needPagesSelectorElt);
var checkContainerExist = document.getElementById(config.pages.displayElement.id);
if (checkContainerExist === null)
throw new Error(errors.elementNotFound + config.pages.displayElement.id);
else {
this.pagination.pages =
{
displayElement: {
id: config.pages.displayElement.id,
eltDOM: checkContainerExist
},
name: (config.pages.name) ? config.pages.name : "Pages :",
selectedValue: 1,
};
}
}
if (config.options !== undefined) {
var checkContainerExist = document.getElementById(config.options.displayElement.id);
if (checkContainerExist === null)
throw new Error(errors.elementNotFound + config.options.displayElement.id);
else {
for (var i = 0; i < config.options.values.length; i++) {
if (freeDatas2HTML.isPositiveInteger(config.options.values[i]) === false)
throw new Error(errors.needPositiveInteger);
}
this._pagination.options =
{
displayElement: { id: config.options.displayElement.id, eltDOM: checkContainerExist },
name: (config.options.name) ? config.options.name : "Pagination :",
values: config.options.values
};
}
}
if (config.selectedValue !== undefined) {
if (config.options !== undefined && (config.options.values.indexOf(config.selectedValue) === -1))
throw new Error(errors.needPaginationByDefaultBeInOptions);
if (freeDatas2HTML.isPositiveInteger(config.selectedValue))
this._pagination.selectedValue = config.selectedValue;
else
throw new Error(errors.needPositiveInteger);
}
},
enumerable: true,
configurable: true
});
freeDatas2HTML.prototype.parse = function () {
FreeDatas2HTML.prototype.parse = function () {
return __awaiter(this, void 0, void 0, function () {
var converter;
return __generator(this, function (_a) {
@ -213,7 +109,7 @@ var freeDatas2HTML = (function () {
realFields.push(results.meta.fields[i]);
}
results.meta.fields = realFields;
converter.parseMeta = results.meta;
converter.parseMetas = results.meta;
resolve(true);
},
error: function (error) {
@ -229,9 +125,8 @@ var freeDatas2HTML = (function () {
});
});
};
freeDatas2HTML.prototype.run = function () {
FreeDatas2HTML.prototype.run = function () {
return __awaiter(this, void 0, void 0, function () {
var converter_1, selectorsHTML, i, values, colName, row, checkedValue, checkedValues, i_1, checkedValue, j, selectElement, values_1, selectorsHTML, j, selectElement_1, indexSelectedValue, i;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
@ -242,81 +137,11 @@ var freeDatas2HTML = (function () {
return [4, this.parse()];
case 1:
_a.sent();
if (this.parseDatas.length === 0 || this.parseMeta.fields === undefined)
if (this.parseDatas.length === 0 || this.parseMetas.fields === undefined)
throw new Error(errors.datasNotFound);
else if (this.stopIfParseErrors && this.parseErrors.length !== 0)
console.error(this.parseErrors);
else {
converter_1 = this;
if (this._datasSelectors.length > 0) {
selectorsHTML = [];
for (i in this._datasSelectors) {
if (this._datasSelectors[i].datasFieldNb > (this.parseMeta.fields.length - 1))
throw new Error(errors.selectorFieldNotFound);
else {
values = [], colName = this.parseMeta.fields[this._datasSelectors[i].datasFieldNb];
for (row in this.parseDatas) {
if (this._datasSelectors[i].separator === undefined) {
checkedValue = this.parseDatas[row][colName].trim();
if (checkedValue !== "" && values.indexOf(checkedValue) === -1)
values.push(checkedValue);
}
else {
checkedValues = this.parseDatas[row][colName].split(this._datasSelectors[i].separator);
for (i_1 in checkedValues) {
checkedValue = checkedValues[i_1].trim();
if (checkedValue !== "" && values.indexOf(checkedValue) === -1)
values.push(checkedValue);
}
}
}
if (values.length > 0) {
if (this.getSortingFunctionForField(this._datasSelectors[i].datasFieldNb) !== undefined)
values.sort(this.getSortingFunctionForField(this._datasSelectors[i].datasFieldNb).sort);
else
values.sort(compare());
this._datasSelectors[i].name = colName;
this._datasSelectors[i].values = values;
selectorsHTML[i] = "<label for='freeDatas2HTMLSelector" + i + "'>" + colName + " : </label><select name='freeDatas2HTMLSelector" + i + "' id='freeDatas2HTMLSelector" + i + "'><option value='0'>----</option>";
for (j in values)
selectorsHTML[i] += "<option value='" + (Number(j) + 1) + "'>" + values[j] + "</option>";
selectorsHTML[i] += "</select>";
this._datasSelectors[i].eltDOM.innerHTML = selectorsHTML[i];
selectElement = document.getElementById("freeDatas2HTMLSelector" + i);
selectElement.addEventListener('change', function (e) {
converter_1.datasHTML = converter_1.createDatasHTML(converter_1.parseMeta.fields, converter_1.parseDatas);
converter_1.refreshView();
});
}
}
}
}
if (converter_1.pagination !== undefined && converter_1.pagination.options !== undefined && converter_1.pagination.options.values.length > 0) {
values_1 = converter_1.pagination.options.values;
selectorsHTML = "<label for='freeDatas2HTMLPaginationSelector'>" + converter_1.pagination.options.name + " </label><select name='freeDatas2HTMLPaginationSelector' id='freeDatas2HTMLPaginationSelector'><option value='0'>----</option>";
for (j in values_1)
selectorsHTML += "<option value='" + (Number(j) + 1) + "'>" + values_1[j] + "</option>";
selectorsHTML += "</select>";
converter_1.pagination.options.displayElement.eltDOM.innerHTML = selectorsHTML;
selectElement_1 = document.getElementById("freeDatas2HTMLPaginationSelector");
if (converter_1.pagination.selectedValue !== undefined) {
indexSelectedValue = converter_1.pagination.options.values.indexOf(converter_1.pagination.selectedValue) + 1;
selectElement_1.value = "" + indexSelectedValue;
}
selectElement_1.addEventListener('change', function (e) {
if (selectElement_1.value === "0")
converter_1.pagination.selectedValue = undefined;
else
converter_1.pagination.selectedValue = values_1[Number(selectElement_1.value) - 1];
converter_1.datasHTML = converter_1.createDatasHTML(converter_1.parseMeta.fields, converter_1.parseDatas);
converter_1.refreshView();
});
}
for (i in this._datasSortingColumns) {
if (this._datasSortingColumns[i].datasFieldNb > (this.parseMeta.fields.length - 1))
throw new Error(errors.sortingColumnsFieldNotFound);
}
this.datasHTML = this.createDatasHTML(this.parseMeta.fields, this.parseDatas);
this.refreshView();
return [2, true];
}
@ -325,55 +150,26 @@ var freeDatas2HTML = (function () {
});
});
};
freeDatas2HTML.prototype.refreshView = function () {
if (this._datasViewElt.eltDOM !== undefined) {
var converter_2 = this;
this._datasViewElt.eltDOM.innerHTML = this.datasHTML;
if (this._datasSortingColumns.length > 0) {
var getTableTh = document.querySelectorAll("table th");
if (getTableTh !== null) {
var _loop_1 = function (i) {
var datasFieldNb = this_1._datasSortingColumns[i].datasFieldNb;
var htmlContent = getTableTh[datasFieldNb].innerHTML;
htmlContent = "<a href='#freeDatas2HTMLSorting" + datasFieldNb + "' id='freeDatas2HTMLSorting" + datasFieldNb + "'>" + htmlContent + "</a>";
getTableTh[datasFieldNb].innerHTML = htmlContent;
var sortingElement = document.getElementById("freeDatas2HTMLSorting" + datasFieldNb);
sortingElement.addEventListener("click", function (e) {
e.preventDefault();
var order = converter_2.datasSortingColumns[i].order;
if (order === undefined || order === "desc")
converter_2.datasSortingColumns[i].order = "asc";
else
converter_2.datasSortingColumns[i].order = "desc";
converter_2._datasSortedColumn = converter_2.datasSortingColumns[i];
converter_2.datasHTML = converter_2.createDatasHTML(converter_2.parseMeta.fields, converter_2.parseDatas);
converter_2.refreshView();
});
};
var this_1 = this;
for (var i in this._datasSortingColumns) {
_loop_1(i);
}
}
}
FreeDatas2HTML.prototype.refreshView = function () {
if (this.parseMetas === undefined || this.parseMetas.fields === undefined || this._datasViewElt.eltDOM === undefined)
throw new Error(errors.refreshFail);
this.datasHTML = this.createDatasHTML(this.parseMetas.fields, this.parseDatas);
this._datasViewElt.eltDOM.innerHTML = this.datasHTML;
for (var i in this.datasSortingFields) {
var field = this.datasSortingFields[i];
field.field2HTML();
}
};
freeDatas2HTML.prototype.createDatasHTML = function (fields, datas) {
var checkSelectorExist, filters = [];
for (var i in this._datasSelectors) {
checkSelectorExist = document.querySelector("#" + this._datasSelectors[i].id + " select");
if (checkSelectorExist != null && checkSelectorExist.selectedIndex != 0)
filters.push({ field: this._datasSelectors[i].name, value: this._datasSelectors[i].values[checkSelectorExist.selectedIndex - 1], separator: this._datasSelectors[i].separator });
}
if (this._datasSortedColumn !== undefined) {
var col_1 = fields[this._datasSortedColumn.datasFieldNb];
var colOrder_1 = this._datasSortedColumn.order;
if (this.getSortingFunctionForField(this._datasSortedColumn.datasFieldNb) !== undefined) {
var myFunction_1 = this.getSortingFunctionForField(this._datasSortedColumn.datasFieldNb);
datas.sort(function (a, b) { return myFunction_1.sort(a[col_1], b[col_1], colOrder_1); });
FreeDatas2HTML.prototype.createDatasHTML = function (fields, datas) {
if (this.datasSortedField !== undefined && this.datasSortedField.datasFieldNb !== undefined) {
var field_1 = fields[this.datasSortedField.datasFieldNb];
var fieldOrder_1 = this.datasSortedField.order;
if (this.getSortingFunctionForField(this.datasSortedField.datasFieldNb) !== undefined) {
var myFunction_1 = this.getSortingFunctionForField(this.datasSortedField.datasFieldNb);
datas.sort(function (a, b) { return myFunction_1.sort(a[field_1], b[field_1], fieldOrder_1); });
}
else
datas.sort(function (a, b) { return compare({ order: colOrder_1 })(a[col_1], b[col_1]); });
datas.sort(function (a, b) { return compare({ order: fieldOrder_1 })(a[field_1], b[field_1]); });
}
var firstData = 0;
if (this.pagination !== undefined && this.pagination.selectedValue !== undefined && this.pagination.pages !== undefined && this.pagination.pages.selectedValue !== undefined)
@ -386,23 +182,10 @@ var freeDatas2HTML = (function () {
var nbVisible = 0, nbTotal = 0;
for (var row in datas) {
var visible = true;
if (filters.length !== 0) {
if (this.datasSelectors.length !== 0) {
var i = 0;
while (filters[i] !== undefined && visible === true) {
if (filters[i].separator === undefined) {
if (datas[row][filters[i].field].trim() !== filters[i].value)
visible = false;
}
else {
visible = false;
var checkedValues = datas[row][filters[i].field].split(filters[i].separator);
for (var j in checkedValues) {
if (checkedValues[j].trim() === filters[i].value) {
visible = true;
break;
}
}
}
while (this.datasSelectors[i] !== undefined && visible === true) {
visible = this.datasSelectors[i].dataIsOk(datas[row]);
i++;
}
}
@ -420,31 +203,13 @@ var freeDatas2HTML = (function () {
nbTotal++;
}
datasHTML += "</tbody></table>";
if (this.pagination !== undefined && this.pagination.selectedValue !== undefined && this.pagination.pages !== undefined && nbTotal > this.pagination.selectedValue) {
var nbPages = Math.ceil(nbTotal / this.pagination.selectedValue);
var selectorsHTML = "<label for='freeDatas2HTMLPagesSelector'>" + this.pagination.pages.name + " </label><select name='freeDatas2HTMLPagesSelector' id='freeDatas2HTMLPagesSelector'><option value='1'>1</option>";
this.pagination.pages.values = [1];
for (var j = 2; j <= nbPages; j++) {
selectorsHTML += "<option value='" + j + "'>" + j + "</option>";
this.pagination.pages.values.push(j);
}
selectorsHTML += "</select>";
this.pagination.pages.displayElement.eltDOM.innerHTML = selectorsHTML;
var selectElement_2 = document.getElementById("freeDatas2HTMLPagesSelector");
if (this.pagination.pages.selectedValue !== undefined)
selectElement_2.value = "" + this.pagination.pages.selectedValue;
var converter_3 = this;
this.pagination.pages.selectedValue = 1;
selectElement_2.addEventListener('change', function (e) {
converter_3.pagination.pages.selectedValue = Number(selectElement_2.value);
converter_3.datasHTML = converter_3.createDatasHTML(converter_3.parseMeta.fields, converter_3.parseDatas);
converter_3.refreshView();
});
}
else if (this.pagination !== undefined && this.pagination.pages !== undefined)
this.pagination.pages.displayElement.eltDOM.innerHTML = "";
if (this.pagination !== undefined)
this.pagination.creaPageSelector(nbTotal);
return datasHTML;
};
return freeDatas2HTML;
return FreeDatas2HTML;
}());
export { freeDatas2HTML };
export { FreeDatas2HTML };
export { Pagination } from "./freeDatas2HTMLPagination";
export { Selector } from "./freeDatas2HTMLSelector";
export { SortingField } from "./freeDatas2HTMLSortingField";

View File

@ -0,0 +1 @@
;

View File

@ -0,0 +1,119 @@
var errors = require("./errors.js");
var Pagination = (function () {
function Pagination(converter, pagesElt, pagesName) {
if (pagesName === void 0) { pagesName = "Pages"; }
if (converter.parseMetas === undefined || converter.parseMetas.fields === undefined)
throw new Error(errors.paginationNeedDatas);
else {
var checkContainerExist = document.getElementById(pagesElt.id);
if (checkContainerExist === null)
throw new Error(errors.elementNotFound + pagesElt.id);
else {
this._converter = converter;
this._pages = { displayElement: { id: pagesElt.id, eltDOM: checkContainerExist }, name: pagesName };
}
}
}
Pagination.isPositiveInteger = function (nb) {
return (Number.isInteger(nb) === false || nb <= 0) ? false : true;
};
Object.defineProperty(Pagination.prototype, "selectedValue", {
get: function () {
return this._selectedValue;
},
set: function (value) {
if (value === undefined || !Pagination.isPositiveInteger(value))
throw new Error(errors.needPositiveInteger);
if (this.options !== undefined && this.options.values.indexOf(value) === -1)
throw new Error(errors.needPaginationByDefaultBeInOptions);
this._selectedValue = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Pagination.prototype, "options", {
get: function () {
return this._options;
},
set: function (options) {
if (options !== undefined) {
var checkContainerExist = document.getElementById(options.displayElement.id);
if (checkContainerExist === null)
throw new Error(errors.elementNotFound + options.displayElement.id);
else
options.displayElement.eltDOM = checkContainerExist;
if (options.values.length === 0)
throw new Error(errors.needPaginationOptionsValues);
for (var i in options.values) {
if (!Pagination.isPositiveInteger(options.values[i]))
throw new Error(errors.needPositiveInteger);
}
options.name = (options.name === undefined) ? "Pagination" : options.name;
this._options = options;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(Pagination.prototype, "pages", {
get: function () {
return this._pages;
},
enumerable: true,
configurable: true
});
Pagination.prototype.rend2HTML = function () {
if (this._converter === undefined || this._options === undefined)
throw new Error(errors.pagination2HTMLFail);
else {
var selectorsHTML = "<label for='freeDatas2HTMLPaginationSelector'>" + this._options.name + " </label><select name='freeDatas2HTMLPaginationSelector' id='freeDatas2HTMLPaginationSelector'><option value='0'>----</option>";
for (var j in this._options.values)
selectorsHTML += "<option value='" + (Number(j) + 1) + "'>" + this._options.values[j] + "</option>";
selectorsHTML += "</select>";
this._options.displayElement.eltDOM.innerHTML = selectorsHTML;
var selectElement_1 = document.getElementById("freeDatas2HTMLPaginationSelector");
if (this._selectedValue !== undefined) {
var indexSelectedValue = this._options.values.indexOf(this._selectedValue) + 1;
selectElement_1.value = "" + indexSelectedValue;
}
var pagination_1 = this;
selectElement_1.addEventListener("change", function (e) {
if (selectElement_1.value === "0")
pagination_1._selectedValue = undefined;
else
pagination_1._selectedValue = pagination_1._options.values[Number(selectElement_1.value) - 1];
pagination_1._converter.refreshView();
});
}
};
Pagination.prototype.creaPageSelector = function (nbTotal) {
if (this.selectedValue !== undefined) {
if (nbTotal > this.selectedValue) {
var nbPages = Math.ceil(nbTotal / this.selectedValue);
var selectorsHTML = "<label for='freeDatas2HTMLPagesSelector'>" + this.pages.name + " </label><select name='freeDatas2HTMLPagesSelector' id='freeDatas2HTMLPagesSelector'><option value='1'>1</option>";
this.pages.values = [1];
for (var j = 2; j <= nbPages; j++) {
selectorsHTML += "<option value='" + j + "'>" + j + "</option>";
this.pages.values.push(j);
}
selectorsHTML += "</select>";
this.pages.displayElement.eltDOM.innerHTML = selectorsHTML;
var selectElement_2 = document.getElementById("freeDatas2HTMLPagesSelector");
if (this.pages.selectedValue !== undefined)
selectElement_2.value = "" + this.pages.selectedValue;
this.pages.selectedValue = 1;
var pagination_2 = this;
selectElement_2.addEventListener('change', function (e) {
pagination_2.pages.selectedValue = Number(selectElement_2.value);
pagination_2._converter.refreshView();
});
}
else
this.pages.displayElement.eltDOM.innerHTML = "";
}
else
this.pages.displayElement.eltDOM.innerHTML = "";
};
return Pagination;
}());
export { Pagination };

View File

@ -0,0 +1,129 @@
var compare = require('natural-orderby').compare;
var errors = require("./errors.js");
var Selector = (function () {
function Selector(converter) {
this._datasViewElt = { id: "", eltDOM: undefined };
this.name = "";
this.values = [];
if (converter.parseMetas === undefined || converter.parseMetas.fields === undefined || converter.parseDatas.length === 0)
throw new Error(errors.selectorNeedDatas);
else
this._converter = converter;
}
Object.defineProperty(Selector.prototype, "datasViewElt", {
get: function () {
return this._datasViewElt;
},
set: function (elt) {
var checkContainerExist = document.getElementById(elt.id);
if (checkContainerExist === null)
throw new Error(errors.elementNotFound + elt.id);
else {
this._datasViewElt.id = elt.id;
this._datasViewElt.eltDOM = checkContainerExist;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(Selector.prototype, "datasFieldNb", {
get: function () {
return this._datasFieldNb;
},
set: function (datasFieldNb) {
if (datasFieldNb !== undefined && this._converter.parseMetas.fields[datasFieldNb] === undefined)
throw new Error(errors.selectorFieldNotFound);
else
this._datasFieldNb = datasFieldNb;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Selector.prototype, "separator", {
set: function (separator) {
if (separator === "")
this._separator = undefined;
else
this._separator = separator;
},
enumerable: true,
configurable: true
});
Selector.prototype.selector2HTML = function () {
if (this._converter === undefined || this._datasViewElt.eltDOM === undefined || this._datasFieldNb === undefined)
throw new Error(errors.selector2HTMLFail);
else {
this.name = this._converter.parseMetas.fields[this._datasFieldNb];
for (var row in this._converter.parseDatas) {
if (this._separator === undefined) {
var checkedValue = String(this._converter.parseDatas[row][this.name]).trim();
if (checkedValue !== "" && this.values.indexOf(checkedValue) === -1)
this.values.push(checkedValue);
}
else {
var checkedValues = String(this._converter.parseDatas[row][this.name]).split(this._separator);
for (var i in checkedValues) {
var checkedValue = checkedValues[i].trim();
if (checkedValue !== "" && this.values.indexOf(checkedValue) === -1)
this.values.push(checkedValue);
}
}
}
if (this.values.length > 0) {
if (this._converter.getSortingFunctionForField(this._datasFieldNb) !== undefined)
this.values.sort(this._converter.getSortingFunctionForField(this._datasFieldNb).sort);
else
this.values.sort(compare());
var selectorsHTML = "<label for='freeDatas2HTML_" + this._datasViewElt.id + "'>" + this.name + " : </label><select name='freeDatas2HTML_" + this._datasViewElt.id + "' id='freeDatas2HTML_" + this._datasViewElt.id + "'><option value='0'>----</option>";
for (var j in this.values)
selectorsHTML += "<option value='" + (Number(j) + 1) + "'>" + this.values[j] + "</option>";
selectorsHTML += "</select>";
this._datasViewElt.eltDOM.innerHTML = selectorsHTML;
var selectElement = document.getElementById("freeDatas2HTML_" + this._datasViewElt.id), mySelector_1 = this;
selectElement.addEventListener("change", function (e) {
mySelector_1._converter.refreshView();
});
}
}
};
Selector.prototype.getSelectionnedId = function () {
var selectElement = document.getElementById("freeDatas2HTML_" + this._datasViewElt.id);
if (selectElement === undefined)
return 0;
else
return parseInt(selectElement.value, 10);
};
Selector.prototype.dataIsOk = function (data) {
if (this.name === undefined || this.name === "")
throw new Error(errors.selectorCheckIsOkFail);
var selectedValue = this.getSelectionnedId();
if (selectedValue === 0)
return true;
else
selectedValue = selectedValue - 1;
if (this.values[selectedValue] === undefined)
throw new Error(errors.selectorSelectedIndexNotFound);
if (data[this.name] === undefined)
return false;
var selectedValueTxt = this.values[selectedValue];
if (this._separator === undefined) {
if (data[this.name].trim() !== selectedValueTxt)
return false;
else
return true;
}
else {
var find = false;
var checkedValues = String(data[this.name]).split(this._separator);
for (var j in checkedValues) {
if (checkedValues[j].trim() === selectedValueTxt) {
find = true;
break;
}
}
return find;
}
};
return Selector;
}());
export { Selector };

View File

@ -0,0 +1,64 @@
var compare = require('natural-orderby').compare;
var errors = require("./errors.js");
var SortingField = (function () {
function SortingField(converter, fieldsDOMSelector) {
if (fieldsDOMSelector === void 0) { fieldsDOMSelector = "th"; }
this._order = undefined;
if (converter.parseMetas === undefined || converter.parseMetas.fields === undefined)
throw new Error(errors.sortingFieldNeedDatas);
else {
var fields = document.querySelectorAll(fieldsDOMSelector);
if (fields === undefined)
throw new Error(errors.sortingFieldsNotInHTML);
else if (fields.length !== converter.parseMetas.fields.length)
throw new Error(errors.sortingFieldsNbFail);
else {
this._converter = converter;
this._fieldsDOMSelector = fieldsDOMSelector;
}
}
}
Object.defineProperty(SortingField.prototype, "datasFieldNb", {
get: function () {
return this._datasFieldNb;
},
set: function (datasFieldNb) {
if (datasFieldNb !== undefined && this._converter.parseMetas.fields[datasFieldNb] === undefined)
throw new Error(errors.sortingFieldFieldNotFound);
else
this._datasFieldNb = datasFieldNb;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SortingField.prototype, "order", {
get: function () {
return this._order;
},
enumerable: true,
configurable: true
});
SortingField.prototype.field2HTML = function () {
if (this._converter === undefined || this._fieldsDOMSelector === "" || this._datasFieldNb === undefined)
throw new Error(errors.sortingField2HTMLFail);
else {
var fields = document.querySelectorAll(this._fieldsDOMSelector);
var htmlContent = fields[this._datasFieldNb].innerHTML;
htmlContent = "<a href='#freeDatas2HTMLSorting" + this._datasFieldNb + "' id='freeDatas2HTMLSorting" + this._datasFieldNb + "'>" + htmlContent + "</a>";
fields[this._datasFieldNb].innerHTML = htmlContent;
var sortingElement = document.getElementById("freeDatas2HTMLSorting" + this._datasFieldNb), field_1 = this;
sortingElement.addEventListener("click", function (e) {
e.preventDefault();
var order = field_1._order;
if (order === undefined || order === "desc")
field_1._order = "asc";
else
field_1._order = "desc";
field_1._converter.datasSortedField = field_1;
field_1._converter.refreshView();
});
}
};
return SortingField;
}());
export { SortingField };

View File

@ -3,11 +3,13 @@ module.exports =
datasNotFound : "Aucune donnée n'a été trouvée.",
elementNotFound : "Aucun élément HTML n'a été trouvé ayant comme \"id\" : ",
needDatasElt: "Merci de fournir un id valide pour l'élément où afficher les données.",
needNaturalNumber: "Merci de fournir un nombre entier supérieur ou égal à zéro pour désigner chaque colonne.",
needPagesSelectorElt: "Merci de fournir l'id de l'élément où afficher le sélecteur de pages.",
needPaginationByDefaultBeInOptions: "La valeur de pagination par défaut doit faire partie des options proposées.",
needPaginationOptionsValues: "Vous n'avez fourni aucune options possibles pour la pagination.",
needPositiveInteger: "Merci de fournir un nombre entier supérieur à zéro pour désigner chaque option de pagination.",
needUrl: "Merci de fournir une url valide pour le fichier CSV à parser.",
paginationNeedDatas: "Il ne peut y avoir de pagination, si les données n'ont pas été récupérées.",
pagination2HTMLFail : "Toutes les donnée nécessaires à la création des sélecteurs de pagination n'ont pas été fournies.",
parserFail: "La lecture des données du fichier a échoué.",
refreshFail: "Le nom des champs et l'élement du DOM receveur sont nécessaires à l'affichage des données.",
selector2HTMLFail: "Le création d'un filtre dans le DOM nécessite l'initialisation de l'élément HTML et du numéro du champs à filter.",

View File

@ -1,13 +1,10 @@
import { freeDatas2HTML } from "./freeDatas2HTML";
import { FreeDatas2HTML, Pagination, Selector, SortingField } from "./freeDatas2HTML";
const initialise = async () =>
{
try
{
let converter=new freeDatas2HTML();
converter.datasViewElt={ id:"datas" };
converter.datasSelectors=[{ datasFieldNb:3, id:"filtre1"}, { datasFieldNb:4, id:"filtre2"},{ datasFieldNb:5, id:"filtre3", separator:"," }];
// Fonction spécifique de classement utile pour les données du 4ième champs
const mySort = (a: any, b: any, order: "asc"|"desc" = "asc") =>
{
const values = [ "> 100000", "> 1 et < 100 000", "≤ 1", "Traces", "Inexistant"];
@ -20,25 +17,56 @@ const initialise = async () =>
else
return 0;
};
converter.datasSortingColumns=[{ datasFieldNb:0 }, { datasFieldNb:1 },{ datasFieldNb:2 }, { datasFieldNb:4 }];
converter.datasSortingFunctions= [{ datasFieldNb:4, sort:mySort}];
converter.pagination=
{
selectedValue:10,
options:
{
displayElement : { id:"paginationOptions" },
values: [10,20,50,500],
name: "Choix de pagination :"
},
pages:
{
displayElement : { id:"pages" },
name: "Page à afficher :"
}
}
// Création d'un convertisseur parsant les données d'un fichier CSV "distant"
let converter=new FreeDatas2HTML();
converter.datasViewElt={ id:"datas" };
converter.datasSourceUrl="http://localhost:8080/datas/elements-chimiques.csv";
await converter.parse();
converter.datasSortingFunctions=[{ datasFieldNb: 4, sort:mySort }];
// Configuration de la pagination
const pagination=new Pagination(converter, { id:"pages" }, "Page à afficher :");
pagination.options={ displayElement: { id:"paginationOptions" }, values: [10,20,50,500] , name: "Choix de pagination :" };
pagination.selectedValue=10; // revoir car n'est pas testé si déclaré avant les options
converter.pagination=pagination;
pagination.rend2HTML();
// Affichage initial
await converter.run();
// Création d'outils permettant de filtrer les données des champs de données
let filtre1=new Selector(converter);
filtre1.datasViewElt={ id:"filtre1"};
filtre1.datasFieldNb=3;
filtre1.selector2HTML();
let filtre2=new Selector(converter);
filtre2.datasViewElt={ id:"filtre2"};
filtre2.datasFieldNb=4;
filtre2.selector2HTML();
let filtre3=new Selector(converter);
filtre3.datasViewElt={ id:"filtre3"};
filtre3.datasFieldNb=5;
filtre3.separator=",";
filtre3.selector2HTML();
// Injection des filtres dans le convertisseur
converter.datasSelectors=[filtre1,filtre2,filtre3];
// Ajout de champs permettant de classer les données
let sortingField1=new SortingField(converter);
sortingField1.datasFieldNb=0;
sortingField1.field2HTML();
let sortingField2=new SortingField(converter);
sortingField2.datasFieldNb=1;
sortingField2.field2HTML();
let sortingField3=new SortingField(converter);
sortingField3.datasFieldNb=2;
sortingField3.field2HTML();
let sortingField4=new SortingField(converter);
sortingField4.datasFieldNb=4;
sortingField4.field2HTML();
// Injection dans le convertisseur
converter.datasSortingFields=[sortingField1,sortingField2,sortingField3,sortingField4];
}
catch(e)
{

View File

@ -2,7 +2,8 @@ const Papa = require("papaparse");
const errors = require("./errors.js");
const { compare }= require('natural-orderby');
import { DOMElement, Pagination, Selectors, SortingFields, SortingFunctions } from "./freeDatas2HTMLInterfaces";
import { DOMElement, Paginations, Selectors, SortingFields, SortingFunctions } from "./freeDatas2HTMLInterfaces";
import { Pagination} from "./freeDatas2HTMLPagination";
import { Selector } from "./freeDatas2HTMLSelector";
import { SortingField } from "./freeDatas2HTMLSortingField";
@ -39,19 +40,8 @@ export class FreeDatas2HTML
datasSortedField: SortingFields|undefined;
// La Pagination :
private _Pagination: Pagination|undefined;
// Fonction utile pour tester les numéros de colonne :
public static isPositiveInteger(nb: number)
{
return (Number.isInteger(nb) === false || nb <= 0) ? false : true;
}
// Fonction utile pour tester les valeurs de Pagination :
public static isNaturalNumber(nb: number)
{
return (Number.isInteger(nb) === false || nb < 0) ? false : true;
}
pagination: Paginations|undefined;
// Vérifie que l'élément devant afficher les données existe dans le DOM :
set datasViewElt(elt: DOMElement)
{
@ -80,9 +70,9 @@ export class FreeDatas2HTML
this._datasSortingFunctions=[];
for(let i = 0; i < SortingFunctions.length; i++)
{
if(FreeDatas2HTML.isNaturalNumber(SortingFunctions[i].datasFieldNb) === false)
console.error(errors.needNaturalNumber);
else
//if(FreeDatas2HTML.isNaturalNumber(SortingFunctions[i].datasFieldNb) === false) // revoir pour tester l'existence du champ
// console.error(errors.needNaturalNumber); // -> à remplacer par un test d'existence de colonne !
//else
this._datasSortingFunctions.push(SortingFunctions[i]);
}
}
@ -98,73 +88,6 @@ export class FreeDatas2HTML
return undefined;
}
// Vérifie la cohérence de toutes les options de pagination reçues :
set Pagination(config: Pagination)
{
this._Pagination={};
// Si une valeur par défaut est fournie ou des valeurs en option, un id valide doit être aussi fourni pour recueillir le sélecteur de pages :
if(config.selectedValue !== undefined || config.options !== undefined)
{
if(config.pages === undefined)
throw new Error(errors.needPagesSelectorElt);
let checkContainerExist=document.getElementById(config.pages.displayElement.id);
if(checkContainerExist === null)
throw new Error(errors.elementNotFound+config.pages.displayElement.id);
else
{
this.Pagination.pages =
{
displayElement:
{
id:config.pages.displayElement.id,
eltDOM: checkContainerExist
},
name: (config.pages.name) ? config.pages.name : "Pages :", // rendre obligatoire cette option s'il doit y avoir affichage ?
selectedValue:1, // c'est la 1ère page qui est affichée par défaut
}
}
}
// Les options de Pagination proposées à l'utilisateur :
if(config.options !== undefined)
{
// Un élément HTML doit exister pour accueillir les options :
let checkContainerExist=document.getElementById(config.options.displayElement.id);
if(checkContainerExist === null)
throw new Error(errors.elementNotFound+config.options.displayElement.id);
else
{
// Seules des entiers positifs sont possibles
for(let i = 0; i < config.options.values.length; i++)
{
if(FreeDatas2HTML.isPositiveInteger(config.options.values[i]) === false)
throw new Error(errors.needPositiveInteger);
}
this._Pagination.options =
{
displayElement: { id:config.options.displayElement.id, eltDOM:checkContainerExist },
name: (config.options.name) ? config.options.name : "Pagination :", // idem, rendre obligatoire ?
values:config.options.values
};
}
}
// Valeur de Pagination par défaut qui doit faire partie des options proposées si elles existent :
if(config.selectedValue !== undefined)
{
if(config.options !== undefined && (config.options.values.indexOf(config.selectedValue) === -1))
throw new Error(errors.needPaginationByDefaultBeInOptions);
if(FreeDatas2HTML.isPositiveInteger(config.selectedValue))
this._Pagination.selectedValue=config.selectedValue;
else
throw new Error(errors.needPositiveInteger);
}
}
// Retourne les options de Pagination actuelles
get Pagination(): Pagination
{
return <Pagination>this._Pagination;
}
// Parse des données distantes (url) fournies en CSV :
public async parse(): Promise<any>
{
@ -220,37 +143,7 @@ export class FreeDatas2HTML
else if(this.stopIfParseErrors && this.parseErrors.length!==0)
console.error(this.parseErrors);
else
{
let converter=this;
// Si demandé, création d'une liste de valeurs de Pagination possibles
if(converter.Pagination !==undefined && converter.Pagination.options !==undefined && converter.Pagination.options.values.length > 0)
{
const values=converter.Pagination.options.values;
let selectorsHTML="<label for='freeDatas2HTMLPaginationSelector'>"+converter.Pagination.options.name+" </label><select name='freeDatas2HTMLPaginationSelector' id='freeDatas2HTMLPaginationSelector'><option value='0'>----</option>";
for(let j in values)
selectorsHTML+="<option value='"+(Number(j)+1)+"'>"+values[j]+"</option>";
selectorsHTML+="</select>";
converter.Pagination.options.displayElement.eltDOM!.innerHTML=selectorsHTML;
let selectElement = document.getElementById("freeDatas2HTMLPaginationSelector") as HTMLInputElement;
// Si une Pagination par défaut existe, on la sélectionne :
if(converter.Pagination.selectedValue !== undefined)
{
let indexSelectedValue=converter.Pagination.options.values.indexOf(converter.Pagination.selectedValue)+1;
selectElement.value=""+indexSelectedValue;
}
selectElement.addEventListener('change', function(e)
{
if(selectElement.value === "0")
converter.Pagination.selectedValue=undefined; // = pas de Pagination
else
converter.Pagination.selectedValue=values[Number(selectElement.value)-1];
// on regénère le HTML :
converter.datasHTML=converter.createDatasHTML(converter.parseMetas!.fields as string[], converter.parseDatas);
converter.refreshView();
});
}
{
// Si tout est ok, affichage initial de toutes les données du fichier
this.refreshView();
return true;
@ -287,12 +180,12 @@ export class FreeDatas2HTML
else
datas.sort( (a, b) => compare( {order: fieldOrder} )(a[field], b[field]));
}
// Dois-je prendre en compte une Pagination ?
// Dois-je prendre en compte une pagination ?
let firstData=0;
if (this.Pagination !== undefined && this.Pagination.selectedValue !== undefined && this.Pagination.pages !== undefined && this.Pagination.pages.selectedValue !== undefined)
firstData=this.Pagination.selectedValue*(this.Pagination.pages.selectedValue-1);
let maxData = (this.Pagination !== undefined && this.Pagination.selectedValue !== undefined) ? this.Pagination.selectedValue : datas.length+1;
if (this.pagination !== undefined && this.pagination.selectedValue !== undefined && this.pagination.pages !== undefined && this.pagination.pages.selectedValue !== undefined)
firstData=this.pagination.selectedValue*(this.pagination.pages.selectedValue-1);
let maxData = (this.pagination !== undefined && this.pagination.selectedValue !== undefined) ? this.pagination.selectedValue : datas.length+1;
// Création du tableau de données :
let datasHTML="<table><thead>";
@ -308,7 +201,7 @@ export class FreeDatas2HTML
let i=0;
while(this.datasSelectors[i] !== undefined && visible===true)
{
visible=this.datasSelectors[i].dataIsOk(datas[row]); // à revoir car cette fonction est nécessaire !
visible=this.datasSelectors[i].dataIsOk(datas[row]);
i++;
}
}
@ -329,39 +222,14 @@ export class FreeDatas2HTML
nbTotal++;
}
datasHTML+="</tbody></table>";
// Si Pagination définie et tous les enregistrements n'ont pas été affichés, alors création d'un sélecteur de pages
if (this.Pagination !== undefined && this.Pagination.selectedValue !== undefined && this.Pagination.pages !== undefined && nbTotal > this.Pagination.selectedValue)
{
let nbPages=Math.ceil(nbTotal/this.Pagination.selectedValue);
let selectorsHTML="<label for='freeDatas2HTMLPagesSelector'>"+this.Pagination.pages.name+" </label><select name='freeDatas2HTMLPagesSelector' id='freeDatas2HTMLPagesSelector'><option value='1'>1</option>";
this.Pagination.pages.values=[1];
for(let j=2; j <= nbPages; j++)
{
selectorsHTML+="<option value='"+j+"'>"+j+"</option>";
this.Pagination.pages.values.push(j);
}
selectorsHTML+="</select>";
this.Pagination.pages.displayElement.eltDOM!.innerHTML=selectorsHTML;
let selectElement = document.getElementById("freeDatas2HTMLPagesSelector") as HTMLInputElement;
if(this.Pagination.pages.selectedValue !== undefined)
selectElement.value=""+this.Pagination.pages.selectedValue;
let converter=this;
this.Pagination.pages.selectedValue=1;
selectElement.addEventListener('change', function(e)
{
converter.Pagination.pages!.selectedValue=Number(selectElement.value);
converter.datasHTML=converter.createDatasHTML(converter.parseMetas!.fields as string[], converter.parseDatas);
converter.refreshView();
});
}
else if(this.Pagination !== undefined && this.Pagination.pages !== undefined)
this.Pagination.pages.displayElement.eltDOM!.innerHTML="";
// Tout réaffichage peut entraîner une modification du nombre de pages (évolution filtres, etc.)
if(this.pagination !== undefined)
this.pagination.creaPageSelector(nbTotal);
return datasHTML;
}
}
// Permet l'appel des dépendances via un seul script
export { Pagination } from "./freeDatas2HTMLPagination";
export { Selector } from "./freeDatas2HTMLSelector";
export { SortingField } from "./freeDatas2HTMLSortingField";

View File

@ -3,6 +3,27 @@ export interface DOMElement
id: string;
eltDOM?: HTMLElement;
}
export interface Paginations
{
options?: PaginationsOptions;
selectedValue?: number; // on peut utiliser une Pagination sans proposer d'options à l'utilisateur.
pages: PaginationsPages;
rend2HTML(): void;
creaPageSelector(nbTotal:number) : void;
}
export interface PaginationsOptions
{
displayElement: DOMElement;
name?: string;
values: number[];
};
export interface PaginationsPages
{
displayElement: DOMElement;
name: string;
values?: number[];
selectedValue?: number;
}
export interface Selectors
{
datasViewElt: DOMElement;
@ -23,21 +44,4 @@ export interface SortingFunctions
{
datasFieldNb: number;
sort(a: any,b: any, order?: "asc"|"desc"): number; // cf. https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
}
export interface Pagination
{
options?:
{
displayElement: DOMElement;
name?: string; // rendre obligatoire ?
values: number[];
};
selectedValue?: number; // on peut utiliser une Pagination sans proposer d'options à l'utilisateur.
pages?:
{
displayElement: DOMElement;
name?: string; // rendre obligatoire ?
values?: number[];
selectedValue?: number;
}
}

View File

@ -0,0 +1,150 @@
const errors = require("./errors.js");
import { DOMElement, Paginations, PaginationsOptions, PaginationsPages } from "./freeDatas2HTMLInterfaces";
import { FreeDatas2HTML } from "./freeDatas2HTML";
export class Pagination implements Paginations
{
private _converter: FreeDatas2HTML;
// la pagination en cours, qui peut être modifiée/initialisée par l'utilisateur, si des options lui sont proposées :
private _selectedValue: number|undefined;
// les éventuelles options de pagination :
private _options: PaginationsOptions | undefined;
// les pages proposées, si le nombre d'enregistrement est > à la pagination en cours.
private _pages: PaginationsPages;
public static isPositiveInteger(nb: number)
{
return (Number.isInteger(nb) === false || nb <= 0) ? false : true;
}
// Injection de la classe principale, mais uniquement si les données ont été importées
// De plus l'élément du DOM devant recevoir la liste des pages doit exister
constructor(converter: FreeDatas2HTML, pagesElt: DOMElement, pagesName: string="Pages")
{
if(converter.parseMetas === undefined || converter.parseMetas.fields === undefined)
throw new Error(errors.paginationNeedDatas);
else
{
let checkContainerExist=document.getElementById(pagesElt.id);
if(checkContainerExist === null)
throw new Error(errors.elementNotFound+pagesElt.id);
else
{
this._converter=converter;
this._pages={ displayElement: { id:pagesElt.id, eltDOM:checkContainerExist }, name: pagesName };
}
}
}
set selectedValue(value : number|undefined)
{
if(value === undefined || !Pagination.isPositiveInteger(value))
throw new Error(errors.needPositiveInteger);
if(this.options !== undefined && this.options.values.indexOf(value) === -1)
throw new Error(errors.needPaginationByDefaultBeInOptions);
this._selectedValue=value;
}
get selectedValue() : number|undefined
{
return this._selectedValue;
}
set options(options : PaginationsOptions|undefined)
{
if(options !== undefined)
{
let checkContainerExist=document.getElementById(options.displayElement.id);
if(checkContainerExist === null)
throw new Error(errors.elementNotFound+options.displayElement.id);
else
options.displayElement.eltDOM=checkContainerExist;
if(options.values.length === 0)
throw new Error(errors.needPaginationOptionsValues);
for(let i in options.values)
{
if(!Pagination.isPositiveInteger(options.values[i]))
throw new Error(errors.needPositiveInteger);
}
options.name= (options.name===undefined) ? "Pagination" : options.name ; // on garde la possibilité d'une chaîne vide, si souhaité
this._options=options;
}
}
get options() : PaginationsOptions|undefined
{
return this._options;
}
get pages() : PaginationsPages
{
return this._pages;
}
// Création du <select> correspondant aux choix de valeurs de pagination.
public rend2HTML() : void
{
if(this._converter === undefined || this._options === undefined)
throw new Error(errors.pagination2HTMLFail);
else
{
let selectorsHTML="<label for='freeDatas2HTMLPaginationSelector'>"+this._options.name+" </label><select name='freeDatas2HTMLPaginationSelector' id='freeDatas2HTMLPaginationSelector'><option value='0'>----</option>";
for(let j in this._options.values)
selectorsHTML+="<option value='"+(Number(j)+1)+"'>"+this._options.values[j]+"</option>";
selectorsHTML+="</select>";
this._options.displayElement.eltDOM!.innerHTML=selectorsHTML; // initialiser dans le setter
let selectElement=document.getElementById("freeDatas2HTMLPaginationSelector") as HTMLInputElement;
// Si une Pagination par défaut existe, on la sélectionne :
if(this._selectedValue !== undefined)
{
let indexSelectedValue=this._options.values.indexOf(this._selectedValue)+1;
selectElement.value=""+indexSelectedValue;
}
const pagination=this;
selectElement.addEventListener("change", function(e)
{
if(selectElement.value === "0")
pagination._selectedValue=undefined; // = pas de Pagination
else
pagination._selectedValue=pagination._options!.values[Number(selectElement.value)-1];
// on regénère le HTML :
pagination._converter.refreshView();
});
}
}
// Création du <select> permettant de changer de page
creaPageSelector(nbTotal:number) : void
{
if (this.selectedValue !== undefined)
{
if( nbTotal > this.selectedValue)
{
let nbPages=Math.ceil(nbTotal/this.selectedValue);
let selectorsHTML="<label for='freeDatas2HTMLPagesSelector'>"+this.pages.name+" </label><select name='freeDatas2HTMLPagesSelector' id='freeDatas2HTMLPagesSelector'><option value='1'>1</option>";
this.pages.values=[1];
for(let j=2; j <= nbPages; j++)
{
selectorsHTML+="<option value='"+j+"'>"+j+"</option>";
this.pages.values.push(j);
}
selectorsHTML+="</select>";
this.pages.displayElement.eltDOM!.innerHTML=selectorsHTML;
let selectElement=document.getElementById("freeDatas2HTMLPagesSelector") as HTMLInputElement;
if(this.pages.selectedValue !== undefined)
selectElement.value=""+this.pages.selectedValue;
this.pages.selectedValue=1;
let pagination=this;
selectElement.addEventListener('change', function(e)
{
pagination.pages.selectedValue=Number(selectElement.value);
pagination._converter.refreshView();
});
}
else
this.pages.displayElement.eltDOM!.innerHTML="";
}
else
this.pages.displayElement.eltDOM!.innerHTML="";
}
}

View File

@ -2,7 +2,7 @@ import { FreeDatas2HTML, Selector } from "../src/freeDatas2HTML";
const errors=require("../src/errors.js");
const fixtures=require("./fixtures.js");
xdescribe("Test du script central de FreeDatas2HTML", () =>
describe("Test du script central de FreeDatas2HTML", () =>
{
let converter: FreeDatas2HTML;
@ -39,23 +39,7 @@ xdescribe("Test du script central de FreeDatas2HTML", () =>
expect(() => { return converter.datasSourceUrl=" "; }).toThrowError(errors.needUrl);
});
it("Doit retourner un booléen indiquant si un nombre est naturel ou non.", () =>
{
expect(FreeDatas2HTML.isNaturalNumber(-1)).toBeFalse();
expect(FreeDatas2HTML.isNaturalNumber(1.25)).toBeFalse();
expect(FreeDatas2HTML.isNaturalNumber(0)).toBeTrue();
expect(FreeDatas2HTML.isNaturalNumber(1)).toBeTrue();
});
it("Doit retourner un booléen indiquant si un nombre est un entier positif ou non.", () =>
{
expect(FreeDatas2HTML.isPositiveInteger(-1)).toBeFalse();
expect(FreeDatas2HTML.isPositiveInteger(1.25)).toBeFalse();
expect(FreeDatas2HTML.isPositiveInteger(0)).toBeFalse();
expect(FreeDatas2HTML.isPositiveInteger(1)).toBeTrue();
});
// Classement des données :
// Fonction spécfique de classement des données :
it("Doit me retourner la fonction associée à une colonne, de manière à ce qu'elle soit utilisable pour comparer deux valeurs.", () =>
{
// Fonction volontairement basique, car ce n'est pas la fonction que l'on teste ici, mais le fait que l'on puisse l'utiliser !
@ -72,58 +56,6 @@ xdescribe("Test du script central de FreeDatas2HTML", () =>
expect(converter.getSortingFunctionForField(0)).toBeDefined();
expect([7,9,3,5].sort(converter.getSortingFunctionForField(0).sort)).toEqual([9,7,5,3]);
});
// Pagination :
it("Doit générer une erreur quand aucun élément n'est fourni pour recevoir le sélecteur de pages, alors que cela est nécessaire.", () =>
{
expect(() => { return converter.Pagination={ selectedValue:10 }; }).toThrowError(errors.needPagesSelectorElt);
expect(() => { return converter.Pagination={ options: { displayElement: { id:"paginationOptions" }, values: [10,20] }}; }).toThrowError(errors.needPagesSelectorElt);
});
it("Doit générer une erreur si l'élément fourni pour recevoir le sélecteur de pages n'existe pas dans le DOM.", () =>
{
expect(() => { return converter.Pagination={ selectedValue:10, pages: { displayElement: { id:"dontExist" }} }; }).toThrowError(errors.elementNotFound+"dontExist");
});
it("Doit générer une erreur si l'élément fourni pour recevoir le sélecteur de Pagination n'existe pas dans le DOM.", () =>
{
expect(() => { return converter.Pagination={ options: { displayElement: { id:"dontExist" }, values: [10,20] }, pages: { displayElement: { id:"pages" }}}; }).toThrowError(errors.elementNotFound+"dontExist");
});
it("Doit générer une erreur si au moins une des options de Pagination proposée n'est pas un entier positif.", () =>
{
expect(() => { return converter.Pagination={ options: { displayElement: { id:"paginationOptions" }, values:[0,10,20] }, pages: { displayElement: { id:"pages" }}}; }).toThrowError(errors.needPositiveInteger);
});
it("Doit générer une erreur si la Pagination par défaut n'est pas un entier positif.", () =>
{
expect(() => { return converter.Pagination={ selectedValue:0, pages: { displayElement: { id:"pages" }} }; }).toThrowError(errors.needPositiveInteger);
});
it("Doit générer une erreur si la Pagination par défaut ne fait pas partie des valeurs proposées en option.", () =>
{
expect(() => { return converter.Pagination={ selectedValue:15, options: { displayElement: { id:"paginationOptions" }, values:[10,20,50] }, pages: { displayElement: { id:"pages" }}}; }).toThrowError(errors.needPaginationByDefaultBeInOptions);
});
it("Doit accepter une configuration correcte pour la Pagination.", () =>
{
let PaginationOk =
{
selectedValue:10,
options:
{
displayElement : { id:"paginationOptions" },
values: [10,20,50],
name: "Choix de Pagination :"
},
pages:
{
displayElement : { id:"pages" },
name: "Page à afficher :"
}
};
expect(() => { return converter.Pagination=PaginationOk; }).not.toThrowError();
});
});
describe("Parsage du fichier et création du tableau de données", () =>
@ -211,84 +143,4 @@ xdescribe("Test du script central de FreeDatas2HTML", () =>
});
});
describe("Création et action des options permettant de paginer les données affichées.", () =>
{
beforeEach( () =>
{
converter.datasViewElt={ id:"datas" };
converter.datasSourceUrl="http://localhost:9876/datas/datas1.csv";
converter.Pagination=
{
selectedValue:10,
options:
{
displayElement : { id:"paginationOptions" },
values: [10,20,50,500],
name: "Choix de pagination :"
},
pages:
{
displayElement : { id:"pages" },
name: "Page à afficher :"
}
}
});
it("Si des options de pagination sont fournies, doit générer un élement <select> listant les valeurs possibles.", async () =>
{
await converter.run();
expect(document.getElementById("paginationOptions").innerHTML).toEqual(fixtures.selectorForPagination);
});
it("Si une valeur de pagination par défaut fournie, ne doit pas afficher plus de données.", async () =>
{
await converter.run();
let getTableTr=document.querySelectorAll("tr");// attention, un tr sert aux titres
expect(getTableTr.length).toEqual(converter.Pagination.selectedValue+1);
});
it("Si une des options de pagination fournies est sélectionnée, doit afficher la première page de résultats correspondants.", async () =>
{
await converter.run();
let selectElement = document.getElementById("freeDatas2HTMLPaginationSelector") as HTMLInputElement;
selectElement.value="2"; // = 20 éléments / page
selectElement.dispatchEvent(new Event('change'));
let getTableTr=document.querySelectorAll("tr");
expect(getTableTr.length).toEqual(21);
selectElement.value="3"; // = 50 éléments / page
selectElement.dispatchEvent(new Event('change'));
getTableTr=document.querySelectorAll("tr");
expect(getTableTr.length).toEqual(51);
selectElement.value="0"; // = pas de Pagination, on affiche les 118 lignes du fichier
selectElement.dispatchEvent(new Event('change'));
getTableTr=document.querySelectorAll("tr");
expect(getTableTr.length).toEqual(119);
});
it("Si il y a plus de données que le nombre de lignes autorisées par page, un <select> listant les pages doit être affichés.", async () =>
{
await converter.run();
let btnPaginationElt=document.getElementById("pages").innerHTML;
expect(btnPaginationElt).toEqual(fixtures.selectorForPages);
});
it("Si l'utilisateur sélectionne une des pages proposées, l'affichage des résultats doit s'adapter en prenant en compte la pagination sélectionnée.", async () =>
{
await converter.run();
let selectElement = document.getElementById("freeDatas2HTMLPaginationSelector") as HTMLInputElement;
selectElement.value="3"; // = 50 éléments / page
selectElement.dispatchEvent(new Event('change'));
selectElement=document.getElementById("freeDatas2HTMLPagesSelector") as HTMLInputElement;
selectElement.value="2";
selectElement.dispatchEvent(new Event('change'));
let getTableTr=document.getElementsByTagName("tr");
expect(getTableTr[1].innerHTML).toEqual(fixtures.firstLineForPageSelection1);
expect(getTableTr[50].innerHTML).toEqual(fixtures.lastLineForPageSelection1);
selectElement.value="3"; // troisième page = incomplèet (18 enregistrements)
selectElement.dispatchEvent(new Event('change'));
getTableTr=document.getElementsByTagName("tr");
expect(getTableTr[1].innerHTML).toEqual(fixtures.firstLineForPageSelection2);
expect(getTableTr[18].innerHTML).toEqual(fixtures.lastLineForPageSelection2);
});
});
});

159
tests/paginationSpec.ts Normal file
View File

@ -0,0 +1,159 @@
import { FreeDatas2HTML, Pagination } from "../src/freeDatas2HTML";
const errors=require("../src/errors.js");
const fixtures=require("./fixtures.js");
describe("Test de la pagination.", () =>
{
let converter: FreeDatas2HTML;
let pagination: Pagination;
beforeEach( async () =>
{
document.body.insertAdjacentHTML("afterbegin", fixtures.datasViewEltHTML);
converter=new FreeDatas2HTML();
converter.datasViewElt={ id:"datas" };
converter.datasSourceUrl="http://localhost:9876/datas/datas1.csv";
await converter.parse();
pagination=new Pagination(converter, { id:"pages" }, "Page à afficher :");
});
afterEach( () =>
{
document.body.removeChild(document.getElementById("fixture"));
});
describe("Test des options de pagination.", () =>
{
it("Doit retourner un booléen indiquant si un nombre est un entier positif ou non.", () =>
{
expect(Pagination.isPositiveInteger(-1)).toBeFalse();
expect(Pagination.isPositiveInteger(1.25)).toBeFalse();
expect(Pagination.isPositiveInteger(0)).toBeFalse();
expect(Pagination.isPositiveInteger(1)).toBeTrue();
});
it("Doit générer une erreur si la pagination est initialisée sans données à traiter.", () =>
{
converter=new FreeDatas2HTML();
expect(() => { return new Pagination(converter, { id:"pages" }); }).toThrowError(errors.paginationNeedDatas);
});
it("Doit générer une erreur si initialisé en fournissant l'id d'un élément n'existant pas pour recevoir la liste des pages.", () =>
{
expect(() => { return new Pagination(converter, { id:"dontExist" }); }).toThrowError(errors.elementNotFound+"dontExist");
});
it("Ne doit pas générer d'erreur si initialisé correctement", () =>
{
expect(() => { return new Pagination(converter, { id:"pages" }); }).not.toThrowError();
});
it("Doit générer une erreur si l'id fourni pour l'élément devant recevoir le sélecteur de pagination n'existe pas dans le DOM.", () =>
{
expect(() => { return pagination.options={ displayElement: { id:"dontExist" }, values: [10,20] }; }).toThrowError(errors.elementNotFound+"dontExist");
});
it("Doit générer une erreur si les options de pagination sont initialisées avec un tableau de valeurs vide.", () =>
{
expect(() => { return pagination.options={ displayElement: { id:"paginationOptions" }, values: [] }; }).toThrowError(errors.needPaginationOptionsValues);
});
it("Doit générer une erreur si au moins une des options de pagination fournies n'est pas un entier positif.", () =>
{
expect(() => { return pagination.options={ displayElement: { id:"paginationOptions" }, values: [0,10,20] }; }).toThrowError(errors.needPositiveInteger);
});
it("Ne doit pas générer d'erreur si les options de pagination fournies sont correctes.", () =>
{
const test={ displayElement: { id:"paginationOptions" }, values: [10,20,50], name: "La pagination" };
expect(() => { return pagination.options=test}).not.toThrowError();
expect(pagination.options).toEqual(test);
});
it("Doit générer une erreur si la pagination par défaut n'est pas un entier positif.", () =>
{
expect(() => { return pagination.selectedValue=0; }).toThrowError(errors.needPositiveInteger);
});
it("Doit générer une erreur si la Pagination par défaut ne fait pas partie des valeurs proposées en option.", () =>
{
pagination.options={ displayElement: { id:"paginationOptions" }, values: [10,20,50] };
expect(() => { return pagination.selectedValue=15; }).toThrowError(errors.needPaginationByDefaultBeInOptions);
});
it("Doit accepter une pagination par défaut correcte, avec ou sans options proposées.", () =>
{
expect(() => { return pagination.selectedValue=10; }).not.toThrowError();
pagination.options={ displayElement: { id:"paginationOptions" }, values: [10,20,50] };
expect(() => { return pagination.selectedValue=10; }).not.toThrowError();
});
});
describe("Création et action des sélecteurs liés à la pagination des données.", () =>
{
beforeEach( async () =>
{
pagination.options={ displayElement: { id:"paginationOptions" }, values: [10,20,50,500] , name: "Choix de pagination :" };
pagination.selectedValue=10; // revoir car n'est pas testé si déclaré avant les options
pagination.rend2HTML();
converter.pagination=pagination;
await converter.run();
});
it("Si des options de pagination sont fournies, doit générer un élement <select> listant les valeurs possibles.", () =>
{
expect(document.getElementById("paginationOptions").innerHTML).toEqual(fixtures.selectorForPagination);
});
it("Si une valeur de pagination par défaut fournie, ne doit pas afficher plus de données.", () =>
{
let getTR=document.getElementsByTagName("tr");
expect(getTR.length).toEqual(pagination.selectedValue+1); // 1er TR sert aux titres
});
it("Si une des options de pagination fournies est sélectionnée, doit afficher le nombre de résultats correspondants.", () =>
{
let selectElement=document.getElementById("freeDatas2HTMLPaginationSelector") as HTMLInputElement;
selectElement.value="2"; // = 20 éléments / page
selectElement.dispatchEvent(new Event('change'));
let getTR=document.getElementsByTagName("tr");
expect(getTR.length).toEqual(21);
selectElement.value="3"; // = 50 éléments / page
selectElement.dispatchEvent(new Event('change'));
getTR=document.getElementsByTagName("tr");
expect(getTR.length).toEqual(51);
selectElement.value="0"; // = pas de Pagination, on affiche les 118 lignes du fichier
selectElement.dispatchEvent(new Event('change'));
getTR=document.getElementsByTagName("tr");
expect(getTR.length).toEqual(119);
});
it("Si il y a plus de données que le nombre de lignes autorisées par page, un <select> listant les pages doit être affiché.", () =>
{
let selectElement=document.getElementById("pages").innerHTML;
expect(selectElement).toEqual(fixtures.selectorForPages);
});
it("Si l'utilisateur sélectionne une des pages proposées, l'affichage des résultats doit s'adapter en prenant en compte la pagination sélectionnée.", () =>
{
let selectElement=document.getElementById("freeDatas2HTMLPaginationSelector") as HTMLInputElement;
selectElement.value="3"; // = 50 éléments / page
selectElement.dispatchEvent(new Event('change'));
selectElement=document.getElementById("freeDatas2HTMLPagesSelector") as HTMLInputElement;
selectElement.value="2";
selectElement.dispatchEvent(new Event('change'));
let getTR=document.getElementsByTagName("tr");
expect(getTR[1].innerHTML).toEqual(fixtures.firstLineForPageSelection1);
expect(getTR[50].innerHTML).toEqual(fixtures.lastLineForPageSelection1);
selectElement.value="3"; // troisième page = incomplète (18 enregistrements)
selectElement.dispatchEvent(new Event('change'));
getTR=document.getElementsByTagName("tr");
expect(getTR[1].innerHTML).toEqual(fixtures.firstLineForPageSelection2);
expect(getTR[18].innerHTML).toEqual(fixtures.lastLineForPageSelection2);
expect(getTR[50]).toBeUndefined();
});
});
});