Skip to content

Commit b400610

Browse files
DOC-5922 changed JS file to avoid XSS risk
1 parent dedcff9 commit b400610

File tree

1 file changed

+41
-11
lines changed

1 file changed

+41
-11
lines changed

static/js/checklist.js

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,47 @@ function createChecklistFromMarkdown(markdown, formId, preElement) {
8080

8181
// Add counters
8282
const countersDiv = document.createElement('div');
83-
countersDiv.innerHTML = `
84-
<label for="${formId}-gcount">&#9989; = </label>
85-
<output name="gcount" id="${formId}-gcount">0</output>/<output id="${formId}-gtotal">0</output>,
86-
<label for="${formId}-rcount">&#x274C; = </label>
87-
<output name="rcount" id="${formId}-rcount">0</output>/<output id="${formId}-rtotal">0</output>,
88-
<label for="${formId}-acount">&#x1F50D; = </label>
89-
<output name="acount" id="${formId}-acount">0</output>/<output id="${formId}-atotal">0</output>
90-
<br/>
91-
(<label for="${formId}-xcount">&#x2205; = </label>
92-
<output name="xcount" id="${formId}-xcount">0</output>)
93-
`;
83+
84+
// Create counter elements safely without innerHTML
85+
const createCounterLabel = (emoji, countId, totalId, isDisabled = false) => {
86+
const label = document.createElement('label');
87+
label.htmlFor = countId;
88+
label.textContent = emoji + ' = ';
89+
90+
const countOutput = document.createElement('output');
91+
countOutput.name = countId.replace(formId + '-', '');
92+
countOutput.id = countId;
93+
countOutput.textContent = '0';
94+
95+
const fragment = document.createDocumentFragment();
96+
fragment.appendChild(label);
97+
fragment.appendChild(countOutput);
98+
99+
if (!isDisabled) {
100+
fragment.appendChild(document.createTextNode('/'));
101+
const totalOutput = document.createElement('output');
102+
totalOutput.id = totalId;
103+
totalOutput.textContent = '0';
104+
fragment.appendChild(totalOutput);
105+
fragment.appendChild(document.createTextNode(', '));
106+
} else {
107+
fragment.appendChild(document.createTextNode(')'));
108+
}
109+
110+
return fragment;
111+
};
112+
113+
countersDiv.appendChild(createCounterLabel('✅', formId + '-gcount', formId + '-gtotal'));
114+
countersDiv.appendChild(createCounterLabel('❌', formId + '-rcount', formId + '-rtotal'));
115+
countersDiv.appendChild(createCounterLabel('🔍', formId + '-acount', formId + '-atotal'));
116+
117+
const brElement = document.createElement('br');
118+
countersDiv.appendChild(brElement);
119+
120+
const openParen = document.createTextNode('(');
121+
countersDiv.appendChild(openParen);
122+
countersDiv.appendChild(createCounterLabel('∅', formId + '-xcount', '', true));
123+
94124
form.appendChild(countersDiv);
95125

96126
// Replace the entire <pre> element with the interactive form

0 commit comments

Comments
 (0)