feat: Add custom branding functionality with CSS and JSON configuration

- Introduced custom branding CSS styles in `custom-branding.css`.
- Created example JSON configuration for custom branding in `custom-branding.example.json`.
- Implemented branding configuration logic in `BrandingConfig.ts` to normalize and validate branding settings.
- Developed CSS loader to manage loading and unloading of custom stylesheets in `BrandingCssLoader.ts`.
- Added DOM rendering capabilities for branding elements in `BrandingDomRenderer.ts`.
- Defined types and interfaces for branding elements and configurations in `BrandingTypes.ts`.
- Included localization support for German in `de-de.js`.
- Added unit tests for branding configuration, CSS loader, and DOM renderer.
- Validated project structure and static assets with new validation scripts.
This commit is contained in:
Torsten Brendgen
2026-07-20 22:55:47 +02:00
parent b99ac31f4d
commit 490e9adbd8
29 changed files with 1809 additions and 588 deletions

196
README.md
View File

@@ -1,20 +1,110 @@
# Custom Branding
# CustomBranding
Custom Branding ist ein SPFx-1.4.1-Application-Customizer fuer SharePoint Server Subscription Edition. Die Solution laedt zentral konfigurierte Stylesheets und kann strukturierte Inhalte in den oberen und unteren SharePoint-Placeholder rendern.
CustomBranding 3.0 ist ein zentraler SPFx-1.4.1-Application-Customizer für SharePoint Server Subscription Edition. Die Solution lädt freigegebene Stylesheets und rendert eine kontrollierte Komponentenstruktur im oberen oder unteren SharePoint-Placeholder. Moderne und klassische Seiten verwenden dieselben `ClientSideComponentProperties`.
## Version
Die Konfiguration liegt in genau einer `SPSite.UserCustomAction` pro Site Collection. Es werden weder eine versteckte Liste noch ein Property Bag benötigt. Dadurch gilt das Branding automatisch für das Root Web, vorhandene Subwebs und später angelegte Subwebs.
`1.0.4.0`
## Architektur
```text
App Catalog
└── zentral bereitgestelltes SPFx-Bundle
Site Collection
├── SPSite.UserCustomAction mit ClientSideComponentProperties
├── moderne Seiten: SPFx Application Customizer
└── klassische Seiten: optionaler SPSite ScriptLink
CustomHeader
├── CustomBrandingTopHost
└── MegaMenuHost (wird nicht verändert)
CustomFooter
└── CustomBrandingBottomHost
```
CustomBranding verändert nur seine eigenen Host-Elemente. Das MegaMenu und andere Erweiterungen im selben Placeholder bleiben bei Navigation und erneutem Rendern erhalten.
## Voraussetzungen und Build
- SharePoint Server Subscription Edition
- SPFx 1.4.1
- Node.js 8.17.0
- npm 6.13.4
- lokale Gulp-Version 3.9.1
```powershell
npm install
npm test
npm run package
```
`npm run package` führt zuerst die Tests und den Classic-Build aus. Das SharePoint-Paket entsteht unter `sharepoint/solution/custom-branding.sppkg`. Die Classic-Dateien liegen anschließend unter `classic/dist`.
Die alte SPFx-Toolchain lässt sich mit aktuellen Node-Versionen nicht zuverlässig paketieren. Der abschließende Ship-Build muss deshalb mit Node.js 8.17.0 erfolgen.
## Installation und zentrale Registrierung
1. `custom-branding.sppkg` im App Catalog hochladen oder ersetzen und zentral bereitstellen.
2. Das Skript in der SharePoint Management Shell ausführen.
3. Eine moderne Seite mit `Strg+F5` neu laden.
```powershell
.\deployment\add-custombranding.ps1 `
-SiteUrl 'http://clshp001/sites/portal' `
-CssPath '~sitecollection/SiteAssets/branding/custom-branding.css'
```
Das Skript arbeitet idempotent: Es erhält vorhandene Properties, entfernt doppelte oder alte web-scoped Registrierungen und erzeugt genau eine site-scoped Action. Ein bewusstes Zurücksetzen erfolgt nur mit `-ResetConfiguration`.
Weitere Optionen:
```powershell
# Debug-Ausgaben einschalten und einen externen HTTPS-CSS-Host freigeben
.\deployment\add-custombranding.ps1 `
-SiteUrl 'http://clshp001/sites/portal' `
-EnableDebug `
-AllowedCssHost 'cdn.example.org'
# Extension deaktivieren, Konfiguration aber erhalten
.\deployment\add-custombranding.ps1 `
-SiteUrl 'http://clshp001/sites/portal' `
-Disable
```
## Konfiguration
Die Konfiguration wird in den `ClientSideComponentProperties` der aktiven UserCustomAction gespeichert und zentral ueber PortalSettings gepflegt:
Das aktuelle Konfigurationsschema hat die Version 2:
```json
{
"cssfiles": [],
"schemaVersion": 2,
"enabled": true,
"debug": false,
"allowedCssHosts": [],
"cssfiles": [
{
"path": "~sitecollection/SiteAssets/branding/custom-branding.css",
"media": "all"
}
],
"placeholdertop": {
"elements": []
"elements": [
{
"type": "section",
"attributes": {
"class": "custom-branding-banner",
"role": "region",
"aria-label": "Portalhinweis"
},
"children": [
{
"type": "strong",
"content": "Willkommen im Portal"
}
]
}
]
},
"placeholderbottom": {
"elements": []
@@ -22,22 +112,92 @@ Die Konfiguration wird in den `ClientSideComponentProperties` der aktiven UserCu
}
```
## Build
Bestehende 1.x-Konfigurationen mit einem Root-Array `elements` werden weiterhin als Top-Inhalt gelesen. Unbekannte Properties ignoriert die Runtime. Das vollständige Beispiel liegt unter `examples/custom-branding.example.json`.
Die Legacy-SPFx-Toolchain benoetigt Node.js 8.17.0:
### Sicherheitsgrenzen
Erlaubte Elemente:
`div`, `span`, `p`, `a`, `button`, `img`, `h1`, `h2`, `h3`, `strong`, `em`, `nav`, `section`
Attribute und Styles werden pro Element über feste Allowlisten geprüft. Insbesondere gelten folgende Regeln:
- `script`, `iframe`, alle `on*`-Attribute, `javascript:`, `data:` und CSS mit `url()` oder `expression()` werden verworfen.
- Bilder benötigen immer ein `alt`; dekorative Bilder verwenden `alt: ""`.
- Leere Links und Buttons sind nicht erlaubt; Buttons erhalten immer `type="button"`.
- Links mit `target="_blank"` erhalten automatisch `rel="noopener noreferrer"`.
- Relative CSS-Pfade und CSS derselben Origin sind erlaubt. Fremde Quellen benötigen HTTPS und einen Eintrag in `allowedCssHosts`.
- Maximal 20 Stylesheets, 200 Elemente, acht Ebenen und 100.000 Zeichen Konfiguration werden verarbeitet.
Unsichere Teilwerte werden kontrolliert verworfen, ohne die SharePoint-Seite zu blockieren. Details erscheinen nur bei `debug: true` in der Browserkonsole mit dem Präfix `[CustomBranding]`.
## Classic SharePoint
Der SPFx Application Customizer selbst läuft nicht auf klassischen Seiten. Version 3.0 enthält deshalb eine separate ES5-Runtime mit demselben Sicherheits- und Konfigurationsmodell.
```powershell
npm install
npm run package
npm run build:classic
```
Das Paket wird unter `sharepoint/solution/custom-branding.sppkg` erzeugt.
Danach `classic/dist/custom-branding-classic.js` nach beispielsweise `/SiteAssets/custom-branding/` hochladen und zentral registrieren:
## Installation
```powershell
.\deployment\add-custombranding.ps1 `
-SiteUrl 'http://clshp001/sites/portal' `
-ClassicScriptUrl '~sitecollection/SiteAssets/custom-branding/custom-branding-classic.js'
```
1. `custom-branding.sppkg` in den App Catalog laden beziehungsweise ersetzen.
2. Die App im Root Web der Site Collection installieren oder aktualisieren.
3. Beim Aktivieren wird der Custom Branding Application Customizer automatisch web-scoped registriert.
4. PortalSettings mit `Strg+F5` neu laden und den Tab **Custom Branding** konfigurieren.
Der site-scoped ScriptLink gilt auch für später angelegte Subwebs. Entfernen lässt er sich mit `-RemoveClassicScriptLink`. Weitere Hinweise stehen in `classic/classic-deployment.md`.
Das Skript `deployment/add-custombranding.ps1` bleibt fuer automatisierte Rollouts oder eine ausdruecklich site-scoped Registrierung verfuegbar.
## PortalSettings v3
CustomBranding funktioniert unabhängig von PortalSettings. Das geplante PortalSettings-v3-Webpart kann die Action anhand folgender Werte erkennen und die Properties schemaerhaltend bearbeiten:
- Component ID: `035ba968-6488-4d42-86b3-0470ffcc95b9`
- Location: `ClientSideExtension.ApplicationCustomizer`
- Scope: `SPSite.UserCustomActions`
- Schema: `schemaVersion: 2`
Ein Editor muss unbekannte Properties erhalten und vor dem Speichern dieselben Element-, Attribut-, URL- und CSS-Grenzen beachten.
## Diagnose
Zentrale Registrierung prüfen:
```powershell
$site = Get-SPSite 'http://clshp001/sites/portal'
$site.UserCustomActions | Where-Object {
$_.ClientSideComponentId -eq [Guid]'035ba968-6488-4d42-86b3-0470ffcc95b9'
} | Select-Object Id, Title, Location, ClientSideComponentProperties
$site.Dispose()
```
Browserkonsole auf einer modernen Seite:
```javascript
performance.getEntriesByType('resource')
.map(function (entry) { return entry.name; })
.filter(function (url) { return url.toLowerCase().indexOf('custom-branding') >= 0; });
({
header: !!document.getElementById('CustomHeader'),
branding: !!document.getElementById('CustomBrandingTopHost'),
megaMenu: !!document.getElementById('MegaMenuHost')
});
```
Classic-Diagnose:
```javascript
typeof window.CustomBrandingClassic
window.CustomBrandingClassic.reload()
```
## Upgrade von 1.x
1. Paket im App Catalog durch Version `3.0.0.0` ersetzen und bereitstellen.
2. `add-custombranding.ps1` einmal pro Site Collection ausführen; bestehende Properties bleiben erhalten.
3. Moderne und gegebenenfalls klassische Seiten testen.
4. Erst nach erfolgreicher Abnahme alte web-scoped Aktionen als bereinigt bestätigen.
Ein Downgrade sollte nur zusammen mit einer Sicherung der `ClientSideComponentProperties` erfolgen.