From e44a7e37b6c7b5961adaffc62b9042b8d442938e Mon Sep 17 00:00:00 2001 From: mensonge Date: Thu, 13 Nov 2008 09:49:11 +0000 Subject: New feature: basic Ajax suggestion for tags and implementation of Dojo toolkit git-svn-id: https://semanticscuttle.svn.sourceforge.net/svnroot/semanticscuttle/trunk@151 b3834d28-1941-0410-a4f8-b48e95affb8f --- includes/js/dojox/rpc/CouchDBRestStore.js | 87 +++ includes/js/dojox/rpc/JsonRPC.js | 58 ++ includes/js/dojox/rpc/JsonReferencing.js | 265 ++++++++ includes/js/dojox/rpc/JsonRestStore.js | 661 +++++++++++++++++++ includes/js/dojox/rpc/PersevereRestStore.js | 39 ++ includes/js/dojox/rpc/README | 52 ++ includes/js/dojox/rpc/Rest.js | 90 +++ includes/js/dojox/rpc/SMDLibrary/yahoo.smd | 493 ++++++++++++++ includes/js/dojox/rpc/Service.js | 293 +++++++++ .../rpc/demos/demo_JsonRestStore_CouchDB.html | 125 ++++ .../rpc/demos/demo_JsonRestStore_Persevere.html | 65 ++ includes/js/dojox/rpc/demos/documentation.html | 33 + .../dojox/rpc/demos/templates/documentation.html | 8 + includes/js/dojox/rpc/demos/templates/yahoo.html | 31 + includes/js/dojox/rpc/demos/yahoo.html | 39 ++ includes/js/dojox/rpc/documentation.smd | 30 + includes/js/dojox/rpc/test.txt | 0 includes/js/dojox/rpc/tests/JsonReferencing.js | 30 + includes/js/dojox/rpc/tests/Service.js | 702 ++++++++++++++++++++ includes/js/dojox/rpc/tests/Yahoo.js | 317 +++++++++ includes/js/dojox/rpc/tests/libraryTests.js | 12 + includes/js/dojox/rpc/tests/module.js | 13 + includes/js/dojox/rpc/tests/resources/JSON.php | 724 +++++++++++++++++++++ includes/js/dojox/rpc/tests/resources/bigQuery | 1 + includes/js/dojox/rpc/tests/resources/bigQuery5 | 1 + includes/js/dojox/rpc/tests/resources/echo.php | 7 + includes/js/dojox/rpc/tests/resources/echoJson.php | 8 + .../js/dojox/rpc/tests/resources/fakestore.php | 36 + .../js/dojox/rpc/tests/resources/jsonRpc10.php | 47 ++ .../js/dojox/rpc/tests/resources/jsonRpc11.php | 52 ++ .../js/dojox/rpc/tests/resources/jsonRpc12.php | 53 ++ .../rpc/tests/resources/jsonRpcPostGetEcho.php | 38 ++ .../js/dojox/rpc/tests/resources/jsonpEcho.php | 23 + .../js/dojox/rpc/tests/resources/jsonpEcho.phps | 23 + .../dojox/rpc/tests/resources/jsonpJsonRpcEcho.php | 37 ++ includes/js/dojox/rpc/tests/resources/obj1 | 1 + .../js/dojox/rpc/tests/resources/obj1testArray | 1 + includes/js/dojox/rpc/tests/resources/obj3 | 1 + includes/js/dojox/rpc/tests/resources/obj4 | 1 + includes/js/dojox/rpc/tests/resources/query | 6 + includes/js/dojox/rpc/tests/resources/rawEcho.php | 5 + includes/js/dojox/rpc/tests/resources/res | 1 + includes/js/dojox/rpc/tests/resources/store.php | 24 + includes/js/dojox/rpc/tests/resources/test.smd | 189 ++++++ includes/js/dojox/rpc/tests/runLibraryTests.html | 9 + includes/js/dojox/rpc/tests/runTests.html | 9 + .../js/dojox/rpc/tests/stores/JsonRestStore.js | 237 +++++++ .../rpc/tests/test_dojo_data_model_persevere.html | 146 +++++ 48 files changed, 5123 insertions(+) create mode 100644 includes/js/dojox/rpc/CouchDBRestStore.js create mode 100644 includes/js/dojox/rpc/JsonRPC.js create mode 100644 includes/js/dojox/rpc/JsonReferencing.js create mode 100644 includes/js/dojox/rpc/JsonRestStore.js create mode 100644 includes/js/dojox/rpc/PersevereRestStore.js create mode 100644 includes/js/dojox/rpc/README create mode 100644 includes/js/dojox/rpc/Rest.js create mode 100644 includes/js/dojox/rpc/SMDLibrary/yahoo.smd create mode 100644 includes/js/dojox/rpc/Service.js create mode 100644 includes/js/dojox/rpc/demos/demo_JsonRestStore_CouchDB.html create mode 100644 includes/js/dojox/rpc/demos/demo_JsonRestStore_Persevere.html create mode 100644 includes/js/dojox/rpc/demos/documentation.html create mode 100644 includes/js/dojox/rpc/demos/templates/documentation.html create mode 100644 includes/js/dojox/rpc/demos/templates/yahoo.html create mode 100644 includes/js/dojox/rpc/demos/yahoo.html create mode 100644 includes/js/dojox/rpc/documentation.smd create mode 100644 includes/js/dojox/rpc/test.txt create mode 100644 includes/js/dojox/rpc/tests/JsonReferencing.js create mode 100644 includes/js/dojox/rpc/tests/Service.js create mode 100644 includes/js/dojox/rpc/tests/Yahoo.js create mode 100644 includes/js/dojox/rpc/tests/libraryTests.js create mode 100644 includes/js/dojox/rpc/tests/module.js create mode 100644 includes/js/dojox/rpc/tests/resources/JSON.php create mode 100644 includes/js/dojox/rpc/tests/resources/bigQuery create mode 100644 includes/js/dojox/rpc/tests/resources/bigQuery5 create mode 100644 includes/js/dojox/rpc/tests/resources/echo.php create mode 100644 includes/js/dojox/rpc/tests/resources/echoJson.php create mode 100644 includes/js/dojox/rpc/tests/resources/fakestore.php create mode 100644 includes/js/dojox/rpc/tests/resources/jsonRpc10.php create mode 100644 includes/js/dojox/rpc/tests/resources/jsonRpc11.php create mode 100644 includes/js/dojox/rpc/tests/resources/jsonRpc12.php create mode 100644 includes/js/dojox/rpc/tests/resources/jsonRpcPostGetEcho.php create mode 100644 includes/js/dojox/rpc/tests/resources/jsonpEcho.php create mode 100644 includes/js/dojox/rpc/tests/resources/jsonpEcho.phps create mode 100644 includes/js/dojox/rpc/tests/resources/jsonpJsonRpcEcho.php create mode 100644 includes/js/dojox/rpc/tests/resources/obj1 create mode 100644 includes/js/dojox/rpc/tests/resources/obj1testArray create mode 100644 includes/js/dojox/rpc/tests/resources/obj3 create mode 100644 includes/js/dojox/rpc/tests/resources/obj4 create mode 100644 includes/js/dojox/rpc/tests/resources/query create mode 100644 includes/js/dojox/rpc/tests/resources/rawEcho.php create mode 100644 includes/js/dojox/rpc/tests/resources/res create mode 100644 includes/js/dojox/rpc/tests/resources/store.php create mode 100644 includes/js/dojox/rpc/tests/resources/test.smd create mode 100644 includes/js/dojox/rpc/tests/runLibraryTests.html create mode 100644 includes/js/dojox/rpc/tests/runTests.html create mode 100644 includes/js/dojox/rpc/tests/stores/JsonRestStore.js create mode 100644 includes/js/dojox/rpc/tests/test_dojo_data_model_persevere.html (limited to 'includes/js/dojox/rpc') diff --git a/includes/js/dojox/rpc/CouchDBRestStore.js b/includes/js/dojox/rpc/CouchDBRestStore.js new file mode 100644 index 0000000..f61836c --- /dev/null +++ b/includes/js/dojox/rpc/CouchDBRestStore.js @@ -0,0 +1,87 @@ +if(!dojo._hasResource["dojox.data.CouchDBRestStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.CouchDBRestStore"] = true; +dojo.provide("dojox.data.CouchDBRestStore"); +dojo.require("dojox.data.JsonRestStore"); +dojo.require("dojox.json.ref"); // TODO: Make it work without this dependency + +// A CouchDBRestStore is an extension of JsonRestStore to handle CouchDB's idiosyncrasies, special features, +// and deviations from standard HTTP Rest. +// NOTE: CouchDB is not designed to be run on a public facing network. There is no access control +// on database documents, and you should NOT rely on client side control to implement security. + + +dojo.declare("dojox.data.CouchDBRestStore", + dojox.data.JsonRestStore, + { + _commitAppend: function(listId,item) { + var deferred = this.service.post(listId,item); + var prefix = this.service.serviceName + '/'; + deferred.addCallback(function(result) { + item._id = prefix + result.id; // update the object with the results of the post + item._rev = result.rev; + return result; + //TODO: Need to go down the graph assigned _id based on path, so that sub items can be modified and properly reflected to the root item (being careful of circular references) + }); + return deferred; + }, + fetch: function(args) { + // summary: + // This only differs from JsonRestStore in that it, will put the query string the query part of the URL and it handles start and count + if (typeof args == 'string') { + args = {query: '_all_docs?' + args}; + } + else if (typeof args.query == 'string') { + args.query = '_all_docs?' + args.query; + } + else + args.query = '_all_docs?'; + if (args.start) { + args.query = (args.query ? (args.query + '&') : '') + 'skip=' + args.start; + delete args.start; + } + if (args.count) { + args.query = (args.query ? (args.query + '&') : '') + 'count=' + args.count; + delete args.count; + } + var prefix = this.service.serviceName + '/'; + var oldOnComplete = args.onComplete; + args.onComplete=function(results) { + if (results.rows) { + for (var i = 0; i < results.rows.length; i++) { + var row = results.rows[i]; // make it into a reference + row._id = prefix + (row.$ref = row.id); + } + } + if (oldOnComplete) + oldOnComplete.apply(this,arguments); + }; + return dojox.data.JsonRestStore.prototype.fetch.call(this,args); + } + } +); + + +dojox.data.CouchDBRestStore.generateSMD = function(couchServerUrl) { + var couchSMD = {contentType:"application/json", + transport:"REST", + envelope:"PATH", + services:{}, + target: couchServerUrl, + }; + var def = dojo.xhrGet({ + url: couchServerUrl+"_all_dbs", + handleAs: "json", + sync: true + }); + def.addCallback(function(dbs) { + for (var i = 0; i < dbs.length; i++) + couchSMD.services[dbs[i]] = { + target:dbs[i], + returns:{}, + parameters:[{type:"string"}] + } + }); + return couchSMD; +} + +} diff --git a/includes/js/dojox/rpc/JsonRPC.js b/includes/js/dojox/rpc/JsonRPC.js new file mode 100644 index 0000000..1710b31 --- /dev/null +++ b/includes/js/dojox/rpc/JsonRPC.js @@ -0,0 +1,58 @@ +if(!dojo._hasResource["dojox.rpc.JsonRPC"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.rpc.JsonRPC"] = true; +dojo.provide("dojox.rpc.JsonRPC"); + +dojox.rpc.envelopeRegistry.register( + "JSON-RPC-1.0",function(str){return str == "JSON-RPC-1.0"},{ + serialize: function(smd, method, data, options){ + //not converted to json it self. This will be done, if appropriate, at the + //transport level + var d = dojox.rpc.toOrdered(method, data); + d = dojox.rpc.toJson({id: this._requestId++, method: method.name, params: d}); + + return { + data: d, + contentType: 'application/json', + transport:"POST" + } + }, + + deserialize: function(results){ + var obj = dojox.rpc.resolveJson(results); + if (obj.error) { + var e = new Error(obj.error); + e._rpcErrorObject = obj.error; + return e; + } + return obj.result || true; + } + } +); + +dojox.rpc.envelopeRegistry.register( + "JSON-RPC-1.2",function(str){return str == "JSON-RPC-1.2"},{ + serialize: function(smd, method, data, options){ + var trans = method.transport || smd.transport || "POST"; + var d = dojox.rpc.toNamed(method, data); + + d = dojox.rpc.toJson({id: this._requestId++, method: method.name, params: data}); + return { + data: d, + contentType: 'application/json', + transport:"POST" + } + }, + + deserialize: function(results){ + var obj = dojox.rpc.resolveJson(results); + if (obj.error) { + var e = new Error(obj.error.message); + e._rpcErrorObject = obj.error; + return e; + } + return obj.result || true; + } + } +); + +} diff --git a/includes/js/dojox/rpc/JsonReferencing.js b/includes/js/dojox/rpc/JsonReferencing.js new file mode 100644 index 0000000..618ea06 --- /dev/null +++ b/includes/js/dojox/rpc/JsonReferencing.js @@ -0,0 +1,265 @@ +if(!dojo._hasResource["dojox.rpc.JsonReferencing"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.rpc.JsonReferencing"] = true; +dojo.provide("dojox.rpc.JsonReferencing"); +dojo.require("dojo.date.stamp"); +dojo.require("dojo._base.Deferred"); + +// summary: +// Adds advanced JSON {de}serialization capabilities to the base json library. +// This enhances the capabilities of dojo.toJson and dojo.fromJson, +// adding referencing support, date handling, and other extra format handling. +// On parsing, references are resolved. When references are made to +// ids/objects that have been loaded yet, a Deferred object will be used as the +// value and as soon as a callback is added to the Deferred object, the target +// object will be loaded. + + + +dojox.rpc._index={}; // the global map of id->object +dojox.rpc.onUpdate = function(/*Object*/ object, /* attribute-name-string */ attribute, /* any */ oldValue, /* any */ newValue){ + // summary: + // This function is called when an existing object in the system is updated. Existing objects are found by id. +}; + +dojox.rpc.resolveJson = function(/*Object*/ root,/*Object?*/ schema){ + // summary: + // Indexes and resolves references in the JSON object. + // A JSON Schema object that can be used to advise the handling of the JSON (defining ids, date properties, urls, etc) + // + // root: + // The root object of the object graph to be processed + // + // schema: A JSON Schema object that can be used to advise the parsing of the JSON (defining ids, date properties, urls, etc) // + // Currently this provides a means for context based id handling + // + // return: + // An object, the result of the processing + var ref,reWalk=[]; + function makeIdInfo(schema){ // find out what attribute and what id prefix to use + if (schema){ + var attr; + if (!(attr = schema._idAttr)){ + for (var i in schema.properties){ + if (schema.properties[i].unique){ + schema._idAttr = attr = i; + } + } + } + if (attr || schema._idPrefix){ + return {attr:attr || 'id',prefix:schema._idPrefix}; + } + } + + return false; + } + function walk(it,stop,schema,idInfo,defaultId){ + // this walks the new graph, resolving references and making other changes + var val,i; + var id = it[idInfo.attr]; + id = (id && (idInfo.prefix + id)) || defaultId; // if there is an id, prefix it, otherwise inherit + var target = it; + + if (id){ // if there is an id available... + it._id = id; + if (dojox.rpc._index[id]){ // if the id already exists in the system, we should use the existing object, and just update it + target = dojox.rpc._index[id]; + delete target.$ref; // remove this artifact + } + dojox.rpc._index[id] = target; // add the prefix, set _id, and index it + if (schema && dojox.validate && dojox.validate.jsonSchema){ // if json schema is activated, we can load it in the registry of instance schemas map + dojox.validate.jsonSchema._schemas[id] = schema; + } + + } + for (i in it){ + if (it.hasOwnProperty(i) && (typeof (val=it[i]) =='object') && val){ + ref=val.$ref; + if (ref){ // a reference was found + var stripped = ref.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');// trim it + if(/[\w\[\]\.\$ \/\r\n\t]/.test(stripped) && !/=|((^|\W)new\W)/.test(stripped)){ // make sure it is a safe reference + var path = ref.match(/(^\.*[^\.\[]+)([\.\[].*)?/); // divide along the path + if ((ref=path[1]=='$' ? root:dojox.rpc._index[new dojo._Url(idInfo.prefix,path[1])]) && // a $ indicates to start with the root, otherwise start with an id + (ref = path[2] ? eval('ref' + path[2]) : ref)){// starting point was found, use eval to resolve remaining property references + // otherwise, no starting point was found (id not found), if stop is set, it does not exist, we have + // unloaded reference, if stop is not set, it may be in a part of the graph not walked yet, + // we will wait for the second loop + val = ref; + } + else{ + if (!stop){ + if (!rewalking) + reWalk.push(it); // we need to rewalk it to resolve references + var rewalking = true; // we only want to add it once + } + else { + ref = val.$ref; + val = new dojo.Deferred(); + val._id = idInfo.prefix + ref; + (function(val,ref){ + var connectId = dojo.connect(val,"addCallbacks",function(){ + dojo.disconnect(connectId); + dojox.rpc.services[idInfo.prefix.substring(0,idInfo.prefix.length-1)](ref) // otherwise call by looking up the service + .addCallback(dojo.hitch(val,val.callback)); + + }); + })(val,ref); + } + } + } + } + else { + if (!stop){ // if we are in stop, that means we are in the second loop, and we only need to check this current one, + // further walking may lead down circular loops + var valSchema = val.schema || // a schema can be self-defined by the object, + (schema && schema.properties && schema.properties[i]); // or it can from the schema sub-object definition + if (valSchema){ + idInfo = makeIdInfo(valSchema)||idInfo; + } + val = walk(val,reWalk==it,valSchema,idInfo,id && (id + ('[' + dojo._escapeString(i) + ']'))); + } + } + } + if (dojo.isString(val) && schema && schema.properties && schema.properties[i] && schema.properties[i].format=='date-time'){// parse the date string + val = dojo.date.stamp.fromISOString(val); // create a date object + } + it[i] = val; + var old = target[i]; + if (val !== old){ // only update if it changed + target[i] = val; // update the target + propertyChange(i,old,val); + } + } + function propertyChange(key,old,newValue){ + setTimeout(function(){ + dojox.rpc.onUpdate(target,i,old,newValue); // call the listener for each update + }); + } + if (target != it){ // this means we are updating, we need to remove deleted + for (i in target){ + if (!it.hasOwnProperty(i) && i != '_id' && !(target instanceof Array && isNaN(i))){ + propertyChange(i,target[i],undefined); + delete target[i]; + } + } + } + return target; + } + var idInfo = makeIdInfo(schema)||{attr:'id',prefix:''}; + if (!root){ return root; } + root = walk(root,false,schema,idInfo,dojox._newId && (new dojo._Url(idInfo.prefix,dojox._newId) +'')); // do the main walk through + walk(reWalk,false,schema,idInfo); // re walk any parts that were not able to resolve references on the first round + return root; +}; +dojox.rpc.fromJson = function(/*String*/ str,/*Object?*/ schema){ + // summary: + // evaluates the passed string-form of a JSON object. + // A JSON Schema object that can be used to advise the parsing of the JSON (defining ids, date properties, urls, etc) + // which may defined by setting dojox.currentSchema to the current schema you want to use for this evaluation + // + // json: + // a string literal of a JSON item, for instance: + // '{ "foo": [ "bar", 1, { "baz": "thud" } ] }' + // schema: A JSON Schema object that can be used to advise the parsing of the JSON (defining ids, date properties, urls, etc) // + // Currently this provides a means for context based id handling + // + // return: + // An object, the result of the evaluation + root = eval('(' + str + ')'); // do the eval + if (root){ + return this.resolveJson(root,schema); + } + return root; +} +dojox.rpc.toJson = function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*Object?*/ schema){ + // summary: + // Create a JSON serialization of an object. + // This has support for referencing, including circular references, duplicate references, and out-of-message references + // id and path-based referencing is supported as well and is based on http://www.json.com/2007/10/19/json-referencing-proposal-and-library/. + // + // it: + // an object to be serialized. + // + // prettyPrint: + // if true, we indent objects and arrays to make the output prettier. + // The variable dojo.toJsonIndentStr is used as the indent string + // -- to use something other than the default (tab), + // change that variable before calling dojo.toJson(). + // + // schema: A JSON Schema object that can be used to advise the parsing of the JSON (defining ids, date properties, urls, etc) // + // Currently this provides a means for context based id handling + // + // return: + // a String representing the serialized version of the passed object. + + var idPrefix = (schema&& schema._idPrefix) || ''; // the id prefix for this context + var paths={}; + function serialize(it,path,_indentStr){ + if (it && dojo.isObject(it)){ + var value; + if (it instanceof Date){ // properly serialize dates + return '"' + dojo.date.stamp.toISOString(it,{zulu:true}) + '"'; + } + var id = it._id; + if (id){ // we found an identifiable object, we will just serialize a reference to it... unless it is the root + + if (path != '$'){ + return serialize({$ref:id.charAt(0)=='$' ? id : // a pure path based reference, leave it alone + id.substring(0,idPrefix.length)==idPrefix ? // see if the reference is in the current context + id.substring(idPrefix.length): // a reference with a prefix matching the current context, the prefix should be removed + '../' + id});// a reference to a different context, assume relative url based referencing + } + path = id; + } + else { + it._id = path; // we will create path ids for other objects in case they are circular + paths[path] = it;// save it here so they can be deleted at the end + } + _indentStr = _indentStr || ""; + var nextIndent = prettyPrint ? _indentStr + dojo.toJsonIndentStr : ""; + var newLine = prettyPrint ? "\n" : ""; + var sep = prettyPrint ? " " : ""; + + if (it instanceof Array){ + var res = dojo.map(it, function(obj,i){ + var val = serialize(obj, path + '[' + i + ']', nextIndent); + if(!dojo.isString(val)){ + val = "undefined"; + } + return newLine + nextIndent + val; + }); + return "[" + res.join("," + sep) + newLine + _indentStr + "]"; + } + + var output = []; + for(var i in it){ + var keyStr; + if(typeof i == "number"){ + keyStr = '"' + i + '"'; + }else if(dojo.isString(i) && i != '_id'){ + keyStr = dojo._escapeString(i); + }else{ + // skip non-string or number keys + continue; + } + var val = serialize(it[i],path+(i.match(/^[a-zA-Z]\w*$/) ? // can we use simple .property syntax? + ('.' + i) : // yes, otherwise we have to escape it + ('[' + dojo._escapeString(i) + ']')),nextIndent); + if(!dojo.isString(val)){ + // skip non-serializable values + continue; + } + output.push(newLine + nextIndent + keyStr + ":" + sep + val); + } + return "{" + output.join("," + sep) + newLine + _indentStr + "}"; + } + + return dojo.toJson(it); // use the default serializer for primitives + } + var json = serialize(it,'$',''); + for (i in paths){ // cleanup the temporary path-generated ids + delete paths[i]._id; + } + return json; +} + +} diff --git a/includes/js/dojox/rpc/JsonRestStore.js b/includes/js/dojox/rpc/JsonRestStore.js new file mode 100644 index 0000000..dd14874 --- /dev/null +++ b/includes/js/dojox/rpc/JsonRestStore.js @@ -0,0 +1,661 @@ +if(!dojo._hasResource["dojox.data.JsonRestStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.JsonRestStore"] = true; +dojo.provide("dojox.data.JsonRestStore"); +dojo.require("dojox.rpc.Rest"); +dojo.require("dojox.rpc.JsonReferencing"); // TODO: Make it work without this dependency + +// A JsonRestStore takes a REST service and uses it the remote communication for a +// read/write dojo.data implementation. To use a JsonRestStore you should create a +// service with a REST transport. This can be configured with an SMD: +//{ +// services: { +// jsonRestStore: { +// transport: "REST", +// envelope: "URL", +// target: "store.php", +// contentType:"application/json", +// parameters: [ +// {name: "location", type: "string", optional: true} +// ] +// } +// } +//} +// The SMD can then be used to create service, and the service can be passed to a JsonRestStore. For example: +// var myServices = new dojox.rpc.Service(dojo.moduleUrl("dojox.rpc.tests.resources", "test.smd")); +// var jsonStore = new dojox.data.JsonRestStore({service:myServices.jsonRestStore}); +// +// The JsonRestStore will then cause all saved modifications to be server using Rest commands (PUT, POST, or DELETE). +// The JsonRestStore also supports lazy loading. References can be made to objects that have not been loaded. +// For example if a service returned: +// {"name":"Example","lazyLoadedObject":{"$ref":"obj2"}} +// +// And this object has accessed using the dojo.data API: +// var obj = jsonStore.getValue(myObject,"lazyLoadedObject"); +// The object would automatically be requested from the server (with an object id of "obj2"). +// +// When using a Rest store on a public network, it is important to implement proper security measures to +// control access to resources + +dojox.data.ASYNC_MODE = 0; +dojox.data.SYNC_MODE = 1; +dojo.declare("dojox.data.JsonRestStore", + null, + { + mode: dojox.data.ASYNC_MODE, + constructor: function(options){ + //summary: + // JsonRestStore constructor, instantiate a new JsonRestStore + // A JsonRestStore can be configured from a JSON Schema. Queries are just + // passed through as URLs for XHR requests, + // so there is nothing to configure, just plug n play. + // Of course there are some options to fiddle with if you want: + // + // jsonSchema: /* object */ + // + // service: /* function */ + // This is the service object that is used to retrieve lazy data and save results + // The function should be directly callable with a single parameter of an object id to be loaded + // The function should also have the following methods: + // put(id,value) - puts the value at the given id + // post(id,value) - posts (appends) the value at the given id + // delete(id) - deletes the value corresponding to the given id + // + // idAttribute: /* string */ + // Defaults to 'id'. The name of the attribute that holds an objects id. + // This can be a preexisting id provided by the server. + // If an ID isn't already provided when an object + // is fetched or added to the store, the autoIdentity system + // will generate an id for it and add it to the index. + + // mode: dojox.data.ASYNC_MODE || dojox.data.SYNC_MODE + // Defaults to ASYNC_MODE. This option sets the default mode for this store. + // Sync calls return their data immediately from the calling function + // instead of calling the callback functions. Functions such as + // fetchItemByIdentity() and fetch() both accept a string parameter in addtion + // to the normal keywordArgs parameter. When passed this option, SYNC_MODE will + // automatically be used even when the default mode of the system is ASYNC_MODE. + // A normal request to fetch or fetchItemByIdentity (with kwArgs object) can also + // include a mode property to override this setting for that one request. + + //setup a byId alias to the api call + this.byId=this.fetchItemByIdentity; + // if the advanced json parser is enabled, we can pass through object updates as onSet events + dojo.connect(dojox.rpc,"onUpdate",this,function(obj,attrName,oldValue,newValue){ + var prefix = this.service.serviceName + '/'; + if (!obj._id){ + console.log("no id on updated object ", obj); + } + else if (obj._id.substring(0,prefix.length) == prefix) + this.onSet(obj,attrName,oldValue,newValue); + }); + if (options){ + dojo.mixin(this,options); + } + if (!this.service) + throw Error("A service is required for JsonRestStore"); + if (!(this.service.contentType + '').match(/application\/json/)) + throw Error("A service must use a contentType of 'application/json' in order to be used in a JsonRestStore"); + this.idAttribute = (this.service._schema && this.service._schema._idAttr) || 'id'; + var arrayModifyingMethodNames = ["splice","push","pop","unshift","shift","reverse","sort"]; + this._arrayModifyingMethods = {}; + var array = []; + var _this = this; + // setup array augmentation, for catching mods and setting arrays as dirty + for (var i = 0; i < arrayModifyingMethodNames.length; i++){ + (function(key){ // closure for the method to be bound correctly + var method = array[key]; + _this._arrayModifyingMethods[key] = function(){ + _this._setDirty(this); // set the array as dirty before the native modifying operation + return method.apply(this,arguments); + } + _this._arrayModifyingMethods[key]._augmented = 1; + })(arrayModifyingMethodNames[i]); + } + this._deletedItems=[]; + this._dirtyItems=[]; + //given a url, load json data from as the store + }, + + _loadById: function(id,callback){ + var slashIndex = id.indexOf('/'); + var serviceName = id.substring(0,slashIndex); + var id = id.substring(slashIndex + 1); + (this.service.serviceName == serviceName ? + this.service : // use the current service if it is the right one + dojox.rpc.services[serviceName])(id) // otherwise call by looking up the service + .addCallback(callback); + }, + getValue: function(item, property,lazyCallback){ + // summary: + // Gets the value of an item's 'property' + // + // item: /* object */ + // property: /* string */ + // property to look up value for + // lazyCallback: /* function*/ + // not part of the API, but if you are using lazy loading properties, you may provide a callback to resume, in order to have asynchronous loading + var value = item[property]; + if (value && value.$ref){ + dojox.rpc._sync = !lazyCallback; // tell the service to operate synchronously (I have some concerns about the "thread" safety with FF3, as I think it does event stacking on sync calls) + this._loadById((value && value._id) || (item._id + '.' + property),lazyCallback); + delete dojox.rpc._sync; // revert to normal async behavior + } else if (lazyCallback){lazyCallback(value);} + return value; + }, + + getValues: function(item, property){ + // summary: + // Gets the value of an item's 'property' and returns + // it. If this value is an array it is just returned, + // if not, the value is added to an array and that is returned. + // + // item: /* object */ + // property: /* string */ + // property to look up value for + + var val = this.getValue(item,property); + return dojo.isArray(val) ? val : [val]; + }, + + getAttributes: function(item){ + // summary: + // Gets the available attributes of an item's 'property' and returns + // it as an array. + // + // item: /* object */ + + var res = []; + for (var i in item){ + res.push(i); + } + return res; + }, + + hasAttribute: function(item,attribute){ + // summary: + // Checks to see if item has attribute + // + // item: /* object */ + // attribute: /* string */ + return attribute in item; + }, + + containsValue: function(item, attribute, value){ + // summary: + // Checks to see if 'item' has 'value' at 'attribute' + // + // item: /* object */ + // attribute: /* string */ + // value: /* anything */ + return getValue(item,attribute)==value; + }, + + + isItem: function(item){ + // summary: + // Checks to see if a passed 'item' + // is really a JsonRestStore item. + // + // item: /* object */ + // attribute: /* string */ + + return !!(dojo.isObject(item) && item._id); + }, + + isItemLoaded: function(item){ + // summary: + // returns isItem() :) + // + // item: /* object */ + + return !item.$ref; + }, + + loadItem: function(item){ + // summary: + // Loads an item that has not been loaded yet. Lazy loading should happen through getValue, and if used properly, this should never need to be called + // returns true. Note this does not work with lazy loaded primitives! + if (item.$ref){ + dojox.rpc._sync = true; // tell the service to operate synchronously + this._loadById(item._id) + delete dojox.rpc._sync; // revert to normal async behavior + } + + return true; + }, + + _walk : function(value,forEach){ + // walk the graph, avoiding duplication + var walked=[]; + function walk(value){ + if (value && typeof value == 'object' && !value.__walked){ + value.__walked = true; + walked.push(value); + for (var i in value){ + if (walk(value[i])){ + forEach(value,i,value[i]); + } + } + return true; + } + } + walk(value); + forEach({},null,value); + for (var i = 0; i < walked.length;i++) + delete walked[i].__walked; + }, + fetch: function(args){ + //console.log("fetch() ", args); + // summary + // + // fetch takes either a string argument or a keywordArgs + // object containing the parameters for the search. + // If passed a string, fetch will interpret this string + // as the query to be performed and will do so in + // SYNC_MODE returning the results immediately. + // If an object is supplied as 'args', its options will be + // parsed and then contained query executed. + // + // query: /* string or object */ + // Defaults to "". This is basically passed to the XHR request as the URL to get the data + // + // start: /* int */ + // Starting item in result set + // + // count: /* int */ + // Maximum number of items to return + // + // cache: /* boolean */ + // + // sort: /* function */ + // Not Implemented yet + // + // The following only apply to ASYNC requests (the default) + // + // onBegin: /* function */ + // called before any results are returned. Parameters + // will be the count and the original fetch request + // + // onItem: /*function*/ + // called for each returned item. Parameters will be + // the item and the fetch request + // + // onComplete: /* function */ + // called on completion of the request. Parameters will + // be the complete result set and the request + // + // onError: /* function */ + // colled in the event of an error + + if(dojo.isString(args)){ + query = args; + args={query: query, mode: dojox.data.SYNC_MODE}; + + } + + var query; + if (!args || !args.query){ + if (!args){ + var args={}; + } + + if (!args.query){ + args.query=""; + query=args.query; + } + + } + + if (dojo.isObject(args.query)){ + if (args.query.query){ + query = args.query.query; + }else{ + query = args.query = ""; + } + if (args.query.queryOptions){ + args.queryOptions=args.query.queryOptions + } + }else{ + query=args.query; + } + if (args.start || args.count){ + query += '[' + (args.start ? args.start : '') + ':' + (args.count ? ((args.start || 0) + args.count) : '') + ']'; + } + var results = dojox.rpc._index[this.service.serviceName + '/' + query]; + if (!args.mode){args.mode = this.mode;} + var _this = this; + var defResult; + dojox.rpc._sync = this.mode; + dojox._newId = query; + if (results && !("cache" in args && !args.cache)){ // TODO: Add TTL maybe? + defResult = new dojo.Deferred; + defResult.callback(results); + } + else { + defResult = this.service(query); + } + defResult.addCallback(function(results){ + delete dojox._newId; // cleanup + if (args.onBegin){ + args["onBegin"].call(_this, results.length, args); + } + _this._walk(results,function(obj,i,value){ + if (value instanceof Array){ + for (var i in _this._arrayModifyingMethods){ + if (!value[i]._augmented){ + value[i] = _this._arrayModifyingMethods[i]; + } + } + + } + }); + if (args.onItem){ + for (var i=0; i 0){ + var dirty = this._dirtyItems.pop(); + var item = dirty.item; + var append = false; + left++; + var deferred; + if (item instanceof Array && dirty.old instanceof Array){ + // see if we can just append the item with a post + append = true; + for (var i = 0, l = dirty.old.length; i < l; i++){ + if (item[i] != dirty.old[i]){ + append = false; + } + } + if (append){ // if we can, we will do posts to add from here + for (;i 0){ + left++; + this.service['delete'](this.getIdentity(this._deletedItems.pop())).addCallback(finishOne); + } + }, + + + revert: function(){ + // summary + // returns any modified data to its original state prior to a save(); + + while (this._dirtyItems.length>0){ + var i; + var d = this._dirtyItems.pop(); + for (i in d.old){ + d.item[i] = d.old[i]; + } + for (i in d.item){ + if (!d.old.hasOwnProperty(i)) + delete d.item[i] + } + } + this.onRevert(); + }, + + + isDirty: function(item){ + // summary + // returns true if the item is marked as dirty. + for (var i=0, l=this._dirtyItems.length; i 0; j--) + arguments[j] = arguments[j-1]; // shift them over + arguments[0] = dojo.mixin({restMethod: restMethod},method); + return svc._executeMethod.apply(svc,arguments); + } + })(); + + } + executor.contentType = method.contentType || svc._smd.contentType; // this is so a Rest service can be examined to know what type of content type to expect + return executor; + }, + restMethods:dojox.rpc._restMethods + } +); + +} diff --git a/includes/js/dojox/rpc/SMDLibrary/yahoo.smd b/includes/js/dojox/rpc/SMDLibrary/yahoo.smd new file mode 100644 index 0000000..cf08ee7 --- /dev/null +++ b/includes/js/dojox/rpc/SMDLibrary/yahoo.smd @@ -0,0 +1,493 @@ +{ + "SMDVersion": "2.0", + // FIXME: is this the kind of value we're supposed to use here? + "id": "http://developer.yahoo.com/search/", + "description": "Yahoo's search API", + + transport: "JSONP", + envelope: "URL", + additionalParameters: true, + parameters: [ + { name: "appid", optional: false, "default": "dojotoolkit" }, + { name: "output", optional: false, "default": "json" } + ], + + // FIXME: Quite a few of these APIs can take multiple entries for the same parameter, to behave + // as multi-select options. How should we handle these? + + services: { + // + // ANSWERS + // + // FIXME: Some of these API endpoints' names only make sense when you know they're in the + // Yahoo Answers part of the API; just reading a flat listing of methods in this SMD + // likely won't have enough information about what they do. Should we split this up? + + // http://developer.yahoo.com/answers/V1/questionSearch.html + questionSearch: { + target: "http://answers.yahooapis.com/AnswersService/V1/questionSearch", + parameters: [ + { name: "query", type: "string", optional: false, "default": "" }, + { name: "search_in", type: "string", optional: true, "default": "all" }, // can be "all", "question", "best_answer" + { name: "category_id", type: "integer", optional: true, "default": null }, // one of (category_id, category_name) is required + { name: "category_name", type: "string", optional: true, "default": null }, + { name: "region", type: "string", optional: true, "default": "us" }, // can be "us", "uk", "ca", "au", "in", "es", "br", "ar", "mx", "e1", "it", "de", "fr", "sg" + { name: "date_range", type: "string", optional: true, "default": "all" }, // can be "all", "7", "7-30", "30-60", "60-90", "more90" + { name: "sort", type: "string", optional: true, "default": "relevance" }, // can be "relevance", "date_desc", "date_asc" + { name: "type", type: "string", optional: true, "default": "all" }, // can be "all", "resolved", "open", "undecided" + { name: "start", type: "integer", optional: true, "default": 0 }, + { name: "results", type: "integer", optional: true, "default": 10 } // max 50 + ] + }, + + // http://developer.yahoo.com/answers/V1/getByCategory.html + getByCategory: { + target: "http://answers.yahooapis.com/AnswersService/V1/getByCategory", + parameters: [ + { name: "category_id", type: "integer", optional: true, "default": null }, // one of (category_id, category_name) is required + { name: "category_name", type: "string", optional: true, "default": null }, + { name: "type", type: "string", optional: true, "default": "all" }, // can be "all", "resolved", "open", "undecided" + { name: "region", type: "string", optional: true, "default": "us" }, // can be "us", "uk", "ca", "au", "in", "es", "br", "ar", "mx", "e1", "it", "de", "fr", "sg" + { name: "sort", type: "string", optional: true, "default": "date_desc" }, // can be "date_desc", "date_asc", "ans_count_desc", "ans_count_asc" + { name: "start", type: "integer", optional: true, "default": 0 }, + { name: "results", type: "integer", optional: true, "default": 10 } // max 50 + ] + }, + + // http://developer.yahoo.com/answers/V1/getQuestion.html + getQuestion: { + target: "http://answers.yahooapis.com/AnswersService/V1/getQuestion", + parameters: [ + { name: "question_id", type: "string", optional: true, "default": null } + ] + }, + + // http://developer.yahoo.com/answers/V1/getByUser.html + getByUser: { + target: "http://answers.yahooapis.com/AnswersService/V1/getByUser", + parameters: [ + { name: "user_id", type: "string", optional: false, "default": "" }, + { name: "type", type: "string", optional: true, "default": "all" }, // can be "all", "resolved", "open", "undecided" + { name: "filter", type: "string", optional: true, "default": "question" }, // can be "question", "answer", "best_answer" + { name: "sort", type: "string", optional: true, "default": "date_desc" }, // can be "date_desc", "date_asc", "ans_count_desc", "ans_count_asc" + { name: "start", type: "integer", optional: true, "default": 0 }, + { name: "results", type: "integer", optional: true, "default": 10 } // max 50 + ] + }, + + // + // AUDIO SEARCH + // + + // http://developer.yahoo.com/search/audio/V1/artistSearch.html + artistSearch: { + target: "http://search.yahooapis.com/AudioSearchService/V1/artistSearch", + parameters: [ + { name: "artist", type: "string", optional: true, "default": "" }, // one of (artist, artistid) is required + { name: "artistid", type: "string", optional: true, "default": "" }, + { name: "type", type: "string", optional: true, "default": "all" }, // can be "all", "any", "phrase" + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 } + ] + }, + + // http://developer.yahoo.com/search/audio/V1/albumSearch.html + albumSearch: { + target: "http://search.yahooapis.com/AudioSearchService/V1/albumSearch", + parameters: [ + { name: "artist", type: "string", optional: true, "default": "" }, + { name: "artistid", type: "string", optional: true, "default": "" }, + { name: "album", type: "string", optional: true, "default": "" }, + { name: "albumid", type: "string", optional: true, "default": "" }, + { name: "type", type: "string", optional: true, "default": "all" }, // can be "all", "any", "phrase" + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 } + ] + }, + + // http://developer.yahoo.com/search/audio/V1/songSearch.html + songSearch: { + // beware, this method has returned many a JSON string containing syntax error(s) + target: "http://search.yahooapis.com/AudioSearchService/V1/songSearch", + parameters: [ + { name: "artist", type: "string", optional: true, "default": "" }, + { name: "artistid", type: "string", optional: true, "default": "" }, + { name: "album", type: "string", optional: true, "default": "" }, + { name: "albumid", type: "string", optional: true, "default": "" }, + { name: "song", type: "string", optional: true, "default": "" }, + { name: "songid", type: "string", optional: true, "default": "" }, + { name: "type", type: "string", optional: true, "default": "all" }, // can be "all", "any", "phrase" + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 } + ] + }, + + // http://developer.yahoo.com/search/audio/V1/songDownloadLocation.html + songDownloadLocation: { + target: "http://search.yahooapis.com/AudioSearchService/V1/songDownloadLocation", + parameters: [ + { name: "songid", type: "string", optional: false, "default": "" }, + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 }, + { name: "source", type: "string", optional: true, "default": "" } // can be "audiolunchbox", "artistdirect", "buymusic", "dmusic", "emusic", "epitonic", "garageband", "itunes", "yahoo", "livedownloads", "mp34u", "msn", "musicmatch", "mapster", "passalong", "rhapsody", "soundclick", "theweb" + ] + }, + + // + // CONTENT ANALYSIS + // + + // http://developer.yahoo.com/search/content/V1/termExtraction.html + contextSearch: { + // FIXME: the API docs say to submit this as a POST, but we need JSONP for cross-domain, right? + // transport: "POST", + target: "http://search.yahooapis.com/ContentAnalysisService/V1/termExtraction", + parameters: [ + { name: "context", type: "string", optional: false, "default": "" }, + { name: "query", type: "string", optional: true, "default": "" } + ] + }, + + // + // IMAGE SEARCH + // + + // http://developer.yahoo.com/search/image/V1/imageSearch.html + imageSearch: { + target: "http://search.yahooapis.com/ImageSearchService/V1/imageSearch", + parameters: [ + { name: "query", type: "string", optional: false, "default": "" }, + { name: "type", type: "string", optional: true, "default": "any" }, // can be "all", "any", "phrase" + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 }, + { name: "format", type: "string", optional: true, "default": "any" }, // can be "any", "bmp", "gif", "jpeg", "png" + { name: "adult_ok", type: "boolean", optional: true, "default": null }, + { name: "coloration", type: "string", optional: true, "default": "any" }, // can be "any", "color", "bw" + { name: "site", type: "string", optional: true, "default": null } + ] + }, + + // + // LOCAL SEARCH + // + + // http://developer.yahoo.com/search/local/V3/localSearch.html + localSearch: { + target: "http://local.yahooapis.com/LocalSearchService/V3/localSearch", + parameters: [ + { name: "query", type: "string", optional: true, "default": "" }, // optional, but one of (query, listing_id) is required + { name: "listing_id", type: "string", optional: true, "default": "" }, + { name: "results", type: "integer", optional: true, "default": 10 }, // max 20 + { name: "start", type: "integer", optional: true, "default": 1 }, + { name: "sort", type: "string", optional: true, "default": "relevance" }, // can be "relevance", "title", "distance", "rating" + { name: "radius", type: "float", optional: true }, // the default varies according to location + { name: "street", type: "string", optional: true, "default": null }, + { name: "city", type: "string", optional: true, "default": null }, + { name: "state", type: "string", optional: true, "default": null }, // full name or two-letter abbreviation + { name: "zip", type: "any", optional: true, "default": null }, // ddddd or ddddd-dddd format + { name: "location", type: "string", optional: true, "default": null }, // free text, supersedes the street, city, state, zip fields + { name: "latitude", type: "float", optional: true }, // -90 to 90 + { name: "longitude", type: "float", optional: true }, // -180 to 180 + { name: "category", type: "integer", optional: true }, + { name: "omit_category", type: "integer", optional: true }, + { name: "minimum_rating", type: "integer", optional: true } + ] + }, + + // http://developer.yahoo.com/local/V1/collectionSearch.html + collectionSearch: { + target: "http://collections.local.yahooapis.com/LocalSearchService/V1/collectionSearch", + parameters: [ + { name: "query", type: "string", optional: true, "default": "" }, // optional, but at least one of (query, username) is required + { name: "username", type: "string", optional: true, "default": "" }, + { name: "city", type: "string", optional: true, "default": null }, + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 } + ] + }, + + // http://developer.yahoo.com/local/V1/getCollection.html + getCollection: { + target: "http://collections.local.yahooapis.com/LocalSearchService/V1/getCollection", + parameters: [ + { name: "collection_id", type: "integer", optional: false, "default": "" } + ] + }, + + // + // MY WEB 2.0 + // + + // http://developer.yahoo.com/search/myweb/V1/urlSearch.html + urlSearch: { + target: "http://search.yahooapis.com/MyWebService/V1/urlSearch", + parameters: [ + { name: "tag", type: "string", optional: true, "default": "" }, + { name: "yahooid", type: "string", optional: true, "default": "" }, + { name: "sort", type: "string", optional: true, "default": "date" }, // can be "date", "title", "url" + { name: "reverse_sort", type: "boolean", optional: true, "default": 0 }, + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 } + ] + }, + + // http://developer.yahoo.com/search/myweb/V1/tagSearch.html + tagSearch: { + target: "http://search.yahooapis.com/MyWebService/V1/tagSearch", + parameters: [ + { name: "url", type: "string", optional: true, "default": "" }, + { name: "yahooid", type: "string", optional: true, "default": "" }, + { name: "sort", type: "string", optional: true, "default": "popularity" }, // can be "popularity", "tag", "date" + { name: "reverse_sort", type: "boolean", optional: true, "default": 0 }, + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 } + ] + }, + + // http://developer.yahoo.com/search/myweb/V1/relatedTags.html + relatedTags: { + target: "http://search.yahooapis.com/MyWebService/V1/relatedTags", + parameters: [ + { name: "tag", type: "string", optional: false, "default": "" }, + { name: "yahooid", type: "string", optional: true, "default": "" }, + { name: "sort", type: "string", optional: true, "default": "popularity" }, // can be "popularity", "tag", "date" + { name: "reverse_sort", type: "boolean", optional: true, "default": 0 }, + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 } + ] + }, + + // + // NEWS SEARCH + // + + // http://developer.yahoo.com/search/news/V1/newsSearch.html + newsSearch: { + target: "http://search.yahooapis.com/NewsSearchService/V1/newsSearch", + parameters: [ + { name: "query", type: "string", optional: false, "default": "" }, + { name: "type", type: "string", optional: true, "default": "any" }, // can be "all", "any", "phrase" + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 }, + { name: "sort", type: "string", optional: true, "default": "rank" }, // can be "rank", "date" + { name: "language", type: "string", optional: true, "default": null }, + { name: "site", type: "string", optional: true, "default": null } + ] + }, + + // + // SHOPPING + // + + // http://developer.yahoo.com/shopping/V2/catalogListing.html + catalogListing: { + target: "http://shopping.yahooapis.com/ShoppingService/V2/catalogListing", + parameters: [ + { name: "catalogid", type: "integer", optional: true, "default": null }, // required if idtype,idvalue are not specified + { name: "getlisting", type: "boolean", optional: true, "default": 1 }, + { name: "getreview", type: "boolean", optional: true, "default": 0 }, + { name: "getspec", type: "boolean", optional: true, "default": 0 }, + { name: "idtype", type: "string", optional: true, "default": null }, // can be "upc", "brand,model", "brand,partnum"; required if catalogid is not specified + { name: "idvalue", type: "string", optional: true, "default": null }, // required if catalogid is not specified + { name: "onlynew", type: "boolean", optional: true, "default": 1 }, + { name: "reviewstart", type: "integer", optional: true, "default": 1 }, + { name: "reviewsort", type: "string", optional: true, "default": "mostRecommended_descending" }, // can be "mostRecommended_descending", "mostRecommended_ascending", "latest_descending", "latest_ascending", "highestRated_descending", "highestRated_ascending" + { name: "zip", type: "string", optional: true, "default": null } + ] + }, + + + // http://developer.yahoo.com/shopping/V1/merchantSearch.html + merchantSearch: { + target: "http://api.shopping.yahoo.com/ShoppingService/V1/merchantSearch", + parameters: [ + { name: "merchantid", type: "integer", optional: false, "default": null } + ] + }, + + + // http://developer.yahoo.com/shopping/V3/productSearch.html + productSearch: { + target: "http://shopping.yahooapis.com/ShoppingService/V3/productSearch", + parameters: [ + { name: "query", type: "string", optional: true, "default": "" }, // required if category is not specified + { name: "category", type: "any", optional: true, "default": "" }, // required if query is not specified + { name: "class", type: "string", optional: true, "default": null }, // can be "catalogs", "freeoffers", "paidoffers"; defaults to all three of these + { name: "department", type: "integer", optional: true, "default": null }, + { name: "highestprice", type: "float", optional: true, "default": null }, + { name: "lowestprice", type: "float", optional: true, "default": null }, + { name: "merchantId", type: "integer", optional: true, "default": null }, + { name: "refinement", type: "string", optional: true, "default": null }, // used only if category is specified + { name: "results", type: "integer", optional: true, "default": 10 }, // 1-50 + { name: "show_numratings", type: "boolean", optional: true, "default": 0 }, + { name: "show_narrowing", type: "boolean", optional: true, "default": 1 }, + { name: "sort", type: "string", optional: true }, // can be "price_ascending", "price_descending", "userrating_ascending", "userrating_descending"; omitted, the default is to sort by relevance + { name: "start", type: "integer", optional: true, "default": 1 } // 1-300 + ] + }, + + // + // SITE EXPLORER + // + + // http://developer.yahoo.com/search/siteexplorer/V1/inlinkData.html + inlinkData: { + target: "http://search.yahooapis.com/SiteExplorerService/V1/inlinkData", + parameters: [ + { name: "query", type: "string", optional: false, "default": "" }, + { name: "results", type: "integer", optional: true, "default": 50 }, // max 100 + { name: "start", type: "integer", optional: true, "default": 1 }, + { name: "entire_site", type: "boolean", optional: true, "default": null }, + { name: "omit_inlinks", type: "string", optional: true, "default": "none" } // can be "none", "domain", "subdomain" + ] + }, + + // http://developer.yahoo.com/search/siteexplorer/V1/pageData.html + pageData: { + target: "http://search.yahooapis.com/SiteExplorerService/V1/pageData", + parameters: [ + { name: "query", type: "string", optional: false, "default": "" }, + { name: "results", type: "integer", optional: true, "default": 50 }, // max 100 + { name: "start", type: "integer", optional: true, "default": 1 }, + { name: "domain_only", type: "boolean", optional: true, "default": null } + ] + }, + + // http://developer.yahoo.com/search/siteexplorer/V1/ping.html + ping: { + target: "http://search.yahooapis.com/SiteExplorerService/V1/ping", + parameters: [ + { name: "sitemap", type: "string", optional: false, "default": "" } + ] + }, + + // http://developer.yahoo.com/search/siteexplorer/V1/updateNotification.html + updateNotification: { + target: "http://search.yahooapis.com/SiteExplorerService/V1/updateNotification", + parameters: [ + { name: "url", type: "string", optional: false, "default": "" } + ] + }, + + // + // TRAFFIC + // + + // http://developer.yahoo.com/traffic/rest/V1/index.html + trafficData: { + target: "http://local.yahooapis.com/MapsService/V1/trafficData", + parameters: [ + { name: "street", type: "string", optional: true, "default": "" }, + { name: "city", type: "string", optional: true, "default": "" }, + { name: "state", type: "string", optional: true, "default": null }, // full name or two-letter abbreviation + { name: "zip", type: "any", optional: true, "default": null }, // ddddd or ddddd-dddd format + { name: "location", type: "string", optional: true, "default": null }, // free text, supersedes the street, city, state, zip fields + { name: "latitude", type: "float", optional: true }, // -90 to 90 + { name: "longitude", type: "float", optional: true }, // -180 to 180 + { name: "severity", type: "integer", optional: true, "default": 1 }, // can be 1-5 + { name: "zoom", type: "integer", optional: true, "default": 6 }, // can be 1-12 + { name: "radius", type: "float", optional: true }, // in miles, default varies with location; ignored if zoom is specified + { name: "include_map", type: "boolean", optional: true, "default": 0 }, + { name: "image_type", type: "string", optional: true, "default": "png" }, // can be "png" or "gif" + { name: "image_height", type: "integer", optional: true, "default": 500 }, // in pixels, can be 10-2000 + { name: "image_width", type: "integer", optional: true, "default": 620 } // in pixels, can be 10-2000 + ] + }, + + // + // TRAVEL + // + + // http://developer.yahoo.com/travel/tripservice/V1.1/tripSearch.html + tripSearch: { + target: "http://travel.yahooapis.com/TripService/V1.1/tripSearch", + parameters: [ + { name: "query", type: "string", optional: true, "default": "" }, + { name: "results", type: "integer", optional: true, "default": 10 }, // max 50 + { name: "start", type: "integer", optional: true, "default": 1 } + ] + }, + + // http://developer.yahoo.com/travel/tripservice/V1.1/getTrip.html + getTrip: { + target: "http://travel.yahooapis.com/TripService/V1.1/getTrip", + parameters: [ + { name: "id", type: "integer", optional: false, "default": null } + ] + }, + + // + // UTILITY SERVICES + // + + // http://developer.yahoo.com/util/timeservice/V1/getTime.html + /* RGG: commented out because it refuses to return JSON format even when you tell it + to do so (it returns a + + + + + + + + + +

