feat: Update version to 2.2.5 and enhance CustomHeader handling in MegaMenu

This commit is contained in:
Torsten Brendgen
2026-08-23 21:59:29 +02:00
parent 767d6bfd10
commit a40a5ddc57
7 changed files with 59 additions and 14 deletions
+6 -1
View File
@@ -4,7 +4,7 @@ Zentrale, barrierearme Portalnavigation aus SharePoint Managed Metadata für Sha
| Eigenschaft | Wert |
|---|---|
| Version | 2.2.4 |
| Version | 2.2.5 |
| SharePoint Framework | 1.4.1 |
| Node.js für den Build | 8.17.0 |
| Moderne Seiten | SPFx Application Customizer |
@@ -272,6 +272,11 @@ MegaMenu/
## Versionshistorie
### 2.2.5
- Das Mega Menu wartet bei vertauschter Ladefolge auf `#CustomHeader` und verschiebt seine bereits gerenderte
Navigation automatisch in den Custom-Branding-Header.
### 2.2.4
- Der Ladehinweis wird auch dann zuverlässig entfernt, wenn der Custom-Branding-Host während des asynchronen Ladens erzeugt wird.
+2 -1
View File
@@ -1,4 +1,4 @@
# MegaMenu – Arbeitsplan Version 2.2.4
# MegaMenu – Arbeitsplan Version 2.2.5
Status: Implementierung abgeschlossen; Ship-Build auf der vorgesehenen Node-8-Buildumgebung ausstehend
@@ -10,6 +10,7 @@ Status: Implementierung abgeschlossen; Ship-Build auf der vorgesehenen Node-8-Bu
- [x] Navigations-URLs validieren und unsichere Protokolle blockieren.
- [x] Externe Links und `MegaMenu.OpenInNewWindow` sicher unterstützen.
- [x] Lade-, Leer- und Fehlerzustände verständlich und barrierearm darstellen.
- [x] Spät erzeugten Custom-Branding-Header beobachten und die Navigation ohne Reload dorthin verschieben.
## Lokale Term-Eigenschaften
+1 -1
View File
@@ -3,7 +3,7 @@
"solution": {
"name": "mega-menu-client-side-solution",
"id": "f4660e06-ce08-43ee-bfb7-5c4464e01133",
"version": "2.2.4.0",
"version": "2.2.5.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true
},
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "mega-menu",
"version": "2.2.4",
"version": "2.2.5",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "mega-menu",
"version": "2.2.4",
"version": "2.2.5",
"private": true,
"main": "lib/index.js",
"engines": {
@@ -38,13 +38,14 @@ export default class MegaMenuApplicationCustomizer
private _menuContainer: HTMLElement | undefined;
private _renderer: MegaMenuRenderer | undefined;
private _statusElement: HTMLElement | undefined;
private _customHeaderObserver: MutationObserver | undefined;
@override
public onInit(): Promise<void> {
const debug: boolean = this._isDebugEnabled();
debugLog(debug, LOG_SOURCE, 'onInit started.', {
componentId: UserCustomActionMegaMenuId,
version: '2.2.4',
version: '2.2.5',
properties: this.properties || {},
pageUrl: window.location.href,
webUrl: this.context.pageContext.web.absoluteUrl,
@@ -178,7 +179,9 @@ export default class MegaMenuApplicationCustomizer
}
private _getOrCreateContainer(id: string, placeholder: PlaceholderContent): HTMLElement {
const container = document.getElementById(id);
const container: HTMLElement = document.getElementById(id);
let host: HTMLElement = this._menuContainer || document.getElementById('MegaMenuHost') ||
document.getElementById('CustomNavigation');
if (container) {
debugLog(this._isDebugEnabled(), LOG_SOURCE, 'Existing host container found.', {
@@ -186,31 +189,63 @@ export default class MegaMenuApplicationCustomizer
containerId: container.id,
containerClassName: container.className || ''
});
let host: HTMLElement = document.getElementById('MegaMenuHost');
if (!host) {
host = document.createElement('div');
host.id = 'MegaMenuHost';
container.appendChild(host);
debugLog(this._isDebugEnabled(), LOG_SOURCE, 'MegaMenuHost was created inside the existing host container.');
} else {
debugLog(this._isDebugEnabled(), LOG_SOURCE, 'Existing MegaMenuHost will be reused.');
}
if (host.parentElement !== container) { container.appendChild(host); }
this._stopCustomHeaderObserver();
debugLog(this._isDebugEnabled(), LOG_SOURCE, 'MegaMenu host is located inside the existing CustomHeader.');
return host;
}
debugLog(this._isDebugEnabled(), LOG_SOURCE, 'No external host container found; the Top placeholder will be used.', {
if (!host) {
host = document.createElement('div');
host.id = 'MegaMenuHost';
}
if (host.parentElement !== placeholder.domElement) { placeholder.domElement.appendChild(host); }
this._startCustomHeaderObserver(id);
debugLog(this._isDebugEnabled(), LOG_SOURCE, 'No external host container found; using a temporary host in the Top placeholder.', {
requestedId: id
});
return placeholder.domElement;
return host;
}
private _startCustomHeaderObserver(id: string): void {
if (this._customHeaderObserver || typeof MutationObserver === 'undefined') { return; }
this._customHeaderObserver = new MutationObserver((): void => {
const customHeader: HTMLElement = document.getElementById(id);
if (!customHeader || !this._menuContainer || this._menuContainer === customHeader) { return; }
if (this._menuContainer.parentElement !== customHeader) {
customHeader.appendChild(this._menuContainer);
debugLog(this._isDebugEnabled(), LOG_SOURCE, 'MegaMenu host moved into the late CustomHeader.', {
containerId: this._menuContainer.id || ''
});
}
this._stopCustomHeaderObserver();
});
this._customHeaderObserver.observe(document.documentElement, { childList: true, subtree: true });
debugLog(this._isDebugEnabled(), LOG_SOURCE, 'Waiting for CustomHeader DOM registration.');
}
private _stopCustomHeaderObserver(): void {
if (this._customHeaderObserver) {
this._customHeaderObserver.disconnect();
this._customHeaderObserver = undefined;
}
}
private _onDispose = (): void => {
this.context.placeholderProvider.changedEvent.remove(this, this._renderPlaceHolders);
this._stopCustomHeaderObserver();
this._clearStatus();
if (this._renderer) {
this._renderer.dispose();
this._renderer = undefined;
}
if (this._menuContainer && this._menuContainer.parentElement) {
this._menuContainer.parentElement.removeChild(this._menuContainer);
}
this._menuContainer = undefined;
this._topPlaceholder = undefined;
debugLog(this._isDebugEnabled(), LOG_SOURCE, 'Disposed custom top placeholder.');
+4
View File
@@ -45,6 +45,10 @@ var applicationCustomizer = read('src/extensions/megaMenu/MegaMenuApplicationCus
assert('modern loading status is cleared before menu render',
applicationCustomizer.indexOf('this._clearStatus();') >= 0 &&
applicationCustomizer.indexOf('private _statusElement: HTMLElement | undefined;') >= 0);
assert('late CustomHeader is observed and receives the menu host',
applicationCustomizer.indexOf('new MutationObserver') >= 0 &&
applicationCustomizer.indexOf('customHeader.appendChild(this._menuContainer)') >= 0 &&
applicationCustomizer.indexOf('this._stopCustomHeaderObserver();') >= 0);
[
'white',
'neutralLighter',