]> BookStack Code Mirror - bookstack/blob - resources/js/services/drawio.js
RTL: Fixed screen-reader-only elements pushout out view
[bookstack] / resources / js / services / drawio.js
1 // Docs: https://www.diagrams.net/doc/faq/embed-mode
2
3 let iFrame = null;
4 let lastApprovedOrigin;
5 let onInit; let
6     onSave;
7
8 function drawPostMessage(data) {
9     iFrame.contentWindow.postMessage(JSON.stringify(data), lastApprovedOrigin);
10 }
11
12 function drawEventExport(message) {
13     if (onSave) {
14         onSave(message.data);
15     }
16 }
17
18 function drawEventSave(message) {
19     drawPostMessage({
20         action: 'export', format: 'xmlpng', xml: message.xml, spin: 'Updating drawing',
21     });
22 }
23
24 function drawEventInit() {
25     if (!onInit) return;
26     onInit().then(xml => {
27         drawPostMessage({action: 'load', autosave: 1, xml});
28     });
29 }
30
31 function drawEventConfigure() {
32     const config = {};
33     window.$events.emitPublic(iFrame, 'editor-drawio::configure', {config});
34     drawPostMessage({action: 'configure', config});
35 }
36
37 function drawEventClose() {
38     // eslint-disable-next-line no-use-before-define
39     window.removeEventListener('message', drawReceive);
40     if (iFrame) document.body.removeChild(iFrame);
41 }
42
43 /**
44  * Receive and handle a message event from the draw.io window.
45  * @param {MessageEvent} event
46  */
47 function drawReceive(event) {
48     if (!event.data || event.data.length < 1) return;
49     if (event.origin !== lastApprovedOrigin) return;
50
51     const message = JSON.parse(event.data);
52     if (message.event === 'init') {
53         drawEventInit();
54     } else if (message.event === 'exit') {
55         drawEventClose();
56     } else if (message.event === 'save') {
57         drawEventSave(message);
58     } else if (message.event === 'export') {
59         drawEventExport(message);
60     } else if (message.event === 'configure') {
61         drawEventConfigure();
62     }
63 }
64
65 /**
66  * Show the draw.io editor.
67  * @param {String} drawioUrl
68  * @param {Function} onInitCallback - Must return a promise with the xml to load for the editor.
69  * @param {Function} onSaveCallback - Is called with the drawing data on save.
70  */
71 export function show(drawioUrl, onInitCallback, onSaveCallback) {
72     onInit = onInitCallback;
73     onSave = onSaveCallback;
74
75     iFrame = document.createElement('iframe');
76     iFrame.setAttribute('frameborder', '0');
77     window.addEventListener('message', drawReceive);
78     iFrame.setAttribute('src', drawioUrl);
79     iFrame.setAttribute('class', 'fullscreen');
80     iFrame.style.backgroundColor = '#FFFFFF';
81     document.body.appendChild(iFrame);
82     lastApprovedOrigin = (new URL(drawioUrl)).origin;
83 }
84
85 export async function upload(imageData, pageUploadedToId) {
86     const data = {
87         image: imageData,
88         uploaded_to: pageUploadedToId,
89     };
90     const resp = await window.$http.post(window.baseUrl('/images/drawio'), data);
91     return resp.data;
92 }
93
94 export function close() {
95     drawEventClose();
96 }
97
98 /**
99  * Load an existing image, by fetching it as Base64 from the system.
100  * @param drawingId
101  * @returns {Promise<string>}
102  */
103 export async function load(drawingId) {
104     try {
105         const resp = await window.$http.get(window.baseUrl(`/images/drawio/base64/${drawingId}`));
106         return `data:image/png;base64,${resp.data.content}`;
107     } catch (error) {
108         if (error instanceof window.$http.HttpError) {
109             window.$events.showResponseError(error);
110         }
111         close();
112         throw error;
113     }
114 }