drawio-interceptor.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /* eslint-disable import/prefer-default-export */
  2. import React from 'react';
  3. import ReactDOM from 'react-dom';
  4. import { BasicInterceptor } from 'growi-commons';
  5. import Drawio from '../../components/Drawio';
  6. /**
  7. * The interceptor for draw.io
  8. *
  9. * replace draw.io tag (render by markdown-it-drawio-viewer) to a React target element
  10. */
  11. export class DrawioInterceptor extends BasicInterceptor {
  12. constructor(appContainer) {
  13. super();
  14. this.previousPreviewContext = null;
  15. this.appContainer = appContainer;
  16. const DrawioViewer = window.GraphViewer;
  17. if (DrawioViewer != null) {
  18. // viewer.min.js の Resize による Scroll イベントを抑止するために無効化する
  19. DrawioViewer.useResizeSensor = false;
  20. }
  21. }
  22. /**
  23. * @inheritdoc
  24. */
  25. isInterceptWhen(contextName) {
  26. return (
  27. contextName === 'preRenderHtml'
  28. || contextName === 'preRenderPreviewHtml'
  29. || contextName === 'postRenderHtml'
  30. || contextName === 'postRenderPreviewHtml'
  31. );
  32. }
  33. /**
  34. * @inheritdoc
  35. */
  36. isProcessableParallel() {
  37. return false;
  38. }
  39. /**
  40. * @inheritdoc
  41. */
  42. async process(contextName, ...args) {
  43. const context = Object.assign(args[0]); // clone
  44. if (contextName === 'preRenderHtml' || contextName === 'preRenderPreviewHtml') {
  45. return this.drawioPreRender(contextName, context);
  46. }
  47. if (contextName === 'postRenderHtml' || contextName === 'postRenderPreviewHtml') {
  48. this.drawioPostRender(contextName, context);
  49. return;
  50. }
  51. }
  52. /**
  53. * @inheritdoc
  54. */
  55. createRandomStr(length) {
  56. const bag = 'abcdefghijklmnopqrstuvwxyz0123456789';
  57. let generated = '';
  58. for (let i = 0; i < length; i++) {
  59. generated += bag[Math.floor(Math.random() * bag.length)];
  60. }
  61. return generated;
  62. }
  63. /**
  64. * @inheritdoc
  65. */
  66. drawioPreRender(contextName, context) {
  67. const div = document.createElement('div');
  68. div.innerHTML = context.parsedHTML;
  69. context.DrawioMap = {};
  70. Array.from(div.querySelectorAll('.mxgraph')).forEach((element) => {
  71. const domId = `mxgraph-${this.createRandomStr(8)}`;
  72. context.DrawioMap[domId] = {
  73. rangeLineNumberOfMarkdown: {
  74. beginLineNumber: element.parentNode.dataset.beginLineNumberOfMarkdown,
  75. endLineNumber: element.parentNode.dataset.endLineNumberOfMarkdown,
  76. },
  77. contentHtml: element.outerHTML,
  78. };
  79. element.outerHTML = `<div id="${domId}"></div>`;
  80. });
  81. context.parsedHTML = div.innerHTML;
  82. // unmount
  83. if (contextName === 'preRenderPreviewHtml') {
  84. this.unmountPreviousReactDOMs(context);
  85. }
  86. // resolve
  87. return context;
  88. }
  89. /**
  90. * @inheritdoc
  91. */
  92. drawioPostRender(contextName, context) {
  93. const isPreview = (contextName === 'postRenderPreviewHtml');
  94. Object.keys(context.DrawioMap).forEach((domId) => {
  95. const elem = document.getElementById(domId);
  96. if (elem) {
  97. this.renderReactDOM(context.DrawioMap[domId], elem, isPreview);
  98. }
  99. });
  100. }
  101. /**
  102. * @inheritdoc
  103. */
  104. renderReactDOM(drawioMapEntry, elem, isPreview) {
  105. ReactDOM.render(
  106. // eslint-disable-next-line react/jsx-filename-extension
  107. <Drawio
  108. appContainer={this.appContainer}
  109. drawioContent={drawioMapEntry.contentHtml}
  110. isPreview={isPreview}
  111. rangeLineNumberOfMarkdown={drawioMapEntry.rangeLineNumberOfMarkdown}
  112. />,
  113. elem,
  114. );
  115. }
  116. /**
  117. * @inheritdoc
  118. */
  119. unmountPreviousReactDOMs(newContext) {
  120. if (this.previousPreviewContext != null) {
  121. Array.from(document.querySelectorAll('.mxgraph')).forEach((element) => {
  122. ReactDOM.unmountComponentAtNode(element);
  123. });
  124. }
  125. this.previousPreviewContext = newContext;
  126. }
  127. }