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.
Files changed (180) hide show
  1. package/.github/workflows/tests.yml +23 -0
  2. package/.idea/dictionaries/v_chupurnov.xml +1 -0
  3. package/.idea/workspace.xml +340 -298
  4. package/CHANGELOG.MD +132 -24
  5. package/README.md +3 -4
  6. package/build/jodit.css +92 -34
  7. package/build/jodit.es2018.css +65 -30
  8. package/build/jodit.es2018.en.css +65 -30
  9. package/build/jodit.es2018.en.js +1214 -693
  10. package/build/jodit.es2018.en.min.css +1 -1
  11. package/build/jodit.es2018.en.min.js +1 -1
  12. package/build/jodit.es2018.js +1214 -693
  13. package/build/jodit.es2018.min.css +1 -1
  14. package/build/jodit.es2018.min.js +1 -1
  15. package/build/jodit.js +2271 -1628
  16. package/build/jodit.min.css +2 -2
  17. package/build/jodit.min.js +1 -1
  18. package/index.d.ts +10 -0
  19. package/package.json +14 -13
  20. package/src/config.ts +1 -1
  21. package/src/core/async.ts +7 -5
  22. package/src/core/constants.ts +2 -0
  23. package/src/core/dom.ts +123 -102
  24. package/src/core/events/{events-native.ts → event-emitter.ts} +14 -9
  25. package/src/core/events/index.ts +1 -1
  26. package/src/core/global.ts +2 -2
  27. package/src/core/helpers/array/to-array.ts +1 -0
  28. package/src/core/helpers/data-bind.ts +2 -2
  29. package/src/core/helpers/size/index.ts +1 -0
  30. package/src/core/helpers/size/object-size.ts +22 -0
  31. package/src/core/helpers/utils/utils.ts +20 -4
  32. package/src/core/request/ajax.ts +212 -0
  33. package/src/core/request/config.ts +37 -0
  34. package/{build-system/minimizer/index.js → src/core/request/index.ts} +2 -1
  35. package/src/core/request/response.ts +39 -0
  36. package/src/core/selection/select.ts +60 -27
  37. package/src/core/selection/style/api/element-has-same-style.ts +13 -0
  38. package/src/core/selection/style/api/{get-closest-wrapper.ts → extract.ts} +26 -43
  39. package/src/core/selection/style/api/finite-state-machine.ts +66 -0
  40. package/src/core/selection/style/api/get-suit-parent.ts +1 -1
  41. package/src/core/selection/style/api/index.ts +12 -5
  42. package/src/core/selection/style/api/{check-special-elements.ts → is-inside-invisible-element.ts} +1 -1
  43. package/src/core/selection/style/api/is-suit-element.ts +36 -5
  44. package/src/core/selection/style/api/toggle/toggle-css.ts +134 -0
  45. package/src/core/selection/style/api/toggle/toggle-ordered-list.ts +49 -0
  46. package/src/core/selection/style/api/toggle-commit-styles.ts +27 -0
  47. package/src/core/selection/style/api/unwrap-children.ts +45 -16
  48. package/src/core/selection/style/api/wrap-and-commit-style.ts +68 -0
  49. package/src/core/selection/style/api/wrap-ordered-list.ts +37 -0
  50. package/src/core/selection/style/api/wrap-unwrapped-text.ts +29 -27
  51. package/src/core/selection/style/apply-style.ts +161 -91
  52. package/src/core/selection/style/commit-style.ts +13 -0
  53. package/src/core/traits/elms.ts +1 -0
  54. package/src/core/ui/button/button/button.less +2 -0
  55. package/src/core/ui/helpers/buttons.ts +14 -6
  56. package/src/core/ui/helpers/get-control-type.ts +3 -1
  57. package/src/core/ui/list/list.less +1 -0
  58. package/src/core/ui/popup/popup.less +5 -3
  59. package/src/core/view/view-with-toolbar.ts +4 -0
  60. package/src/core/view/view.ts +3 -3
  61. package/src/modules/context-menu/context-menu.ts +1 -1
  62. package/src/modules/file-browser/README.MD +1 -1
  63. package/src/modules/file-browser/data-provider.ts +22 -42
  64. package/src/modules/file-browser/file-browser.ts +3 -0
  65. package/src/modules/index.ts +1 -1
  66. package/src/modules/status-bar/status-bar.less +27 -1
  67. package/src/modules/status-bar/status-bar.ts +15 -1
  68. package/src/modules/table.ts +197 -168
  69. package/src/modules/uploader/uploader.ts +4 -3
  70. package/src/modules/widget/tabs/tabs.less +1 -0
  71. package/src/plugins/bold.ts +2 -2
  72. package/src/plugins/fix/clean-html.ts +37 -16
  73. package/src/plugins/font.ts +11 -1
  74. package/src/plugins/indent.ts +25 -18
  75. package/src/plugins/index.ts +1 -0
  76. package/src/plugins/mobile.ts +10 -14
  77. package/src/plugins/ordered-list.ts +40 -1
  78. package/src/plugins/powered-by-jodit.ts +39 -0
  79. package/src/plugins/print/preview.ts +9 -2
  80. package/src/plugins/resizer/resizer.less +10 -7
  81. package/src/plugins/resizer/resizer.ts +12 -14
  82. package/src/plugins/size/assests/resize-handler.svg +4 -0
  83. package/src/plugins/size/resize-handler.ts +5 -5
  84. package/src/plugins/size/size.less +6 -8
  85. package/src/plugins/size/size.ts +1 -3
  86. package/src/plugins/source/source.ts +16 -2
  87. package/src/plugins/table/config.ts +3 -1
  88. package/src/plugins/table/select-cells.ts +23 -5
  89. package/src/plugins/table/table.less +0 -1
  90. package/src/styles/themes/dark.less +11 -1
  91. package/src/types/ajax.d.ts +15 -6
  92. package/src/types/async.d.ts +5 -4
  93. package/src/types/events.d.ts +12 -12
  94. package/src/types/style.d.ts +2 -0
  95. package/src/types/toolbar.d.ts +2 -1
  96. package/src/types/view.d.ts +3 -2
  97. package/types/core/async.d.ts +3 -3
  98. package/types/core/constants.d.ts +1 -0
  99. package/types/core/dom.d.ts +27 -20
  100. package/types/core/events/{events-native.d.ts → event-emitter.d.ts} +8 -3
  101. package/types/core/events/index.d.ts +1 -1
  102. package/types/core/global.d.ts +2 -2
  103. package/types/core/helpers/size/index.d.ts +1 -0
  104. package/{src/types/core.js → types/core/helpers/size/object-size.d.ts} +2 -3
  105. package/types/core/helpers/utils/utils.d.ts +12 -4
  106. package/types/core/{ajax.d.ts → request/ajax.d.ts} +5 -15
  107. package/types/core/request/config.d.ts +14 -0
  108. package/{build-system/rules/css.js → types/core/request/index.d.ts} +2 -7
  109. package/types/core/request/response.d.ts +16 -0
  110. package/types/core/selection/style/api/element-has-same-style.d.ts +4 -0
  111. package/types/core/selection/style/api/{get-closest-wrapper.d.ts → extract.d.ts} +6 -5
  112. package/types/core/selection/style/api/finite-state-machine.d.ts +21 -0
  113. package/types/core/selection/style/api/index.d.ts +12 -5
  114. package/types/core/selection/style/api/{check-special-elements.d.ts → is-inside-invisible-element.d.ts} +1 -1
  115. package/types/core/selection/style/api/is-suit-element.d.ts +10 -0
  116. package/types/core/selection/style/api/toggle/toggle-css.d.ts +11 -0
  117. package/types/core/selection/style/api/toggle/toggle-ordered-list.d.ts +11 -0
  118. package/types/core/selection/style/api/{toggle-styles.d.ts → toggle-commit-styles.d.ts} +1 -3
  119. package/types/core/selection/style/api/{post-process-list-element.d.ts → wrap-and-commit-style.d.ts} +3 -3
  120. package/types/core/selection/style/api/wrap-ordered-list.d.ts +12 -0
  121. package/types/core/selection/style/api/wrap-unwrapped-text.d.ts +2 -2
  122. package/types/core/selection/style/apply-style.d.ts +1 -4
  123. package/types/core/selection/style/commit-style.d.ts +7 -0
  124. package/types/core/ui/helpers/buttons.d.ts +2 -2
  125. package/types/core/view/view-with-toolbar.d.ts +2 -1
  126. package/types/core/view/view.d.ts +2 -2
  127. package/types/modules/file-browser/data-provider.d.ts +1 -1
  128. package/types/modules/index.d.ts +1 -1
  129. package/types/modules/status-bar/status-bar.d.ts +6 -1
  130. package/types/modules/table.d.ts +2 -2
  131. package/types/plugins/fix/clean-html.d.ts +4 -0
  132. package/types/plugins/index.d.ts +1 -0
  133. package/types/plugins/ordered-list.d.ts +8 -1
  134. package/{build-system/plugins/banner.js → types/plugins/powered-by-jodit.d.ts} +7 -10
  135. package/types/plugins/size/resize-handler.d.ts +1 -1
  136. package/types/plugins/source/source.d.ts +1 -1
  137. package/types/types/ajax.d.ts +15 -6
  138. package/types/types/async.d.ts +5 -4
  139. package/types/types/events.d.ts +12 -12
  140. package/types/types/style.d.ts +2 -0
  141. package/types/types/toolbar.d.ts +2 -1
  142. package/types/types/view.d.ts +3 -2
  143. package/.editorconfig +0 -15
  144. package/.eslintignore +0 -3
  145. package/.eslintrc.js +0 -109
  146. package/.prettierrc.json +0 -9
  147. package/.stylelintrc.json +0 -16
  148. package/app.css +0 -112
  149. package/build-system/index.js +0 -78
  150. package/build-system/loaders/css-variables-prefixes.js +0 -12
  151. package/build-system/loaders/lang-loader.js +0 -57
  152. package/build-system/loaders/style.js +0 -31
  153. package/build-system/loaders/svg-loader.js +0 -21
  154. package/build-system/minimizer/css.js +0 -20
  155. package/build-system/minimizer/js.js +0 -41
  156. package/build-system/plugins/define.js +0 -22
  157. package/build-system/plugins/extract-css.js +0 -21
  158. package/build-system/plugins/index.js +0 -31
  159. package/build-system/plugins/post-build.js +0 -52
  160. package/build-system/rules/extra-typescript.js +0 -22
  161. package/build-system/rules/index.js +0 -17
  162. package/build-system/rules/internal-typescript.js +0 -23
  163. package/build-system/rules/langs.js +0 -20
  164. package/build-system/rules/svg.js +0 -16
  165. package/build-system/utils/filename.js +0 -14
  166. package/build-system/utils/post-build.js +0 -28
  167. package/build-system/variables.js +0 -51
  168. package/composer.json +0 -12
  169. package/src/core/ajax.ts +0 -269
  170. package/src/core/selection/style/api/post-process-list-element.ts +0 -33
  171. package/src/core/selection/style/api/toggle-styles.ts +0 -74
  172. package/src/types/core.d.ts +0 -7
  173. package/src/types/core.js.map +0 -1
  174. package/src/types/storage.d.ts +0 -13
  175. package/src/types/storage.js +0 -8
  176. package/src/types/storage.js.map +0 -1
  177. package/types/types/core.js +0 -8
  178. package/types/types/core.js.map +0 -1
  179. package/types/types/storage.js +0 -8
  180. 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;
