chore(docs-app): add table of contents to individual pages
This commit is contained in:
committed by
Martin Staffa
parent
05fdf918d9
commit
ddd78bd3e4
@@ -905,6 +905,35 @@ iframe[name="example-anchoringExample"] {
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
toc-container {
|
||||
display: block;
|
||||
margin: 15px 10px;
|
||||
}
|
||||
|
||||
toc-container b {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
toc-container .btn {
|
||||
padding: 3px 6px;
|
||||
font-size: 13px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
toc-container > div > toc-tree ul {
|
||||
list-style: none;
|
||||
padding-left: 15px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
toc-container > div > toc-tree > ul {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
toc-container > div > toc-tree > ul > li > toc-tree > ul > li toc-tree > ul li {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
@media handheld and (max-width:800px), screen and (max-device-width:800px), screen and (max-width:800px) {
|
||||
.navbar {
|
||||
min-height: auto;
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* This scenario checks the presence of the table of contents for a sample of pages - API and guide.
|
||||
* The expectations are kept vague so that they can be easily adjusted when the docs change.
|
||||
*/
|
||||
|
||||
describe('table of contents', function() {
|
||||
|
||||
it('on provider pages', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/provider/$controllerProvider');
|
||||
|
||||
var toc = element.all(by.css('toc-container > div > toc-tree'));
|
||||
toc.getText().then(function(text) {
|
||||
expect(text.join('')).toContain('Overview');
|
||||
expect(text.join('')).toContain('Methods');
|
||||
});
|
||||
|
||||
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
|
||||
|
||||
tocFirstLevel.then(function(match) {
|
||||
expect(match.length).toBe(2);
|
||||
|
||||
expect(match[1].all(by.css('li')).count()).toBe(2);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('on service pages', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/service/$controller');
|
||||
|
||||
var toc = element.all(by.css('toc-container > div > toc-tree'));
|
||||
toc.getText().then(function(text) {
|
||||
expect(text.join('')).toContain('Overview');
|
||||
expect(text.join('')).toContain('Usage');
|
||||
});
|
||||
|
||||
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
|
||||
|
||||
tocFirstLevel.then(function(match) {
|
||||
expect(match.length).toBe(3);
|
||||
|
||||
expect(match[2].all(by.css('li')).count()).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('on directive pages', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/directive/input');
|
||||
|
||||
var toc = element.all(by.css('toc-container > div > toc-tree'));
|
||||
toc.getText().then(function(text) {
|
||||
expect(text.join('')).toContain('Overview');
|
||||
expect(text.join('')).toContain('Usage');
|
||||
expect(text.join('')).toContain('Directive Info');
|
||||
});
|
||||
|
||||
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
|
||||
|
||||
tocFirstLevel.then(function(match) {
|
||||
expect(match.length).toBe(4);
|
||||
|
||||
expect(match[2].all(by.css('li')).count()).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('on function pages', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/function/angular.bind');
|
||||
|
||||
var toc = element.all(by.css('toc-container > div > toc-tree'));
|
||||
toc.getText().then(function(text) {
|
||||
expect(text.join('')).toContain('Overview');
|
||||
expect(text.join('')).toContain('Usage');
|
||||
});
|
||||
|
||||
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
|
||||
|
||||
tocFirstLevel.then(function(match) {
|
||||
expect(match.length).toBe(2);
|
||||
|
||||
expect(match[1].all(by.css('li')).count()).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('on type pages', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/type/ModelOptions');
|
||||
|
||||
var toc = element.all(by.css('toc-container > div > toc-tree'));
|
||||
toc.getText().then(function(text) {
|
||||
expect(text.join('')).toContain('Overview');
|
||||
expect(text.join('')).toContain('Methods');
|
||||
});
|
||||
|
||||
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
|
||||
|
||||
tocFirstLevel.then(function(match) {
|
||||
expect(match.length).toBe(2);
|
||||
|
||||
expect(match[1].all(by.css('li')).count()).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('on filter pages', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/filter/date');
|
||||
|
||||
var toc = element.all(by.css('toc-container > div > toc-tree'));
|
||||
toc.getText().then(function(text) {
|
||||
expect(text.join('')).toContain('Overview');
|
||||
expect(text.join('')).toContain('Usage');
|
||||
});
|
||||
|
||||
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
|
||||
|
||||
tocFirstLevel.then(function(match) {
|
||||
expect(match.length).toBe(3);
|
||||
|
||||
expect(match[1].all(by.css('li')).count()).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('on guide pages', function() {
|
||||
browser.get('build/docs/index.html#!/guide/services');
|
||||
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
|
||||
|
||||
tocFirstLevel.then(function(match) {
|
||||
expect(match.length).toBe(5);
|
||||
|
||||
expect(match[1].all(by.css('li')).count()).toBe(3);
|
||||
});
|
||||
});
|
||||
});
|
||||
+132
-2
@@ -1,7 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('directives', [])
|
||||
var directivesModule = angular.module('directives', []);
|
||||
|
||||
directivesModule
|
||||
/**
|
||||
* backToTop Directive
|
||||
* @param {Function} $anchorScroll
|
||||
@@ -47,4 +48,133 @@ angular.module('directives', [])
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
})
|
||||
|
||||
.directive('tocCollector', ['$rootScope', function($rootScope) {
|
||||
return {
|
||||
controller: ['$element', function($element) {
|
||||
/* eslint-disable no-invalid-this */
|
||||
var ctrl = this;
|
||||
|
||||
$rootScope.$on('$includeContentRequested', function() {
|
||||
ctrl.hs = [];
|
||||
ctrl.root = [];
|
||||
});
|
||||
|
||||
this.hs = [];
|
||||
this.root = [];
|
||||
this.element = $element;
|
||||
|
||||
this.register = function(h) {
|
||||
var previousLevel;
|
||||
|
||||
for (var i = ctrl.hs.length - 1; i >= 0; i--) {
|
||||
if (ctrl.hs[i].level === (h.level - 1)) {
|
||||
previousLevel = ctrl.hs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (previousLevel) {
|
||||
previousLevel.children.push(h);
|
||||
} else {
|
||||
this.root.push(h);
|
||||
}
|
||||
|
||||
ctrl.hs.push(h);
|
||||
/* eslint-enable no-invalid-this */
|
||||
};
|
||||
}]
|
||||
};
|
||||
}])
|
||||
|
||||
.component('tocTree', {
|
||||
template: '<ul>' +
|
||||
'<li ng-repeat="item in $ctrl.items">' +
|
||||
'<a ng-href="#{{item.fragment}}">{{item.title}}</a>' +
|
||||
'<toc-tree ng-if="::item.children.length > 0" items="item.children"></toc-tree>' +
|
||||
'</li>' +
|
||||
'</ul>',
|
||||
bindings: {
|
||||
items: '<'
|
||||
}
|
||||
})
|
||||
.directive('tocContainer', function() {
|
||||
return {
|
||||
scope: true,
|
||||
restrict: 'E',
|
||||
require: {
|
||||
tocContainer: '',
|
||||
tocCollector: '^^'
|
||||
},
|
||||
controller: function() {
|
||||
this.showToc = true;
|
||||
this.items = [];
|
||||
},
|
||||
controllerAs: '$ctrl',
|
||||
link: function(scope, element, attrs, ctrls) {
|
||||
ctrls.tocContainer.items = ctrls.tocCollector.root;
|
||||
},
|
||||
template: '<div ng-if="::$ctrl.items.length > 1">' +
|
||||
'<b>Contents</b>' +
|
||||
'<button class="btn" ng-click="$ctrl.showToc = !$ctrl.showToc">{{$ctrl.showToc ? \'Hide\' : \'Show\'}}</button><br>' +
|
||||
'<toc-tree items="$ctrl.items" ng-show="$ctrl.showToc"></toc-tree>' +
|
||||
'</div>'
|
||||
};
|
||||
})
|
||||
.directive('header', function() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
controller: ['$element', function($element) {
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
this.element = $element;
|
||||
}]
|
||||
};
|
||||
})
|
||||
.directive('h1', ['$compile', function($compile) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
require: {
|
||||
tocCollector: '^^?',
|
||||
header: '^^?'
|
||||
},
|
||||
link: function(scope, element, attrs, ctrls) {
|
||||
if (!ctrls.tocCollector) return;
|
||||
|
||||
var tocContainer = angular.element('<toc-container></toc-container>');
|
||||
var containerElement = ctrls.header ? ctrls.header.element : element;
|
||||
|
||||
containerElement.after(tocContainer);
|
||||
$compile(tocContainer)(scope);
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
for (var i = 2; i <= 5; i++) {
|
||||
registerHDirective(i);
|
||||
}
|
||||
|
||||
function registerHDirective(i) {
|
||||
directivesModule.directive('h' + i, function() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
require: {
|
||||
'tocCollector': '^^?'
|
||||
},
|
||||
link: function(scope, element, attrs, ctrls) {
|
||||
var toc = ctrls.tocCollector;
|
||||
|
||||
if (!toc || !attrs.id) return;
|
||||
|
||||
toc.register({
|
||||
level: i,
|
||||
fragment: attrs.id,
|
||||
title: element.text(),
|
||||
children: []
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +1,50 @@
|
||||
'use strict';
|
||||
|
||||
describe('code', function() {
|
||||
var prettyPrintOne, oldPP;
|
||||
describe('directives', function() {
|
||||
var compile, scope;
|
||||
|
||||
var any = jasmine.any;
|
||||
|
||||
beforeEach(module('directives'));
|
||||
|
||||
beforeEach(inject(function($rootScope, $compile) {
|
||||
// Provide stub for pretty print function
|
||||
oldPP = window.prettyPrintOne;
|
||||
prettyPrintOne = window.prettyPrintOne = jasmine.createSpy();
|
||||
beforeEach(module(function($compileProvider) {
|
||||
$compileProvider.debugInfoEnabled(false);
|
||||
}));
|
||||
|
||||
beforeEach(inject(function($rootScope, $compile) {
|
||||
scope = $rootScope.$new();
|
||||
compile = $compile;
|
||||
}));
|
||||
|
||||
afterEach(function() {
|
||||
window.prettyPrintOne = oldPP;
|
||||
});
|
||||
describe('code', function() {
|
||||
var prettyPrintOne, oldPP;
|
||||
var any = jasmine.any;
|
||||
|
||||
beforeEach(function() {
|
||||
// Provide stub for pretty print function
|
||||
oldPP = window.prettyPrintOne;
|
||||
prettyPrintOne = window.prettyPrintOne = jasmine.createSpy();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
window.prettyPrintOne = oldPP;
|
||||
});
|
||||
|
||||
|
||||
it('should pretty print innerHTML', function() {
|
||||
compile('<code>var x;</code>')(scope);
|
||||
expect(prettyPrintOne).toHaveBeenCalledWith('var x;', null, false);
|
||||
it('should pretty print innerHTML', function() {
|
||||
compile('<code>var x;</code>')(scope);
|
||||
expect(prettyPrintOne).toHaveBeenCalledWith('var x;', null, false);
|
||||
});
|
||||
|
||||
it('should allow language declaration', function() {
|
||||
compile('<code class="lang-javascript"></code>')(scope);
|
||||
expect(prettyPrintOne).toHaveBeenCalledWith(any(String), 'javascript', false);
|
||||
});
|
||||
|
||||
it('supports allow line numbers', function() {
|
||||
compile('<code class="linenum"></code>')(scope);
|
||||
expect(prettyPrintOne).toHaveBeenCalledWith(any(String), null, true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow language declaration', function() {
|
||||
compile('<code class="lang-javascript"></code>')(scope);
|
||||
expect(prettyPrintOne).toHaveBeenCalledWith(any(String), 'javascript', false);
|
||||
});
|
||||
|
||||
it('supports allow line numbers', function() {
|
||||
compile('<code class="linenum"></code>')(scope);
|
||||
expect(prettyPrintOne).toHaveBeenCalledWith(any(String), null, true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<pre class="minerr-errmsg" error-display="{$ doc.formattedErrorMessage $}">{$ doc.formattedErrorMessage $}</pre>
|
||||
</div>
|
||||
|
||||
<h2>Description</h2>
|
||||
<h2 id="description">Description</h2>
|
||||
<div class="description">
|
||||
{$ doc.description | marked $}
|
||||
</div>
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
</div>
|
||||
<div class="grid-right">
|
||||
<div id="loading" ng-show="loading">Loading...</div>
|
||||
<div ng-hide="loading" ng-include="partialPath" autoscroll></div>
|
||||
<div ng-hide="loading" ng-include="partialPath" toc-collector autoscroll></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
{% block description %}
|
||||
<div class="api-profile-description">
|
||||
<h2 id="overview">Overview</h2>
|
||||
{$ doc.description | marked $}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{% extends "api/api.template.html" %}
|
||||
|
||||
{% block additional %}
|
||||
<h2>Directive Info</h2>
|
||||
<h2 id="{$ doc.name $}-info">Directive Info</h2>
|
||||
<ul>
|
||||
{% if doc.scope %}<li>This directive creates new scope.</li>{% endif %}
|
||||
<li>This directive executes at priority level {$ doc.priority $}.</li>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
{$ x.deprecatedBlock(doc) $}
|
||||
|
||||
<h2>Installation</h2>
|
||||
<h2 id="module-installation">Installation</h2>
|
||||
{% if doc.installation or doc.installation == '' %}
|
||||
{$ doc.installation | marked $}
|
||||
{% else %}
|
||||
@@ -76,7 +76,7 @@
|
||||
|
||||
{% if doc.componentGroups.length %}
|
||||
<div class="component-breakdown">
|
||||
<h2>Module Components</h2>
|
||||
<h2 id="module-components">Module Components</h2>
|
||||
{% for componentGroup in doc.componentGroups %}
|
||||
<div>
|
||||
<h3 class="component-heading" id="{$ componentGroup.groupType | dashCase $}">{$ componentGroup.groupType | title $}</h3>
|
||||
@@ -98,7 +98,7 @@
|
||||
{% endif %}
|
||||
|
||||
{% if doc.usage %}
|
||||
<h2>Usage</h2>
|
||||
<h2 id="module-usage">Usage</h2>
|
||||
{$ doc.usage | marked $}
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
{% import "lib/deprecated.html" as x -%}
|
||||
|
||||
{%- if doc.methods %}
|
||||
<h2>Methods</h2>
|
||||
<h2 id="{$ doc.name $}-methods">Methods</h2>
|
||||
<ul class="methods">
|
||||
{%- for method in doc.methods %}
|
||||
<li id="{$ method.name $}">
|
||||
<h3>{$ lib.functionSyntax(method) $}</h3>
|
||||
<li>
|
||||
<h3 id="{$ method.name $}">{$ lib.functionSyntax(method) $}</h3>
|
||||
<div>{$ method.description | marked $}</div>
|
||||
|
||||
{$ x.deprecatedBlock(method) $}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% import "lib/macros.html" as lib -%}
|
||||
{%- if doc.params %}
|
||||
<section class="api-section">
|
||||
<h3>Arguments</h3>
|
||||
<h3 id="{$ doc.name $}-arguments">Arguments</h3>
|
||||
{$ lib.paramTable(doc.params) $}
|
||||
</section>
|
||||
{%- endif -%}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
{% import "lib/deprecated.html" as x -%}
|
||||
|
||||
{%- if doc.properties %}
|
||||
<h2>Properties</h2>
|
||||
<h2 id="{$ doc.name $}-properties">Properties</h2>
|
||||
<ul class="properties">
|
||||
{%- for property in doc.properties %}
|
||||
<li id="{$ property.name $}">
|
||||
<h3>{$ property.name | code $}</h3>
|
||||
<li>
|
||||
<h3 id="{$ property.name $}">{$ property.name | code $}</h3>
|
||||
{$ lib.typeInfo(property) $}
|
||||
{$ x.deprecatedBlock(property) $}
|
||||
</li>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% import "lib/macros.html" as lib -%}
|
||||
{% if doc.returns -%}
|
||||
<h3>Returns</h3>
|
||||
<h3 id="{$ doc.name $}-returns">Returns</h3>
|
||||
{$ lib.typeInfo(doc.returns) $}
|
||||
{%- endif %}
|
||||
+5
-2
@@ -531,8 +531,11 @@
|
||||
* $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
|
||||
*
|
||||
*
|
||||
* #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
|
||||
* specify what the template should replace. Defaults to `false`.
|
||||
* #### `replace` ([*DEPRECATED*!]
|
||||
*
|
||||
* `replace` will be removed in next major release - i.e. v2.0).
|
||||
*
|
||||
* Specifies what the template should replace. Defaults to `false`.
|
||||
*
|
||||
* * `true` - the template will replace the directive's element.
|
||||
* * `false` - the template will replace the contents of the directive's element.
|
||||
|
||||
@@ -363,7 +363,7 @@ addSetValidityMethod({
|
||||
* If the `name` attribute is specified, the form controller is published onto the current scope under
|
||||
* this name.
|
||||
*
|
||||
* # Alias: {@link ng.directive:ngForm `ngForm`}
|
||||
* ## Alias: {@link ng.directive:ngForm `ngForm`}
|
||||
*
|
||||
* In AngularJS, forms can be nested. This means that the outer form is valid when all of the child
|
||||
* forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
|
||||
@@ -371,7 +371,7 @@ addSetValidityMethod({
|
||||
* `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group
|
||||
* of controls needs to be determined.
|
||||
*
|
||||
* # CSS classes
|
||||
* ## CSS classes
|
||||
* - `ng-valid` is set if the form is valid.
|
||||
* - `ng-invalid` is set if the form is invalid.
|
||||
* - `ng-pending` is set if the form is pending.
|
||||
@@ -382,7 +382,7 @@ addSetValidityMethod({
|
||||
* Keep in mind that ngAnimate can detect each of these classes when added and removed.
|
||||
*
|
||||
*
|
||||
* # Submitting a form and preventing the default action
|
||||
* ## Submitting a form and preventing the default action
|
||||
*
|
||||
* Since the role of forms in client-side AngularJS applications is different than in classical
|
||||
* roundtrip apps, it is desirable for the browser not to translate the form submission into a full
|
||||
|
||||
@@ -1136,7 +1136,7 @@ addSetValidityMethod({
|
||||
* - {@link ng.directive:select select}
|
||||
* - {@link ng.directive:textarea textarea}
|
||||
*
|
||||
* # Complex Models (objects or collections)
|
||||
* ## Complex Models (objects or collections)
|
||||
*
|
||||
* By default, `ngModel` watches the model by reference, not value. This is important to know when
|
||||
* binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the
|
||||
@@ -1152,7 +1152,7 @@ addSetValidityMethod({
|
||||
* first level of the object (or only changing the properties of an item in the collection if it's an array) will still
|
||||
* not trigger a re-rendering of the model.
|
||||
*
|
||||
* # CSS classes
|
||||
* ## CSS classes
|
||||
* The following CSS classes are added and removed on the associated input/select/textarea element
|
||||
* depending on the validity of the model.
|
||||
*
|
||||
@@ -1171,7 +1171,7 @@ addSetValidityMethod({
|
||||
*
|
||||
* Keep in mind that ngAnimate can detect each of these classes when added and removed.
|
||||
*
|
||||
* ## Animation Hooks
|
||||
* ### Animation Hooks
|
||||
*
|
||||
* Animations within models are triggered when any of the associated CSS classes are added and removed
|
||||
* on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`,
|
||||
|
||||
Reference in New Issue
Block a user