| /* |
| Copyright (c) 2004-2006, The Dojo Foundation |
| All Rights Reserved. |
| |
| Licensed under the Academic Free License version 2.1 or above OR the |
| modified BSD license. For more information on Dojo licensing, see: |
| |
| http://dojotoolkit.org/community/licensing.shtml |
| */ |
| |
| dojo.provide("dojo.docs"); |
| dojo.require("dojo.io.*"); |
| dojo.require("dojo.event.topic"); |
| dojo.require("dojo.rpc.JotService"); |
| dojo.require("dojo.dom"); |
| dojo.require("dojo.uri.Uri"); |
| dojo.require("dojo.Deferred"); |
| dojo.require("dojo.DeferredList"); |
| |
| /* |
| * TODO: |
| * |
| * Package summary needs to compensate for "is" |
| * Handle host environments |
| * Deal with dojo.widget weirdness |
| * Parse parameters |
| * Limit function parameters to only the valid ones (Involves packing parameters onto meta during rewriting) |
| * |
| */ |
| |
| dojo.docs = new function() { |
| this._url = dojo.uri.dojoUri("docscripts"); |
| this._rpc = new dojo.rpc.JotService; |
| this._rpc.serviceUrl = dojo.uri.dojoUri("docscripts/jsonrpc.php"); |
| }; |
| dojo.lang.mixin(dojo.docs, { |
| _count: 0, |
| _callbacks: {function_names: []}, |
| _cache: {}, // Saves the JSON objects in cache |
| require: function(/*String*/ require, /*bool*/ sync) { |
| dojo.debug("require(): " + require); |
| var parts = require.split("/"); |
| |
| var size = parts.length; |
| var deferred = new dojo.Deferred; |
| var args = { |
| mimetype: "text/json", |
| load: function(type, data){ |
| dojo.debug("require(): loaded for " + require); |
| |
| if(parts[0] != "function_names") { |
| for(var i = 0, part; part = parts[i]; i++){ |
| data = data[part]; |
| } |
| } |
| deferred.callback(data); |
| }, |
| error: function(){ |
| deferred.errback(); |
| } |
| }; |
| |
| if(location.protocol == "file:"){ |
| if(size){ |
| if(parts[parts.length - 1] == "documentation"){ |
| parts[parts.length - 1] = "meta"; |
| } |
| |
| if(parts[0] == "function_names"){ |
| args.url = [this._url, "local_json", "function_names"].join("/"); |
| }else{ |
| var dirs = parts[0].split("."); |
| args.url = [this._url, "local_json", dirs[0]].join("/"); |
| if(dirs.length > 1){ |
| args.url = [args.url, dirs[1]].join("."); |
| } |
| } |
| } |
| } |
| |
| dojo.io.bind(args); |
| return deferred; |
| }, |
| getFunctionNames: function(){ |
| return this.require("function_names"); // dojo.Deferred |
| }, |
| unFormat: function(/*String*/ string){ |
| var fString = string; |
| if(string.charAt(string.length - 1) == "_"){ |
| fString = [string.substring(0, string.length - 1), "*"].join(""); |
| } |
| return fString; |
| }, |
| getMeta: function(/*String*/ pkg, /*String*/ name, /*Function*/ callback, /*String?*/ id){ |
| // summary: Gets information about a function in regards to its meta data |
| if(typeof name == "function"){ |
| // pId: a |
| // pkg: ignore |
| id = callback; |
| callback = name; |
| name = pkg; |
| pkg = null; |
| dojo.debug("getMeta(" + name + ")"); |
| }else{ |
| dojo.debug("getMeta(" + pkg + "/" + name + ")"); |
| } |
| |
| if(!id){ |
| id = "_"; |
| } |
| }, |
| _withPkg: function(/*String*/ type, /*Object*/ data, /*Object*/ evt, /*Object*/ input, /*String*/ newType){ |
| dojo.debug("_withPkg(" + evt.name + ") has package: " + data[0]); |
| evt.pkg = data[0]; |
| if("load" == type && evt.pkg){ |
| evt.type = newType; |
| }else{ |
| if(evt.callbacks && evt.callbacks.length){ |
| evt.callbacks.shift()("error", {}, evt, evt.input); |
| } |
| } |
| }, |
| _gotMeta: function(/*String*/ type, /*Object*/ data, /*Object*/ evt){ |
| dojo.debug("_gotMeta(" + evt.name + ")"); |
| |
| var cached = dojo.docs._getCache(evt.pkg, evt.name, "meta", "functions", evt.id); |
| if(cached.summary){ |
| data.summary = cached.summary; |
| } |
| if(evt.callbacks && evt.callbacks.length){ |
| evt.callbacks.shift()(type, data, evt, evt.input); |
| } |
| }, |
| getSrc: function(/*String*/ name, /*Function*/ callback, /*String?*/ id){ |
| // summary: Gets src file (created by the doc parser) |
| dojo.debug("getSrc(" + name + ")"); |
| if(!id){ |
| id = "_"; |
| } |
| }, |
| getDoc: function(/*String*/ name, /*Function*/ callback, /*String?*/ id){ |
| // summary: Gets external documentation stored on Jot for a given function |
| dojo.debug("getDoc(" + name + ")"); |
| |
| if(!id){ |
| id = "_"; |
| } |
| |
| var input = {}; |
| |
| input.type = "doc"; |
| input.name = name; |
| input.callbacks = [callback]; |
| }, |
| _gotDoc: function(/*String*/ type, /*Array*/ data, /*Object*/ evt, /*Object*/ input){ |
| dojo.debug("_gotDoc(" + evt.type + ")"); |
| |
| evt[evt.type] = data; |
| if(evt.expects && evt.expects.doc){ |
| for(var i = 0, expect; expect = evt.expects.doc[i]; i++){ |
| if(!(expect in evt)){ |
| dojo.debug("_gotDoc() waiting for more data"); |
| return; |
| } |
| } |
| } |
| |
| var cache = dojo.docs._getCache(evt.pkg, "meta", "functions", evt.name, evt.id, "meta"); |
| |
| var description = evt.fn.description; |
| cache.description = description; |
| data = { |
| returns: evt.fn.returns, |
| id: evt.id, |
| variables: [] |
| } |
| if(!cache.parameters){ |
| cache.parameters = {}; |
| } |
| for(var i = 0, param; param = evt.param[i]; i++){ |
| var fName = param["DocParamForm/name"]; |
| if(!cache.parameters[fName]){ |
| cache.parameters[fName] = {}; |
| } |
| cache.parameters[fName].description = param["DocParamForm/desc"] |
| } |
| |
| data.description = cache.description; |
| data.parameters = cache.parameters; |
| |
| evt.type = "doc"; |
| |
| if(evt.callbacks && evt.callbacks.length){ |
| evt.callbacks.shift()("load", data, evt, input); |
| } |
| }, |
| getPkgDoc: function(/*String*/ name, /*Function*/ callback){ |
| // summary: Gets external documentation stored on Jot for a given package |
| dojo.debug("getPkgDoc(" + name + ")"); |
| var input = {}; |
| }, |
| getPkgInfo: function(/*String*/ name, /*Function*/ callback){ |
| // summary: Gets a combination of the metadata and external documentation for a given package |
| dojo.debug("getPkgInfo(" + name + ")"); |
| |
| var input = { |
| expects: { |
| pkginfo: ["pkgmeta", "pkgdoc"] |
| }, |
| callback: callback |
| }; |
| dojo.docs.getPkgMeta(input, name, dojo.docs._getPkgInfo); |
| dojo.docs.getPkgDoc(input, name, dojo.docs._getPkgInfo); |
| }, |
| _getPkgInfo: function(/*String*/ type, /*Object*/ data, /*Object*/ evt){ |
| dojo.debug("_getPkgInfo() for " + evt.type); |
| var input = {}; |
| var results = {}; |
| if(typeof key == "object"){ |
| input = key; |
| input[evt.type] = data; |
| if(input.expects && input.expects.pkginfo){ |
| for(var i = 0, expect; expect = input.expects.pkginfo[i]; i++){ |
| if(!(expect in input)){ |
| dojo.debug("_getPkgInfo() waiting for more data"); |
| return; |
| } |
| } |
| } |
| results = input.pkgmeta; |
| results.description = input.pkgdoc; |
| } |
| |
| if(input.callback){ |
| input.callback("load", results, evt); |
| } |
| }, |
| getInfo: function(/*String*/ name, /*Function*/ callback){ |
| dojo.debug("getInfo(" + name + ")"); |
| var input = { |
| expects: { |
| "info": ["meta", "doc"] |
| }, |
| callback: callback |
| } |
| dojo.docs.getMeta(input, name, dojo.docs._getInfo); |
| dojo.docs.getDoc(input, name, dojo.docs._getInfo); |
| }, |
| _getInfo: function(/*String*/ type, /*String*/ data, /*Object*/ evt, /*Object*/ input){ |
| dojo.debug("_getInfo(" + evt.type + ")"); |
| if(input && input.expects && input.expects.info){ |
| input[evt.type] = data; |
| for(var i = 0, expect; expect = input.expects.info[i]; i++){ |
| if(!(expect in input)){ |
| dojo.debug("_getInfo() waiting for more data"); |
| return; |
| } |
| } |
| } |
| |
| if(input.callback){ |
| input.callback("load", dojo.docs._getCache(evt.pkg, "meta", "functions", evt.name, evt.id, "meta"), evt, input); |
| } |
| }, |
| _getMainText: function(/*String*/ text){ |
| // summary: Grabs the innerHTML from a Jot Rech Text node |
| dojo.debug("_getMainText()"); |
| return text.replace(/^<html[^<]*>/, "").replace(/<\/html>$/, "").replace(/<\w+\s*\/>/g, ""); |
| }, |
| getPackageMeta: function(/*Object*/ input){ |
| dojo.debug("getPackageMeta(): " + input.package); |
| return this.require(input.package + "/meta", input.sync); |
| }, |
| getFunctionMeta: function(/*Object*/ input){ |
| var package = input.package || ""; |
| var name = input.name; |
| var id = input.id || "_"; |
| dojo.debug("getFunctionMeta(): " + name); |
| |
| if(!name) return; |
| |
| if(package){ |
| return this.require(package + "/meta/functions/" + name + "/" + id + "/meta"); |
| }else{ |
| this.getFunctionNames(); |
| } |
| }, |
| getFunctionDocumentation: function(/*Object*/ input){ |
| var package = input.package || ""; |
| var name = input.name; |
| var id = input.id || "_"; |
| dojo.debug("getFunctionDocumentation(): " + name); |
| |
| if(!name) return; |
| |
| if(package){ |
| return this.require(package + "/meta/functions/" + name + "/" + id + "/documentation"); |
| } |
| }, |
| _onDocSearch: function(/*Object*/ input){ |
| var _this = this; |
| var name = input.name.toLowerCase(); |
| if(!name) return; |
| |
| this.getFunctionNames().addCallback(function(data){ |
| dojo.debug("_onDocSearch(): function names loaded for " + name); |
| |
| var output = []; |
| var list = []; |
| var closure = function(pkg, fn) { |
| return function(data){ |
| dojo.debug("_onDocSearch(): package meta loaded for: " + pkg); |
| if(data.functions){ |
| var functions = data.functions; |
| for(var key in functions){ |
| if(fn == key){ |
| var ids = functions[key]; |
| for(var id in ids){ |
| var fnMeta = ids[id]; |
| output.push({ |
| package: pkg, |
| name: fn, |
| id: id, |
| summary: fnMeta.summary |
| }); |
| } |
| } |
| } |
| } |
| return output; |
| } |
| } |
| |
| pkgLoop: |
| for(var pkg in data){ |
| if(pkg.toLowerCase() == name){ |
| name = pkg; |
| dojo.debug("_onDocSearch found a package"); |
| //dojo.docs._onDocSelectPackage(input); |
| return; |
| } |
| for(var i = 0, fn; fn = data[pkg][i]; i++){ |
| if(fn.toLowerCase().indexOf(name) != -1){ |
| dojo.debug("_onDocSearch(): Search matched " + fn); |
| var meta = _this.getPackageMeta({package: pkg}); |
| meta.addCallback(closure(pkg, fn)); |
| list.push(meta); |
| |
| // Build a list of all packages that need to be loaded and their loaded state. |
| continue pkgLoop; |
| } |
| } |
| } |
| |
| list = new dojo.DeferredList(list); |
| list.addCallback(function(results){ |
| dojo.debug("_onDocSearch(): All packages loaded"); |
| _this._printFunctionResults(results[0][1]); |
| }); |
| }); |
| }, |
| _onDocSearchFn: function(/*String*/ type, /*Array*/ data, /*Object*/ evt){ |
| dojo.debug("_onDocSearchFn(" + evt.name + ")"); |
| |
| var name = evt.name || evt.pkg; |
| |
| dojo.debug("_onDocSearchFn found a function"); |
| |
| evt.pkgs = packages; |
| evt.pkg = name; |
| evt.loaded = 0; |
| for(var i = 0, pkg; pkg = packages[i]; i++){ |
| dojo.docs.getPkgMeta(evt, pkg, dojo.docs._onDocResults); |
| } |
| }, |
| _onPkgResults: function(/*String*/ type, /*Object*/ data, /*Object*/ evt, /*Object*/ input){ |
| dojo.debug("_onPkgResults(" + evt.type + ")"); |
| var description = ""; |
| var path = ""; |
| var methods = {}; |
| var requires = {}; |
| if(input){ |
| input[evt.type] = data; |
| if(input.expects && input.expects.pkgresults){ |
| for(var i = 0, expect; expect = input.expects.pkgresults[i]; i++){ |
| if(!(expect in input)){ |
| dojo.debug("_onPkgResults() waiting for more data"); |
| return; |
| } |
| } |
| } |
| path = input.pkgdoc.path; |
| description = input.pkgdoc.description; |
| methods = input.pkgmeta.methods; |
| requires = input.pkgmeta.requires; |
| } |
| var pkg = evt.name.replace("_", "*"); |
| var results = { |
| path: path, |
| description: description, |
| size: 0, |
| methods: [], |
| pkg: pkg, |
| requires: requires |
| } |
| var rePrivate = /_[^.]+$/; |
| for(var method in methods){ |
| if(!rePrivate.test(method)){ |
| for(var pId in methods[method]){ |
| results.methods.push({ |
| pkg: pkg, |
| name: method, |
| id: pId, |
| summary: methods[method][pId].summary |
| }) |
| } |
| } |
| } |
| results.size = results.methods.length; |
| dojo.docs._printPkgResult(results); |
| }, |
| _onDocResults: function(/*String*/ type, /*Object*/ data, /*Object*/ evt, /*Object*/ input){ |
| dojo.debug("_onDocResults(" + evt.name + "/" + input.pkg + ") " + type); |
| ++input.loaded; |
| |
| if(input.loaded == input.pkgs.length){ |
| var pkgs = input.pkgs; |
| var name = input.pkg; |
| var results = {methods: []}; |
| var rePrivate = /_[^.]+$/; |
| data = dojo.docs._cache; |
| |
| for(var i = 0, pkg; pkg = pkgs[i]; i++){ |
| var methods = dojo.docs._getCache(pkg, "meta", "methods"); |
| for(var fn in methods){ |
| if(fn.toLowerCase().indexOf(name) == -1){ |
| continue; |
| } |
| if(fn != "requires" && !rePrivate.test(fn)){ |
| for(var pId in methods[fn]){ |
| var result = { |
| pkg: pkg, |
| name: fn, |
| id: "_", |
| summary: "" |
| } |
| if(methods[fn][pId].summary){ |
| result.summary = methods[fn][pId].summary; |
| } |
| results.methods.push(result); |
| } |
| } |
| } |
| } |
| |
| dojo.debug("Publishing docResults"); |
| dojo.docs._printFnResults(results); |
| } |
| }, |
| _printFunctionResults: function(results){ |
| dojo.debug("_printFnResults(): called"); |
| // summary: Call this function to send the /docs/function/results topic |
| }, |
| _printPkgResult: function(results){ |
| dojo.debug("_printPkgResult(): called"); |
| }, |
| _onDocSelectFunction: function(/*Object*/ input){ |
| // summary: Get doc, meta, and src |
| var name = input.name; |
| var package = input.package || ""; |
| var id = input.id || "_"; |
| dojo.debug("_onDocSelectFunction(" + name + ")"); |
| if(!name || !package) return false; |
| |
| var pkgMeta = this.getPackageMeta({package: package}); |
| var meta = this.getFunctionMeta({package: package, name: name, id: id}); |
| var doc = this.getFunctionDocumentation({package: package, name: name, id: id}); |
| |
| var list = new dojo.DeferredList([pkgMeta, meta, doc]); |
| list.addCallback(function(results){ |
| dojo.debug("_onDocSelectFunction() loaded"); |
| for(var i = 0, result; result = results[i]; i++){ |
| dojo.debugShallow(result[1]); |
| } |
| }); |
| |
| return list; |
| }, |
| _onDocSelectPackage: function(/*Object*/ input){ |
| dojo.debug("_onDocSelectPackage(" + input.name + ")") |
| input.expects = { |
| "pkgresults": ["pkgmeta", "pkgdoc"] |
| }; |
| dojo.docs.getPkgMeta(input, input.name, dojo.docs._onPkgResults); |
| dojo.docs.getPkgDoc(input, input.name, dojo.docs._onPkgResults); |
| }, |
| _onDocSelectResults: function(/*String*/ type, /*Object*/ data, /*Object*/ evt, /*Object*/ input){ |
| dojo.debug("_onDocSelectResults(" + evt.type + ", " + evt.name + ")"); |
| if(evt.type == "meta"){ |
| dojo.docs.getPkgMeta(input, evt.pkg, dojo.docs._onDocSelectResults); |
| } |
| if(input){ |
| input[evt.type] = data; |
| if(input.expects && input.expects.docresults){ |
| for(var i = 0, expect; expect = input.expects.docresults[i]; i++){ |
| if(!(expect in input)){ |
| dojo.debug("_onDocSelectResults() waiting for more data"); |
| return; |
| } |
| } |
| } |
| } |
| |
| dojo.docs._printFunctionDetail(input); |
| }, |
| |
| _printFunctionDetail: function(results) { |
| // summary: Call this function to send the /docs/function/detail topic event |
| }, |
| |
| selectFunction: function(/*String*/ name, /*String?*/ id){ |
| // summary: The combined information |
| }, |
| savePackage: function(/*Object*/ callbackObject, /*String*/ callback, /*Object*/ parameters){ |
| dojo.event.kwConnect({ |
| srcObj: dojo.docs, |
| srcFunc: "_savedPkgRpc", |
| targetObj: callbackObject, |
| targetFunc: callback, |
| once: true |
| }); |
| |
| var props = {}; |
| var cache = dojo.docs._getCache(parameters.pkg, "meta"); |
| |
| var i = 1; |
| |
| if(!cache.path){ |
| var path = "id"; |
| props[["pname", i].join("")] = "DocPkgForm/require"; |
| props[["pvalue", i++].join("")] = parameters.pkg; |
| }else{ |
| var path = cache.path; |
| } |
| |
| props.form = "//DocPkgForm"; |
| props.path = ["/WikiHome/DojoDotDoc/", path].join(""); |
| |
| if(parameters.description){ |
| props[["pname", i].join("")] = "main/text"; |
| props[["pvalue", i++].join("")] = parameters.description; |
| } |
| |
| dojo.docs._rpc.callRemote("saveForm", props).addCallbacks(dojo.docs._pkgRpc, dojo.docs._pkgRpc); |
| }, |
| _pkgRpc: function(data){ |
| if(data.name){ |
| dojo.docs._getCache(data["DocPkgForm/require"], "meta").path = data.name; |
| dojo.docs._savedPkgRpc("load"); |
| }else{ |
| dojo.docs._savedPkgRpc("error"); |
| } |
| }, |
| _savedPkgRpc: function(type){ |
| }, |
| functionPackages: function(/*String*/ name, /*Function*/ callback, /*Object*/ input){ |
| // summary: Gets the package associated with a function and stores it in the .pkg value of input |
| dojo.debug("functionPackages() name: " + name); |
| |
| if(!input){ |
| input = {}; |
| } |
| if(!input.callbacks){ |
| input.callbacks = []; |
| } |
| |
| input.type = "function_names"; |
| input.name = name; |
| input.callbacks.unshift(callback); |
| input.callbacks.unshift(dojo.docs._functionPackages); |
| }, |
| _functionPackages: function(/*String*/ type, /*Array*/ data, /*Object*/ evt){ |
| dojo.debug("_functionPackages() name: " + evt.name); |
| evt.pkg = ''; |
| |
| var results = []; |
| var data = dojo.docs._cache['function_names']; |
| for(var key in data){ |
| if(dojo.lang.inArray(data[key], evt.name)){ |
| dojo.debug("_functionPackages() package: " + key); |
| results.push(key); |
| } |
| } |
| |
| if(evt.callbacks && evt.callbacks.length){ |
| evt.callbacks.shift()(type, results, evt, evt.input); |
| } |
| }, |
| setUserName: function(/*String*/ name){ |
| dojo.docs._userName = name; |
| if(name && dojo.docs._password){ |
| dojo.docs._logIn(); |
| } |
| }, |
| setPassword: function(/*String*/ password){ |
| dojo.docs._password = password; |
| if(password && dojo.docs._userName){ |
| dojo.docs._logIn(); |
| } |
| }, |
| _logIn: function(){ |
| dojo.io.bind({ |
| url: dojo.docs._rpc.serviceUrl.toString(), |
| method: "post", |
| mimetype: "text/json", |
| content: { |
| username: dojo.docs._userName, |
| password: dojo.docs._password |
| }, |
| load: function(type, data){ |
| if(data.error){ |
| dojo.docs.logInSuccess(); |
| }else{ |
| dojo.docs.logInFailure(); |
| } |
| }, |
| error: function(){ |
| dojo.docs.logInFailure(); |
| } |
| }); |
| }, |
| logInSuccess: function(){}, |
| logInFailure: function(){}, |
| _set: function(/*Object*/ base, /*String...*/ keys, /*String*/ value){ |
| var args = []; |
| for(var i = 0, arg; arg = arguments[i]; i++){ |
| args.push(arg); |
| } |
| |
| if(args.length < 3) return; |
| base = args.shift(); |
| value = args.pop(); |
| var key = args.pop(); |
| for(var i = 0, arg; arg = args[i]; i++){ |
| if(typeof base[arg] != "object"){ |
| base[arg] = {}; |
| } |
| base = base[arg]; |
| } |
| base[key] = value; |
| }, |
| _getCache: function(/*String...*/ keys){ |
| var obj = dojo.docs._cache; |
| for(var i = 0; i < arguments.length; i++){ |
| var arg = arguments[i]; |
| if(!obj[arg]){ |
| obj[arg] = {}; |
| } |
| obj = obj[arg]; |
| } |
| return obj; |
| } |
| }); |
| |
| dojo.event.topic.subscribe("/docs/search", dojo.docs, "_onDocSearch"); |
| dojo.event.topic.subscribe("/docs/function/select", dojo.docs, "_onDocSelectFunction"); |
| dojo.event.topic.subscribe("/docs/package/select", dojo.docs, "_onDocSelectPackage"); |
| |
| dojo.event.topic.registerPublisher("/docs/function/results", dojo.docs, "_printFunctionResults"); |
| dojo.event.topic.registerPublisher("/docs/function/detail", dojo.docs, "_printFunctionDetail"); |
| dojo.event.topic.registerPublisher("/docs/package/detail", dojo.docs, "_printPkgResult"); |