MOBILE-4015 core: Support data-app-url attribute
parent
0143c23395
commit
910d557b87
|
@ -13,6 +13,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Directive, ElementRef, OnInit, Output, EventEmitter } from '@angular/core';
|
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.
|
* Directive to emulate click and key actions following aria role button.
|
||||||
|
@ -36,22 +37,7 @@ export class CoreAriaButtonClickDirective implements OnInit {
|
||||||
* Initialize actions.
|
* Initialize actions.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.element.addEventListener('click', async (event) => {
|
CoreDom.onActivate(this.element, (event) => this.ariaButtonClick.emit(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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -452,9 +452,16 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
||||||
const svgImages = Array.from(div.querySelectorAll('image'));
|
const svgImages = Array.from(div.querySelectorAll('image'));
|
||||||
const promises: Promise<void>[] = [];
|
const promises: Promise<void>[] = [];
|
||||||
|
|
||||||
|
this.treatAppUrlElements(div, site);
|
||||||
|
|
||||||
// Walk through the content to find the links and add our directive to it.
|
// 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.
|
// Important: We need to look for links first because in 'img' we add new links without core-link.
|
||||||
anchors.forEach((anchor) => {
|
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.
|
// Angular 2 doesn't let adding directives dynamically. Create the CoreLinkDirective manually.
|
||||||
const linkDir = new CoreLinkDirective(new ElementRef(anchor), this.content);
|
const linkDir = new CoreLinkDirective(new ElementRef(anchor), this.content);
|
||||||
linkDir.capture = this.captureLinks ?? true;
|
linkDir.capture = this.captureLinks ?? true;
|
||||||
|
@ -546,6 +553,57 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
||||||
await Promise.all(promises);
|
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.
|
* Returns the element width in pixels.
|
||||||
*
|
*
|
||||||
|
|
|
@ -48,7 +48,7 @@ export class CoreLinkDirective implements OnInit {
|
||||||
@Input() autoLogin = 'check';
|
@Input() autoLogin = 'check';
|
||||||
@Input() showBrowserWarning = true; // Whether to show a warning before opening browser. Defaults to true.
|
@Input() showBrowserWarning = true; // Whether to show a warning before opening browser. Defaults to true.
|
||||||
|
|
||||||
protected element: Element;
|
protected element: HTMLElement;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
element: ElementRef,
|
element: ElementRef,
|
||||||
|
@ -68,22 +68,7 @@ export class CoreLinkDirective implements OnInit {
|
||||||
this.element.setAttribute('role', 'button');
|
this.element.setAttribute('role', 'button');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.element.addEventListener('click', async (event) => {
|
CoreDom.onActivate(this.element, (event) => this.performAction(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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue