From 124ccce44315d99107eca61c6768b29e2faaafc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Fri, 15 Nov 2024 10:06:30 +0100 Subject: [PATCH 01/51] modify the drag n drop and groups layer in themes --- js/mviewerstudio.js | 123 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 98 insertions(+), 25 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index 953c35ec..a5a648cc 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -355,24 +355,6 @@ var deleteLayerItem = function (btn, themeid) { el && el.parentNode.removeChild(el); }; -var sortableThemeList = Sortable.create(document.getElementById("themes-list"), { - handle: ".moveList", - animation: 150, - ghostClass: "ghost", - onEnd: function (evt) { - sortThemes(); - }, -}); - -sortThemes = function () { - var orderedThemes = {}; - $(".themes-list-item").each(function (i, item) { - var id = $(this).attr("data-themeid"); - orderedThemes[id] = config.themes[id]; - }); - config.themes = orderedThemes; -}; - setConf = (key, value) => { _conf[key] = value; }; @@ -397,7 +379,7 @@ var addLayer = function (title, layerid, themeid) { saveThemes(); } var item = $(`#themeLayers-${themeid}`).append(` -
+
${title}
@@ -407,6 +389,44 @@ var addLayer = function (title, layerid, themeid) {
`); }; +var addGroup = (themeid) => { + // test if theme is saved + if (!config.themes[themeid]) { + saveThemes(); + } + const title = "Nouveau groupe"; + const item = $(`#themeGroups-${themeid}`).append(` +
+
+ +
+ + +
+
+
+
+ TRUC 01 +
+ + + +
+
+
+ TRUC 02 +
+ + + +
+
+
+
`); + initializeNestedSortables(); + return item; +}; + var editLayer = function (item, themeid, layerid) { mv.setCurrentThemeId(themeid); mv.setCurrentLayerId(layerid); @@ -435,11 +455,31 @@ var importThemes = function () { $("#mod-themesview").modal("hide"); }; +sortThemes = function () { + var orderedThemes = {}; + $(".themes-list-item").each(function (i, item) { + var id = $(this).attr("data-themeid"); + orderedThemes[id] = config.themes[id]; + }); + config.themes = orderedThemes; +}; + +var sortableThemeList = Sortable.create(document.getElementById("themes-list"), { + handle: ".moveList", + animation: 150, + ghostClass: "ghost", + onEnd: function (evt) { + sortThemes(); + }, +}); + var sortableElement = function (targetId, callback) { Sortable.create(document.getElementById(targetId), { handle: ".moveList", animation: 150, ghostClass: "ghost", + fallbackOnBody: true, + swapThreshold: 0.65, onEnd: function (evt) { callback(evt); }, @@ -447,11 +487,40 @@ var sortableElement = function (targetId, callback) { }; sortableElement("themes-list", sortThemes); +function initializeNestedSortables() { + const nestedSortables = document.querySelectorAll(".nested-sortable"); + + nestedSortables.forEach((sortableElement) => { + if (!sortableElement.getAttribute("data-sortable-initialized")) { + new Sortable(sortableElement, { + handle: ".moveList", + animation: 150, + ghostClass: "ghost", + fallbackOnBody: true, + swapThreshold: 0.65, + group: { + name: "nested", + pull: true, + put: true, + }, + onEnd: function (evt) { + console.log(`Élément déplacé de ${evt.from.id} vers ${evt.to.id}`); + }, + }); + // Marquer cet élément comme "initialisé" pour éviter les doublons + sortableElement.setAttribute("data-sortable-initialized", true); + } + }); +} + +// Initialisation au chargement du DOM +initializeNestedSortables(); + var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility) { if (url) { //external theme $("#themes-list").append(` -
+
${title}Ext.
@@ -463,10 +532,10 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility)
`); } else { $("#themes-list").append( - `
+ `
- + 0
@@ -474,14 +543,18 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility)
+ -
-
+
+
+
+
+
` ); - sortableElement("themeLayers-" + themeid, sortLayers); + initializeNestedSortables(); } config.themes[themeid] = { title: title, From a86d7e098ecfcdaf426070d87b3b67b9686c23bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Mon, 18 Nov 2024 14:30:40 +0100 Subject: [PATCH 02/51] wip enregistrement groupes --- css/mviewerstudio.css | 2 +- js/mviewerstudio.js | 37 +++++++++++++++---------------------- lib/mv.js | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/css/mviewerstudio.css b/css/mviewerstudio.css index aa9bab23..d7872f96 100644 --- a/css/mviewerstudio.css +++ b/css/mviewerstudio.css @@ -689,7 +689,7 @@ flex: 1 50%; } - .themes-list-item .theme-layer-list { + .themes-list-item .theme-layer-list .theme-group-list { flex: 1!important; } diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index a5a648cc..cf7cd328 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -389,14 +389,13 @@ var addLayer = function (title, layerid, themeid) {
`); }; -var addGroup = (themeid) => { +var addGroup = (themeid, title, groupId) => { // test if theme is saved if (!config.themes[themeid]) { saveThemes(); } - const title = "Nouveau groupe"; const item = $(`#themeGroups-${themeid}`).append(` -
+
@@ -404,24 +403,7 @@ var addGroup = (themeid) => {
-
-
- TRUC 01 -
- - - -
-
-
- TRUC 02 -
- - - -
-
-
+
`); initializeNestedSortables(); return item; @@ -469,6 +451,7 @@ var sortableThemeList = Sortable.create(document.getElementById("themes-list"), animation: 150, ghostClass: "ghost", onEnd: function (evt) { + console.log("Move thème"); sortThemes(); }, }); @@ -543,7 +526,7 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility)
- + @@ -956,6 +939,11 @@ var getConfig = () => { '">', ]; } + $(t.groups).each((i, g) => { + var group = mv.writeGroupNode(g); + theme.push(group); + }); + $(t.layers).each(function (i, l) { var layer = mv.writeLayerNode(l); theme.push(layer); @@ -985,6 +973,7 @@ var getConfig = () => { themes.join(" "), padding(0) + "", ]; + console.log({ conf }); return conf; }; @@ -1020,6 +1009,8 @@ let previewAppsWithoutSave = (id, showPublish) => { return window.open(previewUrl, "mvs_vizualize"); } const confXml = getConfig(); + console.log({ confXml }); + if (!confXml || (confXml && !mv.validateXML(confXml.join("")))) { return alertCustom("XML invalide !", "danger"); } @@ -1142,6 +1133,8 @@ var saveApplicationParameters = (close) => { }; var saveAppWithPython = (exists, conf, url, close) => { + console.log("conf python : ", conf); + return fetch(url, { method: exists ? "PUT" : "POST", headers: { diff --git a/lib/mv.js b/lib/mv.js index 520a422d..a479e891 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -550,6 +550,23 @@ var mv = (function () { $(".ogc-result input[type='checkbox']:checked").prop("checked", false); }, + getConfGroups: function () { + const themeid = mv.getCurrentThemeId(); + const groupId = `group-${mv.uuid()}`; + const groupTitle = "Nouveau groupe"; + const group = { + id: groupId, + title: groupTitle, + }; + if (!config.themes[themeid].groups) { + config.themes[themeid].groups = []; + } + console.log("CONFIG THEME : ", config.themes[themeid]); + + config.themes[themeid].groups.push(group); + addGroup(themeid, groupTitle, groupId); + }, + resetConfLayer: function () { // Reset input document.getElementById("newlayer-type").value = ""; @@ -1005,6 +1022,29 @@ var mv = (function () { return layer.join(""); }, + writeGroupNode: function (g) { + console.log({ g }); + var padding = function (n) { + return "\r\n" + " ".repeat(n); + }; + var groupParameters = {}; + //require parameters + var requireParameters = ["id", "title"]; + requireParameters.forEach(function (p, i) { + var value = g[p]; + groupParameters[p] = [p, '="', value, '"'].join(""); + }); + + var group = [padding(8) + ""); + group.push(padding(8) + ""); + + return group.join(""); + }, + escapeXml: function (unsafe) { var rep = ""; if (unsafe) { From 50bf662eeb7ab29becc3a7dcaf26e21582eb63d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Fri, 22 Nov 2024 09:15:45 +0100 Subject: [PATCH 03/51] add save and load theme, groups and layers --- js/mviewerstudio.js | 126 +++++++++++++++++++++++++++++++++++++++----- lib/mv.js | 116 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 225 insertions(+), 17 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index cf7cd328..020bc1ee 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -355,6 +355,12 @@ var deleteLayerItem = function (btn, themeid) { el && el.parentNode.removeChild(el); }; +var deleteGroupItem = function (btn, themeid) { + var el = $(btn).closest(".list-group-item")[0]; + deleteGroup(el.id, themeid); + el && el.parentNode.removeChild(el); +}; + setConf = (key, value) => { _conf[key] = value; }; @@ -373,13 +379,13 @@ $("input[type=file]").change(function () { loadApplicationParametersFromFile(); }); -var addLayer = function (title, layerid, themeid) { +var addLayer = function (title, layerid, themeid, groupid) { // test if theme is saved if (!config.themes[themeid]) { saveThemes(); } - var item = $(`#themeLayers-${themeid}`).append(` -
+ var item = $(groupid ? `#${groupid} .list-group` : `#themeLayers-${themeid}`).append(` +
${title}
@@ -387,6 +393,7 @@ var addLayer = function (title, layerid, themeid) {
`); + return item; }; var addGroup = (themeid, title, groupId) => { @@ -395,12 +402,12 @@ var addGroup = (themeid, title, groupId) => { saveThemes(); } const item = $(`#themeGroups-${themeid}`).append(` -
+
- +
@@ -427,7 +434,6 @@ var editLayer = function (item, themeid, layerid) { var importThemes = function () { console.groupCollapsed("importThemes"); - //console.log("external theme to import", _conf.external_themes.data); $("#tableThemaExt .selected").each(function (id, item) { var url = $(item).attr("data-url"); var id = $(item).attr("data-theme-id"); @@ -451,7 +457,6 @@ var sortableThemeList = Sortable.create(document.getElementById("themes-list"), animation: 150, ghostClass: "ghost", onEnd: function (evt) { - console.log("Move thème"); sortThemes(); }, }); @@ -487,7 +492,75 @@ function initializeNestedSortables() { put: true, }, onEnd: function (evt) { - console.log(`Élément déplacé de ${evt.from.id} vers ${evt.to.id}`); + const item = evt.item; + const fromThemeId = evt.from.closest(".themes-list-item")?.id; + const fromGroupId = evt.from.closest(".group-item")?.id + ? evt.from.closest(".group-item").id + : null; + const toThemeId = evt.to.closest(".themes-list-item")?.id; + const toGroupId = evt.to.closest(".group-item")?.id + ? evt.to.closest(".group-item").id + : null; + + item.setAttribute("data-groupid", toGroupId); + item.setAttribute("data-themeid", toThemeId); + + // Si item est un layer + if (item.classList.contains("layers-list-item")) { + config.themes[toThemeId].layers.forEach((layer) => { + if (layer.id === item.getAttribute("data-layerid")) { + layer["data-groupid"] = toGroupId; + layer["data-themeid"] = toThemeId; + } + }); + // Cherche l'index de départ en fonction de si le layer bougé vient d'un groupe ou un thème + const index = fromGroupId + ? config.themes[fromThemeId].groups + .find((group) => group.id === fromGroupId) + .layers.findIndex((layer) => layer.id === item.id) + : config.themes[fromThemeId].layers.findIndex( + (layer) => layer.id === item.id + ); + + // Si l'index éxiste, suppr l'item de la position de départ et l'ajoute à l'arrivée + if (index !== -1) { + // Si le thème n'a pas de layer, on set theme.layers à [] + if (!config.themes[fromThemeId].layers) + config.themes[fromThemeId].layers = []; + // Si le groupe n'a pas de layers, on set group.layers à [] + if ( + !config.themes[toThemeId].groups.find((group) => group.id === toGroupId) + .layers + ) + config.themes[toThemeId].groups.find( + (group) => group.id === toGroupId + ).layers = []; + const [itemToMove] = fromGroupId + ? config.themes[fromThemeId].groups + .find((group) => group.id === fromGroupId) + .layers.splice(index, 1) + : config.themes[fromThemeId].layers.splice(index, 1); + toGroupId + ? config.themes[toThemeId].groups + .find((group) => group.id === toGroupId) + .layers.push(itemToMove) + : config.themes[toThemeId].layers.push(itemToMove); + } + } else { + // sinon item est un groupe + config.themes[toThemeId].groups.forEach((group) => { + if (group.id === item.getAttribute("data-groupid")) { + group["data-themeid"] = toThemeId; + } + }); + const index = config.themes[fromThemeId].groups.findIndex( + (group) => group.id === item.id + ); + if (index !== -1) { + const [itemToMove] = config.themes[fromThemeId].groups.splice(index, 1); + config.themes[toThemeId].groups.push(itemToMove); + } + } }, }); // Marquer cet élément comme "initialisé" pour éviter les doublons @@ -503,7 +576,7 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility) if (url) { //external theme $("#themes-list").append(` -
+
${title}Ext.
@@ -595,6 +668,27 @@ var saveThemes = function () { } }; +var saveGroups = () => { + const themes = $(".themes-list-item"); + for (i = 0; i < themes.length; i++) { + const theme = themes[i]; + const themeId = theme.getAttribute("data-themeid"); + const groups = $(`#${themeId}`).find(".group-item"); + + for (j = 0; j < groups.length; j++) { + const group = groups[j]; + const groupId = group.id; + + const gr = $(`div[id="${groupId}"]`); + const groupTitle = gr.find(".group-name").val(); + + config.themes[themeId].groups.find((group) => group.id === groupId).id = groupId; + config.themes[themeId].groups.find((group) => group.id === groupId).title = + groupTitle; + } + } +}; + var editThemeExt = function (item) { $("#themes-list .list-group-item").removeClass("active"); $(item).parent().parent().addClass("active"); @@ -634,6 +728,13 @@ var deleteLayer = function (layerid, themeid) { config.themes[themeid].layers.splice(index, 1); }; +var deleteGroup = function (groupid, themeid) { + var index = config.themes[themeid].groups.findIndex(function (g) { + return g.id === groupid; + }); + config.themes[themeid].groups.splice(index, 1); +}; + var createId = function (obj) { var d = new Date(); var df = @@ -904,6 +1005,7 @@ var getConfig = () => { // Respect theme order $(".themes-list-item").each(function (id, theme) { saveThemes(); + saveGroups(); var themeid = $(theme).attr("data-themeid"); if (config.themes[themeid]) { var t = config.themes[themeid]; @@ -939,15 +1041,17 @@ var getConfig = () => { '">', ]; } + // push groupes $(t.groups).each((i, g) => { var group = mv.writeGroupNode(g); theme.push(group); }); - + // push layers hors groupes $(t.layers).each(function (i, l) { var layer = mv.writeLayerNode(l); theme.push(layer); }); + themes.push(theme.join(" ")); themes.push(padding(4) + ""); } @@ -973,8 +1077,6 @@ var getConfig = () => { themes.join(" "), padding(0) + "", ]; - console.log({ conf }); - return conf; }; diff --git a/lib/mv.js b/lib/mv.js index a479e891..a63d1df1 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -557,12 +557,11 @@ var mv = (function () { const group = { id: groupId, title: groupTitle, + layers: [], }; if (!config.themes[themeid].groups) { config.themes[themeid].groups = []; } - console.log("CONFIG THEME : ", config.themes[themeid]); - config.themes[themeid].groups.push(group); addGroup(themeid, groupTitle, groupId); }, @@ -1023,7 +1022,6 @@ var mv = (function () { }, writeGroupNode: function (g) { - console.log({ g }); var padding = function (n) { return "\r\n" + " ".repeat(n); }; @@ -1040,9 +1038,14 @@ var mv = (function () { group.push(padding(12) + parameter); }); group.push(">"); + //push layers dans le groupe + $(g.layers).each(function (i, l) { + var layer = mv.writeLayerNode(l); + group.push(layer); + }); group.push(padding(8) + ""); - return group.join(""); + return group.join(" "); }, escapeXml: function (unsafe) { @@ -1616,11 +1619,13 @@ var mv = (function () { $("#frm-bl .custom-bl input").prop("checked", true).trigger("change"); var visibleBaselayer = $(xml).find('baselayer[visible="true"]').attr("id"); $("#frm-bl-visible").val(visibleBaselayer).trigger("change"); + //tHEMES & layers var themePanel = $(xml).find("themes"); if (themePanel.attr("mini") === "true") { $("#opt-mini").prop("checked", true); } + var themes = $(xml).find("theme"); themes.each(function (id, th) { addTheme( @@ -1631,7 +1636,108 @@ var mv = (function () { $(th).attr("url"), $(th).attr("layersvisibility") ); - var layers = $(th).find("layer"); + + // Ajout des groupes et de leurs layers + var groups = $(th).find("group"); + groups.each((id, g) => { + var group = { + id: $(g).attr("id"), + title: $(g).attr("title"), + }; + addGroup($(th).attr("id"), group.title, group.id); + //Si le thème n'a pas de groupes, on set theme.group à [] + if (!config.themes[$(th).attr("id")].groups) + config.themes[$(th).attr("id")].groups = []; + config.themes[$(th).attr("id")].groups.push(group); + + var layers = $(g).find("layer"); + if (layers) + layers.each(function (id, l) { + counter += 1; + var layer = { + id: $(l).attr("id"), + type: $(l).attr("type") || "wms", + tiled: $(l).attr("tiled") === "true", + scalemin: $(l).attr("scalemin"), + scalemax: $(l).attr("scalemax"), + title: $(l).attr("name"), + name: $(l).attr("name"), + url: $(l).attr("url"), + queryable: $(l).attr("queryable") === "true", + featurecount: $(l).attr("featurecount"), + infopanel: $(l).attr("infopanel") || "right-panel", + searchable: $(l).attr("searchable") === "true", + searchengine: $(l).attr("searchengine"), + fusesearchkeys: $(l).attr("fusesearchkeys"), + fusesearchresult: $(l).attr("fusesearchresult"), + secure: $(l).attr("secure") || "public", + useproxy: $(l).attr("useproxy") === "true", + infoformat: $(l).attr("infoformat"), + metadata: $(l).attr("metadata"), + "metadata-csw": $(l).attr("metadata-csw"), + attribution: $(l).attr("attribution"), + filter: $(l).attr("filter"), + visible: $(l).attr("visible") === "true", + opacity: $(l).attr("opacity"), + template: $(l).find("template").text(), + useexternaltemplate: + ($(l).find("template") && $(l).find("template").text().length > 3) || + ($(l).find("template").attr("url") && + $(l).find("template").attr("url").length > 1), + templateurl: false, + fields: $(l).attr("fields"), + fieldsoptions: false, + aliases: $(l).attr("aliases"), + style: $(l).attr("style"), + styleurl: $(l).attr("styleurl"), + filterstyle: $(l).attr("filterstyle"), + stylesalias: $(l).attr("stylesalias"), + sld: $(l).attr("sld"), + legendurl: $(l).attr("legendurl"), + attributefilter: $(l).attr("attributefilter") === "true", + showintoc: $(l).attr("showintoc") === "true", + exclusive: $(l).attr("exclusive") === "true", + toplayer: $(l).attr("toplayer") === "true", + expanded: $(l).attr("expanded") === "true", + dynamiclegend: $(l).attr("dynamiclegend") === "true", + styletitle: $(l).attr("styletitle"), + index: $(l).attr("index"), + jsonfields: $(l).attr("jsonfields"), + }; + addLayer(layer.title, layer.id, $(th).attr("id"), group.id); + if (layer.attributefilter) { + layer.attributefield = $(l).attr("attributefield"); + layer.attributelabel = $(l).attr("attributelabel"); + layer.attributevalues = $(l).attr("attributevalues"); + } + if ( + layer.useexternaltemplate === true && + $(l).find("template").attr("url") + ) { + layer.templateurl = $(l).find("template").attr("url"); + } + $("#frm-template").prop("checked", layer.useexternaltemplate); + if (layer.fields && layer.aliases) { + layer.fieldsoptions = {}; + $(layer.fields.split(",")).each(function (index, fld) { + var type = "text"; + var alias = layer.aliases.split(",")[index]; + layer.fieldsoptions[fld] = { name: fld, alias: alias, type: type }; + }); + } + //Si le groupe n'a pas de layers, on set group.layers à [] + if ( + !config.themes[$(th).attr("id")].groups.find((group) => group.id).layers + ) + config.themes[$(th).attr("id")].groups.find((group) => group.id).layers = + []; + config.themes[$(th).attr("id")].groups + .find((group) => group.id) + .layers.push(layer); + }); + }); + // Ajout des layers hors groupes + var layers = $(th).children("layer"); var counter = 0; layers.each(function (id, l) { counter += 1; From a9cd59fafa3ad979e3cccebd138480eefe653bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Fri, 22 Nov 2024 09:24:58 +0100 Subject: [PATCH 04/51] clean code --- js/mviewerstudio.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index 020bc1ee..338837c2 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -1111,8 +1111,6 @@ let previewAppsWithoutSave = (id, showPublish) => { return window.open(previewUrl, "mvs_vizualize"); } const confXml = getConfig(); - console.log({ confXml }); - if (!confXml || (confXml && !mv.validateXML(confXml.join("")))) { return alertCustom("XML invalide !", "danger"); } @@ -1235,8 +1233,6 @@ var saveApplicationParameters = (close) => { }; var saveAppWithPython = (exists, conf, url, close) => { - console.log("conf python : ", conf); - return fetch(url, { method: exists ? "PUT" : "POST", headers: { From 9e20c591d36de01164e16f6b3e168cf8c77822a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Fri, 22 Nov 2024 12:46:29 +0100 Subject: [PATCH 05/51] clean code and graphic design --- css/bootstrap.css | 4 ++-- css/mviewerstudio.css | 12 ++++++++++++ js/mviewerstudio.js | 39 ++++++++++++++++++++++----------------- lib/Sortable.min.js | 4 ++-- 4 files changed, 38 insertions(+), 21 deletions(-) diff --git a/css/bootstrap.css b/css/bootstrap.css index b3c0e73d..cc228718 100644 --- a/css/bootstrap.css +++ b/css/bootstrap.css @@ -3850,9 +3850,9 @@ input[type="button"].btn-block { .list-group-item { position: relative; display: block; - padding: 0.9rem 1.25rem; + padding: 0.5rem 0.75rem; background-color: #fff; - border: 1px solid rgba(0, 0, 0, 0.125); } +} .list-group-item:first-child { border-top-left-radius: inherit; border-top-right-radius: inherit; } diff --git a/css/mviewerstudio.css b/css/mviewerstudio.css index d7872f96..a645d52a 100644 --- a/css/mviewerstudio.css +++ b/css/mviewerstudio.css @@ -51,6 +51,18 @@ .list-group-item { background-color: #ffffff00; } + + .group_list { + background-color: #e1e1e1; + } + + .layer_item { + background-color: #e1e1e1; + } + + .group_list .layer_item { + background-color: #c5c5c5; + } .modal { overflow-y: auto !important; diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index 338837c2..536909cd 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -385,7 +385,7 @@ var addLayer = function (title, layerid, themeid, groupid) { saveThemes(); } var item = $(groupid ? `#${groupid} .list-group` : `#themeLayers-${themeid}`).append(` -
+
${title}
@@ -410,7 +410,7 @@ var addGroup = (themeid, title, groupId) => {
-
+
`); initializeNestedSortables(); return item; @@ -501,6 +501,7 @@ function initializeNestedSortables() { const toGroupId = evt.to.closest(".group-item")?.id ? evt.to.closest(".group-item").id : null; + const newIndex = evt.newIndex; item.setAttribute("data-groupid", toGroupId); item.setAttribute("data-themeid", toThemeId); @@ -527,14 +528,16 @@ function initializeNestedSortables() { // Si le thème n'a pas de layer, on set theme.layers à [] if (!config.themes[fromThemeId].layers) config.themes[fromThemeId].layers = []; - // Si le groupe n'a pas de layers, on set group.layers à [] - if ( - !config.themes[toThemeId].groups.find((group) => group.id === toGroupId) - .layers - ) - config.themes[toThemeId].groups.find( - (group) => group.id === toGroupId - ).layers = []; + // Si le groupe d'arrivé n'a pas de layers, on set group.layers à [] + if (toGroupId) + if ( + !config.themes[toThemeId].groups.find((group) => group.id === toGroupId) + .layers + ) + config.themes[toThemeId].groups.find( + (group) => group.id === toGroupId + ).layers = []; + const [itemToMove] = fromGroupId ? config.themes[fromThemeId].groups .find((group) => group.id === fromGroupId) @@ -543,8 +546,8 @@ function initializeNestedSortables() { toGroupId ? config.themes[toThemeId].groups .find((group) => group.id === toGroupId) - .layers.push(itemToMove) - : config.themes[toThemeId].layers.push(itemToMove); + .layers.splice(newIndex, 0, itemToMove) + : config.themes[toThemeId].layers.splice(newIndex, 0, itemToMove); } } else { // sinon item est un groupe @@ -605,8 +608,8 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility)
-
-
+
Groupes
+
Couches
` ); @@ -682,9 +685,11 @@ var saveGroups = () => { const gr = $(`div[id="${groupId}"]`); const groupTitle = gr.find(".group-name").val(); - config.themes[themeId].groups.find((group) => group.id === groupId).id = groupId; - config.themes[themeId].groups.find((group) => group.id === groupId).title = - groupTitle; + if (config.themes[themeId].groups) { + config.themes[themeId].groups.find((group) => group.id === groupId).id = groupId; + config.themes[themeId].groups.find((group) => group.id === groupId).title = + groupTitle; + } } } }; diff --git a/lib/Sortable.min.js b/lib/Sortable.min.js index e95d2a30..abe4ddbf 100755 --- a/lib/Sortable.min.js +++ b/lib/Sortable.min.js @@ -1,2 +1,2 @@ -/*! Sortable 1.4.2 - MIT | git://github.com/rubaxa/Sortable.git */ -!function(a){"use strict";"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module&&"undefined"!=typeof module.exports?module.exports=a():"undefined"!=typeof Package?Sortable=a():window.Sortable=a()}(function(){"use strict";function a(a,b){if(!a||!a.nodeType||1!==a.nodeType)throw"Sortable: `el` must be HTMLElement, and not "+{}.toString.call(a);this.el=a,this.options=b=r({},b),a[L]=this;var c={group:Math.random(),sort:!0,disabled:!1,store:null,handle:null,scroll:!0,scrollSensitivity:30,scrollSpeed:10,draggable:/[uo]l/i.test(a.nodeName)?"li":">*",ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",ignore:"a, img",filter:null,animation:0,setData:function(a,b){a.setData("Text",b.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1};for(var d in c)!(d in b)&&(b[d]=c[d]);V(b);for(var f in this)"_"===f.charAt(0)&&(this[f]=this[f].bind(this));this.nativeDraggable=b.forceFallback?!1:P,e(a,"mousedown",this._onTapStart),e(a,"touchstart",this._onTapStart),this.nativeDraggable&&(e(a,"dragover",this),e(a,"dragenter",this)),T.push(this._onDragOver),b.store&&this.sort(b.store.get(this))}function b(a){v&&v.state!==a&&(h(v,"display",a?"none":""),!a&&v.state&&w.insertBefore(v,s),v.state=a)}function c(a,b,c){if(a){c=c||N,b=b.split(".");var d=b.shift().toUpperCase(),e=new RegExp("\\s("+b.join("|")+")(?=\\s)","g");do if(">*"===d&&a.parentNode===c||(""===d||a.nodeName.toUpperCase()==d)&&(!b.length||((" "+a.className+" ").match(e)||[]).length==b.length))return a;while(a!==c&&(a=a.parentNode))}return null}function d(a){a.dataTransfer&&(a.dataTransfer.dropEffect="move"),a.preventDefault()}function e(a,b,c){a.addEventListener(b,c,!1)}function f(a,b,c){a.removeEventListener(b,c,!1)}function g(a,b,c){if(a)if(a.classList)a.classList[c?"add":"remove"](b);else{var d=(" "+a.className+" ").replace(K," ").replace(" "+b+" "," ");a.className=(d+(c?" "+b:"")).replace(K," ")}}function h(a,b,c){var d=a&&a.style;if(d){if(void 0===c)return N.defaultView&&N.defaultView.getComputedStyle?c=N.defaultView.getComputedStyle(a,""):a.currentStyle&&(c=a.currentStyle),void 0===b?c:c[b];b in d||(b="-webkit-"+b),d[b]=c+("string"==typeof c?"":"px")}}function i(a,b,c){if(a){var d=a.getElementsByTagName(b),e=0,f=d.length;if(c)for(;f>e;e++)c(d[e],e);return d}return[]}function j(a,b,c,d,e,f,g){var h=N.createEvent("Event"),i=(a||b[L]).options,j="on"+c.charAt(0).toUpperCase()+c.substr(1);h.initEvent(c,!0,!0),h.to=b,h.from=e||b,h.item=d||b,h.clone=v,h.oldIndex=f,h.newIndex=g,b.dispatchEvent(h),i[j]&&i[j].call(a,h)}function k(a,b,c,d,e,f){var g,h,i=a[L],j=i.options.onMove;return g=N.createEvent("Event"),g.initEvent("move",!0,!0),g.to=b,g.from=a,g.dragged=c,g.draggedRect=d,g.related=e||b,g.relatedRect=f||b.getBoundingClientRect(),a.dispatchEvent(g),j&&(h=j.call(i,g)),h}function l(a){a.draggable=!1}function m(){R=!1}function n(a,b){var c=a.lastElementChild,d=c.getBoundingClientRect();return(b.clientY-(d.top+d.height)>5||b.clientX-(d.right+d.width)>5)&&c}function o(a){for(var b=a.tagName+a.className+a.src+a.href+a.textContent,c=b.length,d=0;c--;)d+=b.charCodeAt(c);return d.toString(36)}function p(a){var b=0;if(!a||!a.parentNode)return-1;for(;a&&(a=a.previousElementSibling);)"TEMPLATE"!==a.nodeName.toUpperCase()&&b++;return b}function q(a,b){var c,d;return function(){void 0===c&&(c=arguments,d=this,setTimeout(function(){1===c.length?a.call(d,c[0]):a.apply(d,c),c=void 0},b))}}function r(a,b){if(a&&b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}var s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J={},K=/\s+/g,L="Sortable"+(new Date).getTime(),M=window,N=M.document,O=M.parseInt,P=!!("draggable"in N.createElement("div")),Q=function(a){return a=N.createElement("x"),a.style.cssText="pointer-events:auto","auto"===a.style.pointerEvents}(),R=!1,S=Math.abs,T=([].slice,[]),U=q(function(a,b,c){if(c&&b.scroll){var d,e,f,g,h=b.scrollSensitivity,i=b.scrollSpeed,j=a.clientX,k=a.clientY,l=window.innerWidth,m=window.innerHeight;if(z!==c&&(y=b.scroll,z=c,y===!0)){y=c;do if(y.offsetWidth=l-j)-(h>=j),g=(h>=m-k)-(h>=k),(f||g)&&(d=M)),(J.vx!==f||J.vy!==g||J.el!==d)&&(J.el=d,J.vx=f,J.vy=g,clearInterval(J.pid),d&&(J.pid=setInterval(function(){d===M?M.scrollTo(M.pageXOffset+f*i,M.pageYOffset+g*i):(g&&(d.scrollTop+=g*i),f&&(d.scrollLeft+=f*i))},24)))}},30),V=function(a){var b=a.group;b&&"object"==typeof b||(b=a.group={name:b}),["pull","put"].forEach(function(a){a in b||(b[a]=!0)}),a.groups=" "+b.name+(b.put.join?" "+b.put.join(" "):"")+" "};return a.prototype={constructor:a,_onTapStart:function(a){var b=this,d=this.el,e=this.options,f=a.type,g=a.touches&&a.touches[0],h=(g||a).target,i=h,k=e.filter;if(!("mousedown"===f&&0!==a.button||e.disabled)&&(h=c(h,e.draggable,d))){if(D=p(h),"function"==typeof k){if(k.call(this,a,h,this))return j(b,i,"filter",h,d,D),void a.preventDefault()}else if(k&&(k=k.split(",").some(function(a){return a=c(i,a.trim(),d),a?(j(b,a,"filter",h,d,D),!0):void 0})))return void a.preventDefault();(!e.handle||c(i,e.handle,d))&&this._prepareDragStart(a,g,h)}},_prepareDragStart:function(a,b,c){var d,f=this,h=f.el,j=f.options,k=h.ownerDocument;c&&!s&&c.parentNode===h&&(G=a,w=h,s=c,t=s.parentNode,x=s.nextSibling,F=j.group,d=function(){f._disableDelayedDrag(),s.draggable=!0,g(s,f.options.chosenClass,!0),f._triggerDragStart(b)},j.ignore.split(",").forEach(function(a){i(s,a.trim(),l)}),e(k,"mouseup",f._onDrop),e(k,"touchend",f._onDrop),e(k,"touchcancel",f._onDrop),j.delay?(e(k,"mouseup",f._disableDelayedDrag),e(k,"touchend",f._disableDelayedDrag),e(k,"touchcancel",f._disableDelayedDrag),e(k,"mousemove",f._disableDelayedDrag),e(k,"touchmove",f._disableDelayedDrag),f._dragStartTimer=setTimeout(d,j.delay)):d())},_disableDelayedDrag:function(){var a=this.el.ownerDocument;clearTimeout(this._dragStartTimer),f(a,"mouseup",this._disableDelayedDrag),f(a,"touchend",this._disableDelayedDrag),f(a,"touchcancel",this._disableDelayedDrag),f(a,"mousemove",this._disableDelayedDrag),f(a,"touchmove",this._disableDelayedDrag)},_triggerDragStart:function(a){a?(G={target:s,clientX:a.clientX,clientY:a.clientY},this._onDragStart(G,"touch")):this.nativeDraggable?(e(s,"dragend",this),e(w,"dragstart",this._onDragStart)):this._onDragStart(G,!0);try{N.selection?N.selection.empty():window.getSelection().removeAllRanges()}catch(b){}},_dragStarted:function(){w&&s&&(g(s,this.options.ghostClass,!0),a.active=this,j(this,w,"start",s,w,D))},_emulateDragOver:function(){if(H){if(this._lastX===H.clientX&&this._lastY===H.clientY)return;this._lastX=H.clientX,this._lastY=H.clientY,Q||h(u,"display","none");var a=N.elementFromPoint(H.clientX,H.clientY),b=a,c=" "+this.options.group.name,d=T.length;if(b)do{if(b[L]&&b[L].options.groups.indexOf(c)>-1){for(;d--;)T[d]({clientX:H.clientX,clientY:H.clientY,target:a,rootEl:b});break}a=b}while(b=b.parentNode);Q||h(u,"display","")}},_onTouchMove:function(b){if(G){a.active||this._dragStarted(),this._appendGhost();var c=b.touches?b.touches[0]:b,d=c.clientX-G.clientX,e=c.clientY-G.clientY,f=b.touches?"translate3d("+d+"px,"+e+"px,0)":"translate("+d+"px,"+e+"px)";I=!0,H=c,h(u,"webkitTransform",f),h(u,"mozTransform",f),h(u,"msTransform",f),h(u,"transform",f),b.preventDefault()}},_appendGhost:function(){if(!u){var a,b=s.getBoundingClientRect(),c=h(s),d=this.options;u=s.cloneNode(!0),g(u,d.ghostClass,!1),g(u,d.fallbackClass,!0),h(u,"top",b.top-O(c.marginTop,10)),h(u,"left",b.left-O(c.marginLeft,10)),h(u,"width",b.width),h(u,"height",b.height),h(u,"opacity","0.8"),h(u,"position","fixed"),h(u,"zIndex","100000"),h(u,"pointerEvents","none"),d.fallbackOnBody&&N.body.appendChild(u)||w.appendChild(u),a=u.getBoundingClientRect(),h(u,"width",2*b.width-a.width),h(u,"height",2*b.height-a.height)}},_onDragStart:function(a,b){var c=a.dataTransfer,d=this.options;this._offUpEvents(),"clone"==F.pull&&(v=s.cloneNode(!0),h(v,"display","none"),w.insertBefore(v,s)),b?("touch"===b?(e(N,"touchmove",this._onTouchMove),e(N,"touchend",this._onDrop),e(N,"touchcancel",this._onDrop)):(e(N,"mousemove",this._onTouchMove),e(N,"mouseup",this._onDrop)),this._loopId=setInterval(this._emulateDragOver,50)):(c&&(c.effectAllowed="move",d.setData&&d.setData.call(this,c,s)),e(N,"drop",this),setTimeout(this._dragStarted,0))},_onDragOver:function(a){var d,e,f,g=this.el,i=this.options,j=i.group,l=j.put,o=F===j,p=i.sort;if(void 0!==a.preventDefault&&(a.preventDefault(),!i.dragoverBubble&&a.stopPropagation()),I=!0,F&&!i.disabled&&(o?p||(f=!w.contains(s)):F.pull&&l&&(F.name===j.name||l.indexOf&&~l.indexOf(F.name)))&&(void 0===a.rootEl||a.rootEl===this.el)){if(U(a,i,this.el),R)return;if(d=c(a.target,i.draggable,g),e=s.getBoundingClientRect(),f)return b(!0),void(v||x?w.insertBefore(s,v||x):p||w.appendChild(s));if(0===g.children.length||g.children[0]===u||g===a.target&&(d=n(g,a))){if(d){if(d.animated)return;r=d.getBoundingClientRect()}b(o),k(w,g,s,e,d,r)!==!1&&(s.contains(g)||(g.appendChild(s),t=g),this._animate(e,s),d&&this._animate(r,d))}else if(d&&!d.animated&&d!==s&&void 0!==d.parentNode[L]){A!==d&&(A=d,B=h(d),C=h(d.parentNode));var q,r=d.getBoundingClientRect(),y=r.right-r.left,z=r.bottom-r.top,D=/left|right|inline/.test(B.cssFloat+B.display)||"flex"==C.display&&0===C["flex-direction"].indexOf("row"),E=d.offsetWidth>s.offsetWidth,G=d.offsetHeight>s.offsetHeight,H=(D?(a.clientX-r.left)/y:(a.clientY-r.top)/z)>.5,J=d.nextElementSibling,K=k(w,g,s,e,d,r);if(K!==!1){if(R=!0,setTimeout(m,30),b(o),1===K||-1===K)q=1===K;else if(D){var M=s.offsetTop,N=d.offsetTop;q=M===N?d.previousElementSibling===s&&!E||H&&E:N>M}else q=J!==s&&!G||H&&G;s.contains(g)||(q&&!J?g.appendChild(s):d.parentNode.insertBefore(s,q?J:d)),t=s.parentNode,this._animate(e,s),this._animate(r,d)}}}},_animate:function(a,b){var c=this.options.animation;if(c){var d=b.getBoundingClientRect();h(b,"transition","none"),h(b,"transform","translate3d("+(a.left-d.left)+"px,"+(a.top-d.top)+"px,0)"),b.offsetWidth,h(b,"transition","all "+c+"ms"),h(b,"transform","translate3d(0,0,0)"),clearTimeout(b.animated),b.animated=setTimeout(function(){h(b,"transition",""),h(b,"transform",""),b.animated=!1},c)}},_offUpEvents:function(){var a=this.el.ownerDocument;f(N,"touchmove",this._onTouchMove),f(a,"mouseup",this._onDrop),f(a,"touchend",this._onDrop),f(a,"touchcancel",this._onDrop)},_onDrop:function(b){var c=this.el,d=this.options;clearInterval(this._loopId),clearInterval(J.pid),clearTimeout(this._dragStartTimer),f(N,"mousemove",this._onTouchMove),this.nativeDraggable&&(f(N,"drop",this),f(c,"dragstart",this._onDragStart)),this._offUpEvents(),b&&(I&&(b.preventDefault(),!d.dropBubble&&b.stopPropagation()),u&&u.parentNode.removeChild(u),s&&(this.nativeDraggable&&f(s,"dragend",this),l(s),g(s,this.options.ghostClass,!1),g(s,this.options.chosenClass,!1),w!==t?(E=p(s),E>=0&&(j(null,t,"sort",s,w,D,E),j(this,w,"sort",s,w,D,E),j(null,t,"add",s,w,D,E),j(this,w,"remove",s,w,D,E))):(v&&v.parentNode.removeChild(v),s.nextSibling!==x&&(E=p(s),E>=0&&(j(this,w,"update",s,w,D,E),j(this,w,"sort",s,w,D,E)))),a.active&&((null===E||-1===E)&&(E=D),j(this,w,"end",s,w,D,E),this.save())),w=s=t=u=x=v=y=z=G=H=I=E=A=B=F=a.active=null)},handleEvent:function(a){var b=a.type;"dragover"===b||"dragenter"===b?s&&(this._onDragOver(a),d(a)):("drop"===b||"dragend"===b)&&this._onDrop(a)},toArray:function(){for(var a,b=[],d=this.el.children,e=0,f=d.length,g=this.options;f>e;e++)a=d[e],c(a,g.draggable,this.el)&&b.push(a.getAttribute(g.dataIdAttr)||o(a));return b},sort:function(a){var b={},d=this.el;this.toArray().forEach(function(a,e){var f=d.children[e];c(f,this.options.draggable,d)&&(b[a]=f)},this),a.forEach(function(a){b[a]&&(d.removeChild(b[a]),d.appendChild(b[a]))})},save:function(){var a=this.options.store;a&&a.set(this)},closest:function(a,b){return c(a,b||this.options.draggable,this.el)},option:function(a,b){var c=this.options;return void 0===b?c[a]:(c[a]=b,void("group"===a&&V(c)))},destroy:function(){var a=this.el;a[L]=null,f(a,"mousedown",this._onTapStart),f(a,"touchstart",this._onTapStart),this.nativeDraggable&&(f(a,"dragover",this),f(a,"dragenter",this)),Array.prototype.forEach.call(a.querySelectorAll("[draggable]"),function(a){a.removeAttribute("draggable")}),T.splice(T.indexOf(this._onDragOver),1),this._onDrop(),this.el=a=null}},a.utils={on:e,off:f,css:h,find:i,is:function(a,b){return!!c(a,b,a)},extend:r,throttle:q,closest:c,toggleClass:g,index:p},a.create=function(b,c){return new a(b,c)},a.version="1.4.2",a}); \ No newline at end of file +/*! Sortable 1.15.3 - MIT | git://github.com/SortableJS/Sortable.git */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).Sortable=e()}(this,function(){"use strict";function e(e,t){var n,o=Object.keys(e);return Object.getOwnPropertySymbols&&(n=Object.getOwnPropertySymbols(e),t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),o.push.apply(o,n)),o}function I(o){for(var t=1;tt.length)&&(e=t.length);for(var n=0,o=new Array(e);n"===e[0]&&(e=e.substring(1)),t))try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(t){return}}function g(t){return t.host&&t!==document&&t.host.nodeType?t.host:t.parentNode}function P(t,e,n,o){if(t){n=n||document;do{if(null!=e&&(">"!==e[0]||t.parentNode===n)&&p(t,e)||o&&t===n)return t}while(t!==n&&(t=g(t)))}return null}var m,v=/\s+/g;function k(t,e,n){var o;t&&e&&(t.classList?t.classList[n?"add":"remove"](e):(o=(" "+t.className+" ").replace(v," ").replace(" "+e+" "," "),t.className=(o+(n?" "+e:"")).replace(v," ")))}function R(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];o[e=!(e in o||-1!==e.indexOf("webkit"))?"-webkit-"+e:e]=n+("string"==typeof n?"":"px")}}function b(t,e){var n="";if("string"==typeof t)n=t;else do{var o=R(t,"transform")}while(o&&"none"!==o&&(n=o+" "+n),!e&&(t=t.parentNode));var i=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return i&&new i(n)}function E(t,e,n){if(t){var o=t.getElementsByTagName(e),i=0,r=o.length;if(n)for(;i=n.left-e&&i<=n.right+e,e=r>=n.top-e&&r<=n.bottom+e;return o&&e?a=t:void 0}}),a);if(e){var n,o={};for(n in t)t.hasOwnProperty(n)&&(o[n]=t[n]);o.target=o.rootEl=e,o.preventDefault=void 0,o.stopPropagation=void 0,e[K]._onDragOver(o)}}var i,r,a}function Ft(t){Z&&Z.parentNode[K]._isOutsideThisEl(t.target)}function jt(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.el=t,this.options=e=a({},e),t[K]=this;var n,o,i={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return kt(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==jt.supportPointer&&"PointerEvent"in window&&!u,emptyInsertThreshold:5};for(n in z.initializePlugins(this,t,i),i)n in e||(e[n]=i[n]);for(o in Rt(e),this)"_"===o.charAt(0)&&"function"==typeof this[o]&&(this[o]=this[o].bind(this));this.nativeDraggable=!e.forceFallback&&It,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?h(t,"pointerdown",this._onTapStart):(h(t,"mousedown",this._onTapStart),h(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(h(t,"dragover",this),h(t,"dragenter",this)),St.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[]),a(this,A())}function Ht(t,e,n,o,i,r,a,l){var s,c,u=t[K],d=u.options.onMove;return!window.CustomEvent||y||w?(s=document.createEvent("Event")).initEvent("move",!0,!0):s=new CustomEvent("move",{bubbles:!0,cancelable:!0}),s.to=e,s.from=t,s.dragged=n,s.draggedRect=o,s.related=i||e,s.relatedRect=r||X(e),s.willInsertAfter=l,s.originalEvent=a,t.dispatchEvent(s),c=d?d.call(u,s,a):c}function Lt(t){t.draggable=!1}function Kt(){xt=!1}function Wt(t){return setTimeout(t,0)}function zt(t){return clearTimeout(t)}jt.prototype={constructor:jt,_isOutsideThisEl:function(t){this.el.contains(t)||t===this.el||(vt=null)},_getDirection:function(t,e){return"function"==typeof this.options.direction?this.options.direction.call(this,t,e,Z):this.options.direction},_onTapStart:function(e){if(e.cancelable){var n=this,o=this.el,t=this.options,i=t.preventOnFilter,r=e.type,a=e.touches&&e.touches[0]||e.pointerType&&"touch"===e.pointerType&&e,l=(a||e).target,s=e.target.shadowRoot&&(e.path&&e.path[0]||e.composedPath&&e.composedPath()[0])||l,c=t.filter;if(!function(t){Ot.length=0;var e=t.getElementsByTagName("input"),n=e.length;for(;n--;){var o=e[n];o.checked&&Ot.push(o)}}(o),!Z&&!(/mousedown|pointerdown/.test(r)&&0!==e.button||t.disabled)&&!s.isContentEditable&&(this.nativeDraggable||!u||!l||"SELECT"!==l.tagName.toUpperCase())&&!((l=P(l,t.draggable,o,!1))&&l.animated||et===l)){if(it=j(l),at=j(l,t.draggable),"function"==typeof c){if(c.call(this,e,l,this))return V({sortable:n,rootEl:s,name:"filter",targetEl:l,toEl:o,fromEl:o}),U("filter",n,{evt:e}),void(i&&e.cancelable&&e.preventDefault())}else if(c=c&&c.split(",").some(function(t){if(t=P(s,t.trim(),o,!1))return V({sortable:n,rootEl:t,name:"filter",targetEl:l,fromEl:o,toEl:o}),U("filter",n,{evt:e}),!0}))return void(i&&e.cancelable&&e.preventDefault());t.handle&&!P(s,t.handle,o,!1)||this._prepareDragStart(e,a,l)}}},_prepareDragStart:function(t,e,n){var o,i=this,r=i.el,a=i.options,l=r.ownerDocument;n&&!Z&&n.parentNode===r&&(o=X(n),J=r,$=(Z=n).parentNode,tt=Z.nextSibling,et=n,st=a.group,ut={target:jt.dragged=Z,clientX:(e||t).clientX,clientY:(e||t).clientY},pt=ut.clientX-o.left,gt=ut.clientY-o.top,this._lastX=(e||t).clientX,this._lastY=(e||t).clientY,Z.style["will-change"]="all",o=function(){U("delayEnded",i,{evt:t}),jt.eventCanceled?i._onDrop():(i._disableDelayedDragEvents(),!s&&i.nativeDraggable&&(Z.draggable=!0),i._triggerDragStart(t,e),V({sortable:i,name:"choose",originalEvent:t}),k(Z,a.chosenClass,!0))},a.ignore.split(",").forEach(function(t){E(Z,t.trim(),Lt)}),h(l,"dragover",Bt),h(l,"mousemove",Bt),h(l,"touchmove",Bt),h(l,"mouseup",i._onDrop),h(l,"touchend",i._onDrop),h(l,"touchcancel",i._onDrop),s&&this.nativeDraggable&&(this.options.touchStartThreshold=4,Z.draggable=!0),U("delayStart",this,{evt:t}),!a.delay||a.delayOnTouchOnly&&!e||this.nativeDraggable&&(w||y)?o():jt.eventCanceled?this._onDrop():(h(l,"mouseup",i._disableDelayedDrag),h(l,"touchend",i._disableDelayedDrag),h(l,"touchcancel",i._disableDelayedDrag),h(l,"mousemove",i._delayedDragTouchMoveHandler),h(l,"touchmove",i._delayedDragTouchMoveHandler),a.supportPointer&&h(l,"pointermove",i._delayedDragTouchMoveHandler),i._dragStartTimer=setTimeout(o,a.delay)))},_delayedDragTouchMoveHandler:function(t){t=t.touches?t.touches[0]:t;Math.max(Math.abs(t.clientX-this._lastX),Math.abs(t.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){Z&&Lt(Z),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;f(t,"mouseup",this._disableDelayedDrag),f(t,"touchend",this._disableDelayedDrag),f(t,"touchcancel",this._disableDelayedDrag),f(t,"mousemove",this._delayedDragTouchMoveHandler),f(t,"touchmove",this._delayedDragTouchMoveHandler),f(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||"touch"==t.pointerType&&t,!this.nativeDraggable||e?this.options.supportPointer?h(document,"pointermove",this._onTouchMove):h(document,e?"touchmove":"mousemove",this._onTouchMove):(h(Z,"dragend",this),h(J,"dragstart",this._onDragStart));try{document.selection?Wt(function(){document.selection.empty()}):window.getSelection().removeAllRanges()}catch(t){}},_dragStarted:function(t,e){var n;Et=!1,J&&Z?(U("dragStarted",this,{evt:e}),this.nativeDraggable&&h(document,"dragover",Ft),n=this.options,t||k(Z,n.dragClass,!1),k(Z,n.ghostClass,!0),jt.active=this,t&&this._appendGhost(),V({sortable:this,name:"start",originalEvent:e})):this._nulling()},_emulateDragOver:function(){if(dt){this._lastX=dt.clientX,this._lastY=dt.clientY,Xt();for(var t=document.elementFromPoint(dt.clientX,dt.clientY),e=t;t&&t.shadowRoot&&(t=t.shadowRoot.elementFromPoint(dt.clientX,dt.clientY))!==e;)e=t;if(Z.parentNode[K]._isOutsideThisEl(t),e)do{if(e[K])if(e[K]._onDragOver({clientX:dt.clientX,clientY:dt.clientY,target:t,rootEl:e})&&!this.options.dragoverBubble)break}while(e=g(t=e));Yt()}},_onTouchMove:function(t){if(ut){var e=this.options,n=e.fallbackTolerance,o=e.fallbackOffset,i=t.touches?t.touches[0]:t,r=Q&&b(Q,!0),a=Q&&r&&r.a,l=Q&&r&&r.d,e=At&&wt&&D(wt),a=(i.clientX-ut.clientX+o.x)/(a||1)+(e?e[0]-Tt[0]:0)/(a||1),l=(i.clientY-ut.clientY+o.y)/(l||1)+(e?e[1]-Tt[1]:0)/(l||1);if(!jt.active&&!Et){if(n&&Math.max(Math.abs(i.clientX-this._lastX),Math.abs(i.clientY-this._lastY))D.right+10||S.clientY>x.bottom&&S.clientX>x.left:S.clientY>D.bottom+10||S.clientX>x.right&&S.clientY>x.top)||m.animated)){if(m&&(t=n,e=r,C=X(B((_=this).el,0,_.options,!0)),_=L(_.el,_.options,Q),e?t.clientX<_.left-10||t.clientY Date: Tue, 26 Nov 2024 17:04:52 +0100 Subject: [PATCH 06/51] modifie le title en name dans les groupes --- js/mviewerstudio.js | 7 ++++--- lib/mv.js | 12 ++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index 536909cd..9c257329 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -683,12 +683,12 @@ var saveGroups = () => { const groupId = group.id; const gr = $(`div[id="${groupId}"]`); - const groupTitle = gr.find(".group-name").val(); + const groupName = gr.find(".group-name").val(); if (config.themes[themeId].groups) { config.themes[themeId].groups.find((group) => group.id === groupId).id = groupId; - config.themes[themeId].groups.find((group) => group.id === groupId).title = - groupTitle; + config.themes[themeId].groups.find((group) => group.id === groupId).name = + groupName; } } } @@ -1268,6 +1268,7 @@ var saveAppWithPython = (exists, conf, url, close) => { var saveApplicationsConfig = (close, message = "") => { const conf = getConfig(); + if (!conf || !mv.validateXML(conf.join(""))) { return alertCustom(mviewer.tr("msg.xml_doc_invalid"), "danger"); } diff --git a/lib/mv.js b/lib/mv.js index a63d1df1..f8480393 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -553,17 +553,17 @@ var mv = (function () { getConfGroups: function () { const themeid = mv.getCurrentThemeId(); const groupId = `group-${mv.uuid()}`; - const groupTitle = "Nouveau groupe"; + const groupName = "Nouveau groupe"; const group = { id: groupId, - title: groupTitle, + name: groupName, layers: [], }; if (!config.themes[themeid].groups) { config.themes[themeid].groups = []; } config.themes[themeid].groups.push(group); - addGroup(themeid, groupTitle, groupId); + addGroup(themeid, groupName, groupId); }, resetConfLayer: function () { @@ -1027,7 +1027,7 @@ var mv = (function () { }; var groupParameters = {}; //require parameters - var requireParameters = ["id", "title"]; + var requireParameters = ["id", "name"]; requireParameters.forEach(function (p, i) { var value = g[p]; groupParameters[p] = [p, '="', value, '"'].join(""); @@ -1642,9 +1642,9 @@ var mv = (function () { groups.each((id, g) => { var group = { id: $(g).attr("id"), - title: $(g).attr("title"), + name: $(g).attr("name"), }; - addGroup($(th).attr("id"), group.title, group.id); + addGroup($(th).attr("id"), group.name, group.id); //Si le thème n'a pas de groupes, on set theme.group à [] if (!config.themes[$(th).attr("id")].groups) config.themes[$(th).attr("id")].groups = []; From 09e01adf2cd73def4bea236f40e9d8be1eb9a126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Wed, 27 Nov 2024 14:56:52 +0100 Subject: [PATCH 07/51] display groups panel depending on whether or not a group is present --- js/mviewerstudio.js | 13 +++++++++++-- lib/mv.js | 8 ++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index 9c257329..b300d9d9 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -407,7 +407,7 @@ var addGroup = (themeid, title, groupId) => {
- +
@@ -602,7 +602,7 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility)
- + @@ -626,6 +626,15 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility) }; }; +// Display groups div if at least one group in +const displayGroupsPanel = (themeId) => { + if ($(`#${themeId} .group_list`).children().length !== 0) { + $(`#${themeId} .group_list`).removeClass("hideBlock").addClass("showBlock"); + } else { + $(`#${themeId} .group_list`).removeClass("showBlock").addClass("hideBlock"); + } +}; + // Only one checkbox "collapsed" checked $("#themes-list").on("change", ".custom-control-input", function () { if ($(this).is(":checked")) { diff --git a/lib/mv.js b/lib/mv.js index f8480393..dd7007fb 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -1636,18 +1636,22 @@ var mv = (function () { $(th).attr("url"), $(th).attr("layersvisibility") ); - // Ajout des groupes et de leurs layers var groups = $(th).find("group"); + // If no groups in theme, hide groups panel + if (groups.length === 0) $(`#${th.id} .group_list`).addClass("hideBlock"); + groups.each((id, g) => { var group = { id: $(g).attr("id"), name: $(g).attr("name"), }; + addGroup($(th).attr("id"), group.name, group.id); //Si le thème n'a pas de groupes, on set theme.group à [] - if (!config.themes[$(th).attr("id")].groups) + if (!config.themes[$(th).attr("id")].groups) { config.themes[$(th).attr("id")].groups = []; + } config.themes[$(th).attr("id")].groups.push(group); var layers = $(g).find("layer"); From b8e6d5acfcc587871ffd03963ecfd43a7a30e2d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Wed, 27 Nov 2024 15:04:54 +0100 Subject: [PATCH 08/51] Modify button title for add theme, groups and layers --- index.html | 4 ++-- js/mviewerstudio.js | 2 +- mviewerstudio.i18n.json | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/index.html b/index.html index c0c4e863..36fbc1fa 100755 --- a/index.html +++ b/index.html @@ -699,9 +699,9 @@

Thématiques & do

- + diff --git a/mviewerstudio.i18n.json b/mviewerstudio.i18n.json index 31c49b79..e6f4b6ff 100644 --- a/mviewerstudio.i18n.json +++ b/mviewerstudio.i18n.json @@ -164,8 +164,8 @@ "tabs.data.title": "Thématiques & données", "tabs.data.themespanel.title": "Panneau des thématiques", "tabs.data.themespanel.subtitle": "Créer, importer et gérer vos thématiques et données", - "tabs.data.themespanel.create": "Créer", - "tabs.data.themespanel.import": "Importer", + "tabs.data.themespanel.create": "Ajouter une thématique", + "tabs.data.themespanel.import": "Importer une thématique", "tabs.data.themespanel.options": "Réduire le panneau des thématiques au démarrage", "modal.theme.paramspanel.title": "Paramètres de la thématique sélectionnée", "modal.theme.paramspanel.name": "Nom", @@ -495,8 +495,8 @@ "tabs.data.help_title": "Selection, configuration and organization of the data", "tabs.data.help_text": "Create several themes (folders) then put some data in them, coming from several platforms. You can also add some external themes", "tabs.data.themespanel.title": "Themes panel", - "tabs.data.themespanel.create": "Create", - "tabs.data.themespanel.import": "Import", + "tabs.data.themespanel.create": "Add a theme", + "tabs.data.themespanel.import": "Import a theme", "tabs.data.themespanel.options": "Display option: shrink the themes panel on startup", "tabs.data.paramspanel.title": "Configure the selected Theme", "tabs.data.paramspanel.name": "Name", From 3dca0caee5ac4994dfd037b7c74f4c54d9b12ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Thu, 28 Nov 2024 14:19:39 +0100 Subject: [PATCH 09/51] issue 294 - clean delete layer in a group --- js/mviewerstudio.js | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index b8caa5be..161fa789 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -351,7 +351,7 @@ var deleteThemeItem = function (btn) { var deleteLayerItem = function (btn, themeid) { var el = $(btn).closest(".layers-list-item")[0]; - deleteLayer(el.getAttribute("data-layerid"), themeid); + deleteLayer(el.getAttribute("data-layerid"), themeid, el.getAttribute("data-groupid")); el && el.parentNode.removeChild(el); }; @@ -735,11 +735,22 @@ var deleteTheme = function (themeid) { delete config.themes[themeid]; }; -var deleteLayer = function (layerid, themeid) { - var index = config.themes[themeid].layers.findIndex(function (l) { - return l.id === layerid; - }); - config.themes[themeid].layers.splice(index, 1); +var deleteLayer = function (layerid, themeid, groupid) { + if (groupid !== undefined) { + var index = config.themes[themeid].layers.findIndex(function (l) { + return l.id === layerid; + }); + config.themes[themeid].layers.splice(index, 1); + } else { + var index = config.themes[themeid].groups + .find((group) => group.id === groupid) + .layers.findIndex(function (l) { + return l.id === layerid; + }); + config.themes[themeid].groups + .find((group) => group.id === groupid) + .layers.splice(index, 1); + } }; var deleteGroup = function (groupid, themeid) { From 2ce63c198f9dfd253245052e003faca9c573db1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Thu, 28 Nov 2024 15:31:07 +0100 Subject: [PATCH 10/51] issue 294 - layer edition in a group && save studio at save editing layer --- index.html | 2 +- js/mviewerstudio.js | 7 +++---- lib/mv.js | 27 ++++++++++++++++++++++++--- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/index.html b/index.html index 36fbc1fa..adefc3ad 100755 --- a/index.html +++ b/index.html @@ -1647,7 +1647,7 @@

diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index 161fa789..1d0766e0 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -390,7 +390,7 @@ var addLayer = function (title, layerid, themeid, groupid) {
- +
`); return item; @@ -416,15 +416,14 @@ var addGroup = (themeid, title, groupId) => { return item; }; -var editLayer = function (item, themeid, layerid) { +var editLayer = function (item, themeid, layerid, groupid) { mv.setCurrentThemeId(themeid); mv.setCurrentLayerId(layerid); var element = $(item).parent().parent(); - var layerid = element.attr("data-layerid"); if (layerid != "undefined") { $("#mod-layerOptions").modal("show"); - mv.showLayerOptions(element, themeid, layerid); + mv.showLayerOptions(element, themeid, layerid, groupid); } else { $("#input-ogc-filter").val(""); $("#csw-results .csw-result").remove(); diff --git a/lib/mv.js b/lib/mv.js index dd7007fb..1735aa27 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -18,6 +18,7 @@ var mv = (function () { var _currentThemeId = ""; var _currentLayerId = ""; + var _currentGroupId = ""; var _userInfo = { userName: "", @@ -43,6 +44,14 @@ var mv = (function () { return _currentLayerId; }, + setCurrentGroupId: (groupId) => { + _currentGroupId = groupId; + }, + + getCurrentGroupId: () => { + return _currentGroupId; + }, + getLayerById: (layerid = null) => { if (!layerid) { var el = $(".layers-list-item.active"); @@ -595,7 +604,7 @@ var mv = (function () { } }, - showLayerOptions: function (el, themeid, layerid) { + showLayerOptions: function (el, themeid, layerid, groupid) { // Init params display [...document.querySelectorAll("#mod-layerOptions .layerOption-wms")].forEach((e) => e.classList.add("d-none") @@ -620,7 +629,12 @@ var mv = (function () { function getLayerbyId(l) { return l.id === layerid; } - var layer = config.themes[themeid].layers.find(getLayerbyId); + var layer = + groupid === "undefined" + ? config.themes[themeid].layers.find(getLayerbyId) + : config.themes[themeid].groups + .find((group) => group.id === groupid) + .layers.find(getLayerbyId); document.getElementById("layerTypeLabel").append(layer.type); @@ -796,10 +810,16 @@ var mv = (function () { saveLayerOptions: function (layerid = null) { var layerid = mv.getCurrentLayerId(); const themeid = mv.getCurrentThemeId(); + const groupid = mv.getCurrentGroupId(); function getLayerbyId(l) { return l.id === layerid; } - var layer = config.themes[themeid].layers.find(getLayerbyId); + var layer = + groupid === "undefined" + ? config.themes[themeid].layers.find(getLayerbyId) + : config.themes[themeid].groups + .find((group) => group.id === groupid) + .layers.find(getLayerbyId); // Commons params layer.type = $("#frm-type").val(); @@ -907,6 +927,7 @@ var mv = (function () { $(`div[data-layerid="${layerid}"] .layer-name`).text(layer.name); mv.writeFieldsOptions(layer); + mv.saveAllThemes(); }, form2xml: function () { From 3321edb65e650d974a1293b42018d7cf261076cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Fri, 15 Nov 2024 10:06:30 +0100 Subject: [PATCH 11/51] modify the drag n drop and groups layer in themes --- js/mviewerstudio.js | 123 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 98 insertions(+), 25 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index 12c2beae..dde20567 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -355,24 +355,6 @@ var deleteLayerItem = function (btn, themeid) { el && el.parentNode.removeChild(el); }; -var sortableThemeList = Sortable.create(document.getElementById("themes-list"), { - handle: ".moveList", - animation: 150, - ghostClass: "ghost", - onEnd: function (evt) { - sortThemes(); - }, -}); - -sortThemes = function () { - var orderedThemes = {}; - $(".themes-list-item").each(function (i, item) { - var id = $(this).attr("data-themeid"); - orderedThemes[id] = config.themes[id]; - }); - config.themes = orderedThemes; -}; - setConf = (key, value) => { _conf[key] = value; }; @@ -397,7 +379,7 @@ var addLayer = function (title, layerid, themeid) { saveThemes(); } var item = $(`#themeLayers-${themeid}`).append(` -
+
${title}
@@ -407,6 +389,44 @@ var addLayer = function (title, layerid, themeid) {
`); }; +var addGroup = (themeid) => { + // test if theme is saved + if (!config.themes[themeid]) { + saveThemes(); + } + const title = "Nouveau groupe"; + const item = $(`#themeGroups-${themeid}`).append(` +
+
+ +
+ + +
+
+
+
+ TRUC 01 +
+ + + +
+
+
+ TRUC 02 +
+ + + +
+
+
+
`); + initializeNestedSortables(); + return item; +}; + var editLayer = function (item, themeid, layerid) { mv.setCurrentThemeId(themeid); mv.setCurrentLayerId(layerid); @@ -435,11 +455,31 @@ var importThemes = function () { $("#mod-themesview").modal("hide"); }; +sortThemes = function () { + var orderedThemes = {}; + $(".themes-list-item").each(function (i, item) { + var id = $(this).attr("data-themeid"); + orderedThemes[id] = config.themes[id]; + }); + config.themes = orderedThemes; +}; + +var sortableThemeList = Sortable.create(document.getElementById("themes-list"), { + handle: ".moveList", + animation: 150, + ghostClass: "ghost", + onEnd: function (evt) { + sortThemes(); + }, +}); + var sortableElement = function (targetId, callback) { Sortable.create(document.getElementById(targetId), { handle: ".moveList", animation: 150, ghostClass: "ghost", + fallbackOnBody: true, + swapThreshold: 0.65, onEnd: function (evt) { callback(evt); }, @@ -447,11 +487,40 @@ var sortableElement = function (targetId, callback) { }; sortableElement("themes-list", sortThemes); +function initializeNestedSortables() { + const nestedSortables = document.querySelectorAll(".nested-sortable"); + + nestedSortables.forEach((sortableElement) => { + if (!sortableElement.getAttribute("data-sortable-initialized")) { + new Sortable(sortableElement, { + handle: ".moveList", + animation: 150, + ghostClass: "ghost", + fallbackOnBody: true, + swapThreshold: 0.65, + group: { + name: "nested", + pull: true, + put: true, + }, + onEnd: function (evt) { + console.log(`Élément déplacé de ${evt.from.id} vers ${evt.to.id}`); + }, + }); + // Marquer cet élément comme "initialisé" pour éviter les doublons + sortableElement.setAttribute("data-sortable-initialized", true); + } + }); +} + +// Initialisation au chargement du DOM +initializeNestedSortables(); + var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility) { if (url) { //external theme $("#themes-list").append(` -
+
${title}Ext.
@@ -463,10 +532,10 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility)
`); } else { $("#themes-list").append( - `
+ `
- + 0
@@ -474,14 +543,18 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility)
+ -
-
+
+
+
+
+
` ); - sortableElement("themeLayers-" + themeid, sortLayers); + initializeNestedSortables(); } config.themes[themeid] = { title: title, From 058e979609987f4ffd3b6729c1e13748d23675e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Mon, 18 Nov 2024 14:30:40 +0100 Subject: [PATCH 12/51] wip enregistrement groupes --- css/mviewerstudio.css | 2 +- js/mviewerstudio.js | 37 +++++++++++++++---------------------- lib/mv.js | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/css/mviewerstudio.css b/css/mviewerstudio.css index aa9bab23..d7872f96 100644 --- a/css/mviewerstudio.css +++ b/css/mviewerstudio.css @@ -689,7 +689,7 @@ flex: 1 50%; } - .themes-list-item .theme-layer-list { + .themes-list-item .theme-layer-list .theme-group-list { flex: 1!important; } diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index dde20567..2dc3becc 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -389,14 +389,13 @@ var addLayer = function (title, layerid, themeid) {
`); }; -var addGroup = (themeid) => { +var addGroup = (themeid, title, groupId) => { // test if theme is saved if (!config.themes[themeid]) { saveThemes(); } - const title = "Nouveau groupe"; const item = $(`#themeGroups-${themeid}`).append(` -
+
@@ -404,24 +403,7 @@ var addGroup = (themeid) => {
-
-
- TRUC 01 -
- - - -
-
-
- TRUC 02 -
- - - -
-
-
+
`); initializeNestedSortables(); return item; @@ -469,6 +451,7 @@ var sortableThemeList = Sortable.create(document.getElementById("themes-list"), animation: 150, ghostClass: "ghost", onEnd: function (evt) { + console.log("Move thème"); sortThemes(); }, }); @@ -543,7 +526,7 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility)
- + @@ -956,6 +939,11 @@ var getConfig = () => { '">', ]; } + $(t.groups).each((i, g) => { + var group = mv.writeGroupNode(g); + theme.push(group); + }); + $(t.layers).each(function (i, l) { var layer = mv.writeLayerNode(l); theme.push(layer); @@ -985,6 +973,7 @@ var getConfig = () => { themes.join(" "), padding(0) + "", ]; + console.log({ conf }); return conf; }; @@ -1020,6 +1009,8 @@ let previewAppsWithoutSave = (id, showPublish) => { return window.open(previewUrl, "mvs_vizualize"); } const confXml = getConfig(); + console.log({ confXml }); + if (!confXml || (confXml && !mv.validateXML(confXml.join("")))) { return alertCustom("XML invalide !", "danger"); } @@ -1142,6 +1133,8 @@ var saveApplicationParameters = (close) => { }; var saveAppWithPython = (exists, conf, url, close) => { + console.log("conf python : ", conf); + return fetch(url, { method: exists ? "PUT" : "POST", headers: { diff --git a/lib/mv.js b/lib/mv.js index 5b351842..c3a16227 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -562,6 +562,23 @@ var mv = (function () { $(".ogc-result input[type='checkbox']:checked").prop("checked", false); }, + getConfGroups: function () { + const themeid = mv.getCurrentThemeId(); + const groupId = `group-${mv.uuid()}`; + const groupTitle = "Nouveau groupe"; + const group = { + id: groupId, + title: groupTitle, + }; + if (!config.themes[themeid].groups) { + config.themes[themeid].groups = []; + } + console.log("CONFIG THEME : ", config.themes[themeid]); + + config.themes[themeid].groups.push(group); + addGroup(themeid, groupTitle, groupId); + }, + resetConfLayer: function () { // Reset input document.getElementById("newlayer-type").value = ""; @@ -1019,6 +1036,29 @@ var mv = (function () { return layer.join(""); }, + writeGroupNode: function (g) { + console.log({ g }); + var padding = function (n) { + return "\r\n" + " ".repeat(n); + }; + var groupParameters = {}; + //require parameters + var requireParameters = ["id", "title"]; + requireParameters.forEach(function (p, i) { + var value = g[p]; + groupParameters[p] = [p, '="', value, '"'].join(""); + }); + + var group = [padding(8) + ""); + group.push(padding(8) + ""); + + return group.join(""); + }, + escapeXml: function (unsafe) { var rep = ""; if (unsafe) { From 5d2ec0a3df36489b6292bf076b1132973164e107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Fri, 22 Nov 2024 09:15:45 +0100 Subject: [PATCH 13/51] add save and load theme, groups and layers --- js/mviewerstudio.js | 126 +++++++++++++++++++++++++++++++++++++++----- lib/mv.js | 116 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 225 insertions(+), 17 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index 2dc3becc..2dcb826f 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -355,6 +355,12 @@ var deleteLayerItem = function (btn, themeid) { el && el.parentNode.removeChild(el); }; +var deleteGroupItem = function (btn, themeid) { + var el = $(btn).closest(".list-group-item")[0]; + deleteGroup(el.id, themeid); + el && el.parentNode.removeChild(el); +}; + setConf = (key, value) => { _conf[key] = value; }; @@ -373,13 +379,13 @@ $("input[type=file]").change(function () { loadApplicationParametersFromFile(); }); -var addLayer = function (title, layerid, themeid) { +var addLayer = function (title, layerid, themeid, groupid) { // test if theme is saved if (!config.themes[themeid]) { saveThemes(); } - var item = $(`#themeLayers-${themeid}`).append(` -
+ var item = $(groupid ? `#${groupid} .list-group` : `#themeLayers-${themeid}`).append(` +
${title}
@@ -387,6 +393,7 @@ var addLayer = function (title, layerid, themeid) {
`); + return item; }; var addGroup = (themeid, title, groupId) => { @@ -395,12 +402,12 @@ var addGroup = (themeid, title, groupId) => { saveThemes(); } const item = $(`#themeGroups-${themeid}`).append(` -
+
- +
@@ -427,7 +434,6 @@ var editLayer = function (item, themeid, layerid) { var importThemes = function () { console.groupCollapsed("importThemes"); - //console.log("external theme to import", _conf.external_themes.data); $("#tableThemaExt .selected").each(function (id, item) { var url = $(item).attr("data-url"); var id = $(item).attr("data-theme-id"); @@ -451,7 +457,6 @@ var sortableThemeList = Sortable.create(document.getElementById("themes-list"), animation: 150, ghostClass: "ghost", onEnd: function (evt) { - console.log("Move thème"); sortThemes(); }, }); @@ -487,7 +492,75 @@ function initializeNestedSortables() { put: true, }, onEnd: function (evt) { - console.log(`Élément déplacé de ${evt.from.id} vers ${evt.to.id}`); + const item = evt.item; + const fromThemeId = evt.from.closest(".themes-list-item")?.id; + const fromGroupId = evt.from.closest(".group-item")?.id + ? evt.from.closest(".group-item").id + : null; + const toThemeId = evt.to.closest(".themes-list-item")?.id; + const toGroupId = evt.to.closest(".group-item")?.id + ? evt.to.closest(".group-item").id + : null; + + item.setAttribute("data-groupid", toGroupId); + item.setAttribute("data-themeid", toThemeId); + + // Si item est un layer + if (item.classList.contains("layers-list-item")) { + config.themes[toThemeId].layers.forEach((layer) => { + if (layer.id === item.getAttribute("data-layerid")) { + layer["data-groupid"] = toGroupId; + layer["data-themeid"] = toThemeId; + } + }); + // Cherche l'index de départ en fonction de si le layer bougé vient d'un groupe ou un thème + const index = fromGroupId + ? config.themes[fromThemeId].groups + .find((group) => group.id === fromGroupId) + .layers.findIndex((layer) => layer.id === item.id) + : config.themes[fromThemeId].layers.findIndex( + (layer) => layer.id === item.id + ); + + // Si l'index éxiste, suppr l'item de la position de départ et l'ajoute à l'arrivée + if (index !== -1) { + // Si le thème n'a pas de layer, on set theme.layers à [] + if (!config.themes[fromThemeId].layers) + config.themes[fromThemeId].layers = []; + // Si le groupe n'a pas de layers, on set group.layers à [] + if ( + !config.themes[toThemeId].groups.find((group) => group.id === toGroupId) + .layers + ) + config.themes[toThemeId].groups.find( + (group) => group.id === toGroupId + ).layers = []; + const [itemToMove] = fromGroupId + ? config.themes[fromThemeId].groups + .find((group) => group.id === fromGroupId) + .layers.splice(index, 1) + : config.themes[fromThemeId].layers.splice(index, 1); + toGroupId + ? config.themes[toThemeId].groups + .find((group) => group.id === toGroupId) + .layers.push(itemToMove) + : config.themes[toThemeId].layers.push(itemToMove); + } + } else { + // sinon item est un groupe + config.themes[toThemeId].groups.forEach((group) => { + if (group.id === item.getAttribute("data-groupid")) { + group["data-themeid"] = toThemeId; + } + }); + const index = config.themes[fromThemeId].groups.findIndex( + (group) => group.id === item.id + ); + if (index !== -1) { + const [itemToMove] = config.themes[fromThemeId].groups.splice(index, 1); + config.themes[toThemeId].groups.push(itemToMove); + } + } }, }); // Marquer cet élément comme "initialisé" pour éviter les doublons @@ -503,7 +576,7 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility) if (url) { //external theme $("#themes-list").append(` -
+
${title}Ext.
@@ -595,6 +668,27 @@ var saveThemes = function () { } }; +var saveGroups = () => { + const themes = $(".themes-list-item"); + for (i = 0; i < themes.length; i++) { + const theme = themes[i]; + const themeId = theme.getAttribute("data-themeid"); + const groups = $(`#${themeId}`).find(".group-item"); + + for (j = 0; j < groups.length; j++) { + const group = groups[j]; + const groupId = group.id; + + const gr = $(`div[id="${groupId}"]`); + const groupTitle = gr.find(".group-name").val(); + + config.themes[themeId].groups.find((group) => group.id === groupId).id = groupId; + config.themes[themeId].groups.find((group) => group.id === groupId).title = + groupTitle; + } + } +}; + var editThemeExt = function (item) { $("#themes-list .list-group-item").removeClass("active"); $(item).parent().parent().addClass("active"); @@ -634,6 +728,13 @@ var deleteLayer = function (layerid, themeid) { config.themes[themeid].layers.splice(index, 1); }; +var deleteGroup = function (groupid, themeid) { + var index = config.themes[themeid].groups.findIndex(function (g) { + return g.id === groupid; + }); + config.themes[themeid].groups.splice(index, 1); +}; + var createId = function (obj) { var d = new Date(); var df = @@ -904,6 +1005,7 @@ var getConfig = () => { // Respect theme order $(".themes-list-item").each(function (id, theme) { saveThemes(); + saveGroups(); var themeid = $(theme).attr("data-themeid"); if (config.themes[themeid]) { var t = config.themes[themeid]; @@ -939,15 +1041,17 @@ var getConfig = () => { '">', ]; } + // push groupes $(t.groups).each((i, g) => { var group = mv.writeGroupNode(g); theme.push(group); }); - + // push layers hors groupes $(t.layers).each(function (i, l) { var layer = mv.writeLayerNode(l); theme.push(layer); }); + themes.push(theme.join(" ")); themes.push(padding(4) + ""); } @@ -973,8 +1077,6 @@ var getConfig = () => { themes.join(" "), padding(0) + "", ]; - console.log({ conf }); - return conf; }; diff --git a/lib/mv.js b/lib/mv.js index c3a16227..db4c045b 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -569,12 +569,11 @@ var mv = (function () { const group = { id: groupId, title: groupTitle, + layers: [], }; if (!config.themes[themeid].groups) { config.themes[themeid].groups = []; } - console.log("CONFIG THEME : ", config.themes[themeid]); - config.themes[themeid].groups.push(group); addGroup(themeid, groupTitle, groupId); }, @@ -1037,7 +1036,6 @@ var mv = (function () { }, writeGroupNode: function (g) { - console.log({ g }); var padding = function (n) { return "\r\n" + " ".repeat(n); }; @@ -1054,9 +1052,14 @@ var mv = (function () { group.push(padding(12) + parameter); }); group.push(">"); + //push layers dans le groupe + $(g.layers).each(function (i, l) { + var layer = mv.writeLayerNode(l); + group.push(layer); + }); group.push(padding(8) + ""); - return group.join(""); + return group.join(" "); }, escapeXml: function (unsafe) { @@ -1630,11 +1633,13 @@ var mv = (function () { $("#frm-bl .custom-bl input").prop("checked", true).trigger("change"); var visibleBaselayer = $(xml).find('baselayer[visible="true"]').attr("id"); $("#frm-bl-visible").val(visibleBaselayer).trigger("change"); + //tHEMES & layers var themePanel = $(xml).find("themes"); if (themePanel.attr("mini") === "true") { $("#opt-mini").prop("checked", true); } + var themes = $(xml).find("theme"); themes.each(function (id, th) { addTheme( @@ -1645,7 +1650,108 @@ var mv = (function () { $(th).attr("url"), $(th).attr("layersvisibility") ); - var layers = $(th).find("layer"); + + // Ajout des groupes et de leurs layers + var groups = $(th).find("group"); + groups.each((id, g) => { + var group = { + id: $(g).attr("id"), + title: $(g).attr("title"), + }; + addGroup($(th).attr("id"), group.title, group.id); + //Si le thème n'a pas de groupes, on set theme.group à [] + if (!config.themes[$(th).attr("id")].groups) + config.themes[$(th).attr("id")].groups = []; + config.themes[$(th).attr("id")].groups.push(group); + + var layers = $(g).find("layer"); + if (layers) + layers.each(function (id, l) { + counter += 1; + var layer = { + id: $(l).attr("id"), + type: $(l).attr("type") || "wms", + tiled: $(l).attr("tiled") === "true", + scalemin: $(l).attr("scalemin"), + scalemax: $(l).attr("scalemax"), + title: $(l).attr("name"), + name: $(l).attr("name"), + url: $(l).attr("url"), + queryable: $(l).attr("queryable") === "true", + featurecount: $(l).attr("featurecount"), + infopanel: $(l).attr("infopanel") || "right-panel", + searchable: $(l).attr("searchable") === "true", + searchengine: $(l).attr("searchengine"), + fusesearchkeys: $(l).attr("fusesearchkeys"), + fusesearchresult: $(l).attr("fusesearchresult"), + secure: $(l).attr("secure") || "public", + useproxy: $(l).attr("useproxy") === "true", + infoformat: $(l).attr("infoformat"), + metadata: $(l).attr("metadata"), + "metadata-csw": $(l).attr("metadata-csw"), + attribution: $(l).attr("attribution"), + filter: $(l).attr("filter"), + visible: $(l).attr("visible") === "true", + opacity: $(l).attr("opacity"), + template: $(l).find("template").text(), + useexternaltemplate: + ($(l).find("template") && $(l).find("template").text().length > 3) || + ($(l).find("template").attr("url") && + $(l).find("template").attr("url").length > 1), + templateurl: false, + fields: $(l).attr("fields"), + fieldsoptions: false, + aliases: $(l).attr("aliases"), + style: $(l).attr("style"), + styleurl: $(l).attr("styleurl"), + filterstyle: $(l).attr("filterstyle"), + stylesalias: $(l).attr("stylesalias"), + sld: $(l).attr("sld"), + legendurl: $(l).attr("legendurl"), + attributefilter: $(l).attr("attributefilter") === "true", + showintoc: $(l).attr("showintoc") === "true", + exclusive: $(l).attr("exclusive") === "true", + toplayer: $(l).attr("toplayer") === "true", + expanded: $(l).attr("expanded") === "true", + dynamiclegend: $(l).attr("dynamiclegend") === "true", + styletitle: $(l).attr("styletitle"), + index: $(l).attr("index"), + jsonfields: $(l).attr("jsonfields"), + }; + addLayer(layer.title, layer.id, $(th).attr("id"), group.id); + if (layer.attributefilter) { + layer.attributefield = $(l).attr("attributefield"); + layer.attributelabel = $(l).attr("attributelabel"); + layer.attributevalues = $(l).attr("attributevalues"); + } + if ( + layer.useexternaltemplate === true && + $(l).find("template").attr("url") + ) { + layer.templateurl = $(l).find("template").attr("url"); + } + $("#frm-template").prop("checked", layer.useexternaltemplate); + if (layer.fields && layer.aliases) { + layer.fieldsoptions = {}; + $(layer.fields.split(",")).each(function (index, fld) { + var type = "text"; + var alias = layer.aliases.split(",")[index]; + layer.fieldsoptions[fld] = { name: fld, alias: alias, type: type }; + }); + } + //Si le groupe n'a pas de layers, on set group.layers à [] + if ( + !config.themes[$(th).attr("id")].groups.find((group) => group.id).layers + ) + config.themes[$(th).attr("id")].groups.find((group) => group.id).layers = + []; + config.themes[$(th).attr("id")].groups + .find((group) => group.id) + .layers.push(layer); + }); + }); + // Ajout des layers hors groupes + var layers = $(th).children("layer"); var counter = 0; layers.each(function (id, l) { counter += 1; From fa72b704af38da96192144b7bb60078a66083b82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Fri, 22 Nov 2024 09:24:58 +0100 Subject: [PATCH 14/51] clean code --- js/mviewerstudio.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index 2dcb826f..c7b72a8f 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -1111,8 +1111,6 @@ let previewAppsWithoutSave = (id, showPublish) => { return window.open(previewUrl, "mvs_vizualize"); } const confXml = getConfig(); - console.log({ confXml }); - if (!confXml || (confXml && !mv.validateXML(confXml.join("")))) { return alertCustom("XML invalide !", "danger"); } @@ -1235,8 +1233,6 @@ var saveApplicationParameters = (close) => { }; var saveAppWithPython = (exists, conf, url, close) => { - console.log("conf python : ", conf); - return fetch(url, { method: exists ? "PUT" : "POST", headers: { From 395d9aae8ae69a8d4bc19ddf531040daaae65976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Fri, 22 Nov 2024 12:46:29 +0100 Subject: [PATCH 15/51] clean code and graphic design --- css/bootstrap.css | 4 ++-- css/mviewerstudio.css | 12 ++++++++++++ js/mviewerstudio.js | 39 ++++++++++++++++++++++----------------- lib/Sortable.min.js | 4 ++-- 4 files changed, 38 insertions(+), 21 deletions(-) diff --git a/css/bootstrap.css b/css/bootstrap.css index b3c0e73d..cc228718 100644 --- a/css/bootstrap.css +++ b/css/bootstrap.css @@ -3850,9 +3850,9 @@ input[type="button"].btn-block { .list-group-item { position: relative; display: block; - padding: 0.9rem 1.25rem; + padding: 0.5rem 0.75rem; background-color: #fff; - border: 1px solid rgba(0, 0, 0, 0.125); } +} .list-group-item:first-child { border-top-left-radius: inherit; border-top-right-radius: inherit; } diff --git a/css/mviewerstudio.css b/css/mviewerstudio.css index d7872f96..a645d52a 100644 --- a/css/mviewerstudio.css +++ b/css/mviewerstudio.css @@ -51,6 +51,18 @@ .list-group-item { background-color: #ffffff00; } + + .group_list { + background-color: #e1e1e1; + } + + .layer_item { + background-color: #e1e1e1; + } + + .group_list .layer_item { + background-color: #c5c5c5; + } .modal { overflow-y: auto !important; diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index c7b72a8f..f62ae8ce 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -385,7 +385,7 @@ var addLayer = function (title, layerid, themeid, groupid) { saveThemes(); } var item = $(groupid ? `#${groupid} .list-group` : `#themeLayers-${themeid}`).append(` -
+
${title}
@@ -410,7 +410,7 @@ var addGroup = (themeid, title, groupId) => {
-
+
`); initializeNestedSortables(); return item; @@ -501,6 +501,7 @@ function initializeNestedSortables() { const toGroupId = evt.to.closest(".group-item")?.id ? evt.to.closest(".group-item").id : null; + const newIndex = evt.newIndex; item.setAttribute("data-groupid", toGroupId); item.setAttribute("data-themeid", toThemeId); @@ -527,14 +528,16 @@ function initializeNestedSortables() { // Si le thème n'a pas de layer, on set theme.layers à [] if (!config.themes[fromThemeId].layers) config.themes[fromThemeId].layers = []; - // Si le groupe n'a pas de layers, on set group.layers à [] - if ( - !config.themes[toThemeId].groups.find((group) => group.id === toGroupId) - .layers - ) - config.themes[toThemeId].groups.find( - (group) => group.id === toGroupId - ).layers = []; + // Si le groupe d'arrivé n'a pas de layers, on set group.layers à [] + if (toGroupId) + if ( + !config.themes[toThemeId].groups.find((group) => group.id === toGroupId) + .layers + ) + config.themes[toThemeId].groups.find( + (group) => group.id === toGroupId + ).layers = []; + const [itemToMove] = fromGroupId ? config.themes[fromThemeId].groups .find((group) => group.id === fromGroupId) @@ -543,8 +546,8 @@ function initializeNestedSortables() { toGroupId ? config.themes[toThemeId].groups .find((group) => group.id === toGroupId) - .layers.push(itemToMove) - : config.themes[toThemeId].layers.push(itemToMove); + .layers.splice(newIndex, 0, itemToMove) + : config.themes[toThemeId].layers.splice(newIndex, 0, itemToMove); } } else { // sinon item est un groupe @@ -605,8 +608,8 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility)
-
-
+
Groupes
+
Couches
` ); @@ -682,9 +685,11 @@ var saveGroups = () => { const gr = $(`div[id="${groupId}"]`); const groupTitle = gr.find(".group-name").val(); - config.themes[themeId].groups.find((group) => group.id === groupId).id = groupId; - config.themes[themeId].groups.find((group) => group.id === groupId).title = - groupTitle; + if (config.themes[themeId].groups) { + config.themes[themeId].groups.find((group) => group.id === groupId).id = groupId; + config.themes[themeId].groups.find((group) => group.id === groupId).title = + groupTitle; + } } } }; diff --git a/lib/Sortable.min.js b/lib/Sortable.min.js index e95d2a30..abe4ddbf 100755 --- a/lib/Sortable.min.js +++ b/lib/Sortable.min.js @@ -1,2 +1,2 @@ -/*! Sortable 1.4.2 - MIT | git://github.com/rubaxa/Sortable.git */ -!function(a){"use strict";"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module&&"undefined"!=typeof module.exports?module.exports=a():"undefined"!=typeof Package?Sortable=a():window.Sortable=a()}(function(){"use strict";function a(a,b){if(!a||!a.nodeType||1!==a.nodeType)throw"Sortable: `el` must be HTMLElement, and not "+{}.toString.call(a);this.el=a,this.options=b=r({},b),a[L]=this;var c={group:Math.random(),sort:!0,disabled:!1,store:null,handle:null,scroll:!0,scrollSensitivity:30,scrollSpeed:10,draggable:/[uo]l/i.test(a.nodeName)?"li":">*",ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",ignore:"a, img",filter:null,animation:0,setData:function(a,b){a.setData("Text",b.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1};for(var d in c)!(d in b)&&(b[d]=c[d]);V(b);for(var f in this)"_"===f.charAt(0)&&(this[f]=this[f].bind(this));this.nativeDraggable=b.forceFallback?!1:P,e(a,"mousedown",this._onTapStart),e(a,"touchstart",this._onTapStart),this.nativeDraggable&&(e(a,"dragover",this),e(a,"dragenter",this)),T.push(this._onDragOver),b.store&&this.sort(b.store.get(this))}function b(a){v&&v.state!==a&&(h(v,"display",a?"none":""),!a&&v.state&&w.insertBefore(v,s),v.state=a)}function c(a,b,c){if(a){c=c||N,b=b.split(".");var d=b.shift().toUpperCase(),e=new RegExp("\\s("+b.join("|")+")(?=\\s)","g");do if(">*"===d&&a.parentNode===c||(""===d||a.nodeName.toUpperCase()==d)&&(!b.length||((" "+a.className+" ").match(e)||[]).length==b.length))return a;while(a!==c&&(a=a.parentNode))}return null}function d(a){a.dataTransfer&&(a.dataTransfer.dropEffect="move"),a.preventDefault()}function e(a,b,c){a.addEventListener(b,c,!1)}function f(a,b,c){a.removeEventListener(b,c,!1)}function g(a,b,c){if(a)if(a.classList)a.classList[c?"add":"remove"](b);else{var d=(" "+a.className+" ").replace(K," ").replace(" "+b+" "," ");a.className=(d+(c?" "+b:"")).replace(K," ")}}function h(a,b,c){var d=a&&a.style;if(d){if(void 0===c)return N.defaultView&&N.defaultView.getComputedStyle?c=N.defaultView.getComputedStyle(a,""):a.currentStyle&&(c=a.currentStyle),void 0===b?c:c[b];b in d||(b="-webkit-"+b),d[b]=c+("string"==typeof c?"":"px")}}function i(a,b,c){if(a){var d=a.getElementsByTagName(b),e=0,f=d.length;if(c)for(;f>e;e++)c(d[e],e);return d}return[]}function j(a,b,c,d,e,f,g){var h=N.createEvent("Event"),i=(a||b[L]).options,j="on"+c.charAt(0).toUpperCase()+c.substr(1);h.initEvent(c,!0,!0),h.to=b,h.from=e||b,h.item=d||b,h.clone=v,h.oldIndex=f,h.newIndex=g,b.dispatchEvent(h),i[j]&&i[j].call(a,h)}function k(a,b,c,d,e,f){var g,h,i=a[L],j=i.options.onMove;return g=N.createEvent("Event"),g.initEvent("move",!0,!0),g.to=b,g.from=a,g.dragged=c,g.draggedRect=d,g.related=e||b,g.relatedRect=f||b.getBoundingClientRect(),a.dispatchEvent(g),j&&(h=j.call(i,g)),h}function l(a){a.draggable=!1}function m(){R=!1}function n(a,b){var c=a.lastElementChild,d=c.getBoundingClientRect();return(b.clientY-(d.top+d.height)>5||b.clientX-(d.right+d.width)>5)&&c}function o(a){for(var b=a.tagName+a.className+a.src+a.href+a.textContent,c=b.length,d=0;c--;)d+=b.charCodeAt(c);return d.toString(36)}function p(a){var b=0;if(!a||!a.parentNode)return-1;for(;a&&(a=a.previousElementSibling);)"TEMPLATE"!==a.nodeName.toUpperCase()&&b++;return b}function q(a,b){var c,d;return function(){void 0===c&&(c=arguments,d=this,setTimeout(function(){1===c.length?a.call(d,c[0]):a.apply(d,c),c=void 0},b))}}function r(a,b){if(a&&b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}var s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J={},K=/\s+/g,L="Sortable"+(new Date).getTime(),M=window,N=M.document,O=M.parseInt,P=!!("draggable"in N.createElement("div")),Q=function(a){return a=N.createElement("x"),a.style.cssText="pointer-events:auto","auto"===a.style.pointerEvents}(),R=!1,S=Math.abs,T=([].slice,[]),U=q(function(a,b,c){if(c&&b.scroll){var d,e,f,g,h=b.scrollSensitivity,i=b.scrollSpeed,j=a.clientX,k=a.clientY,l=window.innerWidth,m=window.innerHeight;if(z!==c&&(y=b.scroll,z=c,y===!0)){y=c;do if(y.offsetWidth=l-j)-(h>=j),g=(h>=m-k)-(h>=k),(f||g)&&(d=M)),(J.vx!==f||J.vy!==g||J.el!==d)&&(J.el=d,J.vx=f,J.vy=g,clearInterval(J.pid),d&&(J.pid=setInterval(function(){d===M?M.scrollTo(M.pageXOffset+f*i,M.pageYOffset+g*i):(g&&(d.scrollTop+=g*i),f&&(d.scrollLeft+=f*i))},24)))}},30),V=function(a){var b=a.group;b&&"object"==typeof b||(b=a.group={name:b}),["pull","put"].forEach(function(a){a in b||(b[a]=!0)}),a.groups=" "+b.name+(b.put.join?" "+b.put.join(" "):"")+" "};return a.prototype={constructor:a,_onTapStart:function(a){var b=this,d=this.el,e=this.options,f=a.type,g=a.touches&&a.touches[0],h=(g||a).target,i=h,k=e.filter;if(!("mousedown"===f&&0!==a.button||e.disabled)&&(h=c(h,e.draggable,d))){if(D=p(h),"function"==typeof k){if(k.call(this,a,h,this))return j(b,i,"filter",h,d,D),void a.preventDefault()}else if(k&&(k=k.split(",").some(function(a){return a=c(i,a.trim(),d),a?(j(b,a,"filter",h,d,D),!0):void 0})))return void a.preventDefault();(!e.handle||c(i,e.handle,d))&&this._prepareDragStart(a,g,h)}},_prepareDragStart:function(a,b,c){var d,f=this,h=f.el,j=f.options,k=h.ownerDocument;c&&!s&&c.parentNode===h&&(G=a,w=h,s=c,t=s.parentNode,x=s.nextSibling,F=j.group,d=function(){f._disableDelayedDrag(),s.draggable=!0,g(s,f.options.chosenClass,!0),f._triggerDragStart(b)},j.ignore.split(",").forEach(function(a){i(s,a.trim(),l)}),e(k,"mouseup",f._onDrop),e(k,"touchend",f._onDrop),e(k,"touchcancel",f._onDrop),j.delay?(e(k,"mouseup",f._disableDelayedDrag),e(k,"touchend",f._disableDelayedDrag),e(k,"touchcancel",f._disableDelayedDrag),e(k,"mousemove",f._disableDelayedDrag),e(k,"touchmove",f._disableDelayedDrag),f._dragStartTimer=setTimeout(d,j.delay)):d())},_disableDelayedDrag:function(){var a=this.el.ownerDocument;clearTimeout(this._dragStartTimer),f(a,"mouseup",this._disableDelayedDrag),f(a,"touchend",this._disableDelayedDrag),f(a,"touchcancel",this._disableDelayedDrag),f(a,"mousemove",this._disableDelayedDrag),f(a,"touchmove",this._disableDelayedDrag)},_triggerDragStart:function(a){a?(G={target:s,clientX:a.clientX,clientY:a.clientY},this._onDragStart(G,"touch")):this.nativeDraggable?(e(s,"dragend",this),e(w,"dragstart",this._onDragStart)):this._onDragStart(G,!0);try{N.selection?N.selection.empty():window.getSelection().removeAllRanges()}catch(b){}},_dragStarted:function(){w&&s&&(g(s,this.options.ghostClass,!0),a.active=this,j(this,w,"start",s,w,D))},_emulateDragOver:function(){if(H){if(this._lastX===H.clientX&&this._lastY===H.clientY)return;this._lastX=H.clientX,this._lastY=H.clientY,Q||h(u,"display","none");var a=N.elementFromPoint(H.clientX,H.clientY),b=a,c=" "+this.options.group.name,d=T.length;if(b)do{if(b[L]&&b[L].options.groups.indexOf(c)>-1){for(;d--;)T[d]({clientX:H.clientX,clientY:H.clientY,target:a,rootEl:b});break}a=b}while(b=b.parentNode);Q||h(u,"display","")}},_onTouchMove:function(b){if(G){a.active||this._dragStarted(),this._appendGhost();var c=b.touches?b.touches[0]:b,d=c.clientX-G.clientX,e=c.clientY-G.clientY,f=b.touches?"translate3d("+d+"px,"+e+"px,0)":"translate("+d+"px,"+e+"px)";I=!0,H=c,h(u,"webkitTransform",f),h(u,"mozTransform",f),h(u,"msTransform",f),h(u,"transform",f),b.preventDefault()}},_appendGhost:function(){if(!u){var a,b=s.getBoundingClientRect(),c=h(s),d=this.options;u=s.cloneNode(!0),g(u,d.ghostClass,!1),g(u,d.fallbackClass,!0),h(u,"top",b.top-O(c.marginTop,10)),h(u,"left",b.left-O(c.marginLeft,10)),h(u,"width",b.width),h(u,"height",b.height),h(u,"opacity","0.8"),h(u,"position","fixed"),h(u,"zIndex","100000"),h(u,"pointerEvents","none"),d.fallbackOnBody&&N.body.appendChild(u)||w.appendChild(u),a=u.getBoundingClientRect(),h(u,"width",2*b.width-a.width),h(u,"height",2*b.height-a.height)}},_onDragStart:function(a,b){var c=a.dataTransfer,d=this.options;this._offUpEvents(),"clone"==F.pull&&(v=s.cloneNode(!0),h(v,"display","none"),w.insertBefore(v,s)),b?("touch"===b?(e(N,"touchmove",this._onTouchMove),e(N,"touchend",this._onDrop),e(N,"touchcancel",this._onDrop)):(e(N,"mousemove",this._onTouchMove),e(N,"mouseup",this._onDrop)),this._loopId=setInterval(this._emulateDragOver,50)):(c&&(c.effectAllowed="move",d.setData&&d.setData.call(this,c,s)),e(N,"drop",this),setTimeout(this._dragStarted,0))},_onDragOver:function(a){var d,e,f,g=this.el,i=this.options,j=i.group,l=j.put,o=F===j,p=i.sort;if(void 0!==a.preventDefault&&(a.preventDefault(),!i.dragoverBubble&&a.stopPropagation()),I=!0,F&&!i.disabled&&(o?p||(f=!w.contains(s)):F.pull&&l&&(F.name===j.name||l.indexOf&&~l.indexOf(F.name)))&&(void 0===a.rootEl||a.rootEl===this.el)){if(U(a,i,this.el),R)return;if(d=c(a.target,i.draggable,g),e=s.getBoundingClientRect(),f)return b(!0),void(v||x?w.insertBefore(s,v||x):p||w.appendChild(s));if(0===g.children.length||g.children[0]===u||g===a.target&&(d=n(g,a))){if(d){if(d.animated)return;r=d.getBoundingClientRect()}b(o),k(w,g,s,e,d,r)!==!1&&(s.contains(g)||(g.appendChild(s),t=g),this._animate(e,s),d&&this._animate(r,d))}else if(d&&!d.animated&&d!==s&&void 0!==d.parentNode[L]){A!==d&&(A=d,B=h(d),C=h(d.parentNode));var q,r=d.getBoundingClientRect(),y=r.right-r.left,z=r.bottom-r.top,D=/left|right|inline/.test(B.cssFloat+B.display)||"flex"==C.display&&0===C["flex-direction"].indexOf("row"),E=d.offsetWidth>s.offsetWidth,G=d.offsetHeight>s.offsetHeight,H=(D?(a.clientX-r.left)/y:(a.clientY-r.top)/z)>.5,J=d.nextElementSibling,K=k(w,g,s,e,d,r);if(K!==!1){if(R=!0,setTimeout(m,30),b(o),1===K||-1===K)q=1===K;else if(D){var M=s.offsetTop,N=d.offsetTop;q=M===N?d.previousElementSibling===s&&!E||H&&E:N>M}else q=J!==s&&!G||H&&G;s.contains(g)||(q&&!J?g.appendChild(s):d.parentNode.insertBefore(s,q?J:d)),t=s.parentNode,this._animate(e,s),this._animate(r,d)}}}},_animate:function(a,b){var c=this.options.animation;if(c){var d=b.getBoundingClientRect();h(b,"transition","none"),h(b,"transform","translate3d("+(a.left-d.left)+"px,"+(a.top-d.top)+"px,0)"),b.offsetWidth,h(b,"transition","all "+c+"ms"),h(b,"transform","translate3d(0,0,0)"),clearTimeout(b.animated),b.animated=setTimeout(function(){h(b,"transition",""),h(b,"transform",""),b.animated=!1},c)}},_offUpEvents:function(){var a=this.el.ownerDocument;f(N,"touchmove",this._onTouchMove),f(a,"mouseup",this._onDrop),f(a,"touchend",this._onDrop),f(a,"touchcancel",this._onDrop)},_onDrop:function(b){var c=this.el,d=this.options;clearInterval(this._loopId),clearInterval(J.pid),clearTimeout(this._dragStartTimer),f(N,"mousemove",this._onTouchMove),this.nativeDraggable&&(f(N,"drop",this),f(c,"dragstart",this._onDragStart)),this._offUpEvents(),b&&(I&&(b.preventDefault(),!d.dropBubble&&b.stopPropagation()),u&&u.parentNode.removeChild(u),s&&(this.nativeDraggable&&f(s,"dragend",this),l(s),g(s,this.options.ghostClass,!1),g(s,this.options.chosenClass,!1),w!==t?(E=p(s),E>=0&&(j(null,t,"sort",s,w,D,E),j(this,w,"sort",s,w,D,E),j(null,t,"add",s,w,D,E),j(this,w,"remove",s,w,D,E))):(v&&v.parentNode.removeChild(v),s.nextSibling!==x&&(E=p(s),E>=0&&(j(this,w,"update",s,w,D,E),j(this,w,"sort",s,w,D,E)))),a.active&&((null===E||-1===E)&&(E=D),j(this,w,"end",s,w,D,E),this.save())),w=s=t=u=x=v=y=z=G=H=I=E=A=B=F=a.active=null)},handleEvent:function(a){var b=a.type;"dragover"===b||"dragenter"===b?s&&(this._onDragOver(a),d(a)):("drop"===b||"dragend"===b)&&this._onDrop(a)},toArray:function(){for(var a,b=[],d=this.el.children,e=0,f=d.length,g=this.options;f>e;e++)a=d[e],c(a,g.draggable,this.el)&&b.push(a.getAttribute(g.dataIdAttr)||o(a));return b},sort:function(a){var b={},d=this.el;this.toArray().forEach(function(a,e){var f=d.children[e];c(f,this.options.draggable,d)&&(b[a]=f)},this),a.forEach(function(a){b[a]&&(d.removeChild(b[a]),d.appendChild(b[a]))})},save:function(){var a=this.options.store;a&&a.set(this)},closest:function(a,b){return c(a,b||this.options.draggable,this.el)},option:function(a,b){var c=this.options;return void 0===b?c[a]:(c[a]=b,void("group"===a&&V(c)))},destroy:function(){var a=this.el;a[L]=null,f(a,"mousedown",this._onTapStart),f(a,"touchstart",this._onTapStart),this.nativeDraggable&&(f(a,"dragover",this),f(a,"dragenter",this)),Array.prototype.forEach.call(a.querySelectorAll("[draggable]"),function(a){a.removeAttribute("draggable")}),T.splice(T.indexOf(this._onDragOver),1),this._onDrop(),this.el=a=null}},a.utils={on:e,off:f,css:h,find:i,is:function(a,b){return!!c(a,b,a)},extend:r,throttle:q,closest:c,toggleClass:g,index:p},a.create=function(b,c){return new a(b,c)},a.version="1.4.2",a}); \ No newline at end of file +/*! Sortable 1.15.3 - MIT | git://github.com/SortableJS/Sortable.git */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).Sortable=e()}(this,function(){"use strict";function e(e,t){var n,o=Object.keys(e);return Object.getOwnPropertySymbols&&(n=Object.getOwnPropertySymbols(e),t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),o.push.apply(o,n)),o}function I(o){for(var t=1;tt.length)&&(e=t.length);for(var n=0,o=new Array(e);n"===e[0]&&(e=e.substring(1)),t))try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(t){return}}function g(t){return t.host&&t!==document&&t.host.nodeType?t.host:t.parentNode}function P(t,e,n,o){if(t){n=n||document;do{if(null!=e&&(">"!==e[0]||t.parentNode===n)&&p(t,e)||o&&t===n)return t}while(t!==n&&(t=g(t)))}return null}var m,v=/\s+/g;function k(t,e,n){var o;t&&e&&(t.classList?t.classList[n?"add":"remove"](e):(o=(" "+t.className+" ").replace(v," ").replace(" "+e+" "," "),t.className=(o+(n?" "+e:"")).replace(v," ")))}function R(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];o[e=!(e in o||-1!==e.indexOf("webkit"))?"-webkit-"+e:e]=n+("string"==typeof n?"":"px")}}function b(t,e){var n="";if("string"==typeof t)n=t;else do{var o=R(t,"transform")}while(o&&"none"!==o&&(n=o+" "+n),!e&&(t=t.parentNode));var i=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return i&&new i(n)}function E(t,e,n){if(t){var o=t.getElementsByTagName(e),i=0,r=o.length;if(n)for(;i=n.left-e&&i<=n.right+e,e=r>=n.top-e&&r<=n.bottom+e;return o&&e?a=t:void 0}}),a);if(e){var n,o={};for(n in t)t.hasOwnProperty(n)&&(o[n]=t[n]);o.target=o.rootEl=e,o.preventDefault=void 0,o.stopPropagation=void 0,e[K]._onDragOver(o)}}var i,r,a}function Ft(t){Z&&Z.parentNode[K]._isOutsideThisEl(t.target)}function jt(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.el=t,this.options=e=a({},e),t[K]=this;var n,o,i={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return kt(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==jt.supportPointer&&"PointerEvent"in window&&!u,emptyInsertThreshold:5};for(n in z.initializePlugins(this,t,i),i)n in e||(e[n]=i[n]);for(o in Rt(e),this)"_"===o.charAt(0)&&"function"==typeof this[o]&&(this[o]=this[o].bind(this));this.nativeDraggable=!e.forceFallback&&It,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?h(t,"pointerdown",this._onTapStart):(h(t,"mousedown",this._onTapStart),h(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(h(t,"dragover",this),h(t,"dragenter",this)),St.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[]),a(this,A())}function Ht(t,e,n,o,i,r,a,l){var s,c,u=t[K],d=u.options.onMove;return!window.CustomEvent||y||w?(s=document.createEvent("Event")).initEvent("move",!0,!0):s=new CustomEvent("move",{bubbles:!0,cancelable:!0}),s.to=e,s.from=t,s.dragged=n,s.draggedRect=o,s.related=i||e,s.relatedRect=r||X(e),s.willInsertAfter=l,s.originalEvent=a,t.dispatchEvent(s),c=d?d.call(u,s,a):c}function Lt(t){t.draggable=!1}function Kt(){xt=!1}function Wt(t){return setTimeout(t,0)}function zt(t){return clearTimeout(t)}jt.prototype={constructor:jt,_isOutsideThisEl:function(t){this.el.contains(t)||t===this.el||(vt=null)},_getDirection:function(t,e){return"function"==typeof this.options.direction?this.options.direction.call(this,t,e,Z):this.options.direction},_onTapStart:function(e){if(e.cancelable){var n=this,o=this.el,t=this.options,i=t.preventOnFilter,r=e.type,a=e.touches&&e.touches[0]||e.pointerType&&"touch"===e.pointerType&&e,l=(a||e).target,s=e.target.shadowRoot&&(e.path&&e.path[0]||e.composedPath&&e.composedPath()[0])||l,c=t.filter;if(!function(t){Ot.length=0;var e=t.getElementsByTagName("input"),n=e.length;for(;n--;){var o=e[n];o.checked&&Ot.push(o)}}(o),!Z&&!(/mousedown|pointerdown/.test(r)&&0!==e.button||t.disabled)&&!s.isContentEditable&&(this.nativeDraggable||!u||!l||"SELECT"!==l.tagName.toUpperCase())&&!((l=P(l,t.draggable,o,!1))&&l.animated||et===l)){if(it=j(l),at=j(l,t.draggable),"function"==typeof c){if(c.call(this,e,l,this))return V({sortable:n,rootEl:s,name:"filter",targetEl:l,toEl:o,fromEl:o}),U("filter",n,{evt:e}),void(i&&e.cancelable&&e.preventDefault())}else if(c=c&&c.split(",").some(function(t){if(t=P(s,t.trim(),o,!1))return V({sortable:n,rootEl:t,name:"filter",targetEl:l,fromEl:o,toEl:o}),U("filter",n,{evt:e}),!0}))return void(i&&e.cancelable&&e.preventDefault());t.handle&&!P(s,t.handle,o,!1)||this._prepareDragStart(e,a,l)}}},_prepareDragStart:function(t,e,n){var o,i=this,r=i.el,a=i.options,l=r.ownerDocument;n&&!Z&&n.parentNode===r&&(o=X(n),J=r,$=(Z=n).parentNode,tt=Z.nextSibling,et=n,st=a.group,ut={target:jt.dragged=Z,clientX:(e||t).clientX,clientY:(e||t).clientY},pt=ut.clientX-o.left,gt=ut.clientY-o.top,this._lastX=(e||t).clientX,this._lastY=(e||t).clientY,Z.style["will-change"]="all",o=function(){U("delayEnded",i,{evt:t}),jt.eventCanceled?i._onDrop():(i._disableDelayedDragEvents(),!s&&i.nativeDraggable&&(Z.draggable=!0),i._triggerDragStart(t,e),V({sortable:i,name:"choose",originalEvent:t}),k(Z,a.chosenClass,!0))},a.ignore.split(",").forEach(function(t){E(Z,t.trim(),Lt)}),h(l,"dragover",Bt),h(l,"mousemove",Bt),h(l,"touchmove",Bt),h(l,"mouseup",i._onDrop),h(l,"touchend",i._onDrop),h(l,"touchcancel",i._onDrop),s&&this.nativeDraggable&&(this.options.touchStartThreshold=4,Z.draggable=!0),U("delayStart",this,{evt:t}),!a.delay||a.delayOnTouchOnly&&!e||this.nativeDraggable&&(w||y)?o():jt.eventCanceled?this._onDrop():(h(l,"mouseup",i._disableDelayedDrag),h(l,"touchend",i._disableDelayedDrag),h(l,"touchcancel",i._disableDelayedDrag),h(l,"mousemove",i._delayedDragTouchMoveHandler),h(l,"touchmove",i._delayedDragTouchMoveHandler),a.supportPointer&&h(l,"pointermove",i._delayedDragTouchMoveHandler),i._dragStartTimer=setTimeout(o,a.delay)))},_delayedDragTouchMoveHandler:function(t){t=t.touches?t.touches[0]:t;Math.max(Math.abs(t.clientX-this._lastX),Math.abs(t.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){Z&&Lt(Z),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;f(t,"mouseup",this._disableDelayedDrag),f(t,"touchend",this._disableDelayedDrag),f(t,"touchcancel",this._disableDelayedDrag),f(t,"mousemove",this._delayedDragTouchMoveHandler),f(t,"touchmove",this._delayedDragTouchMoveHandler),f(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||"touch"==t.pointerType&&t,!this.nativeDraggable||e?this.options.supportPointer?h(document,"pointermove",this._onTouchMove):h(document,e?"touchmove":"mousemove",this._onTouchMove):(h(Z,"dragend",this),h(J,"dragstart",this._onDragStart));try{document.selection?Wt(function(){document.selection.empty()}):window.getSelection().removeAllRanges()}catch(t){}},_dragStarted:function(t,e){var n;Et=!1,J&&Z?(U("dragStarted",this,{evt:e}),this.nativeDraggable&&h(document,"dragover",Ft),n=this.options,t||k(Z,n.dragClass,!1),k(Z,n.ghostClass,!0),jt.active=this,t&&this._appendGhost(),V({sortable:this,name:"start",originalEvent:e})):this._nulling()},_emulateDragOver:function(){if(dt){this._lastX=dt.clientX,this._lastY=dt.clientY,Xt();for(var t=document.elementFromPoint(dt.clientX,dt.clientY),e=t;t&&t.shadowRoot&&(t=t.shadowRoot.elementFromPoint(dt.clientX,dt.clientY))!==e;)e=t;if(Z.parentNode[K]._isOutsideThisEl(t),e)do{if(e[K])if(e[K]._onDragOver({clientX:dt.clientX,clientY:dt.clientY,target:t,rootEl:e})&&!this.options.dragoverBubble)break}while(e=g(t=e));Yt()}},_onTouchMove:function(t){if(ut){var e=this.options,n=e.fallbackTolerance,o=e.fallbackOffset,i=t.touches?t.touches[0]:t,r=Q&&b(Q,!0),a=Q&&r&&r.a,l=Q&&r&&r.d,e=At&&wt&&D(wt),a=(i.clientX-ut.clientX+o.x)/(a||1)+(e?e[0]-Tt[0]:0)/(a||1),l=(i.clientY-ut.clientY+o.y)/(l||1)+(e?e[1]-Tt[1]:0)/(l||1);if(!jt.active&&!Et){if(n&&Math.max(Math.abs(i.clientX-this._lastX),Math.abs(i.clientY-this._lastY))D.right+10||S.clientY>x.bottom&&S.clientX>x.left:S.clientY>D.bottom+10||S.clientX>x.right&&S.clientY>x.top)||m.animated)){if(m&&(t=n,e=r,C=X(B((_=this).el,0,_.options,!0)),_=L(_.el,_.options,Q),e?t.clientX<_.left-10||t.clientY Date: Tue, 26 Nov 2024 17:04:52 +0100 Subject: [PATCH 16/51] modifie le title en name dans les groupes --- js/mviewerstudio.js | 7 ++++--- lib/mv.js | 12 ++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index f62ae8ce..b8c65884 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -683,12 +683,12 @@ var saveGroups = () => { const groupId = group.id; const gr = $(`div[id="${groupId}"]`); - const groupTitle = gr.find(".group-name").val(); + const groupName = gr.find(".group-name").val(); if (config.themes[themeId].groups) { config.themes[themeId].groups.find((group) => group.id === groupId).id = groupId; - config.themes[themeId].groups.find((group) => group.id === groupId).title = - groupTitle; + config.themes[themeId].groups.find((group) => group.id === groupId).name = + groupName; } } } @@ -1268,6 +1268,7 @@ var saveAppWithPython = (exists, conf, url, close) => { var saveApplicationsConfig = (close, message = "") => { const conf = getConfig(); + if (!conf || !mv.validateXML(conf.join(""))) { return alertCustom(mviewer.tr("msg.xml_doc_invalid"), "danger"); } diff --git a/lib/mv.js b/lib/mv.js index db4c045b..dfc4da85 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -565,17 +565,17 @@ var mv = (function () { getConfGroups: function () { const themeid = mv.getCurrentThemeId(); const groupId = `group-${mv.uuid()}`; - const groupTitle = "Nouveau groupe"; + const groupName = "Nouveau groupe"; const group = { id: groupId, - title: groupTitle, + name: groupName, layers: [], }; if (!config.themes[themeid].groups) { config.themes[themeid].groups = []; } config.themes[themeid].groups.push(group); - addGroup(themeid, groupTitle, groupId); + addGroup(themeid, groupName, groupId); }, resetConfLayer: function () { @@ -1041,7 +1041,7 @@ var mv = (function () { }; var groupParameters = {}; //require parameters - var requireParameters = ["id", "title"]; + var requireParameters = ["id", "name"]; requireParameters.forEach(function (p, i) { var value = g[p]; groupParameters[p] = [p, '="', value, '"'].join(""); @@ -1656,9 +1656,9 @@ var mv = (function () { groups.each((id, g) => { var group = { id: $(g).attr("id"), - title: $(g).attr("title"), + name: $(g).attr("name"), }; - addGroup($(th).attr("id"), group.title, group.id); + addGroup($(th).attr("id"), group.name, group.id); //Si le thème n'a pas de groupes, on set theme.group à [] if (!config.themes[$(th).attr("id")].groups) config.themes[$(th).attr("id")].groups = []; From ef4395dfe5af1dafd1bc40c11efc98f1abfb8d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Wed, 27 Nov 2024 14:56:52 +0100 Subject: [PATCH 17/51] display groups panel depending on whether or not a group is present --- js/mviewerstudio.js | 13 +++++++++++-- lib/mv.js | 8 ++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index b8c65884..b9601bf7 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -407,7 +407,7 @@ var addGroup = (themeid, title, groupId) => {
- +
@@ -602,7 +602,7 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility)
- + @@ -626,6 +626,15 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility) }; }; +// Display groups div if at least one group in +const displayGroupsPanel = (themeId) => { + if ($(`#${themeId} .group_list`).children().length !== 0) { + $(`#${themeId} .group_list`).removeClass("hideBlock").addClass("showBlock"); + } else { + $(`#${themeId} .group_list`).removeClass("showBlock").addClass("hideBlock"); + } +}; + // Only one checkbox "collapsed" checked $("#themes-list").on("change", ".custom-control-input", function () { if ($(this).is(":checked")) { diff --git a/lib/mv.js b/lib/mv.js index dfc4da85..d0b401e0 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -1650,18 +1650,22 @@ var mv = (function () { $(th).attr("url"), $(th).attr("layersvisibility") ); - // Ajout des groupes et de leurs layers var groups = $(th).find("group"); + // If no groups in theme, hide groups panel + if (groups.length === 0) $(`#${th.id} .group_list`).addClass("hideBlock"); + groups.each((id, g) => { var group = { id: $(g).attr("id"), name: $(g).attr("name"), }; + addGroup($(th).attr("id"), group.name, group.id); //Si le thème n'a pas de groupes, on set theme.group à [] - if (!config.themes[$(th).attr("id")].groups) + if (!config.themes[$(th).attr("id")].groups) { config.themes[$(th).attr("id")].groups = []; + } config.themes[$(th).attr("id")].groups.push(group); var layers = $(g).find("layer"); From 28bb54df34d55610520f1c76119e642573a08873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Wed, 27 Nov 2024 15:04:54 +0100 Subject: [PATCH 18/51] Modify button title for add theme, groups and layers --- index.html | 2 +- js/mviewerstudio.js | 2 +- mviewerstudio.i18n.json | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index 9c8475f3..36fbc1fa 100755 --- a/index.html +++ b/index.html @@ -701,7 +701,7 @@

Thématiques & do

- + diff --git a/mviewerstudio.i18n.json b/mviewerstudio.i18n.json index 8c1d21ea..475b130f 100644 --- a/mviewerstudio.i18n.json +++ b/mviewerstudio.i18n.json @@ -164,8 +164,8 @@ "tabs.data.title": "Thématiques & données", "tabs.data.themespanel.title": "Panneau des thématiques", "tabs.data.themespanel.subtitle": "Créer, importer et gérer vos thématiques et données", - "tabs.data.themespanel.create": "Créer", - "tabs.data.themespanel.import": "Importer", + "tabs.data.themespanel.create": "Ajouter une thématique", + "tabs.data.themespanel.import": "Importer une thématique", "tabs.data.themespanel.options": "Réduire le panneau des thématiques au démarrage", "modal.theme.paramspanel.title": "Paramètres de la thématique sélectionnée", "modal.theme.paramspanel.name": "Nom", @@ -497,8 +497,8 @@ "tabs.data.help_title": "Selection, configuration and organization of the data", "tabs.data.help_text": "Create several themes (folders) then put some data in them, coming from several platforms. You can also add some external themes", "tabs.data.themespanel.title": "Themes panel", - "tabs.data.themespanel.create": "Create", - "tabs.data.themespanel.import": "Import", + "tabs.data.themespanel.create": "Add a theme", + "tabs.data.themespanel.import": "Import a theme", "tabs.data.themespanel.options": "Display option: shrink the themes panel on startup", "tabs.data.paramspanel.title": "Configure the selected Theme", "tabs.data.paramspanel.name": "Name", From 39ada3836f440306e800d1604b613bb241800814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Thu, 28 Nov 2024 14:19:39 +0100 Subject: [PATCH 19/51] issue 294 - clean delete layer in a group --- js/mviewerstudio.js | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index a851c019..28590408 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -351,7 +351,7 @@ var deleteThemeItem = function (btn) { var deleteLayerItem = function (btn, themeid) { var el = $(btn).closest(".layers-list-item")[0]; - deleteLayer(el.getAttribute("data-layerid"), themeid); + deleteLayer(el.getAttribute("data-layerid"), themeid, el.getAttribute("data-groupid")); el && el.parentNode.removeChild(el); }; @@ -735,11 +735,22 @@ var deleteTheme = function (themeid) { delete config.themes[themeid]; }; -var deleteLayer = function (layerid, themeid) { - var index = config.themes[themeid].layers.findIndex(function (l) { - return l.id === layerid; - }); - config.themes[themeid].layers.splice(index, 1); +var deleteLayer = function (layerid, themeid, groupid) { + if (groupid !== undefined) { + var index = config.themes[themeid].layers.findIndex(function (l) { + return l.id === layerid; + }); + config.themes[themeid].layers.splice(index, 1); + } else { + var index = config.themes[themeid].groups + .find((group) => group.id === groupid) + .layers.findIndex(function (l) { + return l.id === layerid; + }); + config.themes[themeid].groups + .find((group) => group.id === groupid) + .layers.splice(index, 1); + } }; var deleteGroup = function (groupid, themeid) { From 658a6936c115485d5ae74362d27636b7ad79e17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Thu, 28 Nov 2024 15:31:07 +0100 Subject: [PATCH 20/51] issue 294 - layer edition in a group && save studio at save editing layer --- index.html | 2 +- js/mviewerstudio.js | 6 +++--- lib/mv.js | 27 ++++++++++++++++++++++++--- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/index.html b/index.html index 36fbc1fa..adefc3ad 100755 --- a/index.html +++ b/index.html @@ -1647,7 +1647,7 @@

diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index 28590408..1d30013b 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -390,7 +390,7 @@ var addLayer = function (title, layerid, themeid, groupid) {
- +
`); return item; @@ -416,7 +416,7 @@ var addGroup = (themeid, title, groupId) => { return item; }; -var editLayer = function (item, themeid, layerid) { +var editLayer = function (item, themeid, layerid, groupid) { mv.setCurrentThemeId(themeid); mv.setCurrentLayerId(layerid); var element = $(item).parent().parent(); @@ -424,7 +424,7 @@ var editLayer = function (item, themeid, layerid) { element.addClass("active"); if (layerid != "undefined") { $("#mod-layerOptions").modal("show"); - mv.showLayerOptions(element, themeid, layerid); + mv.showLayerOptions(element, themeid, layerid, groupid); } else { $("#input-ogc-filter").val(""); $("#csw-results .csw-result").remove(); diff --git a/lib/mv.js b/lib/mv.js index d0b401e0..e011ef01 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -18,6 +18,7 @@ var mv = (function () { var _currentThemeId = ""; var _currentLayerId = ""; + var _currentGroupId = ""; var _userInfo = { userName: "", @@ -43,6 +44,14 @@ var mv = (function () { return _currentLayerId; }, + setCurrentGroupId: (groupId) => { + _currentGroupId = groupId; + }, + + getCurrentGroupId: () => { + return _currentGroupId; + }, + getLayerById: (layerid = null) => { if (!layerid) { var el = $(".layers-list-item.active"); @@ -607,7 +616,7 @@ var mv = (function () { } }, - showLayerOptions: function (el, themeid, layerid) { + showLayerOptions: function (el, themeid, layerid, groupid) { // Init params display [...document.querySelectorAll("#mod-layerOptions .layerOption-wms")].forEach((e) => e.classList.add("d-none") @@ -632,7 +641,12 @@ var mv = (function () { function getLayerbyId(l) { return l.id === layerid; } - var layer = config.themes[themeid].layers.find(getLayerbyId); + var layer = + groupid === "undefined" + ? config.themes[themeid].layers.find(getLayerbyId) + : config.themes[themeid].groups + .find((group) => group.id === groupid) + .layers.find(getLayerbyId); document.getElementById("layerTypeLabel").append(layer.type); @@ -808,10 +822,16 @@ var mv = (function () { saveLayerOptions: function (layerid = null) { var layerid = mv.getCurrentLayerId(); const themeid = mv.getCurrentThemeId(); + const groupid = mv.getCurrentGroupId(); function getLayerbyId(l) { return l.id === layerid; } - var layer = config.themes[themeid].layers.find(getLayerbyId); + var layer = + groupid === "undefined" + ? config.themes[themeid].layers.find(getLayerbyId) + : config.themes[themeid].groups + .find((group) => group.id === groupid) + .layers.find(getLayerbyId); // Commons params layer.type = $("#frm-type").val(); @@ -921,6 +941,7 @@ var mv = (function () { $(`div[data-layerid="${layerid}"] .layer-name`).text(layer.name); mv.writeFieldsOptions(layer); + mv.saveAllThemes(); }, form2xml: function () { From 7b52fa0bf67f4b1a48dc83df70547a3de118ea78 Mon Sep 17 00:00:00 2001 From: gaetanbrl Date: Fri, 29 Nov 2024 09:43:20 +0100 Subject: [PATCH 21/51] rebase and clean prettify --- js/mviewerstudio.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index 1d30013b..35959dea 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -420,8 +420,10 @@ var editLayer = function (item, themeid, layerid, groupid) { mv.setCurrentThemeId(themeid); mv.setCurrentLayerId(layerid); var element = $(item).parent().parent(); - var layerid = element.attr("data-layerid"); element.addClass("active"); + if (!layerid) { + layerid = element.attr("data-layerid"); + } if (layerid != "undefined") { $("#mod-layerOptions").modal("show"); mv.showLayerOptions(element, themeid, layerid, groupid); @@ -433,7 +435,6 @@ var editLayer = function (item, themeid, layerid, groupid) { }; var importThemes = function () { - console.groupCollapsed("importThemes"); $("#tableThemaExt .selected").each(function (id, item) { var url = $(item).attr("data-url"); var id = $(item).attr("data-theme-id"); From 39473ea566ed3f6430d15e0b7af762dfae99d197 Mon Sep 17 00:00:00 2001 From: gaetanbrl Date: Fri, 29 Nov 2024 09:46:17 +0100 Subject: [PATCH 22/51] Add vscode debug files --- srv/python/.vscode/launch.json | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 srv/python/.vscode/launch.json diff --git a/srv/python/.vscode/launch.json b/srv/python/.vscode/launch.json new file mode 100644 index 00000000..4efb0c14 --- /dev/null +++ b/srv/python/.vscode/launch.json @@ -0,0 +1,31 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python Debugger: Flask", + "type": "python", + "request": "launch", + "module": "flask", + "env": { + "FLASK_APP": "mviewerstudio_backend/app.py", + "FLASK_DEBUG": "1", + "CONF_PATH_FROM_MVIEWER":"apps/store", + "EXPORT_CONF_FOLDER":"/home/user/git/mviewer/apps/store/", + "MVIEWERSTUDIO_PUBLISH_PATH":"/home/user/git/mviewer/apps/public", + "CONF_PUBLISH_PATH_FROM_MVIEWER":"apps/public", + "DEFAULT_ORG":"geobretagne", + + }, + "args": [ + "run", + "--no-debugger", + "--no-reload" + ], + "jinja": true, + "autoStartBrowser": false + } + ] +} From 816ce2be74fbaeeb50413ac997cc4bcc710eaf05 Mon Sep 17 00:00:00 2001 From: gaetanbrl Date: Fri, 29 Nov 2024 10:23:02 +0100 Subject: [PATCH 23/51] standardize code --- lib/mv.js | 861 +++++++++++++++++++++++++----------------------------- 1 file changed, 403 insertions(+), 458 deletions(-) diff --git a/lib/mv.js b/lib/mv.js index e011ef01..05cbd283 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -6,6 +6,61 @@ var mv = (function () { infoFormat: "text/html", }; + const layerAsObject = (layerInfos) => { + const layerObject = { + id: $(layerInfos).attr("id"), + type: $(layerInfos).attr("type") || "wms", + tiled: $(layerInfos).attr("tiled") === "true", + scalemin: $(layerInfos).attr("scalemin"), + scalemax: $(layerInfos).attr("scalemax"), + title: $(layerInfos).attr("name"), + name: $(layerInfos).attr("name"), + url: $(layerInfos).attr("url"), + queryable: $(layerInfos).attr("queryable") === "true", + featurecount: $(layerInfos).attr("featurecount"), + infopanel: $(layerInfos).attr("infopanel") || "right-panel", + searchable: $(layerInfos).attr("searchable") === "true", + searchengine: $(layerInfos).attr("searchengine"), + fusesearchkeys: $(layerInfos).attr("fusesearchkeys"), + fusesearchresult: $(layerInfos).attr("fusesearchresult"), + secure: $(layerInfos).attr("secure") || "public", + useproxy: $(layerInfos).attr("useproxy") === "true", + infoformat: $(layerInfos).attr("infoformat"), + metadata: $(layerInfos).attr("metadata"), + "metadata-csw": $(layerInfos).attr("metadata-csw"), + attribution: $(layerInfos).attr("attribution"), + filter: $(layerInfos).attr("filter"), + visible: $(layerInfos).attr("visible") === "true", + opacity: $(layerInfos).attr("opacity"), + template: $(layerInfos).find("template").text(), + useexternaltemplate: + ($(layerInfos).find("template") && + $(layerInfos).find("template").text().length > 3) || + ($(layerInfos).find("template").attr("url") && + $(layerInfos).find("template").attr("url").length > 1), + templateurl: false, + fields: $(layerInfos).attr("fields"), + fieldsoptions: false, + aliases: $(layerInfos).attr("aliases"), + style: $(layerInfos).attr("style"), + styleurl: $(layerInfos).attr("styleurl"), + filterstyle: $(layerInfos).attr("filterstyle"), + stylesalias: $(layerInfos).attr("stylesalias"), + sld: $(layerInfos).attr("sld"), + legendurl: $(layerInfos).attr("legendurl"), + attributefilter: $(layerInfos).attr("attributefilter") === "true", + showintoc: $(layerInfos).attr("showintoc") === "true", + exclusive: $(layerInfos).attr("exclusive") === "true", + toplayer: $(layerInfos).attr("toplayer") === "true", + expanded: $(layerInfos).attr("expanded") === "true", + dynamiclegend: $(layerInfos).attr("dynamiclegend") === "true", + styletitle: $(layerInfos).attr("styletitle"), + index: $(layerInfos).attr("index"), + jsonfields: $(layerInfos).attr("jsonfields"), + }; + return layerObject; + }; + function uuid() { var dt = new Date().getTime(); var uuid = "xxxxxxxxxxxx".replace(/[xy]/g, function (c) { @@ -723,12 +778,12 @@ var mv = (function () { }) .then(({ wfs_url }) => ogc.getFeatures(wfs_url, { TYPENAME: layerid, MAXFEATURES: 1 }, (data) => { - if (config.temp.layers[layerid]) { - config.temp.layers[layerid].features = data?.features || []; - mv.createDispatchEvent("wfsFeaturesReady", { - features: config.temp.layers[layerid].features, - }); - } + if (config.temp.layers[layerid]) { + config.temp.layers[layerid].features = data?.features || []; + mv.createDispatchEvent("wfsFeaturesReady", { + features: config.temp.layers[layerid].features, + }); + } }) ) .then(() => ogc.getStylesFromWMS(layer.url, layerid)); @@ -1380,19 +1435,19 @@ var mv = (function () { }); return ` - - - ${data.title} - ${creator} - ${UUID} - ${keyworkds} - ${publisher} - ${description} - ${dataDate} - ${relation} - ${themes.length ? themes.join("\r\n") : ""} - - `; + + + ${data.title} + ${creator} + ${UUID} + ${keyworkds} + ${publisher} + ${description} + ${dataDate} + ${relation} + ${themes.length ? themes.join("\r\n") : ""} + + `; }, parseWMC(xml) { @@ -1676,6 +1731,31 @@ var mv = (function () { // If no groups in theme, hide groups panel if (groups.length === 0) $(`#${th.id} .group_list`).addClass("hideBlock"); + const addAndConfigLayer = (layer) => { + addLayer(layer.title, layer.id, $(th).attr("id"), group.id); + if (layer.attributefilter) { + layer.attributefield = $(l).attr("attributefield"); + layer.attributelabel = $(l).attr("attributelabel"); + layer.attributevalues = $(l).attr("attributevalues"); + } + if (layer.useexternaltemplate === true && $(l).find("template").attr("url")) { + layer.templateurl = $(l).find("template").attr("url"); + } + $("#frm-template").prop("checked", layer.useexternaltemplate); + if (layer.fields && layer.aliases) { + layer.fieldsoptions = {}; + $(layer.fields.split(",")).each(function (index, fld) { + var type = "text"; + var alias = layer.aliases.split(",")[index]; + layer.fieldsoptions[fld] = { + name: fld, + alias: alias, + type: type, + }; + }); + } + }; + groups.each((id, g) => { var group = { id: $(g).attr("id"), @@ -1693,77 +1773,8 @@ var mv = (function () { if (layers) layers.each(function (id, l) { counter += 1; - var layer = { - id: $(l).attr("id"), - type: $(l).attr("type") || "wms", - tiled: $(l).attr("tiled") === "true", - scalemin: $(l).attr("scalemin"), - scalemax: $(l).attr("scalemax"), - title: $(l).attr("name"), - name: $(l).attr("name"), - url: $(l).attr("url"), - queryable: $(l).attr("queryable") === "true", - featurecount: $(l).attr("featurecount"), - infopanel: $(l).attr("infopanel") || "right-panel", - searchable: $(l).attr("searchable") === "true", - searchengine: $(l).attr("searchengine"), - fusesearchkeys: $(l).attr("fusesearchkeys"), - fusesearchresult: $(l).attr("fusesearchresult"), - secure: $(l).attr("secure") || "public", - useproxy: $(l).attr("useproxy") === "true", - infoformat: $(l).attr("infoformat"), - metadata: $(l).attr("metadata"), - "metadata-csw": $(l).attr("metadata-csw"), - attribution: $(l).attr("attribution"), - filter: $(l).attr("filter"), - visible: $(l).attr("visible") === "true", - opacity: $(l).attr("opacity"), - template: $(l).find("template").text(), - useexternaltemplate: - ($(l).find("template") && $(l).find("template").text().length > 3) || - ($(l).find("template").attr("url") && - $(l).find("template").attr("url").length > 1), - templateurl: false, - fields: $(l).attr("fields"), - fieldsoptions: false, - aliases: $(l).attr("aliases"), - style: $(l).attr("style"), - styleurl: $(l).attr("styleurl"), - filterstyle: $(l).attr("filterstyle"), - stylesalias: $(l).attr("stylesalias"), - sld: $(l).attr("sld"), - legendurl: $(l).attr("legendurl"), - attributefilter: $(l).attr("attributefilter") === "true", - showintoc: $(l).attr("showintoc") === "true", - exclusive: $(l).attr("exclusive") === "true", - toplayer: $(l).attr("toplayer") === "true", - expanded: $(l).attr("expanded") === "true", - dynamiclegend: $(l).attr("dynamiclegend") === "true", - styletitle: $(l).attr("styletitle"), - index: $(l).attr("index"), - jsonfields: $(l).attr("jsonfields"), - }; - addLayer(layer.title, layer.id, $(th).attr("id"), group.id); - if (layer.attributefilter) { - layer.attributefield = $(l).attr("attributefield"); - layer.attributelabel = $(l).attr("attributelabel"); - layer.attributevalues = $(l).attr("attributevalues"); - } - if ( - layer.useexternaltemplate === true && - $(l).find("template").attr("url") - ) { - layer.templateurl = $(l).find("template").attr("url"); - } - $("#frm-template").prop("checked", layer.useexternaltemplate); - if (layer.fields && layer.aliases) { - layer.fieldsoptions = {}; - $(layer.fields.split(",")).each(function (index, fld) { - var type = "text"; - var alias = layer.aliases.split(",")[index]; - layer.fieldsoptions[fld] = { name: fld, alias: alias, type: type }; - }); - } + let layer = layerAsObject(l); + addAndConfigLayer(layer); //Si le groupe n'a pas de layers, on set group.layers à [] if ( !config.themes[$(th).attr("id")].groups.find((group) => group.id).layers @@ -1780,74 +1791,8 @@ var mv = (function () { var counter = 0; layers.each(function (id, l) { counter += 1; - var layer = { - id: $(l).attr("id"), - type: $(l).attr("type") || "wms", - tiled: $(l).attr("tiled") === "true", - scalemin: $(l).attr("scalemin"), - scalemax: $(l).attr("scalemax"), - title: $(l).attr("name"), - name: $(l).attr("name"), - url: $(l).attr("url"), - queryable: $(l).attr("queryable") === "true", - featurecount: $(l).attr("featurecount"), - infopanel: $(l).attr("infopanel") || "right-panel", - searchable: $(l).attr("searchable") === "true", - searchengine: $(l).attr("searchengine"), - fusesearchkeys: $(l).attr("fusesearchkeys"), - fusesearchresult: $(l).attr("fusesearchresult"), - secure: $(l).attr("secure") || "public", - useproxy: $(l).attr("useproxy") === "true", - infoformat: $(l).attr("infoformat"), - metadata: $(l).attr("metadata"), - "metadata-csw": $(l).attr("metadata-csw"), - attribution: $(l).attr("attribution"), - filter: $(l).attr("filter"), - visible: $(l).attr("visible") === "true", - opacity: $(l).attr("opacity"), - template: $(l).find("template").text(), - useexternaltemplate: - ($(l).find("template") && $(l).find("template").text().length > 3) || - ($(l).find("template").attr("url") && - $(l).find("template").attr("url").length > 1), - templateurl: false, - fields: $(l).attr("fields"), - fieldsoptions: false, - aliases: $(l).attr("aliases"), - style: $(l).attr("style"), - styleurl: $(l).attr("styleurl"), - filterstyle: $(l).attr("filterstyle"), - stylesalias: $(l).attr("stylesalias"), - sld: $(l).attr("sld"), - legendurl: $(l).attr("legendurl"), - attributefilter: $(l).attr("attributefilter") === "true", - showintoc: $(l).attr("showintoc") === "true", - exclusive: $(l).attr("exclusive") === "true", - toplayer: $(l).attr("toplayer") === "true", - expanded: $(l).attr("expanded") === "true", - dynamiclegend: $(l).attr("dynamiclegend") === "true", - styletitle: $(l).attr("styletitle"), - index: $(l).attr("index"), - jsonfields: $(l).attr("jsonfields"), - }; - addLayer(layer.title, layer.id, $(th).attr("id")); - if (layer.attributefilter) { - layer.attributefield = $(l).attr("attributefield"); - layer.attributelabel = $(l).attr("attributelabel"); - layer.attributevalues = $(l).attr("attributevalues"); - } - if (layer.useexternaltemplate === true && $(l).find("template").attr("url")) { - layer.templateurl = $(l).find("template").attr("url"); - } - $("#frm-template").prop("checked", layer.useexternaltemplate); - if (layer.fields && layer.aliases) { - layer.fieldsoptions = {}; - $(layer.fields.split(",")).each(function (index, fld) { - var type = "text"; - var alias = layer.aliases.split(",")[index]; - layer.fieldsoptions[fld] = { name: fld, alias: alias, type: type }; - }); - } + let layer = layerAsObject(l); + addAndConfigLayer(layer); config.themes[$(th).attr("id")].layers.push(layer); }); if ($(th).attr("url")) { @@ -1941,37 +1886,37 @@ var mv = (function () { { show: !_conf.is_php, html: ` - `, + `, }, { show: !_conf.is_php ? app.creator == _userInfo.userName : true, html: ` - `, + `, }, { show: !_conf.is_php && app.creator == _userInfo.userName, html: ` - `, + `, }, ]; @@ -1981,58 +1926,58 @@ var mv = (function () { ? "" : `${badgeLabel}`; const items = ` -
-
-
-
${ - app.title - } ${badge}
-
Thématiques : ${app.subjects}
-
Groupe : ${app.group}
-
Identifiant : ${app.id}
-
Mots clés : ${app.keywords}
-
Auteur : ${app.creator}
-
Date : ${app.date}
-
-
- -
-
-
`; +
+
+
+
${ + app.title + } ${badge}
+
Thématiques : ${app.subjects}
+
Groupe : ${app.group}
+
Identifiant : ${app.id}
+
Mots clés : ${app.keywords}
+
Auteur : ${app.creator}
+
Date : ${app.date}
+
+
+ +
+
+
`; applications.push(items); }); if (!applications.length && search) { document.querySelector("#liste_applications").innerHTML = ` -
-

- -

${mviewer.tr("noresult")}

-

-
`; +
+

+ +

${mviewer.tr("noresult")}

+

+
`; } if (!applications.length && !search) { document.querySelector("#liste_applications").innerHTML = `
-

- -

${mviewer.tr("load.app.any")}

-

-
`; +

+ +

${mviewer.tr("load.app.any")}

+

+ `; } $("#liste_applications").append(applications); // can't delete all with Python backend @@ -2128,24 +2073,24 @@ var mv = (function () { const userFullName = `${data.first_name} ${data.last_name}`; var items = ` - -

${userGroup.full_name}

-
-
${mviewer.tr("auth.group.type")} : ${ - userGroup.group_type - }
-
${"auth.group.role"} : ${mviewer.tr( - _userRole - )}
-
-
`; + +

${userGroup.full_name}

+
+
${mviewer.tr("auth.group.type")} : ${ + userGroup.group_type + }
+
${"auth.group.role"} : ${mviewer.tr( + _userRole + )}
+
+
`; userGroupsAsHtml.push(items.join(" ")); }); @@ -2183,15 +2128,15 @@ var mv = (function () { document.querySelector("#appsListTable").innerHTML = ""; $("#appsListTable").append( `
-
- - -
-
` +
+ + +
+ ` ); }, cleanVersionHistoryUI: () => { @@ -2200,34 +2145,34 @@ var mv = (function () { showAlertChangeVersion: (id, version) => { genericModalContent.innerHTML = ""; genericModalContent.innerHTML = ` - - + `; }, createVersion: (id) => { id = id || config?.id; @@ -2309,20 +2254,20 @@ var mv = (function () { actionVersionFormatter: (value, row, index) => { const flag = ``; return ` - ${mviewer.tr( - "release.preview" - )} - ${mviewer.tr( - "release.restore" - )} - ${row?.version ? flag : ""} - `; + ${mviewer.tr( + "release.preview" + )} + ${mviewer.tr( + "release.restore" + )} + ${row?.version ? flag : ""} + `; }, appsTableToolbar: () => { const toolbar = document.querySelector(".toolbar"); @@ -2344,29 +2289,29 @@ var mv = (function () { }, ]; return ` -
- ${btns - .map( - (b) => ` - - ` - ) - .join("")} -
- - -
-
- `; +
+ ${btns + .map( + (b) => ` + + ` + ) + .join("")} +
+ + +
+
+ `; }, showTagsOnly: (el) => { config.showTags = el.checked; @@ -2421,41 +2366,41 @@ var mv = (function () { }); mv.getApps = () => apps; const tableDom = ` - ${mv.appsTableToolbar()} - - - - - - - - - -
${mviewer.tr("release.active")}Description - ${mviewer.tr("release.date")} - - ${mviewer.tr("release.actions")} -
- `; + ${mv.appsTableToolbar()} + + + + + + + + + +
${mviewer.tr("release.active")}Description + ${mviewer.tr("release.date")} + + ${mviewer.tr("release.actions")} +
+ `; $("#appsListTable").append(tableDom); const $table = $("#tableVersions"); $table.bootstrapTable({ data: data }); @@ -2490,37 +2435,37 @@ var mv = (function () { })); mv.getApps = () => theme; const tableDom = ` - - - - - - - - - - - -
${mviewer.tr( - "table.title" - )}${mviewer.tr( - "table.description" - )}${mviewer.tr( - "table.publisher" - )}${mviewer.tr( - "table.identify" - )}${mviewer.tr( - "table.id" - )}
- `; + + + + + + + + + + + +
${mviewer.tr( + "table.title" + )}${mviewer.tr( + "table.description" + )}${mviewer.tr( + "table.publisher" + )}${mviewer.tr( + "table.identify" + )}${mviewer.tr( + "table.id" + )}
+ `; $("#themesListTable").append(tableDom); const $table = $("#tableThemaExt"); $table.bootstrapTable({ data: data }); @@ -2561,90 +2506,90 @@ var mv = (function () { : mviewer.tr("publish.name.wich"); genericModalContent.innerHTML = ""; genericModalContent.innerHTML = ` - - - `; + + + `; publishAppModal.show(); }, showPublishModal: (shareLink = "", iframeLink = "", draftLink = "") => { const publishModal = new bootstrap.Modal("#genericModal"); genericModalContent.innerHTML = ""; genericModalContent.innerHTML = ` - - - `; + + + `; publishModal.show(); }, publish: (id, name = "", message = "") => { From b9ae420a0308f81fb018be892432f7c93c0319f5 Mon Sep 17 00:00:00 2001 From: gaetanbrl Date: Fri, 29 Nov 2024 10:45:28 +0100 Subject: [PATCH 24/51] translate comments pretty --- js/mviewerstudio.js | 14 +++++++------- lib/mv.js | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index 35959dea..0d6c9e14 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -507,7 +507,7 @@ function initializeNestedSortables() { item.setAttribute("data-groupid", toGroupId); item.setAttribute("data-themeid", toThemeId); - // Si item est un layer + // if item is a layer if (item.classList.contains("layers-list-item")) { config.themes[toThemeId].layers.forEach((layer) => { if (layer.id === item.getAttribute("data-layerid")) { @@ -515,7 +515,7 @@ function initializeNestedSortables() { layer["data-themeid"] = toThemeId; } }); - // Cherche l'index de départ en fonction de si le layer bougé vient d'un groupe ou un thème + // search start index - depends if moved layer come from group or theme const index = fromGroupId ? config.themes[fromThemeId].groups .find((group) => group.id === fromGroupId) @@ -524,12 +524,12 @@ function initializeNestedSortables() { (layer) => layer.id === item.id ); - // Si l'index éxiste, suppr l'item de la position de départ et l'ajoute à l'arrivée + // delete start index item and insert last, only if exists if (index !== -1) { // Si le thème n'a pas de layer, on set theme.layers à [] if (!config.themes[fromThemeId].layers) config.themes[fromThemeId].layers = []; - // Si le groupe d'arrivé n'a pas de layers, on set group.layers à [] + // if target group is empty (no layers), we set empty group.layers list if (toGroupId) if ( !config.themes[toThemeId].groups.find((group) => group.id === toGroupId) @@ -551,7 +551,7 @@ function initializeNestedSortables() { : config.themes[toThemeId].layers.splice(newIndex, 0, itemToMove); } } else { - // sinon item est un groupe + // Else item is a group config.themes[toThemeId].groups.forEach((group) => { if (group.id === item.getAttribute("data-groupid")) { group["data-themeid"] = toThemeId; @@ -567,13 +567,13 @@ function initializeNestedSortables() { } }, }); - // Marquer cet élément comme "initialisé" pour éviter les doublons + // tag element as "initiliazed" to avoid duplicate sortableElement.setAttribute("data-sortable-initialized", true); } }); } -// Initialisation au chargement du DOM +// init on DOM loading initializeNestedSortables(); var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility) { diff --git a/lib/mv.js b/lib/mv.js index 05cbd283..56e406a8 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -778,12 +778,12 @@ var mv = (function () { }) .then(({ wfs_url }) => ogc.getFeatures(wfs_url, { TYPENAME: layerid, MAXFEATURES: 1 }, (data) => { - if (config.temp.layers[layerid]) { - config.temp.layers[layerid].features = data?.features || []; - mv.createDispatchEvent("wfsFeaturesReady", { - features: config.temp.layers[layerid].features, - }); - } + if (config.temp.layers[layerid]) { + config.temp.layers[layerid].features = data?.features || []; + mv.createDispatchEvent("wfsFeaturesReady", { + features: config.temp.layers[layerid].features, + }); + } }) ) .then(() => ogc.getStylesFromWMS(layer.url, layerid)); From 11178e3c8be703f8d8cff03a321df249ab80b091 Mon Sep 17 00:00:00 2001 From: gaetanbrl Date: Fri, 29 Nov 2024 10:49:33 +0100 Subject: [PATCH 25/51] translate comments --- lib/mv.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mv.js b/lib/mv.js index 56e406a8..82212358 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -1685,7 +1685,7 @@ var mv = (function () { var baseLayersMode = $(xml).find("baselayers").attr("style") || "default"; $("#frm-bl-mode option[value='" + baseLayersMode + "']").prop("selected", true); var baselayers = $(xml).find("baselayer"); - //Reinitialisation + //reset $(".bl input").prop("checked", false); $("#frm-bl-visible option").attr("disabled", "disabled"); baselayers.each(function (i, bl) { @@ -1726,7 +1726,7 @@ var mv = (function () { $(th).attr("url"), $(th).attr("layersvisibility") ); - // Ajout des groupes et de leurs layers + // Add group and contains layers var groups = $(th).find("group"); // If no groups in theme, hide groups panel if (groups.length === 0) $(`#${th.id} .group_list`).addClass("hideBlock"); From 1b6cfb8f010eded626a9b7bf6900cfc5e044e2ff Mon Sep 17 00:00:00 2001 From: gaetanbrl Date: Fri, 29 Nov 2024 11:26:02 +0100 Subject: [PATCH 26/51] reset active state on edit close --- lib/mv.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/mv.js b/lib/mv.js index 82212358..ceba88e1 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -6,6 +6,13 @@ var mv = (function () { infoFormat: "text/html", }; + // remove active state + const resetActive = () => { + document.querySelectorAll(".layers-list-item.active").forEach((el) => { + el.classList.remove("active"); + }); + }; + const layerAsObject = (layerInfos) => { const layerObject = { id: $(layerInfos).attr("id"), @@ -84,6 +91,7 @@ var mv = (function () { return { setCurrentThemeId: (themeId) => { + resetActive(); _currentThemeId = themeId; }, @@ -92,6 +100,7 @@ var mv = (function () { }, setCurrentLayerId: (layerId) => { + resetActive(); _currentLayerId = layerId; }, @@ -2800,5 +2809,7 @@ var mv = (function () { saveThemes(); saveStudio(); }, + + resetActive: resetActive, }; })(); From 2481835d757ff707c104141d8048a72d4ac60611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Fri, 29 Nov 2024 11:52:59 +0100 Subject: [PATCH 27/51] modify dnd to fix layers drop in groups panel --- js/mviewerstudio.js | 156 ++++++++++++++++++++++++++------------------ 1 file changed, 92 insertions(+), 64 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index 1d0766e0..add6e345 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -410,7 +410,7 @@ var addGroup = (themeid, title, groupId) => { -
+
`); initializeNestedSortables(); return item; @@ -451,6 +451,7 @@ sortThemes = function () { config.themes = orderedThemes; }; +//D'n'D themes var sortableThemeList = Sortable.create(document.getElementById("themes-list"), { handle: ".moveList", animation: 150, @@ -474,10 +475,13 @@ var sortableElement = function (targetId, callback) { }; sortableElement("themes-list", sortThemes); +//D'n'D groups && layers function initializeNestedSortables() { - const nestedSortables = document.querySelectorAll(".nested-sortable"); + const nestedSortablesGroups = document.querySelectorAll(".nested-sortable-groups"); + const nestedSortablesLayers = document.querySelectorAll(".nested-sortable-layers"); - nestedSortables.forEach((sortableElement) => { + // For groups + nestedSortablesGroups.forEach((sortableElement) => { if (!sortableElement.getAttribute("data-sortable-initialized")) { new Sortable(sortableElement, { handle: ".moveList", @@ -486,9 +490,52 @@ function initializeNestedSortables() { fallbackOnBody: true, swapThreshold: 0.65, group: { - name: "nested", + name: "groups", pull: true, - put: true, + put: ["groups"], + }, + onEnd: function (evt) { + const item = evt.item; + const fromThemeId = evt.from.closest(".themes-list-item")?.id; + const toThemeId = evt.to.closest(".themes-list-item")?.id; + const toGroupId = evt.to.closest(".group-item")?.id + ? evt.to.closest(".group-item").id + : null; + + item.setAttribute("data-groupid", toGroupId); + item.setAttribute("data-themeid", toThemeId); + + config.themes[toThemeId].groups.forEach((group) => { + if (group.id === item.getAttribute("data-groupid")) { + group["data-themeid"] = toThemeId; + } + }); + const index = config.themes[fromThemeId].groups.findIndex( + (group) => group.id === item.id + ); + if (index !== -1) { + const [itemToMove] = config.themes[fromThemeId].groups.splice(index, 1); + config.themes[toThemeId].groups.push(itemToMove); + } + }, + }); + sortableElement.setAttribute("data-sortable-initialized", true); + } + }); + + // For layers + nestedSortablesLayers.forEach((sortableElement) => { + if (!sortableElement.getAttribute("data-sortable-initialized")) { + new Sortable(sortableElement, { + handle: ".moveList", + animation: 150, + ghostClass: "ghost", + fallbackOnBody: true, + swapThreshold: 0.65, + group: { + name: "layers", + pull: true, + put: ["layers"], }, onEnd: function (evt) { const item = evt.item; @@ -505,63 +552,44 @@ function initializeNestedSortables() { item.setAttribute("data-groupid", toGroupId); item.setAttribute("data-themeid", toThemeId); - // Si item est un layer - if (item.classList.contains("layers-list-item")) { - config.themes[toThemeId].layers.forEach((layer) => { - if (layer.id === item.getAttribute("data-layerid")) { - layer["data-groupid"] = toGroupId; - layer["data-themeid"] = toThemeId; - } - }); - // Cherche l'index de départ en fonction de si le layer bougé vient d'un groupe ou un thème - const index = fromGroupId + config.themes[toThemeId].layers.forEach((layer) => { + if (layer.id === item.getAttribute("data-layerid")) { + layer["data-groupid"] = toGroupId; + layer["data-themeid"] = toThemeId; + } + }); + // Cherche l'index de départ en fonction de si le layer bougé vient d'un groupe ou un thème + const index = fromGroupId + ? config.themes[fromThemeId].groups + .find((group) => group.id === fromGroupId) + .layers.findIndex((layer) => layer.id === item.id) + : config.themes[fromThemeId].layers.findIndex( + (layer) => layer.id === item.id + ); + // Si l'index éxiste, suppr l'item de la position de départ et l'ajoute à l'arrivée + if (index !== -1) { + // Si le thème n'a pas de layer, on set theme.layers à [] + if (!config.themes[fromThemeId].layers) + config.themes[fromThemeId].layers = []; + // Si le groupe d'arrivé n'a pas de layers, on set group.layers à [] + if (toGroupId) + if ( + !config.themes[toThemeId].groups.find((group) => group.id === toGroupId) + .layers + ) + config.themes[toThemeId].groups.find( + (group) => group.id === toGroupId + ).layers = []; + const [itemToMove] = fromGroupId ? config.themes[fromThemeId].groups .find((group) => group.id === fromGroupId) - .layers.findIndex((layer) => layer.id === item.id) - : config.themes[fromThemeId].layers.findIndex( - (layer) => layer.id === item.id - ); - - // Si l'index éxiste, suppr l'item de la position de départ et l'ajoute à l'arrivée - if (index !== -1) { - // Si le thème n'a pas de layer, on set theme.layers à [] - if (!config.themes[fromThemeId].layers) - config.themes[fromThemeId].layers = []; - // Si le groupe d'arrivé n'a pas de layers, on set group.layers à [] - if (toGroupId) - if ( - !config.themes[toThemeId].groups.find((group) => group.id === toGroupId) - .layers - ) - config.themes[toThemeId].groups.find( - (group) => group.id === toGroupId - ).layers = []; - - const [itemToMove] = fromGroupId - ? config.themes[fromThemeId].groups - .find((group) => group.id === fromGroupId) - .layers.splice(index, 1) - : config.themes[fromThemeId].layers.splice(index, 1); - toGroupId - ? config.themes[toThemeId].groups - .find((group) => group.id === toGroupId) - .layers.splice(newIndex, 0, itemToMove) - : config.themes[toThemeId].layers.splice(newIndex, 0, itemToMove); - } - } else { - // sinon item est un groupe - config.themes[toThemeId].groups.forEach((group) => { - if (group.id === item.getAttribute("data-groupid")) { - group["data-themeid"] = toThemeId; - } - }); - const index = config.themes[fromThemeId].groups.findIndex( - (group) => group.id === item.id - ); - if (index !== -1) { - const [itemToMove] = config.themes[fromThemeId].groups.splice(index, 1); - config.themes[toThemeId].groups.push(itemToMove); - } + .layers.splice(index, 1) + : config.themes[fromThemeId].layers.splice(index, 1); + toGroupId + ? config.themes[toThemeId].groups + .find((group) => group.id === toGroupId) + .layers.splice(newIndex, 0, itemToMove) + : config.themes[toThemeId].layers.splice(newIndex, 0, itemToMove); } }, }); @@ -578,7 +606,7 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility) if (url) { //external theme $("#themes-list").append(` -
+
${title}Ext.
@@ -590,7 +618,7 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility)
`); } else { $("#themes-list").append( - `
+ `
@@ -607,8 +635,8 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility)
-
Groupes
-
Couches
+
Groupes
+
Couches
` ); From 44c667196f685e09387e3589071aa5dba190a129 Mon Sep 17 00:00:00 2001 From: gaetanbrl Date: Fri, 29 Nov 2024 12:32:08 +0100 Subject: [PATCH 28/51] fix addAndConfigLayer method --- lib/mv.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/mv.js b/lib/mv.js index ceba88e1..23a5db53 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -1740,7 +1740,7 @@ var mv = (function () { // If no groups in theme, hide groups panel if (groups.length === 0) $(`#${th.id} .group_list`).addClass("hideBlock"); - const addAndConfigLayer = (layer) => { + const addAndConfigLayer = (layer, group) => { addLayer(layer.title, layer.id, $(th).attr("id"), group.id); if (layer.attributefilter) { layer.attributefield = $(l).attr("attributefield"); @@ -1783,7 +1783,7 @@ var mv = (function () { layers.each(function (id, l) { counter += 1; let layer = layerAsObject(l); - addAndConfigLayer(layer); + addAndConfigLayer(layer, group); //Si le groupe n'a pas de layers, on set group.layers à [] if ( !config.themes[$(th).attr("id")].groups.find((group) => group.id).layers @@ -1801,7 +1801,7 @@ var mv = (function () { layers.each(function (id, l) { counter += 1; let layer = layerAsObject(l); - addAndConfigLayer(layer); + addAndConfigLayer(layer, group); config.themes[$(th).attr("id")].layers.push(layer); }); if ($(th).attr("url")) { From 03fc729f0b23a0bafa7ce27ba6539a7b9d4434c1 Mon Sep 17 00:00:00 2001 From: gaetanbrl Date: Fri, 29 Nov 2024 12:43:58 +0100 Subject: [PATCH 29/51] case if no group for addlayer --- lib/mv.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mv.js b/lib/mv.js index 23a5db53..74e2d8b7 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -1741,7 +1741,7 @@ var mv = (function () { if (groups.length === 0) $(`#${th.id} .group_list`).addClass("hideBlock"); const addAndConfigLayer = (layer, group) => { - addLayer(layer.title, layer.id, $(th).attr("id"), group.id); + addLayer(layer.title, layer.id, $(th).attr("id"), group?.id); if (layer.attributefilter) { layer.attributefield = $(l).attr("attributefield"); layer.attributelabel = $(l).attr("attributelabel"); @@ -1801,7 +1801,7 @@ var mv = (function () { layers.each(function (id, l) { counter += 1; let layer = layerAsObject(l); - addAndConfigLayer(layer, group); + addAndConfigLayer(layer); config.themes[$(th).attr("id")].layers.push(layer); }); if ($(th).attr("url")) { From 14dbfef6e9193fc1fa828423917198d12fac7ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Fri, 29 Nov 2024 15:49:56 +0100 Subject: [PATCH 30/51] hide groups panel at theme creation --- js/mviewerstudio.js | 4 ++-- lib/mv.js | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index eb3da805..55e4e749 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -637,8 +637,8 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility)
-
Groupes
-
Couches
+
Groupes
+
Données
` ); diff --git a/lib/mv.js b/lib/mv.js index 74e2d8b7..e4a0ca27 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -81,6 +81,7 @@ var mv = (function () { var _currentThemeId = ""; var _currentLayerId = ""; var _currentGroupId = ""; + var _newTheme = false; var _userInfo = { userName: "", @@ -90,6 +91,14 @@ var mv = (function () { }; return { + setNewTheme: (newTheme) => { + _newTheme = newTheme; + }, + + getNewTheme: () => { + return _newTheme; + }, + setCurrentThemeId: (themeId) => { resetActive(); _currentThemeId = themeId; From a9a6fea31dae9b7efdd622852b01195cbe9cc238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Mon, 2 Dec 2024 12:39:41 +0100 Subject: [PATCH 31/51] issue-294 clean groups parsing --- lib/mv.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/mv.js b/lib/mv.js index e4a0ca27..3c68bae4 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -1795,12 +1795,15 @@ var mv = (function () { addAndConfigLayer(layer, group); //Si le groupe n'a pas de layers, on set group.layers à [] if ( - !config.themes[$(th).attr("id")].groups.find((group) => group.id).layers + !config.themes[$(th).attr("id")].groups.find((g) => g.id === group.id) + .layers ) - config.themes[$(th).attr("id")].groups.find((group) => group.id).layers = - []; + config.themes[$(th).attr("id")].groups.find( + (g) => g.id === group.id + ).layers = []; + config.themes[$(th).attr("id")].groups - .find((group) => group.id) + .find((g) => g.id === group.id) .layers.push(layer); }); }); From a12de65b86daa38790cc24efb179a1e190b1e26d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Tue, 3 Dec 2024 11:34:07 +0100 Subject: [PATCH 32/51] prevents editing title for imported theme --- js/mviewerstudio.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index 55e4e749..ff36575a 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -610,7 +610,7 @@ var addTheme = function (title, collapsed, themeid, icon, url, layersvisibility) $("#themes-list").append(`
- ${title}Ext. + ${title}Ext.
From 35f69b9a9bb751621abe67b746e206d587c99886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Tue, 3 Dec 2024 12:04:23 +0100 Subject: [PATCH 33/51] fix layers error if don't exist when drag n drop --- js/mviewerstudio.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index ff36575a..7e1e00cd 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -554,12 +554,6 @@ function initializeNestedSortables() { item.setAttribute("data-groupid", toGroupId); item.setAttribute("data-themeid", toThemeId); - config.themes[toThemeId].layers.forEach((layer) => { - if (layer.id === item.getAttribute("data-layerid")) { - layer["data-groupid"] = toGroupId; - layer["data-themeid"] = toThemeId; - } - }); // Cherche l'index de départ en fonction de si le layer bougé vient d'un groupe ou un thème const index = fromGroupId ? config.themes[fromThemeId].groups @@ -593,6 +587,13 @@ function initializeNestedSortables() { .layers.splice(newIndex, 0, itemToMove) : config.themes[toThemeId].layers.splice(newIndex, 0, itemToMove); } + + config.themes[toThemeId].layers.forEach((layer) => { + if (layer.id === item.getAttribute("data-layerid")) { + layer["data-groupid"] = toGroupId; + layer["data-themeid"] = toThemeId; + } + }); }, }); // Marquer cet élément comme "initialisé" pour éviter les doublons From 5903374b9dbf5a596212e9bba16dfda1c1250360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Tue, 3 Dec 2024 14:43:11 +0100 Subject: [PATCH 34/51] add index.html to hide groups panel --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index adefc3ad..320a39bd 100755 --- a/index.html +++ b/index.html @@ -699,7 +699,7 @@

Thématiques & do
From acb1bd85679634fc4f1790e0bd568a93c04ac4f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Wed, 4 Dec 2024 18:07:20 +0100 Subject: [PATCH 35/51] fix groupid issue --- js/mviewerstudio.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index 7e1e00cd..e0b3a0bc 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -416,14 +416,18 @@ var addGroup = (themeid, title, groupId) => { return item; }; -var editLayer = function (item, themeid, layerid, groupid) { +var editLayer = function (item, themeid, layerid) { mv.setCurrentThemeId(themeid); mv.setCurrentLayerId(layerid); + var element = $(item).parent().parent(); element.addClass("active"); if (!layerid) { layerid = element.attr("data-layerid"); } + var groupid = element.attr("data-groupid"); + mv.setCurrentGroupId(groupid); + if (layerid != "undefined") { $("#mod-layerOptions").modal("show"); mv.showLayerOptions(element, themeid, layerid, groupid); From e090b19ddae2d5c5ba68d775c12234f4b7b5217e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Fri, 6 Dec 2024 11:03:43 +0100 Subject: [PATCH 36/51] fix several issues about drag n drop and saving after d'n'd --- index.html | 4 ++-- js/mviewerstudio.js | 12 +++++------- lib/mv.js | 11 ++++++++--- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/index.html b/index.html index 320a39bd..0ae6f9f2 100755 --- a/index.html +++ b/index.html @@ -1087,7 +1087,7 @@
diff --git a/js/mviewerstudio.js b/js/mviewerstudio.js index e0b3a0bc..1ad20610 100644 --- a/js/mviewerstudio.js +++ b/js/mviewerstudio.js @@ -390,7 +390,7 @@ var addLayer = function (title, layerid, themeid, groupid) {
- +

`); return item; @@ -425,8 +425,7 @@ var editLayer = function (item, themeid, layerid) { if (!layerid) { layerid = element.attr("data-layerid"); } - var groupid = element.attr("data-groupid"); - mv.setCurrentGroupId(groupid); + var groupid = mv.getCurrentGroupId(); if (layerid != "undefined") { $("#mod-layerOptions").modal("show"); @@ -552,9 +551,8 @@ function initializeNestedSortables() { const toThemeId = evt.to.closest(".themes-list-item")?.id; const toGroupId = evt.to.closest(".group-item")?.id ? evt.to.closest(".group-item").id - : null; + : "undefined"; const newIndex = evt.newIndex; - item.setAttribute("data-groupid", toGroupId); item.setAttribute("data-themeid", toThemeId); @@ -572,7 +570,7 @@ function initializeNestedSortables() { if (!config.themes[fromThemeId].layers) config.themes[fromThemeId].layers = []; // Si le groupe d'arrivé n'a pas de layers, on set group.layers à [] - if (toGroupId) + if (toGroupId !== "undefined") if ( !config.themes[toThemeId].groups.find((group) => group.id === toGroupId) .layers @@ -585,7 +583,7 @@ function initializeNestedSortables() { .find((group) => group.id === fromGroupId) .layers.splice(index, 1) : config.themes[fromThemeId].layers.splice(index, 1); - toGroupId + toGroupId !== "undefined" ? config.themes[toThemeId].groups .find((group) => group.id === toGroupId) .layers.splice(newIndex, 0, itemToMove) diff --git a/lib/mv.js b/lib/mv.js index 3c68bae4..f6ba6ff4 100755 --- a/lib/mv.js +++ b/lib/mv.js @@ -80,7 +80,7 @@ var mv = (function () { var _currentThemeId = ""; var _currentLayerId = ""; - var _currentGroupId = ""; + var _currentGroupId = "undefined"; var _newTheme = false; var _userInfo = { @@ -117,7 +117,9 @@ var mv = (function () { return _currentLayerId; }, - setCurrentGroupId: (groupId) => { + setCurrentGroupId: (btn) => { + const parent = $(btn).closest(".layer_item"); + const groupId = parent ? $(parent).attr("data-groupid") : "undefined"; _currentGroupId = groupId; }, @@ -689,7 +691,7 @@ var mv = (function () { } }, - showLayerOptions: function (el, themeid, layerid, groupid) { + showLayerOptions: function (el, themeid, layerid) { // Init params display [...document.querySelectorAll("#mod-layerOptions .layerOption-wms")].forEach((e) => e.classList.add("d-none") @@ -714,6 +716,7 @@ var mv = (function () { function getLayerbyId(l) { return l.id === layerid; } + const groupid = el.attr("data-groupid") || "undefined"; var layer = groupid === "undefined" ? config.themes[themeid].layers.find(getLayerbyId) @@ -896,6 +899,8 @@ var mv = (function () { var layerid = mv.getCurrentLayerId(); const themeid = mv.getCurrentThemeId(); const groupid = mv.getCurrentGroupId(); + console.log({ groupid }); + function getLayerbyId(l) { return l.id === layerid; } From 36c591575ab8306b665a2d223fafedbd9b556721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poincelet?= Date: Fri, 6 Dec 2024 16:55:11 +0100 Subject: [PATCH 37/51] fix newTheme default behaviour && error from generic modal --- index.html | 6 +++--- lib/mv.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index 0ae6f9f2..293c049b 100755 --- a/index.html +++ b/index.html @@ -219,7 +219,7 @@

Besoin d'aide ?

Dépublier Supprimer Prévisualiser - Enregistrer + Enregistrer
@@ -971,7 +971,7 @@
-