jodit 3.9.3 → 3.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/.idea/workspace.xml +306 -295
  2. package/CHANGELOG.MD +349 -119
  3. package/build/jodit.css +675 -538
  4. package/build/jodit.es2018.css +536 -436
  5. package/build/jodit.es2018.en.css +536 -436
  6. package/build/jodit.es2018.en.js +1529 -738
  7. package/build/jodit.es2018.en.min.css +1 -1
  8. package/build/jodit.es2018.en.min.js +1 -1
  9. package/build/jodit.es2018.js +1533 -742
  10. package/build/jodit.es2018.min.css +1 -1
  11. package/build/jodit.es2018.min.js +1 -1
  12. package/build/jodit.js +2598 -1680
  13. package/build/jodit.min.css +2 -2
  14. package/build/jodit.min.js +1 -1
  15. package/index.d.ts +10 -0
  16. package/package.json +10 -10
  17. package/src/config.ts +19 -20
  18. package/src/core/component/component.ts +16 -15
  19. package/src/core/component/statuses.ts +6 -6
  20. package/src/core/dom.ts +16 -4
  21. package/src/core/events/event-emitter.ts +4 -2
  22. package/src/core/global.ts +13 -2
  23. package/src/core/helpers/append-script.ts +14 -0
  24. package/src/core/helpers/selector.ts +8 -3
  25. package/src/core/helpers/size/index.ts +1 -0
  26. package/src/core/helpers/size/object-size.ts +22 -0
  27. package/src/core/selection/select.ts +1 -0
  28. package/src/core/selection/style/api/{get-closest-wrapper.ts → extract.ts} +26 -43
  29. package/src/core/selection/style/api/finite-state-machine.ts +66 -0
  30. package/src/core/selection/style/api/index.ts +12 -5
  31. package/src/core/selection/style/api/{check-special-elements.ts → is-inside-invisible-element.ts} +1 -1
  32. package/src/core/selection/style/api/is-suit-element.ts +12 -1
  33. package/src/core/selection/style/api/toggle/toggle-css.ts +134 -0
  34. package/src/core/selection/style/api/toggle/toggle-ordered-list.ts +49 -0
  35. package/src/core/selection/style/api/toggle-commit-styles.ts +27 -0
  36. package/src/core/selection/style/api/wrap-and-commit-style.ts +68 -0
  37. package/src/core/selection/style/api/wrap-ordered-list.ts +37 -0
  38. package/src/core/selection/style/api/wrap-unwrapped-text.ts +1 -4
  39. package/src/core/selection/style/apply-style.ts +161 -97
  40. package/src/core/selection/style/commit-style.ts +13 -0
  41. package/src/core/storage/engines/local-storage-provider.ts +9 -3
  42. package/src/core/storage/engines/memory-storage-provider.ts +6 -3
  43. package/src/core/storage/storage.ts +7 -4
  44. package/src/core/ui/button/button/button.less +10 -8
  45. package/src/core/ui/button/button/button.ts +9 -9
  46. package/src/core/ui/button/group/group.ts +2 -2
  47. package/src/core/ui/element.ts +4 -3
  48. package/src/core/ui/form/block/block.ts +1 -1
  49. package/src/core/ui/form/form.ts +8 -0
  50. package/src/core/ui/form/inputs/area/area.less +5 -0
  51. package/src/core/ui/form/inputs/area/area.ts +22 -1
  52. package/src/core/ui/form/inputs/checkbox/checkbox.less +50 -0
  53. package/src/core/ui/form/inputs/checkbox/checkbox.ts +48 -4
  54. package/src/core/ui/form/inputs/input/input.less +1 -1
  55. package/src/core/ui/form/inputs/input/input.ts +14 -4
  56. package/src/core/ui/helpers/buttons.ts +14 -6
  57. package/src/core/ui/icon.ts +3 -1
  58. package/src/core/ui/index.ts +1 -3
  59. package/src/core/ui/list/group.less +8 -2
  60. package/src/core/ui/list/group.ts +2 -2
  61. package/src/{modules/file-browser/consts.ts → core/ui/list/index.ts} +4 -4
  62. package/src/core/ui/list/list.less +10 -1
  63. package/src/core/ui/list/list.ts +20 -3
  64. package/src/core/ui/{separator.ts → list/separator.ts} +2 -2
  65. package/src/core/ui/list/spacer.ts +15 -0
  66. package/src/core/ui/popup/popup.less +5 -3
  67. package/src/core/ui/popup/popup.ts +53 -1
  68. package/src/core/view/view-with-toolbar.ts +6 -1
  69. package/src/jodit.ts +17 -14
  70. package/src/modules/dialog/dialog.less +1 -16
  71. package/src/modules/dialog/dialog.ts +10 -3
  72. package/src/modules/file-browser/builders/context-menu.ts +29 -22
  73. package/src/modules/file-browser/config.ts +10 -2
  74. package/src/modules/file-browser/file-browser.ts +50 -29
  75. package/src/modules/file-browser/listeners/native-listeners.ts +37 -19
  76. package/src/modules/file-browser/listeners/state-listeners.ts +48 -22
  77. package/src/modules/file-browser/styles/file-browser.less +4 -291
  78. package/src/modules/file-browser/styles/preview.less +11 -8
  79. package/src/modules/file-browser/ui/files/files.less +174 -0
  80. package/src/modules/file-browser/ui/files/files.ts +14 -0
  81. package/src/modules/file-browser/ui/index.ts +8 -0
  82. package/src/modules/file-browser/ui/tree/tree.less +118 -0
  83. package/src/modules/file-browser/ui/tree/tree.ts +14 -0
  84. package/src/modules/status-bar/status-bar.less +27 -1
  85. package/src/modules/status-bar/status-bar.ts +15 -1
  86. package/src/modules/toolbar/collection/collection.ts +17 -8
  87. package/src/modules/toolbar/collection/editor-collection.ts +27 -2
  88. package/src/modules/widget/file-selector/file-selector.ts +1 -1
  89. package/src/modules/widget/tabs/tabs.less +2 -1
  90. package/src/modules/widget/tabs/tabs.ts +5 -3
  91. package/src/plugins/add-new-line/add-new-line.ts +1 -0
  92. package/src/plugins/bold.ts +2 -2
  93. package/src/plugins/clipboard/drag-and-drop.ts +4 -1
  94. package/src/plugins/clipboard/paste/paste.ts +1 -1
  95. package/src/plugins/font.ts +11 -1
  96. package/src/plugins/image/image-properties/image-properties.ts +7 -0
  97. package/src/plugins/index.ts +1 -0
  98. package/src/plugins/inline-popup/config/config.ts +1 -0
  99. package/src/plugins/inline-popup/config/items/toolbar.ts +33 -0
  100. package/src/plugins/inline-popup/inline-popup.ts +17 -0
  101. package/src/plugins/keyboard/delete.ts +30 -8
  102. package/src/plugins/link/template.ts +2 -2
  103. package/src/plugins/mobile.ts +10 -14
  104. package/src/plugins/ordered-list.ts +40 -1
  105. package/src/plugins/powered-by-jodit.ts +39 -0
  106. package/src/plugins/print/preview.ts +103 -48
  107. package/src/plugins/resizer/resizer.less +10 -7
  108. package/src/plugins/resizer/resizer.ts +12 -14
  109. package/src/plugins/size/resize-handler.ts +4 -1
  110. package/src/plugins/size/size.less +2 -19
  111. package/src/plugins/size/size.ts +6 -1
  112. package/src/plugins/source/const.ts +7 -0
  113. package/src/plugins/source/editor/engines/ace.ts +5 -0
  114. package/src/plugins/source/source.ts +33 -7
  115. package/src/plugins/sticky/sticky.ts +2 -0
  116. package/src/styles/icons/index.ts +2 -0
  117. package/src/styles/icons/resize-handler.svg +4 -0
  118. package/src/styles/jodit.less +6 -0
  119. package/src/styles/mixins.less +20 -0
  120. package/src/styles/themes/dark.less +11 -1
  121. package/src/types/ajax.d.ts +0 -1
  122. package/src/types/file-browser.d.ts +13 -1
  123. package/src/types/jodit.d.ts +4 -1
  124. package/src/types/popup.d.ts +1 -0
  125. package/src/types/select.d.ts +2 -0
  126. package/src/types/storage.ts +3 -3
  127. package/src/types/style.d.ts +8 -0
  128. package/src/types/toolbar.d.ts +9 -2
  129. package/src/types/types.d.ts +1 -1
  130. package/src/types/ui.d.ts +23 -4
  131. package/src/types/view.d.ts +1 -0
  132. package/types/core/component/component.d.ts +10 -5
  133. package/types/core/component/statuses.d.ts +6 -6
  134. package/types/core/dom.d.ts +3 -2
  135. package/types/core/helpers/append-script.d.ts +1 -0
  136. package/types/core/helpers/selector.d.ts +2 -3
  137. package/types/core/helpers/size/index.d.ts +1 -0
  138. package/types/core/helpers/size/object-size.d.ts +7 -0
  139. package/types/core/selection/style/api/{get-closest-wrapper.d.ts → extract.d.ts} +6 -5
  140. package/types/core/selection/style/api/finite-state-machine.d.ts +21 -0
  141. package/types/core/selection/style/api/index.d.ts +12 -5
  142. package/types/core/selection/style/api/{check-special-elements.d.ts → is-inside-invisible-element.d.ts} +1 -1
  143. package/types/core/selection/style/api/is-suit-element.d.ts +9 -0
  144. package/types/core/selection/style/api/toggle/toggle-css.d.ts +11 -0
  145. package/types/core/selection/style/api/toggle/toggle-ordered-list.d.ts +11 -0
  146. package/types/core/selection/style/api/{toggle-styles.d.ts → toggle-commit-styles.d.ts} +1 -3
  147. package/types/core/selection/style/api/{post-process-list-element.d.ts → wrap-and-commit-style.d.ts} +3 -3
  148. package/types/core/selection/style/api/wrap-ordered-list.d.ts +12 -0
  149. package/types/core/selection/style/apply-style.d.ts +1 -4
  150. package/types/core/selection/style/commit-style.d.ts +7 -0
  151. package/types/core/storage/engines/local-storage-provider.d.ts +3 -3
  152. package/types/core/storage/engines/memory-storage-provider.d.ts +3 -3
  153. package/types/core/storage/storage.d.ts +3 -3
  154. package/types/core/ui/button/button/button.d.ts +3 -3
  155. package/types/core/ui/form/form.d.ts +1 -0
  156. package/types/core/ui/form/inputs/area/area.d.ts +7 -1
  157. package/types/core/ui/form/inputs/checkbox/checkbox.d.ts +10 -3
  158. package/types/core/ui/helpers/buttons.d.ts +2 -2
  159. package/types/core/ui/icon.d.ts +1 -1
  160. package/types/core/ui/index.d.ts +1 -3
  161. package/types/core/ui/list/group.d.ts +2 -1
  162. package/types/core/ui/list/index.d.ts +9 -0
  163. package/types/core/ui/{separator.d.ts → list/separator.d.ts} +1 -1
  164. package/types/core/ui/list/spacer.d.ts +9 -0
  165. package/types/core/ui/popup/popup.d.ts +2 -1
  166. package/types/core/view/view-with-toolbar.d.ts +4 -2
  167. package/types/jodit.d.ts +6 -6
  168. package/types/modules/file-browser/file-browser.d.ts +3 -2
  169. package/types/modules/file-browser/listeners/native-listeners.d.ts +5 -1
  170. package/types/modules/file-browser/ui/files/files.d.ts +10 -0
  171. package/types/modules/file-browser/ui/index.d.ts +7 -0
  172. package/types/modules/file-browser/ui/tree/tree.d.ts +10 -0
  173. package/types/modules/status-bar/status-bar.d.ts +6 -1
  174. package/types/modules/toolbar/button/button.d.ts +1 -1
  175. package/types/modules/toolbar/collection/collection.d.ts +5 -2
  176. package/types/modules/toolbar/collection/editor-collection.d.ts +9 -1
  177. package/types/modules/widget/tabs/tabs.d.ts +2 -1
  178. package/types/plugins/index.d.ts +1 -0
  179. package/types/plugins/inline-popup/inline-popup.d.ts +4 -0
  180. package/types/plugins/keyboard/delete.d.ts +2 -0
  181. package/types/plugins/ordered-list.d.ts +8 -1
  182. package/types/plugins/powered-by-jodit.d.ts +12 -0
  183. package/types/plugins/source/const.d.ts +6 -0
  184. package/types/plugins/source/editor/engines/ace.d.ts +1 -0
  185. package/types/plugins/source/source.d.ts +1 -0
  186. package/types/styles/icons/index.d.ts +2 -1
  187. package/types/types/storage.d.ts +3 -3
  188. package/types/types/{ajax.d.ts → types/ajax.d.ts} +0 -1
  189. package/types/types/{async.d.ts → types/async.d.ts} +0 -0
  190. package/types/types/{context.d.ts → types/context.d.ts} +0 -0
  191. package/types/types/{core.ts → types/core.ts} +0 -0
  192. package/types/types/{create.d.ts → types/create.d.ts} +0 -0
  193. package/types/types/{dialog.d.ts → types/dialog.d.ts} +0 -0
  194. package/types/types/{events.d.ts → types/events.d.ts} +0 -0
  195. package/types/types/{file-browser.d.ts → types/file-browser.d.ts} +13 -1
  196. package/types/types/{form.d.ts → types/form.d.ts} +0 -0
  197. package/types/types/{index.d.ts → types/index.d.ts} +0 -0
  198. package/types/types/{jodit.d.ts → types/jodit.d.ts} +4 -1
  199. package/types/types/{observe.d.ts → types/observe.d.ts} +0 -0
  200. package/types/types/{plugin.d.ts → types/plugin.d.ts} +0 -0
  201. package/types/types/{popup.d.ts → types/popup.d.ts} +1 -0
  202. package/types/types/{select.d.ts → types/select.d.ts} +2 -0
  203. package/types/types/{source.d.ts → types/source.d.ts} +0 -0
  204. package/types/types/{storage.ts → types/storage.ts} +3 -3
  205. package/types/types/{style.d.ts → types/style.d.ts} +8 -0
  206. package/types/types/{toolbar.d.ts → types/toolbar.d.ts} +9 -2
  207. package/types/types/{traits.d.ts → types/traits.d.ts} +0 -0
  208. package/types/types/{types.d.ts → types/types.d.ts} +1 -1
  209. package/types/types/{ui.d.ts → types/ui.d.ts} +23 -4
  210. package/types/types/{uploader.d.ts → types/uploader.d.ts} +0 -0
  211. package/types/types/{view.d.ts → types/view.d.ts} +1 -0
  212. package/src/core/selection/style/api/post-process-list-element.ts +0 -33
  213. package/src/core/selection/style/api/toggle-styles.ts +0 -74
  214. package/types/modules/file-browser/consts.d.ts +0 -8
