/* 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(/^/, "").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");