diff options
| -rw-r--r-- | Rakefile | 29 | ||||
| -rw-r--r-- | docs/content/cookbook/deeplinking.ngdoc | 10 | ||||
| -rw-r--r-- | docs/spec/ngdocSpec.js | 14 | ||||
| -rw-r--r-- | docs/src/appCache.js | 4 | ||||
| -rwxr-xr-x | docs/src/gen-docs.js | 21 | ||||
| -rw-r--r-- | docs/src/ngdoc.js | 12 | ||||
| -rw-r--r-- | docs/src/templates/.htaccess | 6 | ||||
| -rw-r--r-- | docs/src/templates/docs.js | 11 | ||||
| -rw-r--r-- | docs/src/templates/index.html | 86 | ||||
| -rw-r--r-- | lib/nodeserver/server.js | 12 | ||||
| -rw-r--r-- | src/markups.js | 15 | ||||
| -rw-r--r-- | src/widgets.js | 10 |
12 files changed, 150 insertions, 80 deletions
@@ -209,7 +209,8 @@ task :package => [:clean, :compile, :docs] do text = f.read f.truncate 0 f.rewind - f.write text.sub('angular.min.js', "angular-#{NG_VERSION.full}.min.js") + f.write text.sub('angular.min.js', "angular-#{NG_VERSION.full}.min.js"). + sub('/build/docs/', "/#{NG_VERSION.full}/docs-#{NG_VERSION.full}/") end @@ -217,10 +218,28 @@ task :package => [:clean, :compile, :docs] do text = f.read f.truncate 0 f.rewind - f.write text.sub('angular.min.js', "angular-#{NG_VERSION.full}.min.js") + f.write text.sub('angular.min.js', "angular-#{NG_VERSION.full}.min.js"). + sub('/build/docs/', "/#{NG_VERSION.full}/docs-#{NG_VERSION.full}/") end + File.open("#{pkg_dir}/docs-#{NG_VERSION.full}/index-debug.html", File::RDWR) do |f| + text = f.read + f.truncate 0 + f.rewind + f.write text.sub('../angular.js', "../angular-#{NG_VERSION.full}.js"). + sub('/build/docs/', "/#{NG_VERSION.full}/docs-#{NG_VERSION.full}/") + end + + + File.open("#{pkg_dir}/docs-#{NG_VERSION.full}/index-jq-debug.html", File::RDWR) do |f| + text = f.read + f.truncate 0 + f.rewind + f.write text.sub('../angular.js', "../angular-#{NG_VERSION.full}.js"). + sub('/build/docs/', "/#{NG_VERSION.full}/docs-#{NG_VERSION.full}/") + end + File.open("#{pkg_dir}/docs-#{NG_VERSION.full}/docs-scenario.html", File::RDWR) do |f| text = f.read f.truncate 0 @@ -232,14 +251,16 @@ task :package => [:clean, :compile, :docs] do text = f.read f.truncate 0 f.rewind - f.write text.sub('angular.min.js', "angular-#{NG_VERSION.full}.min.js") + f.write text.sub('angular.min.js', "angular-#{NG_VERSION.full}.min.js"). + sub('/build/docs/', "/#{NG_VERSION.full}/docs-#{NG_VERSION.full}/") end File.open("#{pkg_dir}/docs-#{NG_VERSION.full}/appcache-offline.manifest", File::RDWR) do |f| text = f.read f.truncate 0 f.rewind - f.write text.sub('angular.min.js', "angular-#{NG_VERSION.full}.min.js") + f.write text.sub('angular.min.js', "angular-#{NG_VERSION.full}.min.js"). + sub('/build/docs/', "/#{NG_VERSION.full}/docs-#{NG_VERSION.full}/") end diff --git a/docs/content/cookbook/deeplinking.ngdoc b/docs/content/cookbook/deeplinking.ngdoc index 10c80f21..6747b55f 100644 --- a/docs/content/cookbook/deeplinking.ngdoc +++ b/docs/content/cookbook/deeplinking.ngdoc @@ -28,14 +28,14 @@ controller. In this example we have a simple app which consist of two screens: -* Welcome: url `#` Show the user contact information. -* Settings: url `#/settings` Show an edit screen for user contact information. +* Welcome: url `welcome` Show the user contact information. +* Settings: url `settings` Show an edit screen for user contact information. The two partials are defined in the following URLs: -* {@link ./examples/settings.html} -* {@link ./examples/welcome.html} +* <a href="./examples/settings.html" ng:ext-link>./examples/settings.html</a> +* <a href="./examples/welcome.html" ng:ext-link>./examples/welcome.html</a> <doc:example> <doc:source> @@ -79,7 +79,7 @@ The two partials are defined in the following URLs: </script> <div ng:controller="AppCntl"> <h1>Your App Chrome</h1> - [ <a href="#!/welcome">Welcome</a> | <a href="#!/settings">Settings</a> ] + [ <a href="welcome">Welcome</a> | <a href="settings">Settings</a> ] <hr/> <span style="background-color: blue; color: white; padding: 3px;"> Partial: {{$route.current.template}} diff --git a/docs/spec/ngdocSpec.js b/docs/spec/ngdocSpec.js index 44d8dc3c..106fd22b 100644 --- a/docs/spec/ngdocSpec.js +++ b/docs/spec/ngdocSpec.js @@ -327,8 +327,8 @@ describe('ngdoc', function(){ expect(doc.requires).toEqual([ {name:'$service', text:'<p>for \n<code>A</code></p>'}, {name:'$another', text:'<p>for <code>B</code></p>'}]); - expect(doc.html()).toContain('<a href="#!/api/angular.service.$service">$service</a>'); - expect(doc.html()).toContain('<a href="#!/api/angular.service.$another">$another</a>'); + expect(doc.html()).toContain('<a href="api/angular.service.$service">$service</a>'); + expect(doc.html()).toContain('<a href="api/angular.service.$another">$another</a>'); expect(doc.html()).toContain('<p>for \n<code>A</code></p>'); expect(doc.html()).toContain('<p>for <code>B</code></p>'); }); @@ -429,13 +429,13 @@ describe('ngdoc', function(){ doc.parse(); expect(doc.description). - toContain('foo <a href="#!/api/angular.foo"><code>angular.foo</code></a>'); + toContain('foo <a href="api/angular.foo"><code>angular.foo</code></a>'); expect(doc.description). - toContain('da <a href="#!/api/angular.foo"><code>bar foo bar</code></a>'); + toContain('da <a href="api/angular.foo"><code>bar foo bar</code></a>'); expect(doc.description). - toContain('dad<a href="#!/api/angular.foo"><code>angular.foo</code></a>'); + toContain('dad<a href="api/angular.foo"><code>angular.foo</code></a>'); expect(doc.description). - toContain('<a href="#!/api/angular.directive.ng:foo"><code>ng:foo</code></a>'); + toContain('<a href="api/angular.directive.ng:foo"><code>ng:foo</code></a>'); expect(doc.description). toContain('<a href="http://angularjs.org">http://angularjs.org</a>'); expect(doc.description). @@ -447,7 +447,7 @@ describe('ngdoc', function(){ '{@link\napi/angular.foo\na\nb}'); doc.parse(); expect(doc.description). - toContain('<a href="#!/api/angular.foo"><code>a b</code></a>'); + toContain('<a href="api/angular.foo"><code>a b</code></a>'); }); }); diff --git a/docs/src/appCache.js b/docs/src/appCache.js index ed35eb79..7b21624e 100644 --- a/docs/src/appCache.js +++ b/docs/src/appCache.js @@ -29,7 +29,7 @@ function appCache(path) { var resultPostfix = ["", "FALLBACK:", - "/offline.html", + "/ /build/docs/index.html", "", "# allow access to google analytics and twitter when we are online", "NETWORK:", @@ -68,7 +68,7 @@ function appCacheTemplate() { "img/yellow_bkgnd.jpg", "", "FALLBACK:", - "/ offline.html", + "/ /build/docs/offline.html", "", "# allow access to google analytics and twitter when we are online", "NETWORK:", diff --git a/docs/src/gen-docs.js b/docs/src/gen-docs.js index e1778bb7..c7b37025 100755 --- a/docs/src/gen-docs.js +++ b/docs/src/gen-docs.js @@ -22,7 +22,7 @@ writer.makeDir('build/docs/syntaxhighlighter').then(function() { ngdoc.merge(docs); var fileFutures = []; docs.forEach(function(doc){ - fileFutures.push(writer.output(doc.section + '/' + doc.id + '.html', doc.html())); + fileFutures.push(writer.output('partials/' + doc.section + '/' + doc.id + '.html', doc.html())); }); writeTheRest(fileFutures); @@ -43,28 +43,19 @@ function writeTheRest(writesFuture) { writesFuture.push(writer.copyDir('img')); writesFuture.push(writer.copyDir('examples')); - var manifest = 'manifest="appcache.manifest"', - jq = '<script src="jquery.min.js"></script>', - ngMin = '<script src="../angular.min.js" ng:autobind></script>', - ng = '<script src="../angular.js" ng:autobind></script>'; + var manifest = 'manifest="/build/docs/appcache.manifest"'; writesFuture.push(writer.copy('docs/src/templates/index.html', 'build/docs/index.html', - writer.replace, {'doc:manifest': manifest, - '<!-- angular script place holder -->': ngMin})); + writer.replace, {'doc:manifest': manifest})); writesFuture.push(writer.copy('docs/src/templates/index.html', 'build/docs/index-jq.html', - writer.replace, {'doc:manifest': manifest, - '<!-- angular script place holder -->': ngMin, - '<!-- jquery place holder -->': jq})); + writer.replace, {'doc:manifest': manifest})); writesFuture.push(writer.copy('docs/src/templates/index.html', 'build/docs/index-debug.html', - writer.replace, {'doc:manifest': '', - '<!-- angular script place holder -->': ng})); + writer.replace, {'doc:manifest': ''})); writesFuture.push(writer.copy('docs/src/templates/index.html', 'build/docs/index-jq-debug.html', - writer.replace, {'doc:manifest': '', - '<!-- angular script place holder -->': ng, - '<!-- jquery place holder -->': jq})); + writer.replace, {'doc:manifest': ''})); writesFuture.push(writer.copyTpl('offline.html')); writesFuture.push(writer.copyTpl('docs-scenario.html')); diff --git a/docs/src/ngdoc.js b/docs/src/ngdoc.js index 1045d39d..abe5e1d7 100644 --- a/docs/src/ngdoc.js +++ b/docs/src/ngdoc.js @@ -133,7 +133,7 @@ Doc.prototype = { if (!isFullUrl) self.links.push(absUrl); - return '<a href="' + (isFullUrl ? '' + url : '#!/' + absUrl) + '">' + return '<a href="' + absUrl + '">' + (isAngular ? '<code>' : '') + (title || url).replace(/\n/g, ' ') + (isAngular ? '</code>' : '') @@ -243,7 +243,7 @@ Doc.prototype = { } dom.h('Dependencies', self.requires, function(require){ dom.tag('code', function(){ - dom.tag('a', {href:"#!/api/angular.service." + require.name}, require.name); + dom.tag('a', {href: 'api/angular.service.' + require.name}, require.name); }); dom.html(require.text); }); @@ -570,23 +570,23 @@ function scenarios(docs){ var specs = []; specs.push('describe("angular+jqlite", function() {'); - appendSpecs('index.html'); + appendSpecs(''); specs.push('});'); specs.push(''); specs.push(''); specs.push('describe("angular+jquery", function() {'); - appendSpecs('index-jq.html'); + appendSpecs('index-jq.html#!/'); specs.push('});'); return specs.join('\n'); - function appendSpecs(htmlFile) { + function appendSpecs(urlPrefix) { docs.forEach(function(doc){ specs.push(' describe("' + doc.section + '/' + doc.id + '", function(){'); specs.push(' beforeEach(function(){'); - specs.push(' browser().navigateTo("' + htmlFile + '#!/' + doc.section + '/' + doc.id + '");'); + specs.push(' browser().navigateTo("' + urlPrefix + doc.section + '/' + doc.id + '");'); specs.push(' });'); specs.push(' '); doc.scenarios.forEach(function(scenario){ diff --git a/docs/src/templates/.htaccess b/docs/src/templates/.htaccess index 87487e9e..9f9a152c 100644 --- a/docs/src/templates/.htaccess +++ b/docs/src/templates/.htaccess @@ -8,4 +8,8 @@ RewriteEngine on RewriteCond %{HTTP_COOKIE} ng-offline="NG_VERSION_FULL" -RewriteRule appcache.manifest appcache-offline.manifest
\ No newline at end of file +RewriteRule appcache.manifest appcache-offline.manifest + + +## HTML5 URL Support ## +RewriteRule ^(guide|api|cookbook|misc|tutorial)(/.*)?$ index.html diff --git a/docs/src/templates/docs.js b/docs/src/templates/docs.js index d1069a77..505aed60 100644 --- a/docs/src/templates/docs.js +++ b/docs/src/templates/docs.js @@ -4,7 +4,8 @@ function DocsController($location, $browser, $window, $cookies) { var self = this, OFFLINE_COOKIE_NAME = 'ng-offline', - DOCS_PATH = /^\/(api)|(guide)|(cookbook)|(misc)|(tutorial)/; + DOCS_PATH = /^\/(api)|(guide)|(cookbook)|(misc)|(tutorial)/, + INDEX_PATH = /^(\/|\/index[^\.]*.html)$/; this.$location = $location; @@ -13,7 +14,7 @@ function DocsController($location, $browser, $window, $cookies) { self.subpage = false; self.offlineEnabled = ($cookies[OFFLINE_COOKIE_NAME] == angular.version.full); - if (!$location.path()) { + if (!$location.path() || INDEX_PATH.test($location.path())) { $location.path('/api').replace(); } @@ -40,11 +41,11 @@ function DocsController($location, $browser, $window, $cookies) { }); this.getUrl = function(page){ - return '#!/' + page.section + '/' + page.id; + return page.section + '/' + page.id; }; this.getCurrentPartial = function(){ - return this.partialId ? ('./' + this.sectionId + '/' + this.partialId + '.html') : ''; + return this.partialId ? ('./partials/' + this.sectionId + '/' + this.partialId + '.html') : ''; }; this.getClass = function(page) { @@ -127,7 +128,7 @@ function TutorialInstructionsCtrl($cookieStore) { angular.service('$locationConfig', function() { return { - html5Mode: false, + html5Mode: true, hashPrefix: '!' }; }); diff --git a/docs/src/templates/index.html b/docs/src/templates/index.html index d5cfaed2..a2def7a6 100644 --- a/docs/src/templates/index.html +++ b/docs/src/templates/index.html @@ -5,23 +5,57 @@ doc:manifest> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> - <title ng:bind-template="AngularJS: {{partialTitle}}">AngularJS</title> <meta name="fragment" content="!"> - <link rel="stylesheet" href="docs-combined.css" type="text/css"/> - <link rel="stylesheet" href="syntaxhighlighter/syntaxhighlighter-combined.css" type="text/css"/> + <title ng:bind-template="AngularJS: {{partialTitle}}">AngularJS</title> + <script type="text/javascript"> + // dynamically add base tag as well as css and javascript files. + // we can't add css/js the usual way, because some browsers (FF) eagerly prefetch resources + // before the base attribute is added, causing 404 and terribly slow loading of the docs app. + (function() { + var indexFile = (location.pathname.match(/\/(index[^\.]*\.html)/) || ['', 'index.html'])[1], + rUrl = /(api|guide|misc|tutorial|cookbook|index[^\.]*\.html).*$/, + baseUrl = location.href.replace(rUrl, indexFile), + jQuery = /index-jq[^\.]*\.html$/.test(baseUrl), + debug = /index[^\.]*-debug\.html$/.test(baseUrl), + angularPath = debug ? '../angular.js' : '../angular.min.js', + headEl = document.getElementsByTagName('head')[0], + sync = true; - <script> - // GA asynchronous tracker - var _gaq = _gaq || []; - _gaq.push(['_setAccount', 'UA-8594346-3']); - _gaq.push(['_setDomainName', '.angularjs.org']); + addTag('base', {href: baseUrl}); + addTag('link', {rel: 'stylesheet', href: 'docs-combined.css', type: 'text/css'}); + addTag('link', {rel: 'stylesheet', href: 'syntaxhighlighter/syntaxhighlighter-combined.css', + type: 'text/css'}); + addTag('script', {src: 'syntaxhighlighter/syntaxhighlighter-combined.js'}, sync); + if (jQuery) addTag('script', {src: 'jquery.min.js'}); + addTag('script', {src: angularPath, 'ng:autobind':''}, sync); + addTag('script', {src: 'docs-combined.js'}, sync); + addTag('script', {src: 'docs-keywords.js'}, sync); - (function() { - var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; - ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; - var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); + function addTag(name, attributes, sync) { + var el = document.createElement(name), + attrName; + + for (attrName in attributes) { + el.setAttribute(attrName, attributes[attrName]); + } + + sync ? document.write(outerHTML(el)) : headEl.appendChild(el); + } + + function outerHTML(node){ + // if IE, Chrome take the internal method otherwise build one + return node.outerHTML || ( + function(n){ + var div = document.createElement('div'), h; + div.appendChild(n); + h = div.innerHTML; + div = null; + return h; + })(node); + } })(); + // force page reload when new update is available window.applicationCache && window.applicationCache.addEventListener('updateready', function(e) { if (window.applicationCache.status == window.applicationCache.UPDATEREADY) { @@ -29,6 +63,18 @@ window.location.reload(); } }, false); + + + // GA asynchronous tracker + var _gaq = _gaq || []; + _gaq.push(['_setAccount', 'UA-8594346-3']); + _gaq.push(['_setDomainName', '.angularjs.org']); + + (function() { + var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); + })(); </script> </head> @@ -45,11 +91,11 @@ <ul id="navbar"> <li><a href="http://angularjs.org/">AngularJS</a></li> - <li><a href="#!/misc/started" ng:class="selectedSection('misc')">Getting Started</a></li> - <li><a href="#!/tutorial" ng:class="selectedSection('tutorial')">Tutorial</a></li> - <li><a href="#!/api" ng:class="selectedSection('api')">API Reference</a></li> - <li><a href="#!/cookbook" ng:class="selectedSection('cookbook')">Examples</a></li> - <li><a href="#!/guide" ng:class="selectedSection('guide')">Developer Guide</a></li> + <li><a href="misc/started" ng:class="selectedSection('misc')">Getting Started</a></li> + <li><a href="tutorial" ng:class="selectedSection('tutorial')">Tutorial</a></li> + <li><a href="api" ng:class="selectedSection('api')">API Reference</a></li> + <li><a href="cookbook" ng:class="selectedSection('cookbook')">Examples</a></li> + <li><a href="guide" ng:class="selectedSection('guide')">Developer Guide</a></li> </ul> <div id="sidebar"> @@ -100,11 +146,5 @@ <button id="cacheButton" ng:click="enableOffline()">Let me have them all!</button> </div> </div> - - <script src="syntaxhighlighter/syntaxhighlighter-combined.js"></script> - <!-- jquery place holder --> - <!-- angular script place holder --> - <script src="docs-combined.js"></script> - <script src="docs-keywords.js"></script> </body> </html> diff --git a/lib/nodeserver/server.js b/lib/nodeserver/server.js index 471bba94..54ae78fc 100644 --- a/lib/nodeserver/server.js +++ b/lib/nodeserver/server.js @@ -91,6 +91,18 @@ StaticServlet.prototype.handleRequest = function(req, res) { var parts = path.split('/'); if (parts[parts.length-1].charAt(0) === '.') return self.sendForbidden_(req, res, path); + + // docs rewriting + var REWRITE = /\/(guide|api|cookbook|misc|tutorial)\/.*$/, + IGNORED = /(\.(css|js|png|jpg)$|partials\/.*\.html$)/, + match; + + if (!IGNORED.test(path) && (match = path.match(REWRITE))) { + path = path.replace(match[0], '/index.html'); + sys.puts('Rewrite to ' + path); + } + // end of docs rewriting + fs.stat(path, function(err, stat) { if (err) return self.sendMissing_(req, res, path); diff --git a/src/markups.js b/src/markups.js index 5c9c14b4..1adad3e0 100644 --- a/src/markups.js +++ b/src/markups.js @@ -166,10 +166,10 @@ angularTextMarkup('option', function(text, textNode, parentElement){ <input name="value" /><br /> <a id="link-1" href ng:click="value = 1">link 1</a> (link, don't reload)<br /> <a id="link-2" href="" ng:click="value = 2">link 2</a> (link, don't reload)<br /> - <a id="link-3" ng:href="#!/{{'123'}}" ng:click="value = 3">link 3</a> (link, reload!)<br /> + <a id="link-3" ng:href="/{{'123'}}" ng:ext-link>link 3</a> (link, reload!)<br /> <a id="link-4" href="" name="xx" ng:click="value = 4">anchor</a> (link, don't reload)<br /> <a id="link-5" name="xxx" ng:click="value = 5">anchor</a> (no link)<br /> - <a id="link-6" ng:href="#!/{{value}}">link</a> (link, change hash) + <a id="link-6" ng:href="/{{value}}" ng:ext-link>link</a> (link, change hash) </doc:source> <doc:scenario> it('should execute ng:click but not reload when href without value', function() { @@ -185,10 +185,10 @@ angularTextMarkup('option', function(text, textNode, parentElement){ }); it('should execute ng:click and change url when ng:href specified', function() { + expect(element('#link-3').attr('href')).toBe("/123"); + element('#link-3').click(); - expect(input('value').val()).toEqual('3'); - expect(element('#link-3').attr('href')).toBe("#!/123"); - expect(browser().location().hash()).toEqual('!/123'); + expect(browser().location().path()).toEqual('/123'); }); it('should execute ng:click but not reload when href empty string and name specified', function() { @@ -205,9 +205,10 @@ angularTextMarkup('option', function(text, textNode, parentElement){ it('should only change url when only ng:href', function() { input('value').enter('6'); + expect(element('#link-6').attr('href')).toBe("/6"); + element('#link-6').click(); - expect(browser().location().hash()).toEqual('!/6'); - expect(element('#link-6').attr('href')).toBe("#!/6"); + expect(browser().location().path()).toEqual('/6'); }); </doc:scenario> </doc:example> diff --git a/src/widgets.js b/src/widgets.js index 1d0217b8..bd7c3d7f 100644 --- a/src/widgets.js +++ b/src/widgets.js @@ -1390,10 +1390,10 @@ angularWidget("@ng:non-bindable", noop); function MyCtrl($route) { $route.when('/overview', { controller: OverviewCtrl, - template: 'guide/dev_guide.overview.html'}); + template: 'partials/guide/dev_guide.overview.html'}); $route.when('/bootstrap', { controller: BootstrapCtrl, - template: 'guide/dev_guide.bootstrap.auto_bootstrap.html'}); + template: 'partials/guide/dev_guide.bootstrap.auto_bootstrap.html'}); }; MyCtrl.$inject = ['$route']; @@ -1401,9 +1401,9 @@ angularWidget("@ng:non-bindable", noop); function OverviewCtrl(){} </script> <div ng:controller="MyCtrl"> - <a href="#!/overview">overview</a> | - <a href="#!/bootstrap">bootstrap</a> | - <a href="#!/undefined">undefined</a> + <a href="overview">overview</a> | + <a href="bootstrap">bootstrap</a> | + <a href="undefined">undefined</a> <br/> |
