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

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
package/dist/index.js CHANGED
@@ -3,8 +3,9 @@
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
4
  */
5
5
  import { Command, Plugin } from '@ckeditor/ckeditor5-core/dist/index.js';
6
- import { global, createElement, Rect, env } from '@ckeditor/ckeditor5-utils/dist/index.js';
7
- import { BodyCollection, DialogViewPosition, MenuBarView, ButtonView, MenuBarMenuListItemButtonView } from '@ckeditor/ckeditor5-ui/dist/index.js';
6
+ import { global, createElement, Rect, ResizeObserver, env } from '@ckeditor/ckeditor5-utils/dist/index.js';
7
+ import { BodyCollection, ButtonView, DialogViewPosition, MenuBarView, MenuBarMenuListItemButtonView } from '@ckeditor/ckeditor5-ui/dist/index.js';
8
+ import { IconPreviousArrow, IconDocumentOutlineToggle } from '@ckeditor/ckeditor5-icons/dist/index.js';
8
9
  import { IconFullscreenLeave, IconFullscreenEnter } from '@ckeditor/ckeditor5-icons/dist/index.js';
9
10
 
10
11
  const DIALOG_OFFSET = 28;
@@ -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
  */ class FullscreenAbstractEditorHandler {
@@ -84,6 +89,29 @@ const DIALOG_OFFSET = 28;
84
89
  * The pagination body collection that is used in the fullscreen mode.
85
90
  * If we don't move pagination lines to the fullscreen container, they won't be visible.
86
91
  */ _paginationBodyCollection = null;
92
+ /**
93
+ * Whether the left sidebar collapse button is created.
94
+ */ _hasLeftCollapseButton = false;
95
+ /**
96
+ * The button that toggles the visibility of the left sidebar.
97
+ */ _collapseLeftSidebarButton = null;
98
+ /**
99
+ * The resize observer that is used to adjust the visibility of the left and right sidebars dynamically.
100
+ */ _resizeObserver = null;
101
+ /**
102
+ * The width of the expanded left and right sidebars in the fullscreen mode. Necessary for logic checking if they should be visible.
103
+ */ _sidebarsWidths = {
104
+ left: 0,
105
+ right: 0
106
+ };
107
+ /**
108
+ * Whether the left sidebar should be kept hidden even if there is enough space for it. It's set to `true` when user
109
+ * collapses the left sidebar with a button. Behavior is reset when exiting the fullscreen mode.
110
+ */ _keepLeftSidebarHidden = false;
111
+ /**
112
+ * Temporary flag used to ignore the first automatic layout adjustment logic when user collapses the left sidebar with a button.
113
+ * It is then immediately set back to `false`.
114
+ */ _forceShowLeftSidebar = false;
87
115
  /**
88
116
  * A callback that hides the document outline header when the source editing mode is enabled.
89
117
  * Document outline element itself is hidden by source editing plugin.
@@ -104,6 +132,9 @@ const DIALOG_OFFSET = 28;
104
132
  /**
105
133
  * A callback that closes the revision viewer, stored to restore the original one after exiting the fullscreen mode.
106
134
  */ _closeRevisionViewerCallback = null;
135
+ /**
136
+ * A map of AI Tabs data that were set before entering the fullscreen mode.
137
+ */ _aiTabsData = null;
107
138
  /**
108
139
  * @inheritDoc
109
140
  */ constructor(editor){
@@ -119,6 +150,9 @@ const DIALOG_OFFSET = 28;
119
150
  if (this._wrapper) {
120
151
  this.destroy();
121
152
  }
153
+ if (this._resizeObserver) {
154
+ this._resizeObserver.destroy();
155
+ }
122
156
  });
123
157
  }
