-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
accessibilityhelpcontentview.ts
147 lines (123 loc) · 4.39 KB
/
accessibilityhelpcontentview.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/**
* @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 ui/editorui/accessibilityhelp/accessibilityhelpcontentview
*/
import {
createElement,
env,
getEnvKeystrokeText,
type Locale
} from '@ckeditor/ckeditor5-utils';
import View from '../../view.js';
import LabelView from '../../label/labelview.js';
import type {
KeystrokeInfoCategoryDefinition,
KeystrokeInfoDefinition,
KeystrokeInfoDefinitions,
KeystrokeInfoGroupDefinition
} from '@ckeditor/ckeditor5-core';
/**
* The view displaying keystrokes in the Accessibility help dialog.
*/
export default class AccessibilityHelpContentView extends View<HTMLDivElement> {
/**
* @inheritDoc
*/
constructor( locale: Locale, keystrokes: KeystrokeInfoDefinitions ) {
super( locale );
const t = locale.t;
const helpLabel = new LabelView();
helpLabel.text = t( 'Help Contents. To close this dialog press ESC.' );
this.setTemplate( {
tag: 'div',
attributes: {
class: [ 'ck', 'ck-accessibility-help-dialog__content' ],
'aria-labelledby': helpLabel.id,
role: 'document',
tabindex: -1
},
children: [
createElement( document, 'p', {}, t( 'Below, you can find a list of keyboard shortcuts that can be used in the editor.' ) ),
...this._createCategories( Array.from( keystrokes.values() ) ),
helpLabel
]
} );
}
/**
* @inheritDoc
*/
public focus(): void {
this.element!.focus();
}
/**
* Creates `<section><h3>Category label</h3>...</section>` elements for each category of keystrokes.
*/
private _createCategories( categories: Array<KeystrokeInfoCategoryDefinition> ): Array<HTMLElement> {
return categories.map( categoryDefinition => {
const elements: Array<HTMLElement> = [
// Category header.
createElement( document, 'h3', {}, categoryDefinition.label ),
// Category definitions (<dl>) and their optional headers (<h4>).
...Array.from( categoryDefinition.groups.values() )
.map( groupDefinition => this._createGroup( groupDefinition ) )
.flat()
];
// Category description (<p>).
if ( categoryDefinition.description ) {
elements.splice( 1, 0, createElement( document, 'p', {}, categoryDefinition.description ) );
}
return createElement( document, 'section', {}, elements );
} );
}
/**
* Creates `[<h4>Optional label</h4>]<dl>...</dl>` elements for each group of keystrokes in a category.
*/
private _createGroup( groupDefinition: KeystrokeInfoGroupDefinition ): Array<HTMLElement> {
const definitionAndDescriptionElements = groupDefinition.keystrokes
.sort( ( a, b ) => a.label.localeCompare( b.label ) )
.map( keystrokeDefinition => this._createGroupRow( keystrokeDefinition ) )
.flat();
const elements: Array<HTMLElement> = [
createElement( document, 'dl', {}, definitionAndDescriptionElements )
];
if ( groupDefinition.label ) {
elements.unshift( createElement( document, 'h4', {}, groupDefinition.label ) );
}
return elements;
}
/**
* Creates `<dt>Keystroke label</dt><dd>Keystroke definition</dd>` elements for each keystroke in a group.
*/
private _createGroupRow( keystrokeDefinition: KeystrokeInfoDefinition ): [ HTMLElement, HTMLElement ] {
const t = this.locale!.t;
const dt = createElement( document, 'dt' );
const dd = createElement( document, 'dd' );
const normalizedKeystrokeDefinition = normalizeKeystrokeDefinition( keystrokeDefinition.keystroke );
const keystrokeAlternativeHTMLs = [];
for ( const keystrokeAlternative of normalizedKeystrokeDefinition ) {
keystrokeAlternativeHTMLs.push( keystrokeAlternative.map( keystrokeToEnvKbd ).join( '' ) );
}
dt.innerHTML = keystrokeDefinition.label;
dd.innerHTML = keystrokeAlternativeHTMLs.join( ', ' ) +
( keystrokeDefinition.mayRequireFn && env.isMac ? ` ${ t( '(may require <kbd>Fn</kbd>)' ) }` : '' );
return [ dt, dd ];
}
}
function keystrokeToEnvKbd( keystroke: string ): string {
return getEnvKeystrokeText( keystroke )
.split( '+' )
.map( part => `<kbd>${ part }</kbd>` )
.join( '+' );
}
function normalizeKeystrokeDefinition( definition: KeystrokeInfoDefinition[ 'keystroke' ] ): Array<Array<string>> {
if ( typeof definition === 'string' ) {
return [ [ definition ] ];
}
if ( typeof definition[ 0 ] === 'string' ) {
return [ definition as Array<string> ];
}
return definition as Array<Array<string>>;
}