+ + DEMO: JsonRestStore Search + +

+ +
+ +

+ + Description: + +

+ +

+ + This simple demo shows how JsonRestStore can be used with Persevere. + +

+ +

+ +

+ + + +
+ + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ + + + + diff --git a/includes/js/dojox/rpc/demos/demo_JsonRestStore_Persevere.html b/includes/js/dojox/rpc/demos/demo_JsonRestStore_Persevere.html new file mode 100644 index 0000000..40c6bac --- /dev/null +++ b/includes/js/dojox/rpc/demos/demo_JsonRestStore_Persevere.html @@ -0,0 +1,65 @@ + + + + Demo of JsonRestStore + + + + + + + +

+ DEMO: JsonRestStore Search +

+
+

+ Description: +

+

+ This simple demo shows how JsonRestStore can be used with Persevere. +

+

+

+ +
+ + + + + + + + +
+ +
+
+ + diff --git a/includes/js/dojox/rpc/demos/documentation.html b/includes/js/dojox/rpc/demos/documentation.html new file mode 100644 index 0000000..4c28103 --- /dev/null +++ b/includes/js/dojox/rpc/demos/documentation.html @@ -0,0 +1,33 @@ + + + + + + +
+ + \ No newline at end of file diff --git a/includes/js/dojox/rpc/demos/templates/documentation.html b/includes/js/dojox/rpc/demos/templates/documentation.html new file mode 100644 index 0000000..d14cf16 --- /dev/null +++ b/includes/js/dojox/rpc/demos/templates/documentation.html @@ -0,0 +1,8 @@ +
+ +
    + {% for result in results %} +
  • {% if result.type %}{{ result.type }} {% endif %}{% ifequal result.type "Function" %}{% if not result.resources %}function {% endif %}{% endifequal %}{{ result.name }}{% ifequal result.type "Function" %}{% if not result.resources %}({% for parameter in result.parameters %}{% if not forloop.first %}, {% endif %}{% if parameter.types %}{% for type in parameter.types %}{% if not forloop.first %}|{% endif %}{{ type.title }}{% endfor %}{% if parameter.optional %}?{% endif %}{% if parameter.repeating %}...{% endif %} {% endif %}{{ parameter.name }}{% endfor %}{% endif %}{% endifequal %}{% ifequal result.type "Function" %}{% if not result.resources %}){% endif %}{% endifequal %}
  • + {% endfor %} +
+
\ No newline at end of file diff --git a/includes/js/dojox/rpc/demos/templates/yahoo.html b/includes/js/dojox/rpc/demos/templates/yahoo.html new file mode 100644 index 0000000..04339d2 --- /dev/null +++ b/includes/js/dojox/rpc/demos/templates/yahoo.html @@ -0,0 +1,31 @@ +
+ +
    + {% for result in results.Result %} +
  • {{ result.Title }}
    {{ result.Summary }}
  • + {% endfor %} +
+ + {% if results.firstResultPosition %} + + + + + {% endif %}{% if results.totalResultsAvailable %} + + + + + {% endif %}{% if results.totalResultsReturned %} + + + + + {% endif %}{% if results.type %} + + + + + {% endif %} +
First Result{{ results.firstResultPosition }}
Total Results Available{{ results.totalResultsAvailable }}
Results Returned{{ results.totalResultsReturned }}
Type{{ results.type }}
+
diff --git a/includes/js/dojox/rpc/demos/yahoo.html b/includes/js/dojox/rpc/demos/yahoo.html new file mode 100644 index 0000000..39cee00 --- /dev/null +++ b/includes/js/dojox/rpc/demos/yahoo.html @@ -0,0 +1,39 @@ + + + + Yahoo Search Demo + + + + + +

