jodit 3.6.2 → 3.6.6

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 (48) hide show
  1. package/CHANGELOG.MD +21 -0
  2. package/README.md +1 -3
  3. package/build/jodit.css +6 -6
  4. package/build/jodit.es2018.css +3 -3
  5. package/build/jodit.es2018.en.css +3 -3
  6. package/build/jodit.es2018.en.js +194 -73
  7. package/build/jodit.es2018.en.min.css +1 -1
  8. package/build/jodit.es2018.en.min.js +2 -2
  9. package/build/jodit.es2018.js +194 -73
  10. package/build/jodit.es2018.min.css +1 -1
  11. package/build/jodit.es2018.min.js +2 -2
  12. package/build/jodit.js +443 -308
  13. package/build/jodit.min.css +2 -2
  14. package/build/jodit.min.js +2 -2
  15. package/package.json +2 -2
  16. package/src/config.ts +2 -0
  17. package/src/core/decorators/persistent.ts +1 -1
  18. package/src/core/decorators/watch.ts +6 -0
  19. package/src/core/helpers/checker/is-url.ts +3 -3
  20. package/src/core/plugin-system.ts +1 -0
  21. package/src/core/ui/helpers/get-control-type.ts +2 -1
  22. package/src/core/ui/list/group.ts +3 -2
  23. package/src/core/ui/popup/popup.ts +17 -8
  24. package/src/core/view/view-with-toolbar.ts +1 -1
  25. package/src/core/view/view.ts +9 -4
  26. package/src/jodit.ts +7 -2
  27. package/src/modules/dialog/dialog.ts +2 -1
  28. package/src/modules/file-browser/config.ts +2 -0
  29. package/src/plugins/clipboard/drag-and-drop-element.ts +1 -0
  30. package/src/plugins/index.ts +1 -0
  31. package/src/plugins/inline-popup/config/items/cells.ts +1 -0
  32. package/src/plugins/inline-popup/inline-popup.ts +39 -9
  33. package/src/plugins/justify.ts +3 -0
  34. package/src/plugins/link/link.ts +8 -2
  35. package/src/plugins/resizer/resizer.ts +52 -55
  36. package/src/plugins/select.ts +88 -0
  37. package/src/plugins/table/select-cells.ts +43 -43
  38. package/src/styles/jodit.less +1 -1
  39. package/src/styles/variables.less +1 -1
  40. package/src/types/view.d.ts +2 -0
  41. package/test/bootstrap.js +7 -0
  42. package/test/tests/acceptance/commandsTest.js +1 -2
  43. package/test/tests/acceptance/imageTest.js +1 -1
  44. package/test/tests/acceptance/inlineModeTest.js +21 -16
  45. package/test/tests/acceptance/plugins/inline-popup.js +1 -2
  46. package/test/tests/acceptance/plugins/link.js +145 -17
  47. package/test/tests/acceptance/tableTest.js +184 -197
  48. package/test/tests/acceptance/toolbarTest.js +34 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jodit",
3
- "version": "3.6.2",
3
+ "version": "3.6.6",
4
4
  "description": "Jodit is awesome and usefully wysiwyg editor with filebrowser",
5
5
  "main": "build/jodit.min.js",
6
6
  "types": "index.d.ts",
@@ -20,7 +20,7 @@
20
20
  "test": "npm run build-no-uglify-es5 && karma start --browsers FirefoxHeadless karma.conf.js",
21
21
  "test-debug": "karma start --browsers Chrome karma.conf.js --single-run false",
22
22
  "test-chrome": "karma start --browsers Chrome karma.conf.js",
23
- "jodit": "cd ../jodit-pro && yarn newversion && cd ../jodit-react/ && npm update && npm run newversion && cd ../jodit-joomla && npm run newversion && cd ../jodit-master && npm run newversion",
23
+ "jodit": "cd ../jodit-pro && npm run newversion && cd ../jodit-react/ && npm update && npm run newversion && cd ../jodit-joomla && npm run newversion && cd ../jodit-master && npm run newversion",
24
24
  "types": "rm -rf types/* && tsc --project . --declaration --outDir types --emitDeclarationOnly",
