jodit 3.15.2 → 3.16.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 (260) hide show
  1. package/.idea/workspace.xml +301 -299
  2. package/CHANGELOG.MD +88 -7
  3. package/CONTRIBUTING.md +97 -0
  4. package/README.md +7 -7
  5. package/build/jodit.css +38 -32
  6. package/build/jodit.es2018.css +37 -31
  7. package/build/jodit.es2018.en.css +37 -31
  8. package/build/jodit.es2018.en.js +1981 -1393
  9. package/build/jodit.es2018.en.min.css +1 -1
  10. package/build/jodit.es2018.en.min.js +1 -1
  11. package/build/jodit.es2018.js +2053 -1447
  12. package/build/jodit.es2018.min.css +1 -1
  13. package/build/jodit.es2018.min.js +1 -1
  14. package/build/jodit.js +3475 -2625
  15. package/build/jodit.min.css +2 -2
  16. package/build/jodit.min.js +1 -1
  17. package/build/vdom.css +1 -1
  18. package/build/vdom.js +32 -20
  19. package/package.json +13 -13
  20. package/src/README.md +1 -1
  21. package/src/config.ts +69 -36
  22. package/src/core/async/async.ts +46 -24
  23. package/src/core/constants.ts +1 -0
  24. package/src/core/decorators/README.md +35 -0
  25. package/src/core/decorators/cache/cache.ts +1 -1
  26. package/src/core/decorators/debounce/debounce.ts +20 -9
  27. package/src/core/decorators/idle/README.md +14 -0
  28. package/src/core/decorators/idle/idle.ts +1 -1
  29. package/src/core/decorators/watch/watch.ts +8 -7
  30. package/src/core/dom/README.md +42 -0
  31. package/src/core/dom/dom.ts +37 -23
  32. package/src/core/dom/index.ts +1 -0
  33. package/src/core/dom/lazy-walker.ts +133 -0
  34. package/src/core/event-emitter/event-emitter.ts +8 -8
  35. package/src/core/event-emitter/eventify.ts +73 -0
  36. package/src/core/event-emitter/index.ts +1 -0
  37. package/src/core/helpers/html/apply-styles.ts +1 -1
  38. package/src/core/helpers/html/strip-tags.ts +3 -2
  39. package/src/core/helpers/string/fuzzy-search-index.ts +58 -0
  40. package/src/core/helpers/string/i18n.ts +1 -1
  41. package/src/core/helpers/string/index.ts +3 -2
  42. package/src/core/helpers/utils/append-script.ts +1 -1
  43. package/src/core/helpers/utils/css.ts +1 -1
  44. package/src/core/helpers/utils/selector.ts +1 -1
  45. package/src/core/helpers/utils/utils.ts +3 -3
  46. package/src/core/plugin/plugin-system.ts +14 -8
  47. package/src/core/request/ajax.ts +3 -3
  48. package/src/core/selection/select.ts +10 -10
  49. package/src/core/selection/style/api/toggle/toggle-css.ts +5 -2
  50. package/src/core/selection/style/api/wrap-unwrapped-text.ts +1 -1
  51. package/src/core/selection/style/apply-style.ts +4 -4
  52. package/src/core/storage/engines/local-storage-provider.ts +20 -19
  53. package/src/core/ui/button/button/button.ts +5 -5
  54. package/src/core/ui/element.ts +2 -2
  55. package/src/core/ui/form/inputs/input/input.ts +1 -1
  56. package/src/core/ui/form/inputs/select/select.ts +1 -1
  57. package/src/core/ui/group/list.ts +2 -2
  58. package/src/core/vdom/render/index.ts +12 -8
  59. package/src/core/vdom/v-dom-jodit.ts +1 -1
  60. package/src/core/view/view.ts +1 -1
  61. package/src/index.ts +3 -3
  62. package/src/jodit.ts +72 -55
  63. package/src/langs/README.md +1 -1
  64. package/src/langs/ar.js +2 -1
  65. package/src/langs/cs_cz.js +2 -1
  66. package/src/langs/de.js +2 -1
  67. package/src/langs/es.js +2 -1
  68. package/src/langs/fa.js +2 -1
  69. package/src/langs/fr.js +2 -1
  70. package/src/langs/he.js +2 -1
  71. package/src/langs/hu.js +2 -1
  72. package/src/langs/id.js +2 -1
  73. package/src/langs/index.ts +1 -1
  74. package/src/langs/it.js +2 -1
  75. package/src/langs/ja.js +2 -1
  76. package/src/langs/ko.js +2 -1
  77. package/src/langs/nl.js +2 -1
  78. package/src/langs/pl.js +2 -1
  79. package/src/langs/pt_br.js +2 -1
  80. package/src/langs/ru.js +2 -1
  81. package/src/langs/tr.js +2 -1
  82. package/src/langs/zh_cn.js +2 -1
  83. package/src/langs/zh_tw.js +2 -1
  84. package/src/modules/dialog/dialog.ts +6 -6
  85. package/src/modules/dialog/prompt.ts +1 -1
  86. package/src/modules/file-browser/README.md +2 -2
  87. package/src/modules/file-browser/builders/context-menu.ts +12 -13
  88. package/src/modules/file-browser/fetch/load-tree.ts +1 -1
  89. package/src/modules/file-browser/file-browser.ts +10 -7
  90. package/src/modules/history/README.md +5 -0
  91. package/src/modules/{observer → history}/command.ts +5 -5
  92. package/src/modules/{observer/observer.ts → history/history.ts} +97 -55
  93. package/src/modules/{observer → history}/snapshot.ts +3 -4
  94. package/src/modules/{observer → history}/stack.ts +4 -4
  95. package/src/modules/image-editor/image-editor.ts +8 -8
  96. package/src/modules/image-editor/templates/form.ts +2 -2
  97. package/src/modules/index.ts +3 -3
  98. package/src/modules/status-bar/status-bar.ts +4 -0
  99. package/src/modules/table/table.ts +2 -2
  100. package/src/modules/toolbar/button/button.ts +2 -2
  101. package/src/modules/toolbar/collection/collection.ts +1 -1
  102. package/src/modules/uploader/helpers/process-old-browser-drag.ts +1 -1
  103. package/src/modules/uploader/helpers/send-files.ts +1 -1
  104. package/src/modules/uploader/helpers/send.ts +1 -1
  105. package/src/modules/uploader/uploader.ts +3 -3
  106. package/src/modules/widget/color-picker/color-picker.ts +2 -3
  107. package/src/modules/widget/tabs/tabs.ts +17 -12
  108. package/src/plugins/add-new-line/add-new-line.ts +8 -8
  109. package/src/plugins/class-span/class-span.ts +1 -1
  110. package/src/plugins/clipboard/copy-format.ts +1 -1
  111. package/src/plugins/clipboard/drag-and-drop-element.ts +4 -2
  112. package/src/plugins/clipboard/paste/config.ts +19 -3
  113. package/src/plugins/clipboard/paste/helpers.ts +17 -50
  114. package/src/plugins/clipboard/paste/interface.ts +6 -0
  115. package/src/plugins/clipboard/paste/paste.ts +22 -8
  116. package/src/plugins/clipboard/paste-from-word/config.ts +17 -0
  117. package/src/plugins/clipboard/paste-from-word/paste-from-word.ts +15 -6
  118. package/src/plugins/clipboard/paste-storage/paste-storage.ts +6 -6
  119. package/src/plugins/color/color.ts +2 -2
  120. package/src/plugins/error-messages/error-messages.ts +2 -2
  121. package/src/plugins/fix/clean-html/README.md +26 -0
  122. package/src/plugins/fix/{clean-html.ts → clean-html/clean-html.ts} +59 -142
  123. package/src/plugins/fix/clean-html/config.ts +106 -0
  124. package/src/plugins/fix/index.ts +12 -0
  125. package/src/plugins/fix/wrap-nodes/README.md +27 -0
  126. package/src/plugins/fix/wrap-nodes/config.ts +24 -0
  127. package/src/plugins/fix/{wrap-text-nodes.ts → wrap-nodes/wrap-nodes.ts} +9 -4
  128. package/src/plugins/focus/focus.ts +1 -1
  129. package/src/plugins/format-block/format-block.ts +1 -1
  130. package/src/plugins/fullsize/fullsize.ts +4 -4
  131. package/src/plugins/iframe/iframe.ts +3 -3
  132. package/src/plugins/image/image-properties/image-properties.ts +12 -13
  133. package/src/plugins/indent/indent.ts +1 -1
  134. package/src/plugins/index.ts +2 -2
  135. package/src/plugins/inline-popup/config/items/a.ts +2 -2
  136. package/src/plugins/inline-popup/config/items/cells.ts +11 -11
  137. package/src/plugins/inline-popup/config/items/iframe.ts +1 -1
  138. package/src/plugins/inline-popup/config/items/img.ts +7 -7
  139. package/src/plugins/inline-popup/inline-popup.ts +5 -5
  140. package/src/plugins/keyboard/backspace/backspace.ts +1 -1
  141. package/src/plugins/keyboard/backspace/cases/check-join-neighbors.ts +1 -1
  142. package/src/plugins/keyboard/helpers.ts +1 -1
  143. package/src/plugins/keyboard/hotkeys.ts +1 -1
  144. package/src/plugins/limit/limit.ts +3 -3
  145. package/src/plugins/line-height/line-height.ts +1 -1
  146. package/src/plugins/link/link.ts +8 -8
  147. package/src/plugins/link/template.ts +2 -2
  148. package/src/plugins/media/file.ts +1 -1
  149. package/src/plugins/media/media.ts +1 -1
  150. package/src/plugins/media/video/config.ts +1 -1
  151. package/src/plugins/mobile/config.ts +1 -1
  152. package/src/plugins/mobile/mobile.ts +1 -1
  153. package/src/plugins/ordered-list/config.ts +61 -0
  154. package/src/plugins/ordered-list/ordered-list.ts +3 -153
  155. package/src/plugins/placeholder/placeholder.ts +3 -3
  156. package/src/plugins/print/helpers.ts +14 -7
  157. package/src/plugins/print/index.ts +1 -1
  158. package/src/plugins/print/{preview.less → preview/preview.less} +1 -1
  159. package/src/plugins/print/{preview.ts → preview/preview.ts} +9 -8
  160. package/src/plugins/print/print.ts +19 -10
  161. package/src/plugins/redo-undo/redo-undo.ts +3 -3
  162. package/src/plugins/resizer/resizer.ts +11 -11
  163. package/src/plugins/search/README.md +38 -0
  164. package/src/plugins/search/config.ts +82 -0
  165. package/src/plugins/search/helpers/index.ts +12 -0
  166. package/src/plugins/search/helpers/sentence-finder.ts +103 -0
  167. package/src/plugins/search/helpers/wrap-ranges-texts-in-tmp-span.ts +120 -0
  168. package/src/plugins/search/search.ts +269 -615
  169. package/src/plugins/search/ui/search.less +159 -0
  170. package/src/plugins/search/ui/search.ts +256 -0
  171. package/src/plugins/select/select.ts +1 -1
  172. package/src/plugins/size/config.ts +8 -8
  173. package/src/plugins/size/resize-handler.ts +3 -3
  174. package/src/plugins/size/size.ts +4 -4
  175. package/src/plugins/source/editor/engines/ace.ts +9 -9
  176. package/src/plugins/source/editor/engines/area.ts +3 -3
  177. package/src/plugins/source/source.ts +6 -6
  178. package/src/plugins/spellcheck/README.md +1 -0
  179. package/src/plugins/spellcheck/config.ts +34 -0
  180. package/src/plugins/spellcheck/spellcheck.svg +4 -0
  181. package/src/plugins/spellcheck/spellcheck.ts +48 -0
  182. package/src/plugins/sticky/sticky.ts +3 -3
  183. package/src/plugins/table/resize-cells.ts +11 -11
  184. package/src/plugins/table/select-cells.ts +2 -2
  185. package/src/plugins/tooltip/tooltip.ts +1 -1
  186. package/src/plugins/xpath/xpath.ts +8 -8
  187. package/src/polyfills.ts +5 -4
  188. package/src/styles/icons/README.md +2 -2
  189. package/src/types/async.d.ts +12 -2
  190. package/src/types/core.ts +1 -1
  191. package/src/types/events.d.ts +6 -2
  192. package/src/types/file-browser.d.ts +1 -2
  193. package/{types/types/observer.d.ts → src/types/history.d.ts} +11 -7
  194. package/src/types/index.d.ts +1 -1
  195. package/src/types/jodit.d.ts +12 -4
  196. package/src/types/toolbar.d.ts +5 -5
  197. package/src/types/types.d.ts +11 -4
  198. package/types/config.d.ts +68 -35
  199. package/types/core/async/async.d.ts +11 -4
  200. package/types/core/constants.d.ts +1 -0
  201. package/types/core/dom/dom.d.ts +3 -5
  202. package/types/core/dom/index.d.ts +1 -0
  203. package/types/core/dom/lazy-walker.d.ts +37 -0
  204. package/types/core/event-emitter/eventify.d.ts +39 -0
  205. package/types/core/event-emitter/index.d.ts +1 -0
  206. package/types/core/helpers/string/fuzzy-search-index.d.ts +10 -0
  207. package/types/core/helpers/string/i18n.d.ts +1 -1
  208. package/types/core/helpers/string/index.d.ts +3 -2
  209. package/types/core/helpers/utils/utils.d.ts +1 -1
  210. package/types/core/selection/select.d.ts +1 -1
  211. package/types/core/ui/button/button/button.d.ts +4 -4
  212. package/types/core/view/view.d.ts +1 -1
  213. package/types/jodit.d.ts +19 -6
  214. package/types/modules/{observer → history}/command.d.ts +4 -4
  215. package/types/modules/{observer/observer.d.ts → history/history.d.ts} +17 -9
  216. package/types/modules/{observer → history}/snapshot.d.ts +1 -1
  217. package/types/modules/{observer → history}/stack.d.ts +3 -3
  218. package/types/modules/image-editor/image-editor.d.ts +1 -1
  219. package/types/modules/index.d.ts +3 -3
  220. package/types/modules/toolbar/button/button.d.ts +2 -5
  221. package/types/modules/widget/tabs/tabs.d.ts +1 -1
  222. package/types/plugins/class-span/class-span.d.ts +1 -1
  223. package/types/plugins/clipboard/paste/config.d.ts +8 -0
  224. package/types/plugins/clipboard/paste/helpers.d.ts +2 -2
  225. package/types/plugins/clipboard/paste/interface.d.ts +5 -0
  226. package/types/plugins/clipboard/paste-from-word/config.d.ts +5 -0
  227. package/types/plugins/clipboard/paste-from-word/paste-from-word.d.ts +3 -2
  228. package/types/plugins/fix/clean-html/clean-html.d.ts +70 -0
  229. package/types/plugins/fix/{clean-html.d.ts → clean-html/config.d.ts} +2 -57
  230. package/types/plugins/fix/index.d.ts +10 -0
  231. package/types/plugins/fix/wrap-nodes/config.d.ts +16 -0
  232. package/types/plugins/fix/{wrap-text-nodes.d.ts → wrap-nodes/wrap-nodes.d.ts} +5 -2
  233. package/types/plugins/fullsize/fullsize.d.ts +2 -2
  234. package/types/plugins/index.d.ts +2 -2
  235. package/types/plugins/ordered-list/config.d.ts +6 -0
  236. package/types/plugins/ordered-list/ordered-list.d.ts +1 -1
  237. package/types/plugins/print/helpers.d.ts +2 -2
  238. package/types/plugins/print/index.d.ts +1 -1
  239. package/types/plugins/print/{preview.d.ts → preview/preview.d.ts} +1 -1
  240. package/types/plugins/search/config.d.ts +36 -0
  241. package/types/plugins/search/helpers/index.d.ts +10 -0
  242. package/types/plugins/search/helpers/sentence-finder.d.ts +21 -0
  243. package/types/plugins/search/helpers/wrap-ranges-texts-in-tmp-span.d.ts +14 -0
  244. package/types/plugins/search/search.d.ts +25 -39
  245. package/types/plugins/search/ui/search.d.ts +37 -0
  246. package/types/plugins/spellcheck/config.d.ts +15 -0
  247. package/types/plugins/spellcheck/spellcheck.d.ts +19 -0
  248. package/types/plugins/sticky/sticky.d.ts +2 -2
  249. package/types/types/async.d.ts +12 -2
  250. package/types/types/core.d.ts +1 -1
  251. package/types/types/core.ts +1 -1
  252. package/types/types/events.d.ts +6 -2
  253. package/types/types/file-browser.d.ts +1 -2
  254. package/{src/types/observer.d.ts → types/types/history.d.ts} +11 -7
  255. package/types/types/index.d.ts +1 -1
  256. package/types/types/jodit.d.ts +12 -4
  257. package/types/types/toolbar.d.ts +5 -5
  258. package/types/types/types.d.ts +11 -4
  259. package/src/modules/observer/README.md +0 -0
  260. package/src/plugins/search/search.less +0 -152
