jodit 4.18.4 → 4.18.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/es2015/jodit.css +13 -34
- package/es2015/jodit.fat.min.css +1 -1
- package/es2015/jodit.fat.min.js +11 -11
- package/es2015/jodit.js +1029 -205
- package/es2015/jodit.min.css +1 -1
- package/es2015/jodit.min.js +11 -11
- package/es2015/plugins/debug/debug.css +1 -1
- package/es2015/plugins/debug/debug.js +1 -1
- package/es2015/plugins/debug/debug.min.js +1 -1
- package/es2015/plugins/speech-recognize/speech-recognize.css +1 -1
- package/es2015/plugins/speech-recognize/speech-recognize.js +1 -1
- package/es2015/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es2018/jodit.fat.min.css +1 -1
- package/es2018/jodit.fat.min.js +11 -11
- package/es2018/jodit.min.css +1 -1
- package/es2018/jodit.min.js +11 -11
- package/es2018/plugins/debug/debug.min.js +1 -1
- package/es2018/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es2021/jodit.css +13 -34
- package/es2021/jodit.fat.min.css +1 -1
- package/es2021/jodit.fat.min.js +15 -15
- package/es2021/jodit.js +1021 -203
- package/es2021/jodit.min.css +1 -1
- package/es2021/jodit.min.js +15 -15
- package/es2021/plugins/debug/debug.css +1 -1
- package/es2021/plugins/debug/debug.js +1 -1
- package/es2021/plugins/debug/debug.min.js +1 -1
- package/es2021/plugins/speech-recognize/speech-recognize.css +1 -1
- package/es2021/plugins/speech-recognize/speech-recognize.js +1 -1
- package/es2021/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es2021.en/jodit.css +13 -34
- package/es2021.en/jodit.fat.min.css +1 -1
- package/es2021.en/jodit.fat.min.js +15 -15
- package/es2021.en/jodit.js +995 -177
- package/es2021.en/jodit.min.css +1 -1
- package/es2021.en/jodit.min.js +15 -15
- package/es2021.en/plugins/debug/debug.css +1 -1
- package/es2021.en/plugins/debug/debug.js +1 -1
- package/es2021.en/plugins/debug/debug.min.js +1 -1
- package/es2021.en/plugins/speech-recognize/speech-recognize.css +1 -1
- package/es2021.en/plugins/speech-recognize/speech-recognize.js +1 -1
- package/es2021.en/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es5/jodit.css +14 -41
- package/es5/jodit.fat.min.css +1 -1
- package/es5/jodit.fat.min.js +2 -2
- package/es5/jodit.js +1152 -254
- package/es5/jodit.min.css +3 -3
- package/es5/jodit.min.js +2 -2
- package/es5/plugins/debug/debug.css +1 -1
- package/es5/plugins/debug/debug.js +1 -1
- package/es5/plugins/debug/debug.min.js +1 -1
- package/es5/plugins/speech-recognize/speech-recognize.css +1 -1
- package/es5/plugins/speech-recognize/speech-recognize.js +1 -1
- package/es5/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es5/polyfills.fat.min.js +1 -1
- package/es5/polyfills.js +1 -1
- package/es5/polyfills.min.js +1 -1
- package/esm/config.d.ts +3 -0
- package/esm/core/constants.js +1 -1
- package/esm/core/helpers/html/apply-styles.js +3 -0
- package/esm/core/helpers/html/clean-from-word.js +3 -0
- package/esm/core/helpers/html/strip-tags.js +24 -6
- package/esm/core/helpers/html/word-lists.d.ts +29 -0
- package/esm/core/helpers/html/word-lists.js +158 -0
- package/esm/core/selection/helpers/index.d.ts +1 -0
- package/esm/core/selection/helpers/index.js +1 -0
- package/esm/core/selection/helpers/is-moved.d.ts +15 -0
- package/esm/core/selection/helpers/is-moved.js +22 -0
- package/esm/core/selection/style/api/list/toggle-ordered-list.js +40 -3
- package/esm/core/selection/style/transactions.js +5 -2
- package/esm/langs/ar.d.ts +3 -0
- package/esm/langs/ar.js +4 -1
- package/esm/langs/az.d.ts +3 -0
- package/esm/langs/az.js +4 -1
- package/esm/langs/cs_cz.d.ts +3 -0
- package/esm/langs/cs_cz.js +4 -1
- package/esm/langs/de.d.ts +3 -0
- package/esm/langs/de.js +4 -1
- package/esm/langs/es.d.ts +3 -0
- package/esm/langs/es.js +4 -1
- package/esm/langs/fa.d.ts +3 -0
- package/esm/langs/fa.js +4 -1
- package/esm/langs/fi.d.ts +3 -0
- package/esm/langs/fi.js +4 -1
- package/esm/langs/fr.d.ts +3 -0
- package/esm/langs/fr.js +4 -1
- package/esm/langs/he.d.ts +3 -0
- package/esm/langs/he.js +4 -1
- package/esm/langs/hu.d.ts +3 -0
- package/esm/langs/hu.js +4 -1
- package/esm/langs/id.d.ts +3 -0
- package/esm/langs/id.js +4 -1
- package/esm/langs/it.d.ts +3 -0
- package/esm/langs/it.js +4 -1
- package/esm/langs/ja.d.ts +3 -0
- package/esm/langs/ja.js +4 -1
- package/esm/langs/ko.d.ts +3 -0
- package/esm/langs/ko.js +4 -1
- package/esm/langs/mn.d.ts +3 -0
- package/esm/langs/mn.js +4 -1
- package/esm/langs/nl.d.ts +3 -0
- package/esm/langs/nl.js +4 -1
- package/esm/langs/no.d.ts +3 -0
- package/esm/langs/no.js +4 -1
- package/esm/langs/pl.d.ts +3 -0
- package/esm/langs/pl.js +4 -1
- package/esm/langs/pt_br.d.ts +3 -0
- package/esm/langs/pt_br.js +4 -1
- package/esm/langs/ru.d.ts +3 -0
- package/esm/langs/ru.js +4 -1
- package/esm/langs/sk.d.ts +3 -0
- package/esm/langs/sk.js +4 -1
- package/esm/langs/sv.d.ts +3 -0
- package/esm/langs/sv.js +4 -1
- package/esm/langs/tr.d.ts +3 -0
- package/esm/langs/tr.js +4 -1
- package/esm/langs/ua.d.ts +3 -0
- package/esm/langs/ua.js +4 -1
- package/esm/langs/zh_cn.d.ts +3 -0
- package/esm/langs/zh_cn.js +4 -1
- package/esm/langs/zh_tw.d.ts +3 -0
- package/esm/langs/zh_tw.js +4 -1
- package/esm/modules/dialog/dialog.d.ts +7 -0
- package/esm/modules/dialog/dialog.js +24 -6
- package/esm/modules/table/table.d.ts +6 -0
- package/esm/modules/table/table.js +18 -26
- package/esm/plugins/backspace/cases/check-join-neighbors.js +90 -3
- package/esm/plugins/clean-html/clean-html.d.ts +8 -0
- package/esm/plugins/clean-html/clean-html.js +21 -1
- package/esm/plugins/clean-html/helpers/index.d.ts +1 -0
- package/esm/plugins/clean-html/helpers/index.js +1 -0
- package/esm/plugins/clean-html/helpers/remove-placeholder-br.d.ts +16 -0
- package/esm/plugins/clean-html/helpers/remove-placeholder-br.js +51 -0
- package/esm/plugins/delete/delete.d.ts +11 -1
- package/esm/plugins/delete/delete.js +92 -16
- package/esm/plugins/focus/focus.js +12 -1
- package/esm/plugins/iframe/config.d.ts +3 -0
- package/esm/plugins/iframe/config.js +0 -27
- package/esm/plugins/iframe/iframe.js +8 -1
- package/esm/plugins/image-processor/image-processor.js +6 -1
- package/esm/plugins/inline-popup/inline-popup.d.ts +19 -0
- package/esm/plugins/inline-popup/inline-popup.js +70 -1
- package/esm/plugins/ordered-list/config.js +13 -2
- package/esm/plugins/ordered-list/start-dialog.d.ts +19 -0
- package/esm/plugins/ordered-list/start-dialog.js +58 -0
- package/esm/plugins/placeholder/placeholder.js +7 -1
- package/esm/plugins/resizer/resizer.d.ts +10 -0
- package/esm/plugins/resizer/resizer.js +76 -2
- package/esm/plugins/select-cells/select-cells.d.ts +23 -0
- package/esm/plugins/select-cells/select-cells.js +75 -1
- package/esm/plugins/table-keyboard-navigation/table-keyboard-navigation.js +3 -2
- package/package.json +1 -1
- package/types/config.d.ts +3 -0
- package/types/core/helpers/html/word-lists.d.ts +29 -0
- package/types/core/selection/helpers/index.d.ts +1 -0
- package/types/core/selection/helpers/is-moved.d.ts +15 -0
- package/types/langs/ar.d.ts +3 -0
- package/types/langs/az.d.ts +3 -0
- package/types/langs/cs_cz.d.ts +3 -0
- package/types/langs/de.d.ts +3 -0
- package/types/langs/es.d.ts +3 -0
- package/types/langs/fa.d.ts +3 -0
- package/types/langs/fi.d.ts +3 -0
- package/types/langs/fr.d.ts +3 -0
- package/types/langs/he.d.ts +3 -0
- package/types/langs/hu.d.ts +3 -0
- package/types/langs/id.d.ts +3 -0
- package/types/langs/it.d.ts +3 -0
- package/types/langs/ja.d.ts +3 -0
- package/types/langs/ko.d.ts +3 -0
- package/types/langs/mn.d.ts +3 -0
- package/types/langs/nl.d.ts +3 -0
- package/types/langs/no.d.ts +3 -0
- package/types/langs/pl.d.ts +3 -0
- package/types/langs/pt_br.d.ts +3 -0
- package/types/langs/ru.d.ts +3 -0
- package/types/langs/sk.d.ts +3 -0
- package/types/langs/sv.d.ts +3 -0
- package/types/langs/tr.d.ts +3 -0
- package/types/langs/ua.d.ts +3 -0
- package/types/langs/zh_cn.d.ts +3 -0
- package/types/langs/zh_tw.d.ts +3 -0
- package/types/modules/dialog/dialog.d.ts +7 -0
- package/types/modules/table/table.d.ts +6 -0
- package/types/plugins/clean-html/clean-html.d.ts +8 -0
- package/types/plugins/clean-html/helpers/index.d.ts +1 -0
- package/types/plugins/clean-html/helpers/remove-placeholder-br.d.ts +16 -0
- package/types/plugins/delete/delete.d.ts +11 -1
- package/types/plugins/iframe/config.d.ts +3 -0
- package/types/plugins/inline-popup/inline-popup.d.ts +19 -0
- package/types/plugins/ordered-list/start-dialog.d.ts +19 -0
- package/types/plugins/resizer/resizer.d.ts +10 -0
- package/types/plugins/select-cells/select-cells.d.ts +23 -0
package/es5/polyfills.fat.min.js
CHANGED
package/es5/polyfills.js
CHANGED
package/es5/polyfills.min.js
CHANGED
package/esm/config.d.ts
CHANGED
|
@@ -1404,6 +1404,9 @@ interface Config {
|
|
|
1404
1404
|
iframeDoctype: string;
|
|
1405
1405
|
/**
|
|
1406
1406
|
* Custom style to be used inside the iframe to display content.
|
|
1407
|
+
* It goes in after `iframeCSSLinks`. The rules Jodit's own plugins need
|
|
1408
|
+
* in the editing document are added apart from it, so a value of your
|
|
1409
|
+
* own doesn't have to repeat them.
|
|
1407
1410
|
*
|
|
1408
1411
|
* ```javascript
|
|
1409
1412
|
* Jodit.make('#editor', {
|
package/esm/core/constants.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Released under MIT see LICENSE.txt in the project root for license information.
|
|
4
4
|
* Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
5
|
*/
|
|
6
|
-
export const APP_VERSION = "4.18.
|
|
6
|
+
export const APP_VERSION = "4.18.6";
|
|
7
7
|
// prettier-ignore
|
|
8
8
|
export const ES = "es2020";
|
|
9
9
|
export const IS_ES_MODERN = true;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { globalDocument, IS_PROD } from "../../constants.js";
|
|
10
10
|
import { Dom } from "../../dom/dom.js";
|
|
11
|
+
import { readWordListItems, wrapWordListItems } from "./word-lists.js";
|
|
11
12
|
import { trim } from "../string/trim.js";
|
|
12
13
|
import { attr } from "../utils/attr.js";
|
|
13
14
|
import { css } from "../utils/css.js";
|
|
@@ -60,6 +61,7 @@ export function applyStyles(html) {
|
|
|
60
61
|
iframeDoc.open();
|
|
61
62
|
iframeDoc.write(html);
|
|
62
63
|
iframeDoc.close();
|
|
64
|
+
const listItems = readWordListItems(iframeDoc.body);
|
|
63
65
|
// Word marks its auto-generated list markers (the literal
|
|
64
66
|
// bullet/number, e.g. `1.` or `·`) with `mso-list:Ignore`.
|
|
65
67
|
// They are display-only and must not be imported, otherwise
|
|
@@ -95,6 +97,7 @@ export function applyStyles(html) {
|
|
|
95
97
|
throw e;
|
|
96
98
|
}
|
|
97
99
|
}
|
|
100
|
+
wrapWordListItems(listItems);
|
|
98
101
|
Dom.each(iframeDoc.body, node => {
|
|
99
102
|
if (Dom.isElement(node)) {
|
|
100
103
|
const cssText = attr(node, 'style');
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { globalDocument } from "../../constants.js";
|
|
10
10
|
import { Dom } from "../../dom/dom.js";
|
|
11
11
|
import { toArray } from "../array/to-array.js";
|
|
12
|
+
import { readWordListItems, wrapWordListItems } from "./word-lists.js";
|
|
12
13
|
import { trim } from "../string/trim.js";
|
|
13
14
|
import { attr, attrRaw } from "../utils/attr.js";
|
|
14
15
|
/**
|
|
@@ -25,6 +26,7 @@ export function cleanFromWord(html) {
|
|
|
25
26
|
const div = globalDocument.createElement('div');
|
|
26
27
|
div.innerHTML = html;
|
|
27
28
|
const marks = [];
|
|
29
|
+
const listItems = readWordListItems(div);
|
|
28
30
|
if (div.firstChild) {
|
|
29
31
|
Dom.each(div, node => {
|
|
30
32
|
if (!node) {
|
|
@@ -76,6 +78,7 @@ export function cleanFromWord(html) {
|
|
|
76
78
|
});
|
|
77
79
|
}
|
|
78
80
|
Dom.safeRemove.apply(null, marks);
|
|
81
|
+
wrapWordListItems(listItems);
|
|
79
82
|
convertedString = div.innerHTML;
|
|
80
83
|
}
|
|
81
84
|
catch (e) { }
|
|
@@ -16,8 +16,12 @@ const NEW_LINE_TAGS = new Set([
|
|
|
16
16
|
'h4',
|
|
17
17
|
'h5',
|
|
18
18
|
'h6',
|
|
19
|
-
'hr'
|
|
19
|
+
'hr',
|
|
20
|
+
'ul',
|
|
21
|
+
'ol',
|
|
22
|
+
'li'
|
|
20
23
|
]);
|
|
24
|
+
const LIST_TAGS = new Set(['ul', 'ol']);
|
|
21
25
|
const INVISIBLE_TAGS = new Set(['script', 'style']);
|
|
22
26
|
const ALONE_TAGS = new Set(['br', 'hr', 'input']);
|
|
23
27
|
/**
|
|
@@ -37,6 +41,16 @@ export function stripTags(html, doc = document, exclude = null, blockBr = false)
|
|
|
37
41
|
Dom.each(tmp, node => {
|
|
38
42
|
Dom.isElement(node) && all.push(node);
|
|
39
43
|
});
|
|
44
|
+
// By default blocks are joined with a single space (single-line
|
|
45
|
+
// plain text). When `blockBr` is set, separate them with a line
|
|
46
|
+
// break instead, so paragraph structure survives — e.g. the
|
|
47
|
+
// "Insert only Text" paste option. See #1232
|
|
48
|
+
const separators = new Set();
|
|
49
|
+
const separator = () => {
|
|
50
|
+
const text = doc.createTextNode(blockBr ? '%%%jodit-single-br%%%' : ' ');
|
|
51
|
+
separators.add(text);
|
|
52
|
+
return text;
|
|
53
|
+
};
|
|
40
54
|
all.forEach(p => {
|
|
41
55
|
const pr = p.parentNode;
|
|
42
56
|
if (!pr) {
|
|
@@ -58,16 +72,20 @@ export function stripTags(html, doc = document, exclude = null, blockBr = false)
|
|
|
58
72
|
if (!Dom.isTag(p, NEW_LINE_TAGS)) {
|
|
59
73
|
return;
|
|
60
74
|
}
|
|
75
|
+
const pv = p.previousSibling;
|
|
76
|
+
// A nested list starts on a new line after its item's own text
|
|
77
|
+
if (Dom.isTag(p, LIST_TAGS) &&
|
|
78
|
+
pv &&
|
|
79
|
+
!separators.has(pv) &&
|
|
80
|
+
!(Dom.isText(pv) && /\s$/.test(pv.nodeValue || ''))) {
|
|
81
|
+
Dom.before(p, separator());
|
|
82
|
+
}
|
|
61
83
|
const nx = p.nextSibling;
|
|
62
84
|
if (Dom.isText(nx) && /^\s/.test(nx.nodeValue || '')) {
|
|
63
85
|
return;
|
|
64
86
|
}
|
|
65
87
|
if (nx) {
|
|
66
|
-
|
|
67
|
-
// plain text). When `blockBr` is set, separate them with a line
|
|
68
|
-
// break instead, so paragraph structure survives — e.g. the
|
|
69
|
-
// "Insert only Text" paste option. See #1232
|
|
70
|
-
Dom.before(nx, doc.createTextNode(blockBr ? '%%%jodit-single-br%%%' : ' '));
|
|
88
|
+
Dom.before(nx, separator());
|
|
71
89
|
}
|
|
72
90
|
});
|
|
73
91
|
return restoreTags(trim(tmp.innerText));
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Jodit Editor (https://xdsoft.net/jodit/)
|
|
3
|
+
* Released under MIT see LICENSE.txt in the project root for license information.
|
|
4
|
+
* Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* A Word list paragraph, read before its `mso-list` style is lost
|
|
8
|
+
*/
|
|
9
|
+
export interface WordListItem {
|
|
10
|
+
paragraph: HTMLElement;
|
|
11
|
+
list: string;
|
|
12
|
+
level: number;
|
|
13
|
+
tag: 'ul' | 'ol';
|
|
14
|
+
listStyleType: string | null;
|
|
15
|
+
start: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Finds Word's list paragraphs (`<p style="mso-list:l0 level1 lfo1">`), reads
|
|
19
|
+
* their list, level and type from the `mso-list:Ignore` marker, and removes the
|
|
20
|
+
* marker. Call it before anything strips the `mso-list` styles, then pass the
|
|
21
|
+
* result to {@link wrapWordListItems}
|
|
22
|
+
*/
|
|
23
|
+
export declare function readWordListItems(root: HTMLElement): WordListItem[];
|
|
24
|
+
/**
|
|
25
|
+
* Turns the paragraphs found by {@link readWordListItems} into `<ul>`/`<ol>`
|
|
26
|
+
* lists, nesting them by level. Each paragraph becomes an `<li>` without Word's
|
|
27
|
+
* hanging indent
|
|
28
|
+
*/
|
|
29
|
+
export declare function wrapWordListItems(items: WordListItem[]): void;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Jodit Editor (https://xdsoft.net/jodit/)
|
|
3
|
+
* Released under MIT see LICENSE.txt in the project root for license information.
|
|
4
|
+
* Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* @module helpers/html
|
|
8
|
+
*/
|
|
9
|
+
import { Dom } from "../../dom/dom.js";
|
|
10
|
+
import { toArray } from "../array/to-array.js";
|
|
11
|
+
import { attr } from "../utils/attr.js";
|
|
12
|
+
const ROMAN = {
|
|
13
|
+
i: 1,
|
|
14
|
+
v: 5,
|
|
15
|
+
x: 10,
|
|
16
|
+
l: 50,
|
|
17
|
+
c: 100,
|
|
18
|
+
d: 500,
|
|
19
|
+
m: 1000
|
|
20
|
+
};
|
|
21
|
+
function romanValue(roman) {
|
|
22
|
+
let value = 0;
|
|
23
|
+
for (let i = 0; i < roman.length; i += 1) {
|
|
24
|
+
const current = ROMAN[roman[i]], next = ROMAN[roman[i + 1]] || 0;
|
|
25
|
+
value += current < next ? -current : current;
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Word's marker text (`1.`, `b)`, `iv.`, `·`, `o`, `§`) decides the list type
|
|
31
|
+
*/
|
|
32
|
+
function parseMarker(marker) {
|
|
33
|
+
const text = marker.replace(/\s+/g, '');
|
|
34
|
+
const decimal = /^\(?(?:\d+\.)*(\d+)[.)]?$/.exec(text);
|
|
35
|
+
if (decimal) {
|
|
36
|
+
return { tag: 'ol', listStyleType: null, start: Number(decimal[1]) };
|
|
37
|
+
}
|
|
38
|
+
const letters = /^\(?([a-z]+|[A-Z]+)[.)]$/.exec(text);
|
|
39
|
+
if (letters) {
|
|
40
|
+
const value = letters[1], lower = value.toLowerCase(), upper = value !== lower;
|
|
41
|
+
if (/^[ivxlcdm]+$/.test(lower) && (lower.length > 1 || lower === 'i')) {
|
|
42
|
+
return {
|
|
43
|
+
tag: 'ol',
|
|
44
|
+
listStyleType: upper ? 'upper-roman' : 'lower-roman',
|
|
45
|
+
start: romanValue(lower)
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// Word continues a lettered list with aa, bb, ...
|
|
49
|
+
if (/^([a-z])\1*$/.test(lower)) {
|
|
50
|
+
return {
|
|
51
|
+
tag: 'ol',
|
|
52
|
+
listStyleType: upper ? 'upper-alpha' : 'lower-alpha',
|
|
53
|
+
start: (lower.length - 1) * 26 + lower.charCodeAt(0) - 96
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return { tag: 'ul', listStyleType: null, start: 1 };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Removes the marker and the wrappers it leaves empty
|
|
61
|
+
*/
|
|
62
|
+
function removeMarker(marker, paragraph) {
|
|
63
|
+
let parent = marker.parentNode;
|
|
64
|
+
Dom.safeRemove(marker);
|
|
65
|
+
while (parent &&
|
|
66
|
+
parent !== paragraph &&
|
|
67
|
+
Dom.isElement(parent) &&
|
|
68
|
+
Dom.isEmpty(parent)) {
|
|
69
|
+
const next = parent.parentNode;
|
|
70
|
+
Dom.safeRemove(parent);
|
|
71
|
+
parent = next;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Finds Word's list paragraphs (`<p style="mso-list:l0 level1 lfo1">`), reads
|
|
76
|
+
* their list, level and type from the `mso-list:Ignore` marker, and removes the
|
|
77
|
+
* marker. Call it before anything strips the `mso-list` styles, then pass the
|
|
78
|
+
* result to {@link wrapWordListItems}
|
|
79
|
+
*/
|
|
80
|
+
export function readWordListItems(root) {
|
|
81
|
+
const items = [];
|
|
82
|
+
toArray(root.querySelectorAll('p')).forEach(paragraph => {
|
|
83
|
+
const match = /mso-list:\s*l(\d+)\s+level(\d+)(?:\s+lfo(\d+))?/i.exec(attr(paragraph, 'style') || '');
|
|
84
|
+
if (!match) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const marker = toArray(paragraph.querySelectorAll('[style]')).find(elm => /mso-list:\s*ignore/i.test(attr(elm, 'style') || ''));
|
|
88
|
+
items.push({
|
|
89
|
+
paragraph,
|
|
90
|
+
list: `${match[1]}:${match[3] || ''}`,
|
|
91
|
+
level: Number(match[2]),
|
|
92
|
+
...parseMarker((marker === null || marker === void 0 ? void 0 : marker.textContent) || '')
|
|
93
|
+
});
|
|
94
|
+
if (marker) {
|
|
95
|
+
removeMarker(marker, paragraph);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
return items;
|
|
99
|
+
}
|
|
100
|
+
function isAdjacent(prev, item) {
|
|
101
|
+
return (Dom.findSibling(item.paragraph, true, n => !Dom.isEmptyTextNode(n) && !Dom.isComment(n)) === prev.paragraph);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Turns the paragraphs found by {@link readWordListItems} into `<ul>`/`<ol>`
|
|
105
|
+
* lists, nesting them by level. Each paragraph becomes an `<li>` without Word's
|
|
106
|
+
* hanging indent
|
|
107
|
+
*/
|
|
108
|
+
export function wrapWordListItems(items) {
|
|
109
|
+
let stack = [];
|
|
110
|
+
const continues = items.map((item, index) => index > 0 && isAdjacent(items[index - 1], item));
|
|
111
|
+
items.forEach((item, index) => {
|
|
112
|
+
const { paragraph } = item;
|
|
113
|
+
if (!continues[index]) {
|
|
114
|
+
stack = [];
|
|
115
|
+
}
|
|
116
|
+
while (stack.length && stack[stack.length - 1].level > item.level) {
|
|
117
|
+
stack.pop();
|
|
118
|
+
}
|
|
119
|
+
let top = stack[stack.length - 1];
|
|
120
|
+
if (top && top.level === item.level && top.list !== item.list) {
|
|
121
|
+
stack.pop();
|
|
122
|
+
top = stack[stack.length - 1];
|
|
123
|
+
}
|
|
124
|
+
const doc = paragraph.ownerDocument;
|
|
125
|
+
if (!top || top.level < item.level) {
|
|
126
|
+
const element = doc.createElement(item.tag);
|
|
127
|
+
if (item.listStyleType) {
|
|
128
|
+
element.style.listStyleType = item.listStyleType;
|
|
129
|
+
}
|
|
130
|
+
if (item.tag === 'ol' && item.start !== 1) {
|
|
131
|
+
attr(element, 'start', item.start);
|
|
132
|
+
}
|
|
133
|
+
if (top && top.li) {
|
|
134
|
+
top.li.appendChild(element);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
Dom.before(paragraph, element);
|
|
138
|
+
}
|
|
139
|
+
top = { level: item.level, list: item.list, element };
|
|
140
|
+
stack.push(top);
|
|
141
|
+
}
|
|
142
|
+
const li = doc.createElement('li');
|
|
143
|
+
toArray(paragraph.attributes).forEach(attribute => {
|
|
144
|
+
if (attribute.name !== 'class') {
|
|
145
|
+
li.setAttribute(attribute.name, attribute.value);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
li.style.removeProperty('margin-left');
|
|
149
|
+
li.style.removeProperty('text-indent');
|
|
150
|
+
if (!attr(li, 'style')) {
|
|
151
|
+
attr(li, 'style', null);
|
|
152
|
+
}
|
|
153
|
+
Dom.moveContent(paragraph, li);
|
|
154
|
+
Dom.safeRemove(paragraph);
|
|
155
|
+
top.element.appendChild(li);
|
|
156
|
+
top.li = li;
|
|
157
|
+
});
|
|
158
|
+
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { INVISIBLE_SPACE_REG_EXP_END as INV_END, INVISIBLE_SPACE_REG_EXP_START as INV_START } from "../../constants.js";
|
|
10
10
|
import { Dom } from "../../dom/dom.js";
|
|
11
11
|
export * from "./composed-ranges.js";
|
|
12
|
+
export * from "./is-moved.js";
|
|
12
13
|
export * from "./move-node-inside-start.js";
|
|
13
14
|
export * from "./move-the-node-along-the-edge-outward.js";
|
|
14
15
|
/**
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Jodit Editor (https://xdsoft.net/jodit/)
|
|
3
|
+
* Released under MIT see LICENSE.txt in the project root for license information.
|
|
4
|
+
* Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* @module selection
|
|
8
|
+
*/
|
|
9
|
+
import type { IJodit, Nullable } from "../../../types/index";
|
|
10
|
+
/**
|
|
11
|
+
* Whether the selection, `before` as it was when a key went down, has since
|
|
12
|
+
* moved to somewhere else in the editor
|
|
13
|
+
* @private
|
|
14
|
+
*/
|
|
15
|
+
export declare function isMoved(jodit: IJodit, before: Nullable<Range>): boolean;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Jodit Editor (https://xdsoft.net/jodit/)
|
|
3
|
+
* Released under MIT see LICENSE.txt in the project root for license information.
|
|
4
|
+
* Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Whether the selection, `before` as it was when a key went down, has since
|
|
8
|
+
* moved to somewhere else in the editor
|
|
9
|
+
* @private
|
|
10
|
+
*/
|
|
11
|
+
export function isMoved(jodit, before) {
|
|
12
|
+
const { s } = jodit;
|
|
13
|
+
// Selecting table cells, for one, removes the selection altogether
|
|
14
|
+
if (!before || !s.isInsideArea) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
const { range } = s;
|
|
18
|
+
return (range.startContainer !== before.startContainer ||
|
|
19
|
+
range.startOffset !== before.startOffset ||
|
|
20
|
+
range.endContainer !== before.endContainer ||
|
|
21
|
+
range.endOffset !== before.endOffset);
|
|
22
|
+
}
|
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
* Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
5
|
*/
|
|
6
6
|
import { Dom } from "../../../../dom/dom.js";
|
|
7
|
+
import { size } from "../../../../helpers/size/object-size.js";
|
|
7
8
|
import { assert } from "../../../../helpers/utils/assert.js";
|
|
8
9
|
import { extractSelectedPart } from "../extract.js";
|
|
10
|
+
import { elementsEqualAttributes } from "../is-same-attributes.js";
|
|
9
11
|
import { toggleAttributes } from "../toggle-attributes.js";
|
|
10
12
|
import { _PREFIX, CHANGE, INITIAL, REPLACE, UNWRAP } from "../../constants.js";
|
|
11
13
|
import { wrapList } from "./wrap-list.js";
|
|
@@ -28,10 +30,23 @@ export function toggleOrderedList(commitStyle, li, jodit, mode) {
|
|
|
28
30
|
const hook = jodit.e.fire.bind(jodit.e, `${_PREFIX}AfterToggleList`);
|
|
29
31
|
if (mode !== UNWRAP) {
|
|
30
32
|
const isChangeMode = toggleAttributes(commitStyle, li.parentElement, jodit, INITIAL, true) === CHANGE;
|
|
33
|
+
const isSameList = Dom.isTag(list, commitStyle.element);
|
|
34
|
+
// ol => ol[style="list-style-type: lower-roman"]: a list's style
|
|
35
|
+
// belongs to the whole list, so it is changed without splitting it
|
|
36
|
+
if (isSameList &&
|
|
37
|
+
isChangeMode &&
|
|
38
|
+
mode !== REPLACE &&
|
|
39
|
+
changesStyleOnly(commitStyle)) {
|
|
40
|
+
toggleAttributes(commitStyle, list, jodit, CHANGE);
|
|
41
|
+
hook(CHANGE, joinPrevious(commitStyle, list, mode), commitStyle);
|
|
42
|
+
return CHANGE;
|
|
43
|
+
}
|
|
44
|
+
// Restyled already, for an earlier part of the selection
|
|
45
|
+
if (isSameList && mode === CHANGE) {
|
|
46
|
+
return CHANGE;
|
|
47
|
+
}
|
|
31
48
|
// ul => ol, ol => ul or ul => ul.class1
|
|
32
|
-
if (mode === REPLACE ||
|
|
33
|
-
isChangeMode ||
|
|
34
|
-
list.tagName.toLowerCase() !== commitStyle.element) {
|
|
49
|
+
if (mode === REPLACE || isChangeMode || !isSameList) {
|
|
35
50
|
const wrapper = unwrapList(REPLACE, list, li, jodit, commitStyle);
|
|
36
51
|
const newList = wrapList(commitStyle, wrapper, jodit);
|
|
37
52
|
hook(REPLACE, newList, commitStyle);
|
|
@@ -42,6 +57,28 @@ export function toggleOrderedList(commitStyle, li, jodit, mode) {
|
|
|
42
57
|
hook(UNWRAP, wrapper, commitStyle);
|
|
43
58
|
return UNWRAP;
|
|
44
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Other attributes, such as a class, still move the items into a new list,
|
|
62
|
+
* where the `beforeWrapList` hook can add markup to each of them
|
|
63
|
+
*/
|
|
64
|
+
function changesStyleOnly({ options: { attributes } }) {
|
|
65
|
+
return Boolean(attributes === null || attributes === void 0 ? void 0 : attributes.style) && size(attributes) === 1;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Joins a restyled list to the list before it, when the selection runs on
|
|
69
|
+
* from that list and the two now match
|
|
70
|
+
*/
|
|
71
|
+
function joinPrevious(commitStyle, list, mode) {
|
|
72
|
+
const prev = Dom.findSibling(list, true);
|
|
73
|
+
if (mode !== CHANGE ||
|
|
74
|
+
!Dom.isTag(prev, commitStyle.element) ||
|
|
75
|
+
!elementsEqualAttributes(prev, list)) {
|
|
76
|
+
return list;
|
|
77
|
+
}
|
|
78
|
+
Dom.append(prev, Array.from(list.childNodes));
|
|
79
|
+
Dom.safeRemove(list);
|
|
80
|
+
return prev;
|
|
81
|
+
}
|
|
45
82
|
function unwrapList(mode, list, li, jodit, cs) {
|
|
46
83
|
const result = jodit.e.fire(`${_PREFIX}BeforeUnwrapList`, mode, list, cs);
|
|
47
84
|
if (result) {
|
|
@@ -7,7 +7,7 @@ import { LIST_TAGS } from "../../constants.js";
|
|
|
7
7
|
import { Dom } from "../../dom/dom.js";
|
|
8
8
|
import { assert } from "../../helpers/utils/assert.js";
|
|
9
9
|
import { extractSelectedPart, getSuitChild, getSuitParent, isInsideInvisibleElement, suitableClosest, toggleAttributes, toggleOrderedList, unwrapChildren, wrap, WRAP_NODES } from "./api/index.js";
|
|
10
|
-
import { INITIAL, REPLACE, UNSET, UNWRAP, WRAP } from "./constants.js";
|
|
10
|
+
import { CHANGE, INITIAL, REPLACE, UNSET, UNWRAP, WRAP } from "./constants.js";
|
|
11
11
|
export const states = {
|
|
12
12
|
START: 'START',
|
|
13
13
|
ELEMENT: 'ELEMENT',
|
|
@@ -54,7 +54,10 @@ export const transactions = {
|
|
|
54
54
|
[states.LIST]: {
|
|
55
55
|
exec(value) {
|
|
56
56
|
const { element, jodit, mode } = value;
|
|
57
|
-
if (mode !== INITIAL &&
|
|
57
|
+
if (mode !== INITIAL &&
|
|
58
|
+
mode !== UNWRAP &&
|
|
59
|
+
mode !== REPLACE &&
|
|
60
|
+
mode !== CHANGE) {
|
|
58
61
|
return { ...value, next: states.END };
|
|
59
62
|
}
|
|
60
63
|
const li = Dom.closest(element, 'li', jodit.editor);
|
package/esm/langs/ar.d.ts
CHANGED
package/esm/langs/ar.js
CHANGED
|
@@ -234,5 +234,8 @@ export default {
|
|
|
234
234
|
Autoplay: 'تشغيل تلقائي',
|
|
235
235
|
Loop: 'تكرار',
|
|
236
236
|
Muted: 'مكتوم الصوت',
|
|
237
|
-
Controls: 'عناصر التحكم'
|
|
237
|
+
Controls: 'عناصر التحكم',
|
|
238
|
+
'Start at...': 'البدء من...',
|
|
239
|
+
'Start numbering at': 'بدء الترقيم من',
|
|
240
|
+
'Number for the first item': 'رقم العنصر الأول'
|
|
238
241
|
};
|
package/esm/langs/az.d.ts
CHANGED
package/esm/langs/az.js
CHANGED
|
@@ -243,5 +243,8 @@ export default {
|
|
|
243
243
|
Autoplay: 'Avtomatik oynatma',
|
|
244
244
|
Loop: 'Təkrarla',
|
|
245
245
|
Muted: 'Səssiz',
|
|
246
|
-
Controls: 'İdarəetmə elementləri'
|
|
246
|
+
Controls: 'İdarəetmə elementləri',
|
|
247
|
+
'Start at...': 'Başlanğıc nömrəsi...',
|
|
248
|
+
'Start numbering at': 'Nömrələmənin başlanğıcı',
|
|
249
|
+
'Number for the first item': 'Birinci bəndin nömrəsi'
|
|
247
250
|
};
|
package/esm/langs/cs_cz.d.ts
CHANGED
package/esm/langs/cs_cz.js
CHANGED
|
@@ -233,5 +233,8 @@ export default {
|
|
|
233
233
|
Autoplay: 'Automatické přehrávání',
|
|
234
234
|
Loop: 'Opakovat',
|
|
235
235
|
Muted: 'Ztlumeno',
|
|
236
|
-
Controls: 'Ovládací prvky'
|
|
236
|
+
Controls: 'Ovládací prvky',
|
|
237
|
+
'Start at...': 'Začít od...',
|
|
238
|
+
'Start numbering at': 'Začít číslování od',
|
|
239
|
+
'Number for the first item': 'Číslo první položky'
|
|
237
240
|
};
|
package/esm/langs/de.d.ts
CHANGED
package/esm/langs/de.js
CHANGED
|
@@ -238,5 +238,8 @@ export default {
|
|
|
238
238
|
Autoplay: 'Automatische Wiedergabe',
|
|
239
239
|
Loop: 'Wiederholen',
|
|
240
240
|
Muted: 'Stumm',
|
|
241
|
-
Controls: 'Steuerelemente'
|
|
241
|
+
Controls: 'Steuerelemente',
|
|
242
|
+
'Start at...': 'Beginnen bei...',
|
|
243
|
+
'Start numbering at': 'Nummerierung beginnen bei',
|
|
244
|
+
'Number for the first item': 'Nummer des ersten Eintrags'
|
|
242
245
|
};
|
package/esm/langs/es.d.ts
CHANGED
package/esm/langs/es.js
CHANGED
|
@@ -237,5 +237,8 @@ export default {
|
|
|
237
237
|
Autoplay: 'Reproducción automática',
|
|
238
238
|
Loop: 'Repetir',
|
|
239
239
|
Muted: 'Silenciado',
|
|
240
|
-
Controls: 'Controles'
|
|
240
|
+
Controls: 'Controles',
|
|
241
|
+
'Start at...': 'Empezar en...',
|
|
242
|
+
'Start numbering at': 'Empezar la numeración en',
|
|
243
|
+
'Number for the first item': 'Número del primer elemento'
|
|
241
244
|
};
|