inital commit

This commit is contained in:
2026-01-01 15:25:19 +05:30
commit f0ae49465a
36361 changed files with 4894111 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
/*!
* 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
*/
/**
* [[include:plugins/clean-html/README.md]]
* @packageDocumentation
* @module plugins/clean-html
*/
import type { IJodit } from "../../types/index";
import { Plugin } from "../../core/plugin/plugin";
import "./config";
/**
* Clean HTML after removeFormat and insertHorizontalRule command
*/
export declare class cleanHtml extends Plugin {
/** @override */
buttons: Plugin['buttons'];
/** @override */
protected afterInit(jodit: IJodit): void;
private get isEditMode();
/**
* Clean HTML code on every change
*/
protected onChangeCleanHTML(): void;
private currentSelectionNode;
private walker;
protected startWalker(): void;
protected beforeCommand(command: string): void | false;
/**
* Event handler when manually assigning a value to the HTML editor.
*/
protected onBeforeSetNativeEditorValue(data: {
value: string;
}): boolean;
protected onSafeHTML(sandBox: HTMLElement): void;
/** @override */
protected beforeDestruct(): void;
}

120
node_modules/jodit/esm/plugins/clean-html/clean-html.js generated vendored Normal file
View File

@@ -0,0 +1,120 @@
/*!
* 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 { hook, watch } from "../../core/decorators/index.js";
import { Dom } from "../../core/dom/dom.js";
import { LazyWalker } from "../../core/dom/lazy-walker.js";
import { pluginSystem } from "../../core/global.js";
import { safeHTML } from "../../core/helpers/html/safe-html.js";
import { Plugin } from "../../core/plugin/plugin.js";
import "./config.js";
import { getHash, removeFormatForCollapsedSelection, removeFormatForSelection, visitNodeWalker } from "./helpers/index.js";
/**
* Clean HTML after removeFormat and insertHorizontalRule command
*/
export class cleanHtml extends Plugin {
constructor() {
super(...arguments);
/** @override */
this.buttons = [
{
name: 'eraser',
group: 'font-style'
}
];
this.currentSelectionNode = null;
this.walker = new LazyWalker(this.j.async, {
timeout: this.j.o.cleanHTML.timeout
});
}
/** @override */
afterInit(jodit) { }
get isEditMode() {
return !(this.j.isInDestruct ||
!this.j.isEditorMode() ||
this.j.getReadOnly());
}
/**
* Clean HTML code on every change
*/
onChangeCleanHTML() {
if (!this.isEditMode) {
return;
}
const editor = this.j;
this.walker.setWork(editor.editor);
this.currentSelectionNode = editor.s.current();
}
startWalker() {
const { jodit } = this;
const allow = getHash(this.j.o.cleanHTML.allowTags);
const deny = getHash(this.j.o.cleanHTML.denyTags);
this.walker
.on('visit', (node) => visitNodeWalker(jodit, node, allow, deny, this.currentSelectionNode))
.on('end', (affected) => {
this.j.e.fire(affected
? 'internalChange finishedCleanHTMLWorker'
: 'finishedCleanHTMLWorker');
});
}
beforeCommand(command) {
if (command.toLowerCase() === 'removeformat') {
if (this.j.s.isCollapsed()) {
removeFormatForCollapsedSelection(this.j);
}
else {
removeFormatForSelection(this.j);
}
return false;
}
}
/**
* Event handler when manually assigning a value to the HTML editor.
*/
onBeforeSetNativeEditorValue(data) {
const [sandBox, iframe] = this.j.o.cleanHTML.useIframeSandbox
? this.j.createInside.sandbox()
: [this.j.createInside.div()];
sandBox.innerHTML = data.value;
this.onSafeHTML(sandBox);
data.value = sandBox.innerHTML;
safeHTML(sandBox, { safeJavaScriptLink: true, removeOnError: true });
Dom.safeRemove(iframe);
return false;
}
onSafeHTML(sandBox) {
safeHTML(sandBox, this.j.o.cleanHTML);
}
/** @override */
beforeDestruct() {
this.walker.destruct();
}
}
__decorate([
watch([':change', ':afterSetMode', ':afterInit', ':mousedown', ':keydown'])
], cleanHtml.prototype, "onChangeCleanHTML", null);
__decorate([
hook('ready')
], cleanHtml.prototype, "startWalker", null);
__decorate([
watch(':beforeCommand')
], cleanHtml.prototype, "beforeCommand", null);
__decorate([
watch(':beforeSetNativeEditorValue')
], cleanHtml.prototype, "onBeforeSetNativeEditorValue", null);
__decorate([
watch(':safeHTML')
], cleanHtml.prototype, "onSafeHTML", null);
pluginSystem.add('cleanHtml', cleanHtml);