124
158
  /**
@@ -166,6 +200,7 @@ const DIALOG_OFFSET = 28;
166
200
  <div class="ck ck-fullscreen__pagination-view" data-ck-fullscreen="pagination-view"></div>
167
201
  </div>
168
202
  <div class="ck ck-fullscreen__sidebar ck-fullscreen__right-sidebar" data-ck-fullscreen="right-sidebar"></div>
203
+ <div class="ck ck-fullscreen__right-edge" data-ck-fullscreen="right-edge"></div>
169
204
  </div>
170
205
  <div class="ck ck-fullscreen__bottom-wrapper">
171
206
  <div class="ck ck-fullscreen__body-wrapper" data-ck-fullscreen="body-wrapper"></div>
@@ -185,9 +220,6 @@ const DIALOG_OFFSET = 28;
185
220
  this._document.body.classList.add('ck-fullscreen');
186
221
  this._document.body.parentElement.classList.add('ck-fullscreen');
187
222
  }
188
- if (this._editor.plugins.has('Dialog')) {
189
- this._registerFullscreenDialogPositionAdjustments();
190
- }
191
223
  // Code coverage is provided in the commercial package repository as integration unit tests.
192
224
  /* istanbul ignore if -- @preserve */ if (this._editor.plugins.has('PresenceListUI')) {
193
225
  this._generatePresenceListContainer();
@@ -196,6 +228,9 @@ const DIALOG_OFFSET = 28;
196
228
  /* istanbul ignore if -- @preserve */ if (this._editor.plugins.has('DocumentOutlineUI')) {
197
229
  this._generateDocumentOutlineContainer();
198
230
  }
231
+ if (this._hasLeftCollapseButton) {
232
+ this._generateCollapseButton();
233
+ }
199
234
  // Code coverage is provided in the commercial package repository as integration unit tests.
200
235
  /* istanbul ignore next -- @preserve */ if (this._editor.plugins.has('Pagination') && this._editor.plugins.get('Pagination').isEnabled) {
201
236
  const paginationRenderer = this._editor.plugins.get('PaginationRenderer');
@@ -220,9 +255,18 @@ const DIALOG_OFFSET = 28;
220
255
  }
221
256
  this._overrideRevisionHistoryCallbacks();
222
257
  }
258
+ // Code coverage is provided in the commercial package repository as integration unit tests.
259
+ /* istanbul ignore if -- @preserve */ if (this._editor.plugins.has('AITabs')) {
260
+ this._handleAITabsTransfer();
261
+ }
223
262
  if (this._editor.plugins.has('SourceEditing') && this._editor.plugins.has('DocumentOutlineUI')) {
263
+ // Register a callback to hide the document outline header in source editing mode.
224
264
  this._editor.plugins.get('SourceEditing').on('change:isSourceEditingMode', this._sourceEditingCallback);
225
265
  }
266
+ // Dialog position should be done after all known elements are moved to the fullscreen container.
267
+ if (this._editor.plugins.has('Dialog')) {
268
+ this._registerFullscreenDialogPositionAdjustments();
269
+ }
226
270
  // Hide all other elements in the container to ensure they don't create an empty unscrollable space.
227
271
  for (const element of this._editor.config.get('fullscreen.container').children){
228
272
  // Do not hide body wrapper and ckbox wrapper to keep dialogs, balloons etc visible.
@@ -232,6 +276,14 @@ const DIALOG_OFFSET = 28;
232
276
  element.style.display = 'none';
233
277
  }
234
278
  }
279
+ // Save the information about the width of the left and right sidebars before they possibly get hidden.
280
+ // It will be used for math checking if they should be visible or not dynamically.
281
+ this._sidebarsWidths = {
282
+ left: this._wrapper.querySelector('.ck-fullscreen__left-sidebar').scrollWidth,
283
+ right: this._wrapper.querySelector('.ck-fullscreen__right-sidebar').scrollWidth
284
+ };
285
+ this._adjustVisibleElements();
286
+ this._setupResizeObserver();
235
287
  if (this._editor.config.get('fullscreen.onEnterCallback')) {
236
288
  this._editor.config.get('fullscreen.onEnterCallback')(this.getWrapper());
237
289
  }
@@ -255,6 +307,10 @@ const DIALOG_OFFSET = 28;
255
307
  if (this._editor.plugins.has('RevisionHistory')) {
256
308
  this._restoreRevisionHistoryCallbacks();
257
309
  }
310
+ // Code coverage is provided in the commercial package repository as integration unit tests.
311
+ /* istanbul ignore if -- @preserve */ if (this._editor.plugins.has('AITabs')) {
312
+ this._restoreAITabs();
313
+ }
258
314
  if (this._editor.plugins.has('SourceEditing') && this._editor.plugins.has('DocumentOutlineUI')) {
259
315
  this._editor.plugins.get('SourceEditing').off('change:isSourceEditingMode', this._sourceEditingCallback);
260
316
  }
