# CustomBranding 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`. 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, "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`. ### 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. 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.