jodit 3.8.7 → 3.9.4
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/.github/workflows/tests.yml +23 -0
- package/.idea/dictionaries/v_chupurnov.xml +1 -0
- package/.idea/workspace.xml +340 -298
- package/CHANGELOG.MD +132 -24
- package/README.md +3 -4
- package/build/jodit.css +92 -34
- package/build/jodit.es2018.css +65 -30
- package/build/jodit.es2018.en.css +65 -30
- package/build/jodit.es2018.en.js +1214 -693
- package/build/jodit.es2018.en.min.css +1 -1
- package/build/jodit.es2018.en.min.js +1 -1
- package/build/jodit.es2018.js +1214 -693
- package/build/jodit.es2018.min.css +1 -1
- package/build/jodit.es2018.min.js +1 -1
- package/build/jodit.js +2271 -1628
- package/build/jodit.min.css +2 -2
- package/build/jodit.min.js +1 -1
- package/index.d.ts +10 -0
- package/package.json +14 -13
- package/src/config.ts +1 -1
- package/src/core/async.ts +7 -5
- package/src/core/constants.ts +2 -0
- package/src/core/dom.ts +123 -102
- package/src/core/events/{events-native.ts → event-emitter.ts} +14 -9
- package/src/core/events/index.ts +1 -1
- package/src/core/global.ts +2 -2
- package/src/core/helpers/array/to-array.ts +1 -0
- package/src/core/helpers/data-bind.ts +2 -2
- package/src/core/helpers/size/index.ts +1 -0
- package/src/core/helpers/size/object-size.ts +22 -0
- package/src/core/helpers/utils/utils.ts +20 -4
- package/src/core/request/ajax.ts +212 -0
- package/src/core/request/config.ts +37 -0
- package/{build-system/minimizer/index.js → src/core/request/index.ts} +2 -1
- package/src/core/request/response.ts +39 -0
- package/src/core/selection/select.ts +60 -27
- package/src/core/selection/style/api/element-has-same-style.ts +13 -0
- package/src/core/selection/style/api/{get-closest-wrapper.ts → extract.ts} +26 -43
- package/src/core/selection/style/api/finite-state-machine.ts +66 -0
- package/src/core/selection/style/api/get-suit-parent.ts +1 -1
- package/src/core/selection/style/api/index.ts +12 -5
- package/src/core/selection/style/api/{check-special-elements.ts → is-inside-invisible-element.ts} +1 -1
- package/src/core/selection/style/api/is-suit-element.ts +36 -5
- package/src/core/selection/style/api/toggle/toggle-css.ts +134 -0
- package/src/core/selection/style/api/toggle/toggle-ordered-list.ts +49 -0
- package/src/core/selection/style/api/toggle-commit-styles.ts +27 -0
- package/src/core/selection/style/api/unwrap-children.ts +45 -16
- package/src/core/selection/style/api/wrap-and-commit-style.ts +68 -0
- package/src/core/selection/style/api/wrap-ordered-list.ts +37 -0
- package/src/core/selection/style/api/wrap-unwrapped-text.ts +29 -27
- package/src/core/selection/style/apply-style.ts +161 -91
- package/src/core/selection/style/commit-style.ts +13 -0
- package/src/core/traits/elms.ts +1 -0
- package/src/core/ui/button/button/button.less +2 -0
- package/src/core/ui/helpers/buttons.ts +14 -6
- package/src/core/ui/helpers/get-control-type.ts +3 -1
- package/src/core/ui/list/list.less +1 -0
- package/src/core/ui/popup/popup.less +5 -3
- package/src/core/view/view-with-toolbar.ts +4 -0
- package/src/core/view/view.ts +3 -3
- package/src/modules/context-menu/context-menu.ts +1 -1
- package/src/modules/file-browser/README.MD +1 -1
- package/src/modules/file-browser/data-provider.ts +22 -42
- package/src/modules/file-browser/file-browser.ts +3 -0
- package/src/modules/index.ts +1 -1
- package/src/modules/status-bar/status-bar.less +27 -1
- package/src/modules/status-bar/status-bar.ts +15 -1
- package/src/modules/table.ts +197 -168
- package/src/modules/uploader/uploader.ts +4 -3
- package/src/modules/widget/tabs/tabs.less +1 -0
- package/src/plugins/bold.ts +2 -2
- package/src/plugins/fix/clean-html.ts +37 -16
- package/src/plugins/font.ts +11 -1
- package/src/plugins/indent.ts +25 -18
- package/src/plugins/index.ts +1 -0
- package/src/plugins/mobile.ts +10 -14
- package/src/plugins/ordered-list.ts +40 -1
- package/src/plugins/powered-by-jodit.ts +39 -0
- package/src/plugins/print/preview.ts +9 -2
- package/src/plugins/resizer/resizer.less +10 -7
- package/src/plugins/resizer/resizer.ts +12 -14
- package/src/plugins/size/assests/resize-handler.svg +4 -0
- package/src/plugins/size/resize-handler.ts +5 -5
- package/src/plugins/size/size.less +6 -8
- package/src/plugins/size/size.ts +1 -3
- package/src/plugins/source/source.ts +16 -2
- package/src/plugins/table/config.ts +3 -1
- package/src/plugins/table/select-cells.ts +23 -5
- package/src/plugins/table/table.less +0 -1
- package/src/styles/themes/dark.less +11 -1
- package/src/types/ajax.d.ts +15 -6
- package/src/types/async.d.ts +5 -4
- package/src/types/events.d.ts +12 -12
- package/src/types/style.d.ts +2 -0
- package/src/types/toolbar.d.ts +2 -1
- package/src/types/view.d.ts +3 -2
- package/types/core/async.d.ts +3 -3
- package/types/core/constants.d.ts +1 -0
- package/types/core/dom.d.ts +27 -20
- package/types/core/events/{events-native.d.ts → event-emitter.d.ts} +8 -3
- package/types/core/events/index.d.ts +1 -1
- package/types/core/global.d.ts +2 -2
- package/types/core/helpers/size/index.d.ts +1 -0
- package/{src/types/core.js → types/core/helpers/size/object-size.d.ts} +2 -3
- package/types/core/helpers/utils/utils.d.ts +12 -4
- package/types/core/{ajax.d.ts → request/ajax.d.ts} +5 -15
- package/types/core/request/config.d.ts +14 -0
- package/{build-system/rules/css.js → types/core/request/index.d.ts} +2 -7
- package/types/core/request/response.d.ts +16 -0
- package/types/core/selection/style/api/element-has-same-style.d.ts +4 -0
- package/types/core/selection/style/api/{get-closest-wrapper.d.ts → extract.d.ts} +6 -5
- package/types/core/selection/style/api/finite-state-machine.d.ts +21 -0
- package/types/core/selection/style/api/index.d.ts +12 -5
- package/types/core/selection/style/api/{check-special-elements.d.ts → is-inside-invisible-element.d.ts} +1 -1
- package/types/core/selection/style/api/is-suit-element.d.ts +10 -0
- package/types/core/selection/style/api/toggle/toggle-css.d.ts +11 -0
- package/types/core/selection/style/api/toggle/toggle-ordered-list.d.ts +11 -0
- package/types/core/selection/style/api/{toggle-styles.d.ts → toggle-commit-styles.d.ts} +1 -3
- package/types/core/selection/style/api/{post-process-list-element.d.ts → wrap-and-commit-style.d.ts} +3 -3
- package/types/core/selection/style/api/wrap-ordered-list.d.ts +12 -0
- package/types/core/selection/style/api/wrap-unwrapped-text.d.ts +2 -2
- package/types/core/selection/style/apply-style.d.ts +1 -4
- package/types/core/selection/style/commit-style.d.ts +7 -0
- package/types/core/ui/helpers/buttons.d.ts +2 -2
- package/types/core/view/view-with-toolbar.d.ts +2 -1
- package/types/core/view/view.d.ts +2 -2
- package/types/modules/file-browser/data-provider.d.ts +1 -1
- package/types/modules/index.d.ts +1 -1
- package/types/modules/status-bar/status-bar.d.ts +6 -1
- package/types/modules/table.d.ts +2 -2
- package/types/plugins/fix/clean-html.d.ts +4 -0
- package/types/plugins/index.d.ts +1 -0
- package/types/plugins/ordered-list.d.ts +8 -1
- package/{build-system/plugins/banner.js → types/plugins/powered-by-jodit.d.ts} +7 -10
- package/types/plugins/size/resize-handler.d.ts +1 -1
- package/types/plugins/source/source.d.ts +1 -1
- package/types/types/ajax.d.ts +15 -6
- package/types/types/async.d.ts +5 -4
- package/types/types/events.d.ts +12 -12
- package/types/types/style.d.ts +2 -0
- package/types/types/toolbar.d.ts +2 -1
- package/types/types/view.d.ts +3 -2
- package/.editorconfig +0 -15
- package/.eslintignore +0 -3
- package/.eslintrc.js +0 -109
- package/.prettierrc.json +0 -9
- package/.stylelintrc.json +0 -16
- package/app.css +0 -112
- package/build-system/index.js +0 -78
- package/build-system/loaders/css-variables-prefixes.js +0 -12
- package/build-system/loaders/lang-loader.js +0 -57
- package/build-system/loaders/style.js +0 -31
- package/build-system/loaders/svg-loader.js +0 -21
- package/build-system/minimizer/css.js +0 -20
- package/build-system/minimizer/js.js +0 -41
- package/build-system/plugins/define.js +0 -22
- package/build-system/plugins/extract-css.js +0 -21
- package/build-system/plugins/index.js +0 -31
- package/build-system/plugins/post-build.js +0 -52
- package/build-system/rules/extra-typescript.js +0 -22
- package/build-system/rules/index.js +0 -17
- package/build-system/rules/internal-typescript.js +0 -23
- package/build-system/rules/langs.js +0 -20
- package/build-system/rules/svg.js +0 -16
- package/build-system/utils/filename.js +0 -14
- package/build-system/utils/post-build.js +0 -28
- package/build-system/variables.js +0 -51
- package/composer.json +0 -12
- package/src/core/ajax.ts +0 -269
- package/src/core/selection/style/api/post-process-list-element.ts +0 -33
- package/src/core/selection/style/api/toggle-styles.ts +0 -74
- package/src/types/core.d.ts +0 -7
- package/src/types/core.js.map +0 -1
- package/src/types/storage.d.ts +0 -13
- package/src/types/storage.js +0 -8
- package/src/types/storage.js.map +0 -1
- package/types/types/core.js +0 -8
- package/types/types/core.js.map +0 -1
- package/types/types/storage.js +0 -8
- package/types/types/storage.js.map +0 -1
|
@@ -0,0 +1,212 @@
|
|
|
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-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
IDictionary,
|
|
9
|
+
IRequest,
|
|
10
|
+
IViewBased,
|
|
11
|
+
AjaxOptions,
|
|
12
|
+
IAjax,
|
|
13
|
+
RejectablePromise,
|
|
14
|
+
IResponse
|
|
15
|
+
} from '../../types';
|
|
16
|
+
|
|
17
|
+
import { Config } from '../../config';
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
error,
|
|
21
|
+
isPlainObject,
|
|
22
|
+
parseQuery,
|
|
23
|
+
buildQuery,
|
|
24
|
+
isString,
|
|
25
|
+
isFunction,
|
|
26
|
+
ConfigProto
|
|
27
|
+
} from '../helpers';
|
|
28
|
+
import { Response } from './response';
|
|
29
|
+
|
|
30
|
+
import './config';
|
|
31
|
+
|
|
32
|
+
export class Ajax<T extends object = any> implements IAjax<T> {
|
|
33
|
+
static log: IRequest[] = [];
|
|
34
|
+
|
|
35
|
+
private readonly xhr!: XMLHttpRequest;
|
|
36
|
+
|
|
37
|
+
private __buildParams(
|
|
38
|
+
obj: string | IDictionary<string | object> | FormData,
|
|
39
|
+
prefix?: string
|
|
40
|
+
): string | FormData {
|
|
41
|
+
if (isFunction(this.o.queryBuild)) {
|
|
42
|
+
return this.o.queryBuild.call(this, obj, prefix);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (
|
|
46
|
+
isString(obj) ||
|
|
47
|
+
((this.j.ow as any).FormData &&
|
|
48
|
+
obj instanceof (this.j.ow as any).FormData)
|
|
49
|
+
) {
|
|
50
|
+
return obj as string | FormData;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return buildQuery(obj);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
options: AjaxOptions;
|
|
57
|
+
get o(): this['options'] {
|
|
58
|
+
return this.options;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Alias for this.jodit
|
|
63
|
+
*/
|
|
64
|
+
get j(): this['jodit'] {
|
|
65
|
+
return this.jodit;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
abort(): Ajax {
|
|
69
|
+
try {
|
|
70
|
+
this.xhr.abort();
|
|
71
|
+
} catch {}
|
|
72
|
+
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private resolved = false;
|
|
77
|
+
|
|
78
|
+
private activated = false;
|
|
79
|
+
|
|
80
|
+
send(): RejectablePromise<IResponse<T>> {
|
|
81
|
+
this.activated = true;
|
|
82
|
+
|
|
83
|
+
const { xhr, o } = this;
|
|
84
|
+
|
|
85
|
+
const request = this.prepareRequest();
|
|
86
|
+
|
|
87
|
+
return this.j.async.promise((resolve, reject) => {
|
|
88
|
+
const onReject = () => {
|
|
89
|
+
reject(error('Connection error'));
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const onResolve = () => {
|
|
93
|
+
this.resolved = true;
|
|
94
|
+
|
|
95
|
+
resolve(
|
|
96
|
+
new Response<T>(
|
|
97
|
+
request,
|
|
98
|
+
xhr.status,
|
|
99
|
+
xhr.statusText,
|
|
100
|
+
xhr.responseText
|
|
101
|
+
)
|
|
102
|
+
);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
xhr.onabort = onReject;
|
|
106
|
+
xhr.onerror = onReject;
|
|
107
|
+
xhr.ontimeout = onReject;
|
|
108
|
+
|
|
109
|
+
xhr.onload = onResolve;
|
|
110
|
+
|
|
111
|
+
xhr.onprogress = (e): void => {
|
|
112
|
+
let percentComplete = 0;
|
|
113
|
+
|
|
114
|
+
if (e.lengthComputable) {
|
|
115
|
+
percentComplete = (e.loaded / e.total) * 100;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
this.options.onProgress?.(percentComplete);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
xhr.onreadystatechange = () => {
|
|
122
|
+
this.options.onProgress?.(10);
|
|
123
|
+
|
|
124
|
+
if (xhr.readyState === XMLHttpRequest.DONE) {
|
|
125
|
+
if (o.successStatuses.includes(xhr.status)) {
|
|
126
|
+
onResolve();
|
|
127
|
+
} else {
|
|
128
|
+
reject(error(xhr.statusText || 'Connection error'));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
xhr.withCredentials = o.withCredentials ?? false;
|
|
134
|
+
|
|
135
|
+
const { url, data, method } = request;
|
|
136
|
+
|
|
137
|
+
xhr.open(method, url, true);
|
|
138
|
+
|
|
139
|
+
if (o.contentType && xhr.setRequestHeader) {
|
|
140
|
+
xhr.setRequestHeader('Content-type', o.contentType);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const { headers } = o;
|
|
144
|
+
|
|
145
|
+
if (headers && xhr.setRequestHeader) {
|
|
146
|
+
Object.keys(headers).forEach(key => {
|
|
147
|
+
xhr.setRequestHeader(key, headers[key]);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// IE
|
|
152
|
+
this.j.async.setTimeout(() => {
|
|
153
|
+
xhr.send(data ? this.__buildParams(data) : undefined);
|
|
154
|
+
}, 0);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
prepareRequest(): IRequest {
|
|
159
|
+
if (!this.o.url) {
|
|
160
|
+
throw error('Need URL for AJAX request');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
let url: string = this.o.url;
|
|
164
|
+
|
|
165
|
+
const data = this.o.data;
|
|
166
|
+
const method = (this.o.method || 'get').toLowerCase();
|
|
167
|
+
|
|
168
|
+
if (method === 'get' && data && isPlainObject(data)) {
|
|
169
|
+
const qIndex = url.indexOf('?');
|
|
170
|
+
|
|
171
|
+
if (qIndex !== -1) {
|
|
172
|
+
const urlData = parseQuery(url);
|
|
173
|
+
|
|
174
|
+
url =
|
|
175
|
+
url.substr(0, qIndex) +
|
|
176
|
+
'?' +
|
|
177
|
+
buildQuery({ ...urlData, ...(data as IDictionary) });
|
|
178
|
+
} else {
|
|
179
|
+
url += '?' + buildQuery(this.o.data as IDictionary);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const request = {
|
|
184
|
+
url,
|
|
185
|
+
method,
|
|
186
|
+
data
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
Ajax.log.splice(100);
|
|
190
|
+
Ajax.log.push(request);
|
|
191
|
+
|
|
192
|
+
return request;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
constructor(readonly jodit: IViewBased, options: Partial<AjaxOptions>) {
|
|
196
|
+
this.options = ConfigProto(
|
|
197
|
+
options || {},
|
|
198
|
+
Config.prototype.defaultAjaxOptions
|
|
199
|
+
) as AjaxOptions;
|
|
200
|
+
|
|
201
|
+
this.xhr = this.o.xhr ? this.o.xhr() : new XMLHttpRequest();
|
|
202
|
+
|
|
203
|
+
jodit && jodit.e && jodit.e.on('beforeDestruct', () => this.destruct());
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
destruct(): void {
|
|
207
|
+
if (this.activated && !this.resolved) {
|
|
208
|
+
this.abort();
|
|
209
|
+
this.resolved = true;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
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-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { AjaxOptions } from '../../types';
|
|
8
|
+
import { Config } from '../../config';
|
|
9
|
+
|
|
10
|
+
declare module '../../config' {
|
|
11
|
+
interface Config {
|
|
12
|
+
/**
|
|
13
|
+
* A set of key/value pairs that configure the Ajax request. All settings are optional
|
|
14
|
+
*/
|
|
15
|
+
defaultAjaxOptions: AjaxOptions;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
Config.prototype.defaultAjaxOptions = {
|
|
20
|
+
successStatuses: [200, 201, 202],
|
|
21
|
+
|
|
22
|
+
dataType: 'json',
|
|
23
|
+
method: 'GET',
|
|
24
|
+
url: '',
|
|
25
|
+
data: null,
|
|
26
|
+
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
|
|
27
|
+
|
|
28
|
+
headers: {
|
|
29
|
+
'X-REQUESTED-WITH': 'XMLHttpRequest' // compatible with jQuery
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
withCredentials: false,
|
|
33
|
+
|
|
34
|
+
xhr(): XMLHttpRequest {
|
|
35
|
+
return new XMLHttpRequest();
|
|
36
|
+
}
|
|
37
|
+
} as AjaxOptions;
|
|
@@ -0,0 +1,39 @@
|
|
|
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-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { IRequest, IResponse } from '../../types';
|
|
8
|
+
|
|
9
|
+
export class Response<T> implements IResponse<T> {
|
|
10
|
+
readonly status: number;
|
|
11
|
+
readonly statusText: string;
|
|
12
|
+
|
|
13
|
+
readonly request: IRequest;
|
|
14
|
+
get url(): string {
|
|
15
|
+
return this.request.url;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
private readonly body: string;
|
|
19
|
+
|
|
20
|
+
constructor(
|
|
21
|
+
request: IRequest,
|
|
22
|
+
status: number,
|
|
23
|
+
statusText: string,
|
|
24
|
+
body: string
|
|
25
|
+
) {
|
|
26
|
+
this.request = request;
|
|
27
|
+
this.status = status;
|
|
28
|
+
this.statusText = statusText;
|
|
29
|
+
this.body = body;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async json(): Promise<T> {
|
|
33
|
+
return JSON.parse(this.body);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
text(): Promise<string> {
|
|
37
|
+
return Promise.resolve(this.body);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -110,6 +110,7 @@ export class Select implements ISelect {
|
|
|
110
110
|
* Return current selection object
|
|
111
111
|
* @param select - Immediately add in selection
|
|
112
112
|
*/
|
|
113
|
+
@autobind
|
|
113
114
|
createRange(select: boolean = false): Range {
|
|
114
115
|
const range = this.doc.createRange();
|
|
115
116
|
|
|
@@ -760,42 +761,74 @@ export class Select implements ISelect {
|
|
|
760
761
|
if (sel && sel.rangeCount) {
|
|
761
762
|
const range = sel.getRangeAt(0);
|
|
762
763
|
|
|
764
|
+
let root = range.commonAncestorContainer;
|
|
765
|
+
|
|
766
|
+
if (!Dom.isHTMLElement(root)) {
|
|
767
|
+
root = root.parentElement as HTMLElement;
|
|
768
|
+
}
|
|
769
|
+
|
|
763
770
|
const nodes: Node[] = [],
|
|
764
771
|
startOffset = range.startOffset,
|
|
765
|
-
length =
|
|
766
|
-
elementOffset = startOffset < length ? startOffset : length - 1
|
|
767
|
-
|
|
772
|
+
length = root.childNodes.length,
|
|
773
|
+
elementOffset = startOffset < length ? startOffset : length - 1;
|
|
774
|
+
|
|
775
|
+
let start: Node =
|
|
768
776
|
range.startContainer === this.area
|
|
769
|
-
?
|
|
777
|
+
? root.childNodes[elementOffset]
|
|
770
778
|
: range.startContainer,
|
|
771
779
|
end: Node =
|
|
772
780
|
range.endContainer === this.area
|
|
773
|
-
?
|
|
781
|
+
? root.childNodes[range.endOffset - 1]
|
|
774
782
|
: range.endContainer;
|
|
775
783
|
|
|
776
|
-
|
|
777
|
-
start
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
) {
|
|
785
|
-
nodes.push(node);
|
|
786
|
-
}
|
|
784
|
+
if (
|
|
785
|
+
Dom.isText(start) &&
|
|
786
|
+
start === range.startContainer &&
|
|
787
|
+
range.startOffset === start.nodeValue?.length &&
|
|
788
|
+
start.nextSibling
|
|
789
|
+
) {
|
|
790
|
+
start = start.nextSibling;
|
|
791
|
+
}
|
|
787
792
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
793
|
+
if (
|
|
794
|
+
Dom.isText(end) &&
|
|
795
|
+
end === range.endContainer &&
|
|
796
|
+
range.endOffset === 0 &&
|
|
797
|
+
end.previousSibling
|
|
798
|
+
) {
|
|
799
|
+
end = end.previousSibling;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
const checkElm = (node: Nullable<Node>) => {
|
|
803
|
+
if (
|
|
804
|
+
node &&
|
|
805
|
+
node !== root &&
|
|
806
|
+
!Dom.isEmptyTextNode(node) &&
|
|
807
|
+
!Select.isMarker(node as HTMLElement)
|
|
808
|
+
) {
|
|
809
|
+
nodes.push(node);
|
|
810
|
+
}
|
|
811
|
+
};
|
|
812
|
+
|
|
813
|
+
checkElm(start);
|
|
814
|
+
|
|
815
|
+
if (start !== end) {
|
|
816
|
+
Dom.find(
|
|
817
|
+
start,
|
|
818
|
+
node => {
|
|
819
|
+
checkElm(node);
|
|
820
|
+
|
|
821
|
+
// checks parentElement as well because partial selections are not equal to entire element
|
|
822
|
+
return (
|
|
823
|
+
node === end ||
|
|
824
|
+
(node && node.contains && node.contains(end))
|
|
825
|
+
);
|
|
826
|
+
},
|
|
827
|
+
<HTMLElement>root,
|
|
828
|
+
true,
|
|
829
|
+
false
|
|
830
|
+
);
|
|
831
|
+
}
|
|
799
832
|
|
|
800
833
|
const forEvery = (current: Node): void => {
|
|
801
834
|
if (!Dom.isOrContains(this.j.editor, current, true)) {
|
|
@@ -29,3 +29,16 @@ export function elementHasSameStyle(elm: Node, rules: IStyle): boolean {
|
|
|
29
29
|
})
|
|
30
30
|
);
|
|
31
31
|
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Element has the similar styles
|
|
35
|
+
*/
|
|
36
|
+
export function elementHasSameStyleKeys(elm: Node, rules: IStyle): boolean {
|
|
37
|
+
return Boolean(
|
|
38
|
+
!Dom.isTag(elm, 'font') &&
|
|
39
|
+
Dom.isHTMLElement(elm) &&
|
|
40
|
+
Object.keys(rules).every(
|
|
41
|
+
property => !isVoid(css(elm, property, true))
|
|
42
|
+
)
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -4,69 +4,52 @@
|
|
|
4
4
|
* Copyright (c) 2013-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type {
|
|
8
|
-
import { Dom } from '../../../dom';
|
|
9
|
-
import { isSuitElement } from './is-suit-element';
|
|
10
|
-
import { call, trim } from '../../../helpers';
|
|
11
|
-
import type { Nullable } from '../../../../types';
|
|
7
|
+
import type { IJodit } from '../../../../types';
|
|
12
8
|
import { Select } from '../../select';
|
|
9
|
+
import { call, trim } from '../../../helpers';
|
|
10
|
+
import { Dom } from '../../../dom';
|
|
13
11
|
|
|
14
12
|
/**
|
|
15
13
|
* If the selection area is inside an element that matches the commit (suitable relative),
|
|
16
14
|
* but does not completely fill it.
|
|
17
15
|
* Then the method cuts the parent and leaves itself in a copy of the parent (suitable relative) in the middle.
|
|
18
|
-
* And returns it copy.
|
|
19
16
|
*
|
|
20
17
|
* @example
|
|
18
|
+
* Apply strong to
|
|
21
19
|
* ```html
|
|
22
20
|
* <strong><span>some<font>SELECTED</font>text</span></strong>
|
|
23
|
-
*
|
|
21
|
+
* ```
|
|
22
|
+
* Should extract selection from parent `strong`
|
|
23
|
+
* ```html
|
|
24
24
|
* `<strong><span>some</span></strong><strong><span><font>SELECTED</font></span></strong><strong><span>test</span></strong>
|
|
25
25
|
* ```
|
|
26
26
|
*/
|
|
27
|
-
export function
|
|
28
|
-
|
|
27
|
+
export function extractSelectedPart(
|
|
28
|
+
wrapper: HTMLElement,
|
|
29
29
|
font: HTMLElement,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const wrapper = Dom.closest(
|
|
34
|
-
font,
|
|
35
|
-
node => isSuitElement(style, node, true),
|
|
36
|
-
root
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
if (wrapper) {
|
|
40
|
-
if (style.elementIsBlock) {
|
|
41
|
-
return wrapper;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const range = getRange();
|
|
45
|
-
|
|
46
|
-
// Left part
|
|
47
|
-
const leftEdge = Select.isMarker(font.previousSibling)
|
|
48
|
-
? font.previousSibling
|
|
49
|
-
: font;
|
|
50
|
-
|
|
51
|
-
range.setStartBefore(wrapper);
|
|
52
|
-
range.setEndBefore(leftEdge);
|
|
30
|
+
jodit: IJodit
|
|
31
|
+
): void {
|
|
32
|
+
const range = jodit.s.createRange();
|
|
53
33
|
|
|
54
|
-
|
|
34
|
+
// Left part
|
|
35
|
+
const leftEdge = Select.isMarker(font.previousSibling)
|
|
36
|
+
? font.previousSibling
|
|
37
|
+
: font;
|
|
55
38
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
? font.nextSibling
|
|
59
|
-
: font;
|
|
39
|
+
range.setStartBefore(wrapper);
|
|
40
|
+
range.setEndBefore(leftEdge);
|
|
60
41
|
|
|
61
|
-
|
|
62
|
-
range.setEndAfter(wrapper);
|
|
42
|
+
extractAndMove(wrapper, range, true);
|
|
63
43
|
|
|
64
|
-
|
|
44
|
+
// Right part
|
|
45
|
+
const rightEdge = Select.isMarker(font.nextSibling)
|
|
46
|
+
? font.nextSibling
|
|
47
|
+
: font;
|
|
65
48
|
|
|
66
|
-
|
|
67
|
-
|
|
49
|
+
range.setStartAfter(rightEdge);
|
|
50
|
+
range.setEndAfter(wrapper);
|
|
68
51
|
|
|
69
|
-
|
|
52
|
+
extractAndMove(wrapper, range, false);
|
|
70
53
|
}
|
|
71
54
|
|
|
72
55
|
/**
|
|
@@ -0,0 +1,66 @@
|
|
|
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-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { CanUndef, IDictionary } from '../../../../types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A state machine implementation for applying styles.
|
|
11
|
+
*/
|
|
12
|
+
export class FiniteStateMachine {
|
|
13
|
+
setState(state: string, subState?: string): void {
|
|
14
|
+
this.state = state;
|
|
15
|
+
|
|
16
|
+
if (subState != null) {
|
|
17
|
+
this.subState = subState;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private subState: string = '';
|
|
22
|
+
|
|
23
|
+
getState(): string {
|
|
24
|
+
return this.state;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
getSubState(): string {
|
|
28
|
+
return this.subState;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
private silent: boolean = true;
|
|
32
|
+
disableSilent(): void {
|
|
33
|
+
this.silent = false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
constructor(
|
|
37
|
+
private state: string,
|
|
38
|
+
private readonly transitions: IDictionary<
|
|
39
|
+
IDictionary<(this: FiniteStateMachine, ...attrs: any[]) => any>
|
|
40
|
+
>
|
|
41
|
+
) {}
|
|
42
|
+
|
|
43
|
+
dispatch<T>(actionName: string, ...attrs: any[]): CanUndef<T> {
|
|
44
|
+
const action = this.transitions[this.state][actionName];
|
|
45
|
+
|
|
46
|
+
if (action) {
|
|
47
|
+
if (!this.silent) {
|
|
48
|
+
console.log('State: ' + this.state, 'Action: ' + actionName);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const res = action.call(this, ...attrs);
|
|
52
|
+
|
|
53
|
+
if (!this.silent) {
|
|
54
|
+
console.log('State: ' + this.state);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return <T>res;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!this.silent) {
|
|
61
|
+
throw new Error('invalid action: ' + this.state + '.' + actionName);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -25,7 +25,7 @@ export function getSuitParent(
|
|
|
25
25
|
const { parentNode } = node;
|
|
26
26
|
|
|
27
27
|
if (
|
|
28
|
-
parentNode &&
|
|
28
|
+
Dom.isHTMLElement(parentNode) &&
|
|
29
29
|
!Dom.next(node, isNormalNode, parentNode) &&
|
|
30
30
|
!Dom.prev(node, isNormalNode, parentNode) &&
|
|
31
31
|
isSuitElement(style, parentNode, false) &&
|
|
@@ -4,11 +4,18 @@
|
|
|
4
4
|
* Copyright (c) 2013-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
export * from './
|
|
7
|
+
export * from './toggle/toggle-css';
|
|
8
|
+
export * from './toggle/toggle-ordered-list';
|
|
9
|
+
export * from './element-has-same-style';
|
|
10
|
+
export * from './extract';
|
|
11
|
+
export * from './finite-state-machine';
|
|
8
12
|
export * from './get-suit-child';
|
|
9
|
-
export * from './
|
|
10
|
-
export * from './
|
|
13
|
+
export * from './get-suit-parent';
|
|
14
|
+
export * from './is-inside-invisible-element';
|
|
15
|
+
export * from './is-normal-node';
|
|
16
|
+
export * from './is-suit-element';
|
|
17
|
+
export * from './toggle-commit-styles';
|
|
11
18
|
export * from './unwrap-children';
|
|
19
|
+
export * from './wrap-and-commit-style';
|
|
20
|
+
export * from './wrap-ordered-list';
|
|
12
21
|
export * from './wrap-unwrapped-text';
|
|
13
|
-
export * from './post-process-list-element';
|
|
14
|
-
export * from './toggle-styles';
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
import type { Nullable } from '../../../../types';
|
|
7
7
|
import type { CommitStyle } from '../commit-style';
|
|
8
8
|
import { isNormalNode } from './is-normal-node';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
elementHasSameStyle,
|
|
11
|
+
elementHasSameStyleKeys
|
|
12
|
+
} from './element-has-same-style';
|
|
10
13
|
import { Dom } from '../../../dom';
|
|
11
14
|
|
|
12
15
|
/**
|
|
@@ -33,7 +36,9 @@ export function isSuitElement(
|
|
|
33
36
|
options.style && elementHasSameStyle(elm, options.style)
|
|
34
37
|
);
|
|
35
38
|
|
|
36
|
-
const elmIsSame =
|
|
39
|
+
const elmIsSame =
|
|
40
|
+
elm.nodeName.toLowerCase() === element ||
|
|
41
|
+
(Dom.isTag(elm, ['ul', 'ol']) && commitStyle.elementIsList);
|
|
37
42
|
|
|
38
43
|
if (
|
|
39
44
|
((!elementIsDefault || !strict) && elmIsSame) ||
|
|
@@ -42,9 +47,35 @@ export function isSuitElement(
|
|
|
42
47
|
return true;
|
|
43
48
|
}
|
|
44
49
|
|
|
45
|
-
|
|
46
|
-
|
|
50
|
+
return Boolean(
|
|
51
|
+
!elmIsSame && !strict && elementIsDefault && Dom.isInlineBlock(elm)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Внутри родительского элемента есть блок с теми же стилями
|
|
57
|
+
* @example
|
|
58
|
+
* For selection:
|
|
59
|
+
* ```html
|
|
60
|
+
* <p>|test<strong>test</strong>|</p>
|
|
61
|
+
* ```
|
|
62
|
+
* Apply `{element:'strong'}`
|
|
63
|
+
*/
|
|
64
|
+
export function isSameStyleChild(
|
|
65
|
+
commitStyle: CommitStyle,
|
|
66
|
+
elm: Nullable<Node>
|
|
67
|
+
): elm is HTMLElement {
|
|
68
|
+
const { element, options } = commitStyle;
|
|
69
|
+
|
|
70
|
+
if (!elm || !isNormalNode(elm)) {
|
|
71
|
+
return false;
|
|
47
72
|
}
|
|
48
73
|
|
|
49
|
-
|
|
74
|
+
const elmIsSame = elm.nodeName.toLowerCase() === element;
|
|
75
|
+
|
|
76
|
+
const elmHasSameStyle = Boolean(
|
|
77
|
+
options.style && elementHasSameStyleKeys(elm, options.style)
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
return elmIsSame && elmHasSameStyle;
|
|
50
81
|
}
|