105
node_modules/jodit/esm/plugins/clean-html/config.d.ts generated vendored Normal file
View File

@@ -0,0 +1,105 @@
/*!
* 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
*/
/**
* @module plugins/clean-html
*/
import type { HTMLTagNames, IDictionary, Nullable } from "../../types/index";
declare module 'jodit/config' {
interface Config {
cleanHTML: {
timeout: number;
/**
* Replace &amp;nbsp; to plain space
*/
replaceNBSP: boolean;
/**
* Remove empty P tags, if they are not in the beginning of the text
*/
fillEmptyParagraph: boolean;
/**
* Remove empty elements
*/
removeEmptyElements: boolean;
/**
* Replace old tags to new eg. <i> to <em>, <b> to <strong>
*/
replaceOldTags: IDictionary<HTMLTagNames> | false;
/**
* You can use an iframe with the sandbox attribute to safely paste and test HTML code.
* It prevents scripts and handlers from running, but it does slow things down.
*
* ```javascript
* Jodit.make('#editor', {
* cleanHTML: {
* useIframeSandbox: true
* }
* });
* ```
*/
useIframeSandbox: boolean;
/**
* Remove onError attributes
*/
removeOnError: boolean;
/**
* Safe href="javascript:" links
*/
safeJavaScriptLink: boolean;
/**
* The allowTags option defines which elements will remain in the
* edited text when the editor saves. You can use this limit the returned HTML.
* @example
* ```javascript
* const jodit = new Jodit.make('#editor', {
* cleanHTML: {
* cleanOnPaste: false
* }
* });
* ```
* @example
* ```javascript
* const editor = Jodit.make('#editor', {
* cleanHTML: {
* allowTags: 'p,a[href],table,tr,td, img[src=1.png]' // allow only <p>,<a>,<table>,<tr>,<td>,<img> tags and
* for <a> allow only `href` attribute and <img> allow only `src` attribute == '1.png'
* }
* });
* editor.value = 'Sorry! <strong>Goodby</strong>\
* <span>mr.</span> <a style="color:red" href="https://xdsoft.net">Freeman</a>';
* console.log(editor.value); //Sorry! <a href="https://xdsoft.net">Freeman</a>
* ```
*
* @example
* ```javascript
* const editor = Jodit.make('#editor', {
* cleanHTML: {
* allowTags: {
* p: true,
* a: {
* href: true
* },
* table: true,
* tr: true,
* td: true,
* img: {
* src: '1.png'
* }
* }
* }
* });
* ```
*/
allowTags: false | string | IDictionary<string>;
denyTags: false | string | IDictionary<string>;
/**
* Node filtering rules that do not need to be applied to content
* The full list of rules is generated dynamically from the folder
* https://github.com/xdan/jodit/tree/main/src/plugins/clean-html/helpers/visitor/filters
*/
disableCleanFilter: Nullable<Set<string>>;
};
}
}

29
node_modules/jodit/esm/plugins/clean-html/config.js generated vendored Normal file
View File

@@ -0,0 +1,29 @@
/*!
* 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
*/
import { Icon } from "../../core/ui/icon.js";
import { Config } from "../../config.js";
import eraserIcon from "./eraser.svg.js";
Config.prototype.cleanHTML = {
timeout: 300,
removeEmptyElements: true,
fillEmptyParagraph: true,
replaceNBSP: true,
replaceOldTags: {
i: 'em',
b: 'strong'
},
allowTags: false,
denyTags: 'script',
useIframeSandbox: false,
removeOnError: true,
safeJavaScriptLink: true,
disableCleanFilter: null
};
Config.prototype.controls.eraser = {
command: 'removeFormat',
tooltip: 'Clear Formatting'
};
Icon.set('eraser', eraserIcon);

View File

