jodit 3.8.2 → 3.8.3

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/.idea/workspace.xml +153 -155
  2. package/CHANGELOG.MD +36 -9
  3. package/app.css +2 -1
  4. package/build/jodit.css +73 -73
  5. package/build/jodit.es2018.css +56 -56
  6. package/build/jodit.es2018.en.css +56 -56
  7. package/build/jodit.es2018.en.js +172 -84
  8. package/build/jodit.es2018.en.min.css +1 -1
  9. package/build/jodit.es2018.en.min.js +2 -2
  10. package/build/jodit.es2018.js +172 -84
  11. package/build/jodit.es2018.min.css +1 -1
  12. package/build/jodit.es2018.min.js +2 -2
  13. package/build/jodit.js +835 -742
  14. package/build/jodit.min.css +2 -2
  15. package/build/jodit.min.js +2 -2
  16. package/package.json +7 -7
  17. package/src/config.ts +4 -4
  18. package/src/core/create.ts +15 -15
  19. package/src/core/helpers/css.ts +3 -5
  20. package/src/core/helpers/html/strip-tags.ts +36 -4
  21. package/src/core/helpers/selector.ts +6 -8
  22. package/src/core/helpers/size/get-scroll-parent.ts +28 -0
  23. package/src/core/helpers/size/index.ts +1 -0
  24. package/src/core/selection/select.ts +35 -45
  25. package/src/core/ui/button/button/button.less +4 -1
  26. package/src/core/ui/button/button/button.ts +6 -8
  27. package/src/core/ui/popup/popup.less +4 -4
  28. package/src/core/ui/popup/popup.ts +17 -7
  29. package/src/core/view/view-with-toolbar.less +3 -2
  30. package/src/jodit.ts +6 -3
  31. package/src/modules/dialog/dialog.ts +1 -2
  32. package/src/modules/file-browser/builders/context-menu.ts +1 -1
  33. package/src/modules/file-browser/listeners/state-listeners.ts +2 -1
  34. package/src/modules/file-browser/styles/preview.less +17 -14
  35. package/src/modules/widget/color-picker/color-picker.less +12 -11
  36. package/src/modules/widget/color-picker/color-picker.ts +20 -30
  37. package/src/plugins/clipboard/paste-storage/paste-storage.ts +9 -20
  38. package/src/plugins/fix/clean-html.ts +36 -3
  39. package/src/plugins/iframe.ts +12 -2
  40. package/src/plugins/link/link.ts +14 -2
  41. package/src/plugins/resizer/resizer.ts +22 -4
  42. package/src/plugins/size/resize-handler.ts +1 -1
  43. package/src/plugins/size/size.less +10 -7
  44. package/src/plugins/symbols/symbols.less +12 -7
  45. package/src/plugins/symbols/symbols.ts +9 -6
  46. package/src/plugins/xpath/xpath.ts +1 -1
  47. package/src/styles/jodit.less +1 -1
  48. package/src/types/ui.d.ts +9 -1
@@ -29,7 +29,7 @@ import {
29
29
  } from '../../helpers';
30
30
  import { eventEmitter, getContainer } from '../../global';
31
31
  import { UIElement } from '../element';
32
- import { autobind } from '../../decorators';
32
+ import { autobind, throttle } from '../../decorators';
33
33
 
34
34
  type getBoundFunc = () => IBound;
35
35
 
