@ckeditor/ckeditor5-bookmark 44.3.0 → 45.0.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 (314) hide show
  1. package/build/bookmark.js +2 -2
  2. package/build/translations/af.js +1 -1
  3. package/build/translations/ar.js +1 -1
  4. package/build/translations/ast.js +1 -1
  5. package/build/translations/az.js +1 -1
  6. package/build/translations/be.js +1 -0
  7. package/build/translations/bg.js +1 -1
  8. package/build/translations/bn.js +1 -1
  9. package/build/translations/bs.js +1 -1
  10. package/build/translations/ca.js +1 -1
  11. package/build/translations/cs.js +1 -1
  12. package/build/translations/da.js +1 -1
  13. package/build/translations/de-ch.js +1 -1
  14. package/build/translations/de.js +1 -1
  15. package/build/translations/el.js +1 -1
  16. package/build/translations/en-au.js +1 -1
  17. package/build/translations/en-gb.js +1 -1
  18. package/build/translations/eo.js +1 -1
  19. package/build/translations/es-co.js +1 -1
  20. package/build/translations/es.js +1 -1
  21. package/build/translations/et.js +1 -1
  22. package/build/translations/eu.js +1 -1
  23. package/build/translations/fa.js +1 -1
  24. package/build/translations/fi.js +1 -1
  25. package/build/translations/fr.js +1 -1
  26. package/build/translations/gl.js +1 -1
  27. package/build/translations/gu.js +1 -1
  28. package/build/translations/he.js +1 -1
  29. package/build/translations/hi.js +1 -1
  30. package/build/translations/hr.js +1 -1
  31. package/build/translations/hu.js +1 -1
  32. package/build/translations/hy.js +1 -1
  33. package/build/translations/id.js +1 -1
  34. package/build/translations/it.js +1 -1
  35. package/build/translations/ja.js +1 -1
  36. package/build/translations/jv.js +1 -1
  37. package/build/translations/kk.js +1 -1
  38. package/build/translations/km.js +1 -1
  39. package/build/translations/kn.js +1 -1
  40. package/build/translations/ko.js +1 -1
  41. package/build/translations/ku.js +1 -1
  42. package/build/translations/lt.js +1 -1
  43. package/build/translations/lv.js +1 -1
  44. package/build/translations/ms.js +1 -1
  45. package/build/translations/nb.js +1 -1
  46. package/build/translations/ne.js +1 -1
  47. package/build/translations/nl.js +1 -1
  48. package/build/translations/no.js +1 -1
  49. package/build/translations/oc.js +1 -1
  50. package/build/translations/pl.js +1 -1
  51. package/build/translations/pt-br.js +1 -1
  52. package/build/translations/pt.js +1 -1
  53. package/build/translations/ro.js +1 -1
  54. package/build/translations/ru.js +1 -1
  55. package/build/translations/si.js +1 -1
  56. package/build/translations/sk.js +1 -1
  57. package/build/translations/sl.js +1 -1
  58. package/build/translations/sq.js +1 -1
  59. package/build/translations/sr-latn.js +1 -1
  60. package/build/translations/sr.js +1 -1
  61. package/build/translations/sv.js +1 -1
  62. package/build/translations/th.js +1 -1
  63. package/build/translations/ti.js +1 -1
  64. package/build/translations/tk.js +1 -1
  65. package/build/translations/tr.js +1 -1
  66. package/build/translations/tt.js +1 -1
  67. package/build/translations/ug.js +1 -1
  68. package/build/translations/uk.js +1 -1
  69. package/build/translations/ur.js +1 -1
  70. package/build/translations/uz.js +1 -1
  71. package/build/translations/vi.js +1 -1
  72. package/build/translations/zh-cn.js +1 -1
  73. package/build/translations/zh.js +1 -1
  74. package/ckeditor5-metadata.json +1 -1
  75. package/dist/index-editor.css +56 -101
  76. package/dist/index.css +59 -119
  77. package/dist/index.css.map +1 -1
  78. package/dist/index.js +283 -389
  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.d.ts +8 -0
  89. package/dist/translations/be.js +5 -0
  90. package/dist/translations/be.umd.js +11 -0
  91. package/dist/translations/bg.js +1 -1
  92. package/dist/translations/bg.umd.js +1 -1
  93. package/dist/translations/bn.js +1 -1
  94. package/dist/translations/bn.umd.js +1 -1
  95. package/dist/translations/bs.js +1 -1
  96. package/dist/translations/bs.umd.js +1 -1
  97. package/dist/translations/ca.js +1 -1
  98. package/dist/translations/ca.umd.js +1 -1
  99. package/dist/translations/cs.js +1 -1
  100. package/dist/translations/cs.umd.js +1 -1
  101. package/dist/translations/da.js +1 -1
  102. package/dist/translations/da.umd.js +1 -1
  103. package/dist/translations/de-ch.js +1 -1
  104. package/dist/translations/de-ch.umd.js +1 -1
  105. package/dist/translations/de.js +1 -1
  106. package/dist/translations/de.umd.js +1 -1
  107. package/dist/translations/el.js +1 -1
  108. package/dist/translations/el.umd.js +1 -1
  109. package/dist/translations/en-au.js +1 -1
  110. package/dist/translations/en-au.umd.js +1 -1
  111. package/dist/translations/en-gb.js +1 -1
  112. package/dist/translations/en-gb.umd.js +1 -1
  113. package/dist/translations/en.js +1 -1
  114. package/dist/translations/en.umd.js +1 -1
  115. package/dist/translations/eo.js +1 -1
  116. package/dist/translations/eo.umd.js +1 -1
  117. package/dist/translations/es-co.js +1 -1
  118. package/dist/translations/es-co.umd.js +1 -1
  119. package/dist/translations/es.js +1 -1
  120. package/dist/translations/es.umd.js +1 -1
  121. package/dist/translations/et.js +1 -1
  122. package/dist/translations/et.umd.js +1 -1
  123. package/dist/translations/eu.js +1 -1
  124. package/dist/translations/eu.umd.js +1 -1
  125. package/dist/translations/fa.js +1 -1
  126. package/dist/translations/fa.umd.js +1 -1
  127. package/dist/translations/fi.js +1 -1
  128. package/dist/translations/fi.umd.js +1 -1
  129. package/dist/translations/fr.js +1 -1
  130. package/dist/translations/fr.umd.js +1 -1
  131. package/dist/translations/gl.js +1 -1
  132. package/dist/translations/gl.umd.js +1 -1
  133. package/dist/translations/gu.js +1 -1
  134. package/dist/translations/gu.umd.js +1 -1
  135. package/dist/translations/he.js +1 -1
  136. package/dist/translations/he.umd.js +1 -1
  137. package/dist/translations/hi.js +1 -1
  138. package/dist/translations/hi.umd.js +1 -1
  139. package/dist/translations/hr.js +1 -1
  140. package/dist/translations/hr.umd.js +1 -1
  141. package/dist/translations/hu.js +1 -1
  142. package/dist/translations/hu.umd.js +1 -1
  143. package/dist/translations/hy.js +1 -1
  144. package/dist/translations/hy.umd.js +1 -1
  145. package/dist/translations/id.js +1 -1
  146. package/dist/translations/id.umd.js +1 -1
  147. package/dist/translations/it.js +1 -1
  148. package/dist/translations/it.umd.js +1 -1
  149. package/dist/translations/ja.js +1 -1
  150. package/dist/translations/ja.umd.js +1 -1
  151. package/dist/translations/jv.js +1 -1
  152. package/dist/translations/jv.umd.js +1 -1
  153. package/dist/translations/kk.js +1 -1
  154. package/dist/translations/kk.umd.js +1 -1
  155. package/dist/translations/km.js +1 -1
  156. package/dist/translations/km.umd.js +1 -1
  157. package/dist/translations/kn.js +1 -1
  158. package/dist/translations/kn.umd.js +1 -1
  159. package/dist/translations/ko.js +1 -1
  160. package/dist/translations/ko.umd.js +1 -1
  161. package/dist/translations/ku.js +1 -1
  162. package/dist/translations/ku.umd.js +1 -1
  163. package/dist/translations/lt.js +1 -1
  164. package/dist/translations/lt.umd.js +1 -1
  165. package/dist/translations/lv.js +1 -1
  166. package/dist/translations/lv.umd.js +1 -1
  167. package/dist/translations/ms.js +1 -1
  168. package/dist/translations/ms.umd.js +1 -1
  169. package/dist/translations/nb.js +1 -1
  170. package/dist/translations/nb.umd.js +1 -1
  171. package/dist/translations/ne.js +1 -1
  172. package/dist/translations/ne.umd.js +1 -1
  173. package/dist/translations/nl.js +1 -1
  174. package/dist/translations/nl.umd.js +1 -1
  175. package/dist/translations/no.js +1 -1
  176. package/dist/translations/no.umd.js +1 -1
  177. package/dist/translations/oc.js +1 -1
  178. package/dist/translations/oc.umd.js +1 -1
  179. package/dist/translations/pl.js +1 -1
  180. package/dist/translations/pl.umd.js +1 -1
  181. package/dist/translations/pt-br.js +1 -1
  182. package/dist/translations/pt-br.umd.js +1 -1
  183. package/dist/translations/pt.js +1 -1
  184. package/dist/translations/pt.umd.js +1 -1
  185. package/dist/translations/ro.js +1 -1
  186. package/dist/translations/ro.umd.js +1 -1
  187. package/dist/translations/ru.js +1 -1
  188. package/dist/translations/ru.umd.js +1 -1
  189. package/dist/translations/si.js +1 -1
  190. package/dist/translations/si.umd.js +1 -1
  191. package/dist/translations/sk.js +1 -1
  192. package/dist/translations/sk.umd.js +1 -1
  193. package/dist/translations/sl.js +1 -1
  194. package/dist/translations/sl.umd.js +1 -1
  195. package/dist/translations/sq.js +1 -1
  196. package/dist/translations/sq.umd.js +1 -1
  197. package/dist/translations/sr-latn.js +1 -1
  198. package/dist/translations/sr-latn.umd.js +1 -1
  199. package/dist/translations/sr.js +1 -1
  200. package/dist/translations/sr.umd.js +1 -1
  201. package/dist/translations/sv.js +1 -1
  202. package/dist/translations/sv.umd.js +1 -1
  203. package/dist/translations/th.js +1 -1
  204. package/dist/translations/th.umd.js +1 -1
  205. package/dist/translations/ti.js +1 -1
  206. package/dist/translations/ti.umd.js +1 -1
  207. package/dist/translations/tk.js +1 -1
  208. package/dist/translations/tk.umd.js +1 -1
  209. package/dist/translations/tr.js +1 -1
  210. package/dist/translations/tr.umd.js +1 -1
  211. package/dist/translations/tt.js +1 -1
  212. package/dist/translations/tt.umd.js +1 -1
  213. package/dist/translations/ug.js +1 -1
  214. package/dist/translations/ug.umd.js +1 -1
  215. package/dist/translations/uk.js +1 -1
  216. package/dist/translations/uk.umd.js +1 -1
  217. package/dist/translations/ur.js +1 -1
  218. package/dist/translations/ur.umd.js +1 -1
  219. package/dist/translations/uz.js +1 -1
  220. package/dist/translations/uz.umd.js +1 -1
  221. package/dist/translations/vi.js +1 -1
  222. package/dist/translations/vi.umd.js +1 -1
  223. package/dist/translations/zh-cn.js +1 -1
  224. package/dist/translations/zh-cn.umd.js +1 -1
  225. package/dist/translations/zh.js +1 -1
  226. package/dist/translations/zh.umd.js +1 -1
  227. package/lang/contexts.json +5 -3
  228. package/lang/translations/af.po +16 -8
  229. package/lang/translations/ar.po +16 -8
  230. package/lang/translations/ast.po +16 -8
  231. package/lang/translations/az.po +16 -8
  232. package/lang/translations/be.po +64 -0
  233. package/lang/translations/bg.po +16 -8
  234. package/lang/translations/bn.po +16 -8
  235. package/lang/translations/bs.po +16 -8
  236. package/lang/translations/ca.po +16 -8
  237. package/lang/translations/cs.po +16 -8
  238. package/lang/translations/da.po +16 -8
  239. package/lang/translations/de-ch.po +16 -8
  240. package/lang/translations/de.po +16 -8
  241. package/lang/translations/el.po +16 -8
  242. package/lang/translations/en-au.po +16 -8
  243. package/lang/translations/en-gb.po +16 -8
  244. package/lang/translations/en.po +16 -8
  245. package/lang/translations/eo.po +16 -8
  246. package/lang/translations/es-co.po +16 -8
  247. package/lang/translations/es.po +16 -8
  248. package/lang/translations/et.po +16 -8
  249. package/lang/translations/eu.po +16 -8
  250. package/lang/translations/fa.po +16 -8
  251. package/lang/translations/fi.po +16 -8
  252. package/lang/translations/fr.po +16 -8
  253. package/lang/translations/gl.po +16 -8
  254. package/lang/translations/gu.po +16 -8
  255. package/lang/translations/he.po +16 -8
  256. package/lang/translations/hi.po +16 -8
  257. package/lang/translations/hr.po +16 -8
  258. package/lang/translations/hu.po +16 -8
  259. package/lang/translations/hy.po +16 -8
  260. package/lang/translations/id.po +16 -8
  261. package/lang/translations/it.po +16 -8
  262. package/lang/translations/ja.po +16 -8
  263. package/lang/translations/jv.po +16 -8
  264. package/lang/translations/kk.po +16 -8
  265. package/lang/translations/km.po +16 -8
  266. package/lang/translations/kn.po +16 -8
  267. package/lang/translations/ko.po +16 -8
  268. package/lang/translations/ku.po +16 -8
  269. package/lang/translations/lt.po +16 -8
  270. package/lang/translations/lv.po +16 -8
  271. package/lang/translations/ms.po +16 -8
  272. package/lang/translations/nb.po +16 -8
  273. package/lang/translations/ne.po +16 -8
  274. package/lang/translations/nl.po +16 -8
  275. package/lang/translations/no.po +16 -8
  276. package/lang/translations/oc.po +16 -8
  277. package/lang/translations/pl.po +16 -8
  278. package/lang/translations/pt-br.po +16 -8
  279. package/lang/translations/pt.po +16 -8
  280. package/lang/translations/ro.po +16 -8
  281. package/lang/translations/ru.po +16 -8
  282. package/lang/translations/si.po +16 -8
  283. package/lang/translations/sk.po +16 -8
  284. package/lang/translations/sl.po +16 -8
  285. package/lang/translations/sq.po +16 -8
  286. package/lang/translations/sr-latn.po +16 -8
  287. package/lang/translations/sr.po +16 -8
  288. package/lang/translations/sv.po +16 -8
  289. package/lang/translations/th.po +16 -8
  290. package/lang/translations/ti.po +16 -8
  291. package/lang/translations/tk.po +16 -8
  292. package/lang/translations/tr.po +16 -8
  293. package/lang/translations/tt.po +16 -8
  294. package/lang/translations/ug.po +16 -8
  295. package/lang/translations/uk.po +16 -8
  296. package/lang/translations/ur.po +16 -8
  297. package/lang/translations/uz.po +16 -8
  298. package/lang/translations/vi.po +16 -8
  299. package/lang/translations/zh-cn.po +16 -8
  300. package/lang/translations/zh.po +16 -8
  301. package/package.json +8 -7
  302. package/src/bookmarkconfig.d.ts +24 -0
  303. package/src/bookmarkediting.d.ts +9 -1
  304. package/src/bookmarkediting.js +23 -9
  305. package/src/bookmarkui.d.ts +24 -57
  306. package/src/bookmarkui.js +208 -212
  307. package/src/ui/bookmarkformview.d.ts +24 -14
  308. package/src/ui/bookmarkformview.js +103 -62
  309. package/theme/bookmark.css +0 -46
  310. package/theme/bookmarkform.css +0 -38
  311. package/theme/bookmarktoolbar.css +4 -0
  312. package/src/ui/bookmarkactionsview.d.ts +0 -102
  313. package/src/ui/bookmarkactionsview.js +0 -154
  314. package/theme/bookmarkactions.css +0 -44
