jodit 3.9.3 → 3.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/.idea/workspace.xml +306 -295
  2. package/CHANGELOG.MD +349 -119
  3. package/build/jodit.css +675 -538
  4. package/build/jodit.es2018.css +536 -436
  5. package/build/jodit.es2018.en.css +536 -436
  6. package/build/jodit.es2018.en.js +1529 -738
  7. package/build/jodit.es2018.en.min.css +1 -1
  8. package/build/jodit.es2018.en.min.js +1 -1
  9. package/build/jodit.es2018.js +1533 -742
  10. package/build/jodit.es2018.min.css +1 -1
  11. package/build/jodit.es2018.min.js +1 -1
  12. package/build/jodit.js +2598 -1680
  13. package/build/jodit.min.css +2 -2
  14. package/build/jodit.min.js +1 -1
  15. package/index.d.ts +10 -0
  16. package/package.json +10 -10
  17. package/src/config.ts +19 -20
  18. package/src/core/component/component.ts +16 -15
  19. package/src/core/component/statuses.ts +6 -6
  20. package/src/core/dom.ts +16 -4
  21. package/src/core/events/event-emitter.ts +4 -2
  22. package/src/core/global.ts +13 -2
  23. package/src/core/helpers/append-script.ts +14 -0
  24. package/src/core/helpers/selector.ts +8 -3
  25. package/src/core/helpers/size/index.ts +1 -0
  26. package/src/core/helpers/size/object-size.ts +22 -0
  27. package/src/core/selection/select.ts +1 -0
  28. package/src/core/selection/style/api/{get-closest-wrapper.ts → extract.ts} +26 -43
  29. package/src/core/selection/style/api/finite-state-machine.ts +66 -0
  30. package/src/core/selection/style/api/index.ts +12 -5
  31. package/src/core/selection/style/api/{check-special-elements.ts → is-inside-invisible-element.ts} +1 -1
  32. package/src/core/selection/style/api/is-suit-element.ts +12 -1
  33. package/src/core/selection/style/api/toggle/toggle-css.ts +134 -0
  34. package/src/core/selection/style/api/toggle/toggle-ordered-list.ts +49 -0
  35. package/src/core/selection/style/api/toggle-commit-styles.ts +27 -0
  36. package/src/core/selection/style/api/wrap-and-commit-style.ts +68 -0
  37. package/src/core/selection/style/api/wrap-ordered-list.ts +37 -0
  38. package/src/core/selection/style/api/wrap-unwrapped-text.ts +1 -4
  39. package/src/core/selection/style/apply-style.ts +161 -97
  40. package/src/core/selection/style/commit-style.ts +13 -0
  41. package/src/core/storage/engines/local-storage-provider.ts +9 -3
  42. package/src/core/storage/engines/memory-storage-provider.ts +6 -3
  43. package/src/core/storage/storage.ts +7 -4
  44. package/src/core/ui/button/button/button.less +10 -8
  45. package/src/core/ui/button/button/button.ts +9 -9
  46. package/src/core/ui/button/group/group.ts +2 -2
  47. package/src/core/ui/element.ts +4 -3
  48. package/src/core/ui/form/block/block.ts +1 -1
  49. package/src/core/ui/form/form.ts +8 -0
  50. package/src/core/ui/form/inputs/area/area.less +5 -0
  51. package/src/core/ui/form/inputs/area/area.ts +22 -1
  52. package/src/core/ui/form/inputs/checkbox/checkbox.less +50 -0
  53. package/src/core/ui/form/inputs/checkbox/checkbox.ts +48 -4
  54. package/src/core/ui/form/inputs/input/input.less +1 -1
  55. package/src/core/ui/form/inputs/input/input.ts +14 -4
  56. package/src/core/ui/helpers/buttons.ts +14 -6
  57. package/src/core/ui/icon.ts +3 -1
  58. package/src/core/ui/index.ts +1 -3
  59. package/src/core/ui/list/group.less +8 -2
  60. package/src/core/ui/list/group.ts +2 -2
  61. package/src/{modules/file-browser/consts.ts → core/ui/list/index.ts} +4 -4
  62. package/src/core/ui/list/list.less +10 -1
  63. package/src/core/ui/list/list.ts +20 -3
  64. package/src/core/ui/{separator.ts → list/separator.ts} +2 -2
  65. package/src/core/ui/list/spacer.ts +15 -0
  66. package/src/core/ui/popup/popup.less +5 -3
  67. package/src/core/ui/popup/popup.ts +53 -1
  68. package/src/core/view/view-with-toolbar.ts +6 -1
  69. package/src/jodit.ts +17 -14
  70. package/src/modules/dialog/dialog.less +1 -16
  71. package/src/modules/dialog/dialog.ts +10 -3
  72. package/src/modules/file-browser/builders/context-menu.ts +29 -22
  73. package/src/modules/file-browser/config.ts +10 -2
  74. package/src/modules/file-browser/file-browser.ts +50 -29
  75. package/src/modules/file-browser/listeners/native-listeners.ts +37 -19
  76. package/src/modules/file-browser/listeners/state-listeners.ts +48 -22
  77. package/src/modules/file-browser/styles/file-browser.less +4 -291
  78. package/src/modules/file-browser/styles/preview.less +11 -8
  79. package/src/modules/file-browser/ui/files/files.less +174 -0
  80. package/src/modules/file-browser/ui/files/files.ts +14 -0
  81. package/src/modules/file-browser/ui/index.ts +8 -0
  82. package/src/modules/file-browser/ui/tree/tree.less +118 -0
  83. package/src/modules/file-browser/ui/tree/tree.ts +14 -0
  84. package/src/modules/status-bar/status-bar.less +27 -1
  85. package/src/modules/status-bar/status-bar.ts +15 -1
  86. package/src/modules/toolbar/collection/collection.ts +17 -8
  87. package/src/modules/toolbar/collection/editor-collection.ts +27 -2
  88. package/src/modules/widget/file-selector/file-selector.ts +1 -1
  89. package/src/modules/widget/tabs/tabs.less +2 -1
  90. package/src/modules/widget/tabs/tabs.ts +5 -3
  91. package/src/plugins/add-new-line/add-new-line.ts +1 -0
  92. package/src/plugins/bold.ts +2 -2
  93. package/src/plugins/clipboard/drag-and-drop.ts +4 -1
  94. package/src/plugins/clipboard/paste/paste.ts +1 -1
  95. package/src/plugins/font.ts +11 -1
  96. package/src/plugins/image/image-properties/image-properties.ts +7 -0
  97. package/src/plugins/index.ts +1 -0
  98. package/src/plugins/inline-popup/config/config.ts +1 -0
  99. package/src/plugins/inline-popup/config/items/toolbar.ts +33 -0
  100. package/src/plugins/inline-popup/inline-popup.ts +17 -0
  101. package/src/plugins/keyboard/delete.ts +30 -8
  102. package/src/plugins/link/template.ts +2 -2
  103. package/src/plugins/mobile.ts +10 -14
  104. package/src/plugins/ordered-list.ts +40 -1
  105. package/src/plugins/powered-by-jodit.ts +39 -0
  106. package/src/plugins/print/preview.ts +103 -48
  107. package/src/plugins/resizer/resizer.less +10 -7
  108. package/src/plugins/resizer/resizer.ts +12 -14
  109. package/src/plugins/size/resize-handler.ts +4 -1
  110. package/src/plugins/size/size.less +2 -19
  111. package/src/plugins/size/size.ts +6 -1
  112. package/src/plugins/source/const.ts +7 -0
  113. package/src/plugins/source/editor/engines/ace.ts +5 -0
  114. package/src/plugins/source/source.ts +33 -7
  115. package/src/plugins/sticky/sticky.ts +2 -0
  116. package/src/styles/icons/index.ts +2 -0
  117. package/src/styles/icons/resize-handler.svg +4 -0
  118. package/src/styles/jodit.less +6 -0
  119. package/src/styles/mixins.less +20 -0
  120. package/src/styles/themes/dark.less +11 -1
  121. package/src/types/ajax.d.ts +0 -1
  122. package/src/types/file-browser.d.ts +13 -1
  123. package/src/types/jodit.d.ts +4 -1
  124. package/src/types/popup.d.ts +1 -0
  125. package/src/types/select.d.ts +2 -0
  126. package/src/types/storage.ts +3 -3
  127. package/src/types/style.d.ts +8 -0
  128. package/src/types/toolbar.d.ts +9 -2
  129. package/src/types/types.d.ts +1 -1
  130. package/src/types/ui.d.ts +23 -4
  131. package/src/types/view.d.ts +1 -0
  132. package/types/core/component/component.d.ts +10 -5
  133. package/types/core/component/statuses.d.ts +6 -6
  134. package/types/core/dom.d.ts +3 -2
  135. package/types/core/helpers/append-script.d.ts +1 -0
  136. package/types/core/helpers/selector.d.ts +2 -3
  137. package/types/core/helpers/size/index.d.ts +1 -0
  138. package/types/core/helpers/size/object-size.d.ts +7 -0
  139. package/types/core/selection/style/api/{get-closest-wrapper.d.ts → extract.d.ts} +6 -5
  140. package/types/core/selection/style/api/finite-state-machine.d.ts +21 -0
  141. package/types/core/selection/style/api/index.d.ts +12 -5
  142. package/types/core/selection/style/api/{check-special-elements.d.ts → is-inside-invisible-element.d.ts} +1 -1
  143. package/types/core/selection/style/api/is-suit-element.d.ts +9 -0
  144. package/types/core/selection/style/api/toggle/toggle-css.d.ts +11 -0
  145. package/types/core/selection/style/api/toggle/toggle-ordered-list.d.ts +11 -0
  146. package/types/core/selection/style/api/{toggle-styles.d.ts → toggle-commit-styles.d.ts} +1 -3
  147. package/types/core/selection/style/api/{post-process-list-element.d.ts → wrap-and-commit-style.d.ts} +3 -3
  148. package/types/core/selection/style/api/wrap-ordered-list.d.ts +12 -0
  149. package/types/core/selection/style/apply-style.d.ts +1 -4
  150. package/types/core/selection/style/commit-style.d.ts +7 -0
  151. package/types/core/storage/engines/local-storage-provider.d.ts +3 -3
  152. package/types/core/storage/engines/memory-storage-provider.d.ts +3 -3
  153. package/types/core/storage/storage.d.ts +3 -3
  154. package/types/core/ui/button/button/button.d.ts +3 -3
  155. package/types/core/ui/form/form.d.ts +1 -0
  156. package/types/core/ui/form/inputs/area/area.d.ts +7 -1
  157. package/types/core/ui/form/inputs/checkbox/checkbox.d.ts +10 -3
  158. package/types/core/ui/helpers/buttons.d.ts +2 -2
  159. package/types/core/ui/icon.d.ts +1 -1
  160. package/types/core/ui/index.d.ts +1 -3
  161. package/types/core/ui/list/group.d.ts +2 -1
  162. package/types/core/ui/list/index.d.ts +9 -0
  163. package/types/core/ui/{separator.d.ts → list/separator.d.ts} +1 -1
  164. package/types/core/ui/list/spacer.d.ts +9 -0
  165. package/types/core/ui/popup/popup.d.ts +2 -1
  166. package/types/core/view/view-with-toolbar.d.ts +4 -2
  167. package/types/jodit.d.ts +6 -6
  168. package/types/modules/file-browser/file-browser.d.ts +3 -2
  169. package/types/modules/file-browser/listeners/native-listeners.d.ts +5 -1
  170. package/types/modules/file-browser/ui/files/files.d.ts +10 -0
  171. package/types/modules/file-browser/ui/index.d.ts +7 -0
  172. package/types/modules/file-browser/ui/tree/tree.d.ts +10 -0
  173. package/types/modules/status-bar/status-bar.d.ts +6 -1
  174. package/types/modules/toolbar/button/button.d.ts +1 -1
  175. package/types/modules/toolbar/collection/collection.d.ts +5 -2
  176. package/types/modules/toolbar/collection/editor-collection.d.ts +9 -1
  177. package/types/modules/widget/tabs/tabs.d.ts +2 -1
  178. package/types/plugins/index.d.ts +1 -0
  179. package/types/plugins/inline-popup/inline-popup.d.ts +4 -0
  180. package/types/plugins/keyboard/delete.d.ts +2 -0
  181. package/types/plugins/ordered-list.d.ts +8 -1
  182. package/types/plugins/powered-by-jodit.d.ts +12 -0
  183. package/types/plugins/source/const.d.ts +6 -0
  184. package/types/plugins/source/editor/engines/ace.d.ts +1 -0
  185. package/types/plugins/source/source.d.ts +1 -0
  186. package/types/styles/icons/index.d.ts +2 -1
  187. package/types/types/storage.d.ts +3 -3
  188. package/types/types/{ajax.d.ts → types/ajax.d.ts} +0 -1
  189. package/types/types/{async.d.ts → types/async.d.ts} +0 -0
  190. package/types/types/{context.d.ts → types/context.d.ts} +0 -0
  191. package/types/types/{core.ts → types/core.ts} +0 -0
  192. package/types/types/{create.d.ts → types/create.d.ts} +0 -0
  193. package/types/types/{dialog.d.ts → types/dialog.d.ts} +0 -0
  194. package/types/types/{events.d.ts → types/events.d.ts} +0 -0
  195. package/types/types/{file-browser.d.ts → types/file-browser.d.ts} +13 -1
  196. package/types/types/{form.d.ts → types/form.d.ts} +0 -0
  197. package/types/types/{index.d.ts → types/index.d.ts} +0 -0
  198. package/types/types/{jodit.d.ts → types/jodit.d.ts} +4 -1
  199. package/types/types/{observe.d.ts → types/observe.d.ts} +0 -0
  200. package/types/types/{plugin.d.ts → types/plugin.d.ts} +0 -0
  201. package/types/types/{popup.d.ts → types/popup.d.ts} +1 -0
  202. package/types/types/{select.d.ts → types/select.d.ts} +2 -0
  203. package/types/types/{source.d.ts → types/source.d.ts} +0 -0
  204. package/types/types/{storage.ts → types/storage.ts} +3 -3
  205. package/types/types/{style.d.ts → types/style.d.ts} +8 -0
  206. package/types/types/{toolbar.d.ts → types/toolbar.d.ts} +9 -2
  207. package/types/types/{traits.d.ts → types/traits.d.ts} +0 -0
  208. package/types/types/{types.d.ts → types/types.d.ts} +1 -1
  209. package/types/types/{ui.d.ts → types/ui.d.ts} +23 -4
  210. package/types/types/{uploader.d.ts → types/uploader.d.ts} +0 -0
  211. package/types/types/{view.d.ts → types/view.d.ts} +1 -0
  212. package/src/core/selection/style/api/post-process-list-element.ts +0 -33
  213. package/src/core/selection/style/api/toggle-styles.ts +0 -74
  214. package/types/modules/file-browser/consts.d.ts +0 -8
