MOBILE-4109 book: Disable unactive pages
parent
56c4877b2e
commit
5370217058
|
@ -31,10 +31,10 @@
|
||||||
</ion-card>
|
</ion-card>
|
||||||
|
|
||||||
<core-swipe-slides [manager]="manager" [options]="slidesOpts">
|
<core-swipe-slides [manager]="manager" [options]="slidesOpts">
|
||||||
<ng-template let-chapter="item">
|
<ng-template let-chapter="item" let-active="active">
|
||||||
<div class="ion-padding">
|
<div class="ion-padding">
|
||||||
<core-format-text [component]="component" [componentId]="cmId" [text]="chapter.content" contextLevel="module"
|
<core-format-text [component]="component" [componentId]="cmId" [text]="chapter.content" contextLevel="module"
|
||||||
[contextInstanceId]="cmId" [courseId]="courseId"></core-format-text>
|
[contextInstanceId]="cmId" [courseId]="courseId" [disabled]="!active"></core-format-text>
|
||||||
<div class="ion-margin-top" *ngIf="chapter.tags?.length > 0">
|
<div class="ion-margin-top" *ngIf="chapter.tags?.length > 0">
|
||||||
<strong>{{ 'core.tag.tags' | translate }}: </strong>
|
<strong>{{ 'core.tag.tags' | translate }}: </strong>
|
||||||
<core-tag-list [tags]="chapter.tags"></core-tag-list>
|
<core-tag-list [tags]="chapter.tags"></core-tag-list>
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper class to control the interactivity of an element.
|
||||||
|
*/
|
||||||
|
export abstract class ElementController {
|
||||||
|
|
||||||
|
protected enabled: boolean;
|
||||||
|
|
||||||
|
constructor(enabled: boolean) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable element.
|
||||||
|
*/
|
||||||
|
enable(): void {
|
||||||
|
if (this.enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.enabled = true;
|
||||||
|
|
||||||
|
this.onEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable element.
|
||||||
|
*/
|
||||||
|
disable(): void {
|
||||||
|
if (!this.enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.enabled = false;
|
||||||
|
|
||||||
|
this.onDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update underlying element to enable interactivity.
|
||||||
|
*/
|
||||||
|
abstract onEnabled(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update underlying element to disable interactivity.
|
||||||
|
*/
|
||||||
|
abstract onDisabled(): void;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { ElementController } from './ElementController';
|
||||||
|
|
||||||
|
export type FrameElement = HTMLIFrameElement | HTMLFrameElement | HTMLObjectElement | HTMLEmbedElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper class to control the interactivity of a frame element.
|
||||||
|
*/
|
||||||
|
export class FrameElementController extends ElementController {
|
||||||
|
|
||||||
|
private frame: FrameElement;
|
||||||
|
private placeholder: Node;
|
||||||
|
|
||||||
|
constructor(element: FrameElement, enabled: boolean) {
|
||||||
|
super(enabled);
|
||||||
|
|
||||||
|
this.frame = element;
|
||||||
|
this.placeholder = document.createComment('disabled frame placeholder');
|
||||||
|
|
||||||
|
enabled || this.onDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
onEnabled(): void {
|
||||||
|
this.placeholder.parentElement?.replaceChild(this.frame, this.placeholder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
onDisabled(): void {
|
||||||
|
this.frame.parentElement?.replaceChild(this.placeholder, this.frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
|
import { ElementController } from './ElementController';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper class to control the interactivity of a media element.
|
||||||
|
*/
|
||||||
|
export class MediaElementController extends ElementController {
|
||||||
|
|
||||||
|
private media: HTMLMediaElement;
|
||||||
|
private autoplay: boolean;
|
||||||
|
private playing?: boolean;
|
||||||
|
private playListener?: () => void;
|
||||||
|
private pauseListener?: () => void;
|
||||||
|
|
||||||
|
constructor(media: HTMLMediaElement, enabled: boolean) {
|
||||||
|
super(enabled);
|
||||||
|
|
||||||
|
this.media = media;
|
||||||
|
this.autoplay = media.autoplay;
|
||||||
|
|
||||||
|
media.autoplay = false;
|
||||||
|
|
||||||
|
enabled && this.onEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
onEnabled(): void {
|
||||||
|
const ready = this.playing ?? this.autoplay
|
||||||
|
? this.media.play()
|
||||||
|
: Promise.resolve();
|
||||||
|
|
||||||
|
ready
|
||||||
|
.then(() => this.addPlaybackEventListeners())
|
||||||
|
.catch(error => CoreUtils.logUnhandledError('Error enabling media element', error));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
async onDisabled(): Promise<void> {
|
||||||
|
this.removePlaybackEventListeners();
|
||||||
|
|
||||||
|
this.media.pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start listening playback events.
|
||||||
|
*/
|
||||||
|
private addPlaybackEventListeners(): void {
|
||||||
|
this.media.addEventListener('play', this.playListener = () => this.playing = true);
|
||||||
|
this.media.addEventListener('pause', this.pauseListener = () => this.playing = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop listening playback events.
|
||||||
|
*/
|
||||||
|
private removePlaybackEventListeners(): void {
|
||||||
|
this.playListener && this.media.removeEventListener('play', this.playListener);
|
||||||
|
this.pauseListener && this.media.removeEventListener('pause', this.pauseListener);
|
||||||
|
|
||||||
|
delete this.playListener;
|
||||||
|
delete this.pauseListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
<ion-slides *ngIf="loaded" (ionSlideWillChange)="slideWillChange()" (ionSlideDidChange)="slideDidChange()" [options]="options">
|
<ion-slides *ngIf="loaded" (ionSlideWillChange)="slideWillChange()" (ionSlideDidChange)="slideDidChange()" [options]="options">
|
||||||
<ion-slide *ngFor="let item of items">
|
<ion-slide *ngFor="let item of items; index as index">
|
||||||
<ng-container *ngIf="template" [ngTemplateOutlet]="template" [ngTemplateOutletContext]="{item: item}"></ng-container>
|
<ng-container *ngIf="template" [ngTemplateOutlet]="template" [ngTemplateOutletContext]="{item: item, active: isActive(index)}">
|
||||||
|
</ng-container>
|
||||||
</ion-slide>
|
</ion-slide>
|
||||||
</ion-slides>
|
</ion-slides>
|
||||||
|
|
|
@ -45,6 +45,7 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
protected unsubscribe?: () => void;
|
protected unsubscribe?: () => void;
|
||||||
protected resizeListener: CoreEventObserver;
|
protected resizeListener: CoreEventObserver;
|
||||||
protected updateSlidesPromise?: Promise<void>;
|
protected updateSlidesPromise?: Promise<void>;
|
||||||
|
protected activeSlideIndexes: number[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
elementRef: ElementRef<HTMLElement>,
|
elementRef: ElementRef<HTMLElement>,
|
||||||
|
@ -74,6 +75,16 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
return !!this.manager?.getSource().isLoaded();
|
return !!this.manager?.getSource().isLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the slide with the given index is active.
|
||||||
|
*
|
||||||
|
* @param index Slide index.
|
||||||
|
* @return Whether the slide is active.
|
||||||
|
*/
|
||||||
|
isActive(index: number): boolean {
|
||||||
|
return this.activeSlideIndexes.includes(index);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize some properties based on the manager.
|
* Initialize some properties based on the manager.
|
||||||
*/
|
*/
|
||||||
|
@ -101,13 +112,15 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate that the initial index is inside the valid range.
|
// Validate that the initial index is inside the valid range.
|
||||||
const initialIndex = CoreMath.clamp(this.options.initialSlide as number, 0, items.length - 1);
|
const initialIndex = CoreMath.clamp(this.options.initialSlide, 0, items.length - 1);
|
||||||
|
|
||||||
const initialItemData = {
|
const initialItemData = {
|
||||||
index: initialIndex,
|
index: initialIndex,
|
||||||
item: items[initialIndex],
|
item: items[initialIndex],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.activeSlideIndexes = [initialIndex];
|
||||||
|
|
||||||
manager.setSelectedItem(items[initialIndex]);
|
manager.setSelectedItem(items[initialIndex]);
|
||||||
this.onWillChange.emit(initialItemData);
|
this.onWillChange.emit(initialItemData);
|
||||||
this.onDidChange.emit(initialItemData);
|
this.onDidChange.emit(initialItemData);
|
||||||
|
@ -205,6 +218,7 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.activeSlideIndexes.push(currentItemData.index);
|
||||||
this.manager?.setSelectedItem(currentItemData.item);
|
this.manager?.setSelectedItem(currentItemData.item);
|
||||||
|
|
||||||
this.onWillChange.emit(currentItemData);
|
this.onWillChange.emit(currentItemData);
|
||||||
|
@ -219,9 +233,13 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
async slideDidChange(): Promise<void> {
|
async slideDidChange(): Promise<void> {
|
||||||
const currentItemData = await this.getCurrentSlideItemData();
|
const currentItemData = await this.getCurrentSlideItemData();
|
||||||
if (!currentItemData) {
|
if (!currentItemData) {
|
||||||
|
this.activeSlideIndexes = [];
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.activeSlideIndexes = [currentItemData.index];
|
||||||
|
|
||||||
this.onDidChange.emit(currentItemData);
|
this.onDidChange.emit(currentItemData);
|
||||||
|
|
||||||
await this.applyScrollOnChange();
|
await this.applyScrollOnChange();
|
||||||
|
@ -304,6 +322,7 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
* @todo Change unknown with the right type once Swiper library is used.
|
* @todo Change unknown with the right type once Swiper library is used.
|
||||||
*/
|
*/
|
||||||
export type CoreSwipeSlidesOptions = Record<string, unknown> & {
|
export type CoreSwipeSlidesOptions = Record<string, unknown> & {
|
||||||
|
initialSlide?: number;
|
||||||
scrollOnChange?: 'top' | 'none'; // Scroll behaviour on change slide. By default, none.
|
scrollOnChange?: 'top' | 'none'; // Scroll behaviour on change slide. By default, none.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,9 @@ import { CoreDom } from '@singletons/dom';
|
||||||
import { CoreEvents } from '@singletons/events';
|
import { CoreEvents } from '@singletons/events';
|
||||||
import { CoreRefreshContext, CORE_REFRESH_CONTEXT } from '@/core/utils/refresh-context';
|
import { CoreRefreshContext, CORE_REFRESH_CONTEXT } from '@/core/utils/refresh-context';
|
||||||
import { CorePlatform } from '@services/platform';
|
import { CorePlatform } from '@services/platform';
|
||||||
|
import { ElementController } from '@classes/element-controllers/ElementController';
|
||||||
|
import { MediaElementController } from '@classes/element-controllers/MediaElementController';
|
||||||
|
import { FrameElementController } from '@classes/element-controllers/FrameElementController';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directive to format text rendered. It renders the HTML and treats all links and media, using CoreLinkDirective
|
* Directive to format text rendered. It renders the HTML and treats all links and media, using CoreLinkDirective
|
||||||
|
@ -84,6 +87,7 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
||||||
@Input() captureLinks?: boolean; // Whether links should tried to be opened inside the app. Defaults to true.
|
@Input() captureLinks?: boolean; // Whether links should tried to be opened inside the app. Defaults to true.
|
||||||
@Input() openLinksInApp?: boolean; // Whether links should be opened in InAppBrowser.
|
@Input() openLinksInApp?: boolean; // Whether links should be opened in InAppBrowser.
|
||||||
@Input() hideIfEmpty = false; // If true, the tag will contain nothing if text is empty.
|
@Input() hideIfEmpty = false; // If true, the tag will contain nothing if text is empty.
|
||||||
|
@Input() disabled?: boolean; // If disabled, autoplay elements will be disabled.
|
||||||
|
|
||||||
@Input() fullOnClick?: boolean | string; // @deprecated on 4.0 Won't do anything.
|
@Input() fullOnClick?: boolean | string; // @deprecated on 4.0 Won't do anything.
|
||||||
@Input() fullTitle?: string; // @deprecated on 4.0 Won't do anything.
|
@Input() fullTitle?: string; // @deprecated on 4.0 Won't do anything.
|
||||||
|
@ -96,6 +100,7 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
||||||
@Output() onClick: EventEmitter<void> = new EventEmitter(); // Called when clicked.
|
@Output() onClick: EventEmitter<void> = new EventEmitter(); // Called when clicked.
|
||||||
|
|
||||||
protected element: HTMLElement;
|
protected element: HTMLElement;
|
||||||
|
protected elementControllers: ElementController[] = [];
|
||||||
protected emptyText = '';
|
protected emptyText = '';
|
||||||
protected domPromises: CoreCancellablePromise<void>[] = [];
|
protected domPromises: CoreCancellablePromise<void>[] = [];
|
||||||
protected domElementPromise?: CoreCancellablePromise<void>;
|
protected domElementPromise?: CoreCancellablePromise<void>;
|
||||||
|
@ -127,6 +132,14 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
||||||
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
|
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
|
||||||
if (changes.text || changes.filter || changes.contextLevel || changes.contextInstanceId) {
|
if (changes.text || changes.filter || changes.contextLevel || changes.contextInstanceId) {
|
||||||
this.formatAndRenderContents();
|
this.formatAndRenderContents();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('disabled' in changes) {
|
||||||
|
const disabled = changes['disabled'].currentValue;
|
||||||
|
|
||||||
|
this.elementControllers.forEach(controller => disabled ? controller.disable() : controller.enable());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,6 +365,8 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
||||||
// Move the children to the current element to be able to calculate the height.
|
// Move the children to the current element to be able to calculate the height.
|
||||||
CoreDomUtils.moveChildren(result.div, this.element);
|
CoreDomUtils.moveChildren(result.div, this.element);
|
||||||
|
|
||||||
|
this.elementControllers = result.elementControllers;
|
||||||
|
|
||||||
await CoreUtils.nextTick();
|
await CoreUtils.nextTick();
|
||||||
|
|
||||||
// Use collapsible-item directive instead.
|
// Use collapsible-item directive instead.
|
||||||
|
@ -432,13 +447,14 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
||||||
|
|
||||||
div.innerHTML = formatted;
|
div.innerHTML = formatted;
|
||||||
|
|
||||||
this.treatHTMLElements(div, site);
|
const elementControllers = this.treatHTMLElements(div, site);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
div,
|
div,
|
||||||
filters,
|
filters,
|
||||||
options,
|
options,
|
||||||
siteId,
|
siteId,
|
||||||
|
elementControllers,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,7 +465,7 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
||||||
* @param site Site instance.
|
* @param site Site instance.
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected treatHTMLElements(div: HTMLElement, site?: CoreSite): void {
|
protected treatHTMLElements(div: HTMLElement, site?: CoreSite): ElementController[] {
|
||||||
const images = Array.from(div.querySelectorAll('img'));
|
const images = Array.from(div.querySelectorAll('img'));
|
||||||
const anchors = Array.from(div.querySelectorAll('a'));
|
const anchors = Array.from(div.querySelectorAll('a'));
|
||||||
const audios = Array.from(div.querySelectorAll('audio'));
|
const audios = Array.from(div.querySelectorAll('audio'));
|
||||||
|
@ -498,16 +514,22 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
audios.forEach((audio) => {
|
const audioControllers = audios.map(audio => {
|
||||||
this.treatMedia(audio);
|
this.treatMedia(audio);
|
||||||
|
|
||||||
|
return new MediaElementController(audio, !this.disabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
videos.forEach((video) => {
|
const videoControllers = videos.map(video => {
|
||||||
this.treatMedia(video, true);
|
this.treatMedia(video, true);
|
||||||
|
|
||||||
|
return new MediaElementController(video, !this.disabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
iframes.forEach((iframe) => {
|
const iframeControllers = iframes.map(iframe => {
|
||||||
promises.push(this.treatIframe(iframe, site));
|
promises.push(this.treatIframe(iframe, site));
|
||||||
|
|
||||||
|
return new FrameElementController(iframe, !this.disabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
svgImages.forEach((image) => {
|
svgImages.forEach((image) => {
|
||||||
|
@ -539,8 +561,10 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle all kind of frames.
|
// Handle all kind of frames.
|
||||||
frames.forEach((frame: HTMLFrameElement | HTMLObjectElement | HTMLEmbedElement) => {
|
const frameControllers = frames.map((frame: HTMLFrameElement | HTMLObjectElement | HTMLEmbedElement) => {
|
||||||
CoreIframeUtils.treatFrame(frame, false);
|
CoreIframeUtils.treatFrame(frame, false);
|
||||||
|
|
||||||
|
return new FrameElementController(frame, !this.disabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
CoreDomUtils.handleBootstrapTooltips(div);
|
CoreDomUtils.handleBootstrapTooltips(div);
|
||||||
|
@ -562,6 +586,13 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
||||||
|
|
||||||
// Run asynchronous operations in the background to avoid blocking rendering.
|
// Run asynchronous operations in the background to avoid blocking rendering.
|
||||||
Promise.all(promises).catch(error => CoreUtils.logUnhandledError('Error treating format-text elements', error));
|
Promise.all(promises).catch(error => CoreUtils.logUnhandledError('Error treating format-text elements', error));
|
||||||
|
|
||||||
|
return [
|
||||||
|
...videoControllers,
|
||||||
|
...audioControllers,
|
||||||
|
...iframeControllers,
|
||||||
|
...frameControllers,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -903,6 +934,7 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
||||||
type FormatContentsResult = {
|
type FormatContentsResult = {
|
||||||
div: HTMLElement;
|
div: HTMLElement;
|
||||||
filters: CoreFilterFilter[];
|
filters: CoreFilterFilter[];
|
||||||
|
elementControllers: ElementController[];
|
||||||
options: CoreFilterFormatTextOptions;
|
options: CoreFilterFormatTextOptions;
|
||||||
siteId?: string;
|
siteId?: string;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue