doc-survival-kit 1.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.
package/notes.js ADDED
@@ -0,0 +1,561 @@
1
+ // ══════════════════════════════════════
2
+ // mesNotes — CRUD notes (localStorage + fichier)
3
+ // ══════════════════════════════════════
4
+
5
+ var expandedNoteIds = (function () {
6
+ try { return JSON.parse(localStorage.getItem("expanded_note_ids")) || {}; } catch (e) { return {}; }
7
+ })();
8
+ var noteIdxASupprimer = null;
9
+ var noteIdxEnEdition = null;
10
+ var noteBlocNoteIdx = null;
11
+ var noteBlocBlocIdx = null;
12
+ var supprBlocNoteIdx = null;
13
+ var supprBlocBlocIdx = null;
14
+
15
+ function loadNotes() {
16
+ try {
17
+ return JSON.parse(localStorage.getItem("mes_notes")) || mesNotesDefaut;
18
+ } catch (e) {
19
+ return mesNotesDefaut;
20
+ }
21
+ }
22
+
23
+ function saveNotes(data) {
24
+ localStorage.setItem("mes_notes", JSON.stringify(data));
25
+ checkDiffNotes();
26
+ }
27
+
28
+ function checkDiffNotes() {
29
+ var stored = localStorage.getItem("mes_notes");
30
+ var areDifferent = stored !== JSON.stringify(mesNotesDefaut);
31
+ document.getElementById("btnSaveNotes").style.display = areDifferent
32
+ ? "inline-flex"
33
+ : "none";
34
+ }
35
+
36
+ // ── Persistance FileSystemFileHandle via IndexedDB ──
37
+ var IDB_KEY_NOTES = "mesNotes";
38
+
39
+ function ouvrirDBNotes() {
40
+ return new Promise(function (resolve, reject) {
41
+ var req = indexedDB.open("doc-survival-kit-db", 1);
42
+ req.onupgradeneeded = function (e) {
43
+ e.target.result.createObjectStore("fileHandles");
44
+ };
45
+ req.onsuccess = function (e) {
46
+ resolve(e.target.result);
47
+ };
48
+ req.onerror = function (e) {
49
+ reject(e.target.error);
50
+ };
51
+ });
52
+ }
53
+
54
+ function sauvegarderHandleNotes(handle) {
55
+ return ouvrirDBNotes().then(function (db) {
56
+ return new Promise(function (resolve, reject) {
57
+ var tx = db.transaction("fileHandles", "readwrite");
58
+ tx.objectStore("fileHandles").put(handle, IDB_KEY_NOTES);
59
+ tx.oncomplete = resolve;
60
+ tx.onerror = function (e) {
61
+ reject(e.target.error);
62
+ };
63
+ });
64
+ });
65
+ }
66
+
67
+ function recupererHandleNotes() {
68
+ return ouvrirDBNotes().then(function (db) {
69
+ return new Promise(function (resolve, reject) {
70
+ var tx = db.transaction("fileHandles", "readonly");
71
+ var req = tx.objectStore("fileHandles").get(IDB_KEY_NOTES);
72
+ req.onsuccess = function (e) {
73
+ resolve(e.target.result || null);
74
+ };
75
+ req.onerror = function (e) {
76
+ reject(e.target.error);
77
+ };
78
+ });
79
+ });
80
+ }
81
+
82
+ // ── Enregistrement du fichier mesNotes.js ──
83
+ function enregistrerModificationsNotes() {
84
+ if (!("showSaveFilePicker" in window)) {
85
+ console.error("File System Access API non disponible dans ce navigateur.");
86
+ return;
87
+ }
88
+ recupererHandleNotes().then(function (handle) {
89
+ if (!handle) {
90
+ document.getElementById("erreurFichierNotes").style.display = "none";
91
+ document
92
+ .getElementById("modalPremiereSauvegardeNotes")
93
+ .classList.add("open");
94
+ } else {
95
+ ecrireFichierNotes(handle);
96
+ }
97
+ });
98
+ }
99
+
100
+ function fermerModalPremiereSauvegardeNotes() {
101
+ document
102
+ .getElementById("modalPremiereSauvegardeNotes")
103
+ .classList.remove("open");
104
+ }
105
+
106
+ function ouvrirSelecteurFichierNotes() {
107
+ fermerModalPremiereSauvegardeNotes();
108
+ window
109
+ .showDirectoryPicker()
110
+ .then(function (dirHandle) {
111
+ return dirHandle.getFileHandle("mesNotes.js");
112
+ })
113
+ .then(function (handle) {
114
+ document.getElementById("erreurFichierNotes").style.display = "none";
115
+ return sauvegarderHandleNotes(handle).then(function () {
116
+ return ecrireFichierNotes(handle);
117
+ });
118
+ })
119
+ .catch(function (err) {
120
+ if (err.name === "NotFoundError") {
121
+ document.getElementById("erreurFichierNotes").style.display = "block";
122
+ document
123
+ .getElementById("modalPremiereSauvegardeNotes")
124
+ .classList.add("open");
125
+ } else if (err.name !== "AbortError") {
126
+ console.error("Erreur lors de la sélection du dossier :", err);
127
+ }
128
+ });
129
+ }
130
+
131
+ function ecrireFichierNotes(handle) {
132
+ return handle
133
+ .queryPermission({ mode: "readwrite" })
134
+ .then(function (permission) {
135
+ if (permission !== "granted") {
136
+ return handle.requestPermission({ mode: "readwrite" });
137
+ }
138
+ return permission;
139
+ })
140
+ .then(function (permission) {
141
+ if (permission !== "granted") {
142
+ console.error("Permission d'écriture refusée.");
143
+ return;
144
+ }
145
+ var data = loadNotes();
146
+ var content =
147
+ "var mesNotesDefaut = " + JSON.stringify(data, null, 2) + ";\n";
148
+ return handle
149
+ .createWritable()
150
+ .then(function (writable) {
151
+ return writable.write(content).then(function () {
152
+ return writable.close();
153
+ });
154
+ })
155
+ .then(function () {
156
+ mesNotesDefaut = data;
157
+ checkDiffNotes();
158
+ console.log("mesNotes.js enregistré avec succès.", data);
159
+ });
160
+ })
161
+ .catch(function (err) {
162
+ console.error("Erreur lors de l'enregistrement :", err);
163
+ });
164
+ }
165
+
166
+ function toggleNote(noteId) {
167
+ if (expandedNoteIds[noteId]) {
168
+ delete expandedNoteIds[noteId];
169
+ } else {
170
+ expandedNoteIds[noteId] = true;
171
+ }
172
+ localStorage.setItem("expanded_note_ids", JSON.stringify(expandedNoteIds));
173
+ renderNotes();
174
+ }
175
+
176
+ function toggleAllNotes() {
177
+ var notes = loadNotes();
178
+ var allExpanded = notes.length > 0 && notes.every(function (n) { return expandedNoteIds[n.id]; });
179
+ if (allExpanded) {
180
+ expandedNoteIds = {};
181
+ } else {
182
+ notes.forEach(function (n) { expandedNoteIds[n.id] = true; });
183
+ }
184
+ localStorage.setItem("expanded_note_ids", JSON.stringify(expandedNoteIds));
185
+ renderNotes();
186
+ }
187
+
188
+ function updateToggleAllBtn() {
189
+ var btn = document.getElementById("btnToggleAllNotes");
190
+ if (!btn) return;
191
+ var notes = loadNotes();
192
+ var allExpanded = notes.length > 0 && notes.every(function (n) { return expandedNoteIds[n.id]; });
193
+ btn.textContent = allExpanded ? window.t.notes_btn_collapse_all : window.t.notes_btn_expand_all;
194
+ }
195
+
196
+ function renderNotes() {
197
+ var notes = loadNotes();
198
+ var container = document.getElementById("notesContainer");
199
+ if (!container) return;
200
+ var hadEditMode = container.classList.contains("edit-mode");
201
+
202
+ if (notes.length === 0) {
203
+ container.innerHTML =
204
+ '<p class="empty-msg">' + window.t.notes_empty + "</p>";
205
+ } else {
206
+ container.innerHTML = notes
207
+ .map(function (note, nIdx) {
208
+ var blocsHtml = note.blocs
209
+ .map(function (bloc, bIdx) {
210
+ var inner = "";
211
+ if (bloc.type === "b") {
212
+ inner = "<b>" + esc(bloc.content) + "</b>";
213
+ } else if (bloc.type === "p") {
214
+ inner = "<p>" + esc(bloc.content) + "</p>";
215
+ } else if (bloc.type === "pre") {
216
+ inner =
217
+ '<div class="pre-wrapper"><pre>' +
218
+ esc(bloc.content) +
219
+ "</pre>" +
220
+ '<button class="btn-copy-pre" onclick="copierBloc(this)">' +
221
+ window.t.notes_btn_copy +
222
+ "</button>" +
223
+ "</div>";
224
+ } else if (bloc.type === "ul") {
225
+ inner =
226
+ "<ul>" +
227
+ bloc.items
228
+ .map(function (i) {
229
+ return "<li>" + esc(i) + "</li>";
230
+ })
231
+ .join("") +
232
+ "</ul>";
233
+ } else if (bloc.type === "table") {
234
+ inner =
235
+ '<div class="table-wrapper"><table>' +
236
+ "<thead><tr>" +
237
+ bloc.headers.map(function(h) { return "<th>" + esc(h) + "</th>"; }).join("") +
238
+ "</tr></thead>" +
239
+ "<tbody>" +
240
+ bloc.rows.map(function(row) {
241
+ return "<tr>" + row.map(function(c) { return "<td>" + esc(c) + "</td>"; }).join("") + "</tr>";
242
+ }).join("") +
243
+ "</tbody></table></div>";
244
+ }
245
+ return (
246
+ '<div class="bloc-wrapper">' +
247
+ inner +
248
+ '<div class="bloc-actions">' +
249
+ '<button class="btn-edit-bloc" onclick="ouvrirModalEditBloc(' +
250
+ nIdx +
251
+ "," +
252
+ bIdx +
253
+ ')">' +
254
+ window.t.notes_btn_edit_bloc +
255
+ "</button>" +
256
+ '<button class="btn-del-bloc" onclick="ouvrirConfirmSupprBloc(' +
257
+ nIdx +
258
+ "," +
259
+ bIdx +
260
+ ')">×</button>' +
261
+ "</div></div>"
262
+ );
263
+ })
264
+ .join("");
265
+
266
+ var isCollapsed = !expandedNoteIds[note.id];
267
+ return (
268
+ '<div class="note ' +
269
+ esc(note.theme) +
270
+ (isCollapsed ? " collapsed" : "") +
271
+ '">' +
272
+ '<div class="note-header">' +
273
+ "<h2>" +
274
+ esc(note.titre) +
275
+ "</h2>" +
276
+ '<div class="note-actions">' +
277
+ '<button class="btn-edit-note" onclick="ouvrirModalEditNote(' +
278
+ nIdx +
279
+ ')">' +
280
+ window.t.notes_btn_edit_note +
281
+ "</button>" +
282
+ '<button class="btn-del-note" onclick="ouvrirConfirmSupprNote(' +
283
+ nIdx +
284
+ ')">×</button>' +
285
+ "</div>" +
286
+ '<button class="btn-toggle-note" onclick="toggleNote(' +
287
+ note.id +
288
+ ')" title="' +
289
+ (isCollapsed ? window.t.notes_btn_expand : window.t.notes_btn_collapse) +
290
+ '">' +
291
+ '<svg viewBox="0 0 10 6" width="10" height="6"><path d="M1 1 L5 5 L9 1" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>' +
292
+ "</button>" +
293
+ "</div>" +
294
+ '<div class="note-content">' +
295
+ (blocsHtml || "") +
296
+ "</div>" +
297
+ '<div class="note-footer">' +
298
+ '<button class="btn-add-bloc" onclick="ouvrirModalBloc(' +
299
+ nIdx +
300
+ ')">' +
301
+ window.t.notes_btn_add_bloc +
302
+ "</button>" +
303
+ "</div></div>"
304
+ );
305
+ })
306
+ .join("");
307
+ }
308
+
309
+ if (hadEditMode) container.classList.add("edit-mode");
310
+ updateToggleAllBtn();
311
+ }
312
+
313
+ // ── Toggle mode édition ──
314
+ function toggleEditModeNotes() {
315
+ var container = document.getElementById("notesContainer");
316
+ var btn = document.getElementById("btnEditModeNotes");
317
+ if (container.classList.toggle("edit-mode")) {
318
+ btn.textContent = window.t.notes_btn_quit_edit_mode;
319
+ } else {
320
+ btn.textContent = window.t.notes_btn_edit_mode;
321
+ }
322
+ }
323
+
324
+ // ── Nouvelle note ──
325
+ function openModalNote() {
326
+ document.getElementById("noteNom").value = "";
327
+ document.getElementById("noteCouleur").value = "t-green";
328
+ document.getElementById("modalNote").classList.add("open");
329
+ setTimeout(function () {
330
+ document.getElementById("noteNom").focus();
331
+ }, 50);
332
+ }
333
+
334
+ function closeModalNote() {
335
+ document.getElementById("modalNote").classList.remove("open");
336
+ }
337
+
338
+ function confirmerNote() {
339
+ var titre = document.getElementById("noteNom").value.trim();
340
+ if (!titre) return;
341
+ var notes = loadNotes();
342
+ notes.push({
343
+ id: Date.now(),
344
+ theme: document.getElementById("noteCouleur").value,
345
+ titre: titre,
346
+ blocs: [],
347
+ });
348
+ saveNotes(notes);
349
+ closeModalNote();
350
+ renderNotes();
351
+ }
352
+
353
+ // ── Édition note ──
354
+ function ouvrirModalEditNote(idx) {
355
+ noteIdxEnEdition = idx;
356
+ var note = loadNotes()[idx];
357
+ document.getElementById("editNoteNom").value = note.titre;
358
+ document.getElementById("editNoteCouleur").value = note.theme;
359
+ document.getElementById("modalEditNote").classList.add("open");
360
+ setTimeout(function () {
361
+ document.getElementById("editNoteNom").focus();
362
+ }, 50);
363
+ }
364
+
365
+ function fermerModalEditNote() {
366
+ document.getElementById("modalEditNote").classList.remove("open");
367
+ noteIdxEnEdition = null;
368
+ }
369
+
370
+ function confirmerEditNote() {
371
+ if (noteIdxEnEdition === null) return;
372
+ var titre = document.getElementById("editNoteNom").value.trim();
373
+ if (!titre) return;
374
+ var notes = loadNotes();
375
+ notes[noteIdxEnEdition].titre = titre;
376
+ notes[noteIdxEnEdition].theme =
377
+ document.getElementById("editNoteCouleur").value;
378
+ saveNotes(notes);
379
+ fermerModalEditNote();
380
+ renderNotes();
381
+ }
382
+
383
+ // ── Suppression note ──
384
+ function ouvrirConfirmSupprNote(idx) {
385
+ noteIdxASupprimer = idx;
386
+ document.getElementById("modalConfirmSupprNote").classList.add("open");
387
+ }
388
+
389
+ function fermerConfirmSupprNote() {
390
+ document.getElementById("modalConfirmSupprNote").classList.remove("open");
391
+ noteIdxASupprimer = null;
392
+ }
393
+
394
+ function supprimerNote() {
395
+ if (noteIdxASupprimer === null) return;
396
+ var notes = loadNotes();
397
+ notes.splice(noteIdxASupprimer, 1);
398
+ saveNotes(notes);
399
+ fermerConfirmSupprNote();
400
+ renderNotes();
401
+ }
402
+
403
+ // ── Ajout / édition bloc ──
404
+ function updateBlocPlaceholder() {
405
+ var type = document.getElementById("blocType").value;
406
+ var ta = document.getElementById("blocContent");
407
+ var inp = document.getElementById("blocContentInput");
408
+ var useInput = type === "b";
409
+ inp.style.display = useInput ? "" : "none";
410
+ ta.style.display = useInput ? "none" : "";
411
+ if (type === "ul") ta.placeholder = window.t.modal_bloc_placeholder_ul;
412
+ else if (type === "pre") ta.placeholder = window.t.modal_bloc_placeholder_pre;
413
+ else if (type === "table") ta.placeholder = window.t.modal_bloc_placeholder_table;
414
+ else if (type === "p") ta.placeholder = window.t.modal_bloc_placeholder_p;
415
+ else inp.placeholder = window.t.modal_bloc_placeholder_b;
416
+ }
417
+
418
+ function ouvrirModalBloc(noteIdx) {
419
+ noteBlocNoteIdx = noteIdx;
420
+ noteBlocBlocIdx = null;
421
+ document.getElementById("modalBlocTitre").textContent =
422
+ window.t.modal_bloc_new;
423
+ document.getElementById("blocType").value = "p";
424
+ document.getElementById("blocContent").value = "";
425
+ document.getElementById("blocContentInput").value = "";
426
+ updateBlocPlaceholder();
427
+ document.getElementById("modalBloc").classList.add("open");
428
+ setTimeout(function () {
429
+ document.getElementById("blocContent").focus();
430
+ }, 50);
431
+ }
432
+
433
+ function ouvrirModalEditBloc(noteIdx, blocIdx) {
434
+ noteBlocNoteIdx = noteIdx;
435
+ noteBlocBlocIdx = blocIdx;
436
+ var bloc = loadNotes()[noteIdx].blocs[blocIdx];
437
+ document.getElementById("modalBlocTitre").textContent =
438
+ window.t.modal_bloc_edit;
439
+ document.getElementById("blocType").value = bloc.type;
440
+ var useInput = bloc.type === "b";
441
+ document.getElementById("blocContentInput").value = useInput
442
+ ? bloc.content
443
+ : "";
444
+ document.getElementById("blocContent").value = useInput
445
+ ? ""
446
+ : bloc.type === "ul"
447
+ ? bloc.items.join("\n")
448
+ : bloc.type === "table"
449
+ ? [bloc.headers.join(" | ")].concat(bloc.rows.map(function(r) { return r.join(" | "); })).join("\n")
450
+ : bloc.content;
451
+ updateBlocPlaceholder();
452
+ document.getElementById("modalBloc").classList.add("open");
453
+ setTimeout(function () {
454
+ document
455
+ .getElementById(useInput ? "blocContentInput" : "blocContent")
456
+ .focus();
457
+ }, 50);
458
+ }
459
+
460
+ function fermerModalBloc() {
461
+ document.getElementById("modalBloc").classList.remove("open");
462
+ noteBlocNoteIdx = null;
463
+ noteBlocBlocIdx = null;
464
+ }
465
+
466
+ function confirmerBloc() {
467
+ var type = document.getElementById("blocType").value;
468
+ var useInput = type === "b";
469
+ var raw = document.getElementById(
470
+ useInput ? "blocContentInput" : "blocContent",
471
+ ).value;
472
+ if (!raw.trim()) return;
473
+ var bloc;
474
+ if (type === "ul") {
475
+ var items = raw
476
+ .split("\n")
477
+ .map(function (s) {
478
+ return s.trim();
479
+ })
480
+ .filter(Boolean);
481
+ if (!items.length) return;
482
+ bloc = { type: "ul", items: items };
483
+ } else if (type === "table") {
484
+ var lines = raw.split("\n").map(function(l) { return l.trim(); }).filter(Boolean);
485
+ if (lines.length < 1) return;
486
+ var headers = lines[0].split("|").map(function(c) { return c.trim(); });
487
+ var rows = lines.slice(1).map(function(l) {
488
+ return l.split("|").map(function(c) { return c.trim(); });
489
+ });
490
+ bloc = { type: "table", headers: headers, rows: rows };
491
+ } else {
492
+ bloc = { type: type, content: raw };
493
+ }
494
+ var notes = loadNotes();
495
+ if (noteBlocBlocIdx === null) {
496
+ notes[noteBlocNoteIdx].blocs.push(bloc);
497
+ } else {
498
+ notes[noteBlocNoteIdx].blocs[noteBlocBlocIdx] = bloc;
499
+ }
500
+ saveNotes(notes);
501
+ fermerModalBloc();
502
+ renderNotes();
503
+ }
504
+
505
+ // ── Suppression bloc ──
506
+ function ouvrirConfirmSupprBloc(noteIdx, blocIdx) {
507
+ supprBlocNoteIdx = noteIdx;
508
+ supprBlocBlocIdx = blocIdx;
509
+ document.getElementById("modalConfirmSupprBloc").classList.add("open");
510
+ }
511
+
512
+ function fermerConfirmSupprBloc() {
513
+ document.getElementById("modalConfirmSupprBloc").classList.remove("open");
514
+ supprBlocNoteIdx = null;
515
+ supprBlocBlocIdx = null;
516
+ }
517
+
518
+ function supprimerBloc() {
519
+ if (supprBlocNoteIdx === null || supprBlocBlocIdx === null) return;
520
+ var notes = loadNotes();
521
+ notes[supprBlocNoteIdx].blocs.splice(supprBlocBlocIdx, 1);
522
+ saveNotes(notes);
523
+ fermerConfirmSupprBloc();
524
+ renderNotes();
525
+ }
526
+
527
+ // ── Copier un bloc pre ──
528
+ function copierBloc(btn) {
529
+ var content = btn.closest(".pre-wrapper").querySelector("pre").textContent;
530
+ navigator.clipboard.writeText(content).then(function () {
531
+ btn.textContent = window.t.notes_btn_copied;
532
+ btn.classList.add("copied");
533
+ setTimeout(function () {
534
+ btn.textContent = window.t.notes_btn_copy;
535
+ btn.classList.remove("copied");
536
+ }, 1500);
537
+ });
538
+ }
539
+
540
+ // ── Init ──
541
+ document.addEventListener("DOMContentLoaded", function () {
542
+ if (!localStorage.getItem("mes_notes")) {
543
+ saveNotes(mesNotesDefaut);
544
+ }
545
+ renderNotes();
546
+ checkDiffNotes();
547
+ [
548
+ "modalNote",
549
+ "modalEditNote",
550
+ "modalConfirmSupprNote",
551
+ "modalBloc",
552
+ "modalConfirmSupprBloc",
553
+ "modalPremiereSauvegardeNotes",
554
+ ].forEach(function (id) {
555
+ var el = document.getElementById(id);
556
+ if (el)
557
+ el.addEventListener("click", function (e) {
558
+ if (e.target === el) el.classList.remove("open");
559
+ });
560
+ });
561
+ });
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "doc-survival-kit",
3
+ "version": "1.0.0",
4
+ "description": "Dashboard personnel offline : diagrammes, tâches, notes et liens dans un seul fichier HTML — fonctionne sans serveur via file://",
5
+ "bin": {
6
+ "doc-survival-kit": "./bin/cli.js"
7
+ },
8
+ "files": [
9
+ "bin/",
10
+ "i18n/",
11
+ "index.html",
12
+ "admin.html",
13
+ "diagram.html",
14
+ "style.css",
15
+ "mesLiens.js",
16
+ "mesNotes.js",
17
+ "diagrammes.js",
18
+ "liens.js",
19
+ "taches.js",
20
+ "notes.js",
21
+ "diagram.js",
22
+ "images/"
23
+ ],
24
+ "engines": {
25
+ "node": ">=16.7.0"
26
+ },
27
+ "keywords": [
28
+ "dashboard",
29
+ "offline",
30
+ "notes",
31
+ "taches",
32
+ "liens",
33
+ "productivity",
34
+ "file-based"
35
+ ],
36
+ "author": "ymedaghri",
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/ymedaghri/doc-survival-kit.git"
41
+ }
42
+ }