/**
* Quill-Modul: Drag-Resize für Bilder im Editor.
*
* Aktivierung pro Editor-Instanz via:
* modules: { imageResize: true }
*
* Verhalten:
* - Click auf
im Editor → 4 Ecken-Handles als position:fixed-Overlay
* - mousedown/touchstart auf einem Handle startet den Drag
* - Drag aktualisiert width-Attribut + Inline-Style mit !important am
* (Inline-Style ist nötig, weil die globale `img { max-width:100% }`-Regel
* im Intranet das HTML-width-Attribut überstimmt — Spezifität 0 verliert
* gegen jede Author-CSS-Regel auf
)
* - Aspect Ratio über CSS `height: auto` gehalten
*
* Persistenz-Pipeline:
* 1) ResizableImage-Blot (unten registriert) whitelisted alt/width/height in
* Quills formats/image-Override, damit die Attribute den Quill-Save-Pfad
* (`quill.update`) überleben.
* 2) Pro Quill-Instanz: Clipboard-Matcher für IMG + Monkey-Patch um
* `dangerouslyPasteHTML`. Die reparieren den Lade-Pfad, weil Quill
* 2.0.0-dev.3 beim HTML→Delta-Parse die Attribute trotz Blot droppt.
* Der Monkey-Patch reappliziert width-Attribut UND Inline-!important-Style
* am Editor-DOM (gleiches Pattern wie Live-Drag).
*
* Bewusst klein gehalten. Keine Abhängigkeit zu third-party Resize-Modulen,
* die für Quill 1.3.x geschrieben wurden und in 2.0.0-dev.3 unstet sind.
*/
(function (global) {
'use strict';
if (typeof Quill === 'undefined') {
console.error('[quill_resize] Quill ist nicht geladen.');
return;
}
// ResizableImage-Blot: Quill 2.0.0-dev.3' nativer formats/image strippt
// beim Re-Parse alle Attribute außer src. Dieser Blot whitelisted alt,
// width, height, damit die per Drag gesetzte Größe den Roundtrip überlebt.
//
// Quill 2.x' Blots sind ES6-Klassen — Vererbung MUSS via `class ... extends`
// erfolgen, nicht via Prototype-Chain (Image.apply würde TypeError werfen,
// weil ES6-Classes nicht ohne `new` aufgerufen werden können).
//
// try/catch: Falls Quill in einer Version vorliegt, die diese Override-API
// nicht unterstützt, kippt der Editor nicht — wir loggen und fallen
// stillschweigend auf den nativen Image-Blot zurück.
if (!global.__ResizableImageRegistered) {
try {
var Image = Quill.import('formats/image');
var ATTRS = ['alt', 'width', 'height'];
var ResizableImage = class extends Image {
static create(value) {
var src = value;
var extras = null;
if (value && typeof value === 'object') {
src = value.src || value.url || '';
extras = value;
}
var node = super.create(src);
if (extras) {
ATTRS.forEach(function (attr) {
if (extras[attr] !== undefined && extras[attr] !== null && extras[attr] !== '') {
node.setAttribute(attr, extras[attr]);
}
});
}
return node;
}
static formats(domNode) {
var base = (typeof super.formats === 'function') ? super.formats(domNode) : {};
ATTRS.forEach(function (attr) {
if (domNode.hasAttribute(attr)) {
base[attr] = domNode.getAttribute(attr);
}
});
return base;
}
format(name, value) {
if (ATTRS.indexOf(name) > -1) {
if (value) {
this.domNode.setAttribute(name, value);
} else {
this.domNode.removeAttribute(name);
}
} else {
super.format(name, value);
}
}
};
ResizableImage.blotName = 'image';
ResizableImage.tagName = 'IMG';
Quill.register(ResizableImage, true);
global.__ResizableImageRegistered = true;
global.ResizableImage = ResizableImage;
} catch (err) {
console.error('[quill_resize] ResizableImage-Blot konnte nicht registriert werden — fallback auf nativen Image-Blot. Resize-Größe geht beim Re-Edit verloren.', err);
}
}
var MIN_WIDTH = 50;
function ImageResize(quill, options) {
this.quill = quill;
this.editor = quill.root;
this.options = options || {};
this.activeImg = null;
this.overlay = null;
this.dragState = null;
// Methoden binden, damit removeEventListener funktioniert
this.onEditorClick = this.onEditorClick.bind(this);
this.onDocPointerDown = this.onDocPointerDown.bind(this);
this.onReposition = this.onReposition.bind(this);
this.onMove = this.onMove.bind(this);
this.onUp = this.onUp.bind(this);
this.editor.addEventListener('click', this.onEditorClick);
document.addEventListener('mousedown', this.onDocPointerDown, true);
document.addEventListener('touchstart', this.onDocPointerDown, true);
window.addEventListener('resize', this.onReposition);
window.addEventListener('scroll', this.onReposition, true);
// Bei Text-Changes Position anpassen (z.B. wenn Bild verschoben wird)
quill.on('text-change', this.onReposition);
// Quill 2.0.0-dev.3 strippt beim dangerouslyPasteHTML alle
-Attribute
// außer src. Reader rendert das gespeicherte HTML direkt — also korrekt;
// aber im Editor ist die Größe nach Re-Open weg. Zwei Schutzschichten:
//
// (a) Clipboard-Matcher: Beim HTML→Delta-Parse die width/height/alt
// als delta.attributes mitführen. Bei korrekt greifendem
// ResizableImage-Blot überlebt das den Render zurück ans DOM.
//
// (b) Monkey-Patch um dangerouslyPasteHTML: Falls (a) in dev.3 nicht
// durchgereicht wird (Embed-format-Hook ignoriert), reapplizieren
// wir die Attribute nach dem Paste direkt am Editor-DOM. Idempotent
// pro Quill-Instanz via Marker-Property.
try {
quill.clipboard.addMatcher('IMG', function (node, delta) {
if (!node || !delta || !delta.ops || !delta.ops.length) return delta;
var op = delta.ops[0];
if (!op || !op.insert) return delta;
var attrs = op.attributes || {};
['alt', 'width', 'height'].forEach(function (a) {
if (node.hasAttribute(a) && attrs[a] == null) {
attrs[a] = node.getAttribute(a);
}
});
if (Object.keys(attrs).length) op.attributes = attrs;
return delta;
});
} catch (e) {
console.warn('[quill_resize] Clipboard-Matcher Setup fehlgeschlagen', e);
}
if (!quill.__pasteHtmlPatched && quill.clipboard
&& typeof quill.clipboard.dangerouslyPasteHTML === 'function') {
var origPaste = quill.clipboard.dangerouslyPasteHTML;
var PASTE_ATTRS = ['alt', 'width', 'height'];
quill.clipboard.dangerouslyPasteHTML = function () {
var args = Array.prototype.slice.call(arguments);
var htmlArg = (typeof args[0] === 'string') ? args[0] : args[1];
var seq = [];
if (typeof htmlArg === 'string' && htmlArg.indexOf('![]()