@@ -0,0 +1 @@
export default "<svg xmlns='http://www.w3.org/2000/svg' viewBox=\"0 0 1792 1792\"> <path d=\"M832 1408l336-384h-768l-336 384h768zm1013-1077q15 34 9.5 71.5t-30.5 65.5l-896 1024q-38 44-96 44h-768q-38 0-69.5-20.5t-47.5-54.5q-15-34-9.5-71.5t30.5-65.5l896-1024q38-44 96-44h768q38 0 69.5 20.5t47.5 54.5z\"/> </svg> ";

View File

@@ -0,0 +1,13 @@
/*!
* 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
*/
/**
* @module plugins/clean-html
*/
import type { IDictionary } from "../../../types/index";
/**
* @private
*/
export declare function getHash(tags: false | string | IDictionary<string>): IDictionary | false;

View File

@@ -0,0 +1,48 @@
/*!
* 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
*/
import { isString } from "../../../core/helpers/checker/is-string.js";
import { trim } from "../../../core/helpers/string/trim.js";
/**
* @private
*/
export function getHash(tags) {
const attributesReg = /([^[]*)\[([^\]]+)]/;
const separator = /[\s]*,[\s]*/, attrReg = /^(.*)[\s]*=[\s]*(.*)$/;
const tagsHash = {};
if (isString(tags)) {
tags.split(separator).map((elm) => {
elm = trim(elm);
const attr = attributesReg.exec(elm), allowAttributes = {}, attributeMap = (attrName) => {
attrName = trim(attrName);
const val = attrReg.exec(attrName);
if (val) {
allowAttributes[val[1]] = val[2];
}
else {
allowAttributes[attrName] = true;
}
};
if (attr) {
const attr2 = attr[2].split(separator);
if (attr[1]) {
attr2.forEach(attributeMap);
tagsHash[attr[1].toUpperCase()] = allowAttributes;
}
}
else {
tagsHash[elm.toUpperCase()] = true;
}
});
return tagsHash;
}
if (tags) {
Object.keys(tags).forEach(tagName => {
tagsHash[tagName.toUpperCase()] = tags[tagName];
});
return tagsHash;
}
return false;
}

View File

@@ -0,0 +1,12 @@
/*!
* 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
*/
/**
* @module plugins/clean-html
*/
export * from "./get-hash";
export * from "./remove-format/remove-format-for-collapsed-selection";
export * from "./remove-format/remove-format-for-selection";
export * from "./visitor/visit-node-walker";

View File

@@ -0,0 +1,12 @@
/*!
* 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
*/
/**
* @module plugins/clean-html
*/
export * from "./get-hash.js";
export * from "./remove-format/remove-format-for-collapsed-selection.js";
export * from "./remove-format/remove-format-for-selection.js";
export * from "./visitor/visit-node-walker.js";

View File

@@ -0,0 +1,19 @@
/*!
* 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
*/
/**
* @module plugins/clean-html
*/
import type { IJodit, Nullable } from "../../../../types/index";
/**
* For collapsed selection move cursor outside or split inline block
* @private
*/
export declare function removeFormatForCollapsedSelection(jodit: IJodit, fake?: Node): Nullable<Text> | void;
/**
* Element has inline display mode
* @private
*/
export declare function isInlineBlock(node: Nullable<Node>): node is Node;

View File

@@ -0,0 +1,45 @@
/*!
* 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
*/
import { INSEPARABLE_TAGS } from "../../../../core/constants.js";
import { Dom } from "../../../../core/dom/dom.js";
/**
* For collapsed selection move cursor outside or split inline block
* @private
*/
export function removeFormatForCollapsedSelection(jodit, fake) {
const { s } = jodit;
let fakeNode = fake;
if (!fakeNode) {
fakeNode = jodit.createInside.fake();
const { range } = s;
Dom.safeInsertNode(range, fakeNode);
range.collapse();
}
const mainInline = Dom.furthest(fakeNode, isInlineBlock, jodit.editor);
if (mainInline) {
if (s.cursorOnTheLeft(mainInline)) {
Dom.before(mainInline, fakeNode);
}
else if (s.cursorOnTheRight(mainInline)) {
Dom.after(mainInline, fakeNode);
}
else {
const leftHand = s.splitSelection(mainInline);
leftHand && Dom.after(leftHand, fakeNode);
}
}
if (!fake) {
s.setCursorBefore(fakeNode);
Dom.safeRemove(fakeNode);
}
}
/**
* Element has inline display mode
* @private
*/
export function isInlineBlock(node) {
return Dom.isInlineBlock(node) && !Dom.isTag(node, INSEPARABLE_TAGS);
}

