diff --git a/Rakefile b/Rakefile index dd0f99b..e06b9a5 100644 --- a/Rakefile +++ b/Rakefile @@ -92,7 +92,7 @@ jasmine.version_= { end task :need_pages_submodule do - unless File.exists?('pages/index.html') + unless File.exists?('pages/index.html.md') raise "Jasmine pages submodule isn't present. Run git submodule update --init" end end @@ -109,6 +109,8 @@ jasmine.version_= { t[:files] = jasmine_sources << jasmine_html_sources t[:options] = "-a" t[:out] = "pages/jsdoc" + # JsdocHelper bug: template must be relative to the JsdocHelper gem, ick + t[:template] = File.join("../".*(100), Dir::getwd, "jsdoc-template") end Rake::Task[:lambda_jsdoc].invoke end diff --git a/jsdoc-template/allclasses.tmpl b/jsdoc-template/allclasses.tmpl new file mode 100644 index 0000000..32f4358 --- /dev/null +++ b/jsdoc-template/allclasses.tmpl @@ -0,0 +1,17 @@ +
{+new Link().toFile("index.html").withText("Class Index")+} +| {+new Link().toFile("files.html").withText("File Index")+}
+
+

Classes

+ +
\ No newline at end of file diff --git a/jsdoc-template/allfiles.tmpl b/jsdoc-template/allfiles.tmpl new file mode 100644 index 0000000..37e9915 --- /dev/null +++ b/jsdoc-template/allfiles.tmpl @@ -0,0 +1,56 @@ + + + + + {! Link.base = ""; /* all generated links will be relative to this */ !} + JsDoc Reference - File Index + + + + + + + {+include("static/header.html")+} + +
+ {+publish.classesIndex+} +
+ +
+

File Index

+ + +
+

{+new Link().toSrc(item.alias).withText(item.name)+}

+ {+resolveLinks(summarize(item.desc))+} +
+ +
Author:
+
{+item.author+}
+
+ +
Version:
+
{+item.version+}
+
+ {! var locations = item.comment.getTag('location').map(function($){return $.toString().replace(/(^\$ ?| ?\$$)/g, '').replace(/^HeadURL: https:/g, 'http:');}) !} + +
Location:
+ +
{+location+}
+
+
+
+
+
+
+ +
+
+ ©{+JSDOC.opt.D.copyright+}
+ Documentation generated by JsDoc Toolkit {+JSDOC.VERSION+} on {+new Date()+} +
+ + \ No newline at end of file diff --git a/jsdoc-template/class.tmpl b/jsdoc-template/class.tmpl new file mode 100644 index 0000000..f8debae --- /dev/null +++ b/jsdoc-template/class.tmpl @@ -0,0 +1,646 @@ + + + + + + {! Link.base = "../"; /* all generated links will be relative to this */ !} + JsDoc Reference - {+data.alias+} + + + + + + + + {+include("static/header.html")+} + + + +
+ + {+publish.classesIndex+} + +
+ +
+ +

+ {! + var classType = ""; + + if (data.isBuiltin()) { + classType += "Built-In "; + } + + if (data.isNamespace) { + if (data.is('FUNCTION')) { + classType += "Function "; + } + classType += "Namespace "; + } + else { + classType += "Class "; + } + !} + {+classType+}{+data.alias+} +

+ + +

+
Extends + {+ + data.augments + .sort() + .map( + function($) { return new Link().toSymbol($); } + ) + .join(", ") + +}.
+
+ + {+resolveLinks(data.classDesc)+} + + {# isn't defined in any file #} +
Defined in: {+new Link().toSrc(data.srcFile)+}. +
+

+ + + + + + + + + + + + + + + + + +
{+classType+}Summary
Constructor AttributesConstructor Name and Description
{! + if (data.isPrivate) output += "<private> "; + if (data.isInner) output += "<inner> "; + !}  +
+ {+ new Link().toSymbol(data.alias).inner('constructor')+}{+ makeSignature(data.params) +} +
+
{+resolveLinks(summarize(data.desc))+}
+
+
+ + + + {! var ownProperties = data.properties.filter(function($){return $.memberOf == data.alias && !$.isNamespace}).sort(makeSortby("name")); !} + + + + + + + + + + + + + + + + + +
Field Summary
Field AttributesField Name and Description
{! + if (member.isPrivate) output += "<private> "; + if (member.isInner) output += "<inner> "; + if (member.isStatic) output += "<static> "; + if (member.isConstant) output += "<constant> "; + !}  +
+ {+member.memberOf+}.{+new Link().toSymbol(member.alias).withText(member.name)+} +
+
{+resolveLinks(summarize(member.desc))+}
+
+
+ + +
+ {! + var borrowedMembers = data.properties.filter(function($) {return $.memberOf != data.alias}); + + var contributers = []; + borrowedMembers.map(function($) {if (contributers.indexOf($.memberOf) < 0) contributers.push($.memberOf)}); + for (var i = 0, l = contributers.length; i < l; i++) { + output += + "
Fields borrowed from class "+new Link().toSymbol(contributers[i])+":
" + + + "
" + + borrowedMembers + .filter( + function($) { return $.memberOf == contributers[i] } + ) + .sort(makeSortby("name")) + .map( + function($) { return new Link().toSymbol($.alias).withText($.name) } + ) + .join(", ") + + + "
"; + } + !} +
+
+
+ + + + {! var ownMethods = data.methods.filter(function($){return $.memberOf == data.alias && !$.isNamespace}).sort(makeSortby("name")); !} + + + + + + + + + + + + + + + + + +
Method Summary
Method AttributesMethod Name and Description
{! + if (member.isPrivate) output += "<private> "; + if (member.isInner) output += "<inner> "; + if (member.isStatic) output += "<static> "; + !}  +
{+member.memberOf+}.{+new Link().toSymbol(member.alias).withText(member.name)+}{+makeSignature(member.params)+} +
+
{+resolveLinks(summarize(member.desc))+}
+
+
+ + +
+ {! + var borrowedMembers = data.methods.filter(function($) {return $.memberOf != data.alias}); + var contributers = []; + borrowedMembers.map(function($) {if (contributers.indexOf($.memberOf) < 0) contributers.push($.memberOf)}); + for (var i = 0, l = contributers.length; i < l; i++) { + output += + "
Methods borrowed from class "+new Link().toSymbol(contributers[i])+":
" + + + "
" + + borrowedMembers + .filter( + function($) { return $.memberOf == contributers[i] } + ) + .sort(makeSortby("name")) + .map( + function($) { return new Link().toSymbol($.alias).withText($.name) } + ) + .join(", ") + + + "
"; + } + + !} +
+
+
+ + + {! var ownEvents = data.events.filter(function($){return $.memberOf == data.alias && !$.isNamespace}).sort(makeSortby("name")); !} + + + + + + + + + + + + + + + + + +
Event Summary
Event AttributesEvent Name and Description
{! + if (member.isPrivate) output += "<private> "; + if (member.isInner) output += "<inner> "; + if (member.isStatic) output += "<static> "; + !}  +
{+member.memberOf+}.{+new Link().toSymbol(member.alias).withText(member.name)+}{+makeSignature(member.params)+} +
+
{+resolveLinks(summarize(member.desc))+}
+
+
+ + +
+ {! + var borrowedMembers = data.events.filter(function($) {return $.memberOf != data.alias}); + var contributers = []; + borrowedMembers.map(function($) {if (contributers.indexOf($.memberOf) < 0) contributers.push($.memberOf)}); + for (var i = 0, l = contributers.length; i < l; i++) { + output += + "
Events borrowed from class "+new Link().toSymbol(contributers[i])+":
" + + + "
" + + borrowedMembers + .filter( + function($) { return $.memberOf == contributers[i] } + ) + .sort(makeSortby("name")) + .map( + function($) { return new Link().toSymbol($.alias).withText($.name) } + ) + .join(", ") + + + "
"; + } + + !} +
+
+
+ + + +
+
+ {+classType+}Detail +
+ +
{! + if (data.isPrivate) output += "<private> "; + if (data.isInner) output += "<inner> "; + !} + {+ data.alias +}{+ makeSignature(data.params) +} +
+ +
+ {+resolveLinks(data.desc)+} +
Author: {+data.author+}.
+
+ + + +
{+example+}
+
+
+ + + +
+
Parameters:
+ +
+ {+((item.type)?""+("{"+(new Link().toSymbol(item.type)+"} ")) : "")+} {+item.name+} + Optional, Default: {+item.defaultValue+} +
+
{+resolveLinks(item.desc)+}
+
+
+
+ +
+
Deprecated:
+
+ {+resolveLinks(data.deprecated)+} +
+
+
+ +
+
Since:
+
{+ data.since +}
+
+
+ +
+
Throws:
+ +
+ {+((item.type)?"{"+(new Link().toSymbol(item.type))+"} " : "")+} {+item.name+} +
+
{+resolveLinks(item.desc)+}
+
+
+
+ +
+
Returns:
+ +
{+((item.type)?"{"+(new Link().toSymbol(item.type))+"} " : "")+}{+resolveLinks(item.desc)+}
+
+
+
+ +
+
Requires:
+ +
{+ resolveLinks(item) +}
+
+
+
+ +
+
See:
+ +
{+ new Link().toSymbol(item) +}
+
+
+
+ +
+
+ + + +
+ Field Detail +
+ + +
{! + if (member.isPrivate) output += "<private> "; + if (member.isInner) output += "<inner> "; + if (member.isStatic) output += "<static> "; + if (member.isConstant) output += "<constant> "; + !} + + {{+new Link().toSymbol(member.type)+}} + {+member.memberOf+}.{+member.name+} + +
+
+ {+resolveLinks(member.desc)+} + +
+ Defined in: {+new Link().toSrc(member.srcFile)+}. +
+
Author: {+member.author+}.
+
+ + + +
{+example+}
+
+
+ + +
+
Deprecated:
+
+ {+ member.deprecated +} +
+
+
+ +
+
Since:
+
{+ member.since +}
+
+
+ +
+
See:
+ +
{+ new Link().toSymbol(item) +}
+
+
+
+ +
+
Default Value:
+
+ {+resolveLinks(member.defaultValue)+} +
+
+
+ +
+
+
+ + + +
+ Method Detail +
+ + +
{! + if (member.isPrivate) output += "<private> "; + if (member.isInner) output += "<inner> "; + if (member.isStatic) output += "<static> "; + !} + + {{+new Link().toSymbol(member.type)+}} + {+member.memberOf+}.{+member.name+}{+makeSignature(member.params)+} + +
+
+ {+resolveLinks(member.desc)+} + +
+ Defined in: {+new Link().toSrc(member.srcFile)+}. +
+
Author: {+member.author+}.
+
+ + + +
{+example+}
+
+
+ + +
+
Parameters:
+ +
+ {+((item.type)?"{"+(new Link().toSymbol(item.type))+"} " : "")+}{+item.name+} + Optional, Default: {+item.defaultValue+} +
+
{+resolveLinks(item.desc)+}
+
+
+
+ +
+
Deprecated:
+
+ {+member.deprecated+} +
+
+
+ +
+
Since:
+
{+ member.since +}
+
+ +
+ +
+
Throws:
+ +
+ {+((item.type)?"{"+(new Link().toSymbol(item.type))+"} " : "")+} {+item.name+} +
+
{+resolveLinks(item.desc)+}
+
+
+
+ +
+
Returns:
+ +
{+((item.type)?"{"+(new Link().toSymbol(item.type))+"} " : "")+}{+resolveLinks(item.desc)+}
+
+
+
+ +
+
Requires:
+ +
{+ resolveLinks(item) +}
+
+
+
+ +
+
See:
+ +
{+ new Link().toSymbol(item) +}
+
+
+
+ +
+
+
+ + + +
+ Event Detail +
+ + +
{! + if (member.isPrivate) output += "<private> "; + if (member.isInner) output += "<inner> "; + if (member.isStatic) output += "<static> "; + !} + + {{+new Link().toSymbol(member.type)+}} + {+member.memberOf+}.{+member.name+}{+makeSignature(member.params)+} + +
+
+ {+resolveLinks(member.desc)+} + +
+ Defined in: {+new Link().toSrc(member.srcFile)+}. +
+
Author: {+member.author+}.
+
+ + + +
{+example+}
+
+
+ + +
+
Parameters:
+ +
+ {+((item.type)?"{"+(new Link().toSymbol(item.type))+"} " : "")+}{+item.name+} + Optional, Default: {+item.defaultValue+} +
+
{+resolveLinks(item.desc)+}
+
+
+
+ +
+
Deprecated:
+
+ {+member.deprecated+} +
+
+
+ +
+
Since:
+
{+ member.since +}
+
+ +
+ +
+
Throws:
+ +
+ {+((item.type)?"{"+(new Link().toSymbol(item.type))+"} " : "")+} {+item.name+} +
+
{+resolveLinks(item.desc)+}
+
+
+
+ +
+
Returns:
+ +
{+((item.type)?"{"+(new Link().toSymbol(item.type))+"} " : "")+}{+resolveLinks(item.desc)+}
+
+
+
+ +
+
Requires:
+ +
{+ resolveLinks(item) +}
+
+
+
+ +
+
See:
+ +
{+ new Link().toSymbol(item) +}
+
+
+
+ +
+
+
+ +
+
+ + + +
+ ©{+JSDOC.opt.D.copyright+}
+ Documentation generated by JsDoc Toolkit {+JSDOC.VERSION+} on {+new Date()+} +
+ + diff --git a/jsdoc-template/index.tmpl b/jsdoc-template/index.tmpl new file mode 100644 index 0000000..61b93cf --- /dev/null +++ b/jsdoc-template/index.tmpl @@ -0,0 +1,39 @@ + + + + + + JsDoc Reference - Index + + + + + + + {+include("static/header.html")+} + +
+ {+publish.classesIndex+} +
+ +
+

Class Index

+ + +
+

{+(new Link().toSymbol(thisClass.alias))+}

+ {+resolveLinks(summarize(thisClass.classDesc))+} +
+
+
+ +
+
+ ©{+JSDOC.opt.D.copyright+}
+ Documentation generated by JsDoc Toolkit {+JSDOC.VERSION+} on {+new Date()+} +
+ + \ No newline at end of file diff --git a/jsdoc-template/publish.js b/jsdoc-template/publish.js new file mode 100644 index 0000000..7e1cbd7 --- /dev/null +++ b/jsdoc-template/publish.js @@ -0,0 +1,184 @@ +/** Called automatically by JsDoc Toolkit. */ +function publish(symbolSet) { + publish.conf = { // trailing slash expected for dirs + ext: ".html", + outDir: JSDOC.opt.d || SYS.pwd+"../out/jsdoc/", + templatesDir: JSDOC.opt.t || SYS.pwd+"../templates/jsdoc/", + symbolsDir: "symbols/", + srcDir: "symbols/src/" + }; + + // is source output is suppressed, just display the links to the source file + if (JSDOC.opt.s && defined(Link) && Link.prototype._makeSrcLink) { + Link.prototype._makeSrcLink = function(srcFilePath) { + return "<"+srcFilePath+">"; + } + } + + // create the folders and subfolders to hold the output + IO.mkPath((publish.conf.outDir+"symbols/src").split("/")); + + // used to allow Link to check the details of things being linked to + Link.symbolSet = symbolSet; + + // create the required templates + try { + var classTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"class.tmpl"); + var classesTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"allclasses.tmpl"); + } + catch(e) { + print("Couldn't create the required templates: "+e); + quit(); + } + + // some ustility filters + function hasNoParent($) {return ($.memberOf == "")} + function isaFile($) {return ($.is("FILE"))} + function isaClass($) {return ($.is("CONSTRUCTOR") || $.isNamespace)} + + // get an array version of the symbolset, useful for filtering + var symbols = symbolSet.toArray(); + + // create the hilited source code files + var files = JSDOC.opt.srcFiles; + for (var i = 0, l = files.length; i < l; i++) { + var file = files[i]; + var srcDir = publish.conf.outDir + "symbols/src/"; + makeSrcFile(file, srcDir); + } + + // get a list of all the classes in the symbolset + var classes = symbols.filter(isaClass).sort(makeSortby("alias")); + + // create a class index, displayed in the left-hand column of every class page + Link.base = "../"; + publish.classesIndex = classesTemplate.process(classes); // kept in memory + + // create each of the class pages + for (var i = 0, l = classes.length; i < l; i++) { + var symbol = classes[i]; + + symbol.events = symbol.getEvents(); // 1 order matters + symbol.methods = symbol.getMethods(); // 2 + + var output = ""; + output = classTemplate.process(symbol); + + IO.saveFile(publish.conf.outDir+"symbols/", symbol.alias+publish.conf.ext, output); + } + + // regenerate the index with different relative links, used in the index pages + Link.base = ""; + publish.classesIndex = classesTemplate.process(classes); + + // create the class index page + try { + var classesindexTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"index.tmpl"); + } + catch(e) { print(e.message); quit(); } + + var classesIndex = classesindexTemplate.process(classes); + IO.saveFile(publish.conf.outDir, "index"+publish.conf.ext, classesIndex); + classesindexTemplate = classesIndex = classes = null; + + // create the file index page + try { + var fileindexTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"allfiles.tmpl"); + } + catch(e) { print(e.message); quit(); } + + var documentedFiles = symbols.filter(isaFile); // files that have file-level docs + var allFiles = []; // not all files have file-level docs, but we need to list every one + + for (var i = 0; i < files.length; i++) { + allFiles.push(new JSDOC.Symbol(files[i], [], "FILE", new JSDOC.DocComment("/** */"))); + } + + for (var i = 0; i < documentedFiles.length; i++) { + var offset = files.indexOf(documentedFiles[i].alias); + allFiles[offset] = documentedFiles[i]; + } + + allFiles = allFiles.sort(makeSortby("name")); + + // output the file index page + var filesIndex = fileindexTemplate.process(allFiles); + IO.saveFile(publish.conf.outDir, "files"+publish.conf.ext, filesIndex); + fileindexTemplate = filesIndex = files = null; +} + + +/** Just the first sentence (up to a full stop). Should not break on dotted variable names. */ +function summarize(desc) { + if (typeof desc != "undefined") + return desc.match(/([\w\W]+?\.)[^a-z0-9_$]/i)? RegExp.$1 : desc; +} + +/** Make a symbol sorter by some attribute. */ +function makeSortby(attribute) { + return function(a, b) { + if (a[attribute] != undefined && b[attribute] != undefined) { + a = a[attribute].toLowerCase(); + b = b[attribute].toLowerCase(); + if (a < b) return -1; + if (a > b) return 1; + return 0; + } + } +} + +/** Pull in the contents of an external file at the given path. */ +function include(path) { + var path = publish.conf.templatesDir+path; + return IO.readFile(path); +} + +/** Turn a raw source file into a code-hilited page in the docs. */ +function makeSrcFile(path, srcDir, name) { + if (JSDOC.opt.s) return; + + if (!name) { + name = path.replace(/\.\.?[\\\/]/g, "").replace(/[\\\/]/g, "_"); + name = name.replace(/\:/g, "_"); + } + + var src = {path: path, name:name, charset: IO.encoding, hilited: ""}; + + if (defined(JSDOC.PluginManager)) { + JSDOC.PluginManager.run("onPublishSrc", src); + } + + if (src.hilited) { + IO.saveFile(srcDir, name+publish.conf.ext, src.hilited); + } +} + +/** Build output for displaying function parameters. */ +function makeSignature(params) { + if (!params) return "()"; + var signature = "(" + + + params.filter( + function($) { + return $.name.indexOf(".") == -1; // don't show config params in signature + } + ).map( + function($) { + return $.name; + } + ).join(", ") + + + ")"; + return signature; +} + +/** Find symbol {@link ...} strings in text and turn into html links */ +function resolveLinks(str, from) { + str = str.replace(/\{@link ([^} ]+) ?\}/gi, + function(match, symbolName) { + return new Link().toSymbol(symbolName); + } + ); + + return str; +} \ No newline at end of file diff --git a/jsdoc-template/static/default.css b/jsdoc-template/static/default.css new file mode 100644 index 0000000..97e021e --- /dev/null +++ b/jsdoc-template/static/default.css @@ -0,0 +1,162 @@ +/* default.css */ +body +{ + font: 12px "Lucida Grande", Tahoma, Arial, Helvetica, sans-serif; + width: 800px; +} + +.header +{ + clear: both; + background-color: #ccc; + padding: 8px; +} + +h1 +{ + font-size: 150%; + font-weight: bold; + padding: 0; + margin: 1em 0 0 .3em; +} + +hr +{ + border: none 0; + border-top: 1px solid #7F8FB1; + height: 1px; +} + +pre.code +{ + display: block; + padding: 8px; + border: 1px dashed #ccc; +} + +#index +{ + margin-top: 24px; + float: left; + width: 160px; + position: absolute; + left: 8px; + background-color: #F3F3F3; + padding: 8px; +} + +#content +{ + margin-left: 190px; + width: 600px; +} + +.classList +{ + list-style-type: none; + padding: 0; + margin: 0 0 0 8px; + font-family: arial, sans-serif; + font-size: 1em; + overflow: auto; +} + +.classList li +{ + padding: 0; + margin: 0 0 8px 0; +} + +.summaryTable { width: 100%; } + +h1.classTitle +{ + font-size:170%; + line-height:130%; +} + +h2 { font-size: 110%; } +caption, div.sectionTitle +{ + background-color: #7F8FB1; + color: #fff; + font-size:130%; + text-align: left; + padding: 2px 6px 2px 6px; + border: 1px #7F8FB1 solid; +} + +div.sectionTitle { margin-bottom: 8px; } +.summaryTable thead { display: none; } + +.summaryTable td +{ + vertical-align: top; + padding: 4px; + border-bottom: 1px #7F8FB1 solid; + border-right: 1px #7F8FB1 solid; +} + +/*col#summaryAttributes {}*/ +.summaryTable td.attributes +{ + border-left: 1px #7F8FB1 solid; + width: 140px; + text-align: right; +} + +td.attributes, .fixedFont +{ + line-height: 15px; + color: #002EBE; + font-family: "Courier New",Courier,monospace; + font-size: 13px; +} + +.summaryTable td.nameDescription +{ + text-align: left; + font-size: 13px; + line-height: 15px; +} + +.summaryTable td.nameDescription, .description +{ + line-height: 15px; + padding: 4px; + padding-left: 4px; +} + +.summaryTable { margin-bottom: 8px; } + +ul.inheritsList +{ + list-style: square; + margin-left: 20px; + padding-left: 0; +} + +.detailList { + margin-left: 20px; + line-height: 15px; +} +.detailList dt { margin-left: 20px; } + +.detailList .heading +{ + font-weight: bold; + padding-bottom: 6px; + margin-left: 0; +} + +.light, td.attributes, .light a:link, .light a:visited +{ + color: #777; + font-style: italic; +} + +.fineprint +{ + text-align: right; + font-size: 10px; +} \ No newline at end of file diff --git a/jsdoc-template/static/header.html b/jsdoc-template/static/header.html new file mode 100644 index 0000000..353b735 --- /dev/null +++ b/jsdoc-template/static/header.html @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/jsdoc-template/static/index.html b/jsdoc-template/static/index.html new file mode 100644 index 0000000..661f6f6 --- /dev/null +++ b/jsdoc-template/static/index.html @@ -0,0 +1,19 @@ + + + + + Generated Javascript Documentation + + + + + + <body> + <p> + This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. + </p> + </body> + + + \ No newline at end of file diff --git a/jsdoc-template/symbol.tmpl b/jsdoc-template/symbol.tmpl new file mode 100644 index 0000000..f8f4bd1 --- /dev/null +++ b/jsdoc-template/symbol.tmpl @@ -0,0 +1,35 @@ + + {+data.name+} + {+data.memberOf+} + {+data.isStatic+} + {+data.isa+} + {+data.desc+} + {+data.classDesc+} + + + + {+method.name+} + {+method.memberOf+} + {+method.isStatic+} + {+method.desc+} + + + {+param.type+} + {+param.name+} + {+param.desc+} + {+param.defaultValue+} + + + + + + + + {+property.name+} + {+property.memberOf+} + {+property.isStatic+} + {+property.desc+} + {+property.type+} + + +