/* 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.doc"); dojo.require("dojo.io.*"); dojo.require("dojo.event.topic"); dojo.require("dojo.rpc.JotService"); dojo.require("dojo.dom"); /* * 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) * Package display page * */ dojo.doc._count = 0; dojo.doc._keys = {}; dojo.doc._myKeys = []; dojo.doc._callbacks = {function_names: []}; dojo.doc._cache = {}; // Saves the JSON objects in cache dojo.doc._rpc = new dojo.rpc.JotService; dojo.doc._rpc.serviceUrl = "http://dojotoolkit.org/~pottedmeat/jsonrpc.php"; dojo.lang.mixin(dojo.doc, { functionNames: function(/*mixed*/ selectKey, /*Function*/ callback){ // summary: Returns an ordered list of package and function names. dojo.debug("functionNames()"); if(!selectKey){ selectKey = ++dojo.doc._count; } dojo.doc._buildCache({ type: "function_names", callbacks: [dojo.doc._functionNames, callback], selectKey: selectKey }); }, _functionNames: function(/*String*/ type, /*Array*/ data, /*Object*/ evt){ dojo.debug("_functionNames()"); var searchData = []; for(var key in data){ // Add the package if it doesn't exist in its children if(!dojo.lang.inArray(data[key], key)){ searchData.push([key, key]); } // Add the functions for(var pkg_key in data[key]){ searchData.push([data[key][pkg_key], data[key][pkg_key]]); } } searchData = searchData.sort(dojo.doc._sort); if(evt.callbacks && evt.callbacks.length){ var callback = evt.callbacks.shift(); callback.call(null, type, searchData, evt); } }, getMeta: function(/*mixed*/ selectKey, /*Function*/ callback, /*Function*/ name, /*String?*/ id){ // summary: Gets information about a function in regards to its meta data dojo.debug("getMeta(" + name + ")"); if(!selectKey){ selectKey = ++dojo.doc._count; } dojo.doc._buildCache({ type: "meta", callbacks: [callback], name: name, id: id, selectKey: selectKey }); }, _getMeta: function(/*String*/ type, /*Object*/ data, /*Object*/ evt){ dojo.debug("_getMeta(" + evt.name + ") has package: " + evt.pkg + " with: " + type); if("load" == type && evt.pkg){ evt.type = "meta"; dojo.doc._buildCache(evt); }else{ if(evt.callbacks && evt.callbacks.length){ var callback = evt.callbacks.shift(); callback.call(null, "error", {}, evt); } } }, getSrc: function(/*mixed*/ selectKey, /*Function*/ callback, /*String*/ name, /*String?*/ id){ // summary: Gets src file (created by the doc parser) dojo.debug("getSrc()"); if(!selectKey){ selectKey = ++dojo.doc._count; } dojo.doc._buildCache({ type: "src", callbacks: [callback], name: name, id: id, selectKey: selectKey }); }, _getSrc: function(/*String*/ type, /*Object*/ data, /*Object*/ evt){ dojo.debug("_getSrc()"); if(evt.pkg){ evt.type = "src"; dojo.doc._buildCache(evt); }else{ if(evt.callbacks && evt.callbacks.length){ var callback = evt.callbacks.shift(); callback.call(null, "error", {}, evt); } } }, getDoc: function(/*mixed*/ selectKey, /*Function*/ callback, /*String*/ name, /*String?*/ id){ // summary: Gets external documentation stored on jot dojo.debug("getDoc()"); if(!selectKey){ selectKey = ++dojo.doc._count; } var input = { type: "doc", callbacks: [callback], name: name, id: id, selectKey: selectKey } dojo.doc.functionPackage(dojo.doc._getDoc, input); }, _getDoc: function(/*String*/ type, /*Object*/ data, /*Object*/ evt){ dojo.debug("_getDoc(" + evt.pkg + "/" + evt.name + ")"); dojo.doc._keys[evt.selectKey] = {count: 0}; var search = {}; search.forFormName = "DocFnForm"; search.limit = 1; if(!evt.id){ search.filter = "it/DocFnForm/require = '" + evt.pkg + "' and it/DocFnForm/name = '" + evt.name + "' and not(it/DocFnForm/id)"; }else{ search.filter = "it/DocFnForm/require = '" + evt.pkg + "' and it/DocFnForm/name = '" + evt.name + "' and it/DocFnForm/id = '" + evt.id + "'"; } dojo.debug(dojo.json.serialize(search)); dojo.doc._rpc.callRemote("search", search).addCallbacks(function(data){ evt.type = "fn"; dojo.doc._gotDoc("load", data.list[0], evt); }, function(data){ evt.type = "fn"; dojo.doc._gotDoc("error", {}, evt); }); search.forFormName = "DocParamForm"; if(!evt.id){ search.filter = "it/DocParamForm/fns = '" + evt.pkg + "=>" + evt.name + "'"; }else{ search.filter = "it/DocParamForm/fns = '" + evt.pkg + "=>" + evt.name + "=>" + evt.id + "'"; } delete search.limit; dojo.doc._rpc.callRemote("search", search).addCallbacks(function(data){ evt.type = "param"; dojo.doc._gotDoc("load", data.list, evt); }, function(data){ evt.type = "param"; dojo.doc._gotDoc("error", {}, evt); }); }, _gotDoc: function(/*String*/ type, /*Array*/ data, /*Object*/ evt){ dojo.debug("_gotDoc(" + evt.type + ") for " + evt.selectKey); dojo.doc._keys[evt.selectKey][evt.type] = data; if(++dojo.doc._keys[evt.selectKey].count == 2){ dojo.debug("_gotDoc() finished"); var keys = dojo.doc._keys[evt.selectKey]; var description = ''; if(!keys.fn){ keys.fn = {} } if(keys.fn["main/text"]){ description = dojo.dom.createDocumentFromText(keys.fn["main/text"]).childNodes[0].innerHTML; if(!description){ description = keys.fn["main/text"]; } } data = { description: description, returns: keys.fn["DocFnForm/returns"], id: keys.fn["DocFnForm/id"], parameters: {}, variables: [] } for(var i = 0, param; param = keys["param"][i]; i++){ data.parameters[param["DocParamForm/name"]] = { description: param["DocParamForm/desc"] }; } delete dojo.doc._keys[evt.selectKey]; if(evt.callbacks && evt.callbacks.length){ var callback = evt.callbacks.shift(); callback.call(null, "load", data, evt); } } }, getPkgMeta: function(/*mixed*/ selectKey, /*Function*/ callback, /*String*/ name){ dojo.debug("getPkgMeta(" + name + ")"); if(!selectKey){ selectKey = ++dojo.doc._count; } dojo.doc._buildCache({ type: "pkgmeta", callbacks: [callback], name: name, selectKey: selectKey }); }, _getPkgMeta: function(/*Object*/ input){ dojo.debug("_getPkgMeta(" + input.name + ")"); input.type = "pkgmeta"; dojo.doc._buildCache(input); }, _onDocSearch: function(/*Object*/ input){ dojo.debug("_onDocSearch(" + input.name + ")"); if(!input.name){ return; } if(!input.selectKey){ input.selectKey = ++dojo.doc._count; } input.callbacks = [dojo.doc._onDocSearchFn]; input.name = input.name.toLowerCase(); input.type = "function_names"; dojo.doc._buildCache(input); }, _onDocSearchFn: function(/*String*/ type, /*Array*/ data, /*Object*/ evt){ dojo.debug("_onDocSearchFn(" + evt.name + ")"); var packages = []; var size = 0; pkgLoop: for(var pkg in data){ for(var i = 0, fn; fn = data[pkg][i]; i++){ if(fn.toLowerCase().indexOf(evt.name) != -1){ // Build a list of all packages that need to be loaded and their loaded state. ++size; packages.push(pkg); continue pkgLoop; } } } dojo.doc._keys[evt.selectKey] = {}; dojo.doc._keys[evt.selectKey].pkgs = packages; dojo.doc._keys[evt.selectKey].pkg = evt.name; // Remember what we were searching for dojo.doc._keys[evt.selectKey].loaded = 0; for(var i = 0, pkg; pkg = packages[i]; i++){ setTimeout("dojo.doc.getPkgMeta(\"" + evt.selectKey + "\", dojo.doc._onDocResults, \"" + pkg + "\");", i*10); } }, _onDocResults: function(/*String*/ type, /*Object*/ data, /*Object*/ evt){ dojo.debug("_onDocResults(" + evt.name + "/" + dojo.doc._keys[evt.selectKey].pkg + ") " + type); ++dojo.doc._keys[evt.selectKey].loaded; if(dojo.doc._keys[evt.selectKey].loaded == dojo.doc._keys[evt.selectKey].pkgs.length){ var info = dojo.doc._keys[evt.selectKey]; var pkgs = info.pkgs; var name = info.pkg; delete dojo.doc._keys[evt.selectKey]; var results = {selectKey: evt.selectKey, docResults: []}; data = dojo.doc._cache; for(var i = 0, pkg; pkg = pkgs[i]; i++){ if(!data[pkg]){ continue; } for(var fn in data[pkg]["meta"]){ if(fn.toLowerCase().indexOf(name) == -1){ continue; } if(fn != "requires"){ for(var pId in data[pkg]["meta"][fn]){ var result = { pkg: pkg, name: fn, summary: "" } if(data[pkg]["meta"][fn][pId].summary){ result.summary = data[pkg]["meta"][fn][pId].summary; } results.docResults.push(result); } } } } dojo.debug("Publishing docResults"); dojo.doc._printResults(results); } }, _printResults: function(results){ dojo.debug("_printResults(): called"); // summary: Call this function to send the /doc/results topic }, _onDocSelectFunction: function(/*Object*/ input){ // summary: Get doc, meta, and src var name = input.name; var selectKey = selectKey; dojo.debug("_onDocSelectFunction(" + name + ")"); if(!name){ return false; } if(!selectKey){ selectKey = ++dojo.doc._count; } dojo.doc._keys[selectKey] = {size: 0}; dojo.doc._myKeys[++dojo.doc._count] = {selectKey: selectKey, type: "meta"} dojo.doc.getMeta(dojo.doc._count, dojo.doc._onDocSelectResults, name); dojo.doc._myKeys[++dojo.doc._count] = {selectKey: selectKey, type: "src"} dojo.doc.getSrc(dojo.doc._count, dojo.doc._onDocSelectResults, name); dojo.doc._myKeys[++dojo.doc._count] = {selectKey: selectKey, type: "doc"} dojo.doc.getDoc(dojo.doc._count, dojo.doc._onDocSelectResults, name); }, _onDocSelectResults: function(/*String*/ type, /*Object*/ data, /*Object*/ evt){ dojo.debug("dojo.doc._onDocSelectResults(" + evt.type + ", " + evt.name + ")"); var myKey = dojo.doc._myKeys[evt.selectKey]; dojo.doc._keys[myKey.selectKey][myKey.type] = data; dojo.doc._keys[myKey.selectKey].size; if(++dojo.doc._keys[myKey.selectKey].size == 3){ var key = dojo.lang.mixin(evt, dojo.doc._keys[myKey.selectKey]); delete key.size; dojo.debug("Publishing docFunctionDetail"); dojo.doc._printFunctionDetail(key); delete dojo.doc._keys[myKey.selectKey]; delete dojo.doc._myKeys[evt.selectKey]; } }, _printFunctionDetail: function(results) { // summary: Call this function to send the /doc/functionDetail topic event }, _buildCache: function(/*Object*/ input){ var type = input.type; var pkg = input.pkg; var callbacks = input.callbacks; var id = input.id; if(!id){ id = "_"; } var name = input.name; dojo.debug("_buildCache() type: " + type); if(type == "function_names"){ if(!dojo.doc._cache["function_names"]){ dojo.debug("_buildCache() new cache"); if(callbacks && callbacks.length){ dojo.doc._callbacks.function_names.push([input, callbacks.shift()]); } dojo.doc._cache["function_names"] = {loading: true}; dojo.io.bind({ url: "json/function_names", mimetype: "text/json", error: function(type, data, evt){ dojo.debug("Unable to load function names"); for(var i = 0, callback; callback = dojo.doc._callbacks.function_names[i]; i++){ callback[1].call(null, "error", {}, callback[0]); } }, load: function(type, data, evt){ dojo.doc._cache['function_names'] = data; for(var i = 0, callback; callback = dojo.doc._callbacks.function_names[i]; i++){ callback[1].call(null, "load", data, callback[0]); } } }); }else if(dojo.doc._cache["function_names"].loading){ dojo.debug("_buildCache() loading cache"); if(callbacks && callbacks.length){ dojo.doc._callbacks.function_names.push([input, callbacks.shift()]); } }else{ dojo.debug("_buildCache() from cache"); if(callbacks && callbacks.length){ var callback = callbacks.shift(); callback.call(null, "load", dojo.doc._cache["function_names"], input); } } }else if(type == "meta" || type == "src"){ if(!pkg){ if(type == "meta"){ dojo.doc.functionPackage(dojo.doc._getMeta, input); }else{ dojo.doc.functionPackage(dojo.doc._getSrc, input); } }else{ try{ var cached = dojo.doc._cache[pkg][name][id][type]; }catch(e){} if(cached){ if(callbacks && callbacks.length){ var callback = callbacks.shift(); callback.call(null, "load", cached, input); return; } } dojo.debug("Finding " + type + " for: " + pkg + ", function: " + name + ", id: " + id); var mimetype = "text/json"; if(type == "src"){ mimetype = "text/plain" } var url = "json/" + pkg + "/" + name + "/" + id + "/" + type; dojo.io.bind({ url: url, input: input, mimetype: mimetype, error: function(type, data, evt, args){ var input = args.input; var pkg = input.pkg; var type = input.type; var callbacks = input.callbacks; var id = input.id; var name = input.name; if(callbacks && callbacks.length){ if(!data){ data = {}; } if(!dojo.doc._cache[pkg]){ dojo.doc._cache[pkg] = {}; } if(!dojo.doc._cache[pkg][name]){ dojo.doc._cache[pkg][name] = {}; } if(type == "meta"){ data.sig = dojo.doc._cache[pkg][name][id].sig; data.params = dojo.doc._cache[pkg][name][id].params; } var callback = callbacks.shift(); callback.call(null, "error", data, args.input); } }, load: function(type, data, evt, args){ var input = args.input; var pkg = input.pkg; var type = input.type; var id = input.id; var name = input.name; var cache = dojo.doc._cache; dojo.debug("_buildCache() loaded " + type); if(!data){ data = {}; } if(!cache[pkg]){ dojo.doc._cache[pkg] = {}; } if(!cache[pkg][name]){ dojo.doc._cache[pkg][name] = {}; } if(!cache[pkg][name][id]){ dojo.doc._cache[pkg][name][id] = {}; } if(!cache[pkg][name][id].meta){ dojo.doc._cache[pkg][name][id].meta = {}; } dojo.doc._cache[pkg][name][id][type] = data; if(callbacks && callbacks.length){ var callback = callbacks.shift(); callback.call(null, "load", data, args.input); } } }); } }else if(type == "pkgmeta"){ try{ var cached = dojo.doc._cache[name]["meta"]; }catch(e){} if(cached){ if(callbacks && callbacks.length){ var callback = callbacks.shift(); callback.call(null, "load", cached, input); return; } } dojo.debug("Finding package meta for: " + name); dojo.io.bind({ url: "json/" + name + "/meta", input: input, mimetype: "text/json", error: function(type, data, evt, args){ var callbacks = args.input.callbacks; if(callbacks && callbacks.length){ var callback = callbacks.shift(); callback.call(null, "error", {}, args.input); } }, load: function(type, data, evt, args){ var pkg = args.input.name; var cache = dojo.doc._cache; dojo.debug("_buildCache() loaded for: " + pkg); if(!cache[pkg]){ dojo.doc._cache[pkg] = {}; } if(!cache[pkg]["meta"]){ dojo.doc._cache[pkg]["meta"] = {}; } var methods = data.methods; if(methods){ for(var method in methods){ if (method == "is") { continue; } for(var pId in methods[method]){ if(!cache[pkg]["meta"][method]){ dojo.doc._cache[pkg]["meta"][method] = {}; } if(!cache[pkg]["meta"][method][pId]){ dojo.doc._cache[pkg]["meta"][method][pId] = {}; } dojo.doc._cache[pkg]["meta"][method][pId].summary = methods[method][pId]; } } } dojo.doc._cache[pkg]["meta"].methods = methods; var requires = data.requires; if(requires){ dojo.doc._cache[pkg]["meta"].requires = requires; } if(callbacks && callbacks.length){ var callback = callbacks.shift(); callback.call(null, "load", methods, input); } } }); } }, selectFunction: function(/*String*/ name, /*String?*/ id){ // summary: The combined information }, savePackage: function(/*String*/ name, /*String*/ description){ dojo.doc._rpc.callRemote( "saveForm", { form: "DocPkgForm", path: "/WikiHome/DojoDotDoc/id", pname1: "main/text", pvalue1: "Test" } ).addCallbacks(dojo.doc._results, dojo.doc._results); }, functionPackage: function(/*Function*/ callback, /*Object*/ input){ dojo.debug("functionPackage() name: " + input.name + " for type: " + input.type); input.type = "function_names"; input.callbacks.unshift(callback); input.callbacks.unshift(dojo.doc._functionPackage); dojo.doc._buildCache(input); }, _functionPackage: function(/*String*/ type, /*Array*/ data, /*Object*/ evt){ dojo.debug("_functionPackage() name: " + evt.name + " for: " + evt.type + " with: " + type); evt.pkg = ''; var data = dojo.doc._cache['function_names']; for(var key in data){ if(dojo.lang.inArray(data[key], evt.name)){ evt.pkg = key; break; } } if(evt.callbacks && evt.callbacks.length){ var callback = evt.callbacks.shift(); callback.call(null, type, data[key], evt); } }, _sort: function(a, b){ if(a[0] < b[0]){ return -1; } if(a[0] > b[0]){ return 1; } return 0; } }); dojo.event.topic.subscribe("/doc/search", dojo.doc, "_onDocSearch"); dojo.event.topic.subscribe("/doc/selectFunction", dojo.doc, "_onDocSelectFunction"); dojo.event.topic.registerPublisher("/doc/results", dojo.doc, "_printResults"); dojo.event.topic.registerPublisher("/doc/functionDetail", dojo.doc, "_printFunctionDetail");