Browse Source

Deduplicate footnotes

pull/14/head
Alex Kocharin 10 years ago
parent
commit
4649deb59b
  1. 16
      lib/renderer.js
  2. 4
      lib/rules_block/footnote.js
  3. 28
      lib/rules_core/footnote_tail.js
  4. 20
      lib/rules_inline/footnote_ref.js

16
lib/renderer.js

@ -278,8 +278,12 @@ rules.abbr_close = function (/* tokens, idx, options, env */) {
rules.footnote_ref = function (tokens, idx) { rules.footnote_ref = function (tokens, idx) {
var id = Number(tokens[idx].id + 1).toString(); var n = Number(tokens[idx].id + 1).toString();
return '<a href="#fn' + id + '" class="footnoteRef" id="fnref' + id + '"><sup>' + id + '</sup></a>'; var id = 'fnref' + n;
if (tokens[idx].subId > 0) {
id += ':' + tokens[idx].subId;
}
return '<a href="#fn' + n + '" class="footnoteRef" id="' + id + '"><sup>' + n + '</sup></a>';
}; };
rules.footnote_block_open = function (tokens, idx, options) { rules.footnote_block_open = function (tokens, idx, options) {
return '<div class="footnotes">\n' + (options.xhtmlOut ? '<hr />' : '<hr>') + '\n<ol>\n'; return '<div class="footnotes">\n' + (options.xhtmlOut ? '<hr />' : '<hr>') + '\n<ol>\n';
@ -295,8 +299,12 @@ rules.footnote_close = function () {
return '</li>\n'; return '</li>\n';
}; };
rules.footnote_anchor = function (tokens, idx) { rules.footnote_anchor = function (tokens, idx) {
var id = Number(tokens[idx].id + 1).toString(); var n = Number(tokens[idx].id + 1).toString();
return '<a href="#fnref' + id + '">↩</a>'; var id = 'fnref' + n;
if (tokens[idx].subId > 0) {
id += ':' + tokens[idx].subId;
}
return '<a href="#' + id + '">↩</a>';
}; };

4
lib/rules_block/footnote.js

@ -28,9 +28,9 @@ module.exports = function footnote(state, startLine, endLine, silent) {
pos++; pos++;
if (!state.env.footnotes) { state.env.footnotes = {}; } if (!state.env.footnotes) { state.env.footnotes = {}; }
if (!state.env.footnotes.available) { state.env.footnotes.available = Object.create(null); } if (!state.env.footnotes.refs) { state.env.footnotes.refs = Object.create(null); }
label = state.src.slice(start + 2, pos - 2); label = state.src.slice(start + 2, pos - 2);
state.env.footnotes.available[label] = true; state.env.footnotes.refs[label] = -1;
state.tokens.push({ state.tokens.push({
type: 'footnote_reference_open', type: 'footnote_reference_open',

28
lib/rules_core/footnote_tail.js

@ -2,7 +2,7 @@
module.exports = function footnote_block(state) { module.exports = function footnote_block(state) {
var i, l, t, list, tokens, current, currentLabel, anchor, var i, l, j, t, lastParagraph, list, tokens, current, currentLabel,
level = 0, level = 0,
insideRef = false, insideRef = false,
refTokens = Object.create(null); refTokens = Object.create(null);
@ -61,19 +61,25 @@ module.exports = function footnote_block(state) {
tokens = refTokens[list[i].label]; tokens = refTokens[list[i].label];
} }
anchor = {
type: 'footnote_anchor',
id: i,
level: level
};
state.tokens = state.tokens.concat(tokens); state.tokens = state.tokens.concat(tokens);
if (state.tokens[state.tokens.length - 1].type === 'paragraph_close') { if (state.tokens[state.tokens.length - 1].type === 'paragraph_close') {
t = state.tokens.pop(); lastParagraph = state.tokens.pop();
state.tokens.push(anchor);
state.tokens.push(t);
} else { } else {
state.tokens.push(anchor); lastParagraph = null;
}
t = list[i].count > 0 ? list[i].count : 1;
for (j = 0; j < t; j++) {
state.tokens.push({
type: 'footnote_anchor',
id: i,
subId: j,
level: level
});
}
if (lastParagraph) {
state.tokens.push(lastParagraph);
} }
state.tokens.push({ state.tokens.push({

20
lib/rules_inline/footnote_ref.js

@ -7,13 +7,14 @@ module.exports = function footnote_ref(state, silent) {
var label, var label,
pos, pos,
footnoteId, footnoteId,
footnoteSubId,
max = state.posMax, max = state.posMax,
start = state.pos; start = state.pos;
// should be at least 4 chars - "[^x]" // should be at least 4 chars - "[^x]"
if (start + 3 > max) { return false; } if (start + 3 > max) { return false; }
if (!state.env.footnotes || !state.env.footnotes.available) { return false; } if (!state.env.footnotes || !state.env.footnotes.refs) { return false; }
if (state.src.charCodeAt(start) !== 0x5B/* [ */) { return false; } if (state.src.charCodeAt(start) !== 0x5B/* [ */) { return false; }
if (state.src.charCodeAt(start + 1) !== 0x5E/* ^ */) { return false; } if (state.src.charCodeAt(start + 1) !== 0x5E/* ^ */) { return false; }
if (state.level >= state.options.maxNesting) { return false; } if (state.level >= state.options.maxNesting) { return false; }
@ -31,19 +32,28 @@ module.exports = function footnote_ref(state, silent) {
pos++; pos++;
label = state.src.slice(start + 2, pos - 1); label = state.src.slice(start + 2, pos - 1);
if (!state.env.footnotes.available[label]) { return false; } if (state.env.footnotes.refs[label] === undefined) { return false; }
if (!silent) { if (!silent) {
if (!state.env.footnotes.list) { state.env.footnotes.list = []; } if (!state.env.footnotes.list) { state.env.footnotes.list = []; }
footnoteId = state.env.footnotes.list.length;
if (state.env.footnotes.refs[label] < 0) {
footnoteId = state.env.footnotes.list.length;
state.env.footnotes.list[footnoteId] = { label: label, count: 0 };
state.env.footnotes.refs[label] = footnoteId;
} else {
footnoteId = state.env.footnotes.refs[label];
}
footnoteSubId = state.env.footnotes.list[footnoteId].count;
state.env.footnotes.list[footnoteId].count++;
state.push({ state.push({
type: 'footnote_ref', type: 'footnote_ref',
id: footnoteId, id: footnoteId,
subId: footnoteSubId,
level: state.level level: state.level
}); });
state.env.footnotes.list[footnoteId] = { label: label };
} }
state.pos = pos; state.pos = pos;

Loading…
Cancel
Save