1/* DressKool â « Mon carnet d'actions ». 2 ------------------------------------------------------------------ 3 C'est la piece qui fait passer l'app de « cours » a « outil » : les 68 lecons 4 ne laissent plus seulement des cases cochees dans un localStorage, elles 5 produisent un PLAN D'AFFAIRES PERSONNEL que l'eleve peut relire, imprimer et 6 emporter (export .md ou .txt). 7 8 Source de verite : S.ex, ecrit par dk-lesson.js 9 ({ lid: { items:[bool], note, num, doneAt } }). Ce module ne fait que lire. 10 11 Points d'accroche, sans jamais toucher aux 6 index.html : 12 - route #/carnet (DK.registerRoute, pose par dk-nav.js) 13 - encart tableau de bord (DK.cards.push) 14 - entree sidebar + nav basse mobile (posees par dk-nav.js) 15 ------------------------------------------------------------------ */ 16(function () { 17 var DK = window.DK; 18 if (!DK || !DK.S) return; 19 var t = DK.t, S = DK.S; 20 21 var L = { 22 fr: { 23 title: 'Mon carnet dâactions', 24 sub: 'Tout ce que tu as réellement fait pendant la formation, module par module. Câest ton plan de travail : relis-le, complète-le, emporte-le.', 25 empty_t: 'Ton carnet est encore vide', 26 empty_b: 'Chaque leçon se termine par un exercice concret. Coche ce que tu fais et note tes chiffres : tout se retrouve ici.', 27 empty_go: 'Commencer un exercice', 28 st_actions: 'actions faites', st_notes: 'notes écrites', st_lessons: 'leçons travaillées', 29 exp_md: '⬠Exporter (.md)', exp_txt: '⬠Exporter (.txt)', 30 note_label: 'Ta note', num_label: 'Ton chiffre', 31 card_t: 'Mon carnet dâactions', card_open: 'Ouvrir le carnet', 32 card_p: '{a} action(s) faite(s) et {n} note(s) sur {l} leçon(s).', 33 card_p0: 'Coche les exercices des leçons : ils construisent ton plan de travail ici.', 34 f_head: 'Mon carnet dâactions · DressKool', 35 f_by: 'Ãlève', f_on: 'Exporté le', f_done: 'Actions faites', f_notes: 'Notes' 36 }, 37 en: { 38 title: 'My action notebook', 39 sub: 'Everything you actually did during the course, module by module. This is your working plan: read it again, complete it, take it with you.', 40 empty_t: 'Your notebook is still empty', 41 empty_b: 'Every lesson ends with a concrete exercise. Tick what you do and write your numbers: it all lands here.', 42 empty_go: 'Start an exercise', 43 st_actions: 'actions done', st_notes: 'notes written', st_lessons: 'lessons worked on', 44 exp_md: '⬠Export (.md)', exp_txt: '⬠Export (.txt)', 45 note_label: 'Your note', num_label: 'Your number', 46 card_t: 'My action notebook', card_open: 'Open the notebook', 47 card_p: '{a} action(s) done and {n} note(s) across {l} lesson(s).', 48 card_p0: 'Tick the lesson exercises: they build your working plan right here.', 49 f_head: 'My action notebook · DressKool', 50 f_by: 'Student', f_on: 'Exported on', f_done: 'Actions done', f_notes: 'Notes' 51 }, 52 es: { 53 title: 'Mi cuaderno de acciones', 54 sub: 'Todo lo que has hecho de verdad durante la formación, módulo a módulo. Es tu plan de trabajo: reléelo, complétalo, llévatelo.', 55 empty_t: 'Tu cuaderno todavÃa está vacÃo', 56 empty_b: 'Cada lección termina con un ejercicio concreto. Marca lo que haces y anota tus cifras: todo aparece aquÃ.', 57 empty_go: 'Empezar un ejercicio', 58 st_actions: 'acciones hechas', st_notes: 'notas escritas', st_lessons: 'lecciones trabajadas', 59 exp_md: '⬠Exportar (.md)', exp_txt: '⬠Exportar (.txt)', 60 note_label: 'Tu nota', num_label: 'Tu cifra', 61 card_t: 'Mi cuaderno de acciones', card_open: 'Abrir el cuaderno', 62 card_p: '{a} acción(es) hecha(s) y {n} nota(s) en {l} lección(es).', 63 card_p0: 'Marca los ejercicios de las lecciones: construyen aquà tu plan de trabajo.', 64 f_head: 'Mi cuaderno de acciones · DressKool', 65 f_by: 'Alumna', f_on: 'Exportado el', f_done: 'Acciones hechas', f_notes: 'Notas' 66 }, 67 it: { 68 title: 'Il mio quaderno di azioni', 69 sub: 'Tutto quello che hai davvero fatto durante il corso, modulo per modulo. à il tuo piano di lavoro: rileggilo, completalo, portalo con te.', 70 empty_t: 'Il tuo quaderno è ancora vuoto', 71 empty_b: 'Ogni lezione finisce con un esercizio concreto. Spunta quello che fai e annota i tuoi numeri: finisce tutto qui.', 72 empty_go: 'Inizia un esercizio', 73 st_actions: 'azioni fatte', st_notes: 'note scritte', st_lessons: 'lezioni lavorate', 74 exp_md: '⬠Esporta (.md)', exp_txt: '⬠Esporta (.txt)', 75 note_label: 'La tua nota', num_label: 'Il tuo numero', 76 card_t: 'Il mio quaderno di azioni', card_open: 'Apri il quaderno', 77 card_p: '{a} azione/i fatte e {n} nota/e su {l} lezione/i.', 78 card_p0: 'Spunta gli esercizi delle lezioni: costruiscono qui il tuo piano di lavoro.', 79 f_head: 'Il mio quaderno di azioni · DressKool', 80 f_by: 'Studentessa', f_on: 'Esportato il', f_done: 'Azioni fatte', f_notes: 'Note' 81 }, 82 de: { 83 title: 'Mein Aktions-Notizbuch', 84 sub: 'Alles, was du in der Schulung wirklich getan hast, Modul für Modul. Das ist de
84in Arbeitsplan: lies ihn nach, ergänze ihn, nimm ihn mit.', 85 empty_t: 'Dein Notizbuch ist noch leer', 86 empty_b: 'Jede Lektion endet mit einer konkreten Ãbung. Hak ab, was du tust, und notiere deine Zahlen: alles landet hier.', 87 empty_go: 'Eine Ãbung starten', 88 st_actions: 'erledigte Aktionen', st_notes: 'geschriebene Notizen', st_lessons: 'bearbeitete Lektionen', 89 exp_md: '⬠Export (.md)', exp_txt: '⬠Export (.txt)', 90 note_label: 'Deine Notiz', num_label: 'Deine Zahl', 91 card_t: 'Mein Aktions-Notizbuch', card_open: 'Notizbuch öffnen', 92 card_p: '{a} Aktion(en) erledigt und {n} Notiz(en) in {l} Lektion(en).', 93 card_p0: 'Hak die Ãbungen der Lektionen ab: sie bauen hier deinen Arbeitsplan auf.', 94 f_head: 'Mein Aktions-Notizbuch · DressKool', 95 f_by: 'Teilnehmerin', f_on: 'Exportiert am', f_done: 'Erledigte Aktionen', f_notes: 'Notizen' 96 }, 97 pt: { 98 title: 'O meu caderno de ações', 99 sub: 'Tudo o que fizeste mesmo durante a formação, módulo a módulo. à o teu plano de trabalho: relê-o, completa-o, leva-o contigo.', 100 empty_t: 'O teu caderno ainda está vazio', 101 empty_b: 'Cada lição acaba com um exercÃcio concreto. Marca o que fazes e escreve os teus números: fica tudo aqui.', 102 empty_go: 'Começar um exercÃcio', 103 st_actions: 'ações feitas', st_notes: 'notas escritas', st_lessons: 'lições trabalhadas', 104 exp_md: '⬠Exportar (.md)', exp_txt: '⬠Exportar (.txt)', 105 note_label: 'A tua nota', num_label: 'O teu número', 106 card_t: 'O meu caderno de ações', card_open: 'Abrir o caderno', 107 card_p: '{a} ação(ões) feita(s) e {n} nota(s) em {l} lição(ões).', 108 card_p0: 'Marca os exercÃcios das lições: são eles que constroem aqui o teu plano de trabalho.', 109 f_head: 'O meu caderno de ações · DressKool', 110 f_by: 'Aluna', f_on: 'Exportado a', f_done: 'Ações feitas', f_notes: 'Notas' 111 } 112 }; 113 function x(k, vars) { 114 var d = L[DK.lang] || L.fr, s = (typeof d[k] === 'string') ? d[k] : (L.fr[k] || k); 115 if (vars) Object.keys(vars).forEach(function (v) { s = s.split('{' + v + '}').join(vars[v]); }); 116 return s; 117 } 118 function esc(s) { 119 return String(s == null ? '' : s) 120 .replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') 121 .replace(/"/g, '"').replace(/'/g, '''); 122 } 123 function plain(html) { 124 if (typeof DK.detag === 'function') return DK.detag(html); 125 var d = document.createElement('div'); 126 d.innerHTML = String(html || ''); 127 return (d.textContent || '').replace(/\s+/g, ' ').trim(); 128 } 129 130 /* ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 131 COLLECTE â on ne lit que S.ex, jamais on n'y ecrit 132 ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 133 function collect() { 134 var DATA = window.DATA || [], ex = S.ex || {}; 135 var out = [], nAct = 0, nNote = 0, nLes = 0; 136 137 DATA.forEach(function (b) { 138 var lessons = []; 139 b.lessons.forEach(function (l) { 140 var e = ex[l.id]; 141 if (!e) return; 142 var labels = []; 143 if (typeof DK.parseExercise === 'function' && Array.isArray(e.items)) { 144 var p = DK.parseExercise(l.exercise); 145 e.items.forEach(function (on, i) { 146 if (on && p.items[i]) labels.push(plain(p.items[i])); 147 }); 148 } 149 var note = (e.note || '').trim(); 150 var num = (e.num || '').trim(); 151 if (!labels.length && !note && !num) return; 152 nAct += labels.length; 153 if (note) nNote++; 154 nLes++; 155 lessons.push({ id: l.id, title: l.title, actions: labels, note: note, num: num, doneAt: e.doneAt || '' }); 156 }); 157 if (lessons.length) out.push({ mod: b, lessons: lessons }); 158 }); 159 return { groups: out, actions: nAct, notes: nNote, lessons: nLes }; 160 } 161 162 /* ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 163 EXPORT 164 ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 165 function buildText(fmt) { 166 var d = collect(), lines = []; 167 var today = new Date().toLocaleDateString(DK.lang); 168 var md = fmt === 'md'; 169 170 lines.push(md ? '# ' + x('f_head') : x('f_head').toUpperCase()); 171 lines.push(''); 172 if (S.user) lines.push(x('f_by') + ' : ' + S.user); 173 lines.push(x('f_on') + ' : ' + today); 174 lines.push(x('f_done') + ' : ' + d.actions + ' · ' + x('f_notes') + ' : ' + d.notes); 175 lines.push(''); 176 177 d.groups.forEach(function (g) { 178 lines.push(md ? '## ' + g.mod.emoji + ' ' + g.mod.id + '. ' + g.mod.title 179 : '== ' + g.mod.id + '. ' + plain(g.mod.title) + ' =='); 180 lines.push(''); 181 g.lessons.forEach(function (l) { 182 lines.push(md ? '### ' + plain(l.title) : '-- ' + plain(l.title)); 183 l.actions.forEach(function (a) { lines.push(md ? '- [x] ' + a : ' [x] ' + a); }); 184 if (l.num) lines.push((md ? '- **' + x('num_label') + '** : ' : ' ' + x('num_label') + ' : ') + l.num); 185 if (l.note) { 186 lines.push(''); 187 lines.push(md ? '> ' + l.note.split('\n').join('\n> ') : ' ' + l.note.split('\n').join('\n ')); 188 } 189 lines.push(''); 190 }); 191 }); 192 if (!d.groups.length) { lines.push(x('empty_b')); lines.push(''); } 193 lines.push(md ? '---' : ''); 194 lines.push('DressKool · https://formation-sooty.vercel.app'); 195 return lines.join('\n'); 196 } 197 198 function download(fmt) { 199 var text = buildText(fmt); 200 var name = 'carnet-dresskool-' + new Date().toISOString().slice(0, 10) + '.' + (fmt === 'md' ? 'md' : 'txt'); 201 try { 202 var blob = new Blob([text], { type: 'text/' + (fmt === 'md' ? 'markdown' : 'plain') + ';charset=utf-8' }); 203 var url = URL.createObjectURL(blob); 204 var a = document.createElement('a'); 205 a.href = url;
205 a.download = name; 206 document.body.appendChild(a); 207 a.click(); 208 setTimeout(function () { document.body.removeChild(a); URL.revokeObjectURL(url); }, 400); 209 if (typeof DK.ftrack === 'function') DK.ftrack('notebook_exported', { format: fmt, actions: collect().actions }); 210 } catch (e) { 211 /* Repli : un onglet avec le texte brut vaut mieux qu'un bouton mort. */ 212 try { var w = window.open('', '_blank'); if (w) { w.document.write('<pre></pre>'); w.document.querySelector('pre').textContent = text; } } 213 catch (e2) {} 214 } 215 } 216 217 /* ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 218 VUE #/carnet 219 ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 220 function view() { 221 if (typeof DK.enterApp === 'function') DK.enterApp(); 222 S.view = 'carnet'; S.cur = null; 223 if (typeof DK.sv === 'function') DK.sv(); 224 if (typeof window.renderSB === 'function') window.renderSB(); 225 226 var main = document.getElementById('main'); 227 if (!main) return; 228 var d = collect(); 229 230 var head = '<div class="dk-nb-hd"><div><h1>ð ' + esc(x('title')) + '</h1><p>' + esc(x('sub')) + '</p></div>' + 231 (d.groups.length 232 ? '<div class="dk-nb-acts"><button type="button" class="pri" id="dk-nb-md">' + esc(x('exp_md')) + 233 '</button><button type="button" id="dk-nb-txt">' + esc(x('exp_txt')) + '</button></div>' 234 : '') + '</div>'; 235 236 if (!d.groups.length) { 237 main.innerHTML = head + 238 (typeof DK.emptyHTML === 'function' 239 ? DK.emptyHTML('ð', x('empty_t'), x('empty_b'), x('empty_go'), 'dk-nb-go') 240 : '<div class="dk-empty"><h3>' + esc(x('empty_t')) + '</h3><p>' + esc(x('empty_b')) + '</p></div>'); 241 var go = document.getElementById('dk-nb-go'); 242 if (go) go.addEventListener('click', function () { window.continueCourse(); }); 243 if (typeof DK.scrollTop === 'function') DK.scrollTop(); 244 return; 245 } 246 247 var stats = '<div class="dk-nb-stats">' + 248 '<div class="dk-nb-stat"><div class="n">' + d.actions + '</div><div class="k">' + esc(x('st_actions')) + '</div></div>' + 249 '<div class="dk-nb-stat"><div class="n">' + d.notes + '</div><div class="k">' + esc(x('st_notes')) + '</div></div>' + 250 '<div class="dk-nb-stat"><div class="n">' + d.lessons + '</div><div class="k">' + esc(x('st_lessons')) + '</div></div>' + 251 '</div>'; 252 253 var body = d.groups.map(function (g) { 254 return '<div class="dk-nb-mod"><h3><span aria-hidden="true">' + g.mod.emoji + '</span>' + 255 t('block') + ' ' + g.mod.id + ' · ' + g.mod.short + '</h3>' + 256 g.lessons.map(function (l) { 257 return '<div class="dk-nb-les"><h4 data-lid="' + esc(l.id) + '" role="button" tabindex="0">' + 258 l.title + '</h4>' + 259 (l.actions.length ? '<ul>' + l.actions.map(function (a) { return '<li>' + esc(a) + '</li>'; }).join('') + '</ul>' : '') + 260 (l.num ? '<div class="dk-nb-num">' + esc(x('num_label')) + ' : ' + esc(l.num) + '</div>' : '') + 261 (l.note ? '<div class="dk-nb-note">' + esc(l.note) + '</div>' : '') + 262 '</div>'; 263 }).join('') + '</div>'; 264 }).join(''); 265 266 main.innerHTML = head + stats + body + '<div style="height:60px"></div>'; 267 268 var bmd = document.getElementById('dk-nb-md'), btxt = document.getElementById('dk-nb-txt'); 269 if (bmd) bmd.addEventListener('click', function () { download('md'); }); 270 if (btxt) btxt.addEventListener('click', function () { download('txt'); }); 271 main.querySelectorAll('.dk-nb-les h4[data-lid]').forEach(function (h) { 272 function go() { 273 if (typeof DK.navigate === 'function') DK.navigate('#/lecon/' + h.dataset.lid); 274 } 275 h.addEventListener('click', go); 276 h.addEventListener('keydown', function (e) { 277 if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); go(); } 278 }); 279 }); 280 if (typeof DK.scrollTop === 'function') DK.scrollTop(); 281 } 282 283 /* ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 284 ENCART TABLEAU DE BORD (registre DK.cards, sans toucher au markup) 285 ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 286 function cardHTML() { 287 var d = collect(); 288 return '<div class="dk-nbcard"><div class="em" aria-hidden="true">ð</div><div class="i">' + 289 '<h3>' + esc(x('card_t')) + '</h3><p>' + 290 esc(d.actions || d.notes ? x('card_p', { a: d.actions, n: d.notes, l: d.lessons }) : x('card_p0')) + 291 '</p></div><button type="button" id="dk-nbcard-btn">' + esc(x('card_open')) + '</button></div>'; 292 } 293 294 DK.cards = DK.cards || []; 295 DK.cards.push(cardHTML); 296 297 /* Le bouton est recree a chaque rendu du tableau de bord : on delegue depuis 298 le document plutot que de rebrancher un listener a chaque fois. */ 299 document.addEventListener('click', function (e) { 300 var b = e.target && e.target.closest ? e.target.closest('#dk-nbcard-btn') : null; 301 if (b && typeof DK.navigate === 'function') DK.navigate('#/carnet'); 302 }); 303 304 function renderNotebookCard() { 305 if (typeof DK.renderCards === 'function') { 306 var dash = document.getElementById('dashboard'); 307 if (dash && dash.classList.contains('visible')) DK.renderCards(); 308 } 309 } 310 311 Object.assign(DK, { 312 notebookCollect: collect, notebookText: buildText, notebookExport: download, 313 renderNotebook: view, renderNotebookCard: renderNotebookCard, notebookCardHTML: cardHTML 314 }); 315 316 /* dk-notebook.js se charge APRES dk-dashboard.js (donc apres DK.init()) : 317 registerRoute() relance le routeur si c'est justement #/carnet qui est 318 demande, et renderCards() rattrape le tableau de bord deja affiche. */ 319 if (typeof DK.registerRoute === 'function') DK.registerRoute('carnet', view); 320 renderNotebookCard(); 321})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.