@ckeditor/ckeditor5-fullscreen 47.1.0 → 47.2.0-alpha.1

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 (303) hide show
  1. package/README.md +1 -1
  2. package/build/fullscreen.js +2 -2
  3. package/build/translations/af.js +1 -1
  4. package/build/translations/ar.js +1 -1
  5. package/build/translations/ast.js +1 -1
  6. package/build/translations/az.js +1 -1
  7. package/build/translations/be.js +1 -1
  8. package/build/translations/bg.js +1 -1
  9. package/build/translations/bn.js +1 -1
  10. package/build/translations/bs.js +1 -1
  11. package/build/translations/ca.js +1 -1
  12. package/build/translations/cs.js +1 -1
  13. package/build/translations/da.js +1 -1
  14. package/build/translations/de-ch.js +1 -1
  15. package/build/translations/de.js +1 -1
  16. package/build/translations/el.js +1 -1
  17. package/build/translations/en-au.js +1 -1
  18. package/build/translations/en-gb.js +1 -1
  19. package/build/translations/eo.js +1 -1
  20. package/build/translations/es-co.js +1 -1
  21. package/build/translations/es.js +1 -1
  22. package/build/translations/et.js +1 -1
  23. package/build/translations/eu.js +1 -1
  24. package/build/translations/fa.js +1 -1
  25. package/build/translations/fi.js +1 -1
  26. package/build/translations/fr.js +1 -1
  27. package/build/translations/gl.js +1 -1
  28. package/build/translations/gu.js +1 -1
  29. package/build/translations/he.js +1 -1
  30. package/build/translations/hi.js +1 -1
  31. package/build/translations/hr.js +1 -1
  32. package/build/translations/hu.js +1 -1
  33. package/build/translations/hy.js +1 -1
  34. package/build/translations/id.js +1 -1
  35. package/build/translations/it.js +1 -1
  36. package/build/translations/ja.js +1 -1
  37. package/build/translations/jv.js +1 -1
  38. package/build/translations/kk.js +1 -1
  39. package/build/translations/km.js +1 -1
  40. package/build/translations/kn.js +1 -1
  41. package/build/translations/ko.js +1 -1
  42. package/build/translations/ku.js +1 -1
  43. package/build/translations/lt.js +1 -1
  44. package/build/translations/lv.js +1 -1
  45. package/build/translations/ms.js +1 -1
  46. package/build/translations/nb.js +1 -1
  47. package/build/translations/ne.js +1 -1
  48. package/build/translations/nl.js +1 -1
  49. package/build/translations/no.js +1 -1
  50. package/build/translations/oc.js +1 -1
  51. package/build/translations/pl.js +1 -1
  52. package/build/translations/pt-br.js +1 -1
  53. package/build/translations/pt.js +1 -1
  54. package/build/translations/ro.js +1 -1
  55. package/build/translations/ru.js +1 -1
  56. package/build/translations/si.js +1 -1
  57. package/build/translations/sk.js +1 -1
  58. package/build/translations/sl.js +1 -1
  59. package/build/translations/sq.js +1 -1
  60. package/build/translations/sr-latn.js +1 -1
  61. package/build/translations/sr.js +1 -1
  62. package/build/translations/sv.js +1 -1
  63. package/build/translations/th.js +1 -1
  64. package/build/translations/ti.js +1 -1
  65. package/build/translations/tk.js +1 -1
  66. package/build/translations/tr.js +1 -1
  67. package/build/translations/tt.js +1 -1
  68. package/build/translations/ug.js +1 -1
  69. package/build/translations/uk.js +1 -1
  70. package/build/translations/ur.js +1 -1
  71. package/build/translations/uz.js +1 -1
  72. package/build/translations/vi.js +1 -1
  73. package/build/translations/zh-cn.js +1 -1
  74. package/build/translations/zh.js +1 -1
  75. package/dist/index-editor.css +53 -6
  76. package/dist/index.css +54 -7
  77. package/dist/index.css.map +1 -1
  78. package/dist/index.js +277 -48
  79. package/dist/index.js.map +1 -1
  80. package/dist/translations/af.js +1 -1
  81. package/dist/translations/af.umd.js +1 -1
  82. package/dist/translations/ar.js +1 -1
  83. package/dist/translations/ar.umd.js +1 -1
  84. package/dist/translations/ast.js +1 -1
  85. package/dist/translations/ast.umd.js +1 -1
  86. package/dist/translations/az.js +1 -1
  87. package/dist/translations/az.umd.js +1 -1
  88. package/dist/translations/be.js +1 -1
  89. package/dist/translations/be.umd.js +1 -1
  90. package/dist/translations/bg.js +1 -1
  91. package/dist/translations/bg.umd.js +1 -1
  92. package/dist/translations/bn.js +1 -1
  93. package/dist/translations/bn.umd.js +1 -1
  94. package/dist/translations/bs.js +1 -1
  95. package/dist/translations/bs.umd.js +1 -1
  96. package/dist/translations/ca.js +1 -1
  97. package/dist/translations/ca.umd.js +1 -1
  98. package/dist/translations/cs.js +1 -1
  99. package/dist/translations/cs.umd.js +1 -1
  100. package/dist/translations/da.js +1 -1
  101. package/dist/translations/da.umd.js +1 -1
  102. package/dist/translations/de-ch.js +1 -1
  103. package/dist/translations/de-ch.umd.js +1 -1
  104. package/dist/translations/de.js +1 -1
  105. package/dist/translations/de.umd.js +1 -1
  106. package/dist/translations/el.js +1 -1
  107. package/dist/translations/el.umd.js +1 -1
  108. package/dist/translations/en-au.js +1 -1
  109. package/dist/translations/en-au.umd.js +1 -1
  110. package/dist/translations/en-gb.js +1 -1
  111. package/dist/translations/en-gb.umd.js +1 -1
  112. package/dist/translations/en.js +1 -1
  113. package/dist/translations/en.umd.js +1 -1
  114. package/dist/translations/eo.js +1 -1
  115. package/dist/translations/eo.umd.js +1 -1
  116. package/dist/translations/es-co.js +1 -1
  117. package/dist/translations/es-co.umd.js +1 -1
  118. package/dist/translations/es.js +1 -1
  119. package/dist/translations/es.umd.js +1 -1
  120. package/dist/translations/et.js +1 -1
  121. package/dist/translations/et.umd.js +1 -1
  122. package/dist/translations/eu.js +1 -1
  123. package/dist/translations/eu.umd.js +1 -1
  124. package/dist/translations/fa.js +1 -1
  125. package/dist/translations/fa.umd.js +1 -1
  126. package/dist/translations/fi.js +1 -1
  127. package/dist/translations/fi.umd.js +1 -1
  128. package/dist/translations/fr.js +1 -1
  129. package/dist/translations/fr.umd.js +1 -1
  130. package/dist/translations/gl.js +1 -1
  131. package/dist/translations/gl.umd.js +1 -1
  132. package/dist/translations/gu.js +1 -1
  133. package/dist/translations/gu.umd.js +1 -1
  134. package/dist/translations/he.js +1 -1
  135. package/dist/translations/he.umd.js +1 -1
  136. package/dist/translations/hi.js +1 -1
  137. package/dist/translations/hi.umd.js +1 -1
  138. package/dist/translations/hr.js +1 -1
  139. package/dist/translations/hr.umd.js +1 -1
  140. package/dist/translations/hu.js +1 -1
  141. package/dist/translations/hu.umd.js +1 -1
  142. package/dist/translations/hy.js +1 -1
  143. package/dist/translations/hy.umd.js +1 -1
  144. package/dist/translations/id.js +1 -1
  145. package/dist/translations/id.umd.js +1 -1
  146. package/dist/translations/it.js +1 -1
  147. package/dist/translations/it.umd.js +1 -1
  148. package/dist/translations/ja.js +1 -1
  149. package/dist/translations/ja.umd.js +1 -1
  150. package/dist/translations/jv.js +1 -1
  151. package/dist/translations/jv.umd.js +1 -1
  152. package/dist/translations/kk.js +1 -1
  153. package/dist/translations/kk.umd.js +1 -1
  154. package/dist/translations/km.js +1 -1
  155. package/dist/translations/km.umd.js +1 -1
  156. package/dist/translations/kn.js +1 -1
  157. package/dist/translations/kn.umd.js +1 -1
  158. package/dist/translations/ko.js +1 -1
  159. package/dist/translations/ko.umd.js +1 -1
  160. package/dist/translations/ku.js +1 -1
  161. package/dist/translations/ku.umd.js +1 -1
  162. package/dist/translations/lt.js +1 -1
  163. package/dist/translations/lt.umd.js +1 -1
  164. package/dist/translations/lv.js +1 -1
  165. package/dist/translations/lv.umd.js +1 -1
  166. package/dist/translations/ms.js +1 -1
  167. package/dist/translations/ms.umd.js +1 -1
  168. package/dist/translations/nb.js +1 -1
  169. package/dist/translations/nb.umd.js +1 -1
  170. package/dist/translations/ne.js +1 -1
  171. package/dist/translations/ne.umd.js +1 -1
  172. package/dist/translations/nl.js +1 -1
  173. package/dist/translations/nl.umd.js +1 -1
  174. package/dist/translations/no.js +1 -1
  175. package/dist/translations/no.umd.js +1 -1
  176. package/dist/translations/oc.js +1 -1
  177. package/dist/translations/oc.umd.js +1 -1
  178. package/dist/translations/pl.js +1 -1
  179. package/dist/translations/pl.umd.js +1 -1
  180. package/dist/translations/pt-br.js +1 -1
  181. package/dist/translations/pt-br.umd.js +1 -1
  182. package/dist/translations/pt.js +1 -1
  183. package/dist/translations/pt.umd.js +1 -1
  184. package/dist/translations/ro.js +1 -1
  185. package/dist/translations/ro.umd.js +1 -1
  186. package/dist/translations/ru.js +1 -1
  187. package/dist/translations/ru.umd.js +1 -1
  188. package/dist/translations/si.js +1 -1
  189. package/dist/translations/si.umd.js +1 -1
  190. package/dist/translations/sk.js +1 -1
  191. package/dist/translations/sk.umd.js +1 -1
  192. package/dist/translations/sl.js +1 -1
  193. package/dist/translations/sl.umd.js +1 -1
  194. package/dist/translations/sq.js +1 -1
  195. package/dist/translations/sq.umd.js +1 -1
  196. package/dist/translations/sr-latn.js +1 -1
  197. package/dist/translations/sr-latn.umd.js +1 -1
  198. package/dist/translations/sr.js +1 -1
  199. package/dist/translations/sr.umd.js +1 -1
  200. package/dist/translations/sv.js +1 -1
  201. package/dist/translations/sv.umd.js +1 -1
  202. package/dist/translations/th.js +1 -1
  203. package/dist/translations/th.umd.js +1 -1
  204. package/dist/translations/ti.js +1 -1
  205. package/dist/translations/ti.umd.js +1 -1
  206. package/dist/translations/tk.js +1 -1
  207. package/dist/translations/tk.umd.js +1 -1
  208. package/dist/translations/tr.js +1 -1
  209. package/dist/translations/tr.umd.js +1 -1
  210. package/dist/translations/tt.js +1 -1
  211. package/dist/translations/tt.umd.js +1 -1
  212. package/dist/translations/ug.js +1 -1
  213. package/dist/translations/ug.umd.js +1 -1
  214. package/dist/translations/uk.js +1 -1
  215. package/dist/translations/uk.umd.js +1 -1
  216. package/dist/translations/ur.js +1 -1
  217. package/dist/translations/ur.umd.js +1 -1
  218. package/dist/translations/uz.js +1 -1
  219. package/dist/translations/uz.umd.js +1 -1
  220. package/dist/translations/vi.js +1 -1
  221. package/dist/translations/vi.umd.js +1 -1
  222. package/dist/translations/zh-cn.js +1 -1
  223. package/dist/translations/zh-cn.umd.js +1 -1
  224. package/dist/translations/zh.js +1 -1
  225. package/dist/translations/zh.umd.js +1 -1
  226. package/lang/contexts.json +4 -1
  227. package/lang/translations/af.po +12 -0
  228. package/lang/translations/ar.po +12 -0
  229. package/lang/translations/ast.po +12 -0
  230. package/lang/translations/az.po +12 -0
  231. package/lang/translations/be.po +12 -0
  232. package/lang/translations/bg.po +12 -0
  233. package/lang/translations/bn.po +12 -0
  234. package/lang/translations/bs.po +12 -0
  235. package/lang/translations/ca.po +12 -0
  236. package/lang/translations/cs.po +12 -0
  237. package/lang/translations/da.po +12 -0
  238. package/lang/translations/de-ch.po +12 -0
  239. package/lang/translations/de.po +12 -0
  240. package/lang/translations/el.po +12 -0
  241. package/lang/translations/en-au.po +12 -0
  242. package/lang/translations/en-gb.po +12 -0
  243. package/lang/translations/en.po +12 -0
  244. package/lang/translations/eo.po +12 -0
  245. package/lang/translations/es-co.po +12 -0
  246. package/lang/translations/es.po +12 -0
  247. package/lang/translations/et.po +12 -0
  248. package/lang/translations/eu.po +12 -0
  249. package/lang/translations/fa.po +12 -0
  250. package/lang/translations/fi.po +12 -0
  251. package/lang/translations/fr.po +12 -0
  252. package/lang/translations/gl.po +12 -0
  253. package/lang/translations/gu.po +12 -0
  254. package/lang/translations/he.po +12 -0
  255. package/lang/translations/hi.po +12 -0
  256. package/lang/translations/hr.po +12 -0
  257. package/lang/translations/hu.po +12 -0
  258. package/lang/translations/hy.po +12 -0
  259. package/lang/translations/id.po +12 -0
  260. package/lang/translations/it.po +12 -0
  261. package/lang/translations/ja.po +12 -0
  262. package/lang/translations/jv.po +12 -0
  263. package/lang/translations/kk.po +12 -0
  264. package/lang/translations/km.po +12 -0
  265. package/lang/translations/kn.po +12 -0
  266. package/lang/translations/ko.po +12 -0
  267. package/lang/translations/ku.po +12 -0
  268. package/lang/translations/lt.po +12 -0
  269. package/lang/translations/lv.po +12 -0
  270. package/lang/translations/ms.po +12 -0
  271. package/lang/translations/nb.po +12 -0
  272. package/lang/translations/ne.po +12 -0
  273. package/lang/translations/nl.po +12 -0
  274. package/lang/translations/no.po +12 -0
  275. package/lang/translations/oc.po +12 -0
  276. package/lang/translations/pl.po +12 -0
  277. package/lang/translations/pt-br.po +12 -0
  278. package/lang/translations/pt.po +12 -0
  279. package/lang/translations/ro.po +12 -0
  280. package/lang/translations/ru.po +12 -0
  281. package/lang/translations/si.po +12 -0
  282. package/lang/translations/sk.po +12 -0
  283. package/lang/translations/sl.po +12 -0
  284. package/lang/translations/sq.po +12 -0
  285. package/lang/translations/sr-latn.po +12 -0
  286. package/lang/translations/sr.po +12 -0
  287. package/lang/translations/sv.po +12 -0
  288. package/lang/translations/th.po +12 -0
  289. package/lang/translations/ti.po +12 -0
  290. package/lang/translations/tk.po +12 -0
  291. package/lang/translations/tr.po +12 -0
  292. package/lang/translations/tt.po +12 -0
  293. package/lang/translations/ug.po +12 -0
  294. package/lang/translations/uk.po +12 -0
  295. package/lang/translations/ur.po +12 -0
  296. package/lang/translations/uz.po +12 -0
  297. package/lang/translations/vi.po +12 -0
  298. package/lang/translations/zh-cn.po +12 -0
  299. package/lang/translations/zh.po +12 -0
  300. package/package.json +8 -8
  301. package/src/handlers/abstracteditorhandler.d.ts +92 -17
  302. package/src/handlers/abstracteditorhandler.js +303 -49
  303. package/theme/fullscreen.css +54 -7
