@ckeditor/ckeditor5-ui 39.0.1 → 40.0.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 (229) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/LICENSE.md +1 -1
  3. package/README.md +4 -4
  4. package/lang/contexts.json +5 -1
  5. package/lang/translations/ar.po +17 -0
  6. package/lang/translations/ast.po +17 -0
  7. package/lang/translations/az.po +17 -0
  8. package/lang/translations/bg.po +17 -0
  9. package/lang/translations/bn.po +17 -0
  10. package/lang/translations/ca.po +17 -0
  11. package/lang/translations/cs.po +17 -0
  12. package/lang/translations/da.po +17 -0
  13. package/lang/translations/de-ch.po +17 -0
  14. package/lang/translations/de.po +17 -0
  15. package/lang/translations/el.po +17 -0
  16. package/lang/translations/en-au.po +17 -0
  17. package/lang/translations/en-gb.po +17 -0
  18. package/lang/translations/en.po +17 -0
  19. package/lang/translations/eo.po +17 -0
  20. package/lang/translations/es.po +17 -0
  21. package/lang/translations/et.po +17 -0
  22. package/lang/translations/eu.po +17 -0
  23. package/lang/translations/fa.po +17 -0
  24. package/lang/translations/fi.po +17 -0
  25. package/lang/translations/fr.po +17 -0
  26. package/lang/translations/gl.po +17 -0
  27. package/lang/translations/he.po +17 -0
  28. package/lang/translations/hi.po +17 -0
  29. package/lang/translations/hr.po +17 -0
  30. package/lang/translations/hu.po +17 -0
  31. package/lang/translations/id.po +17 -0
  32. package/lang/translations/it.po +17 -0
  33. package/lang/translations/ja.po +17 -0
  34. package/lang/translations/km.po +17 -0
  35. package/lang/translations/kn.po +17 -0
  36. package/lang/translations/ko.po +17 -0
  37. package/lang/translations/ku.po +17 -0
  38. package/lang/translations/lt.po +17 -0
  39. package/lang/translations/lv.po +17 -0
  40. package/lang/translations/ms.po +17 -0
  41. package/lang/translations/nb.po +17 -0
  42. package/lang/translations/ne.po +17 -0
  43. package/lang/translations/nl.po +17 -0
  44. package/lang/translations/no.po +17 -0
  45. package/lang/translations/pl.po +17 -0
  46. package/lang/translations/pt-br.po +17 -0
  47. package/lang/translations/pt.po +17 -0
  48. package/lang/translations/ro.po +17 -0
  49. package/lang/translations/ru.po +17 -0
  50. package/lang/translations/sk.po +17 -0
  51. package/lang/translations/sl.po +17 -0
  52. package/lang/translations/sq.po +17 -0
  53. package/lang/translations/sr-latn.po +17 -0
  54. package/lang/translations/sr.po +17 -0
  55. package/lang/translations/sv.po +17 -0
  56. package/lang/translations/th.po +17 -0
  57. package/lang/translations/tk.po +17 -0
  58. package/lang/translations/tr.po +17 -0
  59. package/lang/translations/tt.po +17 -0
  60. package/lang/translations/ug.po +17 -0
  61. package/lang/translations/uk.po +17 -0
  62. package/lang/translations/ur.po +17 -0
  63. package/lang/translations/uz.po +17 -0
  64. package/lang/translations/vi.po +17 -0
  65. package/lang/translations/zh-cn.po +17 -0
  66. package/lang/translations/zh.po +17 -0
  67. package/package.json +3 -7
  68. package/src/augmentation.d.ts +86 -86
  69. package/src/augmentation.js +5 -5
  70. package/src/autocomplete/autocompleteview.d.ts +81 -0
  71. package/src/autocomplete/autocompleteview.js +146 -0
  72. package/src/bindings/addkeyboardhandlingforgrid.d.ts +27 -27
  73. package/src/bindings/addkeyboardhandlingforgrid.js +107 -107
  74. package/src/bindings/clickoutsidehandler.d.ts +28 -28
  75. package/src/bindings/clickoutsidehandler.js +36 -36
  76. package/src/bindings/csstransitiondisablermixin.d.ts +40 -40
  77. package/src/bindings/csstransitiondisablermixin.js +55 -55
  78. package/src/bindings/injectcsstransitiondisabler.d.ts +59 -59
  79. package/src/bindings/injectcsstransitiondisabler.js +71 -71
  80. package/src/bindings/preventdefault.d.ts +33 -33
  81. package/src/bindings/preventdefault.js +34 -34
  82. package/src/bindings/submithandler.d.ts +57 -57
  83. package/src/bindings/submithandler.js +47 -47
  84. package/src/button/button.d.ts +178 -178
  85. package/src/button/button.js +5 -5
  86. package/src/button/buttonlabel.d.ts +34 -0
  87. package/src/button/buttonlabel.js +5 -0
  88. package/src/button/buttonlabelview.d.ts +31 -0
  89. package/src/button/buttonlabelview.js +42 -0
  90. package/src/button/buttonview.d.ts +185 -177
  91. package/src/button/buttonview.js +219 -231
  92. package/src/button/switchbuttonview.d.ts +45 -45
  93. package/src/button/switchbuttonview.js +75 -75
  94. package/src/colorgrid/colorgridview.d.ts +132 -132
  95. package/src/colorgrid/colorgridview.js +124 -124
  96. package/src/colorgrid/colortileview.d.ts +28 -28
  97. package/src/colorgrid/colortileview.js +40 -40
  98. package/src/colorgrid/utils.d.ts +47 -47
  99. package/src/colorgrid/utils.js +84 -84
  100. package/src/colorpicker/colorpickerview.d.ts +137 -137
  101. package/src/colorpicker/colorpickerview.js +270 -270
  102. package/src/colorpicker/utils.d.ts +43 -43
  103. package/src/colorpicker/utils.js +99 -99
  104. package/src/colorselector/colorgridsfragmentview.d.ts +194 -194
  105. package/src/colorselector/colorgridsfragmentview.js +289 -289
  106. package/src/colorselector/colorpickerfragmentview.d.ts +128 -128
  107. package/src/colorselector/colorpickerfragmentview.js +205 -205
  108. package/src/colorselector/colorselectorview.d.ts +242 -242
  109. package/src/colorselector/colorselectorview.js +256 -256
  110. package/src/colorselector/documentcolorcollection.d.ts +70 -70
  111. package/src/colorselector/documentcolorcollection.js +42 -42
  112. package/src/componentfactory.d.ts +81 -81
  113. package/src/componentfactory.js +104 -104
  114. package/src/dropdown/button/dropdownbutton.d.ts +25 -25
  115. package/src/dropdown/button/dropdownbutton.js +5 -5
  116. package/src/dropdown/button/dropdownbuttonview.d.ts +48 -48
  117. package/src/dropdown/button/dropdownbuttonview.js +66 -66
  118. package/src/dropdown/button/splitbuttonview.d.ts +161 -161
  119. package/src/dropdown/button/splitbuttonview.js +152 -152
  120. package/src/dropdown/dropdownpanelfocusable.d.ts +21 -21
  121. package/src/dropdown/dropdownpanelfocusable.js +5 -5
  122. package/src/dropdown/dropdownpanelview.d.ts +62 -62
  123. package/src/dropdown/dropdownpanelview.js +97 -97
  124. package/src/dropdown/dropdownview.d.ts +315 -315
  125. package/src/dropdown/dropdownview.js +379 -378
  126. package/src/dropdown/utils.d.ts +235 -221
  127. package/src/dropdown/utils.js +458 -437
  128. package/src/editableui/editableuiview.d.ts +72 -72
  129. package/src/editableui/editableuiview.js +112 -112
  130. package/src/editableui/inline/inlineeditableuiview.d.ts +40 -40
  131. package/src/editableui/inline/inlineeditableuiview.js +48 -48
  132. package/src/editorui/bodycollection.d.ts +55 -55
  133. package/src/editorui/bodycollection.js +84 -84
  134. package/src/editorui/boxed/boxededitoruiview.d.ts +40 -40
  135. package/src/editorui/boxed/boxededitoruiview.js +81 -81
  136. package/src/editorui/editorui.d.ts +282 -282
  137. package/src/editorui/editorui.js +410 -410
  138. package/src/editorui/editoruiview.d.ts +39 -39
  139. package/src/editorui/editoruiview.js +38 -38
  140. package/src/editorui/poweredby.d.ts +71 -71
  141. package/src/editorui/poweredby.js +276 -299
  142. package/src/focuscycler.d.ts +226 -183
  143. package/src/focuscycler.js +245 -220
  144. package/src/formheader/formheaderview.d.ts +59 -53
  145. package/src/formheader/formheaderview.js +69 -63
  146. package/src/highlightedtext/highlightedtextview.d.ts +38 -0
  147. package/src/highlightedtext/highlightedtextview.js +102 -0
  148. package/src/icon/iconview.d.ts +85 -78
  149. package/src/icon/iconview.js +114 -112
  150. package/src/iframe/iframeview.d.ts +50 -50
  151. package/src/iframe/iframeview.js +63 -63
  152. package/src/index.d.ts +73 -63
  153. package/src/index.js +70 -62
  154. package/src/input/inputbase.d.ts +107 -0
  155. package/src/input/inputbase.js +110 -0
  156. package/src/input/inputview.d.ts +36 -121
  157. package/src/input/inputview.js +24 -106
  158. package/src/inputnumber/inputnumberview.d.ts +49 -49
  159. package/src/inputnumber/inputnumberview.js +40 -40
  160. package/src/inputtext/inputtextview.d.ts +18 -18
  161. package/src/inputtext/inputtextview.js +27 -27
  162. package/src/label/labelview.d.ts +36 -36
  163. package/src/label/labelview.js +41 -41
  164. package/src/labeledfield/labeledfieldview.d.ts +187 -182
  165. package/src/labeledfield/labeledfieldview.js +157 -157
  166. package/src/labeledfield/utils.d.ts +123 -93
  167. package/src/labeledfield/utils.js +176 -131
  168. package/src/labeledinput/labeledinputview.d.ts +125 -125
  169. package/src/labeledinput/labeledinputview.js +125 -125
  170. package/src/list/listitemgroupview.d.ts +51 -0
  171. package/src/list/listitemgroupview.js +75 -0
  172. package/src/list/listitemview.d.ts +36 -35
  173. package/src/list/listitemview.js +42 -40
  174. package/src/list/listseparatorview.d.ts +18 -18
  175. package/src/list/listseparatorview.js +28 -28
  176. package/src/list/listview.d.ts +122 -65
  177. package/src/list/listview.js +187 -90
  178. package/src/model.d.ts +22 -22
  179. package/src/model.js +31 -31
  180. package/src/notification/notification.d.ts +211 -211
  181. package/src/notification/notification.js +187 -187
  182. package/src/panel/balloon/balloonpanelview.d.ts +685 -685
  183. package/src/panel/balloon/balloonpanelview.js +1010 -988
  184. package/src/panel/balloon/contextualballoon.d.ts +299 -299
  185. package/src/panel/balloon/contextualballoon.js +572 -572
  186. package/src/panel/sticky/stickypanelview.d.ts +156 -158
  187. package/src/panel/sticky/stickypanelview.js +234 -231
  188. package/src/search/filteredview.d.ts +31 -0
  189. package/src/search/filteredview.js +5 -0
  190. package/src/search/searchinfoview.d.ts +45 -0
  191. package/src/search/searchinfoview.js +59 -0
  192. package/src/search/searchresultsview.d.ts +54 -0
  193. package/src/search/searchresultsview.js +65 -0
  194. package/src/search/text/searchtextqueryview.d.ts +76 -0
  195. package/src/search/text/searchtextqueryview.js +75 -0
  196. package/src/search/text/searchtextview.d.ts +219 -0
  197. package/src/search/text/searchtextview.js +201 -0
  198. package/src/spinner/spinnerview.d.ts +25 -0
  199. package/src/spinner/spinnerview.js +38 -0
  200. package/src/template.d.ts +942 -942
  201. package/src/template.js +1294 -1294
  202. package/src/textarea/textareaview.d.ts +88 -0
  203. package/src/textarea/textareaview.js +140 -0
  204. package/src/toolbar/balloon/balloontoolbar.d.ts +122 -122
  205. package/src/toolbar/balloon/balloontoolbar.js +300 -300
  206. package/src/toolbar/block/blockbuttonview.d.ts +35 -35
  207. package/src/toolbar/block/blockbuttonview.js +41 -41
  208. package/src/toolbar/block/blocktoolbar.d.ts +161 -161
  209. package/src/toolbar/block/blocktoolbar.js +395 -391
  210. package/src/toolbar/normalizetoolbarconfig.d.ts +40 -39
  211. package/src/toolbar/normalizetoolbarconfig.js +51 -51
  212. package/src/toolbar/toolbarlinebreakview.d.ts +18 -18
  213. package/src/toolbar/toolbarlinebreakview.js +28 -28
  214. package/src/toolbar/toolbarseparatorview.d.ts +18 -18
  215. package/src/toolbar/toolbarseparatorview.js +28 -28
  216. package/src/toolbar/toolbarview.d.ts +266 -265
  217. package/src/toolbar/toolbarview.js +719 -717
  218. package/src/tooltipmanager.d.ts +180 -180
  219. package/src/tooltipmanager.js +353 -353
  220. package/src/view.d.ts +422 -422
  221. package/src/view.js +396 -396
  222. package/src/viewcollection.d.ts +139 -139
  223. package/src/viewcollection.js +206 -206
  224. package/theme/components/autocomplete/autocomplete.css +22 -0
  225. package/theme/components/formheader/formheader.css +8 -0
  226. package/theme/components/highlightedtext/highlightedtext.css +12 -0
  227. package/theme/components/search/search.css +43 -0
  228. package/theme/components/spinner/spinner.css +23 -0
  229. package/theme/components/textarea/textarea.css +10 -0
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module ui/search/searchresultsview
7
+ */
8
+ import View from '../view';
9
+ import type ViewCollection from '../viewcollection';
10
+ import { FocusTracker, type Locale } from '@ckeditor/ckeditor5-utils';
11
+ import { default as FocusCycler, type FocusableView } from '../focuscycler';
12
+ /**
13
+ * A sub-component of {@link module:ui/search/text/searchtextview~SearchTextView}. It hosts the filtered and the information views.
14
+ */
15
+ export default class SearchResultsView extends View implements FocusableView {
16
+ /**
17
+ * Tracks information about the DOM focus in the view.
18
+ *
19
+ * @readonly
20
+ */
21
+ focusTracker: FocusTracker;
22
+ /**
23
+ * The collection of the child views inside of the list item {@link #element}.
24
+ *
25
+ * @readonly
26
+ */
27
+ children: ViewCollection;
28
+ /**
29
+ * Provides the focus management (keyboard navigation) in the view.
30
+ *
31
+ * @readonly
32
+ */
33
+ protected _focusCycler: FocusCycler;
34
+ /**
35
+ * @inheritDoc
36
+ */
37
+ constructor(locale: Locale);
38
+ /**
39
+ * @inheritDoc
40
+ */
41
+ render(): void;
42
+ /**
43
+ * Focuses the view.
44
+ */
45
+ focus(): void;
46
+ /**
47
+ * Focuses the first child view.
48
+ */
49
+ focusFirst(): void;
50
+ /**
51
+ * Focuses the last child view.
52
+ */
53
+ focusLast(): void;
54
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module ui/search/searchresultsview
7
+ */
8
+ import View from '../view';
9
+ import { FocusTracker } from '@ckeditor/ckeditor5-utils';
10
+ import { default as FocusCycler } from '../focuscycler';
11
+ /**
12
+ * A sub-component of {@link module:ui/search/text/searchtextview~SearchTextView}. It hosts the filtered and the information views.
13
+ */
14
+ export default class SearchResultsView extends View {
15
+ /**
16
+ * @inheritDoc
17
+ */
18
+ constructor(locale) {
19
+ super(locale);
20
+ this.children = this.createCollection();
21
+ this.focusTracker = new FocusTracker();
22
+ this.setTemplate({
23
+ tag: 'div',
24
+ attributes: {
25
+ class: [
26
+ 'ck',
27
+ 'ck-search__results'
28
+ ],
29
+ tabindex: -1
30
+ },
31
+ children: this.children
32
+ });
33
+ this._focusCycler = new FocusCycler({
34
+ focusables: this.children,
35
+ focusTracker: this.focusTracker
36
+ });
37
+ }
38
+ /**
39
+ * @inheritDoc
40
+ */
41
+ render() {
42
+ super.render();
43
+ for (const child of this.children) {
44
+ this.focusTracker.add(child.element);
45
+ }
46
+ }
47
+ /**
48
+ * Focuses the view.
49
+ */
50
+ focus() {
51
+ this._focusCycler.focusFirst();
52
+ }
53
+ /**
54
+ * Focuses the first child view.
55
+ */
56
+ focusFirst() {
57
+ this._focusCycler.focusFirst();
58
+ }
59
+ /**
60
+ * Focuses the last child view.
61
+ */
62
+ focusLast() {
63
+ this._focusCycler.focusLast();
64
+ }
65
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module ui/search/text/searchtextqueryview
7
+ */
8
+ import ButtonView from '../../button/buttonview';
9
+ import IconView from '../../icon/iconview';
10
+ import LabeledFieldView, { type LabeledFieldViewCreator } from '../../labeledfield/labeledfieldview';
11
+ import type InputBase from '../../input/inputbase';
12
+ import type { Locale } from '@ckeditor/ckeditor5-utils';
13
+ /**
14
+ * A search input field for the {@link module:ui/search/text/searchtextview~SearchTextView} component.
15
+ *
16
+ * @internal
17
+ * @extends module:ui/labeledfield/labeledfieldview~LabeledFieldView
18
+ */
19
+ export default class SearchTextQueryView<TQueryFieldView extends InputBase<HTMLInputElement | HTMLTextAreaElement>> extends LabeledFieldView<TQueryFieldView> {
20
+ /**
21
+ * The loupe icon displayed next to the {@link #fieldView}.
22
+ */
23
+ iconView?: IconView;
24
+ /**
25
+ * The button that clears and focuses the {@link #fieldView}.
26
+ */
27
+ resetButtonView?: ButtonView;
28
+ /**
29
+ * A reference to the view configuration.
30
+ */
31
+ private readonly _viewConfig;
32
+ /**
33
+ * @inheritDoc
34
+ */
35
+ constructor(locale: Locale, config: SearchTextQueryViewConfig<TQueryFieldView>);
36
+ /**
37
+ * Resets the search field to its default state.
38
+ */
39
+ reset(): void;
40
+ }
41
+ /**
42
+ * An event fired when the field is reset using the
43
+ * {@link module:ui/search/text/searchtextqueryview~SearchTextQueryView#resetButtonView}.
44
+ *
45
+ * @eventName ~SearchTextQueryView#reset
46
+ */
47
+ export type SearchTextQueryViewResetEvent = {
48
+ name: 'reset';
49
+ args: [];
50
+ };
51
+ /**
52
+ * The configuration of the {@link module:ui/search/text/searchtextqueryview~SearchTextQueryView} view.
53
+ */
54
+ export interface SearchTextQueryViewConfig<TConfigSearchField extends InputBase<HTMLInputElement | HTMLTextAreaElement>> {
55
+ /**
56
+ * The human-readable label of the search field.
57
+ */
58
+ label: string;
59
+ /**
60
+ * Determines whether the button that resets the search should be visible.
61
+ *
62
+ * @default true
63
+ */
64
+ showResetButton?: boolean;
65
+ /**
66
+ * Determines whether the loupe icon should be visible.
67
+ *
68
+ * @default true
69
+ */
70
+ showIcon?: boolean;
71
+ /**
72
+ * The function that creates the search field input view. By default, a plain
73
+ * {@link module:ui/inputtext/inputtextview~InputTextView} is used for this purpose.
74
+ */
75
+ creator?: LabeledFieldViewCreator<TConfigSearchField>;
76
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module ui/search/text/searchtextqueryview
7
+ */
8
+ import ButtonView from '../../button/buttonview';
9
+ import IconView from '../../icon/iconview';
10
+ import LabeledFieldView from '../../labeledfield/labeledfieldview';
11
+ import { createLabeledInputText } from '../../labeledfield/utils';
12
+ import { icons } from '@ckeditor/ckeditor5-core';
13
+ /**
14
+ * A search input field for the {@link module:ui/search/text/searchtextview~SearchTextView} component.
15
+ *
16
+ * @internal
17
+ * @extends module:ui/labeledfield/labeledfieldview~LabeledFieldView
18
+ */
19
+ export default class SearchTextQueryView extends LabeledFieldView {
20
+ /**
21
+ * @inheritDoc
22
+ */
23
+ constructor(locale, config) {
24
+ const t = locale.t;
25
+ const viewConfig = Object.assign({}, {
26
+ showResetButton: true,
27
+ showIcon: true,
28
+ creator: createLabeledInputText
29
+ }, config);
30
+ super(locale, viewConfig.creator);
31
+ this.label = config.label;
32
+ this._viewConfig = viewConfig;
33
+ if (this._viewConfig.showIcon) {
34
+ this.iconView = new IconView();
35
+ this.iconView.content = icons.loupe;
36
+ this.fieldWrapperChildren.add(this.iconView, 0);
37
+ this.extendTemplate({
38
+ attributes: {
39
+ class: 'ck-search__query_with-icon'
40
+ }
41
+ });
42
+ }
43
+ if (this._viewConfig.showResetButton) {
44
+ this.resetButtonView = new ButtonView(locale);
45
+ this.resetButtonView.set({
46
+ label: t('Clear'),
47
+ icon: icons.cancel,
48
+ class: 'ck-search__reset',
49
+ isVisible: false,
50
+ tooltip: true
51
+ });
52
+ this.resetButtonView.on('execute', () => {
53
+ this.reset();
54
+ this.focus();
55
+ this.fire('reset');
56
+ });
57
+ this.resetButtonView.bind('isVisible').to(this.fieldView, 'isEmpty', isEmpty => !isEmpty);
58
+ this.fieldWrapperChildren.add(this.resetButtonView);
59
+ this.extendTemplate({
60
+ attributes: {
61
+ class: 'ck-search__query_with-reset'
62
+ }
63
+ });
64
+ }
65
+ }
66
+ /**
67
+ * Resets the search field to its default state.
68
+ */
69
+ reset() {
70
+ this.fieldView.reset();
71
+ if (this._viewConfig.showResetButton) {
72
+ this.resetButtonView.isVisible = false;
73
+ }
74
+ }
75
+ }
@@ -0,0 +1,219 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module ui/search/text/searchtextview
7
+ */
8
+ import { FocusTracker, KeystrokeHandler, type Locale } from '@ckeditor/ckeditor5-utils';
9
+ import View from '../../view';
10
+ import { default as SearchTextQueryView, type SearchTextQueryViewConfig } from './searchtextqueryview';
11
+ import SearchResultsView from '../searchresultsview';
12
+ import FocusCycler from '../../focuscycler';
13
+ import type FilteredView from '../filteredview';
14
+ import type ViewCollection from '../../viewcollection';
15
+ import type InputBase from '../../input/inputbase';
16
+ import type InputTextView from '../../inputtext/inputtextview';
17
+ import '../../../theme/components/search/search.css';
18
+ /**
19
+ * A search component that allows filtering of an arbitrary view based on a search query
20
+ * specified by the user in a text field.
21
+ *
22
+ *```ts
23
+ * // This view must specify the `filter()` and `focus()` methods.
24
+ * const filteredView = ...;
25
+ *
26
+ * const searchView = new SearchTextView( locale, {
27
+ * searchFieldLabel: 'Search list items',
28
+ * filteredView
29
+ * } );
30
+ *
31
+ * view.render();
32
+ *
33
+ * document.body.append( view.element );
34
+ * ```
35
+ */
36
+ export default class SearchTextView<TQueryFieldView extends InputBase<HTMLInputElement | HTMLTextAreaElement> = InputTextView> extends View {
37
+ /**
38
+ * Tracks information about the DOM focus in the view.
39
+ *
40
+ * @readonly
41
+ */
42
+ focusTracker: FocusTracker;
43
+ /**
44
+ * An instance of the keystroke handler managing user interaction and accessibility.
45
+ *
46
+ * @readonly
47
+ */
48
+ keystrokes: KeystrokeHandler;
49
+ /**
50
+ * A view hosting the {@link #filteredView} passed in the configuration and the {@link #infoView}.
51
+ */
52
+ resultsView: SearchResultsView;
53
+ /**
54
+ * The view that is filtered by the search query.
55
+ */
56
+ filteredView: FilteredView;
57
+ /**
58
+ * The view that displays the information about the search results.
59
+ */
60
+ infoView: View | undefined;
61
+ /**
62
+ * The view that allows the user to enter the search query.
63
+ */
64
+ queryView: SearchTextQueryView<TQueryFieldView>;
65
+ /**
66
+ * Controls whether the component is in read-only mode.
67
+ *
68
+ * @default true
69
+ * @observable
70
+ */
71
+ isEnabled: boolean;
72
+ /**
73
+ * The number of results found for the current search query. Updated upon the {@link #search} event.
74
+ *
75
+ * @default 0
76
+ * @observable
77
+ */
78
+ resultsCount: number;
79
+ /**
80
+ * The number of the items that can be searched in the {@link #filteredView}. Updated upon the {@link #search} event.
81
+ *
82
+ * @default 0
83
+ * @observable
84
+ */
85
+ totalItemsCount: number;
86
+ /**
87
+ * The collection of children of the view.
88
+ *
89
+ * @readonly
90
+ */
91
+ readonly children: ViewCollection;
92
+ /**
93
+ * The collection of focusable children of the view. Used by the focus management logic.
94
+ *
95
+ * @readonly
96
+ */
97
+ readonly focusableChildren: ViewCollection;
98
+ locale: Locale;
99
+ /**
100
+ * Provides the focus management (keyboard navigation) between {@link #queryView} and {@link #filteredView}.
101
+ *
102
+ * @readonly
103
+ */
104
+ focusCycler: FocusCycler;
105
+ /**
106
+ * The cached configuration object.
107
+ *
108
+ * @internal
109
+ */
110
+ protected _config: SearchTextViewConfig<TQueryFieldView>;
111
+ /**
112
+ * Creates an instance of the {@link module:ui/search/text/searchtextview~SearchTextView} class.
113
+ *
114
+ * @param locale The localization services instance.
115
+ * @param config Configuration of the view.
116
+ */
117
+ constructor(locale: Locale, config: SearchTextViewConfig<TQueryFieldView>);
118
+ /**
119
+ * @inheritDoc
120
+ */
121
+ render(): void;
122
+ /**
123
+ * Focuses the {@link #queryView}.
124
+ */
125
+ focus(): void;
126
+ /**
127
+ * Resets the component to its initial state.
128
+ */
129
+ reset(): void;
130
+ /**
131
+ * Searches the {@link #filteredView} for the given query.
132
+ *
133
+ * @internal
134
+ * @param query The search query string.
135
+ */
136
+ search(query: string): void;
137
+ /**
138
+ * Creates a search field view based on configured creator..
139
+ */
140
+ private _createSearchTextQueryView;
141
+ /**
142
+ * Initializes the default {@link #infoView} behavior with default text labels when no custom info view
143
+ * was specified in the view config.
144
+ */
145
+ private _enableDefaultInfoViewBehavior;
146
+ }
147
+ /**
148
+ * The configuration of the {@link module:ui/search/text/searchtextview~SearchTextView} class.
149
+ */
150
+ export interface SearchTextViewConfig<TConfigSearchField extends InputBase<HTMLInputElement | HTMLTextAreaElement>> {
151
+ /**
152
+ * The configuration of the view's query field.
153
+ */
154
+ queryView: SearchTextQueryViewConfig<TConfigSearchField>;
155
+ /**
156
+ * The view that is filtered by the search query.
157
+ */
158
+ filteredView: FilteredView;
159
+ /**
160
+ * The view that displays the information about the search results.
161
+ */
162
+ infoView?: {
163
+ /**
164
+ * The view that displays the information about the search results. If not specified,
165
+ * {@link module:ui/search/searchinfoview~SearchInfoView} is used.
166
+ */
167
+ instance?: View;
168
+ /**
169
+ * The configuration of text labels displayed in the {@link #infoView} in different states
170
+ * of the search component.
171
+ *
172
+ * **Note**: This configuration is only used when the {@link #infoView} is **not** specified.
173
+ * In other cases, please use the {@link module:ui/search/searchview~SearchTextViewSearchEvent} to bring about
174
+ * your own info text logic.
175
+ */
176
+ text?: {
177
+ notFound?: {
178
+ primary: SearchTextViewDefaultInfoText;
179
+ secondary?: SearchTextViewDefaultInfoText;
180
+ };
181
+ noSearchableItems?: {
182
+ primary: SearchTextViewDefaultInfoText;
183
+ secondary?: SearchTextViewDefaultInfoText;
184
+ };
185
+ };
186
+ };
187
+ /**
188
+ * The custom CSS class name to be added to the search view element.
189
+ */
190
+ class?: string;
191
+ }
192
+ /**
193
+ * Describes value of a info text configuration in {@link module:ui/search/text/searchtextview~SearchTextViewConfig}.
194
+ * A string or a function that returns a string with the information about the search results.
195
+ */
196
+ export type SearchTextViewDefaultInfoText = string | ((query: string, resultsCount: number, totalItemsCount: number) => string);
197
+ /**
198
+ * An event fired when the search query changes fired by {@link module:ui/search/text/searchtextview~SearchTextView#search}.
199
+ *
200
+ * @eventName ~SearchTextView#search
201
+ */
202
+ export type SearchTextViewSearchEvent = {
203
+ name: 'search';
204
+ args: [SearchTextViewSearchEventData];
205
+ };
206
+ export type SearchTextViewSearchEventData = {
207
+ /**
208
+ * The search query string.
209
+ */
210
+ query: string;
211
+ /**
212
+ * The number of results found for the current search query.
213
+ */
214
+ resultsCount: number;
215
+ /**
216
+ * The number of the items that can be searched.
217
+ */
218
+ totalItemsCount: number;
219
+ };
@@ -0,0 +1,201 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module ui/search/text/searchtextview
7
+ */
8
+ import { FocusTracker, KeystrokeHandler } from '@ckeditor/ckeditor5-utils';
9
+ import View from '../../view';
10
+ import { default as SearchTextQueryView } from './searchtextqueryview';
11
+ import SearchInfoView from '../searchinfoview';
12
+ import SearchResultsView from '../searchresultsview';
13
+ import FocusCycler from '../../focuscycler';
14
+ import { escapeRegExp } from 'lodash-es';
15
+ import '../../../theme/components/search/search.css';
16
+ /**
17
+ * A search component that allows filtering of an arbitrary view based on a search query
18
+ * specified by the user in a text field.
19
+ *
20
+ *```ts
21
+ * // This view must specify the `filter()` and `focus()` methods.
22
+ * const filteredView = ...;
23
+ *
24
+ * const searchView = new SearchTextView( locale, {
25
+ * searchFieldLabel: 'Search list items',
26
+ * filteredView
27
+ * } );
28
+ *
29
+ * view.render();
30
+ *
31
+ * document.body.append( view.element );
32
+ * ```
33
+ */
34
+ export default class SearchTextView extends View {
35
+ /**
36
+ * Creates an instance of the {@link module:ui/search/text/searchtextview~SearchTextView} class.
37
+ *
38
+ * @param locale The localization services instance.
39
+ * @param config Configuration of the view.
40
+ */
41
+ constructor(locale, config) {
42
+ super(locale);
43
+ this._config = config;
44
+ this.filteredView = config.filteredView;
45
+ this.queryView = this._createSearchTextQueryView();
46
+ this.focusTracker = new FocusTracker();
47
+ this.keystrokes = new KeystrokeHandler();
48
+ this.resultsView = new SearchResultsView(locale);
49
+ this.children = this.createCollection();
50
+ this.focusableChildren = this.createCollection([this.queryView, this.resultsView]);
51
+ this.set('isEnabled', true);
52
+ this.set('resultsCount', 0);
53
+ this.set('totalItemsCount', 0);
54
+ if (config.infoView && config.infoView.instance) {
55
+ this.infoView = config.infoView.instance;
56
+ }
57
+ else {
58
+ this.infoView = new SearchInfoView();
59
+ this._enableDefaultInfoViewBehavior();
60
+ this.on('render', () => {
61
+ // Initial search that determines if there are any searchable items
62
+ // and displays the corresponding info text.
63
+ this.search('');
64
+ });
65
+ }
66
+ this.resultsView.children.addMany([this.infoView, this.filteredView]);
67
+ this.focusCycler = new FocusCycler({
68
+ focusables: this.focusableChildren,
69
+ focusTracker: this.focusTracker,
70
+ keystrokeHandler: this.keystrokes,
71
+ actions: {
72
+ // Navigate form fields backwards using the Shift + Tab keystroke.
73
+ focusPrevious: 'shift + tab',
74
+ // Navigate form fields forwards using the Tab key.
75
+ focusNext: 'tab'
76
+ }
77
+ });
78
+ this.on('search', (evt, { resultsCount, totalItemsCount }) => {
79
+ this.resultsCount = resultsCount;
80
+ this.totalItemsCount = totalItemsCount;
81
+ });
82
+ this.setTemplate({
83
+ tag: 'div',
84
+ attributes: {
85
+ class: [
86
+ 'ck',
87
+ 'ck-search',
88
+ config.class || null
89
+ ],
90
+ tabindex: '-1'
91
+ },
92
+ children: this.children
93
+ });
94
+ }
95
+ /**
96
+ * @inheritDoc
97
+ */
98
+ render() {
99
+ super.render();
100
+ this.children.addMany([
101
+ this.queryView,
102
+ this.resultsView
103
+ ]);
104
+ const stopPropagation = (data) => data.stopPropagation();
105
+ for (const focusableChild of this.focusableChildren) {
106
+ this.focusTracker.add(focusableChild.element);
107
+ }
108
+ // Start listening for the keystrokes coming from #element.
109
+ this.keystrokes.listenTo(this.element);
110
+ // Since the form is in the dropdown panel which is a child of the toolbar, the toolbar's
111
+ // keystroke handler would take over the key management in the URL input. We need to prevent
112
+ // this ASAP. Otherwise, the basic caret movement using the arrow keys will be impossible.
113
+ this.keystrokes.set('arrowright', stopPropagation);
114
+ this.keystrokes.set('arrowleft', stopPropagation);
115
+ this.keystrokes.set('arrowup', stopPropagation);
116
+ this.keystrokes.set('arrowdown', stopPropagation);
117
+ }
118
+ /**
119
+ * Focuses the {@link #queryView}.
120
+ */
121
+ focus() {
122
+ this.queryView.focus();
123
+ }
124
+ /**
125
+ * Resets the component to its initial state.
126
+ */
127
+ reset() {
128
+ this.queryView.reset();
129
+ this.search('');
130
+ }
131
+ /**
132
+ * Searches the {@link #filteredView} for the given query.
133
+ *
134
+ * @internal
135
+ * @param query The search query string.
136
+ */
137
+ search(query) {
138
+ const regExp = query ? new RegExp(escapeRegExp(query), 'ig') : null;
139
+ const filteringResults = this.filteredView.filter(regExp);
140
+ this.fire('search', { query, ...filteringResults });
141
+ }
142
+ /**
143
+ * Creates a search field view based on configured creator..
144
+ */
145
+ _createSearchTextQueryView() {
146
+ const queryView = new SearchTextQueryView(this.locale, this._config.queryView);
147
+ this.listenTo(queryView.fieldView, 'input', () => {
148
+ this.search(queryView.fieldView.element.value);
149
+ });
150
+ queryView.on('reset', () => this.reset());
151
+ queryView.bind('isEnabled').to(this);
152
+ return queryView;
153
+ }
154
+ /**
155
+ * Initializes the default {@link #infoView} behavior with default text labels when no custom info view
156
+ * was specified in the view config.
157
+ */
158
+ _enableDefaultInfoViewBehavior() {
159
+ const t = this.locale.t;
160
+ const infoView = this.infoView;
161
+ this.on('search', (evt, data) => {
162
+ if (!data.resultsCount) {
163
+ const defaultTextConfig = this._config.infoView && this._config.infoView.text;
164
+ let primaryText, secondaryText;
165
+ if (data.totalItemsCount) {
166
+ if (defaultTextConfig && defaultTextConfig.notFound) {
167
+ primaryText = defaultTextConfig.notFound.primary;
168
+ secondaryText = defaultTextConfig.notFound.secondary;
169
+ }
170
+ else {
171
+ primaryText = t('No results found');
172
+ secondaryText = '';
173
+ }
174
+ }
175
+ else {
176
+ if (defaultTextConfig && defaultTextConfig.noSearchableItems) {
177
+ primaryText = defaultTextConfig.noSearchableItems.primary;
178
+ secondaryText = defaultTextConfig.noSearchableItems.secondary;
179
+ }
180
+ else {
181
+ primaryText = t('No searchable items');
182
+ secondaryText = '';
183
+ }
184
+ }
185
+ infoView.set({
186
+ primaryText: normalizeInfoText(primaryText, data),
187
+ secondaryText: normalizeInfoText(secondaryText, data),
188
+ isVisible: true
189
+ });
190
+ }
191
+ else {
192
+ infoView.set({
193
+ isVisible: false
194
+ });
195
+ }
196
+ });
197
+ function normalizeInfoText(text, { query, resultsCount, totalItemsCount }) {
198
+ return typeof text === 'function' ? text(query, resultsCount, totalItemsCount) : text;
199
+ }
200
+ }
201
+ }