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/wire/ml/Action.js | 225 ++++++++++++++++++++ includes/js/dojox/wire/ml/Data.js | 143 +++++++++++++ includes/js/dojox/wire/ml/DataStore.js | 116 +++++++++++ includes/js/dojox/wire/ml/Invocation.js | 171 +++++++++++++++ includes/js/dojox/wire/ml/Service.js | 340 ++++++++++++++++++++++++++++++ includes/js/dojox/wire/ml/Transfer.js | 359 ++++++++++++++++++++++++++++++++ includes/js/dojox/wire/ml/util.js | 295 ++++++++++++++++++++++++++ 7 files changed, 1649 insertions(+) create mode 100644 includes/js/dojox/wire/ml/Action.js create mode 100644 includes/js/dojox/wire/ml/Data.js create mode 100644 includes/js/dojox/wire/ml/DataStore.js create mode 100644 includes/js/dojox/wire/ml/Invocation.js create mode 100644 includes/js/dojox/wire/ml/Service.js create mode 100644 includes/js/dojox/wire/ml/Transfer.js create mode 100644 includes/js/dojox/wire/ml/util.js (limited to 'includes/js/dojox/wire/ml') diff --git a/includes/js/dojox/wire/ml/Action.js b/includes/js/dojox/wire/ml/Action.js new file mode 100644 index 0000000..637de41 --- /dev/null +++ b/includes/js/dojox/wire/ml/Action.js @@ -0,0 +1,225 @@ +if(!dojo._hasResource["dojox.wire.ml.Action"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.ml.Action"] = true; +dojo.provide("dojox.wire.ml.Action"); +dojo.provide("dojox.wire.ml.ActionFilter"); + +dojo.require("dijit._Widget"); +dojo.require("dijit._Container"); +dojo.require("dojox.wire.Wire"); +dojo.require("dojox.wire.ml.util"); + +dojo.declare("dojox.wire.ml.Action", [dijit._Widget, dijit._Container], { + // summary: + // A base widget to "run" a task on an event or a topic + // description: + // This widget represents a controller task to be run when an event + // (a function) or a topic is issued. + // Sub-classes must implement _run() method to implement their tasks. + // 'trigger' specifies an event scope, an ID of a widget or an DOM + // element, or its property with the optional dotted notation. + // If this widget has child ActionFilter widgets, their filter() + // methods are called with the arguments to the event or the topic. + // If one of filter() methods returns false, run() won't be invoked. + // This widget also can serve as a composite task to run child + // Actions on an event or a topic specified to this widget. + // trigger: + // An event scope + // triggerEvent: + // An event (function) name + // triggerTopic: + // A topic name + trigger: "", + triggerEvent: "", + triggerTopic: "", + + postCreate: function(){ + // summary: + // Call _connect() + // description: + // See _connect(). + this._connect(); + }, + + _connect: function(){ + // summary: + // Connect run() method to an event or a topic + // description: + // If 'triggerEvent' and 'trigger' are specified, connect() is + // used to set up run() to be called on the event. + // If 'triggerTopic' is specified, subscribe() is used to set up + // run() to be called on the topic. + if(this.triggerEvent){ + if(this.trigger){ + var scope = dojox.wire.ml._getValue(this.trigger); + if(scope){ + if(!scope[this.triggerEvent]){ + // set a dummy function for an anonymous object + scope[this.triggerEvent] = function(){}; + } + this._triggerHandle = dojo.connect(scope, this.triggerEvent, this, "run"); + } + }else{ + var event = this.triggerEvent.toLowerCase(); + if(event == "onload"){ + var self = this; + dojo.addOnLoad(function(){ + self._run.apply(self, arguments); + }); + } + } + }else if(this.triggerTopic){ + this._triggerHandle = dojo.subscribe(this.triggerTopic, this, "run"); + } + }, + + _disconnect: function(){ + // summary: + // Disconnect run() method from an event or a topic + // description: + // If 'triggerEvent' and 'trigger' are specified, disconnect() is + // used to set up run() not to be called on the event. + // If 'triggerTopic' is specified, unsubscribe() is used to set up + // run() not to be called on the topic. + if(this._triggerHandle){ + if(this.triggerTopic){ + dojo.unsubscribe(this.triggerTopic, this._triggerHandle); + }else{ + dojo.disconnect(this._triggerHandle); + } + } + }, + + run: function(){ + // summary: + // Run a task + // description: + // This method calls filter() method of child ActionFilter + // widgets. + // If one of them returns false, this method returns. + // Otherwise, _run() method is called. + var children = this.getChildren(); + for(var i in children){ + var child = children[i]; + if(child instanceof dojox.wire.ml.ActionFilter){ + if(!child.filter.apply(child, arguments)){ + return; + } + } + } + this._run.apply(this, arguments); + }, + + _run: function(){ + // summary: + // Call run() methods of child Action widgets + // description: + // If this widget has child Action widgets, their run() methods + // are called. + var children = this.getChildren(); + for(var i in children){ + var child = children[i]; + if(child instanceof dojox.wire.ml.Action){ + child.run.apply(child, arguments); + } + } + }, + + uninitialize: function(){ + // summary: + // Over-ride of base widget unitialize function to do some connection cleanup. + this._disconnect(); + return true; + } +}); + +dojo.declare("dojox.wire.ml.ActionFilter", dijit._Widget, { + // summary: + // A widget to define a filter for the parent Action to run + // description: + // This base class checks a required property specified with + // 'required' attribute. + // If 'message' is specified, the message is set to a property + // specified with 'error'. + // Subclasses may implement their own filter() method. + // required: + // A property required + // requiredValue: + // Optional. A specific value the property is required to have. If this isn't provided + // than any non-false/non-null value of the required propery will cause this filter + // to pass. + // type: + // Optional. A specific type to compare the values as (if requiredValue is set) + // Valid values for type are boolean, int, string. Default is string. + // message: + // An error message to emit if the filter doesn't execute due to property mismatch. + // error: + // A property to store an error due to property mismatch. + required: "", + requiredValue: "", + type: "", + message: "", + error: "", + + + filter: function(){ + // summary: + // Check if a required property is specified. Also, if provided, check to see + // if the required property contains a specific value. + // description: + // If a value is undefined for a property, specified with + // 'required', this method returns false. + // If the value for a property is defined, but there isn't a requiredValue for it + // then any non-false value will cause the method to return true. + // if requiredValue is set, then filter compares that value with the value from + // the required property and returns true if and only if they match. + // The type option just allows for a way to convert the required property values + // into a proper form for comparison (boolean, number, etc). + // If 'message' is specified, it is set to a proeprty specified + // with 'error' or shown with alert(). + // If 'required' starts with "arguments", a property of + // the method arguments are checked. + // returns: + // True if a required property is specified (and if requiredValue is specified, + // that they match), otherwise false + if(this.required === ""){ + return true; //Boolean + }else{ + var value = dojox.wire.ml._getValue(this.required, arguments); + if(this.requiredValue === ""){ + //Just see if there's a value, nothing to compare it to. + if(value){ + return true; //Boolean + } + }else{ + //See if we need to type convert. + var reqValue = this.requiredValue; + if(this.type !== ""){ + var lType = this.type.toLowerCase(); + if(lType === "boolean"){ + if(reqValue.toLowerCase() === "false"){ + reqValue = false; + }else{ + reqValue = true; + } + }else if(lType === "number"){ + reqValue = parseInt(reqValue, 10); + } + } + if(value === reqValue){ + return true; //boolean + } + } + } + + if(this.message){ + if(this.error){ + dojox.wire.ml._setValue(this.error, this.message); + }else{ + alert(this.message); + } + } + return false; //Boolean + } +}); + +} diff --git a/includes/js/dojox/wire/ml/Data.js b/includes/js/dojox/wire/ml/Data.js new file mode 100644 index 0000000..71ab0ad --- /dev/null +++ b/includes/js/dojox/wire/ml/Data.js @@ -0,0 +1,143 @@ +if(!dojo._hasResource["dojox.wire.ml.Data"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.ml.Data"] = true; +dojo.provide("dojox.wire.ml.Data"); +dojo.provide("dojox.wire.ml.DataProperty"); + +dojo.require("dijit._Widget"); +dojo.require("dijit._Container"); +dojo.require("dojox.wire.ml.util"); + +dojo.declare("dojox.wire.ml.Data", [dijit._Widget, dijit._Container], { + // summary: + // A widget for a data object + // description: + // This widget represents an object with '_properties' property. + // If child 'DataProperty' widgets exist, they are used to initialize + // propertiy values of '_properties' object. + + startup: function(){ + // summary: + // Call _initializeProperties() + // description: + // See _initializeProperties(). + this._initializeProperties(); + }, + + _initializeProperties: function(/*Boolean*/reset){ + // summary: + // Initialize a data object + // description: + // If this widget has child DataProperty widgets, their getValue() + // methods are called and set the return value to a property + // specified by 'name' attribute of the child widgets. + // reset: + // A boolean to reset current properties + if(!this._properties || reset){ + this._properties = {}; + } + var children = this.getChildren(); + for(var i in children){ + var child = children[i]; + if((child instanceof dojox.wire.ml.DataProperty) && child.name){ + this.setPropertyValue(child.name, child.getValue()); + } + } + }, + + getPropertyValue: function(/*String*/property){ + // summary: + // Return a property value + // description: + // This method returns the value of a property, specified with + // 'property' argument, in '_properties' object. + // property: + // A property name + // returns: + // A property value + return this._properties[property]; //anything + }, + + setPropertyValue: function(/*String*/property, /*anything*/value){ + // summary: + // Store a property value + // description: + // This method stores 'value' as a property, specified with + // 'property' argument, in '_properties' object. + // property: + // A property name + // value: + // A property value + this._properties[property] = value; + } +}); + +dojo.declare("dojox.wire.ml.DataProperty", [dijit._Widget, dijit._Container], { + // summary: + // A widget to define a data property + // description: + // Attributes of this widget are used to add a property to the parent + // Data widget. + // 'type' attribute specifies one of "string", "number", "boolean", + // "array", "object" and "element" (DOM Element) + // (default to "string"). + // If 'type' is "array" or "object", child DataProperty widgets are + // used to initialize the array elements or the object properties. + // name: + // A property name + // type: + // A property type name + // value: + // A property value + name: "", + type: "", + value: "", + + getValue: function(){ + // summary: + // Returns a property value + // description: + // If 'type' is specified, 'value' attribute is converted to + // the specified type and returned. + // Otherwise, 'value' attribute is returned as is. + // returns: + // A property value + var value = this.value; + if(this.type){ + if(this.type == "number"){ + value = parseInt(value); + }else if(this.type == "boolean"){ + value = (value == "true"); + }else if(this.type == "array"){ + value = []; + var children = this.getChildren(); + for(var i in children){ + var child = children[i]; + if(child instanceof dojox.wire.ml.DataProperty){ + value.push(child.getValue()); + } + } + }else if(this.type == "object"){ + value = {}; + var children = this.getChildren(); + for(var i in children){ + var child = children[i]; + if((child instanceof dojox.wire.ml.DataProperty) && child.name){ + value[child.name] = child.getValue(); + } + } + }else if(this.type == "element"){ + value = new dojox.wire.ml.XmlElement(value); + var children = this.getChildren(); + for(var i in children){ + var child = children[i]; + if((child instanceof dojox.wire.ml.DataProperty) && child.name){ + value.setPropertyValue(child.name, child.getValue()); + } + } + } + } + return value; //anything + } +}); + +} diff --git a/includes/js/dojox/wire/ml/DataStore.js b/includes/js/dojox/wire/ml/DataStore.js new file mode 100644 index 0000000..e366d05 --- /dev/null +++ b/includes/js/dojox/wire/ml/DataStore.js @@ -0,0 +1,116 @@ +if(!dojo._hasResource["dojox.wire.ml.DataStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.ml.DataStore"] = true; +dojo.provide("dojox.wire.ml.DataStore"); + +dojo.require("dijit._Widget"); +dojo.require("dojox.wire._base"); + +dojo.declare("dojox.wire.ml.DataStore", dijit._Widget, { + // summary: + // A widget for a data store + // description: + // This widget represents a data store of 'storeClass' attribute. + // storeClass: + // A class name of a data store + storeClass: "", + + postCreate: function(){ + // summary: + // Call _createStore() + // description: + // See _createStore(). + this.store = this._createStore(); + }, + + _createStore: function(){ + // summary: + // Create a data store + // desription: + // A data store of 'storeClass' is created with arguments + // specified with attributes. + // returns: + // A data store + if(!this.storeClass){ + return null; //null + } + var storeClass = dojox.wire._getClass(this.storeClass); + if(!storeClass){ + return null; //null + } + var args = {}; + var attributes = this.domNode.attributes; + for(var i = 0; i < attributes.length; i++){ + var a = attributes.item(i); + if(a.specified && !this[a.nodeName]){ + args[a.nodeName] = a.nodeValue; + } + } + return new storeClass(args); //Object + }, + + getFeatures: function(){ + // summary: + // Call getFeatures() method of a data store + // description: + // See dojo.data.api.Read.getFeatures(). + // returns: + // A features object + return this.store.getFeatures(); //Object + }, + + fetch: function(/*Object*/request){ + // summary: + // Call fetch() method of a data store + // description: + // See dojo.data.api.Read.fetch(). + // request: + // A request object + // returns: + // A request object + return this.store.fetch(request); //Object + }, + + save: function(/*Object*/args){ + // summary: + // Call save() method of a data store + // description: + // See dojo.data.api.Write.save(). + // args: + // A save arguments object + this.store.save(args); + }, + + newItem: function(/*Object*/args){ + // summary: + // Call newItem() method of a data store + // description: + // See dojo.data.api.Write.newItem(). + // args: + // A new item arguments object + // returns: + // A new item + return this.store.newItem(args); //Object + }, + + deleteItem: function(/*Object*/item){ + // summary: + // Call deleteItem() method of a data store + // description: + // See dojo.data.api.Write.deleteItem(). + // returns: + // A boolean + return this.store.deleteItem(item); //Boolean + }, + + revert: function(){ + // summary: + // Call revert() method of a data store + // description: + // See dojo.data.api.Write.revert(). + // returns: + // A boolean + return this.store.revert(); //Boolean + } +}); + +} diff --git a/includes/js/dojox/wire/ml/Invocation.js b/includes/js/dojox/wire/ml/Invocation.js new file mode 100644 index 0000000..3d36623 --- /dev/null +++ b/includes/js/dojox/wire/ml/Invocation.js @@ -0,0 +1,171 @@ +if(!dojo._hasResource["dojox.wire.ml.Invocation"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.ml.Invocation"] = true; +dojo.provide("dojox.wire.ml.Invocation"); + +dojo.require("dojox.wire.ml.Action"); + +dojo.declare("dojox.wire.ml.Invocation", dojox.wire.ml.Action, { + // summary: + // A widget to invoke a method or publish a topic + // description: + // This widget represents a controller task to invoke a method or + // publish a topic when an event (a function) or a topic is issued. + // object: + // A scope of a method to invoke + // method: + // A name of a method to invoke + // topic: + // A name of a topic to publish + // parameters: + // Arguments for the method or the topic + // result: + // A property to store a return value of the method call + // error: + // A property to store an error on the method call + object: "", + method: "", + topic: "", + parameters: "", + result: "", + error: "", + + _run: function(){ + // summary: + // Invoke a method or publish a topic + // description: + // If 'topic' is specified, the topic is published with arguments + // specified to 'parameters'. + // If 'method' and 'object' are specified, the method is invoked + // with arguments specified to 'parameters' and set the return + // value to a property specified to 'result'. + // 'object', 'parameters' and 'result' can specify properties of + // a widget or an DOM element with the dotted notation. + // If 'parameters' are omitted, the arguments to this method are + // passed as is. + if(this.topic){ + var args = this._getParameters(arguments); + try{ + dojo.publish(this.topic, args); + this.onComplete(); + }catch(e){ + this.onError(e); + } + }else if(this.method){ + var scope = (this.object ? dojox.wire.ml._getValue(this.object) : dojo.global); + if(!scope){ + return; //undefined + } + var args = this._getParameters(arguments); + var func = scope[this.method]; + if(!func){ + func = scope.callMethod; + if(!func){ + return; //undefined + } + args = [this.method, args]; + } + try{ + var connected = false; + if(scope.getFeatures){ + var features = scope.getFeatures(); + if((this.method == "fetch" && features["dojo.data.api.Read"]) || + (this.method == "save" && features["dojo.data.api.Write"])){ + var arg = args[0]; + if(!arg.onComplete){ + arg.onComplete = function(){}; + } + //dojo.connect(arg, "onComplete", this, "onComplete"); + this.connect(arg, "onComplete", "onComplete"); + if(!arg.onError){ + arg.onError = function(){}; + } + //dojo.connect(arg, "onError", this, "onError"); + this.connect(arg, "onError", "onError"); + connected = true; + } + } + var r = func.apply(scope, args); + if(!connected){ + if(r && (r instanceof dojo.Deferred)){ + var self = this; + r.addCallbacks( + function(result){self.onComplete(result);}, + function(error){self.onError(error);} + ); + }else{ + this.onComplete(r); + } + } + }catch(e){ + this.onError(e); + } + } + }, + + onComplete: function(/*anything*/result){ + // summary: + // A function called when the method or the topic publish + // completed + // description: + // If 'result' attribute is specified, the result object also set + // to the specified property. + // result: + // The return value of a method or undefined for a topic + if(this.result){ + dojox.wire.ml._setValue(this.result, result); + } + if(this.error){ // clear error + dojox.wire.ml._setValue(this.error, ""); + } + }, + + onError: function(/*anything*/error){ + // summary: + // A function called on an error occurs + // description: + // If 'error' attribute is specified, the error object also set to + // the specified property. + // error: + // The exception or error occurred + if(this.error){ + if(error && error.message){ + error = error.message; + } + dojox.wire.ml._setValue(this.error, error); + } + }, + + _getParameters: function(/*Array*/args){ + // summary: + // Returns arguments to a method or topic to invoke + // description: + // This method retunrs an array of arguments specified by + // 'parameters' attribute, a comma-separated list of IDs and + // their properties in a dotted notation. + // If 'parameters' are omitted, the original arguments are + // used. + // args: + // Arguments to a trigger event or topic + if(!this.parameters){ + // use arguments as is + return args; //Array + } + var parameters = []; + var list = this.parameters.split(","); + if(list.length == 1){ + var parameter = dojox.wire.ml._getValue(dojo.trim(list[0]), args); + if(dojo.isArray(parameter)){ + parameters = parameter; + }else{ + parameters.push(parameter); + } + }else{ + for(var i in list){ + parameters.push(dojox.wire.ml._getValue(dojo.trim(list[i]), args)); + } + } + return parameters; //Array + } +}); + +} diff --git a/includes/js/dojox/wire/ml/Service.js b/includes/js/dojox/wire/ml/Service.js new file mode 100644 index 0000000..15f074b --- /dev/null +++ b/includes/js/dojox/wire/ml/Service.js @@ -0,0 +1,340 @@ +if(!dojo._hasResource["dojox.wire.ml.Service"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.ml.Service"] = true; +dojo.provide("dojox.wire.ml.Service"); +dojo.provide("dojox.wire.ml.RestHandler"); +dojo.provide("dojox.wire.ml.XmlHandler"); +dojo.provide("dojox.wire.ml.JsonHandler"); + +dojo.require("dijit._Widget"); +dojo.require("dojox.data.dom"); +dojo.require("dojox.wire._base"); +dojo.require("dojox.wire.ml.util"); + +dojo.declare("dojox.wire.ml.Service", dijit._Widget, { + // summary: + // A widget for a service + // description: + // This widget represents a service defined by a service description + // specified with 'url' attribute. + // If 'serviceType' and 'serviceUrl' attributes are specified, 'url' + // attribute can be omitted. + // url: + // A URL to a service description + // serviceUrl: + // A URL to a service + // serviceType: + // A service type + // handlerClass: + // A service handler class name + url: "", + serviceUrl: "", + serviceType: "", + handlerClass: "", + preventCache: true, + + postCreate: function(){ + // summary: + // Call _createHandler() + // description: + // See _createHandler(). + this.handler = this._createHandler(); + }, + + _handlerClasses: { + "TEXT": "dojox.wire.ml.RestHandler", + "XML": "dojox.wire.ml.XmlHandler", + "JSON": "dojox.wire.ml.JsonHandler", + "JSON-RPC": "dojo.rpc.JsonService" + }, + + _createHandler: function(){ + // summary: + // Create a service handler + // desription: + // A service handler class is determined by: + // 1. 'handlerClass' attribute + // 2. 'serviceType' attribute + // 3. 'serviceType' property in a service description + // returns: + // A service handler + if(this.url){ + var self = this; + var d = dojo.xhrGet({ + url: this.url, + handleAs: "json", + sync: true + }); + d.addCallback(function(result){ + self.smd = result; + }); + if(this.smd && !this.serviceUrl){ + this.serviceUrl = (this.smd.serviceUrl || this.smd.serviceURL); + } + } + var handlerClass = undefined; + if(this.handlerClass){ + handlerClass = dojox.wire._getClass(this.handlerClass); + }else if(this.serviceType){ + handlerClass = this._handlerClasses[this.serviceType]; + if(handlerClass && dojo.isString(handlerClass)){ + handlerClass = dojox.wire._getClass(handlerClass); + this._handlerClasses[this.serviceType] = handlerClass; + } + }else if(this.smd && this.smd.serviceType){ + handlerClass = this._handlerClasses[this.smd.serviceType]; + if(handlerClass && dojo.isString(handlerClass)){ + handlerClass = dojox.wire._getClass(handlerClass); + this._handlerClasses[this.smd.serviceType] = handlerClass; + } + } + if(!handlerClass){ + return null; //null + } + return new handlerClass(); //Object + }, + + callMethod: function(method, parameters){ + // summary: + // Call a service method with parameters + // method: + // A method name + // parameters: + // An array parameters + var deferred = new dojo.Deferred(); + this.handler.bind(method, parameters, deferred, this.serviceUrl); + return deferred; + } +}); + +dojo.declare("dojox.wire.ml.RestHandler", null, { + // summary: + // A REST service handler + // description: + // This class serves as a base REST service. + // Sub-classes may override _getContent() and _getResult() to handle + // specific content types. + contentType: "text/plain", + handleAs: "text", + + bind: function(method, parameters, deferred, url){ + // summary: + // Call a service method with parameters. + // description: + // A service is called with a URL generated by _getUrl() and + // an HTTP method specified with 'method'. + // For "POST" and "PUT", a content is generated by _getContent(). + // When data is loaded, _getResult() is used to pass the result to + // Deferred.callback(). + // method: + // A method name + // parameters: + // An array of parameters + // deferred: + // 'Deferred' + // url: + // A URL for the method + method = method.toUpperCase(); + var self = this; + var args = { + url: this._getUrl(method, parameters, url), + contentType: this.contentType, + handleAs: this.handleAs, + headers: this.headers, + preventCache: this.preventCache + }; + var d = null; + if(method == "POST"){ + args.postData = this._getContent(method, parameters); + d = dojo.rawXhrPost(args); + }else if(method == "PUT"){ + args.putData = this._getContent(method, parameters); + d = dojo.rawXhrPut(args); + }else if(method == "DELETE"){ + d = dojo.xhrDelete(args); + }else{ // "GET" + d = dojo.xhrGet(args); + } + d.addCallbacks(function(result){ + deferred.callback(self._getResult(result)); + }, function(error){ + deferred.errback(error); + }); + }, + + _getUrl: function(/*String*/method, /*Array*/parameters, /*String*/url){ + // summary: + // Generate a URL + // description: + // If 'method' is "GET" or "DELETE", a query string is generated + // from a query object specified to the first parameter in + // 'parameters' and appended to 'url'. + // If 'url' contains variable seguments ("{parameter_name}"), + // they are replaced with corresponding parameter values, instead. + // method: + // A method name + // parameters: + // An array of parameters + // url: + // A base URL + // returns: + // A URL + var query; + if(method == "GET" || method == "DELETE"){ + if(parameters.length > 0){ + query = parameters[0]; + } + }else{ // "POST" || "PUT" + if(parameters.length > 1){ + query = parameters[1]; + } + } + if(query){ + var queryString = ""; + for(var name in query){ + var value = query[name]; + if(value){ + value = encodeURIComponent(value); + var variable = "{" + name + "}"; + var index = url.indexOf(variable); + if(index >= 0){ // encode in path + url = url.substring(0, index) + value + url.substring(index + variable.length); + }else{ // encode as query string + if(queryString){ + queryString += "&"; + } + queryString += (name + "=" + value); + } + } + } + if(queryString){ + url += "?" + queryString; + } + } + return url; //String + }, + + _getContent: function(/*String*/method, /*Array*/parameters){ + // summary: + // Generate a request content + // description: + // If 'method' is "POST" or "PUT", the first parameter in + // 'parameters' is returned. + // method: + // A method name + // parameters: + // An array of parameters + // returns: + // A request content + if(method == "POST" || method == "PUT"){ + return (parameters ? parameters[0] : null); //anything + }else{ + return null; //null + } + }, + + _getResult: function(/*anything*/data){ + // summary: + // Extract a result + // description: + // A response data is returned as is. + // data: + // A response data returned by a service + // returns: + // A result object + return data; //anything + } +}); + +dojo.declare("dojox.wire.ml.XmlHandler", dojox.wire.ml.RestHandler, { + // summary: + // A REST service handler for XML + // description: + // This class provides XML handling for a REST service. + contentType: "text/xml", + handleAs: "xml", + + _getContent: function(/*String*/method, /*Array*/parameters){ + // description: + // If 'method' is "POST" or "PUT", the first parameter in + // 'parameters' is used to generate an XML content. + // method: + // A method name + // parameters: + // An array of parameters + // returns: + // A request content + var content = null; + if(method == "POST" || method == "PUT"){ + var p = parameters[0]; + if(p){ + if(dojo.isString(p)){ + content = p; + }else{ + var element = p; + if(element instanceof dojox.wire.ml.XmlElement){ + element = element.element; + }else if(element.nodeType === 9 /* DOCUMENT_NODE */){ + element = element.documentElement; + } + var declaration = ""; // TODO: encoding? + content = declaration + dojox.data.dom.innerXML(element); + } + } + } + return content; + }, + + _getResult: function(/*Document*/data){ + // summary: + // Extract a result + // description: + // A response data (XML Document) is returned wrapped with + // XmlElement. + // data: + // A response data returned by a service + // returns: + // A result object + if(data){ + data = new dojox.wire.ml.XmlElement(data); + } + return data; + } +}); + +dojo.declare("dojox.wire.ml.JsonHandler", dojox.wire.ml.RestHandler, { + // summary: + // A REST service handler for JSON + // description: + // This class provides JSON handling for a REST service. + contentType: "text/json", + handleAs: "json", + headers: {"Accept": "*/json"}, + + _getContent: function(/*String*/method, /*Array*/parameters){ + // summary: + // Generate a request content + // description: + // If 'method' is "POST" or "PUT", the first parameter in + // 'parameter' is used to generate a JSON content. + // method: + // A method name + // parameters: + // An array of parameters + // returns: + // A request content + var content = null; + if(method == "POST" || method == "PUT"){ + var p = (parameters ? parameters[0] : undefined); + if(p){ + if(dojo.isString(p)){ + content = p; + }else{ + content = dojo.toJson(p); + } + } + } + return content; //String + } +}); + +} diff --git a/includes/js/dojox/wire/ml/Transfer.js b/includes/js/dojox/wire/ml/Transfer.js new file mode 100644 index 0000000..c7780ca --- /dev/null +++ b/includes/js/dojox/wire/ml/Transfer.js @@ -0,0 +1,359 @@ +if(!dojo._hasResource["dojox.wire.ml.Transfer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.ml.Transfer"] = true; +dojo.provide("dojox.wire.ml.Transfer"); +dojo.provide("dojox.wire.ml.ChildWire"); +dojo.provide("dojox.wire.ml.ColumnWire"); +dojo.provide("dojox.wire.ml.NodeWire"); +dojo.provide("dojox.wire.ml.SegmentWire"); + +dojo.require("dijit._Widget"); +dojo.require("dijit._Container"); +dojo.require("dojox.wire._base"); +dojo.require("dojox.wire.ml.Action"); + +dojo.declare("dojox.wire.ml.Transfer", dojox.wire.ml.Action, { + // summary: + // A widget to transfer values through source and target Wires + // description: + // This widget represents a controller task to transfer a value from + // a source to a target, through a source and a target Wires, when + // an event (a function) or a topic is issued. + // If this widget has child ChildWire widgets, their _addWire() + // methods are called to add Wire arguments to a source or a target + // Wire. + // source: + // A source object and/or property + // sourceStore: + // A data store for a source data item + // sourceAttribute: + // An attribute of a source data item + // sourcePath: + // A simplified XPath to a source property of an XML element + // type: + // A type of the value to be transferred + // converter: + // A class name of a converter for the value to be transferred + // target: + // A target object and/or property + // targetStore: + // A data store for a target data item + // targetAttribute: + // An attribute of a target data item + // targetPath: + // A simplified XPath to a target property of an XML element + source: "", + sourceStore: "", + sourceAttribute: "", + sourcePath: "", + type: "", + converter: "", + delimiter: "", + target: "", + targetStore: "", + targetAttribute: "", + targetPath: "", + + _run: function(){ + // summary: + // Transfer a value from a source to a target + // description: + // First, Wires for a source and a target are created from attributes. + // Then, a value is obtained by getValue() of the source Wire is set + // by setValue() of the target Wire. + // The arguments to this method is passed to getValue() and setValue() + // of Wires, so that they can be used to identify the root objects off + // the arguments. + var sourceWire = this._getWire("source"); + var targetWire = this._getWire("target"); + dojox.wire.transfer(sourceWire, targetWire, arguments); + }, + + _getWire: function(/*String*/which){ + // summary: + // Build Wire arguments from attributes + // description: + // Arguments object for a source or a target Wire, specified by + // 'which' argument, are build from corresponding attributes, + // including '*Store' (for 'dataStore'), '*Attribute' + // (for 'attribute), '*Path' (for 'path'), 'type' and 'converter'. + // 'source' or 'target' attribute is parsed as: + // "object_id.property_name[.sub_property_name...]" + // If 'source' or 'target' starts with "arguments", 'object' + // argument for a Wire is set to null, so that the root object is + // given as an event or topic arguments. + // If this widget has child ChildWire widgets with a corresponding + // 'which' attribute, their _addWire() methods are called to add + // additional Wire arguments and nested Wire is created, + // specifying the Wire defined by this widget to 'object' argument. + // which: + // Which Wire arguments to build, "source" or "target" + // returns: + // Wire arguments object + var args = undefined; + if(which == "source"){ + args = { + object: this.source, + dataStore: this.sourceStore, + attribute: this.sourceAttribute, + path: this.sourcePath, + type: this.type, + converter: this.converter + }; + }else{ // "target" + args = { + object: this.target, + dataStore: this.targetStore, + attribute: this.targetAttribute, + path: this.targetPath + }; + } + if(args.object){ + if(args.object.length >= 9 && args.object.substring(0, 9) == "arguments"){ + args.property = args.object.substring(9); + args.object = null; + }else{ + var i = args.object.indexOf('.'); + if(i < 0){ + args.object = dojox.wire.ml._getValue(args.object); + }else{ + args.property = args.object.substring(i + 1); + args.object = dojox.wire.ml._getValue(args.object.substring(0, i)); + } + } + } + if(args.dataStore){ + args.dataStore = dojox.wire.ml._getValue(args.dataStore); + } + var childArgs = undefined; + var children = this.getChildren(); + for(var i in children){ + var child = children[i]; + if(child instanceof dojox.wire.ml.ChildWire && child.which == which){ + if(!childArgs){ + childArgs = {}; + } + child._addWire(this, childArgs); + } + } + if(childArgs){ // make nested Wires + childArgs.object = dojox.wire.create(args); + childArgs.dataStore = args.dataStore; + args = childArgs; + } + return args; //Object + } +}); + +dojo.declare("dojox.wire.ml.ChildWire", dijit._Widget, { + // summary: + // A widget to add a child wire + // description: + // Attributes of this widget are used to add a child Wire to + // a composite Wire of the parent Transfer widget. + // which: + // Which Wire to add a child Wire, "source" or "target", default to + // "source" + // object: + // A root object for the value + // property: + // A property for the value + // type: + // A type of the value + // converter: + // A class name of a converter for the value + // attribute: + // A data item attribute for the value + // path: + // A simplified XPath for the value + // name: + // A composite property name + which: "source", + object: "", + property: "", + type: "", + converter: "", + attribute: "", + path: "", + name: "", + + _addWire: function(/*Transfer*/parent, /*Object*/args){ + // summary: + // Add a child Wire to Wire arguments + // description: + // If 'name' attribute is specified, a child Wire is added as + // the named property of 'children' object of 'args'. + // Otherwise, a child Wire is added to 'children' array of 'args'. + // parent: + // A parent Transfer widget + // args: + // Wire arguments + if(this.name){ // object + if(!args.children){ + args.children = {}; + } + args.children[this.name] = this._getWire(parent); + }else{ // array + if(!args.children){ + args.children = []; + } + args.children.push(this._getWire(parent)); + } + }, + + _getWire: function(/*Transfer*/parent){ + // summary: + // Build child Wire arguments from attributes + // description: + // Arguments object for a child Wire are build from attributes, + // including 'object', 'property', 'type', 'converter', + // 'attribute' and 'path'. + // parent: + // A parent Transfer widget + // returns: + // Wire arguments object + return { + object: (this.object ? dojox.wire.ml._getValue(this.object) : undefined), + property: this.property, + type: this.type, + converter: this.converter, + attribute: this.attribute, + path: this.path + }; //Object + } +}); + +dojo.declare("dojox.wire.ml.ColumnWire", dojox.wire.ml.ChildWire, { + // summary: + // A widget to add a column wire + // description: + // Attributes of this widget are used to add a column Wire to + // a TableAdapter of the parent Transfer widget. + // column: + // A column name + column: "", + + _addWire: function(/*Transfer*/parent, /*Object*/args){ + // summary: + // Add a column Wire to Wire arguments + // description: + // If 'column' attribute is specified, a column Wire is added as + // the named property of 'columns' object of 'args'. + // Otherwise, a column Wire is added to 'columns' array of 'args'. + // parent: + // A parent Transfer widget + // args: + // Wire arguments + if(this.column){ // object + if(!args.columns){ + args.columns = {}; + } + args.columns[this.column] = this._getWire(parent); + }else{ // array + if(!args.columns){ + args.columns = []; + } + args.columns.push(this._getWire(parent)); + } + } +}); + +dojo.declare("dojox.wire.ml.NodeWire", [dojox.wire.ml.ChildWire, dijit._Container], { + // summary: + // A widget to add node wires + // description: + // Attributes of this widget are used to add node Wires to + // a TreeAdapter of the parent Transfer widget. + // titleProperty: + // A property for the node title + // titleAttribute: + // A data item attribute for the node title + // titlePath: + // A simplified XPath for the node title + titleProperty: "", + titleAttribute: "", + titlePath: "", + + _addWire: function(/*Transfer*/parent, /*Object*/args){ + // summary: + // Add node Wires to Wire arguments + // description: + // Node Wires are added to 'nodes' array of 'args'. + // parent: + // A parent Transfer widget + // args: + // Wire arguments + if(!args.nodes){ + args.nodes = []; + } + args.nodes.push(this._getWires(parent)); + }, + + _getWires: function(/*Transfer*/parent){ + // summary: + // Build node Wires arguments from attributes + // description: + // Arguments object for 'node' Wire are build from attributes, + // including 'object', 'property', 'type', 'converter', + // 'attribute' and 'path'. + // Arguments object for 'title' Wire are build from another set of + // attributes, 'titleProperty', 'titleAttribute' and 'titlePath'. + // If this widget has child NodeWire widgets, their _getWires() + // methods are called recursively to build 'children' array of + // 'args'. + // parent: + // A parent Transfer widget + // returns: + // Wire arguments object + var args = { + node: this._getWire(parent), + title: { + type: "string", + property: this.titleProperty, + attribute: this.titleAttribute, + path: this.titlePath + } + }; + var childArgs = []; + var children = this.getChildren(); + for(var i in children){ + var child = children[i]; + if(child instanceof dojox.wire.ml.NodeWire){ + childArgs.push(child._getWires(parent)); + } + } + if(childArgs.length > 0){ + args.children = childArgs; + } + return args; //Object + } +}); + +dojo.declare("dojox.wire.ml.SegmentWire", dojox.wire.ml.ChildWire, { + // summary: + // A widget to add a segment wire + // description: + // Attributes of this widget are used to add a segment Wire to + // a TextAdapter of the parent Transfer widget. + + _addWire: function(/*Transfer*/parent, /*Object*/args){ + // summary: + // Add a segument Wire to Wire arguments + // description: + // A segment Wire is added to 'segments' array of 'args'. + // If 'parent' has 'delimiter' attribute, it is used for + // 'delimiter' property of 'args'. + // parent: + // A parent Transfer widget + // args: + // Wire arguments + if(!args.segments){ + args.segments = []; + } + args.segments.push(this._getWire(parent)); + if(parent.delimiter && !args.delimiter){ + args.delimiter = parent.delimiter; + } + } +}); + +} diff --git a/includes/js/dojox/wire/ml/util.js b/includes/js/dojox/wire/ml/util.js new file mode 100644 index 0000000..a336b28 --- /dev/null +++ b/includes/js/dojox/wire/ml/util.js @@ -0,0 +1,295 @@ +if(!dojo._hasResource["dojox.wire.ml.util"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.wire.ml.util"] = true; +dojo.provide("dojox.wire.ml.util"); + +dojo.require("dojox.data.dom"); +dojo.require("dojox.wire.Wire"); + +dojox.wire.ml._getValue = function(/*String*/source, /*Array*/args){ + // summary: + // Return a value + // description: + // This method obtains an object by an ID of a widget or an DOM + // element. + // If 'source' specifies a dotted notation to its property, a Wire is + // used to get the object property. + // If 'source' starts with "arguments", 'args' is used as a root + // object for the Wire. + // source: + // A string to specify an object and its property + // args: + // An optional arguments array + // returns: + // A value + if(!source){ + return undefined; //undefined + } + var property = undefined; + if(args && source.length >= 9 && source.substring(0, 9) == "arguments"){ + property = source.substring(9); + return new dojox.wire.Wire({property: property}).getValue(args); + } + var i = source.indexOf('.'); + if(i >= 0){ + property = source.substring(i + 1); + source = source.substring(0, i); + } + var object = (dijit.byId(source) || dojo.byId(source) || dojo.getObject(source)); + if(!object){ + return undefined; //undefined + } + if(!property){ + return object; //Object + }else{ + return new dojox.wire.Wire({object: object, property: property}).getValue(); //anything + } +}; + +dojox.wire.ml._setValue = function(/*String*/target, /*anything*/value){ + // summary: + // Store a value + // description: + // This method stores a value by an ID of a widget or an DOM + // element with a dotted notation to its property, using a Wire. + // target: + // A string to specify an object and its property + // value: + // A value + if(!target){ + return; //undefined + } + var i = target.indexOf('.'); + if(i < 0){ + return; //undefined + } + var object = this._getValue(target.substring(0, i)); + if(!object){ + return; //undefined + } + var property = target.substring(i + 1); + new dojox.wire.Wire({object: object, property: property}).setValue(value); +}; + +dojo.declare("dojox.wire.ml.XmlElement", null, { + // summary: + // An object wrapping an XML element + // description: + // This class represents an XML element. + + constructor: function(/*Element||String*/element){ + // summary: + // Initialize with an XML element or a tag name + // element: + // An XML element or a tag name + if(dojo.isString(element)){ + element = this._getDocument().createElement(element); + } + this.element = element; + }, + getPropertyValue: function(/*String*/property){ + // summary: + // Return a property value + // description: + // If 'property' starts with '@', the attribute value is returned. + // If 'property' specifies "text()", the value of the first child + // text is returned. + // Otherwise, child elements of the tag name specified with + // 'property' are returned. + // property: + // A property name + // returns: + // A property value + var value = undefined; + if(!this.element){ + return value; //undefined + } + if(!property){ + return value; //undefined + } + + if(property.charAt(0) == '@'){ + var attribute = property.substring(1); + value = this.element.getAttribute(attribute); + }else if(property == "text()"){ + var text = this.element.firstChild; + if(text){ + value = text.nodeValue; + } + }else{ // child elements + var elements = []; + for(var i = 0; i < this.element.childNodes.length; i++){ + var child = this.element.childNodes[i]; + if(child.nodeType === 1 /* ELEMENT_NODE */ && child.nodeName == property){ + elements.push(new dojox.wire.ml.XmlElement(child)); + } + } + if(elements.length > 0){ + if(elements.length === 1){ + value = elements[0]; + }else{ + value = elements; + } + } + } + return value; //String||Array||XmlElement + }, + + setPropertyValue: function(/*String*/property, /*String||Array||XmlElement*/value){ + // summary: + // Store a property value + // description: + // If 'property' starts with '@', 'value' is set to the attribute. + // If 'property' specifies "text()", 'value' is set as the first + // child text. + // If 'value' is a string, a child element of the tag name + // specified with 'property' is created and 'value' is set as + // the first child text of the child element. + // Otherwise, 'value' is set to as child elements. + // property: + // A property name + // value: + // A property value + if(!this.element){ + return; //undefined + } + if(!property){ + return; //undefined + } + + if(property.charAt(0) == '@'){ + var attribute = property.substring(1); + if(value){ + this.element.setAttribute(attribute, value); + }else{ + this.element.removeAttribute(attribute); + } + }else if(property == "text()"){ + while(this.element.firstChild){ + this.element.removeChild(this.element.firstChild); + } + if(value){ + var text = this._getDocument().createTextNode(value); + this.element.appendChild(text); + } + }else{ // child elements + var nextChild = null; + for(var i = this.element.childNodes.length - 1; i >= 0; i--){ + var child = this.element.childNodes[i]; + if(child.nodeType === 1 /* ELEMENT_NODE */ && child.nodeName == property){ + if(!nextChild){ + nextChild = child.nextSibling; + } + this.element.removeChild(child); + } + } + if(value){ + if(dojo.isArray(value)){ + for(var i in value){ + var e = value[i]; + if(e.element){ + this.element.insertBefore(e.element, nextChild); + } + } + }else if(value instanceof dojox.wire.ml.XmlElement){ + if(value.element){ + this.element.insertBefore(value.element, nextChild); + } + }else{ // assume string + var child = this._getDocument().createElement(property); + var text = this._getDocument().createTextNode(value); + child.appendChild(text); + this.element.insertBefore(child, nextChild); + } + } + } + }, + + toString: function(){ + // summary: + // Return a value of the first text child of the element + // description: + // A value of the first text child of the element is returned. + // returns: + // A value of the first text child of the element + var s = ""; + if(this.element){ + var text = this.element.firstChild; + if(text){ + s = text.nodeValue; + } + } + return s; //String + }, + + toObject: function(){ + // summary: + // Return an object representation of the element + // description: + // An object with properties for child elements, attributes and + // text is returned. + // returns: + // An object representation of the element + if(!this.element){ + return null; //null + } + var text = ""; + var obj = {}; + var elements = 0; + for(var i = 0; i < this.element.childNodes.length; i++){ + var child = this.element.childNodes[i]; + if(child.nodeType === 1 /* ELEMENT_NODE */){ + elements++; + var o = new dojox.wire.ml.XmlElement(child).toObject(); + var name = child.nodeName; + var p = obj[name]; + if(!p){ + obj[name] = o; + }else if(dojo.isArray(p)){ + p.push(o); + }else{ + obj[name] = [p, o]; // make them array + } + }else if(child.nodeType === 3 /* TEXT_NODE */ || + child.nodeType === 4 /* CDATA_SECTION_NODE */){ + text += child.nodeValue; + } + } + var attributes = 0; + if(this.element.nodeType === 1 /* ELEMENT_NODE */){ + attributes = this.element.attributes.length; + for(var i = 0; i < attributes; i++){ + var attr = this.element.attributes[i]; + obj["@" + attr.nodeName] = attr.nodeValue; + } + } + if(elements === 0){ + if(attributes === 0){ + // text only + return text; //String + } + // text with attributes + obj["text()"] = text; + } + // else ignore text + return obj; //Object + }, + + _getDocument: function(){ + // summary: + // Return a DOM document + // description: + // If 'element' is specified, a DOM document of the element is + // returned. + // Otherwise, a DOM document is created. + // returns: + // A DOM document + if(this.element){ + return (this.element.nodeType == 9 /* DOCUMENT_NODE */ ? + this.element : this.element.ownerDocument); //Document + }else{ + return dojox.data.dom.createDocument(); //Document + } + } +}); + +} -- cgit v1.2.3-54-g00ecf