@@ -295,6 +351,9 @@ const DIALOG_OFFSET = 28;
295
351
  if (this._editor.plugins.has('Dialog')) {
296
352
  this._unregisterFullscreenDialogPositionAdjustments();
297
353
  }
354
+ // Reset the behavior of the left sidebar.
355
+ this._keepLeftSidebarHidden = false;
356
+ this._resizeObserver?.destroy();
298
357
  }
299
358
  /**
300
359
  * @inheritDoc
@@ -351,6 +410,7 @@ const DIALOG_OFFSET = 28;
351
410
  document.querySelector('[data-ck-fullscreen="left-sidebar-sticky"]').appendChild(presenceListElement);
352
411
  const presenceListUI = this._editor.plugins.get('PresenceListUI');
353
412
  this.moveToFullscreen(presenceListUI.view.element, 'presence-list');
413
+ this._hasLeftCollapseButton = true;
354
414
  }
355
415
  /**
356
416
  * Checks if the DocumentOutlineUI plugin is available and moves its elements to fullscreen mode.
@@ -381,6 +441,7 @@ const DIALOG_OFFSET = 28;
381
441
  const documentOutlineUI = this._editor.plugins.get('DocumentOutlineUI');
382
442
  documentOutlineUI.view.documentOutlineContainer = document.querySelector('[data-ck-fullscreen="left-sidebar"]');
383
443
  this.moveToFullscreen(documentOutlineUI.view.element, 'document-outline');
444
+ this._hasLeftCollapseButton = true;
384
445
  }
385
446
  /**
386
447
  * Restores the default value of documentOutlineContainer, which is modified in fullscreen mode.
@@ -389,21 +450,44 @@ const DIALOG_OFFSET = 28;
389
450
  const documentOutlineUI = this._editor.plugins.get('DocumentOutlineUI');
390
451
  documentOutlineUI.view.documentOutlineContainer = documentOutlineUI.view.element;
391
452
  }
453
+ // Code coverage is provided in the commercial package repository as integration unit tests.
454
+ /* istanbul ignore next -- @preserve */ _generateCollapseButton() {
455
+ const button = new ButtonView(this._editor.locale);
456
+ const leftSidebarContainer = document.querySelector('.ck-fullscreen__left-sidebar');
457
+ const t = this._editor.t;
458
+ button.set({
459
+ label: t('Toggle sidebar'),
460
+ class: 'ck-fullscreen__left-sidebar-toggle-button',
461
+ tooltip: t('Hide left sidebar'),
462
+ tooltipPosition: 'se',
463
+ icon: IconPreviousArrow
464
+ });
465
+ button.on('execute', ()=>{
466
+ // Change the look of the button to reflect the state of the left sidebar.
467
+ if (leftSidebarContainer.classList.contains('ck-fullscreen__left-sidebar--collapsed')) {
468
+ // Enable automatic left sidebar toggling.
469
+ this._forceShowLeftSidebar = true;
470
+ this._keepLeftSidebarHidden = false;
471
+ this._showLeftSidebar();
472
+ } else {
473
+ // Disable automatic left sidebar toggling.
474
+ this._keepLeftSidebarHidden = true;
475
+ this._hideLeftSidebar();
476
+ }
477
+ // Keep the focus in the editor whenever the button is clicked.
478
+ this._editor.editing.view.focus();
479
+ });
480
+ button.render();
481
+ this._collapseLeftSidebarButton = button;
482
+ // Append the button at the top of the left sidebar.
483
+ leftSidebarContainer.prepend(button.element);
484
+ }
392
485
  /**
393
486
  * Stores the current state of the annotations UIs to restore it when leaving fullscreen mode and switches the UI to the wide sidebar.
394
487
  */ // Code coverage is provided in the commercial package repository as integration unit tests.
