GrowiRenderer.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import MarkdownIt from 'markdown-it';
  2. import * as entities from 'entities';
  3. import Linker from './PreProcessor/Linker';
  4. import CsvToTable from './PreProcessor/CsvToTable';
  5. import XssFilter from './PreProcessor/XssFilter';
  6. import Template from './LangProcessor/Template';
  7. import CommonPluginsConfigurer from './markdown-it/common-plugins';
  8. import EmojiConfigurer from './markdown-it/emoji';
  9. import HeaderLineNumberConfigurer from './markdown-it/header-line-number';
  10. import HeaderConfigurer from './markdown-it/header';
  11. import MathJaxConfigurer from './markdown-it/mathjax';
  12. import PlantUMLConfigurer from './markdown-it/plantuml';
  13. import TableConfigurer from './markdown-it/table';
  14. import TocAndAnchorConfigurer from './markdown-it/toc-and-anchor';
  15. export default class GrowiRenderer {
  16. constructor(crowi) {
  17. this.crowi = crowi;
  18. this.preProcessors = [
  19. new Linker(crowi),
  20. new CsvToTable(crowi),
  21. new XssFilter(crowi),
  22. ];
  23. this.postProcessors = [
  24. ];
  25. this.markdownItConfigurers = [
  26. new CommonPluginsConfigurer(crowi),
  27. new TocAndAnchorConfigurer(crowi),
  28. new HeaderConfigurer(crowi),
  29. new HeaderLineNumberConfigurer(crowi),
  30. new TableConfigurer(crowi),
  31. new EmojiConfigurer(crowi),
  32. new MathJaxConfigurer(crowi),
  33. new PlantUMLConfigurer(crowi),
  34. ];
  35. this.langProcessors = {
  36. 'template': new Template(crowi),
  37. };
  38. this.configure = this.configure.bind(this);
  39. this.configurePlugins = this.configurePlugins.bind(this);
  40. this.process = this.process.bind(this);
  41. this.codeRenderer = this.codeRenderer.bind(this);
  42. this.md = new MarkdownIt();
  43. this.configure(this.crowi.getConfig());
  44. this.configurePlugins(this.crowi.getConfig());
  45. }
  46. /**
  47. * configure markdown-it
  48. * @param {any} config
  49. */
  50. configure(config) {
  51. this.md.set({
  52. html: true,
  53. linkify: true,
  54. breaks: config.isEnabledLineBreaks,
  55. highlight: this.codeRenderer,
  56. });
  57. }
  58. /**
  59. * configure markdown-it plugins
  60. * @param {any} config
  61. */
  62. configurePlugins(config) {
  63. this.markdownItConfigurers.forEach((configurer) => {
  64. configurer.configure(this.md);
  65. });
  66. }
  67. preProcess(markdown) {
  68. for (let i = 0; i < this.preProcessors.length; i++) {
  69. if (!this.preProcessors[i].process) {
  70. continue;
  71. }
  72. markdown = this.preProcessors[i].process(markdown);
  73. }
  74. return markdown;
  75. }
  76. process(markdown) {
  77. return this.md.render(markdown);
  78. }
  79. postProcess(html, dom) {
  80. for (let i = 0; i < this.postProcessors.length; i++) {
  81. if (!this.postProcessors[i].process) {
  82. continue;
  83. }
  84. html = this.postProcessors[i].process(html, dom);
  85. }
  86. return html;
  87. }
  88. codeRenderer(code, langExt) {
  89. if (langExt) {
  90. const langAndFn = langExt.split(':');
  91. const lang = langAndFn[0];
  92. const langFn = langAndFn[1] || null;
  93. // process langProcessors
  94. if (this.langProcessors[lang] != null) {
  95. return this.langProcessors[lang].process(code, langExt);
  96. }
  97. if (hljs.getLanguage(lang)) {
  98. let citeTag = (langFn) ? `<cite>${langFn}</cite>` : '';
  99. try {
  100. return `<pre class="hljs">${citeTag}<code class="language-${lang}">${hljs.highlight(lang, code, true).value}</code></pre>`;
  101. } catch (__) {}
  102. }
  103. }
  104. return '';
  105. }
  106. }