jodit
Version:
Jodit is an awesome and useful wysiwyg editor with filebrowser
163 lines (162 loc) • 6.62 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 * as consts from "../../core/constants.js";
import { INSEPARABLE_TAGS } from "../../core/constants.js";
import { debounce } from "../../core/decorators/index.js";
import { Dom } from "../../core/dom/dom.js";
import { pluginSystem } from "../../core/global.js";
import { isMarker } from "../../core/helpers/checker/is-marker.js";
import { attr } from "../../core/helpers/utils/attr.js";
import { css } from "../../core/helpers/utils/css.js";
import { Plugin } from "../../core/plugin/plugin.js";
import "./config.js";
/**
* Check if root node is empty
* @private
*/
export function isEditorEmpty(root) {
var _a;
if (!root.firstChild) {
return true;
}
const first = root.firstChild;
if (INSEPARABLE_TAGS.has((_a = first.nodeName) === null || _a === void 0 ? void 0 : _a.toLowerCase()) ||
/^(TABLE)$/i.test(first.nodeName)) {
return false;
}
const next = Dom.next(first, node => node && !Dom.isEmptyTextNode(node), root);
if (Dom.isText(first) && !next) {
return Dom.isEmptyTextNode(first);
}
return (!next &&
Dom.each(first, elm => !(Dom.isLeaf(elm) || Dom.isList(elm)) &&
(Dom.isEmpty(elm) || Dom.isTag(elm, 'br'))));
}
/**
* Show placeholder inside empty editor
*/
export class placeholder extends Plugin {
constructor() {
super(...arguments);
this.addNativeListeners = () => {
this.j.e
.off(this.j.editor, 'input.placeholder keydown.placeholder')
.on(this.j.editor, 'input.placeholder keydown.placeholder', this.toggle);
};
this.addEvents = () => {
const editor = this.j;
if (editor.o.useInputsPlaceholder &&
editor.element.hasAttribute('placeholder')) {
this.placeholderElm.innerHTML =
attr(editor.element, 'placeholder') || '';
}
editor.e.fire('placeholder', this.placeholderElm.innerHTML);
editor.e
.off('.placeholder')
.on('changePlace.placeholder', this.addNativeListeners)
.on('change.placeholder focus.placeholder keyup.placeholder mouseup.placeholder keydown.placeholder ' +
'mousedown.placeholder afterSetMode.placeholder changePlace.placeholder', this.toggle)
.on(window, 'load', this.toggle);
this.addNativeListeners();
this.toggle();
};
}
afterInit(editor) {
if (!editor.o.showPlaceholder) {
return;
}
this.placeholderElm = editor.c.fromHTML(`<span data-ref="placeholder" style="display: none;" class="jodit-placeholder">${editor.i18n(editor.o.placeholder)}</span>`);
if (editor.o.direction === 'rtl') {
this.placeholderElm.style.right = '0px';
this.placeholderElm.style.direction = 'rtl';
}
editor.e
.on('readonly', (isReadOnly) => {
if (isReadOnly) {
this.hide();
}
else {
this.toggle();
}
})
.on('changePlace', this.addEvents);
this.addEvents();
}
show() {
const editor = this.j;
if (editor.o.readonly) {
return;
}
let marginTop = 0, marginLeft = 0;
const current = editor.s.current(), wrapper = (current && Dom.closest(current, Dom.isBlock, editor.editor)) ||
editor.editor;
const style = editor.ew.getComputedStyle(wrapper);
const styleEditor = editor.ew.getComputedStyle(editor.editor);
editor.workplace.appendChild(this.placeholderElm);
const { firstChild } = editor.editor;
if (Dom.isElement(firstChild) && !isMarker(firstChild)) {
const style2 = editor.ew.getComputedStyle(firstChild);
marginTop = parseInt(style2.getPropertyValue('margin-top'), 10);
marginLeft = parseInt(style2.getPropertyValue('margin-left'), 10);
this.placeholderElm.style.fontSize =
parseInt(style2.getPropertyValue('font-size'), 10) + 'px';
this.placeholderElm.style.lineHeight =
style2.getPropertyValue('line-height');
}
else {
this.placeholderElm.style.fontSize =
parseInt(style.getPropertyValue('font-size'), 10) + 'px';
this.placeholderElm.style.lineHeight =
style.getPropertyValue('line-height');
}
css(this.placeholderElm, {
display: 'block',
textAlign: style.getPropertyValue('text-align'),
paddingTop: parseInt(styleEditor.paddingTop, 10) + 'px',
paddingLeft: parseInt(styleEditor.paddingLeft, 10) + 'px',
paddingRight: parseInt(styleEditor.paddingRight, 10) + 'px',
marginTop: Math.max(parseInt(style.getPropertyValue('margin-top'), 10), marginTop),
marginLeft: Math.max(parseInt(style.getPropertyValue('margin-left'), 10), marginLeft)
});
}
hide() {
Dom.safeRemove(this.placeholderElm);
}
toggle() {
const editor = this.j;
if (!editor.editor || editor.isInDestruct) {
return;
}
if (editor.getRealMode() !== consts.MODE_WYSIWYG) {
this.hide();
return;
}
if (!isEditorEmpty(editor.editor)) {
this.hide();
}
else {
this.show();
}
}
beforeDestruct(jodit) {
this.hide();
jodit.e.off('.placeholder').off(window, 'load', this.toggle);
}
}
__decorate([
debounce(ctx => ctx.defaultTimeout / 10, true)
], placeholder.prototype, "toggle", null);
pluginSystem.add('placeholder', placeholder);