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

Commit

Permalink
feat(ngdocs): provide support for user to jump between different vers…
Browse files Browse the repository at this point in the history
…ions of the angularjs documentation
  • Loading branch information
matsko authored and mhevery committed Jun 18, 2013
1 parent ef22968 commit 46dfb92
Show file tree
Hide file tree
Showing 10 changed files with 292 additions and 67 deletions.
125 changes: 125 additions & 0 deletions docs/component-spec/versionJumpSpec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
describe('DocsApp', function() {

beforeEach(module('docsApp'));

describe('DocsVersionsCtrl', function() {
var $scope, ctrl, window, version = '9.8.7';

beforeEach(function() {
module(function($provide) {
$provide.value('NG_VERSIONS',[
'1.0.0',
'1.0.1',
'1.0.2',
'1.0.3',
'1.0.4',
'1.0.5',
'1.0.6',
'1.1.0',
'1.1.1',
'1.1.2',
'1.1.3',
'1.1.4',
'2.1.3'
]);
$provide.value('$window', window = angular.mock.createMockWindow());
});
inject(function($controller, $rootScope) {
$scope = $rootScope.$new();
$scope.version = version;
ctrl = $controller('DocsVersionsCtrl',{
$scope : $scope,
$window : window
});
});
});

it('should have the correct version of angular', function() {
expect(version).toBe($scope.version);
});

it('should order versions in decending order', function() {
expect($scope.versions.length).toBeGreaterThan(0);

var one = $scope.versions[0].version;
var two = $scope.versions[1].version;

expect(one).toBeGreaterThan(two);
});

it('should list unstable versions at the top of the list', function() {
expect($scope.versions[0].stable).toBe(false);
});

it('should list all items below the last stable as stable regardless of version number', function() {
var limit = $scope.versions.length - 1,
lastUnstableIndex = 0;

while(lastUnstableIndex <= limit) {
if($scope.versions[lastUnstableIndex++].stable) break;
}

for(var i=lastUnstableIndex;i<=limit;i++) {
expect($scope.versions[i].stable).toBe(true);
}
});

describe('changing the URL', function() {
it('should not support the old < 1.0 docs pages', function() {
window.location = 'old';

$scope.versions.unshift({
stable : true,
version : '0.9.10'
});
$scope.jumpToDocsVersion('0.9.10');
expect(window.location).toBe('old');

$scope.versions.unshift({
stable : true,
version : '0.10.1'
});
$scope.jumpToDocsVersion('0.10.1');
expect(window.location).toBe('old');

$scope.jumpToDocsVersion('2.1.3');
expect(window.location).toBe('http://code.angularjs.org/2.1.3/docs');
});

it('should jump to the older versions of current docs for version >= 1.0.2', function() {
$scope.jumpToDocsVersion('1.0.1');
expect(window.location).toBe('http://code.angularjs.org/1.0.1/docs-1.0.1');

$scope.jumpToDocsVersion('1.0.2');
expect(window.location).toBe('http://code.angularjs.org/1.0.2/docs');

$scope.jumpToDocsVersion('1.1.2');
expect(window.location).toBe('http://code.angularjs.org/1.1.2/docs');
});

it('should use the current docs.angularjs.org page when the selected version is the last stable version', function() {
$scope.versions = [{
stable : true,
title : 'test',
version : '1.1.1'
}];

$scope.jumpToDocsVersion('1.1.1');
expect(window.location).toBe('http://docs.angularjs.org');

$scope.versions.unshift({
stable : true,
title : 'test2',
version : '1.2.1'
});

$scope.jumpToDocsVersion('1.1.1');
expect(window.location).toBe('http://code.angularjs.org/1.1.1/docs');
$scope.jumpToDocsVersion('1.2.1');
expect(window.location).toBe('http://docs.angularjs.org');
});

});
});

});
2 changes: 1 addition & 1 deletion docs/src/appCache.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function appCacheTemplate() {
"syntaxhighlighter/syntaxhighlighter-combined.js",
"../angular.min.js",
"docs-combined.js",
"docs-keywords.js",
"docs-data.js",
"docs-combined.css",
"syntaxhighlighter/syntaxhighlighter-combined.css",
"img/texture_1.png",
Expand Down
10 changes: 8 additions & 2 deletions docs/src/gen-docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ writer.makeDir('build/docs/', true).then(function() {

function writeTheRest(writesFuture) {
var metadata = ngdoc.metadata(docs);
var versions = ngdoc.ngVersions();
var currentVersion = ngdoc.ngCurrentVersion();

writesFuture.push(writer.symlink('../../docs/content/notes', 'build/docs/notes', 'dir'));
writesFuture.push(writer.symlinkTemplate('css', 'dir'));
Expand Down Expand Up @@ -90,8 +92,12 @@ function writeTheRest(writesFuture) {
writesFuture.push(writer.copyTemplate('docs-scenario.html')); // will be rewritten, don't symlink
writesFuture.push(writer.output('docs-scenario.js', ngdoc.scenarios(docs)));

writesFuture.push(writer.output('docs-keywords.js',
['NG_PAGES=', JSON.stringify(metadata).replace(/{/g, '\n{'), ';']));
writesFuture.push(writer.output('docs-data.js',[
"angular.module('docsData', [])",
".value('NG_PAGES'," + JSON.stringify(metadata).replace(/{/g, '\n{') + ")",
".value('NG_VERSION'," + JSON.stringify(currentVersion) + ")",
".value('NG_VERSIONS'," + JSON.stringify(versions) + ");"
]));
writesFuture.push(writer.output('sitemap.xml', new SiteMap(docs).render()));

writesFuture.push(writer.output('robots.txt', 'Sitemap: http://docs.angularjs.org/sitemap.xml\n'));
Expand Down
19 changes: 19 additions & 0 deletions docs/src/ngdoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,32 @@ var globalID = 0;
var fs = require('fs');
var fspath = require('path');
var markdown = new Showdown.converter({ extensions : ['table'] });
var shell = require('shelljs');
var gruntUtil = require('../../lib/grunt/utils.js');

exports.trim = trim;
exports.metadata = metadata;
exports.scenarios = scenarios;
exports.merge = merge;
exports.Doc = Doc;

exports.ngVersions = function() {
var line, versions = [], regex = /^v([1-9]\d*(?:\.\d+)+)$/; //only fetch >= 1.0.0 versions
shell.exec('git tag', {silent: true}).output.split(/\s*\n\s*/)
.forEach(function(line) {
var matches = regex.exec(line);
if(matches && matches.length > 0) {
versions.push(matches[1]);
}
});
versions.push(exports.ngCurrentVersion().number);
return versions;
};

exports.ngCurrentVersion = function() {
return gruntUtil.getVersion();
};

var BOOLEAN_ATTR = {};
['multiple', 'selected', 'checked', 'disabled', 'readOnly', 'required'].forEach(function(value) {
BOOLEAN_ATTR[value] = true;
Expand Down
4 changes: 4 additions & 0 deletions docs/src/templates/css/docs.css
Original file line number Diff line number Diff line change
Expand Up @@ -461,4 +461,8 @@ pre ol li {
box-shadow:-6px 0 5px #555;
display:block;
border-radius:10px;

.docs-version-jump {
width:180px;
margin-bottom:20px;
}
123 changes: 66 additions & 57 deletions docs/src/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
addTag('script', {src: 'components/google-code-prettify.js' }, sync);
addTag('script', {src: 'components/' + (debug ? 'lunr.js' : 'lunr.min.js') }, sync);
addTag('script', {src: 'components/' + (debug ? 'showdown.js' : 'showdown.min.js') }, sync);
addTag('script', {src: 'docs-data.js'}, sync);
addTag('script', {src: 'js/docs.js'}, sync);
addTag('script', {src: 'docs-keywords.js'}, sync);

function path(name) {
if (production) {
Expand Down Expand Up @@ -233,74 +233,83 @@ <h4>{{ key }}</h4>

<div class="row">
<div class="span3">
<form class="well form-search" ng-submit="submitForm()">
<div class="dropdown search"
ng-class="{open: focused && bestMatch.rank > 0 && bestMatch.page != currentPage}">
<input type="text" ng-model="search" placeholder="search the docs"
tabindex="1" accesskey="s" class="input-medium search-query" focused="focused">
<ul class="dropdown-menu">
<li>
<a href="{{bestMatch.page.url}}">{{bestMatch.page.shortName}}</a>
</li>
</ul>
<div class="well">
<div ng-controller="DocsVersionsCtrl">
<select ng-options="v.version as v.title group by v.group for v in versions"
ng-model="version"
ng-change="jumpToDocsVersion(version)"
class="docs-version-jump">
</select>
</div>
<form class="form-search" ng-submit="submitForm()">
<div class="dropdown search"
ng-class="{open: focused && bestMatch.rank > 0 && bestMatch.page != currentPage}">
<input type="text" ng-model="search" placeholder="search the docs"
tabindex="1" accesskey="s" class="input-medium search-query" focused="focused">
<ul class="dropdown-menu">
<li>
<a href="{{bestMatch.page.url}}">{{bestMatch.page.shortName}}</a>
</li>
</ul>
</div>

<div class="spacer"></div>
<div ng-show="search">Filtered results:</div>
<div class="spacer"></div>
<div ng-show="search">Filtered results:</div>

<ul class="nav nav-list" ng-hide="page">
<li ng-repeat="page in pages track by page.url" ng-class="navClass(page)" class="api-list-item">
<a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
</li>
</ul>
<ul class="nav nav-list" ng-hide="page">
<li ng-repeat="page in pages track by page.url" ng-class="navClass(page)" class="api-list-item">
<a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
</li>
</ul>


<ul class="nav nav-list well" ng-repeat="module in modules track by module.url" class="api-list-item">
<li class="nav-header module">
<a class="guide" href="{{URL.module}}">module</a>
<a class="code" href="{{module.url}}">{{module.name}}</a>
</li>
<ul class="nav nav-list well" ng-repeat="module in modules track by module.url" class="api-list-item">
<li class="nav-header module">
<a class="guide" href="{{URL.module}}">module</a>
<a class="code" href="{{module.url}}">{{module.name}}</a>
</li>

<li class="nav-header section" ng-show="module.directives">
<a href="{{URL.directive}}" class="guide">directive</a>
</li>
<li ng-repeat="page in module.directives track by page.url" ng-class="navClass(page)" ng-animate="'expand'" class="api-list-item">
<a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
</li>
<li class="nav-header section" ng-show="module.directives">
<a href="{{URL.directive}}" class="guide">directive</a>
</li>
<li ng-repeat="page in module.directives track by page.url" ng-class="navClass(page)" ng-animate="'expand'" class="api-list-item">
<a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
</li>

<li class="nav-header section" ng-show="module.filters">
<a href="{{URL.filter}}" class="guide">filter</a>
</li>
<li ng-repeat="page in module.filters track by page.url" ng-class="navClass(page)" ng-animate="'expand'" class="api-list-item">
<a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
</li>
<li class="nav-header section" ng-show="module.filters">
<a href="{{URL.filter}}" class="guide">filter</a>
</li>
<li ng-repeat="page in module.filters track by page.url" ng-class="navClass(page)" ng-animate="'expand'" class="api-list-item">
<a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
</li>

<li class="nav-header section" ng-show="module.services">
<a href="{{URL.service}}" class="guide">service</a>
</li>
<li ng-repeat="service in module.services track by service.instance.url" ng-animate="'expand'" ng-class="navClass(service.instance, service.provider)" class="api-list-item">
<a ng-show="service.provider" class="pull-right" href="{{service.provider.url}}" tabindex="2"><i class="icon-cog"></i></a>
<a href="{{service.instance.url}}" tabindex="2">{{service.name}}</a>
</li>
<li class="nav-header section" ng-show="module.services">
<a href="{{URL.service}}" class="guide">service</a>
</li>
<li ng-repeat="service in module.services track by service.instance.url" ng-animate="'expand'" ng-class="navClass(service.instance, service.provider)" class="api-list-item">
<a ng-show="service.provider" class="pull-right" href="{{service.provider.url}}" tabindex="2"><i class="icon-cog"></i></a>
<a href="{{service.instance.url}}" tabindex="2">{{service.name}}</a>
</li>

<li class="nav-header section" ng-show="module.types">
<a href="{{URL.type}}" class="guide">Types</a>
</li>
<li ng-repeat="page in module.types track by page.url" ng-class="navClass(page)" ng-animate="'expand'" class="api-list-item">
<a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
</li>
<li class="nav-header section" ng-show="module.types">
<a href="{{URL.type}}" class="guide">Types</a>
</li>
<li ng-repeat="page in module.types track by page.url" ng-class="navClass(page)" ng-animate="'expand'" class="api-list-item">
<a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
</li>

<li class="nav-header section" ng-show="module.globals">
<a href="{{URL.api}}" class="global guide">global APIs</a>
&nbsp;
</li>
<li ng-repeat="page in module.globals track by page.url" ng-class="navClass(page)" class="api-list-item">
<a href="{{page.url}}" tabindex="2">{{page.id}}</a>
</li>
<li class="nav-header section" ng-show="module.globals">
<a href="{{URL.api}}" class="global guide">global APIs</a>
&nbsp;
</li>
<li ng-repeat="page in module.globals track by page.url" ng-class="navClass(page)" class="api-list-item">
<a href="{{page.url}}" tabindex="2">{{page.id}}</a>
</li>

</ul>
</ul>

</form>
</form>
</div>
</div>
<div class="span9">

Expand Down
Loading

0 comments on commit 46dfb92

Please sign in to comment.