@@ -5,8 +5,9 @@
5
5
  /**
6
6
  * @module fullscreen/handlers/abstracteditorhandler
7
7
  */
8
- import { BodyCollection, DialogViewPosition } from 'ckeditor5/src/ui.js';
9
- import { global, createElement, Rect } from 'ckeditor5/src/utils.js';
8
+ import { BodyCollection, ButtonView, DialogViewPosition } from 'ckeditor5/src/ui.js';
9
+ import { global, createElement, Rect, ResizeObserver } from 'ckeditor5/src/utils.js';
10
+ import { IconDocumentOutlineToggle, IconPreviousArrow } from '@ckeditor/ckeditor5-icons';
10
11
  const DIALOG_OFFSET = 28;
11
12
  /**
12
13
  * The abstract editor type handler.
@@ -31,21 +32,24 @@ const DIALOG_OFFSET = 28;
31
32
  * editable, toolbar, menu bar.
32
33
  * Use {@link #moveToFullscreen} method for this purpose to ensure they are automatically cleaned up after leaving the fullscreen mode.
33
34
  * 3. Adds proper classes to the `<body>` and `<html>` elements to block page scrolling, adjust `z-index` etc.
34
- * 4. Changes the position of some dialogs to utilize the empty space on the right side of the editable element.
35
35
  *
36
- * Steps 5-11 are only executed if the corresponding features are used.
36
+ * Steps 4-12 are only executed if the corresponding features are used.
37
37
  *
38
- * 5. If presence list is used, moves it to the fullscreen mode container.
39
- * 6. If document outline is used, moves it to the fullscreen mode.
40
- * 7. If pagination is used, adjusts it's configuration for the changed view.
41
- * 8. If annotations are used, moves them to the fullscreen mode.
42
- * 9. If revision history is used, overrides the callbacks to show the revision viewer in the fullscreen mode.
43
- * 10. If source editing and document outline are both used, hides the document outline header.
44
- * 11. If custom container is used, hides all other elements in it to ensure they don't create an empty unscrollable space.
38
+ * 4. If presence list is used, moves it to the fullscreen mode container.
39
+ * 5. If document outline is used, moves it to the fullscreen mode.
40
+ * 6. If pagination is used, adjusts it's configuration for the changed view.
41
+ * 7. If annotations are used, moves them to the fullscreen mode.
42
+ * 8. If revision history is used, overrides the callbacks to show the revision viewer in the fullscreen mode.
43
+ * 9. If AI Tabs is used, moves it to the fullscreen mode.
44
+ * 10. If source editing and document outline are both used, registers a callback hiding the document outline header in source editing mode.
45
+ * 11. Changes the position of some dialogs to utilize the empty space on the right side of the editable element.
46
+ * 12. If custom container is used, hides all other elements in it to ensure they don't create an empty unscrollable space.
45
47
  *
46
48
  * Then finally:
47
49
  *
48
- * 12. Executes the configured {@link module:fullscreen/fullscreenconfig~FullscreenConfig#onEnterCallback
50
+ * 13. Adjusts the visibility of the left and right sidebars based on the available space.
51
+ * 14. Sets up a resize observer to adjust the visibility of the left and right sidebars dynamically.
52
+ * 15. Executes the configured {@link module:fullscreen/fullscreenconfig~FullscreenConfig#onEnterCallback
49
53
  * `config.fullscreen.onEnterCallback`} function.
50
54
  * By default, it returns the fullscreen mode container element so it can be further customized.
51
55
  *
@@ -57,14 +61,15 @@ const DIALOG_OFFSET = 28;
57
61
  * 3. If document outline is used, restore its default container.
58
62
  * 4. If annotations are used, restore their original state (UI, filters etc).
59
63
  * 5. If revision history is used, restore the original callbacks.
60
- * 6. If source editing and document outline are both used, restore the document outline header.
61
- * 7. Restore all moved elements to their original place.
62
- * 8. Destroy the fullscreen mode container.
63
- * 9. If the editor has a toolbar, switch its behavior to the one configured in the
64
+ * 7. If AI Tabs is used, restore it to the original state.
65
+ * 8. If source editing and document outline are both used, restore the document outline header.
66
+ * 9. Restore all moved elements to their original place.
67
+ * 10. Destroy the fullscreen mode container.
68
+ * 11. If the editor has a toolbar, switch its behavior to the one configured in the
64
69
  * {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull} property.
65
- * 10. Restore the scroll positions of all ancestors of the editable element.
66
- * 11. If pagination is used, restore its default configuration.
67
- * 12. Restore default dialogs positions.
70
+ * 12. Restore the scroll positions of all ancestors of the editable element.
71
+ * 13. If pagination is used, restore its default configuration.
72
+ * 14. Restore default dialogs positions.
68
73
  *
69
74
  * This class is exported to allow for custom extensions.
70
75
  */
@@ -90,6 +95,32 @@ export class FullscreenAbstractEditorHandler {
90
95
  * If we don't move pagination lines to the fullscreen container, they won't be visible.
91
96
  */
92
97
  _paginationBodyCollection = null;
98
+ /**
99
+ * Whether the left sidebar collapse button is created.
100
+ */
101
+ _hasLeftCollapseButton = false;
102
+ /**
103
+ * The button that toggles the visibility of the left sidebar.
104
+ */
105
+ _collapseLeftSidebarButton = null;
106
+ /**
107
+ * The resize observer that is used to adjust the visibility of the left and right sidebars dynamically.
108
+ */
109
+ _resizeObserver = null;
110
+ /**
111
+ * The width of the expanded left and right sidebars in the fullscreen mode. Necessary for logic checking if they should be visible.
112
+ */
113
+ _sidebarsWidths = { left: 0, right: 0 };
114
+ /**
115
+ * Whether the left sidebar should be kept hidden even if there is enough space for it. It's set to `true` when user
116
+ * collapses the left sidebar with a button. Behavior is reset when exiting the fullscreen mode.
117
+ */
118
+ _keepLeftSidebarHidden = false;
119
+ /**
120
+ * Temporary flag used to ignore the first automatic layout adjustment logic when user collapses the left sidebar with a button.
121
+ * It is then immediately set back to `false`.
122
+ */
123
+ _forceShowLeftSidebar = false;
93
124
  /**
94
125
  * A callback that hides the document outline header when the source editing mode is enabled.
95
126
  * Document outline element itself is hidden by source editing plugin.
@@ -117,6 +148,10 @@ export class FullscreenAbstractEditorHandler {
117
148
  * A callback that closes the revision viewer, stored to restore the original one after exiting the fullscreen mode.
118
149
  */
119
150
  _closeRevisionViewerCallback = null;
151
+ /**
152
+ * A map of AI Tabs data that were set before entering the fullscreen mode.
153
+ */
154
+ _aiTabsData = null;
120
155
  /**
121
156
  * @inheritDoc
122
157
  */
@@ -133,6 +168,9 @@ export class FullscreenAbstractEditorHandler {
133
168
  if (this._wrapper) {
134
169
  this.destroy();
135
170
  }
171
+ if (this._resizeObserver) {
172
+ this._resizeObserver.destroy();
173
+ }
136
174
  });
