markdown-it-footnote

douban markdown

بۇ قوليازمىنى بىۋاسىتە قاچىلاشقا بولمايدۇ. بۇ باشقا قوليازمىلارنىڭ ئىشلىتىشى ئۈچۈن تەمىنلەنگەن ئامبار بولۇپ، ئىشلىتىش ئۈچۈن مېتا كۆرسەتمىسىگە قىستۇرىدىغان كود: // @require https://update.greatest.deepsurf.us/scripts/21647/137863/markdown-it-footnote.js

  1. // ==UserScript==
  2. // @name markdown-it-footnote
  3. // @namespace https://github.com//markdown-it/markdown-it-footnote
  4. // @version 0.1
  5. // @description douban markdown
  6. // @author haidao
  7. // @grant none
  8. // ==/UserScript==
  9.  
  10. /*! markdown-it-footnote 3.0.0 https://github.com//markdown-it/markdown-it-footnote @license MIT */
  11. (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.markdownitFootnote = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  12. // Process footnotes
  13. //
  14. 'use strict';
  15.  
  16. ////////////////////////////////////////////////////////////////////////////////
  17. // Renderer partials
  18.  
  19. function render_footnote_anchor_name(tokens, idx, options, env/*, slf*/) {
  20. var n = Number(tokens[idx].meta.id + 1).toString();
  21.  
  22. if (tokens[idx].meta.subId > 0) {
  23. n += ':' + tokens[idx].meta.subId;
  24. }
  25.  
  26. var prefix = '';
  27.  
  28. if (typeof env.docId === 'string') {
  29. prefix = '-' + env.docId + '-';
  30. }
  31.  
  32. return prefix + n;
  33. }
  34.  
  35. function render_footnote_caption(tokens, idx/*, options, env, slf*/) {
  36. var n = Number(tokens[idx].meta.id + 1).toString();
  37.  
  38. if (tokens[idx].meta.subId > 0) {
  39. n += ':' + tokens[idx].meta.subId;
  40. }
  41.  
  42. return '[' + n + ']';
  43. }
  44.  
  45. function render_footnote_ref(tokens, idx, options, env, slf) {
  46. var id = slf.rules.footnote_anchor_name(tokens, idx, options, env, slf);
  47. var caption = slf.rules.footnote_caption(tokens, idx, options, env, slf);
  48.  
  49. return '<sup class="footnote-ref"><a href="#fn' + id + '" id="fnref' + id + '">' + caption + '</a></sup>';
  50. }
  51.  
  52. function render_footnote_block_open(tokens, idx, options) {
  53. return (options.xhtmlOut ? '<hr class="footnotes-sep" />\n' : '<hr class="footnotes-sep">\n') +
  54. '<section class="footnotes">\n' +
  55. '<ol class="footnotes-list">\n';
  56. }
  57.  
  58. function render_footnote_block_close() {
  59. return '</ol>\n</section>\n';
  60. }
  61.  
  62. function render_footnote_open(tokens, idx, options, env, slf) {
  63. var id = slf.rules.footnote_anchor_name(tokens, idx, options, env, slf);
  64.  
  65. return '<li id="fn' + id + '" class="footnote-item">';
  66. }
  67.  
  68. function render_footnote_close() {
  69. return '</li>\n';
  70. }
  71.  
  72. function render_footnote_anchor(tokens, idx, options, env, slf) {
  73. var id = slf.rules.footnote_anchor_name(tokens, idx, options, env, slf);
  74.  
  75. /* ↩ with escape code to prevent display as Apple Emoji on iOS */
  76. return ' <a href="#fnref' + id + '" class="footnote-backref">\u21a9\uFE0E</a>';
  77. }
  78.  
  79.  
  80. module.exports = function footnote_plugin(md) {
  81. var parseLinkLabel = md.helpers.parseLinkLabel,
  82. isSpace = md.utils.isSpace;
  83.  
  84. md.renderer.rules.footnote_ref = render_footnote_ref;
  85. md.renderer.rules.footnote_block_open = render_footnote_block_open;
  86. md.renderer.rules.footnote_block_close = render_footnote_block_close;
  87. md.renderer.rules.footnote_open = render_footnote_open;
  88. md.renderer.rules.footnote_close = render_footnote_close;
  89. md.renderer.rules.footnote_anchor = render_footnote_anchor;
  90.  
  91. // helpers (only used in other rules, no tokens are attached to those)
  92. md.renderer.rules.footnote_caption = render_footnote_caption;
  93. md.renderer.rules.footnote_anchor_name = render_footnote_anchor_name;
  94.  
  95. // Process footnote block definition
  96. function footnote_def(state, startLine, endLine, silent) {
  97. var oldBMark, oldTShift, oldSCount, oldParentType, pos, label, token,
  98. initial, offset, ch, posAfterColon,
  99. start = state.bMarks[startLine] + state.tShift[startLine],
  100. max = state.eMarks[startLine];
  101.  
  102. // line should be at least 5 chars - "[^x]:"
  103. if (start + 4 > max) { return false; }
  104.  
  105. if (state.src.charCodeAt(start) !== 0x5B/* [ */) { return false; }
  106. if (state.src.charCodeAt(start + 1) !== 0x5E/* ^ */) { return false; }
  107.  
  108. for (pos = start + 2; pos < max; pos++) {
  109. if (state.src.charCodeAt(pos) === 0x20) { return false; }
  110. if (state.src.charCodeAt(pos) === 0x5D /* ] */) {
  111. break;
  112. }
  113. }
  114.  
  115. if (pos === start + 2) { return false; } // no empty footnote labels
  116. if (pos + 1 >= max || state.src.charCodeAt(++pos) !== 0x3A /* : */) { return false; }
  117. if (silent) { return true; }
  118. pos++;
  119.  
  120. if (!state.env.footnotes) { state.env.footnotes = {}; }
  121. if (!state.env.footnotes.refs) { state.env.footnotes.refs = {}; }
  122. label = state.src.slice(start + 2, pos - 2);
  123. state.env.footnotes.refs[':' + label] = -1;
  124.  
  125. token = new state.Token('footnote_reference_open', '', 1);
  126. token.meta = { label: label };
  127. token.level = state.level++;
  128. state.tokens.push(token);
  129.  
  130. oldBMark = state.bMarks[startLine];
  131. oldTShift = state.tShift[startLine];
  132. oldSCount = state.sCount[startLine];
  133. oldParentType = state.parentType;
  134.  
  135. posAfterColon = pos;
  136. initial = offset = state.sCount[startLine] + pos - (state.bMarks[startLine] + state.tShift[startLine]);
  137.  
  138. while (pos < max) {
  139. ch = state.src.charCodeAt(pos);
  140.  
  141. if (isSpace(ch)) {
  142. if (ch === 0x09) {
  143. offset += 4 - offset % 4;
  144. } else {
  145. offset++;
  146. }
  147. } else {
  148. break;
  149. }
  150.  
  151. pos++;
  152. }
  153.  
  154. state.tShift[startLine] = pos - posAfterColon;
  155. state.sCount[startLine] = offset - initial;
  156.  
  157. state.bMarks[startLine] = posAfterColon;
  158. state.blkIndent += 4;
  159. state.parentType = 'footnote';
  160.  
  161. if (state.sCount[startLine] < state.blkIndent) {
  162. state.sCount[startLine] += state.blkIndent;
  163. }
  164.  
  165. state.md.block.tokenize(state, startLine, endLine, true);
  166.  
  167. state.parentType = oldParentType;
  168. state.blkIndent -= 4;
  169. state.tShift[startLine] = oldTShift;
  170. state.sCount[startLine] = oldSCount;
  171. state.bMarks[startLine] = oldBMark;
  172.  
  173. token = new state.Token('footnote_reference_close', '', -1);
  174. token.level = --state.level;
  175. state.tokens.push(token);
  176.  
  177. return true;
  178. }
  179.  
  180. // Process inline footnotes (^[...])
  181. function footnote_inline(state, silent) {
  182. var labelStart,
  183. labelEnd,
  184. footnoteId,
  185. token,
  186. tokens,
  187. max = state.posMax,
  188. start = state.pos;
  189.  
  190. if (start + 2 >= max) { return false; }
  191. if (state.src.charCodeAt(start) !== 0x5E/* ^ */) { return false; }
  192. if (state.src.charCodeAt(start + 1) !== 0x5B/* [ */) { return false; }
  193.  
  194. labelStart = start + 2;
  195. labelEnd = parseLinkLabel(state, start + 1);
  196.  
  197. // parser failed to find ']', so it's not a valid note
  198. if (labelEnd < 0) { return false; }
  199.  
  200. // We found the end of the link, and know for a fact it's a valid link;
  201. // so all that's left to do is to call tokenizer.
  202. //
  203. if (!silent) {
  204. if (!state.env.footnotes) { state.env.footnotes = {}; }
  205. if (!state.env.footnotes.list) { state.env.footnotes.list = []; }
  206. footnoteId = state.env.footnotes.list.length;
  207.  
  208. state.md.inline.parse(
  209. state.src.slice(labelStart, labelEnd),
  210. state.md,
  211. state.env,
  212. tokens = []
  213. );
  214.  
  215. token = state.push('footnote_ref', '', 0);
  216. token.meta = { id: footnoteId };
  217.  
  218. state.env.footnotes.list[footnoteId] = { tokens: tokens };
  219. }
  220.  
  221. state.pos = labelEnd + 1;
  222. state.posMax = max;
  223. return true;
  224. }
  225.  
  226. // Process footnote references ([^...])
  227. function footnote_ref(state, silent) {
  228. var label,
  229. pos,
  230. footnoteId,
  231. footnoteSubId,
  232. token,
  233. max = state.posMax,
  234. start = state.pos;
  235.  
  236. // should be at least 4 chars - "[^x]"
  237. if (start + 3 > max) { return false; }
  238.  
  239. if (!state.env.footnotes || !state.env.footnotes.refs) { return false; }
  240. if (state.src.charCodeAt(start) !== 0x5B/* [ */) { return false; }
  241. if (state.src.charCodeAt(start + 1) !== 0x5E/* ^ */) { return false; }
  242.  
  243. for (pos = start + 2; pos < max; pos++) {
  244. if (state.src.charCodeAt(pos) === 0x20) { return false; }
  245. if (state.src.charCodeAt(pos) === 0x0A) { return false; }
  246. if (state.src.charCodeAt(pos) === 0x5D /* ] */) {
  247. break;
  248. }
  249. }
  250.  
  251. if (pos === start + 2) { return false; } // no empty footnote labels
  252. if (pos >= max) { return false; }
  253. pos++;
  254.  
  255. label = state.src.slice(start + 2, pos - 1);
  256. if (typeof state.env.footnotes.refs[':' + label] === 'undefined') { return false; }
  257.  
  258. if (!silent) {
  259. if (!state.env.footnotes.list) { state.env.footnotes.list = []; }
  260.  
  261. if (state.env.footnotes.refs[':' + label] < 0) {
  262. footnoteId = state.env.footnotes.list.length;
  263. state.env.footnotes.list[footnoteId] = { label: label, count: 0 };
  264. state.env.footnotes.refs[':' + label] = footnoteId;
  265. } else {
  266. footnoteId = state.env.footnotes.refs[':' + label];
  267. }
  268.  
  269. footnoteSubId = state.env.footnotes.list[footnoteId].count;
  270. state.env.footnotes.list[footnoteId].count++;
  271.  
  272. token = state.push('footnote_ref', '', 0);
  273. token.meta = { id: footnoteId, subId: footnoteSubId, label: label };
  274. }
  275.  
  276. state.pos = pos;
  277. state.posMax = max;
  278. return true;
  279. }
  280.  
  281. // Glue footnote tokens to end of token stream
  282. function footnote_tail(state) {
  283. var i, l, j, t, lastParagraph, list, token, tokens, current, currentLabel,
  284. insideRef = false,
  285. refTokens = {};
  286.  
  287. if (!state.env.footnotes) { return; }
  288.  
  289. state.tokens = state.tokens.filter(function (tok) {
  290. if (tok.type === 'footnote_reference_open') {
  291. insideRef = true;
  292. current = [];
  293. currentLabel = tok.meta.label;
  294. return false;
  295. }
  296. if (tok.type === 'footnote_reference_close') {
  297. insideRef = false;
  298. // prepend ':' to avoid conflict with Object.prototype members
  299. refTokens[':' + currentLabel] = current;
  300. return false;
  301. }
  302. if (insideRef) { current.push(tok); }
  303. return !insideRef;
  304. });
  305.  
  306. if (!state.env.footnotes.list) { return; }
  307. list = state.env.footnotes.list;
  308.  
  309. token = new state.Token('footnote_block_open', '', 1);
  310. state.tokens.push(token);
  311.  
  312. for (i = 0, l = list.length; i < l; i++) {
  313. token = new state.Token('footnote_open', '', 1);
  314. token.meta = { id: i, label: list[i].label };
  315. state.tokens.push(token);
  316.  
  317. if (list[i].tokens) {
  318. tokens = [];
  319.  
  320. token = new state.Token('paragraph_open', 'p', 1);
  321. token.block = true;
  322. tokens.push(token);
  323.  
  324. token = new state.Token('inline', '', 0);
  325. token.children = list[i].tokens;
  326. token.content = '';
  327. tokens.push(token);
  328.  
  329. token = new state.Token('paragraph_close', 'p', -1);
  330. token.block = true;
  331. tokens.push(token);
  332.  
  333. } else if (list[i].label) {
  334. tokens = refTokens[':' + list[i].label];
  335. }
  336.  
  337. state.tokens = state.tokens.concat(tokens);
  338. if (state.tokens[state.tokens.length - 1].type === 'paragraph_close') {
  339. lastParagraph = state.tokens.pop();
  340. } else {
  341. lastParagraph = null;
  342. }
  343.  
  344. t = list[i].count > 0 ? list[i].count : 1;
  345. for (j = 0; j < t; j++) {
  346. token = new state.Token('footnote_anchor', '', 0);
  347. token.meta = { id: i, subId: j, label: list[i].label };
  348. state.tokens.push(token);
  349. }
  350.  
  351. if (lastParagraph) {
  352. state.tokens.push(lastParagraph);
  353. }
  354.  
  355. token = new state.Token('footnote_close', '', -1);
  356. state.tokens.push(token);
  357. }
  358.  
  359. token = new state.Token('footnote_block_close', '', -1);
  360. state.tokens.push(token);
  361. }
  362.  
  363. md.block.ruler.before('reference', 'footnote_def', footnote_def, { alt: [ 'paragraph', 'reference' ] });
  364. md.inline.ruler.after('image', 'footnote_inline', footnote_inline);
  365. md.inline.ruler.after('footnote_inline', 'footnote_ref', footnote_ref);
  366. md.core.ruler.after('inline', 'footnote_tail', footnote_tail);
  367. };
  368.  
  369. },{}]},{},[1])(1)
  370. });