Skip to content

Commit 4fa6a6e

Browse files
committed
Fixed - DOM text reinterpreted as HTML #5
1 parent 55037fb commit 4fa6a6e

2 files changed

Lines changed: 102 additions & 26 deletions

File tree

public/cheatsheets/aip-c01-glossary.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,10 @@
705705
render();
706706
}
707707

708+
function htmlToText(html) {
709+
return new DOMParser().parseFromString(html, 'text/html').body.textContent || '';
710+
}
711+
708712
function buildCards() {
709713
const query = document.getElementById('searchInput').value.trim().toLowerCase();
710714
const main = document.getElementById('main');
@@ -721,7 +725,7 @@
721725
terms = terms.filter(t =>
722726
t.name.toLowerCase().includes(query) ||
723727
(t.abbr && t.abbr.toLowerCase().includes(query)) ||
724-
t.def.toLowerCase().replace(/<[^>]+>/g,'').includes(query) ||
728+
htmlToText(t.def).toLowerCase().includes(query) ||
725729
(t.example && t.example.toLowerCase().includes(query))
726730
);
727731
}

public/cheatsheets/aip-c01-scorecard.html

Lines changed: 97 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -301,36 +301,108 @@
301301

302302
function renderTable() {
303303
const wrap = document.getElementById('tableWrap');
304+
wrap.replaceChildren();
304305
if (!entries.length) {
305-
wrap.innerHTML = `<div class="empty-state"><div class="em-icon">📋</div><p>No scores logged yet.<br>Enter your first practice test score above to start tracking.<br><span>Tip: log at least 2 scores to see trends and domain weaknesses.</span></p></div>`;
306+
const emptyState = document.createElement('div');
307+
emptyState.className = 'empty-state';
308+
309+
const icon = document.createElement('div');
310+
icon.className = 'em-icon';
311+
icon.textContent = '📋';
312+
313+
const copy = document.createElement('p');
314+
copy.append('No scores logged yet.');
315+
copy.append(document.createElement('br'));
316+
copy.append('Enter your first practice test score above to start tracking.');
317+
copy.append(document.createElement('br'));
318+
319+
const tip = document.createElement('span');
320+
tip.textContent = 'Tip: log at least 2 scores to see trends and domain weaknesses.';
321+
copy.append(tip);
322+
323+
emptyState.append(icon, copy);
324+
wrap.appendChild(emptyState);
306325
return;
307326
}
327+
308328
const sorted = [...entries].sort((a,b) => b.id - a.id);
309-
let rows = sorted.map(e => {
310-
const s = e.score;
311-
const tag = !s ? '' : s >= 750 ? '<span class="tag tag-pass">PASS</span>' : s >= 700 ? '<span class="tag tag-close">CLOSE</span>' : '<span class="tag tag-fail">FAIL</span>';
312-
const domCells = e.d.map((v,i) => `<td style="color:${DOMAIN_META[i].color}">${v !== null ? v+'%' : '—'}</td>`).join('');
313-
return `<tr>
314-
<td style="color:var(--dim)">${e.date}</td>
315-
<td>${e.source}</td>
316-
<td class="score-cell">${s ? s + ' ' + tag : '—'}</td>
317-
${domCells}
318-
<td><button class="del-btn" onclick="deleteEntry(${e.id})">✕</button></td>
319-
</tr>`;
320-
}).join('');
329+
const table = document.createElement('table');
330+
const thead = document.createElement('thead');
331+
const headRow = document.createElement('tr');
332+
const headers = [
333+
{ label: 'Date' },
334+
{ label: 'Source' },
335+
{ label: 'Score' },
336+
{ label: 'D1', weight: '31%' },
337+
{ label: 'D2', weight: '26%' },
338+
{ label: 'D3', weight: '20%' },
339+
{ label: 'D4', weight: '12%' },
340+
{ label: 'D5', weight: '11%' },
341+
{ label: '' },
342+
];
343+
344+
headers.forEach(({ label, weight }) => {
345+
const th = document.createElement('th');
346+
th.append(label);
347+
if (weight) {
348+
const small = document.createElement('small');
349+
small.style.opacity = '.5';
350+
small.textContent = ` ${weight}`;
351+
th.appendChild(small);
352+
}
353+
headRow.appendChild(th);
354+
});
355+
356+
thead.appendChild(headRow);
357+
table.appendChild(thead);
358+
359+
const tbody = document.createElement('tbody');
360+
sorted.forEach(e => {
361+
const row = document.createElement('tr');
362+
363+
const dateCell = document.createElement('td');
364+
dateCell.style.color = 'var(--dim)';
365+
dateCell.textContent = e.date;
366+
row.appendChild(dateCell);
367+
368+
const sourceCell = document.createElement('td');
369+
sourceCell.textContent = e.source;
370+
row.appendChild(sourceCell);
371+
372+
const scoreCell = document.createElement('td');
373+
scoreCell.className = 'score-cell';
374+
if (e.score) {
375+
scoreCell.append(`${e.score} `);
376+
const tag = document.createElement('span');
377+
tag.className = e.score >= 750 ? 'tag tag-pass' : e.score >= 700 ? 'tag tag-close' : 'tag tag-fail';
378+
tag.textContent = e.score >= 750 ? 'PASS' : e.score >= 700 ? 'CLOSE' : 'FAIL';
379+
scoreCell.appendChild(tag);
380+
} else {
381+
scoreCell.textContent = '—';
382+
}
383+
row.appendChild(scoreCell);
384+
385+
e.d.forEach((v, i) => {
386+
const domainCell = document.createElement('td');
387+
domainCell.style.color = DOMAIN_META[i].color;
388+
domainCell.textContent = v !== null ? `${v}%` : '—';
389+
row.appendChild(domainCell);
390+
});
391+
392+
const actionCell = document.createElement('td');
393+
const deleteButton = document.createElement('button');
394+
deleteButton.className = 'del-btn';
395+
deleteButton.type = 'button';
396+
deleteButton.textContent = '✕';
397+
deleteButton.addEventListener('click', () => deleteEntry(e.id));
398+
actionCell.appendChild(deleteButton);
399+
row.appendChild(actionCell);
400+
401+
tbody.appendChild(row);
402+
});
321403

322-
wrap.innerHTML = `<table>
323-
<thead><tr>
324-
<th>Date</th><th>Source</th><th>Score</th>
325-
<th>D1<small style="opacity:.5"> 31%</small></th>
326-
<th>D2<small style="opacity:.5"> 26%</small></th>
327-
<th>D3<small style="opacity:.5"> 20%</small></th>
328-
<th>D4<small style="opacity:.5"> 12%</small></th>
329-
<th>D5<small style="opacity:.5"> 11%</small></th>
330-
<th></th>
331-
</tr></thead>
332-
<tbody>${rows}</tbody>
333-
</table>`;
404+
table.appendChild(tbody);
405+
wrap.appendChild(table);
334406
}
335407

336408
function renderAnalysis() {

0 commit comments

Comments
 (0)