strikethrough.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // ~~strike through~~
  2. //
  3. 'use strict';
  4. // Insert each marker as a separate text token, and add it to delimiter list
  5. //
  6. module.exports.tokenize = function strikethrough(state, silent) {
  7. var i, scanned, token, len, ch,
  8. start = state.pos,
  9. marker = state.src.charCodeAt(start);
  10. if (silent) { return false; }
  11. if (marker !== 0x7E/* ~ */) { return false; }
  12. scanned = state.scanDelims(state.pos, true);
  13. len = scanned.length;
  14. ch = String.fromCharCode(marker);
  15. if (len < 2) { return false; }
  16. if (len % 2) {
  17. token = state.push('text', '', 0);
  18. token.content = ch;
  19. len--;
  20. }
  21. for (i = 0; i < len; i += 2) {
  22. token = state.push('text', '', 0);
  23. token.content = ch + ch;
  24. state.delimiters.push({
  25. marker: marker,
  26. length: 0, // disable "rule of 3" length checks meant for emphasis
  27. token: state.tokens.length - 1,
  28. end: -1,
  29. open: scanned.can_open,
  30. close: scanned.can_close
  31. });
  32. }
  33. state.pos += scanned.length;
  34. return true;
  35. };
  36. function postProcess(state, delimiters) {
  37. var i, j,
  38. startDelim,
  39. endDelim,
  40. token,
  41. loneMarkers = [],
  42. max = delimiters.length;
  43. for (i = 0; i < max; i++) {
  44. startDelim = delimiters[i];
  45. if (startDelim.marker !== 0x7E/* ~ */) {
  46. continue;
  47. }
  48. if (startDelim.end === -1) {
  49. continue;
  50. }
  51. endDelim = delimiters[startDelim.end];
  52. token = state.tokens[startDelim.token];
  53. token.type = 's_open';
  54. token.tag = 's';
  55. token.nesting = 1;
  56. token.markup = '~~';
  57. token.content = '';
  58. token = state.tokens[endDelim.token];
  59. token.type = 's_close';
  60. token.tag = 's';
  61. token.nesting = -1;
  62. token.markup = '~~';
  63. token.content = '';
  64. if (state.tokens[endDelim.token - 1].type === 'text' &&
  65. state.tokens[endDelim.token - 1].content === '~') {
  66. loneMarkers.push(endDelim.token - 1);
  67. }
  68. }
  69. // If a marker sequence has an odd number of characters, it's splitted
  70. // like this: `~~~~~` -> `~` + `~~` + `~~`, leaving one marker at the
  71. // start of the sequence.
  72. //
  73. // So, we have to move all those markers after subsequent s_close tags.
  74. //
  75. while (loneMarkers.length) {
  76. i = loneMarkers.pop();
  77. j = i + 1;
  78. while (j < state.tokens.length && state.tokens[j].type === 's_close') {
  79. j++;
  80. }
  81. j--;
  82. if (i !== j) {
  83. token = state.tokens[j];
  84. state.tokens[j] = state.tokens[i];
  85. state.tokens[i] = token;
  86. }
  87. }
  88. }
  89. // Walk through delimiter list and replace text tokens with tags
  90. //
  91. module.exports.postProcess = function strikethrough(state) {
  92. var curr,
  93. tokens_meta = state.tokens_meta,
  94. max = state.tokens_meta.length;
  95. postProcess(state, state.delimiters);
  96. for (curr = 0; curr < max; curr++) {
  97. if (tokens_meta[curr] && tokens_meta[curr].delimiters) {
  98. postProcess(state, tokens_meta[curr].delimiters);
  99. }
  100. }
  101. };