X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/ddb7f33868ea499ab8f48a7062f145e8c0fbe02f..refs/pull/2023/head:/resources/js/components/wysiwyg-editor.js diff --git a/resources/js/components/wysiwyg-editor.js b/resources/js/components/wysiwyg-editor.js index 60a6743ea..be1bac6be 100644 --- a/resources/js/components/wysiwyg-editor.js +++ b/resources/js/components/wysiwyg-editor.js @@ -1,5 +1,6 @@ import Code from "../services/code"; import DrawIO from "../services/drawio"; +import Clipboard from "../services/clipboard"; /** * Handle pasting images from clipboard. @@ -8,30 +9,33 @@ import DrawIO from "../services/drawio"; * @param editor */ function editorPaste(event, editor, wysiwygComponent) { - const clipboardItems = event.clipboardData.items; - if (!event.clipboardData || !clipboardItems) return; + const clipboard = new Clipboard(event.clipboardData || event.dataTransfer); - // Don't handle if clipboard includes text content - for (let clipboardItem of clipboardItems) { - if (clipboardItem.type.includes('text/')) { - return; - } + // Don't handle the event ourselves if no items exist of contains table-looking data + if (!clipboard.hasItems() || clipboard.containsTabularData()) { + return; } - for (let clipboardItem of clipboardItems) { - if (!clipboardItem.type.includes("image")) { - continue; - } + const images = clipboard.getImages(); + for (const imageFile of images) { const id = "image-" + Math.random().toString(16).slice(2); const loadingImage = window.baseUrl('/loading.gif'); - const file = clipboardItem.getAsFile(); + event.preventDefault(); setTimeout(() => { editor.insertContent(`
`;
wrap.querySelector('code').innerText = code;
editor.formatter.toggle('pre');
- let node = editor.selection.getNode();
+ const node = editor.selection.getNode();
editor.dom.setHTML(node, wrap.querySelector('pre').innerHTML);
editor.fire('SetContent');
+
+ editor.focus()
});
return;
}
@@ -156,15 +162,17 @@ function codePlugin() {
let currentCode = selectedNode.querySelector('textarea').textContent;
window.vues['code-editor'].open(currentCode, lang, (code, lang) => {
- let editorElem = selectedNode.querySelector('.CodeMirror');
- let cmInstance = editorElem.CodeMirror;
+ const editorElem = selectedNode.querySelector('.CodeMirror');
+ const cmInstance = editorElem.CodeMirror;
if (cmInstance) {
Code.setContent(cmInstance, code);
- Code.setMode(cmInstance, lang);
+ Code.setMode(cmInstance, lang, code);
}
- let textArea = selectedNode.querySelector('textarea');
+ const textArea = selectedNode.querySelector('textarea');
if (textArea) textArea.textContent = code;
selectedNode.setAttribute('data-lang', lang);
+
+ editor.focus()
});
}
@@ -234,7 +242,7 @@ function codePlugin() {
});
}
-function drawIoPlugin() {
+function drawIoPlugin(drawioUrl) {
let pageEditor = null;
let currentNode = null;
@@ -262,7 +270,7 @@ function drawIoPlugin() {
function showDrawingEditor(mceEditor, selectedNode = null) {
pageEditor = mceEditor;
currentNode = selectedNode;
- DrawIO.show(drawingInit, updateContent);
+ DrawIO.show(drawioUrl, drawingInit, updateContent);
}
async function updateContent(pngData) {
@@ -419,10 +427,14 @@ class WysiwygEditor {
loadPlugins() {
codePlugin();
customHrPlugin();
- if (document.querySelector('[drawio-enabled]').getAttribute('drawio-enabled') === 'true') {
- drawIoPlugin();
+
+ const drawioUrlElem = document.querySelector('[drawio-url]');
+ if (drawioUrlElem) {
+ const url = drawioUrlElem.getAttribute('drawio-url');
+ drawIoPlugin(url);
this.plugins += ' drawio';
}
+
if (this.textDirection === 'rtl') {
this.plugins += ' directionality'
}
@@ -496,7 +508,15 @@ class WysiwygEditor {
const originalField = win.document.getElementById(field_name);
originalField.value = entity.link;
const mceForm = originalField.closest('.mce-form');
- mceForm.querySelectorAll('input')[2].value = entity.name;
+ const inputs = mceForm.querySelectorAll('input');
+
+ // Set text to display if not empty
+ if (!inputs[1].value) {
+ inputs[1].value = entity.name;
+ }
+
+ // Set title field
+ inputs[2].value = entity.name;
});
}
@@ -589,6 +609,7 @@ class WysiwygEditor {
registerEditorShortcuts(editor);
let wrap;
+ let draggedContentEditable;
function hasTextContent(node) {
return node && !!( node.textContent || node.innerText );
@@ -597,12 +618,19 @@ class WysiwygEditor {
editor.on('dragstart', function () {
let node = editor.selection.getNode();
- if (node.nodeName !== 'IMG') return;
- wrap = editor.dom.getParent(node, '.mceTemp');
+ if (node.nodeName === 'IMG') {
+ wrap = editor.dom.getParent(node, '.mceTemp');
+
+ if (!wrap && node.parentNode.nodeName === 'A' && !hasTextContent(node.parentNode)) {
+ wrap = node.parentNode;
+ }
+ }
- if (!wrap && node.parentNode.nodeName === 'A' && !hasTextContent(node.parentNode)) {
- wrap = node.parentNode;
+ // Track dragged contenteditable blocks
+ if (node.hasAttribute('contenteditable') && node.getAttribute('contenteditable') === 'false') {
+ draggedContentEditable = node;
}
+
});
editor.on('drop', function (event) {
@@ -610,7 +638,7 @@ class WysiwygEditor {
rng = tinymce.dom.RangeUtils.getCaretRangeFromPoint(event.clientX, event.clientY, editor.getDoc());
// Template insertion
- const templateId = event.dataTransfer.getData('bookstack/template');
+ const templateId = event.dataTransfer && event.dataTransfer.getData('bookstack/template');
if (templateId) {
event.preventDefault();
window.$http.get(`/templates/${templateId}`).then(resp => {
@@ -634,6 +662,26 @@ class WysiwygEditor {
});
}
+ // Handle contenteditable section drop
+ if (!event.isDefaultPrevented() && draggedContentEditable) {
+ event.preventDefault();
+ editor.undoManager.transact(function () {
+ const selectedNode = editor.selection.getNode();
+ const range = editor.selection.getRng();
+ const selectedNodeRoot = selectedNode.closest('body > *');
+ if (range.startOffset > (range.startContainer.length / 2)) {
+ editor.$(selectedNodeRoot).after(draggedContentEditable);
+ } else {
+ editor.$(selectedNodeRoot).before(draggedContentEditable);
+ }
+ });
+ }
+
+ // Handle image insert
+ if (!event.isDefaultPrevented()) {
+ editorPaste(event, editor, context);
+ }
+
wrap = null;
});