doc-survival-kit 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of doc-survival-kit might be problematic. Click here for more details.
- package/diagram.html +46 -0
- package/diagram.js +550 -116
- package/diagrammes.js +863 -216
- package/images/img_1774709818351.png +0 -0
- package/images/img_1774711114086.png +0 -0
- package/images/img_1774711575731.png +0 -0
- package/images/img_1774712426980.png +0 -0
- package/package.json +1 -1
- package/style.css +79 -18
package/diagram.js
CHANGED
|
@@ -5,7 +5,11 @@
|
|
|
5
5
|
// ── État global ──
|
|
6
6
|
var currentTool = "select";
|
|
7
7
|
var diagramsList = [];
|
|
8
|
-
var
|
|
8
|
+
var currentDiagramId = null;
|
|
9
|
+
var diagNavStack = [];
|
|
10
|
+
var diagExpandedIds = {};
|
|
11
|
+
var pendingParentId = null;
|
|
12
|
+
var pendingNavDiagId = null;
|
|
9
13
|
var viewTransform = { x: 60, y: 60, scale: 1 };
|
|
10
14
|
var selectedId = null;
|
|
11
15
|
var selectedType = null; // "shape" | "arrow"
|
|
@@ -26,7 +30,7 @@ var lastClickShapeId = null;
|
|
|
26
30
|
var lastClickArrowId = null;
|
|
27
31
|
var editingArrowId = null;
|
|
28
32
|
var boardLocked = false;
|
|
29
|
-
var
|
|
33
|
+
var diagDragSrcId = null;
|
|
30
34
|
var historyStack = [];
|
|
31
35
|
var MAX_HISTORY = 50;
|
|
32
36
|
|
|
@@ -56,6 +60,7 @@ var COLORS = {
|
|
|
56
60
|
"t-sky": { fill: "rgba(224,242,254,0.75)", stroke: "#0284c7", text: "#0369a1" },
|
|
57
61
|
"t-rose": { fill: "rgba(255,228,230,0.75)", stroke: "#e11d48", text: "#be123c" },
|
|
58
62
|
"t-teal": { fill: "rgba(204,251,241,0.75)", stroke: "#0d9488", text: "#0f766e" },
|
|
63
|
+
"t-white": { fill: "rgba(255,255,255,0.95)", stroke: "#d4d4d4", text: "#404040" },
|
|
59
64
|
};
|
|
60
65
|
var DEFAULT_COLOR = "t-sky";
|
|
61
66
|
|
|
@@ -131,17 +136,103 @@ function wrapPostitLines(text, maxWidth, fontSize) {
|
|
|
131
136
|
return result;
|
|
132
137
|
}
|
|
133
138
|
|
|
139
|
+
function findDiagramById(id, list) {
|
|
140
|
+
if (!list) return null;
|
|
141
|
+
for (var i = 0; i < list.length; i++) {
|
|
142
|
+
if (String(list[i].id) === String(id)) return list[i];
|
|
143
|
+
var found = findDiagramById(id, list[i].children);
|
|
144
|
+
if (found) return found;
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function findParentListOf(id, list) {
|
|
150
|
+
if (!list) return null;
|
|
151
|
+
for (var i = 0; i < list.length; i++) {
|
|
152
|
+
if (String(list[i].id) === String(id)) return { list: list, index: i };
|
|
153
|
+
var found = findParentListOf(id, list[i].children);
|
|
154
|
+
if (found) return found;
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function flattenDiagrams(list, result) {
|
|
160
|
+
result = result || [];
|
|
161
|
+
(list || []).forEach(function (d) {
|
|
162
|
+
result.push(d);
|
|
163
|
+
flattenDiagrams(d.children, result);
|
|
164
|
+
});
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function calcMaxExpandedDepth(list, depth) {
|
|
169
|
+
var max = depth;
|
|
170
|
+
(list || []).forEach(function (d) {
|
|
171
|
+
if (d.children && d.children.length > 0 && diagExpandedIds[String(d.id)]) {
|
|
172
|
+
var childMax = calcMaxExpandedDepth(d.children, depth + 1);
|
|
173
|
+
max = Math.max(max, childMax);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
return max;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function updateSidebarWidth() {
|
|
180
|
+
var depth = calcMaxExpandedDepth(diagramsList, 0);
|
|
181
|
+
var totalW = 220 + depth * 14;
|
|
182
|
+
var panel = document.getElementById("diagramListPanel");
|
|
183
|
+
if (!panel) return;
|
|
184
|
+
panel.style.width = totalW + "px";
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function getAncestorPath(targetId, list, path) {
|
|
188
|
+
path = path || [];
|
|
189
|
+
for (var i = 0; i < (list || []).length; i++) {
|
|
190
|
+
var d = list[i];
|
|
191
|
+
if (String(d.id) === String(targetId)) return path;
|
|
192
|
+
var childPath = getAncestorPath(targetId, d.children, path.concat([String(d.id)]));
|
|
193
|
+
if (childPath !== null) return childPath;
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function updateBackBtn() {
|
|
199
|
+
var btn = document.getElementById("btnDiagBack");
|
|
200
|
+
if (!btn) return;
|
|
201
|
+
btn.style.display = diagNavStack.length > 0 ? "inline-flex" : "none";
|
|
202
|
+
}
|
|
203
|
+
|
|
134
204
|
function getCurrentDiagram() {
|
|
135
|
-
|
|
205
|
+
if (currentDiagramId !== null) {
|
|
206
|
+
var found = findDiagramById(currentDiagramId, diagramsList);
|
|
207
|
+
if (found) return found;
|
|
208
|
+
}
|
|
209
|
+
return diagramsList[0] || null;
|
|
136
210
|
}
|
|
137
211
|
|
|
138
212
|
// ── Persistance localStorage ──
|
|
139
213
|
function loadDiagrammes() {
|
|
140
214
|
try {
|
|
141
215
|
var stored = JSON.parse(localStorage.getItem("mes_diagrammes"));
|
|
142
|
-
if (stored && stored.length)
|
|
216
|
+
if (stored && stored.length) {
|
|
217
|
+
var migrate = function (list) {
|
|
218
|
+
list.forEach(function (d) {
|
|
219
|
+
if (!d.children) d.children = [];
|
|
220
|
+
migrate(d.children);
|
|
221
|
+
});
|
|
222
|
+
};
|
|
223
|
+
migrate(stored);
|
|
224
|
+
return stored;
|
|
225
|
+
}
|
|
143
226
|
} catch (e) {}
|
|
144
|
-
|
|
227
|
+
var defaults = JSON.parse(JSON.stringify(diagrammesDefaut));
|
|
228
|
+
var migrate2 = function (list) {
|
|
229
|
+
list.forEach(function (d) {
|
|
230
|
+
if (!d.children) d.children = [];
|
|
231
|
+
migrate2(d.children);
|
|
232
|
+
});
|
|
233
|
+
};
|
|
234
|
+
migrate2(defaults);
|
|
235
|
+
return defaults;
|
|
145
236
|
}
|
|
146
237
|
|
|
147
238
|
function saveDiagrammes() {
|
|
@@ -157,7 +248,9 @@ function pushHistory() {
|
|
|
157
248
|
function undoAction() {
|
|
158
249
|
if (historyStack.length === 0) return;
|
|
159
250
|
diagramsList = JSON.parse(historyStack.pop());
|
|
160
|
-
if (
|
|
251
|
+
if (!findDiagramById(currentDiagramId, diagramsList)) {
|
|
252
|
+
currentDiagramId = diagramsList[0] ? String(diagramsList[0].id) : null;
|
|
253
|
+
}
|
|
161
254
|
saveDiagrammes();
|
|
162
255
|
renderAll();
|
|
163
256
|
renderDiagramList();
|
|
@@ -177,14 +270,14 @@ function getLockMap() {
|
|
|
177
270
|
try { return JSON.parse(localStorage.getItem("diagrammes_lock") || "{}"); } catch(e) { return {}; }
|
|
178
271
|
}
|
|
179
272
|
function saveCurrentLock() {
|
|
180
|
-
var diag =
|
|
273
|
+
var diag = getCurrentDiagram();
|
|
181
274
|
if (!diag) return;
|
|
182
275
|
var map = getLockMap();
|
|
183
276
|
map[diag.id] = boardLocked;
|
|
184
277
|
localStorage.setItem("diagrammes_lock", JSON.stringify(map));
|
|
185
278
|
}
|
|
186
|
-
function restoreLockForDiagram(
|
|
187
|
-
var diag = diagramsList
|
|
279
|
+
function restoreLockForDiagram(diagId) {
|
|
280
|
+
var diag = findDiagramById(diagId, diagramsList);
|
|
188
281
|
if (!diag) return;
|
|
189
282
|
var map = getLockMap();
|
|
190
283
|
boardLocked = map[diag.id] === true;
|
|
@@ -213,14 +306,14 @@ function getZoomMap() {
|
|
|
213
306
|
try { return JSON.parse(localStorage.getItem("diagrammes_zoom") || "{}"); } catch(e) { return {}; }
|
|
214
307
|
}
|
|
215
308
|
function saveCurrentZoom() {
|
|
216
|
-
var diag =
|
|
309
|
+
var diag = getCurrentDiagram();
|
|
217
310
|
if (!diag) return;
|
|
218
311
|
var map = getZoomMap();
|
|
219
312
|
map[diag.id] = viewTransform.scale;
|
|
220
313
|
localStorage.setItem("diagrammes_zoom", JSON.stringify(map));
|
|
221
314
|
}
|
|
222
|
-
function restoreZoomForDiagram(
|
|
223
|
-
var diag = diagramsList
|
|
315
|
+
function restoreZoomForDiagram(diagId) {
|
|
316
|
+
var diag = findDiagramById(diagId, diagramsList);
|
|
224
317
|
if (!diag) return;
|
|
225
318
|
var map = getZoomMap();
|
|
226
319
|
viewTransform.scale = map[diag.id] !== undefined ? map[diag.id] : 1;
|
|
@@ -864,6 +957,36 @@ function renderShape(shape) {
|
|
|
864
957
|
// ── Texte non rendu pour les images ──
|
|
865
958
|
if (shape.type === "image") return g;
|
|
866
959
|
|
|
960
|
+
// ── Indicateur de lien (diagramme enfant ou lien externe) ──
|
|
961
|
+
if ((shape.linkedDiagramId || shape.externalUrl) && shape.type !== "image") {
|
|
962
|
+
var lnkColor = shape.externalUrl ? "#0284c7" : "#f97316";
|
|
963
|
+
var lnkCirc = createSVGEl("circle");
|
|
964
|
+
lnkCirc.setAttribute("cx", shape.x + shape.w - 5);
|
|
965
|
+
lnkCirc.setAttribute("cy", shape.y + 5);
|
|
966
|
+
lnkCirc.setAttribute("r", 6);
|
|
967
|
+
lnkCirc.setAttribute("fill", lnkColor);
|
|
968
|
+
lnkCirc.setAttribute("stroke", "#fff");
|
|
969
|
+
lnkCirc.setAttribute("stroke-width", 1.5);
|
|
970
|
+
lnkCirc.setAttribute("pointer-events", "none");
|
|
971
|
+
g.appendChild(lnkCirc);
|
|
972
|
+
var lnkTxt = createSVGEl("text");
|
|
973
|
+
lnkTxt.setAttribute("x", shape.x + shape.w - 5);
|
|
974
|
+
lnkTxt.setAttribute("y", shape.y + 8.5);
|
|
975
|
+
lnkTxt.setAttribute("text-anchor", "middle");
|
|
976
|
+
lnkTxt.setAttribute("font-size", "8");
|
|
977
|
+
lnkTxt.setAttribute("font-weight", "bold");
|
|
978
|
+
lnkTxt.setAttribute("fill", "#fff");
|
|
979
|
+
lnkTxt.setAttribute("pointer-events", "none");
|
|
980
|
+
lnkTxt.textContent = "\u2197";
|
|
981
|
+
g.appendChild(lnkTxt);
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
// ── Rotation ──
|
|
985
|
+
if (shape.rotation) {
|
|
986
|
+
var rcx = shape.x + shape.w / 2, rcy = shape.y + shape.h / 2;
|
|
987
|
+
g.setAttribute("transform", "rotate(" + shape.rotation + "," + rcx + "," + rcy + ")");
|
|
988
|
+
}
|
|
989
|
+
|
|
867
990
|
// ── Points de connexion (visibles au hover et en mode flèche — sauf postit) ──
|
|
868
991
|
if (shape.type !== "postit") {
|
|
869
992
|
var hcx = shape.x + shape.w / 2, hcy = shape.y + shape.h / 2;
|
|
@@ -891,16 +1014,35 @@ function renderShape(shape) {
|
|
|
891
1014
|
function getEdgePoint(shape, targetX, targetY) {
|
|
892
1015
|
var cx = shape.x + shape.w / 2;
|
|
893
1016
|
var cy = shape.y + shape.h / 2;
|
|
894
|
-
var
|
|
895
|
-
if (
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
var
|
|
899
|
-
|
|
1017
|
+
var lTargetX = targetX, lTargetY = targetY;
|
|
1018
|
+
if (shape.rotation) {
|
|
1019
|
+
var rad = -shape.rotation * Math.PI / 180;
|
|
1020
|
+
var cos = Math.cos(rad), sin = Math.sin(rad);
|
|
1021
|
+
var ddx = targetX - cx, ddy = targetY - cy;
|
|
1022
|
+
lTargetX = cx + ddx * cos - ddy * sin;
|
|
1023
|
+
lTargetY = cy + ddx * sin + ddy * cos;
|
|
1024
|
+
}
|
|
1025
|
+
var dx = lTargetX - cx, dy = lTargetY - cy;
|
|
1026
|
+
var p;
|
|
1027
|
+
if (dx === 0 && dy === 0) {
|
|
1028
|
+
p = { x: cx, y: shape.y };
|
|
900
1029
|
} else {
|
|
901
|
-
var
|
|
902
|
-
|
|
1030
|
+
var hw = shape.w / 2, hh = shape.h / 2;
|
|
1031
|
+
if (Math.abs(dx) * hh > Math.abs(dy) * hw) {
|
|
1032
|
+
var sx = dx > 0 ? 1 : -1;
|
|
1033
|
+
p = { x: cx + sx * hw, y: cy + dy * hw / Math.abs(dx) };
|
|
1034
|
+
} else {
|
|
1035
|
+
var sy = dy > 0 ? 1 : -1;
|
|
1036
|
+
p = { x: cx + dx * hh / Math.abs(dy), y: cy + sy * hh };
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
if (shape.rotation) {
|
|
1040
|
+
var rad2 = shape.rotation * Math.PI / 180;
|
|
1041
|
+
var cos2 = Math.cos(rad2), sin2 = Math.sin(rad2);
|
|
1042
|
+
var ex = p.x - cx, ey = p.y - cy;
|
|
1043
|
+
p = { x: cx + ex * cos2 - ey * sin2, y: cy + ex * sin2 + ey * cos2 };
|
|
903
1044
|
}
|
|
1045
|
+
return p;
|
|
904
1046
|
}
|
|
905
1047
|
|
|
906
1048
|
function renderArrow(arrow, shapes) {
|
|
@@ -989,104 +1131,93 @@ function renderAll() {
|
|
|
989
1131
|
updateTableOverlay();
|
|
990
1132
|
}
|
|
991
1133
|
|
|
992
|
-
function
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
var
|
|
1134
|
+
function renderDiagramListLevel(list, depth) {
|
|
1135
|
+
return (list || []).map(function (d) {
|
|
1136
|
+
var isActive = String(d.id) === String(currentDiagramId);
|
|
1137
|
+
var isExpanded = !!diagExpandedIds[String(d.id)];
|
|
1138
|
+
var hasChildren = d.children && d.children.length > 0;
|
|
1139
|
+
var indent = 10 + depth * 14;
|
|
1140
|
+
var childrenHtml = (isExpanded && hasChildren)
|
|
1141
|
+
? '<div class="diagram-list-children">' + renderDiagramListLevel(d.children, depth + 1) + '</div>'
|
|
1142
|
+
: '';
|
|
996
1143
|
return (
|
|
997
|
-
'<div class="diagram-list-
|
|
998
|
-
'
|
|
999
|
-
'
|
|
1000
|
-
'
|
|
1001
|
-
'
|
|
1002
|
-
'
|
|
1003
|
-
'
|
|
1004
|
-
'<span class="diagram-list-grip">⠿</span>' +
|
|
1144
|
+
'<div class="diagram-list-group">' +
|
|
1145
|
+
'<div class="diagram-list-item' + (isActive ? ' active' : '') + '"' +
|
|
1146
|
+
' style="padding-left:' + indent + 'px"' +
|
|
1147
|
+
' onclick="selectDiagramme(\'' + d.id + '\', true)">' +
|
|
1148
|
+
'<span class="diagram-list-expand" onclick="event.stopPropagation();toggleDiagExpand(\'' + d.id + '\')">' +
|
|
1149
|
+
(hasChildren ? (isExpanded ? '▼' : '►') : '<span style="display:inline-block;width:0.7em"></span>') +
|
|
1150
|
+
'</span>' +
|
|
1005
1151
|
'<span class="diagram-list-name">' + escDiag(d.titre) + '</span>' +
|
|
1006
|
-
(
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1152
|
+
'<button class="diagram-list-add" onclick="event.stopPropagation();creerEnfantDiagramme(\'' + d.id + '\')" title="Ajouter un diagramme enfant">+</button>' +
|
|
1153
|
+
(depth > 0 || list.length > 1
|
|
1154
|
+
? '<button class="diagram-list-del" onclick="event.stopPropagation();supprimerDiagramme(\'' + d.id + '\')">×</button>'
|
|
1155
|
+
: '') +
|
|
1156
|
+
'</div>' +
|
|
1157
|
+
childrenHtml +
|
|
1158
|
+
'</div>'
|
|
1010
1159
|
);
|
|
1011
|
-
}).join(
|
|
1012
|
-
}
|
|
1013
|
-
|
|
1014
|
-
function onDiagDragStart(e, idx) {
|
|
1015
|
-
diagDragSrcIdx = idx;
|
|
1016
|
-
e.dataTransfer.effectAllowed = "move";
|
|
1017
|
-
e.currentTarget.classList.add("dragging");
|
|
1160
|
+
}).join('');
|
|
1018
1161
|
}
|
|
1019
1162
|
|
|
1020
|
-
function
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
});
|
|
1026
|
-
if (idx !== diagDragSrcIdx) {
|
|
1027
|
-
var goingDown = diagDragSrcIdx < idx;
|
|
1028
|
-
e.currentTarget.classList.add(goingDown ? "drag-over-after" : "drag-over-before");
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
function onDiagDragLeave(e) {
|
|
1033
|
-
e.currentTarget.classList.remove("drag-over-after", "drag-over-before");
|
|
1163
|
+
function renderDiagramList() {
|
|
1164
|
+
var el = document.getElementById("diagramList");
|
|
1165
|
+
if (!el) return;
|
|
1166
|
+
el.innerHTML = renderDiagramListLevel(diagramsList, 0);
|
|
1167
|
+
updateSidebarWidth();
|
|
1034
1168
|
}
|
|
1035
1169
|
|
|
1036
|
-
function
|
|
1037
|
-
|
|
1038
|
-
if (
|
|
1039
|
-
|
|
1040
|
-
return;
|
|
1041
|
-
}
|
|
1042
|
-
var src = diagDragSrcIdx;
|
|
1043
|
-
var item = diagramsList.splice(src, 1)[0];
|
|
1044
|
-
|
|
1045
|
-
// insertAt = idx dans les deux cas :
|
|
1046
|
-
// - descente (src < idx) : après remove, la cible est à idx-1, on insère à idx = après elle ✓
|
|
1047
|
-
// - montée (src > idx) : après remove, la cible est toujours à idx, on insère à idx = avant elle ✓
|
|
1048
|
-
diagramsList.splice(idx, 0, item);
|
|
1049
|
-
|
|
1050
|
-
var cur = currentDiagramIdx;
|
|
1051
|
-
if (cur === src) {
|
|
1052
|
-
currentDiagramIdx = idx;
|
|
1170
|
+
function toggleDiagExpand(id) {
|
|
1171
|
+
var key = String(id);
|
|
1172
|
+
if (diagExpandedIds[key]) {
|
|
1173
|
+
delete diagExpandedIds[key];
|
|
1053
1174
|
} else {
|
|
1054
|
-
|
|
1055
|
-
currentDiagramIdx = adjustedCur >= idx ? adjustedCur + 1 : adjustedCur;
|
|
1175
|
+
diagExpandedIds[key] = true;
|
|
1056
1176
|
}
|
|
1057
|
-
localStorage.setItem("current_diagram_idx", currentDiagramIdx);
|
|
1058
|
-
diagDragSrcIdx = null;
|
|
1059
|
-
saveDiagrammes();
|
|
1060
1177
|
renderDiagramList();
|
|
1061
1178
|
}
|
|
1062
1179
|
|
|
1063
|
-
function onDiagDragEnd() {
|
|
1064
|
-
diagDragSrcIdx = null;
|
|
1065
|
-
document.querySelectorAll(".diagram-list-item").forEach(function (el) {
|
|
1066
|
-
el.classList.remove("dragging", "drag-over-after", "drag-over-before");
|
|
1067
|
-
});
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
1180
|
// ── Gestion des diagrammes ──
|
|
1071
|
-
function selectDiagramme(
|
|
1181
|
+
function selectDiagramme(id, clearStack) {
|
|
1182
|
+
if (clearStack) diagNavStack = [];
|
|
1072
1183
|
saveCurrentZoom();
|
|
1073
1184
|
saveCurrentLock();
|
|
1074
|
-
|
|
1075
|
-
localStorage.setItem("
|
|
1076
|
-
selectedId = null;
|
|
1185
|
+
currentDiagramId = String(id);
|
|
1186
|
+
localStorage.setItem("current_diagram_id", String(id));
|
|
1187
|
+
selectedId = null; selectedType = null;
|
|
1077
1188
|
selectedIds = [];
|
|
1078
|
-
|
|
1079
|
-
|
|
1189
|
+
pendingNavDiagId = null;
|
|
1190
|
+
restoreZoomForDiagram(id);
|
|
1191
|
+
restoreLockForDiagram(id);
|
|
1080
1192
|
viewTransform.x = 60;
|
|
1081
1193
|
viewTransform.y = 60;
|
|
1082
1194
|
document.getElementById("colorPanel").style.display = "none";
|
|
1083
1195
|
renderAll();
|
|
1084
1196
|
updateLockBtn();
|
|
1197
|
+
updateBackBtn();
|
|
1085
1198
|
document.getElementById("diagramListPanel").classList.remove("open");
|
|
1086
1199
|
}
|
|
1087
1200
|
|
|
1201
|
+
function goBackDiagram() {
|
|
1202
|
+
if (diagNavStack.length === 0) return;
|
|
1203
|
+
var prevId = diagNavStack.pop();
|
|
1204
|
+
selectDiagramme(prevId);
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1088
1207
|
function creerDiagramme() {
|
|
1208
|
+
pendingParentId = null;
|
|
1209
|
+
pendingNewDiagram = true;
|
|
1210
|
+
var input = document.getElementById("diagramTitle");
|
|
1211
|
+
input.value = "";
|
|
1212
|
+
input.placeholder = window.t ? window.t.diag_new_diagram : "Nouveau diagramme";
|
|
1213
|
+
input.focus();
|
|
1214
|
+
input.select();
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
function creerEnfantDiagramme(parentId) {
|
|
1218
|
+
pendingParentId = String(parentId);
|
|
1089
1219
|
pendingNewDiagram = true;
|
|
1220
|
+
diagExpandedIds[String(parentId)] = true;
|
|
1090
1221
|
var input = document.getElementById("diagramTitle");
|
|
1091
1222
|
input.value = "";
|
|
1092
1223
|
input.placeholder = window.t ? window.t.diag_new_diagram : "Nouveau diagramme";
|
|
@@ -1100,10 +1231,21 @@ function confirmerNouveauDiagramme() {
|
|
|
1100
1231
|
var input = document.getElementById("diagramTitle");
|
|
1101
1232
|
var titre = input.value.trim() || (window.t ? window.t.diag_new_diagram : "Nouveau diagramme");
|
|
1102
1233
|
input.placeholder = "";
|
|
1103
|
-
var d = { id: Date.now(), titre: titre, shapes: [], arrows: [] };
|
|
1104
|
-
|
|
1234
|
+
var d = { id: Date.now(), titre: titre, shapes: [], arrows: [], children: [] };
|
|
1235
|
+
if (pendingParentId) {
|
|
1236
|
+
var parent = findDiagramById(pendingParentId, diagramsList);
|
|
1237
|
+
if (parent) {
|
|
1238
|
+
if (!parent.children) parent.children = [];
|
|
1239
|
+
parent.children.push(d);
|
|
1240
|
+
} else {
|
|
1241
|
+
diagramsList.push(d);
|
|
1242
|
+
}
|
|
1243
|
+
pendingParentId = null;
|
|
1244
|
+
} else {
|
|
1245
|
+
diagramsList.push(d);
|
|
1246
|
+
}
|
|
1105
1247
|
saveDiagrammes();
|
|
1106
|
-
selectDiagramme(
|
|
1248
|
+
selectDiagramme(d.id);
|
|
1107
1249
|
document.getElementById("diagramTitle").blur();
|
|
1108
1250
|
}
|
|
1109
1251
|
|
|
@@ -1117,18 +1259,31 @@ function annulerNouveauDiagramme() {
|
|
|
1117
1259
|
input.blur();
|
|
1118
1260
|
}
|
|
1119
1261
|
|
|
1120
|
-
function supprimerDiagramme(
|
|
1121
|
-
|
|
1262
|
+
function supprimerDiagramme(id) {
|
|
1263
|
+
var info = findParentListOf(id, diagramsList);
|
|
1264
|
+
if (!info) return;
|
|
1265
|
+
if (info.list === diagramsList && info.list.length <= 1) return;
|
|
1122
1266
|
pushHistory();
|
|
1123
|
-
|
|
1124
|
-
if (
|
|
1125
|
-
|
|
1267
|
+
info.list.splice(info.index, 1);
|
|
1268
|
+
if (!findDiagramById(currentDiagramId, diagramsList)) {
|
|
1269
|
+
currentDiagramId = diagramsList[0] ? String(diagramsList[0].id) : null;
|
|
1270
|
+
localStorage.setItem("current_diagram_id", currentDiagramId || "");
|
|
1271
|
+
}
|
|
1126
1272
|
saveDiagrammes();
|
|
1127
1273
|
renderAll();
|
|
1128
1274
|
}
|
|
1129
1275
|
|
|
1130
1276
|
function toggleDiagramList() {
|
|
1131
|
-
document.getElementById("diagramListPanel")
|
|
1277
|
+
var panel = document.getElementById("diagramListPanel");
|
|
1278
|
+
var isOpening = !panel.classList.contains("open");
|
|
1279
|
+
panel.classList.toggle("open");
|
|
1280
|
+
if (isOpening && currentDiagramId) {
|
|
1281
|
+
var path = getAncestorPath(currentDiagramId, diagramsList);
|
|
1282
|
+
if (path) {
|
|
1283
|
+
path.forEach(function (id) { diagExpandedIds[id] = true; });
|
|
1284
|
+
renderDiagramList();
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1132
1287
|
}
|
|
1133
1288
|
|
|
1134
1289
|
// ── Outil actif ──
|
|
@@ -1297,6 +1452,7 @@ function applyPickMode(srcShape) {
|
|
|
1297
1452
|
shape.h = srcShape.h;
|
|
1298
1453
|
shape.textAlign = srcShape.textAlign || "center";
|
|
1299
1454
|
shape.textValign = srcShape.textValign || "middle";
|
|
1455
|
+
shape.rotation = srcShape.rotation || 0;
|
|
1300
1456
|
}
|
|
1301
1457
|
});
|
|
1302
1458
|
selectedIds = pickTargetIds.slice();
|
|
@@ -1305,6 +1461,42 @@ function applyPickMode(srcShape) {
|
|
|
1305
1461
|
document.getElementById("colorPanel").style.display = "flex";
|
|
1306
1462
|
}
|
|
1307
1463
|
|
|
1464
|
+
function rotateShape(delta) {
|
|
1465
|
+
var diag = getCurrentDiagram();
|
|
1466
|
+
if (!diag || selectedIds.length === 0) return;
|
|
1467
|
+
pushHistory();
|
|
1468
|
+
selectedIds.forEach(function (id) {
|
|
1469
|
+
var s = diag.shapes.find(function (sh) { return sh.id === id; });
|
|
1470
|
+
if (!s || s.type === "image") return;
|
|
1471
|
+
s.rotation = ((s.rotation || 0) + delta + 360) % 360;
|
|
1472
|
+
});
|
|
1473
|
+
saveDiagrammes();
|
|
1474
|
+
renderAll();
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
function changeShapeOrder(delta) {
|
|
1478
|
+
var diag = getCurrentDiagram();
|
|
1479
|
+
if (!diag || selectedIds.length === 0) return;
|
|
1480
|
+
pushHistory();
|
|
1481
|
+
if (delta > 0) {
|
|
1482
|
+
// Avancer : parcourir de la fin vers le début
|
|
1483
|
+
for (var i = diag.shapes.length - 1; i >= 0; i--) {
|
|
1484
|
+
if (selectedIds.indexOf(diag.shapes[i].id) !== -1 && i < diag.shapes.length - 1) {
|
|
1485
|
+
var tmp = diag.shapes[i]; diag.shapes[i] = diag.shapes[i + 1]; diag.shapes[i + 1] = tmp;
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
} else {
|
|
1489
|
+
// Reculer : parcourir du début vers la fin
|
|
1490
|
+
for (var i = 0; i < diag.shapes.length; i++) {
|
|
1491
|
+
if (selectedIds.indexOf(diag.shapes[i].id) !== -1 && i > 0) {
|
|
1492
|
+
var tmp = diag.shapes[i]; diag.shapes[i] = diag.shapes[i - 1]; diag.shapes[i - 1] = tmp;
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
saveDiagrammes();
|
|
1497
|
+
renderAll();
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1308
1500
|
// ── Édition texte inline ──
|
|
1309
1501
|
function startTextEdit(shapeId) {
|
|
1310
1502
|
var diag = getCurrentDiagram();
|
|
@@ -1560,7 +1752,143 @@ function updateTableOverlay() {
|
|
|
1560
1752
|
ar.style.display = rr.style.display = "flex";
|
|
1561
1753
|
}
|
|
1562
1754
|
|
|
1563
|
-
function syncColorPanel() {
|
|
1755
|
+
function syncColorPanel() {
|
|
1756
|
+
var btn = document.getElementById("btnShapeLink");
|
|
1757
|
+
if (!btn) return;
|
|
1758
|
+
if (selectedIds.length === 1 && selectedType === "shape") {
|
|
1759
|
+
var diag = getCurrentDiagram();
|
|
1760
|
+
var shape = diag ? diag.shapes.find(function (s) { return s.id === selectedIds[0]; }) : null;
|
|
1761
|
+
if (shape && shape.linkedDiagramId) {
|
|
1762
|
+
btn.classList.add("active");
|
|
1763
|
+
var linked = findDiagramById(shape.linkedDiagramId, diagramsList);
|
|
1764
|
+
btn.title = linked ? "Lié à : " + linked.titre + " (cliquer pour délier)" : "Supprimer le lien";
|
|
1765
|
+
} else if (shape && shape.externalUrl) {
|
|
1766
|
+
btn.classList.add("active");
|
|
1767
|
+
btn.title = "Lien externe : " + shape.externalUrl + " (cliquer pour délier)";
|
|
1768
|
+
} else {
|
|
1769
|
+
btn.classList.remove("active");
|
|
1770
|
+
btn.title = "Lier à un diagramme enfant ou URL externe";
|
|
1771
|
+
}
|
|
1772
|
+
btn.style.display = "";
|
|
1773
|
+
} else {
|
|
1774
|
+
btn.classList.remove("active");
|
|
1775
|
+
btn.style.display = "none";
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
function toggleShapeLink() {
|
|
1780
|
+
if (selectedIds.length !== 1 || selectedType !== "shape") return;
|
|
1781
|
+
var diag = getCurrentDiagram();
|
|
1782
|
+
var shape = diag ? diag.shapes.find(function (s) { return s.id === selectedIds[0]; }) : null;
|
|
1783
|
+
if (!shape) return;
|
|
1784
|
+
if (shape.linkedDiagramId || shape.externalUrl) {
|
|
1785
|
+
pushHistory();
|
|
1786
|
+
delete shape.linkedDiagramId;
|
|
1787
|
+
delete shape.externalUrl;
|
|
1788
|
+
saveDiagrammes();
|
|
1789
|
+
renderAll();
|
|
1790
|
+
syncColorPanel();
|
|
1791
|
+
hideLinkPicker();
|
|
1792
|
+
} else {
|
|
1793
|
+
showLinkPicker();
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
function showLinkPicker() {
|
|
1798
|
+
var panel = document.getElementById("linkPickerPanel");
|
|
1799
|
+
if (!panel) return;
|
|
1800
|
+
var btn = document.getElementById("btnShapeLink");
|
|
1801
|
+
var r = btn ? btn.getBoundingClientRect() : { bottom: 100, left: 200 };
|
|
1802
|
+
panel.style.top = (r.bottom + 6) + "px";
|
|
1803
|
+
panel.style.left = r.left + "px";
|
|
1804
|
+
var all = flattenDiagrams(diagramsList);
|
|
1805
|
+
var curId = String(currentDiagramId);
|
|
1806
|
+
var items = all.filter(function (d) { return String(d.id) !== curId; });
|
|
1807
|
+
var html = items.map(function (d) {
|
|
1808
|
+
return '<div class="link-picker-item" onclick="lierForme(\'' + d.id + '\')">' + escDiag(d.titre) + '</div>';
|
|
1809
|
+
}).join("");
|
|
1810
|
+
html += '<div class="link-picker-new" onclick="creerEnfantEtLier()">+ Nouveau diagramme enfant</div>';
|
|
1811
|
+
html += '<div class="link-picker-new link-picker-ext-toggle" onclick="showExternalLinkInput()" style="display:flex;align-items:center;gap:6px;">'
|
|
1812
|
+
+ '<svg width="14" height="14" viewBox="0 0 14 14"><circle cx="7" cy="7" r="6" fill="#0284c7" stroke="#fff" stroke-width="1.5"/><text x="7" y="10.5" text-anchor="middle" font-size="8" font-weight="bold" fill="#fff">\u2197</text></svg>'
|
|
1813
|
+
+ 'Lien externe (URL)</div>';
|
|
1814
|
+
html += '<div id="linkPickerExtRow" style="display:none;padding:6px 8px;border-top:1px solid #e7e5e4;">'
|
|
1815
|
+
+ '<input id="linkPickerExtUrl" type="text" placeholder="https://..." '
|
|
1816
|
+
+ 'style="width:100%;box-sizing:border-box;padding:4px 6px;border:1px solid #d4d4d4;border-radius:4px;font-size:12px;" '
|
|
1817
|
+
+ 'onkeydown="if(event.key===\'Enter\')lierFormeExterne()">'
|
|
1818
|
+
+ '<div id="linkPickerExtErr" style="color:#e11d48;font-size:11px;margin-top:3px;display:none;">URL invalide (http://, https:// ou file://)</div>'
|
|
1819
|
+
+ '</div>';
|
|
1820
|
+
document.getElementById("linkPickerList").innerHTML = html;
|
|
1821
|
+
panel.style.display = "block";
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
function showExternalLinkInput() {
|
|
1825
|
+
var row = document.getElementById("linkPickerExtRow");
|
|
1826
|
+
if (!row) return;
|
|
1827
|
+
row.style.display = "block";
|
|
1828
|
+
var input = document.getElementById("linkPickerExtUrl");
|
|
1829
|
+
if (input) setTimeout(function () { input.focus(); }, 10);
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
function lierFormeExterne() {
|
|
1833
|
+
var input = document.getElementById("linkPickerExtUrl");
|
|
1834
|
+
if (!input) return;
|
|
1835
|
+
var url = input.value.trim();
|
|
1836
|
+
var err = document.getElementById("linkPickerExtErr");
|
|
1837
|
+
if (!/^(https?|file):\/\//i.test(url)) {
|
|
1838
|
+
if (err) err.style.display = "block";
|
|
1839
|
+
return;
|
|
1840
|
+
}
|
|
1841
|
+
if (err) err.style.display = "none";
|
|
1842
|
+
if (selectedIds.length !== 1) return;
|
|
1843
|
+
var diag = getCurrentDiagram();
|
|
1844
|
+
var shape = diag ? diag.shapes.find(function (s) { return s.id === selectedIds[0]; }) : null;
|
|
1845
|
+
if (!shape) return;
|
|
1846
|
+
pushHistory();
|
|
1847
|
+
shape.externalUrl = url;
|
|
1848
|
+
delete shape.linkedDiagramId;
|
|
1849
|
+
hideLinkPicker();
|
|
1850
|
+
saveDiagrammes();
|
|
1851
|
+
renderAll();
|
|
1852
|
+
syncColorPanel();
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
function hideLinkPicker() {
|
|
1856
|
+
var panel = document.getElementById("linkPickerPanel");
|
|
1857
|
+
if (panel) panel.style.display = "none";
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
function lierForme(diagId) {
|
|
1861
|
+
if (selectedIds.length !== 1) return;
|
|
1862
|
+
var diag = getCurrentDiagram();
|
|
1863
|
+
var shape = diag ? diag.shapes.find(function (s) { return s.id === selectedIds[0]; }) : null;
|
|
1864
|
+
if (!shape) return;
|
|
1865
|
+
pushHistory();
|
|
1866
|
+
shape.linkedDiagramId = String(diagId);
|
|
1867
|
+
delete shape.externalUrl;
|
|
1868
|
+
hideLinkPicker();
|
|
1869
|
+
saveDiagrammes();
|
|
1870
|
+
renderAll();
|
|
1871
|
+
syncColorPanel();
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
function creerEnfantEtLier() {
|
|
1875
|
+
if (selectedIds.length !== 1) return;
|
|
1876
|
+
var diag = getCurrentDiagram();
|
|
1877
|
+
var shape = diag ? diag.shapes.find(function (s) { return s.id === selectedIds[0]; }) : null;
|
|
1878
|
+
if (!shape) return;
|
|
1879
|
+
hideLinkPicker();
|
|
1880
|
+
var titre = shape.text || "Sous-diagramme";
|
|
1881
|
+
var child = { id: Date.now(), titre: titre, shapes: [], arrows: [], children: [] };
|
|
1882
|
+
if (!diag.children) diag.children = [];
|
|
1883
|
+
diag.children.push(child);
|
|
1884
|
+
diagExpandedIds[String(diag.id)] = true;
|
|
1885
|
+
pushHistory();
|
|
1886
|
+
shape.linkedDiagramId = String(child.id);
|
|
1887
|
+
saveDiagrammes();
|
|
1888
|
+
renderAll();
|
|
1889
|
+
renderDiagramList();
|
|
1890
|
+
syncColorPanel();
|
|
1891
|
+
}
|
|
1564
1892
|
|
|
1565
1893
|
function startArrowTextEdit(arrowId) {
|
|
1566
1894
|
var diag = getCurrentDiagram();
|
|
@@ -1601,7 +1929,16 @@ function shapeAt(x, y) {
|
|
|
1601
1929
|
if (!diag) return null;
|
|
1602
1930
|
for (var i = diag.shapes.length - 1; i >= 0; i--) {
|
|
1603
1931
|
var s = diag.shapes[i];
|
|
1604
|
-
|
|
1932
|
+
var lx = x, ly = y;
|
|
1933
|
+
if (s.rotation) {
|
|
1934
|
+
var scx = s.x + s.w / 2, scy = s.y + s.h / 2;
|
|
1935
|
+
var rad = -s.rotation * Math.PI / 180;
|
|
1936
|
+
var cos = Math.cos(rad), sin = Math.sin(rad);
|
|
1937
|
+
var ddx = x - scx, ddy = y - scy;
|
|
1938
|
+
lx = scx + ddx * cos - ddy * sin;
|
|
1939
|
+
ly = scy + ddx * sin + ddy * cos;
|
|
1940
|
+
}
|
|
1941
|
+
if (lx >= s.x && lx <= s.x + s.w && ly >= s.y && ly <= s.y + s.h) return s;
|
|
1605
1942
|
}
|
|
1606
1943
|
return null;
|
|
1607
1944
|
}
|
|
@@ -1899,6 +2236,31 @@ function onMouseMove(e) {
|
|
|
1899
2236
|
function onMouseUp(e) {
|
|
1900
2237
|
var pt = svgPoint(e.clientX, e.clientY);
|
|
1901
2238
|
|
|
2239
|
+
// En mode verrouillé : détecter un clic (sans déplacement) sur une forme liée
|
|
2240
|
+
if (boardLocked && panStart) {
|
|
2241
|
+
var movedPx = Math.abs(e.clientX - panStart.cx) + Math.abs(e.clientY - panStart.cy);
|
|
2242
|
+
if (movedPx < 5 && !e.shiftKey) {
|
|
2243
|
+
var shape = shapeAt(pt.x, pt.y);
|
|
2244
|
+
if (shape && shape.linkedDiagramId) {
|
|
2245
|
+
var target = findDiagramById(shape.linkedDiagramId, diagramsList);
|
|
2246
|
+
if (target) {
|
|
2247
|
+
hideLinkPicker();
|
|
2248
|
+
diagNavStack.push(currentDiagramId);
|
|
2249
|
+
if (diagNavStack.length > 30) diagNavStack.shift();
|
|
2250
|
+
panStart = null;
|
|
2251
|
+
selectDiagramme(shape.linkedDiagramId);
|
|
2252
|
+
return;
|
|
2253
|
+
}
|
|
2254
|
+
} else if (shape && shape.externalUrl) {
|
|
2255
|
+
panStart = null;
|
|
2256
|
+
window.open(shape.externalUrl, "_blank");
|
|
2257
|
+
return;
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
panStart = null;
|
|
2261
|
+
return;
|
|
2262
|
+
}
|
|
2263
|
+
|
|
1902
2264
|
// Fin de tracé de flèche via conn-dot
|
|
1903
2265
|
if (arrowSrcId && !dragState) {
|
|
1904
2266
|
document.getElementById("tempArrow").style.display = "none";
|
|
@@ -1931,6 +2293,9 @@ function onMouseUp(e) {
|
|
|
1931
2293
|
}
|
|
1932
2294
|
|
|
1933
2295
|
if (dragState) {
|
|
2296
|
+
var wasMoved = dragState.moved;
|
|
2297
|
+
var draggedId = dragState.id;
|
|
2298
|
+
var dragType = dragState.type;
|
|
1934
2299
|
if (dragState.moved && dragState.snapshot) {
|
|
1935
2300
|
historyStack.push(dragState.snapshot);
|
|
1936
2301
|
if (historyStack.length > MAX_HISTORY) historyStack.shift();
|
|
@@ -1938,6 +2303,24 @@ function onMouseUp(e) {
|
|
|
1938
2303
|
saveDiagrammes();
|
|
1939
2304
|
dragState = null;
|
|
1940
2305
|
renderAll();
|
|
2306
|
+
// Naviguer vers le diagramme lié si clic sans déplacement
|
|
2307
|
+
if (!wasMoved && dragType === "move" && draggedId && !e.shiftKey) {
|
|
2308
|
+
var diag = getCurrentDiagram();
|
|
2309
|
+
var clickedShape = diag ? diag.shapes.find(function (s) { return s.id === draggedId; }) : null;
|
|
2310
|
+
if (clickedShape && clickedShape.linkedDiagramId) {
|
|
2311
|
+
var target = findDiagramById(clickedShape.linkedDiagramId, diagramsList);
|
|
2312
|
+
if (target) {
|
|
2313
|
+
hideLinkPicker();
|
|
2314
|
+
diagNavStack.push(currentDiagramId);
|
|
2315
|
+
if (diagNavStack.length > 30) diagNavStack.shift();
|
|
2316
|
+
selectDiagramme(clickedShape.linkedDiagramId);
|
|
2317
|
+
return;
|
|
2318
|
+
}
|
|
2319
|
+
} else if (clickedShape && clickedShape.externalUrl) {
|
|
2320
|
+
window.open(clickedShape.externalUrl, "_blank");
|
|
2321
|
+
return;
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
1941
2324
|
}
|
|
1942
2325
|
panStart = null;
|
|
1943
2326
|
}
|
|
@@ -1977,14 +2360,22 @@ function pasteShapes() {
|
|
|
1977
2360
|
document.addEventListener("DOMContentLoaded", function () {
|
|
1978
2361
|
diagramsList = loadDiagrammes();
|
|
1979
2362
|
if (!localStorage.getItem("mes_diagrammes")) saveDiagrammes();
|
|
1980
|
-
var
|
|
1981
|
-
if (
|
|
1982
|
-
|
|
2363
|
+
var savedDiagId = localStorage.getItem("current_diagram_id");
|
|
2364
|
+
if (savedDiagId && findDiagramById(savedDiagId, diagramsList)) {
|
|
2365
|
+
currentDiagramId = savedDiagId;
|
|
2366
|
+
} else {
|
|
2367
|
+
var savedIdx = parseInt(localStorage.getItem("current_diagram_idx"), 10);
|
|
2368
|
+
if (!isNaN(savedIdx) && savedIdx >= 0 && savedIdx < diagramsList.length) {
|
|
2369
|
+
currentDiagramId = String(diagramsList[savedIdx].id);
|
|
2370
|
+
} else {
|
|
2371
|
+
currentDiagramId = diagramsList[0] ? String(diagramsList[0].id) : null;
|
|
2372
|
+
}
|
|
1983
2373
|
}
|
|
1984
|
-
restoreLockForDiagram(
|
|
2374
|
+
restoreLockForDiagram(currentDiagramId);
|
|
1985
2375
|
checkDiffDiagrammes();
|
|
1986
2376
|
renderAll();
|
|
1987
2377
|
updateLockBtn();
|
|
2378
|
+
updateBackBtn();
|
|
1988
2379
|
|
|
1989
2380
|
var canvas = document.getElementById("canvas");
|
|
1990
2381
|
canvas.addEventListener("mousedown", onMouseDown);
|
|
@@ -2038,15 +2429,25 @@ document.addEventListener("DOMContentLoaded", function () {
|
|
|
2038
2429
|
var rows = shape.rows || 3;
|
|
2039
2430
|
var cols = shape.cols || 3;
|
|
2040
2431
|
var nextRow = editingTableCell.row;
|
|
2041
|
-
var nextCol = editingTableCell.col
|
|
2042
|
-
if (
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2432
|
+
var nextCol = editingTableCell.col;
|
|
2433
|
+
if (e.shiftKey) {
|
|
2434
|
+
// Shift+Tab : cellule précédente, s'arrête à la première
|
|
2435
|
+
nextCol -= 1;
|
|
2436
|
+
if (nextCol < 0) {
|
|
2437
|
+
if (nextRow > 0) { nextRow--; nextCol = cols - 1; }
|
|
2438
|
+
else { nextCol = 0; }
|
|
2439
|
+
}
|
|
2440
|
+
} else {
|
|
2441
|
+
// Tab : cellule suivante, ajoute une ligne à la fin
|
|
2442
|
+
nextCol += 1;
|
|
2443
|
+
if (nextCol >= cols) { nextRow++; nextCol = 0; }
|
|
2444
|
+
if (nextRow >= rows) {
|
|
2445
|
+
pushHistory();
|
|
2446
|
+
shape.rows = rows + 1;
|
|
2447
|
+
if (!shape.cells) shape.cells = [];
|
|
2448
|
+
while (shape.cells.length < shape.rows) shape.cells.push([]);
|
|
2449
|
+
shape.cells[shape.rows - 1] = new Array(cols).fill("");
|
|
2450
|
+
}
|
|
2050
2451
|
}
|
|
2051
2452
|
var shapeId = editingShapeId;
|
|
2052
2453
|
saveDiagrammes();
|
|
@@ -2062,12 +2463,40 @@ document.addEventListener("DOMContentLoaded", function () {
|
|
|
2062
2463
|
document.addEventListener("keydown", function (e) {
|
|
2063
2464
|
if (document.activeElement.tagName === "INPUT" || document.activeElement.tagName === "TEXTAREA") return;
|
|
2064
2465
|
if ((e.ctrlKey || e.metaKey) && e.key === "z") { e.preventDefault(); undoAction(); return; }
|
|
2466
|
+
if ((e.ctrlKey || e.metaKey) && e.key === "a") {
|
|
2467
|
+
e.preventDefault();
|
|
2468
|
+
var diag = getCurrentDiagram();
|
|
2469
|
+
if (diag && diag.shapes.length > 0) {
|
|
2470
|
+
selectedIds = diag.shapes.map(function (s) { return s.id; });
|
|
2471
|
+
selectedType = "shape";
|
|
2472
|
+
selectedId = selectedIds[selectedIds.length - 1];
|
|
2473
|
+
renderAll();
|
|
2474
|
+
document.getElementById("colorPanel").style.display = "flex";
|
|
2475
|
+
syncColorPanel();
|
|
2476
|
+
}
|
|
2477
|
+
return;
|
|
2478
|
+
}
|
|
2065
2479
|
if (boardLocked) return;
|
|
2066
2480
|
if (e.key === "Delete" || e.key === "Backspace") deleteSelected();
|
|
2067
2481
|
if (e.key === "Escape") {
|
|
2482
|
+
hideLinkPicker();
|
|
2068
2483
|
arrowSrcId = null;
|
|
2069
2484
|
document.getElementById("tempArrow").style.display = "none";
|
|
2070
2485
|
setTool("select");
|
|
2486
|
+
selectedIds = []; selectedId = null; selectedType = null;
|
|
2487
|
+
document.getElementById("colorPanel").style.display = "none";
|
|
2488
|
+
renderAll();
|
|
2489
|
+
}
|
|
2490
|
+
if ((e.ctrlKey || e.metaKey) && e.key === "x") {
|
|
2491
|
+
e.preventDefault();
|
|
2492
|
+
if (selectedIds.length === 0) return;
|
|
2493
|
+
var diag = getCurrentDiagram();
|
|
2494
|
+
clipboard = selectedIds.map(function (id) {
|
|
2495
|
+
var s = diag.shapes.find(function (sh) { return sh.id === id; });
|
|
2496
|
+
return s ? JSON.parse(JSON.stringify(s)) : null;
|
|
2497
|
+
}).filter(Boolean);
|
|
2498
|
+
deleteSelected();
|
|
2499
|
+
return;
|
|
2071
2500
|
}
|
|
2072
2501
|
if ((e.ctrlKey || e.metaKey) && e.key === "c") {
|
|
2073
2502
|
e.preventDefault();
|
|
@@ -2112,6 +2541,11 @@ document.addEventListener("DOMContentLoaded", function () {
|
|
|
2112
2541
|
|
|
2113
2542
|
|
|
2114
2543
|
document.addEventListener("mousedown", function (e) {
|
|
2544
|
+
var lp = document.getElementById("linkPickerPanel");
|
|
2545
|
+
if (lp && lp.style.display !== "none") {
|
|
2546
|
+
var lbtn = document.getElementById("btnShapeLink");
|
|
2547
|
+
if (!lp.contains(e.target) && e.target !== lbtn) hideLinkPicker();
|
|
2548
|
+
}
|
|
2115
2549
|
var panel = document.getElementById("diagramListPanel");
|
|
2116
2550
|
if (!panel.classList.contains("open")) return;
|
|
2117
2551
|
var burgerBtn = document.querySelector(".diagram-tool[onclick=\"toggleDiagramList()\"]");
|