aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/component-spec/versionJumpSpec.js125
-rw-r--r--docs/src/appCache.js2
-rwxr-xr-xdocs/src/gen-docs.js10
-rw-r--r--docs/src/ngdoc.js19
-rw-r--r--docs/src/templates/css/docs.css4
-rw-r--r--docs/src/templates/index.html123
-rw-r--r--docs/src/templates/js/docs.js66
-rw-r--r--karma-docs.conf.js2
-rw-r--r--lib/grunt/plugins.js3
-rw-r--r--lib/grunt/utils.js5
10 files changed, 292 insertions, 67 deletions
diff --git a/docs/component-spec/versionJumpSpec.js b/docs/component-spec/versionJumpSpec.js
new file mode 100644
index 00000000..d5a54975
--- /dev/null
+++ b/docs/component-spec/versionJumpSpec.js
@@ -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');
+ });
+
+ });
+ });
+
+});
diff --git a/docs/src/appCache.js b/docs/src/appCache.js
index 7b21624e..01551f2b 100644
--- a/docs/src/appCache.js
+++ b/docs/src/appCache.js
@@ -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",
diff --git a/docs/src/gen-docs.js b/docs/src/gen-docs.js
index 52d1f629..f8ca5548 100755
--- a/docs/src/gen-docs.js
+++ b/docs/src/gen-docs.js
@@ -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'));
@@ -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'));
diff --git a/docs/src/ngdoc.js b/docs/src/ngdoc.js
index 1870f87c..af78c1e3 100644
--- a/docs/src/ngdoc.js
+++ b/docs/src/ngdoc.js
@@ -11,6 +11,8 @@ 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;
@@ -18,6 +20,23 @@ 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;
diff --git a/docs/src/templates/css/docs.css b/docs/src/templates/css/docs.css
index 1b87c551..6977d205 100644
--- a/docs/src/templates/css/docs.css
+++ b/docs/src/templates/css/docs.css
@@ -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;
}
diff --git a/docs/src/templates/index.html b/docs/src/templates/index.html
index 8e2fbc37..15093d4c 100644
--- a/docs/src/templates/index.html
+++ b/docs/src/templates/index.html
@@ -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) {
@@ -233,74 +233,83 @@
<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">
diff --git a/docs/src/templates/js/docs.js b/docs/src/templates/js/docs.js
index 97fea067..ae0f1e58 100644
--- a/docs/src/templates/js/docs.js
+++ b/docs/src/templates/js/docs.js
@@ -4,6 +4,64 @@ var docsApp = {
serviceFactory: {}
};
+docsApp.controller.DocsVersionsCtrl = ['$scope', '$window', 'NG_VERSIONS', function($scope, $window, NG_VERSIONS) {
+ $scope.versions = expandVersions(NG_VERSIONS);
+ $scope.version = ($scope.version || angular.version.full).match(/^([\d\.]+\d+)/)[1]; //match only the number
+
+ $scope.jumpToDocsVersion = function(value) {
+ var isLastStable,
+ version,
+ versions = $scope.versions;
+ for(var i=versions.length-1;i>=0;i--) {
+ var v = versions[i];
+ if(v.version == value) {
+ var next = versions[i - 1];
+ isLastStable = v.stable && (!next || next && !next.stable);
+ version = v;
+ break;
+ }
+ };
+
+ if(version && version.version >= '1.0.0') {
+ //the older versions have a different path to the docs within their repo directory
+ var docsPath = version.version < '1.0.2' ? 'docs-' + version.version : 'docs';
+
+ //the last stable version should redirect to docs.angularjs.org instead of code.angularjs.org
+ var url = 'http://' +
+ (isLastStable ?
+ 'docs.angularjs.org' :
+ 'code.angularjs.org/' + version.version + '/' + docsPath);
+
+ $window.location = url;
+ }
+ };
+
+ function expandVersions(angularVersions) {
+ var unstableVersionStart = 0;
+ angularVersions.forEach(function(version) {
+ var split = version.split('.');
+ unstableVersionStart = split[1] % 2 == 1 ?
+ Math.max(unstableVersionStart, parseInt(split[0] + '' + split[1])) :
+ unstableVersionStart;
+ });
+
+ var versions = [];
+ for(var i=angularVersions.length-1;i>=0;i--) {
+ var version = angularVersions[i];
+ var split = version.split('.');
+ var stable = parseInt(split[0] + '' + split[1]) < unstableVersionStart;
+ versions.push({
+ version : version,
+ stable : stable,
+ title : 'AngularJS - v' + version,
+ group : (stable ? 'Stable' : 'Unstable')
+ });
+ };
+
+ return versions;
+ };
+}];
+
docsApp.controller.DocsNavigationCtrl = ['$scope', 'fullTextSearch', '$location', function($scope, fullTextSearch, $location) {
fullTextSearch.init();
$scope.search = function(q) {
@@ -47,7 +105,7 @@ docsApp.controller.DocsNavigationCtrl = ['$scope', 'fullTextSearch', '$location'
};
}];
-docsApp.serviceFactory.fullTextSearch = ['$q', '$rootScope', function($q, $rootScope) {
+docsApp.serviceFactory.fullTextSearch = ['$q', '$rootScope', 'NG_PAGES', function($q, $rootScope, NG_PAGES) {
return {
dbName : 'docs',
indexName : 'docsindex',
@@ -374,7 +432,7 @@ docsApp.serviceFactory.openJsFiddle = function(templateMerge, formPostData, angu
};
-docsApp.serviceFactory.sections = function sections() {
+docsApp.serviceFactory.sections = ['NG_PAGES', function sections(NG_PAGES) {
var sections = {
guide: [],
api: [],
@@ -407,7 +465,7 @@ docsApp.serviceFactory.sections = function sections() {
});
return sections;
-};
+}];
docsApp.controller.DocsController = function($scope, $location, $window, $cookies, sections) {
@@ -706,7 +764,7 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
};
-angular.module('docsApp', ['ngResource', 'ngRoute', 'ngCookies', 'ngSanitize', 'bootstrap', 'bootstrapPrettify']).
+angular.module('docsApp', ['ngResource', 'ngRoute', 'ngCookies', 'ngSanitize', 'bootstrap', 'bootstrapPrettify', 'docsData']).
config(function($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
}).
diff --git a/karma-docs.conf.js b/karma-docs.conf.js
index c65619a1..69192509 100644
--- a/karma-docs.conf.js
+++ b/karma-docs.conf.js
@@ -20,7 +20,7 @@ files = [
'build/docs/components/angular-bootstrap.js',
'build/docs/components/angular-bootstrap-prettify.js',
'build/docs/js/docs.js',
- 'build/docs/docs-keywords.js',
+ 'build/docs/docs-data.js',
'docs/component-spec/*.js'
];
diff --git a/lib/grunt/plugins.js b/lib/grunt/plugins.js
index b423b61f..ca2d6ec6 100644
--- a/lib/grunt/plugins.js
+++ b/lib/grunt/plugins.js
@@ -42,7 +42,8 @@ module.exports = function(grunt) {
docs.on('exit', function(code){
if(code !== 0) grunt.fail.warn('Error creating docs');
grunt.file.expand(files).forEach(function(file){
- grunt.file.write(file, util.process(grunt.file.read(file), grunt.config('NG_VERSION'), false));
+ var content = util.process(grunt.file.read(file), grunt.config('NG_VERSION'), false);
+ grunt.file.write(file, content);
});
grunt.log.ok('docs created');
done();
diff --git a/lib/grunt/utils.js b/lib/grunt/utils.js
index 3d2ab316..38533f27 100644
--- a/lib/grunt/utils.js
+++ b/lib/grunt/utils.js
@@ -16,8 +16,11 @@ module.exports = {
var semver = match[1].split('.');
var hash = shell.exec('git rev-parse --short HEAD', {silent: true}).output.replace('\n', '');
+ var fullVersion = (match[1] + (match[2] ? '-' + hash : ''));
+ var numVersion = semver[0] + '.' + semver[1] + '.' + semver[2];
var version = {
- full: (match[1] + (match[2] ? '-' + hash : '')),
+ number: numVersion,
+ full: fullVersion,
major: semver[0],
minor: semver[1],
dot: semver[2],