jodit 3.8.8 → 3.9.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 (118) hide show
  1. package/.github/workflows/tests.yml +23 -0
  2. package/.idea/dictionaries/v_chupurnov.xml +1 -0
  3. package/.idea/workspace.xml +295 -286
  4. package/CHANGELOG.MD +110 -24
  5. package/README.md +3 -3
  6. package/build/jodit.css +2 -2
  7. package/build/jodit.es2018.css +1 -1
  8. package/build/jodit.es2018.en.css +1 -1
  9. package/build/jodit.es2018.en.js +329 -210
  10. package/build/jodit.es2018.en.min.js +1 -1
  11. package/build/jodit.es2018.js +329 -210
  12. package/build/jodit.es2018.min.js +1 -1
  13. package/build/jodit.js +1066 -881
  14. package/build/jodit.min.css +1 -1
  15. package/build/jodit.min.js +1 -1
  16. package/package.json +1 -1
  17. package/src/core/async.ts +1 -1
  18. package/src/core/constants.ts +2 -0
  19. package/src/core/dom.ts +113 -99
  20. package/src/core/events/{events-native.ts → event-emitter.ts} +14 -9
  21. package/src/core/events/index.ts +1 -1
  22. package/src/core/global.ts +2 -2
  23. package/src/core/helpers/array/to-array.ts +1 -0
  24. package/src/core/helpers/data-bind.ts +2 -2
  25. package/src/core/helpers/utils/utils.ts +20 -4
  26. package/src/core/request/ajax.ts +212 -0
  27. package/src/core/request/config.ts +37 -0
  28. package/{build-system/minimizer/index.js → src/core/request/index.ts} +2 -1
  29. package/src/core/request/response.ts +39 -0
  30. package/src/core/selection/select.ts +59 -27
  31. package/src/core/selection/style/api/element-has-same-style.ts +13 -0
  32. package/src/core/selection/style/api/get-suit-parent.ts +1 -1
  33. package/src/core/selection/style/api/is-suit-element.ts +24 -4
  34. package/src/core/selection/style/api/unwrap-children.ts +45 -16
  35. package/src/core/selection/style/api/wrap-unwrapped-text.ts +28 -23
  36. package/src/core/selection/style/apply-style.ts +14 -8
  37. package/src/core/traits/elms.ts +1 -0
  38. package/src/core/ui/helpers/get-control-type.ts +3 -1
  39. package/src/core/view/view.ts +3 -3
  40. package/src/modules/context-menu/context-menu.ts +1 -1
  41. package/src/modules/file-browser/README.MD +1 -1
  42. package/src/modules/file-browser/data-provider.ts +22 -42
  43. package/src/modules/file-browser/file-browser.ts +3 -0
  44. package/src/modules/index.ts +1 -1
  45. package/src/modules/table.ts +106 -101
  46. package/src/modules/uploader/uploader.ts +4 -3
  47. package/src/plugins/fix/clean-html.ts +37 -16
  48. package/src/plugins/indent.ts +25 -18
  49. package/src/plugins/size/resize-handler.ts +1 -1
  50. package/src/plugins/size/size.ts +1 -3
  51. package/src/plugins/source/source.ts +1 -1
  52. package/src/plugins/table/select-cells.ts +23 -5
  53. package/src/types/ajax.d.ts +15 -6
  54. package/src/types/async.d.ts +1 -1
  55. package/src/types/events.d.ts +12 -12
  56. package/src/types/view.d.ts +2 -2
  57. package/types/core/async.d.ts +1 -1
  58. package/types/core/constants.d.ts +1 -0
  59. package/types/core/dom.d.ts +25 -19
  60. package/types/core/events/{events-native.d.ts → event-emitter.d.ts} +8 -3
  61. package/types/core/events/index.d.ts +1 -1
  62. package/types/core/global.d.ts +2 -2
  63. package/types/core/helpers/utils/utils.d.ts +12 -4
  64. package/types/core/{ajax.d.ts → request/ajax.d.ts} +4 -14
  65. package/types/core/request/config.d.ts +14 -0
  66. package/{build-system/rules/css.js → types/core/request/index.d.ts} +2 -7
  67. package/types/core/request/response.d.ts +16 -0
  68. package/types/core/selection/style/api/element-has-same-style.d.ts +4 -0
  69. package/types/core/selection/style/api/is-suit-element.d.ts +1 -0
  70. package/types/core/selection/style/api/wrap-unwrapped-text.d.ts +2 -2
  71. package/types/core/view/view.d.ts +2 -2
  72. package/types/modules/file-browser/data-provider.d.ts +1 -1
  73. package/types/modules/index.d.ts +1 -1
  74. package/types/plugins/fix/clean-html.d.ts +4 -0
  75. package/types/plugins/size/resize-handler.d.ts +1 -1
  76. package/types/plugins/source/source.d.ts +1 -1
  77. package/types/types/ajax.d.ts +15 -6
  78. package/types/types/async.d.ts +1 -1
  79. package/types/types/events.d.ts +12 -12
  80. package/types/types/view.d.ts +2 -2
  81. package/.editorconfig +0 -15
  82. package/.eslintignore +0 -3
  83. package/.eslintrc.js +0 -109
  84. package/.prettierrc.json +0 -9
  85. package/.stylelintrc +0 -17
  86. package/app.css +0 -112
  87. package/build-system/index.js +0 -78
  88. package/build-system/loaders/css-variables-prefixes.js +0 -12
  89. package/build-system/loaders/lang-loader.js +0 -57
  90. package/build-system/loaders/style.js +0 -31
  91. package/build-system/loaders/svg-loader.js +0 -21
  92. package/build-system/minimizer/css.js +0 -20
  93. package/build-system/minimizer/js.js +0 -41
  94. package/build-system/plugins/banner.js +0 -15
  95. package/build-system/plugins/define.js +0 -22
  96. package/build-system/plugins/extract-css.js +0 -14
  97. package/build-system/plugins/index.js +0 -31
  98. package/build-system/plugins/post-build.js +0 -52
  99. package/build-system/rules/extra-typescript.js +0 -22
  100. package/build-system/rules/index.js +0 -17
  101. package/build-system/rules/internal-typescript.js +0 -23
  102. package/build-system/rules/langs.js +0 -20
  103. package/build-system/rules/svg.js +0 -19
  104. package/build-system/utils/filename.js +0 -17
  105. package/build-system/utils/post-build.js +0 -28
  106. package/build-system/variables.js +0 -53
  107. package/composer.json +0 -12
  108. package/src/core/ajax.ts +0 -266
  109. package/src/types/core.d.ts +0 -7
  110. package/src/types/core.js +0 -8
  111. package/src/types/core.js.map +0 -1
  112. package/src/types/storage.d.ts +0 -13
  113. package/src/types/storage.js +0 -8
  114. package/src/types/storage.js.map +0 -1
  115. package/types/types/core.js +0 -8
  116. package/types/types/core.js.map +0 -1
  117. package/types/types/storage.js +0 -8
  118. package/types/types/storage.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jodit",