395
488
  /* istanbul ignore next -- @preserve */ _overrideAnnotationsUIs() {
396
489
  const annotationsUIs = this._editor.plugins.get('AnnotationsUIs');
397
490
  this._annotationsUIsData = new Map(annotationsUIs.uisData);
398
- const annotationsFilters = new Map();
399
- for (const [uiName, data] of [
400
- ...this._annotationsUIsData
401
- ]){
402
- // Default filter is `() => true`. Only store filters that are different.
403
- if (data.filter !== annotationsUIs.defaultFilter) {
404
- annotationsFilters.set(uiName, data.filter);
405
- }
406
- }
407
491
  annotationsUIs.deactivateAll();
408
492
  const sidebarPlugin = this._editor.plugins.get('Sidebar');
409
493
  // There are two scenarios to consider: if wide sidebar is already used and when it's not.
@@ -413,25 +497,13 @@ const DIALOG_OFFSET = 28;
413
497
  // 3. Move the sidebar element to the fullscreen mode.
414
498
  if (!sidebarPlugin.container) {
415
499
  sidebarPlugin.setContainer(this.getWrapper().querySelector('[data-ck-fullscreen="right-sidebar"]'));
416
- switchToWideSidebar();
500
+ this._switchAnnotationsUI('wideSidebar');
417
501
  this.moveToFullscreen(sidebarPlugin.container.firstElementChild, 'right-sidebar');
418
502
  } else {
419
- switchToWideSidebar();
503
+ this._switchAnnotationsUI('wideSidebar');
420
504
  this.moveToFullscreen(sidebarPlugin.container.firstElementChild, 'right-sidebar');
421
505
  sidebarPlugin.setContainer(this.getWrapper().querySelector('[data-ck-fullscreen="right-sidebar"]'));
422
506
  }
423
- function switchToWideSidebar() {
424
- // First, check if someone has a filter defined for `wideSidebar`. If so, retrieve and apply it in fullscreen.
425
- if (annotationsFilters.has('wideSidebar')) {
426
- annotationsUIs.activate('wideSidebar', annotationsFilters.get('wideSidebar'));
427
- } else if (annotationsFilters.size) {
428
- annotationsUIs.activate('wideSidebar', (annotation)=>[
429
- ...annotationsFilters.values()
430
- ].some((filter)=>filter(annotation)));
431
- } else {
432
- annotationsUIs.switchTo('wideSidebar');
433
- }
434
- }
435
507
  }