package/dist/index.js CHANGED
@@ -2,11 +2,12 @@
2
2
  * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
4
  */
5
- import { icons, Command, Plugin } from '@ckeditor/ckeditor5-core/dist/index.js';
6
- import { toWidget, Widget } from '@ckeditor/ckeditor5-widget/dist/index.js';
7
- import { View, ViewCollection, FocusCycler, submitHandler, FormHeaderView, LabeledFieldView, createLabeledInputText, ButtonView, LabelView, IconView, ContextualBalloon, CssTransitionDisablerMixin, MenuBarMenuListItemButtonView, clickOutsideHandler } from '@ckeditor/ckeditor5-ui/dist/index.js';
8
- import { ClickObserver } from '@ckeditor/ckeditor5-engine/dist/index.js';
5
+ import { Command, Plugin } from '@ckeditor/ckeditor5-core/dist/index.js';
6
+ import { toWidget, WidgetToolbarRepository, isWidget, Widget } from '@ckeditor/ckeditor5-widget/dist/index.js';
7
+ import { View, ViewCollection, FormRowView, FocusCycler, submitHandler, ButtonView, FormHeaderView, LabeledFieldView, createLabeledInputText, IconView, ContextualBalloon, BalloonPanelView, CssTransitionDisablerMixin, MenuBarMenuListItemButtonView, LabelView, clickOutsideHandler } from '@ckeditor/ckeditor5-ui/dist/index.js';
8
+ import { IconBookmarkInline, IconPencil, IconRemove, IconBookmark, IconBookmarkMedium, IconBookmarkSmall } from '@ckeditor/ckeditor5-icons/dist/index.js';
9
9
  import { FocusTracker, KeystrokeHandler, logWarning } from '@ckeditor/ckeditor5-utils/dist/index.js';
10
+ import { IconPreviousArrow } from '@ckeditor/ckeditor5-icons/dist/index.js';
10
11
 
11
12
  /**
12
13
  * The bookmark form view controller class.
@@ -23,8 +24,11 @@ import { FocusTracker, KeystrokeHandler, logWarning } from '@ckeditor/ckeditor5-
23
24
  * The ID input view.
24
25
  */ idInputView;
25
26
  /**
26
- * The Submit button view.
27
- */ buttonView;
27
+ * The Back button view displayed in the header.
28
+ */ backButtonView;
29
+ /**
30
+ * A button used to submit the form.
31
+ */ saveButtonView;
28
32
  /**
29
33
  * A collection of form child views in the form.
30
34
  */ children;
@@ -46,12 +50,30 @@ import { FocusTracker, KeystrokeHandler, logWarning } from '@ckeditor/ckeditor5-
46
50
  * @param validators Form validators used by {@link #isValid}.
47
51
  */ constructor(locale, validators){
48
52
  super(locale);
49
- const t = locale.t;
50
53
  this._validators = validators;
54
+ // Create buttons.
55
+ this.backButtonView = this._createBackButton();
56
+ this.saveButtonView = this._createSaveButton();
57
+ // Create input fields.
51
58
  this.idInputView = this._createIdInput();
52
- this.buttonView = this._createButton(t('Insert'), 'ck-button-action ck-button-bold');
53
- this.buttonView.type = 'submit';
54
- this.children = this._createViewChildren();
59
+ this.children = this.createCollection([
60
+ this._createHeaderView()
61
+ ]);
62
+ this.children.add(new FormRowView(locale, {
63
+ children: [
64
+ this.idInputView,
65
+ this.saveButtonView
66
+ ],
67
+ class: [
68
+ 'ck-form__row_with-submit',
69
+ 'ck-form__row_large-top-padding'
70
+ ]
71
+ }));
72
+ // Close the panel on esc key press when the **form has focus**.
73
+ this.keystrokes.set('Esc', (data, cancel)=>{
74
+ this.fire('cancel');
75
+ cancel();
76
+ });
55
77
  this._focusCycler = new FocusCycler({
56
78
  focusables: this._focusables,
57
79
  focusTracker: this.focusTracker,
@@ -63,14 +85,15 @@ import { FocusTracker, KeystrokeHandler, logWarning } from '@ckeditor/ckeditor5-
63
85
  focusNext: 'tab'
64
86
  }
65
87
  });
66
- const classList = [
67
- 'ck',
68
- 'ck-bookmark-view'
69
- ];
70
88
  this.setTemplate({
71
89
  tag: 'form',
72
90
  attributes: {
73
- class: classList,
91
+ class: [
92
+ 'ck',
93
+ 'ck-form',
94
+ 'ck-bookmark-form',
95
+ 'ck-responsive-form'
96
+ ],
74
97
  // https://github.com/ckeditor/ckeditor5-link/issues/90
75
98
  tabindex: '-1'
76
99
  },
@@ -85,8 +108,9 @@ import { FocusTracker, KeystrokeHandler, logWarning } from '@ckeditor/ckeditor5-
85
108
  view: this
86
109
  });
87
110
  const childViews = [
111
+ this.backButtonView,
88
112
  this.idInputView,
89
- this.buttonView
113
+ this.saveButtonView
90
114
  ];
91
115
  childViews.forEach((v)=>{
92
116
  // Register the view as focusable.
@@ -107,7 +131,7 @@ import { FocusTracker, KeystrokeHandler, logWarning } from '@ckeditor/ckeditor5-
107
131
  /**
108
132
  * Focuses the fist {@link #_focusables} in the form.
109
133
  */ focus() {
110
- this._focusCycler.focusFirst();
134
+ this.idInputView.focus();
111
135
  }
112
136
  /**
113
137
  * Validates the form and returns `false` when some fields are invalid.
@@ -133,36 +157,41 @@ import { FocusTracker, KeystrokeHandler, logWarning } from '@ckeditor/ckeditor5-
133
157
  this.idInputView.errorText = null;
134
158
  }
135
159
  /**
136
- * Creates header and form view.
137
- */ _createViewChildren() {
138
- const children = this.createCollection();
139
- const t = this.t;
140
- children.add(new FormHeaderView(this.locale, {
141
- label: t('Bookmark')
142
- }));
143
- children.add(this._createFormContentView());
144
- return children;
160
+ * Creates a back button view that cancels the form.
161
+ */ _createBackButton() {
162
+ const t = this.locale.t;
163
+ const backButton = new ButtonView(this.locale);
164
+ backButton.set({
165
+ class: 'ck-button-back',
166
+ label: t('Back'),
167
+ icon: IconPreviousArrow,
168
+ tooltip: true
169
+ });
170
+ backButton.delegate('execute').to(this, 'cancel');
171
+ return backButton;
145
172
  }
146
173
  /**
147
- * Creates form content view with input and button.
148
- */ _createFormContentView() {
149
- const view = new View(this.locale);
150
- const children = this.createCollection();
151
- const classList = [
152
- 'ck',
153
- 'ck-bookmark-form',
154
- 'ck-responsive-form'
155
- ];
156
- children.add(this.idInputView);
157
- children.add(this.buttonView);
158
- view.setTemplate({
159
- tag: 'div',
160
- attributes: {
161
- class: classList
162
- },
163
- children
174
+ * Creates a save button view that saves the bookmark.
175
+ */ _createSaveButton() {
176
+ const t = this.locale.t;
177
+ const saveButton = new ButtonView(this.locale);
178
+ saveButton.set({
179
+ label: t('Save'),
180
+ withText: true,
181
+ type: 'submit',
182
+ class: 'ck-button-action ck-button-bold'
164
183
  });
165
- return view;
184
+ return saveButton;
185
+ }
186
+ /**
187
+ * Creates a header view for the form.
188
+ */ _createHeaderView() {
189
+ const t = this.locale.t;
190
+ const header = new FormHeaderView(this.locale, {
191
+ label: t('Bookmark')
192
+ });
193
+ header.children.add(this.backButtonView, 0);
194
+ return header;
166
195
  }
167
196
  /**
168
197
  * Creates a labeled input view.
@@ -173,27 +202,9 @@ import { FocusTracker, KeystrokeHandler, logWarning } from '@ckeditor/ckeditor5-
173
202
  const labeledInput = new LabeledFieldView(this.locale, createLabeledInputText);
174
203
  labeledInput.label = t('Bookmark name');
175
204
  labeledInput.infoText = t('Enter the bookmark name without spaces.');
205
+ labeledInput.class = 'ck-labeled-field-view_full-width';
176
206
  return labeledInput;
177
207
  }
178
- /**
179
- * Creates a button view.
180
- *
181
- * @param label The button label.
182
- * @param className The additional button CSS class name.
183
- * @returns The button view instance.
184
- */ _createButton(label, className) {
185
- const button = new ButtonView(this.locale);
186
- button.set({
187
- label,
188
- withText: true
189
- });
190
- button.extendTemplate({
191
- attributes: {
192
- class: className
193
- }
194
- });
195
- return button;
196
- }
197
208
  /**
198
209
  * The native DOM `value` of the {@link #idInputView} element.
199
210
  *
@@ -208,149 +219,6 @@ import { FocusTracker, KeystrokeHandler, logWarning } from '@ckeditor/ckeditor5-
208
219
  }
209
220
  }
210
221
 
211
- /**
212
- * The bookmark actions view class. This view displays the bookmark preview, allows
213
- * removing or editing the bookmark.
214
- */ class BookmarkActionsView extends View {
215
- /**
216
- * Tracks information about DOM focus in the actions.
217
- */ focusTracker = new FocusTracker();
218
- /**
219
- * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.
220
- */ keystrokes = new KeystrokeHandler();
221
- /**
222
- * The bookmark preview view.
223
- */ bookmarkPreviewView;
224
- /**
225
- * The remove button view.
226
- */ removeButtonView;
227
- /**
228
- * The edit bookmark button view.
229
- */ editButtonView;
230
- /**
231
- * A collection of views that can be focused in the view.
232
- */ _focusables = new ViewCollection();
233
- /**
234
- * Helps cycling over {@link #_focusables} in the view.
235
- */ _focusCycler;
236
- /**
237
- * @inheritDoc
238
- */ constructor(locale){
239
- super(locale);
240
- const t = locale.t;
241
- this.bookmarkPreviewView = this._createBookmarkPreviewView();
242
- this.removeButtonView = this._createButton(t('Remove bookmark'), icons.remove, 'remove', this.bookmarkPreviewView);
243
- this.editButtonView = this._createButton(t('Edit bookmark'), icons.pencil, 'edit', this.bookmarkPreviewView);
244
- this.set('id', undefined);
245
- this._focusCycler = new FocusCycler({
246
- focusables: this._focusables,
247
- focusTracker: this.focusTracker,
248
- keystrokeHandler: this.keystrokes,
249
- actions: {
250
- // Navigate fields backwards using the Shift + Tab keystroke.
251
- focusPrevious: 'shift + tab',
252
- // Navigate fields forwards using the Tab key.
253
- focusNext: 'tab'
254
- }
255
- });
256
- this.setTemplate({
257
- tag: 'div',
258
- attributes: {
259
- class: [
260
- 'ck',
261
- 'ck-bookmark-actions',
262
- 'ck-responsive-form'
263
- ],
264
- // https://github.com/ckeditor/ckeditor5-link/issues/90
265
- tabindex: '-1'
266
- },
267
- children: [
268
- this.bookmarkPreviewView,
269
- this.editButtonView,
270
- this.removeButtonView
271
- ]
272
- });
273
- }
274
- /**
275
- * @inheritDoc
276
- */ render() {
277
- super.render();
278
- const childViews = [
279
- this.editButtonView,
280
- this.removeButtonView
281
- ];
282
- childViews.forEach((v)=>{
283
- // Register the view as focusable.
284
- this._focusables.add(v);
285
- // Register the view in the focus tracker.
286
- this.focusTracker.add(v.element);
287
- });
288
- // Start listening for the keystrokes coming from #element.
289
- this.keystrokes.listenTo(this.element);
290
- }
291
- /**
292
- * @inheritDoc
293
- */ destroy() {
294
- super.destroy();
295
- this.focusTracker.destroy();
296
- this.keystrokes.destroy();
297
- }
298
- /**
299
- * Focuses the fist {@link #_focusables} in the actions.
300
- */ focus() {
301
- this._focusCycler.focusFirst();
302
- }
303
- /**
304
- * Creates a button view.
305
- *
306
- * @param label The button label.
307
- * @param icon The button icon.
308
- * @param eventName An event name that the `ButtonView#execute` event will be delegated to.
309
- * @param additionalLabel An additional label outside the button.
310
- * @returns The button view instance.
311
- */ _createButton(label, icon, eventName, additionalLabel) {
312
- const button = new ButtonView(this.locale);
313
- button.set({
314
- label,
315
- icon,
316
- tooltip: true
317
- });
318
- button.delegate('execute').to(this, eventName);
319
- // Since button label `id` is bound to the `ariaLabelledBy` property
320
- // we need to modify this binding to include only the first ID token
321
- // as this button will be labeled by multiple labels.
322
- button.labelView.unbind('id');
323
- button.labelView.bind('id').to(button, 'ariaLabelledBy', (ariaLabelledBy)=>{
324
- return getFirstToken(ariaLabelledBy);
325
- });
326
- button.ariaLabelledBy = `${button.ariaLabelledBy} ${additionalLabel.id}`;
327
- return button;
328
- }
329
- /**
330
- * Creates a bookmark name preview label.
331
- *
332
- * @returns The label view instance.
333
- */ _createBookmarkPreviewView() {
334
- const label = new LabelView(this.locale);
335
- label.extendTemplate({
336
- attributes: {
337
- class: [
338
- 'ck',
339
- 'ck-bookmark-actions__preview'
340
- ]
341
- }
342
- });
343
- // Bind label text with the bookmark ID.
344
- label.bind('text').to(this, 'id');
345
- return label;
346
- }
347
- }
348
- /**
349
- * Returns the first token from space separated token list.
350
- */ function getFirstToken(tokenList) {
351
- return tokenList.split(' ')[0];
352
- }
353
-
354
222
  /**
355
223
  * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
356
224
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
@@ -548,6 +416,19 @@ import { FocusTracker, KeystrokeHandler, logWarning } from '@ckeditor/ckeditor5-
548
416
  */ static get isOfficialPlugin() {
549
417
  return true;
550
418
  }
419
+ /**
420
+ * @inheritDoc
421
+ */ constructor(editor){
422
+ super(editor);
423
+ editor.config.define('bookmark', {
424
+ toolbar: [
425
+ 'bookmarkPreview',
426
+ '|',
427
+ 'editBookmark',
428
+ 'removeBookmark'
429
+ ]
430
+ });
431
+ }
551
432
  /**
552
433
  * @inheritDoc
553
434
  */ init() {
@@ -570,6 +451,11 @@ import { FocusTracker, KeystrokeHandler, logWarning } from '@ckeditor/ckeditor5-
570
451
  }
571
452
  return null;
572
453
  }
454
+ /**
455
+ * Returns all unique bookmark names existing in the content.
456
+ */ getAllBookmarkNames() {
457
+ return new Set(this._bookmarkElements.values());
458
+ }
573
459
  /**
574
460
  * Defines the schema for the bookmark feature.
575
461
  */ _defineSchema() {
@@ -622,6 +508,7 @@ import { FocusTracker, KeystrokeHandler, logWarning } from '@ckeditor/ckeditor5-
622
508
  }, [
623
509
  this._createBookmarkUIElement(writer)
624
510
  ]);
511
+ writer.setCustomProperty('bookmark', true, containerElement);
625
512
  this._bookmarkElements.set(modelElement, id);
626
513
  // `getFillerOffset` is not needed to set here, because `toWidget` has already covered it.
627
514
  const labelCreator = ()=>`${id} ${t('bookmark widget')}`;
@@ -641,7 +528,7 @@ import { FocusTracker, KeystrokeHandler, logWarning } from '@ckeditor/ckeditor5-
641
528
  const domElement = this.toDomElement(domDocument);
642
529
  const icon = new IconView();
643
530
  icon.set({
644
- content: icons.bookmarkInline,
531
+ content: IconBookmarkInline,
645
532
  isColorInherited: false
646
533
  });
647
534
  icon.render();
@@ -751,9 +638,6 @@ const VISUAL_SELECTION_MARKER_NAME = 'bookmark-ui';
751
638
  * It registers the `'bookmark'` UI button in the editor's {@link module:ui/componentfactory~ComponentFactory component factory}
752
639
  * which inserts the `bookmark` element upon selection.
753
640
  */ class BookmarkUI extends Plugin {
754
- /**
755
- * The actions view displayed inside of the balloon.
756
- */ actionsView = null;
757
641
  /**
758
642
  * The form view displayed inside the balloon.
759
643
  */ formView = null;
@@ -765,7 +649,8 @@ const VISUAL_SELECTION_MARKER_NAME = 'bookmark-ui';
765
649
  */ static get requires() {
766
650
  return [
767
651
  BookmarkEditing,
768
- ContextualBalloon
652
+ ContextualBalloon,
653
+ WidgetToolbarRepository
769
654
  ];
770
655
  }
771
656
  /**
@@ -782,11 +667,13 @@ const VISUAL_SELECTION_MARKER_NAME = 'bookmark-ui';
782
667
  * @inheritDoc
783
668
  */ init() {
784
669
  const editor = this.editor;
785
- editor.editing.view.addObserver(ClickObserver);
786
670
  this._balloon = editor.plugins.get(ContextualBalloon);
671
+ // Register the link provider in link plugin to display the link form.
672
+ if (editor.plugins.has('LinkUI')) {
673
+ this._registerLinkProvider();
674
+ }
787
675
  // Create toolbar buttons.
788
- this._createToolbarBookmarkButton();
789
- this._enableBalloonActivators();
676
+ this._registerComponents();
790
677
  // Renders a fake visual selection marker on an expanded selection.
791
678
  editor.conversion.for('editingDowncast').markerToHighlight({
792
679
  model: VISUAL_SELECTION_MARKER_NAME,
@@ -812,6 +699,35 @@ const VISUAL_SELECTION_MARKER_NAME = 'bookmark-ui';
812
699
  }
813
700
  });
814
701
  }
702
+ /**
703
+ * @inheritDoc
704
+ */ afterInit() {
705
+ const editor = this.editor;
706
+ const t = editor.locale.t;
707
+ const widgetToolbarRepository = this.editor.plugins.get(WidgetToolbarRepository);
708
+ const defaultPositions = BalloonPanelView.defaultPositions;
709
+ widgetToolbarRepository.register('bookmark', {
710
+ ariaLabel: t('Bookmark toolbar'),
711
+ items: editor.config.get('bookmark.toolbar'),
712
+ getRelatedElement: getSelectedBookmarkWidget,
713
+ balloonClassName: 'ck-bookmark-balloon',
714
+ // Override positions to the same list as for balloon panel default
715
+ // so widget toolbar will try to use same position as form view.
716
+ positions: [
717
+ defaultPositions.southArrowNorth,
718
+ defaultPositions.southArrowNorthMiddleWest,
719
+ defaultPositions.southArrowNorthMiddleEast,
720
+ defaultPositions.southArrowNorthWest,
721
+ defaultPositions.southArrowNorthEast,
722
+ defaultPositions.northArrowSouth,
723
+ defaultPositions.northArrowSouthMiddleWest,
724
+ defaultPositions.northArrowSouthMiddleEast,
725
+ defaultPositions.northArrowSouthWest,
726
+ defaultPositions.northArrowSouthEast,
727
+ defaultPositions.viewportStickyNorth
728
+ ]
729
+ });
730
+ }
815
731
  /**
816
732
  * @inheritDoc
817
733
  */ destroy() {
@@ -820,49 +736,20 @@ const VISUAL_SELECTION_MARKER_NAME = 'bookmark-ui';
820
736
  if (this.formView) {
821
737
  this.formView.destroy();
822
738
  }
823
- if (this.actionsView) {
824
- this.actionsView.destroy();
825
- }
826
739
  }
827
740
  /**
828
741
  * Creates views.
829
742
  */ _createViews() {
830
- this.actionsView = this._createActionsView();
831
743
  this.formView = this._createFormView();
832
744
  // Attach lifecycle actions to the the balloon.
833
745
  this._enableUserBalloonInteractions();
834
746
  }
835
- /**
836
- * Creates the {@link module:bookmark/ui/bookmarkactionsview~BookmarkActionsView} instance.
837
- */ _createActionsView() {
838
- const editor = this.editor;
839
- const actionsView = new BookmarkActionsView(editor.locale);
840
- const updateBookmarkCommand = editor.commands.get('updateBookmark');
841
- const deleteCommand = editor.commands.get('delete');
842
- actionsView.bind('id').to(updateBookmarkCommand, 'value');
843
- actionsView.editButtonView.bind('isEnabled').to(updateBookmarkCommand);
844
- actionsView.removeButtonView.bind('isEnabled').to(deleteCommand);
845
- // Display edit form view after clicking on the "Edit" button.
846
- this.listenTo(actionsView, 'edit', ()=>{
847
- this._addFormView();
848
- });
849
- // Execute remove command after clicking on the "Remove" button.
850
- this.listenTo(actionsView, 'remove', ()=>{
851
- this._hideUI();
852
- editor.execute('delete');
853
- });
854
- // Close the panel on esc key press when the **actions have focus**.
855
- actionsView.keystrokes.set('Esc', (data, cancel)=>{
856
- this._hideUI();
857
- cancel();
858
- });
859
- return actionsView;
860
- }
861
747
  /**
862
748
  * Creates the {@link module:bookmark/ui/bookmarkformview~BookmarkFormView} instance.
863
749
  */ _createFormView() {
864
750
  const editor = this.editor;
865
751
  const locale = editor.locale;
752
+ const t = locale.t;
866
753
  const insertBookmarkCommand = editor.commands.get('insertBookmark');
867
754
  const updateBookmarkCommand = editor.commands.get('updateBookmark');
868
755
  const commands = [
@@ -871,10 +758,15 @@ const VISUAL_SELECTION_MARKER_NAME = 'bookmark-ui';
871
758
  ];
872
759
  const formView = new (CssTransitionDisablerMixin(BookmarkFormView))(locale, getFormValidators(editor));
873
760
  formView.idInputView.fieldView.bind('value').to(updateBookmarkCommand, 'value');
761
+ formView.saveButtonView.bind('label').to(updateBookmarkCommand, 'value', (value)=>value ? t('Save') : t('Insert'));
874
762
  // Form elements should be read-only when corresponding commands are disabled.
875
763
  formView.idInputView.bind('isEnabled').toMany(commands, 'isEnabled', (...areEnabled)=>areEnabled.some((isEnabled)=>isEnabled));
876
764
  // Disable the "save" button if the command is disabled.
877
- formView.buttonView.bind('isEnabled').toMany(commands, 'isEnabled', (...areEnabled)=>areEnabled.some((isEnabled)=>isEnabled));
765
+ formView.saveButtonView.bind('isEnabled').toMany(commands, 'isEnabled', (...areEnabled)=>areEnabled.some((isEnabled)=>isEnabled));
766
+ // Close the panel on form after clicking back button.
767
+ this.listenTo(formView, 'cancel', ()=>{
768
+ this._hideFormView();
769
+ });
878
770
  // Execute link command after clicking the "Save" button.
879
771
  this.listenTo(formView, 'submit', ()=>{
880
772
  if (formView.isValid()) {
@@ -888,39 +780,131 @@ const VISUAL_SELECTION_MARKER_NAME = 'bookmark-ui';
888
780
  bookmarkId: value
889
781
  });
890
782
  }
891
- this._closeFormView();
783
+ this._hideFormView();
892
784
  }
893
785
  });
894
786
  // Update balloon position when form error changes.
895
787
  this.listenTo(formView.idInputView, 'change:errorText', ()=>{
896
788
  editor.ui.update();
897
789
  });
898
- // Close the panel on esc key press when the **form has focus**.
899
- formView.keystrokes.set('Esc', (data, cancel)=>{
900
- this._closeFormView();
901
- cancel();
902
- });
903
790
  return formView;
904
791
  }
792
+ /**
793
+ * Creates link form menu list entry, so it'll be possible to access
794
+ * the list of the bookmarks from the link form.
795
+ */ _registerLinkProvider() {
796
+ const t = this.editor.locale.t;
797
+ const linksUI = this.editor.plugins.get('LinkUI');
798
+ const bookmarkEditing = this.editor.plugins.get(BookmarkEditing);
799
+ const getListItems = ()=>Array.from(bookmarkEditing.getAllBookmarkNames()).sort((a, b)=>a.localeCompare(b)).map((bookmarkId)=>({
800
+ id: bookmarkId,
801
+ href: `#${bookmarkId}`,
802
+ label: bookmarkId,
803
+ icon: IconBookmarkMedium
804
+ }));
805
+ const getItem = (href)=>{
806
+ const bookmark = [
807
+ ...bookmarkEditing.getAllBookmarkNames()
808
+ ].find((item)=>`#${item}` === href);
809
+ if (!bookmark) {
810
+ return null;
811
+ }
812
+ return {
813
+ href,
814
+ label: bookmark,
815
+ icon: IconBookmarkSmall,
816
+ tooltip: t('Scroll to bookmark')
817
+ };
818
+ };
819
+ linksUI.registerLinksListProvider({
820
+ label: t('Bookmarks'),
821
+ emptyListPlaceholder: t('No bookmarks available.'),
822
+ navigate: ({ href })=>this._scrollToBookmark(href),
823
+ getListItems,
824
+ getItem
825
+ });
826
+ }
827
+ /**
828
+ * Scrolls the editor to the bookmark with the given id.
829
+ */ _scrollToBookmark(href) {
830
+ const bookmarkEditing = this.editor.plugins.get(BookmarkEditing);
831
+ const bookmarkElement = bookmarkEditing.getElementForBookmarkId(href.slice(1));
832
+ if (!bookmarkElement) {
833
+ return false;
834
+ }
835
+ this.editor.model.change((writer)=>{
836
+ writer.setSelection(bookmarkElement, 'on');
837
+ });
838
+ this.editor.editing.view.scrollToTheSelection({
839
+ alignToTop: true,
840
+ forceScroll: true
841
+ });
842
+ return true;
843
+ }
905
844
  /**
906
845
  * Creates a toolbar Bookmark button. Clicking this button will show
907
846
  * a {@link #_balloon} attached to the selection.
908
- */ _createToolbarBookmarkButton() {
847
+ */ _registerComponents() {
909
848
  const editor = this.editor;
910
849
  editor.ui.componentFactory.add('bookmark', ()=>{
911
- const buttonView = this._createButton(ButtonView);
850
+ const buttonView = this._createBookmarkButton(ButtonView);
912
851
  buttonView.set({
913
852
  tooltip: true
914
853
  });
915
854
  return buttonView;
916
855
  });
917
856
  editor.ui.componentFactory.add('menuBar:bookmark', ()=>{
918
- return this._createButton(MenuBarMenuListItemButtonView);
857
+ return this._createBookmarkButton(MenuBarMenuListItemButtonView);
858
+ });
859
+ // Bookmark toolbar buttons.
860
+ editor.ui.componentFactory.add('bookmarkPreview', (locale)=>{
861
+ const updateBookmarkCommand = editor.commands.get('updateBookmark');
862
+ const label = new LabelView(locale);
863
+ label.extendTemplate({
864
+ attributes: {
865
+ class: [
866
+ 'ck-bookmark-toolbar__preview'
867
+ ]
868
+ }
869
+ });
870
+ label.bind('text').to(updateBookmarkCommand, 'value');
871
+ return label;
872
+ });
873
+ editor.ui.componentFactory.add('editBookmark', (locale)=>{
874
+ const updateBookmarkCommand = editor.commands.get('updateBookmark');
875
+ const button = new ButtonView(locale);
876
+ const t = locale.t;
877
+ button.set({
878
+ label: t('Edit bookmark'),
879
+ icon: IconPencil,
880
+ tooltip: true
881
+ });
882
+ button.bind('isEnabled').to(updateBookmarkCommand);
883
+ this.listenTo(button, 'execute', ()=>{
884
+ this._showFormView();
885
+ });
886
+ return button;
887
+ });
888
+ editor.ui.componentFactory.add('removeBookmark', (locale)=>{
889
+ const deleteCommand = editor.commands.get('delete');
890
+ const button = new ButtonView(locale);
891
+ const t = locale.t;
892
+ button.set({
893
+ label: t('Remove bookmark'),
894
+ icon: IconRemove,
895
+ tooltip: true
896
+ });
897
+ button.bind('isEnabled').to(deleteCommand);
898
+ this.listenTo(button, 'execute', ()=>{
899
+ editor.execute('delete');
900
+ editor.editing.view.focus();
901
+ });
902
+ return button;
919
903
  });
920
904
  }
921
905
  /**
922
906
  * Creates a button for `bookmark` command to use either in toolbar or in menu bar.
923
- */ _createButton(ButtonClass) {
907
+ */ _createBookmarkButton(ButtonClass) {
924
908
  const editor = this.editor;
925
909
  const locale = editor.locale;
926
910
  const view = new ButtonClass(locale);
@@ -929,10 +913,10 @@ const VISUAL_SELECTION_MARKER_NAME = 'bookmark-ui';
929
913
  const t = locale.t;
930
914
  view.set({
931
915
  label: t('Bookmark'),
932
- icon: icons.bookmark
916
+ icon: IconBookmark
933
917
  });
934
918
  // Execute the command.
935
- this.listenTo(view, 'execute', ()=>this._showUI(true));
919
+ this.listenTo(view, 'execute', ()=>this._showFormView());
936
920
  view.bind('isEnabled').toMany([
937
921
  insertCommand,
938
922
  updateCommand
@@ -940,75 +924,25 @@ const VISUAL_SELECTION_MARKER_NAME = 'bookmark-ui';
940
924
  view.bind('isOn').to(updateCommand, 'value', (value)=>!!value);
941
925
  return view;
942
926
  }
943
- /**
944
- * Attaches actions that control whether the balloon panel containing the
945
- * {@link #formView} should be displayed.
946
- */ _enableBalloonActivators() {
947
- const editor = this.editor;
948
- const viewDocument = editor.editing.view.document;
949
- // Handle click on view document and show panel when selection is placed inside the bookmark element.
950
- // Keep panel open until selection will be inside the same bookmark element.
951
- this.listenTo(viewDocument, 'click', ()=>{
952
- const bookmark = this._getSelectedBookmarkElement();
953
- if (bookmark) {
954
- // Then show panel but keep focus inside editor editable.
955
- this._showUI();
956
- }
957
- });
958
- }
959
927
  /**
960
928
  * Attaches actions that control whether the balloon panel containing the
961
929
  * {@link #formView} is visible or not.
962
930
  */ _enableUserBalloonInteractions() {
963
- // Focus the form if the balloon is visible and the Tab key has been pressed.
964
- this.editor.keystrokes.set('Tab', (data, cancel)=>{
965
- if (this._areActionsVisible && !this.actionsView.focusTracker.isFocused) {
966
- this.actionsView.focus();
967
- cancel();
968
- }
969
- }, {
970
- // Use the high priority because the bookmark UI navigation is more important
971
- // than other feature's actions, e.g. list indentation.
972
- priority: 'high'
973
- });
974
931
  // Close the panel on the Esc key press when the editable has focus and the balloon is visible.
975
932
  this.editor.keystrokes.set('Esc', (data, cancel)=>{
976
- if (this._isUIVisible) {
977
- this._hideUI();
933
+ if (this._isFormVisible) {
934
+ this._hideFormView();
978
935
  cancel();
979
936
  }
980
937
  });
981
938
  // Close on click outside of balloon panel element.
982
939
  clickOutsideHandler({
983
940
  emitter: this.formView,
984
- activator: ()=>this._isUIInPanel,
941
+ activator: ()=>this._isFormInPanel,
985
942
  contextElements: ()=>[
986
943
  this._balloon.view.element
987
944
  ],
988
- callback: ()=>this._hideUI()
989
- });
990
- }
991
- /**
992
- * Updates the button label. If bookmark is selected label is set to 'Update' otherwise
993
- * it is 'Insert'.
994
- */ _updateFormButtonLabel(isBookmarkSelected) {
995
- const t = this.editor.locale.t;
996
- this.formView.buttonView.label = isBookmarkSelected ? t('Update') : t('Insert');
997
- }
998
- /**
999
- * Adds the {@link #actionsView} to the {@link #_balloon}.
1000
- *
1001
- * @internal
1002
- */ _addActionsView() {
1003
- if (!this.actionsView) {
1004
- this._createViews();
1005
- }
1006
- if (this._areActionsInPanel) {
1007
- return;
1008
- }
1009
- this._balloon.add({
1010
- view: this.actionsView,
1011
- position: this._getBalloonPositionData()
945
+ callback: ()=>this._hideFormView()
1012
946
  });
1013
947
  }
1014
948
  /**
@@ -1020,14 +954,14 @@ const VISUAL_SELECTION_MARKER_NAME = 'bookmark-ui';
1020
954
  if (this._isFormInPanel) {
1021
955
  return;
1022
956
  }
1023
- const editor = this.editor;
1024
- const updateBookmarkCommand = editor.commands.get('updateBookmark');
957
+ const updateBookmarkCommand = this.editor.commands.get('updateBookmark');
1025
958
  this.formView.disableCssTransitions();
1026
959
  this.formView.resetFormStatus();
1027
960
  this._balloon.add({
1028
961
  view: this.formView,
1029
962
  position: this._getBalloonPositionData()
1030
963
  });
964
+ this.formView.backButtonView.isVisible = updateBookmarkCommand.isEnabled;
1031
965
  this.formView.idInputView.fieldView.value = updateBookmarkCommand.value || '';
1032
966
  // Select input when form view is currently visible.
1033
967
  if (this._balloon.visibleView === this.formView) {
@@ -1035,69 +969,39 @@ const VISUAL_SELECTION_MARKER_NAME = 'bookmark-ui';
1035
969
  }
1036
970
  this.formView.enableCssTransitions();
1037
971
  }
1038
- /**
1039
- * Closes the form view. Decides whether the balloon should be hidden completely.
1040
- */ _closeFormView() {
1041
- const updateBookmarkCommand = this.editor.commands.get('updateBookmark');
1042
- if (updateBookmarkCommand.value !== undefined) {
1043
- this._removeFormView();
1044
- } else {
1045
- this._hideUI();
1046
- }
1047
- }
1048
972
  /**
1049
973
  * Removes the {@link #formView} from the {@link #_balloon}.
1050
974
  */ _removeFormView() {
1051
- if (this._isFormInPanel) {
1052
- // Blur the input element before removing it from DOM to prevent issues in some browsers.
1053
- // See https://github.com/ckeditor/ckeditor5/issues/1501.
1054
- this.formView.buttonView.focus();
1055
- // Reset the ID field to update the state of the submit button.
1056
- this.formView.idInputView.fieldView.reset();
1057
- this._balloon.remove(this.formView);
1058
- // Because the form has an input which has focus, the focus must be brought back
1059
- // to the editor. Otherwise, it would be lost.
1060
- this.editor.editing.view.focus();
1061
- this._hideFakeVisualSelection();
1062
- }
975
+ // Blur the input element before removing it from DOM to prevent issues in some browsers.
976
+ // See https://github.com/ckeditor/ckeditor5/issues/1501.
977
+ this.formView.saveButtonView.focus();
978
+ // Reset the ID field to update the state of the submit button.
979
+ this.formView.idInputView.fieldView.reset();
980
+ this._balloon.remove(this.formView);
981
+ // Because the form has an input which has focus, the focus must be brought back
982
+ // to the editor. Otherwise, it would be lost.
983
+ this.editor.editing.view.focus();
984
+ this._hideFakeVisualSelection();
1063
985
  }
1064
986
  /**
1065
- * Shows the correct UI type. It is either {@link #formView} or {@link #actionsView}.
1066
- */ _showUI(forceVisible = false) {
987
+ * Shows the {@link #formView}.
988
+ */ _showFormView() {
1067
989
  if (!this.formView) {
1068
990
  this._createViews();
1069
991
  }
1070
- // When there's no bookmark under the selection, go straight to the editing UI.
1071
992
  if (!this._getSelectedBookmarkElement()) {
1072
- // Show visual selection on a text without a bookmark when the contextual balloon is displayed.
1073
993
  this._showFakeVisualSelection();
1074
- this._addActionsView();
1075
- // Be sure panel with bookmark is visible.
1076
- if (forceVisible) {
1077
- this._balloon.showStack('main');
1078
- }
1079
- this._addFormView();
1080
- } else {
1081
- // Go to the editing UI if actions are already visible.
1082
- if (this._areActionsVisible) {
1083
- this._addFormView();
1084
- } else {
1085
- this._addActionsView();
1086
- }
1087
- // Be sure panel with bookmark is visible.
1088
- if (forceVisible) {
1089
- this._balloon.showStack('main');
1090
- }
1091
994
  }
995
+ this._addFormView();
996
+ // Be sure panel with bookmark is visible.
997
+ this._balloon.showStack('main');
1092
998
  // Begin responding to ui#update once the UI is added.
1093
999
  this._startUpdatingUI();
1094
1000
  }
1095
1001
  /**
1096
1002
  * Removes the {@link #formView} from the {@link #_balloon}.
1097
- *
1098
- * See {@link #_addFormView}, {@link #_addActionsView}.
1099
- */ _hideUI() {
1100
- if (!this._isUIInPanel) {
1003
+ */ _hideFormView() {
1004
+ if (!this._isFormInPanel) {
1101
1005
  return;
1102
1006
  }
1103
1007
  const editor = this.editor;
@@ -1108,21 +1012,18 @@ const VISUAL_SELECTION_MARKER_NAME = 'bookmark-ui';
1108
1012
  editor.editing.view.focus();
1109
1013
  // Remove form first because it's on top of the stack.
1110
1014
  this._removeFormView();
1111
- // Then remove the actions view because it's beneath the form.
1112
- this._balloon.remove(this.actionsView);
1113
1015
  this._hideFakeVisualSelection();
1114
1016
  }
1115
1017
  /**
1116
1018
  * Makes the UI react to the {@link module:ui/editorui/editorui~EditorUI#event:update} event to
1117
1019
  * reposition itself when the editor UI should be refreshed.
1118
1020
  *
1119
- * See: {@link #_hideUI} to learn when the UI stops reacting to the `update` event.
1021
+ * See: {@link #_hideFormView} to learn when the UI stops reacting to the `update` event.
1120
1022
  */ _startUpdatingUI() {
1121
1023
  const editor = this.editor;
1122
1024
  const viewDocument = editor.editing.view.document;
1123
1025
  let prevSelectedBookmark = this._getSelectedBookmarkElement();
1124
1026
  let prevSelectionParent = getSelectionParent();
1125
- this._updateFormButtonLabel(!!prevSelectedBookmark);
1126
1027
  const update = ()=>{
1127
1028
  const selectedBookmark = this._getSelectedBookmarkElement();
1128
1029
  const selectionParent = getSelectionParent();
@@ -1135,14 +1036,13 @@ const VISUAL_SELECTION_MARKER_NAME = 'bookmark-ui';
1135
1036
  // * the selection has expanded (e.g. displaying bookmark actions then pressing SHIFT+Right arrow).
1136
1037
  //
1137
1038
  if (prevSelectedBookmark && !selectedBookmark || !prevSelectedBookmark && selectionParent !== prevSelectionParent) {
1138
- this._hideUI();
1139
- } else if (this._isUIVisible) {
1039
+ this._hideFormView();
1040
+ } else if (this._isFormVisible) {
1140
1041
  // If still in a bookmark element, simply update the position of the balloon.
1141
1042
  // If there was no bookmark (e.g. inserting one), the balloon must be moved
1142
1043
  // to the new position in the editing view (a new native DOM range).
1143
1044
  this._balloon.updatePosition(this._getBalloonPositionData());
1144
1045
  }
1145
- this._updateFormButtonLabel(!!prevSelectedBookmark);
1146
1046
  prevSelectedBookmark = selectedBookmark;
1147
1047
  prevSelectionParent = selectionParent;
1148
1048
  };
@@ -1158,27 +1058,9 @@ const VISUAL_SELECTION_MARKER_NAME = 'bookmark-ui';
1158
1058
  return !!this.formView && this._balloon.hasView(this.formView);
1159
1059
  }
1160
1060
  /**
1161
- * Returns `true` when {@link #actionsView} is in the {@link #_balloon}.
1162
- */ get _areActionsInPanel() {
1163
- return !!this.actionsView && this._balloon.hasView(this.actionsView);
1164
- }
1165
- /**
1166
- * Returns `true` when {@link #actionsView} is in the {@link #_balloon} and it is
1167
- * currently visible.
1168
- */ get _areActionsVisible() {
1169
- return !!this.actionsView && this._balloon.visibleView === this.actionsView;
1170
- }
1171
- /**
1172
- * Returns `true` when {@link #actionsView} or {@link #formView} is in the {@link #_balloon}.
1173
- */ get _isUIInPanel() {
1174
- return this._isFormInPanel || this._areActionsInPanel;
1175
- }
1176
- /**
1177
- * Returns `true` when {@link #actionsView} or {@link #formView} is in the {@link #_balloon} and it is
1178
- * currently visible.
1179
- */ get _isUIVisible() {
1180
- const visibleView = this._balloon.visibleView;
1181
- return !!this.formView && visibleView == this.formView || this._areActionsVisible;
1061
+ * Returns `true` when {@link #formView} is in the {@link #_balloon} and it is currently visible.
1062
+ */ get _isFormVisible() {
1063
+ return !!this.formView && this._balloon.visibleView == this.formView;
1182
1064
  }
1183
1065
  /**
1184
1066
  * Returns positioning options for the {@link #_balloon}. They control the way the balloon is attached
@@ -1201,7 +1083,10 @@ const VISUAL_SELECTION_MARKER_NAME = 'bookmark-ui';
1201
1083
  return domConverter.mapViewToDom(viewElement);
1202
1084
  };
1203
1085
  }
1204
- return target && {
1086
+ if (!target) {
1087
+ return;
1088
+ }
1089
+ return {
1205
1090
  target
1206
1091
  };
1207
1092
  }
@@ -1289,6 +1174,15 @@ const VISUAL_SELECTION_MARKER_NAME = 'bookmark-ui';
1289
1174
  }
1290
1175
  ];
1291
1176
  }
1177
+ /**
1178
+ * Returns the currently selected bookmark view element.
1179
+ */ function getSelectedBookmarkWidget(selection) {
1180
+ const element = selection.getSelectedElement();
1181
+ if (!element || !isWidget(element) || !element.getCustomProperty('bookmark')) {
1182
+ return null;
1183
+ }
1184
+ return element;
1185
+ }
1292
1186
 
1293
1187
  /**
1294
1188
  * The bookmark feature.