@@ -34,8 +34,9 @@ export function debounce<V = IViewComponent | IViewBased>(
34
34
  return <T extends Component & IDictionary>(
35
35
  target: IDictionary,
36
36
  propertyKey: string
37
- ): void => {
38
- if (!isFunction(target[propertyKey])) {
37
+ ): PropertyDescriptor => {
38
+ const fn = target[propertyKey];
39
+ if (!isFunction(fn)) {
39
40
  throw error('Handler must be a Function');
40
41
  }
41
42
 
@@ -48,14 +49,24 @@ export function debounce<V = IViewComponent | IViewBased>(
48
49
  ? timeout(component)
49
50
  : timeout;
50
51
 
51
- (component as any)[propertyKey] = view.async[method](
52
- (component as any)[propertyKey].bind(component),
53
- isNumber(realTimeout) || isPlainObject(realTimeout)
54
- ? realTimeout
55
- : view.defaultTimeout,
56
- firstCallImmediately
57
- );
52
+ Object.defineProperty(component, propertyKey, {
53
+ configurable: true,
54
+ value: view.async[method](
55
+ (component as any)[propertyKey].bind(component),
56
+ isNumber(realTimeout) || isPlainObject(realTimeout)
57
+ ? realTimeout
58
+ : view.defaultTimeout,
59
+ firstCallImmediately
60
+ )
61
+ });
58
62
  });
63
+
64
+ return {
65
+ configurable: true,
66
+ get(): typeof fn {
67
+ return fn.bind(this);
68
+ }
69
+ };
59
70
  };
60
71
  }
