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 | | Eigenschaft | Wert |
|---|---| |---|---|
| Version | 2.2.4 | | Version | 2.2.5 |
| SharePoint Framework | 1.4.1 | | SharePoint Framework | 1.4.1 |
| Node.js für den Build | 8.17.0 | | Node.js für den Build | 8.17.0 |
| Moderne Seiten | SPFx Application Customizer | | Moderne Seiten | SPFx Application Customizer |
@@ -272,6 +272,11 @@ MegaMenu/
## Versionshistorie ## 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 ### 2.2.4
- Der Ladehinweis wird auch dann zuverlässig entfernt, wenn der Custom-Branding-Host während des asynchronen Ladens erzeugt wird. - 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 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] Navigations-URLs validieren und unsichere Protokolle blockieren.
- [x] Externe Links und `MegaMenu.OpenInNewWindow` sicher unterstützen. - [x] Externe Links und `MegaMenu.OpenInNewWindow` sicher unterstützen.
- [x] Lade-, Leer- und Fehlerzustände verständlich und barrierearm darstellen. - [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 ## Lokale Term-Eigenschaften
+1 -1
View File
@@ -3,7 +3,7 @@
"solution": { "solution": {
"name": "mega-menu-client-side-solution", "name": "mega-menu-client-side-solution",
"id": "f4660e06-ce08-43ee-bfb7-5c4464e01133", "id": "f4660e06-ce08-43ee-bfb7-5c4464e01133",
"version": "2.2.4.0", "version": "2.2.5.0",
"includeClientSideAssets": true, "includeClientSideAssets": true,
"skipFeatureDeployment": true "skipFeatureDeployment": true
}, },
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "mega-menu", "name": "mega-menu",
"version": "2.2.4", "version": "2.2.5",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "mega-menu", "name": "mega-menu",
"version": "2.2.4", "version": "2.2.5",
"private": true, "private": true,
"main": "lib/index.js", "main": "lib/index.js",
"engines": { "engines": {
@@ -38,13 +38,14 @@ export default class MegaMenuApplicationCustomizer
private _menuContainer: HTMLElement | undefined; private _menuContainer: HTMLElement | undefined;
private _renderer: MegaMenuRenderer | undefined; private _renderer: MegaMenuRenderer | undefined;
private _statusElement: HTMLElement | undefined; private _statusElement: HTMLElement | undefined;
private _customHeaderObserver: MutationObserver | undefined;
@override @override
public onInit(): Promise<void> { public onInit(): Promise<void> {
const debug: boolean = this._isDebugEnabled(); const debug: boolean = this._isDebugEnabled();
debugLog(debug, LOG_SOURCE, 'onInit started.', { debugLog(debug, LOG_SOURCE, 'onInit started.', {
componentId: UserCustomActionMegaMenuId, componentId: UserCustomActionMegaMenuId,
version: '2.2.4', version: '2.2.5',
properties: this.properties || {}, properties: this.properties || {},
pageUrl: window.location.href, pageUrl: window.location.href,
webUrl: this.context.pageContext.web.absoluteUrl, webUrl: this.context.pageContext.web.absoluteUrl,
@@ -178,7 +179,9 @@ export default class MegaMenuApplicationCustomizer
} }
private _getOrCreateContainer(id: string, placeholder: PlaceholderContent): HTMLElement { 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) { if (container) {
debugLog(this._isDebugEnabled(), LOG_SOURCE, 'Existing host container found.', { debugLog(this._isDebugEnabled(), LOG_SOURCE, 'Existing host container found.', {
@@ -186,31 +189,63 @@ export default class MegaMenuApplicationCustomizer
containerId: container.id, containerId: container.id,
containerClassName: container.className || '' containerClassName: container.className || ''
}); });
let host: HTMLElement = document.getElementById('MegaMenuHost');
if (!host) { if (!host) {
host = document.createElement('div'); host = document.createElement('div');
host.id = 'MegaMenuHost'; 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; 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 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 => { private _onDispose = (): void => {
this.context.placeholderProvider.changedEvent.remove(this, this._renderPlaceHolders); this.context.placeholderProvider.changedEvent.remove(this, this._renderPlaceHolders);
this._stopCustomHeaderObserver();
this._clearStatus(); this._clearStatus();
if (this._renderer) { if (this._renderer) {
this._renderer.dispose(); this._renderer.dispose();
this._renderer = undefined; this._renderer = undefined;
} }
if (this._menuContainer && this._menuContainer.parentElement) {
this._menuContainer.parentElement.removeChild(this._menuContainer);
}
this._menuContainer = undefined; this._menuContainer = undefined;
this._topPlaceholder = undefined; this._topPlaceholder = undefined;
debugLog(this._isDebugEnabled(), LOG_SOURCE, 'Disposed custom top placeholder.'); 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', assert('modern loading status is cleared before menu render',
applicationCustomizer.indexOf('this._clearStatus();') >= 0 && applicationCustomizer.indexOf('this._clearStatus();') >= 0 &&
applicationCustomizer.indexOf('private _statusElement: HTMLElement | undefined;') >= 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', 'white',
'neutralLighter', 'neutralLighter',