From 2524664d4bbf33d27340f145eed13e836948692e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Wrzeszcz?= Date: Sun, 11 Dec 2011 14:12:42 +0100 Subject: [PATCH 1/7] Dropped template default parameter. --- rhino_modules/jsdoc/opts/parser.js | 1 - 1 file changed, 1 deletion(-) diff --git a/rhino_modules/jsdoc/opts/parser.js b/rhino_modules/jsdoc/opts/parser.js index 8ffead79..43cb6e3b 100644 --- a/rhino_modules/jsdoc/opts/parser.js +++ b/rhino_modules/jsdoc/opts/parser.js @@ -12,7 +12,6 @@ var common = { var argParser = new common.args.ArgParser(), ourOptions, defaults = { - template: 'templates/default', destination: './out/' }; From 5aca2ce33a1277b2f9794df98c4a0ab6046feeca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Wrzeszcz?= Date: Tue, 13 Dec 2011 10:38:25 +0100 Subject: [PATCH 2/7] Mark inherited methods. --- rhino_modules/jsdoc/augment.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rhino_modules/jsdoc/augment.js b/rhino_modules/jsdoc/augment.js index 36085bdd..bcbd470a 100644 --- a/rhino_modules/jsdoc/augment.js +++ b/rhino_modules/jsdoc/augment.js @@ -48,6 +48,8 @@ members = getMembers(parents[j], docs); for (var k=0, kk=members.length; k Date: Thu, 15 Dec 2011 10:02:05 +0100 Subject: [PATCH 3/7] Tutorials base structure. --- jsdoc.js | 12 ++++- rhino_modules/jsdoc/opts/parser.js | 1 + rhino_modules/jsdoc/tutorial.js | 63 ++++++++++++++++++++++++ rhino_modules/jsdoc/tutorial/resolver.js | 37 ++++++++++++++ 4 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 rhino_modules/jsdoc/tutorial.js create mode 100644 rhino_modules/jsdoc/tutorial/resolver.js diff --git a/jsdoc.js b/jsdoc.js index 5f8447a0..42656b37 100644 --- a/jsdoc.js +++ b/jsdoc.js @@ -142,7 +142,8 @@ function main() { opts: { parser: require('jsdoc/opts/parser'), } - }; + }, + resolver; env.opts = jsdoc.opts.parser.parse(env.args); @@ -240,6 +241,12 @@ function main() { exit(0); } + resolver = require('jsdoc/tutorial/resolver'); + var Tutorial = require('jsdoc/tutorial').Tutorial; + + // tutorials handling + //TODO + env.opts.template = env.opts.template || 'templates/default'; // should define a global "publish" function @@ -248,7 +255,8 @@ function main() { if (typeof publish === 'function') { publish( new (require('typicaljoe/taffy'))(docs), - env.opts + env.opts, + resolver.root ); } else { // TODO throw no publish warning? diff --git a/rhino_modules/jsdoc/opts/parser.js b/rhino_modules/jsdoc/opts/parser.js index 43cb6e3b..4c015b8e 100644 --- a/rhino_modules/jsdoc/opts/parser.js +++ b/rhino_modules/jsdoc/opts/parser.js @@ -25,6 +25,7 @@ argParser.addOption('r', 'recurse', false, 'Recurse into subdirectories when argParser.addOption('h', 'help', false, 'Print this message and quit.'); argParser.addOption('X', 'explain', false, 'Dump all found doclet internals to console and quit.'); argParser.addOption('q', 'query', true, 'Provide a querystring to define custom variable names/values to add to the options hash.'); +argParser.addOption('u', 'tutorials', false, 'Directory in which JSDoc should search for tutorials.'); // TODO [-R, recurseonly] = a number representing the depth to recurse diff --git a/rhino_modules/jsdoc/tutorial.js b/rhino_modules/jsdoc/tutorial.js new file mode 100644 index 00000000..f82ae93a --- /dev/null +++ b/rhino_modules/jsdoc/tutorial.js @@ -0,0 +1,63 @@ +/** + @overview + @author Rafał Wrzeszcz + @license Apache License 2.0 - See file 'LICENSE.md' in this project. + */ + +/** + @module jsdoc/tutorial + */ + +/** + @class + @classdesc Represents a single JSDoc tutorial. + @param {string} name - Tutorial name. + @param {string} content - Text content. + */ +exports.Tutorial = function(name, content) { + this.title = this.name = name; + this.content = content; + + // default values + this.parent = null; + this.children = []; + this.type = exports.Tutorial.HTML; +}; + +/** Tutorial source types. + @enum {string} + */ +exports.Tutorial.TYPES = { + HTML: "html", + MD: "markdown" +}; + +/** Moves children from current parent to different one. + @param {Tutorial} parent + */ +exports.Tutorial.prototype.setParent = function(parent) { + // removes node from old parent + if (this.parent) { + this.parent.removeChild(this); + } + + this.parent = parent; + this.parent.addChild(this); +}; + +/** Removes children from current node. + @param {Tutorial} child + */ +exports.Tutorial.prototype.removeChild = function(child) { + var index = this.children.indexOf(child); + if (index != -1) { + this.children.splice(index, 1); + } +}; + +/** Adds new children to current node. + @param {Tutorial} child + */ +exports.Tutorial.prototype.addChild = function(child) { + this.children.push(child); +}; diff --git a/rhino_modules/jsdoc/tutorial/resolver.js b/rhino_modules/jsdoc/tutorial/resolver.js new file mode 100644 index 00000000..807873fe --- /dev/null +++ b/rhino_modules/jsdoc/tutorial/resolver.js @@ -0,0 +1,37 @@ +/** + @overview + @author Rafał Wrzeszcz + @license Apache License 2.0 - See file 'LICENSE.md' in this project. + */ + +/** + @module jsdoc/tutorial/resolver + */ + +var tutorial = require('jsdoc/tutorial'); + +var tutorials = {}, + length = 0; + +/** Adds new tutorial. + @param {tutorial.Tutorial} tutorial - New tutorial. + */ +exports.addTutorial = function(tutorial) { + tutorials[tutorial.name] = tutorial; + ++length; + + // default temporary parent + tutorial.setParent(exports.root); +}; + +/** Root tutorial. + @type tutorial.Tutorial + */ +exports.root = new tutorial.Tutorial('', ''); + +/** Resolves hierarchical structure. + @param {object} map - Contents map. + */ +exports.resolve = function(map) { + //TODO +}; From 8105cef501dbf1d5ae3c70ccb4ea45e69f676355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Wrzeszcz?= Date: Thu, 15 Dec 2011 12:06:49 +0100 Subject: [PATCH 4/7] Tutorials parsing. --- Jake/templates/package.json.tmpl | 4 + jsdoc.js | 9 +- package.json | 8 +- rhino_modules/fs.js | 2 +- rhino_modules/jsdoc/opts/parser.js | 2 +- rhino_modules/jsdoc/tutorial.js | 56 ++++++++---- rhino_modules/jsdoc/tutorial/resolver.js | 107 ++++++++++++++++++++--- 7 files changed, 153 insertions(+), 35 deletions(-) diff --git a/Jake/templates/package.json.tmpl b/Jake/templates/package.json.tmpl index 2754bcf6..092cc3bc 100644 --- a/Jake/templates/package.json.tmpl +++ b/Jake/templates/package.json.tmpl @@ -21,6 +21,10 @@ { "name": "Michael Mathews", "email": "micmath@gmail.com" + }, + { + "name": "Rafa\u0105 Wrzeszcz", + "email": "rafal.wrzeszcz@wrzasq.pl" } ], "maintainers": [ diff --git a/jsdoc.js b/jsdoc.js index 42656b37..a0077d33 100644 --- a/jsdoc.js +++ b/jsdoc.js @@ -241,11 +241,14 @@ function main() { exit(0); } + // load this module anyway to ensure root instance exists + // it's not a problem since without tutorials root node will have empty children list resolver = require('jsdoc/tutorial/resolver'); - var Tutorial = require('jsdoc/tutorial').Tutorial; - // tutorials handling - //TODO + if (env.opts.tutorials) { + resolver.load(env.opts.tutorials); + resolver.resolve(); + } env.opts.template = env.opts.template || 'templates/default'; diff --git a/package.json b/package.json index 2257aeb5..ed6f2d26 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "JSDoc", "version": "3.0.0alpha", - "revision": "1319671194463", + "revision": "1323947228470", "description": "An automatic documentation generator for javascript.", "keywords": [ "documentation", "javascript" ], "licenses": [ @@ -21,6 +21,10 @@ { "name": "Michael Mathews", "email": "micmath@gmail.com" + }, + { + "name": "Rafa\u0105 Wrzeszcz", + "email": "rafal.wrzeszcz@wrzasq.pl" } ], "maintainers": [ @@ -29,4 +33,4 @@ "email": "micmath@gmail.com" } ] -} \ No newline at end of file +} diff --git a/rhino_modules/fs.js b/rhino_modules/fs.js index 8022dd6e..5b1c38ce 100644 --- a/rhino_modules/fs.js +++ b/rhino_modules/fs.js @@ -133,7 +133,7 @@ exports.copyFile = function(inFile, outDir, fileName) { bis.close(); }; -function toFile(path) { +var toFile = exports.toFile = function(path) { var parts = path.split(/[\\\/]/); return parts.pop(); } diff --git a/rhino_modules/jsdoc/opts/parser.js b/rhino_modules/jsdoc/opts/parser.js index 4c015b8e..5af5b15f 100644 --- a/rhino_modules/jsdoc/opts/parser.js +++ b/rhino_modules/jsdoc/opts/parser.js @@ -25,7 +25,7 @@ argParser.addOption('r', 'recurse', false, 'Recurse into subdirectories when argParser.addOption('h', 'help', false, 'Print this message and quit.'); argParser.addOption('X', 'explain', false, 'Dump all found doclet internals to console and quit.'); argParser.addOption('q', 'query', true, 'Provide a querystring to define custom variable names/values to add to the options hash.'); -argParser.addOption('u', 'tutorials', false, 'Directory in which JSDoc should search for tutorials.'); +argParser.addOption('u', 'tutorials', true, 'Directory in which JSDoc should search for tutorials.'); // TODO [-R, recurseonly] = a number representing the depth to recurse diff --git a/rhino_modules/jsdoc/tutorial.js b/rhino_modules/jsdoc/tutorial.js index f82ae93a..d042ceeb 100644 --- a/rhino_modules/jsdoc/tutorial.js +++ b/rhino_modules/jsdoc/tutorial.js @@ -1,11 +1,13 @@ /** @overview @author Rafał Wrzeszcz - @license Apache License 2.0 - See file 'LICENSE.md' in this project. + @license Apache License 2.0 - See file 'LICENSE.md' in this project. */ +var mdParser = require('evilstreak/markdown'); + /** - @module jsdoc/tutorial + @module jsdoc/tutorial */ /** @@ -13,27 +15,20 @@ @classdesc Represents a single JSDoc tutorial. @param {string} name - Tutorial name. @param {string} content - Text content. + @param {number} type - Source formating. */ -exports.Tutorial = function(name, content) { +exports.Tutorial = function(name, content, type) { this.title = this.name = name; this.content = content; + this.type = type; // default values this.parent = null; this.children = []; - this.type = exports.Tutorial.HTML; -}; - -/** Tutorial source types. - @enum {string} - */ -exports.Tutorial.TYPES = { - HTML: "html", - MD: "markdown" }; /** Moves children from current parent to different one. - @param {Tutorial} parent + @param {Tutorial} parent - New parent. */ exports.Tutorial.prototype.setParent = function(parent) { // removes node from old parent @@ -46,7 +41,7 @@ exports.Tutorial.prototype.setParent = function(parent) { }; /** Removes children from current node. - @param {Tutorial} child + @param {Tutorial} child - Old child. */ exports.Tutorial.prototype.removeChild = function(child) { var index = this.children.indexOf(child); @@ -56,8 +51,39 @@ exports.Tutorial.prototype.removeChild = function(child) { }; /** Adds new children to current node. - @param {Tutorial} child + @param {Tutorial} child - New child. */ exports.Tutorial.prototype.addChild = function(child) { this.children.push(child); }; + +/** Prepares source. + @return {string} HTML source. + */ +exports.Tutorial.prototype.parse = function() { + switch (this.type) { + // nothing to do + case exports.TYPES.HTML: + return this.content; + + // markdown + case exports.TYPES.MARKDOWN: + return mdParser.toHTML(this.content) + .replace(/&/g, '&') // because markdown escapes these + .replace(/</g, '<') + .replace(/>/g, '>'); + + // uhm... should we react somehow? + // if not then this case can be merged with TYPES.HTML + default: + return this.content; + } +}; + +/** Tutorial source types. + @enum {number} + */ +exports.TYPES = { + HTML: 1, + MARKDOWN: 2 +}; diff --git a/rhino_modules/jsdoc/tutorial/resolver.js b/rhino_modules/jsdoc/tutorial/resolver.js index 807873fe..baf115c4 100644 --- a/rhino_modules/jsdoc/tutorial/resolver.js +++ b/rhino_modules/jsdoc/tutorial/resolver.js @@ -1,27 +1,27 @@ /** @overview @author Rafał Wrzeszcz - @license Apache License 2.0 - See file 'LICENSE.md' in this project. + @license Apache License 2.0 - See file 'LICENSE.md' in this project. */ /** - @module jsdoc/tutorial/resolver + @module jsdoc/tutorial/resolver */ -var tutorial = require('jsdoc/tutorial'); - -var tutorials = {}, - length = 0; +var tutorial = require('jsdoc/tutorial'), + fs = require('fs'), + conf = {}, + tutorials = {}, + finder = /^(.*)\.(x(?:ht)?ml|html?|md|markdown|js(?:on)?)$/i; /** Adds new tutorial. - @param {tutorial.Tutorial} tutorial - New tutorial. + @param {tutorial.Tutorial} current - New tutorial. */ -exports.addTutorial = function(tutorial) { - tutorials[tutorial.name] = tutorial; - ++length; +exports.addTutorial = function(current) { + tutorials[current.name] = current; // default temporary parent - tutorial.setParent(exports.root); + current.setParent(exports.root); }; /** Root tutorial. @@ -29,9 +29,90 @@ exports.addTutorial = function(tutorial) { */ exports.root = new tutorial.Tutorial('', ''); +/** Load tutorials from given path. + @param {string} path - Tutorials directory. + */ +exports.load = function(path) { + var match, + type, + name, + current, + files = fs.ls(path); + + // tutorials handling + files.forEach(function(file) { + match = file.match(finder); + + // any filetype that can apply to tutorials + if (match) { + name = fs.toFile(match[1]); + content = fs.readFileSync(file); + + switch (match[2].toLowerCase()) { + // HTML type + case 'xml': + case 'xhtml': + case 'html': + case 'htm': + type = tutorial.TYPES.HTML; + break; + + // Markdown typs + case 'md': + case 'markdown': + type = tutorial.TYPES.MARKDOWN; + break; + + // configuration file + case 'js': + case 'json': + conf[name] = JSON.parse(content); + + // how can it be? check `finder' regexp + default: + // not a file we want to work with + return; + } + + current = new tutorial.Tutorial(name, content, type); + exports.addTutorial(current); + } + }); +}; + /** Resolves hierarchical structure. @param {object} map - Contents map. */ -exports.resolve = function(map) { - //TODO +exports.resolve = function() { + var item, + current; + for (var name in conf) { + // should we be restrictive here? + // what is someone just wants to keep sample sources in same directory with tutorials? + // I've decided to leave such cases alone + if (!(name in tutorials)) { + continue; + } + + item = conf[name]; + current = tutorials[name] + + // set title + if (item.title) { + current.title = item.title; + } + + // add children + if (item.children) { + item.children.forEach(function(child) { + // I really didn't want to throw you an exception in most cases + // but now, user, you pissed me off ;) + if (!(child in tutorials)) { + throw new Error("Missing child tutorial: " + child); + } + + tutorials[child].setParent(current); + }); + } + } }; From f6216e6d286454c1896d99e0235f6cb1053a8141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Wrzeszcz?= Date: Thu, 15 Dec 2011 12:47:56 +0100 Subject: [PATCH 5/7] Support for @tutorial tag (both DocBlock and inline). --- rhino_modules/jsdoc/schema.js | 7 +++ .../jsdoc/tag/dictionary/definitions.js | 8 +++ rhino_modules/jsdoc/tutorial/resolver.js | 8 +++ rhino_modules/jsdoc/util/templateHelper.js | 34 +++++++++++- templates/default/publish.js | 54 +++++++++++++------ .../default/static/styles/jsdoc-default.css | 4 ++ templates/default/tmpl/details.tmpl | 11 ++++ 7 files changed, 109 insertions(+), 17 deletions(-) diff --git a/rhino_modules/jsdoc/schema.js b/rhino_modules/jsdoc/schema.js index 2e3b1e0b..8cd96bd1 100644 --- a/rhino_modules/jsdoc/schema.js +++ b/rhino_modules/jsdoc/schema.js @@ -54,6 +54,13 @@ exports.jsdocSchema = { "items": { "type": "string" } + }, + "tutorials": { // extended tutorials + "type": ["string", "array"], + "optional": true, + "items": { + "type": "string" + } }, "deprecated": { // is usage of this symbol deprecated? "type": ["string", "boolean"], diff --git a/rhino_modules/jsdoc/tag/dictionary/definitions.js b/rhino_modules/jsdoc/tag/dictionary/definitions.js index 190e6fb5..f34cb108 100644 --- a/rhino_modules/jsdoc/tag/dictionary/definitions.js +++ b/rhino_modules/jsdoc/tag/dictionary/definitions.js @@ -486,6 +486,14 @@ exports.defineTags = function(dictionary) { } }); + dictionary.defineTag('tutorial', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + if (!doclet.tutorials) { doclet.tutorials = []; } + doclet.tutorials.push(tag.value); + } + }); + dictionary.defineTag('type', { mustHaveValue: true, canHaveType: true, diff --git a/rhino_modules/jsdoc/tutorial/resolver.js b/rhino_modules/jsdoc/tutorial/resolver.js index baf115c4..fc78ac02 100644 --- a/rhino_modules/jsdoc/tutorial/resolver.js +++ b/rhino_modules/jsdoc/tutorial/resolver.js @@ -29,6 +29,14 @@ exports.addTutorial = function(current) { */ exports.root = new tutorial.Tutorial('', ''); +/** Additional instance method for root node. + @param {string} name - Tutorial name. + @reutrn {tutorial.Tutorial} Tutorial instance. + */ +exports.root.getByName = function(name) { + return tutorials[name]; +}; + /** Load tutorials from given path. @param {string} path - Tutorials directory. */ diff --git a/rhino_modules/jsdoc/util/templateHelper.js b/rhino_modules/jsdoc/util/templateHelper.js index 3ff14c87..4d3710a2 100644 --- a/rhino_modules/jsdoc/util/templateHelper.js +++ b/rhino_modules/jsdoc/util/templateHelper.js @@ -8,7 +8,7 @@ var dictionary = require('jsdoc/tag/dictionary'); exports.globalName = 'global'; exports.fileExtension = '.html'; -/** Find symbol {@link ...} strings in text and turn into html links */ +/** Find symbol {@link ...} and {@tutorial ...} strings in text and turn into html links */ exports.resolveLinks = function(str) { str = str.replace(/(?:\[(.+?)\])?\{@link +(.+?)\}/gi, function(match, content, longname) { @@ -16,6 +16,12 @@ exports.resolveLinks = function(str) { } ); + str = str.replace(/(?:\[(.+?)\])?\{@tutorial +(.+?)\}/gi, + function(match, content, tutorial) { + return toTutorial(tutorial, content); + } + ); + return str; } @@ -102,4 +108,30 @@ function toLink(longname, content) { } } +/** @external {jsdoc.tutorial.Tutorial} */ +var tutorials; + +/** Sets tutorials map. + @param {jsdoc.tutorial.Tutorial} root - Root tutorial node. + */ +exports.setTutorials = function(root) { + tutorials = root; +}; + +exports.toTutorial = toTutorial = function(tutorial, content) { + if (!tutorial) { + throw new Error('Missing required parameter: tutorial'); + } + + var node = tutorials.getByName(tutorial); + // no such tutorial + if (!node) { + return 'Tutorial: '+tutorial+''; + } + + content = content || node.title; + + return ''+content+''; +} + exports.longnameToUrl = linkMap.longnameToUrl; \ No newline at end of file diff --git a/templates/default/publish.js b/templates/default/publish.js index ebdbbe6b..1916f0e1 100644 --- a/templates/default/publish.js +++ b/templates/default/publish.js @@ -13,11 +13,15 @@ @global @param {TAFFY} data See . @param {object} opts + @param {Tutorial} tutorials */ - publish = function(data, opts) { + publish = function(data, opts, tutorials) { var out = '', containerTemplate = template.render(fs.readFileSync(__dirname + '/templates/default/tmpl/container.tmpl')); + // set up tutorials for helper + helper.setTutorials(tutorials); + function render(tmpl, partialData) { var renderFunction = arguments.callee.cache[tmpl]; if (!renderFunction) { @@ -26,6 +30,7 @@ partialData.render = arguments.callee; partialData.find = find; partialData.linkto = linkto; + partialData.tutoriallink = tutoriallink; partialData.htmlsafe = htmlsafe; return renderFunction.call(partialData, partialData); @@ -166,7 +171,7 @@ }; }); } - else if (doclet.see) { + if (doclet.see) { doclet.see.forEach(function(seeItem, i) { doclet.see[i] = hashToLink(doclet, seeItem); }); @@ -203,6 +208,10 @@ return url? ''+(linktext || longname)+'' : (linktext || longname); } + function tutoriallink(tutorial) { + return helper.toTutorial(tutorial); + } + var containers = ['class', 'module', 'external', 'namespace', 'mixin']; data.forEach(function(doclet) { @@ -237,29 +246,29 @@ var moduleNames = find({kind: 'module'}); if (moduleNames.length) { - nav = nav + '

Modules

    '; + nav += '

    Modules

      '; moduleNames.forEach(function(m) { if ( !seen.hasOwnProperty(m.longname) ) nav += '
    • '+linkto(m.longname, m.name)+'
    • '; seen[m.longname] = true; }); - nav = nav + '
    '; + nav += '
'; } var externalNames = find({kind: 'external'}); if (externalNames.length) { - nav = nav + '

Externals

    '; + nav += '

    Externals

      '; externalNames.forEach(function(e) { if ( !seen.hasOwnProperty(e.longname) ) nav += '
    • '+linkto( e.longname, e.name.replace(/(^"|"$)/g, '') )+'
    • '; seen[e.longname] = true; }); - nav = nav + '
    '; + nav += '
'; } var classNames = find({kind: 'class'}); if (classNames.length) { - nav = nav + '

Classes

    '; + nav += '

    Classes

      '; classNames.forEach(function(c) { var moduleSameName = find({kind: 'module', longname: c.longname}); if (moduleSameName.length) { @@ -271,52 +280,61 @@ seen[c.longname] = true; }); - nav = nav + '
    '; + nav += '
'; } var namespaceNames = find({kind: 'namespace'}); if (namespaceNames.length) { - nav = nav + '

Namespaces

    '; + nav += '

    Namespaces

      '; namespaceNames.forEach(function(n) { if ( !seen.hasOwnProperty(n.longname) ) nav += '
    • '+linkto(n.longname, n.name)+'
    • '; seen[n.longname] = true; }); - nav = nav + '
    '; + nav += '
'; } // var constantNames = find({kind: 'constants'}); // if (constantNames.length) { -// nav = nav + '

Constants

    '; +// nav += '

    Constants

      '; // constantNames.forEach(function(c) { // if ( !seen.hasOwnProperty(c.longname) ) nav += '
    • '+linkto(c.longname, c.name)+'
    • '; // seen[c.longname] = true; // }); // -// nav = nav + '
    '; +// nav += '
'; // } var mixinNames = find({kind: 'mixin'}); if (mixinNames.length) { - nav = nav + '

Mixins

    '; + nav += '

    Mixins

      '; mixinNames.forEach(function(m) { if ( !seen.hasOwnProperty(m.longname) ) nav += '
    • '+linkto(m.longname, m.name)+'
    • '; seen[m.longname] = true; }); - nav = nav + '
    '; + nav += '
'; } + if (tutorials.children.length) { + nav += '

Tutorials

    '; + tutorials.children.forEach(function(t) { + nav += '
  • '+tutoriallink(t.name)+'
  • '; + }); + + nav += '
'; + } + var globalNames = find({kind: ['member', 'function', 'constant', 'typedef'], 'memberof': {'isUndefined': true}}); if (globalNames.length) { - nav = nav + '

Global

    '; + nav += '

    Global

      '; globalNames.forEach(function(g) { if ( g.kind !== 'typedef' && !seen.hasOwnProperty(g.longname) ) nav += '
    • '+linkto(g.longname, g.name)+'
    • '; seen[g.longname] = true; }); - nav = nav + '
    '; + nav += '
'; } for (var longname in helper.longnameToUrl) { @@ -352,6 +370,7 @@ render: render, find: find, linkto: linkto, + tutoriallink: tutoriallink, htmlsafe: htmlsafe }; @@ -362,6 +381,9 @@ fs.writeFileSync(path, html) } + + // tutorials can have only one parent so there is no risk for loops + //TODO: generate tutorials from root.children up } function hashToLink(doclet, hash) { diff --git a/templates/default/static/styles/jsdoc-default.css b/templates/default/static/styles/jsdoc-default.css index ea0628ea..ad5f5e0b 100644 --- a/templates/default/static/styles/jsdoc-default.css +++ b/templates/default/static/styles/jsdoc-default.css @@ -254,3 +254,7 @@ h6 .params th, .props th { border-right: 1px solid #aaa; } .params thead .last, .props thead .last { border-right: 1px solid #ddd; } + +.disabled { + color: #454545; +} diff --git a/templates/default/tmpl/details.tmpl b/templates/default/tmpl/details.tmpl index d8326fc3..2147a9bc 100644 --- a/templates/default/tmpl/details.tmpl +++ b/templates/default/tmpl/details.tmpl @@ -60,6 +60,17 @@
Source:
  • , line
+ + +
Tutorials:
+
+
    '+tutoriallink(t)+''); + }); + ?>
+
+
See:
From ac02928d3de1269cd61fbe59f85e18eaa78beeb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Wrzeszcz?= Date: Thu, 15 Dec 2011 13:21:52 +0100 Subject: [PATCH 6/7] Tutorials support in template. --- rhino_modules/jsdoc/util/templateHelper.js | 14 +++++- templates/default/publish.js | 41 +++++++++++++++-- templates/default/tmpl/tutorial.tmpl | 53 ++++++++++++++++++++++ 3 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 templates/default/tmpl/tutorial.tmpl diff --git a/rhino_modules/jsdoc/util/templateHelper.js b/rhino_modules/jsdoc/util/templateHelper.js index 4d3710a2..37c0579d 100644 --- a/rhino_modules/jsdoc/util/templateHelper.js +++ b/rhino_modules/jsdoc/util/templateHelper.js @@ -131,7 +131,17 @@ exports.toTutorial = toTutorial = function(tutorial, content) { content = content || node.title; - return ''+content+''; + return ''+content+''; } -exports.longnameToUrl = linkMap.longnameToUrl; \ No newline at end of file +exports.longnameToUrl = linkMap.longnameToUrl; + +exports.tutorialToUrl = function(tutorial) { + var node = tutorials.getByName(tutorial); + // no such tutorial + if (!node) { + throw new Error('No such tutorial: '+tutorial); + } + + return 'tutorial-'+strToFilename(node.name)+exports.fileExtension; +}; diff --git a/templates/default/publish.js b/templates/default/publish.js index 1916f0e1..013b6c14 100644 --- a/templates/default/publish.js +++ b/templates/default/publish.js @@ -17,7 +17,8 @@ */ publish = function(data, opts, tutorials) { var out = '', - containerTemplate = template.render(fs.readFileSync(__dirname + '/templates/default/tmpl/container.tmpl')); + containerTemplate = template.render(fs.readFileSync(__dirname + '/templates/default/tmpl/container.tmpl')), + tutorialTemplate = template.render(fs.readFileSync(__dirname + '/templates/default/tmpl/tutorial.tmpl')); // set up tutorials for helper helper.setTutorials(tutorials); @@ -358,8 +359,8 @@ } if (globals.length) generate('Global', [{kind: 'globalobj'}], 'global.html'); - - + + function generate(title, docs, filename) { var data = { title: title, @@ -381,9 +382,39 @@ fs.writeFileSync(path, html) } - + + function generateTutorial(title, tutorial, filename) { + var data = { + title: title, + header: tutorial.title, + content: tutorial.parse(), + children: tutorial.children, + nav: nav, + + // helpers + render: render, + find: find, + linkto: linkto, + tutoriallink: tutoriallink, + htmlsafe: htmlsafe + }; + + var path = outdir + '/' + filename, + html = tutorialTemplate.call(data, data); + + // yes, you can use {@link} in tutorials too! + html = helper.resolveLinks(html); // turn {@link foo} into foo + + fs.writeFileSync(path, html) + } + // tutorials can have only one parent so there is no risk for loops - //TODO: generate tutorials from root.children up + function saveChildren(node) { + node.children.forEach(function(child) { + generateTutorial('Tutorial: '+child.title, child, helper.tutorialToUrl(child.name)); + }); + } + saveChildren(tutorials); } function hashToLink(doclet, hash) { diff --git a/templates/default/tmpl/tutorial.tmpl b/templates/default/tmpl/tutorial.tmpl new file mode 100644 index 00000000..b0e1354b --- /dev/null +++ b/templates/default/tmpl/tutorial.tmpl @@ -0,0 +1,53 @@ + + + + + JSDoc: <?js= title ?> + + + + + + + + + + +
+ +

+ +
+ +
+ 0) { ?> +
    '+tutoriallink(t.name)+''); + }); + ?>
+ + +

+
+ +
+ +
+ +
+
+ + + +
+ +
+ Documentation generated by JSDoc 3 on +
+ + + + \ No newline at end of file From 2153d7cd0caa2f5472d101c711f9e32149b04a87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Wrzeszcz?= Date: Thu, 15 Dec 2011 13:46:40 +0100 Subject: [PATCH 7/7] Tutorials sample to tests. --- .gitignore | 1 + test/tutorials/build.sh | 2 ++ test/tutorials/src/x.js | 8 ++++++++ test/tutorials/tutorials/test.html | 3 +++ test/tutorials/tutorials/test.js | 1 + test/tutorials/tutorials/test2.json | 1 + test/tutorials/tutorials/test2.markdown | 1 + 7 files changed, 17 insertions(+) create mode 100755 test/tutorials/build.sh create mode 100644 test/tutorials/src/x.js create mode 100644 test/tutorials/tutorials/test.html create mode 100644 test/tutorials/tutorials/test.js create mode 100644 test/tutorials/tutorials/test2.json create mode 100644 test/tutorials/tutorials/test2.markdown diff --git a/.gitignore b/.gitignore index 2f3dacac..04ae28a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build-files/java/build jsdoc.jar +test/tutorials/out diff --git a/test/tutorials/build.sh b/test/tutorials/build.sh new file mode 100755 index 00000000..8937f26d --- /dev/null +++ b/test/tutorials/build.sh @@ -0,0 +1,2 @@ +rm -rf out +../../jsdoc -u tutorials src -d out diff --git a/test/tutorials/src/x.js b/test/tutorials/src/x.js new file mode 100644 index 00000000..987f8f98 --- /dev/null +++ b/test/tutorials/src/x.js @@ -0,0 +1,8 @@ +/** + * Test {@tutorial test2} {@tutorial dupa} + * + * @class + * @tutorial test + * @tutorial jasia + */ +function Test() {} diff --git a/test/tutorials/tutorials/test.html b/test/tutorials/tutorials/test.html new file mode 100644 index 00000000..aa4a4ff9 --- /dev/null +++ b/test/tutorials/tutorials/test.html @@ -0,0 +1,3 @@ +

Test.html

+ +

{@link Test}

diff --git a/test/tutorials/tutorials/test.js b/test/tutorials/tutorials/test.js new file mode 100644 index 00000000..d894f21e --- /dev/null +++ b/test/tutorials/tutorials/test.js @@ -0,0 +1 @@ +{"title": "Test tutorial", "children": ["test2"]} diff --git a/test/tutorials/tutorials/test2.json b/test/tutorials/tutorials/test2.json new file mode 100644 index 00000000..3c7d98c5 --- /dev/null +++ b/test/tutorials/tutorials/test2.json @@ -0,0 +1 @@ +{"title": "Test 2"} diff --git a/test/tutorials/tutorials/test2.markdown b/test/tutorials/tutorials/test2.markdown new file mode 100644 index 00000000..09510c03 --- /dev/null +++ b/test/tutorials/tutorials/test2.markdown @@ -0,0 +1 @@ +# test2.markdown