(markdown = "", fullMarkdown = markdown)
| 142 | } |
| 143 | |
| 144 | function prepareFootnotes(markdown = "", fullMarkdown = markdown) { |
| 145 | const definitions = []; |
| 146 | const body = []; |
| 147 | for (const line of String(fullMarkdown || "").split("\n")) { |
| 148 | const match = line.match(FOOTNOTE_DEF_RE); |
| 149 | if (match) { |
| 150 | definitions.push({ id: match[1], text: match[2] }); |
| 151 | } |
| 152 | } |
| 153 | for (const line of String(markdown || "").split("\n")) { |
| 154 | if (line.match(FOOTNOTE_DEF_RE)) { |
| 155 | continue; |
| 156 | } |
| 157 | body.push(line); |
| 158 | } |
| 159 | if (!definitions.length) return markdown; |
| 160 | |
| 161 | const counts = new Map(); |
| 162 | let prepared = body.join("\n").replace(/\[\^([^\]]+)\]/g, (_all, id) => { |
| 163 | const number = definitions.findIndex((item) => item.id === id) + 1; |
| 164 | if (number <= 0) return `[^${id}]`; |
| 165 | const count = (counts.get(id) || 0) + 1; |
| 166 | counts.set(id, count); |
| 167 | const safeId = footnoteId(id); |
| 168 | return `<sup class="editor-footnote-ref"><a id="fnref-${safeId}-${count}" href="#fn-${safeId}">${number}</a></sup>`; |
| 169 | }); |
| 170 | |
| 171 | prepared += "\n\n<section class=\"editor-footnotes\" aria-label=\"Footnotes\">\n<ol>\n"; |
| 172 | for (const definition of definitions) { |
| 173 | const safeId = footnoteId(definition.id); |
| 174 | prepared += `<li id="fn-${safeId}">${escapeHtml(definition.text)} <a class="editor-footnote-backref" href="#fnref-${safeId}-1">Back</a></li>\n`; |
| 175 | } |
| 176 | prepared += "</ol>\n</section>"; |
| 177 | return prepared; |
| 178 | } |
| 179 | |
| 180 | function footnoteId(id = "") { |
| 181 | return String(id || "") |
no test coverage detected