diff --git a/frontend/app/src/app/util/ion-content-parallax.directive.ts b/frontend/app/src/app/util/ion-content-parallax.directive.ts
index 1182e386..2eca9fed 100644
--- a/frontend/app/src/app/util/ion-content-parallax.directive.ts
+++ b/frontend/app/src/app/util/ion-content-parallax.directive.ts
@@ -13,6 +13,7 @@
* this program. If not, see .
*/
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'));
+ }
}
diff --git a/frontend/app/src/app/util/ion-icon/replace-util.ts b/frontend/app/src/app/util/ion-icon/replace-util.ts
index bda28d00..cdadf44a 100644
--- a/frontend/app/src/app/util/ion-icon/replace-util.ts
+++ b/frontend/app/src/app/util/ion-icon/replace-util.ts
@@ -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,
@@ -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();
}
}
diff --git a/frontend/app/src/app/util/ion-icon/shadow-attacher.ts b/frontend/app/src/app/util/ion-icon/shadow-attacher.ts
new file mode 100644
index 00000000..6f1157a0
--- /dev/null
+++ b/frontend/app/src/app/util/ion-icon/shadow-attacher.ts
@@ -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(resolve => {
+ const interval = setInterval(() => {
+ if (tries > maxAttempts) {
+ clearInterval(interval);
+ throw new Error('Element not found');
+ }
+ if (query()) {
+ clearInterval(interval);
+ resolve();
+ }
+ tries++;
+ }, retryAfterMs);
+ });
+}
diff --git a/frontend/app/src/app/util/section/section-link-card.html b/frontend/app/src/app/util/section/section-link-card.html
deleted file mode 100644
index e69de29b..00000000
diff --git a/frontend/app/src/app/util/section/section-tail-prompt-card.html b/frontend/app/src/app/util/section/section-tail-prompt-card.html
deleted file mode 100644
index e69de29b..00000000