@@ -4,4 +4,5 @@
4
4
  * Copyright (c) 2013-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
6
 
7
- module.exports = [require('./js'), require('./css')];
7
+ export * from './ajax';
8
+ export * from './response';
@@ -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 = this.area.childNodes.length,
766
- elementOffset = startOffset < length ? startOffset : length - 1,
767
- start: Node =
772
+ length = root.childNodes.length,
773
+ elementOffset = startOffset < length ? startOffset : length - 1;
774
+
775
+ let start: Node =
768
776
  range.startContainer === this.area
769
- ? this.area.childNodes[elementOffset]
777
+ ? root.childNodes[elementOffset]
770
778
  : range.startContainer,
771
779
  end: Node =
772
780
  range.endContainer === this.area
773
- ? this.area.childNodes[range.endOffset - 1]
781
+ ? root.childNodes[range.endOffset - 1]
774
782
  : range.endContainer;
775
783
 
776
- Dom.find(
777
- start,
778
- (node: Node | null) => {
779
- if (
780
- node &&
781
- node !== this.area &&
782
- !Dom.isEmptyTextNode(node) &&
783
- !Select.isMarker(node as HTMLElement)
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
- // checks parentElement as well because partial selections are not equal to entire element
789
- return (
790
- node === end ||
791
- (node && node.contains && node.contains(end))
792
- );
793
- },
794
- this.area,
795
- true,
796
- 'nextSibling',
797
- false
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 { CommitStyle } from '../commit-style';
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
- * to
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 getClosestWrapper(
28
- style: CommitStyle,
27
+ export function extractSelectedPart(
28
+ wrapper: HTMLElement,
29
29
  font: HTMLElement,
30
- root: HTMLElement,
31
- getRange: () => Range
32
- ): Nullable<HTMLElement> {
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
- extractAndMove(wrapper, range, true);
34
+ // Left part
35
+ const leftEdge = Select.isMarker(font.previousSibling)
36
+ ? font.previousSibling
37
+ : font;
55
38
 
56
- // Right part
57
- const rightEdge = Select.isMarker(font.nextSibling)
58
- ? font.nextSibling
59
- : font;
39
+ range.setStartBefore(wrapper);
40
+ range.setEndBefore(leftEdge);
60
41
 
61
- range.setStartAfter(rightEdge);
62
- range.setEndAfter(wrapper);
42
+ extractAndMove(wrapper, range, true);
63
43
 
64
- extractAndMove(wrapper, range, false);
44
+ // Right part
45
+ const rightEdge = Select.isMarker(font.nextSibling)
46
+ ? font.nextSibling
47
+ : font;
65
48
 
66
- return wrapper;
67
- }
49
+ range.setStartAfter(rightEdge);
50
+ range.setEndAfter(wrapper);
68
51
 
69
- return null;
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 './get-suit-parent';
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 './check-special-elements';
10
- export * from './get-closest-wrapper';
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';
@@ -9,7 +9,7 @@ import { Dom } from '../../../dom';
9
9
  /**
10
10
  * Check if FONT inside STYLE or SCRIPT element
11
11
  */
12
- export function checkSpecialElements(
12
+ export function isInsideInvisibleElement(
13
13
  font: HTMLElement,
14
14
  root: HTMLElement
15
15
  ): boolean {
@@ -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 { elementHasSameStyle } from './element-has-same-style';
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 = elm.nodeName.toLowerCase() === element;
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
- if (!elmIsSame && !strict && elementIsDefault && Dom.isInlineBlock(elm)) {
46
- return true;
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
- return false;
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
  }