diff --git a/rhino_modules/jsdoc/util/templateHelper.js b/rhino_modules/jsdoc/util/templateHelper.js
index 53201528..4f2beb2d 100644
--- a/rhino_modules/jsdoc/util/templateHelper.js
+++ b/rhino_modules/jsdoc/util/templateHelper.js
@@ -1,3 +1,4 @@
+/*global env: true */
/**
* @module jsdoc/util/templateHelper
*/
@@ -22,10 +23,11 @@ exports.setTutorials = function(root) {
exports.globalName = 'global';
exports.fileExtension = '.html';
+exports.scopeToPunc = { 'static': '.', 'inner': '~', 'instance': '#' };
function getNamespace(kind) {
if (dictionary.isNamespace(kind)) {
- return kind+':';
+ return kind + ':';
}
return '';
}
@@ -58,6 +60,222 @@ var linkMap = {
urlToLongname: {}
};
+var longnameToUrl = exports.longnameToUrl = linkMap.longnameToUrl;
+
+var linkto = exports.linkto = function(longname, linktext) {
+ var url = longnameToUrl[longname];
+ return url ? '' + (linktext || longname) + '' : (linktext || longname);
+};
+
+var htmlsafe = exports.htmlsafe = function(str) {
+ return str.replace(/} The matching items.
+ */
+var find = exports.find = function(data, spec, sort) {
+ sort = sort === false ? sort : true;
+
+ var items = data.get( data.find(spec) );
+ if (sort) {
+ items.sort(function(a, b) {
+ return a.name > b.name;
+ });
+ }
+
+ return items;
+};
+
+/**
+ * Retrieve all of the following types of members from a set of doclets:
+ *
+ * + Classes
+ * + Externals
+ * + Globals
+ * + Mixins
+ * + Modules
+ * + Namespaces
+ * @param {TAFFY} data The TaffyDB database to search.
+ * @return {object} An object with `classes`, `externals`, `globals`, `mixins`, `modules`, and
+ * `namespaces` properties. Each property contains an array of objects.
+ */
+exports.getMembers = function(data) {
+ return {
+ classes: find( data, {kind: 'class'} ),
+ externals: find( data, {kind: 'external'} ),
+ globals: find(data, {
+ kind: ['member', 'function', 'constant', 'typedef'],
+ 'memberof': {
+ 'isUndefined': true
+ }
+ }),
+ mixins: find( data, {kind: 'mixin'} ),
+ modules: find( data, {kind: 'module'} ),
+ namespaces: find( data, {kind: 'namespace'} )
+ };
+};
+
+/**
+ * Retrieve the member attributes for a doclet (for example, `virtual`, `static`, and
+ * `readonly`).
+ * @param {object} d The doclet whose attributes will be retrieved.
+ * @return {array} The member attributes for the doclet.
+ */
+exports.getAttribs = function(d) {
+ var attribs = [];
+
+ if (d.virtual) {
+ attribs.push('virtual');
+ }
+
+ if (d.access && d.access !== 'public') {
+ attribs.push(d.access);
+ }
+
+ if (d.scope && d.scope !== 'instance' && d.scope !== 'global') {
+ if (d.kind == 'function' || d.kind == 'member' || d.kind == 'constant') {
+ attribs.push(d.scope);
+ }
+ }
+
+ if (d.readonly === true) {
+ if (d.kind == 'member') {
+ attribs.push('readonly');
+ }
+ }
+
+ if (d.kind === 'constant') {
+ attribs.push('constant');
+ }
+
+ return attribs;
+};
+
+/**
+ * Retrieve links to allowed types for the member.
+ * @param {object} d The doclet whose types will be retrieved.
+ * @return {array} HTML links to allowed types for the member.
+ */
+exports.getSignatureTypes = function(d) {
+ var types = [];
+
+ if (d.type && d.type.names) {
+ types = d.type.names;
+ }
+
+ if (types && types.length) {
+ types = types.map(function(t) {
+ return linkto(t, htmlsafe(t));
+ });
+ }
+
+ return types;
+};
+
+/**
+ * Retrieve names of the parameters that the member accepts. If a value is provided for `optClass`,
+ * the names of optional parameters will be wrapped in a `` tag with that class.
+ * @param {object} d The doclet whose parameter names will be retrieved.
+ * @param {string} [optClass] The class to assign to the `` tag that is wrapped around the
+ * names of optional parameters. If a value is not provided, optional parameter names will not be
+ * wrapped with a `` tag. Must be a legal value for a CSS class name.
+ * @return {array} An array of parameter names, with or without `` tags wrapping the
+ * names of optional parameters.
+ */
+exports.getSignatureParams = function(d, optClass) {
+ var pnames = [];
+
+ if (d.params) {
+ d.params.forEach(function(p) {
+ if (p.name && p.name.indexOf('.') === -1) {
+ if (p.optional && optClass) {
+ pnames.push('' + p.name + '');
+ }
+ else {
+ pnames.push(p.name);
+ }
+ }
+ });
+ }
+
+ return pnames;
+};
+
+/**
+ * Retrieve links to types that the member can return.
+ * @param {object} d The doclet whose types will be retrieved.
+ * @return {array} HTML links to types that the member can return.
+ */
+exports.getSignatureReturns = function(d) {
+ var returnTypes = [];
+
+ if (d.returns) {
+ d.returns.forEach(function(r) {
+ if (r.type && r.type.names) {
+ if (!returnTypes.length) {
+ returnTypes = r.type.names;
+ }
+ }
+ });
+ }
+
+ if (returnTypes && returnTypes.length) {
+ returnTypes = returnTypes.map(function(r) {
+ return linkto(r);
+ });
+ }
+
+ return returnTypes;
+};
+
+/**
+ * Retrieve links to a member's ancestors.
+ * @param {TAFFY} data The TaffyDB database to search.
+ * @param {object} doclet The doclet whose ancestors will be retrieved.
+ * @return {array} HTML links to a member's ancestors.
+ */
+exports.getAncestorLinks = function(data, doclet) {
+ var ancestors = [],
+ doc = doclet.memberof;
+
+ while (doc) {
+ doc = find( data, {longname: doc}, false );
+ if (doc) { doc = doc[0]; }
+ if (!doc) { break; }
+ ancestors.unshift( linkto(doc.longname, (exports.scopeToPunc[doc.scope] || '') + doc.name) );
+ doc = doc.memberof;
+ }
+ if (ancestors.length) {
+ ancestors[ancestors.length - 1] += (exports.scopeToPunc[doclet.scope] || '');
+ }
+ return ancestors;
+};
+
+/**
+ * Remove members that will not be included in the output, including:
+ *
+ * + Undocumented members.
+ * + Members tagged `@ignore`.
+ * + Members of anonymous classes.
+ * + Members tagged `@private`, unless the `private` option is enabled.
+ * @param {TAFFY} data The TaffyDB database to prune.
+ * @return {TAFFY} The pruned database.
+ */
+exports.prune = function(data) {
+ data.remove({undocumented: true});
+ data.remove({ignore: true});
+ if (!env.opts.private) { data.remove({access: 'private'}); }
+ data.remove({memberof: ''});
+
+ return data;
+};
+
exports.registerLink = function(longname, url) {
linkMap.longnameToUrl[longname] = url;
linkMap.urlToLongname[url] = longname;
@@ -95,7 +313,31 @@ function toLink(longname, content) {
}
}
-var toTutorial = exports.toTutorial = function(tutorial, content) {
+var tutorialToUrl = exports.tutorialToUrl = function(tutorial) {
+ var node = tutorials.getByName(tutorial);
+ // no such tutorial
+ if (!node) {
+ require('jsdoc/util/error').handle( new Error('No such tutorial: '+tutorial) );
+ return;
+ }
+
+ return 'tutorial-' + strToFilename(node.name) + exports.fileExtension;
+};
+
+/**
+ * Retrieve a link to a tutorial, or the name of the tutorial if the tutorial is missing. If the
+ * `missingOpts` parameter is supplied, the names of missing tutorials will be prefixed by the
+ * specified text and wrapped in the specified HTML tag and CSS class.
+ * @param {string} tutorial The name of the tutorial.
+ * @param {string} content The link text to use.
+ * @param {object} [missingOpts] Options for displaying the name of a missing tutorial.
+ * @param {string} missingOpts.classname The CSS class to wrap around the tutorial name.
+ * @param {string} missingOpts.prefix The prefix to add to the tutorial name.
+ * @param {string} missingOpts.tag The tag to wrap around the tutorial name.
+ * @return {string} An HTML link to the tutorial, or the name of the tutorial with the specified
+ * options.
+ */
+var toTutorial = exports.toTutorial = function(tutorial, content, missingOpts) {
if (!tutorial) {
require('jsdoc/util/error').handle( new Error('Missing required parameter: tutorial') );
return;
@@ -104,12 +346,24 @@ var toTutorial = exports.toTutorial = function(tutorial, content) {
var node = tutorials.getByName(tutorial);
// no such tutorial
if (!node) {
- return 'Tutorial: '+tutorial+'';
+ missingOpts = missingOpts || {};
+ var tag = missingOpts.tag;
+ var classname = missingOpts.classname;
+
+ var link = tutorial;
+ if (missingOpts.prefix) {
+ link = missingOpts.prefix + link;
+ }
+ if (tag) {
+ link = '<' + tag + (classname ? (' class="' + classname + '">') : '>') + link;
+ link += '' + tag + '>';
+ }
+ return link;
}
content = content || node.title;
- return ''+content+'';
+ return '' + content + '';
};
/** Find symbol {@link ...} and {@tutorial ...} strings in text and turn into html links */
@@ -150,16 +404,3 @@ exports.createLink = function(doclet) {
return url;
};
-
-exports.longnameToUrl = linkMap.longnameToUrl;
-
-exports.tutorialToUrl = function(tutorial) {
- var node = tutorials.getByName(tutorial);
- // no such tutorial
- if (!node) {
- require('jsdoc/util/error').handle( new Error('No such tutorial: '+tutorial) );
- return;
- }
-
- return 'tutorial-'+strToFilename(node.name)+exports.fileExtension;
-};
diff --git a/templates/default/publish.js b/templates/default/publish.js
index 69d6ac66..312b2d9f 100644
--- a/templates/default/publish.js
+++ b/templates/default/publish.js
@@ -2,18 +2,198 @@
var template = require('jsdoc/template'),
fs = require('fs'),
helper = require('jsdoc/util/templateHelper'),
- scopeToPunc = { 'static': '.', 'inner': '~', 'instance': '#' },
- hasOwnProp = Object.prototype.hasOwnProperty;
+ scopeToPunc = helper.scopeToPunc,
+ hasOwnProp = Object.prototype.hasOwnProperty,
+ data,
+ view,
+ outdir = env.opts.destination;
+
+
+function find(spec, sort) {
+ return helper.find(data, spec, sort);
+}
+
+function tutoriallink(tutorial) {
+ return helper.toTutorial(tutorial, null, { tag: 'em', classname: 'disabled', prefix: 'Tutorial: ' });
+}
+
+function getAncestorLinks(doclet) {
+ return helper.getAncestorLinks(data, doclet);
+}
+
+var linkto = helper.linkto;
+
+var htmlsafe = helper.htmlsafe;
+
+function hashToLink(doclet, hash) {
+ if ( !/^(#.+)/.test(hash) ) { return hash; }
+
+ var url = helper.createLink(doclet);
+
+ url = url.replace(/(#.+|$)/, hash);
+ return '' + hash + '';
+}
+
+function addSignatureParams(f) {
+ var params = helper.getSignatureParams(f, 'optional');
+
+ f.signature = (f.signature || '') + '('+params.join(', ')+')';
+}
+
+function addSignatureReturns(f) {
+ var returnTypes = helper.getSignatureReturns(f);
+
+ f.signature = ''+(f.signature || '') + '' + ''+(returnTypes.length? ' → {'+returnTypes.join('|')+'}' : '')+'';
+}
+
+function addSignatureTypes(f) {
+ var types = helper.getSignatureTypes(f);
+
+ f.signature = (f.signature || '') + ''+(types.length? ' :'+types.join('|') : '')+'';
+}
+
+function addAttribs(f) {
+ var attribs = helper.getAttribs(f);
+
+ f.attribs = ''+htmlsafe(attribs.length? '<'+attribs.join(', ')+'> ' : '')+'';
+}
+
+function generate(title, docs, filename) {
+ var docData = {
+ title: title,
+ docs: docs
+ };
+
+ var path = outdir + '/' + filename,
+ html = view.render('container.tmpl', docData);
+
+ html = helper.resolveLinks(html); // turn {@link foo} into foo
+
+ fs.writeFileSync(path, html);
+}
/**
- @param {TAFFY} data See .
+ * Create the navigation sidebar.
+ * @param {object} members The members that will be used to create the sidebar.
+ * @param {array