@@ -21,7 +21,8 @@ import { UIButton } from '../button';
21
21
  import { getStrongControlTypes } from '../helpers/get-strong-control-types';
22
22
  import { component, watch } from '../../decorators';
23
23
  import { UIGroup } from './group';
24
- import { UISeparator } from '../separator';
24
+ import { UISpacer } from './spacer';
25
+ import { UISeparator } from './separator';
25
26
  import { isButtonGroup } from '../helpers/buttons';
26
27
  import { getControlType } from '../helpers/get-control-type';
27
28
  import { splitArray } from '../../helpers';
@@ -89,8 +90,9 @@ export class UIList<T extends IViewBased = IViewBased>
89
90
 
90
91
  let lastBtnSeparator: boolean = false;
91
92
 
92
- let line: IUIGroup = this.makeGroup();
93
+ let line = this.makeGroup();
93
94
  this.append(line);
95
+ line.setMod('line', true);
94
96
 
95
97
  let group: IUIGroup;
96
98
 
@@ -100,6 +102,7 @@ export class UIList<T extends IViewBased = IViewBased>
100
102
  switch (control.name) {
101
103
  case '\n':
102
104
  line = this.makeGroup();
105
+ line.setMod('line', true);
103
106
  group = this.makeGroup();
104
107
  line.append(group);
105
108
  this.append(line);
@@ -112,6 +115,19 @@ export class UIList<T extends IViewBased = IViewBased>
112
115
  }
113
116
  break;
114
117
 
118
+ case '---': {
119
+ group.setMod('before-spacer', true);
120
+
121
+ const space = new UISpacer(this.j);
122
+ line.append(space);
123
+
124
+ group = this.makeGroup();
125
+ line.append(group);
126
+ lastBtnSeparator = false;
127
+
128
+ break;
129
+ }
130
+
115
131
  default:
116
132
  lastBtnSeparator = false;
117
133
  elm = this.makeButton(control, target);
@@ -136,9 +152,10 @@ export class UIList<T extends IViewBased = IViewBased>
136
152
 
137
153
  if (buttons.length) {
138
154
  group = this.makeGroup();
139
- line.append(group);
140
155
  group.setMod('separated', true).setMod('group', item.group);
141
156
 
157
+ line.append(group);
158
+
142
159
  getStrongControlTypes(buttons, this.j.o.controls)
143
160
  .filter(isNotRemoved)
144
161
  .forEach(addButton);
@@ -4,8 +4,8 @@
4
4
  * Copyright (c) 2013-2021 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
6
 
7
- import { UIElement } from './element';
8
- import { component } from '../decorators';
7
+ import { UIElement } from '../element';
8
+ import { component } from '../../decorators';
9
9
 
10
10
  @component
11
11
  export class UISeparator extends UIElement {
@@ -0,0 +1,15 @@
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 { UIElement } from '../element';
8
+ import { component } from '../../decorators';
9
+
10
+ @component
11
+ export class UISpacer extends UIElement {
12
+ className(): string {
13
+ return 'UISpacer';
14
+ }
15
+ }
@@ -7,16 +7,18 @@
7
7
  @import (reference) '../../../styles/variables';
8
8
  @import (reference) '../../../styles/mixins';
9
9
 
10
- .jodit-popup {
11
- --box-shadow: 0 4px 1px -2px rgba(76, 76, 76, 0.2),
10
+ :root {
11
+ --popup-box-shadow: 0 4px 1px -2px rgba(76, 76, 76, 0.2),
12
12
  0 3px 3px 0 rgba(76, 76, 76, 0.15), 0 1px 4px 0 rgba(76, 76, 76, 0.13);
13
+ }
13
14
 
15
+ .jodit-popup {
14
16
  .jodit-box();
15
17
 
16
18
  position: fixed;
17
19
  z-index: var(--z-index-popup);
18
20
  display: inline-block;
19
- box-shadow: var(--box-shadow);
21
+ box-shadow: var(--popup-box-shadow);
20
22
  transform: translate3d(0, 0, 0);
21
23
 
22
24
  &__content {
@@ -109,6 +109,8 @@ export class Popup extends UIElement implements IPopup {
109
109
  open(getBound: getBoundFunc, keepPosition: boolean = false): this {
110
110
  markOwner(this.jodit, this.container);
111
111
 
112
+ this.calculateZIndex();
113
+
112
114
  this.isOpened = true;
113
115
  this.addGlobalListeners();
114
116
 
@@ -129,6 +131,56 @@ export class Popup extends UIElement implements IPopup {
129
131
  return this;
130
132
  }
131
133
 
134
+ private calculateZIndex(): void {
135
+ if (this.container.style.zIndex) {
136
+ return;
137
+ }
138
+
139
+ const checkView = (view: IViewBased): boolean => {
140
+ const zIndex = view.container.style.zIndex || view.o.zIndex;
141
+
142
+ if (zIndex) {
143
+ this.setZIndex(1 + parseInt(zIndex.toString(), 10));
144
+ return true;
145
+ }
146
+
147
+ return false;
148
+ };
149
+
150
+ if (checkView(this.j)) {
151
+ return;
152
+ }
153
+
154
+ let pe = this.parentElement;
155
+
156
+ while (pe) {
157
+ if (checkView(pe.j)) {
158
+ return;
159
+ }
160
+
161
+ if (pe.container.style.zIndex) {
162
+ this.setZIndex(
163
+ 1 + parseInt(pe.container.style.zIndex.toString(), 10)
164
+ );
165
+ return;
166
+ }
167
+
168
+ if (!pe.parentElement && pe.container.parentElement) {
169
+ const elm = UIElement.closestElement(
170
+ pe.container.parentElement,
171
+ UIElement
172
+ );
173
+
174
+ if (elm) {
175
+ pe = elm;
176
+ continue;
177
+ }
178
+ }
179
+
180
+ pe = pe.parentElement;
181
+ }
182
+ }
183
+
132
184
  /**
133
185
  * Calculate static bound for point
134
186
  */
@@ -378,7 +430,7 @@ export class Popup extends UIElement implements IPopup {
378
430
  /**
379
431
  * Set ZIndex
380
432
  */
381
- setZIndex(index: number): void {
433
+ setZIndex(index: number | string): void {
382
434
  this.container.style.zIndex = index.toString();
383
435
  }
384
436
 
@@ -24,7 +24,8 @@ import { isButtonGroup } from '../ui/helpers/buttons';
24
24
  import { autobind } from '../decorators';
25
25
 
26
26
  export abstract class ViewWithToolbar extends View implements IViewWithToolbar {
27
- toolbar: IToolbarCollection = makeCollection(this);
27
+ TOOLBAR!: IToolbarCollection;
28
+ toolbar: this['TOOLBAR'] = makeCollection(this);
28
29
 
29
30
  private defaultToolbarContainer: HTMLElement =
30
31
  this.c.div('jodit-toolbar__box');
@@ -75,6 +76,10 @@ export abstract class ViewWithToolbar extends View implements IViewWithToolbar {
75
76
  registeredButtons: Set<IPluginButton> = new Set();
76
77
  private groupToButtons: IDictionary<string[]> = {};
77
78
 
79
+ getRegisteredButtonGroups(): IDictionary<string[]> {
80
+ return this.groupToButtons;
81
+ }
82
+
78
83
  /**
79
84
  * Register button for group
80
85
  */
package/src/jodit.ts CHANGED
@@ -111,17 +111,6 @@ export class Jodit extends ViewWithToolbar implements IJodit {
111
111
  return div.innerText || '';
112
112
  }
113
113
 
114
- /**
115
- * HTML value
116
- */
117
- get value(): string {
118
- return this.getEditorValue();
119
- }
120
-
121
- set value(html: string) {
122
- this.setEditorValue(html);
123
- }
124
-
125
114
  /**
126
115
  * Return default timeout period in milliseconds for some debounce or throttle functions.
127
116
  * By default return `{observer.timeout}` options
@@ -406,10 +395,24 @@ export class Jodit extends ViewWithToolbar implements IJodit {
406
395
  }
407
396
  }
408
397
 
398
+ /**
399
+ * HTML value
400
+ */
401
+ get value(): string {
402
+ return this.getEditorValue();
403
+ }
404
+
405
+ set value(html: string) {
406
+ this.setEditorValue(html);
407
+ }
408
+
409
409
  /**
410
410
  * Return editor value
411
411
  */
412
- getEditorValue(removeSelectionMarkers: boolean = true): string {
412
+ getEditorValue(
413
+ removeSelectionMarkers: boolean = true,
414
+ consumer?: string
415
+ ): string {
413
416
  /**
414
417
  * Triggered before getEditorValue executed.
415
418
  * If returned not undefined getEditorValue will return this value
@@ -423,7 +426,7 @@ export class Jodit extends ViewWithToolbar implements IJodit {
423
426
  */
424
427
  let value: string;
425
428
 
426
- value = this.e.fire('beforeGetValueFromEditor');
429
+ value = this.e.fire('beforeGetValueFromEditor', consumer);
427
430
 
428
431
  if (value !== undefined) {
429
432
  return value;
@@ -459,7 +462,7 @@ export class Jodit extends ViewWithToolbar implements IJodit {
459
462
  */
460
463
  const new_value: { value: string } = { value };
461
464
 
462
- this.e.fire('afterGetValueFromEditor', new_value);
465
+ this.e.fire('afterGetValueFromEditor', new_value, consumer);
463
466
 
464
467
  return new_value.value;
465
468
  }
@@ -115,7 +115,6 @@
115
115
 
116
116
  &__header {
117
117
  display: flex;
118
- overflow: hidden;
119
118
  min-height: 50px;
120
119
  justify-content: space-between;
121
120
  border-bottom: 1px solid var(--color-border);
@@ -268,21 +267,7 @@
268
267
  }
269
268
 
270
269
  &__resizer {
271
- position: absolute;
272
- right: 0;
273
- bottom: 0;
274
- display: inline-block;
275
- width: 0;
276
- height: 0;
277
- border-right: 0 solid transparent;
278
- border-bottom: 10px solid var(--color-border);
279
- border-left: 10px solid transparent;
280
- cursor: se-resize;
281
- opacity: 1;
282
-
283
- &:hover {
284
- border-bottom-color: rgba(0, 0, 0, 0.6);
285
- }
270
+ .resize-handle();
286
271
  }
287
272
 
288
273
  @media (max-width: @screen-xs) {
@@ -39,6 +39,7 @@ import { STATUSES } from '../../core/component';
39
39
  import { eventEmitter, pluginSystem } from '../../core/global';
40
40
  import { component, autobind, hook } from '../../core/decorators';
41
41
  import { View } from '../../core/view/view';
42
+ import { Icon } from '../../core/ui';
42
43
 
43
44
  declare module '../../config' {
44
45
  interface Config {
@@ -661,8 +662,8 @@ export class Dialog extends ViewWithToolbar implements IDialog {
661
662
  /**
662
663
  * Called up to close the window
663
664
  */
664
- if (this.e) {
665
- this.e.fire('beforeClose', this);
665
+ if (this.e && this.e.fire('beforeClose', this) === false) {
666
+ return this;
666
667
  }
667
668
 
668
669
  this.setMod('active', false);
@@ -723,7 +724,13 @@ export class Dialog extends ViewWithToolbar implements IDialog {
723
724
  </div>
724
725
  <div class="${n('content')}"></div>
725
726
  <div class="${n('footer')}"></div>
726
- ${self.o.resizable ? `<div class="${n('resizer')}"></div>` : ''}
727
+ ${
728
+ self.o.resizable
729
+ ? `<div class="${n('resizer')}">${Icon.get(
730
+ 'resize_handler'
731
+ )}</div>`
732
+ : ''
733
+ }
727
734
  </div>
728
735
  </div>`
729
736
  ) as HTMLDivElement;
@@ -8,16 +8,15 @@ import type { FileBrowser } from '../file-browser';
8
8
  import { Dialog } from '../../dialog';
9
9
 
10
10
  import { Dom } from '../../../core/dom';
11
- import { F_CLASS, ICON_LOADER, ITEM_CLASS } from '../consts';
12
11
  import { attr, error } from '../../../core/helpers';
13
12
  import { makeContextMenu } from '../factories';
14
13
  import { Icon } from '../../../core/ui';
15
- import { getItem } from '../listeners/native-listeners';
14
+ import { elementToItem, getItem } from '../listeners/native-listeners';
16
15
  import { openImageEditor } from '../../image-editor/image-editor';
17
16
 
18
- const CLASS_PREVIEW = F_CLASS + '_preview_',
17
+ const CLASS_PREVIEW = 'jodit-filebrowser-preview',
19
18
  preview_tpl_next = (next = 'next', right = 'right') =>
20
- `<div class="${CLASS_PREVIEW}navigation ${CLASS_PREVIEW}navigation-${next}">` +
19
+ `<div class="${CLASS_PREVIEW}__navigation ${CLASS_PREVIEW}__navigation_arrow_${next}">` +
21
20
  '' +
22
21
  Icon.get('angle-' + right) +
23
22
  '</a>';
@@ -42,6 +41,14 @@ export default (self: FileBrowser): ((e: DragEvent) => boolean | void) => {
42
41
  ga = (key: string) => attr(item, key) || '';
43
42
 
44
43
  self.async.setTimeout(() => {
44
+ const selectedItem = elementToItem(a, self.elementsMap);
45
+
46
+ if (!selectedItem) {
47
+ return;
48
+ }
49
+
50
+ self.state.activeElements = [selectedItem];
51
+
45
52
  contextmenu.show(e.clientX, e.clientY, [
46
53
  ga('data-is-file') !== '1' &&
47
54
  opt.editImage &&
@@ -105,11 +112,11 @@ export default (self: FileBrowser): ((e: DragEvent) => boolean | void) => {
105
112
  buttons: ['fullsize', 'dialog.close']
106
113
  }),
107
114
  temp_content = self.c.div(
108
- F_CLASS + '_preview',
109
- ICON_LOADER
115
+ CLASS_PREVIEW,
116
+ '<div class="jodit-icon_loader"></div>'
110
117
  ),
111
118
  preview_box = self.c.div(
112
- F_CLASS + '_preview_box'
119
+ CLASS_PREVIEW + '__box'
113
120
  ),
114
121
  next = self.c.fromHTML(preview_tpl_next()),
115
122
  prev = self.c.fromHTML(
@@ -133,7 +140,9 @@ export default (self: FileBrowser): ((e: DragEvent) => boolean | void) => {
133
140
  if (
134
141
  Dom.prevWithClass(
135
142
  item,
136
- ITEM_CLASS
143
+ self.files.getFullElName(
144
+ 'item'
145
+ )
137
146
  )
138
147
  ) {
139
148
  temp_content.appendChild(
@@ -144,7 +153,9 @@ export default (self: FileBrowser): ((e: DragEvent) => boolean | void) => {
144
153
  if (
145
154
  Dom.nextWithClass(
146
155
  item,
147
- ITEM_CLASS
156
+ self.files.getFullElName(
157
+ 'item'
158
+ )
148
159
  )
149
160
  ) {
150
161
  temp_content.appendChild(
@@ -177,20 +188,15 @@ export default (self: FileBrowser): ((e: DragEvent) => boolean | void) => {
177
188
  [next, prev],
178
189
  'click',
179
190
  function (this: HTMLElement) {
180
- if (
181
- this.classList.contains(
182
- CLASS_PREVIEW +
183
- 'navigation-next'
184
- )
185
- ) {
191
+ if (this === next) {
186
192
  item = Dom.nextWithClass(
187
193
  item,
188
- ITEM_CLASS
194
+ self.files.getFullElName('item')
189
195
  ) as HTMLElement;
190
196
  } else {
191
197
  item = Dom.prevWithClass(
192
198
  item,
193
- ITEM_CLASS
199
+ self.files.getFullElName('item')
194
200
  ) as HTMLElement;
195
201
  }
196
202
 
@@ -201,7 +207,8 @@ export default (self: FileBrowser): ((e: DragEvent) => boolean | void) => {
201
207
  Dom.detach(temp_content);
202
208
  Dom.detach(preview_box);
203
209
 
204
- temp_content.innerHTML = ICON_LOADER;
210
+ temp_content.innerHTML =
211
+ '<div class="jodit-icon_loader"></div>';
205
212
 
206
213
  addLoadHandler(ga('href'));
207
214
  }
@@ -212,7 +219,7 @@ export default (self: FileBrowser): ((e: DragEvent) => boolean | void) => {
212
219
  });
213
220
 
214
221
  preview.container.classList.add(
215
- F_CLASS + '_preview_dialog'
222
+ CLASS_PREVIEW + '__dialog'
216
223
  );
217
224
  preview.setContent(temp_content);
218
225
  preview.setPosition();
@@ -242,9 +249,9 @@ export default (self: FileBrowser): ((e: DragEvent) => boolean | void) => {
242
249
  ]);
243
250
  }, self.defaultTimeout);
244
251
 
245
- self?.e.on('beforeDestruct', () => {
246
- contextmenu.destruct();
247
- });
252
+ self?.dialog.e
253
+ .on('beforeClose', () => contextmenu.close())
254
+ .on('beforeDestruct', () => contextmenu.destruct());
248
255
 
249
256
  e.stopPropagation();
250
257
  e.preventDefault();
@@ -20,7 +20,6 @@ import type {
20
20
  } from '../../types/';
21
21
 
22
22
  import { humanSizeToBytes, isArray, isString } from '../../core/helpers';
23
- import { ITEM_CLASS as IC } from './consts';
24
23
  import { UIFileInput } from '../../core/ui';
25
24
 
26
25
  declare module '../../config' {
@@ -117,7 +116,9 @@ Config.prototype.filebrowser = {
117
116
  renameFolder: true,
118
117
  moveFolder: true,
119
118
  moveFile: true,
119
+
120
120
  showFoldersPanel: true,
121
+ storeLastOpenedFolder: true,
121
122
 
122
123
  width: 859,
123
124
  height: 400,
@@ -156,7 +157,13 @@ Config.prototype.filebrowser = {
156
157
  showFileName: true,
157
158
  showFileSize: true,
158
159
  showFileChangeTime: true,
159
- saveStateInStorage: true,
160
+
161
+ saveStateInStorage: {
162
+ storeLastOpenedFolder: true,
163
+ storeView: true,
164
+ storeSortBy: true
165
+ },
166
+
160
167
  pixelOffsetLoadNewChunk: 200,
161
168
 
162
169
  getThumbTemplate(
@@ -166,6 +173,7 @@ Config.prototype.filebrowser = {
166
173
  source_name: string
167
174
  ): string {
168
175
  const opt = this.options,
176
+ IC = this.files.getFullElName('item'),
169
177
  showName = opt.showFileName,
170
178
  showSize = opt.showFileSize && item.size,
171
179
  showTime = opt.showFileChangeTime && item.time;
@@ -36,26 +36,30 @@ import './config';
36
36
 
37
37
  import { Dom } from '../../core/dom';
38
38
  import { ObserveObject } from '../../core/events/';
39
- import { F_CLASS, ICON_LOADER } from './consts';
40
39
  import { makeDataProvider } from './factories';
41
40
  import { stateListeners } from './listeners/state-listeners';
42
41
  import { nativeListeners } from './listeners/native-listeners';
43
42
  import { selfListeners } from './listeners/self-listeners';
44
43
  import { DEFAULT_SOURCE_NAME } from './data-provider';
45
44
  import { autobind } from '../../core/decorators';
45
+ import { FileBrowserFiles, FileBrowserTree } from './ui';
46
46
 
47
47
  export class FileBrowser extends ViewWithToolbar implements IFileBrowser {
48
48
  /** @override */
49
49
  className(): string {
50
- return 'FileBrowser';
50
+ return 'Filebrowser';
51
51
  }
52
52
 
53
- private loader = this.c.div(F_CLASS + '__loader', ICON_LOADER);
54
- private browser = this.c.div(F_CLASS + ' non-selected');
55
- private status_line = this.c.div(F_CLASS + '__status');
53
+ private loader = this.c.div(
54
+ this.getFullElName('loader'),
55
+ '<div class="jodit-icon_loader"></div>'
56
+ );
56
57
 
57
- tree = this.c.div(F_CLASS + '__tree');
58
- files = this.c.div(F_CLASS + '__files');
58
+ private browser = this.c.div(this.componentName);
59
+ private status_line = this.c.div(this.getFullElName('status'));
60
+
61
+ tree = new FileBrowserTree(this);
62
+ files = new FileBrowserFiles(this);
59
63
 
60
64
  state = ObserveObject.create<IFileBrowserState>({
61
65
  currentPath: '',
@@ -75,8 +79,8 @@ export class FileBrowser extends ViewWithToolbar implements IFileBrowser {
75
79
  dataProvider!: IFileBrowserDataProvider;
76
80
 
77
81
  async loadItems(): Promise<any> {
78
- this.files.classList.add('jodit-filebrowser_active');
79
- this.files.appendChild(this.loader.cloneNode(true));
82
+ this.files.setMod('active', true);
83
+ this.files.container.appendChild(this.loader.cloneNode(true));
80
84
 
81
85
  return this.dataProvider
82
86
  .items(this.state.currentPath, this.state.currentSource, {
@@ -101,11 +105,11 @@ export class FileBrowser extends ViewWithToolbar implements IFileBrowser {
101
105
  this.uploader.setSource(this.state.currentSource);
102
106
  }
103
107
 
104
- this.tree.classList.add('jodit-filebrowser_active');
108
+ this.tree.setMod('active', true);
105
109
 
106
- Dom.detach(this.tree);
110
+ Dom.detach(this.tree.container);
107
111
 
108
- this.tree.appendChild(this.loader.cloneNode(true));
112
+ this.tree.container.appendChild(this.loader.cloneNode(true));
109
113
 
110
114
  const items = this.loadItems();
111
115
 
@@ -125,7 +129,7 @@ export class FileBrowser extends ViewWithToolbar implements IFileBrowser {
125
129
 
126
130
  return Promise.all([tree, items]).catch(error);
127
131
  } else {
128
- this.tree.classList.remove('jodit-filebrowser_active');
132
+ this.tree.setMod('active', false);
129
133
  }
130
134
 
131
135
  return items.catch(error);
@@ -217,21 +221,23 @@ export class FileBrowser extends ViewWithToolbar implements IFileBrowser {
217
221
  message = message.message;
218
222
  }
219
223
 
220
- this.status_line.classList.remove('jodit-filebrowser_success');
224
+ const successClass = this.getFullElName('status', 'success', true),
225
+ activeClass = this.getFullElName('status', 'active', true);
221
226
 
222
- this.status_line.classList.add('jodit-filebrowser_active');
227
+ this.status_line.classList.remove(successClass);
228
+ this.status_line.classList.add(activeClass);
223
229
 
224
230
  const messageBox = this.c.div();
225
231
  messageBox.textContent = message;
226
232
  this.status_line.appendChild(messageBox);
227
233
 
228
234
  if (success) {
229
- this.status_line.classList.add('jodit-filebrowser_success');
235
+ this.status_line.classList.add(successClass);
230
236
  }
231
237
 
232
238
  this.async.setTimeout(
233
239
  () => {
234
- this.status_line.classList.remove('jodit-filebrowser_active');
240
+ this.status_line.classList.remove(activeClass);
235
241
  Dom.detach(this.status_line);
236
242
  },
237
243
  {
@@ -280,9 +286,9 @@ export class FileBrowser extends ViewWithToolbar implements IFileBrowser {
280
286
  let localTimeout: number = 0;
281
287
 
282
288
  this.e
283
- .off(this.files, 'dblclick')
284
- .on(this.files, 'dblclick', this.onSelect(callback))
285
- .on(this.files, 'touchstart', () => {
289
+ .off(this.files.container, 'dblclick')
290
+ .on(this.files.container, 'dblclick', this.onSelect(callback))
291
+ .on(this.files.container, 'touchstart', () => {
286
292
  const now = new Date().getTime();
287
293
 
288
294
  if (now - localTimeout < consts.EMULATE_DBLCLICK_TIMEOUT) {
@@ -345,7 +351,10 @@ export class FileBrowser extends ViewWithToolbar implements IFileBrowser {
345
351
  Config.defaultOptions.filebrowser
346
352
  ) as IFileBrowserOptions;
347
353
 
348
- self.storage = Storage.makeStorage(this.o.saveStateInStorage);
354
+ self.storage = Storage.makeStorage(
355
+ Boolean(this.o.saveStateInStorage),
356
+ this.componentName
357
+ );
349
358
 
350
359
  self.dataProvider = makeDataProvider(self, self.options);
351
360
 
@@ -366,11 +375,13 @@ export class FileBrowser extends ViewWithToolbar implements IFileBrowser {
366
375
  });
367
376
  });
368
377
 
378
+ self.browser.component = this;
379
+
369
380
  if (self.o.showFoldersPanel) {
370
- self.browser.appendChild(self.tree);
381
+ self.browser.appendChild(self.tree.container);
371
382
  }
372
383
 
373
- self.browser.appendChild(self.files);
384
+ self.browser.appendChild(self.files.container);
374
385
  self.browser.appendChild(self.status_line);
375
386
 
376
387
  selfListeners.call(self);
@@ -404,7 +415,14 @@ export class FileBrowser extends ViewWithToolbar implements IFileBrowser {
404
415
  }
405
416
  });
406
417
 
407
- const view = this.storage.get(F_CLASS + '_view');
418
+ const { storeView, storeSortBy, storeLastOpenedFolder } = this.o
419
+ .saveStateInStorage || {
420
+ storeLastOpenedFolder: false,
421
+ storeView: false,
422
+ storeSortBy: false
423
+ };
424
+
425
+ const view = storeView && this.storage.get('view');
408
426
 
409
427
  if (view && this.o.view == null) {
410
428
  self.state.view = view === 'list' ? 'list' : 'tiles';
@@ -414,7 +432,7 @@ export class FileBrowser extends ViewWithToolbar implements IFileBrowser {
414
432
 
415
433
  this.state.fire('change.view');
416
434
 
417
- const sortBy = self.storage.get<string>(F_CLASS + '_sortby');
435
+ const sortBy = storeSortBy && self.storage.get<string>('sortBy');
418
436
 
419
437
  if (sortBy) {
420
438
  const parts = sortBy.split('-');
@@ -426,10 +444,13 @@ export class FileBrowser extends ViewWithToolbar implements IFileBrowser {
426
444
  self.state.sortBy = self.o.sortBy || 'changed-desc';
427
445
  }
428
446
 
429
- // TODO
430
- // self.dataProvider.currentBaseUrl = $$('base', editorDoc).length
431
- // ? attr($$('base', editorDoc)[0], 'href') || ''
432
- // : location.protocol + '//' + location.host;
447
+ if (storeLastOpenedFolder) {
448
+ const currentPath = self.storage.get<string>('currentPath'),
449
+ currentSource = self.storage.get<string>('currentSource');
450
+
451
+ self.state.currentPath = currentPath ?? '';
452
+ self.state.currentSource = currentSource ?? '';
453
+ }
433
454
 
434
455
  self.initUploader(self);
435
456
  }