jodit
Version:
Jodit is an awesome and useful wysiwyg editor with filebrowser
247 lines (246 loc) • 8.64 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 { cache, cached, watch } from "../../core/decorators/index.js";
import { Dom } from "../../core/dom/dom.js";
import { pluginSystem } from "../../core/global.js";
import { isAbortError, isNumeric, markOwner } from "../../core/helpers/index.js";
import { Plugin } from "../../core/plugin/plugin.js";
import { Button } from "../../core/ui/button/index.js";
import "./config.js";
import { UIImagePropertiesForm } from "./ui/ui-image-form.js";
import { openImageEditorDialog } from "./utils/open-image-editor.js";
import { openImagePopup } from "./utils/open-image-popup.js";
import { readValuesFromImage } from "./readers/index.js";
import { applyValuesToImage } from "./writers/index.js";
/**
* Plug-in for image editing window
*
* @example
* ```javascript
* const editor = Jodit.make('#editor', {
* image: {
* editSrc: false,
* editLink: false
* }
* });
* ```
*/
/**
* Show dialog with image's options
*/
export class imageProperties extends Plugin {
constructor() {
super(...arguments);
this.state = {
image: new Image(),
sourceImage: new Image(),
get ratio() {
const { naturalWidth, naturalHeight } = this.image;
return naturalWidth / naturalHeight || 1;
},
sizeIsLocked: true,
marginIsLocked: true,
values: {
style: '',
imageSrc: '',
borderRadius: 0,
imageTitle: '',
imageAlt: '',
imageLink: '',
imageLinkOpenInNewTab: false,
imageWidth: 0,
imageHeight: 0,
marginTop: 0,
marginRight: 0,
marginBottom: 0,
marginLeft: 0,
classes: '',
id: '',
align: ''
}
};
this.activeTabState = {
activeTab: 'Image'
};
}
get form() {
return new UIImagePropertiesForm(this.j, this.state, this.activeTabState, {
openImageEditor: () => openImageEditorDialog(this.j, this.state),
openImagePopup: target => openImagePopup(this.j, this.dialog, this.state, target)
});
}
/**
* Dialog for form
*/
get dialog() {
const { j } = this;
const dialog = j.dlg({
minWidth: Math.min(400, screen.width),
minHeight: 590,
buttons: ['fullsize', 'dialog.close']
});
const buttons = this.__buttons;
buttons.check.onAction(() => {
applyValuesToImage(j, this.state, this.state.sourceImage);
j.synchronizeValues();
dialog.close();
});
buttons.remove.onAction(() => {
j.s.removeNode(this.state.sourceImage);
dialog.close();
});
buttons.cancel.onAction(() => {
dialog.close();
});
dialog.setHeader(j.i18n('Image properties'));
dialog.setContent(this.form);
dialog.setFooter([[buttons.cancel, buttons.remove], buttons.check]);
j.e.on(dialog, 'afterClose', () => {
if (this.state.image.parentNode &&
j.o.image.selectImageAfterClose) {
j.s.select(this.state.sourceImage);
}
});
dialog.setSize(j.o.image.dialogWidth);
markOwner(j, dialog.container);
return dialog;
}
get __buttons() {
const { j } = this;
return {
check: Button(j, 'ok', 'Apply', 'primary'),
remove: Button(j, 'bin', 'Delete'),
cancel: Button(j, 'cancel', 'Cancel')
};
}
/**
* Open dialog editing image properties
*
* @example
* ```javascript
* const editor = Jodit.makeJodit('#editor');
* img = editor.createInside.element('img');
*
* img.setAttribute('src', 'images/some-image.png');
* editor.s.insertImage(img);
* // open the properties of the editing window
* editor.events.fire('openImageProperties', img);
* ```
*/
open() {
this.activeTabState.activeTab = 'Image';
this.__lock();
this.dialog.open().setModal(true).setPosition();
this.async
.promise((resolve, reject) => readValuesFromImage(this.j, this.state).then(resolve, reject))
.catch((e) => {
if (!isAbortError(e)) {
this.dialog.message.error(e.message);
}
})
.finally(() => this.__unlock());
return false;
}
__lock() {
this.dialog.lock();
this.form.setMod('lock', true);
Object.values(this.__buttons).forEach(b => (b.state.disabled = true));
}
__unlock() {
this.dialog.unlock();
this.form.setMod('lock', false);
Object.values(this.__buttons).forEach(b => (b.state.disabled = false));
}
/** @override **/
afterInit(editor) {
const self = this;
editor.e
.on('afterConstructor changePlace', () => {
editor.e
.off(editor.editor, '.imageproperties')
.on(editor.editor, 'dblclick.imageproperties', (e) => {
const image = e.target;
if (!Dom.isTag(image, 'img')) {
return;
}
if (editor.o.image.openOnDblClick) {
if (this.j.e.fire('openOnDblClick', image) ===
false) {
return;
}
self.state.sourceImage = image;
self.state.image = image.cloneNode(true);
if (!editor.o.readonly) {
e.stopImmediatePropagation();
e.preventDefault();
self.open();
}
}
else {
e.stopImmediatePropagation();
editor.s.select(image);
}
});
})
.on('openImageProperties.imageproperties', (image) => {
self.state.sourceImage = image;
this.state.image = image.cloneNode(true);
this.open();
});
}
async onStateValuesImageSrcChange() {
const { image, values } = this.state;
if (!image.src) {
return;
}
try {
this.__lock();
await image.decode();
if (this.state.sizeIsLocked && isNumeric(values.imageWidth)) {
const w = parseFloat(values.imageWidth.toString());
values.imageHeight = Math.round(w / this.state.ratio);
}
this.j.e.fire('updateImageProperties.imageproperties', image);
}
catch (e) {
this.j.alert(e.message);
}
finally {
this.__unlock();
}
}
/** @override */
beforeDestruct(editor) {
var _a, _b, _c;
Object.values((_a = cached(this, '__buttons')) !== null && _a !== void 0 ? _a : {}).forEach(b => b.destruct());
(_b = cached(this, 'dialog')) === null || _b === void 0 ? void 0 : _b.destruct();
(_c = cached(this, 'form')) === null || _c === void 0 ? void 0 : _c.destruct();
editor.e.off(editor.editor, '.imageproperties').off('.imageproperties');
}
}
__decorate([
cache
], imageProperties.prototype, "form", null);
__decorate([
cache
], imageProperties.prototype, "dialog", null);
__decorate([
cache
], imageProperties.prototype, "__buttons", null);
__decorate([
watch('state.image')
], imageProperties.prototype, "onStateValuesImageSrcChange", null);
pluginSystem.add('imageProperties', imageProperties);