Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit ddd78bd

Browse files
committed
chore(docs-app): add table of contents to individual pages
1 parent 05fdf91 commit ddd78bd

16 files changed

+348
-45
lines changed

docs/app/assets/css/docs.css

+29
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,35 @@ iframe[name="example-anchoringExample"] {
905905
background-color: inherit;
906906
}
907907

908+
toc-container {
909+
display: block;
910+
margin: 15px 10px;
911+
}
912+
913+
toc-container b {
914+
text-transform: uppercase;
915+
}
916+
917+
toc-container .btn {
918+
padding: 3px 6px;
919+
font-size: 13px;
920+
margin-left: 5px;
921+
}
922+
923+
toc-container > div > toc-tree ul {
924+
list-style: none;
925+
padding-left: 15px;
926+
padding-bottom: 2px;
927+
}
928+
929+
toc-container > div > toc-tree > ul {
930+
padding-left: 0;
931+
}
932+
933+
toc-container > div > toc-tree > ul > li > toc-tree > ul > li toc-tree > ul li {
934+
font-size: 13px;
935+
}
936+
908937
@media handheld and (max-width:800px), screen and (max-device-width:800px), screen and (max-width:800px) {
909938
.navbar {
910939
min-height: auto;
+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
'use strict';
2+
3+
/**
4+
* This scenario checks the presence of the table of contents for a sample of pages - API and guide.
5+
* The expectations are kept vague so that they can be easily adjusted when the docs change.
6+
*/
7+
8+
describe('table of contents', function() {
9+
10+
it('on provider pages', function() {
11+
browser.get('build/docs/index.html#!/api/ng/provider/$controllerProvider');
12+
13+
var toc = element.all(by.css('toc-container > div > toc-tree'));
14+
toc.getText().then(function(text) {
15+
expect(text.join('')).toContain('Overview');
16+
expect(text.join('')).toContain('Methods');
17+
});
18+
19+
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
20+
21+
tocFirstLevel.then(function(match) {
22+
expect(match.length).toBe(2);
23+
24+
expect(match[1].all(by.css('li')).count()).toBe(2);
25+
});
26+
27+
});
28+
29+
it('on service pages', function() {
30+
browser.get('build/docs/index.html#!/api/ng/service/$controller');
31+
32+
var toc = element.all(by.css('toc-container > div > toc-tree'));
33+
toc.getText().then(function(text) {
34+
expect(text.join('')).toContain('Overview');
35+
expect(text.join('')).toContain('Usage');
36+
});
37+
38+
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
39+
40+
tocFirstLevel.then(function(match) {
41+
expect(match.length).toBe(3);
42+
43+
expect(match[2].all(by.css('li')).count()).toBe(2);
44+
});
45+
});
46+
47+
it('on directive pages', function() {
48+
browser.get('build/docs/index.html#!/api/ng/directive/input');
49+
50+
var toc = element.all(by.css('toc-container > div > toc-tree'));
51+
toc.getText().then(function(text) {
52+
expect(text.join('')).toContain('Overview');
53+
expect(text.join('')).toContain('Usage');
54+
expect(text.join('')).toContain('Directive Info');
55+
});
56+
57+
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
58+
59+
tocFirstLevel.then(function(match) {
60+
expect(match.length).toBe(4);
61+
62+
expect(match[2].all(by.css('li')).count()).toBe(1);
63+
});
64+
});
65+
66+
it('on function pages', function() {
67+
browser.get('build/docs/index.html#!/api/ng/function/angular.bind');
68+
69+
var toc = element.all(by.css('toc-container > div > toc-tree'));
70+
toc.getText().then(function(text) {
71+
expect(text.join('')).toContain('Overview');
72+
expect(text.join('')).toContain('Usage');
73+
});
74+
75+
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
76+
77+
tocFirstLevel.then(function(match) {
78+
expect(match.length).toBe(2);
79+
80+
expect(match[1].all(by.css('li')).count()).toBe(2);
81+
});
82+
});
83+
84+
it('on type pages', function() {
85+
browser.get('build/docs/index.html#!/api/ng/type/ModelOptions');
86+
87+
var toc = element.all(by.css('toc-container > div > toc-tree'));
88+
toc.getText().then(function(text) {
89+
expect(text.join('')).toContain('Overview');
90+
expect(text.join('')).toContain('Methods');
91+
});
92+
93+
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
94+
95+
tocFirstLevel.then(function(match) {
96+
expect(match.length).toBe(2);
97+
98+
expect(match[1].all(by.css('li')).count()).toBe(2);
99+
});
100+
});
101+
102+
it('on filter pages', function() {
103+
browser.get('build/docs/index.html#!/api/ng/filter/date');
104+
105+
var toc = element.all(by.css('toc-container > div > toc-tree'));
106+
toc.getText().then(function(text) {
107+
expect(text.join('')).toContain('Overview');
108+
expect(text.join('')).toContain('Usage');
109+
});
110+
111+
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
112+
113+
tocFirstLevel.then(function(match) {
114+
expect(match.length).toBe(3);
115+
116+
expect(match[1].all(by.css('li')).count()).toBe(2);
117+
});
118+
});
119+
120+
it('on guide pages', function() {
121+
browser.get('build/docs/index.html#!/guide/services');
122+
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
123+
124+
tocFirstLevel.then(function(match) {
125+
expect(match.length).toBe(5);
126+
127+
expect(match[1].all(by.css('li')).count()).toBe(3);
128+
});
129+
});
130+
});

docs/app/src/directives.js

+132-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
'use strict';
22

3-
angular.module('directives', [])
3+
var directivesModule = angular.module('directives', []);
44

5+
directivesModule
56
/**
67
* backToTop Directive
78
* @param {Function} $anchorScroll
@@ -47,4 +48,133 @@ angular.module('directives', [])
4748
}
4849
}
4950
};
50-
});
51+
})
52+
53+
.directive('tocCollector', ['$rootScope', function($rootScope) {
54+
return {
55+
controller: ['$element', function($element) {
56+
/* eslint-disable no-invalid-this */
57+
var ctrl = this;
58+
59+
$rootScope.$on('$includeContentRequested', function() {
60+
ctrl.hs = [];
61+
ctrl.root = [];
62+
});
63+
64+
this.hs = [];
65+
this.root = [];
66+
this.element = $element;
67+
68+
this.register = function(h) {
69+
var previousLevel;
70+
71+
for (var i = ctrl.hs.length - 1; i >= 0; i--) {
72+
if (ctrl.hs[i].level === (h.level - 1)) {
73+
previousLevel = ctrl.hs[i];
74+
break;
75+
}
76+
}
77+
78+
if (previousLevel) {
79+
previousLevel.children.push(h);
80+
} else {
81+
this.root.push(h);
82+
}
83+
84+
ctrl.hs.push(h);
85+
/* eslint-enable no-invalid-this */
86+
};
87+
}]
88+
};
89+
}])
90+
91+
.component('tocTree', {
92+
template: '<ul>' +
93+
'<li ng-repeat="item in $ctrl.items">' +
94+
'<a ng-href="#{{item.fragment}}">{{item.title}}</a>' +
95+
'<toc-tree ng-if="::item.children.length > 0" items="item.children"></toc-tree>' +
96+
'</li>' +
97+
'</ul>',
98+
bindings: {
99+
items: '<'
100+
}
101+
})
102+
.directive('tocContainer', function() {
103+
return {
104+
scope: true,
105+
restrict: 'E',
106+
require: {
107+
tocContainer: '',
108+
tocCollector: '^^'
109+
},
110+
controller: function() {
111+
this.showToc = true;
112+
this.items = [];
113+
},
114+
controllerAs: '$ctrl',
115+
link: function(scope, element, attrs, ctrls) {
116+
ctrls.tocContainer.items = ctrls.tocCollector.root;
117+
},
118+
template: '<div ng-if="::$ctrl.items.length > 1">' +
119+
'<b>Contents</b>' +
120+
'<button class="btn" ng-click="$ctrl.showToc = !$ctrl.showToc">{{$ctrl.showToc ? \'Hide\' : \'Show\'}}</button><br>' +
121+
'<toc-tree items="$ctrl.items" ng-show="$ctrl.showToc"></toc-tree>' +
122+
'</div>'
123+
};
124+
})
125+
.directive('header', function() {
126+
return {
127+
restrict: 'E',
128+
controller: ['$element', function($element) {
129+
// eslint-disable-next-line no-invalid-this
130+
this.element = $element;
131+
}]
132+
};
133+
})
134+
.directive('h1', ['$compile', function($compile) {
135+
return {
136+
restrict: 'E',
137+
require: {
138+
tocCollector: '^^?',
139+
header: '^^?'
140+
},
141+
link: function(scope, element, attrs, ctrls) {
142+
if (!ctrls.tocCollector) return;
143+
144+
var tocContainer = angular.element('<toc-container></toc-container>');
145+
var containerElement = ctrls.header ? ctrls.header.element : element;
146+
147+
containerElement.after(tocContainer);
148+
$compile(tocContainer)(scope);
149+
}
150+
};
151+
}]);
152+
153+
for (var i = 2; i <= 5; i++) {
154+
registerHDirective(i);
155+
}
156+
157+
function registerHDirective(i) {
158+
directivesModule.directive('h' + i, function() {
159+
return {
160+
restrict: 'E',
161+
require: {
162+
'tocCollector': '^^?'
163+
},
164+
link: function(scope, element, attrs, ctrls) {
165+
var toc = ctrls.tocCollector;
166+
167+
if (!toc || !attrs.id) return;
168+
169+
toc.register({
170+
level: i,
171+
fragment: attrs.id,
172+
title: element.text(),
173+
children: []
174+
});
175+
176+
}
177+
};
178+
});
179+
}
180+

