Update Current Navigation to version 1.1.5 with new features and configurable initial expansion
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# CurrentNavigation
|
# CurrentNavigation
|
||||||
|
|
||||||
CurrentNavigation 1.1.4 ist ein SPFx-1.4.1-Application-Customizer für moderne Seiten in SharePoint Server
|
CurrentNavigation 1.1.5 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
|
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.
|
einen Treeview für das aktuelle Web. Native Einträge wie Documents bleiben unverändert sichtbar.
|
||||||
|
|
||||||
@@ -21,6 +21,9 @@ einen Term und seinen Unterbaum aus.
|
|||||||
Der Treeview unterstützt auf- und zuklappbare Zweige, aktive Seitenpfade sowie die Navigation mit den Pfeiltasten,
|
Der Treeview unterstützt auf- und zuklappbare Zweige, aktive Seitenpfade sowie die Navigation mit den Pfeiltasten,
|
||||||
Pos1 und Ende.
|
Pos1 und Ende.
|
||||||
|
|
||||||
|
Der initiale Aufklappzustand ist über `initialExpansion` steuerbar: `activePath` öffnet wie bisher nur den aktiven
|
||||||
|
Pfad, `expanded` öffnet alle Zweige und `collapsed` startet mit vollständig geschlossenen Zweigen.
|
||||||
|
|
||||||
Wenn kein passender Root-Term gefunden wird oder das Termset nicht geladen werden kann, bleibt ausschließlich die
|
Wenn kein passender Root-Term gefunden wird oder das Termset nicht geladen werden kann, bleibt ausschließlich die
|
||||||
native SharePoint-Sitenavigation sichtbar.
|
native SharePoint-Sitenavigation sichtbar.
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"solution": {
|
"solution": {
|
||||||
"name": "current-navigation-client-side-solution",
|
"name": "current-navigation-client-side-solution",
|
||||||
"id": "bb8f9af5-b318-4111-8401-ce189cfe1b1a",
|
"id": "bb8f9af5-b318-4111-8401-ce189cfe1b1a",
|
||||||
"version": "1.1.4.0",
|
"version": "1.1.5.0",
|
||||||
"includeClientSideAssets": true,
|
"includeClientSideAssets": true,
|
||||||
"skipFeatureDeployment": true
|
"skipFeatureDeployment": true
|
||||||
},
|
},
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"termSetId": "00000000-0000-0000-0000-000000000000",
|
"termSetId": "00000000-0000-0000-0000-000000000000",
|
||||||
"cacheMinutes": 15, "cacheVersion": "1", "maxDepth": 3,
|
"cacheMinutes": 15, "cacheVersion": "1", "maxDepth": 3,
|
||||||
"showRoot": false, "debug": true
|
"showRoot": false, "initialExpansion": "activePath", "debug": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ param(
|
|||||||
[string]$CacheVersion = '1',
|
[string]$CacheVersion = '1',
|
||||||
[ValidateRange(1, 8)][int]$MaxDepth = 3,
|
[ValidateRange(1, 8)][int]$MaxDepth = 3,
|
||||||
[switch]$ShowRoot,
|
[switch]$ShowRoot,
|
||||||
|
[ValidateSet('activePath', 'expanded', 'collapsed')][string]$InitialExpansion = 'activePath',
|
||||||
[switch]$EnableDebug
|
[switch]$EnableDebug
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ $properties = @{
|
|||||||
cacheVersion = $(if ([string]::IsNullOrWhiteSpace($CacheVersion)) { '1' } else { $CacheVersion.Trim() })
|
cacheVersion = $(if ([string]::IsNullOrWhiteSpace($CacheVersion)) { '1' } else { $CacheVersion.Trim() })
|
||||||
maxDepth = $MaxDepth
|
maxDepth = $MaxDepth
|
||||||
showRoot = [bool]$ShowRoot.IsPresent
|
showRoot = [bool]$ShowRoot.IsPresent
|
||||||
|
initialExpansion = $InitialExpansion
|
||||||
debug = [bool]$EnableDebug.IsPresent
|
debug = [bool]$EnableDebug.IsPresent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "current-navigation",
|
"name": "current-navigation",
|
||||||
"version": "1.1.4",
|
"version": "1.1.5",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "current-navigation",
|
"name": "current-navigation",
|
||||||
"version": "1.1.4",
|
"version": "1.1.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import * as strings from 'CurrentNavigationApplicationCustomizerStrings';
|
|||||||
import { buildCurrentNavigationItems, selectCurrentNavigationRoot } from '../../services/CurrentNavigationCore';
|
import { buildCurrentNavigationItems, selectCurrentNavigationRoot } from '../../services/CurrentNavigationCore';
|
||||||
import { CurrentNavigationTaxonomyService } from '../../services/CurrentNavigationTaxonomyService';
|
import { CurrentNavigationTaxonomyService } from '../../services/CurrentNavigationTaxonomyService';
|
||||||
import { ICurrentNavigationItem, ICurrentNavigationTerm, ITermSetResult } from '../../services/CurrentNavigationTypes';
|
import { ICurrentNavigationItem, ICurrentNavigationTerm, ITermSetResult } from '../../services/CurrentNavigationTypes';
|
||||||
import { CurrentNavigationRenderer } from './CurrentNavigationRenderer';
|
import { CurrentNavigationInitialExpansion, CurrentNavigationRenderer } from './CurrentNavigationRenderer';
|
||||||
import './CurrentNavigation.module.scss';
|
import './CurrentNavigation.module.scss';
|
||||||
|
|
||||||
export interface ICurrentNavigationApplicationCustomizerProperties {
|
export interface ICurrentNavigationApplicationCustomizerProperties {
|
||||||
@@ -15,6 +15,7 @@ export interface ICurrentNavigationApplicationCustomizerProperties {
|
|||||||
cacheVersion?: string;
|
cacheVersion?: string;
|
||||||
maxDepth?: number;
|
maxDepth?: number;
|
||||||
showRoot?: boolean;
|
showRoot?: boolean;
|
||||||
|
initialExpansion?: CurrentNavigationInitialExpansion;
|
||||||
debug?: boolean;
|
debug?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +124,7 @@ export default class CurrentNavigationApplicationCustomizer
|
|||||||
navigationLabel: strings.NavigationLabel,
|
navigationLabel: strings.NavigationLabel,
|
||||||
expand: strings.Expand,
|
expand: strings.Expand,
|
||||||
collapse: strings.Collapse
|
collapse: strings.Collapse
|
||||||
});
|
}, this.initialExpansion());
|
||||||
}
|
}
|
||||||
} catch (error) { this.debug(strings.LoadError, error); }
|
} catch (error) { this.debug(strings.LoadError, error); }
|
||||||
}
|
}
|
||||||
@@ -141,6 +142,11 @@ export default class CurrentNavigationApplicationCustomizer
|
|||||||
? String(this.properties.cacheVersion).trim() : '1';
|
? String(this.properties.cacheVersion).trim() : '1';
|
||||||
return value || '1';
|
return value || '1';
|
||||||
}
|
}
|
||||||
|
private initialExpansion(): CurrentNavigationInitialExpansion {
|
||||||
|
const value: string = this.properties && this.properties.initialExpansion
|
||||||
|
? String(this.properties.initialExpansion) : 'activePath';
|
||||||
|
return value === 'expanded' || value === 'collapsed' ? value : 'activePath';
|
||||||
|
}
|
||||||
private languageLcid(): number {
|
private languageLcid(): number {
|
||||||
const legacy: any = (this.context.pageContext as any).legacyPageContext; // tslint:disable-line:no-any
|
const legacy: any = (this.context.pageContext as any).legacyPageContext; // tslint:disable-line:no-any
|
||||||
const value: number = legacy ? Number(legacy.currentLanguage) : 0;
|
const value: number = legacy ? Number(legacy.currentLanguage) : 0;
|
||||||
|
|||||||
@@ -7,19 +7,32 @@ export interface ICurrentNavigationRendererStrings {
|
|||||||
collapse: string;
|
collapse: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CurrentNavigationInitialExpansion = 'activePath' | 'expanded' | 'collapsed';
|
||||||
|
|
||||||
|
export function isInitiallyExpanded(
|
||||||
|
initialExpansion: CurrentNavigationInitialExpansion,
|
||||||
|
containsCurrentItem: boolean
|
||||||
|
): boolean {
|
||||||
|
return initialExpansion === 'expanded' ||
|
||||||
|
(initialExpansion === 'activePath' && containsCurrentItem);
|
||||||
|
}
|
||||||
|
|
||||||
export class CurrentNavigationRenderer {
|
export class CurrentNavigationRenderer {
|
||||||
private container: HTMLElement | undefined;
|
private container: HTMLElement | undefined;
|
||||||
private keydownHandler: ((event: KeyboardEvent) => void) | undefined;
|
private keydownHandler: ((event: KeyboardEvent) => void) | undefined;
|
||||||
private strings: ICurrentNavigationRendererStrings;
|
private strings: ICurrentNavigationRendererStrings;
|
||||||
|
private initialExpansion: CurrentNavigationInitialExpansion = 'activePath';
|
||||||
|
|
||||||
public render(
|
public render(
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
items: ICurrentNavigationItem[],
|
items: ICurrentNavigationItem[],
|
||||||
strings: ICurrentNavigationRendererStrings
|
strings: ICurrentNavigationRendererStrings,
|
||||||
|
initialExpansion: CurrentNavigationInitialExpansion
|
||||||
): void {
|
): void {
|
||||||
this.clear(container);
|
this.clear(container);
|
||||||
this.container = container;
|
this.container = container;
|
||||||
this.strings = strings;
|
this.strings = strings;
|
||||||
|
this.initialExpansion = initialExpansion;
|
||||||
const nav: HTMLElement = document.createElement('nav');
|
const nav: HTMLElement = document.createElement('nav');
|
||||||
nav.className = 'current-navigation';
|
nav.className = 'current-navigation';
|
||||||
nav.setAttribute('aria-label', strings.navigationLabel);
|
nav.setAttribute('aria-label', strings.navigationLabel);
|
||||||
@@ -52,7 +65,7 @@ export class CurrentNavigationRenderer {
|
|||||||
private createItem(item: ICurrentNavigationItem, depth: number): HTMLLIElement {
|
private createItem(item: ICurrentNavigationItem, depth: number): HTMLLIElement {
|
||||||
const entry: HTMLLIElement = document.createElement('li');
|
const entry: HTMLLIElement = document.createElement('li');
|
||||||
const hasChildren: boolean = item.items.length > 0;
|
const hasChildren: boolean = item.items.length > 0;
|
||||||
const activeBranch: boolean = this.containsCurrentItem(item);
|
const expanded: boolean = isInitiallyExpanded(this.initialExpansion, this.containsCurrentItem(item));
|
||||||
entry.className = hasChildren ? 'current-navigation-item has-children' : 'current-navigation-item';
|
entry.className = hasChildren ? 'current-navigation-item has-children' : 'current-navigation-item';
|
||||||
entry.setAttribute('role', 'treeitem');
|
entry.setAttribute('role', 'treeitem');
|
||||||
entry.setAttribute('aria-level', String(depth));
|
entry.setAttribute('aria-level', String(depth));
|
||||||
@@ -64,8 +77,8 @@ export class CurrentNavigationRenderer {
|
|||||||
toggle.type = 'button';
|
toggle.type = 'button';
|
||||||
toggle.className = 'current-navigation-toggle';
|
toggle.className = 'current-navigation-toggle';
|
||||||
toggle.tabIndex = -1;
|
toggle.tabIndex = -1;
|
||||||
toggle.setAttribute('aria-expanded', activeBranch ? 'true' : 'false');
|
toggle.setAttribute('aria-expanded', expanded ? 'true' : 'false');
|
||||||
toggle.setAttribute('aria-label', (activeBranch ? this.strings.collapse : this.strings.expand) + ' ' + item.label);
|
toggle.setAttribute('aria-label', (expanded ? this.strings.collapse : this.strings.expand) + ' ' + item.label);
|
||||||
const chevron: HTMLSpanElement = document.createElement('span');
|
const chevron: HTMLSpanElement = document.createElement('span');
|
||||||
chevron.className = 'current-navigation-chevron';
|
chevron.className = 'current-navigation-chevron';
|
||||||
chevron.setAttribute('aria-hidden', 'true');
|
chevron.setAttribute('aria-hidden', 'true');
|
||||||
@@ -74,7 +87,7 @@ export class CurrentNavigationRenderer {
|
|||||||
this.setExpanded(entry, entry.getAttribute('aria-expanded') !== 'true', item.label);
|
this.setExpanded(entry, entry.getAttribute('aria-expanded') !== 'true', item.label);
|
||||||
});
|
});
|
||||||
row.appendChild(toggle);
|
row.appendChild(toggle);
|
||||||
entry.setAttribute('aria-expanded', activeBranch ? 'true' : 'false');
|
entry.setAttribute('aria-expanded', expanded ? 'true' : 'false');
|
||||||
} else {
|
} else {
|
||||||
const spacer: HTMLSpanElement = document.createElement('span');
|
const spacer: HTMLSpanElement = document.createElement('span');
|
||||||
spacer.className = 'current-navigation-toggle-spacer';
|
spacer.className = 'current-navigation-toggle-spacer';
|
||||||
@@ -99,7 +112,7 @@ export class CurrentNavigationRenderer {
|
|||||||
entry.appendChild(row);
|
entry.appendChild(row);
|
||||||
if (hasChildren) {
|
if (hasChildren) {
|
||||||
const children: HTMLUListElement = this.createList(item.items, depth + 1, false);
|
const children: HTMLUListElement = this.createList(item.items, depth + 1, false);
|
||||||
children.hidden = !activeBranch;
|
children.hidden = !expanded;
|
||||||
entry.appendChild(children);
|
entry.appendChild(children);
|
||||||
}
|
}
|
||||||
return entry;
|
return entry;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
selectCurrentNavigationRoot
|
selectCurrentNavigationRoot
|
||||||
} from '../src/services/CurrentNavigationCore';
|
} from '../src/services/CurrentNavigationCore';
|
||||||
import { ICurrentNavigationTerm } from '../src/services/CurrentNavigationTypes';
|
import { ICurrentNavigationTerm } from '../src/services/CurrentNavigationTypes';
|
||||||
|
import { isInitiallyExpanded } from '../src/extensions/currentNavigation/CurrentNavigationRenderer';
|
||||||
|
|
||||||
let passed: number = 0;
|
let passed: number = 0;
|
||||||
function assert(name: string, condition: boolean): void {
|
function assert(name: string, condition: boolean): void {
|
||||||
@@ -27,6 +28,10 @@ const terms: ICurrentNavigationTerm[] = [
|
|||||||
|
|
||||||
assert('German boolean is accepted', parseBoolean('ja'));
|
assert('German boolean is accepted', parseBoolean('ja'));
|
||||||
assert('local property is read', getLocalProperty(terms[0], 'CurrentNavigation.Root') === 'true');
|
assert('local property is read', getLocalProperty(terms[0], 'CurrentNavigation.Root') === 'true');
|
||||||
|
assert('expanded opens every branch', isInitiallyExpanded('expanded', false));
|
||||||
|
assert('collapsed closes even the active branch', !isInitiallyExpanded('collapsed', true));
|
||||||
|
assert('activePath keeps the previous active branch behavior', isInitiallyExpanded('activePath', true));
|
||||||
|
assert('activePath keeps inactive branches closed', !isInitiallyExpanded('activePath', false));
|
||||||
assert('site collection token resolves', resolveTermUrl(term({
|
assert('site collection token resolves', resolveTermUrl(term({
|
||||||
LocalCustomProperties: { '_Sys_Nav_SimpleLinkUrl': '~sitecollection/start' }
|
LocalCustomProperties: { '_Sys_Nav_SimpleLinkUrl': '~sitecollection/start' }
|
||||||
}), 'https://portal/sites/a') === 'https://portal/sites/a/start');
|
}), 'https://portal/sites/a') === 'https://portal/sites/a/start');
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
"files": [
|
"files": [
|
||||||
"../src/services/CurrentNavigationTypes.ts",
|
"../src/services/CurrentNavigationTypes.ts",
|
||||||
"../src/services/CurrentNavigationCore.ts",
|
"../src/services/CurrentNavigationCore.ts",
|
||||||
|
"../src/extensions/currentNavigation/CurrentNavigationRenderer.ts",
|
||||||
"CurrentNavigationCore.test.ts"
|
"CurrentNavigationCore.test.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ var manifest = json('src/extensions/currentNavigation/CurrentNavigationApplicati
|
|||||||
var app = read('src/extensions/currentNavigation/CurrentNavigationApplicationCustomizer.ts');
|
var app = read('src/extensions/currentNavigation/CurrentNavigationApplicationCustomizer.ts');
|
||||||
var renderer = read('src/extensions/currentNavigation/CurrentNavigationRenderer.ts');
|
var renderer = read('src/extensions/currentNavigation/CurrentNavigationRenderer.ts');
|
||||||
var service = read('src/services/CurrentNavigationTaxonomyService.ts');
|
var service = read('src/services/CurrentNavigationTaxonomyService.ts');
|
||||||
assert('package version', packageJson.version === '1.1.4');
|
assert('package version', packageJson.version === '1.1.5');
|
||||||
assert('solution version', solution.version === '1.1.4.0');
|
assert('solution version', solution.version === '1.1.5.0');
|
||||||
assert('tenant deployment', solution.skipFeatureDeployment === true);
|
assert('tenant deployment', solution.skipFeatureDeployment === true);
|
||||||
assert('component type', manifest.extensionType === 'ApplicationCustomizer');
|
assert('component type', manifest.extensionType === 'ApplicationCustomizer');
|
||||||
assert('safe renderer', renderer.indexOf('innerHTML') < 0 && app.indexOf('innerHTML') < 0);
|
assert('safe renderer', renderer.indexOf('innerHTML') < 0 && app.indexOf('innerHTML') < 0);
|
||||||
@@ -26,6 +26,8 @@ assert('custom navigation is appended below SiteNavigation', app.indexOf('this.s
|
|||||||
assert('observer cleanup', app.indexOf('observer.disconnect()') >= 0);
|
assert('observer cleanup', app.indexOf('observer.disconnect()') >= 0);
|
||||||
assert('treeview semantics', renderer.indexOf("setAttribute('role', root ? 'tree' : 'group')") >= 0 &&
|
assert('treeview semantics', renderer.indexOf("setAttribute('role', root ? 'tree' : 'group')") >= 0 &&
|
||||||
renderer.indexOf("setAttribute('role', 'treeitem')") >= 0);
|
renderer.indexOf("setAttribute('role', 'treeitem')") >= 0);
|
||||||
|
assert('configurable initial expansion', renderer.indexOf('isInitiallyExpanded(this.initialExpansion') >= 0 &&
|
||||||
|
renderer.indexOf("initialExpansion === 'expanded'") >= 0 && app.indexOf('this.initialExpansion()') >= 0);
|
||||||
assert('legacy selector compatibility', renderer.indexOf(':scope') < 0);
|
assert('legacy selector compatibility', renderer.indexOf(':scope') < 0);
|
||||||
assert('local properties loaded', service.indexOf('LocalCustomProperties') >= 0);
|
assert('local properties loaded', service.indexOf('LocalCustomProperties') >= 0);
|
||||||
assert('root property present', read('src/services/CurrentNavigationCore.ts').indexOf('CurrentNavigation.Root') >= 0);
|
assert('root property present', read('src/services/CurrentNavigationCore.ts').indexOf('CurrentNavigation.Root') >= 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user