Subversion Repositories Applications.papyrus

Rev

Blame | Last modification | View Log | RSS feed

/*
        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");