detach-code-blocks.js 2.8 KB

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