1 import DrawIO from "../services/drawio";
2 import {build} from "./config";
5 let currentNode = null;
8 * @type {WysiwygConfigOptions}
12 function isDrawing(node) {
13 return node.hasAttribute('drawio-diagram');
16 function showDrawingManager(mceEditor, selectedNode = null) {
17 pageEditor = mceEditor;
18 currentNode = selectedNode;
21 window.ImageManager.show(function (image) {
23 pageEditor.dom.replace(buildDrawingNode(image), selectedNode);
25 const drawingHtml = DrawIO.buildDrawingContentHtml(image);
26 pageEditor.insertContent(drawingHtml);
31 function showDrawingEditor(mceEditor, selectedNode = null) {
32 pageEditor = mceEditor;
33 currentNode = selectedNode;
34 DrawIO.show(options.drawioUrl, drawingInit, updateContent);
37 function buildDrawingNode(drawing) {
38 const drawingEl = DrawIO.buildDrawingContentNode(drawing);
39 drawingEl.setAttribute('contenteditable', 'false');
40 drawingEl.setAttribute('data-ephox-embed-iri', 'true');
44 async function updateContent(drawingData) {
45 const id = "image-" + Math.random().toString(16).slice(2);
46 const loadingImage = window.baseUrl('/loading.gif');
48 const handleUploadError = (error) => {
49 if (error.status === 413) {
50 window.$events.emit('error', options.translations.serverUploadLimitText);
52 window.$events.emit('error', options.translations.imageUploadErrorText);
57 // Handle updating an existing image
61 const img = await DrawIO.upload(drawingData, options.pageId);
62 pageEditor.dom.replace(buildDrawingNode(img), currentNode);
64 handleUploadError(err);
69 setTimeout(async () => {
70 pageEditor.insertContent(`<div drawio-diagram contenteditable="false"><img src="${loadingImage}" alt="Loading" id="${id}"></div>`);
73 const img = await DrawIO.upload(drawingData, options.pageId);
74 pageEditor.dom.replace(buildDrawingNode(img), pageEditor.dom.get(id).parentNode);
76 pageEditor.dom.remove(id);
77 handleUploadError(err);
83 function drawingInit() {
85 return Promise.resolve('');
88 let drawingId = currentNode.getAttribute('drawio-diagram');
89 return DrawIO.load(drawingId);
93 * @param {WysiwygConfigOptions} providedOptions
94 * @return {function(Editor, string)}
96 export function getPlugin(providedOptions) {
97 options = providedOptions;
98 return function(editor, url) {
100 editor.addCommand('drawio', () => {
101 const selectedNode = editor.selection.getNode();
102 showDrawingEditor(editor, isDrawing(selectedNode) ? selectedNode : null);
105 editor.ui.registry.addIcon('diagram', `<svg width="24" height="24" fill="${options.darkMode ? '#BBB' : '#000000'}" xmlns="http://www.w3.org/2000/svg"><path d="M20.716 7.639V2.845h-4.794v1.598h-7.99V2.845H3.138v4.794h1.598v7.99H3.138v4.794h4.794v-1.598h7.99v1.598h4.794v-4.794h-1.598v-7.99zM4.736 4.443h1.598V6.04H4.736zm1.598 14.382H4.736v-1.598h1.598zm9.588-1.598h-7.99v-1.598H6.334v-7.99h1.598V6.04h7.99v1.598h1.598v7.99h-1.598zm3.196 1.598H17.52v-1.598h1.598zM17.52 6.04V4.443h1.598V6.04zm-4.21 7.19h-2.79l-.582 1.599H8.643l2.717-7.191h1.119l2.724 7.19h-1.302zm-2.43-1.006h2.086l-1.039-3.06z"/></svg>`)
107 editor.ui.registry.addSplitButton('drawio', {
108 tooltip: 'Insert/edit drawing',
111 editor.execCommand('drawio');
117 text: 'Drawing manager',
118 value: 'drawing-manager',
122 onItemAction(api, value) {
123 if (value === 'drawing-manager') {
124 const selectedNode = editor.selection.getNode();
125 showDrawingManager(editor, isDrawing(selectedNode) ? selectedNode : null);
130 editor.on('dblclick', event => {
131 let selectedNode = editor.selection.getNode();
132 if (!isDrawing(selectedNode)) return;
133 showDrawingEditor(editor, selectedNode);
136 editor.on('PreInit', () => {
137 editor.parser.addNodeFilter('div', function(nodes) {
138 for (const node of nodes) {
139 if (node.attr('drawio-diagram')) {
140 // Set content editable to be false to prevent direct editing of child content.
141 node.attr('contenteditable', 'false');
142 // Set this attribute to prevent drawing contents being parsed as media embeds
143 // to avoid contents being replaced with placeholder images.
144 // TinyMCE embed plugin sources looks for this attribute in its logic.
145 node.attr('data-ephox-embed-iri', 'true');
150 editor.serializer.addNodeFilter('div', function(nodes) {
151 for (const node of nodes) {
152 // Clean up content attributes
153 if (node.attr('drawio-diagram')) {
154 node.attr('contenteditable', null);
155 node.attr('data-ephox-embed-iri', null);