diff --git a/bin/jsdoc/frame.js b/bin/jsdoc/frame.js new file mode 100644 index 00000000..1beb4055 --- /dev/null +++ b/bin/jsdoc/frame.js @@ -0,0 +1,33 @@ +IO.include("frame/Opt.js"); +IO.include("frame/Chain.js"); +IO.include("frame/Link.js"); +IO.include("frame/String.js"); +IO.include("frame/Hash.js"); +IO.include("frame/Namespace.js"); +//IO.include("frame/Reflection.js"); + +/** A few helper functions to make life a little easier. */ + +function defined(o) { + return (o !== undefined); +} + +function copy(o) { // todo check for circular refs + if (o == null || typeof(o) != 'object') return o; + var c = new o.constructor(); + for(var p in o) c[p] = copy(o[p]); + return c; +} + +function isUnique(arr) { + var l = arr.length; + for(var i = 0; i < l; i++ ) { + if (arr.lastIndexOf(arr[i]) > i) return false; + } + return true; +} + +/** Returns the given string with all regex meta characters backslashed. */ +RegExp.escapeMeta = function(str) { + return str.replace(/([$^\\\/()|?+*\[\]{}.-])/g, "\\$1"); +} diff --git a/bin/jsdoc/frame/Chain.js b/bin/jsdoc/frame/Chain.js new file mode 100644 index 00000000..506469d1 --- /dev/null +++ b/bin/jsdoc/frame/Chain.js @@ -0,0 +1,102 @@ +/**@constructor*/ +function ChainNode(object, link) { + this.value = object; + this.link = link; // describes this node's relationship to the previous node +} + +/**@constructor*/ +function Chain(valueLinks) { + this.nodes = []; + this.cursor = -1; + + if (valueLinks && valueLinks.length > 0) { + this.push(valueLinks[0], "//"); + for (var i = 1, l = valueLinks.length; i < l; i+=2) { + this.push(valueLinks[i+1], valueLinks[i]); + } + } +} + +Chain.prototype.push = function(o, link) { + if (this.nodes.length > 0 && link) this.nodes.push(new ChainNode(o, link)); + else this.nodes.push(new ChainNode(o)); +} + +Chain.prototype.unshift = function(o, link) { + if (this.nodes.length > 0 && link) this.nodes[0].link = link; + this.nodes.unshift(new ChainNode(o)); + this.cursor++; +} + +Chain.prototype.get = function() { + if (this.cursor < 0 || this.cursor > this.nodes.length-1) return null; + return this.nodes[this.cursor]; +} + +Chain.prototype.first = function() { + this.cursor = 0; + return this.get(); +} + +Chain.prototype.last = function() { + this.cursor = this.nodes.length-1; + return this.get(); +} + +Chain.prototype.next = function() { + this.cursor++; + return this.get(); +} + +Chain.prototype.prev = function() { + this.cursor--; + return this.get(); +} + +Chain.prototype.toString = function() { + var string = ""; + for (var i = 0, l = this.nodes.length; i < l; i++) { + if (this.nodes[i].link) string += " -("+this.nodes[i].link+")-> "; + string += this.nodes[i].value.toString(); + } + return string; +} + +Chain.prototype.joinLeft = function() { + var result = ""; + for (var i = 0, l = this.cursor; i < l; i++) { + if (result && this.nodes[i].link) result += this.nodes[i].link; + result += this.nodes[i].value.toString(); + } + return result; +} + + +/* USAGE: + +var path = "one/two/three.four/five-six"; +var pathChain = new Chain(path.split(/([\/.-])/)); +print(pathChain); + +var lineage = new Chain(); +lineage.push("Port"); +lineage.push("Les", "son"); +lineage.push("Dawn", "daughter"); +lineage.unshift("Purdie", "son"); + +print(lineage); + +// walk left +for (var node = lineage.last(); node !== null; node = lineage.prev()) { + print("< "+node.value); +} + +// walk right +var node = lineage.first() +while (node !== null) { + print(node.value); + node = lineage.next(); + if (node && node.link) print("had a "+node.link+" named"); +} + +*/ \ No newline at end of file diff --git a/bin/jsdoc/frame/Dumper.js b/bin/jsdoc/frame/Dumper.js new file mode 100644 index 00000000..d8b007b1 --- /dev/null +++ b/bin/jsdoc/frame/Dumper.js @@ -0,0 +1,144 @@ +/** + * @class +
+This is a lightly modified version of Kevin Jones' JavaScript
+library Data.Dump. To download the original visit:
+    http://openjsan.org/doc/k/ke/kevinj/Data/Dump/
+
+AUTHORS
+
+The Data.Dump JavaScript module is written by Kevin Jones 
+(kevinj@cpan.org), based on Data::Dump by Gisle Aas (gisle@aas.no),
+based on Data::Dumper by Gurusamy Sarathy (gsar@umich.edu).
+
+COPYRIGHT
+
+Copyright 2007 Kevin Jones. Copyright 1998-2000,2003-2004 Gisle Aas.
+Copyright 1996-1998 Gurusamy Sarathy.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the Perl Artistic License
+
+See http://www.perl.com/perl/misc/Artistic.html
+
+ * @static + */ +Dumper = { + /** @param [...] The objects to dump. */ + dump: function () { + if (arguments.length > 1) + return this._dump(arguments); + else if (arguments.length == 1) + return this._dump(arguments[0]); + else + return "()"; + }, + + _dump: function (obj) { + if (typeof obj == 'undefined') return 'undefined'; + var out; + if (obj.serialize) { return obj.serialize(); } + var type = this._typeof(obj); + if (obj.circularReference) obj.circularReference++; + switch (type) { + case 'circular': + out = "{ //circularReference\n}"; + break; + case 'object': + var pairs = new Array; + + for (var prop in obj) { + if (prop != "circularReference" && obj.hasOwnProperty(prop)) { //hide inherited properties + pairs.push(prop + ': ' + this._dump(obj[prop])); + } + } + + out = '{' + this._format_list(pairs) + '}'; + break; + + case 'string': + for (var prop in Dumper.ESC) { + if (Dumper.ESC.hasOwnProperty(prop)) { + obj = obj.replace(prop, Dumper.ESC[prop]); + } + } + + // Escape UTF-8 Strings + if (obj.match(/^[\x00-\x7f]*$/)) { + out = '"' + obj.replace(/\"/g, "\\\"").replace(/([\n\r]+)/g, "\\$1") + '"'; + } + else { + out = "unescape('"+escape(obj)+"')"; + } + break; + + case 'array': + var elems = new Array; + + for (var i=0; i 60 ? '\n' : ' '; + return nl + list.join(',' + nl) + nl; + }, + + _typeof: function (obj) { + if (obj && obj.circularReference && obj.circularReference > 1) return 'circular'; + if (Array.prototype.isPrototypeOf(obj)) return 'array'; + if (Date.prototype.isPrototypeOf(obj)) return 'date'; + if (typeof obj.nodeType != 'undefined') return 'element'; + return typeof(obj); + }, + + _dump_dom: function (obj) { + return '"' + Dumper.nodeTypes[obj.nodeType] + '"'; + } +}; + +Dumper.ESC = { + "\t": "\\t", + "\n": "\\n", + "\f": "\\f" +}; + +Dumper.nodeTypes = { + 1: "ELEMENT_NODE", + 2: "ATTRIBUTE_NODE", + 3: "TEXT_NODE", + 4: "CDATA_SECTION_NODE", + 5: "ENTITY_REFERENCE_NODE", + 6: "ENTITY_NODE", + 7: "PROCESSING_INSTRUCTION_NODE", + 8: "COMMENT_NODE", + 9: "DOCUMENT_NODE", + 10: "DOCUMENT_TYPE_NODE", + 11: "DOCUMENT_FRAGMENT_NODE", + 12: "NOTATION_NODE" +}; \ No newline at end of file diff --git a/bin/jsdoc/frame/Hash.js b/bin/jsdoc/frame/Hash.js new file mode 100644 index 00000000..62cfad64 --- /dev/null +++ b/bin/jsdoc/frame/Hash.js @@ -0,0 +1,84 @@ +/** + @constructor + @example + var _index = new Hash(); + _index.set("a", "apple"); + _index.set("b", "blue"); + _index.set("c", "coffee"); + + for (var p = _index.first(); p; p = _index.next()) { + print(p.key+" is for "+p.value); + } + + */ +var Hash = function() { + this._map = {}; + this._keys = []; + this._vals = []; + this.reset(); +} + +Hash.prototype.set = function(k, v) { + if (k != "") { + this._keys.push(k); + this._map["="+k] = this._vals.length; + this._vals.push(v); + } +} + +Hash.prototype.replace = function(k, k2, v) { + if (k == k2) return; + + var offset = this._map["="+k]; + this._keys[offset] = k2; + if (typeof v != "undefined") this._vals[offset] = v; + this._map["="+k2] = offset; + delete(this._map["="+k]); +} + +Hash.prototype.drop = function(k) { + if (k != "") { + var offset = this._map["="+k]; + this._keys.splice(offset, 1); + this._vals.splice(offset, 1); + delete(this._map["="+k]); + for (var p in this._map) { + if (this._map[p] >= offset) this._map[p]--; + } + if (this._cursor >= offset && this._cursor > 0) this._cursor--; + } +} + +Hash.prototype.get = function(k) { + if (k != "") { + return this._vals[this._map["="+k]]; + } +} + +Hash.prototype.keys = function() { + return this._keys; +} + +Hash.prototype.hasKey = function(k) { + if (k != "") { + return (typeof this._map["="+k] != "undefined"); + } +} + +Hash.prototype.values = function() { + return this._vals; +} + +Hash.prototype.reset = function() { + this._cursor = 0; +} + +Hash.prototype.first = function() { + this.reset(); + return this.next(); +} + +Hash.prototype.next = function() { + if (this._cursor++ < this._keys.length) + return {key: this._keys[this._cursor-1], value: this._vals[this._cursor-1]}; +} \ No newline at end of file diff --git a/bin/jsdoc/frame/Link.js b/bin/jsdoc/frame/Link.js new file mode 100644 index 00000000..1e6241bf --- /dev/null +++ b/bin/jsdoc/frame/Link.js @@ -0,0 +1,173 @@ +/** Handle the creation of HTML links to documented symbols. + @constructor +*/ +function Link() { + this.alias = ""; + this.src = ""; + this.file = ""; + this.text = ""; + this.innerName = ""; + this.classLink = false; + this.targetName = ""; + + this.target = function(targetName) { + if (defined(targetName)) this.targetName = targetName; + return this; + } + this.inner = function(inner) { + if (defined(inner)) this.innerName = inner; + return this; + } + this.withText = function(text) { + if (defined(text)) this.text = text; + return this; + } + this.toSrc = function(filename) { + if (defined(filename)) this.src = filename; + return this; + } + this.toSymbol = function(alias) { + if (defined(alias)) this.alias = new String(alias); + return this; + } + this.toClass = function(alias) { + this.classLink = true; + return this.toSymbol(alias); + } + this.toFile = function(file) { + if (defined(file)) this.file = file; + return this; + } + + this.toString = function() { + var linkString; + var thisLink = this; + + if (this.alias) { + linkString = this.alias.replace(/(^|[^a-z$0-9_#.:^-])([|a-z$0-9_#.:^-]+)($|[^a-z$0-9_#.:^-])/i, + function(match, prematch, symbolName, postmatch) { + var symbolNames = symbolName.split("|"); + var links = []; + for (var i = 0, l = symbolNames.length; i < l; i++) { + thisLink.alias = symbolNames[i]; + links.push(thisLink._makeSymbolLink(symbolNames[i])); + } + return prematch+links.join("|")+postmatch; + } + ); + } + else if (this.src) { + linkString = thisLink._makeSrcLink(this.src); + } + else if (this.file) { + linkString = thisLink._makeFileLink(this.file); + } + + return linkString; + } +} + +/** prefixed for hashes */ +Link.hashPrefix = ""; + +/** Appended to the front of relative link paths. */ +Link.base = ""; + +Link.symbolNameToLinkName = function(symbol) { + var linker = "", + ns = ""; + + if (symbol.isStatic) linker = "."; + else if (symbol.isInner) linker = "-"; + + if (symbol.isEvent && !/^event:/.test(symbol.name)) { + ns = "event:"; + } + return Link.hashPrefix+linker+ns+symbol.name; +} + +Link.getSymbol= function(alias) { + var symbol= Link.symbolSet.getSymbol(alias); + + if (symbol) + return symbol; + + if ('#'!==alias.charAt(0) || !Link.currentSymbol) + return null; + + // resolve relative name + var container= Link.currentSymbol; + + while (container) + { + symbol= Link.symbolSet.getSymbol(container.alias + alias); + if (symbol) + return symbol; + + // No superclass + if (!container.augments.length) + return null; + + container= Link.symbolSet.getSymbol(container.augments[0].desc); + } + + return null; +} + +/** Create a link to another symbol. */ +Link.prototype._makeSymbolLink = function(alias) { + var linkBase = Link.base+publish.conf.symbolsDir; + var linkTo = Link.getSymbol(alias); + var linkPath; + var target = (this.targetName)? " target=\""+this.targetName+"\"" : ""; + + // if there is no symbol by that name just return the name unaltered + if (!linkTo) + return this.text || alias; + + // it's a symbol in another file + else { + if (!linkTo.is("CONSTRUCTOR") && !linkTo.isNamespace) { // it's a method or property + linkPath= (Link.filemap) ? Link.filemap[linkTo.memberOf] : + escape(linkTo.memberOf) || "_global_"; + linkPath += publish.conf.ext + "#" + Link.symbolNameToLinkName(linkTo); + } + else { + linkPath = (Link.filemap)? Link.filemap[linkTo.alias] : escape(linkTo.alias); + linkPath += publish.conf.ext;// + (this.classLink? "":"#" + Link.hashPrefix + "constructor"); + } + linkPath = linkBase + linkPath + } + + var linkText= this.text || alias; + + var link = {linkPath: linkPath, linkText: linkText, linkInner: (this.innerName? "#"+this.innerName : "")}; + + if (typeof JSDOC.PluginManager != "undefined") { + JSDOC.PluginManager.run("onSymbolLink", link); + } + + return ""+link.linkText+""; +} + +/** Create a link to a source file. */ +Link.prototype._makeSrcLink = function(srcFilePath) { + var target = (this.targetName)? " target=\""+this.targetName+"\"" : ""; + + // transform filepath into a filename + var srcFile = srcFilePath.replace(/\.\.?[\\\/]/g, "").replace(/[:\\\/]/g, "_"); + var outFilePath = Link.base + publish.conf.srcDir + srcFile + publish.conf.ext; + + if (!this.text) this.text = FilePath.fileName(srcFilePath); + return ""+this.text+""; +} + +/** Create a link to a source file. */ +Link.prototype._makeFileLink = function(filePath) { + var target = (this.targetName)? " target=\""+this.targetName+"\"" : ""; + + var outFilePath = Link.base + filePath; + + if (!this.text) this.text = filePath; + return ""+this.text+""; +} \ No newline at end of file diff --git a/bin/jsdoc/frame/Namespace.js b/bin/jsdoc/frame/Namespace.js new file mode 100644 index 00000000..fa1e41d1 --- /dev/null +++ b/bin/jsdoc/frame/Namespace.js @@ -0,0 +1,10 @@ +_global_ = this; + +function Namespace(name, f) { + var n = name.split("."); + for (var o = _global_, i = 0, l = n.length; i < l; i++) { + o = o[n[i]] = o[n[i]] || {}; + } + + if (f) f(); +} \ No newline at end of file diff --git a/bin/jsdoc/frame/Opt.js b/bin/jsdoc/frame/Opt.js new file mode 100644 index 00000000..352f1590 --- /dev/null +++ b/bin/jsdoc/frame/Opt.js @@ -0,0 +1,134 @@ +/** @namespace */ +Opt = { + /** + * Get commandline option values. + * @param {Array} args Commandline arguments. Like ["-a=xml", "-b", "--class=new", "--debug"] + * @param {object} optNames Map short names to long names. Like {a:"accept", b:"backtrace", c:"class", d:"debug"}. + * @return {object} Short names and values. Like {a:"xml", b:true, c:"new", d:true} + */ + get: function(args, optNames) { + var opt = {"_": []}; // the unnamed option allows multiple values + for (var i = 0; i < args.length; i++) { + var arg = new String(args[i]); + var name; + var value; + if (arg.charAt(0) == "-") { + if (arg.charAt(1) == "-") { // it's a longname like --foo + arg = arg.substring(2); + var m = arg.split("="); + name = m.shift(); + value = m.shift(); + if (typeof value == "undefined") value = true; + + for (var n in optNames) { // convert it to a shortname + if (name == optNames[n]) { + name = n; + } + } + } + else { // it's a shortname like -f + arg = arg.substring(1); + var m = arg.split("="); + name = m.shift(); + value = m.shift(); + if (typeof value == "undefined") value = true; + + for (var n in optNames) { // find the matching key + if (name == n || name+'[]' == n) { + name = n; + break; + } + } + } + if (name.match(/(.+)\[\]$/)) { // it's an array type like n[] + name = RegExp.$1; + if (!opt[name]) opt[name] = []; + } + + if (opt[name] && opt[name].push) { + opt[name].push(value); + } + else { + opt[name] = value; + } + } + else { // not associated with any optname + opt._.push(args[i]); + } + } + return opt; + } +} + +/*t: + plan(11, "Testing Opt."); + + is( + typeof Opt, + "object", + "Opt is an object." + ); + + is( + typeof Opt.get, + "function", + "Opt.get is a function." + ); + + var optNames = {a:"accept", b:"backtrace", c:"class", d:"debug", "e[]":"exceptions"}; + var t_options = Opt.get(["-a=xml", "-b", "--class=new", "--debug", "-e=one", "-e=two", "foo", "bar"], optNames); + + is( + t_options.a, + "xml", + "an option defined with a short name can be accessed by its short name." + ); + + is( + t_options.b, + true, + "an option defined with a short name and no value are true." + ); + + is( + t_options.c, + "new", + "an option defined with a long name can be accessed by its short name." + ); + + is( + t_options.d, + true, + "an option defined with a long name and no value are true." + ); + + is( + typeof t_options.e, + "object", + "an option that can accept multiple values is defined." + ); + + is( + t_options.e.length, + 2, + "an option that can accept multiple values can have more than one value." + ); + + is( + t_options.e[1], + "two", + "an option that can accept multiple values can be accessed as an array." + ); + + is( + typeof t_options._, + "object", + "the property '_' is defined for unnamed options." + ); + + is( + t_options._[0], + "foo", + "the property '_' can be accessed as an array." + ); + */ \ No newline at end of file diff --git a/bin/jsdoc/frame/Reflection.js b/bin/jsdoc/frame/Reflection.js new file mode 100644 index 00000000..0968f1c6 --- /dev/null +++ b/bin/jsdoc/frame/Reflection.js @@ -0,0 +1,26 @@ +/**@constructor*/ +function Reflection(obj) { + this.obj = obj; +} + +Reflection.prototype.getConstructorName = function() { + if (this.obj.constructor.name) return this.obj.constructor.name; + var src = this.obj.constructor.toSource(); + var name = src.substring(name.indexOf("function")+8, src.indexOf('(')).replace(/ /g,''); + return name; +} + +Reflection.prototype.getMethod = function(name) { + for (var p in this.obj) { + if (p == name && typeof(this.obj[p]) == "function") return this.obj[p]; + } + return null; +} + +Reflection.prototype.getParameterNames = function() { + var src = this.obj.toSource(); + src = src.substring( + src.indexOf("(", 8)+1, src.indexOf(")") + ); + return src.split(/, ?/); +} diff --git a/bin/jsdoc/frame/String.js b/bin/jsdoc/frame/String.js new file mode 100644 index 00000000..c183c27d --- /dev/null +++ b/bin/jsdoc/frame/String.js @@ -0,0 +1,93 @@ +/** + @name String + @class Additions to the core string object. +*/ + +/** @author Steven Levithan, released as public domain. */ +String.prototype.trim = function() { + var str = this.replace(/^\s+/, ''); + for (var i = str.length - 1; i >= 0; i--) { + if (/\S/.test(str.charAt(i))) { + str = str.substring(0, i + 1); + break; + } + } + return str; +} +/*t: + plan(6, "Testing String.prototype.trim."); + + var s = " a bc ".trim(); + is(s, "a bc", "multiple spaces front and back are trimmed."); + + s = "a bc\n\n".trim(); + is(s, "a bc", "newlines only in back are trimmed."); + + s = "\ta bc".trim(); + is(s, "a bc", "tabs only in front are trimmed."); + + s = "\n \t".trim(); + is(s, "", "an all-space string is trimmed to empty."); + + s = "a b\nc".trim(); + is(s, "a b\nc", "a string with no spaces in front or back is trimmed to itself."); + + s = "".trim(); + is(s, "", "an empty string is trimmed to empty."); + +*/ + +String.prototype.balance = function(open, close) { + var i = 0; + while (this.charAt(i) != open) { + if (i == this.length) return [-1, -1]; + i++; + } + + var j = i+1; + var balance = 1; + while (j < this.length) { + if (this.charAt(j) == open) balance++; + if (this.charAt(j) == close) balance--; + if (balance == 0) break; + j++; + if (j == this.length) return [-1, -1]; + } + + return [i, j]; +} +/*t: + plan(16, "Testing String.prototype.balance."); + + var s = "{abc}".balance("{","}"); + is(s[0], 0, "opener in first is found."); + is(s[1], 4, "closer in last is found."); + + s = "ab{c}de".balance("{","}"); + is(s[0], 2, "opener in middle is found."); + is(s[1], 4, "closer in middle is found."); + + s = "a{b{c}de}f".balance("{","}"); + is(s[0], 1, "nested opener is found."); + is(s[1], 8, "nested closer is found."); + + s = "{}".balance("{","}"); + is(s[0], 0, "opener with no content is found."); + is(s[1], 1, "closer with no content is found."); + + s = "".balance("{","}"); + is(s[0], -1, "empty string opener is -1."); + is(s[1], -1, "empty string closer is -1."); + + s = "{abc".balance("{","}"); + is(s[0], -1, "opener with no closer returns -1."); + is(s[1], -1, "no closer returns -1."); + + s = "abc".balance("{","}"); + is(s[0], -1, "no opener or closer returns -1 for opener."); + is(s[1], -1, "no opener or closer returns -1 for closer."); + + s = "aX11/MIT License + * (See the accompanying README file for full details.) + */ + +/** + Yet another unit testing tool for JavaScript. + @author Michael Mathews micmath@gmail.com + @param {object} testCases Properties are testcase names, values are functions to execute as tests. +*/ +function testrun(testCases) { + var ran = 0; + for (t in testCases) { + var result = testCases[t](); + ran++; + } + + return testrun.reportOut+"-------------------------------\n"+((testrun.fails>0)? ":( Failed "+testrun.fails+"/" : ":) Passed all ")+testrun.count+" test"+((testrun.count == 1)? "":"s")+".\n"; +} + + +testrun.count = 0; +testrun.current = null; +testrun.passes = 0; +testrun.fails = 0; +testrun.reportOut = ""; + +/** @private */ +testrun.report = function(text) { + testrun.reportOut += text+"\n"; +} + +/** + Check if test evaluates to true. + @param {string} test To be evaluated. + @param {string} message Optional. To be displayed in the report. + @return {boolean} True if the string test evaluates to true. +*/ +ok = function(test, message) { + testrun.count++; + + var result; + try { + result = eval(test); + + if (result) { + testrun.passes++; + testrun.report(" OK "+testrun.count+" - "+((message != null)? message : "")); + } + else { + testrun.fails++; + testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : "")); + } + } + catch(e) { + testrun.fails++ + testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : "")); + + } +} + +/** + Check if test is same as expected. + @param {string} test To be evaluated. + @param {string} expected + @param {string} message Optional. To be displayed in the report. + @return {boolean} True if (test == expected). Note that the comparison is not a strict equality check. +*/ +is = function(test, expected, message) { + testrun.count++; + + var result; + try { + result = eval(test); + + if (result == expected) { + testrun.passes++ + testrun.report(" OK "+testrun.count+" - "+((message != null)? message : "")); + } + else { + testrun.fails++ + testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : "")); + testrun.report("expected: "+expected); + testrun.report(" got: "+result); + } + } + catch(e) { + testrun.fails++ + testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : "")); + testrun.report("expected: "+expected); + testrun.report(" got: "+result);} +} + +/** + Check if test matches pattern. + @param {string} test To be evaluated. + @param {string} pattern Used to create a RegExp. + @param {string} message Optional. To be displayed in the report. + @return {boolean} True if test matches pattern. +*/ +like = function(test, pattern, message) { + testrun.count++; + + var result; + try { + result = eval(test); + var rgx = new RegExp(pattern); + + if (rgx.test(result)) { + testrun.passes++ + testrun.report(" OK "+testrun.count+" - "+((message != null)? message : "")); + } + else { + testrun.fails++ + testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : "")); + testrun.report(" this: "+result); + testrun.report("is not like: "+pattern); + } + } + catch(e) { + testrun.fails++ + testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : "")); + } +} \ No newline at end of file diff --git a/bin/jsdoc/handlers/FOODOC.js b/bin/jsdoc/handlers/FOODOC.js new file mode 100644 index 00000000..b208f55b --- /dev/null +++ b/bin/jsdoc/handlers/FOODOC.js @@ -0,0 +1,26 @@ +/** + This is the main container for the FOODOC handler. + @namespace +*/ +FOODOC = { +}; + +/** The current version string of this application. */ +FOODOC.VERSION = "1.0"; + +FOODOC.handle = function(srcFile, src) { + LOG.inform("Handling file '" + srcFile + "'"); + + return [ + new JSDOC.Symbol( + "foo", + [], + "VIRTUAL", + new JSDOC.DocComment("/** This is a foo. */") + ) + ]; +}; + +FOODOC.publish = function(symbolgroup) { + LOG.inform("Publishing symbolgroup."); +}; diff --git a/bin/jsdoc/handlers/XMLDOC.js b/bin/jsdoc/handlers/XMLDOC.js new file mode 100755 index 00000000..40f87b35 --- /dev/null +++ b/bin/jsdoc/handlers/XMLDOC.js @@ -0,0 +1,26 @@ +/** + * This is the main container for the XMLDOC handler. + * @namespace + * @author Brett Fattori (bfattori@fry.com) + * @version $Revision: 498 $ + */ +XMLDOC = { + +}; + +/** The current version string of this application. */ +XMLDOC.VERSION = "1.0"; + +/** Include the library necessary to handle XML files */ +IO.includeDir("handlers/XMLDOC/"); + +/** + * @type Symbol[] + */ +XMLDOC.handle = function(srcFile, src) { + +}; + +XMLDOC.publish = function(symbolgroup) { + +} \ No newline at end of file diff --git a/bin/jsdoc/handlers/XMLDOC/DomReader.js b/bin/jsdoc/handlers/XMLDOC/DomReader.js new file mode 100755 index 00000000..240563da --- /dev/null +++ b/bin/jsdoc/handlers/XMLDOC/DomReader.js @@ -0,0 +1,159 @@ +LOG.inform("XMLDOC.DomReader loaded"); + +XMLDOC.DomReader = function(root) { + + this.dom = root; + + /** + * The current node the reader is on + */ + this.node = root; + + /** + * Get the current node the reader is on + * @type XMLDOC.Parser.node + */ + XMLDOC.DomReader.prototype.getNode = function() { + return this.node; + }; + + /** + * Set the node the reader should be positioned on. + * @param node {XMLDOC.Parser.node} + */ + XMLDOC.DomReader.prototype.setNode = function(node) { + this.node = node; + }; + + /** + * A helper method to make sure the current node will + * never return null, unless null is passed as the root. + * @param step {String} An expression to evaluate - should return a node or null + */ + XMLDOC.DomReader.prototype.navigate = function(step) { + var n; + if ((n = step) != null) + { + this.node = n; + return this.node; + } + return null; + }; + + /** + * Get the root node of the current node's document. + */ + XMLDOC.DomReader.prototype.root = function() { + this.navigate(this.dom); + }; + + /** + * Get the parent of the current node. + */ + XMLDOC.DomReader.prototype.parent = function() { + return this.navigate(this.node.parentNode()); + }; + + /** + * Get the first child of the current node. + */ + XMLDOC.DomReader.prototype.firstChild = function() { + return this.navigate(this.node.firstChild()); + }; + + /** + * Get the last child of the current node. + */ + XMLDOC.DomReader.prototype.lastChild = function() { + return this.navigate(this.node.lastChild()); + }; + + /** + * Get the next sibling of the current node. + */ + XMLDOC.DomReader.prototype.nextSibling = function() { + return this.navigate(this.node.nextSibling()); + }; + + /** + * Get the previous sibling of the current node. + */ + XMLDOC.DomReader.prototype.prevSibling = function() { + return this.navigate(this.node.prevSibling()); + }; + + //=============================================================================================== + // Support methods + + /** + * Walk the tree starting with the current node, calling the plug-in for + * each node visited. Each time the plug-in is called, the DomReader + * is passed as the only parameter. Use the {@link XMLDOC.DomReader#getNode} method + * to access the current node. This method uses a depth first traversal pattern. + * + * @param srcFile {String} The source file being evaluated + */ + XMLDOC.DomReader.prototype.getSymbols = function(srcFile) + { + XMLDOC.DomReader.symbols = []; + XMLDOC.DomReader.currentFile = srcFile; + JSDOC.Symbol.srcFile = (srcFile || ""); + + if (defined(JSDOC.PluginManager)) { + JSDOC.PluginManager.run("onDomGetSymbols", this); + } + + return XMLDOC.DomReader.symbols; + }; + + /** + * Find the node with the given name using a depth first traversal. + * Does not modify the DomReader's current node. + * + * @param name {String} The name of the node to find + * @return the node that was found, or null if not found + */ + XMLDOC.DomReader.prototype.findNode = function(name) + { + var findNode = null; + + // Start at the current node and move into the subtree, + // looking for the node with the given name + function deeper(node, find) + { + var look = null; + + if (node) { + if (node.name == find) + { + return node; + } + + if (node.firstChild()) + { + look = deeper(node.firstChild(), find); + } + + if (!look && node.nextSibling()) + { + look = deeper(node.nextSibling(), find); + } + } + + return look; + } + + return deeper(this.getNode().firstChild(), name); + }; + + /** + * Find the next node with the given name using a depth first traversal. + * + * @param name {String} The name of the node to find + */ + XMLDOC.DomReader.prototype.findPreviousNode = function(name) + { + }; + +}; + diff --git a/bin/jsdoc/handlers/XMLDOC/XMLDoc.js b/bin/jsdoc/handlers/XMLDOC/XMLDoc.js new file mode 100755 index 00000000..e9b3e3ce --- /dev/null +++ b/bin/jsdoc/handlers/XMLDOC/XMLDoc.js @@ -0,0 +1,16 @@ +LOG.inform("XMLDOC.symbolize loaded"); + +/** + * Convert the source file to a set of symbols + */ +XMLDOC.symbolize = function(srcFile, src) { + + LOG.inform("Symbolizing file '" + srcFile + "'"); + + // XML files already have a defined structure, so we don't need to + // do anything but parse them. The DOM reader can create a symbol + // table from the parsed XML. + var dr = new XMLDOC.DomReader(XMLDOC.Parser.parse(src)); + return dr.getSymbols(srcFile); + +}; diff --git a/bin/jsdoc/handlers/XMLDOC/XMLParse.js b/bin/jsdoc/handlers/XMLDOC/XMLParse.js new file mode 100755 index 00000000..78e8f455 --- /dev/null +++ b/bin/jsdoc/handlers/XMLDOC/XMLParse.js @@ -0,0 +1,292 @@ +LOG.inform("XMLDOC.Parser loaded"); + +/** + * XML Parser object. Returns an {@link #XMLDOC.Parser.node} which is + * the root element of the parsed document. + *

+ * By default, this parser will only handle well formed XML. To + * allow the parser to handle HTML, set the XMLDOC.Parser.strictMode + * variable to false before calling XMLDOC.Parser.parse(). + *

+ * Note: If you pass poorly formed XML, it will cause the parser to throw + * an exception. + * + * @author Brett Fattori (bfattori@fry.com) + * @author $Author: micmath $ + * @version $Revision: 497 $ + */ +XMLDOC.Parser = {}; + +/** + * Strict mode setting. Setting this to false allows HTML-style source to + * be parsed. Normally, well formed XML has defined end tags, or empty tags + * are properly formed. Default: true + * @type Boolean + */ +XMLDOC.Parser.strictMode = true; + +/** + * A node in an XML Document. Node types are ROOT, ELEMENT, COMMENT, PI, and TEXT. + * @param parent {XMLDOC.Parser.node} The parent node + * @param name {String} The node name + * @param type {String} One of the types + */ +XMLDOC.Parser.node = function(parent, name, type) +{ + this.name = name; + this.type = type || "ELEMENT"; + this.parent = parent; + this.charData = ""; + this.attrs = {}; + this.nodes = []; + this.cPtr = 0; + + XMLDOC.Parser.node.prototype.getAttributeNames = function() { + var a = []; + for (var o in this.attrs) + { + a.push(o); + } + + return a; + }; + + XMLDOC.Parser.node.prototype.getAttribute = function(attr) { + return this.attrs[attr]; + }; + + XMLDOC.Parser.node.prototype.setAttribute = function(attr, val) { + this.attrs[attr] = val; + }; + + XMLDOC.Parser.node.prototype.getChild = function(idx) { + return this.nodes[idx]; + }; + + XMLDOC.Parser.node.prototype.parentNode = function() { + return this.parent; + }; + + XMLDOC.Parser.node.prototype.firstChild = function() { + return this.nodes[0]; + }; + + XMLDOC.Parser.node.prototype.lastChild = function() { + return this.nodes[this.nodes.length - 1]; + }; + + XMLDOC.Parser.node.prototype.nextSibling = function() { + var p = this.parent; + if (p && (p.nodes.indexOf(this) + 1 != p.nodes.length)) + { + return p.getChild(p.nodes.indexOf(this) + 1); + } + return null; + }; + + XMLDOC.Parser.node.prototype.prevSibling = function() { + var p = this.parent; + if (p && (p.nodes.indexOf(this) - 1 >= 0)) + { + return p.getChild(p.nodes.indexOf(this) - 1); + } + return null; + }; +}; + +/** + * Parse an XML Document from the specified source. The XML should be + * well formed, unless strict mode is disabled, then the parser will + * handle HTML-style XML documents. + * @param src {String} The source to parse + */ +XMLDOC.Parser.parse = function(src) +{ + var A = []; + + // Normailize whitespace + A = src.split("\r\n"); + src = A.join("\n"); + A = src.split("\r"); + src = A.join("\n"); + + // Remove XML and DOCTYPE specifier + src.replace(/<\?XML .*\?>/i, ""); + src.replace(//i, ""); + + // The document is the root node and cannot be modified or removed + var doc = new XMLDOC.Parser.node(null, "ROOT", "DOCUMENT"); + + // Let's break it down + XMLDOC.Parser.eat(doc, src); + + return doc; +}; + +/** + * The XML fragment processing routine. This method is private and should not be called + * directly. + * @param parentNode {XMLDOC.Parser.node} The node which is the parent of this fragment + * @param src {String} The source within the fragment to process + * @private + */ +XMLDOC.Parser.eat = function(parentNode, src) +{ + // A simple tag def + var reTag = new RegExp("<(!|)(\\?|--|)((.|\\s)*?)\\2>","g"); + + // Special tag types + var reCommentTag = //; + var rePITag = /<\?((.|\s)*?)\?>/; + + // A start tag (with potential empty marker) + var reStartTag = /<(.*?)( +([\w_\-]*)=(\"|')(.*)\4)*(\/)?>/; + + // An empty HTML style tag (not proper XML, but we'll accept it so we can process HTML) + var reHTMLEmptyTag = /<(.*?)( +([\w_\-]*)=(\"|')(.*)\4)*>/; + + // Fully enclosing tag with nested tags + var reEnclosingTag = /<(.*?)( +([\w_\-]*)=(\"|')(.*?)\4)*>((.|\s)*?)<\/\1>/; + + // Breaks down attributes + var reAttributes = new RegExp(" +([\\w_\\-]*)=(\"|')(.*?)\\2","g"); + + // Find us a tag + var tag; + while ((tag = reTag.exec(src)) != null) + { + if (tag.index > 0) + { + // The next tag has some text before it + var text = src.substring(0, tag.index).replace(/^[ \t\n]+((.|\n)*?)[ \t\n]+$/, "$1"); + + if (text.length > 0 && (text != "\n")) + { + var txtnode = new XMLDOC.Parser.node(parentNode, "", "TEXT"); + txtnode.charData = text; + + // Append the new text node + parentNode.nodes.push(txtnode); + } + + // Reset the lastIndex of reTag + reTag.lastIndex -= src.substring(0, tag.index).length; + + // Eat the text + src = src.substring(tag.index); + } + + if (reCommentTag.test(tag[0])) + { + // Is this a comment? + var comment = new XMLDOC.Parser.node(parentNode, "", "COMMENT"); + comment.charData = reCommentTag.exec(tag[0])[1]; + + // Append the comment + parentNode.nodes.push(comment); + + // Move the lastIndex of reTag + reTag.lastIndex -= tag[0].length; + + // Eat the tag + src = src.replace(reCommentTag, ""); + } + else if (rePITag.test(tag[0])) + { + // Is this a processing instruction? + var pi = new XMLDOC.Parser.node(parentNode, "", "PI"); + pi.charData = rePITag.exec(tag[0])[1]; + + // Append the processing instruction + parentNode.nodes.push(pi); + + // Move the lastIndex of reTag + reTag.lastIndex -= tag[0].length; + + // Eat the tag + src = src.replace(rePITag, ""); + } + else if (reStartTag.test(tag[0])) + { + // Break it down + var e = reStartTag.exec(tag[0]); + var elem = new XMLDOC.Parser.node(parentNode, e[1], "ELEMENT"); + + // Get attributes from the tag + var a; + while ((a = reAttributes.exec(e[2])) != null ) + { + elem.attrs[a[1]] = a[3]; + } + + // Is this an empty XML-style tag? + if (e[6] == "/") + { + // Append the empty element + parentNode.nodes.push(elem); + + // Move the lastIndex of reTag (include the start tag length) + reTag.lastIndex -= e[0].length; + + // Eat the tag + src = src.replace(reStartTag, ""); + } + else + { + // Check for malformed XML tags + var htmlParsed = false; + var htmlStartTag = reHTMLEmptyTag.exec(src); + + // See if there isn't an end tag within this block + var reHTMLEndTag = new RegExp(""); + var htmlEndTag = reHTMLEndTag.exec(src); + + if (XMLDOC.Parser.strictMode && htmlEndTag == null) + { + // Poorly formed XML fails in strict mode + var err = new Error("Malformed XML passed to XMLDOC.Parser... Error contains malformed 'src'"); + err.src = src; + throw err; + } + else if (htmlEndTag == null) + { + // This is an HTML-style empty tag, store the element for it in non-strict mode + parentNode.nodes.push(elem); + + // Eat the tag + src = src.replace(reHTMLEmptyTag, ""); + htmlParsed = true; + } + + // If we didn't parse HTML-style, it must be an enclosing tag + if (!htmlParsed) + { + var enc = reEnclosingTag.exec(src); + + // Go deeper into the document + XMLDOC.Parser.eat(elem, enc[6]); + + // Append the new element node + parentNode.nodes.push(elem); + + // Eat the tag + src = src.replace(reEnclosingTag, ""); + } + } + + // Reset the lastIndex of reTag + reTag.lastIndex = 0; + } + } + + // No tag was found... append the text if there is any + src = src.replace(/^[ \t\n]+((.|\n)*?)[ \t\n]+$/, "$1"); + if (src.length > 0 && (src != "\n")) + { + var txtNode = new XMLDOC.Parser.node(parentNode, "", "TEXT"); + txtNode.charData = src; + + // Append the new text node + parentNode.nodes.push(txtNode); + } +}; diff --git a/bin/jsdoc/jsrun.jar b/bin/jsdoc/jsrun.jar new file mode 100644 index 00000000..49c03f4c Binary files /dev/null and b/bin/jsdoc/jsrun.jar differ diff --git a/bin/jsdoc/lib/JSDOC.js b/bin/jsdoc/lib/JSDOC.js new file mode 100644 index 00000000..5de7b9ef --- /dev/null +++ b/bin/jsdoc/lib/JSDOC.js @@ -0,0 +1,106 @@ +/** + @overview + @date $Date: 2010-06-13 22:02:44 +0100 (Sun, 13 Jun 2010) $ + @version $Revision: 837 $ + @location $HeadURL: https://jsdoc-toolkit.googlecode.com/svn/tags/jsdoc_toolkit-2.4.0/jsdoc-toolkit/app/lib/JSDOC.js $ + @name JSDOC.js + */ + +/** + This is the main container for the JSDOC application. + @namespace +*/ +JSDOC = { +}; + +/** + @requires Opt + */ +if (typeof arguments == "undefined") arguments = []; +JSDOC.opt = Opt.get( + arguments, + { + a: "allfunctions", + c: "conf", + d: "directory", + "D[]": "define", + e: "encoding", + "E[]": "exclude", + h: "help", + m: "multiple", + n: "nocode", + o: "out", + p: "private", + q: "quiet", + r: "recurse", + S: "securemodules", + s: "suppress", + t: "template", + T: "testmode", + u: "unique", + v: "verbose", + x: "ext" + } +); + +/** The current version string of this application. */ +JSDOC.VERSION = "2.4.0"; + +/** Print out usage information and quit. */ +JSDOC.usage = function() { + print("USAGE: java -jar jsrun.jar app/run.js [OPTIONS] ..."); + print(""); + print("OPTIONS:"); + print(" -a or --allfunctions\n Include all functions, even undocumented ones.\n"); + print(" -c or --conf\n Load a configuration file.\n"); + print(" -d= or --directory=\n Output to this directory (defaults to \"out\").\n"); + print(" -D=\"myVar:My value\" or --define=\"myVar:My value\"\n Multiple. Define a variable, available in JsDoc as JSDOC.opt.D.myVar.\n"); + print(" -e= or --encoding=\n Use this encoding to read and write files.\n"); + print(" -E=\"REGEX\" or --exclude=\"REGEX\"\n Multiple. Exclude files based on the supplied regex.\n"); + print(" -h or --help\n Show this message and exit.\n"); + print(" -m or --multiples\n Don't warn about symbols being documented more than once.\n"); + print(" -n or --nocode\n Ignore all code, only document comments with @name tags.\n"); + print(" -o= or --out=\n Print log messages to a file (defaults to stdout).\n"); + print(" -p or --private\n Include symbols tagged as private, underscored and inner symbols.\n"); + print(" -q or --quiet\n Do not output any messages, not even warnings.\n"); + print(" -r= or --recurse=\n Descend into src directories.\n"); + print(" -s or --suppress\n Suppress source code output.\n"); + print(" -S or --securemodules\n Use Secure Modules mode to parse source code.\n"); + print(" -t= or --template=\n Required. Use this template to format the output.\n"); + print(" -T or --test\n Run all unit tests and exit.\n"); + print(" -u or --unique\n Force file names to be unique, but not based on symbol names.\n"); + print(" -v or --verbose\n Provide verbose feedback about what is happening.\n"); + print(" -x=[,EXT]... or --ext=[,EXT]...\n Scan source files with the given extension/s (defaults to js).\n"); + + quit(); +} + +/*t: + plan(4, "Testing JSDOC namespace."); + + is( + typeof JSDOC, + "object", + "JSDOC.usage is a function." + ); + + is( + typeof JSDOC.VERSION, + "string", + "JSDOC.VERSION is a string." + ); + + is( + typeof JSDOC.usage, + "function", + "JSDOC.usage is a function." + ); + + is( + typeof JSDOC.opt, + "object", + "JSDOC.opt is a object." + ); + */ + +if (this.IO) IO.includeDir("lib/JSDOC/"); diff --git a/bin/jsdoc/lib/JSDOC/DocComment.js b/bin/jsdoc/lib/JSDOC/DocComment.js new file mode 100644 index 00000000..4b21cd71 --- /dev/null +++ b/bin/jsdoc/lib/JSDOC/DocComment.js @@ -0,0 +1,204 @@ +if (typeof JSDOC == "undefined") JSDOC = {}; + +/** + Create a new DocComment. This takes a raw documentation comment, + and wraps it in useful accessors. + @class Represents a documentation comment object. + */ +JSDOC.DocComment = function(/**String*/comment) { + this.init(); + if (typeof comment != "undefined") { + this.parse(comment); + } +} + +JSDOC.DocComment.prototype.init = function() { + this.isUserComment = true; + this.src = ""; + this.meta = ""; + this.tagTexts = []; + this.tags = []; +} + +/** + @requires JSDOC.DocTag + */ +JSDOC.DocComment.prototype.parse = function(/**String*/comment) { + if (comment == "") { + comment = "/** @desc */"; + this.isUserComment = false; + } + + this.src = JSDOC.DocComment.unwrapComment(comment); + + this.meta = ""; + if (this.src.indexOf("#") == 0) { + this.src.match(/#(.+[+-])([\s\S]*)$/); + if (RegExp.$1) this.meta = RegExp.$1; + if (RegExp.$2) this.src = RegExp.$2; + } + + if (typeof JSDOC.PluginManager != "undefined") { + JSDOC.PluginManager.run("onDocCommentSrc", this); + } + + this.fixDesc(); + + this.src = JSDOC.DocComment.shared+"\n"+this.src; + + this.tagTexts = + this.src + .split(/(^|[\r\n])\s*@/) + .filter(function($){return $.match(/\S/)}); + + /** + The tags found in the comment. + @type JSDOC.DocTag[] + */ + this.tags = this.tagTexts.map(function($){return new JSDOC.DocTag($)}); + + if (typeof JSDOC.PluginManager != "undefined") { + JSDOC.PluginManager.run("onDocCommentTags", this); + } +} + +/*t: + plan(5, "testing JSDOC.DocComment"); + requires("../frame/String.js"); + requires("../lib/JSDOC/DocTag.js"); + + var com = new JSDOC.DocComment("/**@foo some\n* comment here*"+"/"); + is(com.tagTexts[0], "foo some\ncomment here", "first tag text is found."); + is(com.tags[0].title, "foo", "the title is found in a comment with one tag."); + + var com = new JSDOC.DocComment("/** @foo first\n* @bar second*"+"/"); + is(com.getTag("bar").length, 1, "getTag() returns one tag by that title."); + + JSDOC.DocComment.shared = "@author John Smith"; + var com = new JSDOC.DocComment("/**@foo some\n* comment here*"+"/"); + is(com.tags[0].title, "author", "shared comment is added."); + is(com.tags[1].title, "foo", "shared comment is added to existing tag."); +*/ + +/** + If no @desc tag is provided, this function will add it. + */ +JSDOC.DocComment.prototype.fixDesc = function() { + if (this.meta && this.meta != "@+") return; + if (/^\s*[^@\s]/.test(this.src)) { + this.src = "@desc "+this.src; + } +} + +/*t: + plan(5, "testing JSDOC.DocComment#fixDesc"); + + var com = new JSDOC.DocComment(); + + com.src = "this is a desc\n@author foo"; + com.fixDesc(); + is(com.src, "@desc this is a desc\n@author foo", "if no @desc tag is provided one is added."); + + com.src = "x"; + com.fixDesc(); + is(com.src, "@desc x", "if no @desc tag is provided one is added to a single character."); + + com.src = "\nx"; + com.fixDesc(); + is(com.src, "@desc \nx", "if no @desc tag is provided one is added to return and character."); + + com.src = " "; + com.fixDesc(); + is(com.src, " ", "if no @desc tag is provided one is not added to just whitespace."); + + com.src = ""; + com.fixDesc(); + is(com.src, "", "if no @desc tag is provided one is not added to empty."); +*/ + +/** + Remove slash-star comment wrapper from a raw comment string. + @type String + */ +JSDOC.DocComment.unwrapComment = function(/**String*/comment) { + if (!comment) return ""; + var unwrapped = comment.replace(/(^\/\*\*|\*\/$)/g, "").replace(/^\s*\* ?/gm, ""); + return unwrapped; +} + +/*t: + plan(5, "testing JSDOC.DocComment.unwrapComment"); + + var com = "/**x*"+"/"; + var unwrapped = JSDOC.DocComment.unwrapComment(com); + is(unwrapped, "x", "a single character jsdoc is found."); + + com = "/***x*"+"/"; + unwrapped = JSDOC.DocComment.unwrapComment(com); + is(unwrapped, "x", "three stars are allowed in the opener."); + + com = "/****x*"+"/"; + unwrapped = JSDOC.DocComment.unwrapComment(com); + is(unwrapped, "*x", "fourth star in the opener is kept."); + + com = "/**x\n * y\n*"+"/"; + unwrapped = JSDOC.DocComment.unwrapComment(com); + is(unwrapped, "x\ny\n", "leading stars and spaces are trimmed."); + + com = "/**x\n * y\n*"+"/"; + unwrapped = JSDOC.DocComment.unwrapComment(com); + is(unwrapped, "x\n y\n", "only first space after leading stars are trimmed."); +*/ + +/** + Provides a printable version of the comment. + @type String + */ +JSDOC.DocComment.prototype.toString = function() { + return this.src; +} + +/*t: + plan(1, "testing JSDOC.DocComment#fixDesc"); + var com = new JSDOC.DocComment(); + com.src = "foo"; + is(""+com, "foo", "stringifying a comment returns the unwrapped src."); +*/ + +/** + Given the title of a tag, returns all tags that have that title. + @type JSDOC.DocTag[] + */ +JSDOC.DocComment.prototype.getTag = function(/**String*/tagTitle) { + return this.tags.filter(function($){return $.title == tagTitle}); +} + +JSDOC.DocComment.prototype.deleteTag = function(/**String*/tagTitle) { + this.tags = this.tags.filter(function($){return $.title != tagTitle}) +} + +/*t: + plan(1, "testing JSDOC.DocComment#getTag"); + requires("../frame/String.js"); + requires("../lib/JSDOC/DocTag.js"); + + var com = new JSDOC.DocComment("/**@foo some\n* @bar\n* @bar*"+"/"); + is(com.getTag("bar").length, 2, "getTag returns expected number of tags."); +*/ + +/** + Used to store the currently shared tag text. +*/ +JSDOC.DocComment.shared = ""; + +/*t: + plan(2, "testing JSDOC.DocComment.shared"); + requires("../frame/String.js"); + requires("../lib/JSDOC/DocTag.js"); + + JSDOC.DocComment.shared = "@author Michael"; + + var com = new JSDOC.DocComment("/**@foo\n* @foo*"+"/"); + is(com.getTag("author").length, 1, "getTag returns shared tag."); + is(com.getTag("foo").length, 2, "getTag returns unshared tags too."); +*/ \ No newline at end of file diff --git a/bin/jsdoc/lib/JSDOC/DocTag.js b/bin/jsdoc/lib/JSDOC/DocTag.js new file mode 100644 index 00000000..77ec07ca --- /dev/null +++ b/bin/jsdoc/lib/JSDOC/DocTag.js @@ -0,0 +1,294 @@ +if (typeof JSDOC == "undefined") JSDOC = {}; + +/** + @constructor + */ +JSDOC.DocTag = function(src) { + this.init(); + if (typeof src != "undefined") { + this.parse(src); + } +} + +/** + Create and initialize the properties of this. + */ +JSDOC.DocTag.prototype.init = function() { + this.title = ""; + this.type = ""; + this.name = ""; + this.isOptional = false; + this.defaultValue = ""; + this.desc = ""; + + return this; +} + +/** + Populate the properties of this from the given tag src. + @param {string} src + */ +JSDOC.DocTag.prototype.parse = function(src) { + if (typeof src != "string") throw "src must be a string not "+(typeof src); + + try { + src = this.nibbleTitle(src); + if (JSDOC.PluginManager) { + JSDOC.PluginManager.run("onDocTagSynonym", this); + } + + src = this.nibbleType(src); + + // only some tags are allowed to have names. + if (this.title == "param" || this.title == "property" || this.title == "config") { // @config is deprecated + src = this.nibbleName(src); + } + } + catch(e) { + if (LOG) LOG.warn(e); + else throw e; + } + this.desc = src; // whatever is left + + // example tags need to have whitespace preserved + if (this.title != "example") this.desc = this.desc.trim(); + + if (JSDOC.PluginManager) { + JSDOC.PluginManager.run("onDocTag", this); + } +} + +/** + Automatically called when this is stringified. + */ +JSDOC.DocTag.prototype.toString = function() { + return this.desc; +} + +/*t: + plan(1, "testing JSDOC.DocTag#toString"); + + var tag = new JSDOC.DocTag("param {object} date A valid date."); + is(""+tag, "A valid date.", "stringifying a tag returns the desc."); + */ + +/** + Find and shift off the title of a tag. + @param {string} src + @return src + */ +JSDOC.DocTag.prototype.nibbleTitle = function(src) { + if (typeof src != "string") throw "src must be a string not "+(typeof src); + + var parts = src.match(/^\s*(\S+)(?:\s([\s\S]*))?$/); + + if (parts && parts[1]) this.title = parts[1]; + if (parts && parts[2]) src = parts[2]; + else src = ""; + + return src; +} + +/*t: + plan(8, "testing JSDOC.DocTag#nibbleTitle"); + + var tag = new JSDOC.DocTag(); + + tag.init().nibbleTitle("aTitleGoesHere"); + is(tag.title, "aTitleGoesHere", "a title can be found in a single-word string."); + + var src = tag.init().nibbleTitle("aTitleGoesHere and the rest"); + is(tag.title, "aTitleGoesHere", "a title can be found in a multi-word string."); + is(src, "and the rest", "the rest is returned when the title is nibbled off."); + + src = tag.init().nibbleTitle(""); + is(tag.title, "", "given an empty string the title is empty."); + is(src, "", "the rest is empty when the tag is empty."); + + var src = tag.init().nibbleTitle(" aTitleGoesHere\n a description"); + is(tag.title, "aTitleGoesHere", "leading and trailing spaces are not part of the title."); + is(src, " a description", "leading spaces (less one) are part of the description."); + + tag.init().nibbleTitle("a.Title::Goes_Here foo"); + is(tag.title, "a.Title::Goes_Here", "titles with punctuation are allowed."); + */ + +/** + Find and shift off the type of a tag. + @requires frame/String.js + @param {string} src + @return src + */ +JSDOC.DocTag.prototype.nibbleType = function(src) { + if (typeof src != "string") throw "src must be a string not "+(typeof src); + + if (src.match(/^\s*\{/)) { + var typeRange = src.balance("{", "}"); + if (typeRange[1] == -1) { + throw "Malformed comment tag ignored. Tag type requires an opening { and a closing }: "+src; + } + this.type = src.substring(typeRange[0]+1, typeRange[1]).trim(); + this.type = this.type.replace(/\s*,\s*/g, "|"); // multiples can be separated by , or | + src = src.substring(typeRange[1]+1); + } + + return src; +} + +/*t: + plan(5, "testing JSDOC.DocTag.parser.nibbleType"); + requires("../frame/String.js"); + + var tag = new JSDOC.DocTag(); + + tag.init().nibbleType("{String[]} aliases"); + is(tag.type, "String[]", "type can have non-alpha characters."); + + tag.init().nibbleType("{ aTypeGoesHere } etc etc"); + is(tag.type, "aTypeGoesHere", "type is trimmed."); + + tag.init().nibbleType("{ oneType, twoType ,\n threeType } etc etc"); + is(tag.type, "oneType|twoType|threeType", "multiple types can be separated by commas."); + + var error; + try { tag.init().nibbleType("{widget foo"); } + catch(e) { error = e; } + is(typeof error, "string", "malformed tag type throws error."); + isnt(error.indexOf("Malformed"), -1, "error message tells tag is malformed."); + */ + +/** + Find and shift off the name of a tag. + @requires frame/String.js + @param {string} src + @return src + */ +JSDOC.DocTag.prototype.nibbleName = function(src) { + if (typeof src != "string") throw "src must be a string not "+(typeof src); + + src = src.trim(); + + // is optional? + if (src.charAt(0) == "[") { + var nameRange = src.balance("[", "]"); + if (nameRange[1] == -1) { + throw "Malformed comment tag ignored. Tag optional name requires an opening [ and a closing ]: "+src; + } + this.name = src.substring(nameRange[0]+1, nameRange[1]).trim(); + this.isOptional = true; + + src = src.substring(nameRange[1]+1); + + // has default value? + var nameAndValue = this.name.split("="); + if (nameAndValue.length) { + this.name = nameAndValue.shift().trim(); + this.defaultValue = nameAndValue.join("="); + } + } + else { + var parts = src.match(/^(\S+)(?:\s([\s\S]*))?$/); + if (parts) { + if (parts[1]) this.name = parts[1]; + if (parts[2]) src = parts[2].trim(); + else src = ""; + } + } + + return src; +} + +/*t: + requires("../frame/String.js"); + plan(9, "testing JSDOC.DocTag.parser.nibbleName"); + + var tag = new JSDOC.DocTag(); + + tag.init().nibbleName("[foo] This is a description."); + is(tag.isOptional, true, "isOptional syntax is detected."); + is(tag.name, "foo", "optional param name is found."); + + tag.init().nibbleName("[foo] This is a description."); + is(tag.isOptional, true, "isOptional syntax is detected when no type."); + is(tag.name, "foo", "optional param name is found when no type."); + + tag.init().nibbleName("[foo=7] This is a description."); + is(tag.name, "foo", "optional param name is found when default value."); + is(tag.defaultValue, 7, "optional param default value is found when default value."); + + //tag.init().nibbleName("[foo= a value] This is a description."); + //is(tag.defaultValue, " a value", "optional param default value is found when default value has spaces (issue #112)."); + + tag.init().nibbleName("[foo=[]] This is a description."); + is(tag.defaultValue, "[]", "optional param default value is found when default value is [] (issue #95)."); + + tag.init().nibbleName("[foo=a=b] This is a description."); + is(tag.name, "foo", "optional param name is found when default value is a=b."); + is(tag.defaultValue, "a=b", "optional param default value is found when default value is a=b.") + */ + +/*t: + plan(32, "Testing JSDOC.DocTag.parser."); + requires("../frame/String.js"); + + var tag = new JSDOC.DocTag(); + + is(typeof tag, "object", "JSDOC.DocTag.parser with an empty string returns an object."); + is(typeof tag.title, "string", "returned object has a string property 'title'."); + is(typeof tag.type, "string", "returned object has a string property 'type'."); + is(typeof tag.name, "string", "returned object has a string property 'name'."); + is(typeof tag.defaultValue, "string", "returned object has a string property 'defaultValue'."); + is(typeof tag.isOptional, "boolean", "returned object has a boolean property 'isOptional'."); + is(typeof tag.desc, "string", "returned object has a string property 'desc'."); + + tag = new JSDOC.DocTag("param {widget} foo"); + is(tag.title, "param", "param title is found."); + is(tag.name, "foo", "param name is found when desc is missing."); + is(tag.desc, "", "param desc is empty when missing."); + + tag = new JSDOC.DocTag("param {object} date A valid date."); + is(tag.name, "date", "param name is found with a type."); + is(tag.type, "object", "param type is found."); + is(tag.desc, "A valid date.", "param desc is found with a type."); + + tag = new JSDOC.DocTag("param aName a description goes\n here."); + is(tag.name, "aName", "param name is found without a type."); + is(tag.desc, "a description goes\n here.", "param desc is found without a type."); + + tag = new JSDOC.DocTag("param {widget}"); + is(tag.name, "", "param name is empty when it is not given."); + + tag = new JSDOC.DocTag("param {widget} [foo] This is a description."); + is(tag.name, "foo", "optional param name is found."); + + tag = new JSDOC.DocTag("return {aType} This is a description."); + is(tag.type, "aType", "when return tag has no name, type is found."); + is(tag.desc, "This is a description.", "when return tag has no name, desc is found."); + + tag = new JSDOC.DocTag("author Joe Coder "); + is(tag.title, "author", "author tag has a title."); + is(tag.type, "", "the author tag has no type."); + is(tag.name, "", "the author tag has no name."); + is(tag.desc, "Joe Coder ", "author tag has desc."); + + tag = new JSDOC.DocTag("private \t\n "); + is(tag.title, "private", "private tag has a title."); + is(tag.type, "", "the private tag has no type."); + is(tag.name, "", "the private tag has no name."); + is(tag.desc, "", "private tag has no desc."); + + tag = new JSDOC.DocTag("example\n example(code);\n more();"); + is(tag.desc, " example(code);\n more();", "leading whitespace (less one) in examples code is preserved."); + + tag = new JSDOC.DocTag("param theName \n"); + is(tag.name, "theName", "name only is found."); + + tag = new JSDOC.DocTag("type theDesc \n"); + is(tag.desc, "theDesc", "desc only is found."); + + tag = new JSDOC.DocTag("type {theType} \n"); + is(tag.type, "theType", "type only is found."); + + tag = new JSDOC.DocTag(""); + is(tag.title, "", "title is empty when tag is empty."); + */ \ No newline at end of file diff --git a/bin/jsdoc/lib/JSDOC/JsDoc.js b/bin/jsdoc/lib/JSDOC/JsDoc.js new file mode 100644 index 00000000..02275a69 --- /dev/null +++ b/bin/jsdoc/lib/JSDOC/JsDoc.js @@ -0,0 +1,140 @@ +/** + @constructor + @param [opt] Used to override the commandline options. Useful for testing. + @version $Id: JsDoc.js 831 2010-03-09 14:24:56Z micmath $ +*/ +JSDOC.JsDoc = function(/**object*/ opt) { + if (opt) { + JSDOC.opt = opt; + } + + if (JSDOC.opt.h) { + JSDOC.usage(); + quit(); + } + + // defend against options that are not sane + if (JSDOC.opt._.length == 0) { + LOG.warn("No source files to work on. Nothing to do."); + quit(); + } + if (JSDOC.opt.t === true || JSDOC.opt.d === true) { + JSDOC.usage(); + } + + if (typeof JSDOC.opt.d == "string") { + if (!JSDOC.opt.d.charAt(JSDOC.opt.d.length-1).match(/[\\\/]/)) { + JSDOC.opt.d = JSDOC.opt.d+"/"; + } + LOG.inform("Output directory set to '"+JSDOC.opt.d+"'."); + IO.mkPath(JSDOC.opt.d); + } + if (JSDOC.opt.e) IO.setEncoding(JSDOC.opt.e); + + // the -r option: scan source directories recursively + if (typeof JSDOC.opt.r == "boolean") JSDOC.opt.r = 10; + else if (!isNaN(parseInt(JSDOC.opt.r))) JSDOC.opt.r = parseInt(JSDOC.opt.r); + else JSDOC.opt.r = 1; + + // the -D option: define user variables + var D = {}; + if (JSDOC.opt.D) { + for (var i = 0; i < JSDOC.opt.D.length; i++) { + var param = JSDOC.opt.D[i]; + // remove first and last character if both == " + if ( + param.length > 1 + && param.charAt(0) == '"' + && param.charAt(param.length-1) == '"' + ) { + param = param.substr(1, param.length-2); + } + var defineParts = param.split(":"); + if (defineParts && defineParts.length > 1) { + for ( var dpIdx = 2; dpIdx < defineParts.length; dpIdx++ ) { + defineParts[1] += ':' + defineParts[dpIdx]; + } + D[defineParts[0]] = defineParts[1]; + } + } + } + JSDOC.opt.D = D; + // combine any conf file D options with the commandline D options + if (defined(JSDOC.conf)) for (var c in JSDOC.conf.D) { + if (!defined(JSDOC.opt.D[c])) { + JSDOC.opt.D[c] = JSDOC.conf.D[c]; + } + } + + // Give plugins a chance to initialize + if (defined(JSDOC.PluginManager)) { + JSDOC.PluginManager.run("onInit", JSDOC.opt); + } + + JSDOC.opt.srcFiles = JSDOC.JsDoc._getSrcFiles(); + JSDOC.JsDoc._parseSrcFiles(); + JSDOC.JsDoc.symbolSet = JSDOC.Parser.symbols; +} + +/** + Retrieve source file list. + @returns {String[]} The pathnames of the files to be parsed. + */ +JSDOC.JsDoc._getSrcFiles = function() { + JSDOC.JsDoc.srcFiles = []; + + var ext = ["js"]; + if (JSDOC.opt.x) { + ext = JSDOC.opt.x.split(",").map(function($) {return $.toLowerCase()}); + } + + for (var i = 0; i < JSDOC.opt._.length; i++) { + JSDOC.JsDoc.srcFiles = JSDOC.JsDoc.srcFiles.concat( + IO.ls(JSDOC.opt._[i], JSDOC.opt.r).filter( + function($) { + var thisExt = $.split(".").pop().toLowerCase(); + + if (JSDOC.opt.E) { + for(var n = 0; n < JSDOC.opt.E.length; n++) { + if ($.match(new RegExp(JSDOC.opt.E[n]))) { + LOG.inform("Excluding " + $); + return false; // if the file matches the regex then it's excluded. + } + } + } + + return (ext.indexOf(thisExt) > -1); // we're only interested in files with certain extensions + } + ) + ); + } + + return JSDOC.JsDoc.srcFiles; +} + +JSDOC.JsDoc._parseSrcFiles = function() { + JSDOC.Parser.init(); + for (var i = 0, l = JSDOC.JsDoc.srcFiles.length; i < l; i++) { + var srcFile = JSDOC.JsDoc.srcFiles[i]; + + if (JSDOC.opt.v) LOG.inform("Parsing file: " + srcFile); + + try { + var src = IO.readFile(srcFile); + } + catch(e) { + LOG.warn("Can't read source file '"+srcFile+"': "+e.message); + } + + var tr = new JSDOC.TokenReader(); + var ts = new JSDOC.TokenStream(tr.tokenize(new JSDOC.TextStream(src))); + + JSDOC.Parser.parse(ts, srcFile); + + } + JSDOC.Parser.finish(); + + if (JSDOC.PluginManager) { + JSDOC.PluginManager.run("onFinishedParsing", JSDOC.Parser.symbols); + } +} diff --git a/bin/jsdoc/lib/JSDOC/JsPlate.js b/bin/jsdoc/lib/JSDOC/JsPlate.js new file mode 100644 index 00000000..bcaebc9c --- /dev/null +++ b/bin/jsdoc/lib/JSDOC/JsPlate.js @@ -0,0 +1,109 @@ +/** + @constructor +*/ +JSDOC.JsPlate = function(templateFile) { + if (templateFile) this.template = IO.readFile(templateFile); + + this.templateFile = templateFile; + this.code = ""; + this.parse(); +} + +JSDOC.JsPlate.prototype.parse = function() { + this.template = this.template.replace(/\{#[\s\S]+?#\}/gi, ""); + this.code = "var output=\u001e"+this.template; + + this.code = this.code.replace( + //gi, + function (match, eachName, inName) { + return "\u001e;\rvar $"+eachName+"_keys = keys("+inName+");\rfor(var $"+eachName+"_i = 0; $"+eachName+"_i < $"+eachName+"_keys.length; $"+eachName+"_i++) {\rvar $"+eachName+"_last = ($"+eachName+"_i == $"+eachName+"_keys.length-1);\rvar $"+eachName+"_key = $"+eachName+"_keys[$"+eachName+"_i];\rvar "+eachName+" = "+inName+"[$"+eachName+"_key];\routput+=\u001e"; + } + ); + this.code = this.code.replace(//g, "\u001e;\rif ($1) { output+=\u001e"); + this.code = this.code.replace(//g, "\u001e;}\relse if ($1) { output+=\u001e"); + this.code = this.code.replace(//g, "\u001e;}\relse { output+=\u001e"); + this.code = this.code.replace(/<\/(if|for)>/g, "\u001e;\r};\routput+=\u001e"); + this.code = this.code.replace( + /\{\+\s*([\s\S]+?)\s*\+\}/gi, + function (match, code) { + code = code.replace(/"/g, "\u001e"); // prevent qoute-escaping of inline code + code = code.replace(/(\r?\n)/g, " "); + return "\u001e+ ("+code+") +\u001e"; + } + ); + this.code = this.code.replace( + /\{!\s*([\s\S]+?)\s*!\}/gi, + function (match, code) { + code = code.replace(/"/g, "\u001e"); // prevent qoute-escaping of inline code + code = code.replace(/(\n)/g, " "); + return "\u001e; "+code+";\routput+=\u001e"; + } + ); + this.code = this.code+"\u001e;"; + + this.code = this.code.replace(/(\r?\n)/g, "\\n"); + this.code = this.code.replace(/"/g, "\\\""); + this.code = this.code.replace(/\u001e/g, "\""); +} + +JSDOC.JsPlate.prototype.toCode = function() { + return this.code; +} + +JSDOC.JsPlate.keys = function(obj) { + var keys = []; + if (obj.constructor.toString().indexOf("Array") > -1) { + for (var i = 0; i < obj.length; i++) { + keys.push(i); + } + } + else { + for (var i in obj) { + keys.push(i); + } + } + return keys; +}; + +JSDOC.JsPlate.values = function(obj) { + var values = []; + if (obj.constructor.toString().indexOf("Array") > -1) { + for (var i = 0; i < obj.length; i++) { + values.push(obj[i]); + } + } + else { + for (var i in obj) { + values.push(obj[i]); + } + } + return values; +}; + +JSDOC.JsPlate.prototype.process = function(data, compact) { + var keys = JSDOC.JsPlate.keys; + var values = JSDOC.JsPlate.values; + + try { + eval(this.code); + } + catch (e) { + print(">> There was an error evaluating the compiled code from template: "+this.templateFile); + print(" The error was on line "+e.lineNumber+" "+e.name+": "+e.message); + var lines = this.code.split("\r"); + if (e.lineNumber-2 >= 0) print("line "+(e.lineNumber-1)+": "+lines[e.lineNumber-2]); + print("line "+e.lineNumber+": "+lines[e.lineNumber-1]); + print(""); + } + + if (compact) { // patch by mcbain.asm + // Remove lines that contain only space-characters, usually left by lines in the template + // which originally only contained JSPlate tags or code. This makes it easier to write + // non-tricky templates which still put out nice code (not bloated with extra lines). + // Lines purposely left blank (just a line ending) are left alone. + output = output.replace(/\s+?(\r?)\n/g, "$1\n"); + } + + /*debug*///print(this.code); + return output; +} \ No newline at end of file diff --git a/bin/jsdoc/lib/JSDOC/Lang.js b/bin/jsdoc/lib/JSDOC/Lang.js new file mode 100644 index 00000000..62919d7d --- /dev/null +++ b/bin/jsdoc/lib/JSDOC/Lang.js @@ -0,0 +1,144 @@ +/** + @namespace +*/ +JSDOC.Lang = { +} + +JSDOC.Lang.isBuiltin = function(name) { + return (JSDOC.Lang.isBuiltin.coreObjects.indexOf(name) > -1); +} +JSDOC.Lang.isBuiltin.coreObjects = ['_global_', 'Array', 'Boolean', 'Date', 'Error', 'Function', 'Math', 'Number', 'Object', 'RegExp', 'String']; + +JSDOC.Lang.whitespace = function(ch) { + return JSDOC.Lang.whitespace.names[ch]; +} +JSDOC.Lang.whitespace.names = { + " ": "SPACE", + "\f": "FORMFEED", + "\t": "TAB", + "\u0009": "UNICODE_TAB", + "\u000A": "UNICODE_NBR", + "\u0008": "VERTICAL_TAB" +}; + +JSDOC.Lang.newline = function(ch) { + return JSDOC.Lang.newline.names[ch]; +} +JSDOC.Lang.newline.names = { + "\n": "NEWLINE", + "\r": "RETURN", + "\u000A": "UNICODE_LF", + "\u000D": "UNICODE_CR", + "\u2029": "UNICODE_PS", + "\u2028": "UNICODE_LS" +}; + +JSDOC.Lang.keyword = function(word) { + return JSDOC.Lang.keyword.names["="+word]; +} +JSDOC.Lang.keyword.names = { + "=break": "BREAK", + "=case": "CASE", + "=catch": "CATCH", + "=const": "VAR", + "=continue": "CONTINUE", + "=default": "DEFAULT", + "=delete": "DELETE", + "=do": "DO", + "=else": "ELSE", + "=false": "FALSE", + "=finally": "FINALLY", + "=for": "FOR", + "=function": "FUNCTION", + "=if": "IF", + "=in": "IN", + "=instanceof": "INSTANCEOF", + "=new": "NEW", + "=null": "NULL", + "=return": "RETURN", + "=switch": "SWITCH", + "=this": "THIS", + "=throw": "THROW", + "=true": "TRUE", + "=try": "TRY", + "=typeof": "TYPEOF", + "=void": "VOID", + "=while": "WHILE", + "=with": "WITH", + "=var": "VAR" +}; + +JSDOC.Lang.punc = function(ch) { + return JSDOC.Lang.punc.names[ch]; +} +JSDOC.Lang.punc.names = { + ";": "SEMICOLON", + ",": "COMMA", + "?": "HOOK", + ":": "COLON", + "||": "OR", + "&&": "AND", + "|": "BITWISE_OR", + "^": "BITWISE_XOR", + "&": "BITWISE_AND", + "===": "STRICT_EQ", + "==": "EQ", + "=": "ASSIGN", + "!==": "STRICT_NE", + "!=": "NE", + "<<": "LSH", + "<=": "LE", + "<": "LT", + ">>>": "URSH", + ">>": "RSH", + ">=": "GE", + ">": "GT", + "++": "INCREMENT", + "--": "DECREMENT", + "+": "PLUS", + "-": "MINUS", + "*": "MUL", + "/": "DIV", + "%": "MOD", + "!": "NOT", + "~": "BITWISE_NOT", + ".": "DOT", + "[": "LEFT_BRACKET", + "]": "RIGHT_BRACKET", + "{": "LEFT_CURLY", + "}": "RIGHT_CURLY", + "(": "LEFT_PAREN", + ")": "RIGHT_PAREN" +}; + +JSDOC.Lang.matching = function(name) { + return JSDOC.Lang.matching.names[name]; +} +JSDOC.Lang.matching.names = { + "LEFT_PAREN": "RIGHT_PAREN", + "RIGHT_PAREN": "LEFT_PAREN", + "LEFT_CURLY": "RIGHT_CURLY", + "RIGHT_CURLY": "LEFT_CURLY", + "LEFT_BRACE": "RIGHT_BRACE", + "RIGHT_BRACE": "LEFT_BRACE" +} + +JSDOC.Lang.isNumber = function(str) { + return /^(\.[0-9]|[0-9]+\.|[0-9])[0-9]*([eE][+-][0-9]+)?$/i.test(str); +} + +JSDOC.Lang.isHexDec = function(str) { + return /^0x[0-9A-F]+$/i.test(str); +} + +JSDOC.Lang.isWordChar = function(str) { + return /^[a-zA-Z0-9$_.]+$/.test(str); +} + +JSDOC.Lang.isSpace = function(str) { + return (typeof JSDOC.Lang.whitespace(str) != "undefined"); +} + +JSDOC.Lang.isNewline = function(str) { + return (typeof JSDOC.Lang.newline(str) != "undefined"); +} \ No newline at end of file diff --git a/bin/jsdoc/lib/JSDOC/Parser.js b/bin/jsdoc/lib/JSDOC/Parser.js new file mode 100644 index 00000000..e489c61d --- /dev/null +++ b/bin/jsdoc/lib/JSDOC/Parser.js @@ -0,0 +1,146 @@ +if (typeof JSDOC == "undefined") JSDOC = {}; + +/** + @namespace + @requires JSDOC.Walker + @requires JSDOC.Symbol + @requires JSDOC.DocComment +*/ +JSDOC.Parser = { + conf: { + ignoreCode: JSDOC.opt.n, + ignoreAnonymous: true, // factory: true + treatUnderscoredAsPrivate: true, // factory: true + explain: false // factory: false + }, + + addSymbol: function(symbol) { + + if (JSDOC.Parser.rename) { + for (var n in JSDOC.Parser.rename) { + if (symbol.alias.indexOf(n) == 0) { + if (symbol.name == symbol.alias) { + symbol.name = symbol.name.replace(n, JSDOC.Parser.rename[n]); + } + symbol.alias = symbol.alias.replace(n, JSDOC.Parser.rename[n]); + } + } + } + + if (JSDOC.opt.S) { + if (typeof JSDOC.Parser.secureModules == "undefined") JSDOC.Parser.secureModules = {}; + if (/^exports\./.test(symbol.alias)) { + symbol.srcFile.match(/(^|[\\\/])([^\\\/]+)\.js/i); + var fileNS = RegExp.$2; + + // need to create the namespace associated with this file first + if (!JSDOC.Parser.secureModules[fileNS]) { + JSDOC.Parser.secureModules[fileNS] = 1; + var nsSymbol = new JSDOC.Symbol(fileNS, [], "GLOBAL", new JSDOC.DocComment("")); + nsSymbol.isNamespace = true; + nsSymbol.srcFile = ""; + nsSymbol.isPrivate = false; + nsSymbol.srcFile = symbol.srcFile; + nsSymbol.desc = (JSDOC.Parser.symbols.getSymbol(symbol.srcFile) || {desc: ""}).desc; + JSDOC.Parser.addSymbol(nsSymbol); + } + + symbol.alias = symbol.alias.replace(/^exports\./, fileNS + '.'); + symbol.name = symbol.name.replace(/^exports\./, ''); + symbol.memberOf = fileNS; + symbol.isStatic = true; + } + } + + // if a symbol alias is documented more than once the first one with the user docs wins + if (JSDOC.Parser.symbols.hasSymbol(symbol.alias)) { + var oldSymbol = JSDOC.Parser.symbols.getSymbol(symbol.alias); + if (oldSymbol.comment.isUserComment) { + if (JSDOC.opt.m) return; + if (symbol.comment.isUserComment) { // old and new are both documented + LOG.warn("The symbol '"+symbol.alias+"' is documented more than once."); + return; + } + else { // old is documented but new isn't + return; + } + } + } + + // we don't document anonymous things + if (JSDOC.Parser.conf.ignoreAnonymous && symbol.name.match(/\$anonymous\b/)) return; + + // uderscored things may be treated as if they were marked private, this cascades + if (JSDOC.Parser.conf.treatUnderscoredAsPrivate && symbol.name.match(/[.#-]_[^.#-]+$/)) { + if (!symbol.comment.getTag("public").length > 0) symbol.isPrivate = true; + } + + // -p flag is required to document private things + if (!JSDOC.opt.p && symbol.isPrivate) return; // issue #161 fixed by mcbain.asm + + // ignored things are not documented, this doesn't cascade + if (symbol.isIgnored) return; + JSDOC.Parser.symbols.addSymbol(symbol); + }, + + addBuiltin: function(name) { + var builtin = new JSDOC.Symbol(name, [], "CONSTRUCTOR", new JSDOC.DocComment("")); + builtin.isNamespace = true; + builtin.srcFile = ""; + builtin.isPrivate = false; + JSDOC.Parser.addSymbol(builtin); + return builtin; + }, + + init: function() { + JSDOC.Parser.symbols = new JSDOC.SymbolSet(); + JSDOC.Parser.walker = new JSDOC.Walker(); + }, + + finish: function() { + JSDOC.Parser.symbols.relate(); + + // make a litle report about what was found + if (JSDOC.Parser.conf.explain) { + var symbols = JSDOC.Parser.symbols.toArray(); + var srcFile = ""; + for (var i = 0, l = symbols.length; i < l; i++) { + var symbol = symbols[i]; + if (srcFile != symbol.srcFile) { + srcFile = symbol.srcFile; + print("\n"+srcFile+"\n-------------------"); + } + print(i+":\n alias => "+symbol.alias + "\n name => "+symbol.name+ "\n isa => "+symbol.isa + "\n memberOf => " + symbol.memberOf + "\n isStatic => " + symbol.isStatic + ", isInner => " + symbol.isInner+ ", isPrivate => " + symbol.isPrivate); + } + print("-------------------\n"); + } + } +} + +JSDOC.Parser.parse = function(/**JSDOC.TokenStream*/ts, /**String*/srcFile) { + JSDOC.Symbol.srcFile = (srcFile || ""); + JSDOC.DocComment.shared = ""; // shared comments don't cross file boundaries + + if (!JSDOC.Parser.walker) JSDOC.Parser.init(); + JSDOC.Parser.walker.walk(ts); // adds to our symbols + + // filter symbols by option + for (var p = JSDOC.Parser.symbols._index.first(); p; p = JSDOC.Parser.symbols._index.next()) { + var symbol = p.value; + + if (!symbol) continue; + + if (symbol.is("FILE") || symbol.is("GLOBAL")) { + continue; + } + else if (!JSDOC.opt.a && !symbol.comment.isUserComment) { + JSDOC.Parser.symbols.deleteSymbol(symbol.alias); + } + + if (/#$/.test(symbol.alias)) { // we don't document prototypes + JSDOC.Parser.symbols.deleteSymbol(symbol.alias); + } + } + + return JSDOC.Parser.symbols.toArray(); +} diff --git a/bin/jsdoc/lib/JSDOC/PluginManager.js b/bin/jsdoc/lib/JSDOC/PluginManager.js new file mode 100644 index 00000000..9c911931 --- /dev/null +++ b/bin/jsdoc/lib/JSDOC/PluginManager.js @@ -0,0 +1,33 @@ +/** + @namespace Holds functionality related to running plugins. +*/ +JSDOC.PluginManager = { +} + +/** + @param name A unique name that identifies that plugin. + @param handlers A collection of named functions. The names correspond to hooks in the core code. +*/ +JSDOC.PluginManager.registerPlugin = function(/**String*/name, /**Object*/handlers) { + if (!defined(JSDOC.PluginManager.plugins)) + /** The collection of all plugins. Requires a unique name for each. + */ + JSDOC.PluginManager.plugins = {}; + + + JSDOC.PluginManager.plugins[name] = handlers; +} + +/** + @param hook The name of the hook that is being caught. + @param target Any object. This will be passed as the only argument to the handler whose + name matches the hook name. Handlers cannot return a value, so must modify the target + object to have an effect. +*/ +JSDOC.PluginManager.run = function(/**String*/hook, /**Mixed*/target) { + for (var name in JSDOC.PluginManager.plugins) { + if (defined(JSDOC.PluginManager.plugins[name][hook])) { + JSDOC.PluginManager.plugins[name][hook](target); + } + } +} diff --git a/bin/jsdoc/lib/JSDOC/Symbol.js b/bin/jsdoc/lib/JSDOC/Symbol.js new file mode 100644 index 00000000..1aa44da8 --- /dev/null +++ b/bin/jsdoc/lib/JSDOC/Symbol.js @@ -0,0 +1,644 @@ +if (typeof JSDOC == "undefined") JSDOC = {}; + +/** + Create a new Symbol. + @class Represents a symbol in the source code. + */ +JSDOC.Symbol = function() { + this.init(); + if (arguments.length) this.populate.apply(this, arguments); +} + +JSDOC.Symbol.count = 0; + +JSDOC.Symbol.prototype.init = function() { + this._name = ""; + this._params = []; + this.$args = []; + this.addOn = ""; + this.alias = ""; + this.augments = []; + this.author = ""; + this.classDesc = ""; + this.comment = {}; + this.defaultValue = undefined; + this.deprecated = ""; + this.desc = ""; + this.example = []; + this.exceptions = []; + this.fires = []; + this.id = JSDOC.Symbol.count++; + this.inherits = []; + this.inheritsFrom = []; + this.isa = "OBJECT"; + this.isConstant = false; + this.isEvent = false; + this.isIgnored = false; + this.isInner = false; + this.isNamespace = false; + this.isPrivate = false; + this.isStatic = false; + this.memberOf = ""; + this.methods = []; + this.properties = []; + this.requires = []; + this.returns = []; + this.see = []; + this.since = ""; + this.srcFile = {}; + this.type = ""; + this.version = ""; +} + +JSDOC.Symbol.prototype.serialize = function() { + var keys = []; + for (var p in this) { + keys.push (p); + } + keys = keys.sort(); + + var out = ""; + for (var i in keys) { + if (typeof this[keys[i]] == "function") continue; + out += keys[i]+" => "+Dumper.dump(this[keys[i]])+",\n"; + } + return "\n{\n" + out + "}\n"; +} + +JSDOC.Symbol.prototype.clone = function() { + var clone = new JSDOC.Symbol(); + clone.populate.apply(clone, this.$args); // repopulate using the original arguments + clone.srcFile = this.srcFile; // not the current srcFile, the one when the original was made + return clone; +} + +JSDOC.Symbol.prototype.__defineSetter__("name", + function(n) { n = n.replace(/^_global_[.#-]/, ""); n = n.replace(/\.prototype\.?/g, '#'); this._name = n; } +); +JSDOC.Symbol.prototype.__defineGetter__("name", + function() { return this._name; } +); +JSDOC.Symbol.prototype.__defineSetter__("params", + function(v) { + for (var i = 0, l = v.length; i < l; i++) { + if (v[i].constructor != JSDOC.DocTag) { // may be a generic object parsed from signature, like {type:..., name:...} + this._params[i] = new JSDOC.DocTag("param"+((v[i].type)?" {"+v[i].type+"}":"")+" "+v[i].name); + } + else { + this._params[i] = v[i]; + } + } + } +); +JSDOC.Symbol.prototype.__defineGetter__("params", + function() { return this._params; } +); + +JSDOC.Symbol.prototype.getEvents = function() { + var events = []; + for (var i = 0, l = this.methods.length; i < l; i++) { + if (this.methods[i].isEvent) { + this.methods[i].name = this.methods[i].name.replace("event:", ""); + events.push(this.methods[i]); + } + } + return events; +} + +JSDOC.Symbol.prototype.getMethods = function() { + var nonEvents = []; + for (var i = 0, l = this.methods.length; i < l; i++) { + if (!this.methods[i].isEvent) { + nonEvents.push(this.methods[i]); + } + } + return nonEvents; +} + + +JSDOC.Symbol.prototype.populate = function( + /** String */ name, + /** Object[] */ params, + /** String */ isa, + /** JSDOC.DocComment */ comment +) { + this.$args = arguments; + + this.name = name; + this.alias = this.name; + + this.params = params; + this.isa = (isa == "VIRTUAL")? "OBJECT":isa; + this.comment = comment || new JSDOC.DocComment(""); + this.srcFile = JSDOC.Symbol.srcFile; + + if (this.is("FILE") && !this.alias) this.alias = this.srcFile; + + this.setTags(); + + if (typeof JSDOC.PluginManager != "undefined") { + JSDOC.PluginManager.run("onSymbol", this); + } +} + +JSDOC.Symbol.prototype.setTags = function() { + // @author + var authors = this.comment.getTag("author"); + if (authors.length) { + this.author = authors.map(function($){return $.desc;}).join(", "); + } + + /*t: + plan(34, "testing JSDOC.Symbol"); + + requires("../lib/JSDOC/DocComment.js"); + requires("../frame/String.js"); + requires("../lib/JSDOC/DocTag.js"); + + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@author Joe Smith*"+"/")); + is(sym.author, "Joe Smith", "@author tag, author is found."); + */ + + // @desc + var descs = this.comment.getTag("desc"); + if (descs.length) { + this.desc = descs.map(function($){return $.desc;}).join("\n"); // multiple descriptions are concatenated into one + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@desc This is a description.*"+"/")); + is(sym.desc, "This is a description.", "@desc tag, description is found."); + */ + + // @overview + if (this.is("FILE")) { + if (!this.alias) this.alias = this.srcFile; + + var overviews = this.comment.getTag("overview"); + if (overviews.length) { + this.desc = [this.desc].concat(overviews.map(function($){return $.desc;})).join("\n"); + } + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@overview This is an overview.*"+"/")); + is(sym.desc, "\nThis is an overview.", "@overview tag, description is found."); + */ + + // @since + var sinces = this.comment.getTag("since"); + if (sinces.length) { + this.since = sinces.map(function($){return $.desc;}).join(", "); + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@since 1.01*"+"/")); + is(sym.since, "1.01", "@since tag, description is found."); + */ + + // @constant + if (this.comment.getTag("constant").length) { + this.isConstant = true; + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@constant*"+"/")); + is(sym.isConstant, true, "@constant tag, isConstant set."); + */ + + // @version + var versions = this.comment.getTag("version"); + if (versions.length) { + this.version = versions.map(function($){return $.desc;}).join(", "); + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@version 2.0x*"+"/")); + is(sym.version, "2.0x", "@version tag, version is found."); + */ + + // @deprecated + var deprecateds = this.comment.getTag("deprecated"); + if (deprecateds.length) { + this.deprecated = deprecateds.map(function($){return $.desc;}).join("\n"); + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@deprecated Use other method.*"+"/")); + is(sym.deprecated, "Use other method.", "@deprecated tag, desc is found."); + */ + + // @example + var examples = this.comment.getTag("example"); + if (examples.length) { + this.example = examples.map( + // trim trailing whitespace + function($) { + $.desc = $.desc.replace(/\s+$/, ""); + return $; + } + ); + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@example This\n is an example. \n*"+"/")); + isnt(typeof sym.example[0], "undefined", "@example tag, creates sym.example array."); + is(sym.example[0], "This\n is an example.", "@example tag, desc is found."); + */ + + // @see + var sees = this.comment.getTag("see"); + if (sees.length) { + var thisSee = this.see; + sees.map(function($){thisSee.push($.desc);}); + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "FILE", new JSDOC.DocComment("/**@see The other thing.*"+"/")); + is(sym.see, "The other thing.", "@see tag, desc is found."); + */ + + // @class + var classes = this.comment.getTag("class"); + if (classes.length) { + this.isa = "CONSTRUCTOR"; + this.classDesc = classes[0].desc; // desc can't apply to the constructor as there is none. + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@class This describes the class.*"+"/")); + is(sym.isa, "CONSTRUCTOR", "@class tag, makes symbol a constructor."); + is(sym.classDesc, "This describes the class.", "@class tag, class description is found."); + */ + + // @namespace + var namespaces = this.comment.getTag("namespace"); + if (namespaces.length) { + this.classDesc = namespaces[0].desc; + this.isNamespace = true; + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@namespace This describes the namespace.*"+"/")); + is(sym.classDesc, "This describes the namespace.", "@namespace tag, class description is found."); + */ + + // @param + var params = this.comment.getTag("param"); + if (params.length) { + // user-defined params overwrite those with same name defined by the parser + var thisParams = this.params; + + if (thisParams.length == 0) { // none exist yet, so just bung all these user-defined params straight in + this.params = params; + } + else { // need to overlay these user-defined params on to existing parser-defined params + for (var i = 0, l = params.length; i < l; i++) { + if (thisParams[i]) { + if (params[i].type) thisParams[i].type = params[i].type; + thisParams[i].name = params[i].name; + thisParams[i].desc = params[i].desc; + thisParams[i].isOptional = params[i].isOptional; + thisParams[i].defaultValue = params[i].defaultValue; + } + else thisParams[i] = params[i]; + } + } + } + + /*t: + var sym = new JSDOC.Symbol("foo", [{type: "array", name: "pages"}], "FUNCTION", new JSDOC.DocComment("/**Description.*"+"/")); + is(sym.params.length, 1, "parser defined param is found."); + + sym = new JSDOC.Symbol("foo", [], "FUNCTION", new JSDOC.DocComment("/**Description.\n@param {array} pages*"+"/")); + is(sym.params.length, 1, "user defined param is found."); + is(sym.params[0].type, "array", "user defined param type is found."); + is(sym.params[0].name, "pages", "user defined param name is found."); + + sym = new JSDOC.Symbol("foo", [{type: "array", name: "pages"}], "FUNCTION", new JSDOC.DocComment("/**Description.\n@param {string} uid*"+"/")); + is(sym.params.length, 1, "user defined param overwrites parser defined param."); + is(sym.params[0].type, "string", "user defined param type overwrites parser defined param type."); + is(sym.params[0].name, "uid", "user defined param name overwrites parser defined param name."); + + sym = new JSDOC.Symbol("foo", [{type: "array", name: "pages"}, {type: "number", name: "count"}], "FUNCTION", new JSDOC.DocComment("/**Description.\n@param {string} uid*"+"/")); + is(sym.params.length, 2, "user defined params overlay parser defined params."); + is(sym.params[1].type, "number", "user defined param type overlays parser defined param type."); + is(sym.params[1].name, "count", "user defined param name overlays parser defined param name."); + + sym = new JSDOC.Symbol("foo", [], "FUNCTION", new JSDOC.DocComment("/**Description.\n@param {array} pages The pages description.*"+"/")); + is(sym.params.length, 1, "user defined param with description is found."); + is(sym.params[0].desc, "The pages description.", "user defined param description is found."); + */ + + // @constructor + if (this.comment.getTag("constructor").length) { + this.isa = "CONSTRUCTOR"; + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@constructor*"+"/")); + is(sym.isa, "CONSTRUCTOR", "@constructor tag, makes symbol a constructor."); + */ + + // @static + if (this.comment.getTag("static").length) { + this.isStatic = true; + if (this.isa == "CONSTRUCTOR") { + this.isNamespace = true; + } + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@static\n@constructor*"+"/")); + is(sym.isStatic, true, "@static tag, makes isStatic true."); + is(sym.isNamespace, true, "@static and @constructor tag, makes isNamespace true."); + */ + + // @inner + if (this.comment.getTag("inner").length) { + this.isInner = true; + this.isStatic = false; + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@inner*"+"/")); + is(sym.isStatic, false, "@inner tag, makes isStatic false."); + is(sym.isInner, true, "@inner makes isInner true."); + */ + + // @name + var names = this.comment.getTag("name"); + if (names.length) { + this.name = names[0].desc; + } + + /*t: + // todo + */ + + // @field + if (this.comment.getTag("field").length) { + this.isa = "OBJECT"; + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "FUNCTION", new JSDOC.DocComment("/**@field*"+"/")); + is(sym.isa, "OBJECT", "@field tag, makes symbol an object."); + */ + + // @function + if (this.comment.getTag("function").length) { + this.isa = "FUNCTION"; + if (/event:/.test(this.alias)) this.isEvent = true; + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@function*"+"/")); + is(sym.isa, "FUNCTION", "@function tag, makes symbol a function."); + */ + + // @event + var events = this.comment.getTag("event"); + if (events.length) { + this.isa = "FUNCTION"; + this.isEvent = true; + if (!/event:/.test(this.alias)) + this.alias = this.alias.replace(/^(.*[.#-])([^.#-]+)$/, "$1event:$2"); + } + + /*t: + var sym = new JSDOC.Symbol("foo", [], "OBJECT", new JSDOC.DocComment("/**@event*"+"/")); + is(sym.isa, "FUNCTION", "@event tag, makes symbol a function."); + is(sym.isEvent, true, "@event makes isEvent true."); + */ + + // @fires + var fires = this.comment.getTag("fires"); + if (fires.length) { + for (var i = 0; i < fires.length; i++) { + this.fires.push(fires[i].desc); + } + } + + /*t: + // todo + */ + + // @property + var properties = this.comment.getTag("property"); + if (properties.length) { + thisProperties = this.properties; + for (var i = 0; i < properties.length; i++) { + var property = new JSDOC.Symbol(this.alias+"#"+properties[i].name, [], "OBJECT", new JSDOC.DocComment("/**"+properties[i].desc+"*/")); + // TODO: shouldn't the following happen in the addProperty method of Symbol? + if (properties[i].type) property.type = properties[i].type; + if (properties[i].defaultValue) property.defaultValue = properties[i].defaultValue; + this.addProperty(property); + if (!JSDOC.Parser.symbols.getSymbolByName(property.name)) + JSDOC.Parser.addSymbol(property); + } + } + + /*t: + // todo + */ + + // @return + var returns = this.comment.getTag("return"); + if (returns.length) { // there can be many return tags in a single doclet + this.returns = returns; + this.type = returns.map(function($){return $.type}).join(", "); + } + + /*t: + // todo + */ + + // @exception + this.exceptions = this.comment.getTag("throws"); + + /*t: + // todo + */ + + // @requires + var requires = this.comment.getTag("requires"); + if (requires.length) { + this.requires = requires.map(function($){return $.desc}); + } + + /*t: + // todo + */ + + // @type + var types = this.comment.getTag("type"); + if (types.length) { + this.type = types[0].desc; //multiple type tags are ignored + } + + /*t: + // todo + */ + + // @private + if (this.comment.getTag("private").length || this.isInner) { + this.isPrivate = true; + } + + // @ignore + if (this.comment.getTag("ignore").length) { + this.isIgnored = true; + } + + /*t: + // todo + */ + + // @inherits ... as ... + var inherits = this.comment.getTag("inherits"); + if (inherits.length) { + for (var i = 0; i < inherits.length; i++) { + if (/^\s*([a-z$0-9_.#:-]+)(?:\s+as\s+([a-z$0-9_.#:-]+))?/i.test(inherits[i].desc)) { + var inAlias = RegExp.$1; + var inAs = RegExp.$2 || inAlias; + + if (inAlias) inAlias = inAlias.replace(/\.prototype\.?/g, "#"); + + if (inAs) { + inAs = inAs.replace(/\.prototype\.?/g, "#"); + inAs = inAs.replace(/^this\.?/, "#"); + } + + if (inAs.indexOf(inAlias) != 0) { //not a full namepath + var joiner = "."; + if (this.alias.charAt(this.alias.length-1) == "#" || inAs.charAt(0) == "#") { + joiner = ""; + } + inAs = this.alias + joiner + inAs; + } + } + this.inherits.push({alias: inAlias, as: inAs}); + } + } + + /*t: + // todo + */ + + // @augments + this.augments = this.comment.getTag("augments"); + + // @default + var defaults = this.comment.getTag("default"); + if (defaults.length) { + if (this.is("OBJECT")) { + this.defaultValue = defaults[0].desc; + } + } + + /*t: + // todo + */ + + // @memberOf + var memberOfs = this.comment.getTag("memberOf"); + if (memberOfs.length) { + this.memberOf = memberOfs[0].desc; + this.memberOf = this.memberOf.replace(/\.prototype\.?/g, "#"); + } + + /*t: + // todo + */ + + // @public + if (this.comment.getTag("public").length) { + this.isPrivate = false; + } + + /*t: + // todo + */ + + if (JSDOC.PluginManager) { + JSDOC.PluginManager.run("onSetTags", this); + } +} + +JSDOC.Symbol.prototype.is = function(what) { + return this.isa === what; +} + +JSDOC.Symbol.prototype.isBuiltin = function() { + return JSDOC.Lang.isBuiltin(this.alias); +} + +JSDOC.Symbol.prototype.setType = function(/**String*/comment, /**Boolean*/overwrite) { + if (!overwrite && this.type) return; + var typeComment = JSDOC.DocComment.unwrapComment(comment); + this.type = typeComment; +} + +JSDOC.Symbol.prototype.inherit = function(symbol) { + if (!this.hasMember(symbol.name) && !symbol.isInner) { + if (symbol.is("FUNCTION")) + this.methods.push(symbol); + else if (symbol.is("OBJECT")) + this.properties.push(symbol); + } +} + +JSDOC.Symbol.prototype.hasMember = function(name) { + return (this.hasMethod(name) || this.hasProperty(name)); +} + +JSDOC.Symbol.prototype.addMember = function(symbol) { + if (symbol.is("FUNCTION")) { this.addMethod(symbol); } + else if (symbol.is("OBJECT")) { this.addProperty(symbol); } +} + +JSDOC.Symbol.prototype.hasMethod = function(name) { + var thisMethods = this.methods; + for (var i = 0, l = thisMethods.length; i < l; i++) { + if (thisMethods[i].name == name) return true; + if (thisMethods[i].alias == name) return true; + } + return false; +} + +JSDOC.Symbol.prototype.addMethod = function(symbol) { + var methodAlias = symbol.alias; + var thisMethods = this.methods; + for (var i = 0, l = thisMethods.length; i < l; i++) { + if (thisMethods[i].alias == methodAlias) { + thisMethods[i] = symbol; // overwriting previous method + return; + } + } + thisMethods.push(symbol); // new method with this alias +} + +JSDOC.Symbol.prototype.hasProperty = function(name) { + var thisProperties = this.properties; + for (var i = 0, l = thisProperties.length; i < l; i++) { + if (thisProperties[i].name == name) return true; + if (thisProperties[i].alias == name) return true; + } + return false; +} + +JSDOC.Symbol.prototype.addProperty = function(symbol) { + var propertyAlias = symbol.alias; + var thisProperties = this.properties; + for (var i = 0, l = thisProperties.length; i < l; i++) { + if (thisProperties[i].alias == propertyAlias) { + thisProperties[i] = symbol; // overwriting previous property + return; + } + } + + thisProperties.push(symbol); // new property with this alias +} + +JSDOC.Symbol.srcFile = ""; //running reference to the current file being parsed diff --git a/bin/jsdoc/lib/JSDOC/SymbolSet.js b/bin/jsdoc/lib/JSDOC/SymbolSet.js new file mode 100644 index 00000000..8e3a2ebf --- /dev/null +++ b/bin/jsdoc/lib/JSDOC/SymbolSet.js @@ -0,0 +1,243 @@ +/** @constructor */ +JSDOC.SymbolSet = function() { + this.init(); +} + +JSDOC.SymbolSet.prototype.init = function() { + this._index = new Hash(); +} + +JSDOC.SymbolSet.prototype.keys = function() { + return this._index.keys(); +} + +JSDOC.SymbolSet.prototype.hasSymbol = function(alias) { + return this._index.hasKey(alias); +} + +JSDOC.SymbolSet.prototype.addSymbol = function(symbol) { + if (JSDOC.opt.a && this.hasSymbol(symbol.alias)) { + LOG.warn("Overwriting symbol documentation for: " + symbol.alias + "."); + this.deleteSymbol(symbol.alias); + } + this._index.set(symbol.alias, symbol); +} + +JSDOC.SymbolSet.prototype.getSymbol = function(alias) { + if (this.hasSymbol(alias)) return this._index.get(alias); +} + +JSDOC.SymbolSet.prototype.getSymbolByName = function(name) { + for (var p = this._index.first(); p; p = this._index.next()) { + var symbol = p.value; + if (symbol.name == name) return symbol; + } +} + +JSDOC.SymbolSet.prototype.toArray = function() { + return this._index.values(); +} + +JSDOC.SymbolSet.prototype.deleteSymbol = function(alias) { + if (!this.hasSymbol(alias)) return; + this._index.drop(alias); +} + +JSDOC.SymbolSet.prototype.renameSymbol = function(oldName, newName) { + // todo: should check if oldname or newname already exist + this._index.replace(oldName, newName); + this._index.get(newName).alias = newName; + return newName; +} + +JSDOC.SymbolSet.prototype.relate = function() { + this.resolveBorrows(); + this.resolveMemberOf(); + this.resolveAugments(); +} + +JSDOC.SymbolSet.prototype.resolveBorrows = function() { + for (var p = this._index.first(); p; p = this._index.next()) { + var symbol = p.value; + if (symbol.is("FILE") || symbol.is("GLOBAL")) continue; + + var borrows = symbol.inherits; + for (var i = 0; i < borrows.length; i++) { + +if (/#$/.test(borrows[i].alias)) { + LOG.warn("Attempted to borrow entire instance of "+borrows[i].alias+" but that feature is not yet implemented."); + return; +} + var borrowed = this.getSymbol(borrows[i].alias); + + if (!borrowed) { + LOG.warn("Can't borrow undocumented "+borrows[i].alias+"."); + continue; + } + + if (borrows[i].as == borrowed.alias) { + var assumedName = borrowed.name.split(/([#.-])/).pop(); + borrows[i].as = symbol.name+RegExp.$1+assumedName; + LOG.inform("Assuming borrowed as name is "+borrows[i].as+" but that feature is experimental."); + } + + var borrowAsName = borrows[i].as; + var borrowAsAlias = borrowAsName; + if (!borrowAsName) { + LOG.warn("Malformed @borrow, 'as' is required."); + continue; + } + + if (borrowAsName.length > symbol.alias.length && borrowAsName.indexOf(symbol.alias) == 0) { + borrowAsName = borrowAsName.replace(borrowed.alias, "") + } + else { + var joiner = ""; + if (borrowAsName.charAt(0) != "#") joiner = "."; + borrowAsAlias = borrowed.alias + joiner + borrowAsName; + } + + borrowAsName = borrowAsName.replace(/^[#.]/, ""); + + if (this.hasSymbol(borrowAsAlias)) continue; + + var clone = borrowed.clone(); + clone.name = borrowAsName; + clone.alias = borrowAsAlias; + this.addSymbol(clone); + } + } +} + +JSDOC.SymbolSet.prototype.resolveMemberOf = function() { + for (var p = this._index.first(); p; p = this._index.next()) { + var symbol = p.value; + + if (symbol.is("FILE") || symbol.is("GLOBAL")) continue; + + // the memberOf value was provided in the @memberOf tag + else if (symbol.memberOf) { + // like foo.bar is a memberOf foo + if (symbol.alias.indexOf(symbol.memberOf) == 0) { + var memberMatch = new RegExp("^("+symbol.memberOf+")[.#-]?(.+)$"); + var aliasParts = symbol.alias.match(memberMatch); + + if (aliasParts) { + symbol.memberOf = aliasParts[1]; + symbol.name = aliasParts[2]; + } + + var nameParts = symbol.name.match(memberMatch); + + if (nameParts) { + symbol.name = nameParts[2]; + } + } + // like bar is a memberOf foo + else { + var joiner = symbol.memberOf.charAt(symbol.memberOf.length-1); + if (!/[.#-]/.test(joiner)) symbol.memberOf += "."; + this.renameSymbol(symbol.alias, symbol.memberOf + symbol.name); + } + } + // the memberOf must be calculated + else { + var parts = symbol.alias.match(/^(.*[.#-])([^.#-]+)$/); + + if (parts) { + symbol.memberOf = parts[1]; + symbol.name = parts[2]; + } + } + + // set isStatic, isInner + if (symbol.memberOf) { + switch (symbol.memberOf.charAt(symbol.memberOf.length-1)) { + case '#' : + symbol.isStatic = false; + symbol.isInner = false; + break; + case '.' : + symbol.isStatic = true; + symbol.isInner = false; + break; + case '-' : + symbol.isStatic = false; + symbol.isInner = true; + break; + default: // memberOf ends in none of the above + symbol.isStatic = true; + break; + } + } + + // unowned methods and fields belong to the global object + if (!symbol.is("CONSTRUCTOR") && !symbol.isNamespace && symbol.memberOf == "") { + symbol.memberOf = "_global_"; + } + + // clean up + if (symbol.memberOf.match(/[.#-]$/)) { + symbol.memberOf = symbol.memberOf.substr(0, symbol.memberOf.length-1); + } + // add to parent's methods or properties list + if (symbol.memberOf) { + + var container = this.getSymbol(symbol.memberOf); + if (!container) { + if (JSDOC.Lang.isBuiltin(symbol.memberOf)) container = JSDOC.Parser.addBuiltin(symbol.memberOf); + else { + LOG.warn("Trying to document "+symbol.name +" as a member of undocumented symbol "+symbol.memberOf+"."); + } + } + + if (container) container.addMember(symbol); + } + } +} + +JSDOC.SymbolSet.prototype.resolveAugments = function() { + for (var p = this._index.first(); p; p = this._index.next()) { + var symbol = p.value; + + if (symbol.alias == "_global_" || symbol.is("FILE")) continue; + JSDOC.SymbolSet.prototype.walk.apply(this, [symbol]); + } +} + +JSDOC.SymbolSet.prototype.walk = function(symbol) { + var augments = symbol.augments; + for(var i = 0; i < augments.length; i++) { + var contributer = this.getSymbol(augments[i]); + if (!contributer && JSDOC.Lang.isBuiltin(''+augments[i])) { + contributer = new JSDOC.Symbol("_global_."+augments[i], [], augments[i], new JSDOC.DocComment("Built in.")); + contributer.isNamespace = true; + contributer.srcFile = ""; + contributer.isPrivate = false; + JSDOC.Parser.addSymbol(contributer); + } + + if (contributer) { + if (contributer.augments.length) { + JSDOC.SymbolSet.prototype.walk.apply(this, [contributer]); + } + + symbol.inheritsFrom.push(contributer.alias); + //if (!isUnique(symbol.inheritsFrom)) { + // LOG.warn("Can't resolve augments: Circular reference: "+symbol.alias+" inherits from "+contributer.alias+" more than once."); + //} + //else { + var cmethods = contributer.methods; + var cproperties = contributer.properties; + + for (var ci = 0, cl = cmethods.length; ci < cl; ci++) { + if (!cmethods[ci].isStatic) symbol.inherit(cmethods[ci]); + } + for (var ci = 0, cl = cproperties.length; ci < cl; ci++) { + if (!cproperties[ci].isStatic) symbol.inherit(cproperties[ci]); + } + //} + } + else LOG.warn("Can't augment contributer: "+augments[i]+", not found."); + } +} diff --git a/bin/jsdoc/lib/JSDOC/TextStream.js b/bin/jsdoc/lib/JSDOC/TextStream.js new file mode 100644 index 00000000..ccc48a87 --- /dev/null +++ b/bin/jsdoc/lib/JSDOC/TextStream.js @@ -0,0 +1,41 @@ + +/** + @constructor +*/ +JSDOC.TextStream = function(text) { + if (typeof(text) == "undefined") text = ""; + text = ""+text; + this.text = text; + this.cursor = 0; +} + +JSDOC.TextStream.prototype.look = function(n) { + if (typeof n == "undefined") n = 0; + + if (this.cursor+n < 0 || this.cursor+n >= this.text.length) { + var result = new String(""); + result.eof = true; + return result; + } + return this.text.charAt(this.cursor+n); +} + +JSDOC.TextStream.prototype.next = function(n) { + if (typeof n == "undefined") n = 1; + if (n < 1) return null; + + var pulled = ""; + for (var i = 0; i < n; i++) { + if (this.cursor+i < this.text.length) { + pulled += this.text.charAt(this.cursor+i); + } + else { + var result = new String(""); + result.eof = true; + return result; + } + } + + this.cursor += n; + return pulled; +} \ No newline at end of file diff --git a/bin/jsdoc/lib/JSDOC/Token.js b/bin/jsdoc/lib/JSDOC/Token.js new file mode 100644 index 00000000..fb7f9d94 --- /dev/null +++ b/bin/jsdoc/lib/JSDOC/Token.js @@ -0,0 +1,18 @@ +if (typeof JSDOC == "undefined") JSDOC = {}; + +/** + @constructor +*/ +JSDOC.Token = function(data, type, name) { + this.data = data; + this.type = type; + this.name = name; +} + +JSDOC.Token.prototype.toString = function() { + return "<"+this.type+" name=\""+this.name+"\">"+this.data+""; +} + +JSDOC.Token.prototype.is = function(what) { + return this.name === what || this.type === what; +} \ No newline at end of file diff --git a/bin/jsdoc/lib/JSDOC/TokenReader.js b/bin/jsdoc/lib/JSDOC/TokenReader.js new file mode 100644 index 00000000..9f658fb9 --- /dev/null +++ b/bin/jsdoc/lib/JSDOC/TokenReader.js @@ -0,0 +1,332 @@ +if (typeof JSDOC == "undefined") JSDOC = {}; + +/** + @class Search a {@link JSDOC.TextStream} for language tokens. +*/ +JSDOC.TokenReader = function() { + this.keepDocs = true; + this.keepWhite = false; + this.keepComments = false; +} + +/** + @type {JSDOC.Token[]} + */ +JSDOC.TokenReader.prototype.tokenize = function(/**JSDOC.TextStream*/stream) { + var tokens = []; + /**@ignore*/ tokens.last = function() { return tokens[tokens.length-1]; } + /**@ignore*/ tokens.lastSym = function() { + for (var i = tokens.length-1; i >= 0; i--) { + if (!(tokens[i].is("WHIT") || tokens[i].is("COMM"))) return tokens[i]; + } + } + + while (!stream.look().eof) { + if (this.read_mlcomment(stream, tokens)) continue; + if (this.read_slcomment(stream, tokens)) continue; + if (this.read_dbquote(stream, tokens)) continue; + if (this.read_snquote(stream, tokens)) continue; + if (this.read_regx(stream, tokens)) continue; + if (this.read_numb(stream, tokens)) continue; + if (this.read_punc(stream, tokens)) continue; + if (this.read_newline(stream, tokens)) continue; + if (this.read_space(stream, tokens)) continue; + if (this.read_word(stream, tokens)) continue; + + // if execution reaches here then an error has happened + tokens.push(new JSDOC.Token(stream.next(), "TOKN", "UNKNOWN_TOKEN")); + } + return tokens; +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_word = function(/**JSDOC.TokenStream*/stream, tokens) { + var found = ""; + while (!stream.look().eof && JSDOC.Lang.isWordChar(stream.look())) { + found += stream.next(); + } + + if (found === "") { + return false; + } + else { + var name; + if ((name = JSDOC.Lang.keyword(found))) tokens.push(new JSDOC.Token(found, "KEYW", name)); + else tokens.push(new JSDOC.Token(found, "NAME", "NAME")); + return true; + } +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_punc = function(/**JSDOC.TokenStream*/stream, tokens) { + var found = ""; + var name; + while (!stream.look().eof && JSDOC.Lang.punc(found+stream.look())) { + found += stream.next(); + } + + if (found === "") { + return false; + } + else { + tokens.push(new JSDOC.Token(found, "PUNC", JSDOC.Lang.punc(found))); + return true; + } +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_space = function(/**JSDOC.TokenStream*/stream, tokens) { + var found = ""; + + while (!stream.look().eof && JSDOC.Lang.isSpace(stream.look())) { + found += stream.next(); + } + + if (found === "") { + return false; + } + else { + if (this.collapseWhite) found = " "; + if (this.keepWhite) tokens.push(new JSDOC.Token(found, "WHIT", "SPACE")); + return true; + } +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_newline = function(/**JSDOC.TokenStream*/stream, tokens) { + var found = ""; + + while (!stream.look().eof && JSDOC.Lang.isNewline(stream.look())) { + found += stream.next(); + } + + if (found === "") { + return false; + } + else { + if (this.collapseWhite) found = "\n"; + if (this.keepWhite) tokens.push(new JSDOC.Token(found, "WHIT", "NEWLINE")); + return true; + } +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_mlcomment = function(/**JSDOC.TokenStream*/stream, tokens) { + if (stream.look() == "/" && stream.look(1) == "*") { + var found = stream.next(2); + + while (!stream.look().eof && !(stream.look(-1) == "/" && stream.look(-2) == "*")) { + found += stream.next(); + } + + // to start doclet we allow /** or /*** but not /**/ or /**** + if (/^\/\*\*([^\/]|\*[^*])/.test(found) && this.keepDocs) tokens.push(new JSDOC.Token(found, "COMM", "JSDOC")); + else if (this.keepComments) tokens.push(new JSDOC.Token(found, "COMM", "MULTI_LINE_COMM")); + return true; + } + return false; +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_slcomment = function(/**JSDOC.TokenStream*/stream, tokens) { + var found; + if ( + (stream.look() == "/" && stream.look(1) == "/" && (found=stream.next(2))) + || + (stream.look() == "<" && stream.look(1) == "!" && stream.look(2) == "-" && stream.look(3) == "-" && (found=stream.next(4))) + ) { + + while (!stream.look().eof && !JSDOC.Lang.isNewline(stream.look())) { + found += stream.next(); + } + + if (this.keepComments) { + tokens.push(new JSDOC.Token(found, "COMM", "SINGLE_LINE_COMM")); + } + return true; + } + return false; +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_dbquote = function(/**JSDOC.TokenStream*/stream, tokens) { + if (stream.look() == "\"") { + // find terminator + var string = stream.next(); + + while (!stream.look().eof) { + if (stream.look() == "\\") { + if (JSDOC.Lang.isNewline(stream.look(1))) { + do { + stream.next(); + } while (!stream.look().eof && JSDOC.Lang.isNewline(stream.look())); + string += "\\\n"; + } + else { + string += stream.next(2); + } + } + else if (stream.look() == "\"") { + string += stream.next(); + tokens.push(new JSDOC.Token(string, "STRN", "DOUBLE_QUOTE")); + return true; + } + else { + string += stream.next(); + } + } + } + return false; // error! unterminated string +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_snquote = function(/**JSDOC.TokenStream*/stream, tokens) { + if (stream.look() == "'") { + // find terminator + var string = stream.next(); + + while (!stream.look().eof) { + if (stream.look() == "\\") { // escape sequence + string += stream.next(2); + } + else if (stream.look() == "'") { + string += stream.next(); + tokens.push(new JSDOC.Token(string, "STRN", "SINGLE_QUOTE")); + return true; + } + else { + string += stream.next(); + } + } + } + return false; // error! unterminated string +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_numb = function(/**JSDOC.TokenStream*/stream, tokens) { + if (stream.look() === "0" && stream.look(1) == "x") { + return this.read_hex(stream, tokens); + } + + var found = ""; + + while (!stream.look().eof && JSDOC.Lang.isNumber(found+stream.look())){ + found += stream.next(); + } + + if (found === "") { + return false; + } + else { + if (/^0[0-7]/.test(found)) tokens.push(new JSDOC.Token(found, "NUMB", "OCTAL")); + else tokens.push(new JSDOC.Token(found, "NUMB", "DECIMAL")); + return true; + } +} +/*t: + requires("../lib/JSDOC/TextStream.js"); + requires("../lib/JSDOC/Token.js"); + requires("../lib/JSDOC/Lang.js"); + + plan(3, "testing JSDOC.TokenReader.prototype.read_numb"); + + //// setup + var src = "function foo(num){while (num+8.0 >= 0x20 && num < 0777){}}"; + var tr = new JSDOC.TokenReader(); + var tokens = tr.tokenize(new JSDOC.TextStream(src)); + + var hexToken, octToken, decToken; + for (var i = 0; i < tokens.length; i++) { + if (tokens[i].name == "HEX_DEC") hexToken = tokens[i]; + if (tokens[i].name == "OCTAL") octToken = tokens[i]; + if (tokens[i].name == "DECIMAL") decToken = tokens[i]; + } + //// + + is(decToken.data, "8.0", "decimal number is found in source."); + is(hexToken.data, "0x20", "hexdec number is found in source (issue #99)."); + is(octToken.data, "0777", "octal number is found in source."); +*/ + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_hex = function(/**JSDOC.TokenStream*/stream, tokens) { + var found = stream.next(2); + + while (!stream.look().eof) { + if (JSDOC.Lang.isHexDec(found) && !JSDOC.Lang.isHexDec(found+stream.look())) { // done + tokens.push(new JSDOC.Token(found, "NUMB", "HEX_DEC")); + return true; + } + else { + found += stream.next(); + } + } + return false; +} + +/** + @returns {Boolean} Was the token found? + */ +JSDOC.TokenReader.prototype.read_regx = function(/**JSDOC.TokenStream*/stream, tokens) { + var last; + if ( + stream.look() == "/" + && + ( + + ( + !(last = tokens.lastSym()) // there is no last, the regex is the first symbol + || + ( + !last.is("NUMB") + && !last.is("NAME") + && !last.is("RIGHT_PAREN") + && !last.is("RIGHT_BRACKET") + ) + ) + ) + ) { + var regex = stream.next(); + + while (!stream.look().eof) { + if (stream.look() == "\\") { // escape sequence + regex += stream.next(2); + } + else if (stream.look() == "/") { + regex += stream.next(); + + while (/[gmi]/.test(stream.look())) { + regex += stream.next(); + } + + tokens.push(new JSDOC.Token(regex, "REGX", "REGX")); + return true; + } + else { + regex += stream.next(); + } + } + // error: unterminated regex + } + return false; +} diff --git a/bin/jsdoc/lib/JSDOC/TokenStream.js b/bin/jsdoc/lib/JSDOC/TokenStream.js new file mode 100644 index 00000000..1eeb44cb --- /dev/null +++ b/bin/jsdoc/lib/JSDOC/TokenStream.js @@ -0,0 +1,133 @@ +if (typeof JSDOC == "undefined") JSDOC = {}; + +/** + @constructor +*/ +JSDOC.TokenStream = function(tokens) { + this.tokens = (tokens || []); + this.rewind(); +} + +/** + @constructor + @private +*/ +function VoidToken(/**String*/type) { + this.toString = function() {return ""}; + this.is = function(){return false;} +} + +JSDOC.TokenStream.prototype.rewind = function() { + this.cursor = -1; +} + +/** + @type JSDOC.Token +*/ +JSDOC.TokenStream.prototype.look = function(/**Number*/n, /**Boolean*/considerWhitespace) { + if (typeof n == "undefined") n = 0; + + if (considerWhitespace == true) { + if (this.cursor+n < 0 || this.cursor+n > this.tokens.length) return {}; + return this.tokens[this.cursor+n]; + } + else { + var count = 0; + var i = this.cursor; + + while (true) { + if (i < 0) return new JSDOC.Token("", "VOID", "START_OF_STREAM"); + else if (i > this.tokens.length) return new JSDOC.Token("", "VOID", "END_OF_STREAM"); + + if (i != this.cursor && (this.tokens[i] === undefined || this.tokens[i].is("WHIT"))) { + if (n < 0) i--; else i++; + continue; + } + + if (count == Math.abs(n)) { + return this.tokens[i]; + } + count++; + (n < 0)? i-- : i++; + } + + return new JSDOC.Token("", "VOID", "STREAM_ERROR"); // because null isn't an object and caller always expects an object + } +} + +/** + @type JSDOC.Token|JSDOC.Token[] +*/ +JSDOC.TokenStream.prototype.next = function(/**Number*/howMany) { + if (typeof howMany == "undefined") howMany = 1; + if (howMany < 1) return null; + var got = []; + + for (var i = 1; i <= howMany; i++) { + if (this.cursor+i >= this.tokens.length) { + return null; + } + got.push(this.tokens[this.cursor+i]); + } + this.cursor += howMany; + + if (howMany == 1) { + return got[0]; + } + else return got; +} + +/** + @type JSDOC.Token[] +*/ +JSDOC.TokenStream.prototype.balance = function(/**String*/start, /**String*/stop) { + if (!stop) stop = JSDOC.Lang.matching(start); + + var depth = 0; + var got = []; + var started = false; + + while ((token = this.look())) { + if (token.is(start)) { + depth++; + started = true; + } + + if (started) { + got.push(token); + } + + if (token.is(stop)) { + depth--; + if (depth == 0) return got; + } + if (!this.next()) break; + } +} + +JSDOC.TokenStream.prototype.getMatchingToken = function(/**String*/start, /**String*/stop) { + var depth = 0; + var cursor = this.cursor; + + if (!start) { + start = JSDOC.Lang.matching(stop); + depth = 1; + } + if (!stop) stop = JSDOC.Lang.matching(start); + + while ((token = this.tokens[cursor])) { + if (token.is(start)) { + depth++; + } + + if (token.is(stop) && cursor) { + depth--; + if (depth == 0) return this.tokens[cursor]; + } + cursor++; + } +} + +JSDOC.TokenStream.prototype.insertAhead = function(/**JSDOC.Token*/token) { + this.tokens.splice(this.cursor+1, 0, token); +} \ No newline at end of file diff --git a/bin/jsdoc/lib/JSDOC/Util.js b/bin/jsdoc/lib/JSDOC/Util.js new file mode 100644 index 00000000..6d7edb36 --- /dev/null +++ b/bin/jsdoc/lib/JSDOC/Util.js @@ -0,0 +1,32 @@ +/** + * @namespace + * @deprecated Use {@link FilePath} instead. + */ +JSDOC.Util = { +} + +/** + * @deprecated Use {@link FilePath.fileName} instead. + */ +JSDOC.Util.fileName = function(path) { + LOG.warn("JSDOC.Util.fileName is deprecated. Use FilePath.fileName instead."); + var nameStart = Math.max(path.lastIndexOf("/")+1, path.lastIndexOf("\\")+1, 0); + return path.substring(nameStart); +} + +/** + * @deprecated Use {@link FilePath.fileExtension} instead. + */ +JSDOC.Util.fileExtension = function(filename) { + LOG.warn("JSDOC.Util.fileExtension is deprecated. Use FilePath.fileExtension instead."); + return filename.split(".").pop().toLowerCase(); +}; + +/** + * @deprecated Use {@link FilePath.dir} instead. + */ +JSDOC.Util.dir = function(path) { + LOG.warn("JSDOC.Util.dir is deprecated. Use FilePath.dir instead."); + var nameStart = Math.max(path.lastIndexOf("/")+1, path.lastIndexOf("\\")+1, 0); + return path.substring(0, nameStart-1); +} diff --git a/bin/jsdoc/lib/JSDOC/Walker.js b/bin/jsdoc/lib/JSDOC/Walker.js new file mode 100644 index 00000000..6ecaea88 --- /dev/null +++ b/bin/jsdoc/lib/JSDOC/Walker.js @@ -0,0 +1,507 @@ +if (typeof JSDOC == "undefined") JSDOC = {}; + +/** @constructor */ +JSDOC.Walker = function(/**JSDOC.TokenStream*/ts) { + this.init(); + if (typeof ts != "undefined") { + this.walk(ts); + } +} + +JSDOC.Walker.prototype.init = function() { + this.ts = null; + + var globalSymbol = new JSDOC.Symbol("_global_", [], "GLOBAL", new JSDOC.DocComment("")); + globalSymbol.isNamespace = true; + globalSymbol.srcFile = ""; + globalSymbol.isPrivate = false; + JSDOC.Parser.addSymbol(globalSymbol); + this.lastDoc = null; + this.token = null; + + /** + The chain of symbols under which we are currently nested. + @type Array + */ + this.namescope = [globalSymbol]; + this.namescope.last = function(n){ if (!n) n = 0; return this[this.length-(1+n)] || "" }; +} + +JSDOC.Walker.prototype.walk = function(/**JSDOC.TokenStream*/ts) { + this.ts = ts; + while (this.token = this.ts.look()) { + if (this.token.popNamescope) { + + var symbol = this.namescope.pop(); + if (symbol.is("FUNCTION")) { + if (this.ts.look(1).is("LEFT_PAREN") && symbol.comment.getTag("function").length == 0) { + symbol.isa = "OBJECT"; + } + } + } + this.step(); + if (!this.ts.next()) break; + } +} + +JSDOC.Walker.prototype.step = function() { + if (this.token.is("JSDOC")) { // it's a doc comment + + var doc = new JSDOC.DocComment(this.token.data); + + + if (doc.getTag("exports").length > 0) { + var exports = doc.getTag("exports")[0]; + + exports.desc.match(/(\S+) as (\S+)/i); + var n1 = RegExp.$1; + var n2 = RegExp.$2; + + if (!n1 && n2) throw "@exports tag requires a value like: 'name as ns.name'"; + + JSDOC.Parser.rename = (JSDOC.Parser.rename || {}); + JSDOC.Parser.rename[n1] = n2 + } + + if (doc.getTag("lends").length > 0) { + var lends = doc.getTag("lends")[0]; + + var name = lends.desc + if (!name) throw "@lends tag requires a value."; + + var symbol = new JSDOC.Symbol(name, [], "OBJECT", doc); + + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken("LEFT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + + this.lastDoc = null; + return true; + } + else if (doc.getTag("name").length > 0 && doc.getTag("overview").length == 0) { // it's a virtual symbol + var virtualName = doc.getTag("name")[0].desc; + if (!virtualName) throw "@name tag requires a value."; + + if (doc.getTag("memberOf").length > 0) { + virtualName = (doc.getTag("memberOf")[0] + "." + virtualName) + .replace(/([#.])\./, "$1"); + doc.deleteTag("memberOf"); + } + + var symbol = new JSDOC.Symbol(virtualName, [], "VIRTUAL", doc); + + JSDOC.Parser.addSymbol(symbol); + + this.lastDoc = null; + return true; + } + else if (doc.meta) { // it's a meta doclet + if (doc.meta == "@+") JSDOC.DocComment.shared = doc.src; + else if (doc.meta == "@-") JSDOC.DocComment.shared = ""; + else if (doc.meta == "nocode+") JSDOC.Parser.conf.ignoreCode = true; + else if (doc.meta == "nocode-") JSDOC.Parser.conf.ignoreCode = JSDOC.opt.n; + else throw "Unrecognized meta comment: "+doc.meta; + + this.lastDoc = null; + return true; + } + else if (doc.getTag("overview").length > 0) { // it's a file overview + symbol = new JSDOC.Symbol("", [], "FILE", doc); + + JSDOC.Parser.addSymbol(symbol); + + this.lastDoc = null; + return true; + } + else { + this.lastDoc = doc; + return false; + } + } + else if (!JSDOC.Parser.conf.ignoreCode) { // it's code + if (this.token.is("NAME")) { // it's the name of something + var symbol; + var name = this.token.data; + var doc = null; if (this.lastDoc) doc = this.lastDoc; + var params = []; + + // it's inside an anonymous object + if (this.ts.look(1).is("COLON") && this.ts.look(-1).is("LEFT_CURLY") && !(this.ts.look(-2).is("JSDOC") || this.namescope.last().comment.getTag("lends").length || this.ts.look(-2).is("ASSIGN") || this.ts.look(-2).is("COLON"))) { + name = "$anonymous"; + name = this.namescope.last().alias+"-"+name + + params = []; + + symbol = new JSDOC.Symbol(name, params, "OBJECT", doc); + + JSDOC.Parser.addSymbol(symbol); + + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken(null, "RIGHT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + } + // function foo() {} + else if (this.ts.look(-1).is("FUNCTION") && this.ts.look(1).is("LEFT_PAREN")) { + var isInner; + + if (this.lastDoc) doc = this.lastDoc; + + if (doc && doc.getTag("memberOf").length > 0) { + name = (doc.getTag("memberOf")[0]+"."+name).replace("#.", "#"); + doc.deleteTag("memberOf"); + } + else { + name = this.namescope.last().alias+"-"+name; + if (!this.namescope.last().is("GLOBAL")) isInner = true; + } + + if (!this.namescope.last().is("GLOBAL")) isInner = true; + + params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN")); + + symbol = new JSDOC.Symbol(name, params, "FUNCTION", doc); + if (isInner) symbol.isInner = true; + + if (this.ts.look(1).is("JSDOC")) { + var inlineReturn = ""+this.ts.look(1).data; + inlineReturn = inlineReturn.replace(/(^\/\*\* *| *\*\/$)/g, ""); + symbol.type = inlineReturn; + } + + JSDOC.Parser.addSymbol(symbol); + + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken("LEFT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + } + // foo = function() {} + else if (this.ts.look(1).is("ASSIGN") && this.ts.look(2).is("FUNCTION")) { + var constructs; + var isConstructor = false; + if (doc && (constructs = doc.getTag("constructs")) && constructs.length) { + if (constructs[0].desc) { + name = constructs[0].desc; + isConstructor = true; + } + } + + var isInner; + if (this.ts.look(-1).is("VAR") || this.isInner) { + if (doc && doc.getTag("memberOf").length > 0) { + name = (doc.getTag("memberOf")[0]+"."+name).replace("#.", "#"); + doc.deleteTag("memberOf"); + } + else { + name = this.namescope.last().alias+"-"+name; + if (!this.namescope.last().is("GLOBAL")) isInner = true; + } + if (!this.namescope.last().is("GLOBAL")) isInner = true; + } + else if (name.indexOf("this.") == 0) { + name = this.resolveThis(name); + } + + if (this.lastDoc) doc = this.lastDoc; + params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN")); + + symbol = new JSDOC.Symbol(name, params, "FUNCTION", doc); + + if (isInner) symbol.isInner = true; + if (isConstructor) symbol.isa = "CONSTRUCTOR"; + + if (this.ts.look(1).is("JSDOC")) { + var inlineReturn = ""+this.ts.look(1).data; + inlineReturn = inlineReturn.replace(/(^\/\*\* *| *\*\/$)/g, ""); + symbol.type = inlineReturn; + } + + JSDOC.Parser.addSymbol(symbol); + + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken("LEFT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + } + // foo = new function() {} or foo = (function() {} + else if (this.ts.look(1).is("ASSIGN") && (this.ts.look(2).is("NEW") || this.ts.look(2).is("LEFT_PAREN")) && this.ts.look(3).is("FUNCTION")) { + var isInner; + if (this.ts.look(-1).is("VAR") || this.isInner) { + name = this.namescope.last().alias+"-"+name + if (!this.namescope.last().is("GLOBAL")) isInner = true; + } + else if (name.indexOf("this.") == 0) { + name = this.resolveThis(name); + } + + this.ts.next(3); // advance past the "new" or "(" + + if (this.lastDoc) doc = this.lastDoc; + params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN")); + + symbol = new JSDOC.Symbol(name, params, "OBJECT", doc); + if (isInner) symbol.isInner = true; + + if (this.ts.look(1).is("JSDOC")) { + var inlineReturn = ""+this.ts.look(1).data; + inlineReturn = inlineReturn.replace(/(^\/\*\* *| *\*\/$)/g, ""); + symbol.type = inlineReturn; + } + + JSDOC.Parser.addSymbol(symbol); + + symbol.scopeType = "INSTANCE"; + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken("LEFT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + } + // foo: function() {} + else if (this.ts.look(1).is("COLON") && this.ts.look(2).is("FUNCTION")) { + name = (this.namescope.last().alias+"."+name).replace("#.", "#"); + + if (this.lastDoc) doc = this.lastDoc; + params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN")); + + if (doc && doc.getTag("constructs").length) { + name = name.replace(/\.prototype(\.|$)/, "#"); + + if (name.indexOf("#") > -1) name = name.match(/(^[^#]+)/)[0]; + else name = this.namescope.last().alias; + + symbol = new JSDOC.Symbol(name, params, "CONSTRUCTOR", doc); + } + else { + symbol = new JSDOC.Symbol(name, params, "FUNCTION", doc); + } + + if (this.ts.look(1).is("JSDOC")) { + var inlineReturn = ""+this.ts.look(1).data; + inlineReturn = inlineReturn.replace(/(^\/\*\* *| *\*\/$)/g, ""); + symbol.type = inlineReturn; + } + + JSDOC.Parser.addSymbol(symbol); + + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken("LEFT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + } + // foo = {} + else if (this.ts.look(1).is("ASSIGN") && this.ts.look(2).is("LEFT_CURLY")) { + var isInner; + if (this.ts.look(-1).is("VAR") || this.isInner) { + name = this.namescope.last().alias+"-"+name + if (!this.namescope.last().is("GLOBAL")) isInner = true; + } + else if (name.indexOf("this.") == 0) { + name = this.resolveThis(name); + } + + if (this.lastDoc) doc = this.lastDoc; + + symbol = new JSDOC.Symbol(name, params, "OBJECT", doc); + if (isInner) symbol.isInner = true; + + + if (doc) JSDOC.Parser.addSymbol(symbol); + + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken("LEFT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + } + // var foo; + else if (this.ts.look(1).is("SEMICOLON")) { + var isInner; + + if (this.ts.look(-1).is("VAR") || this.isInner) { + name = this.namescope.last().alias+"-"+name + if (!this.namescope.last().is("GLOBAL")) isInner = true; + + if (this.lastDoc) doc = this.lastDoc; + + symbol = new JSDOC.Symbol(name, params, "OBJECT", doc); + if (isInner) symbol.isInner = true; + + + if (doc) JSDOC.Parser.addSymbol(symbol); + } + } + // foo = x + else if (this.ts.look(1).is("ASSIGN")) { + var isInner; + if (this.ts.look(-1).is("VAR") || this.isInner) { + name = this.namescope.last().alias+"-"+name + if (!this.namescope.last().is("GLOBAL")) isInner = true; + } + else if (name.indexOf("this.") == 0) { + name = this.resolveThis(name); + } + + if (this.lastDoc) doc = this.lastDoc; + + symbol = new JSDOC.Symbol(name, params, "OBJECT", doc); + if (isInner) symbol.isInner = true; + + + if (doc) JSDOC.Parser.addSymbol(symbol); + } + // foo: {} + else if (this.ts.look(1).is("COLON") && this.ts.look(2).is("LEFT_CURLY")) { + name = (this.namescope.last().alias+"."+name).replace("#.", "#"); + + if (this.lastDoc) doc = this.lastDoc; + + symbol = new JSDOC.Symbol(name, params, "OBJECT", doc); + + + if (doc) JSDOC.Parser.addSymbol(symbol); + + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken("LEFT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + } + // foo: x + else if (this.ts.look(1).is("COLON")) { + name = (this.namescope.last().alias+"."+name).replace("#.", "#");; + + if (this.lastDoc) doc = this.lastDoc; + + symbol = new JSDOC.Symbol(name, params, "OBJECT", doc); + + + if (doc) JSDOC.Parser.addSymbol(symbol); + } + // foo(...) + else if (this.ts.look(1).is("LEFT_PAREN")) { + if (typeof JSDOC.PluginManager != "undefined") { + var functionCall = {name: name}; + + var cursor = this.ts.cursor; + params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN")); + this.ts.cursor = cursor; + + for (var i = 0; i < params.length; i++) + functionCall["arg" + (i + 1)] = params[i].name; + + JSDOC.PluginManager.run("onFunctionCall", functionCall); + if (functionCall.doc) { + this.ts.insertAhead(new JSDOC.Token(functionCall.doc, "COMM", "JSDOC")); + } + } + } + this.lastDoc = null; + } + else if (this.token.is("FUNCTION")) { // it's an anonymous function + if ( + (!this.ts.look(-1).is("COLON") || !this.ts.look(-1).is("ASSIGN")) + && !this.ts.look(1).is("NAME") + ) { + if (this.lastDoc) doc = this.lastDoc; + + name = "$anonymous"; + name = this.namescope.last().alias+"-"+name + + params = JSDOC.Walker.onParamList(this.ts.balance("LEFT_PAREN")); + + symbol = new JSDOC.Symbol(name, params, "FUNCTION", doc); + + JSDOC.Parser.addSymbol(symbol); + + this.namescope.push(symbol); + + var matching = this.ts.getMatchingToken("LEFT_CURLY"); + if (matching) matching.popNamescope = name; + else LOG.warn("Mismatched } character. Can't parse code in file " + symbol.srcFile + "."); + } + } + } + return true; +} + +/** + Resolves what "this." means when it appears in a name. + @param name The name that starts with "this.". + @returns The name with "this." resolved. + */ +JSDOC.Walker.prototype.resolveThis = function(name) { + name.match(/^this\.(.+)$/) + var nameFragment = RegExp.$1; + if (!nameFragment) return name; + + var symbol = this.namescope.last(); + var scopeType = symbol.scopeType || symbol.isa; + + // if we are in a constructor function, `this` means the instance + if (scopeType == "CONSTRUCTOR") { + name = symbol.alias+"#"+nameFragment; + } + + // if we are in an anonymous constructor function, `this` means the instance + else if (scopeType == "INSTANCE") { + name = symbol.alias+"."+nameFragment; + } + + // if we are in a function, `this` means the container (possibly the global) + else if (scopeType == "FUNCTION") { + // in a method of a prototype, so `this` means the constructor + if (symbol.alias.match(/(^.*)[#.-][^#.-]+/)) { + var parentName = RegExp.$1; + var parent = JSDOC.Parser.symbols.getSymbol(parentName); + + if (!parent) { + if (JSDOC.Lang.isBuiltin(parentName)) parent = JSDOC.Parser.addBuiltin(parentName); + else { + if (symbol.alias.indexOf("$anonymous") < 0) // these will be ignored eventually + LOG.warn("Trying to document "+symbol.alias+" without first documenting "+parentName+"."); + } + } + if (parent) name = parentName+(parent.is("CONSTRUCTOR")?"#":".")+nameFragment; + } + else { + parent = this.namescope.last(1); + name = parent.alias+(parent.is("CONSTRUCTOR")?"#":".")+nameFragment; + } + } + // otherwise it means the global + else { + name = nameFragment; + } + + return name; +} + +JSDOC.Walker.onParamList = function(/**Array*/paramTokens) { + if (!paramTokens) { + LOG.warn("Malformed parameter list. Can't parse code."); + return []; + } + var params = []; + for (var i = 0, l = paramTokens.length; i < l; i++) { + if (paramTokens[i].is("JSDOC")) { + var paramType = paramTokens[i].data.replace(/(^\/\*\* *| *\*\/$)/g, ""); + + if (paramTokens[i+1] && paramTokens[i+1].is("NAME")) { + i++; + params.push({type: paramType, name: paramTokens[i].data}); + } + } + else if (paramTokens[i].is("NAME")) { + params.push({name: paramTokens[i].data}); + } + } + return params; +} diff --git a/bin/jsdoc/main.js b/bin/jsdoc/main.js new file mode 100644 index 00000000..f9008c87 --- /dev/null +++ b/bin/jsdoc/main.js @@ -0,0 +1,111 @@ +/** + * @version $Id: main.js 818 2009-11-08 14:51:41Z micmath $ + */ + +function main() { + IO.include("lib/JSDOC.js"); + IO.includeDir("plugins/"); + + // process the options + + // the -c option: options are defined in a configuration file + if (JSDOC.opt.c) { + eval("JSDOC.conf = " + IO.readFile(JSDOC.opt.c)); + + LOG.inform("Using configuration file at '"+JSDOC.opt.c+"'."); + + for (var c in JSDOC.conf) { + if (c !== "D" && !defined(JSDOC.opt[c])) { // commandline overrules config file + JSDOC.opt[c] = JSDOC.conf[c]; + } + } + + if (typeof JSDOC.conf["_"] != "undefined") { + JSDOC.opt["_"] = JSDOC.opt["_"].concat(JSDOC.conf["_"]); + } + + LOG.inform("With configuration: "); + for (var o in JSDOC.opt) { + LOG.inform(" "+o+": "+JSDOC.opt[o]); + } + } + + // be verbose + if (JSDOC.opt.v) LOG.verbose = true; + + // send log messages to a file + if (JSDOC.opt.o) LOG.out = IO.open(JSDOC.opt.o); + + // run the unit tests + if (JSDOC.opt.T) { + LOG.inform("JsDoc Toolkit running in test mode at "+new Date()+"."); + IO.include("frame/Testrun.js"); + IO.include("test.js"); + } + else { + // a template must be defined and must be a directory path + if (!JSDOC.opt.t && System.getProperty("jsdoc.template.dir")) { + JSDOC.opt.t = System.getProperty("jsdoc.template.dir"); + } + if (JSDOC.opt.t && SYS.slash != JSDOC.opt.t.slice(-1)) { + JSDOC.opt.t += SYS.slash; + } + + // verbose messages about the options we were given + LOG.inform("JsDoc Toolkit main() running at "+new Date()+"."); + LOG.inform("With options: "); + for (var o in JSDOC.opt) { + LOG.inform(" "+o+": "+JSDOC.opt[o]); + } + + // initialize and build a symbolSet from your code + JSDOC.JsDoc(); + + // debugger's option: dump the entire symbolSet produced from your code + if (JSDOC.opt.Z) { + LOG.warn("So you want to see the data structure, eh? This might hang if you have circular refs..."); + IO.include("frame/Dumper.js"); + var symbols = JSDOC.JsDoc.symbolSet.toArray(); + for (var i = 0, l = symbols.length; i < l; i++) { + var symbol = symbols[i]; + print("// symbol: " + symbol.alias); + print(symbol.serialize()); + } + } + else { + if (typeof JSDOC.opt.t != "undefined") { + try { + // a file named "publish.js" must exist in the template directory + load(JSDOC.opt.t+"publish.js"); + + // and must define a function named "publish" + if (!publish) { + LOG.warn("No publish() function is defined in that template so nothing to do."); + } + else { + // which will be called with the symbolSet produced from your code + publish(JSDOC.JsDoc.symbolSet); + } + } + catch(e) { + LOG.warn("Sorry, that doesn't seem to be a valid template: "+JSDOC.opt.t+"publish.js : "+e); + } + } + else { + LOG.warn("No template given. Might as well read the usage notes."); + JSDOC.usage(); + } + } + } + + // notify of any warnings + if (!JSDOC.opt.q && LOG.warnings.length) { + print(LOG.warnings.length+" warning"+(LOG.warnings.length != 1? "s":"")+"."); + } + + // stop sending log messages to a file + if (LOG.out) { + LOG.out.flush(); + LOG.out.close(); + } +} \ No newline at end of file diff --git a/bin/jsdoc/plugins/commentSrcJson.js b/bin/jsdoc/plugins/commentSrcJson.js new file mode 100644 index 00000000..e826b572 --- /dev/null +++ b/bin/jsdoc/plugins/commentSrcJson.js @@ -0,0 +1,20 @@ +JSDOC.PluginManager.registerPlugin( + "JSDOC.commentSrcJson", + { + onDocCommentSrc: function(comment) { + var json; + if (/^\s*@json\b/.test(comment)) { + comment.src = new String(comment.src).replace("@json", ""); + + eval("json = "+comment.src); + var tagged = ""; + for (var i in json) { + var tag = json[i]; + // todo handle cases where tag is an object + tagged += "@"+i+" "+tag+"\n"; + } + comment.src = tagged; + } + } + } +); \ No newline at end of file diff --git a/bin/jsdoc/plugins/frameworkPrototype.js b/bin/jsdoc/plugins/frameworkPrototype.js new file mode 100644 index 00000000..9c417518 --- /dev/null +++ b/bin/jsdoc/plugins/frameworkPrototype.js @@ -0,0 +1,16 @@ +JSDOC.PluginManager.registerPlugin( + "JSDOC.frameworkPrototype", + { + onPrototypeClassCreate: function(classCreator) { + var desc = ""; + if (classCreator.comment) { + desc = classCreator.comment; + } + var insert = desc+"/** @name "+classCreator.name+"\n@constructor\n@scope "+classCreator.name+".prototype */" + + insert = insert.replace(/\*\/\/\*\*/g, "\n"); + /*DEBUG*///print("insert is "+insert); + classCreator.addComment.data = insert; + } + } +); diff --git a/bin/jsdoc/plugins/functionCall.js b/bin/jsdoc/plugins/functionCall.js new file mode 100644 index 00000000..6f87705e --- /dev/null +++ b/bin/jsdoc/plugins/functionCall.js @@ -0,0 +1,10 @@ +JSDOC.PluginManager.registerPlugin( + "JSDOC.functionCall", + { + onFunctionCall: function(functionCall) { + if (functionCall.name == "dojo.define" && functionCall.arg1) { + functionCall.doc = "/** @lends "+eval(functionCall.arg1)+".prototype */"; + } + } + } +); \ No newline at end of file diff --git a/bin/jsdoc/plugins/publishSrcHilite.js b/bin/jsdoc/plugins/publishSrcHilite.js new file mode 100644 index 00000000..65514f2c --- /dev/null +++ b/bin/jsdoc/plugins/publishSrcHilite.js @@ -0,0 +1,62 @@ +JSDOC.PluginManager.registerPlugin( + "JSDOC.publishSrcHilite", + { + onPublishSrc: function(src) { + if (src.path in JsHilite.cache) { + return; // already generated src code + } + else JsHilite.cache[src.path] = true; + + try { + var sourceCode = IO.readFile(src.path); + } + catch(e) { + print(e.message); + quit(); + } + + var hiliter = new JsHilite(sourceCode, src.charset); + src.hilited = hiliter.hilite(); + } + } +); + +function JsHilite(src, charset) { + + var tr = new JSDOC.TokenReader(); + + tr.keepComments = true; + tr.keepDocs = true; + tr.keepWhite = true; + + this.tokens = tr.tokenize(new JSDOC.TextStream(src)); + + // TODO is redefining toString() the best way? + JSDOC.Token.prototype.toString = function() { + return ""+this.data.replace(/"; + } + + if (!charset) charset = "utf-8"; + + this.header = ' '+ + "

";
+	this.footer = "
"; + this.showLinenumbers = true; +} + +JsHilite.cache = {}; + +JsHilite.prototype.hilite = function() { + var hilited = this.tokens.join(""); + var line = 1; + if (this.showLinenumbers) hilited = hilited.replace(/(^|\n)/g, function(m){return m+""+((line<10)? " ":"")+((line<100)? " ":"")+(line++)+" "}); + + return this.header+hilited+this.footer; +} \ No newline at end of file diff --git a/bin/jsdoc/plugins/symbolLink.js b/bin/jsdoc/plugins/symbolLink.js new file mode 100644 index 00000000..c87f1ca7 --- /dev/null +++ b/bin/jsdoc/plugins/symbolLink.js @@ -0,0 +1,10 @@ +JSDOC.PluginManager.registerPlugin( + "JSDOC.symbolLink", + { + onSymbolLink: function(link) { + // modify link.linkPath (the href part of the link) + // or link.linkText (the text displayed) + // or link.linkInner (the #name part of the link) + } + } +); \ No newline at end of file diff --git a/bin/jsdoc/plugins/tagParamConfig.js b/bin/jsdoc/plugins/tagParamConfig.js new file mode 100644 index 00000000..3ea8a1be --- /dev/null +++ b/bin/jsdoc/plugins/tagParamConfig.js @@ -0,0 +1,31 @@ +JSDOC.PluginManager.registerPlugin( + "JSDOC.tagParamConfig", + { + onDocCommentTags: function(comment) { + var currentParam = null; + var tags = comment.tags; + for (var i = 0, l = tags.length; i < l; i++) { + + if (tags[i].title == "param") { + if (tags[i].name.indexOf(".") == -1) { + currentParam = i; + } + } + else if (tags[i].title == "config") { + tags[i].title = "param"; + if (currentParam == null) { + tags[i].name = "arguments"+"."+tags[i].name; + } + else if (tags[i].name.indexOf(tags[currentParam].name+".") != 0) { + tags[i].name = tags[currentParam].name+"."+tags[i].name; + } + currentParam != null + //tags[currentParam].properties.push(tags[i]); + } + else { + currentParam = null; + } + } + } + } +); diff --git a/bin/jsdoc/plugins/tagSynonyms.js b/bin/jsdoc/plugins/tagSynonyms.js new file mode 100644 index 00000000..49a874f1 --- /dev/null +++ b/bin/jsdoc/plugins/tagSynonyms.js @@ -0,0 +1,43 @@ +JSDOC.PluginManager.registerPlugin( + "JSDOC.tagSynonyms", + { + onDocCommentSrc: function(comment) { + comment.src = comment.src.replace(/@methodOf\b/i, "@function\n@memberOf"); + comment.src = comment.src.replace(/@fieldOf\b/i, "@field\n@memberOf"); + }, + + onDocCommentTags: function(comment) { + for (var i = 0, l = comment.tags.length; i < l; i++) { + var title = comment.tags[i].title.toLowerCase(); + var syn; + if ((syn = JSDOC.tagSynonyms.synonyms["="+title])) { + comment.tags[i].title = syn; + } + } + } + } +); + +new Namespace( + "JSDOC.tagSynonyms", + function() { + JSDOC.tagSynonyms.synonyms = { + "=member": "memberOf", + "=memberof": "memberOf", + "=description": "desc", + "=exception": "throws", + "=argument": "param", + "=returns": "return", + "=classdescription": "class", + "=fileoverview": "overview", + "=extends": "augments", + "=base": "augments", + "=projectdescription": "overview", + "=classdescription": "class", + "=link": "see", + "=borrows": "inherits", + "=scope": "lends", + "=construct": "constructor" + } + } +); \ No newline at end of file diff --git a/bin/jsdoc/run.js b/bin/jsdoc/run.js new file mode 100644 index 00000000..1f875cdb --- /dev/null +++ b/bin/jsdoc/run.js @@ -0,0 +1,348 @@ +/** + * @fileOverview + * A bootstrap script that creates some basic required objects + * for loading other scripts. + * @author Michael Mathews, micmath@gmail.com + * @version $Id: run.js 756 2009-01-07 21:32:58Z micmath $ + */ + +/** + * @namespace Keep track of any messages from the running script. + */ +LOG = { + warn: function(msg, e) { + if (JSDOC.opt.q) return; + if (e) msg = e.fileName+", line "+e.lineNumber+": "+msg; + + msg = ">> WARNING: "+msg; + LOG.warnings.push(msg); + if (LOG.out) LOG.out.write(msg+"\n"); + else print(msg); + }, + + inform: function(msg) { + if (JSDOC.opt.q) return; + msg = " > "+msg; + if (LOG.out) LOG.out.write(msg+"\n"); + else if (typeof LOG.verbose != "undefined" && LOG.verbose) print(msg); + } +}; +LOG.warnings = []; +LOG.verbose = false +LOG.out = undefined; + +/** + * @class Manipulate a filepath. + */ +function FilePath(absPath, separator) { + this.slash = separator || "/"; + this.root = this.slash; + this.path = []; + this.file = ""; + + var parts = absPath.split(/[\\\/]/); + if (parts) { + if (parts.length) this.root = parts.shift() + this.slash; + if (parts.length) this.file = parts.pop() + if (parts.length) this.path = parts; + } + + this.path = this.resolvePath(); +} + +/** Collapse any dot-dot or dot items in a filepath. */ +FilePath.prototype.resolvePath = function() { + var resolvedPath = []; + for (var i = 0; i < this.path.length; i++) { + if (this.path[i] == "..") resolvedPath.pop(); + else if (this.path[i] != ".") resolvedPath.push(this.path[i]); + } + return resolvedPath; +} + +/** Trim off the filename. */ +FilePath.prototype.toDir = function() { + if (this.file) this.file = ""; + return this; +} + +/** Go up a directory. */ +FilePath.prototype.upDir = function() { + this.toDir(); + if (this.path.length) this.path.pop(); + return this; +} + +FilePath.prototype.toString = function() { + return this.root + + this.path.join(this.slash) + + ((this.path.length > 0)? this.slash : "") + + this.file; +} + +/** + * Turn a path into just the name of the file. + */ +FilePath.fileName = function(path) { + var nameStart = Math.max(path.lastIndexOf("/")+1, path.lastIndexOf("\\")+1, 0); + return path.substring(nameStart); +} + +/** + * Get the extension of a filename + */ +FilePath.fileExtension = function(filename) { + return filename.split(".").pop().toLowerCase(); +}; + +/** + * Turn a path into just the directory part. + */ +FilePath.dir = function(path) { + var nameStart = Math.max(path.lastIndexOf("/")+1, path.lastIndexOf("\\")+1, 0); + return path.substring(0, nameStart-1); +} + + +importClass(java.lang.System); + +/** + * @namespace A collection of information about your system. + */ +SYS = { + /** + * Information about your operating system: arch, name, version. + * @type string + */ + os: [ + new String(System.getProperty("os.arch")), + new String(System.getProperty("os.name")), + new String(System.getProperty("os.version")) + ].join(", "), + + /** + * Which way does your slash lean. + * @type string + */ + slash: System.getProperty("file.separator")||"/", + + /** + * The path to the working directory where you ran java. + * @type string + */ + userDir: new String(System.getProperty("user.dir")), + + /** + * Where is Java's home folder. + * @type string + */ + javaHome: new String(System.getProperty("java.home")), + + /** + * The absolute path to the directory containing this script. + * @type string + */ + pwd: undefined +}; + +// jsrun appends an argument, with the path to here. +if (arguments[arguments.length-1].match(/^-j=(.+)/)) { + if (RegExp.$1.charAt(0) == SYS.slash || RegExp.$1.charAt(1) == ":") { // absolute path to here + SYS.pwd = new FilePath(RegExp.$1).toDir().toString(); + } + else { // relative path to here + SYS.pwd = new FilePath(SYS.userDir + SYS.slash + RegExp.$1).toDir().toString(); + } + arguments.pop(); +} +else { + print("The run.js script requires you use jsrun.jar."); + quit(); +} + +// shortcut +var File = Packages.java.io.File; + +/** + * @namespace A collection of functions that deal with reading a writing to disk. + */ +IO = { + + /** + * Create a new file in the given directory, with the given name and contents. + */ + saveFile: function(/**string*/ outDir, /**string*/ fileName, /**string*/ content) { + var out = new Packages.java.io.PrintWriter( + new Packages.java.io.OutputStreamWriter( + new Packages.java.io.FileOutputStream(outDir+SYS.slash+fileName), + IO.encoding + ) + ); + out.write(content); + out.flush(); + out.close(); + }, + + /** + * @type string + */ + readFile: function(/**string*/ path) { + if (!IO.exists(path)) { + throw "File doesn't exist there: "+path; + } + return readFile(path, IO.encoding); + }, + + /** + * @param inFile + * @param outDir + * @param [fileName=The original filename] + */ + copyFile: function(/**string*/ inFile, /**string*/ outDir, /**string*/ fileName) { + if (fileName == null) fileName = FilePath.fileName(inFile); + + var inFile = new File(inFile); + var outFile = new File(outDir+SYS.slash+fileName); + + var bis = new Packages.java.io.BufferedInputStream(new Packages.java.io.FileInputStream(inFile), 4096); + var bos = new Packages.java.io.BufferedOutputStream(new Packages.java.io.FileOutputStream(outFile), 4096); + var theChar; + while ((theChar = bis.read()) != -1) { + bos.write(theChar); + } + bos.close(); + bis.close(); + }, + + /** + * Creates a series of nested directories. + */ + mkPath: function(/**Array*/ path) { + if (path.constructor != Array) path = path.split(/[\\\/]/); + var make = ""; + for (var i = 0, l = path.length; i < l; i++) { + make += path[i] + SYS.slash; + if (! IO.exists(make)) { + IO.makeDir(make); + } + } + }, + + /** + * Creates a directory at the given path. + */ + makeDir: function(/**string*/ path) { + (new File(path)).mkdir(); + }, + + /** + * @type string[] + * @param dir The starting directory to look in. + * @param [recurse=1] How many levels deep to scan. + * @returns An array of all the paths to files in the given dir. + */ + ls: function(/**string*/ dir, /**number*/ recurse, _allFiles, _path) { + if (_path === undefined) { // initially + var _allFiles = []; + var _path = [dir]; + } + if (_path.length == 0) return _allFiles; + if (recurse === undefined) recurse = 1; + + dir = new File(dir); + if (!dir.directory) return [String(dir)]; + var files = dir.list(); + + for (var f = 0; f < files.length; f++) { + var file = String(files[f]); + if (file.match(/^\.[^\.\/\\]/)) continue; // skip dot files + + if ((new File(_path.join(SYS.slash)+SYS.slash+file)).list()) { // it's a directory + _path.push(file); + if (_path.length-1 < recurse) IO.ls(_path.join(SYS.slash), recurse, _allFiles, _path); + _path.pop(); + } + else { + _allFiles.push((_path.join(SYS.slash)+SYS.slash+file).replace(SYS.slash+SYS.slash, SYS.slash)); + } + } + + return _allFiles; + }, + + /** + * @type boolean + */ + exists: function(/**string*/ path) { + file = new File(path); + + if (file.isDirectory()){ + return true; + } + if (!file.exists()){ + return false; + } + if (!file.canRead()){ + return false; + } + return true; + }, + + /** + * + */ + open: function(/**string*/ path, /**string*/ append) { + var append = true; + var outFile = new File(path); + var out = new Packages.java.io.PrintWriter( + new Packages.java.io.OutputStreamWriter( + new Packages.java.io.FileOutputStream(outFile, append), + IO.encoding + ) + ); + return out; + }, + + /** + * Sets {@link IO.encoding}. + * Encoding is used when reading and writing text to files, + * and in the meta tags of HTML output. + */ + setEncoding: function(/**string*/ encoding) { + if (/ISO-8859-([0-9]+)/i.test(encoding)) { + IO.encoding = "ISO8859_"+RegExp.$1; + } + else { + IO.encoding = encoding; + } + }, + + /** + * @default "utf-8" + * @private + */ + encoding: "utf-8", + + /** + * Load the given script. + */ + include: function(relativePath) { + load(SYS.pwd+relativePath); + }, + + /** + * Loads all scripts from the given directory path. + */ + includeDir: function(path) { + if (!path) return; + + for (var lib = IO.ls(SYS.pwd+path), i = 0; i < lib.length; i++) + if (/\.js$/i.test(lib[i])) load(lib[i]); + } +} + +// now run the application +IO.include("frame.js"); +IO.include("main.js"); + +main(); diff --git a/bin/jsdoc/t/TestDoc.js b/bin/jsdoc/t/TestDoc.js new file mode 100644 index 00000000..c0768b71 --- /dev/null +++ b/bin/jsdoc/t/TestDoc.js @@ -0,0 +1,144 @@ +var TestDoc = { + fails: 0, + plans: 0, + passes: 0, + results: [] +}; + +TestDoc.record = function(result) { + TestDoc.results.push(result); + if (typeof result.verdict == "boolean") { + if (result.verdict === false) TestDoc.fails++; + if (result.verdict === true) TestDoc.passes++; + } +} + +TestDoc.prove = function(filePath) { + if (typeof document != "undefined" && typeof document.write != "undefined") { + if (TestDoc.console) print = function(s) { TestDoc.console.appendChild(document.createTextNode(s+"\n")); } + else print = function(s) { document.write(s+"
"); } + } + TestDoc.run(TestDoc.readFile(filePath)); +} + +TestDoc.run = function(src) { + try { eval(src); } catch(e) { print("# ERROR! "+e); } + + var chunks = src.split(/\/\*t:/); + + var run = function(chunk) { + // local shortcuts + var is = TestDoc.assertEquals; + var isnt = TestDoc.assertNotEquals; + var plan = TestDoc.plan; + var requires = TestDoc.requires; + + try { eval(chunk); } catch(e) { print("# ERROR! "+e); } + } + for (var start = -1, end = 0; (start = src.indexOf("/*t:", end)) > end; start = end) { + run( + src.substring( + start+4, + (end = src.indexOf("*/", start)) + ) + ); + } +} + +TestDoc.Result = function(verdict, message) { + this.verdict = verdict; + this.message = message; +} + +TestDoc.Result.prototype.toString = function() { + if (typeof this.verdict == "boolean") { + return (this.verdict? "ok" : "not ok") + " " + (++TestDoc.report.counter) + " - " + this.message; + } + + return "# " + this.message; +} + +TestDoc.requires = function(file) { + if (!TestDoc.requires.loaded[file]) { + load(file); + TestDoc.requires.loaded[file] = true; + } +} +TestDoc.requires.loaded = {}; + +TestDoc.report = function() { + TestDoc.report.counter = 0; + print("1.."+TestDoc.plans); + for (var i = 0; i < TestDoc.results.length; i++) { + print(TestDoc.results[i]); + } + print("----------------------------------------"); + if (TestDoc.fails == 0 && TestDoc.passes == TestDoc.plans) { + print("All tests successful."); + } + else { + print("Failed " + TestDoc.fails + "/" + TestDoc.plans + " tests, "+((TestDoc.plans == 0)? 0 : Math.round(TestDoc.passes/(TestDoc.passes+TestDoc.fails)*10000)/100)+"% okay. Planned to run "+TestDoc.plans+", did run "+(TestDoc.passes+TestDoc.fails)+".") + } +} + +TestDoc.plan = function(n, message) { + TestDoc.plans += n; + TestDoc.record(new TestDoc.Result(null, message+" ("+n+" tests)")); +} + +TestDoc.assertEquals = function(a, b, message) { + var result = (a == b); + if (!result) message += "\n#\n# " + a + " does not equal " + b + "\n#"; + TestDoc.record(new TestDoc.Result(result, message)); +} + +TestDoc.assertNotEquals = function(a, b, message) { + var result = (a != b); + if (!result) message += "\n#\n# " + a + " equals " + b + "\n#"; + TestDoc.record(new TestDoc.Result(result, message)); +} + +TestDoc.readFile = (function(){ + // rhino + if (typeof readFile == "function") { + return function(url) { + var text = readFile(url); + return text || ""; + } + } + + // a web browser + else { + return function(url) { + var httpRequest; + + if (window.XMLHttpRequest) { // Mozilla, Safari, etc + httpRequest = new XMLHttpRequest(); + } + else if (window.ActiveXObject) { // IE + try { + httpRequest = new ActiveXObject("Msxml2.XMLHTTP"); + } + catch (e) { + try { + httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); + } + catch (e) { + } + } + } + + if (!httpRequest) { throw "Cannot create HTTP Request."; } + + httpRequest.open('GET', url, false); + httpRequest.send(''); + if (httpRequest.readyState == 4) { + if (httpRequest.status >= 400) { + throw "The HTTP Request returned an error code: "+httpRequest.status; + } + } + + return httpRequest.responseText || ""; + } + } +})(); diff --git a/bin/jsdoc/t/runner.js b/bin/jsdoc/t/runner.js new file mode 100644 index 00000000..3f9fb4c9 --- /dev/null +++ b/bin/jsdoc/t/runner.js @@ -0,0 +1,13 @@ +// try: java -jar ../../jsrun.jar runner.js + +load("TestDoc.js"); + +TestDoc.prove("../frame/Opt.js"); +TestDoc.prove("../lib/JSDOC.js"); +TestDoc.prove("../frame/String.js"); +TestDoc.prove("../lib/JSDOC/DocTag.js"); +TestDoc.prove("../lib/JSDOC/DocComment.js"); +TestDoc.prove("../lib/JSDOC/TokenReader.js"); +TestDoc.prove("../lib/JSDOC/Symbol.js"); + +TestDoc.report(); diff --git a/bin/jsdoc/templates/README.txt b/bin/jsdoc/templates/README.txt new file mode 100755 index 00000000..f593f4aa --- /dev/null +++ b/bin/jsdoc/templates/README.txt @@ -0,0 +1,5 @@ +Codeview is a template for JSDoc Toolkit. With JSDoc Toolkit you can generate a documentation website. + +The Codeview template is, like JSDoc Toolkit itself, published under the X11/MIT License. + +Codeview is Copyright (c) 2010 Wouter Bos (www.thebrightlines.com) \ No newline at end of file diff --git a/bin/jsdoc/templates/allclasses.tmpl b/bin/jsdoc/templates/allclasses.tmpl new file mode 100755 index 00000000..774643ab --- /dev/null +++ b/bin/jsdoc/templates/allclasses.tmpl @@ -0,0 +1,20 @@ +{! Link.base = ""; /* all generated links will be relative to this */ !} +{+subtemplate("subtemplates/head.tmpl", {subtitle: "Class Index"})+} +{+subtemplate("subtemplates/menu.tmpl")+} +
+
+
+

Class Index

+ +
    + +
  • +

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

    +

    {+resolveLinks(summarize(thisClass.classDesc))+}

    +
  • +
    +
+
+
+
+{+subtemplate("subtemplates/foot.tmpl")+} diff --git a/bin/jsdoc/templates/allfiles.tmpl b/bin/jsdoc/templates/allfiles.tmpl new file mode 100755 index 00000000..042927a2 --- /dev/null +++ b/bin/jsdoc/templates/allfiles.tmpl @@ -0,0 +1,41 @@ +{! Link.base = ""; /* all generated links will be relative to this */ !} +{+subtemplate("subtemplates/head.tmpl", {subtitle: "File Index"})+} +{+subtemplate("subtemplates/menu.tmpl")+} +
+
+
+

File Index

+ +
    + +
  • +

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

    + + {+resolveLinks(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+}
    +
    +
    +
    +
  • +
    +
+
+
+
+{+subtemplate("subtemplates/foot.tmpl")+} \ No newline at end of file diff --git a/bin/jsdoc/templates/class.tmpl b/bin/jsdoc/templates/class.tmpl new file mode 100755 index 00000000..276a91b7 --- /dev/null +++ b/bin/jsdoc/templates/class.tmpl @@ -0,0 +1,712 @@ +{! Link.base = "../"; /* all generated links will be relative to this */ !} +{+subtemplate("subtemplates/head.tmpl", {subtitle: data.alias})+} +{+subtemplate("subtemplates/menu.tmpl")+} +
+
+
+
+

+ {! + 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+} +

+ +
+

+ {+resolveLinks(data.classDesc)+} +

+ + +
    + +
  • Version {+ data.version +}
  • +
    + + {# isn't defined in any file #} +
  • Defined in: {+new Link().toSrc(data.srcFile)+}
  • +
    +
  • Extends + {+ + data.augments + .sort() + .map( + function($) { return new Link().toSymbol($); } + ) + .join(", ") + +}
  • +
    +
+
+
+
+ + +
+
+ + + + + + + + + + + + + + +
{+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")); !} +
+ + + + + + + +
+
+ + +
+ {! var ownMethods = data.methods.filter(function($){return $.memberOf == data.alias && !$.isNamespace}).sort(makeSortby("name")); !} + +
+

Method Summary

+ + + + + + + + +
+
+
+ + + + {! var ownEvents = data.events.filter(function($){return $.memberOf == data.alias && !$.isNamespace}).sort(makeSortby("name")); !} +
+ + + + + + + +
+
+ + +
+
+
+

+ {+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)+}
+
+
+
+ + +
+ +
+ {+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:
+
+ {+ resolveLinks(member.deprecated) +} +
+
+ +
Since:
+
{+ member.since +}
+
+ +
See:
+ +
{+ new Link().toSymbol(item) +}
+
+
+ +
Default Value:
+
+ {+resolveLinks(member.defaultValue)+} +
+
+
+
+ +
+
+
+
+
+
+ + +
+
+
+

+ Method Detail +

+ +
    + {! + var methodDetailCount = 0; + !} + +
  • +
    + + {! + if (member.isPrivate) output += "<private> "; + if (member.isInner) output += "<inner> "; + if (member.isStatic) output += "<static> "; + !} + + + {{+new Link().toSymbol(member.type)+}} + + {+member.memberOf+}.{+member.name.replace(/\^\d+$/, '')+}{+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:
    +
    + {+ resolveLinks(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:
+
{+ resolveLinks(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) +}
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +{+subtemplate("subtemplates/foot.tmpl")+} diff --git a/bin/jsdoc/templates/css/all.css b/bin/jsdoc/templates/css/all.css new file mode 100755 index 00000000..c253cb0d --- /dev/null +++ b/bin/jsdoc/templates/css/all.css @@ -0,0 +1,358 @@ +/* TABLE OF CONTENTS: + * - Browser reset + * - HTML elements + * - JsDoc styling + */ + + + + + + +/* + * BEGIN BROWSER RESET + */ + +body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,p,pre,form,fieldset,input,textarea,p,blockquote,th,td { + margin:0; + padding:0 +} +html { + height:100%; + overflow:-moz-scrollbars-vertical; + overflow-x:auto +} +table { + border:0; + border-collapse:collapse; + border-spacing:0 +} +fieldset,img { + border:0 +} +address,caption,cite,code,dfn,em,strong,th,var { + font-style:normal; + font-weight:normal +} +em,cite { + font-style:italic +} +strong { + font-weight:bold +} +ol,ul { + list-style:none +} +caption,th { + text-align:left +} +h1,h2,h3,h4,h5,h6 { + font-size:100%; + font-weight:normal; + margin:0; + padding:0 +} +q:before,q:after { + content:'' +} +abbr,acronym { + border:0 +} +section,article,header,footer,nav,aside,hgroup { + display:block +} + +/* + * END BROWSER RESET + */ + + + + + + +/* + * HTML ELEMENTS + */ + +@font-face { + font-family: 'M1m'; + src: url('fonts/mplus-1m-regular-webfont.eot'); + src: local('☺'), url('fonts/mplus-1m-regular-webfont.woff') format('woff'), url('fonts/mplus-1m-regular-webfont.ttf') format('truetype'), url('fonts/mplus-1m-regular-webfont.svg#webfontVd14f4NN') format('svg'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'M1m'; + src: url('fonts/mplus-1m-bold-webfont.eot'); + src: local('☺'), url('fonts/mplus-1m-bold-webfont.woff') format('woff'), url('fonts/mplus-1m-bold-webfont.ttf') format('truetype'), url('fonts/mplus-1m-bold-webfont.svg#webfontIjI5mZqE') format('svg'); + font-weight: bold; + font-style: normal; +} + + + +* { + line-height: 1.4em; +} + +html { + font-size: 100%; +} + +body { + font-size: 0.75em; + padding: 15px 0; + background: #eee; + background-image: -moz-linear-gradient(left, #dddddd, #f9f9f9) fixed; + background-image: -webkit-gradient(linear,left bottom,right bottom,color-stop(0, #dddddd),color-stop(1, #f9f9f9)) fixed; + } + +body, +input, +select, +textarea { + color: #000; + font-family: Arial, Geneva, sans-serif; +} + +a:link, +a:hover, +a:active, +a:visited { + color: #19199e; +} +a:hover, +a:focus { + color: #00f; + text-decoration: none; +} + +p { + margin: 0 0 1.5em 0; +} + +/* + * END HTML ELEMENTS + */ + + + +/* + * BEGIN HACK + */ + +div.containerMain:after, +div.safeBox:after { + content:""; + display:block; + height:0; + clear:both; +} + +/* + * END HACK + */ + + + +/* + * BEGIN JSDOC + */ + +/* Start menu */ +div.index *.heading1 { + margin-bottom: 0.5em; + border-bottom: 1px solid #999999; + font-family: M1m, Arial, sans-serif; + font-size: 1.6em; + letter-spacing: 1px; + line-height: 1.3em; +} + +div.index div.menu { + background-color: #FFFFFF; +} +*+html div.index div.menu { + background-color: #FFFFFF; +} +* html div.index div.menu { + background-color: #FFFFFF; +} + +div.index div.menu div { + text-align: left; +} + +div.index div.menu a { + text-decoration: none; +} +div.index div.menu a:hover { + text-decoration: underline; +} + +div.index ul.classList { + padding-left: 0; +} + +div.index ul.classList a { + display: block; + margin: 1px 0; + padding: 4px 0 2px 10px; + text-indent: -10px; +} + +div.index div.fineprint { + color: #777; + font-size: 0.9em; +} +div.index div.fineprint a { + color: #777; +} +/* End menu */ + + + +/* Start content */ +div.content ul { + padding-left: 0; +} + +div.content *.classTitle { + font-size: 1.2em; + font-weight: bold; + line-height: 1em; +} + +div.content *.classTitle span { + display: block; + font-size: 2em; + letter-spacing: 2px; + line-height: 1em; + padding-top: 5px; + text-shadow: 1px 1px 1px #999999; + word-wrap: break-word; +} + +div.content p.summary { + font-size: 1.25em; +} + +div.content ul *.classname a, +div.content ul *.filename a { + font-family: Consolas, "Courier New", Courier, monospace; + text-decoration: none; + font-weight: bold; +} +div.content ul *.classname a:hover, +div.content ul *.filename a:hover { + text-decoration: underline; +} + +div.content div.props { + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + background: #fff; + background: -moz-linear-gradient(top, rgba(255, 255, 255, 0.7), rgba(255, 255, 255, 0.2)); /* FF3.6 */ + background: -webkit-gradient(linear,left top,left bottom,color-stop(0, rgba(255, 255, 255, 0.7)),color-stop(1, rgba(255, 255, 255, 0.2))); + -moz-box-shadow: 0px 0px 10px #ccc; + -webkit-box-shadow: 0px 0px 5px #bbb; + box-shadow: 0px 0px 5px #bbb; +} + + + +*.sectionTitle { + font-family: M1m, sans-serif; + font-size: 1.6em; + letter-spacing: 1px; +} + +table.summaryTable td, +table.summaryTable th { + vertical-align: top; +} +table.summaryTable tr:last-child td { + padding-bottom: 0; +} + +table.summaryTable th { + font-weight: bold; +} + +table.summaryTable td.attributes { + font-family: Consolas, "Courier New", Courier, monospace; + color: #666; +} + +table.summaryTable td.nameDescription div.fixedFont { + font-weight: bold; +} + +table.summaryTable div.description { + color: #333; +} + + + +dl.detailList dt { + font-weight: bold; +} + +dl.inheritsList dd + dt { + margin-top: 10px; +} + +dl.inheritsList dd { + display: inline; +} + + + +.fixedFont { + font-family: Consolas, "Courier New", Courier, monospace; +} + +.fixedFont.heading { + font-size: 1.25em; + line-height: 1.1em +} + +.fixedFont.heading + .description { + font-size: 1.2em; +} + +.fixedFont.heading .light, +.fixedFont.heading .lighter { + font-weight: bold; +} + +pre.code { + overflow: auto; + font-family: Consolas, "Courier New", Courier, monospace; + background: #eee; +} +/* Start content */ + + + +/* Start general styles */ +.light { + color: #666; +} + +.lighter { + color: #999; +} + +span.break { + font-size: 1px; + line-height: 1px; +} +/* End general styles */ + +/* + * END JSDOC + */ diff --git a/bin/jsdoc/templates/css/fonts/mplus-1m-bold-webfont.eot b/bin/jsdoc/templates/css/fonts/mplus-1m-bold-webfont.eot new file mode 100755 index 00000000..6c64f8d7 Binary files /dev/null and b/bin/jsdoc/templates/css/fonts/mplus-1m-bold-webfont.eot differ diff --git a/bin/jsdoc/templates/css/fonts/mplus-1m-bold-webfont.svg b/bin/jsdoc/templates/css/fonts/mplus-1m-bold-webfont.svg new file mode 100755 index 00000000..51295128 --- /dev/null +++ b/bin/jsdoc/templates/css/fonts/mplus-1m-bold-webfont.svg @@ -0,0 +1,134 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Foundry URL : http://mplus-fonts.sourceforge.jp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bin/jsdoc/templates/css/fonts/mplus-1m-bold-webfont.ttf b/bin/jsdoc/templates/css/fonts/mplus-1m-bold-webfont.ttf new file mode 100755 index 00000000..0cf54cbb Binary files /dev/null and b/bin/jsdoc/templates/css/fonts/mplus-1m-bold-webfont.ttf differ diff --git a/bin/jsdoc/templates/css/fonts/mplus-1m-bold-webfont.woff b/bin/jsdoc/templates/css/fonts/mplus-1m-bold-webfont.woff new file mode 100755 index 00000000..f90475d8 Binary files /dev/null and b/bin/jsdoc/templates/css/fonts/mplus-1m-bold-webfont.woff differ diff --git a/bin/jsdoc/templates/css/fonts/mplus-1m-regular-webfont.eot b/bin/jsdoc/templates/css/fonts/mplus-1m-regular-webfont.eot new file mode 100755 index 00000000..a53f8b54 Binary files /dev/null and b/bin/jsdoc/templates/css/fonts/mplus-1m-regular-webfont.eot differ diff --git a/bin/jsdoc/templates/css/fonts/mplus-1m-regular-webfont.svg b/bin/jsdoc/templates/css/fonts/mplus-1m-regular-webfont.svg new file mode 100755 index 00000000..3c835a31 --- /dev/null +++ b/bin/jsdoc/templates/css/fonts/mplus-1m-regular-webfont.svg @@ -0,0 +1,134 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Foundry URL : http://mplus-fonts.sourceforge.jp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bin/jsdoc/templates/css/fonts/mplus-1m-regular-webfont.ttf b/bin/jsdoc/templates/css/fonts/mplus-1m-regular-webfont.ttf new file mode 100755 index 00000000..684abfd1 Binary files /dev/null and b/bin/jsdoc/templates/css/fonts/mplus-1m-regular-webfont.ttf differ diff --git a/bin/jsdoc/templates/css/fonts/mplus-1m-regular-webfont.woff b/bin/jsdoc/templates/css/fonts/mplus-1m-regular-webfont.woff new file mode 100755 index 00000000..49585d82 Binary files /dev/null and b/bin/jsdoc/templates/css/fonts/mplus-1m-regular-webfont.woff differ diff --git a/bin/jsdoc/templates/css/handheld.css b/bin/jsdoc/templates/css/handheld.css new file mode 100755 index 00000000..073c0d1d --- /dev/null +++ b/bin/jsdoc/templates/css/handheld.css @@ -0,0 +1,217 @@ +/* + * TABLE OF CONTENTS: + * - Browser reset + * - HTML elements + * - JsDoc styling + * - Media query check + */ + + + + + + +/* + * HTML ELEMENTS + */ + +body { + padding: 1% 4% 1% 4%; +} + +/* + * HTML ELEMENTS + */ + + + + + +/* + * BEGIN JSDOC + */ + +/* Start menu */ +div.index div.menu { + position: fixed; + top: 0; + right: 0; + -moz-border-radius-bottomleft: 15px; + -webkit-border-bottom-left-radius: 15px; + -border-bottom-left-radius: 15px; + padding: 4px 5px 8px 10px; + -moz-box-shadow: 0px 0px 10px #c4c4c4; + -webkit-box-shadow: 0px 0px 10px #c4c4c4; + box-shadow: 0px 0px 10px #c4c4c4; + background-color: rgba(255, 255, 255, 0.9); +} + +div.index input.classFilter { + display: none; +} + +div.index div.indexLinks a { + float: right; + clear: both; + font-size: 1.1em; +} + +div.index *.heading1 { + display:none; +} + +div.index ul.classList { + display:none; +} + +div.index div.fineprint { + display:none; +} + +div.indexStatic { + display: none; +} +/* End menu */ + + + +/* Start content */ +div.content *.classTitle { + margin-right: 60px; + margin-bottom: 15px; +} + +div.content div.intro { + margin: 15px 0 35px; +} + +div.content p.description.summary { + margin-bottom: 0.2em; +} + +div.content div.props { + margin: 1.5em -2% 0 -2%; + padding: 2%; +} + +table.summaryTable { + position: relative; + left: -10px; + width: 100%; + border-collapse: collapse; + box-sizing: content-box; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + -ms-box-sizing: content-box; + -o-box-sizing: content-box; + -icab-box-sizing: content-box; + -khtml-box-sizing: content-box; +} + +*.sectionTitle { + padding: 0 10px 10px 0; +} +caption.sectionTitle { + padding-left: 10px; +} + +table.summaryTable td, +table.summaryTable th { + padding: 0px 10px 10px 10px; +} +table.summaryTable tr:last-child td { + padding-bottom: 0; +} + +table.summaryTable td.attributes { + width: 35%; +} + +table.summaryTable td.nameDescription { + width: 65% +} + + + +dl.detailList { + margin-top: 0.5em; +} + +dl.detailList.nomargin + dl.detailList.nomargin { + margin-top: 0; +} + +dl.detailList dt { + display: inline; + margin-right: 5px; +} + +dl.detailList dt:before { + display: block; + content: ""; +} + +dl.detailList dd { + display: inline; +} + +dl.detailList.params dt { + display: block; +} +dl.detailList.params dd { + display: block; + padding-left: 2em; + padding-bottom: 0.4em; +} + + + + +ul.fileList li { + margin-bottom: 1.5em; +} + + + +.fixedFont.heading { + margin-bottom: 0.5em; +} + +pre.code { + margin: 10px 0 10px 0; + padding: 10px; + border: 1px solid #ccc; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; +} +/* End content */ + +/* + * END JSDOC + */ + + + + + + + +/* + * START MEDIA QUERY CHECK + */ + +.cssLoadCheck { + position: absolute; + top: -99999px; + left: -99999px; + border: 0; + width: 100px; + padding: 0; + overflow: hidden; +} + +/* + * END MEDIA QUERY CHECK + */ + diff --git a/bin/jsdoc/templates/css/screen.css b/bin/jsdoc/templates/css/screen.css new file mode 100755 index 00000000..8cb4bba3 --- /dev/null +++ b/bin/jsdoc/templates/css/screen.css @@ -0,0 +1,297 @@ +/* + * TABLE OF CONTENTS: + * - JsDoc styling + * - Media query check + */ + + + + + + +/* + * BEGIN JSDOC + */ + +/* Start menu */ +div.index { + position: fixed; + top: 0; + bottom: 0; + float: left; + width: 30%; + min-width: 100px; + max-width: 300px; + padding: 0 0 10px 0; + overflow: auto; +} + +div.index *.heading1 { + padding: 8px 0 0 0; +} + +div.index div.menu { + margin: 0 15px 0 -15px; + -moz-border-radius-bottomright: 15px; + -webkit-border-bottom-right-radius: 15px; + -border-bottom-right-radius: 15px; + padding: 15px 15px 15px 30px; + -moz-box-shadow: 0px 0px 10px #c4c4c4; + -webkit-box-shadow: 0px 0px 10px #c4c4c4; + box-shadow: 0px 0px 10px #c4c4c4; + background-color: rgba(255, 255, 255, 0.5); +} + +div.index div.indexLinks { + margin-top: 13px; + position: absolute; + right: 30px; +} + +div.index div.indexLinks a { + color: #999999; + text-transform: lowercase; +} + +div.index div.indexLinks a:first-child { + margin-right: 3px; + border-right: 1px solid #999999; + padding-right: 5px; +} + +div.index input.classFilter { + margin-bottom: 4px; + width: 100%; + border-width: 1px; + border-style: solid; + border-color: #CCCCCC #999999 #999999 #CCCCCC; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + -border-radius: 3px; +} + +div.index ul.classList a { + line-height: 1.3em; +} + +div.index ul.classList a + a { + margin-left: 0.5em; +} + +div.index div.fineprint { + margin: 1em 0 0 15px; + color: #777; + font-size: 0.9em; +} + +div.index div.fineprint a { + color: #777; +} + +div.indexStatic { + position: static; + min-height: 1em; +} +/* End menu */ + + +/* Start content */ +div.content { + float: left; + width: 70%; + min-width: 300px; + max-width: 600px; +} +div.innerContent { + padding: 0 0 0 2.5em; +} + +div.content ul, +div.content ol { + margin-bottom: 3em; +} + +div.content ul.methodDetail { + margin-bottom: 0; +} + +div.content *.classTitle { + position: relative; + left: -10px; + margin: -30px 0 15px 0; + -moz-border-radius: 15px; + -webkit-border-radius: 15px; + border-radius: 15px; + padding: 25px 15px 15px 15px; + background-color: #FFFFFF; + background-color: rgba(255, 255, 255, 0.5); + -moz-box-shadow: 0px 0px 10px #c4c4c4; + -webkit-box-shadow: 0px 0px 10px #c4c4c4; + box-shadow: 0px 0px 10px #c4c4c4; +} + +div.content div.intro { + margin: 15px 0 45px +} + +div.content p.summary { + margin-bottom: 0.5em; +} + +div.content ul.summary { + margin-bottom: 1.5em; +} + +div.content ul *.classname a, +div.content ul *.filename a { + font-family: Consolas, "Courier New", Courier, monospace; + text-decoration: none; + font-weight: bold; +} +div.content ul *.classname a:hover, +div.content ul *.filename a:hover { + text-decoration: underline; +} + +div.content div.props { + position: relative; + left: -10px; + margin-bottom: 2.5em; + padding: 10px 15px 15px 15px; + overflow: hidden; +} + +div.content div.hr { + margin: 0 10px 0 0; + height: 4em; +} + + + +table.summaryTable { + position: relative; + left: -10px; + width: 100%; + border-collapse: collapse; + box-sizing: content-box; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + -ms-box-sizing: content-box; + -o-box-sizing: content-box; + -icab-box-sizing: content-box; + -khtml-box-sizing: content-box; +} + +*.sectionTitle { + padding: 0 10px 10px 0; +} +caption.sectionTitle { + padding-left: 10px; +} + +table.summaryTable td, +table.summaryTable th { + padding: 0px 10px 10px 10px; +} +table.summaryTable tr:last-child td { + padding-bottom: 0; +} + +table.summaryTable td.attributes { + width: 35%; +} + +table.summaryTable td.nameDescription { + width: 65% +} + + + +dl.detailList { + margin-top: 0.5em; +} + +dl.detailList.nomargin + dl.detailList.nomargin { + margin-top: 0; +} + +dl.detailList dt { + display: inline; + margin-right: 5px; +} + +dl.detailList dt:before { + display: block; + content: ""; +} + +dl.detailList dd { + display: inline; +} + +dl.detailList.params dt { + display: block; +} +dl.detailList.params dd { + display: block; + padding-left: 2em; + padding-bottom: 0.4em; +} + + + + +ul.fileList li { + margin-bottom: 1.5em; +} + + + +.fixedFont.heading { + margin-bottom: 0.5em; +} + +pre.code { + margin: 10px 0 10px 0; + padding: 10px; + border: 1px solid #ccc; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; +} +/* End content */ + +.clear { + clear: both; + width: 100%; + min-height: 0; +} + +/* + * END JSDOC + */ + + + + + + + +/* + * START MEDIA QUERY CHECK + */ + +.cssLoadCheck { + position: absolute; + top: -99999px; + left: -99999px; + border: 0; + width: 100px; + padding: 0; + overflow: hidden; +} + +/* + * END MEDIA QUERY CHECK + */ + diff --git a/bin/jsdoc/templates/javascript/all.js b/bin/jsdoc/templates/javascript/all.js new file mode 100755 index 00000000..5b6876af --- /dev/null +++ b/bin/jsdoc/templates/javascript/all.js @@ -0,0 +1,326 @@ +/** + * @fileOverview Contains standard code in the namespace 'wbos' and code specifically written for Codeview in the namespace 'codeview' + * @author Wouter Bos (www.thebrightlines.com) + * @since 1.0 - 2010-09-10 + * @version 1.0 - 2010-09-10 + */ + + + + + + +if (typeof(wbos) == "undefined") { + /** + * @namespace Standard code of Wouter Bos (wbos) + */ + wbos = {} +} +if (typeof(wbos.CssTools) == "undefined") { + /** + * @namespace Namespace for CSS-related functionality + */ + wbos.CssTools = {} +} + + + + +/** + * @namespace Fallback for CSS advanced media query + * @class + * @since 1.0 - 2010-09-10 + * @version 1.0 - 2010-09-10 + */ +wbos.CssTools.MediaQueryFallBack = ( function() { + var config = { + cssScreen: "/css/screen.css", + cssHandheld: "/css/handheld.css", + mobileMaxWidth: 660, + testDivClass: "cssLoadCheck", + dynamicCssLinkId: "DynCssLink", + resizeDelay: 30 + } + var noMediaQuery = false; + var delay; + var currentCssMediaType; + + // Adding events to elements in the DOM without overwriting it + function addEvent(element, newFunction, eventType) { + var oldEvent = eval("element." + eventType); + var eventContentType = eval("typeof element." + eventType) + + if ( eventContentType != 'function' ) { + eval("element." + eventType + " = newFunction") + } else { + eval("element." + eventType + " = function(e) { oldEvent(e); newFunction(e); }") + } + } + + // Get the the inner width of the browser window + function getWindowWidth() { + if (window.innerWidth) { + return window.innerWidth; + } else if (document.documentElement.clientWidth) { + return document.documentElement.clientWidth; + } else if (document.body.clientWidth) { + return document.body.clientWidth; + } else{ + return 0; + } + } + + function addCssLink(cssHref) { + var cssNode = document.createElement('link'); + var windowWidth; + cssNode.type = 'text/css'; + cssNode.rel = 'stylesheet'; + cssNode.media = 'screen, handheld, fallback'; + cssNode.href = cssHref; + document.getElementsByTagName("head")[0].appendChild(cssNode); + } + + + + /* Start public */ + return { + /** + * Adds link to CSS in the head if no CSS is loaded + * + * @since 1.0 - 2010-08-21 + * @version 1.0 - 2010-08-21 + * @param {String|Object} cssScreen URL to CSS file for larger screens + * @param {String|Object} cssHandheld URL to CSS file for smaller screens + * @param {Number} mobileMaxWidth Maximum width for handheld devices + * @example + * wbos.CssTools.MediaQueryFallBack.LoadCss(['screen.css', 'screen2.css'], 'mobile.css', 480) + */ + LoadCss: function(cssScreen, cssHandheld, mobileMaxWidth) { + // Set config values + if (typeof(cssScreen) != "undefined") { + config.cssScreen = cssScreen; + } + if (typeof(cssHandheld) != "undefined") { + config.cssHandheld = cssHandheld; + } + if (typeof(mobileMaxWidth) != "undefined") { + config.mobileMaxWidth = mobileMaxWidth; + } + + // Check if CSS is loaded + var cssloadCheckNode = document.createElement('div'); + cssloadCheckNode.className = config.testDivClass; + document.getElementsByTagName("body")[0].appendChild(cssloadCheckNode); + if (cssloadCheckNode.offsetWidth != 100 && noMediaQuery == false) { + noMediaQuery = true; + } + cssloadCheckNode.parentNode.removeChild(cssloadCheckNode) + + if (noMediaQuery == true) { + // Browser does not support Media Queries, so JavaScript will supply a fallback + var cssHref = ""; + + // Determines what CSS file to load + if (getWindowWidth() <= config.mobileMaxWidth) { + cssHref = config.cssHandheld; + newCssMediaType = "handheld"; + } else { + cssHref = config.cssScreen; + newCssMediaType = "screen"; + } + + // Add CSS link to of page + if (cssHref != "" && currentCssMediaType != newCssMediaType) { + var currentCssLinks = document.styleSheets + for (var i = 0; i < currentCssLinks.length; i++) { + for (var ii = 0; ii < currentCssLinks[i].media.length; ii++) { + if (typeof(currentCssLinks[i].media) == "object") { + if (currentCssLinks[i].media.item(ii) == "fallback") { + currentCssLinks[i].ownerNode.parentNode.removeChild(currentCssLinks[i].ownerNode) + i-- + break; + } + } else { + if (currentCssLinks[i].media.indexOf("fallback") >= 0) { + currentCssLinks[i].owningElement.parentNode.removeChild(currentCssLinks[i].owningElement) + i-- + break; + } + } + } + } + if (typeof(cssHref) == "object") { + for (var i = 0; i < cssHref.length; i++) { + addCssLink(cssHref[i]) + } + } else { + addCssLink(cssHref) + } + + currentCssMediaType = newCssMediaType; + } + + + // Check screen size again if user resizes window + addEvent(window, wbos.CssTools.MediaQueryFallBack.LoadCssDelayed, 'onresize') + } + }, + + /** + * Runs LoadCSS after a short delay + * + * @since 1.0 - 2010-08-21 + * @version 1.0 - 2010-08-21 + * @example + * wbos.CssTools.MediaQueryFallBack.LoadCssDelayed() + */ + LoadCssDelayed: function() { + clearTimeout(delay); + delay = setTimeout( "wbos.CssTools.MediaQueryFallBack.LoadCss()", config.resizeDelay) + } + + } + /* End public */ +})(); + + + + + + +/** + * @namespace Adds a function to an event of a single element. Use this if + * you don't want to use jQuery + * @class + * @since 1.0 - 2010-02-23 + * @version 1.0 - 2010-02-23 + */ +wbos.Events = ( function() { + /* Start public */ + return { + /** + * Adds a function to an event of a single element + * + * @since 1.0 - 2010-02-23 + * @version 1.0 - 2010-02-23 + * @param {Object} element The element on which the event is placed + * @param {Function} newFunction The function that has to be linked to the event + * @param {String} eventType Name of the event + * @example + * wbos.Events.AddEvent( document.getElementById('elementId'), functionName, "onclick" ) + */ + AddEvent: function( element, newFunction, eventType ) { + var oldEvent = eval("element." + eventType); + var eventContentType = eval("typeof element." + eventType) + + if ( eventContentType != 'function' ) { + eval("element." + eventType + " = newFunction") + } else { + eval("element." + eventType + " = function(e) { oldEvent(e); newFunction(e); }") + } + } + } + /* End public */ +})(); + + + + + + +if (typeof(codeview) == "undefined") { + /** + * @namespace Code written for the Codeview template + */ + codeview = {} +} + + + + + + + +/** + * @namespace Enables filtering in class lists + * @class + * @since 1.0 - 2010-11-08 + * @version 1.0 - 2010-11-08 + */ +codeview.classFilter = ( function() { + function onkeyup_ClassFilter() { + var listItems + var search = document.getElementById('ClassFilter').value + search = search.toLowerCase() + if (document.getElementById('ClassList')) { + listItems = document.getElementById('ClassList').getElementsByTagName('li') + filterList(listItems, search) + } + if (document.getElementById('ClassList2')) { + listItems = document.getElementById('ClassList2').getElementsByTagName('li') + filterList(listItems, search) + } + if (document.getElementById('FileList')) { + listItems = document.getElementById('FileList').getElementsByTagName('li') + filterList(listItems, search) + } + if (document.getElementById('MethodsListInherited')) { + var links = document.getElementById('MethodsListInherited').getElementsByTagName('a') + var linksSelected = new Array() + for (var i=0; i < links.length; i++) { + if (links[i].parentNode.parentNode.tagName == "DD") { + linksSelected.push(links[i]) + } + } + filterList(linksSelected, search) + } + if (document.getElementById('MethodsList')) { + listItems = document.getElementById('MethodsList').getElementsByTagName('tbody')[0].getElementsByTagName('tr') + filterList(listItems, search, document.getElementById('MethodDetail').getElementsByTagName('li')) + } + } + + function filterList(listItems, search, relatedElements) { + var itemContent = "" + for (var i=0; i < listItems.length; i++) { + itemContent = listItems[i].textContent||listItems[i].innerText + if (itemContent != undefined) { + itemContent = itemContent.toLowerCase() + itemContent = itemContent.replace(/\s/g, "") + if (itemContent.indexOf(search) >= 0 || itemContent == "") { + listItems[i].style.display = "" + } else { + listItems[i].style.display = "none" + } + if (relatedElements != null) { + filterRelatedList(listItems[i], search, relatedElements) + } + } + } + } + + function filterRelatedList(listItem, search, relatedElements) { + var itemIndex = parseInt(listItem.className.replace('item', '')) + if (itemIndex <= relatedElements.length) { + if (relatedElements[itemIndex].className == "item"+ itemIndex) { + relatedElements[itemIndex].style.display = listItem.style.display + } + } + } + + + + + + /* Start public */ + return { + Init: function() { + wbos.Events.AddEvent( + document.getElementById('ClassFilter'), + onkeyup_ClassFilter, + "onkeyup" + ) + } + } + /* End public */ +})(); diff --git a/bin/jsdoc/templates/javascript/html5.js b/bin/jsdoc/templates/javascript/html5.js new file mode 100755 index 00000000..3587bf73 --- /dev/null +++ b/bin/jsdoc/templates/javascript/html5.js @@ -0,0 +1,6 @@ +// html5shiv MIT @rem remysharp.com/html5-enabling-script +// iepp v1.6.2 MIT @jon_neal iecss.com/print-protector +/*@cc_on(function(m,c){var z="abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video";function n(d){for(var a=-1;++ai";if(g.childNodes.length!==1){var i=z.split("|"),o=i.length,s=RegExp("(^|\\s)("+z+")", +"gi"),t=RegExp("<(/*)("+z+")","gi"),u=RegExp("(^|[^\\n]*?\\s)("+z+")([^\\n]*)({[\\n\\w\\W]*?})","gi"),r=c.createDocumentFragment(),k=c.documentElement;g=k.firstChild;var h=c.createElement("body"),l=c.createElement("style"),f;n(c);n(r);g.insertBefore(l, +g.firstChild);l.media="print";m.attachEvent("onbeforeprint",function(){var d=-1,a=p(c.styleSheets,"all"),e=[],b;for(f=f||c.body;(b=u.exec(a))!=null;)e.push((b[1]+b[2]+b[3]).replace(s,"$1.iepp_$2")+b[4]);for(l.styleSheet.cssText=e.join("\n");++d 1)? + lcAlias+"_"+filemapCounts[lcAlias] : lcAlias; + } + } + + // create each of the class pages + for (var i = 0, l = publish.classes.length; i < l; i++) { + var symbol = publish.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+publish.conf.symbolsDir, ((JSDOC.opt.u)? Link.filemap[symbol.alias] : symbol.alias) + publish.conf.ext, output); + } + + // create the class index page + try { + var classesindexTemplate = new JSDOC.JsPlate(publish.conf.templatesDir+"allclasses.tmpl"); + } + catch(e) { print(e.message); quit(); } + + var classesIndex = classesindexTemplate.process(publish.classes); + IO.saveFile(publish.conf.outDir, (JSDOC.opt.D.index=="files"?"allclasses":"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, (JSDOC.opt.D.index=="files"?"index":"files")+publish.conf.ext, filesIndex); + fileindexTemplate = filesIndex = files = null; + + // copy static files + IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.cssDir+"all.css", publish.conf.outDir+"/"+publish.conf.cssDir); + IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.cssDir+"screen.css", publish.conf.outDir+"/"+publish.conf.cssDir); + IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.cssDir+"handheld.css", publish.conf.outDir+"/"+publish.conf.cssDir); + IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.jsDir+"all.js", publish.conf.outDir+"/"+publish.conf.jsDir); + IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.jsDir+"html5.js", publish.conf.outDir+"/"+publish.conf.jsDir); + IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.fontsDir+"mplus-1m-regular-webfont.eot", publish.conf.outDir+"/"+publish.conf.fontsDir); + IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.fontsDir+"mplus-1m-regular-webfont.svg", publish.conf.outDir+"/"+publish.conf.fontsDir); + IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.fontsDir+"mplus-1m-regular-webfont.ttf", publish.conf.outDir+"/"+publish.conf.fontsDir); + IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.fontsDir+"mplus-1m-regular-webfont.woff", publish.conf.outDir+"/"+publish.conf.fontsDir); + IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.fontsDir+"mplus-1m-bold-webfont.eot", publish.conf.outDir+"/"+publish.conf.fontsDir); + IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.fontsDir+"mplus-1m-bold-webfont.svg", publish.conf.outDir+"/"+publish.conf.fontsDir); + IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.fontsDir+"mplus-1m-bold-webfont.ttf", publish.conf.outDir+"/"+publish.conf.fontsDir); + IO.copyFile(publish.conf.templatesDir+"/"+publish.conf.fontsDir+"mplus-1m-bold-webfont.woff", publish.conf.outDir+"/"+publish.conf.fontsDir); } + +/** Include a sub-template in the current template, specifying a data object */ +function subtemplate(template, data) { + try { + return new JSDOC.JsPlate(publish.conf.templatesDir+template).process(data); + } + catch(e) { print(e.message); quit(); } +} + +/** 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; + } + } +} + +function wordwrapNamespace(classLink) { + var classText = classLink.match(/[^<>]+(?=[<])/) + ""; + var classTextNew = classText.replace(/\./g, " . ") + ""; + classLink = classLink.replace(/[^<>]+(?=[<])/, classTextNew); + return classLink; +} + +/** 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) { + symbolName = symbolName.trim(); + var index = symbolName.indexOf(' '); + if (index > 0) { + var label = symbolName.substring(index + 1); + symbolName = symbolName.substring(0, index); + return new Link().toSymbol(symbolName).withText(label); + } else { + return new Link().toSymbol(symbolName); + } + } + ); + return str; +} \ No newline at end of file diff --git a/bin/jsdoc/templates/subtemplates/foot.tmpl b/bin/jsdoc/templates/subtemplates/foot.tmpl new file mode 100755 index 00000000..27bc13f0 --- /dev/null +++ b/bin/jsdoc/templates/subtemplates/foot.tmpl @@ -0,0 +1,6 @@ + + + diff --git a/bin/jsdoc/templates/subtemplates/head.tmpl b/bin/jsdoc/templates/subtemplates/head.tmpl new file mode 100755 index 00000000..d823e78f --- /dev/null +++ b/bin/jsdoc/templates/subtemplates/head.tmpl @@ -0,0 +1,22 @@ + + + + + + {+data.subtitle+} | <if test="JSDOC.opt.D.title">{+JSDOC.opt.D.title+}<else />JsDoc Reference</if> + + + + + + + + + + + + + + diff --git a/bin/jsdoc/templates/subtemplates/menu.tmpl b/bin/jsdoc/templates/subtemplates/menu.tmpl new file mode 100755 index 00000000..add1ddd6 --- /dev/null +++ b/bin/jsdoc/templates/subtemplates/menu.tmpl @@ -0,0 +1,43 @@ +
+ +
+
+ ©{+JSDOC.opt.D.copyright+}
+ Documentation generator: JsDoc Toolkit {+JSDOC.VERSION+}
+ Template: {+publish.conf.templateName+} {+publish.conf.templateVersion+}
+ Generated on: + {! + var date = new Date(); + var minutes = date.getMinutes() +""; + if (minutes.length == 1) { + minutes = '0'+ minutes; + } + var timeHuman = date.getFullYear() + "-" + date.getMonth() + "-" + date.getDate() + " " + date.getHours() + ":" + minutes; + var timeData = date.getFullYear() + "-" + date.getMonth() + "-" + date.getDate(); + output += ""; + !} +
+
+
+ +
diff --git a/bin/jsdoc/test.js b/bin/jsdoc/test.js new file mode 100644 index 00000000..8b2dc8b1 --- /dev/null +++ b/bin/jsdoc/test.js @@ -0,0 +1,342 @@ +load("app/frame/Dumper.js"); +function symbolize(opt) { + symbols = null; + JSDOC.JsDoc(opt); + symbols = JSDOC.JsDoc.symbolSet; +} + +var testCases = [ + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/overview.js"]}); + //print(Dumper.dump(symbols)); + is('symbols.getSymbolByName("My Cool Library").name', 'My Cool Library', 'File overview can be found by alias.'); + } + , + function() { + symbolize({_: [SYS.pwd+"test/name.js"]}); + + is('symbols.getSymbol("Response").name', "Response", 'Virtual class name is found.'); + is('symbols.getSymbol("Response#text").alias', "Response#text", 'Virtual method name is found.'); + is('symbols.getSymbol("Response#text").memberOf', "Response", 'Virtual method parent name is found.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/prototype.js"]}); + + is('symbols.getSymbol("Article").name', "Article", 'Function set to constructor prototype with inner constructor name is found.'); + is('symbols.getSymbol("Article").hasMethod("init")', true, 'The initializer method name of prototype function is correct.'); + is('symbols.getSymbol("Article").hasMember("counter")', true, 'A static property set in the prototype definition is found.'); + is('symbols.getSymbol("Article").hasMember("title")', true, 'An instance property set in the prototype is found.'); + is('symbols.getSymbol("Article#title").isStatic', false, 'An instance property has isStatic set to false.'); + is('symbols.getSymbol("Article.counter").name', "counter", 'A static property set in the initializer has the name set correctly.'); + is('symbols.getSymbol("Article.counter").memberOf', "Article", 'A static property set in the initializer has the memberOf set correctly.'); + is('symbols.getSymbol("Article.counter").isStatic', true, 'A static property set in the initializer has isStatic set to true.'); + } + , + function() { + symbolize({a:true, _: [SYS.pwd+"test/prototype_oblit.js"]}); + + is('symbols.getSymbol("Article").name', "Article", 'Oblit set to constructor prototype name is found.'); + is('typeof symbols.getSymbol("Article.prototype")', "undefined", 'The prototype oblit is not a symbol.'); + is('symbols.getSymbol("Article#getTitle").name', "getTitle", 'The nonstatic method name of prototype oblit is correct.'); + is('symbols.getSymbol("Article#getTitle").alias', "Article#getTitle", 'The alias of non-static method of prototype oblit is correct.'); + is('symbols.getSymbol("Article#getTitle").isStatic', false, 'The isStatic of a nonstatic method of prototype oblit is correct.'); + is('symbols.getSymbol("Article.getTitle").name', "getTitle", 'The static method name of prototype oblit is correct.'); + is('symbols.getSymbol("Article.getTitle").isStatic', true, 'The isStatic of a static method of prototype oblit is correct.'); + is('symbols.getSymbol("Article#getTitle").isa', "FUNCTION", 'The isa of non-static method of prototype oblit is correct.'); + is('symbols.getSymbol("Article.getTitle").alias', "Article.getTitle", 'The alias of a static method of prototype oblit is correct.'); + is('symbols.getSymbol("Article.getTitle").isa', "FUNCTION", 'The isa of static method of prototype oblit is correct.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/prototype_oblit_constructor.js"]}); + + is('symbols.getSymbol("Article").name', "Article", 'Oblit set to constructor prototype with inner constructor name is found.'); + is('symbols.getSymbol("Article#init").name', "init", 'The initializer method name of prototype oblit is correct.'); + is('symbols.getSymbol("Article").hasMember("pages")', true, 'Property set by initializer method "this" is on the outer constructor.'); + is('symbols.getSymbol("Article#Title").name', "Title", 'Name of the inner constructor name is found.'); + is('symbols.getSymbol("Article#Title").memberOf', "Article", 'The memberOf of the inner constructor name is found.'); + is('symbols.getSymbol("Article#Title").isa', "CONSTRUCTOR", 'The isa of the inner constructor name is constructor.'); + is('symbols.getSymbol("Article#Title").hasMember("title")', true, 'A property set on the inner constructor "this" is on the inner constructor.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/inner.js"]}); + + is('symbols.getSymbol("Outer").name', "Outer", 'Outer constructor prototype name is found.'); + is('symbols.getSymbol("Outer").methods.length', 1, 'Inner function doesnt appear as a method of the outer.'); + is('symbols.getSymbol("Outer").hasMethod("open")', true, 'Outer constructors methods arent affected by inner function.'); + is('symbols.getSymbol("Outer-Inner").alias', "Outer-Inner", 'Alias of inner function is found.'); + is('symbols.getSymbol("Outer-Inner").isa', "CONSTRUCTOR", 'isa of inner function constructor is found.'); + is('symbols.getSymbol("Outer-Inner").memberOf', "Outer", 'The memberOf of inner function is found.'); + is('symbols.getSymbol("Outer-Inner").name', "Inner", 'The name of inner function is found.'); + is('symbols.getSymbol("Outer-Inner#name").name', "name", 'A member of the inner function constructor, attached to "this" is found on inner.'); + is('symbols.getSymbol("Outer-Inner#name").memberOf', "Outer-Inner", 'The memberOf of an inner function member is found.'); + } + , + function() { + symbolize({a:true, _: [SYS.pwd+"test/prototype_nested.js"]}); + + is('symbols.getSymbol("Word").name', "Word", 'Base constructor name is found.'); + is('symbols.getSymbol("Word").hasMethod("reverse")', true, 'Base constructor method is found.'); + is('symbols.getSymbol("Word").methods.length', 1, 'Base constructor has only one method.'); + is('symbols.getSymbol("Word").memberOf', "", 'Base constructor memberOf is empty.'); + is('symbols.getSymbol("Word#reverse").name', "reverse", 'Member of constructor prototype name is found.'); + is('symbols.getSymbol("Word#reverse").memberOf', "Word", 'Member of constructor prototype memberOf is found.'); + is('symbols.getSymbol("Word#reverse.utf8").name', "utf8", 'Member of constructor prototype method name is found.'); + is('symbols.getSymbol("Word#reverse.utf8").memberOf', "Word#reverse", 'Static nested member memberOf is found.'); + } + , + function() { + symbolize({a:true, _: [SYS.pwd+"test/namespace_nested.js"]}); + + is('symbols.getSymbol("ns1").name', "ns1", 'Base namespace name is found.'); + is('symbols.getSymbol("ns1").memberOf', "", 'Base namespace memberOf is empty (its a constructor).'); + is('symbols.getSymbol("ns1.ns2").name', "ns2", 'Nested namespace name is found.'); + is('symbols.getSymbol("ns1.ns2").alias', "ns1.ns2", 'Nested namespace alias is found.'); + is('symbols.getSymbol("ns1.ns2").memberOf', "ns1", 'Nested namespace memberOf is found.'); + is('symbols.getSymbol("ns1.ns2.Function1").name', "Function1", 'Method of nested namespace name is found.'); + is('symbols.getSymbol("ns1.ns2.Function1").memberOf', "ns1.ns2", 'Constructor of nested namespace memberOf is found.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/functions_nested.js"]}); + + is('symbols.getSymbol("Zop").name', "Zop", 'Any constructor name is found.'); + is('symbols.getSymbol("Zop").isa', "CONSTRUCTOR", 'It isa constructor.'); + is('symbols.getSymbol("Zop").hasMethod("zap")', true, 'Its method name, set later, is in methods array.'); + is('symbols.getSymbol("Foo").name', "Foo", 'The containing constructor name is found.'); + is('symbols.getSymbol("Foo").hasMethod("methodOne")', true, 'Its method name is found.'); + is('symbols.getSymbol("Foo").hasMethod("methodTwo")', true, 'Its second method name is found.'); + is('symbols.getSymbol("Foo#methodOne").alias', "Foo#methodOne", 'A methods alias is found.'); + is('symbols.getSymbol("Foo#methodOne").isStatic', false, 'A methods is not static.'); + is('symbols.getSymbol("Bar").name', "Bar", 'A global function declared inside another function is found.'); + is('symbols.getSymbol("Bar").isa', "FUNCTION", 'It isa function.'); + is('symbols.getSymbol("Bar").memberOf', "_global_", 'It is global.'); + is('symbols.getSymbol("Foo-inner").name', "inner", 'An inner functions name is found.'); + is('symbols.getSymbol("Foo-inner").memberOf', "Foo", 'It is member of the outer function.'); + is('symbols.getSymbol("Foo-inner").isInner', true, 'It is an inner function.'); + } + , + function() { + symbolize({a:true, _: [SYS.pwd+"test/memberof_constructor.js"]}); + + is('symbols.getSymbol("Circle#Tangent").name', "Tangent", 'Constructor set on prototype using @member has correct name.'); + is('symbols.getSymbol("Circle#Tangent").memberOf', "Circle", 'Constructor set on prototype using @member has correct memberOf.'); + is('symbols.getSymbol("Circle#Tangent").alias', "Circle#Tangent", 'Constructor set on prototype using @member has correct alias.'); + is('symbols.getSymbol("Circle#Tangent").isa', "CONSTRUCTOR", 'Constructor set on prototype using @member has correct isa.'); + is('symbols.getSymbol("Circle#Tangent").isStatic', false, 'Constructor set on prototype using @member is not static.'); + is('symbols.getSymbol("Circle#Tangent#getDiameter").name', "getDiameter", 'Method set on prototype using @member has correct name.'); + is('symbols.getSymbol("Circle#Tangent#getDiameter").memberOf', "Circle#Tangent", 'Method set on prototype using @member has correct memberOf.'); + is('symbols.getSymbol("Circle#Tangent#getDiameter").alias', "Circle#Tangent#getDiameter", 'Method set on prototype using @member has correct alias.'); + is('symbols.getSymbol("Circle#Tangent#getDiameter").isa', "FUNCTION", 'Method set on prototype using @member has correct isa.'); + is('symbols.getSymbol("Circle#Tangent#getDiameter").isStatic', false, 'Method set on prototype using @member is not static.'); + } + , + function() { + symbolize({a:true, p: true, _: [SYS.pwd+"test/memberof.js"]}); + + is('symbols.getSymbol("pack.install").alias', "pack.install", 'Using @memberOf sets alias, when parent name is in memberOf tag.'); + is('symbols.getSymbol("pack.install.overwrite").name', "install.overwrite", 'Using @memberOf sets name, even if the name is dotted.'); + is('symbols.getSymbol("pack.install.overwrite").memberOf', "pack", 'Using @memberOf sets memberOf.'); + is('symbols.getSymbol("pack.install.overwrite").isStatic', true, 'Using @memberOf with value not ending in octothorp sets isStatic to true.'); + } + , + function() { + symbolize({a:true, p: true, _: [SYS.pwd+"test/memberof2.js"]}); + + is('symbols.getSymbol("Foo#bar").alias', "Foo#bar", 'An inner function can be documented as an instance method.'); + is('symbols.getSymbol("Foo.zip").alias', "Foo.zip", 'An inner function can be documented as a static method.'); + is('symbols.getSymbol("Foo.Fiz").alias', "Foo.Fiz", 'An inner function can be documented as a static constructor.'); + is('symbols.getSymbol("Foo.Fiz#fipple").alias', "Foo.Fiz#fipple", 'An inner function can be documented as a static constructor with a method.'); + is('symbols.getSymbol("Foo#blat").alias', "Foo#blat", 'An global function can be documented as an instance method.'); + } + , + function() { + symbolize({a:true, p: true, _: [SYS.pwd+"test/memberof3.js"]}); + + is('symbols.getSymbol("Foo#bar").alias', "Foo#bar", 'A virtual field can be documented as an instance method.'); + is('symbols.getSymbol("Foo2#bar").alias', "Foo2#bar", 'A virtual field with the same name can be documented as an instance method.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/borrows.js"]}); + + is('symbols.getSymbol("Layout").name', "Layout", 'Constructor can be found.'); + is('symbols.getSymbol("Layout").hasMethod("init")', true, 'Constructor method name can be found.'); + is('symbols.getSymbol("Layout").hasMember("orientation")', true, 'Constructor property name can be found.'); + + is('symbols.getSymbol("Page").hasMethod("reset")', true, 'Second constructor method name can be found.'); + is('symbols.getSymbol("Page").hasMember("orientation")', true, 'Second constructor borrowed property name can be found in properties.'); + is('symbols.getSymbol("Page#orientation").memberOf', "Page", 'Second constructor borrowed property memberOf can be found.'); + is('symbols.getSymbol("Page-getInnerElements").alias', "Page-getInnerElements", 'Can borrow an inner function and it is still inner.'); + is('symbols.getSymbol("Page.units").alias', "Page.units", 'Can borrow a static function and it is still static.'); + + is('symbols.getSymbol("ThreeColumnPage#init").alias', "ThreeColumnPage#init", 'Third constructor method can be found even though method with same name is borrowed.'); + is('symbols.getSymbol("ThreeColumnPage#reset").alias', "ThreeColumnPage#reset", 'Borrowed method can be found.'); + is('symbols.getSymbol("ThreeColumnPage#orientation").alias', "ThreeColumnPage#orientation", 'Twice borrowed method can be found.'); + + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/borrows2.js"]}); + + is('symbols.getSymbol("Foo").hasMethod("my_zop")', true, 'Borrowed method can be found.'); + is('symbols.getSymbol("Bar").hasMethod("my_zip")', true, 'Second borrowed method can be found.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/constructs.js"]}); + + is('symbols.getSymbol("Person").hasMethod("say")', true, 'The constructs tag creates a class that lends can add a method to.'); + } + , + function() { + symbolize({a: true, _: [SYS.pwd+"test/augments.js", SYS.pwd+"test/augments2.js"]}); + + is('symbols.getSymbol("Page").augments[0]', "Layout", 'An augmented class can be found.'); + is('symbols.getSymbol("Page#reset").alias', "Page#reset", 'Method of augmenter can be found.'); + is('symbols.getSymbol("Page").hasMethod("Layout#init")', true, 'Method from augmented can be found.'); + is('symbols.getSymbol("Page").hasMember("Layout#orientation")', true, 'Property from augmented can be found.'); + is('symbols.getSymbol("Page").methods.length', 3, 'Methods of augmented class are included in methods array.'); + + is('symbols.getSymbol("ThreeColumnPage").augments[0]', "Page", 'The extends tag is a synonym for augments.'); + is('symbols.getSymbol("ThreeColumnPage").hasMethod("ThreeColumnPage#init")', true, 'Local method overrides augmented method of same name.'); + is('symbols.getSymbol("ThreeColumnPage").methods.length', 3, 'Local method count is right.'); + + is('symbols.getSymbol("NewsletterPage").augments[0]', "ThreeColumnPage", 'Can augment across file boundaries.'); + is('symbols.getSymbol("NewsletterPage").augments.length', 2, 'Multiple augments are supported.'); + is('symbols.getSymbol("NewsletterPage").inherits[0].alias', "Junkmail#annoy", 'Inherited method with augments.'); + is('symbols.getSymbol("NewsletterPage").methods.length', 6, 'Methods of augmented class are included in methods array across files.'); + is('symbols.getSymbol("NewsletterPage").properties.length', 1, 'Properties of augmented class are included in properties array across files.'); + } + , + function() { + symbolize({a:true, _: [SYS.pwd+"test/static_this.js"]}); + + is('symbols.getSymbol("box.holder").name', "holder", 'Static namespace name can be found.'); + is('symbols.getSymbol("box.holder.foo").name', "foo", 'Static namespace method name can be found.'); + is('symbols.getSymbol("box.holder").isStatic', true, 'Static namespace method is static.'); + + is('symbols.getSymbol("box.holder.counter").name', "counter", 'Instance namespace property name set on "this" can be found.'); + is('symbols.getSymbol("box.holder.counter").alias', "box.holder.counter", 'Instance namespace property alias set on "this" can be found.'); + is('symbols.getSymbol("box.holder.counter").memberOf', "box.holder", 'Static namespace property memberOf set on "this" can be found.'); + } + , + function() { + symbolize({a:true, p: true, _: [SYS.pwd+"test/lend.js"]}); + + is('symbols.getSymbol("Person").name', "Person", 'Class defined in lend comment is found.'); + is('symbols.getSymbol("Person").hasMethod("initialize")', true, 'Lent instance method name can be found.'); + is('symbols.getSymbol("Person").hasMethod("say")', true, 'Second instance method can be found.'); + is('symbols.getSymbol("Person#sing").isStatic', false, 'Instance method is known to be not static.'); + + is('symbols.getSymbol("Person.getCount").name', "getCount", 'Static method name from second lend comment can be found.'); + is('symbols.getSymbol("Person.getCount").isStatic', true, 'Static method from second lend comment is known to be static.'); + + is('LOG.warnings.filter(function($){if($.indexOf("notok") > -1) return $}).length', 1, 'A warning is emitted when lending to an undocumented parent.'); + } + , + function() { + symbolize({a:true, _: [SYS.pwd+"test/param_inline.js"]}); + + is('symbols.getSymbol("Layout").params[0].type', "int", 'Inline param name is set.'); + is('symbols.getSymbol("Layout").params[0].desc', "The number of columns.", 'Inline param desc is set from comment.'); + is('symbols.getSymbol("Layout#getElement").params[0].name', "id", 'User defined param documentation takes precedence over parser defined.'); + is('symbols.getSymbol("Layout#getElement").params[0].isOptional', true, 'Default for param is to not be optional.'); + is('symbols.getSymbol("Layout#getElement").params[1].isOptional', false, 'Can mark a param as being optional.'); + is('symbols.getSymbol("Layout#getElement").params[1].type', "number|string", 'Type of inline param doc can have multiple values.'); + is('symbols.getSymbol("Layout#Canvas").params[0].type', "", 'Type can be not defined for some params.'); + is('symbols.getSymbol("Layout#Canvas").params[2].type', "int", 'Type can be defined inline for only some params.'); + is('symbols.getSymbol("Layout#rotate").params.length', 0, 'Docomments inside function sig is ignored without a param.'); + is('symbols.getSymbol("Layout#init").params[2].type', "zoppler", 'Doc comment type overrides inline type for param with same name.'); + } + , + function() { + symbolize({a: true, _: [SYS.pwd+"test/shared.js", SYS.pwd+"test/shared2.js"]}); + + is('symbols.getSymbol("Array#some").name', 'some', 'The name of a symbol in a shared section is found.'); + is('symbols.getSymbol("Array#some").alias', 'Array#some', 'The alias of a symbol in a shared section is found.'); + is('symbols.getSymbol("Array#some").desc', "Extension to builtin array.", 'A description can be shared.'); + is('symbols.getSymbol("Array#filter").desc', "Extension to builtin array.\nChange every element of an array.", 'A shared description is appended.'); + is('symbols.getSymbol("Queue").desc', "A first in, first out data structure.", 'A description is not shared when outside a shared section.'); + is('symbols.getSymbol("Queue.rewind").alias', "Queue.rewind", 'Second shared tag can be started.'); + is('symbols.getSymbol("startOver").alias', "startOver", 'Shared tag doesnt cross over files.'); + } + , + function() { + symbolize({a: true, _: [SYS.pwd+"test/config.js"]}); + is('symbols.getSymbol("Contact").params[0].name', 'person', 'The name of a param is found.'); + is('symbols.getSymbol("Contact").params[1].name', 'person.name', 'The name of a param set with a dot name is found.'); + is('symbols.getSymbol("Contact").params[2].name', 'person.age', 'The name of a second param set with a dot name is found.'); + is('symbols.getSymbol("Contact").params[4].name', 'connection', 'The name of a param after config is found.'); + + is('symbols.getSymbol("Family").params[0].name', 'persons', 'Another name of a param is found.'); + is('symbols.getSymbol("Family").params[1].name', 'persons.Father', 'The name of a param+config is found.'); + is('symbols.getSymbol("Family").params[2].name', 'persons.Mother', 'The name of a second param+config is found.'); + is('symbols.getSymbol("Family").params[3].name', 'persons.Children', 'The name of a third param+config is found.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/ignore.js"]}); + is('LOG.warnings.filter(function($){if($.indexOf("undocumented symbol Ignored") > -1) return $}).length', 1, 'A warning is emitted when documenting members of an ignored parent.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/functions_anon.js"]}); + is('symbols.getSymbol("a.b").alias', 'a.b', 'In anonymous constructor this is found to be the container object.'); + is('symbols.getSymbol("a.f").alias', 'a.f', 'In anonymous constructor this can have a method.'); + is('symbols.getSymbol("a.c").alias', 'a.c', 'In anonymous constructor method this is found to be the container object.'); + is('symbols.getSymbol("g").alias', 'g', 'In anonymous function executed inline this is the global.'); + is('symbols.getSymbol("bar2.p").alias', 'bar2.p', 'In named constructor executed inline this is the container object.'); + is('symbols.getSymbol("module.pub").alias', 'module.pub', 'In parenthesized anonymous function executed inline function scoped variables arent documented.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/oblit_anon.js"]}); + is('symbols.getSymbol("opt").name', 'opt', 'Anonymous object properties are created.'); + is('symbols.getSymbol("opt.conf.keep").alias', 'opt.conf.keep', 'Anonymous object first property is assigned to $anonymous.'); + is('symbols.getSymbol("opt.conf.base").alias', 'opt.conf.base', 'Anonymous object second property is assigned to $anonymous.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/params_optional.js"]}); + is('symbols.getSymbol("Document").params.length', 3, 'Correct number of params are found when optional param syntax is used.'); + is('symbols.getSymbol("Document").params[1].name', "id", 'Name of optional param is found.'); + is('symbols.getSymbol("Document").params[1].isOptional', true, 'Optional param is marked isOptional.'); + is('symbols.getSymbol("Document").params[2].name', "title", 'Name of optional param with default value is found.'); + is('symbols.getSymbol("Document").params[2].isOptional', true, 'Optional param with default value is marked isOptional.'); + is('symbols.getSymbol("Document").params[2].defaultValue', " This is untitled.", 'Optional param default value is found.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/synonyms.js"]}); + is('symbols.getSymbol("myObject.myFunc").type', 'function', 'Type can be set to function.'); + } + , + function() { + symbolize({a:true, p:true, _: [SYS.pwd+"test/event.js"]}); + is('symbols.getSymbol("Kitchen#event:cakeEaten").isEvent', true, 'Function with event prefix is an event.'); + is('symbols.getSymbol("Kitchen#cakeEaten").isa', "FUNCTION", 'Function with same name as event isa function.'); + } + , + function() { + symbolize({x:"js", a:true, _: [SYS.pwd+"test/scripts/"]}); + is('JSDOC.JsDoc.srcFiles.length', 1, 'Only js files are scanned when -x=js.'); + } + , + function() { + symbolize({x:"js", a:true, _: [SYS.pwd+"test/exports.js"]}); + is('symbols.getSymbol("mxn.Map#doThings").name', 'doThings', 'Exports creates a documentation alias that can have methods.'); + } + , + function() { + symbolize({p:true, a:true, _: [SYS.pwd+"test/module.js"]}); + is('symbols.getSymbol("myProject.myModule.myPublicMethod").name', 'myPublicMethod', 'A function wrapped in parens can be recognized.'); + is('symbols.getSymbol("myProject.myModule-myPrivateMethod").name', 'myPrivateMethod', 'A private method in the scope of a function wrapped in parens can be recognized.'); + is('symbols.getSymbol("myProject.myModule-myPrivateVar").name', 'myPrivateVar', 'A private member in the scope of a function wrapped in parens can be recognized.'); + } +]; + +//// run and print results +print(testrun(testCases)); diff --git a/bin/jsdoc/test/addon.js b/bin/jsdoc/test/addon.js new file mode 100644 index 00000000..88862053 --- /dev/null +++ b/bin/jsdoc/test/addon.js @@ -0,0 +1,24 @@ +String.prototype.reverse = function() { +} + +String.prototype.reverse.utf8 = function() { +} + +Function.count = function() { +} + +/** @memberOf Function */ +Function.count.reset = function() { +} + +/** @memberOf Function */ +count.getValue = function() { +} + +/** @memberOf Function.prototype */ +getSig = function() { +} + +/** @memberOf Function.prototype */ +Function.prototype.getProps = function() { +} diff --git a/bin/jsdoc/test/anon_inner.js b/bin/jsdoc/test/anon_inner.js new file mode 100644 index 00000000..227eeee5 --- /dev/null +++ b/bin/jsdoc/test/anon_inner.js @@ -0,0 +1,14 @@ +/** + * @name bar + * @namespace + */ + +new function() { + /** + * @name bar-foo + * @function + * @param {number} x + */ + function foo(x) { + } +} \ No newline at end of file diff --git a/bin/jsdoc/test/augments.js b/bin/jsdoc/test/augments.js new file mode 100644 index 00000000..12e706eb --- /dev/null +++ b/bin/jsdoc/test/augments.js @@ -0,0 +1,31 @@ +/** +@constructor +*/ +function Layout(p) { + this.init = function(p) { + } + + this.getId = function() { + } + + /** @type Page */ + this.orientation = "landscape"; +} + +/** +@constructor +@augments Layout +*/ +function Page() { + this.reset = function(b) { + } +} + +/** +@extends Page +@constructor +*/ +function ThreeColumnPage() { + this.init = function(resetCode) { + } +} diff --git a/bin/jsdoc/test/augments2.js b/bin/jsdoc/test/augments2.js new file mode 100644 index 00000000..e8388f0f --- /dev/null +++ b/bin/jsdoc/test/augments2.js @@ -0,0 +1,26 @@ +/** +@constructor +*/ +function LibraryItem() { + this.reserve = function() { + } +} + +/** +@constructor +*/ +function Junkmail() { + this.annoy = function() { + } +} + +/** +@inherits Junkmail.prototype.annoy as pester +@augments ThreeColumnPage +@augments LibraryItem +@constructor +*/ +function NewsletterPage() { + this.getHeadline = function() { + } +} diff --git a/bin/jsdoc/test/borrows.js b/bin/jsdoc/test/borrows.js new file mode 100644 index 00000000..a5d8ea4a --- /dev/null +++ b/bin/jsdoc/test/borrows.js @@ -0,0 +1,46 @@ +/** +@constructor +*/ +function Layout(p) { + /** initilize 1 */ + this.init = function(p) { + } + + /** get the id */ + this.getId = function() { + } + + /** @type string */ + this.orientation = "landscape"; + + function getInnerElements(elementSecretId){ + } +} + +/** A static method. */ +Layout.units = function() { +} + +/** +@constructor +@borrows Layout#orientation +@borrows Layout-getInnerElements +@borrows Layout.units +*/ +function Page() { + /** reset the page */ + this.reset = function(b) { + } +} + +/** +@constructor +@borrows Layout.prototype.orientation as this.orientation +@borrows Layout.prototype.init as #init +@inherits Page.prototype.reset as #reset +*/ +function ThreeColumnPage() { + /** initilize 2 */ + this.init = function(p) { + } +} diff --git a/bin/jsdoc/test/borrows2.js b/bin/jsdoc/test/borrows2.js new file mode 100644 index 00000000..c0d5ea21 --- /dev/null +++ b/bin/jsdoc/test/borrows2.js @@ -0,0 +1,23 @@ +// testing circular borrows + +/** + @class + @borrows Bar#zop as this.my_zop +*/ +function Foo() { + /** this is a zip. */ + this.zip = function() {} + + this.my_zop = new Bar().zop; +} + +/** + @class + @borrows Foo#zip as this.my_zip +*/ +function Bar() { + /** this is a zop. */ + this.zop = function() {} + + this.my_zip = new Foo().zip; +} \ No newline at end of file diff --git a/bin/jsdoc/test/config.js b/bin/jsdoc/test/config.js new file mode 100644 index 00000000..0748a210 --- /dev/null +++ b/bin/jsdoc/test/config.js @@ -0,0 +1,22 @@ +/** + * @constructor + * @param person The person. + * @param {string} person.name The person's name. + * @config {integer} age The person's age. + * @config [id=1] Optional id number to use. + * @param connection + */ +function Contact(person, connection) { + +} + +/** + * @constructor + * @param persons + * @config {string} Father The paternal person. + * @config {string} Mother The maternal person. + * @config {string[]} Children And the rest. + */ +function Family(/**Object*/persons) { + +} diff --git a/bin/jsdoc/test/constructs.js b/bin/jsdoc/test/constructs.js new file mode 100644 index 00000000..cca5dbd3 --- /dev/null +++ b/bin/jsdoc/test/constructs.js @@ -0,0 +1,18 @@ +var Person = makeClass( + /** + @scope Person + */ + { + /** + This is just another way to define a constructor. + @constructs + @param {string} name The name of the person. + */ + initialize: function(name) { + this.name = name; + }, + say: function(message) { + return this.name + " says: " + message; + } + } +); \ No newline at end of file diff --git a/bin/jsdoc/test/encoding.js b/bin/jsdoc/test/encoding.js new file mode 100644 index 00000000..ba642193 --- /dev/null +++ b/bin/jsdoc/test/encoding.js @@ -0,0 +1,10 @@ + +/** + * @Constructor + * @desc é…置文件 + * @class 什么也ä¸è¿”回 + */ +function Test(conf) { + // do something; +} + diff --git a/bin/jsdoc/test/encoding_other.js b/bin/jsdoc/test/encoding_other.js new file mode 100644 index 00000000..b144da4c --- /dev/null +++ b/bin/jsdoc/test/encoding_other.js @@ -0,0 +1,12 @@ + +/** + * @Constructor + * @desc ðïîÛ + * @class ßàáâãäåæçèçìëêíîï °±²³´µ¡¶·¸¹ + */ +function Test(conf) { + // do something; +} + +// run with commanline option -e=iso-8859-5 + diff --git a/bin/jsdoc/test/event.js b/bin/jsdoc/test/event.js new file mode 100644 index 00000000..7e41d6f6 --- /dev/null +++ b/bin/jsdoc/test/event.js @@ -0,0 +1,54 @@ +/** + * @name Kitchen + * @constructor + * @fires Bakery#event:donutOrdered + */ + +/** + * Fired when some cake is eaten. + * @name Kitchen#event:cakeEaten + * @function + * @param {Number} pieces The number of pieces eaten. + */ + +/** + * Find out if cake was eaten. + * @name Kitchen#cakeEaten + * @function + * @param {Boolean} wasEaten + */ + +/** + * @name getDesert + * @function + * @fires Kitchen#event:cakeEaten + */ + +/** + * @name Bakery + * @constructor + * @extends Kitchen + */ + +/** + * Fired when a donut order is made. + * @name Bakery#event:donutOrdered + * @event + * @param {Event} e The event object. + * @param {String} [e.topping] Optional sprinkles. + */ + +/** + * @constructor + * @borrows Bakery#event:donutOrdered as this.event:cakeOrdered + */ +function CakeShop() { +} + +/** @event */ +CakeShop.prototype.icingReady = function(isPink) { +} + +/** @event */ +function amHungry(/**Boolean*/enoughToEatAHorse) { +} \ No newline at end of file diff --git a/bin/jsdoc/test/exports.js b/bin/jsdoc/test/exports.js new file mode 100644 index 00000000..63a87cb4 --- /dev/null +++ b/bin/jsdoc/test/exports.js @@ -0,0 +1,14 @@ +/** @namespace */ +var mxn = {}; + +(function(){ + /** @exports Map as mxn.Map */ + var Map = + /** @constructor */ + mxn.Map = function() { + }; + + /** A method. */ + Map.prototype.doThings = function() { + }; +})(); \ No newline at end of file diff --git a/bin/jsdoc/test/functions_anon.js b/bin/jsdoc/test/functions_anon.js new file mode 100644 index 00000000..e9dd6c1b --- /dev/null +++ b/bin/jsdoc/test/functions_anon.js @@ -0,0 +1,39 @@ +/** an anonymous constructor executed inline */ +a = new function() { + /** a.b*/ + this.b = 1; + /** a.f */ + this.f = function() { + /** a.c */ + this.c = 2; + } +} + + +/** + named function executed inline +*/ +bar1 = function Zoola1() { + /** property of global */ + this.g = 1; +}(); + +/** + named constructor executed inline +*/ +bar2 = new function Zoola2() { + /** property of bar */ + this.p = 1; +}; + +/** module pattern */ +module = (function () { + /** won't appear in documentation */ + var priv = 1; + + /** @scope module */ + return { + /** will appear as a property of module */ + pub: 1 + } +})(); diff --git a/bin/jsdoc/test/functions_nested.js b/bin/jsdoc/test/functions_nested.js new file mode 100644 index 00000000..f044fafe --- /dev/null +++ b/bin/jsdoc/test/functions_nested.js @@ -0,0 +1,33 @@ +/** @constructor */ +function Zop() { +} + +/** + @class +*/ +Foo = function(id) { + // this is a bit twisted, but if you call Foo() you will then + // modify Foo(). This is kinda, sorta non-insane, because you + // would have to call Foo() 100% of the time to use Foo's methods + Foo.prototype.methodOne = function(bar) { + alert(bar); + }; + + // same again + Foo.prototype.methodTwo = function(bar2) { + alert(bar2); + }; + + // and these are only executed if the enclosing function is actually called + // and who knows if that will ever happen? + Bar = function(pez) { + alert(pez); + }; + Zop.prototype.zap = function(p){ + alert(p); + }; + + // but this is only visible inside Foo + function inner() { + } +}; diff --git a/bin/jsdoc/test/global.js b/bin/jsdoc/test/global.js new file mode 100644 index 00000000..5ea48949 --- /dev/null +++ b/bin/jsdoc/test/global.js @@ -0,0 +1,13 @@ +/** ecks */ +var x = [1, 2, 4]; + +var y = { + foo: function(){ + } +} + +bar = function() { +} + +function zop() { +} diff --git a/bin/jsdoc/test/globals.js b/bin/jsdoc/test/globals.js new file mode 100644 index 00000000..3f83fb1f --- /dev/null +++ b/bin/jsdoc/test/globals.js @@ -0,0 +1,25 @@ +function example(/**Circle*/a, b) { + /** a global defined in function */ + var number = a; + + var hideNumber = function(){ + } + + setNumber = function(){ + } + alert('You have chosen: ' + b); +} + +function initPage() { + var supported = document.createElement && document.getElementsByTagName; + if (!supported) return; + // start of DOM script + var x = document.getElementById('writeroot'); + // etc. +} + +/** an example var */ +var document = new Document(x, y); + +var getNumber = function(){ +} \ No newline at end of file diff --git a/bin/jsdoc/test/ignore.js b/bin/jsdoc/test/ignore.js new file mode 100644 index 00000000..d3fac9ed --- /dev/null +++ b/bin/jsdoc/test/ignore.js @@ -0,0 +1,10 @@ +/** + * A test constructor. + * @constructor + * @ignore + */ +function Ignored() { + /** a method */ + this.bar = function() { + } +} \ No newline at end of file diff --git a/bin/jsdoc/test/inner.js b/bin/jsdoc/test/inner.js new file mode 100644 index 00000000..37cfa9dc --- /dev/null +++ b/bin/jsdoc/test/inner.js @@ -0,0 +1,16 @@ +/** + * @constructor + */ +function Outer() { + /** + * @constructor + */ + function Inner(name) { + /** The name of this. */ + this.name = name; + } + + this.open = function(name) { + return (new Inner(name)); + } +} \ No newline at end of file diff --git a/bin/jsdoc/test/jsdoc_test.js b/bin/jsdoc/test/jsdoc_test.js new file mode 100644 index 00000000..08177128 --- /dev/null +++ b/bin/jsdoc/test/jsdoc_test.js @@ -0,0 +1,477 @@ +/** + * @fileoverview This file is to be used for testing the JSDoc parser + * It is not intended to be an example of good JavaScript OO-programming, + * nor is it intended to fulfill any specific purpose apart from + * demonstrating the functionality of the + * JSDoc parser + * + * @author Gabriel Reid gab_reid@users.sourceforge.net + * @version 0.1 + */ + + +/** + * Construct a new Shape object. + * @class This is the basic Shape class. + * It can be considered an abstract class, even though no such thing + * really existing in JavaScript + * @constructor + * @throws MemoryException if there is no more memory + * @throws GeneralShapeException rarely (if ever) + * @return {Shape|Coordinate} A new shape. + */ +function Shape(){ + + /** + * This is an example of a function that is not given as a property + * of a prototype, but instead it is assigned within a constructor. + * For inner functions like this to be picked up by the parser, the + * function that acts as a constructor must be denoted with + * the @constructor tag in its comment. + * @type String + */ + this.getClassName = function(){ + return "Shape"; + } + + /** + * This is an inner method, just used here as an example + * @since version 0.5 + * @author Sue Smart + */ + function addReference(){ + // Do nothing... + } + +} + +/** + * Create a new Hexagon instance. + * @extends Shape + * @class Hexagon is a class that is a logical sublcass of + * {@link Shape} (thanks to the @extends tag), but in + * reality it is completely unrelated to Shape. + * @param {int} sideLength The length of one side for the new Hexagon + * @example + * var h = new Hexagon(2); + * @example + * if (hasHex) { + * hex = new Hexagon(5); + * color = hex.getColor(); + * } + */ +function Hexagon(sideLength) { +} + + +/** + * This is an unattached (static) function that adds two integers together. + * @param {int} One The first number to add + * @param {int} Two The second number to add + * @author Gabriel Reid + * @deprecated So you shouldn't use it anymore! Use {@link Shape#getClassName} instead. + */ +function Add(One, Two){ + return One + Two; +} + + +/** + * The color of this shape + * @type Color + */ +Shape.prototype.color = null; + +/** + * The border of this shape. + * @field + * @type int + */ +Shape.prototype.border = function(){return border;}; + +/* + * These are all the instance method implementations for Shape + */ + +/** + * Get the coordinates of this shape. It is assumed that we're always talking + * about shapes in a 2D location here. + * @requires The {@link Shape} class + * @returns A Coordinate object representing the location of this Shape + * @type Coordinate[] + */ +Shape.prototype.getCoords = function(){ + return this.coords; +} + +/** + * Get the color of this shape. + * @see #setColor + * @see The Color library. + * @link Shape + * @type Color + */ +Shape.prototype.getColor = function(){ + return this.color; +} + +/** + * Set the coordinates for this Shape + * @param {Coordinate} coordinates The coordinates to set for this Shape + */ +Shape.prototype.setCoords = function(coordinates){ + this.coords = coordinates; +} + +/** + * Set the color for this Shape + * @param {Color} color The color to set for this Shape + * @param other There is no other param, but it can still be documented if + * optional parameters are used + * @throws NonExistantColorException (no, not really!) + * @see #getColor + */ +Shape.prototype.setColor = function(color){ + this.color = color; +} + +/** + * Clone this shape + * @returns A copy of this shape + * @type Shape + * @author Gabriel Reid + */ +Shape.prototype.clone = function(){ + return new Shape(); +} + +/** + * Create a new Rectangle instance. + * @class A basic rectangle class, inherits from Shape. + * This class could be considered a concrete implementation class + * @constructor + * @param {int} width The optional width for this Rectangle + * @param {int} height Thie optional height for this Rectangle + * @author Gabriel Reid + * @see Shape is the base class for this + * @augments Shape + * @hilited + */ +function Rectangle(width, // This is the width + height // This is the height + ){ + if (width){ + this.width = width; + if (height){ + this.height = height; + } + } +} + + +/* Inherit from Shape */ +Rectangle.prototype = new Shape(); + +/** + * Value to represent the width of the Rectangle. + *
Text in bold and italic and a + * link to SourceForge + * @private + * @type int + */ +Rectangle.prototype.width = 0; + +/** + * Value to represent the height of the Rectangle + * @private + * @type int + */ +Rectangle.prototype.height = 0; + +/** + * Get the type of this object. + * @type String + */ +Rectangle.prototype.getClassName= function(){ + return "Rectangle"; +} + +/** + * Get the value of the width for the Rectangle + * @type int + * @see Rectangle#setWidth + */ +Rectangle.prototype.getWidth = function(){ + return this.width; +} + +/** + * Get the value of the height for the Rectangle. + * Another getter is the {@link Shape#getColor} method in the + * {@link Shape} base class. + * @return The height of this Rectangle + * @type int + * @see Rectangle#setHeight + */ +Rectangle.prototype.getHeight = function(){ + return this.height; +} + +/** + * Set the width value for this Rectangle. + * @param {int} width The width value to be set + * @see #setWidth + */ +Rectangle.prototype.setWidth = function(width){ + this.width = width; +} + +/** + * Set the height value for this Rectangle. + * @param {int} height The height value to be set + * @see #getHeight + */ +Rectangle.prototype.setHeight = function(height){ + this.height = height; +} + +/** + * Get the value for the total area of this Rectangle + * @return total area of this Rectangle + * @type int + */ +Rectangle.prototype.getArea = function(){ + return width * height; +} + + +/** + * Create a new Square instance. + * @class A Square is a subclass of {@link Rectangle} + * @param {int} width The optional width for this Rectangle + * @param {int} height The optional height for this Rectangle + * @augments Rectangle + */ +function Square(width, height){ + if (width){ + this.width = width; + if (height){ + this.height = height; + } + } + +} + +/* Square is a subclass of Rectangle */ +Square.prototype = new Rectangle(); + +/** + * Set the width value for this Shape. + * @param {int} width The width value to be set + * @see #getWidth + */ +Square.prototype.setWidth = function(width){ + this.width = this.height = width; +} + +/** + * Set the height value for this Shape + * Sets the {@link Rectangle#height} attribute in the Rectangle. + * @param {int} height The height value to be set + */ +Square.prototype.setHeight = function(height){ + this.height = this.width = height; +} + + +/** + * Create a new Circle instance based on a radius. + * @class Circle class is another subclass of Shape + * @extends Shape + * @param {int} radius The optional radius of this {@link Circle } + * @mixin Square.prototype.setWidth as this.setDiameter + */ +function Circle(radius){ + if (radius) { + /** The radius of the this Circle. */ + this.radius = radius; + } +} + +/* Circle inherits from {@link Shape} */ +Circle.prototype = new Shape(); + +/** + * The radius value for this Circle + * @private + * @type int + */ +Circle.prototype.radius = 0; + +/** + * A very simple class (static) field that is also a constant + * @final + * @type float + */ +Circle.PI = 3.14; + +/** + * Get the radius value for this Circle + * @type int + * @see #setRadius + */ +Circle.prototype.getRadius = function(){ + return this.radius; +} + +/** + * Set the radius value for this Circle + * @param {int} radius The {@link Circle#radius} value to set + * @see #getRadius + */ +Circle.prototype.setRadius = function(radius){ + this.radius = radius; +} + +/** + * An example of a class (static) method that acts as a factory for Circle + * objects. Given a radius value, this method creates a new Circle. + * @param {int} radius The radius value to use for the new Circle. + * @type Circle + */ +Circle.createCircle = function(radius){ + return new Circle(radius); +} + + +/** + * Create a new Coordinate instance based on x and y grid data. + * @class Coordinate is a class that can encapsulate location information. + * @param {int} [x=0] The optional x portion of the Coordinate + * @param {int} [y=0] The optinal y portion of the Coordinate + */ +function Coordinate(x, y){ + if (x){ + this.x = x; + if (y){ + this.y = y; + } + } +} + +/** + * The x portion of the Coordinate + * @type int + * @see #getX + * @see #setX + */ +Coordinate.prototype.x = 0; + +/** + * The y portion of the Coordinate + * @type int + * @see #getY + * @see #setY + */ +Coordinate.prototype.y = 0; + +/** + * Gets the x portion of the Coordinate. + * @type int + * @see #setX + */ +Coordinate.prototype.getX = function(){ + return this.x; +} + +/** + * Get the y portion of the Coordinate. + * @type int + * @see #setY + */ +Coordinate.prototype.getY = function(){ + return this.y; +} + +/** + * Sets the x portion of the Coordinate. + * @param {int} x The x value to set + * @see #getX + */ +Coordinate.prototype.setX = function(x){ + this.x = x; +} + +/** + * Sets the y portion of the Coordinate. + * @param {int} y The y value to set + * @see #getY + */ +Coordinate.prototype.setY = function(y){ + this.y = y; +} + +/** + * @class This class exists to demonstrate the assignment of a class prototype + * as an anonymous block. + */ +function ShapeFactory(){ +} + +ShapeFactory.prototype = { + /** + * Creates a new {@link Shape} instance. + * @return A new {@link Shape} + * @type Shape + */ + createShape: function(){ + return new Shape(); + } +} + +/** + * An example of a singleton class + * @param ... Arguments represent {@link coordinate}s in the shape. + * @constructor + */ +MySingletonShapeFactory = function(){ + + /** + * Get the next {@link Shape} + * @type Shape + * @return A new {@link Shape} + */ + this.getShape = function(){ + return null; + } + +} + + +/** + * Create a new Foo instance. + * @class This is the Foo class. It exists to demonstrate 'nested' classes. + * @constructor + * @see Foo.Bar + */ +function Foo(){} + +/** + * Creates a new instance of Bar. + * @class This class exists to demonstrate 'nested' classes. + * @constructor + * @see Foo.Bar + */ +function Bar(){} + +/** + * Nested class + * @constructor + */ +Foo.Bar = function(){ + /** The x. */ this.x = 2; +} + +Foo.Bar.prototype = new Bar(); +/** The y. */ +Foo.Bar.prototype.y = '3'; diff --git a/bin/jsdoc/test/lend.js b/bin/jsdoc/test/lend.js new file mode 100644 index 00000000..92b15d5a --- /dev/null +++ b/bin/jsdoc/test/lend.js @@ -0,0 +1,33 @@ + /** @class */ +var Person = Class.create( + /** + @lends Person.prototype + */ + { + initialize: function(name) { + this.name = name; + }, + say: function(message) { + return this.name + ': ' + message; + } + } + ); + +/** @lends Person.prototype */ +{ + /** like say but more musical */ + sing: function(song) { + } +} + +/** @lends Person */ +{ + getCount: function() { + } +} + +/** @lends Unknown.prototype */ +{ + notok: function() { + } +} \ No newline at end of file diff --git a/bin/jsdoc/test/memberof.js b/bin/jsdoc/test/memberof.js new file mode 100644 index 00000000..883bbdeb --- /dev/null +++ b/bin/jsdoc/test/memberof.js @@ -0,0 +1,19 @@ +/** @constructor */ +pack = function() { + this.init = function(){} + function config(){} +} + + pack.build = function(task) {}; + +/** @memberOf pack */ +pack.install = function() {} + +/** @memberOf pack */ +pack.install.overwrite = function() {} + +/** @memberOf pack */ +clean = function() {} + +/** @memberOf pack-config */ +install = function() {}; diff --git a/bin/jsdoc/test/memberof2.js b/bin/jsdoc/test/memberof2.js new file mode 100644 index 00000000..bc3d9d8f --- /dev/null +++ b/bin/jsdoc/test/memberof2.js @@ -0,0 +1,38 @@ +/** + * @constructor + */ +function Foo() { + /** + @memberOf Foo.prototype + */ + function bar(a, b) { + } + + /** + @memberOf Foo + */ + var zip = function(p, q) { + } + + /** + @memberOf Foo + */ + function zop( x,y ) { + } + + /** + @memberOf Foo + @constructor + */ + function Fiz() { + /** A method of Foo#Fiz. */ + this.fipple = function(fop){} + } +} + +/** + @memberOf Foo# + */ +var blat = function() { + +} \ No newline at end of file diff --git a/bin/jsdoc/test/memberof3.js b/bin/jsdoc/test/memberof3.js new file mode 100644 index 00000000..8c259425 --- /dev/null +++ b/bin/jsdoc/test/memberof3.js @@ -0,0 +1,33 @@ +/** +* @name Foo +* @class +*/ + +/**#@+ +* @memberOf Foo# +* @field +*/ + +/** +* @name bar +* @type Object[] +*/ + +/**#@-*/ + +/** +* @name Foo2 +* @class +*/ + +/**#@+ +* @memberOf Foo2# +* @field +*/ + +/** +* @name bar +* @type Object[] +*/ + +/**#@-*/ \ No newline at end of file diff --git a/bin/jsdoc/test/memberof_constructor.js b/bin/jsdoc/test/memberof_constructor.js new file mode 100644 index 00000000..80fde735 --- /dev/null +++ b/bin/jsdoc/test/memberof_constructor.js @@ -0,0 +1,17 @@ +/** @constructor */ +function Circle(){} + +/** + @constructor + @memberOf Circle# + */ +Circle.prototype.Tangent = function(){}; + +// renaming Circle#Tangent to Circle#Circle#Tangent + +/** + @memberOf Circle#Tangent# + */ +Circle.prototype.Tangent.prototype.getDiameter = function(){}; + + diff --git a/bin/jsdoc/test/module.js b/bin/jsdoc/test/module.js new file mode 100644 index 00000000..5b3fe42c --- /dev/null +++ b/bin/jsdoc/test/module.js @@ -0,0 +1,17 @@ +/** @namespace */ +myProject = myProject || {}; + +/** @namespace */ +myProject.myModule = (function () { + /** describe myPrivateVar here */ + var myPrivateVar = ""; + + var myPrivateMethod = function () { + } + + /** @scope myProject.myModule */ + return { + myPublicMethod: function () { + } + }; +})(); \ No newline at end of file diff --git a/bin/jsdoc/test/multi_methods.js b/bin/jsdoc/test/multi_methods.js new file mode 100644 index 00000000..bab35c76 --- /dev/null +++ b/bin/jsdoc/test/multi_methods.js @@ -0,0 +1,25 @@ + +/** + Get the entire flavor. + @name flavor^3 + @function + @returns {Object} The entire flavor hash. +*/ +/** + Get a named flavor. + @name flavor^2 + @function + @param {String} name The name of the flavor to get. + @returns {String} The value of that flavor. +*/ +/** + Set the flavor. + @param {String} name The name of the flavor to set. + @param {String} value The value of the flavor. + @returns {String} The value of that flavor. +*/ +function flavor(name, value) { + if (arguments.length > 1) flavor[name] = value; + else if (arguments.length == 1) return flavor[name]; + else return flavor; +} \ No newline at end of file diff --git a/bin/jsdoc/test/name.js b/bin/jsdoc/test/name.js new file mode 100644 index 00000000..e88a51a7 --- /dev/null +++ b/bin/jsdoc/test/name.js @@ -0,0 +1,19 @@ +/** + @name Response + @class +*/ + +Response.prototype = { + /** + @name Response#text + @function + @description + Gets the body of the response as plain text + @returns {String} + Response as text + */ + + text: function() { + return this.nativeResponse.responseText; + } +} \ No newline at end of file diff --git a/bin/jsdoc/test/namespace_nested.js b/bin/jsdoc/test/namespace_nested.js new file mode 100644 index 00000000..46cafa2f --- /dev/null +++ b/bin/jsdoc/test/namespace_nested.js @@ -0,0 +1,23 @@ +/** + @namespace This is the first namespace. +*/ +ns1 = {}; + +/** + This is the second namespace. + @namespace +*/ +ns1.ns2 = {}; + +/** + This part of ns1.ns2 + @constructor +*/ +ns1.ns2.Function1 = function() { +}; + +ns1.staticFunction = function() { +}; + +/** A static field in a namespace. */ +ns1.ns2.staticField = 1; diff --git a/bin/jsdoc/test/nocode.js b/bin/jsdoc/test/nocode.js new file mode 100644 index 00000000..1cf99bc9 --- /dev/null +++ b/bin/jsdoc/test/nocode.js @@ -0,0 +1,13 @@ +/**#nocode+*/ + /** + @name star + @function + */ + function blahblah() { + + } +/**#nocode-*/ + +function yaddayadda() { + +} \ No newline at end of file diff --git a/bin/jsdoc/test/oblit_anon.js b/bin/jsdoc/test/oblit_anon.js new file mode 100644 index 00000000..8d9e9413 --- /dev/null +++ b/bin/jsdoc/test/oblit_anon.js @@ -0,0 +1,20 @@ +/** the options */ +opt = Opt.get( + arguments, + { + d: "directory", + c: "conf", + "D[]": "define" + } +); + +/** configuration */ +opt.conf = { + /** keep */ + keep: true, + /** base */ + base: getBase(this, {p: properties}) +} + + + diff --git a/bin/jsdoc/test/overview.js b/bin/jsdoc/test/overview.js new file mode 100644 index 00000000..1dfc09b1 --- /dev/null +++ b/bin/jsdoc/test/overview.js @@ -0,0 +1,20 @@ +/** + * @overview This "library" contains a + * lot of classes and functions. + * @example +
+	var x (x < 1);
+	alert("This 'is' \"code\"");
+ 
+ * @name My Cool Library + * @author Joe Smith jsmith@company.com + * @version 0.1 + */ + +/** + * Gets the current foo + * @param {String} fooId The unique identifier for the foo. + * @return {Object} Returns the current foo. + */ +function getFoo(fooID){ +} \ No newline at end of file diff --git a/bin/jsdoc/test/param_inline.js b/bin/jsdoc/test/param_inline.js new file mode 100644 index 00000000..09845b28 --- /dev/null +++ b/bin/jsdoc/test/param_inline.js @@ -0,0 +1,37 @@ +/** + @constructor + @param columns The number of columns. +*/ +function Layout(/**int*/columns){ + /** + @param [id] The id of the element. + @param elName The name of the element. + */ + this.getElement = function( + /** string */ elName, + /** number|string */ id + ) { + }; + + /** + @constructor + */ + this.Canvas = function(top, left, /**int*/width, height) { + /** Is it initiated yet? */ + this.initiated = true; + } + + this.rotate = function(/**nothing*/) { + } + + /** + @param x + @param y + @param {zoppler} z*/ + this.init = function(x, y, /**abbler*/z) { + /** The xyz. */ + this.xyz = x+y+z; + this.getXyz = function() { + } + } +} diff --git a/bin/jsdoc/test/params_optional.js b/bin/jsdoc/test/params_optional.js new file mode 100644 index 00000000..18bf5982 --- /dev/null +++ b/bin/jsdoc/test/params_optional.js @@ -0,0 +1,8 @@ + +/** + * @param {Page[]} pages + * @param {number} [id] Specifies the id, if applicable. + * @param {String} [title = This is untitled.] Specifies the title. + */ +function Document(pages, id, title){ +} \ No newline at end of file diff --git a/bin/jsdoc/test/prototype.js b/bin/jsdoc/test/prototype.js new file mode 100644 index 00000000..11470083 --- /dev/null +++ b/bin/jsdoc/test/prototype.js @@ -0,0 +1,17 @@ +/** @constructor */ +function Article() { +} + +Article.prototype.init = function(title) { + /** the instance title */ + this.title = title; + + /** the static counter */ + Article.counter = 1; +} + +a = new Article(); +a.Init("my title"); + +print(a.title); +print(Article.counter); \ No newline at end of file diff --git a/bin/jsdoc/test/prototype_nested.js b/bin/jsdoc/test/prototype_nested.js new file mode 100644 index 00000000..e8ca1ced --- /dev/null +++ b/bin/jsdoc/test/prototype_nested.js @@ -0,0 +1,9 @@ +/** @constructor */ +function Word() { +} + +Word.prototype.reverse = function() { +} + +Word.prototype.reverse.utf8 = function() { +} \ No newline at end of file diff --git a/bin/jsdoc/test/prototype_oblit.js b/bin/jsdoc/test/prototype_oblit.js new file mode 100644 index 00000000..6cfc39ca --- /dev/null +++ b/bin/jsdoc/test/prototype_oblit.js @@ -0,0 +1,13 @@ +/** @constructor */ +function Article() { +} + +Article.prototype = { + /** instance get title */ + getTitle: function(){ + } +} + +/** static get title */ +Article.getTitle = function(){ +} \ No newline at end of file diff --git a/bin/jsdoc/test/prototype_oblit_constructor.js b/bin/jsdoc/test/prototype_oblit_constructor.js new file mode 100644 index 00000000..92482486 --- /dev/null +++ b/bin/jsdoc/test/prototype_oblit_constructor.js @@ -0,0 +1,24 @@ +/** @constructor */ +function Article() { +} + +Article.prototype = { + /** @constructor */ + Title: function(title) { + /** the value of the Title instance */ + this.title = title; + }, + + init: function(pages) { + /** the value of the pages of the Article instance */ + this.pages = pages; + } +} + +f = new Article(); +f.init("one two three"); + +t = new f.Title("my title"); + +print(f.pages); +print(t.title); \ No newline at end of file diff --git a/bin/jsdoc/test/public.js b/bin/jsdoc/test/public.js new file mode 100644 index 00000000..35d34f6f --- /dev/null +++ b/bin/jsdoc/test/public.js @@ -0,0 +1,10 @@ +/**@constructor*/ +function Foo() { + /** + @public + @static + @field + */ + var bar = function(x) { + } +} \ No newline at end of file diff --git a/bin/jsdoc/test/scripts/code.js b/bin/jsdoc/test/scripts/code.js new file mode 100644 index 00000000..e9d7ed2e --- /dev/null +++ b/bin/jsdoc/test/scripts/code.js @@ -0,0 +1,5 @@ +/** + @class + */ +function thisiscode() { +} \ No newline at end of file diff --git a/bin/jsdoc/test/scripts/notcode.txt b/bin/jsdoc/test/scripts/notcode.txt new file mode 100644 index 00000000..fcd737e7 --- /dev/null +++ b/bin/jsdoc/test/scripts/notcode.txt @@ -0,0 +1,5 @@ +(This is not code) +function foo(){{{{ +( +! +@ \ No newline at end of file diff --git a/bin/jsdoc/test/shared.js b/bin/jsdoc/test/shared.js new file mode 100644 index 00000000..e1c277a6 --- /dev/null +++ b/bin/jsdoc/test/shared.js @@ -0,0 +1,42 @@ + +/** + * Builtin object. + * @class + * @name Array + */ + +/**#@+ + * Extension to builtin array. + * @memberOf Array + * @method + */ + +/** + * @returns Boolen if some array members... + */ +Array.prototype.some = function(){}; + +/** + * Change every element of an array. + * @returns Filtered array copy. + */ +Array.prototype.filter = function(){}; + +/**#@-*/ + + +/** + * A first in, first out data structure. + * @constructor + */ +Queue = function(){}; + +/**#@+ + * Extension to Queue. + * @memberOf Queue + */ + +rewind = function(){ +} + +// should close automatically here. \ No newline at end of file diff --git a/bin/jsdoc/test/shared2.js b/bin/jsdoc/test/shared2.js new file mode 100644 index 00000000..3f7736a7 --- /dev/null +++ b/bin/jsdoc/test/shared2.js @@ -0,0 +1,2 @@ +startOver = function(){ +} \ No newline at end of file diff --git a/bin/jsdoc/test/shortcuts.js b/bin/jsdoc/test/shortcuts.js new file mode 100644 index 00000000..f738f1e1 --- /dev/null +++ b/bin/jsdoc/test/shortcuts.js @@ -0,0 +1,22 @@ +// /**#=+ +// * { +// * 'D': 'Date.prototype', +// * '$N': 'Number' +// * } +// */ +// var D = Date.prototype, +// $N = Number; +// +// D.locale = function(){ +// }; +// +// /** +// @return {string} The cardinal number string. +// */ +// $N.nth = function(n){ +// }; +// +// LOAD.file = function(){ +// } +// +// /**#=-*/ \ No newline at end of file diff --git a/bin/jsdoc/test/static_this.js b/bin/jsdoc/test/static_this.js new file mode 100644 index 00000000..9407b20f --- /dev/null +++ b/bin/jsdoc/test/static_this.js @@ -0,0 +1,13 @@ +/** the parent */ +var box = {}; + +/** @namespace */ +box.holder = {} + +box.holder.foo = function() { + /** the counter */ + this.counter = 1; +} + +box.holder.foo(); +print(box.holder.counter); diff --git a/bin/jsdoc/test/synonyms.js b/bin/jsdoc/test/synonyms.js new file mode 100644 index 00000000..09066b98 --- /dev/null +++ b/bin/jsdoc/test/synonyms.js @@ -0,0 +1,31 @@ +/** + @class + @inherits Bar#zop as #my_zop +*/ +function Foo() { + /** this is a zip. */ + this.zip = function() {} + + /** from Bar */ + this.my_zop = new Bar().zop; +} + +/** + @class + @borrows Foo#zip as this.my_zip +*/ +function Bar() { + /** this is a zop. */ + this.zop = function() {} + + /** from Foo */ + this.my_zip = new Foo().zip; +} + +/** @namespace */ +var myObject = { + /** + @type function + */ + myFunc: getFunction() +} \ No newline at end of file diff --git a/bin/jsdoc/test/tosource.js b/bin/jsdoc/test/tosource.js new file mode 100644 index 00000000..706d4765 --- /dev/null +++ b/bin/jsdoc/test/tosource.js @@ -0,0 +1,23 @@ +/** + * @param {Object} object + * @return {string} + */ +function valueOf(object) {} + +/** + * @param {Object} object + * @return {string} + */ +function toString(object) {} + +/** + * @param {Object} object + * @return {string} + */ +function toSource(object) {} + +/** + * @param {Object} object + * @return {string} + */ +function constructor(object) {} \ No newline at end of file diff --git a/bin/jsdoc/test/variable_redefine.js b/bin/jsdoc/test/variable_redefine.js new file mode 100644 index 00000000..2c07da09 --- /dev/null +++ b/bin/jsdoc/test/variable_redefine.js @@ -0,0 +1,14 @@ +/** @constructor */ +function Foo() { + var bar = 1; + bar = 2; // redefining a private + + this.baz = 1; + baz = 2; // global + + /** a private */ + var blap = { + /** in here */ + tada: 1 + } +} \ No newline at end of file diff --git a/bin/run-jsdoc.js b/bin/run-jsdoc.js new file mode 100644 index 00000000..1f875cdb --- /dev/null +++ b/bin/run-jsdoc.js @@ -0,0 +1,348 @@ +/** + * @fileOverview + * A bootstrap script that creates some basic required objects + * for loading other scripts. + * @author Michael Mathews, micmath@gmail.com + * @version $Id: run.js 756 2009-01-07 21:32:58Z micmath $ + */ + +/** + * @namespace Keep track of any messages from the running script. + */ +LOG = { + warn: function(msg, e) { + if (JSDOC.opt.q) return; + if (e) msg = e.fileName+", line "+e.lineNumber+": "+msg; + + msg = ">> WARNING: "+msg; + LOG.warnings.push(msg); + if (LOG.out) LOG.out.write(msg+"\n"); + else print(msg); + }, + + inform: function(msg) { + if (JSDOC.opt.q) return; + msg = " > "+msg; + if (LOG.out) LOG.out.write(msg+"\n"); + else if (typeof LOG.verbose != "undefined" && LOG.verbose) print(msg); + } +}; +LOG.warnings = []; +LOG.verbose = false +LOG.out = undefined; + +/** + * @class Manipulate a filepath. + */ +function FilePath(absPath, separator) { + this.slash = separator || "/"; + this.root = this.slash; + this.path = []; + this.file = ""; + + var parts = absPath.split(/[\\\/]/); + if (parts) { + if (parts.length) this.root = parts.shift() + this.slash; + if (parts.length) this.file = parts.pop() + if (parts.length) this.path = parts; + } + + this.path = this.resolvePath(); +} + +/** Collapse any dot-dot or dot items in a filepath. */ +FilePath.prototype.resolvePath = function() { + var resolvedPath = []; + for (var i = 0; i < this.path.length; i++) { + if (this.path[i] == "..") resolvedPath.pop(); + else if (this.path[i] != ".") resolvedPath.push(this.path[i]); + } + return resolvedPath; +} + +/** Trim off the filename. */ +FilePath.prototype.toDir = function() { + if (this.file) this.file = ""; + return this; +} + +/** Go up a directory. */ +FilePath.prototype.upDir = function() { + this.toDir(); + if (this.path.length) this.path.pop(); + return this; +} + +FilePath.prototype.toString = function() { + return this.root + + this.path.join(this.slash) + + ((this.path.length > 0)? this.slash : "") + + this.file; +} + +/** + * Turn a path into just the name of the file. + */ +FilePath.fileName = function(path) { + var nameStart = Math.max(path.lastIndexOf("/")+1, path.lastIndexOf("\\")+1, 0); + return path.substring(nameStart); +} + +/** + * Get the extension of a filename + */ +FilePath.fileExtension = function(filename) { + return filename.split(".").pop().toLowerCase(); +}; + +/** + * Turn a path into just the directory part. + */ +FilePath.dir = function(path) { + var nameStart = Math.max(path.lastIndexOf("/")+1, path.lastIndexOf("\\")+1, 0); + return path.substring(0, nameStart-1); +} + + +importClass(java.lang.System); + +/** + * @namespace A collection of information about your system. + */ +SYS = { + /** + * Information about your operating system: arch, name, version. + * @type string + */ + os: [ + new String(System.getProperty("os.arch")), + new String(System.getProperty("os.name")), + new String(System.getProperty("os.version")) + ].join(", "), + + /** + * Which way does your slash lean. + * @type string + */ + slash: System.getProperty("file.separator")||"/", + + /** + * The path to the working directory where you ran java. + * @type string + */ + userDir: new String(System.getProperty("user.dir")), + + /** + * Where is Java's home folder. + * @type string + */ + javaHome: new String(System.getProperty("java.home")), + + /** + * The absolute path to the directory containing this script. + * @type string + */ + pwd: undefined +}; + +// jsrun appends an argument, with the path to here. +if (arguments[arguments.length-1].match(/^-j=(.+)/)) { + if (RegExp.$1.charAt(0) == SYS.slash || RegExp.$1.charAt(1) == ":") { // absolute path to here + SYS.pwd = new FilePath(RegExp.$1).toDir().toString(); + } + else { // relative path to here + SYS.pwd = new FilePath(SYS.userDir + SYS.slash + RegExp.$1).toDir().toString(); + } + arguments.pop(); +} +else { + print("The run.js script requires you use jsrun.jar."); + quit(); +} + +// shortcut +var File = Packages.java.io.File; + +/** + * @namespace A collection of functions that deal with reading a writing to disk. + */ +IO = { + + /** + * Create a new file in the given directory, with the given name and contents. + */ + saveFile: function(/**string*/ outDir, /**string*/ fileName, /**string*/ content) { + var out = new Packages.java.io.PrintWriter( + new Packages.java.io.OutputStreamWriter( + new Packages.java.io.FileOutputStream(outDir+SYS.slash+fileName), + IO.encoding + ) + ); + out.write(content); + out.flush(); + out.close(); + }, + + /** + * @type string + */ + readFile: function(/**string*/ path) { + if (!IO.exists(path)) { + throw "File doesn't exist there: "+path; + } + return readFile(path, IO.encoding); + }, + + /** + * @param inFile + * @param outDir + * @param [fileName=The original filename] + */ + copyFile: function(/**string*/ inFile, /**string*/ outDir, /**string*/ fileName) { + if (fileName == null) fileName = FilePath.fileName(inFile); + + var inFile = new File(inFile); + var outFile = new File(outDir+SYS.slash+fileName); + + var bis = new Packages.java.io.BufferedInputStream(new Packages.java.io.FileInputStream(inFile), 4096); + var bos = new Packages.java.io.BufferedOutputStream(new Packages.java.io.FileOutputStream(outFile), 4096); + var theChar; + while ((theChar = bis.read()) != -1) { + bos.write(theChar); + } + bos.close(); + bis.close(); + }, + + /** + * Creates a series of nested directories. + */ + mkPath: function(/**Array*/ path) { + if (path.constructor != Array) path = path.split(/[\\\/]/); + var make = ""; + for (var i = 0, l = path.length; i < l; i++) { + make += path[i] + SYS.slash; + if (! IO.exists(make)) { + IO.makeDir(make); + } + } + }, + + /** + * Creates a directory at the given path. + */ + makeDir: function(/**string*/ path) { + (new File(path)).mkdir(); + }, + + /** + * @type string[] + * @param dir The starting directory to look in. + * @param [recurse=1] How many levels deep to scan. + * @returns An array of all the paths to files in the given dir. + */ + ls: function(/**string*/ dir, /**number*/ recurse, _allFiles, _path) { + if (_path === undefined) { // initially + var _allFiles = []; + var _path = [dir]; + } + if (_path.length == 0) return _allFiles; + if (recurse === undefined) recurse = 1; + + dir = new File(dir); + if (!dir.directory) return [String(dir)]; + var files = dir.list(); + + for (var f = 0; f < files.length; f++) { + var file = String(files[f]); + if (file.match(/^\.[^\.\/\\]/)) continue; // skip dot files + + if ((new File(_path.join(SYS.slash)+SYS.slash+file)).list()) { // it's a directory + _path.push(file); + if (_path.length-1 < recurse) IO.ls(_path.join(SYS.slash), recurse, _allFiles, _path); + _path.pop(); + } + else { + _allFiles.push((_path.join(SYS.slash)+SYS.slash+file).replace(SYS.slash+SYS.slash, SYS.slash)); + } + } + + return _allFiles; + }, + + /** + * @type boolean + */ + exists: function(/**string*/ path) { + file = new File(path); + + if (file.isDirectory()){ + return true; + } + if (!file.exists()){ + return false; + } + if (!file.canRead()){ + return false; + } + return true; + }, + + /** + * + */ + open: function(/**string*/ path, /**string*/ append) { + var append = true; + var outFile = new File(path); + var out = new Packages.java.io.PrintWriter( + new Packages.java.io.OutputStreamWriter( + new Packages.java.io.FileOutputStream(outFile, append), + IO.encoding + ) + ); + return out; + }, + + /** + * Sets {@link IO.encoding}. + * Encoding is used when reading and writing text to files, + * and in the meta tags of HTML output. + */ + setEncoding: function(/**string*/ encoding) { + if (/ISO-8859-([0-9]+)/i.test(encoding)) { + IO.encoding = "ISO8859_"+RegExp.$1; + } + else { + IO.encoding = encoding; + } + }, + + /** + * @default "utf-8" + * @private + */ + encoding: "utf-8", + + /** + * Load the given script. + */ + include: function(relativePath) { + load(SYS.pwd+relativePath); + }, + + /** + * Loads all scripts from the given directory path. + */ + includeDir: function(path) { + if (!path) return; + + for (var lib = IO.ls(SYS.pwd+path), i = 0; i < lib.length; i++) + if (/\.js$/i.test(lib[i])) load(lib[i]); + } +} + +// now run the application +IO.include("frame.js"); +IO.include("main.js"); + +main(); diff --git a/build.properties b/build.properties index 78ad7a3b..e40d3257 100644 --- a/build.properties +++ b/build.properties @@ -1,15 +1,19 @@ -#OpenSeadragon build.properties -#TODO: how do you auto-increment build_id's with every commit? +# OpenSeadragon build.properties +# TODO: how do you auto-increment build_id's with every commit? # TRY: continuos integration # TRY: git-hooks PROJECT: openseadragon BUILD_MAJOR: 0 BUILD_MINOR: 8 -BUILD_ID: 23 +BUILD_ID: 24 BUILD: ${PROJECT}.${BUILD_MAJOR}.${BUILD_MINOR}.${BUILD_ID} VERSION: ${BUILD_MAJOR}.${BUILD_MINOR}.${BUILD_ID} # This is the location of where we want to copy the built js file # and other distributables like images. WWW: ../www/openseadragon/ +WWW_DOCS: ${WWW}docs/ + +# Supporting libraries for supplimental build tasks +DOC_LIB: ./lib/jsdoc.jar diff --git a/build.xml b/build.xml index 06090e41..5e05ca58 100644 --- a/build.xml +++ b/build.xml @@ -26,7 +26,7 @@ - + @@ -54,4 +54,18 @@ + + + | Generating Public API Documentation + + + + + + + + + \ No newline at end of file diff --git a/openseadragon.js b/openseadragon.js index 8298070c..a20ba81e 100644 --- a/openseadragon.js +++ b/openseadragon.js @@ -1,9 +1,26 @@ /** - * (c) 2011 Christopher Thatcher - * (c) 2010 OpenSeadragon - * (c) 2010 CodePlex Foundation + * @version OpenSeadragon 0.8.24 * - * OpenSeadragon 0.8.23 + * @fileOverview + *

+ * + * OpenSeadragon - Javascript Deep Zooming + * + *

+ *

+ * OpenSeadragon is provides an html interface for creating + * deep zoom user interfaces. The simplest examples include deep + * zoom for large resolution images, and complex examples include + * zoomable map interfaces driven by SVG files. + *

+ * + * @author
(c) 2011 Christopher Thatcher + * @author
(c) 2010 OpenSeadragon Team + * @author
(c) 2010 CodePlex Foundation + * + *

+ * Original license preserved below:
+ *

  * ----------------------------------------------------------------------------
  * 
  *  License: New BSD License (BSD)
@@ -37,11 +54,21 @@
  *  POSSIBILITY OF SUCH DAMAGE.
  * 
  * ----------------------------------------------------------------------------
- *
+ * 
+ *

**/ + /** + * The root namespace for OpenSeadragon. All utility methods and classes + * are defined on or below this namespace. The OpenSeadragon namespace will + * only be defined once even if mutliple versions are loaded on the page in + * succession. + * @namespace + * @name OpenSeadragon + * @exports $ as OpenSeadragon + */ OpenSeadragon = window.OpenSeadragon || (function(){ - + //Taken from jquery 1.6.1 // [[Class]] -> type pairs var class2type = { @@ -120,36 +147,52 @@ OpenSeadragon = window.OpenSeadragon || (function(){ }()); -(function( $ ){ - +(function( $ ){ + + /** + * @static + * @ignore + */ $.SIGNAL = "----seadragon----"; - $.delegate = function(object, method) { + /** + * Invokes the the method as if it where a method belonging to the object. + * @param {Object} object + * @param {Function} method + */ + $.delegate = function( object, method ) { return function() { - if (arguments === undefined) + if ( arguments === undefined ) arguments = []; - return method.apply(object, arguments); + return method.apply( object, arguments ); }; }; - - //Taken from jQuery 1.6.1: + + /** + * Taken from jQuery 1.6.1, see the jQuery documentation + */ $.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; + var options, + name, + src, + copy, + copyIsArray, + clone, + target = arguments[ 0 ] || {}, + length = arguments.length, + deep = false, + i = 1; // Handle a deep copy situation if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; + deep = target; + target = arguments[ 1 ] || {}; // skip the boolean and the target i = 2; } // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !OpenSeadragon.isFunction(target) ) { + if ( typeof target !== "object" && !OpenSeadragon.isFunction( target ) ) { target = {}; } @@ -161,7 +204,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){ for ( ; i < length; i++ ) { // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { + if ( ( options = arguments[ i ] ) != null ) { // Extend the base object for ( name in options ) { src = target[ name ]; @@ -173,13 +216,13 @@ OpenSeadragon = window.OpenSeadragon || (function(){ } // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( OpenSeadragon.isPlainObject(copy) || (copyIsArray = OpenSeadragon.isArray(copy)) ) ) { + if ( deep && copy && ( OpenSeadragon.isPlainObject( copy ) || ( copyIsArray = OpenSeadragon.isArray( copy ) ) ) ) { if ( copyIsArray ) { copyIsArray = false; - clone = src && OpenSeadragon.isArray(src) ? src : []; + clone = src && OpenSeadragon.isArray( src ) ? src : []; } else { - clone = src && OpenSeadragon.isPlainObject(src) ? src : {}; + clone = src && OpenSeadragon.isPlainObject( src ) ? src : {}; } // Never move original objects, clone them @@ -198,10 +241,16 @@ OpenSeadragon = window.OpenSeadragon || (function(){ }; //The following functions are originally from the Openseadragon Utils - //module but have been moved to Openseadragon to avoid the Utils anti- + //module but have been moved to Openseadragon to avoid the 'Utils' anti- //pattern. Not all of the code is A-grade compared to equivalent functions // from libraries like jquery, but until we need better we'll leave those //orignally developed by the project. + + /** + * An enumeration of Browser vendors including UNKNOWN, IE, FIREFOX, + * SAFARI, CHROME, and OPERA. + * @static + */ $.BROWSERS = { UNKNOWN: 0, IE: 1, @@ -211,6 +260,13 @@ OpenSeadragon = window.OpenSeadragon || (function(){ OPERA: 5 }; + /** + * The current browser vendor, version, and related information regarding + * detected features. Features include
+ * 'alpha' - Does the browser support image alpha + * transparency.
+ * @static + */ $.Browser = { vendor: $.BROWSERS.UNKNOWN, version: 0, @@ -233,7 +289,8 @@ OpenSeadragon = window.OpenSeadragon || (function(){ URLPARAMS = {}; (function() { - + //A small auto-executing routine to determine the browser vendor, + //version and supporting feature sets. var app = navigator.appName, ver = navigator.appVersion, ua = navigator.userAgent; @@ -277,8 +334,8 @@ OpenSeadragon = window.OpenSeadragon || (function(){ break; } - - var query = window.location.search.substring( 1 ), // ignore '?' + // ignore '?' portion of query string + var query = window.location.search.substring( 1 ), parts = query.split('&'), part, sep, @@ -294,7 +351,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){ } } - //determine if this browser supports + //determine if this browser supports image alpha transparency $.Browser.alpha = !( $.Browser.vendor == $.BROWSERS.IE || ( $.Browser.vendor == $.BROWSERS.CHROME && @@ -304,16 +361,28 @@ OpenSeadragon = window.OpenSeadragon || (function(){ })(); - //TODO: $.Debug is often used inside a try/catch block which generally + //TODO: $.console is often used inside a try/catch block which generally // prevents allowings errors to occur with detection until a debugger // is attached. Although I've been guilty of the same anti-pattern // I eventually was convinced that errors should naturally propogate in // all but the most special cases. - $.Debug = window.console ? window.console : function(){}; + /** + * A convenient alias for console when available, and a simple null + * function when console is unavailable. + * @static + */ + $.console = window.console ? window.console : function(){}; $.extend( $, { + /** + * Returns a DOM Element for the given id or element. + * @function + * @name OpenSeadragon.getElement + * @param {String|Element} element Accepts an id or element. + * @returns {Element} The element with the given id, null, or the element itself. + */ getElement: function( element ) { if ( typeof ( element ) == "string") { element = document.getElementById( element ); @@ -321,6 +390,13 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return element; }, + /** + * @function + * @name OpenSeadragon.getOffsetParent + * @param {Element} element + * @param {Boolean} [isFixed] + * @returns {Element} + */ getOffsetParent: function( element, isFixed ) { if ( isFixed && element != document.body ) { return document.body; @@ -329,6 +405,12 @@ OpenSeadragon = window.OpenSeadragon || (function(){ } }, + /** + * @function + * @name OpenSeadragon.getElementPosition + * @param {Element|String} element + * @returns {Point} + */ getElementPosition: function( element ) { var result = new $.Point(), isFixed, @@ -355,6 +437,12 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return result; }, + /** + * @function + * @name OpenSeadragon.getElementSize + * @param {Element|String} element + * @returns {Point} + */ getElementSize: function( element ) { element = $.getElement( element ); @@ -364,6 +452,12 @@ OpenSeadragon = window.OpenSeadragon || (function(){ ); }, + /** + * @function + * @name OpenSeadragon.getElementStyle + * @param {Element|String} element + * @returns {CSSStyle} + */ getElementStyle: function( element ) { element = $.getElement( element ); @@ -376,10 +470,22 @@ OpenSeadragon = window.OpenSeadragon || (function(){ } }, + /** + * @function + * @name OpenSeadragon.getEvent + * @param {Event} [event] + * @returns {Event} + */ getEvent: function( event ) { return event ? event : window.event; }, + /** + * @function + * @name OpenSeadragon.getMousePosition + * @param {Event} [event] + * @returns {Point} + */ getMousePosition: function( event ) { var result = new $.Point(); @@ -406,6 +512,11 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return result; }, + /** + * @function + * @name OpenSeadragon.getPageScroll + * @returns {Point} + */ getPageScroll: function() { var result = new $.Point(), docElmt = document.documentElement || {}, @@ -425,6 +536,11 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return result; }, + /** + * @function + * @name OpenSeadragon.getWindowSize + * @returns {Point} + */ getWindowSize: function() { var result = new $.Point(), docElmt = document.documentElement || {}, @@ -446,11 +562,23 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return result; }, + /** + * @function + * @name OpenSeadragon.imageFormatSupported + * @param {String} [extension] + * @returns {Boolean} + */ imageFormatSupported: function( extension ) { extension = extension ? extension : ""; return !!FILEFORMATS[ extension.toLowerCase() ]; }, + /** + * @function + * @name OpenSeadragon.makeCenteredNode + * @param {Element|String} element + * @returns {Element} + */ makeCenteredNode: function( element ) { var div = $.makeNeutralElement( "div" ), @@ -488,6 +616,12 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return div; }, + /** + * @function + * @name OpenSeadragon.makeNeutralElement + * @param {String} tagName + * @returns {Element} + */ makeNeutralElement: function( tagName ) { var element = document.createElement( tagName ), style = element.style; @@ -501,6 +635,12 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return element; }, + /** + * @function + * @name OpenSeadragon.makeTransparentImage + * @param {String} src + * @returns {Element} + */ makeTransparentImage: function( src ) { var img = $.makeNeutralElement( "img" ), element = null; @@ -535,6 +675,13 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return element; }, + /** + * @function + * @name OpenSeadragon.setElementOpacity + * @param {Element|String} element + * @param {Number} opacity + * @param {Boolean} [usesAlpha] + */ setElementOpacity: function( element, opacity, usesAlpha ) { var previousFilter, @@ -575,6 +722,15 @@ OpenSeadragon = window.OpenSeadragon || (function(){ } }, + /** + * @function + * @name OpenSeadragon.addEvent + * @param {Element|String} element + * @param {String} eventName + * @param {Function} handler + * @param {Boolean} [useCapture] + * @throws {Error} + */ addEvent: function( element, eventName, handler, useCapture ) { element = $.getElement( element ); @@ -594,6 +750,15 @@ OpenSeadragon = window.OpenSeadragon || (function(){ } }, + /** + * @function + * @name OpenSeadragon.removeEvent + * @param {Element|String} element + * @param {String} eventName + * @param {Function} handler + * @param {Boolean} [useCapture] + * @throws {Error} + */ removeEvent: function( element, eventName, handler, useCapture ) { element = $.getElement( element ); @@ -613,17 +778,29 @@ OpenSeadragon = window.OpenSeadragon || (function(){ } }, + /** + * @function + * @name OpenSeadragon.cancelEvent + * @param {Event} [event] + */ cancelEvent: function( event ) { event = $.getEvent( event ); if ( event.preventDefault ) { - event.preventDefault(); // W3C for preventing default + // W3C for preventing default + event.preventDefault(); } - - event.cancel = true; // legacy for preventing default - event.returnValue = false; // IE for preventing default + // legacy for preventing default + event.cancel = true; + // IE for preventing default + event.returnValue = false; }, + /** + * @function + * @name OpenSeadragon.stopEvent + * @param {Event} [event] + */ stopEvent: function( event ) { event = $.getEvent( event ); @@ -634,6 +811,14 @@ OpenSeadragon = window.OpenSeadragon || (function(){ event.cancelBubble = true; // IE for stopping propagation }, + /** + * @function + * @name OpenSeadragon.createCallback + * @param {Object} object + * @param {Function} method + * @param [args] any additional arguments are passed as arguments to the created callback + * @returns {Function} + */ createCallback: function( object, method ) { //TODO: This pattern is painful to use and debug. It's much cleaner // to use pinning plus anonymous functions. Get rid of this @@ -655,11 +840,23 @@ OpenSeadragon = window.OpenSeadragon || (function(){ }; }, + /** + * @function + * @name OpenSeadragon.getUrlParameter + * @param {String} key + * @returns {String} The value of the url parameter or null if no param matches. + */ getUrlParameter: function( key ) { var value = URLPARAMS[ key ]; return value ? value : null; }, + /** + * @function + * @name OpenSeadragon.makeAjaxRequest + * @param {String} url + * @param {Function} [callback] + */ makeAjaxRequest: function( url, callback ) { var async = typeof( callback ) == "function", request = null, @@ -699,6 +896,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){ if ( async ) { + /** @ignore */ request.onreadystatechange = function() { if ( request.readyState == 4) { request.onreadystatechange = new function() { }; @@ -728,6 +926,13 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return async ? null : request; }, + /** + * Parses an XML string into a DOM Document. + * @function + * @name OpenSeadragon.parseXml + * @param {String} string + * @returns {Document} + */ parseXml: function( string ) { //TODO: yet another example where we can determine the correct // implementation once at start-up instead of everytime we use @@ -759,61 +964,63 @@ OpenSeadragon = window.OpenSeadragon || (function(){ (function($){ +/** + * @class + */ +$.EventHandler = function() { + this.events = {}; +}; - $.EventHandler = function() { - this.events = {}; - }; +$.EventHandler.prototype = { - $.EventHandler.prototype = { - - addHandler: function( id, handler ) { - var events = this.events[ id ]; - if( !events ){ - this.events[ id ] = events = []; - } - events[ events.length ] = handler; - }, - - removeHandler: function( id, handler ) { - //Start Thatcher - unneccessary indirection. Also, because events were - // - not actually being removed, we need to add the code - // - to do the removal ourselves. TODO - var events = this.events[ id ]; - if ( !events ){ - return; - } - //End Thatcher - }, - - getHandler: function( id ) { - var events = this.events[ id ]; - if ( !events || !events.length ){ - return null; - } - events = events.length === 1 ? - [ events[ 0 ] ] : - Array.apply( null, events ); - return function( source, args ) { - var i, - length = events.length; - for ( i = 0; i < length; i++ ) { - events[ i ]( source, args ); - } - }; - }, - - raiseEvent: function( eventName, eventArgs ) { - var handler = this.getHandler( eventName ); - - if ( handler ) { - if ( !eventArgs ) { - eventArgs = new Object(); - } - - handler( this, eventArgs ); - } + addHandler: function( id, handler ) { + var events = this.events[ id ]; + if( !events ){ + this.events[ id ] = events = []; } - }; + events[ events.length ] = handler; + }, + + removeHandler: function( id, handler ) { + //Start Thatcher - unneccessary indirection. Also, because events were + // - not actually being removed, we need to add the code + // - to do the removal ourselves. TODO + var events = this.events[ id ]; + if ( !events ){ + return; + } + //End Thatcher + }, + + getHandler: function( id ) { + var events = this.events[ id ]; + if ( !events || !events.length ){ + return null; + } + events = events.length === 1 ? + [ events[ 0 ] ] : + Array.apply( null, events ); + return function( source, args ) { + var i, + length = events.length; + for ( i = 0; i < length; i++ ) { + events[ i ]( source, args ); + } + }; + }, + + raiseEvent: function( eventName, eventArgs ) { + var handler = this.getHandler( eventName ); + + if ( handler ) { + if ( !eventArgs ) { + eventArgs = new Object(); + } + + handler( this, eventArgs ); + } + } +}; }( OpenSeadragon )); @@ -833,7 +1040,9 @@ OpenSeadragon = window.OpenSeadragon || (function(){ ieTrackersActive = {}, // dictionary from hash to MouseTracker ieTrackersCapturing = []; // list of trackers interested in capture - + /** + * @class + */ $.MouseTracker = function (elmt, clickTimeThreshold, clickDistThreshold) { //Start Thatcher - TODO: remove local function definitions in favor of // - a global closure for MouseTracker so the number @@ -986,7 +1195,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){ self.enterHandler(self, getMouseRelative(event, elmt), buttonDownElmt, buttonDownAny); } catch (e) { - $.Debug.error(e.name + + $.console.error(e.name + " while executing enter handler: " + e.message, e); } } @@ -1012,7 +1221,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){ self.exitHandler(self, getMouseRelative(event, elmt), buttonDownElmt, buttonDownAny); } catch (e) { - $.Debug.error(e.name + + $.console.error(e.name + " while executing exit handler: " + e.message, e); } } @@ -1035,7 +1244,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){ try { self.pressHandler(self, getMouseRelative(event, elmt)); } catch (e) { - $.Debug.error(e.name + + $.console.error(e.name + " while executing press handler: " + e.message, e); } } @@ -1069,7 +1278,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){ self.releaseHandler(self, getMouseRelative(event, elmt), insideElmtPress, insideElmtRelease); } catch (e) { - $.Debug.error(e.name + + $.console.error(e.name + " while executing release handler: " + e.message, e); } } @@ -1152,7 +1361,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){ try { self.scrollHandler(self, getMouseRelative(event, elmt), nDelta, event.shiftKey); } catch (e) { - $.Debug.error(e.name + + $.console.error(e.name + " while executing scroll handler: " + e.message, e); } @@ -1178,7 +1387,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){ self.clickHandler(self, getMouseRelative(event, elmt), quick, event.shiftKey); } catch (e) { - $.Debug.error(e.name + + $.console.error(e.name + " while executing click handler: " + e.message, e); } } @@ -1200,7 +1409,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){ event.shiftKey ); } catch (e) { - $.Debug.error( + $.console.error( e.name + " while executing drag handler: " + e.message, @@ -1240,6 +1449,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){ } /** + * @private * Returns true if elmtB is a child node of elmtA, or if they're equal. */ function isChild( elmtA, elmtB ) { @@ -1277,7 +1487,12 @@ OpenSeadragon = window.OpenSeadragon || (function(){ (function( $ ){ - +/** + * An enumeration of supported locations where controls can be anchored, + * including NONE, TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT, and BOTTOM_LEFT. + * The anchoring is always relative to the container + * @static + */ $.ControlAnchor = { NONE: 0, TOP_LEFT: 1, @@ -1286,6 +1501,24 @@ $.ControlAnchor = { BOTTOM_LEFT: 4 }; +/** + * A Control represents any interface element which is meant to allow the user + * to interact with the zoomable interface. Any control can be anchored to any + * element. + * @class + * @param {Element} elmt - the contol element to be anchored in the container. + * @param {OpenSeadragon.ControlAnchor} anchor - the location to anchor at. + * @param {Element} container - the element to control will be anchored too. + * + * @property {Element} elmt - the element providing the user interface with + * some type of control. Eg a zoom-in button + * @property {OpenSeadragon.ControlAnchor} anchor - the position of the control + * relative to the container. + * @property {Element} container - the element within with the control is + * positioned. + * @property {Element} wrapper - a nuetral element surrounding the control + * element. + */ $.Control = function ( elmt, anchor, container ) { this.elmt = elmt; this.anchor = anchor; @@ -1312,21 +1545,40 @@ $.Control = function ( elmt, anchor, container ) { $.Control.prototype = { + /** + * Removes the control from the container. + * @function + */ destroy: function() { this.wrapper.removeChild( this.elmt ); this.container.removeChild( this.wrapper ); }, + /** + * Determines if the control is currently visible. + * @function + * @return {Boolean} true if currenly visible, false otherwise. + */ isVisible: function() { return this.wrapper.style.display != "none"; }, + /** + * Toggles the visibility of the control. + * @function + * @param {Boolean} visible - true to make visible, false to hide. + */ setVisible: function( visible ) { this.wrapper.style.display = visible ? "inline-block" : "none"; }, + /** + * Sets the opacity level for the control. + * @function + * @param {Number} opactiy - a value between 1 and 0 inclusively. + */ setOpacity: function( opacity ) { if ( this.elmt[ $.SIGNAL ] && $.Browser.vendor == $.BROWSERS.IE ) { $.setElementOpacity( this.elmt, opacity, true ); @@ -1340,7 +1592,7 @@ $.Control.prototype = { (function( $ ){ /** - * OpenSeadragon Viewer + * @class * * The main point of entry into creating a zoomable image on the page. * @@ -1726,7 +1978,7 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, { this._lastOpenEndTime = +new Date(); if ( this._lastOpenStartTime < viewer._lastOpenStartTime ) { - $.Debug.log( "Ignoring out-of-date open." ); + $.console.log( "Ignoring out-of-date open." ); this.raiseEvent( "ignore" ); return; } @@ -1747,7 +1999,8 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, { this.viewport, this.canvas ); - this.profiler = new $.Profiler(); + + //this.profiler = new $.Profiler(); this._animating = false; this._forceRedraw = true; @@ -1790,7 +2043,7 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, { this.source = null; this.viewport = null; this.drawer = null; - this.profiler = null; + //this.profiler = null; this.canvas.innerHTML = ""; }, @@ -2337,6 +2590,9 @@ $.extend( $, { (function( $ ){ +/** + * @class + */ $.Point = function( x, y ) { this.x = typeof ( x ) == "number" ? x : 0; this.y = typeof ( y ) == "number" ? y : 0; @@ -2406,91 +2662,10 @@ $.Point.prototype = { (function( $ ){ -$.Profiler = function() { - - this.midUpdate = false; - this.numUpdates = 0; - - this.lastBeginTime = null; - this.lastEndTime = null; - - this.minUpdateTime = Infinity; - this.avgUpdateTime = 0; - this.maxUpdateTime = 0; - - this.minIdleTime = Infinity; - this.avgIdleTime = 0; - this.maxIdleTime = 0; -}; - -$.Profiler.prototype = { - - beginUpdate: function() { - if (this.midUpdate) { - this.endUpdate(); - } - - this.midUpdate = true; - this.lastBeginTime = new Date().getTime(); - - if (this.numUpdates < 1) { - return; // this is the first update - } - - var time = this.lastBeginTime - this.lastEndTime; - - this.avgIdleTime = (this.avgIdleTime * (this.numUpdates - 1) + time) / this.numUpdates; - - if (time < this.minIdleTime) { - this.minIdleTime = time; - } - if (time > this.maxIdleTime) { - this.maxIdleTime = time; - } - }, - - endUpdate: function() { - if (!this.midUpdate) { - return; - } - - this.lastEndTime = new Date().getTime(); - this.midUpdate = false; - - var time = this.lastEndTime - this.lastBeginTime; - - this.numUpdates++; - this.avgUpdateTime = (this.avgUpdateTime * (this.numUpdates - 1) + time) / this.numUpdates; - - if (time < this.minUpdateTime) { - this.minUpdateTime = time; - } - if (time > this.maxUpdateTime) { - this.maxUpdateTime = time; - } - }, - - clearProfile: function() { - this.midUpdate = false; - this.numUpdates = 0; - - this.lastBeginTime = null; - this.lastEndTime = null; - - this.minUpdateTime = Infinity; - this.avgUpdateTime = 0; - this.maxUpdateTime = 0; - - this.minIdleTime = Infinity; - this.avgIdleTime = 0; - this.maxIdleTime = 0; - } -}; - -}( OpenSeadragon )); - -(function( $ ){ +/** + * @class + */ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLevel ) { this.aspectRatio = width / height; this.dimensions = new $.Point( width, height ); @@ -2567,7 +2742,9 @@ $.TileSource.prototype = { (function( $ ){ - +/** + * @class + */ $.DziTileSource = function( width, height, tileSize, tileOverlap, tilesUrl, fileFormat, displayRects ) { var i, rect, @@ -2641,6 +2818,9 @@ $.extend( $.DziTileSource.prototype, $.TileSource.prototype, { } }); +/** + * @static + */ $.DziTileSourceHelper = { createFromXml: function( xmlUrl, xmlString, callback ) { @@ -2821,8 +3001,13 @@ $.DziTileSourceHelper = { }( OpenSeadragon )); + (function( $ ){ +/** + * An enumeration of button states including, REST, GROUP, HOVER, and DOWN + * @static + */ $.ButtonState = { REST: 0, GROUP: 1, @@ -2830,6 +3015,18 @@ $.ButtonState = { DOWN: 3 }; +/** + * Manages events, hover states for individual buttons, tool-tips, as well + * as fading the bottons out when the user has not interacted with them + * for a specified period. + * @class + * @param {Object} options + * @param {String} options.tooltip + * @param {String} options.srcRest URL of image to use in 'rest' state + * @param {String} options.srcGroup URL of image to use in 'up' state + * @param {String} options.srcHover URL of image to use in 'hover' state + * @param {String} options.srcDown URL of image to use in 'domn' state + */ $.Button = function( options ) { var _this = this; @@ -3061,7 +3258,7 @@ function outTo( button, newState ) { (function( $ ){ /** - * OpenSeadragon ButtonGroup + * @class * * Manages events on groups of buttons. * @@ -3142,6 +3339,9 @@ $.ButtonGroup.prototype = { (function( $ ){ +/** + * @class + */ $.Rect = function( x, y, width, height ) { this.x = typeof ( x ) == "number" ? x : 0; this.y = typeof ( y ) == "number" ? y : 0; @@ -3199,6 +3399,9 @@ $.Rect.prototype = { (function( $ ){ +/** + * @class + */ $.DisplayRect = function( x, y, width, height, minLevel, maxLevel ) { $.Rect.apply( this, [ x, y, width, height ] ); @@ -3212,6 +3415,9 @@ $.extend( $.DisplayRect.prototype, $.Rect.prototype ); (function( $ ){ +/** + * @class + */ $.Spring = function( options ) { var args = arguments; @@ -3297,6 +3503,9 @@ function transform( stiffness, x ) { (function( $ ){ +/** + * @class + */ $.Tile = function(level, x, y, bounds, exists, url) { this.level = level; this.x = x; @@ -3334,7 +3543,7 @@ $.Tile.prototype = { size = this.size.apply( Math.ceil ); if ( !this.loaded ) { - $.Debug.warn( + $.console.warn( "Attempting to draw tile %s when it's not yet loaded.", this.toString() ); @@ -3370,7 +3579,7 @@ $.Tile.prototype = { size = this.size; if (!this.loaded) { - $.Debug.warn( + $.console.warn( "Attempting to draw tile %s when it's not yet loaded.", this.toString() ); @@ -3397,6 +3606,12 @@ $.Tile.prototype = { (function( $ ){ + /** + * An enumeration of positions that an overlay may be assigned relative + * to the viewport including CENTER, TOP_LEFT (default), TOP, TOP_RIGHT, + * RIGHT, BOTTOM_RIGHT, BOTTOM, BOTTOM_LEFT, and LEFT. + * @static + */ $.OverlayPlacement = { CENTER: 0, TOP_LEFT: 1, @@ -3409,6 +3624,9 @@ $.Tile.prototype = { LEFT: 8 }; + /** + * @class + */ $.Overlay = function( elmt, location, placement ) { this.elmt = elmt; this.scales = location instanceof $.Rect; @@ -3562,6 +3780,9 @@ var QUOTA = 100, USE_CANVAS = $.isFunction( document.createElement( "canvas" ).getContext ) && SUBPIXEL_RENDERING; +/** + * @class + */ $.Drawer = function(source, viewport, elmt) { this.container = $.getElement( elmt ); @@ -4328,7 +4549,11 @@ function numberOfTiles( drawer, level ){ }( OpenSeadragon )); (function( $ ){ - + + +/** + * @class + */ $.Viewport = function( options ) { var options; @@ -4377,16 +4602,19 @@ $.Viewport = function( options ) { }; $.Viewport.prototype = { + getHomeZoom: function() { var aspectFactor = this.contentAspect / this.getAspectRatio(); - return (aspectFactor >= 1) ? 1 : aspectFactor; + return ( aspectFactor >= 1 ) ? + 1 : + aspectFactor; }, getMinZoom: function() { var homeZoom = this.getHomeZoom() zoom = this.minZoomImageRatio * homeZoom; - return Math.min(zoom, homeZoom); + return Math.min( zoom, homeZoom ); }, getMaxZoom: function() { @@ -4394,7 +4622,7 @@ $.Viewport.prototype = { this.contentSize.x * this.maxZoomPixelRatio / this.containerSize.x; - return Math.max(zoom, this.getHomeZoom()); + return Math.max( zoom, this.getHomeZoom() ); }, getAspectRatio: function() { @@ -4402,12 +4630,15 @@ $.Viewport.prototype = { }, getContainerSize: function() { - return new $.Point(this.containerSize.x, this.containerSize.y); + return new $.Point( + this.containerSize.x, + this.containerSize.y + ); }, getBounds: function( current ) { - var center = this.getCenter(current), - width = 1.0 / this.getZoom(current), + var center = this.getCenter( current ), + width = 1.0 / this.getZoom( current ), height = width / this.getAspectRatio(); return new $.Rect( @@ -4436,9 +4667,9 @@ $.Viewport.prototype = { deltaZoomPixels, deltaZoomPoints; - if (current) { + if ( current ) { return centerCurrent; - } else if (!this.zoomPoint) { + } else if ( !this.zoomPoint ) { return centerTarget; } @@ -4531,6 +4762,9 @@ $.Viewport.prototype = { this.applyConstraints( immediately ); }, + /** + * + */ fitBounds: function( bounds, immediately ) { var aspect = this.getAspectRatio(), center = bounds.getCenter(), @@ -4545,7 +4779,7 @@ $.Viewport.prototype = { newZoom, referencePoint; - if (newBounds.getAspectRatio() >= aspect) { + if ( newBounds.getAspectRatio() >= aspect ) { newBounds.height = bounds.width / aspect; newBounds.y = center.y - newBounds.height / 2; } else { @@ -4553,13 +4787,13 @@ $.Viewport.prototype = { newBounds.x = center.x - newBounds.width / 2; } - this.panTo(this.getCenter(true), true); - this.zoomTo(this.getZoom(true), null, true); + this.panTo( this.getCenter( true ), true ); + this.zoomTo( this.getZoom( true ), null, true ); oldBounds = this.getBounds(); oldZoom = this.getZoom(); newZoom = 1.0 / newBounds.width; - if (newZoom == oldZoom || newBounds.width == oldBounds.width) { + if ( newZoom == oldZoom || newBounds.width == oldBounds.width ) { this.panTo( center, immediately ); return; } @@ -4579,25 +4813,27 @@ $.Viewport.prototype = { this.zoomTo( newZoom, referencePoint, immediately ); }, - goHome: function(immediately) { + goHome: function( immediately ) { var center = this.getCenter(); if ( this.wrapHorizontal ) { - center.x = (1 + (center.x % 1)) % 1; - this.centerSpringX.resetTo(center.x); + center.x = ( 1 + ( center.x % 1 ) ) % 1; + this.centerSpringX.resetTo( center.x ); this.centerSpringX.update(); } if ( this.wrapVertical ) { - center.y = (this.contentHeight + (center.y % this.contentHeight)) % this.contentHeight; - this.centerSpringY.resetTo(center.y); + center.y = ( + this.contentHeight + ( center.y % this.contentHeight ) + ) % this.contentHeight; + this.centerSpringY.resetTo( center.y ); this.centerSpringY.update(); } - this.fitBounds(this.homeBounds, immediately); + this.fitBounds( this.homeBounds, immediately ); }, - panBy: function(delta, immediately) { + panBy: function( delta, immediately ) { var center = new $.Point( this.centerSpringX.target.value, this.centerSpringY.target.value @@ -4605,44 +4841,49 @@ $.Viewport.prototype = { this.panTo( center.plus( delta ), immediately ); }, - panTo: function(center, immediately) { - if (immediately) { - this.centerSpringX.resetTo(center.x); - this.centerSpringY.resetTo(center.y); + panTo: function( center, immediately ) { + if ( immediately ) { + this.centerSpringX.resetTo( center.x ); + this.centerSpringY.resetTo( center.y ); } else { - this.centerSpringX.springTo(center.x); - this.centerSpringY.springTo(center.y); + this.centerSpringX.springTo( center.x ); + this.centerSpringY.springTo( center.y ); } }, - zoomBy: function(factor, refPoint, immediately) { - this.zoomTo(this.zoomSpring.target.value * factor, refPoint, immediately); + zoomBy: function( factor, refPoint, immediately ) { + this.zoomTo( this.zoomSpring.target.value * factor, refPoint, immediately ); }, - zoomTo: function(zoom, refPoint, immediately) { + zoomTo: function( zoom, refPoint, immediately ) { - if (immediately) { - this.zoomSpring.resetTo(zoom); + if ( immediately ) { + this.zoomSpring.resetTo( zoom ); } else { - this.zoomSpring.springTo(zoom); + this.zoomSpring.springTo( zoom ); } - this.zoomPoint = refPoint instanceof $.Point ? refPoint : null; + this.zoomPoint = refPoint instanceof $.Point ? + refPoint : + null; }, - resize: function(newContainerSize, maintain) { + resize: function( newContainerSize, maintain ) { var oldBounds = this.getBounds(), newBounds = oldBounds, widthDeltaFactor = newContainerSize.x / this.containerSize.x; - this.containerSize = new $.Point(newContainerSize.x, newContainerSize.y); + this.containerSize = new $.Point( + newContainerSize.x, + newContainerSize.y + ); if (maintain) { newBounds.width = oldBounds.width * widthDeltaFactor; newBounds.height = newBounds.width / this.getAspectRatio(); } - this.fitBounds(newBounds, true); + this.fitBounds( newBounds, true ); }, update: function() { @@ -4655,14 +4896,14 @@ $.Viewport.prototype = { deltaZoomPoints; if (this.zoomPoint) { - oldZoomPixel = this.pixelFromPoint(this.zoomPoint, true); + oldZoomPixel = this.pixelFromPoint( this.zoomPoint, true ); } this.zoomSpring.update(); if (this.zoomPoint && this.zoomSpring.current.value != oldZoom) { newZoomPixel = this.pixelFromPoint( this.zoomPoint, true ); - deltaZoomPixels = newZoomPixel.minus( oldZoomPixel); + deltaZoomPixels = newZoomPixel.minus( oldZoomPixel ); deltaZoomPoints = this.deltaPointsFromPixels( deltaZoomPixels, true ); this.centerSpringX.shiftBy( deltaZoomPoints.x ); @@ -4680,19 +4921,19 @@ $.Viewport.prototype = { }, - deltaPixelsFromPoints: function(deltaPoints, current) { + deltaPixelsFromPoints: function( deltaPoints, current ) { return deltaPoints.times( this.containerSize.x * this.getZoom( current ) ); }, - deltaPointsFromPixels: function(deltaPixels, current) { + deltaPointsFromPixels: function( deltaPixels, current ) { return deltaPixels.divide( this.containerSize.x * this.getZoom( current ) ); }, - pixelFromPoint: function(point, current) { + pixelFromPoint: function( point, current ) { var bounds = this.getBounds( current ); return point.minus( bounds.getTopLeft() @@ -4701,7 +4942,7 @@ $.Viewport.prototype = { ); }, - pointFromPixel: function(pixel, current) { + pointFromPixel: function( pixel, current ) { var bounds = this.getBounds( current ); return pixel.divide( this.containerSize.x / bounds.width diff --git a/src/button.js b/src/button.js index 4115783b..680c3c31 100644 --- a/src/button.js +++ b/src/button.js @@ -1,6 +1,11 @@ + (function( $ ){ +/** + * An enumeration of button states including, REST, GROUP, HOVER, and DOWN + * @static + */ $.ButtonState = { REST: 0, GROUP: 1, @@ -8,6 +13,18 @@ $.ButtonState = { DOWN: 3 }; +/** + * Manages events, hover states for individual buttons, tool-tips, as well + * as fading the bottons out when the user has not interacted with them + * for a specified period. + * @class + * @param {Object} options + * @param {String} options.tooltip + * @param {String} options.srcRest URL of image to use in 'rest' state + * @param {String} options.srcGroup URL of image to use in 'up' state + * @param {String} options.srcHover URL of image to use in 'hover' state + * @param {String} options.srcDown URL of image to use in 'domn' state + */ $.Button = function( options ) { var _this = this; diff --git a/src/buttongroup.js b/src/buttongroup.js index 2fd29799..c1f1f774 100644 --- a/src/buttongroup.js +++ b/src/buttongroup.js @@ -1,7 +1,7 @@ (function( $ ){ /** - * OpenSeadragon ButtonGroup + * @class * * Manages events on groups of buttons. * diff --git a/src/control.js b/src/control.js index 87d10aa9..3d244cb9 100644 --- a/src/control.js +++ b/src/control.js @@ -1,7 +1,12 @@ (function( $ ){ - +/** + * An enumeration of supported locations where controls can be anchored, + * including NONE, TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT, and BOTTOM_LEFT. + * The anchoring is always relative to the container + * @static + */ $.ControlAnchor = { NONE: 0, TOP_LEFT: 1, @@ -10,6 +15,24 @@ $.ControlAnchor = { BOTTOM_LEFT: 4 }; +/** + * A Control represents any interface element which is meant to allow the user + * to interact with the zoomable interface. Any control can be anchored to any + * element. + * @class + * @param {Element} elmt - the contol element to be anchored in the container. + * @param {OpenSeadragon.ControlAnchor} anchor - the location to anchor at. + * @param {Element} container - the element to control will be anchored too. + * + * @property {Element} elmt - the element providing the user interface with + * some type of control. Eg a zoom-in button + * @property {OpenSeadragon.ControlAnchor} anchor - the position of the control + * relative to the container. + * @property {Element} container - the element within with the control is + * positioned. + * @property {Element} wrapper - a nuetral element surrounding the control + * element. + */ $.Control = function ( elmt, anchor, container ) { this.elmt = elmt; this.anchor = anchor; @@ -36,21 +59,40 @@ $.Control = function ( elmt, anchor, container ) { $.Control.prototype = { + /** + * Removes the control from the container. + * @function + */ destroy: function() { this.wrapper.removeChild( this.elmt ); this.container.removeChild( this.wrapper ); }, + /** + * Determines if the control is currently visible. + * @function + * @return {Boolean} true if currenly visible, false otherwise. + */ isVisible: function() { return this.wrapper.style.display != "none"; }, + /** + * Toggles the visibility of the control. + * @function + * @param {Boolean} visible - true to make visible, false to hide. + */ setVisible: function( visible ) { this.wrapper.style.display = visible ? "inline-block" : "none"; }, + /** + * Sets the opacity level for the control. + * @function + * @param {Number} opactiy - a value between 1 and 0 inclusively. + */ setOpacity: function( opacity ) { if ( this.elmt[ $.SIGNAL ] && $.Browser.vendor == $.BROWSERS.IE ) { $.setElementOpacity( this.elmt, opacity, true ); diff --git a/src/displayrectangle.js b/src/displayrectangle.js index 6966c9b3..5171028e 100644 --- a/src/displayrectangle.js +++ b/src/displayrectangle.js @@ -1,6 +1,9 @@ (function( $ ){ +/** + * @class + */ $.DisplayRect = function( x, y, width, height, minLevel, maxLevel ) { $.Rect.apply( this, [ x, y, width, height ] ); diff --git a/src/drawer.js b/src/drawer.js index c1ec117e..085b6a18 100644 --- a/src/drawer.js +++ b/src/drawer.js @@ -21,6 +21,9 @@ var QUOTA = 100, USE_CANVAS = $.isFunction( document.createElement( "canvas" ).getContext ) && SUBPIXEL_RENDERING; +/** + * @class + */ $.Drawer = function(source, viewport, elmt) { this.container = $.getElement( elmt ); diff --git a/src/dzitilesource.js b/src/dzitilesource.js index da4fe4b9..209211ee 100644 --- a/src/dzitilesource.js +++ b/src/dzitilesource.js @@ -1,7 +1,9 @@ (function( $ ){ - +/** + * @class + */ $.DziTileSource = function( width, height, tileSize, tileOverlap, tilesUrl, fileFormat, displayRects ) { var i, rect, @@ -75,6 +77,9 @@ $.extend( $.DziTileSource.prototype, $.TileSource.prototype, { } }); +/** + * @static + */ $.DziTileSourceHelper = { createFromXml: function( xmlUrl, xmlString, callback ) { diff --git a/src/eventhandler.js b/src/eventhandler.js index c49c7d43..446e2fff 100644 --- a/src/eventhandler.js +++ b/src/eventhandler.js @@ -1,60 +1,62 @@ (function($){ +/** + * @class + */ +$.EventHandler = function() { + this.events = {}; +}; - $.EventHandler = function() { - this.events = {}; - }; +$.EventHandler.prototype = { - $.EventHandler.prototype = { - - addHandler: function( id, handler ) { - var events = this.events[ id ]; - if( !events ){ - this.events[ id ] = events = []; - } - events[ events.length ] = handler; - }, - - removeHandler: function( id, handler ) { - //Start Thatcher - unneccessary indirection. Also, because events were - // - not actually being removed, we need to add the code - // - to do the removal ourselves. TODO - var events = this.events[ id ]; - if ( !events ){ - return; - } - //End Thatcher - }, - - getHandler: function( id ) { - var events = this.events[ id ]; - if ( !events || !events.length ){ - return null; - } - events = events.length === 1 ? - [ events[ 0 ] ] : - Array.apply( null, events ); - return function( source, args ) { - var i, - length = events.length; - for ( i = 0; i < length; i++ ) { - events[ i ]( source, args ); - } - }; - }, - - raiseEvent: function( eventName, eventArgs ) { - var handler = this.getHandler( eventName ); - - if ( handler ) { - if ( !eventArgs ) { - eventArgs = new Object(); - } - - handler( this, eventArgs ); - } + addHandler: function( id, handler ) { + var events = this.events[ id ]; + if( !events ){ + this.events[ id ] = events = []; } - }; + events[ events.length ] = handler; + }, + + removeHandler: function( id, handler ) { + //Start Thatcher - unneccessary indirection. Also, because events were + // - not actually being removed, we need to add the code + // - to do the removal ourselves. TODO + var events = this.events[ id ]; + if ( !events ){ + return; + } + //End Thatcher + }, + + getHandler: function( id ) { + var events = this.events[ id ]; + if ( !events || !events.length ){ + return null; + } + events = events.length === 1 ? + [ events[ 0 ] ] : + Array.apply( null, events ); + return function( source, args ) { + var i, + length = events.length; + for ( i = 0; i < length; i++ ) { + events[ i ]( source, args ); + } + }; + }, + + raiseEvent: function( eventName, eventArgs ) { + var handler = this.getHandler( eventName ); + + if ( handler ) { + if ( !eventArgs ) { + eventArgs = new Object(); + } + + handler( this, eventArgs ); + } + } +}; }( OpenSeadragon )); diff --git a/src/mousetracker.js b/src/mousetracker.js index ef774db0..7b503588 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -15,7 +15,9 @@ ieTrackersActive = {}, // dictionary from hash to MouseTracker ieTrackersCapturing = []; // list of trackers interested in capture - + /** + * @class + */ $.MouseTracker = function (elmt, clickTimeThreshold, clickDistThreshold) { //Start Thatcher - TODO: remove local function definitions in favor of // - a global closure for MouseTracker so the number @@ -168,7 +170,7 @@ self.enterHandler(self, getMouseRelative(event, elmt), buttonDownElmt, buttonDownAny); } catch (e) { - $.Debug.error(e.name + + $.console.error(e.name + " while executing enter handler: " + e.message, e); } } @@ -194,7 +196,7 @@ self.exitHandler(self, getMouseRelative(event, elmt), buttonDownElmt, buttonDownAny); } catch (e) { - $.Debug.error(e.name + + $.console.error(e.name + " while executing exit handler: " + e.message, e); } } @@ -217,7 +219,7 @@ try { self.pressHandler(self, getMouseRelative(event, elmt)); } catch (e) { - $.Debug.error(e.name + + $.console.error(e.name + " while executing press handler: " + e.message, e); } } @@ -251,7 +253,7 @@ self.releaseHandler(self, getMouseRelative(event, elmt), insideElmtPress, insideElmtRelease); } catch (e) { - $.Debug.error(e.name + + $.console.error(e.name + " while executing release handler: " + e.message, e); } } @@ -334,7 +336,7 @@ try { self.scrollHandler(self, getMouseRelative(event, elmt), nDelta, event.shiftKey); } catch (e) { - $.Debug.error(e.name + + $.console.error(e.name + " while executing scroll handler: " + e.message, e); } @@ -360,7 +362,7 @@ self.clickHandler(self, getMouseRelative(event, elmt), quick, event.shiftKey); } catch (e) { - $.Debug.error(e.name + + $.console.error(e.name + " while executing click handler: " + e.message, e); } } @@ -382,7 +384,7 @@ event.shiftKey ); } catch (e) { - $.Debug.error( + $.console.error( e.name + " while executing drag handler: " + e.message, @@ -422,6 +424,7 @@ } /** + * @private * Returns true if elmtB is a child node of elmtA, or if they're equal. */ function isChild( elmtA, elmtB ) { diff --git a/src/openseadragon.js b/src/openseadragon.js index 76a886a8..1c710964 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -1,9 +1,26 @@ /** - * (c) 2011 Christopher Thatcher - * (c) 2010 OpenSeadragon - * (c) 2010 CodePlex Foundation + * @version OpenSeadragon @VERSION@ * - * OpenSeadragon @VERSION@ + * @fileOverview + *

+ * + * OpenSeadragon - Javascript Deep Zooming + * + *

+ *

+ * OpenSeadragon is provides an html interface for creating + * deep zoom user interfaces. The simplest examples include deep + * zoom for large resolution images, and complex examples include + * zoomable map interfaces driven by SVG files. + *

+ * + * @author
(c) 2011 Christopher Thatcher + * @author
(c) 2010 OpenSeadragon Team + * @author
(c) 2010 CodePlex Foundation + * + *

+ * Original license preserved below:
+ *

  * ----------------------------------------------------------------------------
  * 
  *  License: New BSD License (BSD)
@@ -37,11 +54,21 @@
  *  POSSIBILITY OF SUCH DAMAGE.
  * 
  * ----------------------------------------------------------------------------
- *
+ * 
+ *

**/ + /** + * The root namespace for OpenSeadragon. All utility methods and classes + * are defined on or below this namespace. The OpenSeadragon namespace will + * only be defined once even if mutliple versions are loaded on the page in + * succession. + * @namespace + * @name OpenSeadragon + * @exports $ as OpenSeadragon + */ OpenSeadragon = window.OpenSeadragon || (function(){ - + //Taken from jquery 1.6.1 // [[Class]] -> type pairs var class2type = { @@ -120,36 +147,52 @@ OpenSeadragon = window.OpenSeadragon || (function(){ }()); -(function( $ ){ - +(function( $ ){ + + /** + * @static + * @ignore + */ $.SIGNAL = "----seadragon----"; - $.delegate = function(object, method) { + /** + * Invokes the the method as if it where a method belonging to the object. + * @param {Object} object + * @param {Function} method + */ + $.delegate = function( object, method ) { return function() { - if (arguments === undefined) + if ( arguments === undefined ) arguments = []; - return method.apply(object, arguments); + return method.apply( object, arguments ); }; }; - - //Taken from jQuery 1.6.1: + + /** + * Taken from jQuery 1.6.1, see the jQuery documentation + */ $.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; + var options, + name, + src, + copy, + copyIsArray, + clone, + target = arguments[ 0 ] || {}, + length = arguments.length, + deep = false, + i = 1; // Handle a deep copy situation if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; + deep = target; + target = arguments[ 1 ] || {}; // skip the boolean and the target i = 2; } // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !OpenSeadragon.isFunction(target) ) { + if ( typeof target !== "object" && !OpenSeadragon.isFunction( target ) ) { target = {}; } @@ -161,7 +204,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){ for ( ; i < length; i++ ) { // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { + if ( ( options = arguments[ i ] ) != null ) { // Extend the base object for ( name in options ) { src = target[ name ]; @@ -173,13 +216,13 @@ OpenSeadragon = window.OpenSeadragon || (function(){ } // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( OpenSeadragon.isPlainObject(copy) || (copyIsArray = OpenSeadragon.isArray(copy)) ) ) { + if ( deep && copy && ( OpenSeadragon.isPlainObject( copy ) || ( copyIsArray = OpenSeadragon.isArray( copy ) ) ) ) { if ( copyIsArray ) { copyIsArray = false; - clone = src && OpenSeadragon.isArray(src) ? src : []; + clone = src && OpenSeadragon.isArray( src ) ? src : []; } else { - clone = src && OpenSeadragon.isPlainObject(src) ? src : {}; + clone = src && OpenSeadragon.isPlainObject( src ) ? src : {}; } // Never move original objects, clone them @@ -198,10 +241,16 @@ OpenSeadragon = window.OpenSeadragon || (function(){ }; //The following functions are originally from the Openseadragon Utils - //module but have been moved to Openseadragon to avoid the Utils anti- + //module but have been moved to Openseadragon to avoid the 'Utils' anti- //pattern. Not all of the code is A-grade compared to equivalent functions // from libraries like jquery, but until we need better we'll leave those //orignally developed by the project. + + /** + * An enumeration of Browser vendors including UNKNOWN, IE, FIREFOX, + * SAFARI, CHROME, and OPERA. + * @static + */ $.BROWSERS = { UNKNOWN: 0, IE: 1, @@ -211,6 +260,13 @@ OpenSeadragon = window.OpenSeadragon || (function(){ OPERA: 5 }; + /** + * The current browser vendor, version, and related information regarding + * detected features. Features include
+ * 'alpha' - Does the browser support image alpha + * transparency.
+ * @static + */ $.Browser = { vendor: $.BROWSERS.UNKNOWN, version: 0, @@ -233,7 +289,8 @@ OpenSeadragon = window.OpenSeadragon || (function(){ URLPARAMS = {}; (function() { - + //A small auto-executing routine to determine the browser vendor, + //version and supporting feature sets. var app = navigator.appName, ver = navigator.appVersion, ua = navigator.userAgent; @@ -277,8 +334,8 @@ OpenSeadragon = window.OpenSeadragon || (function(){ break; } - - var query = window.location.search.substring( 1 ), // ignore '?' + // ignore '?' portion of query string + var query = window.location.search.substring( 1 ), parts = query.split('&'), part, sep, @@ -294,7 +351,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){ } } - //determine if this browser supports + //determine if this browser supports image alpha transparency $.Browser.alpha = !( $.Browser.vendor == $.BROWSERS.IE || ( $.Browser.vendor == $.BROWSERS.CHROME && @@ -304,16 +361,28 @@ OpenSeadragon = window.OpenSeadragon || (function(){ })(); - //TODO: $.Debug is often used inside a try/catch block which generally + //TODO: $.console is often used inside a try/catch block which generally // prevents allowings errors to occur with detection until a debugger // is attached. Although I've been guilty of the same anti-pattern // I eventually was convinced that errors should naturally propogate in // all but the most special cases. - $.Debug = window.console ? window.console : function(){}; + /** + * A convenient alias for console when available, and a simple null + * function when console is unavailable. + * @static + */ + $.console = window.console ? window.console : function(){}; $.extend( $, { + /** + * Returns a DOM Element for the given id or element. + * @function + * @name OpenSeadragon.getElement + * @param {String|Element} element Accepts an id or element. + * @returns {Element} The element with the given id, null, or the element itself. + */ getElement: function( element ) { if ( typeof ( element ) == "string") { element = document.getElementById( element ); @@ -321,6 +390,13 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return element; }, + /** + * @function + * @name OpenSeadragon.getOffsetParent + * @param {Element} element + * @param {Boolean} [isFixed] + * @returns {Element} + */ getOffsetParent: function( element, isFixed ) { if ( isFixed && element != document.body ) { return document.body; @@ -329,6 +405,12 @@ OpenSeadragon = window.OpenSeadragon || (function(){ } }, + /** + * @function + * @name OpenSeadragon.getElementPosition + * @param {Element|String} element + * @returns {Point} + */ getElementPosition: function( element ) { var result = new $.Point(), isFixed, @@ -355,6 +437,12 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return result; }, + /** + * @function + * @name OpenSeadragon.getElementSize + * @param {Element|String} element + * @returns {Point} + */ getElementSize: function( element ) { element = $.getElement( element ); @@ -364,6 +452,12 @@ OpenSeadragon = window.OpenSeadragon || (function(){ ); }, + /** + * @function + * @name OpenSeadragon.getElementStyle + * @param {Element|String} element + * @returns {CSSStyle} + */ getElementStyle: function( element ) { element = $.getElement( element ); @@ -376,10 +470,22 @@ OpenSeadragon = window.OpenSeadragon || (function(){ } }, + /** + * @function + * @name OpenSeadragon.getEvent + * @param {Event} [event] + * @returns {Event} + */ getEvent: function( event ) { return event ? event : window.event; }, + /** + * @function + * @name OpenSeadragon.getMousePosition + * @param {Event} [event] + * @returns {Point} + */ getMousePosition: function( event ) { var result = new $.Point(); @@ -406,6 +512,11 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return result; }, + /** + * @function + * @name OpenSeadragon.getPageScroll + * @returns {Point} + */ getPageScroll: function() { var result = new $.Point(), docElmt = document.documentElement || {}, @@ -425,6 +536,11 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return result; }, + /** + * @function + * @name OpenSeadragon.getWindowSize + * @returns {Point} + */ getWindowSize: function() { var result = new $.Point(), docElmt = document.documentElement || {}, @@ -446,11 +562,23 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return result; }, + /** + * @function + * @name OpenSeadragon.imageFormatSupported + * @param {String} [extension] + * @returns {Boolean} + */ imageFormatSupported: function( extension ) { extension = extension ? extension : ""; return !!FILEFORMATS[ extension.toLowerCase() ]; }, + /** + * @function + * @name OpenSeadragon.makeCenteredNode + * @param {Element|String} element + * @returns {Element} + */ makeCenteredNode: function( element ) { var div = $.makeNeutralElement( "div" ), @@ -488,6 +616,12 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return div; }, + /** + * @function + * @name OpenSeadragon.makeNeutralElement + * @param {String} tagName + * @returns {Element} + */ makeNeutralElement: function( tagName ) { var element = document.createElement( tagName ), style = element.style; @@ -501,6 +635,12 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return element; }, + /** + * @function + * @name OpenSeadragon.makeTransparentImage + * @param {String} src + * @returns {Element} + */ makeTransparentImage: function( src ) { var img = $.makeNeutralElement( "img" ), element = null; @@ -535,6 +675,13 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return element; }, + /** + * @function + * @name OpenSeadragon.setElementOpacity + * @param {Element|String} element + * @param {Number} opacity + * @param {Boolean} [usesAlpha] + */ setElementOpacity: function( element, opacity, usesAlpha ) { var previousFilter, @@ -575,6 +722,15 @@ OpenSeadragon = window.OpenSeadragon || (function(){ } }, + /** + * @function + * @name OpenSeadragon.addEvent + * @param {Element|String} element + * @param {String} eventName + * @param {Function} handler + * @param {Boolean} [useCapture] + * @throws {Error} + */ addEvent: function( element, eventName, handler, useCapture ) { element = $.getElement( element ); @@ -594,6 +750,15 @@ OpenSeadragon = window.OpenSeadragon || (function(){ } }, + /** + * @function + * @name OpenSeadragon.removeEvent + * @param {Element|String} element + * @param {String} eventName + * @param {Function} handler + * @param {Boolean} [useCapture] + * @throws {Error} + */ removeEvent: function( element, eventName, handler, useCapture ) { element = $.getElement( element ); @@ -613,17 +778,29 @@ OpenSeadragon = window.OpenSeadragon || (function(){ } }, + /** + * @function + * @name OpenSeadragon.cancelEvent + * @param {Event} [event] + */ cancelEvent: function( event ) { event = $.getEvent( event ); if ( event.preventDefault ) { - event.preventDefault(); // W3C for preventing default + // W3C for preventing default + event.preventDefault(); } - - event.cancel = true; // legacy for preventing default - event.returnValue = false; // IE for preventing default + // legacy for preventing default + event.cancel = true; + // IE for preventing default + event.returnValue = false; }, + /** + * @function + * @name OpenSeadragon.stopEvent + * @param {Event} [event] + */ stopEvent: function( event ) { event = $.getEvent( event ); @@ -634,6 +811,14 @@ OpenSeadragon = window.OpenSeadragon || (function(){ event.cancelBubble = true; // IE for stopping propagation }, + /** + * @function + * @name OpenSeadragon.createCallback + * @param {Object} object + * @param {Function} method + * @param [args] any additional arguments are passed as arguments to the created callback + * @returns {Function} + */ createCallback: function( object, method ) { //TODO: This pattern is painful to use and debug. It's much cleaner // to use pinning plus anonymous functions. Get rid of this @@ -655,11 +840,23 @@ OpenSeadragon = window.OpenSeadragon || (function(){ }; }, + /** + * @function + * @name OpenSeadragon.getUrlParameter + * @param {String} key + * @returns {String} The value of the url parameter or null if no param matches. + */ getUrlParameter: function( key ) { var value = URLPARAMS[ key ]; return value ? value : null; }, + /** + * @function + * @name OpenSeadragon.makeAjaxRequest + * @param {String} url + * @param {Function} [callback] + */ makeAjaxRequest: function( url, callback ) { var async = typeof( callback ) == "function", request = null, @@ -699,6 +896,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){ if ( async ) { + /** @ignore */ request.onreadystatechange = function() { if ( request.readyState == 4) { request.onreadystatechange = new function() { }; @@ -728,6 +926,13 @@ OpenSeadragon = window.OpenSeadragon || (function(){ return async ? null : request; }, + /** + * Parses an XML string into a DOM Document. + * @function + * @name OpenSeadragon.parseXml + * @param {String} string + * @returns {Document} + */ parseXml: function( string ) { //TODO: yet another example where we can determine the correct // implementation once at start-up instead of everytime we use diff --git a/src/overlay.js b/src/overlay.js index 7bbcb53f..9f135b6e 100644 --- a/src/overlay.js +++ b/src/overlay.js @@ -1,6 +1,12 @@ (function( $ ){ + /** + * An enumeration of positions that an overlay may be assigned relative + * to the viewport including CENTER, TOP_LEFT (default), TOP, TOP_RIGHT, + * RIGHT, BOTTOM_RIGHT, BOTTOM, BOTTOM_LEFT, and LEFT. + * @static + */ $.OverlayPlacement = { CENTER: 0, TOP_LEFT: 1, @@ -13,6 +19,9 @@ LEFT: 8 }; + /** + * @class + */ $.Overlay = function( elmt, location, placement ) { this.elmt = elmt; this.scales = location instanceof $.Rect; diff --git a/src/point.js b/src/point.js index 21c11b70..dbea4b98 100644 --- a/src/point.js +++ b/src/point.js @@ -1,6 +1,9 @@ (function( $ ){ +/** + * @class + */ $.Point = function( x, y ) { this.x = typeof ( x ) == "number" ? x : 0; this.y = typeof ( y ) == "number" ? y : 0; diff --git a/src/profiler.js b/src/profiler.js index 17703ec8..0c0f0b5e 100644 --- a/src/profiler.js +++ b/src/profiler.js @@ -1,6 +1,9 @@ (function( $ ){ +/** + * @class + */ $.Profiler = function() { this.midUpdate = false; diff --git a/src/rectangle.js b/src/rectangle.js index a4311982..af3c942c 100644 --- a/src/rectangle.js +++ b/src/rectangle.js @@ -1,6 +1,9 @@ (function( $ ){ +/** + * @class + */ $.Rect = function( x, y, width, height ) { this.x = typeof ( x ) == "number" ? x : 0; this.y = typeof ( y ) == "number" ? y : 0; diff --git a/src/spring.js b/src/spring.js index 54634333..c00e70b1 100644 --- a/src/spring.js +++ b/src/spring.js @@ -1,6 +1,9 @@ (function( $ ){ +/** + * @class + */ $.Spring = function( options ) { var args = arguments; diff --git a/src/tile.js b/src/tile.js index 24922af1..f9a7cb69 100644 --- a/src/tile.js +++ b/src/tile.js @@ -1,6 +1,9 @@ (function( $ ){ +/** + * @class + */ $.Tile = function(level, x, y, bounds, exists, url) { this.level = level; this.x = x; @@ -38,7 +41,7 @@ $.Tile.prototype = { size = this.size.apply( Math.ceil ); if ( !this.loaded ) { - $.Debug.warn( + $.console.warn( "Attempting to draw tile %s when it's not yet loaded.", this.toString() ); @@ -74,7 +77,7 @@ $.Tile.prototype = { size = this.size; if (!this.loaded) { - $.Debug.warn( + $.console.warn( "Attempting to draw tile %s when it's not yet loaded.", this.toString() ); diff --git a/src/tilesource.js b/src/tilesource.js index f51f4589..be667dc1 100644 --- a/src/tilesource.js +++ b/src/tilesource.js @@ -1,6 +1,10 @@ (function( $ ){ + +/** + * @class + */ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLevel ) { this.aspectRatio = width / height; this.dimensions = new $.Point( width, height ); diff --git a/src/viewer.js b/src/viewer.js index 5de59ca2..42ee974d 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -1,7 +1,7 @@ (function( $ ){ /** - * OpenSeadragon Viewer + * @class * * The main point of entry into creating a zoomable image on the page. * @@ -387,7 +387,7 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, { this._lastOpenEndTime = +new Date(); if ( this._lastOpenStartTime < viewer._lastOpenStartTime ) { - $.Debug.log( "Ignoring out-of-date open." ); + $.console.log( "Ignoring out-of-date open." ); this.raiseEvent( "ignore" ); return; } @@ -408,7 +408,8 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, { this.viewport, this.canvas ); - this.profiler = new $.Profiler(); + + //this.profiler = new $.Profiler(); this._animating = false; this._forceRedraw = true; @@ -451,7 +452,7 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, { this.source = null; this.viewport = null; this.drawer = null; - this.profiler = null; + //this.profiler = null; this.canvas.innerHTML = ""; }, diff --git a/src/viewport.js b/src/viewport.js index cb4d28a5..27f1b8e3 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -1,6 +1,10 @@ (function( $ ){ - + + +/** + * @class + */ $.Viewport = function( options ) { var options; @@ -49,16 +53,19 @@ $.Viewport = function( options ) { }; $.Viewport.prototype = { + getHomeZoom: function() { var aspectFactor = this.contentAspect / this.getAspectRatio(); - return (aspectFactor >= 1) ? 1 : aspectFactor; + return ( aspectFactor >= 1 ) ? + 1 : + aspectFactor; }, getMinZoom: function() { var homeZoom = this.getHomeZoom() zoom = this.minZoomImageRatio * homeZoom; - return Math.min(zoom, homeZoom); + return Math.min( zoom, homeZoom ); }, getMaxZoom: function() { @@ -66,7 +73,7 @@ $.Viewport.prototype = { this.contentSize.x * this.maxZoomPixelRatio / this.containerSize.x; - return Math.max(zoom, this.getHomeZoom()); + return Math.max( zoom, this.getHomeZoom() ); }, getAspectRatio: function() { @@ -74,12 +81,15 @@ $.Viewport.prototype = { }, getContainerSize: function() { - return new $.Point(this.containerSize.x, this.containerSize.y); + return new $.Point( + this.containerSize.x, + this.containerSize.y + ); }, getBounds: function( current ) { - var center = this.getCenter(current), - width = 1.0 / this.getZoom(current), + var center = this.getCenter( current ), + width = 1.0 / this.getZoom( current ), height = width / this.getAspectRatio(); return new $.Rect( @@ -108,9 +118,9 @@ $.Viewport.prototype = { deltaZoomPixels, deltaZoomPoints; - if (current) { + if ( current ) { return centerCurrent; - } else if (!this.zoomPoint) { + } else if ( !this.zoomPoint ) { return centerTarget; } @@ -203,6 +213,9 @@ $.Viewport.prototype = { this.applyConstraints( immediately ); }, + /** + * + */ fitBounds: function( bounds, immediately ) { var aspect = this.getAspectRatio(), center = bounds.getCenter(), @@ -217,7 +230,7 @@ $.Viewport.prototype = { newZoom, referencePoint; - if (newBounds.getAspectRatio() >= aspect) { + if ( newBounds.getAspectRatio() >= aspect ) { newBounds.height = bounds.width / aspect; newBounds.y = center.y - newBounds.height / 2; } else { @@ -225,13 +238,13 @@ $.Viewport.prototype = { newBounds.x = center.x - newBounds.width / 2; } - this.panTo(this.getCenter(true), true); - this.zoomTo(this.getZoom(true), null, true); + this.panTo( this.getCenter( true ), true ); + this.zoomTo( this.getZoom( true ), null, true ); oldBounds = this.getBounds(); oldZoom = this.getZoom(); newZoom = 1.0 / newBounds.width; - if (newZoom == oldZoom || newBounds.width == oldBounds.width) { + if ( newZoom == oldZoom || newBounds.width == oldBounds.width ) { this.panTo( center, immediately ); return; } @@ -251,25 +264,27 @@ $.Viewport.prototype = { this.zoomTo( newZoom, referencePoint, immediately ); }, - goHome: function(immediately) { + goHome: function( immediately ) { var center = this.getCenter(); if ( this.wrapHorizontal ) { - center.x = (1 + (center.x % 1)) % 1; - this.centerSpringX.resetTo(center.x); + center.x = ( 1 + ( center.x % 1 ) ) % 1; + this.centerSpringX.resetTo( center.x ); this.centerSpringX.update(); } if ( this.wrapVertical ) { - center.y = (this.contentHeight + (center.y % this.contentHeight)) % this.contentHeight; - this.centerSpringY.resetTo(center.y); + center.y = ( + this.contentHeight + ( center.y % this.contentHeight ) + ) % this.contentHeight; + this.centerSpringY.resetTo( center.y ); this.centerSpringY.update(); } - this.fitBounds(this.homeBounds, immediately); + this.fitBounds( this.homeBounds, immediately ); }, - panBy: function(delta, immediately) { + panBy: function( delta, immediately ) { var center = new $.Point( this.centerSpringX.target.value, this.centerSpringY.target.value @@ -277,44 +292,49 @@ $.Viewport.prototype = { this.panTo( center.plus( delta ), immediately ); }, - panTo: function(center, immediately) { - if (immediately) { - this.centerSpringX.resetTo(center.x); - this.centerSpringY.resetTo(center.y); + panTo: function( center, immediately ) { + if ( immediately ) { + this.centerSpringX.resetTo( center.x ); + this.centerSpringY.resetTo( center.y ); } else { - this.centerSpringX.springTo(center.x); - this.centerSpringY.springTo(center.y); + this.centerSpringX.springTo( center.x ); + this.centerSpringY.springTo( center.y ); } }, - zoomBy: function(factor, refPoint, immediately) { - this.zoomTo(this.zoomSpring.target.value * factor, refPoint, immediately); + zoomBy: function( factor, refPoint, immediately ) { + this.zoomTo( this.zoomSpring.target.value * factor, refPoint, immediately ); }, - zoomTo: function(zoom, refPoint, immediately) { + zoomTo: function( zoom, refPoint, immediately ) { - if (immediately) { - this.zoomSpring.resetTo(zoom); + if ( immediately ) { + this.zoomSpring.resetTo( zoom ); } else { - this.zoomSpring.springTo(zoom); + this.zoomSpring.springTo( zoom ); } - this.zoomPoint = refPoint instanceof $.Point ? refPoint : null; + this.zoomPoint = refPoint instanceof $.Point ? + refPoint : + null; }, - resize: function(newContainerSize, maintain) { + resize: function( newContainerSize, maintain ) { var oldBounds = this.getBounds(), newBounds = oldBounds, widthDeltaFactor = newContainerSize.x / this.containerSize.x; - this.containerSize = new $.Point(newContainerSize.x, newContainerSize.y); + this.containerSize = new $.Point( + newContainerSize.x, + newContainerSize.y + ); if (maintain) { newBounds.width = oldBounds.width * widthDeltaFactor; newBounds.height = newBounds.width / this.getAspectRatio(); } - this.fitBounds(newBounds, true); + this.fitBounds( newBounds, true ); }, update: function() { @@ -327,14 +347,14 @@ $.Viewport.prototype = { deltaZoomPoints; if (this.zoomPoint) { - oldZoomPixel = this.pixelFromPoint(this.zoomPoint, true); + oldZoomPixel = this.pixelFromPoint( this.zoomPoint, true ); } this.zoomSpring.update(); if (this.zoomPoint && this.zoomSpring.current.value != oldZoom) { newZoomPixel = this.pixelFromPoint( this.zoomPoint, true ); - deltaZoomPixels = newZoomPixel.minus( oldZoomPixel); + deltaZoomPixels = newZoomPixel.minus( oldZoomPixel ); deltaZoomPoints = this.deltaPointsFromPixels( deltaZoomPixels, true ); this.centerSpringX.shiftBy( deltaZoomPoints.x ); @@ -352,19 +372,19 @@ $.Viewport.prototype = { }, - deltaPixelsFromPoints: function(deltaPoints, current) { + deltaPixelsFromPoints: function( deltaPoints, current ) { return deltaPoints.times( this.containerSize.x * this.getZoom( current ) ); }, - deltaPointsFromPixels: function(deltaPixels, current) { + deltaPointsFromPixels: function( deltaPixels, current ) { return deltaPixels.divide( this.containerSize.x * this.getZoom( current ) ); }, - pixelFromPoint: function(point, current) { + pixelFromPoint: function( point, current ) { var bounds = this.getBounds( current ); return point.minus( bounds.getTopLeft() @@ -373,7 +393,7 @@ $.Viewport.prototype = { ); }, - pointFromPixel: function(pixel, current) { + pointFromPixel: function( pixel, current ) { var bounds = this.getBounds( current ); return pixel.divide( this.containerSize.x / bounds.width