# CustomBranding CustomBranding 3.0.2 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`. 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. ## 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 Das aktuelle Konfigurationsschema hat die Version 2: ```json { "schemaVersion": 2, "portalSettings": { "providerKey": "custombranding", "contractVersion": 1, "minimumPortalSettingsVersion": "3.0.0" }, "enabled": true, "debug": false, "allowedCssHosts": [], "cssfiles": [ { "path": "~sitecollection/SiteAssets/branding/custom-branding.css", "media": "all" } ], "placeholdertop": { "elements": [ { "type": "section", "attributes": { "class": "custom-branding-banner", "role": "region", "aria-label": "Portalhinweis" }, "children": [ { "type": "strong", "content": "Willkommen im Portal" } ] } ] }, "placeholderbottom": { "elements": [] } } ``` 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`. Ist `placeholderbottom.elements` leer oder fehlt die Eigenschaft, rendert CustomBranding automatisch den bisherigen **Portal Settings**-Link auf `~sitecollection/SitePages/PortalSettings.aspx`. Sobald eigene Footer-Elemente konfiguriert sind, ersetzen sie diesen Standard. ### 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 run build:classic ``` Danach `classic/dist/custom-branding-classic.js` nach beispielsweise `/SiteAssets/custom-branding/` hochladen und zentral registrieren: ```powershell .\deployment\add-custombranding.ps1 ` -SiteUrl 'http://clshp001/sites/portal' ` -ClassicScriptUrl '~sitecollection/SiteAssets/custom-branding/custom-branding-classic.js' ``` 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`. ## PortalSettings v3 CustomBranding funktioniert unabhängig von PortalSettings. PortalSettings ab Version 3.0.1 kann die zentrale Action anhand folgender Werte erkennen, die Properties schemaerhaltend bearbeiten und eine noch fehlende Action beim ersten Speichern selbst anlegen: - Component ID: `035ba968-6488-4d42-86b3-0470ffcc95b9` - Location: `ClientSideExtension.ApplicationCustomizer` - Scope: `SPSite.UserCustomActions` - Schema: `schemaVersion: 2` - Provider-Marker: `portalSettings.providerKey: custombranding` Ist noch keine Action vorhanden, erscheint CustomBranding in PortalSettings als **Bereit zur Aktivierung**. Voraussetzung ist lediglich, dass `custom-branding.sppkg` bereits im App Catalog bereitgestellt wurde. Der Button **CustomBranding aktivieren** erzeugt anschließend genau eine site-scoped Action. Das PowerShell-Skript bleibt für automatisierte Rollouts und Classic-ScriptLink-Registrierungen verfügbar. 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.1.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.