@@ -0,0 +1,134 @@
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 { CommitMode, IJodit } from '../../../../../types';
8
+ import type { CommitStyle } from '../../commit-style';
9
+ import {
10
+ attr,
11
+ css,
12
+ dataBind,
13
+ kebabCase,
14
+ normalizeCssValue,
15
+ size
16
+ } from '../../../../helpers';
17
+ import { Dom } from '../../../../dom';
18
+ import { CHANGE, UNSET, UNWRAP } from '../../commit-style';
19
+ import { getContainer } from '../../../../global';
20
+
21
+ /**
22
+ * Toggles css and classname
23
+ */
24
+ export function toggleCSS(
25
+ commitStyle: CommitStyle,
26
+ elm: HTMLElement,
27
+ jodit: IJodit,
28
+ mode: CommitMode,
29
+ dry: boolean = false
30
+ ): CommitMode {
31
+ const { style, className } = commitStyle.options;
32
+
33
+ if (style && size(style) > 0) {
34
+ Object.keys(style).forEach((rule: string) => {
35
+ const inlineValue = elm.style.getPropertyValue(kebabCase(rule));
36
+
37
+ if (inlineValue === '' && style[rule] == null) {
38
+ return;
39
+ }
40
+
41
+ if (
42
+ getNativeCSSValue(jodit, elm, rule) ===
43
+ normalizeCssValue(rule, style[rule] as string)
44
+ ) {
45
+ !dry && css(elm, rule, null);
46
+ mode = UNSET;
47
+ mode = removeExtraCSS(commitStyle, elm, mode);
48
+ return;
49
+ }
50
+
51
+ mode = CHANGE;
52
+ !dry && css(elm, rule, style[rule]);
53
+ });
54
+ }
55
+
56
+ if (className) {
57
+ if (elm.classList.contains(className)) {
58
+ elm.classList.remove(className);
59
+ mode = UNSET;
60
+ } else {
61
+ elm.classList.add(className);
62
+ mode = CHANGE;
63
+ }
64
+ }
65
+
66
+ return mode;
67
+ }
68
+
69
+ /**
70
+ * If the element has an empty style attribute, it removes the attribute,
71
+ * and if it is default, it removes the element itself
72
+ */
73
+ function removeExtraCSS(
74
+ commitStyle: CommitStyle,
75
+ elm: HTMLElement,
76
+ mode: CommitMode
77
+ ): CommitMode {
78
+ if (!attr(elm, 'style')) {
79
+ attr(elm, 'style', null);
80
+
81
+ if (elm.tagName.toLowerCase() === commitStyle.defaultTag) {
82
+ Dom.unwrap(elm);
83
+ mode = UNWRAP;
84
+ }
85
+ }
86
+
87
+ return mode;
88
+ }
89
+
90
+ /**
91
+ * Creates an iframe into which elements will be inserted to test their default styles in the browser
92
+ */
93
+ function getShadowRoot(jodit: IJodit): HTMLElement {
94
+ if (dataBind(jodit, 'shadowRoot') !== undefined) {
95
+ return dataBind(jodit, 'shadowRoot');
96
+ }
97
+
98
+ const container = getContainer(jodit, function Utils() {});
99
+
100
+ const iframe = document.createElement('iframe');
101
+ css(iframe, {
102
+ width: 0,
103
+ height: 0,
104
+ position: 'absolute',
105
+ border: 0
106
+ });
107
+
108
+ iframe.src = 'about:blank';
109
+ container.appendChild(iframe);
110
+
111
+ const doc = iframe.contentWindow?.document;
112
+
113
+ const shadowRoot = !doc ? jodit.od.body : doc.body;
114
+ dataBind(jodit, 'shadowRoot', shadowRoot);
115
+
116
+ return shadowRoot;
117
+ }
118
+
119
+ /**
120
+ * `strong -> fontWeight 700`
121
+ */
122
+ function getNativeCSSValue(
123
+ jodit: IJodit,
124
+ elm: HTMLElement,
125
+ key: string
126
+ ): ReturnType<typeof css> {
127
+ const newElm = jodit.create.element(elm.tagName.toLowerCase());
128
+ newElm.style.cssText = elm.style.cssText;
129
+ const root = getShadowRoot(jodit);
130
+ root.appendChild(newElm);
131
+ const result = css(newElm, key);
132
+ Dom.safeRemove(newElm);
133
+ return result;
134
+ }
@@ -0,0 +1,49 @@
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 { IJodit, CommitMode } from '../../../../../types';
8
+ import type { CommitStyle } from '../../commit-style';
9
+ import { Dom } from '../../../../dom';
10
+ import { extractSelectedPart } from '../extract';
11
+ import { CHANGE, INITIAL, REPLACE } from '../../commit-style';
12
+ import { toggleCSS } from './toggle-css';
13
+
14
+ /**
15
+ * Replaces `ul->ol` or `ol->ul`, apply styles to the list, or remove a list item from it
16
+ */
17
+ export function toggleOrderedList(
18
+ style: CommitStyle,
19
+ li: HTMLElement,
20
+ jodit: IJodit,
21
+ mode: CommitMode
22
+ ): CommitMode {
23
+ if (!li) {
24
+ return mode;
25
+ }
26
+
27
+ const list = li.parentElement;
28
+
29
+ if (!list) {
30
+ return mode;
31
+ }
32
+
33
+ // ul => ol, ol => ul
34
+ if (list.tagName.toLowerCase() !== style.element) {
35
+ const newList = Dom.replace(list, style.element, jodit.createInside);
36
+ toggleCSS(style, newList, jodit, mode);
37
+ return REPLACE;
38
+ }
39
+
40
+ if (toggleCSS(style, li.parentElement, jodit, INITIAL, true) === CHANGE) {
41
+ return toggleCSS(style, li.parentElement, jodit, mode);
42
+ }
43
+
44
+ extractSelectedPart(list, li, jodit);
45
+ Dom.unwrap(li.parentElement);
46
+ Dom.replace(li, jodit.o.enter, jodit.createInside);
47
+
48
+ return mode;
49
+ }
@@ -0,0 +1,27 @@
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 { CommitStyle } from '../commit-style';
8
+ import { Dom } from '../../../dom';
9
+
10
+ /**
11
+ * Add or remove styles to element
12
+ * @param elm - The element to switch styles
13
+ */
14
+ export function toggleCommitStyles(
15
+ commitStyle: CommitStyle,
16
+ elm: HTMLElement
17
+ ): boolean {
18
+ if (
19
+ commitStyle.elementIsBlock ||
20
+ (Dom.isTag(elm, commitStyle.element) && !commitStyle.elementIsDefault)
21
+ ) {
22
+ Dom.unwrap(elm);
23
+ return true;
24
+ }
25
+
26
+ return false;
27
+ }
@@ -0,0 +1,68 @@
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 { IJodit } from '../../../../types';
8
+ import type { CommitStyle } from '../commit-style';
9
+ import { Dom } from '../../../dom';
10
+ import { wrapUnwrappedText } from './wrap-unwrapped-text';
11
+ import { attr } from '../../../helpers';
12
+ import { wrapOrderedList } from './wrap-ordered-list';
13
+
14
+ /**
15
+ * Replaces the parent tag with the applicable one, or wraps the text and also replaces the tag
16
+ */
17
+ export function wrapAndCommitStyle(
18
+ commitStyle: CommitStyle,
19
+ font: HTMLElement,
20
+ jodit: IJodit
21
+ ): HTMLElement {
22
+ const wrapper = findOrCreateWrapper(commitStyle, font, jodit);
23
+
24
+ return commitStyle.elementIsList
25
+ ? wrapOrderedList(commitStyle, wrapper, jodit)
26
+ : Dom.replace(wrapper, commitStyle.element, jodit.createInside, true);
27
+ }
28
+
29
+ /**
30
+ * If we apply a block element, then it finds the closest block parent (exclude table cell etc.),
31
+ * otherwise it wraps free text in an element.
32
+ */
33
+ function findOrCreateWrapper(
34
+ commitStyle: CommitStyle,
35
+ font: HTMLElement,
36
+ jodit: IJodit
37
+ ): HTMLElement {
38
+ if (commitStyle.elementIsBlock) {
39
+ const box = Dom.up(
40
+ font,
41
+ node =>
42
+ Dom.isBlock(node) &&
43
+ !Dom.isTag(node, [
44
+ 'td',
45
+ 'th',
46
+ 'tr',
47
+ 'tbody',
48
+ 'table',
49
+ 'li',
50
+ 'ul',
51
+ 'ol'
52
+ ]),
53
+ jodit.editor
54
+ );
55
+
56
+ if (box) {
57
+ return box;
58
+ }
59
+ }
60
+
61
+ if (commitStyle.elementIsBlock) {
62
+ return wrapUnwrappedText(commitStyle, font, jodit, jodit.s.createRange);
63
+ }
64
+
65
+ attr(font, 'size', null);
66
+
67
+ return font;
68
+ }
@@ -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 { IJodit } from '../../../../types';
8
+ import { Dom } from '../../../dom';
9
+ import type { CommitStyle } from '../commit-style';
10
+
11
+ /**
12
+ * Replaces non-leaf items with leaf items and either creates a new list or
13
+ * adds a new item to the nearest old list
14
+ */
15
+ export function wrapOrderedList(
16
+ commitStyle: CommitStyle,
17
+ wrapper: HTMLElement,
18
+ jodit: IJodit
19
+ ): HTMLElement {
20
+ const newWrapper = Dom.replace(wrapper, 'li', jodit.createInside);
21
+
22
+ let list =
23
+ newWrapper.previousElementSibling || newWrapper.nextElementSibling;
24
+
25
+ if (!Dom.isTag(list, ['ul', 'ol'])) {
26
+ list = jodit.createInside.element(commitStyle.element);
27
+ Dom.before(newWrapper, list);
28
+ }
29
+
30
+ if (newWrapper.previousElementSibling === list) {
31
+ Dom.append(list, newWrapper);
32
+ } else {
33
+ Dom.prepend(list, newWrapper);
34
+ }
35
+
36
+ return <HTMLElement>list;
37
+ }
@@ -7,7 +7,6 @@
7
7
  import type { IJodit, Nullable } from '../../../../types';
