MOBILE-3153 usertours: Dismiss on removed elements
parent
0db4781814
commit
2e473ee55d
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { AfterViewInit, Component, ElementRef, HostBinding, Input, ViewChild } from '@angular/core';
|
import { AfterViewInit, Component, ElementRef, EventEmitter, HostBinding, Input, Output, ViewChild } from '@angular/core';
|
||||||
import { CorePromisedValue } from '@classes/promised-value';
|
import { CorePromisedValue } from '@classes/promised-value';
|
||||||
import { CoreUserToursFocusLayout } from '@features/usertours/classes/focus-layout';
|
import { CoreUserToursFocusLayout } from '@features/usertours/classes/focus-layout';
|
||||||
import { CoreUserToursPopoverLayout } from '@features/usertours/classes/popover-layout';
|
import { CoreUserToursPopoverLayout } from '@features/usertours/classes/popover-layout';
|
||||||
|
@ -42,6 +42,8 @@ export class CoreUserToursUserTourComponent implements AfterViewInit {
|
||||||
@Input() focus?: HTMLElement;
|
@Input() focus?: HTMLElement;
|
||||||
@Input() side?: CoreUserToursSide;
|
@Input() side?: CoreUserToursSide;
|
||||||
@Input() alignment?: CoreUserToursAlignment;
|
@Input() alignment?: CoreUserToursAlignment;
|
||||||
|
@Output() beforeDismiss = new EventEmitter<void>();
|
||||||
|
@Output() afterDismiss = new EventEmitter<void>();
|
||||||
@HostBinding('class.is-active') active = false;
|
@HostBinding('class.is-active') active = false;
|
||||||
@HostBinding('class.is-popover') popover = false;
|
@HostBinding('class.is-popover') popover = false;
|
||||||
@ViewChild('wrapper') wrapper?: ElementRef<HTMLElement>;
|
@ViewChild('wrapper') wrapper?: ElementRef<HTMLElement>;
|
||||||
|
@ -80,6 +82,13 @@ export class CoreUserToursUserTourComponent implements AfterViewInit {
|
||||||
|
|
||||||
await CoreDomUtils.waitForImages(tour);
|
await CoreDomUtils.waitForImages(tour);
|
||||||
|
|
||||||
|
// Calculate focus styles or dismiss if the element is gone.
|
||||||
|
if (this.focus && !CoreDomUtils.isElementVisible(this.focus)) {
|
||||||
|
await this.dismiss(false);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.calculateStyles();
|
this.calculateStyles();
|
||||||
|
|
||||||
// Show tour.
|
// Show tour.
|
||||||
|
@ -94,11 +103,15 @@ export class CoreUserToursUserTourComponent implements AfterViewInit {
|
||||||
* @param acknowledge Whether to confirm that the user has seen the User Tour.
|
* @param acknowledge Whether to confirm that the user has seen the User Tour.
|
||||||
*/
|
*/
|
||||||
async dismiss(acknowledge: boolean = true): Promise<void> {
|
async dismiss(acknowledge: boolean = true): Promise<void> {
|
||||||
|
this.beforeDismiss.emit();
|
||||||
|
|
||||||
await this.playLeaveAnimation();
|
await this.playLeaveAnimation();
|
||||||
|
await Promise.all<unknown>([
|
||||||
|
AngularFrameworkDelegate.removeViewFromDom(this.container, this.element),
|
||||||
|
acknowledge && CoreUserTours.acknowledge(this.id),
|
||||||
|
]);
|
||||||
|
|
||||||
AngularFrameworkDelegate.removeViewFromDom(this.container, this.element);
|
this.afterDismiss.emit();
|
||||||
|
|
||||||
acknowledge && CoreUserTours.acknowledge(this.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { CoreApp } from '@services/app';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { AngularFrameworkDelegate, makeSingleton } from '@singletons';
|
import { AngularFrameworkDelegate, makeSingleton } from '@singletons';
|
||||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||||
|
import { CoreSubscriptions } from '@singletons/subscriptions';
|
||||||
import { CoreUserToursUserTourComponent } from '../components/user-tour/user-tour';
|
import { CoreUserToursUserTourComponent } from '../components/user-tour/user-tour';
|
||||||
import { APP_SCHEMA, CoreUserToursDBEntry, USER_TOURS_TABLE_NAME } from './database/user-tours';
|
import { APP_SCHEMA, CoreUserToursDBEntry, USER_TOURS_TABLE_NAME } from './database/user-tours';
|
||||||
|
|
||||||
|
@ -106,8 +107,10 @@ export class CoreUserToursService {
|
||||||
protected async show(options: CoreUserToursBasicOptions | CoreUserToursFocusedOptions): Promise<void> {
|
protected async show(options: CoreUserToursBasicOptions | CoreUserToursFocusedOptions): Promise<void> {
|
||||||
const { delay, ...componentOptions } = options;
|
const { delay, ...componentOptions } = options;
|
||||||
|
|
||||||
|
// Delay start.
|
||||||
await CoreUtils.wait(delay ?? 200);
|
await CoreUtils.wait(delay ?? 200);
|
||||||
|
|
||||||
|
// Create tour.
|
||||||
const container = document.querySelector('ion-app') ?? document.body;
|
const container = document.querySelector('ion-app') ?? document.body;
|
||||||
const element = await AngularFrameworkDelegate.attachViewToDom(
|
const element = await AngularFrameworkDelegate.attachViewToDom(
|
||||||
container,
|
container,
|
||||||
|
@ -117,6 +120,22 @@ export class CoreUserToursService {
|
||||||
const tour = CoreComponentsRegistry.require(element, CoreUserToursUserTourComponent);
|
const tour = CoreComponentsRegistry.require(element, CoreUserToursUserTourComponent);
|
||||||
|
|
||||||
this.tours.push(tour);
|
this.tours.push(tour);
|
||||||
|
|
||||||
|
// Handle present/dismiss lifecycle.
|
||||||
|
CoreSubscriptions.once(tour.beforeDismiss, () => {
|
||||||
|
const index = this.tours.indexOf(tour);
|
||||||
|
|
||||||
|
if (index === -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tours.splice(index, 1);
|
||||||
|
|
||||||
|
const nextTour = this.tours[0] as CoreUserToursUserTourComponent | undefined;
|
||||||
|
|
||||||
|
nextTour?.present().then(() => this.tourReadyCallbacks.get(nextTour)?.());
|
||||||
|
});
|
||||||
|
|
||||||
this.tours.length > 1
|
this.tours.length > 1
|
||||||
? await new Promise<void>(resolve => this.tourReadyCallbacks.set(tour, resolve))
|
? await new Promise<void>(resolve => this.tourReadyCallbacks.set(tour, resolve))
|
||||||
: await tour.present();
|
: await tour.present();
|
||||||
|
@ -128,19 +147,7 @@ export class CoreUserToursService {
|
||||||
* @param acknowledge Whether to acknowledge that the user has seen this User Tour or not.
|
* @param acknowledge Whether to acknowledge that the user has seen this User Tour or not.
|
||||||
*/
|
*/
|
||||||
async dismiss(acknowledge: boolean = true): Promise<void> {
|
async dismiss(acknowledge: boolean = true): Promise<void> {
|
||||||
if (this.tours.length === 0) {
|
await this.tours[0]?.dismiss(acknowledge);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const activeTour = this.tours.shift() as CoreUserToursUserTourComponent;
|
|
||||||
const nextTour = this.tours[0] as CoreUserToursUserTourComponent | undefined;
|
|
||||||
|
|
||||||
await Promise.all([
|
|
||||||
activeTour.dismiss(acknowledge),
|
|
||||||
nextTour?.present(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
nextTour && this.tourReadyCallbacks.get(nextTour)?.();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue