markdown-it-mathjax.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. ;(function (root, factory) {
  2. if (typeof exports === 'object') {
  3. module.exports = factory()
  4. } else {
  5. root.markdownitMathjax = factory()
  6. }
  7. })(this, function () {
  8. function math (state, silent) {
  9. var startMathPos = state.pos
  10. if (state.src.charCodeAt(startMathPos) !== 0x5C /* \ */) {
  11. return false
  12. }
  13. var match = state.src.slice(++startMathPos).match(/^(?:\\\[|\\\(|begin\{([^}]*)\})/)
  14. if (!match) {
  15. return false
  16. }
  17. startMathPos += match[0].length
  18. var type, endMarker, includeMarkers
  19. if (match[0] === '\\[') {
  20. type = 'display_math'
  21. endMarker = '\\\\]'
  22. } else if (match[0] === '\\(') {
  23. type = 'inline_math'
  24. endMarker = '\\\\)'
  25. } else if (match[1]) {
  26. type = 'math'
  27. endMarker = '\\end{' + match[1] + '}'
  28. includeMarkers = true
  29. }
  30. var endMarkerPos = state.src.indexOf(endMarker, startMathPos)
  31. if (endMarkerPos === -1) {
  32. return false
  33. }
  34. var nextPos = endMarkerPos + endMarker.length
  35. if (!silent) {
  36. var token = state.push(type, '', 0)
  37. token.content = includeMarkers
  38. ? state.src.slice(state.pos, nextPos)
  39. : state.src.slice(startMathPos, endMarkerPos)
  40. }
  41. state.pos = nextPos
  42. return true
  43. }
  44. function texMath (state, silent) {
  45. var startMathPos = state.pos
  46. if (state.src.charCodeAt(startMathPos) !== 0x24 /* $ */) {
  47. return false
  48. }
  49. // Parse tex math according to http://pandoc.org/README.html#math
  50. var endMarker = '$'
  51. var afterStartMarker = state.src.charCodeAt(++startMathPos)
  52. if (afterStartMarker === 0x24 /* $ */) {
  53. endMarker = '$$'
  54. if (state.src.charCodeAt(++startMathPos) === 0x24 /* $ */) {
  55. // 3 markers are too much
  56. return false
  57. }
  58. } else {
  59. // Skip if opening $ is succeeded by a space character
  60. if (afterStartMarker === 0x20 /* space */ || afterStartMarker === 0x09 /* \t */ || afterStartMarker === 0x0a /* \n */) {
  61. return false
  62. }
  63. }
  64. var endMarkerPos = state.src.indexOf(endMarker, startMathPos)
  65. if (endMarkerPos === -1) {
  66. return false
  67. }
  68. if (state.src.charCodeAt(endMarkerPos - 1) === 0x5C /* \ */) {
  69. return false
  70. }
  71. var nextPos = endMarkerPos + endMarker.length
  72. if (endMarker.length === 1) {
  73. // Skip if $ is preceded by a space character
  74. var beforeEndMarker = state.src.charCodeAt(endMarkerPos - 1)
  75. if (beforeEndMarker === 0x20 /* space */ || beforeEndMarker === 0x09 /* \t */ || beforeEndMarker === 0x0a /* \n */) {
  76. return false
  77. }
  78. // Skip if closing $ is succeeded by a digit (eg $5 $10 ...)
  79. var suffix = state.src.charCodeAt(nextPos)
  80. if (suffix >= 0x30 && suffix < 0x3A) {
  81. return false
  82. }
  83. }
  84. if (!silent) {
  85. var token = state.push(endMarker.length === 1 ? 'inline_math' : 'display_math', '', 0)
  86. token.content = state.src.slice(startMathPos, endMarkerPos)
  87. }
  88. state.pos = nextPos
  89. return true
  90. }
  91. function escapeHtml (html) {
  92. return html.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ')
  93. }
  94. function extend (options, defaults) {
  95. return Object.keys(defaults).reduce(function (result, key) {
  96. if (result[key] === undefined) {
  97. result[key] = defaults[key]
  98. }
  99. return result
  100. }, options)
  101. }
  102. var mapping = {
  103. 'math': 'Math',
  104. 'inline_math': 'InlineMath',
  105. 'display_math': 'DisplayMath'
  106. }
  107. return function (options) {
  108. var defaults = {
  109. beforeMath: '',
  110. afterMath: '',
  111. beforeInlineMath: '\\(',
  112. afterInlineMath: '\\)',
  113. beforeDisplayMath: '\\[',
  114. afterDisplayMath: '\\]'
  115. }
  116. options = extend(options || {}, defaults)
  117. return function (md) {
  118. md.inline.ruler.before('escape', 'math', math)
  119. md.inline.ruler.push('texMath', texMath)
  120. Object.keys(mapping).forEach(function (key) {
  121. var before = options['before' + mapping[key]]
  122. var after = options['after' + mapping[key]]
  123. md.renderer.rules[key] = function (tokens, idx) {
  124. return before + escapeHtml(tokens[idx].content) + after
  125. }
  126. })
  127. }
  128. }
  129. })