3
- "version": "3.8.8",
3
+ "version": "3.9.2",
4
4
  "description": "Jodit is awesome and usefully wysiwyg editor with filebrowser",
5
5
  "main": "build/jodit.min.js",
6
6
  "types": "./types/index.d.ts",
package/src/core/async.ts CHANGED
@@ -201,7 +201,7 @@ export class Async implements IAsync {
201
201
  promise<T>(
202
202
  executor: (
203
203
  resolve: (value: T | PromiseLike<T>) => void,
204
- reject?: (reason?: any) => void
204
+ reject: (reason?: any) => void
205
205
  ) => void
206
206
  ): RejectablePromise<T> {
207
207
  let rejectCallback: RejectablePromise<T>['rejectCallback'] = () => {};
@@ -162,3 +162,5 @@ export const BASE_PATH: string = ((): string => {
162
162
 
163
163
  return window.location.href;
164
164
  })();
165
+
166
+ export const TEMP_ATTR = 'data-jodit-temp';
package/src/core/dom.ts CHANGED
@@ -30,6 +30,7 @@ import {
30
30
  trim
31
31
  } from './helpers';
32
32
  import { Select } from './selection';
33
+ import { TEMP_ATTR } from './constants';
33
34
 
34
35
  /**
35
36
  * Module for working with DOM
@@ -146,47 +147,6 @@ export class Dom {
146
147
  }
147
148
  }
148
149
 
149
- /**
150
- * It goes through all the internal elements of the node, causing a callback function
151
- *
152
- * @param elm - the element whose children and descendants you want to iterate over
153
- * @param callback - It called for each item found
154
- * @example
155
- * ```javascript
156
- * Jodit.modules.Dom.each(parent.s.current(), function (node) {
157
- * if (node.nodeType === Node.TEXT_NODE) {
158
- * node.nodeValue = node.nodeValue.replace(Jodit.INVISIBLE_SPACE_REG_EX, '') // remove all of
159
- * the text element codes invisible character
160
- * }
161
- * });
162
- * ```
163
- */
164
- static each(
165
- elm: Node | HTMLElement,
166
- callback: (node: Node) => void | boolean
167
- ): boolean {
168
- let node: Node | null | false = elm.firstChild;
169
-
170
- if (node) {
171
- while (node) {
172
- const next = Dom.next(node, Boolean, elm);
173
-
174
- if (callback(node) === false) {
175
- return false;
176
- }
177
-
178
- // inside callback - node could be removed
179
- if (node.parentNode && !Dom.each(node, callback)) {
180
- return false;
181
- }
182
-
183
- node = next;
184
- }
185
- }
186
-
187
- return true;
188
- }
189
-
190
150
  /**
191
151
  * Call function for all nodes between `start` and `end`
192
152
  */
@@ -461,39 +421,25 @@ export class Dom {
461
421
  /**
462
422
  * Find previous node
463
423
  */
464
- static prev(
424
+ static prev<T extends Node = Node>(
465
425
  node: Node,
466
426
  condition: NodeCondition,
467
- root: Node | HTMLElement | ParentNode,
427
+ root: HTMLElement,
468
428
  withChild: boolean = true
469
- ): Nullable<Node> {
470
- return Dom.find(
471
- node,
472
- condition,
473
- root,
474
- false,
475
- 'previousSibling',
476
- withChild ? 'lastChild' : false
477
- );
429
+ ): Nullable<T> {
430
+ return Dom.find<T>(node, condition, root, false, withChild);
478
431
  }
479
432
 
480
433
  /**
481
434
  * Find next node what `condition(next) === true`
482
435
  */
483
- static next(
436
+ static next<T extends Node = Node>(
484
437
  node: Node,
485
438
  condition: NodeCondition,
486
- root: Node | HTMLElement | ParentNode,
439
+ root: HTMLElement,
487
440
  withChild: boolean = true
488
- ): Nullable<Node> {
489
- return Dom.find(
490
- node,
491
- condition,
492
- root,
493
- undefined,
494
- undefined,
495
- withChild ? 'firstChild' : false
496
- );
441
+ ): Nullable<T> {
442
+ return Dom.find<T>(node, condition, root, true, withChild);
497
443
  }
498
444
 
499
445
  static prevWithClass(
@@ -525,51 +471,122 @@ export class Dom {
525
471
  /**
526
472
  * Find next/prev node what `condition(next) === true`
527
473
  */
528
- static find(
474
+ static find<T extends Node = Node>(
529
475
  node: Node,
530
476
  condition: NodeCondition,
531
- root: ParentNode | HTMLElement | Node,
532
- recurse = false,
533
- sibling: keyof Node = 'nextSibling',
534
- child: keyof Node | false = 'firstChild'
535
- ): Nullable<Node> {
536
- if (recurse && condition(node)) {
537
- return node;
477
+ root: HTMLElement,
478
+ leftToRight: boolean = true,
479
+ withChild: boolean = true
480
+ ): Nullable<T> {
481
+ const gen = this.nextGen(node, root, leftToRight, withChild);
482
+
483
+ let item = gen.next();
484
+
485
+ while (!item.done) {
486
+ if (condition(item.value)) {
487
+ return <T>item.value;
488
+ }
489
+
490
+ item = gen.next();
538
491
  }
539
492
 
540
- let start: Nullable<Node> = node,
541
- next: Nullable<Node>;
493
+ return null;
494
+ }
495
+
496
+ /**
497
+ * Find next/prev node what `condition(next) === true`
498
+ */
499
+ static *nextGen(
500
+ start: Node,
501
+ root: HTMLElement,
502
+ leftToRight: boolean = true,
503
+ withChild: boolean = true
504
+ ): Generator<Node> {
505
+ const stack: Node[] = [];
506
+
507
+ let currentNode = start;
542
508
 
543
509
  do {
544
- next = start[sibling] as Node;
510
+ let next = leftToRight
511
+ ? currentNode.nextSibling
512
+ : currentNode.previousSibling;
545
513
 
546
- if (condition(next)) {
547
- return next ? next : null;
514
+ while (next) {
515
+ stack.unshift(next);
516
+ next = leftToRight ? next.nextSibling : next.previousSibling;
548
517
  }
549
518
 
550
- if (child && next && next[child]) {
551
- const nextOne = Dom.find(
552
- next[child] as Node,
553
- condition,
554
- next,
555
- true,
556
- sibling,
557
- child
558
- );
519
+ yield* this.runInStack(start, stack, leftToRight, withChild);
559
520
 
560
- if (nextOne) {
561
- return nextOne;
562
- }
521
+ currentNode = <Node>currentNode.parentNode;
522
+ } while (currentNode !== root);
523
+
524
+ return null;
525
+ }
526
+
527
+ /**
528
+ * It goes through all the internal elements of the node, causing a callback function
529
+ *
530
+ * @param elm - the element whose children and descendants you want to iterate over
531
+ * @param callback - It called for each item found
532
+ * @example
533
+ * ```javascript
534
+ * Jodit.modules.Dom.each(parent.s.current(), function (node) {
535
+ * if (node.nodeType === Node.TEXT_NODE) {
536
+ * node.nodeValue = node.nodeValue.replace(Jodit.INVISIBLE_SPACE_REG_EX, '') // remove all of
537
+ * the text element codes invisible character
538
+ * }
539
+ * });
540
+ * ```
541
+ */
542
+ static each(
543
+ elm: Node,
544
+ callback: (node: Node) => void | boolean,
545
+ leftToRight: boolean = true
546
+ ): boolean {
547
+ const gen = this.eachGen(elm, leftToRight);
548
+
549
+ let item = gen.next();
550
+
551
+ while (!item.done) {
552
+ if (callback(item.value) === false) {
553
+ return false;
563
554
  }
564
555
 
565
- if (!next) {
566
- next = start.parentNode;
556
+ item = gen.next();
557
+ }
558
+
559
+ return true;
560
+ }
561
+
562
+ static eachGen(root: Node, leftToRight: boolean = true): Generator<Node> {
563
+ return this.runInStack(root, [root], leftToRight);
564
+ }
565
+
566
+ private static *runInStack(
567
+ start: Node,
568
+ stack: Node[],
569
+ leftToRight: boolean,
570
+ withChild: boolean = true
571
+ ): Generator<Node> {
572
+ while (stack.length) {
573
+ const item = <Node>stack.pop();
574
+
575
+ if (start !== item) {
576
+ yield item;
567
577
  }
568
578
 
569
- start = next;
570
- } while (start && start !== root);
579
+ if (withChild) {
580
+ let child = leftToRight ? item.lastChild : item.firstChild;
571
581
 
572
- return null;
582
+ while (child) {
583
+ stack.push(child);
584
+ child = leftToRight
585
+ ? child.previousSibling
586
+ : child.nextSibling;
587
+ }
588
+ }
589
+ }
573
590
  }
574
591
 
575
592
  /**
@@ -948,7 +965,7 @@ export class Dom {
948
965
  attributes?: IDictionary
949
966
  ): K {
950
967
  attributes && attr(element, attributes);
951
- attr(element, 'data-jodit-temp', true);
968
+ attr(element, TEMP_ATTR, true);
952
969
  return element;
953
970
  }
954
971
 
@@ -960,10 +977,7 @@ export class Dom {
960
977
  return false;
961
978
  }
962
979
 
963
- return (
964
- Select.isMarker(element) ||
965
- attr(element, 'data-jodit-temp') === 'true'
966
- );
980
+ return Select.isMarker(element) || attr(element, TEMP_ATTR) === 'true';
967
981
  }
968
982
 
969
983
  /**
@@ -980,6 +994,6 @@ export class Dom {
980
994
  * Get temporary list
981
995
  */
982
996
  static temporaryList(root: HTMLElement): HTMLElement[] {
983
- return $$('[data-jodit-temp]', root);
997
+ return $$(`[${TEMP_ATTR}]`, root);
984
998
  }
985
999
  }
@@ -4,14 +4,11 @@
4
4
  * Copyright (c) 2013-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
6
 
7
- /**
8
- * The module editor's event manager
9
- */
10
-
7
+ // eslint-disable-next-line max-classes-per-file
11
8
  import type {
12
9
  CallbackFunction,
13
10
  EventHandlerBlock,
14
- IEventsNative
11
+ IEventEmitter
15
12
  } from '../../types';
16
13
  import { defaultNameSpace, EventHandlersStore } from './store';
17
14
  import { isString } from '../helpers/checker/is-string';
@@ -19,7 +16,10 @@ import { isFunction } from '../helpers/checker/is-function';
19
16
  import { isArray } from '../helpers/checker/is-array';
20
17
  import { error } from '../helpers/type';
21
18
 
22
- export class EventsNative implements IEventsNative {
19
+ /**
20
+ * The module editor's event manager
21
+ */
22
+ export class EventEmitter implements IEventEmitter {
23
23
  private mutedEvents: Set<string> = new Set();
24
24
 
25
25
  mute(event?: string): this {
@@ -40,7 +40,7 @@ export class EventsNative implements IEventsNative {
40
40
  return this;
41
41
  }
42
42
 
43
- readonly __key: string = '__JoditEventsNativeNamespaces';
43
+ readonly __key: string = '__JoditEventEmitterNamespaces';
44
44
 
45
45
  private doc: Document = document;
46
46
 
@@ -265,7 +265,7 @@ export class EventsNative implements IEventsNative {
265
265
  }
266
266
 
267
267
  const isDOMElement = isFunction((subject as any).addEventListener),
268
- self: EventsNative = this;
268
+ self: EventEmitter = this;
269
269
 
270
270
  let syntheticCallback: CallbackFunction = function (
271
271
  this: any,
@@ -564,7 +564,7 @@ export class EventsNative implements IEventsNative {
564
564
  * ```
565
565
  * or you can trigger native browser listener
566
566
  * ```javascript
567
- * var events = new Jodit.modules.EventsNative();
567
+ * var events = new Jodit.modules.EventEmitter();
568
568
  * events.on(document.body, 'click',function (event) {
569
569
  * alert('click on ' + event.target.id );
570
570
  * });
@@ -697,3 +697,8 @@ export class EventsNative implements IEventsNative {
697
697
  delete (this as any)[this.__key];
698
698
  }
699
699
  }
700
+
701
+ /**
702
+ * @deprecated Use `EventEmitter` instead
703
+ */
704
+ export class EventsNative extends EventEmitter implements IEventEmitter {}
@@ -4,6 +4,6 @@
4
4
  * Copyright (c) 2013-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
6
 
7
- export * from './events-native';
7
+ export * from './event-emitter';
8
8
  export * from './observe-object';
9
9
  export * from './store';
@@ -24,7 +24,7 @@ import {
24
24
  kebabCase
25
25
  } from './helpers/';
26
26
 
27
- import { EventsNative } from './events';
27
+ import { EventEmitter } from './events';
28
28
 
29
29
  export const instances: IDictionary<IJodit> = {};
30
30
 
@@ -124,4 +124,4 @@ export function getContainer<T extends HTMLTagNames = HTMLTagNames>(
124
124
  /**
125
125
  * Global event emitter
126
126
  */
127
- export const eventEmitter = new EventsNative();
127
+ export const eventEmitter = new EventEmitter();
@@ -17,5 +17,6 @@ export const toArray = function toArray<T extends typeof Array.from>(
17
17
  const func = isNativeFunction(Array.from)
18
18
  ? Array.from
19
19
  : reset<typeof Array.from>('Array.from') ?? Array.from;
20
+
20
21
  return func.apply(Array, args) as ReturnType<T>;
21
22
  } as typeof Array.from;
@@ -4,7 +4,7 @@
4
4
  * Copyright (c) 2013-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
6
 
7
- import type { IEventsNative, IViewComponent, Nullable } from '../../types';
7
+ import type { IEventEmitter, IViewComponent, Nullable } from '../../types';
8
8
  import { ViewComponent } from '../component';
9
9
  import { isViewObject } from './checker';
10
10
 
@@ -21,7 +21,7 @@ export const dataBind = <T = any>(
21
21
  itemStore = {};
22
22
  store.set(elm, itemStore);
23
23
 
24
- let e: Nullable<IEventsNative> = null;
24
+ let e: Nullable<IEventEmitter> = null;
25
25
 
26
26
  if (elm instanceof ViewComponent) {
27
27
  e = (elm as IViewComponent).j.e;
@@ -40,21 +40,37 @@ export function call<T extends any[], R>(
40
40
  }
41
41
 
42
42
  /**
43
- * Alias for `elm.getAttribute` but if set second argument `-{key}`
44
- * it will also check `data-{key}` attribute
45
- * if set `value` it is alias for setAttribute with same logic
43
+ * Get attribute
46
44
  */
47
45
  export function attr(elm: Element, key: string): null | string;
46
+
47
+ /**
48
+ * Remove attribute
49
+ */
50
+ export function attr(elm: Element, key: string, value: null): null | string;
51
+
52
+ /**
53
+ * Set attribute
54
+ */
48
55
  export function attr(
49
56
  elm: Element,
50
57
  key: string,
51
- value: string | number | boolean | null | undefined
58
+ value: string | number | boolean | undefined | null
52
59
  ): null;
60
+
61
+ /**
62
+ * Set or remove several attributes
63
+ */
53
64
  export function attr(
54
65
  elm: Element,
55
66
  attributes: IDictionary<string | number | boolean | null>
56
67
  ): null;
57
68
 
69
+ /**
70
+ * Alias for `elm.getAttribute` but if set second argument `-{key}`
71
+ * it will also check `data-{key}` attribute
72
+ * if set `value` it is alias for setAttribute with same logic
73
+ */
58
74
  export function attr(
59
75
  elm: Element,
60
76
  keyOrAttributes: string | IDictionary<string | number | boolean | null>,
@@ -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
+ }