View File

@@ -0,0 +1,14 @@
/*!
* 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
*/
/**
* @module plugins/clean-html
*/
import type { IJodit } from "../../../../types/index";
/**
* Remove formatting for all selected elements
* @private
*/
export declare function removeFormatForSelection(jodit: IJodit): void;

View File

@@ -0,0 +1,53 @@
/*!
* 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
*/
import { Dom } from "../../../../core/dom/dom.js";
import { attr } from "../../../../core/helpers/utils/index.js";
import { isInlineBlock, removeFormatForCollapsedSelection } from "./remove-format-for-collapsed-selection.js";
/**
* Remove formatting for all selected elements
* @private
*/
export function removeFormatForSelection(jodit) {
const { s, editor, createInside } = jodit, { range } = s, left = range.cloneRange(), right = range.cloneRange(), fakeLeft = createInside.fake(), fakeRight = createInside.fake();
left.collapse(true);
right.collapse(false);
Dom.safeInsertNode(left, fakeLeft);
Dom.safeInsertNode(right, fakeRight);
range.setStartBefore(fakeLeft);
range.collapse(true);
s.selectRange(range);
removeFormatForCollapsedSelection(jodit, fakeLeft);
range.setEndAfter(fakeRight);
range.collapse(false);
s.selectRange(range);
removeFormatForCollapsedSelection(jodit, fakeRight);
const shouldUnwrap = [];
Dom.between(fakeLeft, fakeRight, node => {
if (isInlineBlock(node) && !Dom.isTag(node, 'a')) {
shouldUnwrap.push(node);
}
if (Dom.isElement(node) && attr(node, 'style')) {
attr(node, 'style', null);
}
});
shouldUnwrap.forEach(node => Dom.unwrap(node));
const clearParent = (node, left) => {
if (!Dom.findNotEmptySibling(node, left)) {
const pn = node.parentNode;
if (pn && pn !== editor && attr(pn, 'style')) {
attr(pn, 'style', null);
clearParent(pn, left);
return true;
}
}
};
clearParent(fakeLeft, true) && clearParent(fakeRight, false);
range.setStartAfter(fakeLeft);
range.setEndBefore(fakeRight);
s.selectRange(range);
Dom.safeRemove(fakeLeft);
Dom.safeRemove(fakeRight);
}

View File

@@ -0,0 +1,13 @@
/*!
* 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
*/
/**
* @module plugins/clean-html
*/
import type { IDictionary, IJodit } from "../../../../../types/index";
/**
* @private
*/
export declare function allowAttributes(jodit: IJodit, nodeElm: Node, hadEffect: boolean, allow: IDictionary | false): boolean;

View File

@@ -0,0 +1,30 @@
/*!
* 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
*/
import { Dom } from "../../../../../core/dom/dom.js";
/**
* @private
*/
export function allowAttributes(jodit, nodeElm, hadEffect, allow) {
if (allow && Dom.isElement(nodeElm) && allow[nodeElm.nodeName] !== true) {
const attrs = nodeElm.attributes;
if (attrs && attrs.length) {
const removeAttrs = [];
for (let i = 0; i < attrs.length; i += 1) {
const attr = allow[nodeElm.nodeName][attrs[i].name];
if (!attr || (attr !== true && attr !== attrs[i].value)) {
removeAttrs.push(attrs[i].name);
}
}
if (removeAttrs.length) {
hadEffect = true;
}
removeAttrs.forEach(attr => {
nodeElm.removeAttribute(attr);
});
}
}
return hadEffect;
}

View File

@@ -0,0 +1,13 @@
/*!
* 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
*/
/**
* @module plugins/clean-html
*/
import type { IJodit } from "../../../../../types/index";
/**
* @private
*/
export declare function fillEmptyParagraph(jodit: IJodit, nodeElm: Node, hadEffect: boolean): boolean;

View File

