Skip to content

Commit

Permalink
Merge branch 'master' into ck/app-menu-bar
Browse files Browse the repository at this point in the history
  • Loading branch information
oleq committed Mar 20, 2024
2 parents 365d27a + 571bcf5 commit 7c95902
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 4 deletions.
1 change: 1 addition & 0 deletions docs/installation/getting-started/predefined-builds.md
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,7 @@ The table below presents the list of all plugins included in various builds. <!-
<li><a href="https://ckeditor.com/docs/ckeditor5/latest/api/select-all.html">SelectAll</a></li>
<li><a href="https://ckeditor.com/docs/ckeditor5/latest/api/typing.html">Typing</a></li>
<li><a href="https://ckeditor.com/docs/ckeditor5/latest/api/undo.html">Undo</a></li>
<li><a href="https://ckeditor.com/docs/ckeditor5/latest/features/keyboard-support.html#displaying-keyboard-shortcuts-in-the-editor">Accessibility help dialog</a></li>
</ul>
</td>
<td style="text-align:center; width:70px">✅</td>
Expand Down
2 changes: 2 additions & 0 deletions docs/installation/integrations/angular.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Currently, the CKEditor&nbsp;5 component for Angular supports integrating CKEdit

<info-box hint>
Starting from version 6.0.0 of this package, you can use native type definitions provided by CKEditor&nbsp;5. Check the details about {@link installation/working-with-typescript TypeScript support}.

For best results, we suggest using TypeScript version 5.0 or newer.
</info-box>

## Supported Angular versions
Expand Down
2 changes: 2 additions & 0 deletions docs/installation/integrations/react.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ The easiest way to use CKEditor&nbsp;5 in your React application is by choosing

<info-box hint>
Starting from version 6.0.0 of this package, you can use native type definitions provided by CKEditor&nbsp;5. Check the details about {@link installation/working-with-typescript TypeScript support}.

For best results, we suggest using TypeScript version 5.0 or newer.
</info-box>

## Quick start
Expand Down
2 changes: 2 additions & 0 deletions docs/installation/working-with-typescript.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ CKEditor&nbsp;5 is built using TypeScript and has native type definitions. All t

<info-box hint>
Using TypeScript is just an option. If you do not need its features, you can continue using CKEditor&nbsp;5 in JavaScript.

For best results, we suggest using TypeScript version 5.0 or newer.
</info-box>

<info-box warning>
Expand Down
19 changes: 17 additions & 2 deletions packages/ckeditor5-heading/src/headingui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ export default class HeadingUI extends Plugin {
return areEnabled.some( isEnabled => isEnabled );
} );

