jodit 4.16.0 → 4.17.0
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 +22 -0
- package/es2015/jodit.css +11 -1
- package/es2015/jodit.fat.min.css +1 -1
- package/es2015/jodit.fat.min.js +7 -7
- package/es2015/jodit.js +176 -33
- package/es2015/jodit.min.css +1 -1
- 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.css +1 -1
- package/es2018/jodit.fat.min.js +7 -7
- package/es2018/jodit.min.css +1 -1
- 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 +11 -1
- package/es2021/jodit.fat.min.css +1 -1
- package/es2021/jodit.fat.min.js +7 -7
- package/es2021/jodit.js +168 -32
- package/es2021/jodit.min.css +1 -1
- 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 +11 -1
- package/es2021.en/jodit.fat.min.css +1 -1
- package/es2021.en/jodit.fat.min.js +7 -7
- package/es2021.en/jodit.js +168 -32
- package/es2021.en/jodit.min.css +1 -1
- package/es2021.en/jodit.min.js +7 -7
- 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 +15 -2
- package/es5/jodit.fat.min.css +1 -1
- package/es5/jodit.fat.min.js +2 -2
- package/es5/jodit.js +188 -33
- 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 +40 -1
- package/esm/core/constants.js +1 -1
- package/esm/modules/widget/file-selector/file-selector.d.ts +10 -1
- package/esm/modules/widget/file-selector/file-selector.js +30 -18
- package/esm/plugins/file/file.d.ts +24 -1
- package/esm/plugins/file/file.js +17 -1
- package/esm/plugins/iframe/config.js +4 -0
- package/esm/plugins/image-processor/image-processor.d.ts +5 -0
- package/esm/plugins/image-processor/image-processor.js +29 -2
- package/esm/plugins/inline-popup/config/items/img.js +22 -1
- package/esm/plugins/source/editor/engines/ace.js +2 -1
- package/esm/plugins/source/source.d.ts +17 -0
- package/esm/plugins/source/source.js +58 -10
- package/esm/plugins/video/config.d.ts +21 -1
- package/esm/plugins/video/config.js +22 -2
- package/package.json +1 -1
- package/types/config.d.ts +40 -1
- package/types/modules/widget/file-selector/file-selector.d.ts +10 -1
- package/types/plugins/file/file.d.ts +24 -1
- package/types/plugins/image-processor/image-processor.d.ts +5 -0
- package/types/plugins/source/source.d.ts +17 -0
- package/types/plugins/video/config.d.ts +21 -1
package/es5/polyfills.fat.min.js
CHANGED
package/es5/polyfills.js
CHANGED
package/es5/polyfills.min.js
CHANGED
package/esm/config.d.ts
CHANGED
|
@@ -8,9 +8,10 @@ import type { HTMLTagNames } from "./types/index";
|
|
|
8
8
|
import type { AiAssistantSettings } from "./plugins/ai-assistant/interface";
|
|
9
9
|
import type { IDictionary } from "./types/index";
|
|
10
10
|
import type { Nullable } from "./types/index";
|
|
11
|
+
import type { IJodit } from "./types/index";
|
|
12
|
+
import type { IUploaderData } from "./types/index";
|
|
11
13
|
import type { ImagePropertiesOptions } from "./plugins/image-properties/interface";
|
|
12
14
|
import type { IControlType } from "./types/index";
|
|
13
|
-
import type { IJodit } from "./types/index";
|
|
14
15
|
import type { formTemplate } from "./plugins/link/template";
|
|
15
16
|
import type { IUIForm } from "./types/index";
|
|
16
17
|
import type { IUIOption } from "./types/index";
|
|
@@ -1264,6 +1265,27 @@ interface Config {
|
|
|
1264
1265
|
blockLimits: IDictionary<1>;
|
|
1265
1266
|
};
|
|
1266
1267
|
}
|
|
1268
|
+
interface Config {
|
|
1269
|
+
file: {
|
|
1270
|
+
/**
|
|
1271
|
+
* Inserts the files uploaded from the file popup's Upload tab. By default
|
|
1272
|
+
* each one goes in as a link, an image as well, the way
|
|
1273
|
+
* `uploader.defaultHandlerSuccess` inserts a file that isn't an image.
|
|
1274
|
+
* ```javascript
|
|
1275
|
+
* Jodit.make('#editor', {
|
|
1276
|
+
* file: {
|
|
1277
|
+
* defaultHandlerSuccess(data) {
|
|
1278
|
+
* data.files.forEach(file => {
|
|
1279
|
+
* this.s.insertHTML(`<a class="file" href="${data.baseurl + file}">${file}</a>`);
|
|
1280
|
+
* });
|
|
1281
|
+
* }
|
|
1282
|
+
* }
|
|
1283
|
+
* });
|
|
1284
|
+
* ```
|
|
1285
|
+
*/
|
|
1286
|
+
defaultHandlerSuccess?: (this: IJodit, data: IUploaderData) => void;
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1267
1289
|
interface Config {
|
|
1268
1290
|
autofocus: boolean;
|
|
1269
1291
|
cursorAfterAutofocus: 'start' | 'end';
|
|
@@ -1971,6 +1993,23 @@ interface Config {
|
|
|
1971
1993
|
* Default height for video iframe. Default: 345
|
|
1972
1994
|
*/
|
|
1973
1995
|
defaultHeight?: number;
|
|
1996
|
+
/**
|
|
1997
|
+
* Inserts the videos uploaded from the popup's Upload tab, which is shown
|
|
1998
|
+
* when `uploader.url` or `uploader.customUploadFunction` is set. By default
|
|
1999
|
+
* each one goes in as `<video controls src="…">`.
|
|
2000
|
+
* ```javascript
|
|
2001
|
+
* Jodit.make('#editor', {
|
|
2002
|
+
* video: {
|
|
2003
|
+
* defaultHandlerSuccess(data) {
|
|
2004
|
+
* data.files.forEach(file => {
|
|
2005
|
+
* this.s.insertHTML(`<video controls preload="metadata" src="${data.baseurl + file}"></video>`);
|
|
2006
|
+
* });
|
|
2007
|
+
* }
|
|
2008
|
+
* }
|
|
2009
|
+
* });
|
|
2010
|
+
* ```
|
|
2011
|
+
*/
|
|
2012
|
+
defaultHandlerSuccess?: (this: IJodit, data: IUploaderData) => void;
|
|
1974
2013
|
};
|
|
1975
2014
|
}
|
|
1976
2015
|
interface Config {
|
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.
|
|
6
|
+
export const APP_VERSION = "4.17.0";
|
|
7
7
|
// prettier-ignore
|
|
8
8
|
export const ES = "es2020";
|
|
9
9
|
export const IS_ES_MODERN = true;
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* @packageDocumentation
|
|
9
9
|
* @module modules/widget/file-selector
|
|
10
10
|
*/
|
|
11
|
-
import type { IFileBrowserCallBackData, IJodit } from "../../../types/index";
|
|
11
|
+
import type { IFileBrowserCallBackData, IJodit, IUploaderData } from "../../../types/index";
|
|
12
|
+
import { type TabOption } from "../tabs/tabs";
|
|
12
13
|
interface ImageSelectorCallbacks {
|
|
13
14
|
/**
|
|
14
15
|
* Function that will be called when the user enters the URL of the tab image and alternative text for images
|
|
@@ -34,4 +35,12 @@ interface ImageSelectorCallbacks {
|
|
|
34
35
|
* functions with different parameters
|
|
35
36
|
*/
|
|
36
37
|
export declare const FileSelectorWidget: (editor: IJodit, callbacks: ImageSelectorCallbacks, elm: HTMLElement | null, close: () => void, isImage?: boolean) => HTMLDivElement;
|
|
38
|
+
/**
|
|
39
|
+
* The Upload tab: a box that uploads the files dropped on it or chosen in its
|
|
40
|
+
* file input, then passes the uploader's answer to `onSuccess` and closes the popup
|
|
41
|
+
*/
|
|
42
|
+
export declare const UploadTab: (editor: IJodit, onSuccess: (this: IJodit, data: IUploaderData) => void, { label, accept }: {
|
|
43
|
+
label: string;
|
|
44
|
+
accept: string;
|
|
45
|
+
}) => TabOption;
|
|
37
46
|
export {};
|
|
@@ -25,28 +25,17 @@ export const FileSelectorWidget = (editor, callbacks, elm, close, isImage = true
|
|
|
25
25
|
(options.url ||
|
|
26
26
|
options.insertImageAsBase64URI ||
|
|
27
27
|
options.customUploadFunction)) {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
'</div>');
|
|
33
|
-
editor.uploader.bind(dragBox, resp => {
|
|
34
|
-
const handler = isFunction(callbacks.upload)
|
|
35
|
-
? callbacks.upload
|
|
28
|
+
const { upload } = callbacks;
|
|
29
|
+
tabs.push(UploadTab(editor, resp => {
|
|
30
|
+
const handler = isFunction(upload)
|
|
31
|
+
? upload
|
|
36
32
|
: options.defaultHandlerSuccess;
|
|
37
33
|
if (isFunction(handler)) {
|
|
38
34
|
handler.call(editor, resp);
|
|
39
35
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
editor.e.fire('closeAllPopups');
|
|
44
|
-
});
|
|
45
|
-
tabs.push({
|
|
46
|
-
icon: 'upload',
|
|
47
|
-
name: 'Upload',
|
|
48
|
-
content: dragBox
|
|
49
|
-
});
|
|
36
|
+
}, isImage
|
|
37
|
+
? { label: 'Drop image', accept: 'image/*' }
|
|
38
|
+
: { label: 'Drop file', accept: '*' }));
|
|
50
39
|
}
|
|
51
40
|
if (callbacks.filebrowser) {
|
|
52
41
|
if (editor.o.filebrowser.ajax.url || editor.o.filebrowser.items.url) {
|
|
@@ -115,6 +104,29 @@ export const FileSelectorWidget = (editor, callbacks, elm, close, isImage = true
|
|
|
115
104
|
box.classList.add('jodit-file-selector');
|
|
116
105
|
return box;
|
|
117
106
|
};
|
|
107
|
+
/**
|
|
108
|
+
* The Upload tab: a box that uploads the files dropped on it or chosen in its
|
|
109
|
+
* file input, then passes the uploader's answer to `onSuccess` and closes the popup
|
|
110
|
+
*/
|
|
111
|
+
export const UploadTab = (editor, onSuccess, { label, accept }) => {
|
|
112
|
+
const dragBox = editor.c.fromHTML('<div class="jodit-drag-and-drop__file-box">' +
|
|
113
|
+
`<strong>${editor.i18n(label)}</strong>` +
|
|
114
|
+
`<span><br>${editor.i18n('or click')}</span>` +
|
|
115
|
+
`<input type="file" accept="${accept}" tabindex="-1" dir="auto" multiple=""/>` +
|
|
116
|
+
'</div>');
|
|
117
|
+
editor.uploader.bind(dragBox, resp => {
|
|
118
|
+
onSuccess.call(editor, resp);
|
|
119
|
+
editor.e.fire('closeAllPopups');
|
|
120
|
+
}, error => {
|
|
121
|
+
editor.message.error(error.message);
|
|
122
|
+
editor.e.fire('closeAllPopups');
|
|
123
|
+
});
|
|
124
|
+
return {
|
|
125
|
+
icon: 'upload',
|
|
126
|
+
name: 'Upload',
|
|
127
|
+
content: dragBox
|
|
128
|
+
};
|
|
129
|
+
};
|
|
118
130
|
function val(elm, name, value) {
|
|
119
131
|
const child = Dom.first(elm, node => Dom.isTag(node, 'input') && attr(node, 'name') === name);
|
|
120
132
|
if (!child) {
|
|
@@ -8,5 +8,28 @@
|
|
|
8
8
|
* @packageDocumentation
|
|
9
9
|
* @module plugins/file
|
|
10
10
|
*/
|
|
11
|
-
import type { IJodit } from "../../types/index";
|
|
11
|
+
import type { IJodit, IUploaderData } from "../../types/index";
|
|
12
|
+
declare module 'jodit/config' {
|
|
13
|
+
interface Config {
|
|
14
|
+
file: {
|
|
15
|
+
/**
|
|
16
|
+
* Inserts the files uploaded from the file popup's Upload tab. By default
|
|
17
|
+
* each one goes in as a link, an image as well, the way
|
|
18
|
+
* `uploader.defaultHandlerSuccess` inserts a file that isn't an image.
|
|
19
|
+
* ```javascript
|
|
20
|
+
* Jodit.make('#editor', {
|
|
21
|
+
* file: {
|
|
22
|
+
* defaultHandlerSuccess(data) {
|
|
23
|
+
* data.files.forEach(file => {
|
|
24
|
+
* this.s.insertHTML(`<a class="file" href="${data.baseurl + file}">${file}</a>`);
|
|
25
|
+
* });
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
defaultHandlerSuccess?: (this: IJodit, data: IUploaderData) => void;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
12
35
|
export declare function file(editor: IJodit): void;
|
package/esm/plugins/file/file.js
CHANGED
|
@@ -8,6 +8,19 @@ import { pluginSystem } from "../../core/global.js";
|
|
|
8
8
|
import { attr } from "../../core/helpers/utils/attr.js";
|
|
9
9
|
import { Config } from "../../config.js";
|
|
10
10
|
import { FileSelectorWidget } from "../../modules/widget/index.js";
|
|
11
|
+
function insertLinks(data) {
|
|
12
|
+
var _a;
|
|
13
|
+
(_a = data.files) === null || _a === void 0 ? void 0 : _a.forEach(file => {
|
|
14
|
+
const link = this.createInside.element('a', {
|
|
15
|
+
href: data.baseurl + file
|
|
16
|
+
});
|
|
17
|
+
link.textContent = this.o.uploader.getDisplayName.call(this.uploader, data.baseurl, file);
|
|
18
|
+
this.s.insertNode(link);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
Config.prototype.file = {
|
|
22
|
+
defaultHandlerSuccess: insertLinks
|
|
23
|
+
};
|
|
11
24
|
Config.prototype.controls.file = {
|
|
12
25
|
popup: (editor, current, close) => {
|
|
13
26
|
const insert = (url, title = '') => {
|
|
@@ -27,7 +40,10 @@ Config.prototype.controls.file = {
|
|
|
27
40
|
data.files.forEach(file => insert(data.baseurl + file));
|
|
28
41
|
close();
|
|
29
42
|
},
|
|
30
|
-
upload:
|
|
43
|
+
upload: (data) => {
|
|
44
|
+
var _a, _b;
|
|
45
|
+
((_b = (_a = editor.o.file) === null || _a === void 0 ? void 0 : _a.defaultHandlerSuccess) !== null && _b !== void 0 ? _b : insertLinks).call(editor, data);
|
|
46
|
+
},
|
|
31
47
|
url: (url, text) => {
|
|
32
48
|
if (sourceAnchor) {
|
|
33
49
|
attr(sourceAnchor, 'href', url);
|
|
@@ -69,6 +69,10 @@ Config.prototype.iframeStyle =
|
|
|
69
69
|
'display: block;' +
|
|
70
70
|
'background: rgba(0, 0, 0, 0);' +
|
|
71
71
|
'} ' +
|
|
72
|
+
'.jodit-wysiwyg_image-selected::selection,' +
|
|
73
|
+
'.jodit-wysiwyg_image-selected *:not(img)::selection{' +
|
|
74
|
+
'background:transparent' +
|
|
75
|
+
'}' +
|
|
72
76
|
'.jodit_disabled{' +
|
|
73
77
|
'user-select: none;' +
|
|
74
78
|
'-o-user-select: none;' +
|
|
@@ -23,6 +23,11 @@ export declare class imageProcessor extends Plugin {
|
|
|
23
23
|
protected onBeforeSetElementValue(data: {
|
|
24
24
|
value: string;
|
|
25
25
|
}): void;
|
|
26
|
+
/**
|
|
27
|
+
* While the selection is an image, only the image is highlighted: Safari
|
|
28
|
+
* paints the rest of a block image's line with its parent's highlight. See #1528
|
|
29
|
+
*/
|
|
30
|
+
private onSelectionChange;
|
|
26
31
|
protected afterChange(data: {
|
|
27
32
|
value: string;
|
|
28
33
|
}): Promise<void>;
|
|
@@ -14,7 +14,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
14
14
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
15
15
|
};
|
|
16
16
|
import { INVISIBLE_SPACE_REG_EXP, SOURCE_CONSUMER } from "../../core/constants.js";
|
|
17
|
-
import { cached, debounce, watch } from "../../core/decorators/index.js";
|
|
17
|
+
import { autobind, cached, debounce, watch } from "../../core/decorators/index.js";
|
|
18
18
|
import { Dom } from "../../core/dom/dom.js";
|
|
19
19
|
import { pluginSystem } from "../../core/global.js";
|
|
20
20
|
import { $$, dataBind } from "../../core/helpers/index.js";
|
|
@@ -23,12 +23,17 @@ import { dataURItoBlob } from "../../modules/uploader/helpers/data-uri-to-blob.j
|
|
|
23
23
|
import "./config.js";
|
|
24
24
|
const JODIT_IMAGE_PROCESSOR_BINDED = '__jodit_imageprocessor_binded';
|
|
25
25
|
const JODIT_IMAGE_BLOB_ID = JODIT_IMAGE_PROCESSOR_BINDED + 'blob-id';
|
|
26
|
+
const IMAGE_SELECTED = 'jodit-wysiwyg_image-selected';
|
|
26
27
|
/**
|
|
27
28
|
* Change editor's size after load all images
|
|
28
29
|
*/
|
|
29
30
|
export class imageProcessor extends Plugin {
|
|
30
|
-
afterInit(jodit) {
|
|
31
|
+
afterInit(jodit) {
|
|
32
|
+
jodit.e.on(jodit.ed, 'selectionchange', this.onSelectionChange);
|
|
33
|
+
}
|
|
31
34
|
beforeDestruct(jodit) {
|
|
35
|
+
jodit.e.off(jodit.ed, 'selectionchange', this.onSelectionChange);
|
|
36
|
+
jodit.editor.classList.remove(IMAGE_SELECTED);
|
|
32
37
|
const buffer = cached(jodit, 'buffer');
|
|
33
38
|
const list = buffer === null || buffer === void 0 ? void 0 : buffer.get(JODIT_IMAGE_BLOB_ID);
|
|
34
39
|
if (buffer && list) {
|
|
@@ -59,6 +64,14 @@ export class imageProcessor extends Plugin {
|
|
|
59
64
|
}
|
|
60
65
|
}
|
|
61
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* While the selection is an image, only the image is highlighted: Safari
|
|
69
|
+
* paints the rest of a block image's line with its parent's highlight. See #1528
|
|
70
|
+
*/
|
|
71
|
+
onSelectionChange() {
|
|
72
|
+
const { jodit } = this;
|
|
73
|
+
jodit.editor.classList.toggle(IMAGE_SELECTED, isImageSelected(jodit));
|
|
74
|
+
}
|
|
62
75
|
async afterChange(data) {
|
|
63
76
|
const { jodit: editor } = this;
|
|
64
77
|
if (!editor.editor) {
|
|
@@ -91,10 +104,24 @@ __decorate([
|
|
|
91
104
|
__decorate([
|
|
92
105
|
watch(':beforeSetElementValue')
|
|
93
106
|
], imageProcessor.prototype, "onBeforeSetElementValue", null);
|
|
107
|
+
__decorate([
|
|
108
|
+
autobind
|
|
109
|
+
], imageProcessor.prototype, "onSelectionChange", null);
|
|
94
110
|
__decorate([
|
|
95
111
|
watch([':change', ':afterInit', ':changePlace']),
|
|
96
112
|
debounce()
|
|
97
113
|
], imageProcessor.prototype, "afterChange", null);
|
|
114
|
+
function isImageSelected(jodit) {
|
|
115
|
+
const { sel } = jodit.s;
|
|
116
|
+
if (!sel || !sel.rangeCount) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
const { startContainer, startOffset, endContainer, endOffset } = sel.getRangeAt(0);
|
|
120
|
+
return (startContainer === endContainer &&
|
|
121
|
+
endOffset === startOffset + 1 &&
|
|
122
|
+
Dom.isTag(startContainer.childNodes[startOffset], 'img') &&
|
|
123
|
+
Dom.isOrContains(jodit.editor, startContainer));
|
|
124
|
+
}
|
|
98
125
|
/**
|
|
99
126
|
* Remove the invisible-space text beside an image, which only held a caret.
|
|
100
127
|
* Selecting the image replaces the caret, and with the text still after a
|
|
@@ -10,6 +10,26 @@ import { css } from "../../../../core/helpers/utils/css.js";
|
|
|
10
10
|
// Images align with `imageAlignClasses`; the wrappers of iframes and media
|
|
11
11
|
// keep inline styles
|
|
12
12
|
const alignClasses = (editor, elm) => Dom.isTag(elm, 'img') ? editor.o.imageAlignClasses : null;
|
|
13
|
+
// A Normal image sits where the text of its line is aligned (#1531)
|
|
14
|
+
const lineAlign = (editor, elm) => {
|
|
15
|
+
const block = (elm && Dom.closest(elm, Dom.isBlock, editor.editor)) || editor.editor;
|
|
16
|
+
const rtl = css(block, 'direction') === 'rtl';
|
|
17
|
+
switch (css(block, 'text-align')) {
|
|
18
|
+
case 'center':
|
|
19
|
+
case '-webkit-center':
|
|
20
|
+
return 'center';
|
|
21
|
+
case 'justify':
|
|
22
|
+
return 'justify';
|
|
23
|
+
case 'right':
|
|
24
|
+
return 'right';
|
|
25
|
+
case 'end':
|
|
26
|
+
return rtl ? 'left' : 'right';
|
|
27
|
+
case 'start':
|
|
28
|
+
return rtl ? 'right' : 'left';
|
|
29
|
+
default:
|
|
30
|
+
return 'left';
|
|
31
|
+
}
|
|
32
|
+
};
|
|
13
33
|
const currentAlign = (editor, elm) => (elm ? getHAlign(elm, alignClasses(editor, elm)) : 'normal');
|
|
14
34
|
export const align = {
|
|
15
35
|
name: 'left',
|
|
@@ -17,7 +37,8 @@ export const align = {
|
|
|
17
37
|
list: ['Left', 'Right', 'Center', 'Normal'],
|
|
18
38
|
update: (editor, button) => {
|
|
19
39
|
const current = currentAlign(editor, button.target);
|
|
20
|
-
button.state.icon.name =
|
|
40
|
+
button.state.icon.name =
|
|
41
|
+
current === 'normal' ? lineAlign(editor, button.target) : current;
|
|
21
42
|
},
|
|
22
43
|
isActive: (editor, button) => currentAlign(editor, button.target) !== 'normal',
|
|
23
44
|
isChildActive: (editor, button) => {
|
|
@@ -146,7 +146,8 @@ export class AceEditor extends SourceEditor {
|
|
|
146
146
|
}
|
|
147
147
|
return;
|
|
148
148
|
}
|
|
149
|
-
this
|
|
149
|
+
// The source plugin carries the fallback editor's text over when this
|
|
150
|
+
// one is ready; refilling from WYSIWYG here would drop unsynced typing
|
|
150
151
|
tryInitAceEditor();
|
|
151
152
|
};
|
|
152
153
|
editor.e.on('afterSetMode', initAceEditor);
|
|
@@ -21,6 +21,11 @@ export declare class source extends Plugin {
|
|
|
21
21
|
private mirrorContainer;
|
|
22
22
|
private __lock;
|
|
23
23
|
private __oldMirrorValue;
|
|
24
|
+
/**
|
|
25
|
+
* What the source view was last filled with from WYSIWYG, read back from
|
|
26
|
+
* the editor; while the view still holds it, nothing has been typed there
|
|
27
|
+
*/
|
|
28
|
+
private __filledValue;
|
|
24
29
|
private tempMarkerStart;
|
|
25
30
|
private tempMarkerStartReg;
|
|
26
31
|
private tempMarkerEnd;
|
|
@@ -50,6 +55,18 @@ export declare class source extends Plugin {
|
|
|
50
55
|
afterInit(editor: IJodit): void;
|
|
51
56
|
private syncValueFromWYSIWYG;
|
|
52
57
|
private initSourceEditor;
|
|
58
|
+
/**
|
|
59
|
+
* Replaces the source editor (the textarea shown while ACE loads) with
|
|
60
|
+
* the one that just became ready, carrying its text, selection and focus
|
|
61
|
+
* over. Filling the new editor from WYSIWYG instead would drop what was
|
|
62
|
+
* typed since the last, debounced, sync and normalise half-typed markup.
|
|
63
|
+
*/
|
|
64
|
+
private takeOver;
|
|
65
|
+
/**
|
|
66
|
+
* The beautifier arrived after the source view was opened: format the
|
|
67
|
+
* view if nothing has been typed into it, otherwise leave the typing alone
|
|
68
|
+
*/
|
|
69
|
+
private beautifyUntouched;
|
|
53
70
|
/** @override */
|
|
54
71
|
beforeDestruct(): void;
|
|
55
72
|
}
|
|
@@ -37,6 +37,11 @@ export class source extends Plugin {
|
|
|
37
37
|
];
|
|
38
38
|
this.__lock = false;
|
|
39
39
|
this.__oldMirrorValue = '';
|
|
40
|
+
/**
|
|
41
|
+
* What the source view was last filled with from WYSIWYG, read back from
|
|
42
|
+
* the editor; while the view still holds it, nothing has been typed there
|
|
43
|
+
*/
|
|
44
|
+
this.__filledValue = '';
|
|
40
45
|
this.tempMarkerStart = '{start-jodit-selection}';
|
|
41
46
|
this.tempMarkerStartReg = /{start-jodit-selection}/g;
|
|
42
47
|
this.tempMarkerEnd = '{end-jodit-selection}';
|
|
@@ -69,6 +74,7 @@ export class source extends Plugin {
|
|
|
69
74
|
if (new_value !== this.getMirrorValue()) {
|
|
70
75
|
this.setMirrorValue(new_value);
|
|
71
76
|
}
|
|
77
|
+
this.__filledValue = this.getMirrorValue();
|
|
72
78
|
this.__lock = false;
|
|
73
79
|
}
|
|
74
80
|
}
|
|
@@ -272,11 +278,7 @@ export class source extends Plugin {
|
|
|
272
278
|
}
|
|
273
279
|
loading = true;
|
|
274
280
|
loadNext(editor, editor.o.beautifyHTMLCDNUrlsJS).then(() => {
|
|
275
|
-
|
|
276
|
-
// beautifier arrived — format it now.
|
|
277
|
-
if (addEventListener()) {
|
|
278
|
-
this.syncValueFromWYSIWYG(true);
|
|
279
|
-
}
|
|
281
|
+
addEventListener() && this.beautifyUntouched();
|
|
280
282
|
}, () => null);
|
|
281
283
|
};
|
|
282
284
|
editor.e.on('afterSetMode.source', loadBeautify);
|
|
@@ -298,11 +300,9 @@ export class source extends Plugin {
|
|
|
298
300
|
if (editor.o.sourceEditor !== 'area') {
|
|
299
301
|
const sourceEditor = createSourceEditor(editor.o.sourceEditor, editor, this.mirrorContainer, this.toWYSIWYG, this.fromWYSIWYG);
|
|
300
302
|
sourceEditor.onReadyAlways(() => {
|
|
301
|
-
var _a
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
this.syncValueFromWYSIWYG(true);
|
|
305
|
-
(_b = editor.events) === null || _b === void 0 ? void 0 : _b.fire('sourceEditorReady', editor);
|
|
303
|
+
var _a;
|
|
304
|
+
this.takeOver(sourceEditor);
|
|
305
|
+
(_a = editor.events) === null || _a === void 0 ? void 0 : _a.fire('sourceEditorReady', editor);
|
|
306
306
|
});
|
|
307
307
|
}
|
|
308
308
|
else {
|
|
@@ -313,6 +313,54 @@ export class source extends Plugin {
|
|
|
313
313
|
});
|
|
314
314
|
}
|
|
315
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* Replaces the source editor (the textarea shown while ACE loads) with
|
|
318
|
+
* the one that just became ready, carrying its text, selection and focus
|
|
319
|
+
* over. Filling the new editor from WYSIWYG instead would drop what was
|
|
320
|
+
* typed since the last, debounced, sync and normalise half-typed markup.
|
|
321
|
+
*/
|
|
322
|
+
takeOver(sourceEditor) {
|
|
323
|
+
const previous = this.sourceEditor;
|
|
324
|
+
if (!previous || previous === sourceEditor) {
|
|
325
|
+
this.sourceEditor = sourceEditor;
|
|
326
|
+
this.syncValueFromWYSIWYG(true);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const value = previous.getValue(), start = previous.getSelectionStart(), end = previous.getSelectionEnd(), focused = previous.isFocused, untouched = value === this.__filledValue;
|
|
330
|
+
previous.destruct();
|
|
331
|
+
this.sourceEditor = sourceEditor;
|
|
332
|
+
if (untouched) {
|
|
333
|
+
this.syncValueFromWYSIWYG(true);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
sourceEditor.setValue(value);
|
|
337
|
+
this.toWYSIWYG();
|
|
338
|
+
}
|
|
339
|
+
if (start >= 0) {
|
|
340
|
+
sourceEditor.setSelectionRange(start, end);
|
|
341
|
+
}
|
|
342
|
+
focused && sourceEditor.focus();
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* The beautifier arrived after the source view was opened: format the
|
|
346
|
+
* view if nothing has been typed into it, otherwise leave the typing alone
|
|
347
|
+
*/
|
|
348
|
+
beautifyUntouched() {
|
|
349
|
+
var _a, _b;
|
|
350
|
+
const value = this.getMirrorValue();
|
|
351
|
+
if (this.j.o.editHTMLDocumentMode ||
|
|
352
|
+
!value ||
|
|
353
|
+
value !== this.__filledValue) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
const html = this.j.e.fire('beautifyHTML', value);
|
|
357
|
+
if (isString(html) && html !== value) {
|
|
358
|
+
const focused = (_a = this.sourceEditor) === null || _a === void 0 ? void 0 : _a.isFocused;
|
|
359
|
+
this.setMirrorValue(html);
|
|
360
|
+
this.__filledValue = this.getMirrorValue();
|
|
361
|
+
focused && ((_b = this.sourceEditor) === null || _b === void 0 ? void 0 : _b.focus());
|
|
362
|
+
}
|
|
363
|
+
}
|
|
316
364
|
/** @override */
|
|
317
365
|
beforeDestruct() {
|
|
318
366
|
if (this.sourceEditor) {
|
|
@@ -3,6 +3,10 @@
|
|
|
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/video
|
|
8
|
+
*/
|
|
9
|
+
import type { IJodit, IUploaderData } from "../../types/index";
|
|
6
10
|
declare module 'jodit/config' {
|
|
7
11
|
interface Config {
|
|
8
12
|
video: {
|
|
@@ -29,7 +33,23 @@ declare module 'jodit/config' {
|
|
|
29
33
|
* Default height for video iframe. Default: 345
|
|
30
34
|
*/
|
|
31
35
|
defaultHeight?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Inserts the videos uploaded from the popup's Upload tab, which is shown
|
|
38
|
+
* when `uploader.url` or `uploader.customUploadFunction` is set. By default
|
|
39
|
+
* each one goes in as `<video controls src="…">`.
|
|
40
|
+
* ```javascript
|
|
41
|
+
* Jodit.make('#editor', {
|
|
42
|
+
* video: {
|
|
43
|
+
* defaultHandlerSuccess(data) {
|
|
44
|
+
* data.files.forEach(file => {
|
|
45
|
+
* this.s.insertHTML(`<video controls preload="metadata" src="${data.baseurl + file}"></video>`);
|
|
46
|
+
* });
|
|
47
|
+
* }
|
|
48
|
+
* }
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
defaultHandlerSuccess?: (this: IJodit, data: IUploaderData) => void;
|
|
32
53
|
};
|
|
33
54
|
}
|
|
34
55
|
}
|
|
35
|
-
export {};
|