@@ -0,0 +1,28 @@
/*!
* 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
*/
import { INSEPARABLE_TAGS } from "../../../../../core/constants.js";
import { Dom } from "../../../../../core/dom/dom.js";
const TABLE_CONTAINER_TAGS = new Set([
'table',
'tbody',
'thead',
'tfoot',
'tr'
]);
/**
* @private
*/
export function fillEmptyParagraph(jodit, nodeElm, hadEffect) {
if (jodit.o.cleanHTML.fillEmptyParagraph &&
Dom.isBlock(nodeElm) &&
Dom.isEmpty(nodeElm, INSEPARABLE_TAGS) &&
!Dom.isTag(nodeElm, TABLE_CONTAINER_TAGS)) {
const br = jodit.createInside.element('br');
nodeElm.appendChild(br);
return true;
}
return hadEffect;
}

View File

@@ -0,0 +1,18 @@
/*!
* 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
*/
/**
* @module plugins/clean-html
*/
/**
* @private
*/
export * from "./allow-attributes";
export * from "./fill-empty-paragraph";
export * from "./remove-empty-text-node";
export * from "./remove-inv-text-nodes";
export * from "./replace-old-tags";
export * from "./sanitize-attributes";
export * from "./try-remove-node";

View File

@@ -0,0 +1,18 @@
/*!
* 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
*/
/**
* @module plugins/clean-html
*/
/**
* @private
*/
export * from "./allow-attributes.js";
export * from "./fill-empty-paragraph.js";
export * from "./remove-empty-text-node.js";
export * from "./remove-inv-text-nodes.js";
export * from "./replace-old-tags.js";
export * from "./sanitize-attributes.js";
export * from "./try-remove-node.js";

View File

@@ -0,0 +1,13 @@
/*!
* 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
*/
/**
* @module plugins/clean-html
*/
import type { IJodit, Nullable } from "../../../../../types/index";
/**
* @private
*/
export declare function removeEmptyTextNode(jodit: IJodit, node: Node, hadEffect: boolean, arg: unknown, argi: unknown, currentNode: Nullable<Node>): boolean;

View File

@@ -0,0 +1,19 @@
/*!
* 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
*/
import { Dom } from "../../../../../core/dom/dom.js";
/**
* @private
*/
export function removeEmptyTextNode(jodit, node, hadEffect, arg, argi, currentNode) {
if (Dom.isText(node) && !node.nodeValue) {
if (node === currentNode && jodit.s.isCollapsed()) {
jodit.s.setCursorAfter(node);
}
Dom.safeRemove(node);
return true;
}
return hadEffect;
}

View File

@@ -0,0 +1,13 @@
/*!
* 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
*/
/**
* @module plugins/clean-html
*/
import type { IJodit, Nullable } from "../../../../../types/index";
/**
* @private
*/
export declare function removeInvTextNodes(jodit: IJodit, node: Node, hadEffect: boolean, arg: unknown, argi: unknown, currentNode: Nullable<Node>): boolean;

View File

@@ -0,0 +1,30 @@
/*!
* 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
*/
import { INVISIBLE_SPACE_REG_EXP as INV_REG } from "../../../../../core/constants.js";
import { Dom } from "../../../../../core/dom/dom.js";
/**
* @private
*/
export function removeInvTextNodes(jodit, node, hadEffect, arg, argi, currentNode) {
if (currentNode === node || !Dom.isText(node) || node.nodeValue == null) {
return hadEffect;
}
if (!INV_REG().test(node.nodeValue)) {
return hadEffect;
}
const focusBox = Dom.furthest(currentNode, Dom.isBlock, jodit.editor);
if (!focusBox || Dom.isOrContains(focusBox, node)) {
return hadEffect;
}
node.nodeValue = node.nodeValue.replace(INV_REG(), '');
if (node === currentNode && jodit.s.isCollapsed()) {
jodit.s.setCursorAfter(node);
}
if (!node.nodeValue) {
Dom.safeRemove(node);
}
return true;
}

View File

@@ -0,0 +1,13 @@
/*!
* 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
*/
/**
* @module plugins/clean-html
*/
import type { IJodit } from "../../../../../types/index";
/**
* @private
*/
export declare function replaceOldTags(jodit: IJodit, nodeElm: Node, hadEffect: boolean): boolean;

View File

@@ -0,0 +1,31 @@
/*!
* 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
*/
import { Dom } from "../../../../../core/dom/dom.js";
/**
* @private
*/
export function replaceOldTags(jodit, nodeElm, hadEffect) {
const newNodeElm = replaceIfMatched(jodit, nodeElm, jodit.o.cleanHTML.replaceOldTags);
if (nodeElm !== newNodeElm) {
nodeElm = newNodeElm;
return true;
}
return hadEffect;
}
/**
* Replaces an element with a newer one if specified in the configuration match
* @private
*/
function replaceIfMatched(jodit, oldParent, list) {
if (!list || !Dom.isHTMLElement(oldParent)) {
return oldParent;
}
const tagName = list[oldParent.nodeName.toLowerCase()] || list[oldParent.nodeName];
if (tagName) {
return Dom.replace(oldParent, tagName, jodit.createInside, true, false);
}
return oldParent;
}

