diff options
Diffstat (limited to 'docs/src/ngdoc.js')
| -rw-r--r-- | docs/src/ngdoc.js | 1435 |
1 files changed, 0 insertions, 1435 deletions
diff --git a/docs/src/ngdoc.js b/docs/src/ngdoc.js deleted file mode 100644 index 78f968d9..00000000 --- a/docs/src/ngdoc.js +++ /dev/null @@ -1,1435 +0,0 @@ -/** - * All parsing/transformation code goes here. All code here should be sync to ease testing. - */ -var DOM = require('./dom.js').DOM; -var htmlEscape = require('./dom.js').htmlEscape; -var Example = require('./example.js').Example; -var NEW_LINE = /\n\r?/; -var globalID = 0; -var fs = require('fs'); -var fspath = require('path'); -var shell = require('shelljs'); -var gruntUtil = require('../../lib/grunt/utils.js'); -var errorsJson; -var marked = require('marked'); -marked.setOptions({ - gfm: true, - tables: true -}); - -var lookupMinerrMsg = function (doc) { - var code, namespace; - - if (errorsJson === undefined) { - errorsJson = require('../../build/errors.json').errors; - } - - namespace = doc.getMinerrNamespace(); - code = doc.getMinerrCode(); - if (namespace === undefined) { - return errorsJson[code]; - } - return errorsJson[namespace][code]; -}; - -exports.trim = trim; -exports.metadata = metadata; -exports.scenarios = scenarios; -exports.writeProtractorTest = writeProtractorTest; -exports.merge = merge; -exports.checkBrokenLinks = checkBrokenLinks; -exports.Doc = Doc; - -exports.ngVersions = function() { - var versions = [], regex = /^v([1-9]\d*(?:\.\d+\S+)+)$/; //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]); - } - }); - - //match the future version of AngularJS that is set in the package.json file - return expandVersions(sortVersionsNaturally(versions), exports.ngCurrentVersion().full); - - function expandVersions(versions, latestVersion) { - var RC_VERSION = /rc\d/; - //copy the array to avoid changing the versions param data - //the latest version is not on the git tags list, but - //docs.angularjs.org will always point to master as of 1.2 - versions = versions.concat([latestVersion]); - - var firstUnstable, expanded = []; - for(var i=versions.length-1;i>=0;i--) { - var version = versions[i], - split = version.split('.'), - isMaster = version == latestVersion, - isStable = split[1] % 2 === 0 && !RC_VERSION.test(version); - - var title = 'AngularJS - v' + version; - - var docsPath = version < '1.0.2' ? 'docs-' + version : 'docs'; - - var url = isMaster ? - 'http://docs.angularjs.org' : - 'http://code.angularjs.org/' + version + '/' + docsPath; - - expanded.push({ - version : version, - stable : isStable, - title : title, - group : (isStable ? 'Stable' : 'Unstable'), - url : url - }); - }; - - return expanded; - }; - - function sortVersionsNaturally(versions) { - var versionMap = {}, - NON_RC_RELEASE_NUMBER = 999; - for(var i = versions.length - 1; i >= 0; i--) { - var version = versions[i]; - var split = version.split(/\.|rc/); - var baseVersion = split[0] + '.' + split[1] + '.' + split[2]; - - //create a map of RC versions for each version - //this way each RC version can be sorted in "natural" order - versionMap[baseVersion] = versionMap[baseVersion] || []; - - //NON_RC_RELEASE_NUMBER is used to signal the non-RC version for the release and - //it will always appear at the top of the list since the number is so high! - versionMap[baseVersion].push( - version == baseVersion ? NON_RC_RELEASE_NUMBER : parseInt(version.match(/rc\.?(\d+)/)[1])); - }; - - //flatten the map so that the RC versions occur in a natural sorted order - //and the official non-RC version shows up at the top of the list of sorted - //RC versions! - var angularVersions = []; - sortedKeys(versionMap).forEach(function(key) { - var versions = versionMap[key]; - - //basic numerical sort - versions.sort(function(a,b) { - return a - b; - }); - - versions.forEach(function(v) { - angularVersions.push(v == NON_RC_RELEASE_NUMBER ? key : key + 'rc' + v); - }); - }); - - return angularVersions; - }; - - function sortedKeys(obj) { - var keys = []; - for(var key in obj) { - keys.push(key); - }; - keys.sort(true); - return keys; - }; -}; - -exports.ngCurrentVersion = function() { - return gruntUtil.getVersion(); -}; - -var BOOLEAN_ATTR = {}; -['multiple', 'selected', 'checked', 'disabled', 'readOnly', 'required'].forEach(function(value) { - BOOLEAN_ATTR[value] = true; -}); - -////////////////////////////////////////////////////////// -function Doc(text, file, line) { - if (typeof text == 'object') { - for ( var key in text) { - this[key] = text[key]; - } - } else { - this.text = text; - this.file = file; - this.line = line; - } - this.scenarios = this.scenarios || []; - this.protractorTests = this.protractorTests || []; - this.requires = this.requires || []; - this.param = this.param || []; - this.properties = this.properties || []; - this.methods = this.methods || []; - this.events = this.events || []; - this.links = this.links || []; - this.anchors = this.anchors || []; -} -Doc.METADATA_IGNORE = (function() { - var words = fs.readFileSync(__dirname + '/ignore.words', 'utf8'); - return words.toString().split(/[,\s\n\r]+/gm); -})(); - - -Doc.prototype = { - keywords: function keywords() { - var keywords = {}; - var words = []; - Doc.METADATA_IGNORE.forEach(function(ignore){ keywords[ignore] = true; }); - - function extractWords(text) { - var tokens = text.toLowerCase().split(/[\.\s,`'"#]+/mg); - tokens.forEach(function(key){ - var match = key.match(/^((ng:|[\$_a-z])[\w\-_]+)/); - if (match){ - key = match[1]; - if (!keywords[key]) { - keywords[key] = true; - words.push(key); - } - } - }); - } - - extractWords(this.text); - this.properties.forEach(function(prop) { - extractWords(prop.text || prop.description || ''); - }); - this.methods.forEach(function(method) { - extractWords(method.text || method.description || ''); - }); - if (this.ngdoc === 'error') { - words.push(this.getMinerrNamespace()); - words.push(this.getMinerrCode()); - } - words.sort(); - return words.join(' '); - }, - - shortDescription : function() { - if (!this.description) return this.description; - var text = this.description.split("\n")[0]; - text = text.replace(/<.+?\/?>/g, ''); - text = text.replace(/{/g,'{'); - text = text.replace(/}/g,'}'); - return text; - }, - - getMinerrNamespace: function () { - if (this.ngdoc !== 'error') { - throw new Error('Tried to get the minErr namespace, but @ngdoc ' + - this.ngdoc + ' was supplied. It should be @ngdoc error'); - } - return this.name.split(':')[0]; - }, - - getMinerrCode: function () { - if (this.ngdoc !== 'error') { - throw new Error('Tried to get the minErr error code, but @ngdoc ' + - this.ngdoc + ' was supplied. It should be @ngdoc error'); - } - return this.name.split(':')[1]; - }, - - /** - * Converts relative urls (without section) into absolute - * Absolute url means url with section - * - * @example - * - if the link is inside any api doc: - * angular.widget -> api/angular.widget - * - * - if the link is inside any guid doc: - * intro -> guide/intro - * - * @param {string} url Absolute or relative url - * @returns {string} Absolute url - */ - convertUrlToAbsolute: function(url) { - var hashIdx = url.indexOf('#'); - - // Lowercase hash parts of the links, - // so that we can keep correct API names even when the urls are lowercased. - if (hashIdx !== -1) { - url = url.substr(0, hashIdx) + url.substr(hashIdx).toLowerCase(); - } - - if (url.substr(-1) == '/') return url + 'index'; - if (url.match(/\//)) return url; - return this.section + '/' + url; - }, - - markdown: function(text) { - if (!text) return text; - - var self = this, - IS_URL = /^(https?:\/\/|ftps?:\/\/|mailto:|\.|\/)/, - IS_ANGULAR = /^(api\/)?(angular|ng|AUTO)\./, - IS_HASH = /^#/, - parts = trim(text).split(/(<pre.*?>[\s\S]*?<\/pre>|<doc:example(\S*).*?>[\s\S]*?<\/doc:example>|<example[^>]*>[\s\S]*?<\/example>)/), - seq = 0, - placeholderMap = {}; - - function placeholder(text) { - var id = 'REPLACEME' + (seq++); - placeholderMap[id] = text; - return id; - } - - function extractInlineDocCode(text, tag) { - if(tag == 'all') { - //use a greedy operator to match the last </docs> tag - regex = /\/\/<docs.*?>([.\s\S]+)\/\/<\/docs>/im; - } - else { - //use a non-greedy operator to match the next </docs> tag - regex = new RegExp("\/\/<docs\\s*tag=\"" + tag + "\".*?>([.\\s\\S]+?)\/\/<\/docs>","im"); - } - var matches = regex.exec(text.toString()); - return matches && matches.length > 1 ? matches[1] : ""; - } - - parts.forEach(function(text, i) { - parts[i] = (text || ''). - replace(/<example(?:\s+module="([^"]*)")?(?:\s+deps="([^"]*)")?(\s+animations="true")?>([\s\S]*?)<\/example>/gmi, - function(_, module, deps, animations, content) { - - var example = new Example(self.scenarios, self.protractorTests); - if(animations) { - example.enableAnimations(); - example.addDeps('angular-animate.js'); - } - - example.setModule(module); - example.addDeps(deps); - content.replace(/<file\s+name="([^"]*)"\s*>([\s\S]*?)<\/file>/gmi, function(_, name, content) { - example.addSource(name, content); - }); - content.replace(/<file\s+src="([^"]+)"(?:\s+tag="([^"]+)")?(?:\s+name="([^"]+)")?\s*\/?>/gmi, function(_, file, tag, name) { - if(fs.existsSync(file)) { - var content = fs.readFileSync(file, 'utf8'); - if(content && content.length > 0) { - if(tag && tag.length > 0) { - content = extractInlineDocCode(content, tag); - } - name = name && name.length > 0 ? name : fspath.basename(file); - example.addSource(name, content); - } - } - return ''; - }) - return placeholder(example.toHtml()); - }). - replace(/(?:\*\s+)?<file.+?src="([^"]+)"(?:\s+tag="([^"]+)")?\s*\/?>/i, function(_, file, tag) { - if(fs.existsSync(file)) { - var content = fs.readFileSync(file, 'utf8'); - if(tag && tag.length > 0) { - content = extractInlineDocCode(content, tag); - } - return content; - } - }). - replace(/^<doc:example(\s+[^>]*)?>([\s\S]*)<\/doc:example>/mi, function(_, attrs, content) { - var html, script, scenario, - example = new Example(self.scenarios, self.protractorTests); - - example.setModule((attrs||'module=""').match(/^\s*module=["'](.*)["']\s*$/)[1]); - content. - replace(/<doc:source(\s+[^>]*)?>([\s\S]*)<\/doc:source>/mi, function(_, attrs, content) { - example.addSource('index.html', content. - replace(/<script>([\s\S]*)<\/script>/mi, function(_, script) { - example.addSource('script.js', script); - return ''; - }). - replace(/<style>([\s\S]*)<\/style>/mi, function(_, style) { - example.addSource('style.css', style); - return ''; - }) - ); - }). - replace(/(<doc:scenario>)([\s\S]*)(<\/doc:scenario>)/mi, function(_, before, content){ - example.addSource('scenario.js', content); - }).replace(/(<doc:protractor>)([\s\S]*)(<\/doc:protractor>)/mi, function(_, before, content){ - example.addSource('protractorTest.js', content); - }); - - return placeholder(example.toHtml()); - }). - replace(/^<pre(.*?)>([\s\S]*?)<\/pre>/mi, function(_, attrs, content){ - return placeholder( - '<pre'+attrs+' class="prettyprint linenums">' + - content.replace(/</g, '<').replace(/>/g, '>') + - '</pre>'); - }). - replace(/<div([^>]*)><\/div>/, '<div$1>\n<\/div>'). - replace(/{@link\s+([^\s}]+)\s*([^}]*?)\s*}/g, function(_all, url, title){ - var isFullUrl = url.match(IS_URL), - isAngular = url.match(IS_ANGULAR), - isHash = url.match(IS_HASH), - absUrl = isHash - ? url - : (isFullUrl ? url : self.convertUrlToAbsolute(url)); - - if (!isFullUrl) self.links.push(absUrl); - - return '<a href="' + absUrl + '">' + - (isAngular ? '<code>' : '') + - (title || url).replace(/^#/g, '').replace(/\n/g, ' ') + - (isAngular ? '</code>' : '') + - '</a>'; - }). - replace(/{@type\s+(\S+)(?:\s+(\S+))?}/g, function(_, type, url) { - url = url || '#'; - return '<a href="' + url + '" class="' + self.prepare_type_hint_class_name(type) + '">' + type + '</a>'; - }). - replace(/{@installModule\s+(\S+)?}/g, function(_, module) { - return explainModuleInstallation(module); - }); - }); - text = parts.join(''); - - function prepareClassName(text) { - return text.toLowerCase().replace(/[_\W]+/g, '-'); - }; - - var pageClassName, suffix = '-page'; - if(this.name) { - var split = this.name.match(/^\s*(.+?)\s*:\s*(.+)/); - if(split && split.length > 1) { - var before = prepareClassName(split[1]); - var after = prepareClassName(split[2]); - pageClassName = before + suffix + ' ' + before + '-' + after + suffix; - } - } - pageClassName = pageClassName || prepareClassName(this.name || 'docs') + suffix; - - text = '<div class="' + pageClassName + '">' + - marked(text) + - '</div>'; - text = text.replace(/(?:<p>)?(REPLACEME\d+)(?:<\/p>)?/g, function(_, id) { - return placeholderMap[id]; - }); - - //!annotate CONTENT - //!annotate="REGEX" CONTENT - //!annotate="REGEX" TITLE|CONTENT - text = text.replace(/\n?\/\/!annotate\s*(?:=\s*['"](.+?)['"])?\s+(.+?)\n\s*(.+?\n)/img, - function(_, pattern, content, line) { - var pattern = new RegExp(pattern || '.+'); - var title, text, split = content.split(/\|/); - if(split.length > 1) { - text = split[1]; - title = split[0]; - } - else { - title = 'Info'; - text = content; - } - return "\n" + line.replace(pattern, function(match) { - return '<div class="nocode nocode-content" data-popover ' + - 'data-content="' + text + '" ' + - 'data-title="' + title + '">' + - match + - '</div>'; - }); - } - ); - - //!details /path/to/local/docs/file.html - //!details="REGEX" /path/to/local/docs/file.html - text = text.replace(/\/\/!details\s*(?:=\s*['"](.+?)['"])?\s+(.+?)\n\s*(.+?\n)/img, - function(_, pattern, url, line) { - url = '/notes/' + url; - var pattern = new RegExp(pattern || '.+'); - return line.replace(pattern, function(match) { - return '<div class="nocode nocode-content" data-foldout data-url="' + url + '">' + match + '</div>'; - }); - } - ); - - return text; - }, - - parse: function() { - var atName; - var atText; - var match; - var self = this; - self.text.split(NEW_LINE).forEach(function(line){ - if ((match = line.match(/^\s*@(\w+)(\s+(.*))?/))) { - // we found @name ... - // if we have existing name - flush(); - atName = match[1]; - atText = []; - if(match[3]) atText.push(match[3]); - } else { - if (atName) { - atText.push(line); - } - } - }); - flush(); - this.shortName = this.name.split(/[\.:#]/).pop().trim(); - this.id = this.id || // if we have an id just use it - (this.ngdoc === 'error' ? this.name : '') || - (((this.file||'').match(/.*(\/|\\)([^(\/|\\)]*)\.ngdoc/)||{})[2]) || // try to extract it from file name - this.name; // default to name - this.moduleName = parseModuleName(this.id); - this.description = this.markdown(this.description); - this.example = this.markdown(this.example); - this['this'] = this.markdown(this['this']); - return this; - - function parseModuleName(id) { - var module = id.split('.')[0]; - if(module == 'angular') { - module = 'ng'; - } - return module; - } - - function flush() { - if (atName) { - var text = trim(atText.join('\n')), match; - if (atName == 'param') { - match = text.match(/^\{([^}]+)\}\s+(([^\s=]+)|\[(\S+)=([^\]]+)\])\s+(.*)/); - // 1 1 23 3 4 4 5 5 2 6 6 - if (!match) { - throw new Error("Not a valid 'param' format: " + text + ' (found in: ' + self.file + ':' + self.line + ')'); - } - - var optional = (match[1].slice(-1) === '='); - var param = { - name: match[4] || match[3], - description:self.markdown(text.replace(match[0], match[6])), - type: optional ? match[1].substring(0, match[1].length-1) : match[1], - optional: optional, - default: match[5] - }; - self.param.push(param); - } else if (atName == 'returns' || atName == 'return') { - match = text.match(/^\{([^}]+)\}\s+(.*)/); - if (!match) { - throw new Error("Not a valid 'returns' format: " + text + ' (found in: ' + self.file + ':' + self.line + ')'); - } - self.returns = { - type: match[1], - description: self.markdown(text.replace(match[0], match[2])) - }; - } else if(atName == 'requires') { - match = text.match(/^([^\s]*)\s*([\S\s]*)/); - self.requires.push({ - name: match[1], - text: self.markdown(match[2]) - }); - } else if(atName == 'property') { - match = text.match(/^\{(\S+)\}\s+(\S+)(\s+(.*))?/); - if (!match) { - throw new Error("Not a valid 'property' format: " + text + ' (found in: ' + self.file + ':' + self.line + ')'); - } - var property = new Doc({ - type: match[1], - name: match[2], - shortName: match[2], - description: self.markdown(text.replace(match[0], match[4])) - }); - self.properties.push(property); - } else if(atName == 'eventType') { - match = text.match(/^([^\s]*)\s+on\s+([\S\s]*)/); - self.type = match[1]; - self.target = match[2]; - } else { - self[atName] = text; - } - } - } - }, - - html: function() { - var dom = new DOM(), - self = this, - minerrMsg; - - var gitTagFromFullVersion = function(version) { - var match = version.match(/sha\.(\w{7})/); - - if (match) { - // git sha - return match[1]; - } - - // git tag - return 'v' + version; - }; - - if (this.section === 'api') { - dom.tag('a', { - href: 'http://github.com/angular/angular.js/tree/' + - gitTagFromFullVersion(gruntUtil.getVersion().full) + '/' + self.file + '#L' + self.line, - class: 'view-source btn btn-action' }, function(dom) { - dom.tag('i', {class:'icon-zoom-in'}, ' '); - dom.text(' View source'); - }); - } - dom.tag('a', { - href: 'http://github.com/angular/angular.js/edit/master/' + self.file, - class: 'improve-docs btn btn-primary' }, function(dom) { - dom.tag('i', {class:'icon-edit'}, ' '); - dom.text(' Improve this doc'); - }); - dom.h(title(this), function() { - notice('deprecated', 'Deprecated API', self.deprecated); - if (self.ngdoc === 'error') { - minerrMsg = lookupMinerrMsg(self); - dom.tag('pre', { - class:'minerr-errmsg', - 'error-display': minerrMsg.replace(/"/g, '"') - }, minerrMsg); - } - if (self.ngdoc != 'overview') { - dom.h('Description', self.description, dom.html); - } - dom.h('Dependencies', self.requires, function(require){ - dom.tag('code', function() { - dom.tag('a', {href: 'api/ng.' + require.name}, require.name); - }); - dom.html(require.text); - }); - - (self['html_usage_' + self.ngdoc] || function() { - throw new Error("Don't know how to format @ngdoc: " + self.ngdoc); - }).call(self, dom); - - dom.h('Example', self.example, dom.html); - }); - - self.anchors = dom.anchors; - - return dom.toString(); - - ////////////////////////// - - function notice(name, legend, msg){ - if (self[name] === undefined) return; - dom.tag('fieldset', {'class':name}, function(dom){ - dom.tag('legend', legend); - dom.text(msg); - }); - } - - }, - - prepare_type_hint_class_name : function(type) { - var typeClass = type.toLowerCase().match(/^[-\w]+/) || []; - typeClass = typeClass[0] ? typeClass[0] : 'object'; - return 'label type-hint type-hint-' + typeClass; - }, - - html_usage_parameters: function(dom) { - var self = this; - var params = this.param ? this.param : []; - if(this.animations) { - dom.h('Animations', this.animations, function(animations){ - dom.html('<ul>'); - var animations = animations.split("\n"); - animations.forEach(function(ani) { - dom.html('<li>'); - dom.text(ani); - dom.html('</li>'); - }); - dom.html('</ul>'); - }); - dom.html('<a href="api/ngAnimate.$animate">Click here</a> to learn more about the steps involved in the animation.'); - } - if(params.length > 0) { - dom.html('<h2>Parameters</h2>'); - dom.html('<table class="variables-matrix table table-bordered table-striped">'); - dom.html('<thead>'); - dom.html('<tr>'); - dom.html('<th>Param</th>'); - dom.html('<th>Type</th>'); - dom.html('<th>Details</th>'); - dom.html('</tr>'); - dom.html('</thead>'); - dom.html('<tbody>'); - for(var i=0;i<params.length;i++) { - param = params[i]; - var name = param.name; - var types = param.type; - if(types[0]=='(') { - types = types.substr(1); - } - - var limit = types.length - 1; - if(types.charAt(limit) == ')' && types.charAt(limit-1) != '(') { - types = types.substr(0,limit); - } - types = types.split(/\|(?![\(\)\w\|\s]+>)/); - if (param.optional) { - name += ' <div><em>(optional)</em></div>'; - } - dom.html('<tr>'); - dom.html('<td>' + name + '</td>'); - dom.html('<td>'); - for(var j=0;j<types.length;j++) { - var type = types[j]; - dom.html('<a href="" class="' + self.prepare_type_hint_class_name(type) + '">'); - dom.text(type); - dom.html('</a>'); - } - - dom.html('</td>'); - var description = '<td>'; - description += param.description; - if (param.default) { - description += ' <p><em>(default: ' + param.default + ')</em></p>'; - } - description += '</td>'; - dom.html(description); - dom.html('</tr>'); - }; - dom.html('</tbody>'); - dom.html('</table>'); - } - }, - - html_usage_returns: function(dom) { - var self = this; - if (self.returns) { - dom.html('<h2>Returns</h2>'); - dom.html('<table class="variables-matrix">'); - dom.html('<tr>'); - dom.html('<td>'); - dom.html('<a href="" class="' + self.prepare_type_hint_class_name(self.returns.type) + '">'); - dom.text(self.returns.type); - dom.html('</a>'); - dom.html('</td>'); - dom.html('<td>'); - dom.html(self.returns.description); - dom.html('</td>'); - dom.html('</tr>'); - dom.html('</table>'); - } - }, - - html_usage_this: function(dom) { - var self = this; - if (self['this']) { - dom.h(function(dom){ - dom.html("Method's <code>this</code>"); - }, function(dom){ - dom.html(self['this']); - }); - } - }, - - html_usage_function: function(dom){ - var self = this; - var name = self.name.match(/^angular(\.mock)?\.(\w+)$/) ? self.name : self.name.split(/\./).pop() - - dom.h('Usage', function() { - dom.code(function() { - dom.text(name); - dom.text('('); - self.parameters(dom, ', '); - dom.text(');'); - }); - - self.html_usage_parameters(dom); - self.html_usage_this(dom); - self.html_usage_returns(dom); - }); - this.method_properties_events(dom); - }, - - html_usage_property: function(dom){ - var self = this; - dom.h('Usage', function() { - dom.code(function() { - dom.text(self.name); - }); - - self.html_usage_returns(dom); - }); - }, - - html_usage_directive: function(dom){ - var self = this; - dom.h('Usage', function() { - var restrict = self.restrict || 'A'; - - if (restrict.match(/E/)) { - dom.html('<p>'); - dom.text('This directive can be used as custom element, but be aware of '); - dom.tag('a', {href:'guide/ie'}, 'IE restrictions'); - dom.text('.'); - dom.html('</p>'); - } - - if (self.usage) { - dom.tag('pre', function() { - dom.tag('code', function() { - dom.text(self.usage); - }); - }); - } else { - if (restrict.match(/E/)) { - dom.text('as element:'); - dom.code(function() { - dom.text('<'); - dom.text(dashCase(self.shortName)); - renderParams('\n ', '="', '"'); - dom.text('>\n</'); - dom.text(dashCase(self.shortName)); - dom.text('>'); - }); - } - if (restrict.match(/A/)) { - var element = self.element || 'ANY'; - dom.text('as attribute'); - dom.code(function() { - dom.text('<' + element + ' '); - dom.text(dashCase(self.shortName)); - renderParams('\n ', '="', '"', true); - dom.text('>\n ...\n'); - dom.text('</' + element + '>'); - }); - } - if (restrict.match(/C/)) { - dom.text('as class'); - var element = self.element || 'ANY'; - dom.code(function() { - dom.text('<' + element + ' class="'); - dom.text(dashCase(self.shortName)); - renderParams(' ', ': ', ';', true); - dom.text('">\n ...\n'); - dom.text('</' + element + '>'); - }); - } - } - self.html_usage_directiveInfo(dom); - self.html_usage_parameters(dom); - }); - - self.method_properties_events(dom); - - function renderParams(prefix, infix, suffix, skipSelf) { - (self.param||[]).forEach(function(param) { - var skip = skipSelf && (param.name == self.shortName || param.name.indexOf(self.shortName + '|') == 0); - if (!skip) { - dom.text(prefix); - dom.text(param.optional ? '[' : ''); - var parts = param.name.split('|'); - dom.text(dashCase(parts[skipSelf ? 0 : 1] || parts[0])); - } - if (BOOLEAN_ATTR[param.name]) { - dom.text(param.optional ? ']' : ''); - } else { - dom.text(BOOLEAN_ATTR[param.name] ? '' : infix ); - dom.text(('{' + param.type + '}').replace(/^\{\'(.*)\'\}$/, '$1')); - dom.text(suffix); - dom.text(param.optional && !skip ? ']' : ''); - } - }); - } - - }, - - html_usage_filter: function(dom){ - var self = this; - dom.h('Usage', function() { - dom.h('In HTML Template Binding', function() { - dom.tag('code', function() { - if (self.usage) { - dom.text(self.usage); - } else { - dom.text('{{ '); - dom.text(self.shortName); - dom.text('_expression | '); - dom.text(self.shortName); - self.parameters(dom, ':', true); - dom.text(' }}'); - } - }); - }); - - dom.h('In JavaScript', function() { - dom.tag('code', function() { - dom.text('$filter(\''); - dom.text(self.shortName); - dom.text('\')('); - self.parameters(dom, ', '); - dom.text(')'); - }); - }); - - self.html_usage_parameters(dom); - self.html_usage_this(dom); - self.html_usage_returns(dom); - }); - }, - - html_usage_inputType: function(dom){ - var self = this; - dom.h('Usage', function() { - dom.code(function() { - dom.text('<input type="' + self.shortName + '"'); - (self.param||[]).forEach(function(param){ - dom.text('\n '); - dom.text(param.optional ? ' [' : ' '); - dom.text(dashCase(param.name)); - dom.text(BOOLEAN_ATTR[param.name] ? '' : '="{' + param.type + '}"'); - dom.text(param.optional ? ']' : ''); - }); - dom.text('>'); - }); - self.html_usage_parameters(dom); - }); - }, - - html_usage_directiveInfo: function(dom) { - var self = this; - var list = []; - - - if (self.scope !== undefined) { - list.push('This directive creates new scope.'); - } - if (self.priority !== undefined) { - list.push('This directive executes at priority level ' + self.priority + '.'); - } - - if (list.length) { - dom.h('Directive info', function() { - dom.ul(list); - }); - } - }, - - html_usage_overview: function(dom){ - dom.html(this.description); - }, - - html_usage_error: function (dom) { - dom.html(); - }, - - html_usage_interface: function(dom){ - var self = this; - - if (this.param.length) { - dom.h('Usage', function() { - dom.code(function() { - dom.text(self.name.split('.').pop()); - dom.text('('); - self.parameters(dom, ', '); - dom.text(');'); - }); - - self.html_usage_parameters(dom); - self.html_usage_this(dom); - self.html_usage_returns(dom); - }); - } - this.method_properties_events(dom); - }, - - html_usage_service: function(dom) { - this.html_usage_interface(dom) - }, - - html_usage_object: function(dom) { - this.html_usage_interface(dom) - }, - - method_properties_events: function(dom) { - var self = this; - if (self.methods.length) { - dom.div({class:'member method'}, function(){ - 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); - self.html_usage_this(dom); - method.html_usage_returns(dom); - - dom.h('Example', method.example, dom.html); - }); - }); - }); - } - if (self.properties.length) { - dom.div({class:'member property'}, function(){ - dom.h('Properties', self.properties, function(property){ - dom.h(property.shortName, function() { - dom.html(property.description); - if (!property.html_usage_returns) { - console.log(property); - } - property.html_usage_returns(dom); - dom.h('Example', property.example, dom.html); - }); - }); - }); - } - if (self.events.length) { - dom.div({class:'member event'}, function(){ - dom.h('Events', self.events, function(event){ - dom.h(event.shortName, event, function() { - dom.html(event.description); - if (event.type == 'listen') { - dom.tag('div', {class:'inline'}, function() { - dom.h('Listen on:', event.target); - }); - } else { - dom.tag('div', {class:'inline'}, function() { - dom.h('Type:', event.type); - }); - dom.tag('div', {class:'inline'}, function() { - dom.h('Target:', event.target); - }); - } - event.html_usage_parameters(dom); - self.html_usage_this(dom); - - dom.h('Example', event.example, dom.html); - }); - }); - }); - } - }, - - parameters: function(dom, separator, skipFirst, prefix) { - var sep = prefix ? separator : ''; - (this.param||[]).forEach(function(param, i){ - if (!(skipFirst && i==0)) { - if (param.optional) { - dom.text('[' + sep + param.name + ']'); - } else { - dom.text(sep + param.name); - } - } - sep = separator; - }); - } - -}; -////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////// -var GLOBALS = /^angular\.([^\.]+)$/, - MODULE = /^((?:(?!^angular\.)[^\.])+)$/, - MODULE_MOCK = /^angular\.mock\.([^\.]+)$/, - MODULE_DIRECTIVE = /^((?:(?!^angular\.)[^\.])+)\.directive:([^\.]+)$/, - MODULE_DIRECTIVE_INPUT = /^((?:(?!^angular\.)[^\.])+)\.directive:input\.([^\.]+)$/, - MODULE_FILTER = /^((?:(?!^angular\.)[^\.])+)\.filter:([^\.]+)$/, - MODULE_SERVICE = /^((?:(?!^angular\.)[^\.])+)\.([^\.]+?)(Provider)?$/, - MODULE_TYPE = /^((?:(?!^angular\.)[^\.])+)\..+\.([A-Z][^\.]+)$/; - - -function title(doc) { - if (!doc.name) return doc.name; - var match, - text = doc.name; - - var makeTitle = function (name, type, componentType, component) { - // Makes title markup. - // makeTitle('Foo', 'directive', 'module', 'ng') -> - // Foo is a directive in module ng - return function () { - this.tag('code', name); - this.tag('div', function () { - this.tag('span', {class: 'hint'}, function () { - if (type && component) { - this.text(type + ' in ' + componentType + ' '); - this.tag('code', component); - } - }); - }); - }; - }; - - if (doc.ngdoc === 'error') { - return makeTitle(doc.fullName, 'error', 'component', doc.getMinerrNamespace()); - } else if (text == 'angular.Module') { - return makeTitle('Module', 'Type', 'module', 'ng'); - } else if (match = text.match(GLOBALS)) { - return makeTitle('angular.' + match[1], 'API', 'module', 'ng'); - } else if (match = text.match(MODULE)) { - return makeTitle('', '', 'module', match[1]); - } else if (match = text.match(MODULE_MOCK)) { - return makeTitle('angular.mock.' + match[1], 'API', 'module', 'ng'); - } else if (match = text.match(MODULE_DIRECTIVE)) { - return makeTitle(match[2], 'directive', 'module', match[1]); - } else if (match = text.match(MODULE_DIRECTIVE_INPUT)) { - return makeTitle('input [' + match[2] + ']', 'directive', 'module', match[1]); - } else if (match = text.match(MODULE_FILTER)) { - return makeTitle(match[2], 'filter', 'module', match[1]); - } else if (match = text.match(MODULE_SERVICE)) { - return makeTitle(match[2] + (match[3] || ''), 'service', 'module', match[1]); - } else if (match = text.match(MODULE_TYPE)) { - return makeTitle(match[2], 'type', 'module', match[1]); - } - return text; -} - - -function scenarios(docs){ - var specs = []; - - specs.push('describe("angular+jqlite", function() {'); - appendSpecs('index-nocache.html#!/'); - specs.push('});'); - - specs.push(''); - specs.push(''); - - specs.push('describe("angular+jquery", function() {'); - appendSpecs('index-jq-nocache.html#!/'); - specs.push('});'); - - return specs.join('\n'); - - function appendSpecs(urlPrefix) { - docs.forEach(function(doc){ - specs.push(' describe("' + doc.section + '/' + doc.id + '", function() {'); - specs.push(' beforeEach(function() {'); - specs.push(' browser().navigateTo("' + urlPrefix + doc.section + '/' + doc.id + '");'); - specs.push(' });'); - specs.push(' '); - doc.scenarios.forEach(function(scenario){ - specs.push(indentCode(trim(scenario), 4)); - specs.push(''); - }); - specs.push('});'); - specs.push(''); - }); - } -} - -function writeProtractorTest(doc, pathPrefix){ - var lines = []; - lines.push('describe("' + doc.section + '/' + doc.id + '", function() {'); - lines.push(' beforeEach(function() {'); - lines.push(' browser.get("' + pathPrefix + doc.section + '/' + doc.id + '");'); - lines.push(' });'); - lines.push(''); - doc.protractorTests.forEach(function(test){ - lines.push(indentCode(trim(test), 0)); - lines.push(''); - }); - lines.push('});'); - lines.push(''); - return lines.join('\n'); -} - - -////////////////////////////////////////////////////////// -function metadata(docs){ - var pages = []; - docs.forEach(function(doc){ - var path = (doc.name || '').split(/(\:\s*)/); - for ( var i = 1; i < path.length; i++) { - path.splice(i, 1); - } - var shortName = path.pop().trim(); - - if (path.pop() == 'input') { - shortName = 'input [' + shortName + ']'; - } - - pages.push({ - section: doc.section, - id: doc.id, - name: title(doc), - shortName: shortName, - type: doc.ngdoc, - moduleName: doc.moduleName, - shortDescription: doc.shortDescription(), - keywords: doc.keywords() - }); - }); - pages.sort(sidebarSort); - return pages; -} - -var KEYWORD_PRIORITY = { - '.index': 1, - '.overview': 1, - '.bootstrap': 2, - '.mvc': 3, - '.scopes': 4, - '.compiler': 5, - '.templates': 6, - '.services': 7, - '.di': 8, - '.unit-testing': 9, - '.dev_guide': 9, - '.dev_guide.overview': 1, - '.dev_guide.bootstrap': 2, - '.dev_guide.bootstrap.auto_bootstrap': 1, - '.dev_guide.bootstrap.manual_bootstrap': 2, - '.dev_guide.mvc': 3, - '.dev_guide.mvc.understanding_model': 1, - '.dev_guide.mvc.understanding_controller': 2, - '.dev_guide.mvc.understanding_view': 3, - '.dev_guide.scopes': 4, - '.dev_guide.scopes.understanding_scopes': 1, - '.dev_guide.scopes.internals': 2, - '.dev_guide.compiler': 5, - '.dev_guide.templates': 6, - '.dev_guide.services': 7, - '.dev_guide.di': 8, - '.dev_guide.unit-testing': 9 -}; - -var GUIDE_PRIORITY = [ - 'introduction', - 'overview', - 'concepts', - 'dev_guide.mvc', - - 'dev_guide.mvc.understanding_controller', - 'dev_guide.mvc.understanding_model', - 'dev_guide.mvc.understanding_view', - - 'dev_guide.services.understanding_services', - 'dev_guide.services.managing_dependencies', - 'dev_guide.services.creating_services', - 'dev_guide.services.injecting_controllers', - 'dev_guide.services.testing_services', - 'dev_guide.services.$location', - 'dev_guide.services', - - 'databinding', - 'dev_guide.templates.css-styling', - 'dev_guide.templates.filters.creating_filters', - 'dev_guide.templates.filters', - 'dev_guide.templates.filters.using_filters', - 'dev_guide.templates', - - 'di', - 'providers', - 'module', - 'scope', - 'expression', - 'bootstrap', - 'directive', - 'compiler', - - 'forms', - 'animations', - - 'dev_guide.e2e-testing', - 'dev_guide.unit-testing', - - 'i18n', - 'ie', - 'migration', -]; - -function sidebarSort(a, b){ - priorityA = GUIDE_PRIORITY.indexOf(a.id); - priorityB = GUIDE_PRIORITY.indexOf(b.id); - - if (priorityA > -1 || priorityB > -1) { - return priorityA < priorityB ? -1 : (priorityA > priorityB ? 1 : 0); - } - - 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 (doc.section + '/' + mangled.join('.')).toLowerCase(); - } - var nameA = mangleName(a); - var nameB = mangleName(b); - return nameA < nameB ? -1 : (nameA > nameB ? 1 : 0); -} - - -////////////////////////////////////////////////////////// -function trim(text) { - var MAX_INDENT = 9999; - var empty = RegExp.prototype.test.bind(/^\s*$/); - var lines = text.split('\n'); - var minIndent = MAX_INDENT; - var indentRegExp; - var ignoreLine = (lines[0][0] != ' ' && lines.length > 1); - // ignore first line if it has no indentation and there is more than one line - - lines.forEach(function(line){ - if (ignoreLine) { - ignoreLine = false; - return; - } - - var indent = line.match(/^\s*/)[0].length; - if (indent > 0 || minIndent == MAX_INDENT) { - minIndent = Math.min(minIndent, indent); - } - }); - - indentRegExp = new RegExp('^\\s{0,' + minIndent + '}'); - - for ( var i = 0; i < lines.length; i++) { - lines[i] = lines[i].replace(indentRegExp, ''); - } - - // remove leading lines - while (empty(lines[0])) { - lines.shift(); - } - - // remove trailing - while (empty(lines[lines.length - 1])) { - lines.pop(); - } - return lines.join('\n'); -} - -function indentCode(text, spaceCount) { - var lines = text.split('\n'), - indent = '', - fixedLines = []; - - while(spaceCount--) indent += ' '; - - lines.forEach(function(line) { - fixedLines.push(indent + line); - }); - - return fixedLines.join('\n'); -} - -////////////////////////////////////////////////////////// -function merge(docs){ - var byFullId = {}; - - docs.forEach(function(doc) { - byFullId[doc.section + '/' + doc.id] = doc; - }); - - for(var i = 0; i < docs.length;) { - if (findParent(docs[i], 'method') || findParent(docs[i], 'property') || findParent(docs[i], 'event')) { - docs.splice(i, 1); - } else { - i++; - } - } - - function findParent(doc, name) { - var parentName = doc[name + 'Of']; - if (!parentName) return false; - - var parent = byFullId['api/' + parentName]; - if (!parent) - throw new Error("No parent named '" + parentName + "' for '" + - doc.name + "' in @" + name + "Of."); - - var listName = (name + 's').replace(/ys$/, 'ies'); - var list = parent[listName] = (parent[listName] || []); - list.push(doc); - list.sort(orderByName); - return true; - } - - function orderByName(a, b){ - return a.name < b.name ? -1 : (a.name > b.name ? 1 : 0); - } -} -////////////////////////////////////////////////////////// - - -function checkBrokenLinks(docs) { - var byFullId = Object.create(null); - - docs.forEach(function(doc) { - byFullId[doc.section + '/' + doc.id] = doc; - if (doc.section === 'api') { - doc.anchors.push('directive', 'service', 'filter', 'function'); - } - }); - - docs.forEach(function(doc) { - doc.links.forEach(function(link) { - // convert #id to path#id - if (link[0] == '#') { - link = doc.section + '/' + doc.id.split('#').shift() + link; - } - - var parts = link.split('#'); - var pageLink = parts[0]; - var anchorLink = parts[1]; - var linkedPage = byFullId[pageLink]; - - if (!linkedPage) { - console.log('WARNING: ' + doc.section + '/' + doc.id + ' (defined in ' + doc.file + ') points to a non existing page "' + link + '"!'); - } else if (anchorLink && linkedPage.anchors.indexOf(anchorLink) === -1) { - console.log('WARNING: ' + doc.section + '/' + doc.id + ' (defined in ' + doc.file + ') points to a non existing anchor "' + link + '"!'); - } - }); - }); -} - - -function property(name) { - return function(value){ - return value[name]; - }; -} - - -var DASH_CASE_REGEXP = /[A-Z]/g; -function dashCase(name){ - return name.replace(DASH_CASE_REGEXP, function(letter, pos) { - return (pos ? '-' : '') + letter.toLowerCase(); - }); -} -////////////////////////////////////////////////////////// - -function explainModuleInstallation(moduleName){ - var ngMod = ngModule(moduleName), - modulePackage = 'angular-' + moduleName, - modulePackageFile = modulePackage + '.js'; - - // Deal with inconsistent ngMock naming - doing it verbosely and explicitly here - // rather than cleverly interweaving it in the previous lines to make it obvious - // what is going on - if ( moduleName == 'mock' ) { - modulePackage = 'angular-mocks'; - modulePackageFile = modulePackage + '.js'; - } - - return '<h1>Installation</h1>' + - '<p>First include <code>' + modulePackageFile +'</code> in your HTML:</p><pre><code>' + - ' <script src="angular.js">\n' + - ' <script src="' + modulePackageFile + '"></pre></code>' + - - '<p>You can download this file from the following places:</p>' + - '<ul>' + - '<li>[Google CDN](https://developers.google.com/speed/libraries/devguide#angularjs)<br>' + - 'e.g. <code>"//ajax.googleapis.com/ajax/libs/angularjs/X.Y.Z/' + modulePackageFile + '"</code></li>' + - '<li>[Bower](http://bower.io)<br>' + - 'e.g. <code>bower install ' + modulePackage + '@X.Y.Z</code></li>' + - '<li><a href="http://code.angularjs.org/">code.angularjs.org</a><br>' + - 'e.g. <code>"//code.angularjs.org/X.Y.Z/' + modulePackageFile + '"</code></li>' + - '</ul>' + - '<p>where X.Y.Z is the AngularJS version you are running.</p>' + - '<p>Then load the module in your application by adding it as a dependent module:</p><pre><code>' + - ' angular.module(\'app\', [\'' + ngMod + '\']);</pre></code>' + - - '<p>With that you\'re ready to get started!</p>'; -} - -function ngModule(moduleName) { - return 'ng' + moduleName[0].toUpperCase() + moduleName.substr(1); -} |
