DrawioCommunicationHelper.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import { extractCodeFromMxfile } from '@growi/remark-drawio';
  2. import loggerFactory from '~/utils/logger';
  3. const logger = loggerFactory('growi:cli:DrawioCommunicationHelper');
  4. export type DrawioConfig = {
  5. css: string,
  6. customFonts: string[],
  7. }
  8. export type DrawioCommunicationCallbackOptions = {
  9. onClose?: () => void;
  10. onSave?: (drawioData: string) => void;
  11. }
  12. export class DrawioCommunicationHelper {
  13. drawioUri: string;
  14. drawioConfig: DrawioConfig;
  15. callbackOpts?: DrawioCommunicationCallbackOptions;
  16. constructor(drawioUri: string, drawioConfig: DrawioConfig, callbackOpts?: DrawioCommunicationCallbackOptions) {
  17. this.drawioUri = drawioUri;
  18. this.drawioConfig = drawioConfig;
  19. this.callbackOpts = callbackOpts;
  20. }
  21. onReceiveMessage(event: MessageEvent, drawioMxFile: string): void {
  22. // check origin
  23. if (event.origin != null && this.drawioUri != null) {
  24. const originUrl = new URL(event.origin);
  25. const drawioUrl = new URL(this.drawioUri);
  26. if (originUrl.origin !== drawioUrl.origin) {
  27. logger.debug(`Skipping the event because the origins are mismatched. expected: '${drawioUrl.origin}', actual: '${originUrl.origin}'`);
  28. return;
  29. }
  30. }
  31. // configure
  32. if (event.data === '{"event":"configure"}') {
  33. if (event.source == null) {
  34. return;
  35. }
  36. // refs:
  37. // * https://desk.draw.io/support/solutions/articles/16000103852-how-to-customise-the-draw-io-interface
  38. // * https://desk.draw.io/support/solutions/articles/16000042544-how-does-embed-mode-work-
  39. // * https://desk.draw.io/support/solutions/articles/16000058316-how-to-configure-draw-io-
  40. event.source.postMessage(JSON.stringify({
  41. action: 'configure',
  42. config: this.drawioConfig,
  43. }), { targetOrigin: '*' });
  44. return;
  45. }
  46. // restore diagram data
  47. if (event.data === 'ready') {
  48. let code = drawioMxFile;
  49. try {
  50. code = extractCodeFromMxfile(drawioMxFile);
  51. }
  52. // catch error if drawioMxFile is not XML
  53. catch (err) {
  54. // do nothing because drawioMxFile might be base64 code
  55. }
  56. event.source?.postMessage(code, { targetOrigin: '*' });
  57. return;
  58. }
  59. if (typeof event.data === 'string' && event.data.match(/mxfile/)) {
  60. if (event.data.length > 0) {
  61. const parser = new DOMParser();
  62. const dom = parser.parseFromString(event.data, 'text/xml');
  63. const drawioData = dom.getElementsByTagName('diagram')[0].innerHTML;
  64. /*
  65. * Saving Drawio will be implemented by the following tasks
  66. * https://redmine.weseek.co.jp/issues/100845
  67. * https://redmine.weseek.co.jp/issues/104507
  68. */
  69. this.callbackOpts?.onSave?.(drawioData);
  70. }
  71. this.callbackOpts?.onClose?.();
  72. return;
  73. }
  74. if (typeof event.data === 'string' && event.data.length === 0) {
  75. this.callbackOpts?.onClose?.();
  76. return;
  77. }
  78. // NOTHING DONE. (Receive unknown iframe message.)
  79. }
  80. }