docs/app/test/directivesSpec.js

+31-21
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,50 @@
11
'use strict';
22

3-
describe('code', function() {
4-
var prettyPrintOne, oldPP;
3+
describe('directives', function() {
54
var compile, scope;
65

7-
var any = jasmine.any;
86

97
beforeEach(module('directives'));
108

11-
beforeEach(inject(function($rootScope, $compile) {
12-
// Provide stub for pretty print function
13-
oldPP = window.prettyPrintOne;
14-
prettyPrintOne = window.prettyPrintOne = jasmine.createSpy();
9+
beforeEach(module(function($compileProvider) {
10+
$compileProvider.debugInfoEnabled(false);
11+
}));
1512

13+
beforeEach(inject(function($rootScope, $compile) {
1614
scope = $rootScope.$new();
1715
compile = $compile;
1816
}));
1917

20-
afterEach(function() {
21-
window.prettyPrintOne = oldPP;
22-
});
18+
describe('code', function() {
19+
var prettyPrintOne, oldPP;
20+
var any = jasmine.any;
2321

22+
beforeEach(function() {
23+
// Provide stub for pretty print function
24+
oldPP = window.prettyPrintOne;
25+
prettyPrintOne = window.prettyPrintOne = jasmine.createSpy();
26+
});
2427

25-
it('should pretty print innerHTML', function() {
26-
compile('<code>var x;</code>')(scope);
27-
expect(prettyPrintOne).toHaveBeenCalledWith('var x;', null, false);
28-
});
28+
afterEach(function() {
29+
window.prettyPrintOne = oldPP;
30+
});
2931

30-
it('should allow language declaration', function() {
31-
compile('<code class="lang-javascript"></code>')(scope);
32-
expect(prettyPrintOne).toHaveBeenCalledWith(any(String), 'javascript', false);
33-
});
3432

35-
it('supports allow line numbers', function() {
36-
compile('<code class="linenum"></code>')(scope);
37-
expect(prettyPrintOne).toHaveBeenCalledWith(any(String), null, true);
33+
it('should pretty print innerHTML', function() {
34+
compile('<code>var x;</code>')(scope);
35+
expect(prettyPrintOne).toHaveBeenCalledWith('var x;', null, false);
36+
});
37+
38+
it('should allow language declaration', function() {
39+
compile('<code class="lang-javascript"></code>')(scope);
40+
expect(prettyPrintOne).toHaveBeenCalledWith(any(String), 'javascript', false);
41+
});
42+
43+
it('supports allow line numbers', function() {
44+
compile('<code class="linenum"></code>')(scope);
45+
expect(prettyPrintOne).toHaveBeenCalledWith(any(String), null, true);
46+
});
3847
});
48+
3949
});
4050

docs/config/templates/app/error.template.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ <h1>Error: {$ doc.namespace $}:{$ doc.name $}
99
<pre class="minerr-errmsg" error-display="{$ doc.formattedErrorMessage $}">{$ doc.formattedErrorMessage $}</pre>
1010
</div>
1111

12-
<h2>Description</h2>
12+
<h2 id="description">Description</h2>
1313
<div class="description">
1414
{$ doc.description | marked $}
1515
</div>

0 commit comments

Comments
 (0)