@@ -106,9 +106,6 @@ export class Popup extends UIElement implements IPopup {
106
106
 
107
107
  /**
108
108
  * Open popup near with some bound
109
- *
110
- * @param getBound
111
- * @param keepPosition
112
109
  */
113
110
  open(getBound: getBoundFunc, keepPosition: boolean = false): this {
114
111
  markOwner(this.jodit, this.container);
@@ -135,7 +132,6 @@ export class Popup extends UIElement implements IPopup {
135
132
 
136
133
  /**
137
134
  * Calculate static bound for point
138
- * @param getBound
139
135
  */
140
136
  protected getKeepBound(getBound: getBoundFunc): getBoundFunc {
141
137
  const oldBound = getBound();
@@ -193,6 +189,12 @@ export class Popup extends UIElement implements IPopup {
193
189
  return this;
194
190
  }
195
191
 
192
+ @throttle(10)
193
+ @autobind
194
+ throttleUpdatePosition(): void {
195
+ this.updatePosition();
196
+ }
197
+
196
198
  /**
197
199
  * Calculate start point
198
200
  *
@@ -333,7 +335,7 @@ export class Popup extends UIElement implements IPopup {
333
335
  }
334
336
 
335
337
  private addGlobalListeners(): void {
336
- const up = this.updatePosition,
338
+ const up = this.throttleUpdatePosition,
337
339
  ow = this.ow;
338
340
 
339
341
  eventEmitter.on('closeAllPopups', this.close);
@@ -351,10 +353,14 @@ export class Popup extends UIElement implements IPopup {
351
353
  .on(this.container, 'scroll mousewheel', up)
352
354
  .on(ow, 'scroll', up)
353
355
  .on(ow, 'resize', up);
356
+
357
+ Dom.up(this.j.container, box => {
358
+ box && this.j.e.on(box, 'scroll mousewheel', up);
359
+ });
354
360
  }
355
361
 
356
362
  private removeGlobalListeners(): void {
357
- const up = this.updatePosition,
363
+ const up = this.throttleUpdatePosition,
358
364
  ow = this.ow;
359
365
 
360
366
  eventEmitter.off('closeAllPopups', this.close);
@@ -373,6 +379,10 @@ export class Popup extends UIElement implements IPopup {
373
379
  .off(this.container, 'scroll mousewheel', up)
374
380
  .off(ow, 'scroll', up)
375
381
  .off(ow, 'resize', up);
382
+
383
+ Dom.up(this.j.container, box => {
384
+ box && this.j.e.off(box, 'scroll mousewheel', up);
385
+ });
376
386
  }
377
387
 
378
388
  /**
@@ -10,11 +10,12 @@
10
10
  &__box {
11
11
  &:not(:empty) {
12
12
  --color-background-default: var(--color-panel);
13
- background-color: var(--color-panel);
13
+
14
14
  overflow: hidden;
15
+ border-bottom: 1px solid var(--color-border);
16
+ background-color: var(--color-panel);
15
17
  border-radius: var(--border-radius-default)
16
18
  var(--border-radius-default) 0 0;
17
- border-bottom: 1px solid var(--color-border);
18
19
  }
19
20
  }
20
21
  }
package/src/jodit.ts CHANGED
@@ -402,15 +402,18 @@ export class Jodit extends ViewWithToolbar implements IJodit {
402
402
 
403
403
  /**
404
404
  * Set value to native editor
405
- * @param value
406
405
  */
407
406
  setNativeEditorValue(value: string): void {
408
- if (this.e.fire('beforeSetNativeEditorValue', value)) {
407
+ const data = {
408
+ value
409
+ };
410
+
411
+ if (this.e.fire('beforeSetNativeEditorValue', data)) {
409
412
  return;
410
413
  }
411
414
 
412
415
  if (this.editor) {
413
- this.editor.innerHTML = value;
416
+ this.editor.innerHTML = data.value;
414
417
  }
415
418
  }
416
419
 
@@ -660,7 +660,7 @@ export class Dialog extends ViewWithToolbar implements IDialog {
660
660
  * //You can close dialog two ways
661
661
  * var dialog = new Jodit.modules.Dialog();
662
662
  * dialog.open('Hello world!', 'Title');
663
- * var $close = Jodit.modules.helper.dom('<a href="javascript:void(0)" style="float:left;" class="jodit-button">
663
+ * var $close = dialog.create.fromHTML('<a href="#" style="float:left;" class="jodit-button">
664
664
  * <i class="icon icon-check"></i>&nbsp;' + Jodit.prototype.i18n('Ok') + '</a>');
665
665
  * $close.addEventListener('click', function () {
666
666
  * dialog.close();
@@ -690,7 +690,6 @@ export class Dialog extends ViewWithToolbar implements IDialog {
690
690
  * Called up to close the window
691
691
  *
692
692
  * @event beforeClose
693
- * @this {Dialog} current dialog
694
693
  */
695
694
  if (this.e) {
696
695
  this.e.fire('beforeClose', this);
@@ -17,7 +17,7 @@ import { openImageEditor } from '../../image-editor/image-editor';
17
17
 
18
18
  const CLASS_PREVIEW = F_CLASS + '_preview_',
19
19
  preview_tpl_next = (next = 'next', right = 'right') =>
20
- `<a href="javascript:void(0)" class="${CLASS_PREVIEW}navigation ${CLASS_PREVIEW}navigation-${next}">` +
20
+ `<div class="${CLASS_PREVIEW}navigation ${CLASS_PREVIEW}navigation-${next}">` +
21
21
  '' +
22
22
  Icon.get('angle-' + right) +
23
23
  '</a>';
@@ -123,7 +123,7 @@ export function stateListeners(this: FileBrowser): void {
123
123
  F_CLASS + '__tree-item',
124
124
  {
125
125
  draggable: 'draggable',
126
- href: 'javascript:void(0)',
126
+ href: '#',
127
127
  'data-path': normalizePath(
128
128
  source.path,
129
129
  name + '/'
@@ -144,6 +144,7 @@ export function stateListeners(this: FileBrowser): void {
144
144
  });
145
145
 
146
146
  e.stopPropagation();
147
+ e.preventDefault();
147
148
  };
148
149
 
149
150
  this.e.on(folderElm, 'click', action('openFolder'));
@@ -7,50 +7,53 @@
7
7
  @import (reference) '../../../styles/variables';
8
8
 
9
9
  .jodit-filebrowser_preview {
10
- text-align: center;
10
+ position: relative;
11
+ display: flex;
12
+
11
13
  min-width: 600px;
12
14
  max-width: 1000px;
13
15
  min-height: 700px;
14
16
  max-height: 100%;
15
- position: relative;
16
- display: flex;
17
- justify-content: center;
17
+
18
18
  align-items: center;
19
+ justify-content: center;
20
+
21
+ text-align: center;
19
22
 
20
23
  @media (max-width: @screen-sm) {
21
- max-width: 100%;
22
- max-height: 100%;
23
24
  min-width: auto;
24
- min-height: auto;
25
+ max-width: 100%;
25
26
  height: 100%;
27
+ min-height: auto;
28
+ max-height: 100%;
26
29
  }
27
30
 
28
31
  &_box {
29
- flex-grow: 1;
30
32
  display: flex;
31
- justify-content: center;
33
+ flex-grow: 1;
32
34
  align-items: center;
35
+ justify-content: center;
33
36
  }
34
37
 
35
38
  &_navigation {
36
39
  position: absolute;
37
40
  top: 0;
38
- height: 100%;
39
41
  left: 0;
42
+ height: 100%;
40
43
 
41
44
  &-next {
42
- left: auto;
43
45
  right: 0;
46
+ left: auto;
44
47
  }
45
48
 
46
49
  svg {
47
- width: 45px;
48
- height: 45px;
49
50
  position: relative;
50
51
  top: 50%;
52
+ width: 45px;
53
+ height: 45px;
51
54
  margin-top: -22px;
52
- transition: fill 0.3s linear;
53
55
  fill: #9e9ba7;
56
+ transition: fill 0.3s linear;
54
57
  }
55
58
 
56
59
  &:hover svg {
@@ -11,33 +11,34 @@
11
11
  --color-cell-size: 24px;
12
12
  --color-cell-icon-size: 12px;
13
13
 
14
- text-align: left;
15
14
  margin: 0;
15
+ text-align: left;
16
16
  user-select: none;
17
17
 
18
- .jodit-color-picker__group {
19
- margin-bottom: calc(var(--padding-default) / 2);
20
- white-space: normal;
21
- max-width: calc(var(--color-cell-size) * 10);
18
+ &__group {
22
19
  display: flex;
20
+ max-width: calc(var(--color-cell-size) * 10);
23
21
  flex-wrap: wrap;
22
+ margin-bottom: calc(var(--padding-default) / 2);
23
+ white-space: normal;
24
24
  }
25
25
 
26
- a {
26
+ &__color-item {
27
+ display: block;
28
+
27
29
  width: var(--color-cell-size);
28
30
  height: var(--color-cell-size);
29
31
 
30
- display: block;
32
+ border: 1px solid transparent;
33
+ text-align: center;
31
34
  text-decoration: none;
32
35
  vertical-align: middle;
33
- text-align: center;
34
- border: 1px solid transparent;
35
36
 
36
37
  &:hover {
37
38
  border-color: #000;
38
39
  }
39
40
 
40
- &.jodit_active,
41
+ &_active_true,
41
42
  &:active {
42
43
  border: 2px solid var(--color-border-selected);
43
44
  }
@@ -45,9 +46,9 @@
45
46
 
46
47
  &__native {
47
48
  svg {
49
+ display: inline-block;
48
50
  width: 16px;
49
51
  height: 16px;
50
- display: inline-block;
51
52
  margin-right: 4px;
52
53
  }
53
54
 
@@ -41,8 +41,9 @@ export const ColorPickerWidget = (
41
41
  callback: (newColor: string) => void,
42
42
  coldColor: string
43
43
  ): HTMLDivElement => {
44
- const valueHex = normalizeColor(coldColor),
45
- form = editor.c.div('jodit-color-picker'),
44
+ const cn = 'jodit-color-picker',
45
+ valueHex = normalizeColor(coldColor),
46
+ form = editor.c.div(cn),
46
47
  iconPalette: string = editor.o.textIcons
47
48
  ? `<span>${editor.i18n('palette')}</span>`
48
49
  : Icon.get('palette'),
@@ -52,9 +53,7 @@ export const ColorPickerWidget = (
52
53
  if (isPlainObject(colors)) {
53
54
  Object.keys(colors).forEach(key => {
54
55
  stack.push(
55
- '<div class="jodit-color-picker__group jodit-color-picker__group-' +
56
- key +
57
- '">'
56
+ `<div class="${cn}__group ${cn}__group-${key}">`
58
57
  );
59
58
  stack.push(eachColor((colors as any)[key]));
60
59
  stack.push('</div>');
@@ -62,35 +61,26 @@ export const ColorPickerWidget = (
62
61
  } else if (isArray(colors)) {
63
62
  colors.forEach(color => {
64
63
  stack.push(
65
- '<a ' +
66
- (valueHex === color
67
- ? ' class="jodit_active" '
68
- : '') +
69
- ' title="' +
70
- color +
71
- '" style="background-color:' +
72
- color +
73
- '" data-color="' +
74
- color +
75
- '" href="javascript:void(0)"></a>'
64
+ `<span class='${cn}__color-item ${
65
+ valueHex === color
66
+ ? cn + '__color-item_active_true'
67
+ : ''
68
+ }' title="${color}" style="background-color:${color}" data-color="${color}"></span>`
76
69
  );
77
70
  });
78
71
  }
72
+
79
73
  return stack.join('');
80
74
  };
81
75
 
82
76
  form.appendChild(
83
77
  editor.c.fromHTML(
84
- '<div class="jodit-color-picker__groups">' +
85
- eachColor(editor.o.colors) +
86
- '</div>'
78
+ `<div class="${cn}__groups">${eachColor(editor.o.colors)}</div>`
87
79
  )
88
80
  );
89
81
 
90
82
  form.appendChild(
91
- editor.c.fromHTML(
92
- '<div data-ref="extra" class="jodit-color-picker__extra"></div>'
93
- )
83
+ editor.c.fromHTML(`<div data-ref="extra" class="${cn}__extra"></div>`)
94
84
  );
95
85
 
96
86
  const { extra } = refs(form);
@@ -98,17 +88,14 @@ export const ColorPickerWidget = (
98
88
  if (editor.o.showBrowserColorPicker && hasBrowserColorPicker()) {
99
89
  extra.appendChild(
100
90
  editor.c.fromHTML(
101
- '<div class="jodit-color-picker__native">' +
102
- iconPalette +
103
- '<input type="color" value="#ffffff"/>' +
104
- '</div>'
91
+ `<div class="${cn}__native">${iconPalette}<input type="color" value="#ffffff"/></div>`
105
92
  )
106
93
  );
107
94
 
108
95
  editor.e.on(form, 'change', (e: MouseEvent) => {
109
96
  e.stopPropagation();
110
97
 
111
- const target: HTMLInputElement = e.target as HTMLInputElement;
98
+ const target = e.target as HTMLInputElement;
112
99
 
113
100
  if (!target || !target.tagName || !Dom.isTag(target, 'input')) {
114
101
  return;
@@ -138,18 +125,21 @@ export const ColorPickerWidget = (
138
125
  ) {
139
126
  target = Dom.closest(
140
127
  target.parentNode,
141
- 'a',
128
+ 'span',
142
129
  editor.editor
143
130
  ) as HTMLElement;
144
131
  }
145
132
 
146
- if (!Dom.isTag(target, 'a')) {
133
+ if (
134
+ !Dom.isTag(target, 'span') ||
135
+ !target.classList.contains(cn + '__color-item')
136
+ ) {
147
137
  return;
148
138
  }
149
139
 
150
140
  const color: string = attr(target, '-color') || '';
151
141
 
152
- if (callback && typeof callback === 'function') {
142
+ if (callback && isFunction(callback)) {
153
143
  callback(color);
154
144
  }
155
145
 
@@ -16,6 +16,7 @@ import { Dialog } from '../../../modules/dialog';
16
16
  import { Plugin } from '../../../core/plugin';
17
17
  import { Dom } from '../../../core/dom';
18
18
  import { attr, toArray } from '../../../core/helpers';
19
+ import { Button } from '../../../core/ui';
19
20
 
20
21
  /**
21
22
  * Show dialog choose content to paste
@@ -121,7 +122,7 @@ export class pasteStorage extends Plugin {
121
122
 
122
123
  this.j.e.on(a, 'keydown', this.onKeyDown);
123
124
 
124
- attr(a, 'href', 'javascript:void(0)');
125
+ attr(a, 'href', '#');
125
126
  attr(a, 'data-index', index.toString());
126
127
  attr(a, 'tab-index', '-1');
127
128
 
@@ -140,25 +141,13 @@ export class pasteStorage extends Plugin {
140
141
  language: this.j.o.language
141
142
  });
142
143
 
143
- const pasteButton: HTMLAnchorElement = this.j.c.fromHTML(
144
- '<a href="javascript:void(0)" style="float:right;" class="jodit-button">' +
145
- '<span>' +
146
- this.j.i18n('Paste') +
147
- '</span>' +
148
- '</a>'
149
- ) as HTMLAnchorElement;
150
-
151
- this.j.e.on(pasteButton, 'click', this.paste);
152
-
153
- const cancelButton: HTMLAnchorElement = this.j.c.fromHTML(
154
- '<a href="javascript:void(0)" style="float:right; margin-right: 10px;" class="jodit-button">' +
155
- '<span>' +
156
- this.j.i18n('Cancel') +
157
- '</span>' +
158
- '</a>'
159
- ) as HTMLAnchorElement;
160
-
161
- this.j.e.on(cancelButton, 'click', this.dialog.close);
144
+ const pasteButton = Button(this.j, 'paste', 'Paste', 'primary');
145
+
146
+ pasteButton.onAction(this.paste);
147
+
148
+ const cancelButton = Button(this.j, '', 'Cancel');
149
+
150
+ cancelButton.onAction(this.dialog.close);
162
151
 
163
152
  this.container = this.j.c.div();
164
153
  this.container.classList.add('jodit-paste-storage');
@@ -18,9 +18,9 @@ import {
18
18
  INSEPARABLE_TAGS
19
19
  } from '../../core/constants';
20
20
  import { Dom, Select } from '../../modules';
21
- import { isString, keys, trim } from '../../core/helpers';
21
+ import { isString, keys, safeHTML, trim } from '../../core/helpers';
22
22
  import { Plugin } from '../../core/plugin';
23
- import { autobind, debounce } from '../../core/decorators';
23
+ import { watch, autobind, debounce } from '../../core/decorators';
24
24
  import { findNotEmptySibling } from '../keyboard/helpers';
25
25
 
26
26
  declare module '../../config' {
@@ -36,6 +36,16 @@ declare module '../../config' {
36
36
  removeEmptyElements: boolean;
37
37
  replaceOldTags: IDictionary<HTMLTagNames> | false;
38
38
 
39
+ /**
40
+ * Remove onError attributes
41
+ */
42
+ removeOnError: boolean;
43
+
44
+ /**
45
+ * Safe href="javascript:" links
46
+ */
47
+ safeJavaScriptLink: boolean;
48
+
39
49
  /**
40
50
  * The allowTags option defines which elements will remain in the
41
51
  * edited text when the editor saves. You can use this limit the returned HTML.
@@ -96,7 +106,10 @@ Config.prototype.cleanHTML = {
96
106
  b: 'strong'
97
107
  },
98
108
  allowTags: false,
99
- denyTags: false
109
+ denyTags: false,
110
+
111
+ removeOnError: true,
112
+ safeJavaScriptLink: true
100
113
  };
101
114
 
102
115
  Config.prototype.controls.eraser = {
@@ -139,6 +152,8 @@ export class cleanHtml extends Plugin {
139
152
 
140
153
  const editor = this.j;
141
154
 
155
+ this.onSafeHTML(editor.editor);
156
+
142
157
  const current = editor.s.current();
143
158
 
144
159
  const replaceOldTags = editor.o.cleanHTML.replaceOldTags;
@@ -528,6 +543,24 @@ export class cleanHtml extends Plugin {
528
543
  return false;
529
544
  }
530
545
 
546
+ /**
547
+ * Event handler when manually assigning a value to the HTML editor.
548
+ */
549
+ @watch(':beforeSetNativeEditorValue')
550
+ protected onBeforeSetNativeEditorValue(data: { value: string }): boolean {
551
+ const sandBox = this.j.createInside.div();
552
+ sandBox.innerHTML = data.value;
553
+ this.onSafeHTML(sandBox);
554
+ data.value = sandBox.innerHTML;
555
+
556
+ return false;
557
+ }
558
+
559
+ @watch(':safeHTML')
560
+ protected onSafeHTML(sandBox: HTMLElement): void {
561
+ safeHTML(sandBox, this.j.o.cleanHTML);
562
+ }
563
+
531
564
  /** @override */
532
565
  protected override beforeDestruct(): void {
533
566
  this.j.e.off('.cleanHtml');
@@ -321,7 +321,7 @@ export function iframe(editor: IJodit): void {
321
321
  )
322
322
  .on(
323
323
  'beforeSetNativeEditorValue',
324
- (value: string): boolean => {
324
+ ({ value }: { value: string }): boolean => {
325
325
  if (editor.isLocked) {
326
326
  return false;
327
327
  }
@@ -340,16 +340,26 @@ export function iframe(editor: IJodit): void {
340
340
  );
341
341
  doc.close();
342
342
  editor.editor = doc.body;
343
+ editor.e.fire(
344
+ 'safeHTML',
345
+ editor.editor
346
+ );
343
347
 
344
348
  toggleEditable();
345
349
  editor.e.fire('prepareWYSIWYGEditor');
350
+
351
+ editor.e.stopPropagation(
352
+ 'beforeSetNativeEditorValue'
353
+ );
346
354
  }
347
355
  } else {
348
356
  doc.body.innerHTML = value;
349
357
  }
350
358
 
351
359
  return true;
352
- }
360
+ },
361
+ undefined,
362
+ true
353
363
  );
354
364
  }
355
365
 
@@ -360,6 +360,7 @@ export class link extends Plugin {
360
360
 
361
361
  if (unlink) {
362
362
  jodit.e.on(unlink, 'click', (e: MouseEvent) => {
363
+ jodit.s.restore();
363
364
  jodit.observer.snapshot.restore(snapshot);
364
365
 
365
366
  if (link) {
@@ -382,6 +383,7 @@ export class link extends Plugin {
382
383
 
383
384
  let links: HTMLAnchorElement[];
384
385
 
386
+ jodit.s.restore();
385
387
  jodit.s.removeMarkers();
386
388
  jodit.editor.normalize();
387
389
  jodit.observer.snapshot.restore(snapshot);
@@ -405,6 +407,8 @@ export class link extends Plugin {
405
407
  jodit.s.insertNode(a, false, false);
406
408
  links = [a];
407
409
  }
410
+
411
+ links.forEach(link => jodit.s.select(link));
408
412
  } else {
409
413
  links = [link];
410
414
  }
@@ -445,12 +449,20 @@ export class link extends Plugin {
445
449
  }
446
450
 
447
451
  if (!isImageContent) {
452
+ let newContent = a.textContent;
453
+
448
454
  if (content_input.value.trim().length) {
449
455
  if (textWasChanged) {
450
- a.textContent = content_input.value;
456
+ newContent = content_input.value;
451
457
  }
452
458
  } else {
453
- a.textContent = url_input.value;
459
+ newContent = url_input.value;
460
+ }
461
+
462
+ const content = a.textContent;
463
+
464
+ if (newContent !== content) {
465
+ a.textContent = newContent;
454
466
  }
455
467
  }
456
468
 
@@ -42,6 +42,11 @@ declare module '../../config' {
42
42
  showSize: boolean;
43
43
  hideSizeTimeout: number;
44
44
 
45
+ /**
46
+ * When resizing images, change not the styles but the width and height attributes
47
+ */
48
+ forImageChangeAttributes: boolean;
49
+
45
50
  /**
46
51
  * The minimum width for the editable element
47
52
  */
@@ -60,6 +65,7 @@ Config.prototype.allowResizeTags = ['img', 'iframe', 'table', 'jodit'];
60
65
  Config.prototype.resizer = {
61
66
  showSize: true,
62
67
  hideSizeTimeout: 1000,
68
+ forImageChangeAttributes: true,
63
69
  min_width: 10,
64
70
  min_height: 10
65
71
  };
@@ -119,7 +125,7 @@ export class resizer extends Plugin {
119
125
  'afterGetValueFromEditor.resizer',
120
126
  (data: { value: string }) => {
121
127
  const rgx =
122
- /<jodit[^>]+data-jodit_iframe_wrapper[^>]+>(.*?<iframe[^>]+>.*?<\/iframe>.*?)<\/jodit>/gi;
128
+ /<jodit[^>]+data-jodit_iframe_wrapper[^>]+>(.*?<iframe[^>]*>.*?<\/iframe>.*?)<\/jodit>/gi;
123
129
 
124
130
  if (rgx.test(data.value)) {
125
131
  data.value = data.value.replace(rgx, '$1');
@@ -276,14 +282,14 @@ export class resizer extends Plugin {
276
282
 
277
283
  if (new_w > this.j.o.resizer.min_width) {
278
284
  if (new_w < (this.rect.parentNode as HTMLElement).offsetWidth) {
279
- css(this.element, 'width', new_w);
285
+ this.applySize(this.element, 'width', new_w);
280
286
  } else {
281
- css(this.element, 'width', '100%');
287
+ this.applySize(this.element, 'width', '100%');
282
288
  }
283
289
  }
284
290
 
285
291
  if (new_h > this.j.o.resizer.min_height) {
286
- css(this.element, 'height', new_h);
292
+ this.applySize(this.element, 'height', new_h);
287
293
  }
288
294
 
289
295
  this.updateSize();
@@ -297,6 +303,18 @@ export class resizer extends Plugin {
297
303
  }
298
304
  };
299
305
 
306
+ private applySize(
307
+ element: HTMLElement,
308
+ key: 'width' | 'height',
309
+ value: number | string
310
+ ): void {
311
+ if (Dom.isImage(element) && this.j.o.resizer.forImageChangeAttributes) {
312
+ attr(element, key, value);
313
+ } else {
314
+ css(element, key, value);
315
+ }
316
+ }
317
+
300
318
  private onClickOutside = (e: MouseEvent) => {
301
319
  if (this.isShown) {
302
320
  if (this.isResized) {
@@ -114,7 +114,7 @@ export class resizeHandler extends Plugin {
114
114
  */
115
115
  private handle = this.j.c.div(
116
116
  'jodit-editor__resize',
117
- '<a tabindex="-1" href="javascript:void(0)"></a>'
117
+ '<span tabindex="-1"></span>'
118
118
  );
119
119
 
120
120
  /** @override **/