MOBILE-3833 user-tours: Listen to changes on scroll and resize
parent
09c2b89c44
commit
7236dd34c1
|
@ -13,7 +13,17 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { BackButtonEvent } from '@ionic/core';
|
||||
import { AfterViewInit, Component, ElementRef, EventEmitter, HostBinding, Input, Output, ViewChild } from '@angular/core';
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
HostBinding,
|
||||
Input,
|
||||
OnDestroy,
|
||||
Output,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { CorePromisedValue } from '@classes/promised-value';
|
||||
import { CoreUserToursFocusLayout } from '@features/usertours/classes/focus-layout';
|
||||
import { CoreUserToursPopoverLayout } from '@features/usertours/classes/popover-layout';
|
||||
|
@ -22,6 +32,7 @@ import { CoreDomUtils } from '@services/utils/dom';
|
|||
import { AngularFrameworkDelegate } from '@singletons';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDom } from '@singletons/dom';
|
||||
import { CoreEventObserver } from '@singletons/events';
|
||||
|
||||
const ANIMATION_DURATION = 200;
|
||||
const USER_TOURS_BACK_BUTTON_PRIORITY = 100;
|
||||
|
@ -36,7 +47,7 @@ const USER_TOURS_BACK_BUTTON_PRIORITY = 100;
|
|||
templateUrl: 'core-user-tours-user-tour.html',
|
||||
styleUrls: ['user-tour.scss'],
|
||||
})
|
||||
export class CoreUserToursUserTourComponent implements AfterViewInit {
|
||||
export class CoreUserToursUserTourComponent implements AfterViewInit, OnDestroy {
|
||||
|
||||
@Input() container!: HTMLElement;
|
||||
@Input() id!: string;
|
||||
|
@ -59,6 +70,9 @@ export class CoreUserToursUserTourComponent implements AfterViewInit {
|
|||
private wrapperTransform = '';
|
||||
private wrapperElement = new CorePromisedValue<HTMLElement>();
|
||||
private backButtonListener?: (event: BackButtonEvent) => void;
|
||||
protected resizeListener?: CoreEventObserver;
|
||||
protected scrollListener?: EventListener;
|
||||
protected content?: HTMLIonContentElement | null;
|
||||
|
||||
constructor({ nativeElement: element }: ElementRef<HTMLElement>) {
|
||||
this.element = element;
|
||||
|
@ -100,18 +114,7 @@ export class CoreUserToursUserTourComponent implements AfterViewInit {
|
|||
|
||||
this.calculateStyles();
|
||||
|
||||
// Show tour.
|
||||
this.active = true;
|
||||
|
||||
document.addEventListener(
|
||||
'ionBackButton',
|
||||
this.backButtonListener = ({ detail }) => detail.register(
|
||||
USER_TOURS_BACK_BUTTON_PRIORITY,
|
||||
() => {
|
||||
// Silence back button.
|
||||
},
|
||||
),
|
||||
);
|
||||
this.activate();
|
||||
|
||||
await this.playEnterAnimation();
|
||||
}
|
||||
|
@ -125,8 +128,7 @@ export class CoreUserToursUserTourComponent implements AfterViewInit {
|
|||
await this.playLeaveAnimation();
|
||||
await AngularFrameworkDelegate.removeViewFromDom(wrapper, this.tour);
|
||||
|
||||
this.active = false;
|
||||
this.backButtonListener && document.removeEventListener('ionBackButton', this.backButtonListener);
|
||||
this.deactivate();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,11 +141,11 @@ export class CoreUserToursUserTourComponent implements AfterViewInit {
|
|||
|
||||
if (this.active) {
|
||||
await this.playLeaveAnimation();
|
||||
await AngularFrameworkDelegate.removeViewFromDom(this.container, this.element);
|
||||
|
||||
this.backButtonListener && document.removeEventListener('ionBackButton', this.backButtonListener);
|
||||
}
|
||||
|
||||
await AngularFrameworkDelegate.removeViewFromDom(this.container, this.element);
|
||||
this.deactivate();
|
||||
|
||||
acknowledge && await CoreUserTours.acknowledge(this.id);
|
||||
|
||||
this.afterDismiss.emit();
|
||||
|
@ -205,4 +207,76 @@ export class CoreUserToursUserTourComponent implements AfterViewInit {
|
|||
await Promise.all(animations.map(animation => animation?.finished));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.deactivate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate tour.
|
||||
*/
|
||||
protected activate(): void {
|
||||
if (this.active) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.active = true;
|
||||
|
||||
if (!this.backButtonListener) {
|
||||
document.addEventListener(
|
||||
'ionBackButton',
|
||||
this.backButtonListener = ({ detail }) => detail.register(
|
||||
USER_TOURS_BACK_BUTTON_PRIORITY,
|
||||
() => {
|
||||
// Silence back button.
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (!this.focus) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.resizeListener) {
|
||||
this.resizeListener = CoreDom.onWindowResize(() => {
|
||||
this.calculateStyles();
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.content) {
|
||||
this.content = CoreDom.closest(this.focus, 'ion-content');
|
||||
}
|
||||
|
||||
if (!this.scrollListener && this.content) {
|
||||
this.content.scrollEvents = true;
|
||||
|
||||
this.content.addEventListener('ionScrollEnd', this.scrollListener = (): void => {
|
||||
this.calculateStyles();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivate tour.
|
||||
*/
|
||||
protected deactivate(): void {
|
||||
if (!this.active) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.active = false;
|
||||
|
||||
this.resizeListener?.off();
|
||||
this.backButtonListener && document.removeEventListener('ionBackButton', this.backButtonListener);
|
||||
this.backButtonListener = undefined;
|
||||
this.resizeListener = undefined;
|
||||
|
||||
if (this.content && this.scrollListener) {
|
||||
this.content.removeEventListener('ionScrollEnd', this.scrollListener);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,33 @@ export class CoreDom {
|
|||
// Nothing to do.
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a dom closest function piercing the shadow DOM.
|
||||
*
|
||||
* @param node DOM Element.
|
||||
* @param selector Selector to search.
|
||||
* @return Closest ancestor or null if not found.
|
||||
*/
|
||||
static closest<T = HTMLElement>(node: HTMLElement | Node | null, selector: string): T | null {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (node instanceof ShadowRoot) {
|
||||
return CoreDom.closest(node.host, selector);
|
||||
}
|
||||
|
||||
if (node instanceof HTMLElement) {
|
||||
if (node.matches(selector)) {
|
||||
return node as unknown as T;
|
||||
} else {
|
||||
return CoreDom.closest<T>(node.parentNode, selector);
|
||||
}
|
||||
}
|
||||
|
||||
return CoreDom.closest<T>(node.parentNode, selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the position of a element relative to another element.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue