jodit 3.23.3 → 3.24.2
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/README.md +4 -4
- package/build/jodit.css +8 -3
- package/build/jodit.es2018.css +7 -2
- package/build/jodit.es2018.en.css +7 -2
- package/build/jodit.es2018.en.js +8384 -7869
- package/build/jodit.es2018.en.min.css +1 -1
- package/build/jodit.es2018.en.min.js +1 -1
- package/build/jodit.es2018.js +8384 -7869
- package/build/jodit.es2018.min.css +1 -1
- package/build/jodit.es2018.min.js +1 -1
- package/build/jodit.js +2954 -2414
- package/build/jodit.min.css +2 -2
- package/build/jodit.min.js +1 -1
- package/build/plugins/debug/debug.es2018.en.js +8 -8
- package/build/plugins/debug/debug.es2018.en.min.js +1 -1
- package/build/plugins/debug/debug.es2018.js +8 -8
- package/build/plugins/debug/debug.es2018.min.js +1 -1
- package/build/plugins/debug/debug.js +8 -8
- package/build/plugins/debug/debug.min.js +1 -1
- package/build/plugins/speech-recognize/speech-recognize.css +1 -1
- package/build/plugins/speech-recognize/speech-recognize.es2018.css +1 -1
- package/build/plugins/speech-recognize/speech-recognize.es2018.en.css +1 -1
- package/build/plugins/speech-recognize/speech-recognize.es2018.en.js +38 -38
- package/build/plugins/speech-recognize/speech-recognize.es2018.en.min.js +1 -1
- package/build/plugins/speech-recognize/speech-recognize.es2018.js +38 -38
- package/build/plugins/speech-recognize/speech-recognize.es2018.min.js +1 -1
- package/build/plugins/speech-recognize/speech-recognize.js +30 -30
- package/build/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/build/vdom.css +12 -1
- package/build/vdom.js +1445 -41
- package/package.json +23 -23
- package/src/core/constants.ts +10 -8
- package/src/core/dom/dom.test.js +25 -0
- package/src/core/dom/dom.ts +90 -41
- package/src/core/helpers/checker/has-browser-color-picker.ts +2 -2
- package/src/core/helpers/checker/index.ts +1 -0
- package/src/core/helpers/checker/is-boolean.ts +1 -1
- package/src/core/helpers/checker/is-marker.ts +20 -0
- package/src/core/helpers/normalize/normalize-css-value.ts +19 -0
- package/src/core/helpers/normalize/normalize-node.ts +2 -2
- package/src/core/helpers/size/position.test.js +198 -187
- package/src/core/helpers/utils/css.ts +7 -14
- package/src/core/plugin/plugin.ts +1 -1
- package/src/core/selection/interface.ts +24 -0
- package/src/core/selection/select.ts +69 -29
- package/src/core/selection/selection.test.js +5 -17
- package/src/core/selection/style/api/extract.ts +6 -7
- package/src/core/selection/style/api/finite-state-machine.ts +40 -35
- package/src/core/selection/style/api/get-suit-child.ts +3 -4
- package/src/core/selection/style/api/get-suit-parent.ts +3 -4
- package/src/core/selection/style/api/{element-has-same-style.ts → has-same-style.ts} +25 -6
- package/src/core/selection/style/api/index.ts +6 -6
- package/src/core/selection/style/api/is-inside-invisible-element.ts +1 -1
- package/src/core/selection/style/api/is-normal-node.ts +3 -3
- package/src/core/selection/style/api/is-same-attributes.ts +56 -0
- package/src/core/selection/style/api/is-suit-element.ts +22 -12
- package/src/core/selection/style/api/list/toggle-ordered-list.ts +100 -0
- package/src/core/selection/style/api/list/wrap-list.ts +71 -0
- package/src/core/selection/style/api/toggle-attributes.ts +251 -0
- package/src/core/selection/style/api/unwrap-children.ts +10 -8
- package/src/core/selection/style/api/wrap-unwrapped-text.ts +7 -8
- package/src/core/selection/style/api/{wrap-and-commit-style.ts → wrap.ts} +8 -11
- package/src/core/selection/style/apply-style.ts +32 -181
- package/src/core/selection/style/commit-style.ts +79 -4
- package/src/core/selection/style/style.test.js +457 -128
- package/src/core/selection/style/transactions.ts +256 -0
- package/src/core/ui/button/tooltip/tooltip.test.js +95 -76
- package/src/core/ui/popup/popup.test.js +158 -153
- package/src/{plugins/backspace/interface.d.ts → core/vdom/on-demand.ts} +7 -5
- package/src/core/vdom/render/index.ts +2 -4
- package/src/core/vdom/render/patcher.ts +14 -0
- package/src/core/vdom/v-dom-jodit.less +17 -0
- package/src/core/vdom/v-dom-jodit.ts +102 -3
- package/src/core/view/view.ts +2 -2
- package/src/index.ts +2 -0
- package/src/jodit.ts +5 -1
- package/src/langs/i18n.test.js +221 -216
- package/src/modules/dialog/dialog.less +9 -1
- package/src/modules/dialog/dialog.ts +25 -16
- package/src/modules/file-browser/data-provider.ts +44 -12
- package/src/modules/file-browser/file-browser.test.js +1019 -958
- package/src/modules/file-browser/file-browser.ts +0 -1
- package/src/modules/messages/messages.ts +3 -8
- package/src/plugins/backspace/backspace.test.js +2 -9
- package/src/plugins/backspace/backspace.ts +5 -0
- package/src/plugins/backspace/cases/check-join-neighbors.ts +7 -1
- package/src/plugins/backspace/cases/check-join-two-lists.ts +2 -1
- package/src/plugins/backspace/helpers.ts +9 -1
- package/src/plugins/backspace/interface.ts +31 -0
- package/src/plugins/clean-html/helpers/visitor/filters/fill-empty-paragraph.ts +2 -1
- package/src/plugins/color/color.test.js +122 -119
- package/src/plugins/enter/enter.test.js +18 -5
- package/src/plugins/enter/enter.ts +9 -5
- package/src/plugins/enter/interface.ts +41 -0
- package/src/plugins/font/config.ts +8 -8
- package/src/plugins/font/font.test.js +18 -23
- package/src/plugins/hotkeys/hotkeys.test.js +35 -47
- package/src/plugins/iframe/iframe.test.js +206 -195
- package/src/plugins/image/image.ts +1 -1
- package/src/plugins/image-properties/config.ts +22 -0
- package/src/plugins/image-properties/image-properties.test.js +174 -93
- package/src/plugins/image-properties/templates/position-tab.ts +22 -1
- package/src/plugins/indent/indent.test.js +2 -8
- package/src/plugins/link/link.test.js +19 -0
- package/src/plugins/link/link.ts +25 -15
- package/src/plugins/placeholder/placeholder.ts +8 -7
- package/src/plugins/size/size.test.js +239 -225
- package/src/plugins/tab/cases/on-tab-inside-li.ts +131 -22
- package/src/plugins/tab/tab.test.js +95 -11
- package/src/plugins/tab/tab.ts +22 -2
- package/src/plugins/wrap-nodes/config.ts +11 -0
- package/src/plugins/wrap-nodes/wrap-nodes.ts +0 -1
- package/src/types/events.d.ts +4 -0
- package/src/types/file-browser.d.ts +17 -10
- package/src/types/select.d.ts +6 -1
- package/src/types/style.d.ts +72 -5
- package/src/types/uploader.d.ts +14 -0
- package/src/types/view.d.ts +2 -2
- package/types/core/async/async.d.ts +1 -1
- package/types/core/constants.d.ts +3 -3
- package/types/core/dom/dom.d.ts +6 -3
- package/types/core/helpers/checker/index.d.ts +1 -0
- package/types/core/helpers/checker/is-boolean.d.ts +1 -1
- package/types/core/helpers/checker/is-marker.d.ts +10 -0
- package/types/core/helpers/html/safe-html.d.ts +1 -1
- package/types/core/helpers/normalize/normalize-css-value.d.ts +2 -0
- package/types/core/helpers/normalize/normalize-node.d.ts +1 -1
- package/types/core/helpers/utils/append-script.d.ts +1 -1
- package/types/core/selection/interface.d.ts +19 -0
- package/types/core/selection/select.d.ts +22 -5
- package/types/core/selection/style/api/finite-state-machine.d.ts +10 -9
- package/types/core/selection/style/api/get-suit-child.d.ts +2 -3
- package/types/core/selection/style/api/get-suit-parent.d.ts +2 -3
- package/types/core/selection/style/api/{element-has-same-style.d.ts → has-same-style.d.ts} +2 -2
- package/types/core/selection/style/api/index.d.ts +6 -6
- package/types/core/selection/style/api/is-same-attributes.d.ts +12 -0
- package/types/core/selection/style/api/is-suit-element.d.ts +4 -4
- package/types/core/selection/style/api/{toggle → list}/toggle-ordered-list.d.ts +2 -3
- package/types/core/selection/style/api/{wrap-ordered-list.d.ts → list/wrap-list.d.ts} +2 -3
- package/types/core/selection/style/api/toggle-attributes.d.ts +11 -0
- package/types/core/selection/style/api/unwrap-children.d.ts +2 -2
- package/types/core/selection/style/api/wrap-unwrapped-text.d.ts +2 -3
- package/types/core/selection/style/api/{wrap-and-commit-style.d.ts → wrap.d.ts} +2 -3
- package/types/core/selection/style/apply-style.d.ts +3 -3
- package/types/core/selection/style/commit-style.d.ts +6 -2
- package/types/core/selection/style/transactions.d.ts +29 -0
- package/types/core/ui/popup/popup.d.ts +1 -1
- package/types/core/view/view.d.ts +1 -1
- package/types/index.d.ts +2 -0
- package/types/modules/file-browser/builders/elements-map.d.ts +1 -1
- package/types/modules/file-browser/data-provider.d.ts +5 -0
- package/types/modules/messages/messages.d.ts +2 -1
- package/types/plugins/backspace/helpers.d.ts +5 -1
- package/types/plugins/backspace/interface.d.ts +21 -0
- package/types/plugins/enter/enter.d.ts +2 -0
- package/types/plugins/enter/interface.d.ts +32 -0
- package/types/plugins/image-properties/config.d.ts +19 -0
- package/types/plugins/link/link.d.ts +1 -1
- package/types/plugins/paste/interface.d.ts +2 -2
- package/types/plugins/tab/cases/on-tab-inside-li.d.ts +1 -1
- package/types/plugins/wrap-nodes/config.d.ts +10 -0
- package/types/types/events.d.ts +4 -0
- package/types/types/file-browser.d.ts +17 -10
- package/types/types/select.d.ts +6 -1
- package/types/types/storage.d.ts +1 -1
- package/types/types/style.d.ts +72 -5
- package/types/types/uploader.d.ts +14 -0
- package/types/types/view.d.ts +2 -2
- package/vdom.html +20 -0
- package/src/core/selection/style/api/toggle/toggle-css.ts +0 -136
- package/src/core/selection/style/api/toggle/toggle-ordered-list.ts +0 -54
- package/src/core/selection/style/api/toggle-commit-styles.ts +0 -35
- package/src/core/selection/style/api/wrap-ordered-list.ts +0 -42
- package/types/core/selection/style/api/toggle/toggle-css.d.ts +0 -12
- package/types/core/selection/style/api/toggle-commit-styles.d.ts +0 -13
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
IJodit,
|
|
18
18
|
ISelect,
|
|
19
19
|
IStyle,
|
|
20
|
+
IStyleOptions,
|
|
20
21
|
MarkerInfo,
|
|
21
22
|
Nullable
|
|
22
23
|
} from 'jodit/types';
|
|
@@ -32,10 +33,9 @@ import {
|
|
|
32
33
|
import { Dom } from 'jodit/core/dom';
|
|
33
34
|
|
|
34
35
|
import {
|
|
36
|
+
size,
|
|
35
37
|
attr,
|
|
36
38
|
error,
|
|
37
|
-
isFunction,
|
|
38
|
-
isString,
|
|
39
39
|
$$,
|
|
40
40
|
css,
|
|
41
41
|
call,
|
|
@@ -45,6 +45,10 @@ import {
|
|
|
45
45
|
import { CommitStyle } from './style/commit-style';
|
|
46
46
|
import { autobind } from 'jodit/core/decorators';
|
|
47
47
|
import { moveTheNodeAlongTheEdgeOutward } from 'jodit/core/selection/helpers';
|
|
48
|
+
import { assert } from 'jodit/core/helpers/utils/assert';
|
|
49
|
+
import { isMarker, isFunction, isString } from 'jodit/core/helpers/checker';
|
|
50
|
+
|
|
51
|
+
import './interface';
|
|
48
52
|
|
|
49
53
|
export class Select implements ISelect {
|
|
50
54
|
constructor(readonly jodit: IJodit) {
|
|
@@ -214,17 +218,6 @@ export class Select implements ISelect {
|
|
|
214
218
|
return false;
|
|
215
219
|
}
|
|
216
220
|
|
|
217
|
-
/**
|
|
218
|
-
* Define element is selection helper
|
|
219
|
-
*/
|
|
220
|
-
static isMarker(elm: Nullable<Node>): elm is HTMLElement {
|
|
221
|
-
return (
|
|
222
|
-
Dom.isNode(elm) &&
|
|
223
|
-
Dom.isTag(elm, 'span') &&
|
|
224
|
-
elm.hasAttribute('data-' + consts.MARKER_CLASS)
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
221
|
/**
|
|
229
222
|
* Check if editor has selection markers
|
|
230
223
|
*/
|
|
@@ -837,7 +830,7 @@ export class Select implements ISelect {
|
|
|
837
830
|
node &&
|
|
838
831
|
node !== root &&
|
|
839
832
|
!Dom.isEmptyTextNode(node) &&
|
|
840
|
-
!
|
|
833
|
+
!isMarker(node as HTMLElement)
|
|
841
834
|
) {
|
|
842
835
|
nodes.push(node);
|
|
843
836
|
}
|
|
@@ -926,8 +919,17 @@ export class Select implements ISelect {
|
|
|
926
919
|
const container = start ? range.startContainer : range.endContainer;
|
|
927
920
|
const offset = start ? range.startOffset : range.endOffset;
|
|
928
921
|
|
|
929
|
-
const
|
|
930
|
-
Boolean(
|
|
922
|
+
const isSignificant = (elm: Node | null): boolean =>
|
|
923
|
+
Boolean(
|
|
924
|
+
elm &&
|
|
925
|
+
!Dom.isTag(elm, 'br') &&
|
|
926
|
+
!Dom.isEmptyTextNode(elm) &&
|
|
927
|
+
!Dom.isTemporary(elm) &&
|
|
928
|
+
!(
|
|
929
|
+
Dom.isElement(elm) &&
|
|
930
|
+
this.j.e.fire('isInvisibleForCursor', elm) === true
|
|
931
|
+
)
|
|
932
|
+
);
|
|
931
933
|
|
|
932
934
|
// check right offset
|
|
933
935
|
if (Dom.isText(container)) {
|
|
@@ -949,17 +951,32 @@ export class Select implements ISelect {
|
|
|
949
951
|
const children = toArray(container.childNodes);
|
|
950
952
|
|
|
951
953
|
if (end) {
|
|
952
|
-
if (children.slice(offset).some(
|
|
954
|
+
if (children.slice(offset).some(isSignificant)) {
|
|
953
955
|
return false;
|
|
954
956
|
}
|
|
955
957
|
} else {
|
|
956
|
-
if (children.slice(0, offset).some(
|
|
958
|
+
if (children.slice(0, offset).some(isSignificant)) {
|
|
957
959
|
return false;
|
|
958
960
|
}
|
|
959
961
|
}
|
|
960
962
|
}
|
|
961
963
|
|
|
962
|
-
|
|
964
|
+
let next: Nullable<Node> = current;
|
|
965
|
+
|
|
966
|
+
while (next && next !== parentBlock) {
|
|
967
|
+
const nextOne = Dom.sibling(next, start);
|
|
968
|
+
if (!nextOne) {
|
|
969
|
+
next = next.parentNode;
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
972
|
+
next = nextOne;
|
|
973
|
+
|
|
974
|
+
if (next && isSignificant(next)) {
|
|
975
|
+
return false;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
return true;
|
|
963
980
|
}
|
|
964
981
|
|
|
965
982
|
/**
|
|
@@ -1221,17 +1238,17 @@ export class Select implements ISelect {
|
|
|
1221
1238
|
if (
|
|
1222
1239
|
firstChild &&
|
|
1223
1240
|
firstChild === lastChild &&
|
|
1224
|
-
|
|
1241
|
+
isMarker(firstChild)
|
|
1225
1242
|
) {
|
|
1226
1243
|
Dom.unwrap(font);
|
|
1227
1244
|
continue;
|
|
1228
1245
|
}
|
|
1229
1246
|
|
|
1230
|
-
if (firstChild &&
|
|
1247
|
+
if (firstChild && isMarker(firstChild)) {
|
|
1231
1248
|
Dom.before(font, firstChild);
|
|
1232
1249
|
}
|
|
1233
1250
|
|
|
1234
|
-
if (lastChild &&
|
|
1251
|
+
if (lastChild && isMarker(lastChild)) {
|
|
1235
1252
|
Dom.after(font, lastChild);
|
|
1236
1253
|
}
|
|
1237
1254
|
|
|
@@ -1253,7 +1270,7 @@ export class Select implements ISelect {
|
|
|
1253
1270
|
if (
|
|
1254
1271
|
font.firstChild &&
|
|
1255
1272
|
font.firstChild === font.lastChild &&
|
|
1256
|
-
|
|
1273
|
+
isMarker(font.firstChild)
|
|
1257
1274
|
) {
|
|
1258
1275
|
continue;
|
|
1259
1276
|
}
|
|
@@ -1281,6 +1298,30 @@ export class Select implements ISelect {
|
|
|
1281
1298
|
return result;
|
|
1282
1299
|
}
|
|
1283
1300
|
|
|
1301
|
+
/**
|
|
1302
|
+
* Apply some css rules for all selections. It method wraps selections in nodeName tag.
|
|
1303
|
+
* @example
|
|
1304
|
+
* ```js
|
|
1305
|
+
* const editor = Jodit.make('#editor');
|
|
1306
|
+
* editor.value = 'test';
|
|
1307
|
+
* editor.execCommand('selectall');
|
|
1308
|
+
*
|
|
1309
|
+
* editor.s.commitStyle({
|
|
1310
|
+
* style: {color: 'red'}
|
|
1311
|
+
* }) // will wrap `text` in `span` and add style `color:red`
|
|
1312
|
+
* editor.s.commitStyle({
|
|
1313
|
+
* style: {color: 'red'}
|
|
1314
|
+
* }) // will remove `color:red` from `span`
|
|
1315
|
+
* ```
|
|
1316
|
+
*/
|
|
1317
|
+
commitStyle(options: IStyleOptions): void {
|
|
1318
|
+
assert(size(options) > 0, 'Need to pass at least one option');
|
|
1319
|
+
|
|
1320
|
+
const styleElm = new CommitStyle(options);
|
|
1321
|
+
|
|
1322
|
+
styleElm.apply(this.j);
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1284
1325
|
/**
|
|
1285
1326
|
* Apply some css rules for all selections. It method wraps selections in nodeName tag.
|
|
1286
1327
|
* @example
|
|
@@ -1292,6 +1333,7 @@ export class Select implements ISelect {
|
|
|
1292
1333
|
* editor.s.applyStyle({color: 'red'}) // will wrap `text` in `span` and add style `color:red`
|
|
1293
1334
|
* editor.s.applyStyle({color: 'red'}) // will remove `color:red` from `span`
|
|
1294
1335
|
* ```
|
|
1336
|
+
* @deprecated
|
|
1295
1337
|
*/
|
|
1296
1338
|
applyStyle(
|
|
1297
1339
|
style: CanUndef<IStyle>,
|
|
@@ -1300,21 +1342,19 @@ export class Select implements ISelect {
|
|
|
1300
1342
|
* equal CSSRule (e.g. strong === font-weight: 700)
|
|
1301
1343
|
*/
|
|
1302
1344
|
element?: HTMLTagNames;
|
|
1345
|
+
/** @deprecated Instead use attributes.class*/
|
|
1303
1346
|
className?: string;
|
|
1347
|
+
attributes?: IDictionary<string | number>;
|
|
1304
1348
|
/**
|
|
1305
1349
|
* tag for wrapping and apply styles
|
|
1306
1350
|
*/
|
|
1307
1351
|
defaultTag?: HTMLTagNames;
|
|
1308
1352
|
} = {}
|
|
1309
1353
|
): void {
|
|
1310
|
-
|
|
1354
|
+
this.commitStyle({
|
|
1311
1355
|
style,
|
|
1312
|
-
|
|
1313
|
-
className: options.className,
|
|
1314
|
-
defaultTag: options.defaultTag
|
|
1356
|
+
...options
|
|
1315
1357
|
});
|
|
1316
|
-
|
|
1317
|
-
styleElm.apply(this.j);
|
|
1318
1358
|
}
|
|
1319
1359
|
|
|
1320
1360
|
/**
|
|
@@ -109,15 +109,8 @@ describe('Selection Module Tests', function () {
|
|
|
109
109
|
describe('Cursor in the end of text node', function () {
|
|
110
110
|
it('Should work correct', function () {
|
|
111
111
|
const editor = getJodit();
|
|
112
|
-
editor.value = '<ul><li><p>test
|
|
113
|
-
|
|
114
|
-
const range = editor.s.createRange();
|
|
115
|
-
|
|
116
|
-
range.setStartAfter(
|
|
117
|
-
editor.editor.querySelector('p').firstChild
|
|
118
|
-
);
|
|
119
|
-
range.collapse(true);
|
|
120
|
-
editor.s.selectRange(range);
|
|
112
|
+
editor.value = '<ul><li><p>test|</p></li></ul>';
|
|
113
|
+
setCursorToChar(editor);
|
|
121
114
|
|
|
122
115
|
['li', 'p'].forEach(function (tag) {
|
|
123
116
|
expect(
|
|
@@ -185,13 +178,8 @@ describe('Selection Module Tests', function () {
|
|
|
185
178
|
describe('Cursor in the end of text node but after this has image', function () {
|
|
186
179
|
it('Should return false', function () {
|
|
187
180
|
const editor = getJodit();
|
|
188
|
-
editor.value = '<p>test
|
|
189
|
-
|
|
190
|
-
const range = editor.s.createRange();
|
|
191
|
-
|
|
192
|
-
range.setStart(editor.editor.firstChild.firstChild, 4);
|
|
193
|
-
range.collapse(true);
|
|
194
|
-
editor.s.selectRange(range);
|
|
181
|
+
editor.value = '<p>test|<img/></p>';
|
|
182
|
+
setCursorToChar(editor);
|
|
195
183
|
|
|
196
184
|
expect(editor.s.cursorOnTheRight(editor.editor.firstChild))
|
|
197
185
|
.is.false;
|
|
@@ -538,7 +526,7 @@ describe('Selection Module Tests', function () {
|
|
|
538
526
|
});
|
|
539
527
|
});
|
|
540
528
|
|
|
541
|
-
describe('
|
|
529
|
+
describe('Cursor in the end of span inside P and check cursorInTheEdge(true)', function () {
|
|
542
530
|
it('Should return false', function () {
|
|
543
531
|
const editor = getJodit();
|
|
544
532
|
editor.value = '<p>Some <span>|text|</span></p>';
|
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { IJodit } from 'jodit/types';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { Dom } from 'jodit/core/dom';
|
|
8
|
+
import { call } from 'jodit/core/helpers/utils/utils';
|
|
9
|
+
import { trim } from 'jodit/core/helpers/string/trim';
|
|
10
|
+
import { Dom } from 'jodit/core/dom/dom';
|
|
11
|
+
import { isMarker } from 'jodit/core/helpers/checker/is-marker';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* If the selection area is inside an element that matches the commit (suitable relative),
|
|
@@ -33,7 +34,7 @@ export function extractSelectedPart(
|
|
|
33
34
|
const range = jodit.s.createRange();
|
|
34
35
|
|
|
35
36
|
// Left part
|
|
36
|
-
const leftEdge =
|
|
37
|
+
const leftEdge = isMarker(font.previousSibling)
|
|
37
38
|
? font.previousSibling
|
|
38
39
|
: font;
|
|
39
40
|
|
|
@@ -43,9 +44,7 @@ export function extractSelectedPart(
|
|
|
43
44
|
extractAndMove(wrapper, range, true);
|
|
44
45
|
|
|
45
46
|
// Right part
|
|
46
|
-
const rightEdge =
|
|
47
|
-
? font.nextSibling
|
|
48
|
-
: font;
|
|
47
|
+
const rightEdge = isMarker(font.nextSibling) ? font.nextSibling : font;
|
|
49
48
|
|
|
50
49
|
range.setStartAfter(rightEdge);
|
|
51
50
|
range.setEndAfter(wrapper);
|
|
@@ -4,28 +4,32 @@
|
|
|
4
4
|
* Copyright (c) 2013-2022 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type {
|
|
7
|
+
import type { IDictionary } from 'jodit/types';
|
|
8
|
+
import { isString } from 'jodit/core/helpers/checker/is-string';
|
|
9
|
+
import { assert } from 'jodit/src/core/helpers/utils/assert';
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* A state machine implementation for applying styles.
|
|
11
13
|
*/
|
|
12
|
-
export class FiniteStateMachine
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
export class FiniteStateMachine<
|
|
15
|
+
K extends string,
|
|
16
|
+
V extends object & { next: K },
|
|
17
|
+
T extends IDictionary<IDictionary<(value: V) => V>, K> = IDictionary<
|
|
18
|
+
IDictionary<(...attrs: any[]) => any>,
|
|
19
|
+
K
|
|
20
|
+
>,
|
|
21
|
+
A extends keyof T[K] = keyof T[K]
|
|
22
|
+
> {
|
|
23
|
+
private __state!: K;
|
|
24
|
+
private setState(state: K): void {
|
|
25
|
+
assert(!this.__previewsStates.has(state), 'Circled states');
|
|
15
26
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
27
|
+
this.__previewsStates.add(state);
|
|
28
|
+
this.__state = state;
|
|
19
29
|
}
|
|
20
30
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
getState(): string {
|
|
24
|
-
return this.state;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
getSubState(): string {
|
|
28
|
-
return this.subState;
|
|
31
|
+
getState(): K {
|
|
32
|
+
return this.__state;
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
private silent: boolean = true;
|
|
@@ -33,34 +37,35 @@ export class FiniteStateMachine {
|
|
|
33
37
|
this.silent = false;
|
|
34
38
|
}
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
>
|
|
41
|
-
) {}
|
|
40
|
+
private __previewsStates: Set<K> = new Set();
|
|
41
|
+
constructor(state: K, private readonly transitions: T) {
|
|
42
|
+
this.setState(state);
|
|
43
|
+
}
|
|
42
44
|
|
|
43
|
-
dispatch
|
|
44
|
-
const action = this.transitions[this.
|
|
45
|
+
dispatch(actionName: A, value: V): V {
|
|
46
|
+
const action = this.transitions[this.getState()][actionName];
|
|
45
47
|
|
|
46
48
|
if (action) {
|
|
47
|
-
|
|
48
|
-
console.log('State: ' + this.state, 'Action: ' + actionName);
|
|
49
|
-
}
|
|
49
|
+
const res = action.call(this, value);
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
assert(res && res !== value, 'Action should return new value');
|
|
52
|
+
assert(isString(res.next), 'Value should contains next state');
|
|
53
|
+
assert(
|
|
54
|
+
res.next !== this.getState(),
|
|
55
|
+
'The new state should not be equal to the old one.'
|
|
56
|
+
);
|
|
52
57
|
|
|
53
|
-
|
|
54
|
-
console.log('State: ' + this.state);
|
|
55
|
-
}
|
|
58
|
+
this.setState(res.next);
|
|
56
59
|
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
if (!isProd && !this.silent) {
|
|
61
|
+
console.log(`State: ${this.getState()}`);
|
|
62
|
+
}
|
|
59
63
|
|
|
60
|
-
|
|
61
|
-
throw new Error('invalid action: ' + this.state + '.' + actionName);
|
|
64
|
+
return res;
|
|
62
65
|
}
|
|
63
66
|
|
|
64
|
-
|
|
67
|
+
throw new Error(
|
|
68
|
+
`invalid action: ${this.getState()}.${actionName.toString()}`
|
|
69
|
+
);
|
|
65
70
|
}
|
|
66
71
|
}
|
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
* Copyright (c) 2013-2022 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type { Nullable } from 'jodit/types';
|
|
8
|
-
import
|
|
9
|
-
import { Dom } from 'jodit/core/dom';
|
|
7
|
+
import type { Nullable, ICommitStyle } from 'jodit/types';
|
|
8
|
+
import { Dom } from 'jodit/core/dom/dom';
|
|
10
9
|
import { isNormalNode } from './is-normal-node';
|
|
11
10
|
import { isSuitElement } from './is-suit-element';
|
|
12
11
|
|
|
@@ -19,7 +18,7 @@ import { isSuitElement } from './is-suit-element';
|
|
|
19
18
|
* @private
|
|
20
19
|
*/
|
|
21
20
|
export function getSuitChild(
|
|
22
|
-
style:
|
|
21
|
+
style: ICommitStyle,
|
|
23
22
|
font: HTMLElement
|
|
24
23
|
): Nullable<HTMLElement> {
|
|
25
24
|
let { firstChild: child } = font;
|
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
* Copyright (c) 2013-2022 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type { Nullable } from 'jodit/types';
|
|
8
|
-
import
|
|
9
|
-
import { Dom } from 'jodit/core/dom';
|
|
7
|
+
import type { Nullable, ICommitStyle } from 'jodit/types';
|
|
8
|
+
import { Dom } from 'jodit/core/dom/dom';
|
|
10
9
|
import { isNormalNode } from './is-normal-node';
|
|
11
10
|
import { isSuitElement } from './is-suit-element';
|
|
12
11
|
|
|
@@ -19,7 +18,7 @@ import { isSuitElement } from './is-suit-element';
|
|
|
19
18
|
* @private
|
|
20
19
|
*/
|
|
21
20
|
export function getSuitParent(
|
|
22
|
-
style:
|
|
21
|
+
style: ICommitStyle,
|
|
23
22
|
node: Node,
|
|
24
23
|
root: Node
|
|
25
24
|
): Nullable<HTMLElement> {
|
|
@@ -8,19 +8,27 @@ import type { IStyle } from 'jodit/types';
|
|
|
8
8
|
import { css } from 'jodit/core/helpers/utils/css';
|
|
9
9
|
import { isVoid } from 'jodit/core/helpers/checker/is-void';
|
|
10
10
|
import { normalizeCssValue } from 'jodit/core/helpers/normalize/normalize-css-value';
|
|
11
|
-
import { Dom } from 'jodit/core/dom';
|
|
11
|
+
import { Dom } from 'jodit/core/dom/dom';
|
|
12
|
+
import { assert } from 'jodit/core/helpers/utils/assert';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Element has the same styles as in the commit
|
|
15
16
|
* @private
|
|
16
17
|
*/
|
|
17
|
-
export function
|
|
18
|
+
export function hasSameStyle(elm: Node, rules: IStyle): boolean {
|
|
18
19
|
return Boolean(
|
|
19
20
|
!Dom.isTag(elm, 'font') &&
|
|
20
21
|
Dom.isHTMLElement(elm) &&
|
|
21
22
|
Object.keys(rules).every(property => {
|
|
22
23
|
const value = css(elm, property, true);
|
|
23
24
|
|
|
25
|
+
if (
|
|
26
|
+
value === '' &&
|
|
27
|
+
(rules[property] === '' || rules[property] == null)
|
|
28
|
+
) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
|
|
24
32
|
return (
|
|
25
33
|
!isVoid(value) &&
|
|
26
34
|
value !== '' &&
|
|
@@ -33,15 +41,26 @@ export function elementHasSameStyle(elm: Node, rules: IStyle): boolean {
|
|
|
33
41
|
);
|
|
34
42
|
}
|
|
35
43
|
|
|
44
|
+
const elm = document.createElement('div');
|
|
45
|
+
elm.style.color = 'red';
|
|
46
|
+
assert(hasSameStyle(elm, { color: 'red' }), 'Style test');
|
|
47
|
+
assert(hasSameStyle(elm, { fontSize: null }), 'Style test');
|
|
48
|
+
assert(hasSameStyle(elm, { fontSize: '' }), 'Style test');
|
|
49
|
+
|
|
36
50
|
/**
|
|
37
51
|
* Element has the similar styles
|
|
38
52
|
*/
|
|
39
|
-
export function
|
|
53
|
+
export function hasSameStyleKeys(elm: Node, rules: IStyle): boolean {
|
|
40
54
|
return Boolean(
|
|
41
55
|
!Dom.isTag(elm, 'font') &&
|
|
42
56
|
Dom.isHTMLElement(elm) &&
|
|
43
|
-
Object.keys(rules).every(
|
|
44
|
-
|
|
45
|
-
|
|
57
|
+
Object.keys(rules).every(property => {
|
|
58
|
+
const value = css(elm, property, true);
|
|
59
|
+
|
|
60
|
+
return !isVoid(value);
|
|
61
|
+
})
|
|
46
62
|
);
|
|
47
63
|
}
|
|
64
|
+
|
|
65
|
+
assert(hasSameStyleKeys(elm, { color: 'red' }), 'Style test');
|
|
66
|
+
assert(hasSameStyleKeys(elm, { font: 'Arial', color: 'red' }), 'Style test');
|
|
@@ -4,18 +4,18 @@
|
|
|
4
4
|
* Copyright (c) 2013-2022 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
export * from './toggle
|
|
8
|
-
export * from './
|
|
9
|
-
export * from './
|
|
7
|
+
export * from './toggle-attributes';
|
|
8
|
+
export * from './list/toggle-ordered-list';
|
|
9
|
+
export * from './list/wrap-list';
|
|
10
|
+
export * from './has-same-style';
|
|
10
11
|
export * from './extract';
|
|
11
12
|
export * from './finite-state-machine';
|
|
12
13
|
export * from './get-suit-child';
|
|
13
14
|
export * from './get-suit-parent';
|
|
14
15
|
export * from './is-inside-invisible-element';
|
|
16
|
+
export * from './is-same-attributes';
|
|
15
17
|
export * from './is-normal-node';
|
|
16
18
|
export * from './is-suit-element';
|
|
17
|
-
export * from './toggle-commit-styles';
|
|
18
19
|
export * from './unwrap-children';
|
|
19
|
-
export * from './wrap
|
|
20
|
-
export * from './wrap-ordered-list';
|
|
20
|
+
export * from './wrap';
|
|
21
21
|
export * from './wrap-unwrapped-text';
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { Nullable } from 'jodit/types';
|
|
8
|
-
import { Dom } from 'jodit/core/dom';
|
|
9
|
-
import {
|
|
8
|
+
import { Dom } from 'jodit/core/dom/dom';
|
|
9
|
+
import { isMarker } from 'jodit/core/helpers/checker/is-marker';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Is normal usual element
|
|
@@ -17,6 +17,6 @@ export function isNormalNode(elm: Nullable<Node>): boolean {
|
|
|
17
17
|
elm &&
|
|
18
18
|
!Dom.isEmptyTextNode(elm) &&
|
|
19
19
|
!Dom.isTemporary(elm) &&
|
|
20
|
-
!
|
|
20
|
+
!isMarker(elm)
|
|
21
21
|
);
|
|
22
22
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
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-2022 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { IDictionary, IStyle } from 'jodit/types';
|
|
8
|
+
import { attr } from 'jodit/core/helpers/utils';
|
|
9
|
+
import { size } from 'jodit/core/helpers/size/object-size';
|
|
10
|
+
import { assert } from 'jodit/core/helpers/utils/assert';
|
|
11
|
+
import { hasSameStyle } from './has-same-style';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Compares whether the given attributes match the element's own attributes
|
|
15
|
+
* @private
|
|
16
|
+
*/
|
|
17
|
+
export function isSameAttributes(
|
|
18
|
+
elm: HTMLElement,
|
|
19
|
+
attrs?: IDictionary
|
|
20
|
+
): elm is HTMLElement {
|
|
21
|
+
if (!elm.attributes.length && !size(attrs)) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!size(attrs)) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
assert(attrs, 'Attrs must be a non-empty object');
|
|
30
|
+
|
|
31
|
+
return Object.keys(attrs).every(key => {
|
|
32
|
+
if (key === 'class') {
|
|
33
|
+
return elm.classList.contains(attrs[key]);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (key === 'style') {
|
|
37
|
+
return hasSameStyle(elm, attrs[key] as IStyle);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return attr(elm, key) === attrs[key];
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function elementsEqualAttributes(
|
|
45
|
+
elm1: HTMLElement,
|
|
46
|
+
elm2: HTMLElement
|
|
47
|
+
): boolean {
|
|
48
|
+
return (
|
|
49
|
+
elm1.attributes.length === elm2.attributes.length &&
|
|
50
|
+
Array.from(elm1.attributes).every(
|
|
51
|
+
attr =>
|
|
52
|
+
elm2.hasAttribute(attr.name) &&
|
|
53
|
+
elm2.getAttribute(attr.name) === attr.value
|
|
54
|
+
)
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -3,14 +3,10 @@
|
|
|
3
3
|
* Released under MIT see LICENSE.txt in the project root for license information.
|
|
4
4
|
* Copyright (c) 2013-2022 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
5
|
*/
|
|
6
|
-
import type { Nullable } from 'jodit/types';
|
|
7
|
-
import
|
|
6
|
+
import type { IStyle, Nullable, ICommitStyle } from 'jodit/types';
|
|
7
|
+
import { Dom } from 'jodit/core/dom/dom';
|
|
8
8
|
import { isNormalNode } from './is-normal-node';
|
|
9
|
-
import {
|
|
10
|
-
elementHasSameStyle,
|
|
11
|
-
elementHasSameStyleKeys
|
|
12
|
-
} from './element-has-same-style';
|
|
13
|
-
import { Dom } from 'jodit/core/dom';
|
|
9
|
+
import { hasSameStyle, hasSameStyleKeys } from './has-same-style';
|
|
14
10
|
|
|
15
11
|
/**
|
|
16
12
|
* Checks if an item is suitable for applying a commit. The element suits us if it
|
|
@@ -23,7 +19,7 @@ import { Dom } from 'jodit/core/dom';
|
|
|
23
19
|
* @private
|
|
24
20
|
*/
|
|
25
21
|
export function isSuitElement(
|
|
26
|
-
commitStyle:
|
|
22
|
+
commitStyle: ICommitStyle,
|
|
27
23
|
elm: Nullable<Node>,
|
|
28
24
|
strict: boolean
|
|
29
25
|
): elm is HTMLElement {
|
|
@@ -34,7 +30,8 @@ export function isSuitElement(
|
|
|
34
30
|
const { element, elementIsDefault, options } = commitStyle;
|
|
35
31
|
|
|
36
32
|
const elmHasSameStyle = Boolean(
|
|
37
|
-
options.style &&
|
|
33
|
+
options.attributes?.style &&
|
|
34
|
+
hasSameStyle(elm, options.attributes.style as IStyle)
|
|
38
35
|
);
|
|
39
36
|
|
|
40
37
|
const elmIsSame =
|
|
@@ -43,7 +40,7 @@ export function isSuitElement(
|
|
|
43
40
|
|
|
44
41
|
if (
|
|
45
42
|
((!elementIsDefault || !strict) && elmIsSame) ||
|
|
46
|
-
(elmHasSameStyle && isNormalNode(elm))
|
|
43
|
+
(elmHasSameStyle && isNormalNode(elm) && !commitStyle.elementIsList)
|
|
47
44
|
) {
|
|
48
45
|
return true;
|
|
49
46
|
}
|
|
@@ -53,6 +50,18 @@ export function isSuitElement(
|
|
|
53
50
|
);
|
|
54
51
|
}
|
|
55
52
|
|
|
53
|
+
export function findSuitClosest(
|
|
54
|
+
commitStyle: ICommitStyle,
|
|
55
|
+
element: HTMLElement,
|
|
56
|
+
root: HTMLElement
|
|
57
|
+
): Nullable<HTMLElement> {
|
|
58
|
+
return Dom.closest(
|
|
59
|
+
element,
|
|
60
|
+
node => isSuitElement(commitStyle, node, true),
|
|
61
|
+
root
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
56
65
|
/**
|
|
57
66
|
* Inside the parent element there is a block with the same styles
|
|
58
67
|
* @example
|
|
@@ -63,7 +72,7 @@ export function isSuitElement(
|
|
|
63
72
|
* Apply `{element:'strong'}`
|
|
64
73
|
*/
|
|
65
74
|
export function isSameStyleChild(
|
|
66
|
-
commitStyle:
|
|
75
|
+
commitStyle: ICommitStyle,
|
|
67
76
|
elm: Nullable<Node>
|
|
68
77
|
): elm is HTMLElement {
|
|
69
78
|
const { element, options } = commitStyle;
|
|
@@ -75,7 +84,8 @@ export function isSameStyleChild(
|
|
|
75
84
|
const elmIsSame = elm.nodeName.toLowerCase() === element;
|
|
76
85
|
|
|
77
86
|
const elmHasSameStyle = Boolean(
|
|
78
|
-
options.style &&
|
|
87
|
+
options.attributes?.style &&
|
|
88
|
+
hasSameStyleKeys(elm, options.attributes?.style as IStyle)
|
|
79
89
|
);
|
|
80
90
|
|
|
81
91
|
return elmIsSame && elmHasSameStyle;
|