DrawioModal.jsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import i18next from 'i18next';
  4. import {
  5. Modal,
  6. ModalBody,
  7. } from 'reactstrap';
  8. export default class DrawioModal extends React.PureComponent {
  9. constructor(props) {
  10. super(props);
  11. this.state = {
  12. show: false,
  13. drawioMxFile: '',
  14. };
  15. this.drawioIFrame = React.createRef();
  16. this.headerColor = '#334455';
  17. this.fontFamily = "Lato, -apple-system, BlinkMacSystemFont, 'Hiragino Kaku Gothic ProN', Meiryo, sans-serif";
  18. this.init = this.init.bind(this);
  19. this.cancel = this.cancel.bind(this);
  20. this.receiveFromDrawio = this.receiveFromDrawio.bind(this);
  21. this.drawioURL = this.drawioURL.bind(this);
  22. }
  23. init(drawioMxFile) {
  24. const initDrawioMxFile = drawioMxFile;
  25. this.setState(
  26. {
  27. drawioMxFile: initDrawioMxFile,
  28. },
  29. );
  30. }
  31. show(drawioMxFile) {
  32. this.init(drawioMxFile);
  33. window.addEventListener('message', this.receiveFromDrawio);
  34. this.setState({ show: true });
  35. }
  36. hide() {
  37. this.setState({
  38. show: false,
  39. });
  40. }
  41. cancel() {
  42. this.hide();
  43. }
  44. receiveFromDrawio(event) {
  45. if (event.data === 'ready') {
  46. event.source.postMessage(this.state.drawioMxFile, '*');
  47. return;
  48. }
  49. if (event.data === '{"event":"configure"}') {
  50. if (event.source == null) {
  51. return;
  52. }
  53. // refs:
  54. // * https://desk.draw.io/support/solutions/articles/16000103852-how-to-customise-the-draw-io-interface
  55. // * https://desk.draw.io/support/solutions/articles/16000042544-how-does-embed-mode-work-
  56. // * https://desk.draw.io/support/solutions/articles/16000058316-how-to-configure-draw-io-
  57. event.source.postMessage(JSON.stringify({
  58. action: 'configure',
  59. config: {
  60. css: `
  61. .geMenubarContainer { background-color: ${this.headerColor} !important; }
  62. .geMenubar { background-color: ${this.headerColor} !important; }
  63. .geEditor { font-family: ${this.fontFamily} !important; }
  64. html td.mxPopupMenuItem {
  65. font-family: ${this.fontFamily} !important;
  66. font-size: 8pt !important;
  67. }
  68. `,
  69. customFonts: ['Lato', 'Charter'],
  70. },
  71. }), '*');
  72. return;
  73. }
  74. if (typeof event.data === 'string' && event.data.match(/mxfile/)) {
  75. if (event.data.length > 0) {
  76. const parser = new DOMParser();
  77. const dom = parser.parseFromString(event.data, 'text/xml');
  78. const value = dom.getElementsByTagName('diagram')[0].innerHTML;
  79. this.props.onSave(value);
  80. }
  81. window.removeEventListener('message', this.receiveFromDrawio);
  82. this.hide();
  83. return;
  84. }
  85. if (typeof event.data === 'string' && event.data.length === 0) {
  86. window.removeEventListener('message', this.receiveFromDrawio);
  87. this.hide();
  88. return;
  89. }
  90. // NOTHING DONE. (Receive unknown iframe message.)
  91. }
  92. drawioURL() {
  93. const url = new URL('https://www.draw.io/');
  94. // refs: https://desk.draw.io/support/solutions/articles/16000042546-what-url-parameters-are-supported-
  95. url.searchParams.append('spin', 1);
  96. url.searchParams.append('embed', 1);
  97. url.searchParams.append('lang', i18next.language);
  98. url.searchParams.append('ui', 'atlas');
  99. url.searchParams.append('configure', 1);
  100. return url;
  101. }
  102. render() {
  103. return (
  104. // <Modal show={this.state.show} onHide={this.cancel} bsSize="large" dialogClassName={dialogClassName} keyboard={false}>
  105. <Modal isOpen={this.state.show} toggle={this.cancel} className="drawio-modal" bsSize="large" keyboard={false}>
  106. <ModalBody className="p-0">
  107. {/* Loading spinner */}
  108. <div className="w-100 h-100 position-absolute d-flex">
  109. <div className="mx-auto my-auto">
  110. <i className="fa fa-3x fa-spinner fa-pulse mx-auto text-muted"></i>
  111. </div>
  112. </div>
  113. {/* iframe */}
  114. <div className="w-100 h-100 position-absolute d-flex">
  115. { this.state.show && (
  116. <iframe
  117. ref={(c) => { this.drawioIFrame = c }}
  118. src={this.drawioURL()}
  119. className="border-0 flex-grow-1"
  120. >
  121. </iframe>
  122. ) }
  123. </div>
  124. </ModalBody>
  125. </Modal>
  126. );
  127. }
  128. }
  129. DrawioModal.propTypes = {
  130. onSave: PropTypes.func,
  131. };