feat: Add support for flyout menu mode in MegaMenu

- Introduced `MegaMenuMode` type and `normalizeMegaMenuMode` function to handle menu modes.
- Updated `MegaMenuApplicationCustomizer` to accept `menuMode` property.
- Enhanced `MegaMenuRenderer` to render flyout menus based on the selected mode.
- Created new HTML previews for both flyout and mega menu modes.
- Removed unused mock services and user custom action service interfaces.
This commit is contained in:
Torsten Brendgen
2026-07-20 20:37:32 +02:00
parent e75b11117f
commit bc61166267
27 changed files with 1320 additions and 1833 deletions

369
README.md
View File

@@ -1,312 +1,253 @@
# SharePoint MegaMenu
Barrierearme, dreistufige Portalnavigation auf Basis von SharePoint Managed Metadata für SharePoint Server Subscription Edition und SharePoint Server 2019.
Zentrale, barrierearme Portalnavigation aus SharePoint Managed Metadata für SharePoint Server Subscription Edition und SharePoint Server 2019.
| Eigenschaft | Wert |
|---|---|
| Version | 2.0.1 |
| SharePoint Framework | SPFx 1.4.1 |
| Node.js | 8.17.0 |
| Zieloberfläche | Moderne SharePoint-Seiten |
| Version | 2.1.0 |
| SharePoint Framework | 1.4.1 |
| Node.js für den Build | 8.17.0 |
| Moderne Seiten | SPFx Application Customizer |
| Klassische Seiten | separate ScriptLink-Variante |
| Paket | `sharepoint/solution/mega-menu.sppkg` |
## Funktionen
- Dreistufige Navigation aus einem Managed-Metadata-Termset
- Auswahl des Termsets per GUID oder, abwärtskompatibel, per Name
- Benutzerdefinierte Sortierung aus dem Term Store
- Unterstützung der Navigations-Eigenschaften `_Sys_Nav_SimpleLinkUrl`, `_Sys_Nav_TargetUrl` und `_Sys_Nav_HoverText`
- Auflösung von `~sitecollection` in Navigations-URLs
- Markierung des aktuellen Menüpunktes und seiner übergeordneten Einträge
- Bedienung mit Maus, Tastatur und Touch
- Responsive Darstellung
- Optionales zusätzliches Stylesheet
- Taxonomy-Cache mit konfigurierbarer Ablaufzeit
- Bereinigter SPFx-Lifecycle ohne verbleibende globale Event Listener
- Deutsche und englische Statusmeldungen
- zentrale Konfiguration pro Site Collection
- Termset-Auswahl bevorzugt per GUID, alternativ per Name
- drei Navigationsebenen
- zwei Darstellungsmodi: SharePoint-ähnliches Mega Menu und strukturelles Flyout
- benutzerdefinierte Sortierung aus dem Term Store
- Unterstützung für `_Sys_Nav_SimpleLinkUrl`, `_Sys_Nav_TargetUrl` und `_Sys_Nav_HoverText`
- Auflösung von `~sitecollection`
- Markierung des aktuellen Navigationspfads
- Tastatur-, Fokus-, Maus- und Touch-Bedienung
- responsive Darstellung und Unterstützung reduzierter Bewegung
- Session-Cache mit konfigurierbarer Laufzeit
- Debug-Protokollierung ohne Ausgabe im Normalbetrieb
- Unterstützung moderner und klassischer SharePoint-Seiten
## Architektur
```text
UserCustomAction.ClientSideComponentProperties
MegaMenuApplicationCustomizer
├── TaxonomyNavigationService
│ └── SPTermStorePickerService
│ └── Default Site Collection Term Store
└── MegaMenuRenderer
├── semantische Navigation
├── Fokus- und Tastatursteuerung
└── responsive Darstellung
App Catalog
└── zentral bereitgestelltes MegaMenu-SPFx-Bundle
Site Collection
└── SPSite.UserCustomAction
├── ComponentId
└── ClientSideComponentProperties
├── termSetId / termSetName
├── cacheMinutes
├── menuMode
└── debug
Moderne Seite Klassische Seite
└── Application Customizer └── ScriptLink + Classic-Runtime
```
Das MegaMenu wird einmal pro Site Collection konfiguriert. Das Paket wird mit `skipFeatureDeployment: true` zentral über den App Catalog bereitgestellt, damit das SPFx-Bundle ohne eine App-Installation in jedem einzelnen Web verfügbar ist. PortalSettings speichert die zentrale Konfiguration im Property Bag des Root Webs. Eine Site-Collection-Action aktiviert das MegaMenu auf dem Root Web sowie auf vorhandenen und zukünftigen Unterwebs. Das MegaMenu selbst enthält keine eigene Administrationsoberfläche.
Die Site-Collection-Action ist die einzige Konfigurationsquelle. Es gibt keine versteckte Konfigurationsliste, keine MegaMenu-Konfiguration im Property Bag und keine Web-scoped Kopien. PortalSettings kann diese Action zentral lesen und aktualisieren.
## Voraussetzungen
- SharePoint Server Subscription Edition oder SharePoint Server 2019
- konfigurierter App Catalog
- konfigurierter App Management Service
- ein Termset im Standard-Term-Store der Site Collection
- Leseberechtigung der Benutzer auf den Managed-Metadata-Service
- für Entwicklung und Build: Node.js 8.17.0 und eine zu SPFx 1.4.1 passende npm-Version
Das SPFx-Paket verwendet `skipFeatureDeployment: true`. Es wird im App Catalog zentral bereitgestellt und nicht in Root Web oder Unterwebs über „App hinzufügen“ installiert.
## Konfiguration
Die UserCustomAction unterstützt folgende `ClientSideComponentProperties`:
```json
{
"termSetId": "6f36a1a8-7bd8-4ed0-a22f-e219f4d2eacc",
"termSetId": "7948e6f9-7af4-431e-b6fe-328122f2746c",
"termSetName": "Global Navigation",
"cacheMinutes": 15,
"menuMode": "megaMenu",
"debug": false
}
```
| Eigenschaft | Typ | Standard | Beschreibung |
|---|---:|---:|---|
| `termSetId` | GUID | leer | Bevorzugte, eindeutige Identifikation des Termsets |
| `termSetName` | String | leer | Rückwärtskompatibler Fallback, wenn keine gültige `termSetId` vorhanden ist |
| `cacheMinutes` | Zahl | `15` | Gültigkeit des Session-Caches, zulässig sind 1 bis 1440 Minuten |
| `debug` | Boolean | `false` | Aktiviert zusätzliche Konsolenausgaben |
| Property | Typ | Standard | Beschreibung |
|---|---|---|---|
| `termSetId` | String | leer | GUID des Termsets; hat Vorrang vor dem Namen |
| `termSetName` | String | leer | Fallback für bestehende Konfigurationen |
| `cacheMinutes` | Number | `15` | Cachezeit von 1 bis 1440 Minuten |
| `menuMode` | String | `megaMenu` | `megaMenu` oder `flyout` |
| `debug` | Boolean | `false` | ausführliche Browser-Konsolenausgaben |
`termSetId` hat Vorrang vor `termSetName`. Für neue Installationen wird die GUID empfohlen, weil Termset-Namen nicht zwingend eindeutig sind.
### Mega Menu
### Kompatibilität mit PortalSettings
`"menuMode": "megaMenu"` zeigt die zweite Ebene als breites, spaltenbasiertes Panel. Die dritte Ebene wird als Linkliste unter der jeweiligen Kategorie dargestellt.
PortalSettings verwaltet `termSetId`, `termSetName`, `cacheMinutes` und `debug`. Individuelle Gestaltung wird nicht vom MegaMenu selbst geladen, sondern zentral über die Solution Custom Branding bereitgestellt.
### Flyout
## Termset-Aufbau
Die Darstellung unterstützt drei Ebenen:
```text
Ebene 1: Hauptnavigation
├── Ebene 2: Kategorie
│ ├── Ebene 3: Link
│ └── Ebene 3: Link
└── Ebene 2: Kategorie
```
Für Zieladressen werden die lokalen benutzerdefinierten Eigenschaften des Terms ausgewertet:
1. `_Sys_Nav_SimpleLinkUrl`
2. `_Sys_Nav_TargetUrl`
Optional kann `_Sys_Nav_HoverText` als ergänzender Hilfetext verwendet werden. Veraltete Terms werden nicht angezeigt. Terms, die nicht für Tagging verfügbar sind, bleiben für Navigationsszenarien sichtbar.
`"menuMode": "flyout"` zeigt die zweite Ebene als kompaktes Dropdown. Die dritte Ebene öffnet sich seitlich als strukturelles Flyout.
## Build
SPFx 1.4.1 verwendet die Legacy-Gulp-Toolchain. Neuere Node-Versionen sind nicht kompatibel.
```powershell
npm install
npm run package
```
Alternativ einzeln:
`npm run package` erstellt automatisch beide Ausgaben:
- das SPFx-Paket für moderne Seiten
- das Classic-Paket unter `classic/dist/`
Nur die Classic-Dateien neu erzeugen:
```powershell
gulp clean
gulp bundle --ship
gulp package-solution --ship
npm run build:classic
```
Das fertige Paket befindet sich anschließend unter:
Erwartete Umgebung:
```text
Node.js 8.17.0
npm 6.x
lokales Gulp 3.9.1
```
Das Ergebnis liegt unter:
```text
sharepoint/solution/mega-menu.sppkg
```
## Deployment
## Moderne Bereitstellung
1. `mega-menu.sppkg` in den App Catalog laden.
2. Die Solution freigeben.
3. Die App im Root Web der gewünschten Site Collection installieren. Der MegaMenu Application Customizer wird dort zunächst web-scoped registriert und von PortalSettings erkannt.
4. Das Termset in PortalSettings konfigurieren.
1. `mega-menu.sppkg` in den Farm App Catalog hochladen beziehungsweise ersetzen.
2. Die Lösung zentral für alle Sites verfügbar machen.
3. MegaMenu nicht über „App hinzufügen“ in Inhaltswebsites installieren.
4. Pro gewünschter Site Collection eine Site-Collection-Action anlegen.
Das folgende Skript ist nur erforderlich, wenn PortalSettings nicht verwendet wird oder eine vollständig skriptbasierte Vorkonfiguration gewünscht ist.
Empfohlen mit Termset-GUID:
Beispiel für das Mega Menu:
```powershell
.\deployment\add-megamenu.ps1 `
-SiteUrl 'https://sharepoint/sites/portal' `
-TermSetId '6f36a1a8-7bd8-4ed0-a22f-e219f4d2eacc' `
-SiteUrl 'http://clshp001/sites/target' `
-TermSetId '7948e6f9-7af4-431e-b6fe-328122f2746c' `
-TermSetName 'Global Navigation' `
-CacheMinutes 15
-CacheMinutes 15 `
-MenuMode megaMenu
```
Abwärtskompatibel nur mit Namen:
Beispiel für das Flyout:
```powershell
.\deployment\add-megamenu.ps1 `
-SiteUrl 'https://sharepoint/sites/portal' `
-TermSetName 'Global Navigation'
-SiteUrl 'http://clshp001/sites/target' `
-TermSetId '7948e6f9-7af4-431e-b6fe-328122f2746c' `
-MenuMode flyout `
-EnableDebug
```
Das Skript speichert die Konfiguration zentral unter `PortalSettings.MegaMenu.Configuration`, entfernt alte beziehungsweise doppelte Component IDs und synchronisiert die neue web-scoped Runtime-Bindung idempotent auf alle vorhandenen Webs. Fuer spaeter angelegte Unterwebs kann es ohne Nebenwirkungen erneut ausgefuehrt werden.
Das Skript entfernt alte Web- und Site-Registrierungen, bereinigt die frühere Property-Bag-Konfiguration und erstellt genau eine neue Site-Collection-Action.
## Individuelles Branding
## Classic Pages
Zusätzliche Stylesheets werden zentral über die Solution Custom Branding eingebunden. Das MegaMenu besitzt bewusst keine eigene `cssUrl`-Property.
Die Classic-Variante bleibt erhalten, weil ein SPFx Application Customizer nur in der modernen Oberfläche ausgeführt wird.
Die wichtigsten CSS-Klassen sind:
Das Classic-Paket wird bei `npm run build` und `npm run package` automatisch erzeugt. Es kann bei Bedarf auch separat gebaut werden:
```css
#CustomNavigation { }
#Mega-Menu { }
.mega-menu-top-level { }
.mega-menu-top-item { }
.mega-menu { }
.mega-menu-grid { }
.mega-menu-category { }
.mega-menu-links { }
```powershell
npm run build:classic
```
Viele Farben und Abstände können über CSS Custom Properties überschrieben werden, beispielsweise:
Ausgabe:
```text
classic/dist/
├── megamenu-classic.css
├── megamenu-services-standalone.js
├── megamenu-classic.js
└── classic-deployment.md
```
Die Classic-Runtime liest dieselben `ClientSideComponentProperties` der zentralen Site-Collection-Action und unterstützt ebenfalls beide Menümodi. Die Installationsdetails stehen in [classic/classic-deployment.md](classic/classic-deployment.md).
## Styling
Das moderne Styling liegt in:
```text
src/extensions/megaMenu/MegaMenu.module.scss
```
SPFx kompiliert diese Datei in das Bundle-CSS. Die eigenständige Classic-CSS liegt unter:
```text
classic/megamenu-classic.css
```
Beide Varianten orientieren sich an SharePoint mit Segoe UI, neutralen Flächen, Theme-Farbe für den aktiven Pfad, kompakten Abständen und Fabric-kompatiblen Fokusmarkierungen.
Die wichtigsten CSS-Variablen können durch Custom Branding überschrieben werden:
```css
:root {
--megaMenuNavBackground: #5f6f74;
--megaMenuNavTextColor: #ffffff;
--megaMenuPanelWidth: 1280px;
--megaMenuBarHeight: 44px;
--megaMenuContentWidth: 1200px;
--megaMenuFlyoutWidth: 288px;
--megaMenuZIndex: 6000;
}
```
## Cache
Das MegaMenu lädt bewusst keine externe `cssUrl`-Property. Kundenspezifische Gestaltung gehört in die Solution Custom Branding.
Das geladene Termset wird im `sessionStorage` des Browsers gespeichert. Der Schlüssel ist mit `MegaMenu:TermSet:` namensräumlich getrennt. Nach Ablauf von `cacheMinutes` wird das Termset automatisch neu geladen.
## Diagnose
Für einen sofortigen administrativen Test kann der Session-Cache in den Browser-Entwicklertools gelöscht oder ein neues privates Browserfenster verwendet werden.
Mit `"debug": true` schreibt die moderne Extension Meldungen mit diesen Quellen:
## Barrierefreiheit
```text
[MegaMenuApplicationCustomizer]
[TaxonomyNavigationService]
[SPTermStorePickerService]
[MegaMenuRenderer]
```
- semantisches `<nav aria-label="Hauptnavigation">`
- native Listen- und Linksemantik
- `aria-expanded` und `aria-haspopup` für aufklappbare Einträge
- `aria-current="page"` für den aktuellen Navigationspfad
- Öffnen über Leertaste oder Pfeil nach unten
- Schließen über Escape
- sichtbare Fokusindikatoren
- Unterstützung von `prefers-reduced-motion` und kontrastreichen Darstellungen
Geladenes Bundle prüfen:
Bewusst wird kein `role="menubar"` verwendet: Eine Portalnavigation ist eine normale Navigation und kein Desktop-Menü-Widget. Dadurch bleiben native Browser- und Screenreader-Erwartungen erhalten.
```javascript
performance.getEntriesByType('resource')
.map(function (entry) { return entry.name; })
.filter(function (url) { return url.toLowerCase().indexOf('mega-menu') >= 0; });
```
## Fehlerdiagnose
Aktiven Modus prüfen:
### „Die Navigation ist nicht konfiguriert“
Weder eine gültige `termSetId` noch ein `termSetName` ist gesetzt. UserCustomAction beziehungsweise PortalSettings-Konfiguration prüfen.
### „Die Navigation konnte nicht geladen werden“
- Existiert das Termset im Standard-Term-Store der Site Collection?
- Ist die GUID korrekt?
- Haben Benutzer Zugriff auf den Managed-Metadata-Service?
- Enthält das Termset mindestens einen sichtbaren Term?
- Ist der App-Catalog-Eintrag aktuell?
Für weitere technische Details kann vorübergehend `debug: true` gesetzt werden.
Bei aktiviertem Debug-Modus protokolliert MegaMenu den kompletten Startpfad mit den Quellen
`MegaMenuApplicationCustomizer`, `TaxonomyNavigationService`, `SPTermStorePickerService` und
`MegaMenuRenderer`. Dazu gehören die übergebenen Properties, Placeholder-Erkennung,
Taxonomy-Anfrage, Cache-Nutzung, Term-Anzahl, Containerwahl und vollständige Fehlerdetails.
Wenn keine dieser Meldungen erscheint, wurde das MegaMenu-Bundle nicht durch den SPFx-Loader
ausgeführt.
### Änderungen am Termset erscheinen verzögert
Die Navigation wird bis zu `cacheMinutes` im Session-Cache gehalten. Cache leeren oder Ablaufzeit abwarten.
### Zusätzliches CSS wird nicht geladen
- URL und Dateiberechtigungen prüfen.
- Für externe Quellen HTTPS verwenden.
- Browser-Konsole bei aktiviertem Debug-Modus prüfen.
## Upgrade von 1.0.x
- Bestehende `termSetName`-Konfigurationen funktionieren unverändert.
- Der alte unversionierte Session-Cache wird nicht weiterverwendet.
- `cacheMinutes` verwendet ohne Konfiguration den Wert 15.
- Die eigene, nicht verwendete MegaMenu-Einstellungsseite wurde entfernt; PortalSettings ist der zentrale Konfigurationsweg.
- Globale Event Listener werden beim Dispose der Extension entfernt.
- Paket-, npm- und Dokumentationsversion wurden auf 1.1.0 vereinheitlicht.
## Classic Pages
Unter `classic/` befindet sich eine separate Kompatibilitätsimplementierung für klassische SharePoint-Seiten. Sie wird nicht vom SPFx-Bundle ausgeführt und besitzt einen eigenen Deploymentweg. Neue Funktionen sollten zuerst in der modernen SPFx-Variante umgesetzt und anschließend bewusst in die Classic-Variante übernommen werden.
```javascript
document.getElementById('Mega-Menu').getAttribute('data-menu-mode');
```
## Projektstruktur
```text
MegaMenu/
├── config/ SPFx-Build- und Paketkonfiguration
├── deployment/ Farm-/Site-Registrierung
├── src/
├── extensions/megaMenu/ Application Customizer und Renderer
│ └── services/ Taxonomy- und Datenmodelle
├── classic/ optionale Classic-Kompatibilität
├── build-classic.ps1 Classic-Build
├── classic/ Classic-Runtime und CSS
├── config/ SPFx-Buildkonfiguration
├── deployment/add-megamenu.ps1 zentrale Site-Registrierung
├── src/extensions/megaMenu/ Application Customizer, Renderer und SCSS
├── src/services/ Taxonomy- und Navigationsdienste
├── build-classic.ps1
├── gulpfile.js
└── package.json
```
## Versionshistorie
### 2.1.0
- SharePoint-ähnliches, helles Navigationsdesign.
- Neue Property `menuMode` mit `megaMenu` und `flyout`.
- Eigenständiges Flyout-Rendering für zweite und dritte Ebene.
- Classic-Runtime und Classic-CSS auf beide Modi aktualisiert.
- Konfiguration auf eine Site-Collection-Action konsolidiert.
- Veraltete `elements.xml`, Azure-CDN-Konfiguration, Mock- und UserCustomAction-Service-Dateien entfernt.
- Bereitstellungs- und Classic-Buildskripte vereinfacht.
### 2.0.1
- Zentrale SPFx-Bereitstellung mit `skipFeatureDeployment: true`.
- Das MegaMenu-Paket muss nicht mehr als App in jedem Unterweb installiert werden.
- Feature-Framework-Registrierung aus dem Paket entfernt; die Aktivierung erfolgt zentral über PortalSettings oder das Deploymentskript.
- Keine App-Installation in einzelnen Inhaltswebsites erforderlich.
### 2.0.0
- Neue Application-Customizer-ID `c0abbffb-355d-4d4e-bd38-9e15fb811506`, um alte On-Premises-Manifest- und Loader-Zuordnungen sicher zu umgehen.
- Eine zentrale MegaMenu-Konfiguration pro Site Collection im Property Bag des Root Webs.
- Web-scoped Runtime-Bindungen werden auf Root Web und alle vorhandenen Unterwebs synchronisiert.
- Aktivierungsskript entfernt alte Component IDs und kann fuer neue Unterwebs idempotent erneut ausgefuehrt werden.
### 1.1.4
- Unnötige externe Abhängigkeit zu `@microsoft/sp-lodash-subset` entfernt.
- Terms werden beim Sortieren über eine lokale, SPFx-1.4.1-kompatible Pfadsuche zugeordnet.
- Verhindert, dass der Application Customizer bereits bei der Systemkomponenten-Auflösung übersprungen wird.
### 1.1.3
- Ausführliches, ausschließlich über `debug: true` aktiviertes Lifecycle-Logging ergänzt.
- Taxonomy-Anfragen, Session-Cache, Term-Filterung und Renderer werden nachvollziehbar protokolliert.
- Fehlerausgaben enthalten Name, Meldung und Stacktrace.
### 1.1.2
- `cssUrl` zugunsten der zentralen Custom-Branding-Solution entfernt
- deaktivierte, veraltete oder nicht zum Tagging verfügbare Terms werden ausgeblendet
- Cache-Namespace aktualisiert, damit alte deaktivierte Einträge nicht weiter angezeigt werden
### 1.1.1
- automatische Registrierung des MegaMenu Application Customizers bei der App-Installation
- direkte Erkennung durch PortalSettings ohne vorherigen Skriptaufruf
### 1.1.0
- konsistente Verwendung des Default Site Collection Term Store
- optionale Konfiguration per Termset-GUID
- Cache-TTL und namensräumlich getrennter Session-Cache
- korrekte Anwendung der Deprecated-/Availability-Filter
- Prüfung der Taxonomy-HTTP-Antworten
- Lifecycle-Cleanup für globale Event Listener
- korrigierte Navigationssemantik und aktive Screenreader-Statusmeldungen
- Validierung externer CSS-URLs
- sichtbare Konfigurations- und Ladefehler
- Entfernung des ungenutzten lokalen Settings-Panels
- vereinheitlichte Projektversion und neue Build-/Deployment-Dokumentation
- Neue Application-Customizer-ID `c0abbffb-355d-4d4e-bd38-9e15fb811506`.
- Alte On-Premises-Manifest- und Loader-Zuordnungen umgangen.