Yahoo Web Search

+
+ + diff --git a/includes/js/dojox/rpc/documentation.smd b/includes/js/dojox/rpc/documentation.smd new file mode 100644 index 0000000..3ff1623 --- /dev/null +++ b/includes/js/dojox/rpc/documentation.smd @@ -0,0 +1,30 @@ +{ + envelope: "URL", + transport: "JSONP", + callbackParamName: "callback", + services: { + get: { + target: "http://redesign.dojotoolkit.org/jsdoc/jsonp", + parameters: [ + { name: "name", type: "string", optional: false }, + { name: "exact", type: "boolean", optional: true }, + { name: "recursion", type: "boolean", optional: true }, + { name: "resource", type: "string", optional: true }, + { name: "project", type: "string", optional: true }, + { name: "version", type: "string", optional: true }, + { name: "attributes", type: "array", optional: true } + ] + }, + batch: { + target: "http://redesign.dojotoolkit.org/jsdoc/jsonp/batch", + parameters: [ + { name: "names", type: "array", optional: false }, + { name: "exact", type: "boolean", optional: true }, + { name: "recursion", type: "boolean", optional: true }, + { name: "project", type: "string", optional: true }, + { name: "version", type: "string", optional: true }, + { name: "attributes", type: "array", optional: false } + ] + } + } +} \ No newline at end of file diff --git a/includes/js/dojox/rpc/test.txt b/includes/js/dojox/rpc/test.txt new file mode 100644 index 0000000..e69de29 diff --git a/includes/js/dojox/rpc/tests/JsonReferencing.js b/includes/js/dojox/rpc/tests/JsonReferencing.js new file mode 100644 index 0000000..69a6782 --- /dev/null +++ b/includes/js/dojox/rpc/tests/JsonReferencing.js @@ -0,0 +1,30 @@ +if(!dojo._hasResource["dojox.rpc.tests.JsonReferencing"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.rpc.tests.JsonReferencing"] = true; +dojo.provide("dojox.rpc.tests.JsonReferencing"); +dojo.require("dojox.rpc.JsonReferencing"); + + +doh.register("dojox.rpc.tests.JsonReferencing", [ + function fromRefJson(t) { + var testStr = '{a:{$ref:"$"},id:"root",c:{d:"e",f:{$ref:"root.c"}},b:{$ref:"$.c"}}'; + + var mirrorObj = dojox.rpc.fromJson(testStr); + t.assertEqual(mirrorObj, mirrorObj.a); + t.assertEqual(mirrorObj.c, mirrorObj.c.f); + t.assertEqual(mirrorObj.c, mirrorObj.b); + }, + function toAndFromRefJson(t) { + var testObj = {a:{},b:{c:{}}}; + testObj.a.d= testObj; + testObj.b.g=testObj.a; + testObj.b.c.f = testObj.b; + testObj.b.h=testObj.a; + var mirrorObj = dojox.rpc.fromJson(dojox.rpc.toJson(testObj)); + t.assertEqual(mirrorObj.a.d, mirrorObj); + t.assertEqual(mirrorObj.b.g, mirrorObj.a); + t.assertEqual(mirrorObj.b.c.f, mirrorObj.b); + t.assertEqual(mirrorObj.b.h, mirrorObj.a); + } +]); + +} diff --git a/includes/js/dojox/rpc/tests/Service.js b/includes/js/dojox/rpc/tests/Service.js new file mode 100644 index 0000000..353519e --- /dev/null +++ b/includes/js/dojox/rpc/tests/Service.js @@ -0,0 +1,702 @@ +if(!dojo._hasResource["dojox.rpc.tests.Service"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.rpc.tests.Service"] = true; +dojo.provide("dojox.rpc.tests.Service"); +dojo.require("dojo.io.script"); +dojo.require("dojox.rpc.Service"); +dojo.require("dojox.rpc.JsonRPC"); +dojo.require("dojox.rpc.Rest"); +//this is a copy of our smd in js form, so we can just share it easily +//dojo.require("dojox.rpc.tests.resources.testSmd"); + + +dojox.rpc.tests.service = new dojox.rpc.Service(dojo.moduleUrl("dojox.rpc.tests.resources", "test.smd")); + +doh.register("dojox.rpc.tests.echo", + [ + { + name: "#1 POST,URL,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + //test when given named params + var td = this.svc.postEcho({message: this.name,foo:2}); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#2 POST,URL,Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postEcho(this.name,2); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#3 GET,URL,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.getEcho({message: this.name}); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + + { + name: "#3.1 REST PUT,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + res = this.name + Math.random(); + //test when given named params + var td = this.svc.restStore.put({location: "res"},res); + td.addCallback(this, function(result){ + var td = this.svc.restStore({location: "res"}); + td.addCallback(this, function(result){ + if (result==res){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + }); + + return d; + } + }, + { + name: "#3.2 REST POST,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + var newRes = this.name + Math.random(); + res += newRes; + //test when given named params + var td = this.svc.restStore.post({location: "res"},newRes); + td.addCallback(this, function(result){ + var td = this.svc.restStore({location: "res"}); + td.addCallback(this, function(result){ + if (result==res){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + }); + + return d; + } + }, + { + name: "#3.3 REST DELETE,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.restStore['delete']({location: "res"}); + td.addCallback(this, function(result){ + var td = this.svc.restStore({location: "res"}); + td.addCallback(this, function(result){ + if (result=="deleted"){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + }); + + return d; + } + }, + { + name: "#3.4 GET,URL,Named Parameters, Returning Json", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.getEchoJson({message:'{"foo":"bar"}'}); + td.addCallback(this, function(result){ + if (result.foo=='bar'){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#3.5 GET,PATH,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.getPathEcho({path: "pathname"}); + td.addCallback(this, function(result){ + if (result=="/path/pathname"){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + + { + name: "#4 GET,URL,Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.getEcho(this.name); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + + { + name: "#5 POST,URL,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonEcho({message: this.name}); + td.addCallback(this, function(res){ + var result = dojo.fromJson(res); + if (result && result.message && result.message==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + + { + name: "#6 POST,JSON,Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonEcho(this.name); + td.addCallback(this, function(res){ + var result = dojo.fromJson(res); + if (result && result.message && result.message==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#7 JSONP,URL,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.jsonpEcho({message: this.name}); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#8 JSONP,URL, Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.jsonpEcho(this.name); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#9 POST,JSON-RPC-1.0,Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonRpc10Echo(this.name); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#10 POST,JSON-RPC-1.0,Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonRpc10EchoNamed(this.name); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#11 POST,JSON-RPC 1.2, Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonRpc12Echo(this.name); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#12 POST,JSON-RPC 1.2, Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonRpc12Echo({message: this.name}); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + } + /* + ,{ + name: "#13 GET,JSON-RPC 1.2, Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.getJsonRpc12Echo(this.name); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + { + name: "#14 GET,JSON-RPC 1.2, Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.getJsonRpc12EchoNamed({message: this.name}); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + }, + ,{ + name: "#15 JSONP,JSON-RPC 1.2, Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.jsonpJsonRpc12Echo(this.name); + td.addCallback(this, function(result){ + if (result==this.name){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + + return d; + } + } + */ + ] +); + +doh.register("dojox.rpc.tests.jsonRpcForcedError", [ + { + name: "POST,JSON-RPC 1.0, Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonRpc10ForcedError(this.name); + + td.addErrback(this, function(error){ + d.callback(true); + }); + + return d; + } + }, + { + name: "POST,JSON-RPC 1.2, Ordered Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonRpc12ForcedError(this.name); + + td.addErrback(this, function(error){ + d.callback(true); + }); + + return d; + } + }, + { + name: "POST,JSON-RPC 1.2, Named Parameters", + timeout: 4000, + setUp: function(){ + //this.svc = new dojox.rpc.Service(dojox.rpc.tests.resources.testSmd); + this.svc = dojox.rpc.tests.service; + }, + runTest: function(){ + var d = new doh.Deferred(); + + if (window.location.protocol=="file:") { + var err= new Error("This Test requires a webserver and will fail intentionally if loaded from file://"); + d.errback(err); + return d; + } + + //test when given named params + var td = this.svc.postJsonRpc12ForcedError({message: this.name}); + + td.addErrback(this, function(error){ + d.callback(true); + }); + + return d; + } + } +]); + +} diff --git a/includes/js/dojox/rpc/tests/Yahoo.js b/includes/js/dojox/rpc/tests/Yahoo.js new file mode 100644 index 0000000..7e5dbfa --- /dev/null +++ b/includes/js/dojox/rpc/tests/Yahoo.js @@ -0,0 +1,317 @@ +if(!dojo._hasResource["dojox.rpc.tests.Yahoo"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.rpc.tests.Yahoo"] = true; +dojo.provide("dojox.rpc.tests.Yahoo"); +dojo.require("dojo.io.script"); +dojo.require("dojox.rpc.Service"); + +dojox.rpc.tests.yahooService = new dojox.rpc.Service(dojo.moduleUrl("dojox.rpc.SMDLibrary", "yahoo.smd")); + +dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT = 8000; +dojox.rpc.tests.yahooService.TEST_METHOD_LONG_TIMEOUT = 30000; + +dojox.rpc.tests.yahooService._testMethod = function(method){ + return function(m){ + var d = new doh.Deferred(); + + if (method.name && method.parameters && method.expectedResult) { + var yd = dojox.rpc.tests.yahooService[method.name](method.parameters); + yd.addCallback(this, function(result){ + if (result[method.expectedResult]){ + d.callback(true); + }else{ + d.errback(new Error("Unexpected Return Value: ", result)); + } + }); + } + + return d; + } +}; + +doh.register("dojox.rpc.tests.yahoo", + [ + { + name: "#1, Yahoo Answers::questionSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "questionSearch", + parameters: {query: "dojo toolkit"}, + expectedResult: "all" + }) + }, + { + name: "#2, Yahoo Answers::getByCategory", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "getByCategory", + parameters: {category_name: "Computers+%26+Internet%3ESoftware"}, + expectedResult: "all" + }) + }, + { + name: "#3, Yahoo Answers::getQuestion", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "getQuestion", + parameters: {question_id: "1005120800412"}, + expectedResult: "all" + }) + }, + { + name: "#4, Yahoo Answers::getByUser", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "getByUser", + parameters: {user_id: "AA10001397"}, + expectedResult: "all" + }) + }, + { + name: "#5, Yahoo Audio::artistSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "artistSearch", + parameters: {artist: "The Beatles"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#6, Yahoo Audio::albumSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "albumSearch", + parameters: {artist: "The Beatles", album: "Magical Mystery Tour"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#7, Yahoo Audio::songSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "songSearch", + parameters: {artist: "The Beatles", album: "Magical Mystery Tour", song: "Penny Lane"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#8, Yahoo Audio::songDownloadLocation", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "songDownloadLocation", + parameters: {songid: "XXXXXXT000995691"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#9, Yahoo ContentAnalysis::contextSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "contextSearch", + parameters: { + context: "Welcome to the Book of Dojo. This book covers both versions 0.9 and 1.0, and all 1.0 extensions and changes are clearly marked for your enjoyment. Please use the forums for support questions, but if you see something missing, incomplete, or just plain wrong in this book, please leave a comment.", + query: "dojo" + }, + expectedResult: "ResultSet" + }) + }, + { + name: "#10, Yahoo Image::imageSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "imageSearch", + parameters: {query: "dojo"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#11, Yahoo Local::localSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "localSearch", + parameters: {query: "pizza", zip: "98201"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#12, Yahoo Local::collectionSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_LONG_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "collectionSearch", + parameters: {query: "dojo"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#13, Yahoo Local::getCollection", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_LONG_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + expectedResult: "getCollection", + parameters: {collection_id: "1000031487"}, + expectedResult: "Result" + }) + }, + { + name: "#14, Yahoo Local::trafficData", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_LONG_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "trafficData", + parameters: {street: "1600 Pennsylvania Ave", city: "Washington, DC"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#15, Yahoo MyWebs::urlSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_LONG_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "urlSearch", + parameters: {tag: "javascript"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#16, Yahoo MyWebs::tagSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_LONG_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "tagSearch", + parameters: {url: "dojotoolkit.org"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#17, Yahoo MyWebs::relatedTags", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_LONG_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "relatedTags", + parameters: {tag: "javascript"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#18, Yahoo NewsSearch::newsSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "newsSearch", + parameters: {query: "dojo toolkit"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#19, Yahoo Shopping::catalogListing", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "catalogListing", + parameters: {idtype: "brand,partnum", idvalue: "canon,1079B001", getspec: 1}, + expectedResult: "Catalog" + }) + }, + { + name: "#20, Yahoo Shopping::merchantSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "merchantSearch", + parameters: {merchantid: "1021849"}, + expectedResult: "Merchant" + }) + }, + { + name: "#21, Yahoo Shopping::productSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "productSearch", + parameters: {query: "dojo"}, + expectedResult: "Categories" + }) + }, + { + name: "#22, Yahoo SiteExplorer::inlinkData", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "inlinkData", + parameters: {query: "dojotoolkit.org"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#23, Yahoo SiteExplorer::pageData", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "pageData", + parameters: {query: "dojotoolkit.org"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#24, Yahoo SiteExplorer::ping", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "ping", + parameters: {sitemap: "http://www.yahoo.com"}, + expectedResult: "Success" + }) + }, + { + name: "#25, Yahoo SiteExplorer::updateNotification", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "updateNotification", + parameters: {url: "http://www.yahoo.com"}, + expectedResult: "Success" + }) + }, + { + name: "#26, Yahoo Trip::tripSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "tripSearch", + parameters: {query: "eiffel tower"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#27, Yahoo Trip::getTrip", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "getTrip", + parameters: {id: "546303"}, + expectedResult: "Result" + }) + }, + { + name: "#28, Yahoo Video::videoSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "videoSearch", + parameters: {query: "star wars kid"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#29, Yahoo Web::webSearch", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "webSearch", + parameters: {query: "dojo toolkit"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#30, Yahoo Web::spellingSuggestion", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "spellingSuggestion", + parameters: {query: "beatls"}, + expectedResult: "ResultSet" + }) + }, + { + name: "#31, Yahoo Web::relatedSuggestion", + timeout: dojox.rpc.tests.yahooService.TEST_METHOD_TIMEOUT, + runTest: dojox.rpc.tests.yahooService._testMethod({ + name: "relatedSuggestion", + parameters: {query: "dojo toolkit"}, + expectedResult: "ResultSet" + }) + } +]); + +} diff --git a/includes/js/dojox/rpc/tests/libraryTests.js b/includes/js/dojox/rpc/tests/libraryTests.js new file mode 100644 index 0000000..7af2ae6 --- /dev/null +++ b/includes/js/dojox/rpc/tests/libraryTests.js @@ -0,0 +1,12 @@ +if(!dojo._hasResource["dojox.rpc.tests.libraryTests"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.rpc.tests.libraryTests"] = true; +dojo.provide("dojox.rpc.tests.libraryTests"); + +try{ + dojo.require("dojox.rpc.tests.Yahoo"); +}catch(e){ + doh.debug(e); +} + + +} diff --git a/includes/js/dojox/rpc/tests/module.js b/includes/js/dojox/rpc/tests/module.js new file mode 100644 index 0000000..038a9ad --- /dev/null +++ b/includes/js/dojox/rpc/tests/module.js @@ -0,0 +1,13 @@ +if(!dojo._hasResource["dojox.rpc.tests.module"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.rpc.tests.module"] = true; +dojo.provide("dojox.rpc.tests.module"); + +try{ + dojo.require("dojox.rpc.tests.Service"); + dojo.require("dojox.rpc.tests.JsonReferencing"); +}catch(e){ + doh.debug(e); +} + + +} diff --git a/includes/js/dojox/rpc/tests/resources/JSON.php b/includes/js/dojox/rpc/tests/resources/JSON.php new file mode 100644 index 0000000..4a21ce7 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/JSON.php @@ -0,0 +1,724 @@ + + * @author Matt Knapp + * @author Brett Stimmerman + * @copyright 2005 Michal Migurski + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 + */ + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_SLICE', 1); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_STR', 2); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_ARR', 4); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_OBJ', 8); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_CMT', 16); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_LOOSE_TYPE', 10); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_STRICT_TYPE', 11); + +/** + * Converts to and from JSON format. + * + * Brief example of use: + * + * + * // create a new instance of Services_JSON + * $json = new Services_JSON(); + * + * // convert a complexe value to JSON notation, and send it to the browser + * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); + * $output = $json->encode($value); + * + * print($output); + * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]] + * + * // accept incoming POST data, assumed to be in JSON notation + * $input = file_get_contents('php://input', 1000000); + * $value = $json->decode($input); + * + */ +class Services_JSON +{ + /** + * constructs a new JSON instance + * + * @param int $use object behavior: when encoding or decoding, + * be loose or strict about object/array usage + * + * possible values: + * - SERVICES_JSON_STRICT_TYPE: strict typing, default. + * "{...}" syntax creates objects in decode(). + * - SERVICES_JSON_LOOSE_TYPE: loose typing. + * "{...}" syntax creates associative arrays in decode(). + */ + function Services_JSON($use = SERVICES_JSON_STRICT_TYPE) + { + $this->use = $use; + } + + /** + * convert a string from one UTF-16 char to one UTF-8 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf16 UTF-16 character + * @return string UTF-8 character + * @access private + */ + function utf162utf8($utf16) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) + return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); + + $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); + + switch(true) { + case ((0x7F & $bytes) == $bytes): + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x7F & $bytes); + + case (0x07FF & $bytes) == $bytes: + // return a 2-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xC0 | (($bytes >> 6) & 0x1F)) + . chr(0x80 | ($bytes & 0x3F)); + + case (0xFFFF & $bytes) == $bytes: + // return a 3-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xE0 | (($bytes >> 12) & 0x0F)) + . chr(0x80 | (($bytes >> 6) & 0x3F)) + . chr(0x80 | ($bytes & 0x3F)); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + function utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + + switch(strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $ut8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return string JSON string representation of input var + * @access public + */ + function encode($var) + { + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2})); + $c += 2; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + return '{' . + join(',', array_map(array($this, 'name_value'), + array_keys($var), + array_values($var))) + . '}'; + } + + // treat it like a regular array + return '[' . join(',', array_map(array($this, 'encode'), $var)) . ']'; + + case 'object': + $vars = get_object_vars($var); + return '{' . + join(',', array_map(array($this, 'name_value'), + array_keys($vars), + array_values($vars))) + . '}'; + + default: + return ''; + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + function name_value($name, $value) + { + return $this->encode(strval($name)) . ':' . $this->encode($value); + } + + /** + * reduce a string by removing leading and trailing comments and whitespace + * + * @param $str string string value to strip of comments and whitespace + * + * @return string string value stripped of comments and whitespace + * @access private + */ + function reduce_string($str) + { + $str = preg_replace(array( + + // eliminate single line comments in '// ...' form + '#^\s*//(.+)$#m', + + // eliminate multi-line comments in '/* ... */' form, at start of string + '#^\s*/\*(.+)\*/#Us', + + // eliminate multi-line comments in '/* ... */' form, at end of string + '#/\*(.+)\*/\s*$#Us' + + ), '', $str); + + // eliminate extraneous space + return trim($str); + } + + /** + * decodes a JSON string into appropriate variable + * + * @param string $str JSON-formatted string + * + * @return mixed number, boolean, string, array, or object + * corresponding to given JSON input string. + * See argument 1 to Services_JSON() above for object-output behavior. + * Note that decode() always returns strings + * in ASCII or UTF-8 format! + * @access public + */ + function decode($str) + { + $str = $this->reduce_string($str); + + switch (strtolower($str)) { + case 'true': + return true; + + case 'false': + return false; + + case 'null': + return null; + + default: + if (is_numeric($str)) { + // Lookie-loo, it's a number + + // This would work on its own, but I'm trying to be + // good about returning integers where appropriate: + // return (float)$str; + + // Return float or int, as appropriate + return ((float)$str == (integer)$str) + ? (integer)$str + : (float)$str; + + } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { + // STRINGS RETURNED IN UTF-8 FORMAT + $delim = substr($str, 0, 1); + $chrs = substr($str, 1, -1); + $utf8 = ''; + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c < $strlen_chrs; ++$c) { + + $substr_chrs_c_2 = substr($chrs, $c, 2); + $ord_chrs_c = ord($chrs{$c}); + + switch (true) { + case $substr_chrs_c_2 == '\b': + $utf8 .= chr(0x08); + ++$c; + break; + case $substr_chrs_c_2 == '\t': + $utf8 .= chr(0x09); + ++$c; + break; + case $substr_chrs_c_2 == '\n': + $utf8 .= chr(0x0A); + ++$c; + break; + case $substr_chrs_c_2 == '\f': + $utf8 .= chr(0x0C); + ++$c; + break; + case $substr_chrs_c_2 == '\r': + $utf8 .= chr(0x0D); + ++$c; + break; + + case $substr_chrs_c_2 == '\\"': + case $substr_chrs_c_2 == '\\\'': + case $substr_chrs_c_2 == '\\\\': + case $substr_chrs_c_2 == '\\/': + if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || + ($delim == "'" && $substr_chrs_c_2 != '\\"')) { + $utf8 .= $chrs{++$c}; + } + break; + + case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): + // single, escaped unicode character + $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) + . chr(hexdec(substr($chrs, ($c + 4), 2))); + $utf8 .= $this->utf162utf8($utf16); + $c += 5; + break; + + case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): + $utf8 .= $chrs{$c}; + break; + + case ($ord_chrs_c & 0xE0) == 0xC0: + // characters U-00000080 - U-000007FF, mask 110XXXXX + //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 2); + ++$c; + break; + + case ($ord_chrs_c & 0xF0) == 0xE0: + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 3); + $c += 2; + break; + + case ($ord_chrs_c & 0xF8) == 0xF0: + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 4); + $c += 3; + break; + + case ($ord_chrs_c & 0xFC) == 0xF8: + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 5); + $c += 4; + break; + + case ($ord_chrs_c & 0xFE) == 0xFC: + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 6); + $c += 5; + break; + + } + + } + + return $utf8; + + } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { + // array, or object notation + + if ($str{0} == '[') { + $stk = array(SERVICES_JSON_IN_ARR); + $arr = array(); + } else { + if ($this->use == SERVICES_JSON_LOOSE_TYPE) { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = array(); + } else { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = new stdClass(); + } + } + + array_push($stk, array('what' => SERVICES_JSON_SLICE, + 'where' => 0, + 'delim' => false)); + + $chrs = substr($str, 1, -1); + $chrs = $this->reduce_string($chrs); + + if ($chrs == '') { + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } else { + return $obj; + + } + } + + //print("\nparsing {$chrs}\n"); + + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c <= $strlen_chrs; ++$c) { + + $top = end($stk); + $substr_chrs_c_2 = substr($chrs, $c, 2); + + if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { + // found a comma that is not inside a string, array, etc., + // OR we've reached the end of the character list + $slice = substr($chrs, $top['where'], ($c - $top['where'])); + array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); + //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + // we are in an array, so just push an element onto the stack + array_push($arr, $this->decode($slice)); + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + // we are in an object, so figure + // out the property name and set an + // element in an associative array, + // for now + if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // "name":value pair + $key = $this->decode($parts[1]); + $val = $this->decode($parts[2]); + + if ($this->use == SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // name:value pair, where name is unquoted + $key = $parts[1]; + $val = $this->decode($parts[2]); + + if ($this->use == SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } + + } + + } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { + // found a quote, and we are not inside a string + array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); + //print("Found start of string at {$c}\n"); + + } elseif (($chrs{$c} == $top['delim']) && + ($top['what'] == SERVICES_JSON_IN_STR) && + (($chrs{$c - 1} != '\\') || + ($chrs{$c - 1} == '\\' && $chrs{$c - 2} == '\\'))) { + // found a quote, we're in a string, and it's not escaped + array_pop($stk); + //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '[') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-bracket, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); + //print("Found start of array at {$c}\n"); + + } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { + // found a right-bracket, and we're in an array + array_pop($stk); + //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '{') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-brace, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); + //print("Found start of object at {$c}\n"); + + } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { + // found a right-brace, and we're in an object + array_pop($stk); + //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($substr_chrs_c_2 == '/*') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a comment start, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); + $c++; + //print("Found start of comment at {$c}\n"); + + } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { + // found a comment end, and we're in one now + array_pop($stk); + $c++; + + for ($i = $top['where']; $i <= $c; ++$i) + $chrs = substr_replace($chrs, ' ', $i, 1); + + //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } + + } + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + return $obj; + + } + + } + } + } + +} + +?> \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/bigQuery b/includes/js/dojox/rpc/tests/resources/bigQuery new file mode 100644 index 0000000..e8f9429 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/bigQuery @@ -0,0 +1 @@ +[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20] \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/bigQuery5 b/includes/js/dojox/rpc/tests/resources/bigQuery5 new file mode 100644 index 0000000..e77ca8d --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/bigQuery5 @@ -0,0 +1 @@ +[1,2,3,4,5] \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/echo.php b/includes/js/dojox/rpc/tests/resources/echo.php new file mode 100644 index 0000000..b38a3ee --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/echo.php @@ -0,0 +1,7 @@ + diff --git a/includes/js/dojox/rpc/tests/resources/echoJson.php b/includes/js/dojox/rpc/tests/resources/echoJson.php new file mode 100644 index 0000000..52b5d03 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/echoJson.php @@ -0,0 +1,8 @@ + diff --git a/includes/js/dojox/rpc/tests/resources/fakestore.php b/includes/js/dojox/rpc/tests/resources/fakestore.php new file mode 100644 index 0000000..075926a --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/fakestore.php @@ -0,0 +1,36 @@ + diff --git a/includes/js/dojox/rpc/tests/resources/jsonRpc10.php b/includes/js/dojox/rpc/tests/resources/jsonRpc10.php new file mode 100644 index 0000000..fc99b75 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/jsonRpc10.php @@ -0,0 +1,47 @@ + sudo pear install File + // Your server will also need the Pear library directory included in PHP's + // include_path configuration directive + // require_once('File.php'); + + // ensure that we don't try to send "html" down to the client + header("Content-Type: text/plain"); + + $json = new Services_JSON; + //$fp = new File(); + + $results = array(); + $results['error'] = null; + + $jsonRequest = file_get_contents('php://input'); + //$jsonRequest = '{"params":["Blah"],"method":"myecho","id":86}'; + + $req = $json->decode($jsonRequest); + + $method = $req->method; + $params = $req->params; + + switch($method) { + case "postJsonRpc10EchoNamed": + case "postJsonRpc10Echo": + $results['result']=$params[0]; + break; + default: + $results['result']=""; + $results['error']="JSON-RPC 1.0 METHOD NOT FOUND"; + break; + } + + $results['id'] = $req->id; + + $encoded = $json->encode($results); + + print $encoded; +?> diff --git a/includes/js/dojox/rpc/tests/resources/jsonRpc11.php b/includes/js/dojox/rpc/tests/resources/jsonRpc11.php new file mode 100644 index 0000000..1c91e51 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/jsonRpc11.php @@ -0,0 +1,52 @@ + sudo pear install File + // Your server will also need the Pear library directory included in PHP's + // include_path configuration directive + // require_once('File.php'); + + // ensure that we don't try to send "html" down to the client + header("Content-Type: text/plain"); + + $json = new Services_JSON; + //$fp = new File(); + + $results = array(); + $results['error'] = null; + + $jsonRequest = file_get_contents('php://input'); + //$jsonRequest = '{"params":["Blah"],"method":"myecho","id":86}'; + + $req = $json->decode($jsonRequest); + + $method = $req->method; + $params = $req->params; + + switch($method) { + case "rawPostJsonRpc11Echo": + if (is_array($params)){ + $results['result']=$params; + }else{ + $results['result']=$params->message; + } + break; + default: + $results['result']=""; + $results['error']=array(); + $results['error']['code']=-32601; + $results['error']["message"]="The requested remote-procedure does not exist / is not available."; + break; + } + + $results['id'] = $req->id; + + $encoded = $json->encode($results); + + print $encoded; +?> diff --git a/includes/js/dojox/rpc/tests/resources/jsonRpc12.php b/includes/js/dojox/rpc/tests/resources/jsonRpc12.php new file mode 100644 index 0000000..8fad2e5 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/jsonRpc12.php @@ -0,0 +1,53 @@ + sudo pear install File + // Your server will also need the Pear library directory included in PHP's + // include_path configuration directive + // require_once('File.php'); + + // ensure that we don't try to send "html" down to the client + header("Content-Type: text/plain"); + + $json = new Services_JSON; + //$fp = new File(); + + $results = array(); + $results['error'] = null; + + $jsonRequest = file_get_contents('php://input'); + //$jsonRequest = '{"params":["Blah"],"method":"myecho","id":86}'; + + $req = $json->decode($jsonRequest); + + $method = $req->method; + $params = $req->params; + + switch($method) { + case "postJsonRpc12Echo": + case "postJsonRpc12EchoNamed": + if (is_array($params)){ + $results['result']=$params; + }else{ + $results['result']=$params->message; + } + break; + default: + $results['result']=""; + $results['error']=array(); + $results['error']['code']=-32601; + $results['error']["message"]="The requested remote-procedure does not exist / is not available."; + break; + } + + $results['id'] = $req->id; + + $encoded = $json->encode($results); + + print $encoded; +?> diff --git a/includes/js/dojox/rpc/tests/resources/jsonRpcPostGetEcho.php b/includes/js/dojox/rpc/tests/resources/jsonRpcPostGetEcho.php new file mode 100644 index 0000000..7db9153 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/jsonRpcPostGetEcho.php @@ -0,0 +1,38 @@ +decode($params); + $result = "{id:" . $id . ", 'result':'" . $p[0]. "', error:''}"; + break; + case "postJsonRpc12Echo": + case "getJsonRpc12Echo": + case "postJsonRpc12EchoNamed": + case "getJsonRpc12EchoNamed": + $p = $json->decode($params); + + if ($p->message){ + $d = $p->message; + }else{ + $d=$p[0]; + } + $result = "{id:" . $id . ", 'result':'" . $d . "'}"; + break; + default: + $result = "{id:'1','error':'Unknown Method', 'result':'this result only here for this test, shouldnt be here in real code'}"; + break; + } + + print $result; + +?> diff --git a/includes/js/dojox/rpc/tests/resources/jsonpEcho.php b/includes/js/dojox/rpc/tests/resources/jsonpEcho.php new file mode 100644 index 0000000..15d9aaa --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/jsonpEcho.php @@ -0,0 +1,23 @@ + diff --git a/includes/js/dojox/rpc/tests/resources/jsonpEcho.phps b/includes/js/dojox/rpc/tests/resources/jsonpEcho.phps new file mode 100644 index 0000000..15d9aaa --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/jsonpEcho.phps @@ -0,0 +1,23 @@ + diff --git a/includes/js/dojox/rpc/tests/resources/jsonpJsonRpcEcho.php b/includes/js/dojox/rpc/tests/resources/jsonpJsonRpcEcho.php new file mode 100644 index 0000000..251f38e --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/jsonpJsonRpcEcho.php @@ -0,0 +1,37 @@ +decode($_REQUEST['params']); + $callback = $_REQUEST["callback"]; + + switch($method){ + case "jsonpJsonRpc10EchoNamed": + case "jsonpJsonRpc11Echo": + case "jsonpJsonRpc11EchoNamed": + case "jsonpJsonRpc10Echo": + if ( ($method=="jsonpJsonRpc10EchoNamed")||($method=="jsonpJsonRpc11EchoNamed")){ + $message = $params->message; + }else{ + $message = $params[0]; + } + if ($message){ + switch($method){ + case "jsonpJsonRpc11Echo": + case "jsonpJsonRpc11EchoNamed": + $res = "{'id': '$id', result: '$message'}"; + break; + default: + $res = "{'id': '$id', result: '$message', 'error':''}"; + break; + } + }else{ + $res = "{'id': '$id', error: {'code': 100, 'message':'no message provided'}}"; + } + } + + print "$callback($res)"; + +?> diff --git a/includes/js/dojox/rpc/tests/resources/obj1 b/includes/js/dojox/rpc/tests/resources/obj1 new file mode 100644 index 0000000..ff02ba8 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/obj1 @@ -0,0 +1 @@ +{"id":"obj1","name":"Object 1","updated":1202755814406,"obj":{"foo":"bar"},"obj dup":{"$ref":"obj1.obj"},"testArray":[1,2,3,4]} \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/obj1testArray b/includes/js/dojox/rpc/tests/resources/obj1testArray new file mode 100644 index 0000000..0c624c1 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/obj1testArray @@ -0,0 +1 @@ +[1,2,3,undefined,4] \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/obj3 b/includes/js/dojox/rpc/tests/resources/obj3 new file mode 100644 index 0000000..21cb328 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/obj3 @@ -0,0 +1 @@ +{"id":"obj3","name":"Object 3"} \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/obj4 b/includes/js/dojox/rpc/tests/resources/obj4 new file mode 100644 index 0000000..a429ecf --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/obj4 @@ -0,0 +1 @@ +{"id":"obj4","name":"Object 4"} \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/query b/includes/js/dojox/rpc/tests/resources/query new file mode 100644 index 0000000..cd18d6e --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/query @@ -0,0 +1,6 @@ +[ + {id:"obj1",name:"Object 1"}, + {id:"obj2",name:"Object 2"}, + {$ref:"obj3"}, + {$ref:"obj4"} +] \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/rawEcho.php b/includes/js/dojox/rpc/tests/resources/rawEcho.php new file mode 100644 index 0000000..e0c15c0 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/rawEcho.php @@ -0,0 +1,5 @@ + + diff --git a/includes/js/dojox/rpc/tests/resources/res b/includes/js/dojox/rpc/tests/resources/res new file mode 100644 index 0000000..3c22137 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/res @@ -0,0 +1 @@ +deleted \ No newline at end of file diff --git a/includes/js/dojox/rpc/tests/resources/store.php b/includes/js/dojox/rpc/tests/resources/store.php new file mode 100644 index 0000000..941e113 --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/store.php @@ -0,0 +1,24 @@ + diff --git a/includes/js/dojox/rpc/tests/resources/test.smd b/includes/js/dojox/rpc/tests/resources/test.smd new file mode 100644 index 0000000..6ad56be --- /dev/null +++ b/includes/js/dojox/rpc/tests/resources/test.smd @@ -0,0 +1,189 @@ +{ + transport: "POST", + envelope: "URL", + strictParameters: false, + parameters: { + appId: {}, + outputType: { + default: "json" + }, + + ignoreErrors: { + optional: true + } + }, + + services: { + postEcho: { + target: "echo.php", + parameters: [ + {name: "message", type: "string", optional: true} + ] + }, + + getEcho: { + transport: "GET", + target: "echo.php", + + parameters: [ + {name: "message", type: "string", optional: true} + ] + }, + getEchoJson: { + transport: "GET", + target: "echoJson.php", + contentType:"application/json", + parameters: [ + {name: "message", type: "string", optional: true} + ] + }, + getPathEcho: { + transport: "GET", + envelope: "PATH", + target: "echo.php?message=", + + parameters: [ + {name: "message", type: "string", optional: true} + ] + }, + restStore: { + transport: "REST", + contentType:"text/plain", + target: "fakestore.php", + parameters: [ + {name: "location", type: "string", optional: true} + ] + }, + jsonRestStore: { + transport: "REST", + target: "fakestore.php", + contentType:"application/json", + parameters: [ + {name: "location", type: "string", optional: true} + ] + }, + + + + postJsonEcho: { + transport: "POST", + envelope: "JSON", + target: "rawEcho.php", + + parameters: [ + {name: "message", type: "string", optional: true} + ] + }, + + jsonpEcho: { + transport: "JSONP", + target: "jsonpEcho.php", + callbackParamName: "testCallbackParam", + + parameters: [ + {name: "message", type: "string", optional: true} + ] + }, + + postJsonRpc10Echo: { + transport: "POST", + envelope: "JSON-RPC-1.0", + target: "jsonRpc10.php", + + parameters: [ + {type: "string", optional: true} + ] + }, + + postJsonRpc10EchoNamed: { + transport: "POST", + envelope: "JSON-RPC-1.0", + target: "jsonRpc10.php", + + parameters: [ + {type: "string", optional: true} + ] + }, + + jsonpJsonRpc12Echo: { + transport: "JSONP", + envelope: "JSON-RPC-2.0", + target: "jsonpJsonRpcEcho.php", + + parameters: [ + {type: "string", optional: true} + ] + }, + + jsonpJsonRpc12EchoNamed: { + transport: "JSONP", + envelope: "JSON-RPC-2.0", + target: "jsonpJsonRpcEcho.php", + + parameters: [ + {name: "message", type: "string", optional: true} + ] + }, + + postJsonRpc10ForcedError: { + envelope: "JSON-RPC-1.0", + transport: "POST", + target: "jsonRpc10.php", + + parameters: [ + {type: "string", optional: true} + ] + }, + + postJsonRpc12Echo: { + transport: "POST", + envelope: "JSON-RPC-2.0", + target: "jsonRpc12.php", + + parameters: [ + {name: "message", type: "string", optional: true} + ] + }, + + getJsonRpc12Echo: { + transport: "GET", + envelope: "JSON-RPC-2.0", + target: "jsonRpcPostGetEcho.php", + + parameters: [ + {type: "string", optional: true} + ] + }, + + postJsonRpc12EchoNamed: { + transport: "POST", + envelope: "JSON-RPC-2.0", + target: "jsonRpcPostGetEcho.php", + + parameters: [ + {type: "string", optional: true} + ] + }, + + getJsonRpc12EchoNamed: { + transport: "GET", + envelope: "JSON-RPC-2.0", + target: "jsonRpcPostGetEcho.php", + + parameters: [ + {type: "string", optional: true} + ] + }, + + + postJsonRpc12ForcedError: { + envelope: "JSON-RPC-2.0", + transport: "POST", + target: "jsonRpc12.php", + + parameters: [ + {type: "string", optional: true} + ] + } + } +} diff --git a/includes/js/dojox/rpc/tests/runLibraryTests.html b/includes/js/dojox/rpc/tests/runLibraryTests.html new file mode 100644 index 0000000..25c88a7 --- /dev/null +++ b/includes/js/dojox/rpc/tests/runLibraryTests.html @@ -0,0 +1,9 @@ + + + + Dojox Unit Test Runner + + + Redirecting to D.O.H runner. + + diff --git a/includes/js/dojox/rpc/tests/runTests.html b/includes/js/dojox/rpc/tests/runTests.html new file mode 100644 index 0000000..bb937c6 --- /dev/null +++ b/includes/js/dojox/rpc/tests/runTests.html @@ -0,0 +1,9 @@ + + + + Dojox Unit Test Runner + + + Redirecting to D.O.H runner. + + diff --git a/includes/js/dojox/rpc/tests/stores/JsonRestStore.js b/includes/js/dojox/rpc/tests/stores/JsonRestStore.js new file mode 100644 index 0000000..25e0fc7 --- /dev/null +++ b/includes/js/dojox/rpc/tests/stores/JsonRestStore.js @@ -0,0 +1,237 @@ +if(!dojo._hasResource["dojox.data.tests.stores.JsonRestStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.data.tests.stores.JsonRestStore"] = true; +dojo.provide("dojox.data.tests.stores.JsonRestStore"); +dojo.require("dojox.data.JsonRestStore"); +dojo.require("dojo.data.api.Read"); +dojo.require("dojox.rpc.Service"); + +dojox.data.tests.stores.JsonRestStore.error = function(t, d, errData){ + // summary: + // The error callback function to be used for all of the tests. + d.errback(errData); +} +var testServices = new dojox.rpc.Service(dojo.moduleUrl("dojox.rpc.tests.resources", "test.smd")); +var jsonStore = new dojox.data.JsonRestStore({service:testServices.jsonRestStore}); + +doh.register("dojox.data.tests.stores.JsonRestStore", + [ + { + name: "Fetch some items", + timeout: 10000, //10 seconds. + runTest: function(t) { + // summary: + // Simple test of a basic fetch on JsonRestStore of a simple query. + var d = new doh.Deferred(); + jsonStore.fetch({query:"query", + onComplete: function(items, request){ + t.is(4, items.length); + d.callback(true); + }, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, doh, d)}); + return d; //Object + } + }, + { + name: "fetch by id", + timeout: 10000, //10 seconds. + runTest: function(t) { + // summary: + // Simple test of a basic fetch on JsonRestStore of a single item. + var d = new doh.Deferred(); + jsonStore.fetch({query:"obj1", + onComplete: function(item, request){ + t.is("Object 1", item.name); + t.t(jsonStore.hasAttribute(item,"name")); + t.is(jsonStore.getValues(item,"name").length,1); + t.t(jsonStore.isItem(item)); + d.callback(true); + }, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, doh, d)}); + return d; //Object + } + }, + { + name: "Modify,save, check by id", + timeout: 10000, //10 seconds. + runTest: function(t) { + // summary: + // Fetch an item from a query, modify and save it, and check to see if it was modified correctly + var d = new doh.Deferred(); + jsonStore.fetch({query:"query", + onComplete: function(items, request){ + var now = new Date().getTime(); + jsonStore.setValue(items[0],"updated",now); + jsonStore.setValue(items[0],"obj",{foo:'bar'}); + jsonStore.setValue(items[0],"obj dup",items[0].obj); + jsonStore.setValue(items[0],"testArray",[1,2,3,4]); + jsonStore.save(); + jsonStore.fetch({query:"obj1", + onComplete: function(item, request){ + t.is("Object 1", item.name); + t.is(now, item.updated); + t.is("bar", item.obj.foo); + t.is(item.obj, item['obj dup']); + d.callback(true); + }, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, doh, d)}); + }, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, doh, d)}); + return d; //Object + } + }, + { + name: "Post, delete, and put", + timeout: 10000, //10 seconds. + runTest: function(t) { + // summary: + // append/post an item, delete it, sort the lists, resort the list, saving each time. + var d = new doh.Deferred(); + jsonStore.fetch({query:"obj1", + onComplete: function(item, request){ + var now = new Date().getTime(); + var testArray = item.testArray; + var newObject = {"name":"new object"}; + testArray.push(newObject); + jsonStore.save(); + jsonStore.deleteItem(newObject,{parent:testArray}); + jsonStore.save(); + testArray.sort(function(obj1,obj2) { return obj1 < obj2; }); + jsonStore.save(); + testArray.sort(function(obj1,obj2) { return obj1 > obj2; }); + jsonStore.save(); + d.callback(true); + }, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, doh, d)}); + return d; //Object + } + }, + { + name: "Revert", + timeout: 10000, //10 seconds. + runTest: function(t) { + // summary: + // append/post an item, delete it, sort the lists, resort the list, saving each time. + var d = new doh.Deferred(); + jsonStore.fetch({query:"obj1", + onComplete: function(item, request){ + jsonStore.setValue(item,"name","new name"); + jsonStore.setValue(item,"newProp","new value"); + jsonStore.unsetAttribute(item,"updated"); + t.is(jsonStore.getValue(item,"name"),"new name"); + t.is(jsonStore.getValue(item,"newProp"),"new value"); + t.is(jsonStore.getValue(item,"updated"),undefined); + jsonStore.revert(); + t.is(jsonStore.getValue(item,"name"),"Object 1"); + t.is(jsonStore.getValue(item,"newProp"),undefined); + t.t(typeof jsonStore.getValue(item,"updated") == 'number'); + d.callback(true); + }, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, doh, d)}); + return d; //Object + } + }, + { + name: "Lazy loading", + timeout: 10000, //10 seconds. + runTest: function(t) { + // summary: + // test lazy loading + var d = new doh.Deferred(); + jsonStore.fetch({query:"query", + onComplete: function(items, request){ + /*var item = jsonStore.getValue(items,2); // sync lazy loading + t.is(item.name == 'Object 3');*/ + jsonStore.getValue(items,3,function(item) { // async lazy loading + t.is(item.name,'Object 4'); + d.callback(true); + }); + }, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, doh, d)}); + return d; //Object + } + }, + { + name: "Array manipulation", + timeout: 10000, //10 seconds. + runTest: function(t) { + // summary: + // test array manipulation + var d = new doh.Deferred(); + jsonStore.fetch({query:"obj1", + onComplete: function(item, request){ + var testArray = item.testArray; + testArray.reverse(); + testArray.unshift(testArray.pop()); + jsonStore.onSave = function(data) { + t.is(data.length,1); + d.callback(true); + jsonStore.onSave = function(){}; + }; + jsonStore.save(); + }, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, doh, d)}); + return d; //Object + } + }, + + { + name: "ReadAPI: Fetch_20_Streaming", + timeout: 10000, //10 seconds. Json can sometimes be slow. + runTest: function(t) { + // summary: + // fetching with paging + + var d = new doh.Deferred(); + var count = 0; + + function onItem(item, requestObj){ + t.assertTrue(typeof item == 'number'); + count++; + } + function onComplete(items, request){ + t.is(5, count); + + t.is(null, items); + d.callback(true); + } + //Get everything... + jsonStore.fetch({ + query: "bigQuery", + onBegin: null, + count: 5, + onItem: onItem, + onComplete: onComplete, + onError: dojo.partial(dojox.data.tests.stores.JsonRestStore.error, t, d) + }); + return d; //Object + } + }, + function testReadAPI_functionConformance(t){ + // summary: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + // description: + // Simple test read API conformance. Checks to see all declared functions are actual functions on the instances. + + var readApi = new dojo.data.api.Read(); + var passed = true; + + for(i in readApi){ + if(i.toString().charAt(0) !== '_') + { + var member = readApi[i]; + //Check that all the 'Read' defined functions exist on the test store. + if(typeof member === "function"){ + var testStoreMember = jsonStore [i]; + if(!(typeof testStoreMember === "function")){ + passed = false; + break; + } + } + } + } + } + ] +); + + +} diff --git a/includes/js/dojox/rpc/tests/test_dojo_data_model_persevere.html b/includes/js/dojox/rpc/tests/test_dojo_data_model_persevere.html new file mode 100644 index 0000000..063dc9b --- /dev/null +++ b/includes/js/dojox/rpc/tests/test_dojo_data_model_persevere.html @@ -0,0 +1,146 @@ + + + + dojox.Grid with Dojo.Data via binding + + + + + + + +
dojox.Grid using interactive PersevereRestStore
+
+ + +     + +     + + + +
+ +
+
+ + -- cgit v1.2.3