436
508
  /**
437
509
  * Restores the saved state of the annotations UIs.
@@ -555,13 +627,17 @@ const DIALOG_OFFSET = 28;
555
627
  if (!dialogView || dialogView.position !== DialogViewPosition.EDITOR_TOP_SIDE) {
556
628
  return;
557
629
  }
558
- const fullscreenViewContainerRect = new Rect(this._wrapper).getVisible();
630
+ // It's possible that the right edge container is used but not visible. We then fallback to the wrapper.
631
+ const keepRightEdgeContainerVisible = new Rect(this._wrapper.querySelector('.ck-fullscreen__right-edge')).getVisible();
632
+ const relativeContainer = keepRightEdgeContainerVisible ? this._wrapper.querySelector('.ck-fullscreen__right-edge') : this._wrapper;
633
+ const relativeContainerRect = new Rect(relativeContainer).getVisible();
559
634
  const editorContainerRect = new Rect(document.querySelector('.ck-fullscreen__editable')).getVisible();
560
635
  const dialogRect = new Rect(dialogView.element.querySelector('.ck-dialog')).getVisible();
561
636
  const scrollOffset = new Rect(document.querySelector('.ck-fullscreen__editable-wrapper')).excludeScrollbarsAndBorders().getVisible().width - new Rect(document.querySelector('.ck-fullscreen__editable-wrapper')).getVisible().width;
562
- if (fullscreenViewContainerRect && editorContainerRect && dialogRect) {
637
+ if (relativeContainerRect && editorContainerRect && dialogRect) {
563
638
  dialogView.position = null;
564
- dialogView.moveTo(fullscreenViewContainerRect.left + fullscreenViewContainerRect.width - dialogRect.width - DIALOG_OFFSET + scrollOffset, editorContainerRect.top);
639
+ const leftOffset = keepRightEdgeContainerVisible ? relativeContainerRect.left - dialogRect.width - DIALOG_OFFSET : relativeContainerRect.left + relativeContainerRect.width - dialogRect.width - DIALOG_OFFSET + scrollOffset;
640
+ dialogView.moveTo(leftOffset, editorContainerRect.top);
565
641
  }
566
642
  }
567
643
  /**
@@ -589,6 +665,159 @@ const DIALOG_OFFSET = 28;
589
665
  element = element.parentElement;
590
666
  }
591
667
  }
668
+ /**
669
+ * Stores the current state of the AI Tabs and moves it to the fullscreen mode.
670
+ */ // Code coverage is provided in the commercial package repository as integration unit tests.
671
+ /* istanbul ignore next -- @preserve */ _handleAITabsTransfer() {
672
+ const aiTabs = this._editor.plugins.get('AITabs');
673
+ this._aiTabsData = {
674
+ side: aiTabs.side,
675
+ type: aiTabs.type
676
+ };
677
+ this.moveToFullscreen(aiTabs.view.element, 'right-edge');
678
+ aiTabs.side = 'right';
679
+ aiTabs.type = 'sidebar';
680
+ // Adjust the visible elements when the transition (changing the size of the AI tabs) ends. Earlier we do not have the
681
+ // correct sizes of elements.
682
+ aiTabs.view.element.addEventListener('transitionend', (evt)=>this._handleAISidebarTransitions(evt));
683
+ }
684
+ /**
685
+ * 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.
686
+ */ _handleAISidebarTransitions(evt) {
687
+ const aiTabs = this._editor.plugins.get('AITabs');
688
+ // Transition may occur on any element inside the AI tabs (e.g. changing the box-shadow in review mode),
689
+ // so we need to check the target and the property name.
690
+ if (evt.target === aiTabs.view.element && evt.propertyName.includes('width')) {
691
+ this._adjustVisibleElements();
692
+ }
693
+ }
694
+ /**
695
+ * Restores the state of the AI Tabs to the original values.
696
+ */ // Code coverage is provided in the commercial package repository as integration unit tests.
697
+ /* istanbul ignore next -- @preserve */ _restoreAITabs() {
698
+ const aiTabs = this._editor.plugins.get('AITabs');
699
+ aiTabs.side = this._aiTabsData?.side;
700
+ aiTabs.type = this._aiTabsData?.type;
701
+ this._aiTabsData = null;
702
+ aiTabs.view.element.removeEventListener('transitionend', this._handleAISidebarTransitions);
703
+ }
704
+ /**
705
+ * Adjusts the visibility of the left and right sidebars based on the available space.
706
+ */ _adjustVisibleElements() {
707
+ const editableWrapper = this._wrapper.querySelector('.ck-fullscreen__editable-wrapper');
708
+ // If user has explicitly opened the left sidebar, don't try to hide it automatically - but only once. Any later
709
+ // resizes will affect the sidebar visibility.
710
+ if (this._forceShowLeftSidebar) {
711
+ this._forceShowLeftSidebar = false;
712
+ return;
713
+ }
714
+ // First of all, check if we need to collapse something or not.
715
+ if (editableWrapper.scrollWidth > editableWrapper.clientWidth) {
716
+ // If we do, collapse left sidebar first.
717
+ this._hideLeftSidebar();
718
+ // If we still need more space, collapse right sidebar.
719
+ if (editableWrapper.scrollWidth > editableWrapper.clientWidth) {
720
+ this._hideRightSidebar();
721
+ }
722
+ } else {
723
+ // Try to expand right sidebar first. It's not enough to check if scrollWidth + rightSidebarWidth < clientWidth,
724
+ // because the wrapper will always stretch to the full available width.
725
+ // We need to check the sum of its children widths instead.
726
+ let actualWidth = [
727
+ ...editableWrapper.children
728
+ ].reduce((acc, child)=>acc + child.scrollWidth, 0);
729
+ // If adding right sidebar width to the factual width of the wrapper
730
+ // would still be less than the client width, expand right sidebar.
731
+ if (actualWidth + this._sidebarsWidths.right < editableWrapper.clientWidth) {
732
+ this._showRightSidebar();
733
+ actualWidth = [
734
+ ...editableWrapper.children
735
+ ].reduce((acc, child)=>acc + child.scrollWidth, 0);
736
+ }
737
+ // Then follow the same logic for left sidebar - but only if we are controlling it
738
+ // (i.e. user hasn't explicitly collapsed the sidebar with a button).
739
+ if (actualWidth + this._sidebarsWidths.left < editableWrapper.clientWidth && !this._keepLeftSidebarHidden) {
740
+ this._showLeftSidebar();
741
+ }
742
+ }
743
+ }
744
+ /**
745
+ * Switches the annotations UI to the requested one.
746
+ */ // Code coverage is provided in the commercial package repository as integration unit tests.
747
+ /* istanbul ignore next -- @preserve */ _switchAnnotationsUI(uiName) {
748
+ const annotationsUIs = this._editor.plugins.get('AnnotationsUIs');
749
+ annotationsUIs.deactivateAll();
750
+ const annotationsFilters = new Map();
751
+ for (const [uiName, data] of [
752
+ ...this._annotationsUIsData
753
+ ]){
754
+ // Default filter is `() => true`. Only store filters that are different.
755
+ if (data.filter !== annotationsUIs.defaultFilter) {
756
+ annotationsFilters.set(uiName, data.filter);
757
+ }
758
+ }
759
+ // First, check if someone has a filter defined for requested UI. If so, retrieve and apply it in fullscreen.
760
+ if (annotationsFilters.has(uiName)) {
761
+ annotationsUIs.activate(uiName, annotationsFilters.get(uiName));
762
+ } else if (annotationsFilters.size) {
763
+ annotationsUIs.activate(uiName, (annotation)=>[
764
+ ...annotationsFilters.values()
765
+ ].some((filter)=>filter(annotation)));
766
+ } else {
767
+ annotationsUIs.switchTo(uiName);
768
+ }
769
+ }
770
+ /**
771
+ * Sets up a resize observer to adjust the visibility of the left and right sidebars dynamically.
772
+ */ _setupResizeObserver() {
773
+ const wrapper = this._wrapper.querySelector('.ck-fullscreen__editable-wrapper');
774
+ if (this._resizeObserver) {
775
+ this._resizeObserver.destroy();
776
+ }
777
+ this._resizeObserver = new ResizeObserver(wrapper, ()=>{
778
+ this._adjustVisibleElements();
779
+ });
780
+ }
781
+ /**
782
+ * Hides the left sidebar. Works only if there is anything to hide.
783
+ */ // Code coverage is provided in the commercial package repository as integration unit tests.
784
+ /* istanbul ignore next -- @preserve */ _hideLeftSidebar() {
785
+ const t = this._editor.t;
786
+ if (this._collapseLeftSidebarButton) {
787
+ const leftSidebar = this._wrapper.querySelector('.ck-fullscreen__left-sidebar');
788
+ leftSidebar.classList.add('ck-fullscreen__left-sidebar--collapsed');
789
+ this._collapseLeftSidebarButton.icon = IconDocumentOutlineToggle;
790
+ this._collapseLeftSidebarButton.tooltip = t('Show left sidebar');
791
+ }
792
+ }
793
+ /**
794
+ * Shows the left sidebar. Works only if there is anything to show.
795
+ */ // Code coverage is provided in the commercial package repository as integration unit tests.
796
+ /* istanbul ignore next -- @preserve */ _showLeftSidebar() {
797
+ const t = this._editor.t;
798
+ if (this._collapseLeftSidebarButton) {
799
+ const leftSidebar = this._wrapper.querySelector('.ck-fullscreen__left-sidebar');
800
+ leftSidebar.classList.remove('ck-fullscreen__left-sidebar--collapsed');
801
+ this._collapseLeftSidebarButton.icon = IconPreviousArrow;
802
+ this._collapseLeftSidebarButton.tooltip = t('Hide left sidebar');
803
+ }
804
+ }
805
+ /**
806
+ * Hides the right sidebar. Works only if there is anything to hide.
807
+ */ _hideRightSidebar() {
808
+ if (this._wrapper.querySelector('.ck-fullscreen__right-sidebar').firstChild) {
809
+ this._switchAnnotationsUI('narrowSidebar');
810
+ this._wrapper.querySelector('.ck-fullscreen__right-sidebar').classList.add('ck-fullscreen__right-sidebar--collapsed');
811
+ }
812
+ }
813
+ /**
814
+ * Shows the right sidebar. Works only if there is anything to show.
815
+ */ _showRightSidebar() {
816
+ if (this._wrapper.querySelector('.ck-fullscreen__right-sidebar').firstChild) {
817
+ this._switchAnnotationsUI('wideSidebar');
818
+ this._wrapper.querySelector('.ck-fullscreen__right-sidebar').classList.remove('ck-fullscreen__right-sidebar--collapsed');
819
+ }
820
+ }
592
821
  }
593
822
 
594
823
  /**