jodit
Version:
Jodit is awesome and usefully wysiwyg editor with filebrowser
259 lines (213 loc) • 5.61 kB
text/typescript
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2020 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import './placeholder.less';
import { Config } from '../../config';
import * as consts from '../../core/constants';
import { css, attr } from '../../core/helpers';
import { Dom } from '../../core/dom';
import { IJodit } from '../../types';
import { Plugin } from '../../core/plugin';
import { MAY_BE_REMOVED_WITH_KEY } from '../../core/constants';
/**
* Show placeholder
*/
/**
* @property {boolean} showPlaceholder=true Show placeholder
* @example
* ```javascript
* var editor = new Jodit('#editor', {
* showPlaceholder: false
* });
* ```
*/
declare module '../../config' {
interface Config {
showPlaceholder: boolean;
useInputsPlaceholder: boolean;
placeholder: string;
}
}
Config.prototype.showPlaceholder = true;
/**
* @property useInputsPlaceholder=true use a placeholder from original input field, if it was set
* @example
* ```javascript
* //<textarea id="editor" placeholder="start typing text ..." cols="30" rows="10"></textarea>
* var editor = new Jodit('#editor', {
* useInputsPlaceholder: true
* });
* ```
*/
Config.prototype.useInputsPlaceholder = true;
/**
* @property placeholder='Type something' Default placeholder
* @example
* ```javascript
* var editor = new Jodit('#editor', {
* placeholder: 'start typing text ...'
* });
* ```
*/
Config.prototype.placeholder = 'Type something';
/**
* Show placeholder inside empty editor
*
* @param {Jodit} editor
*/
export class placeholder extends Plugin {
private placeholderElm!: HTMLElement;
protected afterInit(editor: IJodit): void {
if (!editor.o.showPlaceholder) {
return;
}
this.toggle = editor.async.debounce(
this.toggle.bind(this),
this.j.defaultTimeout / 10
);
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: boolean) => {
if (isReadOnly) {
this.hide();
} else {
this.toggle();
}
})
.on('changePlace', this.init);
this.addEvents();
}
private 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(
'change.placeholder focus.placeholder keyup.placeholder mouseup.placeholder keydown.placeholder ' +
'mousedown.placeholder afterSetMode.placeholder changePlace.placeholder',
this.toggle
)
.on(window, 'load', this.toggle);
this.toggle();
};
private show() {
const editor = this.j;
if (editor.o.readonly) {
return;
}
let marginTop: number = 0,
marginLeft: number = 0;
const current = editor.s.current(),
wrapper =
(current &&
Dom.closest(
current,
n => Dom.isBlock(n, editor.ew),
editor.editor
)) ||
editor.editor;
const style = editor.ew.getComputedStyle(wrapper);
editor.workplace.appendChild(this.placeholderElm);
if (Dom.isElement(editor.editor.firstChild)) {
const style2 = editor.ew.getComputedStyle(
editor.editor.firstChild as Element
);
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'),
marginTop: Math.max(
parseInt(style.getPropertyValue('margin-top'), 10),
marginTop
),
marginLeft: Math.max(
parseInt(style.getPropertyValue('margin-left'), 10),
marginLeft
)
});
}
private hide(): void {
Dom.safeRemove(this.placeholderElm);
}
private toggle() {
const editor = this.j;
if (!editor.editor || editor.isInDestruct) {
return;
}
if (editor.getRealMode() !== consts.MODE_WYSIWYG) {
this.hide();
return;
}
if (!this.isEmpty(editor.editor)) {
this.hide();
} else {
this.show();
}
}
private isEmpty(root: HTMLElement): boolean {
if (!root.firstChild) {
return true;
}
const first = root.firstChild;
if (
MAY_BE_REMOVED_WITH_KEY.test(first.nodeName) ||
/^(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);
}
if (
!next &&
Dom.each(
first,
elm =>
!Dom.isTag(elm, ['ul', 'li', 'ol']) &&
(Dom.isEmpty(elm) || Dom.isTag(elm, 'br'))
)
) {
return true;
}
return false;
}
protected beforeDestruct(jodit: IJodit): void {
this.hide();
jodit.e.off('.placeholder').off(window, 'load', this.toggle);
}
}