Ajout de la fonctionnalité Favoris (V2.2)

- Nouvelle catégorie Favoris: recuperation des favoris depuis Project.gfx (getFavorites.dg5)
- Pages menuFavorites.dg5 et showDataFav.dg5 + bibliothèques JSZip/jQuery
- Navigation index.dg5: ajout de la catégorie Favoris
- Correctif override.dg5: exclusion des points /services/subnet
- Bump version 2.2 et description "Alternative to Command"
- Mise a jour README (doc Favoris + changelog)
This commit is contained in:
2026-06-10 05:54:31 +02:00
parent fbd191d9dc
commit c6482c396d
13 changed files with 279 additions and 9 deletions
+37
View File
@@ -0,0 +1,37 @@
// test if a parameter value is designer table
let dgIframeId;
function dgIsParamTable(val){
return (val !== null && typeof(val)=='object' && val.hasOwnProperty('cols')
&& val.hasOwnProperty('rows'));
}
// interface to the dglux5 application
function onDGFrameMessage(e){
var data = e.data;
if (typeof(data)=='object'){
if (data.hasOwnProperty('dgIframeInit')){
dgIframeId = data['dgIframeInit'];
console.log(dgIframeId);
if (window.parent !== null){
// the first post back shouldn't contain any data change
window.parent.postMessage({'dgIframe':dgIframeId},'*');
}
} else if (data.hasOwnProperty('dgIframeUpdate')){
var updates = data['updates'];
if (typeof(updates)=='object'){
if (typeof(dgParams) == 'object'){
for (key in dgParams){
if (updates.hasOwnProperty(key)){
dgParams[key](updates[key]);
}}}
if (typeof(dgParamsUpdated) == 'function'){
dgParamsUpdated();
}}}}}
window.addEventListener('message',onDGFrameMessage);
// push parameter changes back to dglux
function dgUpdateParams(changes) {
if (dgIframeId !== null) {
window.parent.postMessage({'dgIframe':dgIframeId, changes:changes},'*');
} else {
throw 'dgUpdateParams failed, handshake not finished';
}
}
+154
View File
@@ -0,0 +1,154 @@
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript' src='jquery-3.7.1.min.js'></script>
<script type='text/javascript' src='jszip.min.js'></script>
<script type='text/javascript' src='jszip-utils.min.js'></script>
<script type='text/javascript' src='dgframe.js'></script>
</head>
<body>
<div id="fetch"></div>
<script type='text/javascript'>
"use strict";
let zipSource = "";
let fileContent;
let blacklistFiles = "";
let blacklistSet = new Set();
let dgParams = {
"zipSource": function(val) {
zipSource = val;
unzip(zipSource);
},
"blacklistFiles": function(val) {
blacklistFiles = val;
blacklistSet = parseBlacklist(val);
},
"fileContent": function(val) {
fileContent = val;
}
};
// "chemin1,chemin2,..." -> Set de chemins normalises (slashes en /)
function parseBlacklist(str) {
let set = new Set();
if (!str) {
return set;
}
str.split(",").forEach(function(p) {
let norm = p.trim().replace(/\\/g, "/");
if (norm) {
set.add(norm);
}
});
return set;
}
// Prepare la donnee a charger par JSZip selon la forme recue.
// JSZip.loadAsync accepte aussi bien une chaine binaire qu'un Uint8Array.
function toZipData(input) {
if (typeof input === "string") {
let trimmed = input.trim();
// Reponse JSON {"binary":"<base64>"} -> decoder le base64
if (trimmed.charAt(0) === "{") {
let base64 = JSON.parse(trimmed).binary;
let bin = atob(base64);
let out = new Uint8Array(bin.length);
for (let i = 0; i < bin.length; i++) {
out[i] = bin.charCodeAt(i);
}
return out;
}
// Tableau d'octets en texte "[123,34,...]"
if (trimmed.charAt(0) === "[") {
return Uint8Array.from(JSON.parse(trimmed));
}
// Zip brut en chaine binaire (commence par "PK") -> JSZip l'accepte tel quel
return input;
}
// ArrayBuffer / TypedArray / tableau d'octets -> JSZip l'accepte tel quel
return input;
}
// Octets -> base64 (navigateur)
function bytesToBase64(bytes) {
let bin = "";
for (let i = 0; i < bytes.length; i++) {
bin += String.fromCharCode(bytes[i]);
}
return btoa(bin);
}
// Type MIME a partir de l'extension du fichier
function mimeFromName(name) {
let ext = name.split(".").pop().toLowerCase();
let map = {
png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg",
gif: "image/gif", bmp: "image/bmp", webp: "image/webp",
ico: "image/x-icon", svg: "image/svg+xml"
};
return map[ext] || "application/octet-stream";
}
// Decode le contenu d'un fichier selon son encodage reel.
// Texte: UTF-16 (BOM) ou UTF-8. Binaire (image): data URI base64 pour <img src="">.
function decodeContent(bytes, name) {
if (bytes.length >= 2 && bytes[0] === 0xFF && bytes[1] === 0xFE) {
return new TextDecoder("utf-16le").decode(bytes);
}
if (bytes.length >= 2 && bytes[0] === 0xFE && bytes[1] === 0xFF) {
return new TextDecoder("utf-16be").decode(bytes);
}
try {
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
} catch (e) {
return "data:" + mimeFromName(name) + ";base64," + bytesToBase64(bytes);
}
}
function unzip(source) {
let zipData;
try {
zipData = toZipData(source);
} catch (e) {
console.log("Erreur de decodage de l'entree:", e);
return;
}
JSZip.loadAsync(zipData)
.then(function(zip) {
let promises = [];
zip.forEach(function (relativePath, zipEntry) {
if (zipEntry.dir) {
return;
}
// Exclu: ni dans la table, ni chargement du contenu (memoire)
if (blacklistSet.has(relativePath.replace(/\\/g, "/"))) {
return;
}
promises.push(
zipEntry.async("uint8array").then(function(bytes) {
return {
name: zipEntry.name.split("/").pop().split("\\").pop(),
path: relativePath,
content: decodeContent(bytes, zipEntry.name)
};
})
);
});
return Promise.all(promises);
})
.then(function success(table) {
dgUpdateParams({ 'fileContent': JSON.stringify(table, null, 2) });
}, function error(e) {
console.log("Erreur de lecture du zip:", e);
});
}
</script>
</body>
</html>
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.JSZipUtils=e():"undefined"!=typeof global?global.JSZipUtils=e():"undefined"!=typeof self&&(self.JSZipUtils=e())}(function(){return function o(i,f,u){function s(n,e){if(!f[n]){if(!i[n]){var t="function"==typeof require&&require;if(!e&&t)return t(n,!0);if(a)return a(n,!0);throw new Error("Cannot find module '"+n+"'")}var r=f[n]={exports:{}};i[n][0].call(r.exports,function(e){var t=i[n][1][e];return s(t||e)},r,r.exports,o,i,f,u)}return f[n].exports}for(var a="function"==typeof require&&require,e=0;e<u.length;e++)s(u[e]);return s}({1:[function(e,t,n){"use strict";var u={};function r(){try{return new window.XMLHttpRequest}catch(e){}}u._getBinaryFromXHR=function(e){return e.response||e.responseText};var s="undefined"!=typeof window&&window.ActiveXObject?function(){return r()||function(){try{return new window.ActiveXObject("Microsoft.XMLHTTP")}catch(e){}}()}:r;u.getBinaryContent=function(t,n){var e,r,o,i;"function"==typeof(n=n||{})?(i=n,n={}):"function"==typeof n.callback&&(i=n.callback),i||"undefined"==typeof Promise?(r=function(e){i(null,e)},o=function(e){i(e,null)}):e=new Promise(function(e,t){r=e,o=t});try{var f=s();f.open("GET",t,!0),"responseType"in f&&(f.responseType="arraybuffer"),f.overrideMimeType&&f.overrideMimeType("text/plain; charset=x-user-defined"),f.onreadystatechange=function(e){if(4===f.readyState)if(200===f.status||0===f.status)try{r(u._getBinaryFromXHR(f))}catch(e){o(new Error(e))}else o(new Error("Ajax error for "+t+" : "+this.status+" "+this.statusText))},n.progress&&(f.onprogress=function(e){n.progress({path:t,originalEvent:e,percent:e.loaded/e.total*100,loaded:e.loaded,total:e.total})}),f.send()}catch(e){o(new Error(e),null)}return e},t.exports=u},{}]},{},[1])(1)});
File diff suppressed because one or more lines are too long