61
72
 
@@ -1 +1,15 @@
1
1
  Wrap function in [[Async.requestIdleCallback]] wrapper
2
+
3
+ ```ts
4
+ import { component, idle } from 'jodit/src/core/decorators';
5
+ import { UIElement } from 'jodit/src/ui';
6
+
7
+ @component
8
+ class SomeClass extends UIElement {
9
+ @idle
10
+ runIdle(): void {
11
+ // Do some havy work
12
+ this.runIdle(); // This will work and won't go into stack depth error and break the main thread
13
+ }
14
+ }
15
+ ```
@@ -35,7 +35,7 @@ export function idle<V = IViewComponent | IViewBased>(): DecoratorHandler {
35
35
 
36
36
  const originalMethod = (component as any)[propertyKey];
37
37
 
38
- (component as any)[propertyKey] = (...args: unknown[]) =>
38
+ (component as any)[propertyKey] = (...args: unknown[]): number =>
39
39
  view.async.requestIdleCallback(
40
40
  originalMethod.bind(component, ...args)
41
41
  );
@@ -56,7 +56,7 @@ export function watch(
56
56
  throw error('Handler must be a Function');
57
57
  }
58
58
 
59
- const process = (component: IComponent) => {
59
+ const process = (component: IComponent): void => {
60
60
  const callback = (key: string, ...args: any[]): void | any => {
61
61
  if (!component.isInDestruct) {
62
62
  return (component as any)[propertyKey](key, ...args);
@@ -66,6 +66,7 @@ export function watch(
66
66
  splitArray(observeFields).forEach(field => {
67
67
  if (/:/.test(field)) {
68
68
  const [objectPath, eventName] = field.split(':');
69
+ let ctx = context;
69
70
 
70
71
  const view = isViewObject(component)
71
72
  ? component
@@ -73,22 +74,22 @@ export function watch(
73
74
 
74
75
  if (objectPath.length) {
75
76
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
76
- context = component.get<CanUndef<object>>(objectPath)!;
77
+ ctx = component.get<CanUndef<object>>(objectPath)!;
77
78
  }
78
79
 
79
- if (isFunction(context)) {
80
- context = context(component);
80
+ if (isFunction(ctx)) {
81
+ ctx = ctx(component);
81
82
  }
82
83
 
83
- view.events.on(context || component, eventName, callback);
84
+ view.events.on(ctx || component, eventName, callback);
84
85
 
85
- if (!context) {
86
+ if (!ctx) {
86
87
  view.events.on(eventName, callback);
87
88
  }
88
89
 
89
90
  view.hookStatus('beforeDestruct', () => {
90
91
  view.events
91
- .off(context || component, eventName, callback)
92
+ .off(ctx || component, eventName, callback)
92
93
  .off(eventName, callback);
93
94
  });
94
95
 
@@ -13,3 +13,45 @@ Dom.before(elm, div);
13
13
  The rest of the methods can be found in the [[Dom | documentation]]
14
14
 
15
15
  > All module methods are static. So you don't need an instance to use them.
16
+
17
+ The module also includes the [[LazyWalker]] class. It is convenient for cases when it is necessary to go through
18
+ the entire tree of elements, but this must be done without stopping the main thread of execution.
19
+ For example, your plugin can search for some nodes, or text. If each time you run through the entire tree in a loop,
20
+ then the interface will noticeably slow down on large documents. To avoid this, this class is made.
21
+
22
+ ```js
23
+ const walker = new Jodit.modules.LazyWalker(new Jodit.modules.Async(), 100);
24
+ const names = [];
25
+
26
+ walker
27
+ .on('visit', node => {
28
+ names.push(node.nodeName.toLowerCase());
29
+ })
30
+ .on('end', () => {
31
+ expect(names).deep.eq([
32
+ 'div',
33
+ 'ul',
34
+ 'li',
35
+ 'strong',
36
+ '#text',
37
+ 'span',
38
+ '#text',
39
+ 'u',
40
+ '#text',
41
+ 'li',
42
+ 'i',
43
+ '#text',
44
+ 'b',
45
+ '#text',
46
+ 'u',
47
+ '#text',
48
+ 'img'
49
+ ]);
50
+ done();
51
+ });
52
+
53
+ const div = document.createElement('div');
54
+ div.innerHTML =
55
+ "<ul><li><strong>test</strong><span>test</span><u>test</u></li><li><i>test</i><b>test</b><u>test</u><img src='' alt=''></li></ul>";
56
+ walker.setWork(div);
57
+ ```
@@ -111,29 +111,40 @@ export class Dom {
111
111
  return wrapper as HTMLElement;
112
112
  }
113
113
 
114
- /**
115
- * Wrap node inside another node
116
- */
117
114
  static wrap<K extends HTMLTagNames>(
118
- current: Node,
115
+ current: Node | Range,
116
+ tag: HTMLElement,
117
+ create: ICreate
118
+ ): HTMLElementTagNameMap[K];
119
+
120
+ static wrap<K extends HTMLTagNames>(
121
+ current: Node | Range,
119
122
  tag: K,
120
123
  create: ICreate
121
124
  ): HTMLElementTagNameMap[K];
122
125
 
126
+ /**
127
+ * Wrap node inside another node
128
+ */
123
129
  static wrap(
124
- current: Node,
130
+ current: Node | Range,
125
131
  tag: HTMLElement | HTMLTagNames,
126
132
  create: ICreate
127
133
  ): HTMLElement {
128
134
  const wrapper = isString(tag) ? create.element(tag) : tag;
129
135
 
130
- if (!current.parentNode) {
131
- throw error('Element should be in DOM');
132
- }
133
-
134
- current.parentNode.insertBefore(wrapper, current);
136
+ if (Dom.isNode(current)) {
137
+ if (!current.parentNode) {
138
+ throw error('Element should be in DOM');
139
+ }
135
140
 
136
- wrapper.appendChild(current);
141
+ current.parentNode.insertBefore(wrapper, current);
142
+ wrapper.appendChild(current);
143
+ } else {
144
+ const fragment = current.extractContents();
145
+ current.insertNode(wrapper);
146
+ wrapper.appendChild(fragment);
147
+ }
137
148
 
138
149
  return wrapper;
139
150
  }
@@ -597,10 +608,6 @@ export class Dom {
597
608
  while (stack.length) {
598
609
  const item = <Node>stack.pop();
599
610
 
600
- if (start !== item) {
601
- yield item;
602
- }
603
-
604
611
  if (withChild) {
605
612
  let child = leftToRight ? item.lastChild : item.firstChild;
606
613
 
@@ -611,6 +618,10 @@ export class Dom {
611
618
  : child.nextSibling;
612
619
  }
613
620
  }
621
+
622
+ if (start !== item) {
623
+ yield item;
624
+ }
614
625
  }
615
626
  }
616
627
 
@@ -663,7 +674,8 @@ export class Dom {
663
674
  static findSibling(
664
675
  node: Node,
665
676
  left: boolean = true,
666
- cond: (n: Node) => boolean = (n: Node) => !Dom.isEmptyTextNode(n)
677
+ cond: (n: Node) => boolean = (n: Node): boolean =>
678
+ !Dom.isEmptyTextNode(n)
667
679
  ): Nullable<Node> {
668
680
  let sibling = Dom.sibling(node, left);
669
681
 
@@ -674,7 +686,7 @@ export class Dom {
674
686
  return sibling && cond(sibling) ? sibling : null;
675
687
  }
676
688
 
677
- static sibling(node: Node, left: boolean): Nullable<Node> {
689
+ static sibling(node: Node, left?: boolean): Nullable<Node> {
678
690
  return left ? node.previousSibling : node.nextSibling;
679
691
  }
680
692
 
@@ -746,14 +758,16 @@ export class Dom {
746
758
  if (isFunction(tagsOrCondition)) {
747
759
  condition = tagsOrCondition;
748
760
  } else if (isArray(tagsOrCondition)) {
749
- condition = (tag: Node | null) =>
750
- tag &&
751
- tagsOrCondition.includes(
752
- tag.nodeName.toLowerCase() as HTMLTagNames
761
+ condition = (tag: Node | null): boolean =>
762
+ Boolean(
763
+ tag &&
764
+ tagsOrCondition.includes(
765
+ tag.nodeName.toLowerCase() as HTMLTagNames
766
+ )
753
767
  );
754
768
  } else {
755
- condition = (tag: Node | null) =>
756
- tag && tagsOrCondition === tag.nodeName.toLowerCase();
769
+ condition = (tag: Node | null): boolean =>
770
+ Boolean(tag && tagsOrCondition === tag.nodeName.toLowerCase());
757
771
  }
758
772
 
759
773
  return Dom.up(node, condition, root);
@@ -9,3 +9,4 @@
9
9
  */
10
10
 
11
11
  export * from './dom';
12
+ export * from './lazy-walker';
@@ -0,0 +1,133 @@
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-2022 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
5
+ */
6
+
7
+ /**
8
+ * @module dom
9
+ */
10
+
11
+ import type { IAsync, IDestructible } from 'jodit/types';
12
+ import type { Nullable, CanUndef } from 'jodit/types';
13
+ import { Eventify } from 'jodit/core/event-emitter/eventify';
14
+ import { autobind } from 'jodit/core/decorators';
15
+ import { Dom } from 'jodit/core/dom/dom';
16
+
17
+ export class LazyWalker
18
+ extends Eventify<{
19
+ visit: (node: Node) => boolean;
20
+ break: (reason?: string) => void;
21
+ end: (affect: boolean) => void;
22
+ }>
23
+ implements IDestructible
24
+ {
25
+ private workNodes: Nullable<Generator<Node>> = null;
26
+
27
+ setWork(root: Node): this {
28
+ if (this.isWorked) {
29
+ this.break();
30
+ }
31
+
32
+ this.workNodes = Dom.eachGen(root, !this.options.reverse);
33
+
34
+ this.isFinished = false;
35
+ this.startIdleRequest();
36
+ return this;
37
+ }
38
+
39
+ private hadAffect: boolean = false;
40
+ private isWorked: boolean = false;
41
+ private isFinished: boolean = false;
42
+
43
+ constructor(
44
+ private readonly async: IAsync,
45
+ private readonly options: {
46
+ readonly timeout?: number;
47
+ readonly whatToShow?: number;
48
+ readonly reverse?: boolean;
49
+ readonly timeoutChunkSize?: number;
50
+ } = {}
51
+ ) {
52
+ super();
53
+ }
54
+
55
+ private idleId: number = 0;
56
+
57
+ private startIdleRequest(): void {
58
+ this.idleId = this.async.requestIdleCallback(this.workPerform, {
59
+ timeout: this.options.timeout ?? 10
60
+ });
61
+ }
62
+
63
+ break(reason?: string): void {
64
+ if (this.isWorked) {
65
+ this.stop();
66
+ this.emit('break', reason);
67
+ }
68
+ }
69
+
70
+ end(): void {
71
+ if (this.isWorked) {
72
+ this.stop();
73
+ this.emit('end', this.hadAffect);
74
+ this.hadAffect = false;
75
+ }
76
+ }
77
+
78
+ private stop(): void {
79
+ this.isWorked = false;
80
+ this.isFinished = true;
81
+ this.workNodes = null;
82
+ this.async.cancelIdleCallback(this.idleId);
83
+ }
84
+
85
+ destruct(): void {
86
+ this.stop();
87
+ }
88
+
89
+ @autobind
90
+ private workPerform(deadline: IdleDeadline): void {
91
+ if (this.workNodes) {
92
+ this.isWorked = true;
93
+
94
+ let count = 0;
95
+ const chunkSize = this.options.timeoutChunkSize ?? 50;
96
+
97
+ while (
98
+ !this.isFinished &&
99
+ (deadline.timeRemaining() > 0 ||
100
+ (deadline.didTimeout && count <= chunkSize))
101
+ ) {
102
+ const item = this.workNodes.next();
103
+ count += 1;
104
+ if (this.visitNode(item.value)) {
105
+ this.hadAffect = true;
106
+ }
107
+
108
+ if (item.done) {
109
+ this.end();
110
+ return;
111
+ }
112
+ }
113
+ } else {
114
+ this.end();
115
+ }
116
+
117
+ if (!this.isFinished) {
118
+ this.startIdleRequest();
119
+ }
120
+ }
121
+
122
+ private visitNode(nodeElm: CanUndef<Nullable<Element | Node>>): boolean {
123
+ if (
124
+ !nodeElm ||
125
+ (this.options.whatToShow !== undefined &&
126
+ nodeElm.nodeType !== this.options.whatToShow)
127
+ ) {
128
+ return false;
129
+ }
130
+
131
+ return this.emit('visit', nodeElm) ?? false;
132
+ }
133
+ }
@@ -52,7 +52,7 @@ export class EventEmitter implements IEventEmitter {
52
52
  private eachEvent(
53
53
  events: string,
54
54
  callback: (event: string, namespace: string) => void
55
- ) {
55
+ ): void {
56
56
  const eventParts: string[] = events.split(/[\s,]+/);
57
57
 
58
58
  eventParts.forEach((eventNameSpace: string) => {
@@ -82,7 +82,7 @@ export class EventEmitter implements IEventEmitter {
82
82
  return subject[this.__key];
83
83
  }
84
84
 
85
- private clearStore(subject: any) {
85
+ private clearStore(subject: any): void {
86
86
  if (subject[this.__key] !== undefined) {
87
87
  delete subject[this.__key];
88
88
  }
@@ -90,7 +90,7 @@ export class EventEmitter implements IEventEmitter {
90
90
 
91
91
  private prepareEvent = (
92
92
  event: TouchEvent | MouseEvent | ClipboardEvent
93
- ) => {
93
+ ): void => {
94
94
  if (event.cancelBubble) {
95
95
  return;
96
96
  }
@@ -133,7 +133,7 @@ export class EventEmitter implements IEventEmitter {
133
133
  private triggerNativeEvent(
134
134
  element: Document | Element | HTMLElement | Window,
135
135
  event: string | Event | MouseEvent
136
- ) {
136
+ ): void {
137
137
  const evt: Event = this.doc.createEvent('HTMLEvents');
138
138
 
139
139
  if (typeof event === 'string') {
@@ -365,7 +365,7 @@ export class EventEmitter implements IEventEmitter {
365
365
  callback = eventsOrCallback as CallbackFunction;
366
366
  }
367
367
 
368
- const newCallback = (...args: any) => {
368
+ const newCallback = (...args: any): void => {
369
369
  this.off(subject, events, newCallback);
370
370
  return callback(...args);
371
371
  };
@@ -439,7 +439,7 @@ export class EventEmitter implements IEventEmitter {
439
439
  }
440
440
 
441
441
  const isDOMElement = isFunction((subject as any).removeEventListener),
442
- removeEventListener = (block: EventHandlerBlock) => {
442
+ removeEventListener = (block: EventHandlerBlock): void => {
443
443
  if (isDOMElement) {
444
444
  (subject as HTMLElement).removeEventListener(
445
445
  block.event,
@@ -451,7 +451,7 @@ export class EventEmitter implements IEventEmitter {
451
451
  removeCallbackFromNameSpace = (
452
452
  event: string,
453
453
  namespace: string
454
- ) => {
454
+ ): void => {
455
455
  if (event !== '') {
456
456
  const blocks: EventHandlerBlock[] | void = store.get(
457
457
  event,
@@ -540,7 +540,7 @@ export class EventEmitter implements IEventEmitter {
540
540
 
541
541
  private __stopped: EventHandlerBlock[][] = [];
542
542
 
543
- private removeStop(currentBlocks: EventHandlerBlock[]) {
543
+ private removeStop(currentBlocks: EventHandlerBlock[]): void {
544
544
  if (currentBlocks) {
545
545
  const index: number = this.__stopped.indexOf(currentBlocks);
546
546
  index !== -1 && this.__stopped.splice(0, index + 1);
@@ -0,0 +1,73 @@
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-2022 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
5
+ */
6
+
7
+ /**
8
+ * @module event-emitter
9
+ */
10
+
11
+ import type { CanUndef } from 'jodit/types';
12
+
13
+ /**
14
+ * Class for adding event handling capability
15
+ *
16
+ * ```ts
17
+ * class SomeClass extends Eventify<{ start: (node: Node) => boolean; }> {
18
+ * constructor() {
19
+ * super();
20
+ * setTimeout(() => {
21
+ * if (this.emit('start', document.body)) {
22
+ * console.log('yes');
23
+ * };
24
+ * }, 100);
25
+ * }
26
+ * }
27
+ *
28
+ * const sm = new SomeClass();
29
+ * sm.on('start', (node) => {
30
+ * console.log(node);
31
+ * return true;
32
+ * })
33
+ * ```
34
+ */
35
+ export abstract class Eventify<
36
+ MAP extends { [key: string]: (...args: any[]) => any },
37
+ EVENT extends keyof MAP = keyof MAP
38
+ > {
39
+ private map: Map<keyof MAP, Set<Function>> = new Map();
40
+
41
+ on(name: EVENT, func: MAP[EVENT]): this {
42
+ if (!this.map.has(name)) {
43
+ this.map.set(name, new Set());
44
+ }
45
+
46
+ this.map.get(name)?.add(func);
47
+
48
+ return this;
49
+ }
50
+
51
+ off(name: keyof MAP, func: MAP[EVENT]): this {
52
+ if (this.map.has(name)) {
53
+ this.map.get(name)?.delete(func);
54
+ }
55
+
56
+ return this;
57
+ }
58
+
59
+ protected emit(
60
+ name: EVENT,
61
+ ...args: Parameters<MAP[EVENT]>
62
+ ): CanUndef<ReturnType<MAP[EVENT]>> {
63
+ let result: CanUndef<ReturnType<MAP[EVENT]>>;
64
+
65
+ if (this.map.has(name)) {
66
+ this.map.get(name)?.forEach(cb => {
67
+ result = cb(...args);
68
+ });
69
+ }
70
+
71
+ return result;
72
+ }
73
+ }
@@ -9,5 +9,6 @@
9
9
  */
10
10
 
11
11
  export * from './event-emitter';
12
+ export * from './eventify';
12
13
  export * from './observable';
13
14
  export * from './store';
@@ -12,7 +12,7 @@ import { Dom } from 'jodit/core/dom';
12
12
  import { $$ } from 'jodit/core/helpers/utils';
13
13
  import { trim } from '../string';
14
14
 
15
- function normalizeCSS(s: string) {
15
+ function normalizeCSS(s: string): string {
16
16
  return s
17
17
  .replace(/mso-[a-z-]+:[\s]*[^;]+;/gi, '')
18
18
  .replace(/mso-[a-z-]+:[\s]*[^";']+$/gi, '')
@@ -63,8 +63,9 @@ export function safeHTML(
63
63
  return;
64
64
  }
65
65
 
66
- const removeOnError = (elm: HTMLElement) => attr(elm, 'onerror', null),
67
- safeLink = (elm: HTMLElement) => {
66
+ const removeOnError = (elm: HTMLElement): void =>
67
+ attr(elm, 'onerror', null),
68
+ safeLink = (elm: HTMLElement): void => {
68
69
  const href = elm.getAttribute('href');
69
70
 
70
71
  if (href && href.trim().indexOf('javascript') === 0) {
@@ -0,0 +1,58 @@
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-2022 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
5
+ */
6
+
7
+ /**
8
+ * @module helpers/string
9
+ */
10
+
11
+ import { INVISIBLE_SPACE } from 'jodit/core/constants';
12
+
13
+ /**
14
+ * Finds the position of the substring in the string, if any, and returns the length of the found subsequence.
15
+ * Unlike `indexOf` ignores INVISIBLE_SPACE and may fail at `maxDistance` characters
16
+ */
17
+ export function fuzzySearchIndex(
18
+ needle: string,
19
+ haystack: string,
20
+ offset: number = 0,
21
+ maxDistance: number = 1
22
+ ): [number, number] {
23
+ let i = 0,
24
+ j = 0,
25
+ startIndex = -1,
26
+ len = 0,
27
+ errorDistance = 0;
28
+
29
+ for (j = offset; i < needle.length && j < haystack.length; ) {
30
+ if (needle[i].toLowerCase() === haystack[j].toLowerCase()) {
31
+ i++;
32
+ len++;
33
+ errorDistance = 0;
34
+
35
+ if (startIndex === -1) {
36
+ startIndex = j;
37
+ }
38
+ } else if (i > 0) {
39
+ if (
40
+ errorDistance >= maxDistance &&
41
+ haystack[j] !== INVISIBLE_SPACE
42
+ ) {
43
+ i = 0;
44
+ startIndex = -1;
45
+ len = 0;
46
+ errorDistance = 0;
47
+ j--;
48
+ } else {
49
+ errorDistance++;
50
+ len++;
51
+ }
52
+ }
53
+
54
+ j++;
55
+ }
56
+
57
+ return i === needle.length ? [startIndex, len] : [-1, 0];
58
+ }
@@ -46,7 +46,7 @@ export const sprintf = (str: string, args?: Array<string | number>): string => {
46
46
  * Internationalization method. Uses Jodit.lang object
47
47
  * @example
48
48
  * ```javascript
49
- * var editor = new Jodit("#redactor", {
49
+ * var editor = Jodit.make("#redactor", {
50
50
  * language: 'ru'
51
51
  * });
52
52
  * console.log(editor.i18n('Cancel')) //Отмена;
@@ -9,8 +9,9 @@
9
9
  */
10
10
 
11
11
  export * from './camel-case';
12
- export * from './stringify';
12
+ export * from './fuzzy-search-index';
13
+ export * from './i18n';
13
14
  export * from './kebab-case';
15
+ export * from './stringify';
14
16
  export * from './trim';
15
17
  export * from './ucfirst';
16
- export * from './i18n';
@@ -88,7 +88,7 @@ export const appendStyleAsync = cacheLoaders(
88
88
  link.media = 'all';
89
89
  link.crossOrigin = 'anonymous';
90
90
 
91
- const callback = () => resolve(link);
91
+ const callback = (): void => resolve(link);
92
92
 
93
93
  !jodit.isInDestruct &&
94
94
  jodit.e.on(link, 'load', callback).on(link, 'error', reject);
@@ -62,7 +62,7 @@ export function css(
62
62
  elm: HTMLElement,
63
63
  _key: string,
64
64
  _value: StyleValue
65
- ) => {
65
+ ): void => {
66
66
  if (
67
67
  !isVoid(_value) &&
68
68
  numberFieldsReg.test(_key) &&