MOBILE-3749 rte: Add key actions for toolbar buttons
parent
a41df38a71
commit
6127dac080
|
@ -16,98 +16,120 @@
|
|||
|
||||
<div #toolbar class="core-rte-toolbar" [class.toolbar-hidden]="toolbarHidden">
|
||||
<button *ngIf="toolbarArrows" class="toolbar-arrow" [class.toolbar-arrow-hidden]="toolbarPrevHidden"
|
||||
(click)="toolbarPrev($event)" (mousedown)="mouseDownAction($event)" [attr.aria-label]="'core.previous' | translate">
|
||||
(click)="toolbarPrev($event)" (keyup)="toolbarPrev($event)"
|
||||
(mousedown)="downAction($event)" (keydown)="downAction($event)"
|
||||
[attr.aria-label]="'core.previous' | translate">
|
||||
<ion-icon name="fas-chevron-left" aria-hidden="true"></ion-icon>
|
||||
</button>
|
||||
<ion-slides [options]="slidesOpts" [dir]="direction" (ionSlideDidChange)="updateToolbarArrows()">
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand -->
|
||||
<ion-slide>
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.strong" [title]="'core.editor.bold' | translate"
|
||||
(click)="buttonAction($event, 'bold', 'strong')" (mousedown)="mouseDownAction($event)">
|
||||
(click)="buttonAction($event, 'bold', 'strong')" (keyup)="buttonAction($event, 'bold', 'strong')"
|
||||
(mousedown)="downAction($event)" (keydown)="downAction($event)">
|
||||
<ion-icon name="fas-bold" aria-hidden="true"></ion-icon>
|
||||
</button>
|
||||
</ion-slide>
|
||||
<ion-slide>
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.em" (click)="buttonAction($event, 'italic', 'em')"
|
||||
(mousedown)="mouseDownAction($event)" [title]=" 'core.editor.italic' | translate">
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.em" [title]=" 'core.editor.italic' | translate"
|
||||
(click)="buttonAction($event, 'italic', 'em')" (keyup)="buttonAction($event, 'italic', 'em')"
|
||||
(mousedown)="downAction($event)" (keydown)="downAction($event)">
|
||||
<ion-icon name="fas-italic" aria-hidden="true"></ion-icon>
|
||||
</button>
|
||||
</ion-slide>
|
||||
<ion-slide>
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.u" (click)="buttonAction($event, 'underline', 'u')"
|
||||
(mousedown)="mouseDownAction($event)" [title]="'core.editor.underline' | translate">
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.u" [title]="'core.editor.underline' | translate"
|
||||
(click)="buttonAction($event, 'underline', 'u')" (keyup)="buttonAction($event, 'underline', 'u')"
|
||||
(mousedown)="downAction($event)" (keydown)="downAction($event)"
|
||||
>
|
||||
<ion-icon name="fas-underline" aria-hidden="true"></ion-icon>
|
||||
</button>
|
||||
</ion-slide>
|
||||
<ion-slide>
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.strike" [title]="'core.editor.strike' | translate"
|
||||
(click)="buttonAction($event, 'strikethrough', 'strike')" (mousedown)="mouseDownAction($event)">
|
||||
(click)="buttonAction($event, 'strikethrough', 'strike')" (keyup)="buttonAction($event, 'strikethrough', 'strike')"
|
||||
(mousedown)="downAction($event)" (keydown)="downAction($event)">
|
||||
<ion-icon name="fas-strikethrough" aria-hidden="true"></ion-icon>
|
||||
</button>
|
||||
</ion-slide>
|
||||
<ion-slide>
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.p" (click)="buttonAction($event, 'p', 'block')"
|
||||
(mousedown)="mouseDownAction($event)" [title]="'core.editor.p' | translate">
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.p" [title]="'core.editor.p' | translate"
|
||||
(click)="buttonAction($event, 'p', 'block')" (keyup)="buttonAction($event, 'p', 'block')"
|
||||
(mousedown)="downAction($event)" (keydown)="downAction($event)">
|
||||
<ion-icon name="fas-paragraph" aria-hidden="true"></ion-icon>
|
||||
</button>
|
||||
</ion-slide>
|
||||
<ion-slide>
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.h3" (click)="buttonAction($event, 'h3', 'block')"
|
||||
(mousedown)="mouseDownAction($event)" [title]="'core.editor.h3' | translate">
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.h3" [title]="'core.editor.h3' | translate"
|
||||
(click)="buttonAction($event, 'h3', 'block')" (keyup)="buttonAction($event, 'h3', 'block')"
|
||||
(mousedown)="downAction($event)" (keydown)="downAction($event)" >
|
||||
<ion-icon name="fas-heading" aria-hidden="true"></ion-icon><span aria-hidden="true">3</span>
|
||||
</button>
|
||||
</ion-slide>
|
||||
<ion-slide>
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.h4" (click)="buttonAction($event, 'h4', 'block')"
|
||||
(mousedown)="mouseDownAction($event)" [title]="'core.editor.h4' | translate">
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.h4" [title]="'core.editor.h4' | translate"
|
||||
(click)="buttonAction($event, 'h4', 'block')" (keyup)="buttonAction($event, 'h4', 'block')"
|
||||
(mousedown)="downAction($event)" (keydown)="downAction($event)">
|
||||
<ion-icon name="fas-heading" aria-hidden="true"></ion-icon><span aria-hidden="true">4</span>
|
||||
</button>
|
||||
</ion-slide>
|
||||
<ion-slide>
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.h5" (click)="buttonAction($event, 'h5', 'block')"
|
||||
(mousedown)="mouseDownAction($event)" [title]="'core.editor.h5' | translate">
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.h5" [title]="'core.editor.h5' | translate"
|
||||
(click)="buttonAction($event, 'h5', 'block')" (keyup)="buttonAction($event, 'h5', 'block')"
|
||||
(mousedown)="downAction($event)" (keydown)="downAction($event)">
|
||||
<ion-icon name="fas-heading" aria-hidden="true"></ion-icon><span aria-hidden="true">5</span>
|
||||
</button>
|
||||
</ion-slide>
|
||||
<ion-slide>
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.ul" (mousedown)="mouseDownAction($event)"
|
||||
(click)="buttonAction($event, 'insertUnorderedList')" [title]="'core.editor.unorderedlist' | translate">
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.ul"
|
||||
[title]="'core.editor.unorderedlist' | translate"
|
||||
(click)="buttonAction($event, 'insertUnorderedList')" (click)="buttonAction($event, 'insertUnorderedList')"
|
||||
(mousedown)="downAction($event)" (keydown)="downAction($event)">
|
||||
<ion-icon name="fas-list-ul" aria-hidden="true"></ion-icon>
|
||||
</button>
|
||||
</ion-slide>
|
||||
<ion-slide>
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.ol" (mousedown)="mouseDownAction($event)"
|
||||
(click)="buttonAction($event, 'insertOrderedList')" [title]="'core.editor.orderedlist' | translate">
|
||||
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.ol" [title]="'core.editor.orderedlist' | translate"
|
||||
(click)="buttonAction($event, 'insertOrderedList')" (keyup)="buttonAction($event, 'insertOrderedList')"
|
||||
(mousedown)="downAction($event)" (keydown)="downAction($event)">
|
||||
<ion-icon name="fas-list-ol" aria-hidden="true"></ion-icon>
|
||||
</button>
|
||||
</ion-slide>
|
||||
<ion-slide>
|
||||
<button [disabled]="!rteEnabled" (click)="buttonAction($event, 'removeFormat')" (mousedown)="mouseDownAction($event)"
|
||||
<button [disabled]="!rteEnabled"
|
||||
(click)="buttonAction($event, 'removeFormat')" (keyup)="buttonAction($event, 'removeFormat')"
|
||||
(mousedown)="downAction($event)" (keydown)="downAction($event)"
|
||||
[title]="'core.editor.clear' | translate">
|
||||
<ion-icon name="fas-eraser" aria-hidden="true"></ion-icon>
|
||||
</button>
|
||||
</ion-slide>
|
||||
<ion-slide *ngIf="canScanQR">
|
||||
<button [disabled]="!rteEnabled" (click)="scanQR($event)" (mousedown)="stopBubble($event)"
|
||||
<button [disabled]="!rteEnabled"
|
||||
(click)="scanQR($event)" (keyup)="scanQR($event)"
|
||||
(mousedown)="stopBubble($event)" (keydown)="stopBubble($event)"
|
||||
[title]="'core.scanqr' | translate">
|
||||
<ion-icon name="fas-qrcode" aria-hidden="true"></ion-icon>
|
||||
</button>
|
||||
</ion-slide>
|
||||
<ion-slide>
|
||||
<button [attr.aria-pressed]="!rteEnabled" (click)="toggleEditor($event)" (mousedown)="mouseDownAction($event)"
|
||||
[title]=" 'core.editor.toggle' | translate">
|
||||
<button [attr.aria-pressed]="!rteEnabled" [title]=" 'core.editor.toggle' | translate"
|
||||
(click)="toggleEditor($event)" (keyup)="toggleEditor($event)"
|
||||
(mousedown)="downAction($event)" (keydown)="downAction($event)">
|
||||
<ion-icon name="fas-code" aria-hidden="true"></ion-icon>
|
||||
</button>
|
||||
</ion-slide>
|
||||
<ion-slide *ngIf="isPhone">
|
||||
<button (click)="hideToolbar($event)" (mousedown)="mouseDownAction($event)"
|
||||
[title]=" 'core.editor.hidetoolbar' | translate">
|
||||
<button [title]=" 'core.editor.hidetoolbar' | translate"
|
||||
(click)="hideToolbar($event)" (keyup)="hideToolbar($event)"
|
||||
(mousedown)="downAction($event)" (keydown)="downAction($event)">
|
||||
<ion-icon name="fas-times" aria-hidden="true"></ion-icon>
|
||||
</button>
|
||||
</ion-slide>
|
||||
</ion-slides>
|
||||
<button *ngIf="toolbarArrows" class="toolbar-arrow" [class.toolbar-arrow-hidden]="toolbarNextHidden"
|
||||
(click)="toolbarNext($event)" (mousedown)="mouseDownAction($event)" [attr.aria-label]="'core.next' | translate">
|
||||
[attr.aria-label]="'core.next' | translate"
|
||||
(click)="toolbarNext($event)" (keyup)="toolbarNext($event)"
|
||||
(mousedown)="downAction($event)" (keydown)="downAction($event)" >
|
||||
<ion-icon name="fas-chevron-right" aria-hidden="true"></ion-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -511,6 +511,10 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn
|
|||
* @param event The event.
|
||||
*/
|
||||
async toggleEditor(event: Event): Promise<void> {
|
||||
if (event.type == 'keyup' && !this.isValidKeyboardKey(<KeyboardEvent>event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.stopBubble(event);
|
||||
|
||||
this.setContent(this.control?.value || '');
|
||||
|
@ -654,6 +658,10 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn
|
|||
* toolbar styles button when set.
|
||||
*/
|
||||
buttonAction(event: Event, command: string, parameters?: string): void {
|
||||
if (event.type == 'keyup' && !this.isValidKeyboardKey(<KeyboardEvent>event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.stopBubble(event);
|
||||
|
||||
if (!command) {
|
||||
|
@ -725,6 +733,10 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn
|
|||
* Hide the toolbar in phone mode.
|
||||
*/
|
||||
hideToolbar(event: Event): void {
|
||||
if (event.type == 'keyup' && !this.isValidKeyboardKey(<KeyboardEvent>event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.element.classList.remove('has-focus');
|
||||
|
||||
this.stopBubble(event);
|
||||
|
@ -734,6 +746,16 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if Space or Enter have been pressed.
|
||||
*
|
||||
* @param event Keyboard Event.
|
||||
* @returns Wether space or enter have been pressed.
|
||||
*/
|
||||
protected isValidKeyboardKey(event: KeyboardEvent): boolean {
|
||||
return event.key == ' ' || event.key == 'Enter';
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the toolbar.
|
||||
*/
|
||||
|
@ -754,7 +776,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn
|
|||
* @param event Event.
|
||||
*/
|
||||
stopBubble(event: Event): void {
|
||||
if (event.type != 'mouseup') {
|
||||
if (event.type != 'mouseup' && event.type != 'keyup') {
|
||||
event.preventDefault();
|
||||
}
|
||||
event.stopPropagation();
|
||||
|
@ -765,7 +787,11 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn
|
|||
*
|
||||
* @param event Event.
|
||||
*/
|
||||
mouseDownAction(event: Event): void {
|
||||
downAction(event: Event): void {
|
||||
if (event.type == 'keydown' && !this.isValidKeyboardKey(<KeyboardEvent>event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selection = window.getSelection()?.toString();
|
||||
|
||||
// When RTE is focused with a whole paragraph in desktop the stopBubble will not fire click.
|
||||
|
@ -778,6 +804,10 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn
|
|||
* Method that shows the next toolbar buttons.
|
||||
*/
|
||||
async toolbarNext(event: Event): Promise<void> {
|
||||
if (event.type == 'keyup' && !this.isValidKeyboardKey(<KeyboardEvent>event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.stopBubble(event);
|
||||
|
||||
if (!this.toolbarNextHidden) {
|
||||
|
@ -792,6 +822,10 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn
|
|||
* Method that shows the previous toolbar buttons.
|
||||
*/
|
||||
async toolbarPrev(event: Event): Promise<void> {
|
||||
if (event.type == 'keyup' && !this.isValidKeyboardKey(<KeyboardEvent>event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.stopBubble(event);
|
||||
|
||||
if (!this.toolbarPrevHidden) {
|
||||
|
|
Loading…
Reference in New Issue