@ckeditor/ckeditor5-ui 39.0.2 → 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 (226) hide show
  1. package/lang/contexts.json +5 -1
  2. package/lang/translations/ar.po +16 -0
  3. package/lang/translations/ast.po +16 -0
  4. package/lang/translations/az.po +16 -0
  5. package/lang/translations/bg.po +16 -0
  6. package/lang/translations/bn.po +16 -0
  7. package/lang/translations/ca.po +16 -0
  8. package/lang/translations/cs.po +16 -0
  9. package/lang/translations/da.po +16 -0
  10. package/lang/translations/de-ch.po +16 -0
  11. package/lang/translations/de.po +16 -0
  12. package/lang/translations/el.po +16 -0
  13. package/lang/translations/en-au.po +16 -0
  14. package/lang/translations/en-gb.po +16 -0
  15. package/lang/translations/en.po +16 -0
  16. package/lang/translations/eo.po +16 -0
  17. package/lang/translations/es.po +16 -0
  18. package/lang/translations/et.po +16 -0
  19. package/lang/translations/eu.po +16 -0
  20. package/lang/translations/fa.po +16 -0
  21. package/lang/translations/fi.po +16 -0
  22. package/lang/translations/fr.po +16 -0
  23. package/lang/translations/gl.po +16 -0
  24. package/lang/translations/he.po +16 -0
  25. package/lang/translations/hi.po +16 -0
  26. package/lang/translations/hr.po +16 -0
  27. package/lang/translations/hu.po +16 -0
  28. package/lang/translations/id.po +16 -0
  29. package/lang/translations/it.po +16 -0
  30. package/lang/translations/ja.po +16 -0
  31. package/lang/translations/km.po +16 -0
  32. package/lang/translations/kn.po +16 -0
  33. package/lang/translations/ko.po +16 -0
  34. package/lang/translations/ku.po +16 -0
  35. package/lang/translations/lt.po +16 -0
  36. package/lang/translations/lv.po +16 -0
  37. package/lang/translations/ms.po +16 -0
  38. package/lang/translations/nb.po +16 -0
  39. package/lang/translations/ne.po +16 -0
  40. package/lang/translations/nl.po +16 -0
  41. package/lang/translations/no.po +16 -0
  42. package/lang/translations/pl.po +16 -0
  43. package/lang/translations/pt-br.po +16 -0
  44. package/lang/translations/pt.po +16 -0
  45. package/lang/translations/ro.po +16 -0
  46. package/lang/translations/ru.po +16 -0
  47. package/lang/translations/sk.po +16 -0
  48. package/lang/translations/sl.po +16 -0
  49. package/lang/translations/sq.po +16 -0
  50. package/lang/translations/sr-latn.po +16 -0
  51. package/lang/translations/sr.po +16 -0
  52. package/lang/translations/sv.po +16 -0
  53. package/lang/translations/th.po +16 -0
  54. package/lang/translations/tk.po +16 -0
  55. package/lang/translations/tr.po +16 -0
  56. package/lang/translations/tt.po +16 -0
  57. package/lang/translations/ug.po +16 -0
  58. package/lang/translations/uk.po +16 -0
  59. package/lang/translations/ur.po +16 -0
  60. package/lang/translations/uz.po +16 -0
  61. package/lang/translations/vi.po +16 -0
  62. package/lang/translations/zh-cn.po +16 -0
  63. package/lang/translations/zh.po +16 -0
  64. package/package.json +3 -3
  65. package/src/augmentation.d.ts +86 -86
  66. package/src/augmentation.js +5 -5
  67. package/src/autocomplete/autocompleteview.d.ts +81 -0
  68. package/src/autocomplete/autocompleteview.js +146 -0
  69. package/src/bindings/addkeyboardhandlingforgrid.d.ts +27 -27
  70. package/src/bindings/addkeyboardhandlingforgrid.js +107 -107
  71. package/src/bindings/clickoutsidehandler.d.ts +28 -28
  72. package/src/bindings/clickoutsidehandler.js +36 -36
  73. package/src/bindings/csstransitiondisablermixin.d.ts +40 -40
  74. package/src/bindings/csstransitiondisablermixin.js +55 -55
  75. package/src/bindings/injectcsstransitiondisabler.d.ts +59 -59
  76. package/src/bindings/injectcsstransitiondisabler.js +71 -71
  77. package/src/bindings/preventdefault.d.ts +33 -33
  78. package/src/bindings/preventdefault.js +34 -34
  79. package/src/bindings/submithandler.d.ts +57 -57
  80. package/src/bindings/submithandler.js +47 -47
  81. package/src/button/button.d.ts +178 -178
  82. package/src/button/button.js +5 -5
  83. package/src/button/buttonlabel.d.ts +34 -0
  84. package/src/button/buttonlabel.js +5 -0
  85. package/src/button/buttonlabelview.d.ts +31 -0
  86. package/src/button/buttonlabelview.js +42 -0
  87. package/src/button/buttonview.d.ts +185 -177
  88. package/src/button/buttonview.js +219 -231
  89. package/src/button/switchbuttonview.d.ts +45 -45
  90. package/src/button/switchbuttonview.js +75 -75
  91. package/src/colorgrid/colorgridview.d.ts +132 -132
  92. package/src/colorgrid/colorgridview.js +124 -124
  93. package/src/colorgrid/colortileview.d.ts +28 -28
  94. package/src/colorgrid/colortileview.js +40 -40
  95. package/src/colorgrid/utils.d.ts +47 -47
  96. package/src/colorgrid/utils.js +84 -84
  97. package/src/colorpicker/colorpickerview.d.ts +137 -137
  98. package/src/colorpicker/colorpickerview.js +270 -270
  99. package/src/colorpicker/utils.d.ts +43 -43
  100. package/src/colorpicker/utils.js +99 -99
  101. package/src/colorselector/colorgridsfragmentview.d.ts +194 -194
  102. package/src/colorselector/colorgridsfragmentview.js +289 -289
  103. package/src/colorselector/colorpickerfragmentview.d.ts +128 -128
  104. package/src/colorselector/colorpickerfragmentview.js +205 -205
  105. package/src/colorselector/colorselectorview.d.ts +242 -242
  106. package/src/colorselector/colorselectorview.js +256 -256
  107. package/src/colorselector/documentcolorcollection.d.ts +70 -70
  108. package/src/colorselector/documentcolorcollection.js +42 -42
  109. package/src/componentfactory.d.ts +81 -81
  110. package/src/componentfactory.js +104 -104
  111. package/src/dropdown/button/dropdownbutton.d.ts +25 -25
  112. package/src/dropdown/button/dropdownbutton.js +5 -5
  113. package/src/dropdown/button/dropdownbuttonview.d.ts +48 -48
  114. package/src/dropdown/button/dropdownbuttonview.js +66 -66
  115. package/src/dropdown/button/splitbuttonview.d.ts +161 -161
  116. package/src/dropdown/button/splitbuttonview.js +152 -152
  117. package/src/dropdown/dropdownpanelfocusable.d.ts +21 -21
  118. package/src/dropdown/dropdownpanelfocusable.js +5 -5
  119. package/src/dropdown/dropdownpanelview.d.ts +62 -62
  120. package/src/dropdown/dropdownpanelview.js +97 -97
  121. package/src/dropdown/dropdownview.d.ts +315 -315
  122. package/src/dropdown/dropdownview.js +379 -378
  123. package/src/dropdown/utils.d.ts +235 -221
  124. package/src/dropdown/utils.js +458 -437
  125. package/src/editableui/editableuiview.d.ts +72 -72
  126. package/src/editableui/editableuiview.js +112 -112
  127. package/src/editableui/inline/inlineeditableuiview.d.ts +40 -40
  128. package/src/editableui/inline/inlineeditableuiview.js +48 -48
  129. package/src/editorui/bodycollection.d.ts +55 -55
  130. package/src/editorui/bodycollection.js +84 -84
  131. package/src/editorui/boxed/boxededitoruiview.d.ts +40 -40
  132. package/src/editorui/boxed/boxededitoruiview.js +81 -81
  133. package/src/editorui/editorui.d.ts +282 -282
  134. package/src/editorui/editorui.js +410 -410
  135. package/src/editorui/editoruiview.d.ts +39 -39
  136. package/src/editorui/editoruiview.js +38 -38
  137. package/src/editorui/poweredby.d.ts +71 -71
  138. package/src/editorui/poweredby.js +276 -299
  139. package/src/focuscycler.d.ts +226 -183
  140. package/src/focuscycler.js +245 -220
  141. package/src/formheader/formheaderview.d.ts +59 -53
  142. package/src/formheader/formheaderview.js +69 -63
  143. package/src/highlightedtext/highlightedtextview.d.ts +38 -0
  144. package/src/highlightedtext/highlightedtextview.js +102 -0
  145. package/src/icon/iconview.d.ts +85 -78
  146. package/src/icon/iconview.js +114 -112
  147. package/src/iframe/iframeview.d.ts +50 -50
  148. package/src/iframe/iframeview.js +63 -63
  149. package/src/index.d.ts +73 -63
  150. package/src/index.js +70 -62
  151. package/src/input/inputbase.d.ts +107 -0
  152. package/src/input/inputbase.js +110 -0
  153. package/src/input/inputview.d.ts +36 -121
  154. package/src/input/inputview.js +24 -106
  155. package/src/inputnumber/inputnumberview.d.ts +49 -49
  156. package/src/inputnumber/inputnumberview.js +40 -40
  157. package/src/inputtext/inputtextview.d.ts +18 -18
  158. package/src/inputtext/inputtextview.js +27 -27
  159. package/src/label/labelview.d.ts +36 -36
  160. package/src/label/labelview.js +41 -41
  161. package/src/labeledfield/labeledfieldview.d.ts +187 -182
  162. package/src/labeledfield/labeledfieldview.js +157 -157
  163. package/src/labeledfield/utils.d.ts +123 -93
  164. package/src/labeledfield/utils.js +176 -131
  165. package/src/labeledinput/labeledinputview.d.ts +125 -125
  166. package/src/labeledinput/labeledinputview.js +125 -125
  167. package/src/list/listitemgroupview.d.ts +51 -0
  168. package/src/list/listitemgroupview.js +75 -0
  169. package/src/list/listitemview.d.ts +36 -35
  170. package/src/list/listitemview.js +42 -40
  171. package/src/list/listseparatorview.d.ts +18 -18
  172. package/src/list/listseparatorview.js +28 -28
  173. package/src/list/listview.d.ts +122 -65
  174. package/src/list/listview.js +187 -90
  175. package/src/model.d.ts +22 -22
  176. package/src/model.js +31 -31
  177. package/src/notification/notification.d.ts +211 -211
  178. package/src/notification/notification.js +187 -187
  179. package/src/panel/balloon/balloonpanelview.d.ts +685 -685
  180. package/src/panel/balloon/balloonpanelview.js +1010 -988
  181. package/src/panel/balloon/contextualballoon.d.ts +299 -299
  182. package/src/panel/balloon/contextualballoon.js +572 -572
  183. package/src/panel/sticky/stickypanelview.d.ts +156 -158
  184. package/src/panel/sticky/stickypanelview.js +234 -231
  185. package/src/search/filteredview.d.ts +31 -0
  186. package/src/search/filteredview.js +5 -0
  187. package/src/search/searchinfoview.d.ts +45 -0
  188. package/src/search/searchinfoview.js +59 -0
  189. package/src/search/searchresultsview.d.ts +54 -0
  190. package/src/search/searchresultsview.js +65 -0
  191. package/src/search/text/searchtextqueryview.d.ts +76 -0
  192. package/src/search/text/searchtextqueryview.js +75 -0
  193. package/src/search/text/searchtextview.d.ts +219 -0
  194. package/src/search/text/searchtextview.js +201 -0
  195. package/src/spinner/spinnerview.d.ts +25 -0
  196. package/src/spinner/spinnerview.js +38 -0
  197. package/src/template.d.ts +942 -942
  198. package/src/template.js +1294 -1294
  199. package/src/textarea/textareaview.d.ts +88 -0
  200. package/src/textarea/textareaview.js +140 -0
  201. package/src/toolbar/balloon/balloontoolbar.d.ts +122 -122
  202. package/src/toolbar/balloon/balloontoolbar.js +300 -300
  203. package/src/toolbar/block/blockbuttonview.d.ts +35 -35
  204. package/src/toolbar/block/blockbuttonview.js +41 -41
  205. package/src/toolbar/block/blocktoolbar.d.ts +161 -161
  206. package/src/toolbar/block/blocktoolbar.js +395 -391
  207. package/src/toolbar/normalizetoolbarconfig.d.ts +40 -39
  208. package/src/toolbar/normalizetoolbarconfig.js +51 -51
  209. package/src/toolbar/toolbarlinebreakview.d.ts +18 -18
  210. package/src/toolbar/toolbarlinebreakview.js +28 -28
  211. package/src/toolbar/toolbarseparatorview.d.ts +18 -18
  212. package/src/toolbar/toolbarseparatorview.js +28 -28
  213. package/src/toolbar/toolbarview.d.ts +266 -265
  214. package/src/toolbar/toolbarview.js +719 -717
  215. package/src/tooltipmanager.d.ts +180 -180
  216. package/src/tooltipmanager.js +353 -353
  217. package/src/view.d.ts +422 -422
  218. package/src/view.js +396 -396
  219. package/src/viewcollection.d.ts +139 -139
  220. package/src/viewcollection.js +206 -206
  221. package/theme/components/autocomplete/autocomplete.css +22 -0
  222. package/theme/components/formheader/formheader.css +8 -0
  223. package/theme/components/highlightedtext/highlightedtext.css +12 -0
  224. package/theme/components/search/search.css +43 -0
  225. package/theme/components/spinner/spinner.css +23 -0
  226. 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
+ }