137
175
  }
138
176
  /**
@@ -180,6 +218,7 @@ export class FullscreenAbstractEditorHandler {
180
218
  <div class="ck ck-fullscreen__pagination-view" data-ck-fullscreen="pagination-view"></div>
181
219
  </div>
182
220
  <div class="ck ck-fullscreen__sidebar ck-fullscreen__right-sidebar" data-ck-fullscreen="right-sidebar"></div>
221
+ <div class="ck ck-fullscreen__right-edge" data-ck-fullscreen="right-edge"></div>
183
222
  </div>
184
223
  <div class="ck ck-fullscreen__bottom-wrapper">
185
224
  <div class="ck ck-fullscreen__body-wrapper" data-ck-fullscreen="body-wrapper"></div>
@@ -200,9 +239,6 @@ export class FullscreenAbstractEditorHandler {
200
239
  this._document.body.classList.add('ck-fullscreen');
201
240
  this._document.body.parentElement.classList.add('ck-fullscreen');
202
241
  }
203
- if (this._editor.plugins.has('Dialog')) {
204
- this._registerFullscreenDialogPositionAdjustments();
205
- }
206
242
  // Code coverage is provided in the commercial package repository as integration unit tests.
207
243
  /* istanbul ignore if -- @preserve */
208
244
  if (this._editor.plugins.has('PresenceListUI')) {
@@ -213,6 +249,9 @@ export class FullscreenAbstractEditorHandler {
213
249
  if (this._editor.plugins.has('DocumentOutlineUI')) {
214
250
  this._generateDocumentOutlineContainer();
215
251
  }
252
+ if (this._hasLeftCollapseButton) {
253
+ this._generateCollapseButton();
254
+ }
216
255
  // Code coverage is provided in the commercial package repository as integration unit tests.
217
256
  /* istanbul ignore next -- @preserve */
218
257
  if (this._editor.plugins.has('Pagination') && this._editor.plugins.get('Pagination').isEnabled) {
@@ -240,9 +279,19 @@ export class FullscreenAbstractEditorHandler {
240
279
  }
241
280
  this._overrideRevisionHistoryCallbacks();
242
281
  }
282
+ // Code coverage is provided in the commercial package repository as integration unit tests.
283
+ /* istanbul ignore if -- @preserve */
284
+ if (this._editor.plugins.has('AITabs')) {
285
+ this._handleAITabsTransfer();
286
+ }
243
287
  if (this._editor.plugins.has('SourceEditing') && this._editor.plugins.has('DocumentOutlineUI')) {
288
+ // Register a callback to hide the document outline header in source editing mode.
244
289
  this._editor.plugins.get('SourceEditing').on('change:isSourceEditingMode', this._sourceEditingCallback);
245
290
  }
291
+ // Dialog position should be done after all known elements are moved to the fullscreen container.
292
+ if (this._editor.plugins.has('Dialog')) {
293
+ this._registerFullscreenDialogPositionAdjustments();
294
+ }
246
295
  // Hide all other elements in the container to ensure they don't create an empty unscrollable space.
247
296
  for (const element of this._editor.config.get('fullscreen.container').children) {
248
297
  // Do not hide body wrapper and ckbox wrapper to keep dialogs, balloons etc visible.
@@ -255,6 +304,14 @@ export class FullscreenAbstractEditorHandler {
255
304
  element.style.display = 'none';
256
305
  }
257
306
  }
307
+ // Save the information about the width of the left and right sidebars before they possibly get hidden.
308
+ // It will be used for math checking if they should be visible or not dynamically.
309
+ this._sidebarsWidths = {
310
+ left: this._wrapper.querySelector('.ck-fullscreen__left-sidebar').scrollWidth,
311
+ right: this._wrapper.querySelector('.ck-fullscreen__right-sidebar').scrollWidth
312
+ };
313
+ this._adjustVisibleElements();
314
+ this._setupResizeObserver();
258
315
  if (this._editor.config.get('fullscreen.onEnterCallback')) {
259
316
  this._editor.config.get('fullscreen.onEnterCallback')(this.getWrapper());
260
317
  }
@@ -281,6 +338,11 @@ export class FullscreenAbstractEditorHandler {
281
338
  if (this._editor.plugins.has('RevisionHistory')) {
282
339
  this._restoreRevisionHistoryCallbacks();
283
340
  }
341
+ // Code coverage is provided in the commercial package repository as integration unit tests.
342
+ /* istanbul ignore if -- @preserve */
343
+ if (this._editor.plugins.has('AITabs')) {
344
+ this._restoreAITabs();
345
+ }
284
346
  if (this._editor.plugins.has('SourceEditing') && this._editor.plugins.has('DocumentOutlineUI')) {
285
347
  this._editor.plugins.get('SourceEditing').off('change:isSourceEditingMode', this._sourceEditingCallback);
286
348
  }
@@ -318,6 +380,9 @@ export class FullscreenAbstractEditorHandler {
318
380
  if (this._editor.plugins.has('Dialog')) {
319
381
  this._unregisterFullscreenDialogPositionAdjustments();
320
382
  }
383
+ // Reset the behavior of the left sidebar.
384
+ this._keepLeftSidebarHidden = false;
385
+ this._resizeObserver?.destroy();
321
386
  }
322
387
  /**
323
388
  * @inheritDoc
@@ -379,6 +444,7 @@ export class FullscreenAbstractEditorHandler {
379
444
  document.querySelector('[data-ck-fullscreen="left-sidebar-sticky"]').appendChild(presenceListElement);
380
445
  const presenceListUI = this._editor.plugins.get('PresenceListUI');
381
446
  this.moveToFullscreen(presenceListUI.view.element, 'presence-list');
447
+ this._hasLeftCollapseButton = true;
382
448
  }
383
449
  /**
384
450
  * Checks if the DocumentOutlineUI plugin is available and moves its elements to fullscreen mode.
@@ -411,6 +477,7 @@ export class FullscreenAbstractEditorHandler {
411
477
  const documentOutlineUI = this._editor.plugins.get('DocumentOutlineUI');
412
478
  documentOutlineUI.view.documentOutlineContainer = document.querySelector('[data-ck-fullscreen="left-sidebar"]');
413
479
  this.moveToFullscreen(documentOutlineUI.view.element, 'document-outline');
480
+ this._hasLeftCollapseButton = true;
414
481
  }
415
482
  /**
416
483
  * Restores the default value of documentOutlineContainer, which is modified in fullscreen mode.
@@ -421,6 +488,40 @@ export class FullscreenAbstractEditorHandler {
421
488
  const documentOutlineUI = this._editor.plugins.get('DocumentOutlineUI');
422
489
  documentOutlineUI.view.documentOutlineContainer = documentOutlineUI.view.element;
423
490
  }
491
+ // Code coverage is provided in the commercial package repository as integration unit tests.
492
+ /* istanbul ignore next -- @preserve */
493
+ _generateCollapseButton() {
494
+ const button = new ButtonView(this._editor.locale);
495
+ const leftSidebarContainer = document.querySelector('.ck-fullscreen__left-sidebar');
496
+ const t = this._editor.t;
497
+ button.set({
498
+ label: t('Toggle sidebar'),
499
+ class: 'ck-fullscreen__left-sidebar-toggle-button',
500
+ tooltip: t('Hide left sidebar'),
501
+ tooltipPosition: 'se',
502
+ icon: IconPreviousArrow
503
+ });
504
+ button.on('execute', () => {
505
+ // Change the look of the button to reflect the state of the left sidebar.
506
+ if (leftSidebarContainer.classList.contains('ck-fullscreen__left-sidebar--collapsed')) {
507
+ // Enable automatic left sidebar toggling.
508
+ this._forceShowLeftSidebar = true;
509
+ this._keepLeftSidebarHidden = false;
510
+ this._showLeftSidebar();
511
+ }
512
+ else {
513
+ // Disable automatic left sidebar toggling.
514
+ this._keepLeftSidebarHidden = true;
515
+ this._hideLeftSidebar();
516
+ }
517
+ // Keep the focus in the editor whenever the button is clicked.
518
+ this._editor.editing.view.focus();
519
+ });
520
+ button.render();
521
+ this._collapseLeftSidebarButton = button;
522
+ // Append the button at the top of the left sidebar.
523
+ leftSidebarContainer.prepend(button.element);
524
+ }
424
525
  /**
425
526
  * Stores the current state of the annotations UIs to restore it when leaving fullscreen mode and switches the UI to the wide sidebar.
426
527
  */
@@ -429,13 +530,6 @@ export class FullscreenAbstractEditorHandler {
429
530
  _overrideAnnotationsUIs() {
430
531
  const annotationsUIs = this._editor.plugins.get('AnnotationsUIs');
431
532
  this._annotationsUIsData = new Map(annotationsUIs.uisData);
432
- const annotationsFilters = new Map();
433
- for (const [uiName, data] of [...this._annotationsUIsData]) {
434
- // Default filter is `() => true`. Only store filters that are different.
435
- if (data.filter !== annotationsUIs.defaultFilter) {
436
- annotationsFilters.set(uiName, data.filter);
437
- }
438
- }
439
533
  annotationsUIs.deactivateAll();
440
534
  const sidebarPlugin = this._editor.plugins.get('Sidebar');
441
535
  // There are two scenarios to consider: if wide sidebar is already used and when it's not.
@@ -445,7 +539,7 @@ export class FullscreenAbstractEditorHandler {
445
539
  // 3. Move the sidebar element to the fullscreen mode.
446
540
  if (!sidebarPlugin.container) {
447
541
  sidebarPlugin.setContainer(this.getWrapper().querySelector('[data-ck-fullscreen="right-sidebar"]'));
448
- switchToWideSidebar();
542
+ this._switchAnnotationsUI('wideSidebar');
449
543
  this.moveToFullscreen(sidebarPlugin.container.firstElementChild, 'right-sidebar');
450
544
  }
451
545
  // If sidebar was already used:
@@ -455,25 +549,10 @@ export class FullscreenAbstractEditorHandler {
455
549
  // If we set the container before moving the sidebar, we lose the reference to the original sidebar container and it won't be
456
550
  // moved back to the correct position after leaving fullscreen.
457
551
  else {
458
- switchToWideSidebar();
552
+ this._switchAnnotationsUI('wideSidebar');
459
553
  this.moveToFullscreen(sidebarPlugin.container.firstElementChild, 'right-sidebar');
460
554
  sidebarPlugin.setContainer(this.getWrapper().querySelector('[data-ck-fullscreen="right-sidebar"]'));
461
555
  }
462
- function switchToWideSidebar() {
463
- // First, check if someone has a filter defined for `wideSidebar`. If so, retrieve and apply it in fullscreen.
464
- if (annotationsFilters.has('wideSidebar')) {
465
- annotationsUIs.activate('wideSidebar', annotationsFilters.get('wideSidebar'));
466
- }
467
- // If no filter is defined for `wideSidebar`, read the filters for the active display(s) mode and apply them on wide sidebar.
468
- // It's possible there are filters for both `narrowSidebar` and `inline` modes, so display annotations that match any of them.
469
- else if (annotationsFilters.size) {
470
- annotationsUIs.activate('wideSidebar', (annotation) => [...annotationsFilters.values()].some(filter => filter(annotation)));
471
- }
472
- // If no filters are defined for the active display mode(s), simply display all annotations in the wide sidebar.
473
- else {
474
- annotationsUIs.switchTo('wideSidebar');
475
- }
476
- }
477
556
  }
478
557
  /**
479
558
  * Restores the saved state of the annotations UIs.
@@ -606,15 +685,23 @@ export class FullscreenAbstractEditorHandler {
606
685
  if (!dialogView || dialogView.position !== DialogViewPosition.EDITOR_TOP_SIDE) {
607
686
  return;
608
687
  }
609
- const fullscreenViewContainerRect = new Rect(this._wrapper).getVisible();
688
+ // It's possible that the right edge container is used but not visible. We then fallback to the wrapper.
689
+ const keepRightEdgeContainerVisible = new Rect(this._wrapper.querySelector('.ck-fullscreen__right-edge')).getVisible();
690
+ const relativeContainer = keepRightEdgeContainerVisible ?
691
+ this._wrapper.querySelector('.ck-fullscreen__right-edge') :
692
+ this._wrapper;
693
+ const relativeContainerRect = new Rect(relativeContainer).getVisible();
610
694
  const editorContainerRect = new Rect(document.querySelector('.ck-fullscreen__editable')).getVisible();
611
695
  const dialogRect = new Rect(dialogView.element.querySelector('.ck-dialog')).getVisible();
612
696
  const scrollOffset = new Rect(document.querySelector('.ck-fullscreen__editable-wrapper'))
613
697
  .excludeScrollbarsAndBorders().getVisible().width -
614
698
  new Rect(document.querySelector('.ck-fullscreen__editable-wrapper')).getVisible().width;
615
- if (fullscreenViewContainerRect && editorContainerRect && dialogRect) {
699
+ if (relativeContainerRect && editorContainerRect && dialogRect) {
616
700
  dialogView.position = null;
617
- dialogView.moveTo(fullscreenViewContainerRect.left + fullscreenViewContainerRect.width - dialogRect.width - DIALOG_OFFSET + scrollOffset, editorContainerRect.top);
701
+ const leftOffset = keepRightEdgeContainerVisible ?
702
+ relativeContainerRect.left - dialogRect.width - DIALOG_OFFSET :
703
+ relativeContainerRect.left + relativeContainerRect.width - dialogRect.width - DIALOG_OFFSET + scrollOffset;
704
+ dialogView.moveTo(leftOffset, editorContainerRect.top);
618
705
  }
619
706
  }
620
707
  /**
@@ -647,4 +734,171 @@ export class FullscreenAbstractEditorHandler {
647
734
  element = element.parentElement;
648
735
  }
649
736
  }
737
+ /**
738
+ * Stores the current state of the AI Tabs and moves it to the fullscreen mode.
739
+ */
740
+ // Code coverage is provided in the commercial package repository as integration unit tests.
741
+ /* istanbul ignore next -- @preserve */
742
+ _handleAITabsTransfer() {
743
+ const aiTabs = this._editor.plugins.get('AITabs');
744
+ this._aiTabsData = {
745
+ side: aiTabs.side,
746
+ type: aiTabs.type
747
+ };
748
+ this.moveToFullscreen(aiTabs.view.element, 'right-edge');
749
+ aiTabs.side = 'right';
750
+ aiTabs.type = 'sidebar';
751
+ // Adjust the visible elements when the transition (changing the size of the AI tabs) ends. Earlier we do not have the
752
+ // correct sizes of elements.
753
+ aiTabs.view.element.addEventListener('transitionend', (evt) => this._handleAISidebarTransitions(evt));
754
+ }
755
+ /**
756
+ * Checks the transition event to see if it's changing the width of the AI tabs and if so, adjusts the visible fullscreen mode elements.
757
+ */
758
+ _handleAISidebarTransitions(evt) {
759
+ const aiTabs = this._editor.plugins.get('AITabs');
760
+ // Transition may occur on any element inside the AI tabs (e.g. changing the box-shadow in review mode),
761
+ // so we need to check the target and the property name.
762
+ if (evt.target === aiTabs.view.element && evt.propertyName.includes('width')) {
763
+ this._adjustVisibleElements();
764
+ }
765
+ }
766
+ /**
767
+ * Restores the state of the AI Tabs to the original values.
768
+ */
769
+ // Code coverage is provided in the commercial package repository as integration unit tests.
770
+ /* istanbul ignore next -- @preserve */
771
+ _restoreAITabs() {
772
+ const aiTabs = this._editor.plugins.get('AITabs');
773
+ aiTabs.side = this._aiTabsData?.side;
774
+ aiTabs.type = this._aiTabsData?.type;
775
+ this._aiTabsData = null;
776
+ aiTabs.view.element.removeEventListener('transitionend', this._handleAISidebarTransitions);
777
+ }
778
+ /**
779
+ * Adjusts the visibility of the left and right sidebars based on the available space.
780
+ */
781
+ _adjustVisibleElements() {
782
+ const editableWrapper = this._wrapper.querySelector('.ck-fullscreen__editable-wrapper');
783
+ // If user has explicitly opened the left sidebar, don't try to hide it automatically - but only once. Any later
784
+ // resizes will affect the sidebar visibility.
785
+ if (this._forceShowLeftSidebar) {
786
+ this._forceShowLeftSidebar = false;
787
+ return;
788
+ }
789
+ // First of all, check if we need to collapse something or not.
790
+ if (editableWrapper.scrollWidth > editableWrapper.clientWidth) {
791
+ // If we do, collapse left sidebar first.
792
+ this._hideLeftSidebar();
793
+ // If we still need more space, collapse right sidebar.
794
+ if (editableWrapper.scrollWidth > editableWrapper.clientWidth) {
795
+ this._hideRightSidebar();
796
+ }
797
+ }
798
+ // If we don't need more space, maybe we could expand sidebars instead.
799
+ else {
800
+ // Try to expand right sidebar first. It's not enough to check if scrollWidth + rightSidebarWidth < clientWidth,
801
+ // because the wrapper will always stretch to the full available width.
802
+ // We need to check the sum of its children widths instead.
803
+ let actualWidth = [...editableWrapper.children].reduce((acc, child) => acc + child.scrollWidth, 0);
804
+ // If adding right sidebar width to the factual width of the wrapper
805
+ // would still be less than the client width, expand right sidebar.
806
+ if (actualWidth + this._sidebarsWidths.right < editableWrapper.clientWidth) {
807
+ this._showRightSidebar();
808
+ actualWidth = [...editableWrapper.children].reduce((acc, child) => acc + child.scrollWidth, 0);
809
+ }
810
+ // Then follow the same logic for left sidebar - but only if we are controlling it
811
+ // (i.e. user hasn't explicitly collapsed the sidebar with a button).
812
+ if (actualWidth + this._sidebarsWidths.left < editableWrapper.clientWidth && !this._keepLeftSidebarHidden) {
813
+ this._showLeftSidebar();
814
+ }
815
+ }
816
+ }
817
+ /**
818
+ * Switches the annotations UI to the requested one.
819
+ */
820
+ // Code coverage is provided in the commercial package repository as integration unit tests.
821
+ /* istanbul ignore next -- @preserve */
822
+ _switchAnnotationsUI(uiName) {
823
+ const annotationsUIs = this._editor.plugins.get('AnnotationsUIs');
824
+ annotationsUIs.deactivateAll();
825
+ const annotationsFilters = new Map();
826
+ for (const [uiName, data] of [...this._annotationsUIsData]) {
827
+ // Default filter is `() => true`. Only store filters that are different.
828
+ if (data.filter !== annotationsUIs.defaultFilter) {
829
+ annotationsFilters.set(uiName, data.filter);
830
+ }
831
+ }
832
+ // First, check if someone has a filter defined for requested UI. If so, retrieve and apply it in fullscreen.
833
+ if (annotationsFilters.has(uiName)) {
834
+ annotationsUIs.activate(uiName, annotationsFilters.get(uiName));
835
+ }
836
+ // If no filter is defined for requested UI, read the filters for the active display(s) mode and apply them.
837
+ // It's possible there are filters for modes other than selected, so display annotations that match any of them.
838
+ else if (annotationsFilters.size) {
839
+ annotationsUIs.activate(uiName, (annotation) => [...annotationsFilters.values()].some(filter => filter(annotation)));
840
+ }
841
+ // If no filters are defined for the active display mode(s), simply display all annotations in the requested UI.
842
+ else {
843
+ annotationsUIs.switchTo(uiName);
844
+ }
845
+ }
846
+ /**
847
+ * Sets up a resize observer to adjust the visibility of the left and right sidebars dynamically.
848
+ */
849
+ _setupResizeObserver() {
850
+ const wrapper = this._wrapper.querySelector('.ck-fullscreen__editable-wrapper');
851
+ if (this._resizeObserver) {
852
+ this._resizeObserver.destroy();
853
+ }
854
+ this._resizeObserver = new ResizeObserver(wrapper, () => {
855
+ this._adjustVisibleElements();
856
+ });
857
+ }
858
+ /**
859
+ * Hides the left sidebar. Works only if there is anything to hide.
860
+ */
861
+ // Code coverage is provided in the commercial package repository as integration unit tests.
862
+ /* istanbul ignore next -- @preserve */
863
+ _hideLeftSidebar() {
864
+ const t = this._editor.t;
865
+ if (this._collapseLeftSidebarButton) {
866
+ const leftSidebar = this._wrapper.querySelector('.ck-fullscreen__left-sidebar');
867
+ leftSidebar.classList.add('ck-fullscreen__left-sidebar--collapsed');
868
+ this._collapseLeftSidebarButton.icon = IconDocumentOutlineToggle;
869
+ this._collapseLeftSidebarButton.tooltip = t('Show left sidebar');
870
+ }
871
+ }
872
+ /**
873
+ * Shows the left sidebar. Works only if there is anything to show.
874
+ */
875
+ // Code coverage is provided in the commercial package repository as integration unit tests.
876
+ /* istanbul ignore next -- @preserve */
877
+ _showLeftSidebar() {
878
+ const t = this._editor.t;
879
+ if (this._collapseLeftSidebarButton) {
880
+ const leftSidebar = this._wrapper.querySelector('.ck-fullscreen__left-sidebar');
881
+ leftSidebar.classList.remove('ck-fullscreen__left-sidebar--collapsed');
882
+ this._collapseLeftSidebarButton.icon = IconPreviousArrow;
883
+ this._collapseLeftSidebarButton.tooltip = t('Hide left sidebar');
884
+ }
885
+ }
886
+ /**
887
+ * Hides the right sidebar. Works only if there is anything to hide.
888
+ */
889
+ _hideRightSidebar() {
890
+ if (this._wrapper.querySelector('.ck-fullscreen__right-sidebar').firstChild) {
891
+ this._switchAnnotationsUI('narrowSidebar');
892
+ this._wrapper.querySelector('.ck-fullscreen__right-sidebar').classList.add('ck-fullscreen__right-sidebar--collapsed');
893
+ }
894
+ }
895
+ /**
896
+ * Shows the right sidebar. Works only if there is anything to show.
897
+ */
898
+ _showRightSidebar() {
899
+ if (this._wrapper.querySelector('.ck-fullscreen__right-sidebar').firstChild) {
900
+ this._switchAnnotationsUI('wideSidebar');
901
+ this._wrapper.querySelector('.ck-fullscreen__right-sidebar').classList.remove('ck-fullscreen__right-sidebar--collapsed');
902
+ }
903
+ }
650
904
  }
@@ -46,6 +46,7 @@ Fullscreen layout:
46
46
  <div class="ck ck-fullscreen__sidebar ck-fullscreen__left-sidebar" data-ck-fullscreen="left-sidebar"></div>
47
47
  <div class="ck ck-fullscreen__editable" data-ck-fullscreen="editable"></div>
48
48
  <div class="ck ck-fullscreen__sidebar ck-fullscreen__right-sidebar" data-ck-fullscreen="right-sidebar"></div>
49
+ <div class="ck ck-fullscreen__right-edge" data-ck-fullscreen="right-edge"></div>
49
50
  </div>
50
51
  <div class="ck ck-fullscreen__bottom-wrapper">
51
52
  <div class="ck ck-fullscreen__body-wrapper" data-ck-fullscreen="body-wrapper"></div>
@@ -135,7 +136,7 @@ Fullscreen layout:
135
136
  }
136
137
 
137
138
  .ck-fullscreen__sidebar {
138
- width: 300px;
139
+ width: 270px;
139
140
  margin-top: var(--ck-fullscreen-editor-top-margin);
140
141
  margin-left: 10px;
141
142
  }
@@ -149,15 +150,38 @@ Fullscreen layout:
149
150
  height: 100%;
150
151
  background-color: transparent;
151
152
  margin-top: 0px;
153
+ margin-right: 10px;
152
154
  box-sizing: border-box;
153
155
  display: flex;
154
156
  flex-direction: column;
155
157
 
156
- > :first-child {
158
+ & .ck-button.ck-fullscreen__left-sidebar-toggle-button {
159
+ --ck-icon-size: 20px;
160
+ --ck-ui-component-min-height: 0px;
161
+
162
+ align-self: flex-start;
163
+ padding-top: 0;
164
+ margin-top: var(--ck-fullscreen-editor-top-margin);
165
+ margin-bottom: var(--ck-spacing-large);
166
+ opacity: 0.5;
167
+ border-radius: 100%;
168
+ }
169
+
170
+ > .ck-fullscreen__left-sidebar-sticky {
157
171
  /* Set minimal width if there is any item in the sidebar. */
158
- min-width: 300px;
159
- /* We have to use padding-top instead of margin-top because margin is scrollable. */
160
- padding-top: var(--ck-fullscreen-editor-top-margin);
172
+ min-width: 270px;
173
+
174
+ &:first-child {
175
+ padding-top: var(--ck-fullscreen-editor-top-margin);
176
+ }
177
+ }
178
+
179
+ &.ck-fullscreen__left-sidebar--collapsed {
180
+ width: 65px;
181
+
182
+ > :not(.ck-fullscreen__left-sidebar-toggle-button) {
183
+ display: none;
184
+ }
161
185
  }
162
186
  }
163
187
 
@@ -229,8 +253,31 @@ Fullscreen layout:
229
253
  margin-top: var(--ck-fullscreen-editor-top-margin);
230
254
  margin-right: auto;
231
255
 
232
- &> :first-child {
256
+ &:not(.ck-fullscreen__right-sidebar--collapsed) > :first-child {
233
257
  /* Set minimal width if there is any item in the sidebar. */
234
- min-width: 300px;
258
+ min-width: 270px;
259
+ }
260
+
261
+ &.ck-fullscreen__right-sidebar--collapsed {
262
+ width: 65px;
263
+
264
+ & > :first-child {
265
+ min-width: 65px;
266
+ }
267
+ }
268
+ }
269
+
270
+ .ck.ck-fullscreen__right-edge {
271
+ position: sticky;
272
+ top: 0;
273
+ margin-top: 0;
274
+ margin-left: 10px;
275
+
276
+ & > :first-child {
277
+ border-top: none;
278
+ border-bottom: none;
279
+ border-right: none;
280
+ height: 100%;
281
+ width: 495px;
235
282
  }
236
283
  }