diff options
| author | Misko Hevery | 2011-01-25 21:55:11 -0800 |
|---|---|---|
| committer | Igor Minar | 2011-01-26 23:31:15 -0800 |
| commit | bd33f60276a0fa37acffbad7a0cdcff92db594c8 (patch) | |
| tree | 7cd957c19182ddc430a6320b77b2f03cb1bd223d /docs/src | |
| parent | 8682befc7284a3c0b35cd5d85d4f42b1484ec71a (diff) | |
| download | angular.js-bd33f60276a0fa37acffbad7a0cdcff92db594c8.tar.bz2 | |
Added part of guide documentation and supporting changes to doc generator
Diffstat (limited to 'docs/src')
| -rw-r--r-- | docs/src/dom.js | 25 | ||||
| -rw-r--r-- | docs/src/gen-docs.js | 5 | ||||
| -rw-r--r-- | docs/src/ngdoc.js | 210 | ||||
| -rw-r--r-- | docs/src/templates/doc_widgets.js | 15 | ||||
| -rw-r--r-- | docs/src/templates/docs.css | 18 | ||||
| -rw-r--r-- | docs/src/templates/docs.js | 10 | ||||
| -rw-r--r-- | docs/src/templates/index.html | 2 | ||||
| -rw-r--r-- | docs/src/writer.js | 27 |
8 files changed, 204 insertions, 108 deletions
diff --git a/docs/src/dom.js b/docs/src/dom.js index fedd4e19..7708cbc9 100644 --- a/docs/src/dom.js +++ b/docs/src/dom.js @@ -3,12 +3,18 @@ */ exports.DOM = DOM; +exports.htmlEscape = htmlEscape; ////////////////////////////////////////////////////////// +function htmlEscape(text){ + return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); +} + + function DOM(){ this.out = []; - this.headingDepth = 1; + this.headingDepth = 0; } var INLINE_TAGS = { @@ -23,7 +29,7 @@ DOM.prototype = { text: function(content) { if (typeof content == "string") { - this.out.push(content.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')); + this.out.push(htmlEscape(content)); } else if (typeof content == 'function') { content.call(this, this); } else if (content instanceof Array) { @@ -33,6 +39,13 @@ DOM.prototype = { html: function(html) { if (html) { + var headingDepth = this.headingDepth; + for ( var i = 10; i > 0; --i) { + html = html + .replace(new RegExp('(<\/?h)' + i + '(>)', 'gm'), function(all, start, end){ + return start + (i + headingDepth) + end; + }); + } this.out.push(html); } }, @@ -80,15 +93,17 @@ DOM.prototype = { h: function(heading, content, fn){ if (content==undefined || content && content.legth == 0) return; - this.tag('h' + this.headingDepth, heading); this.headingDepth++; + this.tag('h' + this.headingDepth, heading); var className = typeof heading == 'string' - ? {'class': heading.toLowerCase().replace(/[^\d\w_]/, '-')} + ? {'class': heading.toLowerCase().replace(/[^\d\w_]/mg, '-').replace(/-+/gm, '-')} : null; if (content instanceof Array) { this.ul(content, className, fn); } else if (fn) { - this.tag('div', className, fn); + this.tag('div', className, function(){ + fn.call(this, content); + }); } else { this.tag('div', className, content); } diff --git a/docs/src/gen-docs.js b/docs/src/gen-docs.js index a287a2be..7e17ea8f 100644 --- a/docs/src/gen-docs.js +++ b/docs/src/gen-docs.js @@ -20,10 +20,11 @@ var work = callback.chain(function(){ var writes = callback.chain(function(){ ngdoc.merge(docs); docs.forEach(function(doc){ - writer.output(doc.name + '.html', doc.html(), writes.waitFor()); + writer.output(doc.id + '.html', doc.html(), writes.waitFor()); }); var metadata = ngdoc.metadata(docs); - writer.output('docs-keywords.js', ['NG_PAGES=', JSON.stringify(metadata), ';'], writes.waitFor()); + writer.output('docs-keywords.js', ['NG_PAGES=', JSON.stringify(metadata).replace(/{/g, '\n{'), ';'], writes.waitFor()); + writer.copyImages(writes.waitFor()); writer.copy('index.html', writes.waitFor()); writer.copy('docs.js', writes.waitFor()); writer.copy('docs.css', writes.waitFor()); diff --git a/docs/src/ngdoc.js b/docs/src/ngdoc.js index 7fb9af73..e01d9ccf 100644 --- a/docs/src/ngdoc.js +++ b/docs/src/ngdoc.js @@ -4,6 +4,7 @@ var Showdown = require('showdown').Showdown; var DOM = require('dom.js').DOM; +var htmlEscape = require('dom.js').htmlEscape; var NEW_LINE = /\n\r?/; exports.markdown = markdown; @@ -39,7 +40,7 @@ Doc.prototype = { var words = []; var tokens = this.text.toLowerCase().split(/[,\.\`\'\"\s]+/mg); tokens.forEach(function(key){ - var match = key.match(/^(([a-z]|ng\:)[\w\_\-]{2,})/); + var match = key.match(/^(([\$\_a-z]|ng\:)[\w\_\-]{2,})/); if (match){ key = match[1]; if (!keywords[key]) { @@ -57,6 +58,11 @@ Doc.prototype = { var atText; var match; var self = this; + this.scenarios = []; + this.requires = []; + this.param = []; + this.properties = []; + this.methods = []; self.text.split(NEW_LINE).forEach(function(line){ if (match = line.match(/^\s*@(\w+)(\s+(.*))?/)) { // we found @name ... @@ -73,6 +79,9 @@ Doc.prototype = { }); flush(); this.shortName = (this.name || '').split(/[\.#]/).pop(); + this.id = this.id // if we have an id just use it + || (((this.file||'').match(/.*\/([^\/]*)\.ngdoc/)||{})[1]) // try to extract it from file name + || this.name; // default to name this.description = markdown(this.description); this['this'] = markdown(this['this']); this.exampleDescription = markdown(this.exampleDescription || this.exampleDesc); @@ -94,7 +103,6 @@ Doc.prototype = { optional: !!match[2], 'default':match[6] }; - self.param = self.param || []; self.param.push(param); } else if (atName == 'returns') { var match = text.match(/^{([^}=]+)}\s+(.*)/); @@ -105,9 +113,16 @@ Doc.prototype = { type: match[1], description: markdown(text.replace(match[0], match[2])) }; + } else if(atName == 'description') { + text.replace(/<doc:scenario>([\s\S]*)<\/doc:scenario>/mi, + function(_, scenario){ + self.scenarios.push(scenario); + }); + self.description = text; } else if(atName == 'requires') { - self.requires = self.requires || []; self.requires.push(text); + } else if(atName == 'scenario') { + self.scenarios.push(text); } else if(atName == 'property') { var match = text.match(/^({(\S+)}\s*)?(\S+)(\s+(.*))?/); if (!match) { @@ -118,7 +133,6 @@ Doc.prototype = { name: match[3], description: match[5] || '' }; - self.properties = self.properties || []; self.properties.push(property); } else { self[atName] = text; @@ -135,25 +149,10 @@ Doc.prototype = { notice('workInProgress', 'Work in Progress', 'This page is currently being revised. It might be incomplete or contain inaccuracies.'); notice('deprecated', 'Deprecated API', self.deprecated); - dom.h('Description', self.description, html); - dom.h('Dependencies', self.requires); - usage(); - - dom.h('Methods', self.methods, function(method){ - var signature = (method.param || []).map(property('name')); - dom.h(method.shortName + '(' + signature.join(', ') + ')', method, function(){ - dom.html(method.description); - method.html_usage_parameters(dom); - dom.example(method.exampleDescription, method.example, false); - }); - }); - dom.h('Properties', self.properties, function(property){ - dom.h(property.name, function(){ - dom.text(property.description); - dom.example(property.exampleDescription, property.example, false); - }); - }); + (self['html_usage_' + self.ngdoc] || function(){ + throw new Error("Don't know how to format @ngdoc: " + self.ngdoc); + }).call(self, dom); dom.example(self.exampleDescription, self.example, self.scenario); }); @@ -162,29 +161,6 @@ Doc.prototype = { ////////////////////////// - function html(text){ - this.html(text); - } - - function usage(){ - (self['html_usage_' + self.ngdoc] || function(){ - throw new Error("Don't know how to format @ngdoc: " + self.ngdoc); - }).call(self, dom); - } - - function section(name, property, fn) { - var value = self[property]; - if (value) { - dom.h2(name); - if (typeof value == 'string') { - value = markdown(value) + '\n'; - fn ? fn(value) : dom.html(value); - } else if (value instanceof Array) { - dom.ul(value, fn); - } - } - } - function notice(name, legend, msg){ if (self[name] == undefined) return; dom.tag('fieldset', {'class':name}, function(dom){ @@ -240,6 +216,8 @@ Doc.prototype = { html_usage_function: function(dom){ var self = this; + dom.h('Description', self.description, dom.html); + dom.h('Dependencies', self.requires); dom.h('Usage', function(){ dom.code(function(){ dom.text(self.name); @@ -256,11 +234,13 @@ Doc.prototype = { html_usage_directive: function(dom){ var self = this; + dom.h('Description', self.description, dom.html); + dom.h('Dependencies', self.requires); dom.h('Usage', function(){ dom.tag('pre', {'class':"brush: js; html-script: true;"}, function(){ dom.text('<' + self.element + ' '); dom.text(self.shortName); - if (self.param) { + if (self.param.length) { dom.text('="' + self.param[0].name + '"'); } dom.text('>\n ...\n'); @@ -272,6 +252,8 @@ Doc.prototype = { html_usage_filter: function(dom){ var self = this; + dom.h('Description', self.description, dom.html); + dom.h('Dependencies', self.requires); dom.h('Usage', function(){ dom.h('In HTML Template Binding', function(){ dom.tag('code', function(){ @@ -302,6 +284,8 @@ Doc.prototype = { html_usage_formatter: function(dom){ var self = this; + dom.h('Description', self.description, dom.html); + dom.h('Dependencies', self.requires); dom.h('Usage', function(){ dom.h('In HTML Template Binding', function(){ dom.code(function(){ @@ -340,6 +324,8 @@ Doc.prototype = { html_usage_validator: function(dom){ var self = this; + dom.h('Description', self.description, dom.html); + dom.h('Dependencies', self.requires); dom.h('Usage', function(){ dom.h('In HTML Template Binding', function(){ dom.code(function(){ @@ -368,6 +354,8 @@ Doc.prototype = { html_usage_widget: function(dom){ var self = this; + dom.h('Description', self.description, dom.html); + dom.h('Dependencies', self.requires); dom.h('Usage', function(){ dom.h('In HTML Template Binding', function(){ dom.code(function(){ @@ -376,7 +364,7 @@ Doc.prototype = { dom.text(self.element); dom.text(' '); dom.text(self.shortName.substring(1)); - if (self.param) { + if (self.param.length) { dom.text('="'); dom.text(self.param[0].name); dom.text('"'); @@ -407,9 +395,27 @@ Doc.prototype = { }, html_usage_overview: function(dom){ + dom.html(this.description); }, html_usage_service: function(dom){ + dom.h('Description', this.description, dom.html); + dom.h('Dependencies', this.requires); + + dom.h('Methods', this.methods, function(method){ + var signature = (method.param || []).map(property('name')); + dom.h(method.shortName + '(' + signature.join(', ') + ')', method, function(){ + dom.html(method.description); + method.html_usage_parameters(dom); + dom.example(method.exampleDescription, method.example, false); + }); + }); + dom.h('Properties', this.properties, function(property){ + dom.h(property.name, function(){ + dom.text(property.description); + dom.example(property.exampleDescription, property.example, false); + }); + }); }, parameters: function(dom, separator, skipFirst, prefix) { @@ -433,7 +439,7 @@ Doc.prototype = { ////////////////////////////////////////////////////////// function markdown (text) { if (!text) return text; - var parts = text.split(/(<pre>[\s\S]*?<\/pre>)/), + var parts = text.split(/(<pre>[\s\S]*?<\/pre>|<doc:example>[\s\S]*?<\/doc:example>)/), match; parts.forEach(function(text, i){ @@ -443,39 +449,51 @@ function markdown (text) { content.replace(/</g, '<').replace(/>/g, '>') + '</pre></div>'; }); + } else if (text.match(/^<doc:example>/)) { + text = text.replace(/(<doc:source>)([\s\S]*)(<\/doc:source>)/mi, + function(_, before, content, after){ + return before + htmlEscape(content) + after; + }); + text = text.replace(/(<doc:scenario>)([\s\S]*)(<\/doc:scenario>)/mi, + function(_, before, content, after){ + return before + htmlEscape(content) + after; + }); } else { text = text.replace(/<angular\/>/gm, '<tt><angular/></tt>'); - text = new Showdown.converter().makeHtml(text.replace(/^#/gm, '###')); - - while (match = text.match(R_LINK)) { - text = text.replace(match[0], '<a href="#!' + match[1] + '"><code>' + - (match[4] || match[1]) + - '</code></a>'); - } + text = text.replace(/{@link ([^\s}]+)((\s|\n)+(.+?))?\s*}/gm, + function(_all, url, _2, _3, title){ + return '<a href="#!' + url + '">' + + (url.match(/^angular\./) ? '<code>' : '') + + (title || url) + + (url.match(/^angular\./) ? '</code>' : '') + + '</a>'; + }); + text = new Showdown.converter().makeHtml(text); } parts[i] = text; }); return parts.join(''); }; -var R_LINK = /{@link ([^\s}]+)((\s|\n)+(.+?))?\s*}/m; - // 1 123 3 4 42 ////////////////////////////////////////////////////////// function scenarios(docs){ var specs = []; docs.forEach(function(doc){ + specs.push('describe("' + doc.id + '", function(){'); + specs.push(' beforeEach(function(){'); + specs.push(' browser().navigateTo("index.html#!' + doc.id + '");'); + specs.push(' });'); + specs.push(''); + doc.scenarios.forEach(function(scenario){ + specs.push(trim(scenario, ' ')); + specs.push(''); + }); + specs.push('});'); + specs.push(''); if (doc.scenario) { - specs.push('describe("'); - specs.push(doc.name); - specs.push('", function(){\n'); - specs.push(' beforeEach(function(){\n'); - specs.push(' browser().navigateTo("index.html#!' + doc.name + '");'); - specs.push(' });\n\n'); - specs.push(doc.scenario); - specs.push('\n});\n\n'); } }); - return specs; + return specs.join('\n'); } @@ -483,8 +501,17 @@ function scenarios(docs){ function metadata(docs){ var words = []; docs.forEach(function(doc){ + var path = (doc.name || '').split(/(\.|\:\s+)/); + for ( var i = 1; i < path.length; i++) { + path.splice(i, 1); + } + var depth = path.length - 1; + var shortName = path.pop(); words.push({ - name:doc.name, + id: doc.id, + name: doc.name, + depth: depth, + shortName: shortName, type: doc.ngdoc, keywords:doc.keywords() }); @@ -493,37 +520,50 @@ function metadata(docs){ return words; } -function keywordSort(a,b){ - // supper ugly comparator that orders all utility methods and objects before all the other stuff - // like widgets, directives, services, etc. - // Mother of all beautiful code please forgive me for the sin that this code certainly is. - - if (a.name === b.name) return 0; - if (a.name === 'angular') return -1; - if (b.name === 'angular') return 1; - - function namespacedName(page) { - return (page.name.match(/\./g).length === 1 && page.type !== 'overview' ? '0' : '1') + page.name; +var KEYWORD_PRIORITY = { + '.guide': 1, + '.guide.overview': 1, + '.angular': 7, + '.angular.Array': 7, + '.angular.Object': 7, + '.angular.directive': 7, + '.angular.filter': 7, + '.angular.formatter': 7, + '.angular.scope': 7, + '.angular.service': 7, + '.angular.validator': 7, + '.angular.widget': 7 +}; +function keywordSort(a, b){ + function mangleName(doc) { + var path = doc.id.split(/\./); + var mangled = []; + var partialName = ''; + path.forEach(function(name){ + partialName += '.' + name; + mangled.push(KEYWORD_PRIORITY[partialName] || 5); + mangled.push(name); + }); + return mangled.join('.'); } - - var namespacedA = namespacedName(a), - namespacedB = namespacedName(b); - - return namespacedA < namespacedB ? -1 : 1; + var nameA = mangleName(a); + var nameB = mangleName(b); + return nameA < nameB ? -1 : (nameA > nameB ? 1 : 0); } ////////////////////////////////////////////////////////// -function trim(text) { +function trim(text, prefix) { var MAX = 9999; var empty = RegExp.prototype.test.bind(/^\s*$/); var lines = text.split('\n'); var minIndent = MAX; + prefix = prefix || ''; lines.forEach(function(line){ minIndent = Math.min(minIndent, indent(line)); }); for ( var i = 0; i < lines.length; i++) { - lines[i] = lines[i].substring(minIndent); + lines[i] = prefix + lines[i].substring(minIndent); } // remove leading lines while (empty(lines[0])) { diff --git a/docs/src/templates/doc_widgets.js b/docs/src/templates/doc_widgets.js index 2d1ab8c6..39b9ff48 100644 --- a/docs/src/templates/doc_widgets.js +++ b/docs/src/templates/doc_widgets.js @@ -58,11 +58,22 @@ function indent(text) { var lines = text.split(/\n/); var lineNo = []; + // remove any leading blank lines while (lines[0].match(/^\s*$/)) lines.shift(); + // remove any trailing blank lines while (lines[lines.length - 1].match(/^\s*$/)) lines.pop(); + var minIndent = 999; for ( var i = 0; i < lines.length; i++) { - lines[i] = ' ' + lines[i]; - lineNo.push(6 + i); + var line = lines[0]; + var indent = line.match(/^\s*/)[0]; + if (indent !== line && indent.length < minIndent) { + minIndent = indent.length; + } + } + + for ( var i = 0; i < lines.length; i++) { + lines[i] = ' ' + lines[i].substring(minIndent); + lineNo.push(5 + i); } return {html: lines.join('\n'), hilite: lineNo.join(',') }; }; diff --git a/docs/src/templates/docs.css b/docs/src/templates/docs.css index a687ce87..a7566e79 100644 --- a/docs/src/templates/docs.css +++ b/docs/src/templates/docs.css @@ -181,11 +181,16 @@ a { } #sidebar ul li.level-0 { + margin-top: 0.5em; margin-left: 0em; font-weight: bold; font-size: 1.2em; } +#sidebar ul li.level-0:first-child { + margin-top: 0; +} + #sidebar ul li.level-1.level-angular { font-family: monospace; font-weight: normal; @@ -211,6 +216,11 @@ a { font-family: monospace; } +#sidebar ul li.level-4 { + margin-left: 4em; + font-family: monospace; +} + /* Warning and Info Banners */ @@ -282,3 +292,11 @@ a { #main::-webkit-scrollbar { background-color:#fff; } + +/* Content */ +img.right { + float: right; +} +h1, h2, h3, h4, h5 { + clear: both; +} diff --git a/docs/src/templates/docs.js b/docs/src/templates/docs.js index f1cfc3e7..aaea8c9d 100644 --- a/docs/src/templates/docs.js +++ b/docs/src/templates/docs.js @@ -4,7 +4,7 @@ function DocsController($location, $browser, $window) { window.$root = this.$root; this.getUrl = function(page){ - return '#!' + page.name; + return '#!' + page.id; }; this.getCurrentPartial = function(){ @@ -13,14 +13,14 @@ function DocsController($location, $browser, $window) { this.getTitle = function(){ var hashPath = $location.hashPath || '!angular'; - if (hashPath.match(/^!angular/)) { + if (hashPath.match(/^!/)) { this.partialTitle = hashPath.substring(1); } return this.partialTitle; }; this.getClass = function(page) { - var depth = page.name.split(/\./).length - 1, + var depth = page.depth, cssClass = 'level-' + depth + (page.name == this.getTitle() ? ' selected' : ''); if (depth == 1 && page.type !== 'overview') cssClass += ' level-angular'; @@ -40,8 +40,4 @@ function DocsController($location, $browser, $window) { } -angular.filter('short', function(name){ - return (name||'').split(/\./).pop(); -}); - SyntaxHighlighter['defaults'].toolbar = false; diff --git a/docs/src/templates/index.html b/docs/src/templates/index.html index bb80a4ba..538be297 100644 --- a/docs/src/templates/index.html +++ b/docs/src/templates/index.html @@ -34,7 +34,7 @@ tabindex="1" accesskey="s"/> <ul id="api-list"> <li ng:repeat="page in pages.$filter(search)" ng:class="getClass(page)"> - <a href="{{getUrl(page)}}" ng:click="" tabindex="2">{{page.name | short}}</a> + <a href="{{getUrl(page)}}" ng:click="" tabindex="2">{{page.shortName}}</a> </li> </ul> </div> diff --git a/docs/src/writer.js b/docs/src/writer.js index c72a54a4..953302d4 100644 --- a/docs/src/writer.js +++ b/docs/src/writer.js @@ -50,12 +50,27 @@ exports.makeDir = function (path, callback) { }; exports.copy = function(filename, callback){ - //console.log('writing', OUTPUT_DIR + filename, '...'); - fs.readFile('docs/src/templates/' + filename, function(err, content){ + copy('docs/src/templates/' + filename, OUTPUT_DIR + filename, callback); +}; + +function copy(from, to, callback) { + //console.log('writing', to, '...'); + fs.readFile(from, function(err, content){ if (err) return callback.error(err); - fs.writeFile( - OUTPUT_DIR + filename, - content, - callback); + fs.writeFile(to, content, callback); }); +} + +exports.copyImages = function(callback) { + exports.makeDir(OUTPUT_DIR + '/img', callback.waitFor(function(){ + fs.readdir('docs/img', callback.waitFor(function(err, files){ + if (err) return this.error(err); + files.forEach(function(file){ + if (file.match(/\.(png|gif|jpg|jpeg)$/)) { + copy('docs/img/' + file, OUTPUT_DIR + '/img/' + file, callback.waitFor()); + } + }); + callback(); + })); + })); }; |
