jodit
Version:
Jodit is an awesome and useful wysiwyg editor with filebrowser
174 lines (173 loc) • 5.97 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
*/
import { LIST_TAGS } from "../../constants.js";
import { Dom } from "../../dom/dom.js";
import { assert } from "../../helpers/utils/assert.js";
import { INITIAL, REPLACE, UNSET, UNWRAP, WRAP } from "../index.js";
import { extractSelectedPart, getSuitChild, getSuitParent, isInsideInvisibleElement, suitableClosest, toggleAttributes, toggleOrderedList, unwrapChildren, wrap } from "./api/index.js";
export const states = {
START: 'START',
ELEMENT: 'ELEMENT',
UNWRAP: 'UNWRAP',
UNWRAP_CHILDREN: 'UNWRAP_CHILDREN',
CHANGE: 'CHANGE',
REPLACE_DEFAULT: 'REPLACE_DEFAULT',
LIST: 'LIST',
TOGGLE_LIST: 'TOGGLE_LIST',
WRAP: 'WRAP',
EXTRACT: 'EXTRACT',
END: 'END'
};
export const transactions = {
[states.START]: {
exec(value) {
const { element, jodit, style, mode, collapsed } = value;
if (isInsideInvisibleElement(element, jodit.editor) ||
(!collapsed && Dom.isEmptyContent(element))) {
return { ...value, next: states.END };
}
const elm = getSuitParent(style, element, jodit.editor) ||
getSuitChild(style, element);
if (elm) {
return { ...value, next: states.ELEMENT, element: elm };
}
const suit = suitableClosest(style, element, jodit.editor);
if (style.elementIsList && Dom.isList(suit)) {
return { ...value, next: states.LIST };
}
if (suit) {
return {
...value,
next: states.EXTRACT
};
}
return {
...value,
next: mode !== UNWRAP ? states.UNWRAP_CHILDREN : states.END
};
}
},
[states.LIST]: {
exec(value) {
const { element, jodit, mode } = value;
if (mode !== INITIAL && mode !== UNWRAP && mode !== REPLACE) {
return { ...value, next: states.END };
}
const li = Dom.closest(element, 'li', jodit.editor);
if (!li) {
return { ...value, next: states.END };
}
const list = Dom.closest(element, LIST_TAGS, jodit.editor);
if (list) {
return { ...value, element: li, next: states.TOGGLE_LIST };
}
return {
...value,
next: states.END
};
}
},
[states.TOGGLE_LIST]: {
exec(value) {
return {
...value,
mode: toggleOrderedList(value.style, value.element, value.jodit, value.mode),
next: states.END
};
}
},
[states.EXTRACT]: {
exec(value) {
const { element, jodit, style } = value;
const suit = suitableClosest(style, element, jodit.editor);
assert(suit, 'This place should have an element');
if (!style.elementIsBlock) {
extractSelectedPart(suit, element, jodit);
}
return {
...value,
element: suit,
next: states.ELEMENT
};
}
},
[states.UNWRAP_CHILDREN]: {
exec(value) {
const { element, style } = value;
if (!unwrapChildren(style, element)) {
return {
...value,
next: states.WRAP
};
}
return {
...value,
mode: UNWRAP,
next: states.END
};
}
},
[states.WRAP]: {
exec(value) {
const { element, jodit, style } = value;
const wrapper = wrap(style, element, jodit);
return {
...value,
next: style.elementIsList ? states.END : states.CHANGE,
mode: WRAP,
element: wrapper
};
}
},
[states.ELEMENT]: {
exec(value) {
const { style, element, jodit } = value;
if (toggleAttributes(style, element, jodit, INITIAL, true) !==
INITIAL) {
return { ...value, next: states.CHANGE };
}
// Apply same color for anchor https://github.com/xdan/jodit/issues/936
if (!Dom.isTag(element, style.element)) {
return { ...value, next: states.END };
}
return { ...value, next: states.UNWRAP };
}
},
[states.CHANGE]: {
exec(value) {
const { style, element, jodit, mode } = value;
const newMode = toggleAttributes(style, element, jodit, value.mode);
if (mode !== WRAP &&
newMode === UNSET &&
!element.attributes.length &&
Dom.isTag(element, style.element)) {
return { ...value, next: states.UNWRAP };
}
return { ...value, mode: newMode, next: states.END };
}
},
[states.UNWRAP]: {
exec(value) {
if (value.element.attributes.length &&
Dom.isTag(value.element, value.style.element)) {
return { ...value, next: states.REPLACE_DEFAULT };
}
Dom.unwrap(value.element);
return { ...value, mode: UNWRAP, next: states.END };
}
},
[states.REPLACE_DEFAULT]: {
exec(value) {
Dom.replace(value.element, value.style.defaultTag, value.jodit.createInside, true);
return { ...value, mode: REPLACE, next: states.END };
}
},
[states.END]: {
exec(value) {
return value;
}
}
};