jodit
Version:
Jodit is an awesome and useful wysiwyg editor with filebrowser
208 lines (207 loc) • 7.43 kB
JavaScript
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
r = Reflect.decorate(decorators, target, key, desc);
else
for (var i = decorators.length - 1; i >= 0; i--)
if (d = decorators[i])
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { autobind, throttle } from "../../core/decorators/index.js";
import { Dom } from "../../core/dom/index.js";
import { getContainer, pluginSystem } from "../../core/global.js";
import { css, ctrlKey, dataBind, splitArray } from "../../core/helpers/index.js";
import { Plugin } from "../../core/plugin/index.js";
import "./config.js";
var DragState;
(function (DragState) {
DragState[DragState["IDLE"] = 0] = "IDLE";
DragState[DragState["WAIT_DRAGGING"] = 1] = "WAIT_DRAGGING";
DragState[DragState["DRAGGING"] = 2] = "DRAGGING";
})(DragState || (DragState = {}));
/**
* Process drag and drop image or another element inside the editor
*/
export class dragAndDropElement extends Plugin {
constructor() {
super(...arguments);
this.dragList = [];
this.draggable = null;
this.isCopyMode = false;
/**
* Shift in pixels after which we consider that the transfer of the element has begun
*/
this.diffStep = 10;
this.startX = 0;
this.startY = 0;
this.state = DragState.IDLE;
}
/** @override */
afterInit() {
this.dragList = this.j.o.draggableTags
? splitArray(this.j.o.draggableTags)
.filter(Boolean)
.map(item => item.toLowerCase())
: [];
if (!this.dragList.length) {
return;
}
this.j.e.on('mousedown dragstart', this.onDragStart);
}
/**
* Drag start handler
*/
onDragStart(event) {
if (event.type === 'dragstart' && this.draggable) {
return false;
}
if (this.state > DragState.IDLE) {
return;
}
const target = event.target;
if (!this.dragList.length || !target) {
return;
}
const matched = (node) => Boolean(node && this.dragList.includes(node.nodeName.toLowerCase()));
let lastTarget = Dom.furthest(target, matched, this.j.editor) ||
(matched(target) ? target : null);
if (!lastTarget) {
return;
}
if (Dom.isTag(lastTarget.parentElement, 'a') &&
lastTarget.parentElement.firstChild === lastTarget &&
lastTarget.parentElement.lastChild === lastTarget) {
lastTarget = lastTarget.parentElement;
}
this.startX = event.clientX;
this.startY = event.clientY;
this.isCopyMode = ctrlKey(event); // we can move only element from editor
this.draggable = lastTarget.cloneNode(true);
dataBind(this.draggable, 'target', lastTarget);
this.state = DragState.WAIT_DRAGGING;
this.addDragListeners();
}
/**
* Mouse move handler handler
*/
onDrag(event) {
var _a, _b;
if (!this.draggable || this.state === DragState.IDLE) {
return;
}
const x = event.clientX, y = event.clientY;
if (this.state === DragState.WAIT_DRAGGING &&
Math.sqrt(Math.pow(x - this.startX, 2) + Math.pow(y - this.startY, 2)) < this.diffStep) {
return;
}
if (this.state === DragState.WAIT_DRAGGING) {
this.j.lock('drag-and-drop-element');
this.state = DragState.DRAGGING;
}
this.j.e.fire('hidePopup hideResizer');
if (!this.draggable.parentNode) {
const target = dataBind(this.draggable, 'target');
css(this.draggable, {
zIndex: 10000000000000,
pointerEvents: 'none',
pointer: 'drag',
position: 'fixed',
opacity: 0.7,
display: 'inline-block',
left: event.clientX,
top: event.clientY,
width: (_a = target === null || target === void 0 ? void 0 : target.offsetWidth) !== null && _a !== void 0 ? _a : 100,
height: (_b = target === null || target === void 0 ? void 0 : target.offsetHeight) !== null && _b !== void 0 ? _b : 100
});
getContainer(this.j, dragAndDropElement).appendChild(this.draggable);
}
css(this.draggable, {
left: event.clientX,
top: event.clientY
});
this.j.s.insertCursorAtPoint(event.clientX, event.clientY);
}
/**
* Mouseup handler in any place
*/
onDragEnd() {
if (this.isInDestruct) {
return;
}
this.removeDragListeners();
this.j.unlock();
this.state = DragState.IDLE;
if (this.draggable) {
Dom.safeRemove(this.draggable);
this.draggable = null;
}
}
/**
* Mouseup handler inside editor
*/
onDrop() {
if (!this.draggable || this.state < DragState.DRAGGING) {
this.onDragEnd();
return;
}
let fragment = dataBind(this.draggable, 'target');
this.onDragEnd();
if (this.isCopyMode) {
fragment = fragment.cloneNode(true);
}
const { parentElement } = fragment;
this.j.s.insertNode(fragment, true, false);
if (parentElement &&
Dom.isEmpty(parentElement) &&
!Dom.isCell(parentElement)) {
Dom.safeRemove(parentElement);
}
if (Dom.isTag(fragment, 'img') && this.j.e) {
this.j.e.fire('afterInsertImage', fragment);
}
this.j.e.fire('synchro');
}
/**
* Add global event listener after drag start
*/
addDragListeners() {
this.j.e
.on(this.j.editor, 'mousemove', this.onDrag)
.on('mouseup', this.onDrop)
.on([this.j.ew, this.ow], 'mouseup', this.onDragEnd);
}
/**
* Remove global event listener after drag start
*/
removeDragListeners() {
this.j.e
.off(this.j.editor, 'mousemove', this.onDrag)
.off('mouseup', this.onDrop)
.off([this.j.ew, this.ow], 'mouseup', this.onDragEnd);
}
/** @override */
beforeDestruct() {
this.onDragEnd();
this.j.e.off('mousedown dragstart', this.onDragStart);
this.removeDragListeners();
}
}
__decorate([
autobind
], dragAndDropElement.prototype, "onDragStart", null);
__decorate([
throttle(ctx => ctx.defaultTimeout / 10)
], dragAndDropElement.prototype, "onDrag", null);
__decorate([
autobind
], dragAndDropElement.prototype, "onDragEnd", null);
__decorate([
autobind
], dragAndDropElement.prototype, "onDrop", null);
pluginSystem.add('dragAndDropElement', dragAndDropElement);