diff --git a/README.md b/README.md index 0f2e511..fae1439 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # CurrentNavigation -CurrentNavigation 1.1.0 ist ein SPFx-1.4.1-Application-Customizer für moderne Seiten in SharePoint Server -Subscription Edition. Die Solution ersetzt die Einträge im modernen SiteNavigation-Bereich durch einen Treeview -für das aktuelle Web. Beim Entladen der Extension wird die ursprüngliche SharePoint-Navigation wieder sichtbar. +CurrentNavigation 1.1.2 ist ein SPFx-1.4.1-Application-Customizer für moderne Seiten in SharePoint Server +Subscription Edition. Die Solution ergänzt unterhalb der vorhandenen Einträge im modernen SiteNavigation-Bereich +einen Treeview für das aktuelle Web. Native Einträge wie Documents bleiben unverändert sichtbar. ## Term-Konfiguration @@ -18,8 +18,12 @@ Kinder bilden die erste Navigationsebene. Der Treeview unterstützt auf- und zuklappbare Zweige, aktive Seitenpfade sowie die Navigation mit den Pfeiltasten, Pos1 und Ende. -Wenn kein passender Root-Term gefunden wird oder das Termset nicht geladen werden kann, bleibt die native -SharePoint-Sitenavigation unverändert sichtbar. +Wenn kein passender Root-Term gefunden wird oder das Termset nicht geladen werden kann, bleibt ausschließlich die +native SharePoint-Sitenavigation sichtbar. + +Für moderne Teamwebsites wird unter anderem das stabile Fabric-Muster +nav[role="navigation"].ms-Nav mit enthaltener ms-Nav-navItems-Liste erkannt. Dynamisch erzeugte Klassen wie root-70 +werden nicht verwendet. ## Build und Bereitstellung diff --git a/ToDo.md b/ToDo.md index b32d7c5..d319e3d 100644 --- a/ToDo.md +++ b/ToDo.md @@ -1,10 +1,10 @@ # CurrentNavigation – Umsetzungsstand -Zielversion: 1.1.0 +Zielversion: 1.1.2 Status: Implementierung und lokale Tests abgeschlossen; Ship-Build auf Node 8 ausstehend - [x] SPFx Application Customizer für moderne Seiten -- [x] Rendering im modernen SiteNavigation-Container statt im Top-Placeholder +- [x] Ergänzendes Rendering unterhalb der nativen Einträge im modernen SiteNavigation-Container - [x] Barrierearmer Treeview mit Tastatursteuerung - [x] Site-Collection-weite Registrierung - [x] Termset-Picker über PortalSettings diff --git a/config/package-solution.json b/config/package-solution.json index 9ecda25..976a44d 100644 --- a/config/package-solution.json +++ b/config/package-solution.json @@ -3,7 +3,7 @@ "solution": { "name": "current-navigation-client-side-solution", "id": "bb8f9af5-b318-4111-8401-ce189cfe1b1a", - "version": "1.1.0.0", + "version": "1.1.2.0", "includeClientSideAssets": true, "skipFeatureDeployment": true }, diff --git a/package-lock.json b/package-lock.json index 0c132d5..fcb62f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "current-navigation", - "version": "1.1.0", + "version": "1.1.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2879aa0..443093e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "current-navigation", - "version": "1.1.0", + "version": "1.1.2", "private": true, "main": "lib/index.js", "engines": { diff --git a/src/extensions/currentNavigation/CurrentNavigation.module.scss b/src/extensions/currentNavigation/CurrentNavigation.module.scss index 27ad0a6..f6278bc 100644 --- a/src/extensions/currentNavigation/CurrentNavigation.module.scss +++ b/src/extensions/currentNavigation/CurrentNavigation.module.scss @@ -1,12 +1,9 @@ @import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss'; :global { - .current-navigation-managed > :not(#CurrentNavigationHost) { - display: none !important; - } - #CurrentNavigationHost { width: 100%; + border-top: 1px solid $ms-color-neutralLight; } .current-navigation { diff --git a/src/extensions/currentNavigation/CurrentNavigationApplicationCustomizer.ts b/src/extensions/currentNavigation/CurrentNavigationApplicationCustomizer.ts index 22df32d..a56ae11 100644 --- a/src/extensions/currentNavigation/CurrentNavigationApplicationCustomizer.ts +++ b/src/extensions/currentNavigation/CurrentNavigationApplicationCustomizer.ts @@ -73,6 +73,7 @@ export default class CurrentNavigationApplicationCustomizer const selectors: string[] = [ '[data-automationid="SiteNavigation"]', '[data-automation-id="SiteNavigation"]', + 'nav[role="navigation"].ms-Nav', '#spLeftNav', 'nav[aria-label="Site navigation"]', 'nav[aria-label="Websitenavigation"]' @@ -81,6 +82,8 @@ export default class CurrentNavigationApplicationCustomizer const candidates: NodeListOf = document.querySelectorAll(selectors[i]); for (let j: number = 0; j < candidates.length; j++) { const candidate: HTMLElement = candidates[j] as HTMLElement; + if (selectors[i] === 'nav[role="navigation"].ms-Nav' && + !candidate.querySelector('.ms-Nav-navItems')) { continue; } if (candidate.id !== 'CurrentNavigationHost' && !this.hostContains(candidate)) { return candidate; } } } @@ -94,7 +97,6 @@ export default class CurrentNavigationApplicationCustomizer private async renderNavigation(): Promise { const version: number = ++this.renderVersion; if (!this.host) { return; } - if (this.siteNavigation) { this.siteNavigation.classList.remove('current-navigation-managed'); } this.renderer.clear(this.host); const termSetId: string = this.properties && this.properties.termSetId ? String(this.properties.termSetId).trim() : ''; @@ -117,7 +119,6 @@ export default class CurrentNavigationApplicationCustomizer this.languageLcid(), this.maxDepth(), !!(this.properties && this.properties.showRoot) ); if (items.length && this.host) { - if (this.siteNavigation) { this.siteNavigation.classList.add('current-navigation-managed'); } this.renderer.render(this.host, items, { navigationLabel: strings.NavigationLabel, expand: strings.Expand, @@ -155,7 +156,6 @@ export default class CurrentNavigationApplicationCustomizer this.renderer.clear(this.host); if (this.host.parentElement) { this.host.parentElement.removeChild(this.host); } } - if (this.siteNavigation) { this.siteNavigation.classList.remove('current-navigation-managed'); } this.host = undefined; this.siteNavigation = undefined; } diff --git a/tests/validate-static-assets.js b/tests/validate-static-assets.js index e331039..ae75824 100644 --- a/tests/validate-static-assets.js +++ b/tests/validate-static-assets.js @@ -9,16 +9,18 @@ var manifest = json('src/extensions/currentNavigation/CurrentNavigationApplicati var app = read('src/extensions/currentNavigation/CurrentNavigationApplicationCustomizer.ts'); var renderer = read('src/extensions/currentNavigation/CurrentNavigationRenderer.ts'); var service = read('src/services/CurrentNavigationTaxonomyService.ts'); -assert('package version', packageJson.version === '1.1.0'); -assert('solution version', solution.version === '1.1.0.0'); +assert('package version', packageJson.version === '1.1.2'); +assert('solution version', solution.version === '1.1.2.0'); assert('tenant deployment', solution.skipFeatureDeployment === true); assert('component type', manifest.extensionType === 'ApplicationCustomizer'); assert('safe renderer', renderer.indexOf('innerHTML') < 0 && app.indexOf('innerHTML') < 0); assert('does not use Top placeholder', app.indexOf('PlaceholderName.Top') < 0); assert('targets modern SiteNavigation', app.indexOf('data-automationid="SiteNavigation"') >= 0); -assert('restores native navigation', app.indexOf("classList.remove('current-navigation-managed')") >= 0); -assert('native navigation is only replaced after successful load', - app.indexOf("classList.add('current-navigation-managed')") > app.indexOf('if (items.length')); +assert('targets SharePoint ms-Nav fallback', app.indexOf('nav[role="navigation"].ms-Nav') >= 0 && + app.indexOf("querySelector('.ms-Nav-navItems')") >= 0); +assert('native navigation is not hidden', app.indexOf('current-navigation-managed') < 0 && + read('src/extensions/currentNavigation/CurrentNavigation.module.scss').indexOf(':not(#CurrentNavigationHost)') < 0); +assert('custom navigation is appended below SiteNavigation', app.indexOf('this.siteNavigation.appendChild(this.host)') >= 0); assert('observer cleanup', app.indexOf('observer.disconnect()') >= 0); assert('treeview semantics', renderer.indexOf("setAttribute('role', root ? 'tree' : 'group')") >= 0 && renderer.indexOf("setAttribute('role', 'treeitem')") >= 0);