feat(aio): add tooltip to nav node if none specified
This commit is contained in:
parent
efaf502e95
commit
d32bc5df3e
|
@ -80,20 +80,54 @@ describe('NavigationService', () => {
|
||||||
it('should do WHAT(?) if the request fails');
|
it('should do WHAT(?) if the request fails');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('node.tooltip', () => {
|
||||||
|
let view: NavigationNode[];
|
||||||
|
|
||||||
|
const sideNav: NavigationNode[] = [
|
||||||
|
{ title: 'a', tooltip: 'a tip' },
|
||||||
|
{ title: 'b' },
|
||||||
|
{ title: 'c!'},
|
||||||
|
{ url: 'foo' }
|
||||||
|
];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
navService.navigationViews.subscribe(views => view = views.sideNav);
|
||||||
|
backend.connectionsArray[0].mockRespond(createResponse({sideNav}));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have the supplied tooltip', () => {
|
||||||
|
expect(view[0].tooltip).toEqual('a tip');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a tooltip from title + period', () => {
|
||||||
|
expect(view[1].tooltip).toEqual('b.');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a tooltip from title, keeping its trailing punctuation', () => {
|
||||||
|
expect(view[2].tooltip).toEqual('c!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not create a tooltip if there is no title', () => {
|
||||||
|
expect(view[3].tooltip).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('currentNode', () => {
|
describe('currentNode', () => {
|
||||||
let currentNode: CurrentNode;
|
let currentNode: CurrentNode;
|
||||||
let locationService: MockLocationService;
|
let locationService: MockLocationService;
|
||||||
|
|
||||||
const topBarNodes: NavigationNode[] = [{ url: 'features', title: 'Features' }];
|
const topBarNodes: NavigationNode[] = [
|
||||||
|
{ url: 'features', title: 'Features', tooltip: 'tip' }
|
||||||
|
];
|
||||||
const sideNavNodes: NavigationNode[] = [
|
const sideNavNodes: NavigationNode[] = [
|
||||||
{ title: 'a', children: [
|
{ title: 'a', tooltip: 'tip', children: [
|
||||||
{ url: 'b', title: 'b', children: [
|
{ url: 'b', title: 'b', tooltip: 'tip', children: [
|
||||||
{ url: 'c', title: 'c' },
|
{ url: 'c', title: 'c', tooltip: 'tip' },
|
||||||
{ url: 'd', title: 'd' }
|
{ url: 'd', title: 'd', tooltip: 'tip' }
|
||||||
] },
|
] },
|
||||||
{ url: 'e', title: 'e' }
|
{ url: 'e', title: 'e', tooltip: 'tip' }
|
||||||
] },
|
] },
|
||||||
{ url: 'f', title: 'f' }
|
{ url: 'f', title: 'f', tooltip: 'tip' }
|
||||||
];
|
];
|
||||||
|
|
||||||
const navJson = {
|
const navJson = {
|
||||||
|
@ -199,6 +233,7 @@ describe('NavigationService', () => {
|
||||||
describe('docVersions', () => {
|
describe('docVersions', () => {
|
||||||
let actualDocVersions: NavigationNode[];
|
let actualDocVersions: NavigationNode[];
|
||||||
let docVersions: NavigationNode[];
|
let docVersions: NavigationNode[];
|
||||||
|
let expectedDocVersions: NavigationNode[];
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
actualDocVersions = [];
|
actualDocVersions = [];
|
||||||
|
@ -207,12 +242,16 @@ describe('NavigationService', () => {
|
||||||
{ title: 'v2', url: 'https://v2.angular.io' }
|
{ title: 'v2', url: 'https://v2.angular.io' }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
expectedDocVersions = docVersions.map(v => (
|
||||||
|
{...v, ...{ tooltip: v.title + '.'}})
|
||||||
|
);
|
||||||
|
|
||||||
navService.navigationViews.subscribe(views => actualDocVersions = views.docVersions);
|
navService.navigationViews.subscribe(views => actualDocVersions = views.docVersions);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should extract the docVersions', () => {
|
it('should extract the docVersions', () => {
|
||||||
backend.connectionsArray[0].mockRespond(createResponse({ docVersions }));
|
backend.connectionsArray[0].mockRespond(createResponse({ docVersions }));
|
||||||
expect(actualDocVersions).toEqual(docVersions);
|
expect(actualDocVersions).toEqual(expectedDocVersions);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -90,7 +90,7 @@ export class NavigationService {
|
||||||
*/
|
*/
|
||||||
private getCurrentNode(navigationViews: Observable<NavigationViews>): Observable<CurrentNode> {
|
private getCurrentNode(navigationViews: Observable<NavigationViews>): Observable<CurrentNode> {
|
||||||
const currentNode = combineLatest(
|
const currentNode = combineLatest(
|
||||||
navigationViews.map(this.computeUrlToNavNodesMap),
|
navigationViews.map(views => this.computeUrlToNavNodesMap(views)),
|
||||||
this.location.currentPath,
|
this.location.currentPath,
|
||||||
(navMap, url) => {
|
(navMap, url) => {
|
||||||
const urlKey = url.startsWith('api/') ? 'api' : url;
|
const urlKey = url.startsWith('api/') ? 'api' : url;
|
||||||
|
@ -110,21 +110,42 @@ export class NavigationService {
|
||||||
private computeUrlToNavNodesMap(navigation: NavigationViews) {
|
private computeUrlToNavNodesMap(navigation: NavigationViews) {
|
||||||
const navMap = new Map<string, CurrentNode>();
|
const navMap = new Map<string, CurrentNode>();
|
||||||
Object.keys(navigation)
|
Object.keys(navigation)
|
||||||
.forEach(view => navigation[view].forEach(node => walkNodes(view, node)));
|
.forEach(view => navigation[view]
|
||||||
|
.forEach(node => this.walkNodes(view, navMap, node)));
|
||||||
return navMap;
|
return navMap;
|
||||||
|
}
|
||||||
|
|
||||||
function walkNodes(view: string, node: NavigationNode, ancestors: NavigationNode[] = []) {
|
/**
|
||||||
|
* Add tooltip to node if it doesn't have one and have title.
|
||||||
|
* If don't want tooltip, specify `"tooltip": ""` in navigation.json
|
||||||
|
*/
|
||||||
|
private ensureHasTooltip(node: NavigationNode) {
|
||||||
|
const title = node.title;
|
||||||
|
const tooltip = node.tooltip;
|
||||||
|
if (tooltip == null && title ) {
|
||||||
|
// add period if no trailing punctuation
|
||||||
|
node.tooltip = title + (/[a-zA-Z0-9]$/.test(title) ? '.' : '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Walk the nodes of a navigation tree-view,
|
||||||
|
* patching them and computing their ancestor nodes
|
||||||
|
*/
|
||||||
|
private walkNodes(
|
||||||
|
view: string, navMap: Map<string, CurrentNode>,
|
||||||
|
node: NavigationNode, ancestors: NavigationNode[] = []) {
|
||||||
const nodes = [node, ...ancestors];
|
const nodes = [node, ...ancestors];
|
||||||
const url = node.url;
|
const url = node.url;
|
||||||
|
this.ensureHasTooltip(node);
|
||||||
|
|
||||||
// only map to this node if it has a url associated with it
|
// only map to this node if it has a url
|
||||||
if (url) {
|
if (url) {
|
||||||
// Strip off trailing slashes from nodes in the navMap - they are not relevant to matching
|
// Strip off trailing slashes from nodes in the navMap - they are not relevant to matching
|
||||||
navMap[url.replace(/\/$/, '')] = { url, view, nodes };
|
navMap[url.replace(/\/$/, '')] = { url, view, nodes };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.children) {
|
if (node.children) {
|
||||||
node.children.forEach(child => walkNodes(view, child, nodes));
|
node.children.forEach(child => this.walkNodes(view, navMap, child, nodes));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue