jodit 4.12.23 → 4.12.24
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 +15 -0
- package/es2015/jodit.css +1 -1
- package/es2015/jodit.fat.min.js +8 -8
- package/es2015/jodit.js +144 -19
- package/es2015/jodit.min.js +7 -7
- 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.js +8 -8
- package/es2018/jodit.min.js +7 -7
- package/es2018/plugins/debug/debug.min.js +1 -1
- package/es2018/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es2021/jodit.css +1 -1
- package/es2021/jodit.fat.min.js +8 -8
- package/es2021/jodit.js +143 -19
- package/es2021/jodit.min.js +7 -7
- 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 +1 -1
- package/es2021.en/jodit.fat.min.js +7 -7
- package/es2021.en/jodit.js +143 -19
- package/es2021.en/jodit.min.js +8 -8
- 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 +2 -2
- package/es5/jodit.fat.min.js +2 -2
- package/es5/jodit.js +190 -51
- package/es5/jodit.min.css +2 -2
- 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 +30 -0
- package/esm/core/constants.js +1 -1
- package/esm/modules/image-editor/image-editor.js +5 -0
- package/esm/modules/uploader/helpers/send-files.js +9 -0
- package/esm/plugins/backspace/backspace.js +7 -3
- package/esm/plugins/backspace/cases/index.d.ts +19 -3
- package/esm/plugins/backspace/cases/index.js +18 -13
- package/esm/plugins/backspace/config.d.ts +15 -0
- package/esm/plugins/clean-html/clean-html.d.ts +8 -0
- package/esm/plugins/clean-html/clean-html.js +16 -0
- package/esm/plugins/clean-html/config.d.ts +9 -0
- package/esm/plugins/clean-html/config.js +1 -0
- package/esm/plugins/font/config.js +19 -0
- package/esm/plugins/link/config.d.ts +6 -0
- package/esm/plugins/link/config.js +1 -0
- package/esm/plugins/link/link.js +8 -1
- package/esm/plugins/link/template.js +10 -1
- package/esm/plugins/select-cells/select-cells.d.ts +1 -1
- package/esm/plugins/select-cells/select-cells.js +29 -2
- package/esm/types/uploader.d.ts +23 -0
- package/package.json +1 -1
- package/types/config.d.ts +30 -0
- package/types/plugins/backspace/cases/index.d.ts +19 -3
- package/types/plugins/backspace/config.d.ts +15 -0
- package/types/plugins/clean-html/clean-html.d.ts +8 -0
- package/types/plugins/clean-html/config.d.ts +9 -0
- package/types/plugins/link/config.d.ts +6 -0
- package/types/plugins/select-cells/select-cells.d.ts +1 -1
- package/types/types/uploader.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
|
@@ -956,6 +956,21 @@ interface Config {
|
|
|
956
956
|
backspaceWord: string[];
|
|
957
957
|
backspaceSentence: string[];
|
|
958
958
|
};
|
|
959
|
+
/**
|
|
960
|
+
* Disable specific Backspace/Delete cleanup cases by their stable
|
|
961
|
+
* key, so the plugin no longer applies that particular behavior.
|
|
962
|
+
* Available keys: `remove-unbreakable`, `remove-not-editable`,
|
|
963
|
+
* `remove-char`, `table-cell`, `remove-empty-parent`,
|
|
964
|
+
* `remove-empty-neighbor`, `join-two-lists`, `join-neighbors`,
|
|
965
|
+
* `unwrap-first-list-item`.
|
|
966
|
+
*
|
|
967
|
+
* ```javascript
|
|
968
|
+
* Jodit.make('#editor', {
|
|
969
|
+
* delete: { disableCases: new Set(['remove-empty-parent']) }
|
|
970
|
+
* });
|
|
971
|
+
* ```
|
|
972
|
+
*/
|
|
973
|
+
disableCases?: Set<string>;
|
|
959
974
|
};
|
|
960
975
|
}
|
|
961
976
|
interface Config {
|
|
@@ -973,6 +988,15 @@ interface Config {
|
|
|
973
988
|
* Remove empty elements
|
|
974
989
|
*/
|
|
975
990
|
removeEmptyElements: boolean;
|
|
991
|
+
/**
|
|
992
|
+
* Return an empty string from `editor.value` (and the synced source
|
|
993
|
+
* element) when the editor holds only a single empty block — e.g.
|
|
994
|
+
* `<p><br></p>` left after the user deletes all the content.
|
|
995
|
+
* `contenteditable` keeps that caret container in the DOM, so by
|
|
996
|
+
* default the value getter returns it as-is; enable this to collapse
|
|
997
|
+
* it to `''` for form submission.
|
|
998
|
+
*/
|
|
999
|
+
collapseEmptyValueToEmptyString: boolean;
|
|
976
1000
|
/**
|
|
977
1001
|
* Replace old tags to new eg. <i> to <em>, <b> to <strong>
|
|
978
1002
|
*/
|
|
@@ -1371,6 +1395,12 @@ interface Config {
|
|
|
1371
1395
|
* Default value for the `Open in new tab` checkbox when inserting a new link.
|
|
1372
1396
|
*/
|
|
1373
1397
|
openInNewTabCheckboxDefaultChecked: boolean;
|
|
1398
|
+
/**
|
|
1399
|
+
* Show an `aria-label` text input in the link dialog so an
|
|
1400
|
+
* accessible name can be set on the `<a>` (useful when several
|
|
1401
|
+
* links share the same visible text, e.g. "here"). Default: false.
|
|
1402
|
+
*/
|
|
1403
|
+
ariaLabelInput: boolean;
|
|
1374
1404
|
/**
|
|
1375
1405
|
* Use an input text to ask the classname or a select or not ask
|
|
1376
1406
|
*/
|
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.12.
|
|
6
|
+
export const APP_VERSION = "4.12.24";
|
|
7
7
|
// prettier-ignore
|
|
8
8
|
export const ES = "es2020";
|
|
9
9
|
export const IS_ES_MODERN = true;
|
|
@@ -439,12 +439,17 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
|
|
|
439
439
|
self.j.alert('The name should not be empty');
|
|
440
440
|
return false;
|
|
441
441
|
}
|
|
442
|
+
self.j.e.fire('afterImageEditorSave', data, name);
|
|
442
443
|
self.onSave(name, data, self.hide, (e) => {
|
|
443
444
|
self.j.alert(e.message);
|
|
444
445
|
});
|
|
445
446
|
});
|
|
446
447
|
break;
|
|
447
448
|
case self.buttons.save:
|
|
449
|
+
// Notify listeners that a crop/resize was applied,
|
|
450
|
+
// passing the action box (action + box dimensions).
|
|
451
|
+
// See https://github.com/xdan/jodit/issues/820
|
|
452
|
+
self.j.e.fire('afterImageEditorSave', data);
|
|
448
453
|
self.onSave(undefined, data, self.hide, (e) => {
|
|
449
454
|
self.j.alert(e.message);
|
|
450
455
|
});
|
|
@@ -17,6 +17,15 @@ export function sendFiles(uploader, files, handlerSuccess, handlerError, process
|
|
|
17
17
|
if (!fileList.length) {
|
|
18
18
|
return Promise.reject(error('Need files'));
|
|
19
19
|
}
|
|
20
|
+
// Client-side validation hook — returning `false` aborts the upload.
|
|
21
|
+
// See https://github.com/xdan/jodit/issues/1329
|
|
22
|
+
if (isFunction(o.beforeUpload)) {
|
|
23
|
+
if (o.beforeUpload.call(uploader, fileList) === false) {
|
|
24
|
+
const err = error('Upload canceled');
|
|
25
|
+
(handlerError || o.defaultHandlerError).call(uploader, err);
|
|
26
|
+
return Promise.reject(err);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
20
29
|
const promises = [];
|
|
21
30
|
if (o.insertImageAsBase64URI) {
|
|
22
31
|
readImagesWithReader(fileList, o.imagesExtensions, promises, uploader, handlerSuccess, o.defaultHandlerSuccess);
|
|
@@ -11,7 +11,7 @@ import { Plugin } from "../../core/plugin/index.js";
|
|
|
11
11
|
import { moveNodeInsideStart } from "../../core/selection/helpers/index.js";
|
|
12
12
|
import "./config.js";
|
|
13
13
|
import { checkNotCollapsed } from "./cases/check-not-collapsed.js";
|
|
14
|
-
import {
|
|
14
|
+
import { casesMap } from "./cases/index.js";
|
|
15
15
|
export class backspace extends Plugin {
|
|
16
16
|
afterInit(jodit) {
|
|
17
17
|
jodit
|
|
@@ -71,11 +71,15 @@ export class backspace extends Plugin {
|
|
|
71
71
|
return false;
|
|
72
72
|
}
|
|
73
73
|
moveNodeInsideStart(jodit, fakeNode, backspace);
|
|
74
|
-
|
|
74
|
+
const disabled = jodit.o.delete.disableCases;
|
|
75
|
+
if (casesMap.some(([key, func]) => {
|
|
76
|
+
if (disabled && disabled.has(key)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
75
79
|
if (isFunction(func) &&
|
|
76
80
|
func(jodit, fakeNode, backspace, mode)) {
|
|
77
81
|
if (!IS_PROD) {
|
|
78
|
-
console.info('Remove case:',
|
|
82
|
+
console.info('Remove case:', key);
|
|
79
83
|
}
|
|
80
84
|
return true;
|
|
81
85
|
}
|
|
@@ -3,9 +3,25 @@
|
|
|
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
|
-
|
|
7
|
-
|
|
6
|
+
/**
|
|
7
|
+
* @module plugins/backspace
|
|
8
|
+
*/
|
|
9
|
+
import type { IJodit } from "../../../types/index";
|
|
10
|
+
import type { DeleteMode } from "../interface";
|
|
11
|
+
type CaseFn = (jodit: IJodit, fakeNode: any, backspace: boolean, mode: DeleteMode) => void | boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Ordered delete/backspace cases with stable keys. The first one returning
|
|
14
|
+
* `true` wins. The keys are stable across minified builds (function names are
|
|
15
|
+
* mangled by terser) so they can be referenced by `delete.disableCases`.
|
|
16
|
+
* @private
|
|
17
|
+
*/
|
|
18
|
+
export declare const casesMap: ReadonlyArray<readonly [
|
|
19
|
+
string,
|
|
20
|
+
CaseFn
|
|
21
|
+
]>;
|
|
8
22
|
/**
|
|
9
23
|
* @private
|
|
24
|
+
* @deprecated Use `casesMap` to also get the stable case keys.
|
|
10
25
|
*/
|
|
11
|
-
export declare const cases:
|
|
26
|
+
export declare const cases: CaseFn[];
|
|
27
|
+
export {};
|
|
@@ -3,9 +3,6 @@
|
|
|
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
|
-
/**
|
|
7
|
-
* @module plugins/backspace
|
|
8
|
-
*/
|
|
9
6
|
import { checkJoinNeighbors } from "./check-join-neighbors.js";
|
|
10
7
|
import { checkJoinTwoLists } from "./check-join-two-lists.js";
|
|
11
8
|
import { checkRemoveChar } from "./check-remove-char.js";
|
|
@@ -16,16 +13,24 @@ import { checkRemoveUnbreakableElement } from "./check-remove-unbreakable-elemen
|
|
|
16
13
|
import { checkTableCell } from "./check-table-cell.js";
|
|
17
14
|
import { checkUnwrapFirstListItem } from "./check-unwrap-first-list-item.js";
|
|
18
15
|
/**
|
|
16
|
+
* Ordered delete/backspace cases with stable keys. The first one returning
|
|
17
|
+
* `true` wins. The keys are stable across minified builds (function names are
|
|
18
|
+
* mangled by terser) so they can be referenced by `delete.disableCases`.
|
|
19
19
|
* @private
|
|
20
20
|
*/
|
|
21
|
-
export const
|
|
22
|
-
checkRemoveUnbreakableElement,
|
|
23
|
-
checkRemoveContentNotEditable,
|
|
24
|
-
checkRemoveChar,
|
|
25
|
-
checkTableCell,
|
|
26
|
-
checkRemoveEmptyParent,
|
|
27
|
-
checkRemoveEmptyNeighbor,
|
|
28
|
-
checkJoinTwoLists,
|
|
29
|
-
checkJoinNeighbors,
|
|
30
|
-
checkUnwrapFirstListItem
|
|
21
|
+
export const casesMap = [
|
|
22
|
+
['remove-unbreakable', checkRemoveUnbreakableElement],
|
|
23
|
+
['remove-not-editable', checkRemoveContentNotEditable],
|
|
24
|
+
['remove-char', checkRemoveChar],
|
|
25
|
+
['table-cell', checkTableCell],
|
|
26
|
+
['remove-empty-parent', checkRemoveEmptyParent],
|
|
27
|
+
['remove-empty-neighbor', checkRemoveEmptyNeighbor],
|
|
28
|
+
['join-two-lists', checkJoinTwoLists],
|
|
29
|
+
['join-neighbors', checkJoinNeighbors],
|
|
30
|
+
['unwrap-first-list-item', checkUnwrapFirstListItem]
|
|
31
31
|
];
|
|
32
|
+
/**
|
|
33
|
+
* @private
|
|
34
|
+
* @deprecated Use `casesMap` to also get the stable case keys.
|
|
35
|
+
*/
|
|
36
|
+
export const cases = casesMap.map(([, fn]) => fn);
|
|
@@ -17,6 +17,21 @@ declare module 'jodit/config' {
|
|
|
17
17
|
backspaceWord: string[];
|
|
18
18
|
backspaceSentence: string[];
|
|
19
19
|
};
|
|
20
|
+
/**
|
|
21
|
+
* Disable specific Backspace/Delete cleanup cases by their stable
|
|
22
|
+
* key, so the plugin no longer applies that particular behavior.
|
|
23
|
+
* Available keys: `remove-unbreakable`, `remove-not-editable`,
|
|
24
|
+
* `remove-char`, `table-cell`, `remove-empty-parent`,
|
|
25
|
+
* `remove-empty-neighbor`, `join-two-lists`, `join-neighbors`,
|
|
26
|
+
* `unwrap-first-list-item`.
|
|
27
|
+
*
|
|
28
|
+
* ```javascript
|
|
29
|
+
* Jodit.make('#editor', {
|
|
30
|
+
* delete: { disableCases: new Set(['remove-empty-parent']) }
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
disableCases?: Set<string>;
|
|
20
35
|
};
|
|
21
36
|
}
|
|
22
37
|
}
|
|
@@ -34,6 +34,14 @@ export declare class cleanHtml extends Plugin {
|
|
|
34
34
|
protected onBeforeSetNativeEditorValue(data: {
|
|
35
35
|
value: string;
|
|
36
36
|
}): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Collapse a value that holds only a single empty block (e.g.
|
|
39
|
+
* `<p><br></p>` left after deleting all content) to an empty string —
|
|
40
|
+
* opt-in via `cleanHTML.collapseEmptyValueToEmptyString`. See #1149
|
|
41
|
+
*/
|
|
42
|
+
protected onAfterGetValueFromEditor(data: {
|
|
43
|
+
value: string;
|
|
44
|
+
}): void;
|
|
37
45
|
protected onSafeHTML(sandBox: HTMLElement): void;
|
|
38
46
|
/** @override */
|
|
39
47
|
protected beforeDestruct(): void;
|
|
@@ -100,6 +100,19 @@ export class cleanHtml extends Plugin {
|
|
|
100
100
|
Dom.safeRemove(iframe);
|
|
101
101
|
return false;
|
|
102
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Collapse a value that holds only a single empty block (e.g.
|
|
105
|
+
* `<p><br></p>` left after deleting all content) to an empty string —
|
|
106
|
+
* opt-in via `cleanHTML.collapseEmptyValueToEmptyString`. See #1149
|
|
107
|
+
*/
|
|
108
|
+
onAfterGetValueFromEditor(data) {
|
|
109
|
+
if (!this.j.o.cleanHTML.collapseEmptyValueToEmptyString) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (/^<([a-z][a-z0-9]*)\b[^>]*>(?:<br\/?>)?<\/\1>$/i.test(data.value.trim())) {
|
|
113
|
+
data.value = '';
|
|
114
|
+
}
|
|
115
|
+
}
|
|
103
116
|
onSafeHTML(sandBox) {
|
|
104
117
|
const sanitizer = this.j.o.cleanHTML.sanitizer;
|
|
105
118
|
if (sanitizer) {
|
|
@@ -124,6 +137,9 @@ __decorate([
|
|
|
124
137
|
__decorate([
|
|
125
138
|
watch(':beforeSetNativeEditorValue')
|
|
126
139
|
], cleanHtml.prototype, "onBeforeSetNativeEditorValue", null);
|
|
140
|
+
__decorate([
|
|
141
|
+
watch(':afterGetValueFromEditor')
|
|
142
|
+
], cleanHtml.prototype, "onAfterGetValueFromEditor", null);
|
|
127
143
|
__decorate([
|
|
128
144
|
watch(':safeHTML')
|
|
129
145
|
], cleanHtml.prototype, "onSafeHTML", null);
|
|
@@ -23,6 +23,15 @@ declare module 'jodit/config' {
|
|
|
23
23
|
* Remove empty elements
|
|
24
24
|
*/
|
|
25
25
|
removeEmptyElements: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Return an empty string from `editor.value` (and the synced source
|
|
28
|
+
* element) when the editor holds only a single empty block — e.g.
|
|
29
|
+
* `<p><br></p>` left after the user deletes all the content.
|
|
30
|
+
* `contenteditable` keeps that caret container in the DOM, so by
|
|
31
|
+
* default the value getter returns it as-is; enable this to collapse
|
|
32
|
+
* it to `''` for form submission.
|
|
33
|
+
*/
|
|
34
|
+
collapseEmptyValueToEmptyString: boolean;
|
|
26
35
|
/**
|
|
27
36
|
* Replace old tags to new eg. <i> to <em>, <b> to <strong>
|
|
28
37
|
*/
|
|
@@ -117,5 +117,24 @@ Config.prototype.controls.font = {
|
|
|
117
117
|
.replace(/[^a-z0-9-]+/g, ',');
|
|
118
118
|
}
|
|
119
119
|
},
|
|
120
|
+
// When no font is explicitly set, the computed font-family equals the
|
|
121
|
+
// editor's own default (e.g. `-apple-system, …`). Return '' so the
|
|
122
|
+
// button shows the `Default` list entry instead of that raw stack.
|
|
123
|
+
// See #1370
|
|
124
|
+
value: (editor) => {
|
|
125
|
+
const current = editor.s.current();
|
|
126
|
+
if (!current) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const box = Dom.closest(current, Dom.isElement, editor.editor);
|
|
130
|
+
if (!box) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const value = css(box, 'font-family').toString();
|
|
134
|
+
if (value === css(editor.editor, 'font-family').toString()) {
|
|
135
|
+
return '';
|
|
136
|
+
}
|
|
137
|
+
return value;
|
|
138
|
+
},
|
|
120
139
|
tooltip: 'Font family'
|
|
121
140
|
};
|
|
@@ -39,6 +39,12 @@ declare module 'jodit/config' {
|
|
|
39
39
|
* Default value for the `Open in new tab` checkbox when inserting a new link.
|
|
40
40
|
*/
|
|
41
41
|
openInNewTabCheckboxDefaultChecked: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Show an `aria-label` text input in the link dialog so an
|
|
44
|
+
* accessible name can be set on the `<a>` (useful when several
|
|
45
|
+
* links share the same visible text, e.g. "here"). Default: false.
|
|
46
|
+
*/
|
|
47
|
+
ariaLabelInput: boolean;
|
|
42
48
|
/**
|
|
43
49
|
* Use an input text to ask the classname or a select or not ask
|
|
44
50
|
*/
|
package/esm/plugins/link/link.js
CHANGED
|
@@ -121,7 +121,7 @@ export class link extends Plugin {
|
|
|
121
121
|
const currentElement = current;
|
|
122
122
|
const isImageContent = Dom.isImage(currentElement);
|
|
123
123
|
let { content_input } = elements;
|
|
124
|
-
const { className_input } = elements, { className_select } = elements;
|
|
124
|
+
const { className_input } = elements, { className_select } = elements, { aria_label_input } = elements;
|
|
125
125
|
if (!content_input) {
|
|
126
126
|
content_input = jodit.c.element('input', {
|
|
127
127
|
type: 'hidden',
|
|
@@ -147,6 +147,9 @@ export class link extends Plugin {
|
|
|
147
147
|
if (!isImageContent && current) {
|
|
148
148
|
content_input.value = getSelectionText();
|
|
149
149
|
}
|
|
150
|
+
if (aria_label_input) {
|
|
151
|
+
aria_label_input.value = link ? attr(link, 'aria-label') || '' : '';
|
|
152
|
+
}
|
|
150
153
|
if (link) {
|
|
151
154
|
url_input.value = attr(link, 'href') || '';
|
|
152
155
|
if (modeClassName) {
|
|
@@ -237,6 +240,10 @@ export class link extends Plugin {
|
|
|
237
240
|
}
|
|
238
241
|
attr(a, 'rel', relParts.length ? relParts.join(' ') : null);
|
|
239
242
|
}
|
|
243
|
+
if (aria_label_input) {
|
|
244
|
+
const ariaLabel = aria_label_input.value.trim();
|
|
245
|
+
attr(a, 'aria-label', ariaLabel || null);
|
|
246
|
+
}
|
|
240
247
|
jodit.e.fire('applyLink', jodit, a, form);
|
|
241
248
|
});
|
|
242
249
|
jodit.synchronizeValues();
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { UIButton } from "../../core/ui/button/index.js";
|
|
7
7
|
import { UIBlock, UICheckbox, UIForm, UIInput, UISelect } from "../../core/ui/form/index.js";
|
|
8
8
|
export const formTemplate = (editor) => {
|
|
9
|
-
const { openInNewTabCheckbox, noFollowCheckbox, modeClassName, selectSizeClassName, selectMultipleClassName, selectOptionsClassName } = editor.o.link;
|
|
9
|
+
const { openInNewTabCheckbox, noFollowCheckbox, ariaLabelInput, modeClassName, selectSizeClassName, selectMultipleClassName, selectOptionsClassName } = editor.o.link;
|
|
10
10
|
return new UIForm(editor, [
|
|
11
11
|
new UIBlock(editor, [
|
|
12
12
|
new UIInput(editor, {
|
|
@@ -18,6 +18,15 @@ export const formTemplate = (editor) => {
|
|
|
18
18
|
required: true
|
|
19
19
|
})
|
|
20
20
|
]),
|
|
21
|
+
ariaLabelInput
|
|
22
|
+
? new UIBlock(editor, [
|
|
23
|
+
new UIInput(editor, {
|
|
24
|
+
name: 'ariaLabel',
|
|
25
|
+
ref: 'aria_label_input',
|
|
26
|
+
label: 'Aria label'
|
|
27
|
+
})
|
|
28
|
+
])
|
|
29
|
+
: null,
|
|
21
30
|
new UIBlock(editor, [
|
|
22
31
|
new UIInput(editor, {
|
|
23
32
|
name: 'content',
|
|
@@ -29,7 +29,7 @@ export declare class selectCells extends Plugin {
|
|
|
29
29
|
/**
|
|
30
30
|
* Mouse click inside the table
|
|
31
31
|
*/
|
|
32
|
-
protected onStartSelection(cell: HTMLTableCellElement): void | false;
|
|
32
|
+
protected onStartSelection(cell: HTMLTableCellElement, event?: MouseEvent): void | false;
|
|
33
33
|
protected onOutsideClick(): void;
|
|
34
34
|
protected onChange(): void;
|
|
35
35
|
/**
|
|
@@ -79,15 +79,42 @@ export class selectCells extends Plugin {
|
|
|
79
79
|
/**
|
|
80
80
|
* Mouse click inside the table
|
|
81
81
|
*/
|
|
82
|
-
onStartSelection(cell) {
|
|
82
|
+
onStartSelection(cell, event) {
|
|
83
|
+
var _a;
|
|
83
84
|
if (this.j.o.readonly) {
|
|
84
85
|
return;
|
|
85
86
|
}
|
|
87
|
+
const table = Dom.closest(cell, 'table', this.j.editor);
|
|
88
|
+
// Ctrl/Cmd + click toggles a single cell into the existing selection
|
|
89
|
+
// instead of resetting it — non-contiguous multi-cell selection.
|
|
90
|
+
// See https://github.com/xdan/jodit/issues/1163
|
|
91
|
+
if (((event === null || event === void 0 ? void 0 : event.ctrlKey) || (event === null || event === void 0 ? void 0 : event.metaKey)) &&
|
|
92
|
+
cell !== this.j.editor &&
|
|
93
|
+
table &&
|
|
94
|
+
Dom.isCell(cell)) {
|
|
95
|
+
if (this.__tableModule.getAllSelectedCells().includes(cell)) {
|
|
96
|
+
this.__tableModule.removeSelection(cell);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
if (!cell.firstChild) {
|
|
100
|
+
cell.appendChild(this.j.createInside.element('br'));
|
|
101
|
+
}
|
|
102
|
+
this.__tableModule.addSelection(cell);
|
|
103
|
+
}
|
|
104
|
+
this.__selectedCell = cell;
|
|
105
|
+
(_a = this.j.s.sel) === null || _a === void 0 ? void 0 : _a.removeAllRanges();
|
|
106
|
+
if (this.__tableModule.getAllSelectedCells().length) {
|
|
107
|
+
this.j.e.fire('showPopup', table, () => position(cell, this.j), 'cells');
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
this.j.e.fire('hidePopup', 'cells');
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
86
114
|
this.unselectCells();
|
|
87
115
|
if (cell === this.j.editor) {
|
|
88
116
|
return;
|
|
89
117
|
}
|
|
90
|
-
const table = Dom.closest(cell, 'table', this.j.editor);
|
|
91
118
|
if (!cell || !table) {
|
|
92
119
|
return;
|
|
93
120
|
}
|
package/esm/types/uploader.d.ts
CHANGED
|
@@ -80,6 +80,29 @@ export interface IUploaderOptions<T> {
|
|
|
80
80
|
getDisplayName(this: T, baseurl: string, filename: string): string;
|
|
81
81
|
pathVariableName: string;
|
|
82
82
|
withCredentials: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Called with the list of files right before they are uploaded (or read as
|
|
85
|
+
* base64). Return `false` to abort the whole upload — useful for client
|
|
86
|
+
* side validation (size, type, count). Throwing an Error also aborts and
|
|
87
|
+
* routes the message through the uploader error handler.
|
|
88
|
+
*
|
|
89
|
+
* ```javascript
|
|
90
|
+
* Jodit.make('#editor', {
|
|
91
|
+
* uploader: {
|
|
92
|
+
* url: '...',
|
|
93
|
+
* beforeUpload(files) {
|
|
94
|
+
* for (const file of files) {
|
|
95
|
+
* if (file.size > 2 * 1024 * 1024) {
|
|
96
|
+
* this.jodit.message.error('Max 2MB');
|
|
97
|
+
* return false;
|
|
98
|
+
* }
|
|
99
|
+
* }
|
|
100
|
+
* }
|
|
101
|
+
* }
|
|
102
|
+
* });
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
beforeUpload?: (this: T, files: File[]) => boolean | void;
|
|
83
106
|
prepareData: (this: T, formData: FormData) => any;
|
|
84
107
|
buildData?: (this: T, formData: any) => BuildDataResult;
|
|
85
108
|
queryBuild?: (obj: string | IDictionary<string | object> | FormData, prefix?: string) => string | FormData;
|
package/package.json
CHANGED
package/types/config.d.ts
CHANGED
|
@@ -956,6 +956,21 @@ interface Config {
|
|
|
956
956
|
backspaceWord: string[];
|
|
957
957
|
backspaceSentence: string[];
|
|
958
958
|
};
|
|
959
|
+
/**
|
|
960
|
+
* Disable specific Backspace/Delete cleanup cases by their stable
|
|
961
|
+
* key, so the plugin no longer applies that particular behavior.
|
|
962
|
+
* Available keys: `remove-unbreakable`, `remove-not-editable`,
|
|
963
|
+
* `remove-char`, `table-cell`, `remove-empty-parent`,
|
|
964
|
+
* `remove-empty-neighbor`, `join-two-lists`, `join-neighbors`,
|
|
965
|
+
* `unwrap-first-list-item`.
|
|
966
|
+
*
|
|
967
|
+
* ```javascript
|
|
968
|
+
* Jodit.make('#editor', {
|
|
969
|
+
* delete: { disableCases: new Set(['remove-empty-parent']) }
|
|
970
|
+
* });
|
|
971
|
+
* ```
|
|
972
|
+
*/
|
|
973
|
+
disableCases?: Set<string>;
|
|
959
974
|
};
|
|
960
975
|
}
|
|
961
976
|
interface Config {
|
|
@@ -973,6 +988,15 @@ interface Config {
|
|
|
973
988
|
* Remove empty elements
|
|
974
989
|
*/
|
|
975
990
|
removeEmptyElements: boolean;
|
|
991
|
+
/**
|
|
992
|
+
* Return an empty string from `editor.value` (and the synced source
|
|
993
|
+
* element) when the editor holds only a single empty block — e.g.
|
|
994
|
+
* `<p><br></p>` left after the user deletes all the content.
|
|
995
|
+
* `contenteditable` keeps that caret container in the DOM, so by
|
|
996
|
+
* default the value getter returns it as-is; enable this to collapse
|
|
997
|
+
* it to `''` for form submission.
|
|
998
|
+
*/
|
|
999
|
+
collapseEmptyValueToEmptyString: boolean;
|
|
976
1000
|
/**
|
|
977
1001
|
* Replace old tags to new eg. <i> to <em>, <b> to <strong>
|
|
978
1002
|
*/
|
|
@@ -1371,6 +1395,12 @@ interface Config {
|
|
|
1371
1395
|
* Default value for the `Open in new tab` checkbox when inserting a new link.
|
|
1372
1396
|
*/
|
|
1373
1397
|
openInNewTabCheckboxDefaultChecked: boolean;
|
|
1398
|
+
/**
|
|
1399
|
+
* Show an `aria-label` text input in the link dialog so an
|
|
1400
|
+
* accessible name can be set on the `<a>` (useful when several
|
|
1401
|
+
* links share the same visible text, e.g. "here"). Default: false.
|
|
1402
|
+
*/
|
|
1403
|
+
ariaLabelInput: boolean;
|
|
1374
1404
|
/**
|
|
1375
1405
|
* Use an input text to ask the classname or a select or not ask
|
|
1376
1406
|
*/
|