MOBILE-4015 core: Support data-app-url attribute

main
Dani Palou 2022-03-31 17:16:19 +02:00
parent 0143c23395
commit 910d557b87
4 changed files with 85 additions and 33 deletions

View File

@ -13,6 +13,7 @@
// limitations under the License.
import { Directive, ElementRef, OnInit, Output, EventEmitter } from '@angular/core';
import { CoreDom } from '@singletons/dom';
/**
* Directive to emulate click and key actions following aria role button.
@ -36,22 +37,7 @@ export class CoreAriaButtonClickDirective implements OnInit {
* Initialize actions.
*/
ngOnInit(): void {
this.element.addEventListener('click', async (event) => {
this.ariaButtonClick.emit(event);
});
this.element.addEventListener('keydown', async (event) => {
if ((event.key == ' ' || event.key == 'Enter')) {
event.preventDefault();
event.stopPropagation();
}
});
this.element.addEventListener('keyup', async (event) => {
if ((event.key == ' ' || event.key == 'Enter')) {
this.ariaButtonClick.emit(event);
}
});
CoreDom.onActivate(this.element, (event) => this.ariaButtonClick.emit(event));
}
}

View File

@ -452,9 +452,16 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
const svgImages = Array.from(div.querySelectorAll('image'));
const promises: Promise<void>[] = [];
this.treatAppUrlElements(div, site);
// Walk through the content to find the links and add our directive to it.
// Important: We need to look for links first because in 'img' we add new links without core-link.
anchors.forEach((anchor) => {
if (anchor.getAttribute('data-app-url')) {
// Link already treated in data-app-url, ignore it.
return;
}
// Angular 2 doesn't let adding directives dynamically. Create the CoreLinkDirective manually.
const linkDir = new CoreLinkDirective(new ElementRef(anchor), this.content);
linkDir.capture = this.captureLinks ?? true;
@ -546,6 +553,57 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
await Promise.all(promises);
}
/**
* Treat elements with an app-url data attribute.
*
* @param div Div containing the elements.
* @param site Site.
*/
protected treatAppUrlElements(div: HTMLElement, site?: CoreSite): void {
const appUrlElements = Array.from(div.querySelectorAll<HTMLElement>('*[data-app-url]'));
appUrlElements.forEach((element) => {
const url = element.getAttribute('data-app-url');
if (!url) {
return;
}
if (element.tagName !== 'BUTTON' && element.tagName !== 'A') {
element.setAttribute('tabindex', '0');
element.setAttribute('role', 'button');
}
CoreDom.onActivate(element, async (event) => {
event.preventDefault();
event.stopPropagation();
site = site || CoreSites.getCurrentSite();
if (!site) {
return;
}
const confirmMessage = element.getAttribute('data-app-url-confirm');
const openInApp = element.getAttribute('data-open-in') === 'app';
if (confirmMessage) {
try {
await CoreDomUtils.showConfirm(Translate.instant(confirmMessage));
} catch {
return;
}
}
if (openInApp) {
site.openInAppWithAutoLoginIfSameSite(url);
} else {
site.openInBrowserWithAutoLoginIfSameSite(url, undefined, {
showBrowserWarning: !confirmMessage,
});
}
});
});
}
/**
* Returns the element width in pixels.
*

View File

@ -48,7 +48,7 @@ export class CoreLinkDirective implements OnInit {
@Input() autoLogin = 'check';
@Input() showBrowserWarning = true; // Whether to show a warning before opening browser. Defaults to true.
protected element: Element;
protected element: HTMLElement;
constructor(
element: ElementRef,
@ -68,22 +68,7 @@ export class CoreLinkDirective implements OnInit {
this.element.setAttribute('role', 'button');
}
this.element.addEventListener('click', async (event) => {
this.performAction(event);
});
this.element.addEventListener('keydown', (event: KeyboardEvent) => {
if ((event.key == ' ' || event.key == 'Enter')) {
event.preventDefault();
event.stopPropagation();
}
});
this.element.addEventListener('keyup', (event: KeyboardEvent) => {
if ((event.key == ' ' || event.key == 'Enter')) {
this.performAction(event);
}
});
CoreDom.onActivate(this.element, (event) => this.performAction(event));
}
/**

View File

@ -481,6 +481,29 @@ export class CoreDom {
);
}
/**
* Listen to click and Enter/Space keys in an element.
*
* @param element Element to listen to events.
* @param callback Callback to call when clicked or the key is pressed.
*/
static onActivate(element: HTMLElement, callback: (event: MouseEvent | KeyboardEvent) => void): void {
element.addEventListener('click', (event) => callback(event));
element.addEventListener('keydown', (event) => {
if ((event.key == ' ' || event.key == 'Enter')) {
event.preventDefault();
event.stopPropagation();
}
});
element.addEventListener('keyup', (event) => {
if ((event.key == ' ' || event.key == 'Enter')) {
callback(event);
}
});
}
}
/**