From 46dfb92afd185c93f60ca90a72653f33d7cb18e8 Mon Sep 17 00:00:00 2001 From: Matias Niemelä Date: Thu, 13 Jun 2013 22:37:13 -0400 Subject: feat(ngdocs): provide support for user to jump between different versions of the angularjs documentation --- docs/component-spec/versionJumpSpec.js | 125 +++++++++++++++++++++++++++++++++ docs/src/appCache.js | 2 +- docs/src/gen-docs.js | 10 ++- docs/src/ngdoc.js | 19 +++++ docs/src/templates/css/docs.css | 4 ++ docs/src/templates/index.html | 123 +++++++++++++++++--------------- docs/src/templates/js/docs.js | 66 +++++++++++++++-- 7 files changed, 285 insertions(+), 64 deletions(-) create mode 100644 docs/component-spec/versionJumpSpec.js (limited to 'docs') 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 @@