8
8
  import type { CommitStyle } from '../commit-style';
9
9
  import { Dom } from '../../../dom';
10
- import { postProcessListElement } from './post-process-list-element';
11
10
 
12
11
  /**
13
12
  * Wrap text or inline elements inside Block element
@@ -58,13 +57,11 @@ export function wrapUnwrappedText(
58
57
  range.setEndAfter(end);
59
58
  const fragment = range.extractContents();
60
59
 
61
- let wrapper = ci.element(style.element);
60
+ const wrapper = ci.element(style.element);
62
61
  wrapper.appendChild(fragment);
63
62
  range.insertNode(wrapper);
64
63
 
65
64
  if (style.elementIsBlock) {
66
- wrapper = postProcessListElement(style, wrapper, ci);
67
-
68
65
  if (
69
66
  Dom.isEmpty(wrapper) &&
70
67
  !Dom.isTag(wrapper.firstElementChild, 'br')
@@ -4,132 +4,196 @@
4
4
  * Copyright (c) 2013-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
6
 
7
- import type { IJodit, Nullable } from '../../../types';
7
+ import type { IJodit, Nullable, CanUndef, CommitMode } from '../../../types';
8
8
  import type { CommitStyle } from './commit-style';
9
- import { Dom } from '../../dom';
10
- import { attr, css, normalizeNode } from '../../helpers';
9
+ import { normalizeNode } from '../../helpers';
11
10
  import {
12
11
  getSuitParent,
13
12
  getSuitChild,
14
- checkSpecialElements,
15
- getClosestWrapper,
16
- unwrapChildren,
17
- wrapUnwrappedText,
18
- postProcessListElement,
19
- toggleStyles
13
+ isInsideInvisibleElement,
14
+ toggleCommitStyles,
15
+ unwrapChildren
16
+ } from './api';
17
+ import { CHANGE, INITIAL, REPLACE, UNWRAP, WRAP } from './commit-style';
18
+ import { Dom } from '../../dom';
19
+ import {
20
+ toggleOrderedList,
21
+ wrapAndCommitStyle,
22
+ isSuitElement,
23
+ extractSelectedPart,
24
+ toggleCSS,
25
+ FiniteStateMachine
20
26
  } from './api';
21
27
 
22
- /**
23
- * Apply options to selection
24
- */
25
- export function ApplyStyle(jodit: IJodit, style: CommitStyle): void {
26
- const { s: sel } = jodit,
27
- rng = () => sel.createRange();
28
+ export function ApplyStyle(jodit: IJodit, cs: CommitStyle): void {
29
+ const { s: sel, editor } = jodit;
30
+
31
+ const fsm = new FiniteStateMachine('start', {
32
+ start: {
33
+ start() {
34
+ sel.save();
35
+ normalizeNode(editor.firstChild); // FF fix for test "commandsTest - Exec command "bold"
36
+ this.setState('generator');
37
+ }
38
+ },
39
+
40
+ generator: {
41
+ initGenerator() {
42
+ return jodit.s.wrapInTagGen();
43
+ },
28
44
 
29
- let wrap: Nullable<boolean> = null;
45
+ nextFont(gen: Generator<HTMLElement>): CanUndef<HTMLElement> {
46
+ const font = gen.next();
30
47
 
31
- sel.save();
48
+ if (font.done) {
49
+ this.setState('end');
50
+ return;
51
+ }
32
52
 
33
- normalizeNode(sel.area.firstChild); // FF fix for test "commandsTest - Exec command "bold"
53
+ if (
54
+ isInsideInvisibleElement(font.value, editor) ||
55
+ Dom.isEmptyContent(font.value)
56
+ ) {
57
+ return;
58
+ }
34
59
 
35
- const gen = jodit.s.wrapInTagGen();
36
- let font = gen.next();
60
+ this.setState('check');
37
61
 
38
- while (!font.done) {
39
- wrap = applyToElement(style, font.value, rng, jodit, wrap);
40
- font = gen.next();
41
- }
62
+ return font.value;
63
+ }
64
+ },
42
65
 
43
- sel.restore();
44
- }
66
+ check: {
67
+ work(font: HTMLElement): Nullable<HTMLElement> {
68
+ let elm =
69
+ getSuitParent(cs, font, jodit.editor) ||
70
+ getSuitChild(cs, font);
45
71
 
46
- /**
47
- * Apply options to all selected fragment
48
- * @param font - a fake element that wraps all parts of the selection
49
- */
50
- function applyToElement(
51
- style: CommitStyle,
52
- font: HTMLElement,
53
- range: () => Range,
54
- jodit: IJodit,
55
- wrap: Nullable<boolean>
56
- ): Nullable<boolean> {
57
- const root = jodit.editor;
58
-
59
- if (checkSpecialElements(font, root)) {
60
- return wrap;
61
- }
72
+ if (elm) {
73
+ this.setState('wholeElement');
74
+ return elm;
75
+ }
62
76
 
63
- const toggleNode =
64
- getSuitParent(style, font, root) ||
65
- getSuitChild(style, font) ||
66
- getClosestWrapper(style, font, root, range);
77
+ elm = Dom.closest(
78
+ font,
79
+ node => isSuitElement(cs, node, true),
80
+ jodit.editor
81
+ );
67
82
 
68
- if (toggleNode) {
69
- return toggleStyles(style, toggleNode, wrap);
70
- }
83
+ if (elm) {
84
+ if (!cs.elementIsBlock) {
85
+ extractSelectedPart(elm, font, jodit);
86
+ }
87
+ }
71
88
 
72
- if (unwrapChildren(style, font)) {
73
- return wrap;
74
- }
89
+ if (cs.elementIsList && Dom.isTag(elm, ['ul', 'ol'])) {
90
+ this.setState('orderList');
91
+ return font;
92
+ }
75
93
 
76
- if (wrap == null) {
77
- wrap = true;
78
- }
94
+ if (elm) {
95
+ this.setState('wholeElement');
96
+ return elm;
97
+ }
79
98
 
80
- if (!wrap) {
81
- return wrap;
82
- }
99
+ if (unwrapChildren(cs, font)) {
100
+ this.setState('endProcess');
101
+ return null;
102
+ }
83
103
 
84
- let wrapper = font;
104
+ this.setState('wrap');
105
+ return font;
106
+ }
107
+ },
85
108
 
86
- if (style.elementIsBlock) {
87
- const ulReg = /^(ul|ol|li|td|th|tr|tbody|table)$/i;
109
+ wholeElement: {
110
+ toggleStyles(toggleElm: HTMLElement): void {
111
+ let mode: CommitMode = INITIAL;
88
112
 
89
- const box = Dom.up(
90
- font,
91
- node => {
92
- if (Dom.isBlock(node)) {
93
- if (
94
- ulReg.test(style.element) ||
95
- !ulReg.test(node.nodeName)
96
- ) {
97
- return true;
98
- }
113
+ if (toggleCommitStyles(cs, toggleElm)) {
114
+ mode = UNWRAP;
115
+ } else {
116
+ mode = toggleCSS(cs, toggleElm, jodit, mode);
99
117
  }
100
118
 
101
- return false;
102
- },
103
- root
104
- );
119
+ this.setState('generator', mode);
120
+ }
121
+ },
105
122
 
106
- if (box) {
107
- wrapper = box;
108
- } else {
109
- wrapper = wrapUnwrappedText(style, font, jodit, range);
110
- }
111
- }
123
+ orderList: {
124
+ toggleStyles(font: HTMLElement): void {
125
+ let mode: CommitMode = INITIAL;
126
+ const li = Dom.closest(font, 'li', jodit.editor);
112
127
 
113
- const newWrapper = Dom.replace(
114
- wrapper,
115
- style.element,
116
- jodit.createInside,
117
- true
118
- );
128
+ if (!li) {
129
+ this.setState('generator');
130
+ return;
131
+ }
119
132
 
120
- attr(newWrapper, 'size', null);
133
+ const ul = Dom.closest(font, ['ul', 'ol'], jodit.editor);
121
134
 
122
- if (style.elementIsBlock) {
123
- postProcessListElement(style, newWrapper, jodit.createInside);
124
- }
135
+ if (!ul) {
136
+ this.setState('generator');
137
+ return;
138
+ }
125
139
 
126
- if (style.options.style && style.elementIsDefault) {
127
- css(newWrapper, style.options.style);
128
- }
140
+ mode = toggleOrderedList(cs, li, jodit, mode);
141
+
142
+ if (mode === REPLACE || mode === UNWRAP || mode === CHANGE) {
143
+ this.setState('endWhile');
144
+ return;
145
+ }
146
+
147
+ this.setState('generator');
148
+ }
149
+ },
129
150
 
130
- if (style.options.className) {
131
- newWrapper.classList.toggle(style.options.className);
151
+ wrap: {
152
+ toggleStyles(font: HTMLElement): void {
153
+ if (this.getSubState() !== 'unwrap') {
154
+ const toggleElm = wrapAndCommitStyle(cs, font, jodit);
155
+ toggleCSS(cs, toggleElm, jodit, WRAP);
156
+ }
157
+
158
+ this.setState('generator');
159
+ }
160
+ },
161
+
162
+ endWhile: {
163
+ nextFont(gen: Generator<HTMLElement>): void {
164
+ const font = gen.next();
165
+
166
+ if (font.done) {
167
+ this.setState('end');
168
+ }
169
+ }
170
+ },
171
+
172
+ endProcess: {
173
+ toggleStyles() {
174
+ this.setState('generator');
175
+ }
176
+ },
177
+
178
+ end: {
179
+ finalize() {
180
+ sel.restore();
181
+ }
182
+ }
183
+ });
184
+
185
+ fsm.dispatch('start');
186
+
187
+ const gen = fsm.dispatch('initGenerator');
188
+
189
+ while (fsm.getState() !== 'end') {
190
+ const font = fsm.dispatch<HTMLElement>('nextFont', gen);
191
+
192
+ if (font) {
193
+ const wrapper = fsm.dispatch<HTMLElement>('work', font);
194
+ fsm.dispatch('toggleStyles', wrapper);
195
+ }
132
196
  }
133
197
 
134
- return wrap;
198
+ fsm.dispatch('finalize', gen);
135
199
  }
@@ -8,7 +8,20 @@ import type { HTMLTagNames, IJodit, IStyleOptions } from '../../../types';
8
8
  import { IS_BLOCK } from '../../constants';
9
9
  import { ApplyStyle } from './apply-style';
10
10
 
11
+ export const WRAP = 'wrap';
12
+ export const UNWRAP = 'unwrap';
13
+ export const CHANGE = 'change';
14
+ export const UNSET = 'unset';
15
+ export const INITIAL = 'initial';
16
+ export const REPLACE = 'replace';
17
+
11
18
  export class CommitStyle {
19
+ get elementIsList(): boolean {
20
+ return Boolean(
21
+ this.options.element && ['ul', 'ol'].includes(this.options.element)
22
+ );
23
+ }
24
+
12
25
  get element(): HTMLTagNames {
13
26
  return this.options.element || this.defaultTag;
14
27
  }
@@ -43,7 +43,7 @@ export const canUsePersistentStorage: BooleanFunction = (() => {
43
43
  * Persistent storage in localStorage
44
44
  */
45
45
  export class LocalStorageProvider<T = StorageValueType> implements IStorage<T> {
46
- set(key: string, value: T): void {
46
+ set(key: string, value: T): IStorage<T> {
47
47
  try {
48
48
  const buffer = localStorage.getItem(this.rootKey);
49
49
 
@@ -53,12 +53,16 @@ export class LocalStorageProvider<T = StorageValueType> implements IStorage<T> {
53
53
 
54
54
  localStorage.setItem(this.rootKey, JSON.stringify(json));
55
55
  } catch {}
56
+
57
+ return this;
56
58
  }
57
59
 
58
- delete(key: string): void {
60
+ delete(key: string): IStorage<T> {
59
61
  try {
60
62
  localStorage.removeItem(this.rootKey);
61
63
  } catch {}
64
+
65
+ return this;
62
66
  }
63
67
 
64
68
  get<R = T>(key: string): R | void {
@@ -77,9 +81,11 @@ export class LocalStorageProvider<T = StorageValueType> implements IStorage<T> {
77
81
 
78
82
  constructor(readonly rootKey: string) {}
79
83
 
80
- clear(): void {
84
+ clear(): IStorage<T> {
81
85
  try {
82
86
  localStorage.removeItem(this.rootKey);
83
87
  } catch {}
88
+
89
+ return this;
84
90
  }
85
91
  }