25
25
  "pretty": "npx prettier --write ./src/*.{ts,less} ./src/**/*.{ts,less} ./src/**/**/*.{ts,less} ./src/**/**/**/*.{ts,less} ./src/**/**/**/**/*.{ts,less}",
26
26
  "fix": "npx eslint ./src/* ./test/ --fix && npm run pretty",
package/src/config.ts CHANGED
@@ -22,6 +22,8 @@ import * as consts from './core/constants';
22
22
  * Default Editor's Configuration
23
23
  */
24
24
  export class Config implements IViewOptions {
25
+ namespace: string = '';
26
+
25
27
  /**
26
28
  * When this option is enabled, the editor's content will be placed in an iframe and isolated from the rest of the page.
27
29
  *
@@ -19,7 +19,7 @@ export function persistent<T extends IComponent>(target: T, propertyKey: string)
19
19
  const jodit = isViewObject(component)
20
20
  ? component
21
21
  : ((component as unknown) as IViewComponent).jodit,
22
- storageKey = `${component.componentName}_prop_${propertyKey}`,
22
+ storageKey = `${jodit.options.namespace}${component.componentName}_prop_${propertyKey}`,
23
23
  initialValue = (component as IDictionary)[propertyKey];
24
24
 
25
25
  Object.defineProperty(component, propertyKey, {
@@ -63,6 +63,12 @@ export function watch(observeFields: string[] | string, context?: object | ((c:
63
63
  .on(context || component, eventName, callback)
64
64
  .on(eventName, callback);
65
65
 
66
+ view.hookStatus('beforeDestruct', () => {
67
+ view.events
68
+ .off(context || component, eventName, callback)
69
+ .off(eventName, callback);
70
+ });
71
+
66
72
  return;
67
73
  }
68
74
 
@@ -16,9 +16,9 @@ export function isURL(str: string): boolean {
16
16
  '^(https?:\\/\\/)' + // protocol
17
17
  '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}|' + // domain name
18
18
  '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
19
- '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
20
- '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
21
- '(\\#[-a-z\\d_]*)?$',
19
+ '(\\:\\d+)?(\\/[-a-zа-яё\\d%_.~+]*)*' + // port and path
20
+ '(\\?[;&a-zа-яё\\d%_.~+=-]*)?' + // query string
21
+ '(\\#[-a-zа-яё\\d_]*)?$',
22
22
  'i'
23
23
  ); // fragment locator
24
24
 
@@ -280,6 +280,7 @@ export class PluginSystem implements IPluginSystem {
280
280
 
281
281
  return appendStyleAsync(jodit, url);
282
282
  }
283
+
283
284
  private static styles: Set<string> = new Set();
284
285
 
285
286
  /**
@@ -25,7 +25,8 @@ export function getControlType(
25
25
  ): IControlTypeStrong {
26
26
  let buttonControl: IControlTypeStrong;
27
27
 
28
- controls ||= Config.defaultOptions.controls;
28
+ if (!controls)
29
+ controls = Config.defaultOptions.controls;
29
30
 
30
31
  if (!isString(button)) {
31
32
  buttonControl = { name: 'empty', ...ConfigFlatten(button) };
@@ -39,17 +39,18 @@ export class UIGroup<T extends IViewBased = IViewBased>
39
39
  */
40
40
  get allChildren(): IUIElement[] {
41
41
  const result: IUIElement[] = [];
42
+
42
43
  const stack: Array<IUIElement | IUIElement[] | IUIGroup> = [
43
44
  ...this.elements
44
45
  ];
45
46
 
46
47
  while (stack.length) {
47
- const elm = stack.pop();
48
+ const elm = stack.shift();
48
49
 
49
50
  if (isArray(elm)) {
50
51
  stack.push(...elm);
51
52
  } else if (elm instanceof UIGroup) {
52
- stack.push(...elm.elements.reverse());
53
+ stack.push(...elm.elements);
53
54
  } else {
54
55
  elm && result.push(elm);
55
56
  }
@@ -303,7 +303,7 @@ export class Popup extends UIElement implements IPopup {
303
303
  this.childrenPopups.forEach(popup => popup.close());
304
304
 
305
305
  this.j.e.fire(this, 'beforeClose');
306
- this.j.e.fire( 'beforePopupClose', this);
306
+ this.j.e.fire('beforePopupClose', this);
307
307
 
308
308
  this.removeGlobalListeners();
309
309
 
@@ -342,13 +342,17 @@ export class Popup extends UIElement implements IPopup {
342
342
 
343
343
  eventEmitter.on('closeAllPopups', this.close);
344
344
 
345
+ if (this.smart) {
346
+ this.j.e
347
+ .on('escape', this.close)
348
+ .on('mousedown touchstart', this.closeOnOutsideClick)
349
+ .on(ow, 'mousedown touchstart', this.closeOnOutsideClick);
350
+ }
351
+
345
352
  this.j.e
346
353
  .on('closeAllPopups', this.close)
347
- .on('escape', this.close)
348
354
  .on('resize', up)
349
355
  .on(this.container, 'scroll mousewheel', up)
350
- .on('mousedown touchstart', this.closeOnOutsideClick)
351
- .on(ow, 'mousedown touchstart', this.closeOnOutsideClick)
352
356
  .on(ow, 'scroll', up)
353
357
  .on(ow, 'resize', up);
354
358
  }
@@ -359,13 +363,18 @@ export class Popup extends UIElement implements IPopup {
359
363
 
360
364
  eventEmitter.off('closeAllPopups', this.close);
361
365
 
366
+ if (this.smart) {
367
+ this.j.e
368
+ .off('escape', this.close)
369
+ .off('mousedown touchstart', this.closeOnOutsideClick)
370
+ .off(ow, 'mousedown touchstart', this.closeOnOutsideClick);
371
+ }
372
+
362
373
  this.j.e
363
374
  .off('closeAllPopups', this.close)
364
- .off('escape', this.close)
375
+
365
376
  .off('resize', up)
366
377
  .off(this.container, 'scroll mousewheel', up)
367
- .off('mousedown touchstart', this.closeOnOutsideClick)
368
- .off(ow, 'mousedown touchstart', this.closeOnOutsideClick)
369
378
  .off(ow, 'scroll', up)
370
379
  .off(ow, 'resize', up);
371
380
  }
@@ -378,7 +387,7 @@ export class Popup extends UIElement implements IPopup {
378
387
  this.container.style.zIndex = index.toString();
379
388
  }
380
389
 
381
- constructor(jodit: IViewBased) {
390
+ constructor(jodit: IViewBased, readonly smart: boolean = true) {
382
391
  super(jodit);
383
392
  attr(this.container, 'role', 'popup');
384
393
  }
@@ -154,7 +154,7 @@ export abstract class ViewWithToolbar extends View implements IViewWithToolbar {
154
154
 
155
155
  /** @override **/
156
156
  protected constructor(
157
- options?: IViewOptions,
157
+ options?: Partial<IViewOptions>,
158
158
  readonly isJodit: boolean = false
159
159
  ) {
160
160
  super(options, isJodit);
@@ -235,15 +235,19 @@ export abstract class View extends Component implements IViewBased, Mods, Elms {
235
235
  * Return current version
236
236
  */
237
237
  getVersion(): string {
238
- return this.version;
238
+ return appVersion;
239
+ }
240
+
241
+ static getVersion(): string {
242
+ return appVersion;
239
243
  }
240
244
 
241
245
  /** @override */
242
- protected initOptions(options?: IViewOptions): void {
246
+ protected initOptions(options?: Partial<IViewOptions>): void {
243
247
  this.options = ConfigProto(
244
248
  options || {},
245
249
  ConfigProto(this.options || {}, View.defaultOptions)
246
- );
250
+ ) as IViewOptions;
247
251
  }
248
252
 
249
253
  /**
@@ -252,7 +256,7 @@ export abstract class View extends Component implements IViewBased, Mods, Elms {
252
256
  protected initOwners(): void {}
253
257
 
254
258
  protected constructor(
255
- options?: IViewOptions,
259
+ options?: Partial<IViewOptions>,
256
260
  readonly isJodit: boolean = false
257
261
  ) {
258
262
  super();
@@ -360,6 +364,7 @@ export abstract class View extends Component implements IViewBased, Mods, Elms {
360
364
  View.defaultOptions = {
361
365
  extraButtons: [],
362
366
  textIcons: false,
367
+ namespace: '',
363
368
  removeButtons: [],
364
369
  zIndex: 100002,
365
370
  defaultTimeout: 100,
package/src/jodit.ts CHANGED
@@ -136,6 +136,8 @@ export class Jodit extends ViewWithToolbar implements IJodit {
136
136
  return Config.defaultOptions;
137
137
  }
138
138
 
139
+ static fatMode: boolean = false;
140
+
139
141
  static plugins: IPluginSystem = pluginSystem;
140
142
 
141
143
  static modules: IDictionary<Function> = modules;
@@ -1221,14 +1223,17 @@ export class Jodit extends ViewWithToolbar implements IJodit {
1221
1223
 
1222
1224
  workplace.appendChild(editor);
1223
1225
 
1224
- const currentPlace = {
1226
+ const currentPlace: IWorkPlace = {
1225
1227
  editor,
1226
1228
  element,
1227
1229
  container,
1228
1230
  workplace,
1229
1231
  statusbar,
1230
1232
  options: this.isReady
1231
- ? ConfigProto(options || {}, Config.defaultOptions)
1233
+ ? (ConfigProto(
1234
+ options || {},
1235
+ Config.defaultOptions
1236
+ ) as IWorkPlace['options'])
1232
1237
  : this.options,
1233
1238
  observer: new Observer(this),
1234
1239
  editorWindow: this.ow
@@ -56,6 +56,7 @@ declare module '../../config' {
56
56
  }
57
57
 
58
58
  Config.prototype.dialog = {
59
+ namespace: '',
59
60
  extraButtons: [],
60
61
  resizable: true,
61
62
  draggable: true,
@@ -728,7 +729,7 @@ export class Dialog extends ViewWithToolbar implements IDialog {
728
729
  return this;
729
730
  }
730
731
 
731
- constructor(options?: IDialogOptions) {
732
+ constructor(options?: Partial<IDialogOptions>) {
732
733
  super(options);
733
734
 
734
735
  const self: Dialog = this;
@@ -30,6 +30,8 @@ declare module '../../config' {
30
30
  }
31
31
 
32
32
  Config.prototype.filebrowser = {
33
+ namespace: '',
34
+
33
35
  extraButtons: [],
34
36
 
35
37
  filter(item: string | ISourceFile, search: string) {
@@ -115,6 +115,7 @@ export class DragAndDropElement extends Plugin {
115
115
  pointerEvents: 'none',
116
116
  pointer: 'drag',
117
117
  position: 'fixed',
118
+ opacity: 0.7,
118
119
  display: 'inline-block',
119
120
  left: event.clientX,
120
121
  top: event.clientY,
@@ -37,6 +37,7 @@ export { placeholder } from './placeholder/placeholder';
37
37
  export { redoUndo } from './redo-undo';
38
38
  export { resizer } from './resizer/resizer';
39
39
  export { search } from './search/search';
40
+ export { select } from './select';
40
41
  export { size, resizeHandler } from './size';
41
42
  export { source } from './source';
42
43
  export { stat } from './stat';
@@ -14,6 +14,7 @@ const cmd = (control: IControlType): string =>
14
14
  control.args && isString(control.args[0])
15
15
  ? control.args[0].toLowerCase()
16
16
  : '';
17
+
17
18
  export default [
18
19
  {
19
20
  name: 'brush',
@@ -27,18 +27,21 @@ import {
27
27
  isArray,
28
28
  isFunction,
29
29
  toArray,
30
- keys
30
+ keys,
31
+ camelCase
31
32
  } from '../../core/helpers';
32
33
  import { Dom, Table, ToolbarCollection, UIElement } from '../../modules';
33
- import { debounce, wait, autobind } from '../../core/decorators';
34
+ import { debounce, wait, autobind, watch } from '../../core/decorators';
34
35
 
35
36
  /**
36
37
  * Plugin for show inline popup dialog
37
38
  */
38
39
  export class inlinePopup extends Plugin {
40
+ requires = ['select'];
41
+
39
42
  private type: Nullable<string> = null;
40
43
 
41
- private popup: IPopup = new Popup(this.jodit);
44
+ private popup: IPopup = new Popup(this.jodit, false);
42
45
 
43
46
  private toolbar: IToolbarCollection = makeCollection(
44
47
  this.jodit,
@@ -46,9 +49,8 @@ export class inlinePopup extends Plugin {
46
49
  );
47
50
 
48
51
  @autobind
49
- private onClick(e: MouseEvent): void {
50
- const node = e.target as Node,
51
- elements = keys(this.j.o.popup, false) as HTMLTagNames[],
52
+ private onClick(node: Node): void | false {
53
+ const elements = this.elmsList as HTMLTagNames[],
52
54
  target = Dom.isTag(node, 'img')
53
55
  ? node
54
56
  : Dom.closest(node, elements, this.j.editor);
@@ -59,6 +61,8 @@ export class inlinePopup extends Plugin {
59
61
  target.nodeName.toLowerCase(),
60
62
  target
61
63
  );
64
+
65
+ return false;
62
66
  }
63
67
  }
64
68
 
@@ -114,13 +118,19 @@ export class inlinePopup extends Plugin {
114
118
  /**
115
119
  * Hide opened popup
116
120
  */
121
+ @watch(':clickEditor')
117
122
  @autobind
118
123
  private hidePopup(type?: string): void {
119
- if (!type || type === this.type) {
124
+ if (!isString(type) || type === this.type) {
120
125
  this.popup.close();
121
126
  }
122
127
  }
123
128
 
129
+ @watch(':outsideClick')
130
+ protected onOutsideClick(e: MouseEvent): void {
131
+ this.popup.close();
132
+ }
133
+
124
134
  /**
125
135
  * Can show popup for this type
126
136
  * @param type
@@ -189,9 +199,10 @@ export class inlinePopup extends Plugin {
189
199
  );
190
200
  }
191
201
  )
192
- .on('click', this.onClick)
193
202
  .on('mousedown keydown', this.onSelectionStart)
194
203
  .on([this.j.ew, this.j.ow], 'mouseup keyup', this.onSelectionEnd);
204
+
205
+ this.addListenersForElements();
195
206
  }
196
207
 
197
208
  private snapRange: Nullable<Range> = null;
@@ -289,7 +300,26 @@ export class inlinePopup extends Plugin {
289
300
  protected beforeDestruct(jodit: IJodit): void {
290
301
  jodit.e
291
302
  .off('showPopup')
292
- .off('click', this.onClick)
293
303
  .off([this.j.ew, this.j.ow], 'mouseup keyup', this.onSelectionEnd);
304
+
305
+ this.removeListenersForElements();
306
+ }
307
+
308
+ private elmsList: string[] = keys(this.j.o.popup, false).filter(
309
+ s => !this.isExcludedTarget(s)
310
+ );
311
+
312
+ private addListenersForElements() {
313
+ this.j.e.on(
314
+ this.elmsList.map(e => camelCase(`click_${e}`)).join(' '),
315
+ this.onClick
316
+ );
317
+ }
318
+
319
+ private removeListenersForElements() {
320
+ this.j.e.off(
321
+ this.elmsList.map(e => camelCase(`click_${e}`)).join(' '),
322
+ this.onClick
323
+ );
294
324
  }
295
325
  }
@@ -152,12 +152,15 @@ export const alignElement = (
152
152
  case 'justifyfull':
153
153
  box.style.textAlign = 'justify';
154
154
  break;
155
+
155
156
  case 'justifyright':
156
157
  box.style.textAlign = 'right';
157
158
  break;
159
+
158
160
  case 'justifyleft':
159
161
  box.style.textAlign = 'left';
160
162
  break;
163
+
161
164
  case 'justifycenter':
162
165
  box.style.textAlign = 'center';
163
166
  break;
@@ -202,7 +202,6 @@ export class link extends Plugin {
202
202
  html: string
203
203
  ): HTMLAnchorElement | void {
204
204
  const { jodit } = this;
205
-
206
205
  if (isURL(html)) {
207
206
  if (jodit.o.link.processVideoLink) {
208
207
  const embed = convertMediaUrlToVideoEmbed(html);
@@ -307,6 +306,7 @@ export class link extends Plugin {
307
306
  className_input.value = attr(link, 'class') || '';
308
307
  }
309
308
  break;
309
+
310
310
  case 'select':
311
311
  if (className_select) {
312
312
  for (
@@ -394,7 +394,13 @@ export class link extends Plugin {
394
394
 
395
395
  if (!link) {
396
396
  if (!jodit.s.isCollapsed()) {
397
- links = jodit.s.wrapInTag('a') as HTMLAnchorElement[];
397
+ const node = jodit.s.current();
398
+
399
+ if (Dom.isTag(node, ['img'])) {
400
+ links = [Dom.wrap(node, 'a', jodit) as HTMLAnchorElement];
401
+ } else {
402
+ links = jodit.s.wrapInTag('a') as HTMLAnchorElement[];
403
+ }
398
404
  } else {
399
405
  const a = jodit.createInside.element('a');
400
406
  jodit.s.insertNode(a);
@@ -6,7 +6,7 @@
6
6
 
7
7
  import './resizer.less';
8
8
 
9
- import type { IBound } from '../../types';
9
+ import type { HTMLTagNames, IBound, Nullable } from '../../types';
10
10
  import type { IJodit } from '../../types';
11
11
  import { Config } from '../../config';
12
12
  import * as consts from '../../core/constants';
@@ -22,7 +22,7 @@ import {
22
22
  } from '../../core/helpers';
23
23
  import { Plugin } from '../../core/plugin';
24
24
  import { eventEmitter } from '../../core/global';
25
- import { autobind } from '../../core/decorators';
25
+ import { autobind, debounce, watch } from '../../core/decorators';
26
26
 
27
27
  /**
28
28
  * The module creates a supporting frame for resizing of the elements img and table
@@ -34,9 +34,7 @@ import { autobind } from '../../core/decorators';
34
34
  */
35
35
  declare module '../../config' {
36
36
  interface Config {
37
- useIframeResizer: boolean;
38
- useTableResizer: boolean;
39
- useImageResizer: boolean;
37
+ allowResizeTags: HTMLTagNames[];
40
38
 
41
39
  resizer: {
42
40
  showSize: boolean;
@@ -46,17 +44,8 @@ declare module '../../config' {
46
44
  };
47
45
  }
48
46
  }
49
- Config.prototype.useIframeResizer = true;
50
47
 
51
- /**
52
- * @property{boolean} useTableResizer=true Use true frame for editing table size
53
- */
54
- Config.prototype.useTableResizer = true;
55
-
56
- /**
57
- * @property{boolean} useImageResizer=true Use true image editing frame size
58
- */
59
- Config.prototype.useImageResizer = true;
48
+ Config.prototype.allowResizeTags = ['img', 'iframe', 'table', 'jodit'];
60
49
 
61
50
  /**
62
51
  * @property {object} resizer
@@ -105,6 +94,7 @@ export class resizer extends Plugin {
105
94
  'span'
106
95
  )[0];
107
96
 
97
+ /** @override */
108
98
  protected afterInit(editor: IJodit): void {
109
99
  $$('i', this.rect).forEach((resizeHandle: HTMLElement) => {
110
100
  editor.e.on(
@@ -134,18 +124,37 @@ export class resizer extends Plugin {
134
124
  }
135
125
  )
136
126
  .on('hideResizer', this.hide)
137
- .on(
138
- 'change afterInit afterSetMode',
139
- editor.async.debounce(
140
- this.onChangeEditor.bind(this),
141
- editor.defaultTimeout
142
- )
143
- );
127
+ .on('change afterInit afterSetMode', this.onChangeEditor);
144
128
 
145
129
  this.addEventListeners();
146
130
  this.onChangeEditor();
147
131
  }
148
132
 
133
+ /**
134
+ * Click in the editor area
135
+ * @param e
136
+ * @protected
137
+ */
138
+ @watch(':click')
139
+ protected onEditorClick(e: MouseEvent): void {
140
+ let node = e.target as Nullable<Node>;
141
+
142
+ const {
143
+ editor,
144
+ options: { allowResizeTags }
145
+ } = this.j;
146
+
147
+ while (node && node !== editor) {
148
+ if (Dom.isTag(node, allowResizeTags)) {
149
+ this.bind(node);
150
+ this.onClickElement(node, e);
151
+ return;
152
+ }
153
+
154
+ node = node.parentNode;
155
+ }
156
+ }
157
+
149
158
  private addEventListeners() {
150
159
  const editor = this.j;
151
160
 
@@ -303,9 +312,8 @@ export class resizer extends Plugin {
303
312
  }
304
313
  }
305
314
 
315
+ @debounce()
306
316
  private onChangeEditor() {
307
- const editor = this.j;
308
-
309
317
  if (this.isShown) {
310
318
  if (!this.element || !this.element.parentNode) {
311
319
  this.hide();
@@ -314,35 +322,20 @@ export class resizer extends Plugin {
314
322
  }
315
323
  }
316
324
 
317
- if (!editor.isDestructed) {
318
- $$('img, table, iframe', editor.editor).forEach(
319
- (elm: HTMLElement) => {
320
- if (editor.getMode() === consts.MODE_SOURCE) {
321
- return;
322
- }
323
-
324
- if (
325
- !(elm as any)[keyBInd] &&
326
- ((Dom.isTag(elm, 'iframe') &&
327
- editor.o.useIframeResizer) ||
328
- (Dom.isTag(elm, 'img') &&
329
- editor.o.useImageResizer) ||
330
- (Dom.isTag(elm, 'table') &&
331
- editor.o.useTableResizer))
332
- ) {
333
- (elm as any)[keyBInd] = true;
334
- this.bind(elm);
335
- }
336
- }
337
- );
338
- }
325
+ $$('iframe', this.j.editor).forEach(this.bind)
339
326
  }
340
327
 
341
328
  /**
342
329
  * Bind an edit element toWYSIWYG element
343
330
  * @param {HTMLElement} element The element that you want toWYSIWYG add a function toWYSIWYG resize
344
331
  */
345
- private bind(element: HTMLElement) {
332
+ @autobind
333
+ private bind(element: HTMLElement): void {
334
+ if ((element as any)[keyBInd]) {
335
+ return;
336
+ }
337
+
338
+ (element as any)[keyBInd] = true;
346
339
  let wrapper: HTMLElement;
347
340
 
348
341
  if (Dom.isTag(element, 'iframe')) {
@@ -399,11 +392,14 @@ export class resizer extends Plugin {
399
392
  if (IS_IE && Dom.isTag(element, 'img')) {
400
393
  event.preventDefault();
401
394
  }
402
- })
403
- .on(element, 'click', () => this.onClickElement(element));
395
+ });
404
396
  }
405
397
 
406
- private onClickElement = (element: HTMLElement) => {
398
+ private onClickElement = (element: HTMLElement, e: MouseEvent) => {
399
+ if (this.isResized) {
400
+ return;
401
+ }
402
+
407
403
  if (this.element !== element || !this.isShown) {
408
404
  this.element = element;
409
405
 
@@ -514,11 +510,12 @@ export class resizer extends Plugin {
514
510
  */
515
511
  @autobind
516
512
  private hide(): void {
517
- this.isResized = false;
518
- this.isShown = false;
519
- this.element = null;
520
-
521
- Dom.safeRemove(this.rect);
513
+ if (!this.isResized) {
514
+ this.isResized = false;
515
+ this.isShown = false;
516
+ this.element = null;
517
+ Dom.safeRemove(this.rect);
518
+ }
522
519
  }
523
520
 
524
521
  private hideSizeViewer = () => {