View File

@@ -0,0 +1,13 @@
/*!
* 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
*/
/**
* @module plugins/clean-html
*/
import type { IJodit } from "../../../../../types/index";
/**
* @private
*/
export declare function sanitizeAttributes(jodit: IJodit, nodeElm: Node, hadEffect: boolean): boolean;

View File

@@ -0,0 +1,20 @@
/*!
* 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
*/
import { Dom } from "../../../../../core/dom/dom.js";
import { sanitizeHTMLElement } from "../../../../../core/helpers/index.js";
/**
* @private
*/
export function sanitizeAttributes(jodit, nodeElm, hadEffect) {
if (Dom.isElement(nodeElm) &&
sanitizeHTMLElement(nodeElm, {
safeJavaScriptLink: jodit.options.cleanHTML.safeJavaScriptLink,
removeOnError: jodit.options.cleanHTML.removeOnError
})) {
return true;
}
return hadEffect;
}

View File

@@ -0,0 +1,13 @@
/*!
* 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
*/
/**
* @module plugins/clean-html
*/
import type { IDictionary, IJodit, Nullable } from "../../../../../types/index";
/**
* @private
*/
export declare function tryRemoveNode(jodit: IJodit, nodeElm: Node, hadEffect: boolean, allowTags: IDictionary | false, denyTags: IDictionary | false, currentSelectionNode: Nullable<Node>): boolean;

View File

@@ -0,0 +1,39 @@
/*!
* 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
*/
import { IS_INLINE } from "../../../../../core/constants.js";
import { Dom } from "../../../../../core/dom/dom.js";
import { trimInv } from "../../../../../core/helpers/string/trim.js";
/**
* @private
*/
export function tryRemoveNode(jodit, nodeElm, hadEffect, allowTags, denyTags, currentSelectionNode) {
if (isRemovableNode(jodit, nodeElm, currentSelectionNode, allowTags, denyTags)) {
Dom.safeRemove(nodeElm);
return true;
}
return hadEffect;
}
/**
* @private
*/
function isRemovableNode(jodit, node, current, allow, deny) {
if (!Dom.isText(node)) {
if (allow && !allow[node.nodeName]) {
return true;
}
if (!allow && deny && deny[node.nodeName]) {
return true;
}
}
if (!jodit.o.cleanHTML.removeEmptyElements) {
return false;
}
return (Dom.isElement(node) &&
node.nodeName.match(IS_INLINE) != null &&
!Dom.isTemporary(node) &&
trimInv(node.innerHTML).length === 0 &&
(current == null || !Dom.isOrContains(node, current)));
}

View File

@@ -0,0 +1,13 @@
/*!
* 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
*/
/**
* @module plugins/clean-html
*/
import type { IDictionary, IJodit, Nullable } from "../../../../types/index";
/**
* @private
*/
export declare function visitNodeWalker(jodit: IJodit, nodeElm: Node, allowTags: IDictionary | false, denyTags: IDictionary | false, currentSelectionNode: Nullable<Node>): boolean;

View File

@@ -0,0 +1,30 @@
/*!
* 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
*/
import { IS_PROD } from "../../../../core/constants.js";
import * as filters from "./filters/index.js";
const keys = Object.keys(filters);
/**
* @private
*/
export function visitNodeWalker(jodit, nodeElm, allowTags, denyTags, currentSelectionNode) {
let hadEffect = false;
const dcf = jodit.o.cleanHTML.disableCleanFilter;
for (const key of keys) {
if (dcf && dcf.has(key)) {
continue;
}
const filter = filters[key];
const tmp = hadEffect;
hadEffect = filter(jodit, nodeElm, hadEffect, allowTags, denyTags, currentSelectionNode);
if (!IS_PROD && !tmp && hadEffect) {
console.warn(`CleanHTML: Effect "${key}"`);
}
if (!nodeElm.isConnected) {
return true;
}
}
return hadEffect;
}