jodit 4.2.14 → 4.2.15
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/es2015/jodit.css +115 -115
- package/es2015/jodit.fat.min.css +1 -1
- package/es2015/jodit.fat.min.js +2 -2
- package/es2015/jodit.js +525 -444
- package/es2015/jodit.min.css +1 -1
- package/es2015/jodit.min.js +2 -2
- 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.css +115 -115
- package/es2018/jodit.fat.min.css +1 -1
- package/es2018/jodit.fat.min.js +2 -2
- package/es2018/jodit.js +525 -444
- package/es2018/jodit.min.css +1 -1
- package/es2018/jodit.min.js +2 -2
- package/es2018/plugins/debug/debug.js +1 -1
- package/es2018/plugins/debug/debug.min.js +1 -1
- package/es2018/plugins/speech-recognize/speech-recognize.css +1 -1
- package/es2018/plugins/speech-recognize/speech-recognize.js +1 -1
- package/es2018/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es2021/jodit.css +115 -115
- package/es2021/jodit.fat.min.css +1 -1
- package/es2021/jodit.fat.min.js +2 -2
- package/es2021/jodit.js +519 -440
- package/es2021/jodit.min.css +1 -1
- package/es2021/jodit.min.js +2 -2
- 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 +115 -115
- package/es2021.en/jodit.fat.min.css +1 -1
- package/es2021.en/jodit.fat.min.js +2 -2
- package/es2021.en/jodit.js +519 -440
- package/es2021.en/jodit.min.css +1 -1
- package/es2021.en/jodit.min.js +2 -2
- 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 +129 -129
- package/es5/jodit.fat.min.css +1 -1
- package/es5/jodit.fat.min.js +2 -2
- package/es5/jodit.js +542 -460
- package/es5/jodit.min.css +3 -3
- package/es5/jodit.min.js +2 -2
- 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/esm/core/constants.js +1 -1
- package/esm/core/selection/helpers/index.d.ts +9 -3
- package/esm/core/selection/helpers/index.js +48 -0
- package/esm/core/selection/selection.d.ts +6 -1
- package/esm/core/selection/selection.js +95 -117
- package/esm/index.d.ts +6 -1
- package/esm/index.js +3 -2
- package/esm/modules/table/table.d.ts +3 -1
- package/esm/modules/table/table.js +38 -33
- package/esm/modules/uploader/helpers/send-files.js +33 -29
- package/esm/plugins/backspace/cases/check-remove-char.js +65 -55
- package/esm/plugins/drag-and-drop/drag-and-drop.d.ts +2 -0
- package/esm/plugins/drag-and-drop/drag-and-drop.js +43 -36
- package/esm/plugins/link/link.js +71 -64
- package/esm/plugins/search/helpers/highlight-text-ranges.d.ts +0 -4
- package/esm/plugins/search/helpers/highlight-text-ranges.js +58 -49
- package/esm/plugins/table-keyboard-navigation/table-keyboard-navigation.js +35 -29
- package/package.json +1 -1
- package/types/core/selection/helpers/index.d.ts +9 -3
- package/types/core/selection/selection.d.ts +6 -1
- package/types/index.d.ts +6 -1
- package/types/modules/table/table.d.ts +3 -1
- package/types/plugins/drag-and-drop/drag-and-drop.d.ts +2 -0
- package/types/plugins/search/helpers/highlight-text-ranges.d.ts +0 -4
|
@@ -19,34 +19,7 @@ export function sendFiles(uploader, files, handlerSuccess, handlerError, process
|
|
|
19
19
|
}
|
|
20
20
|
const promises = [];
|
|
21
21
|
if (o.insertImageAsBase64URI) {
|
|
22
|
-
|
|
23
|
-
for (i = 0; i < fileList.length; i += 1) {
|
|
24
|
-
file = fileList[i];
|
|
25
|
-
if (file && file.type) {
|
|
26
|
-
const mime = file.type.match(/\/([a-z0-9]+)/i);
|
|
27
|
-
const extension = mime[1] ? mime[1].toLowerCase() : '';
|
|
28
|
-
if (o.imagesExtensions.includes(extension)) {
|
|
29
|
-
const reader = new FileReader();
|
|
30
|
-
promises.push(uploader.j.async.promise((resolve, reject) => {
|
|
31
|
-
reader.onerror = reject;
|
|
32
|
-
reader.onloadend = () => {
|
|
33
|
-
const resp = {
|
|
34
|
-
baseurl: '',
|
|
35
|
-
files: [reader.result],
|
|
36
|
-
isImages: [true]
|
|
37
|
-
};
|
|
38
|
-
const handler = isFunction(handlerSuccess)
|
|
39
|
-
? handlerSuccess
|
|
40
|
-
: o.defaultHandlerSuccess;
|
|
41
|
-
handler.call(uploader, resp);
|
|
42
|
-
resolve(resp);
|
|
43
|
-
};
|
|
44
|
-
reader.readAsDataURL(file);
|
|
45
|
-
}));
|
|
46
|
-
fileList[i] = null;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
22
|
+
readImagesWithReader(fileList, o.imagesExtensions, promises, uploader, handlerSuccess, o.defaultHandlerSuccess);
|
|
50
23
|
}
|
|
51
24
|
fileList = fileList.filter(a => a);
|
|
52
25
|
if (fileList.length) {
|
|
@@ -57,7 +30,7 @@ export function sendFiles(uploader, files, handlerSuccess, handlerError, process
|
|
|
57
30
|
for (let i = 0; i < fileList.length; i += 1) {
|
|
58
31
|
file = fileList[i];
|
|
59
32
|
if (file) {
|
|
60
|
-
const hasRealExtension =
|
|
33
|
+
const hasRealExtension = /\.\w+$/.test(file.name);
|
|
61
34
|
const mime = file.type.match(/\/([a-z0-9]+)/i);
|
|
62
35
|
const extension = mime && mime[1] ? mime[1].toLowerCase() : '';
|
|
63
36
|
let newName = fileList[i].name ||
|
|
@@ -106,3 +79,34 @@ export function sendFiles(uploader, files, handlerSuccess, handlerError, process
|
|
|
106
79
|
}
|
|
107
80
|
return Promise.all(promises);
|
|
108
81
|
}
|
|
82
|
+
function readImagesWithReader(fileList, imagesExtensions, promises, uploader, handlerSuccess, defaultHandlerSuccess) {
|
|
83
|
+
let file, i;
|
|
84
|
+
for (i = 0; i < fileList.length; i += 1) {
|
|
85
|
+
file = fileList[i];
|
|
86
|
+
if (file && file.type) {
|
|
87
|
+
const mime = file.type.match(/\/([a-z0-9]+)/i);
|
|
88
|
+
const extension = mime[1] ? mime[1].toLowerCase() : '';
|
|
89
|
+
if (!imagesExtensions.includes(extension)) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const reader = new FileReader();
|
|
93
|
+
promises.push(uploader.j.async.promise((resolve, reject) => {
|
|
94
|
+
reader.onerror = reject;
|
|
95
|
+
reader.onloadend = () => {
|
|
96
|
+
const resp = {
|
|
97
|
+
baseurl: '',
|
|
98
|
+
files: [reader.result],
|
|
99
|
+
isImages: [true]
|
|
100
|
+
};
|
|
101
|
+
const handler = isFunction(handlerSuccess)
|
|
102
|
+
? handlerSuccess
|
|
103
|
+
: defaultHandlerSuccess;
|
|
104
|
+
handler.call(uploader, resp);
|
|
105
|
+
resolve(resp);
|
|
106
|
+
};
|
|
107
|
+
reader.readAsDataURL(file);
|
|
108
|
+
}));
|
|
109
|
+
fileList[i] = null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -23,19 +23,12 @@ import { findMostNestedNeighbor } from "../helpers.js";
|
|
|
23
23
|
export function checkRemoveChar(jodit, fakeNode, backspace, mode) {
|
|
24
24
|
const step = backspace ? -1 : 1;
|
|
25
25
|
const anotherSibling = Dom.sibling(fakeNode, !backspace);
|
|
26
|
-
let sibling = Dom.sibling(fakeNode, backspace)
|
|
27
|
-
let
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (!nextSibling &&
|
|
31
|
-
sibling.parentNode &&
|
|
32
|
-
sibling.parentNode !== jodit.editor) {
|
|
33
|
-
nextSibling = findMostNestedNeighbor(sibling, !backspace, jodit.editor, true);
|
|
34
|
-
}
|
|
35
|
-
return nextSibling;
|
|
36
|
-
};
|
|
26
|
+
let sibling = Dom.sibling(fakeNode, backspace);
|
|
27
|
+
let removeNeighbor = null;
|
|
28
|
+
let charRemoved = false;
|
|
29
|
+
let removed;
|
|
37
30
|
if (!sibling) {
|
|
38
|
-
sibling = getNextInlineSibling(fakeNode);
|
|
31
|
+
sibling = getNextInlineSibling(fakeNode, backspace, jodit.editor);
|
|
39
32
|
}
|
|
40
33
|
while (sibling && (Dom.isText(sibling) || Dom.isInlineBlock(sibling))) {
|
|
41
34
|
while (Dom.isInlineBlock(sibling)) {
|
|
@@ -45,57 +38,17 @@ export function checkRemoveChar(jodit, fakeNode, backspace, mode) {
|
|
|
45
38
|
break;
|
|
46
39
|
}
|
|
47
40
|
if (sibling.nodeValue?.length) {
|
|
48
|
-
|
|
49
|
-
let value = toArray(sibling.nodeValue);
|
|
50
|
-
const length = value.length;
|
|
51
|
-
let index = backspace ? length - 1 : 0;
|
|
52
|
-
if (value[index] === INVISIBLE_SPACE) {
|
|
53
|
-
while (value[index] === INVISIBLE_SPACE) {
|
|
54
|
-
index += step;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
removed = value[index];
|
|
58
|
-
if (value[index + step] === INVISIBLE_SPACE) {
|
|
59
|
-
index += step;
|
|
60
|
-
while (value[index] === INVISIBLE_SPACE) {
|
|
61
|
-
index += step;
|
|
62
|
-
}
|
|
63
|
-
index += backspace ? 1 : -1;
|
|
64
|
-
}
|
|
65
|
-
if (backspace && index < 0) {
|
|
66
|
-
value = [];
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
value = value.slice(backspace ? 0 : index + 1, backspace ? index : length);
|
|
70
|
-
}
|
|
71
|
-
if (!anotherSibling ||
|
|
72
|
-
!Dom.isText(anotherSibling) ||
|
|
73
|
-
(!backspace ? / $/ : /^ /).test(anotherSibling.nodeValue ?? '') ||
|
|
74
|
-
!trimInv(anotherSibling.nodeValue || '').length) {
|
|
75
|
-
for (let i = backspace ? value.length - 1 : 0; backspace ? i >= 0 : i < value.length; i += backspace ? -1 : 1) {
|
|
76
|
-
if (value[i] === ' ') {
|
|
77
|
-
value[i] = NBSP_SPACE;
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
break;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
sibling.nodeValue = value.join('');
|
|
41
|
+
removed = tryRemoveChar(sibling, backspace, step, anotherSibling);
|
|
85
42
|
}
|
|
86
43
|
if (!sibling.nodeValue?.length) {
|
|
87
44
|
removeNeighbor = sibling;
|
|
88
45
|
}
|
|
89
46
|
if (!isVoid(removed) && removed !== INVISIBLE_SPACE) {
|
|
47
|
+
checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed, jodit);
|
|
90
48
|
charRemoved = true;
|
|
91
|
-
call(backspace ? Dom.after : Dom.before, sibling, fakeNode);
|
|
92
|
-
if (mode === 'sentence' ||
|
|
93
|
-
(mode === 'word' && removed !== ' ' && removed !== NBSP_SPACE)) {
|
|
94
|
-
checkRemoveChar(jodit, fakeNode, backspace, mode);
|
|
95
|
-
}
|
|
96
49
|
break;
|
|
97
50
|
}
|
|
98
|
-
const nextSibling = getNextInlineSibling(sibling);
|
|
51
|
+
const nextSibling = getNextInlineSibling(sibling, backspace, jodit.editor);
|
|
99
52
|
if (removeNeighbor) {
|
|
100
53
|
Dom.safeRemove(removeNeighbor);
|
|
101
54
|
removeNeighbor = null;
|
|
@@ -117,6 +70,13 @@ export function checkRemoveChar(jodit, fakeNode, backspace, mode) {
|
|
|
117
70
|
}
|
|
118
71
|
return charRemoved;
|
|
119
72
|
}
|
|
73
|
+
function getNextInlineSibling(sibling, backspace, root) {
|
|
74
|
+
let nextSibling = Dom.sibling(sibling, backspace);
|
|
75
|
+
if (!nextSibling && sibling.parentNode && sibling.parentNode !== root) {
|
|
76
|
+
nextSibling = findMostNestedNeighbor(sibling, !backspace, root, true);
|
|
77
|
+
}
|
|
78
|
+
return nextSibling;
|
|
79
|
+
}
|
|
120
80
|
/**
|
|
121
81
|
* Helper removes all empty inline parents
|
|
122
82
|
*/
|
|
@@ -141,3 +101,53 @@ function addBRInsideEmptyBlock(jodit, node) {
|
|
|
141
101
|
Dom.after(node, jodit.createInside.element('br'));
|
|
142
102
|
}
|
|
143
103
|
}
|
|
104
|
+
function tryRemoveChar(sibling, backspace, step, anotherSibling) {
|
|
105
|
+
// For Unicode escapes
|
|
106
|
+
let value = toArray(sibling.nodeValue);
|
|
107
|
+
const length = value.length;
|
|
108
|
+
let index = backspace ? length - 1 : 0;
|
|
109
|
+
if (value[index] === INVISIBLE_SPACE) {
|
|
110
|
+
while (value[index] === INVISIBLE_SPACE) {
|
|
111
|
+
index += step;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const removed = value[index];
|
|
115
|
+
if (value[index + step] === INVISIBLE_SPACE) {
|
|
116
|
+
index += step;
|
|
117
|
+
while (value[index] === INVISIBLE_SPACE) {
|
|
118
|
+
index += step;
|
|
119
|
+
}
|
|
120
|
+
index += backspace ? 1 : -1;
|
|
121
|
+
}
|
|
122
|
+
if (backspace && index < 0) {
|
|
123
|
+
value = [];
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
value = value.slice(backspace ? 0 : index + 1, backspace ? index : length);
|
|
127
|
+
}
|
|
128
|
+
replaceSpaceOnNBSP(anotherSibling, backspace, value);
|
|
129
|
+
sibling.nodeValue = value.join('');
|
|
130
|
+
return removed;
|
|
131
|
+
}
|
|
132
|
+
function replaceSpaceOnNBSP(anotherSibling, backspace, value) {
|
|
133
|
+
if (!anotherSibling ||
|
|
134
|
+
!Dom.isText(anotherSibling) ||
|
|
135
|
+
(!backspace ? / $/ : /^ /).test(anotherSibling.nodeValue ?? '') ||
|
|
136
|
+
!trimInv(anotherSibling.nodeValue || '').length) {
|
|
137
|
+
for (let i = backspace ? value.length - 1 : 0; backspace ? i >= 0 : i < value.length; i += backspace ? -1 : 1) {
|
|
138
|
+
if (value[i] === ' ') {
|
|
139
|
+
value[i] = NBSP_SPACE;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed, jodit) {
|
|
148
|
+
call(backspace ? Dom.after : Dom.before, sibling, fakeNode);
|
|
149
|
+
if (mode === 'sentence' ||
|
|
150
|
+
(mode === 'word' && removed !== ' ' && removed !== NBSP_SPACE)) {
|
|
151
|
+
checkRemoveChar(jodit, fakeNode, backspace, mode);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -107,45 +107,11 @@ export class dragAndDrop extends Plugin {
|
|
|
107
107
|
const sel = this.j.s.sel;
|
|
108
108
|
const range = this.bufferRange ||
|
|
109
109
|
(sel && sel.rangeCount ? sel.getRangeAt(0) : null);
|
|
110
|
-
|
|
111
|
-
if (!this.draggable && range) {
|
|
112
|
-
fragment = this.isCopyMode
|
|
113
|
-
? range.cloneContents()
|
|
114
|
-
: range.extractContents();
|
|
115
|
-
}
|
|
116
|
-
else if (this.draggable) {
|
|
117
|
-
if (this.isCopyMode) {
|
|
118
|
-
const [tagName, field] = attr(this.draggable, '-is-file') === '1'
|
|
119
|
-
? ['a', 'href']
|
|
120
|
-
: ['img', 'src'];
|
|
121
|
-
fragment = this.j.createInside.element(tagName);
|
|
122
|
-
fragment.setAttribute(field, attr(this.draggable, 'data-src') ||
|
|
123
|
-
attr(this.draggable, 'src') ||
|
|
124
|
-
'');
|
|
125
|
-
if (tagName === 'a') {
|
|
126
|
-
fragment.textContent = attr(fragment, field) || '';
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
fragment = dataBind(this.draggable, 'target');
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
else if (this.getText(event)) {
|
|
134
|
-
fragment = this.j.createInside.fromHTML(this.getText(event));
|
|
135
|
-
}
|
|
110
|
+
const fragment = this.__getWorkFragment(range, event);
|
|
136
111
|
sel && sel.removeAllRanges();
|
|
137
112
|
this.j.s.insertCursorAtPoint(event.clientX, event.clientY);
|
|
138
113
|
if (fragment) {
|
|
139
|
-
this.
|
|
140
|
-
if (range && fragment.firstChild && fragment.lastChild) {
|
|
141
|
-
range.setStartBefore(fragment.firstChild);
|
|
142
|
-
range.setEndAfter(fragment.lastChild);
|
|
143
|
-
this.j.s.selectRange(range);
|
|
144
|
-
this.j.e.fire('synchro');
|
|
145
|
-
}
|
|
146
|
-
if (Dom.isTag(fragment, 'img') && this.j.events) {
|
|
147
|
-
this.j.e.fire('afterInsertImage', fragment);
|
|
148
|
-
}
|
|
114
|
+
this.__insertFragment.call(this, fragment, range);
|
|
149
115
|
}
|
|
150
116
|
event.preventDefault();
|
|
151
117
|
event.stopPropagation();
|
|
@@ -153,6 +119,47 @@ export class dragAndDrop extends Plugin {
|
|
|
153
119
|
this.isFragmentFromEditor = false;
|
|
154
120
|
this.removeDragListeners();
|
|
155
121
|
}
|
|
122
|
+
__getWorkFragment(range, event) {
|
|
123
|
+
let fragment = null;
|
|
124
|
+
if (!this.draggable && range) {
|
|
125
|
+
fragment = this.isCopyMode
|
|
126
|
+
? range.cloneContents()
|
|
127
|
+
: range.extractContents();
|
|
128
|
+
}
|
|
129
|
+
else if (this.draggable) {
|
|
130
|
+
if (this.isCopyMode) {
|
|
131
|
+
const [tagName, field] = attr(this.draggable, '-is-file') === '1'
|
|
132
|
+
? ['a', 'href']
|
|
133
|
+
: ['img', 'src'];
|
|
134
|
+
fragment = this.j.createInside.element(tagName);
|
|
135
|
+
fragment.setAttribute(field, attr(this.draggable, 'data-src') ||
|
|
136
|
+
attr(this.draggable, 'src') ||
|
|
137
|
+
'');
|
|
138
|
+
if (tagName === 'a') {
|
|
139
|
+
fragment.textContent = attr(fragment, field) || '';
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
fragment = dataBind(this.draggable, 'target');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else if (this.getText(event)) {
|
|
147
|
+
fragment = this.j.createInside.fromHTML(this.getText(event));
|
|
148
|
+
}
|
|
149
|
+
return fragment;
|
|
150
|
+
}
|
|
151
|
+
__insertFragment(fragment, range) {
|
|
152
|
+
this.j.s.insertNode(fragment, false, false);
|
|
153
|
+
if (range && fragment.firstChild && fragment.lastChild) {
|
|
154
|
+
range.setStartBefore(fragment.firstChild);
|
|
155
|
+
range.setEndAfter(fragment.lastChild);
|
|
156
|
+
this.j.s.selectRange(range);
|
|
157
|
+
this.j.e.fire('synchro');
|
|
158
|
+
}
|
|
159
|
+
if (Dom.isTag(fragment, 'img') && this.j.events) {
|
|
160
|
+
this.j.e.fire('afterInsertImage', fragment);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
156
163
|
/** @override */
|
|
157
164
|
beforeDestruct() {
|
|
158
165
|
this.onDragEnd();
|
package/esm/plugins/link/link.js
CHANGED
|
@@ -138,35 +138,7 @@ export class link extends Plugin {
|
|
|
138
138
|
if (link) {
|
|
139
139
|
url_input.value = attr(link, 'href') || '';
|
|
140
140
|
if (modeClassName) {
|
|
141
|
-
|
|
142
|
-
case 'input':
|
|
143
|
-
if (className_input) {
|
|
144
|
-
className_input.value = attr(link, 'class') || '';
|
|
145
|
-
}
|
|
146
|
-
break;
|
|
147
|
-
case 'select':
|
|
148
|
-
if (className_select) {
|
|
149
|
-
for (let i = 0; i < className_select.selectedOptions.length; i++) {
|
|
150
|
-
const option = className_select.options.item(i);
|
|
151
|
-
if (option) {
|
|
152
|
-
option.selected = false;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
const classNames = attr(link, 'class') || '';
|
|
156
|
-
classNames.split(' ').forEach(className => {
|
|
157
|
-
if (className) {
|
|
158
|
-
for (let i = 0; i < className_select.options.length; i++) {
|
|
159
|
-
const option = className_select.options.item(i);
|
|
160
|
-
if (option?.value &&
|
|
161
|
-
option.value === className) {
|
|
162
|
-
option.selected = true;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
break;
|
|
169
|
-
}
|
|
141
|
+
readClassnames(modeClassName, className_input, link, className_select);
|
|
170
142
|
}
|
|
171
143
|
if (openInNewTabCheckbox && target_checkbox) {
|
|
172
144
|
target_checkbox.checked = attr(link, 'target') === '_blank';
|
|
@@ -228,42 +200,9 @@ export class link extends Plugin {
|
|
|
228
200
|
}
|
|
229
201
|
links.forEach(a => {
|
|
230
202
|
attr(a, 'href', url_input.value);
|
|
231
|
-
|
|
232
|
-
if (modeClassName === 'input') {
|
|
233
|
-
if (className_input.value === '' &&
|
|
234
|
-
a.hasAttribute('class')) {
|
|
235
|
-
attr(a, 'class', null);
|
|
236
|
-
}
|
|
237
|
-
if (className_input.value !== '') {
|
|
238
|
-
attr(a, 'class', className_input.value);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
else if (modeClassName === 'select') {
|
|
242
|
-
if (a.hasAttribute('class')) {
|
|
243
|
-
attr(a, 'class', null);
|
|
244
|
-
}
|
|
245
|
-
for (let i = 0; i < className_select.selectedOptions.length; i++) {
|
|
246
|
-
const className = className_select.selectedOptions.item(i)?.value;
|
|
247
|
-
if (className) {
|
|
248
|
-
a.classList.add(className);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
203
|
+
writeClasses(modeClassName, className_input, className_select, a);
|
|
253
204
|
if (!isImageContent) {
|
|
254
|
-
|
|
255
|
-
if (content_input.value.trim().length) {
|
|
256
|
-
if (textWasChanged) {
|
|
257
|
-
newContent = content_input.value;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
else {
|
|
261
|
-
newContent = url_input.value;
|
|
262
|
-
}
|
|
263
|
-
const content = a.textContent;
|
|
264
|
-
if (newContent !== content) {
|
|
265
|
-
a.textContent = newContent;
|
|
266
|
-
}
|
|
205
|
+
writeImage(a, content_input, textWasChanged, url_input);
|
|
267
206
|
}
|
|
268
207
|
if (openInNewTabCheckbox && target_checkbox) {
|
|
269
208
|
attr(a, 'target', target_checkbox.checked ? '_blank' : null);
|
|
@@ -308,3 +247,71 @@ __decorate([
|
|
|
308
247
|
autobind
|
|
309
248
|
], link.prototype, "__generateForm", null);
|
|
310
249
|
pluginSystem.add('link', link);
|
|
250
|
+
function writeClasses(modeClassName, className_input, className_select, a) {
|
|
251
|
+
if (modeClassName && (className_input ?? className_select)) {
|
|
252
|
+
if (modeClassName === 'input') {
|
|
253
|
+
if (className_input.value === '' && a.hasAttribute('class')) {
|
|
254
|
+
attr(a, 'class', null);
|
|
255
|
+
}
|
|
256
|
+
if (className_input.value !== '') {
|
|
257
|
+
attr(a, 'class', className_input.value);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
else if (modeClassName === 'select') {
|
|
261
|
+
if (a.hasAttribute('class')) {
|
|
262
|
+
attr(a, 'class', null);
|
|
263
|
+
}
|
|
264
|
+
for (let i = 0; i < className_select.selectedOptions.length; i++) {
|
|
265
|
+
const className = className_select.selectedOptions.item(i)?.value;
|
|
266
|
+
if (className) {
|
|
267
|
+
a.classList.add(className);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function readClassnames(modeClassName, className_input, link, className_select) {
|
|
274
|
+
switch (modeClassName) {
|
|
275
|
+
case 'input':
|
|
276
|
+
if (className_input) {
|
|
277
|
+
className_input.value = attr(link, 'class') || '';
|
|
278
|
+
}
|
|
279
|
+
break;
|
|
280
|
+
case 'select':
|
|
281
|
+
if (className_select) {
|
|
282
|
+
for (let i = 0; i < className_select.selectedOptions.length; i++) {
|
|
283
|
+
const option = className_select.options.item(i);
|
|
284
|
+
if (option) {
|
|
285
|
+
option.selected = false;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const classNames = attr(link, 'class') || '';
|
|
289
|
+
classNames.split(' ').forEach(className => {
|
|
290
|
+
if (className) {
|
|
291
|
+
for (let i = 0; i < className_select.options.length; i++) {
|
|
292
|
+
const option = className_select.options.item(i);
|
|
293
|
+
if (option?.value && option.value === className) {
|
|
294
|
+
option.selected = true;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function writeImage(a, content_input, textWasChanged, url_input) {
|
|
304
|
+
let newContent = a.textContent;
|
|
305
|
+
if (content_input.value.trim().length) {
|
|
306
|
+
if (textWasChanged) {
|
|
307
|
+
newContent = content_input.value;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
newContent = url_input.value;
|
|
312
|
+
}
|
|
313
|
+
const content = a.textContent;
|
|
314
|
+
if (newContent !== content) {
|
|
315
|
+
a.textContent = newContent;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
@@ -23,7 +23,3 @@ export declare function clearSelectionWrappers(root: HTMLElement): void;
|
|
|
23
23
|
* @private
|
|
24
24
|
*/
|
|
25
25
|
export declare function clearSelectionWrappersFromHTML(root: string): string;
|
|
26
|
-
/**
|
|
27
|
-
* @private
|
|
28
|
-
*/
|
|
29
|
-
export declare function isSelectionWrapper(node: unknown): boolean;
|
|
@@ -17,60 +17,14 @@ export function highlightTextRanges(jodit, rng, restRanges, ci, root) {
|
|
|
17
17
|
rng.endContainer.nodeValue == null) {
|
|
18
18
|
return;
|
|
19
19
|
}
|
|
20
|
-
if (jodit
|
|
21
|
-
// @ts-ignore Because Highlight is not defined in the types TS 5.3.3
|
|
22
|
-
typeof window.Highlight !== 'undefined') {
|
|
23
|
-
const ranges = [rng, ...restRanges].map(rng => {
|
|
24
|
-
const range = jodit.selection.createRange();
|
|
25
|
-
range.setStart(rng.startContainer, rng.startOffset);
|
|
26
|
-
range.setEnd(rng.endContainer, rng.endOffset);
|
|
27
|
-
return range;
|
|
28
|
-
});
|
|
29
|
-
// @ts-ignore Because Highlight is not defined in the types TS 5.3.3
|
|
30
|
-
const searchHighlight = new Highlight(...ranges);
|
|
31
|
-
// @ts-ignore
|
|
32
|
-
CSS.highlights.clear();
|
|
33
|
-
// @ts-ignore
|
|
34
|
-
CSS.highlights.set('jodit-search-result', searchHighlight);
|
|
35
|
-
restRanges.length = 0;
|
|
20
|
+
if (checkNativeSelectionMethod(jodit, rng, restRanges)) {
|
|
36
21
|
return;
|
|
37
22
|
}
|
|
38
23
|
const span = ci.element('span', {
|
|
39
24
|
[TMP_ATTR]: true
|
|
40
25
|
});
|
|
41
26
|
Dom.markTemporary(span);
|
|
42
|
-
|
|
43
|
-
let diff = 0;
|
|
44
|
-
if (rng.startOffset !== 0) {
|
|
45
|
-
const text = ci.text(startText.substring(0, rng.startOffset));
|
|
46
|
-
rng.startContainer.nodeValue = startText.substring(rng.startOffset);
|
|
47
|
-
Dom.before(rng.startContainer, text);
|
|
48
|
-
if (rng.startContainer === rng.endContainer) {
|
|
49
|
-
diff = rng.startOffset;
|
|
50
|
-
rng.endOffset -= diff;
|
|
51
|
-
}
|
|
52
|
-
rng.startOffset = 0;
|
|
53
|
-
}
|
|
54
|
-
const endText = rng.endContainer.nodeValue;
|
|
55
|
-
if (rng.endOffset !== endText.length) {
|
|
56
|
-
const text = ci.text(endText.substring(rng.endOffset));
|
|
57
|
-
rng.endContainer.nodeValue = endText.substring(0, rng.endOffset);
|
|
58
|
-
Dom.after(rng.endContainer, text);
|
|
59
|
-
for (const range of restRanges) {
|
|
60
|
-
if (range.startContainer === rng.endContainer) {
|
|
61
|
-
range.startContainer = text;
|
|
62
|
-
range.startOffset = range.startOffset - rng.endOffset - diff;
|
|
63
|
-
if (range.endContainer === rng.endContainer) {
|
|
64
|
-
range.endContainer = text;
|
|
65
|
-
range.endOffset = range.endOffset - rng.endOffset - diff;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
break;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
rng.endOffset = rng.endContainer.nodeValue.length;
|
|
73
|
-
}
|
|
27
|
+
normalizeRanges(rng, restRanges, ci);
|
|
74
28
|
let next = rng.startContainer;
|
|
75
29
|
do {
|
|
76
30
|
if (!next) {
|
|
@@ -113,6 +67,61 @@ export function clearSelectionWrappersFromHTML(root) {
|
|
|
113
67
|
/**
|
|
114
68
|
* @private
|
|
115
69
|
*/
|
|
116
|
-
|
|
70
|
+
function isSelectionWrapper(node) {
|
|
117
71
|
return Dom.isElement(node) && node.hasAttribute(TMP_ATTR);
|
|
118
72
|
}
|
|
73
|
+
function checkNativeSelectionMethod(jodit, rng, restRanges) {
|
|
74
|
+
if (jodit.o.search.useCustomHighlightAPI &&
|
|
75
|
+
// @ts-ignore Because Highlight is not defined in the types TS 5.3.3
|
|
76
|
+
typeof window.Highlight !== 'undefined') {
|
|
77
|
+
const ranges = [rng, ...restRanges].map(rng => {
|
|
78
|
+
const range = jodit.selection.createRange();
|
|
79
|
+
range.setStart(rng.startContainer, rng.startOffset);
|
|
80
|
+
range.setEnd(rng.endContainer, rng.endOffset);
|
|
81
|
+
return range;
|
|
82
|
+
});
|
|
83
|
+
// @ts-ignore Because Highlight is not defined in the types TS 5.3.3
|
|
84
|
+
const searchHighlight = new Highlight(...ranges);
|
|
85
|
+
// @ts-ignore
|
|
86
|
+
CSS.highlights.clear();
|
|
87
|
+
// @ts-ignore
|
|
88
|
+
CSS.highlights.set('jodit-search-result', searchHighlight);
|
|
89
|
+
restRanges.length = 0;
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
function normalizeRanges(rng, restRanges, ci) {
|
|
95
|
+
const startText = rng.startContainer.nodeValue;
|
|
96
|
+
let diff = 0;
|
|
97
|
+
if (rng.startOffset !== 0) {
|
|
98
|
+
const text = ci.text(startText.substring(0, rng.startOffset));
|
|
99
|
+
rng.startContainer.nodeValue = startText.substring(rng.startOffset);
|
|
100
|
+
Dom.before(rng.startContainer, text);
|
|
101
|
+
if (rng.startContainer === rng.endContainer) {
|
|
102
|
+
diff = rng.startOffset;
|
|
103
|
+
rng.endOffset -= diff;
|
|
104
|
+
}
|
|
105
|
+
rng.startOffset = 0;
|
|
106
|
+
}
|
|
107
|
+
const endText = rng.endContainer.nodeValue;
|
|
108
|
+
if (rng.endOffset !== endText.length) {
|
|
109
|
+
const text = ci.text(endText.substring(rng.endOffset));
|
|
110
|
+
rng.endContainer.nodeValue = endText.substring(0, rng.endOffset);
|
|
111
|
+
Dom.after(rng.endContainer, text);
|
|
112
|
+
for (const range of restRanges) {
|
|
113
|
+
if (range.startContainer === rng.endContainer) {
|
|
114
|
+
range.startContainer = text;
|
|
115
|
+
range.startOffset = range.startOffset - rng.endOffset - diff;
|
|
116
|
+
if (range.endContainer === rng.endContainer) {
|
|
117
|
+
range.endContainer = text;
|
|
118
|
+
range.endOffset = range.endOffset - rng.endOffset - diff;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
rng.endOffset = rng.endContainer.nodeValue.length;
|
|
126
|
+
}
|
|
127
|
+
}
|