detach-code-blocks.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import { BasicInterceptor } from 'crowi-pluginkit';
  2. class DetachCodeBlockUtil {
  3. static createReplaceStr(replaceId) {
  4. return `<pre>${replaceId}</pre>`;
  5. }
  6. }
  7. /**
  8. * The interceptor that detach code blocks
  9. */
  10. export class DetachCodeBlockInterceptor extends BasicInterceptor {
  11. constructor(crowi) {
  12. super();
  13. this.crowi = crowi;
  14. this.crowiForJquery = crowi.getCrowiForJquery();
  15. }
  16. /**
  17. * @inheritdoc
  18. */
  19. isInterceptWhen(contextName) {
  20. return (
  21. contextName === 'prePreProcess'
  22. );
  23. }
  24. /**
  25. * @inheritdoc
  26. */
  27. process(contextName, ...args) {
  28. const context = Object.assign(args[0]); // clone
  29. const markdown = context.markdown;
  30. const currentPagePath = context.currentPagePath;
  31. context.dcbContextMap = {};
  32. // see: https://regex101.com/r/8PAEcC/3
  33. context.markdown = markdown.replace(/((```|~~~)(.|[\r\n])*?(```|~~~))|(`[^\r\n]*?`)/gm, (all) => {
  34. // create ID
  35. const replaceId = 'dcb-' + this.createRandomStr(8);
  36. // register to context
  37. let dcbContext = {};
  38. dcbContext.content = all;
  39. dcbContext.substituteContent = DetachCodeBlockUtil.createReplaceStr(replaceId);
  40. context.dcbContextMap[replaceId] = dcbContext;
  41. // return substituteContent
  42. return dcbContext.substituteContent;
  43. });
  44. // resolve
  45. return Promise.resolve(context);
  46. }
  47. /**
  48. * @see http://qiita.com/ryounagaoka/items/4736c225bdd86a74d59c
  49. *
  50. * @param {number} length
  51. * @return random strings
  52. */
  53. createRandomStr(length) {
  54. const bag = "abcdefghijklmnopqrstuvwxyz0123456789";
  55. let generated = "";
  56. for (var i = 0; i < length; i++) {
  57. generated += bag[Math.floor(Math.random() * bag.length)];
  58. }
  59. return generated;
  60. }
  61. }
  62. /**
  63. * The interceptor that restore detached code blocks
  64. */
  65. export class RestoreCodeBlockInterceptor extends BasicInterceptor {
  66. constructor(crowi) {
  67. super();
  68. this.crowi = crowi;
  69. this.crowiForJquery = crowi.getCrowiForJquery();
  70. }
  71. /**
  72. * @inheritdoc
  73. */
  74. isInterceptWhen(contextName) {
  75. return (
  76. contextName === 'postPreProcess'
  77. );
  78. }
  79. /**
  80. * @inheritdoc
  81. */
  82. process(contextName, ...args) {
  83. const context = Object.assign(args[0]); // clone
  84. // forEach keys of dcbContextMap
  85. Object.keys(context.dcbContextMap).forEach((replaceId) => {
  86. // get context object from context
  87. let dcbContext = context.dcbContextMap[replaceId];
  88. // replace it with content by using getter function so that the doller sign does not work
  89. // see: https://github.com/weseek/crowi-plus/issues/285
  90. context.markdown = context.markdown.replace(dcbContext.substituteContent, () => { return dcbContext.content; });
  91. });
  92. // resolve
  93. return Promise.resolve(context);
  94. }
  95. }