5fd8e7e0e9
- Adds support for handling drawings as embeds, based on image extension. - Adds additional attribute to drawio elements within editor to prevent tinymce replacing embeds with a placeholder. - Updates how contenteditable is applied to drawio blocks within editor, to use proper filters instead of using the SetContent event.
162 lines
No EOL
5.8 KiB
JavaScript
162 lines
No EOL
5.8 KiB
JavaScript
import DrawIO from "../services/drawio";
|
|
import {build} from "./config";
|
|
|
|
let pageEditor = null;
|
|
let currentNode = null;
|
|
|
|
/**
|
|
* @type {WysiwygConfigOptions}
|
|
*/
|
|
let options = {};
|
|
|
|
function isDrawing(node) {
|
|
return node.hasAttribute('drawio-diagram');
|
|
}
|
|
|
|
function showDrawingManager(mceEditor, selectedNode = null) {
|
|
pageEditor = mceEditor;
|
|
currentNode = selectedNode;
|
|
|
|
// Show image manager
|
|
window.ImageManager.show(function (image) {
|
|
if (selectedNode) {
|
|
pageEditor.dom.replace(buildDrawingNode(image), selectedNode);
|
|
} else {
|
|
const drawingHtml = DrawIO.buildDrawingContentHtml(image);
|
|
pageEditor.insertContent(drawingHtml);
|
|
}
|
|
}, 'drawio');
|
|
}
|
|
|
|
function showDrawingEditor(mceEditor, selectedNode = null) {
|
|
pageEditor = mceEditor;
|
|
currentNode = selectedNode;
|
|
DrawIO.show(options.drawioUrl, drawingInit, updateContent);
|
|
}
|
|
|
|
function buildDrawingNode(drawing) {
|
|
const drawingEl = DrawIO.buildDrawingContentNode(drawing);
|
|
drawingEl.setAttribute('contenteditable', 'false');
|
|
drawingEl.setAttribute('data-ephox-embed-iri', 'true');
|
|
return drawingEl;
|
|
}
|
|
|
|
async function updateContent(drawingData) {
|
|
const id = "image-" + Math.random().toString(16).slice(2);
|
|
const loadingImage = window.baseUrl('/loading.gif');
|
|
|
|
const handleUploadError = (error) => {
|
|
if (error.status === 413) {
|
|
window.$events.emit('error', options.translations.serverUploadLimitText);
|
|
} else {
|
|
window.$events.emit('error', options.translations.imageUploadErrorText);
|
|
}
|
|
console.log(error);
|
|
};
|
|
|
|
// Handle updating an existing image
|
|
if (currentNode) {
|
|
DrawIO.close();
|
|
try {
|
|
const img = await DrawIO.upload(drawingData, options.pageId);
|
|
pageEditor.dom.replace(buildDrawingNode(img), currentNode);
|
|
} catch (err) {
|
|
handleUploadError(err);
|
|
}
|
|
return;
|
|
}
|
|
|
|
setTimeout(async () => {
|
|
pageEditor.insertContent(`<div drawio-diagram contenteditable="false"><img src="${loadingImage}" alt="Loading" id="${id}"></div>`);
|
|
DrawIO.close();
|
|
try {
|
|
const img = await DrawIO.upload(drawingData, options.pageId);
|
|
pageEditor.dom.replace(buildDrawingNode(img), pageEditor.dom.get(id).parentNode);
|
|
} catch (err) {
|
|
pageEditor.dom.remove(id);
|
|
handleUploadError(err);
|
|
}
|
|
}, 5);
|
|
}
|
|
|
|
|
|
function drawingInit() {
|
|
if (!currentNode) {
|
|
return Promise.resolve('');
|
|
}
|
|
|
|
let drawingId = currentNode.getAttribute('drawio-diagram');
|
|
return DrawIO.load(drawingId);
|
|
}
|
|
|
|
/**
|
|
* @param {WysiwygConfigOptions} providedOptions
|
|
* @return {function(Editor, string)}
|
|
*/
|
|
export function getPlugin(providedOptions) {
|
|
options = providedOptions;
|
|
return function(editor, url) {
|
|
|
|
editor.addCommand('drawio', () => {
|
|
const selectedNode = editor.selection.getNode();
|
|
showDrawingEditor(editor, isDrawing(selectedNode) ? selectedNode : null);
|
|
});
|
|
|
|
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>`)
|
|
|
|
editor.ui.registry.addSplitButton('drawio', {
|
|
tooltip: 'Insert/edit drawing',
|
|
icon: 'diagram',
|
|
onAction() {
|
|
editor.execCommand('drawio');
|
|
},
|
|
fetch(callback) {
|
|
callback([
|
|
{
|
|
type: 'choiceitem',
|
|
text: 'Drawing manager',
|
|
value: 'drawing-manager',
|
|
}
|
|
]);
|
|
},
|
|
onItemAction(api, value) {
|
|
if (value === 'drawing-manager') {
|
|
const selectedNode = editor.selection.getNode();
|
|
showDrawingManager(editor, isDrawing(selectedNode) ? selectedNode : null);
|
|
}
|
|
}
|
|
});
|
|
|
|
editor.on('dblclick', event => {
|
|
let selectedNode = editor.selection.getNode();
|
|
if (!isDrawing(selectedNode)) return;
|
|
showDrawingEditor(editor, selectedNode);
|
|
});
|
|
|
|
editor.on('PreInit', () => {
|
|
editor.parser.addNodeFilter('div', function(nodes) {
|
|
for (const node of nodes) {
|
|
if (node.attr('drawio-diagram')) {
|
|
// Set content editable to be false to prevent direct editing of child content.
|
|
node.attr('contenteditable', 'false');
|
|
// Set this attribute to prevent drawing contents being parsed as media embeds
|
|
// to avoid contents being replaced with placeholder images.
|
|
// TinyMCE embed plugin sources looks for this attribute in its logic.
|
|
node.attr('data-ephox-embed-iri', 'true');
|
|
}
|
|
}
|
|
});
|
|
|
|
editor.serializer.addNodeFilter('div', function(nodes) {
|
|
for (const node of nodes) {
|
|
// Clean up content attributes
|
|
if (node.attr('drawio-diagram')) {
|
|
node.attr('contenteditable', null);
|
|
node.attr('data-ephox-embed-iri', null);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
};
|
|
} |