mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2025-12-13 01:36:22 +00:00
fix: parallax replacer might fail to find shadow root on its first try
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Directive, ElementRef, HostBinding, Input, OnDestroy, OnInit} from '@angular/core';
|
||||
import {waitForElement} from './ion-icon/shadow-attacher';
|
||||
|
||||
type IonicColor =
|
||||
| 'danger'
|
||||
@@ -86,31 +87,39 @@ export class IonContentParallaxDirective implements OnInit, OnDestroy {
|
||||
|
||||
constructor(private element: ElementRef) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.mutationObserver = new MutationObserver(() => {
|
||||
const inner = this.element.nativeElement.shadowRoot.querySelector('.inner-scroll') as
|
||||
| HTMLDivElement
|
||||
| undefined;
|
||||
if (!inner) return;
|
||||
|
||||
// eslint-disable-next-line unicorn/no-array-for-each
|
||||
inner.childNodes.forEach(node => node.remove());
|
||||
|
||||
inner.part.add('parallax-scroll');
|
||||
const parallaxParentElement = document.createElement('div');
|
||||
parallaxParentElement.part.add('parallax-parent');
|
||||
const parallaxElement = document.createElement('div');
|
||||
parallaxElement.part.add('parallax');
|
||||
|
||||
inner.append(parallaxParentElement);
|
||||
parallaxParentElement.append(parallaxElement, document.createElement('slot'));
|
||||
});
|
||||
this.mutationObserver.observe(this.element.nativeElement.shadowRoot, {
|
||||
childList: true,
|
||||
});
|
||||
async ngOnInit() {
|
||||
this.mutationObserver = new MutationObserver(this.replace.bind(this));
|
||||
const element = this.element.nativeElement;
|
||||
if (element.shadowRoot) {
|
||||
this.mutationObserver.observe(element.shadowRoot, {childList: true});
|
||||
} else {
|
||||
console.warn("Shadow root didn't exist for parallax, retrying...");
|
||||
await waitForElement(() => this.element.nativeElement.shadowRoot);
|
||||
this.mutationObserver.observe(element.shadowRoot, {childList: true});
|
||||
this.replace();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.mutationObserver.disconnect();
|
||||
}
|
||||
|
||||
replace() {
|
||||
const inner = this.element.nativeElement.shadowRoot.querySelector('.inner-scroll') as
|
||||
| HTMLDivElement
|
||||
| undefined;
|
||||
if (!inner) return;
|
||||
|
||||
// eslint-disable-next-line unicorn/no-array-for-each
|
||||
inner.childNodes.forEach(node => node.remove());
|
||||
|
||||
inner.part.add('parallax-scroll');
|
||||
const parallaxParentElement = document.createElement('div');
|
||||
parallaxParentElement.part.add('parallax-parent');
|
||||
const parallaxElement = document.createElement('div');
|
||||
parallaxElement.part.add('parallax');
|
||||
|
||||
inner.append(parallaxParentElement);
|
||||
parallaxParentElement.append(parallaxElement, document.createElement('slot'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
import {ComponentRef, Directive, ElementRef, OnDestroy, OnInit, ViewContainerRef} from '@angular/core';
|
||||
import {IonIcon} from '@ionic/angular';
|
||||
import {IonIconDirective} from './ion-icon.directive';
|
||||
import {waitForElement} from './shadow-attacher';
|
||||
|
||||
export type IconData = Omit<
|
||||
Partial<IonIconDirective>,
|
||||
@@ -79,25 +80,15 @@ export abstract class IconReplacer implements OnInit, OnDestroy {
|
||||
// noop
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
async ngOnInit() {
|
||||
this.init();
|
||||
|
||||
if (this.host) {
|
||||
this.attachObserver();
|
||||
} else {
|
||||
let tries = 0;
|
||||
console.warn('IconReplacer: host not found, trying again');
|
||||
const interval = setInterval(() => {
|
||||
if (tries > this.maxAttempts) {
|
||||
clearInterval(interval);
|
||||
throw new Error('IconReplacer: host not found');
|
||||
}
|
||||
if (this.host) {
|
||||
clearInterval(interval);
|
||||
this.replace();
|
||||
}
|
||||
tries++;
|
||||
}, this.retryAfterMs);
|
||||
console.warn("Shadow root didn't exist for ion icon replacer, retrying...");
|
||||
await waitForElement(() => this.host);
|
||||
this.replace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
23
frontend/app/src/app/util/ion-icon/shadow-attacher.ts
Normal file
23
frontend/app/src/app/util/ion-icon/shadow-attacher.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Waits for an element to appear
|
||||
*
|
||||
* In normal circumstances *please* use the mutation observer for these kinds of tasks.
|
||||
* However, shadowDom attachment is **not** covered by the mutation observer,
|
||||
* so a solution like this is required.
|
||||
*/
|
||||
export async function waitForElement(query: () => HTMLElement, maxAttempts = 10, retryAfterMs = 10) {
|
||||
let tries = 0;
|
||||
return new Promise<void>(resolve => {
|
||||
const interval = setInterval(() => {
|
||||
if (tries > maxAttempts) {
|
||||
clearInterval(interval);
|
||||
throw new Error('Element not found');
|
||||
}
|
||||
if (query()) {
|
||||
clearInterval(interval);
|
||||
resolve();
|
||||
}
|
||||
tries++;
|
||||
}, retryAfterMs);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user