-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
mentionsview.ts
129 lines (106 loc) · 3.04 KB
/
mentionsview.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/**
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @module mention/ui/mentionsview
*/
import { ListView } from 'ckeditor5/src/ui.js';
import { Rect, type Locale } from 'ckeditor5/src/utils.js';
import type MentionListItemView from './mentionlistitemview.js';
import '../../theme/mentionui.css';
/**
* The mention ui view.
*/
export default class MentionsView extends ListView {
public selected: MentionListItemView | undefined;
public position: string | undefined;
/**
* @inheritDoc
*/
constructor( locale: Locale ) {
super( locale );
this.extendTemplate( {
attributes: {
class: [
'ck-mentions'
],
tabindex: '-1'
}
} );
}
/**
* {@link #select Selects} the first item.
*/
public selectFirst(): void {
this.select( 0 );
}
/**
* Selects next item to the currently {@link #select selected}.
*
* If the last item is already selected, it will select the first item.
*/
public selectNext(): void {
const item = this.selected;
const index = this.items.getIndex( item! );
this.select( index + 1 );
}
/**
* Selects previous item to the currently {@link #select selected}.
*
* If the first item is already selected, it will select the last item.
*/
public selectPrevious(): void {
const item = this.selected;
const index = this.items.getIndex( item! );
this.select( index - 1 );
}
/**
* Marks item at a given index as selected.
*
* Handles selection cycling when passed index is out of bounds:
* - if the index is lower than 0, it will select the last item,
* - if the index is higher than the last item index, it will select the first item.
*
* @param index Index of an item to be marked as selected.
*/
public select( index: number ): void {
let indexToGet = 0;
if ( index > 0 && index < this.items.length ) {
indexToGet = index;
} else if ( index < 0 ) {
indexToGet = this.items.length - 1;
}
const item = this.items.get( indexToGet ) as MentionListItemView;
// Return early if item is already selected.
if ( this.selected === item ) {
return;
}
// Remove highlight of previously selected item.
if ( this.selected ) {
this.selected.removeHighlight();
}
item.highlight();
this.selected = item;
// Scroll the mentions view to the selected element.
if ( !this._isItemVisibleInScrolledArea( item ) ) {
this.element!.scrollTop = item.element!.offsetTop;
}
}
/**
* Triggers the `execute` event on the {@link #select selected} item.
*/
public executeSelected(): void {
this.selected!.fire( 'execute' );
}
/**
* Checks if an item is visible in the scrollable area.
*
* The item is considered visible when:
* - its top boundary is inside the scrollable rect
* - its bottom boundary is inside the scrollable rect (the whole item must be visible)
*/
private _isItemVisibleInScrolledArea( item: MentionListItemView ) {
return new Rect( this.element! ).contains( new Rect( item.element! ) );
}
}