dropdownView.buttonView.bind( 'label' ).to( headingCommand, 'value', paragraphCommand, 'value', ( value, para ) => {
const whichModel = value || para && 'paragraph';
dropdownView.buttonView.bind( 'label' ).to( headingCommand, 'value', paragraphCommand, 'value', ( heading, paragraph ) => {
const whichModel = paragraph ? 'paragraph' : heading;

if ( typeof whichModel === 'boolean' ) {
return defaultTitle;
Expand All @@ -126,6 +126,21 @@ export default class HeadingUI extends Plugin {
return titles[ whichModel ];
} );

dropdownView.buttonView.bind( 'ariaLabel' ).to( headingCommand, 'value', paragraphCommand, 'value', ( heading, paragraph ) => {
const whichModel = paragraph ? 'paragraph' : heading;

if ( typeof whichModel === 'boolean' ) {
return accessibleLabel;
}

// If none of the commands is active, display default title.
if ( !titles[ whichModel ] ) {
return accessibleLabel;
}

return `${ titles[ whichModel ] }, ${ accessibleLabel }`;
} );

// Execute command when an item from the dropdown is selected.
this.listenTo<ButtonExecuteEvent>( dropdownView, 'execute', evt => {
const { commandName, commandValue } = evt.source as any;
Expand Down
30 changes: 29 additions & 1 deletion packages/ckeditor5-heading/tests/headingui.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ describe( 'HeadingUI', () => {
expect( dropdown.buttonView.isOn ).to.be.false;
expect( dropdown.buttonView.label ).to.equal( 'Paragraph' );
expect( dropdown.buttonView.tooltip ).to.equal( 'Heading' );
expect( dropdown.buttonView.ariaLabel ).to.equal( 'Heading' );
expect( dropdown.buttonView.ariaLabel ).to.equal( 'Paragraph, Heading' );
expect( dropdown.buttonView.ariaLabelledBy ).to.be.undefined;
} );

Expand Down Expand Up @@ -156,6 +156,34 @@ describe( 'HeadingUI', () => {
paragraphCommand.value = true;
expect( dropdown.buttonView.label ).to.equal( 'Paragraph' );
} );

it( 'label when heading and paragraph commands active', () => {
command.value = 'heading2';
paragraphCommand.value = true;

expect( dropdown.buttonView.label ).to.equal( 'Paragraph' );
} );

it( 'ariaLabel', () => {
command.value = false;
paragraphCommand.value = false;

expect( dropdown.buttonView.ariaLabel ).to.equal( 'Heading' );

command.value = 'heading2';
expect( dropdown.buttonView.ariaLabel ).to.equal( 'Heading 2, Heading' );
command.value = false;

paragraphCommand.value = true;
expect( dropdown.buttonView.ariaLabel ).to.equal( 'Paragraph, Heading' );
} );

it( 'ariaLabel when heading and paragraph commands active', () => {
command.value = 'heading2';
paragraphCommand.value = true;

expect( dropdown.buttonView.ariaLabel ).to.equal( 'Paragraph, Heading' );
} );
} );

describe( 'localization', () => {
Expand Down
10 changes: 10 additions & 0 deletions packages/ckeditor5-language/src/textpartlanguageui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,16 @@ export default class TextPartLanguageUI extends Plugin {
return ( value && titles[ value ] ) || defaultTitle;
} );

dropdownView.buttonView.bind( 'ariaLabel' ).to( languageCommand, 'value', value => {
const selectedLanguageTitle = value && titles[ value ];

if ( !selectedLanguageTitle ) {
return accessibleLabel;
}

return `${ selectedLanguageTitle }, ${ accessibleLabel }`;
} );

// Execute command when an item from the dropdown is selected.
this.listenTo( dropdownView, 'execute', evt => {
languageCommand.execute( {
Expand Down
12 changes: 12 additions & 0 deletions packages/ckeditor5-language/tests/textpartlanguageui.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,18 @@ describe( 'TextPartLanguageUI', () => {
expect( dropdown.buttonView.label ).to.equal( 'Arabic' );
} );

it( 'ariaLabel', () => {
command.value = false;

expect( dropdown.buttonView.ariaLabel ).to.equal( 'Language' );

command.value = 'fr:ltr';
expect( dropdown.buttonView.ariaLabel ).to.equal( 'French, Language' );

command.value = 'ar:rtl';
expect( dropdown.buttonView.ariaLabel ).to.equal( 'Arabic, Language' );
} );

it( 'reflects the #value of the command', () => {
// Trigger lazy init.
dropdown.isOpen = true;
Expand Down
20 changes: 19 additions & 1 deletion packages/ckeditor5-ui/src/input/inputbase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ export default abstract class InputBase<TElement extends HTMLInputElement | HTML
*/
declare public placeholder: string | undefined;

/**
* The `tabindex` attribute of the input.
*
* @observable
*/
declare public tabIndex: number | undefined;

/**
* The `aria-label` attribute of the input.
*
* @observable
*/
declare public ariaLabel: string | undefined;

/**
* Controls whether the input view is in read-only mode.
*
Expand Down Expand Up @@ -98,9 +112,11 @@ export default abstract class InputBase<TElement extends HTMLInputElement | HTML
this.set( 'value', undefined );
this.set( 'id', undefined );
this.set( 'placeholder', undefined );
this.set( 'tabIndex', undefined );
this.set( 'isReadOnly', false );
this.set( 'hasError', false );
this.set( 'ariaDescribedById', undefined );
this.set( 'ariaLabel', undefined );

this.focusTracker = new FocusTracker();

Expand All @@ -121,9 +137,11 @@ export default abstract class InputBase<TElement extends HTMLInputElement | HTML
],
id: bind.to( 'id' ),
placeholder: bind.to( 'placeholder' ),
tabindex: bind.to( 'tabIndex' ),
readonly: bind.to( 'isReadOnly' ),
'aria-invalid': bind.if( 'hasError', true ),
'aria-describedby': bind.to( 'ariaDescribedById' )
'aria-describedby': bind.to( 'ariaDescribedById' ),
'aria-label': bind.to( 'ariaLabel' )
},
on: {
input: bind.to( ( ...args ) => {
Expand Down
20 changes: 20 additions & 0 deletions packages/ckeditor5-ui/tests/input/inputbase.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,26 @@ describe( 'InputBase', () => {
} );
} );

describe( 'tabIndex', () => {
it( 'should react on view#tabIndex', () => {
expect( view.element.getAttribute( 'tabIndex' ) ).to.be.null;

view.tabIndex = 123;

expect( view.element.getAttribute( 'tabIndex' ) ).to.equal( '123' );
} );
} );

describe( 'aria-label', () => {
it( 'should react on view#ariaLabel', () => {
expect( view.element.getAttribute( 'aria-label' ) ).to.be.null;

view.ariaLabel = 'reader text';

expect( view.element.getAttribute( 'aria-label' ) ).to.equal( 'reader text' );
} );
} );

describe( 'aria-describedby', () => {
it( 'should react on view#hasError', () => {
expect( view.element.getAttribute( 'aria-describedby' ) ).to.be.null;
Expand Down

0 comments on commit 7c95902

Please sign in to comment.