Added: ofbiz/trunk/framework/images/webapp/images/dojo/src/io/BrowserIO.js
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/images/webapp/images/dojo/src/io/BrowserIO.js?view=auto&rev=509273 ============================================================================== --- ofbiz/trunk/framework/images/webapp/images/dojo/src/io/BrowserIO.js (added) +++ ofbiz/trunk/framework/images/webapp/images/dojo/src/io/BrowserIO.js Mon Feb 19 09:56:06 2007 @@ -0,0 +1,680 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.io.BrowserIO"); + +dojo.require("dojo.io.common"); +dojo.require("dojo.lang.array"); +dojo.require("dojo.lang.func"); +dojo.require("dojo.string.extras"); +dojo.require("dojo.dom"); +dojo.require("dojo.undo.browser"); + +if(!dj_undef("window")) { + +dojo.io.checkChildrenForFile = function(/*DOMNode*/node){ + //summary: Checks any child nodes of node for an input type="file" element. + var hasFile = false; + var inputs = node.getElementsByTagName("input"); + dojo.lang.forEach(inputs, function(input){ + if(hasFile){ return; } + if(input.getAttribute("type")=="file"){ + hasFile = true; + } + }); + return hasFile; //boolean +} + +dojo.io.formHasFile = function(/*DOMNode*/formNode){ + //summary: Just calls dojo.io.checkChildrenForFile(). + return dojo.io.checkChildrenForFile(formNode); //boolean +} + +dojo.io.updateNode = function(/*DOMNode*/node, /*String or Object*/urlOrArgs){ + //summary: Updates a DOMnode with the result of a dojo.io.bind() call. + //node: DOMNode + //urlOrArgs: String or Object + // Either a String that has an URL, or an object containing dojo.io.bind() + // arguments. + node = dojo.byId(node); + var args = urlOrArgs; + if(dojo.lang.isString(urlOrArgs)){ + args = { url: urlOrArgs }; + } + args.mimetype = "text/html"; + args.load = function(t, d, e){ + while(node.firstChild){ + dojo.dom.destroyNode(node.firstChild); + } + node.innerHTML = d; + }; + dojo.io.bind(args); +} + +dojo.io.formFilter = function(/*DOMNode*/node) { + //summary: Returns true if the node is an input element that is enabled, has + //a name, and whose type is one of the following values: ["file", "submit", "image", "reset", "button"] + var type = (node.type||"").toLowerCase(); + return !node.disabled && node.name + && !dojo.lang.inArray(["file", "submit", "image", "reset", "button"], type); //boolean +} + +// TODO: Move to htmlUtils +dojo.io.encodeForm = function(/*DOMNode*/formNode, /*String?*/encoding, /*Function?*/formFilter){ + //summary: Converts the names and values of form elements into an URL-encoded + //string (name=value&name=value...). + //formNode: DOMNode + //encoding: String? + // The encoding to use for the values. Specify a string that starts with + // "utf" (for instance, "utf8"), to use encodeURIComponent() as the encoding + // function. Otherwise, dojo.string.encodeAscii will be used. + //formFilter: Function? + // A function used to filter out form elements. The element node will be passed + // to the formFilter function, and a boolean result is expected (true indicating + // indicating that the element should have its name/value included in the output). + // If no formFilter is specified, then dojo.io.formFilter() will be used. + if((!formNode)||(!formNode.tagName)||(!formNode.tagName.toLowerCase() == "form")){ + dojo.raise("Attempted to encode a non-form element."); + } + if(!formFilter) { formFilter = dojo.io.formFilter; } + var enc = /utf/i.test(encoding||"") ? encodeURIComponent : dojo.string.encodeAscii; + var values = []; + + for(var i = 0; i < formNode.elements.length; i++){ + var elm = formNode.elements[i]; + if(!elm || elm.tagName.toLowerCase() == "fieldset" || !formFilter(elm)) { continue; } + var name = enc(elm.name); + var type = elm.type.toLowerCase(); + + if(type == "select-multiple"){ + for(var j = 0; j < elm.options.length; j++){ + if(elm.options[j].selected) { + values.push(name + "=" + enc(elm.options[j].value)); + } + } + }else if(dojo.lang.inArray(["radio", "checkbox"], type)){ + if(elm.checked){ + values.push(name + "=" + enc(elm.value)); + } + }else{ + values.push(name + "=" + enc(elm.value)); + } + } + + // now collect input type="image", which doesn't show up in the elements array + var inputs = formNode.getElementsByTagName("input"); + for(var i = 0; i < inputs.length; i++) { + var input = inputs[i]; + if(input.type.toLowerCase() == "image" && input.form == formNode + && formFilter(input)) { + var name = enc(input.name); + values.push(name + "=" + enc(input.value)); + values.push(name + ".x=0"); + values.push(name + ".y=0"); + } + } + return values.join("&") + "&"; //String +} + +dojo.io.FormBind = function(/*DOMNode or Object*/args) { + //summary: constructor for a dojo.io.FormBind object. See the Dojo Book for + //some information on usage: http://manual.dojotoolkit.org/WikiHome/DojoDotBook/Book23 + //args: DOMNode or Object + // args can either be the DOMNode for a form element, or an object containing + // dojo.io.bind() arguments, one of which should be formNode with the value of + // a form element DOMNode. + this.bindArgs = {}; + + if(args && args.formNode) { + this.init(args); + } else if(args) { + this.init({formNode: args}); + } +} +dojo.lang.extend(dojo.io.FormBind, { + form: null, + + bindArgs: null, + + clickedButton: null, + + init: function(/*DOMNode or Object*/args) { + //summary: Internal function called by the dojo.io.FormBind() constructor + //do not call this method directly. + var form = dojo.byId(args.formNode); + + if(!form || !form.tagName || form.tagName.toLowerCase() != "form") { + throw new Error("FormBind: Couldn't apply, invalid form"); + } else if(this.form == form) { + return; + } else if(this.form) { + throw new Error("FormBind: Already applied to a form"); + } + + dojo.lang.mixin(this.bindArgs, args); + this.form = form; + + this.connect(form, "onsubmit", "submit"); + + for(var i = 0; i < form.elements.length; i++) { + var node = form.elements[i]; + if(node && node.type && dojo.lang.inArray(["submit", "button"], node.type.toLowerCase())) { + this.connect(node, "onclick", "click"); + } + } + + var inputs = form.getElementsByTagName("input"); + for(var i = 0; i < inputs.length; i++) { + var input = inputs[i]; + if(input.type.toLowerCase() == "image" && input.form == form) { + this.connect(input, "onclick", "click"); + } + } + }, + + onSubmit: function(/*DOMNode*/form) { + //summary: Function used to verify that the form is OK to submit. + //Override this function if you want specific form validation done. + return true; //boolean + }, + + submit: function(/*Event*/e) { + //summary: internal function that is connected as a listener to the + //form's onsubmit event. + e.preventDefault(); + if(this.onSubmit(this.form)) { + dojo.io.bind(dojo.lang.mixin(this.bindArgs, { + formFilter: dojo.lang.hitch(this, "formFilter") + })); + } + }, + + click: function(/*Event*/e) { + //summary: internal method that is connected as a listener to the + //form's elements whose click event can submit a form. + var node = e.currentTarget; + if(node.disabled) { return; } + this.clickedButton = node; + }, + + formFilter: function(/*DOMNode*/node) { + //summary: internal function used to know which form element values to include + // in the dojo.io.bind() request. + var type = (node.type||"").toLowerCase(); + var accept = false; + if(node.disabled || !node.name) { + accept = false; + } else if(dojo.lang.inArray(["submit", "button", "image"], type)) { + if(!this.clickedButton) { this.clickedButton = node; } + accept = node == this.clickedButton; + } else { + accept = !dojo.lang.inArray(["file", "submit", "reset", "button"], type); + } + return accept; //boolean + }, + + // in case you don't have dojo.event.* pulled in + connect: function(/*Object*/srcObj, /*Function*/srcFcn, /*Function*/targetFcn) { + //summary: internal function used to connect event listeners to form elements + //that trigger events. Used in case dojo.event is not loaded. + if(dojo.evalObjPath("dojo.event.connect")) { + dojo.event.connect(srcObj, srcFcn, this, targetFcn); + } else { + var fcn = dojo.lang.hitch(this, targetFcn); + srcObj[srcFcn] = function(e) { + if(!e) { e = window.event; } + if(!e.currentTarget) { e.currentTarget = e.srcElement; } + if(!e.preventDefault) { e.preventDefault = function() { window.event.returnValue = false; } } + fcn(e); + } + } + } +}); + +dojo.io.XMLHTTPTransport = new function(){ + //summary: The object that implements the dojo.io.bind transport for XMLHttpRequest. + var _this = this; + + var _cache = {}; // FIXME: make this public? do we even need to? + this.useCache = false; // if this is true, we'll cache unless kwArgs.useCache = false + this.preventCache = false; // if this is true, we'll always force GET requests to cache + + // FIXME: Should this even be a function? or do we just hard code it in the next 2 functions? + function getCacheKey(url, query, method) { + return url + "|" + query + "|" + method.toLowerCase(); + } + + function addToCache(url, query, method, http) { + _cache[getCacheKey(url, query, method)] = http; + } + + function getFromCache(url, query, method) { + return _cache[getCacheKey(url, query, method)]; + } + + this.clearCache = function() { + _cache = {}; + } + + // moved successful load stuff here + function doLoad(kwArgs, http, url, query, useCache) { + if( ((http.status>=200)&&(http.status<300))|| // allow any 2XX response code + (http.status==304)|| // get it out of the cache + (location.protocol=="file:" && (http.status==0 || http.status==undefined))|| + (location.protocol=="chrome:" && (http.status==0 || http.status==undefined)) + ){ + var ret; + if(kwArgs.method.toLowerCase() == "head"){ + var headers = http.getAllResponseHeaders(); + ret = {}; + ret.toString = function(){ return headers; } + var values = headers.split(/[\r\n]+/g); + for(var i = 0; i < values.length; i++) { + var pair = values[i].match(/^([^:]+)\s*:\s*(.+)$/i); + if(pair) { + ret[pair[1]] = pair[2]; + } + } + }else if(kwArgs.mimetype == "text/javascript"){ + try{ + ret = dj_eval(http.responseText); + }catch(e){ + dojo.debug(e); + dojo.debug(http.responseText); + ret = null; + } + }else if(kwArgs.mimetype == "text/json" || kwArgs.mimetype == "application/json"){ + try{ + ret = dj_eval("("+http.responseText+")"); + }catch(e){ + dojo.debug(e); + dojo.debug(http.responseText); + ret = false; + } + }else if((kwArgs.mimetype == "application/xml")|| + (kwArgs.mimetype == "text/xml")){ + ret = http.responseXML; + if(!ret || typeof ret == "string" || !http.getResponseHeader("Content-Type")) { + ret = dojo.dom.createDocumentFromText(http.responseText); + } + }else{ + ret = http.responseText; + } + + if(useCache){ // only cache successful responses + addToCache(url, query, kwArgs.method, http); + } + kwArgs[(typeof kwArgs.load == "function") ? "load" : "handle"]("load", ret, http, kwArgs); + }else{ + var errObj = new dojo.io.Error("XMLHttpTransport Error: "+http.status+" "+http.statusText); + kwArgs[(typeof kwArgs.error == "function") ? "error" : "handle"]("error", errObj, http, kwArgs); + } + } + + // set headers (note: Content-Type will get overriden if kwArgs.contentType is set) + function setHeaders(http, kwArgs){ + if(kwArgs["headers"]) { + for(var header in kwArgs["headers"]) { + if(header.toLowerCase() == "content-type" && !kwArgs["contentType"]) { + kwArgs["contentType"] = kwArgs["headers"][header]; + } else { + http.setRequestHeader(header, kwArgs["headers"][header]); + } + } + } + } + + this.inFlight = []; + this.inFlightTimer = null; + + this.startWatchingInFlight = function(){ + //summary: internal method used to trigger a timer to watch all inflight + //XMLHttpRequests. + if(!this.inFlightTimer){ + // setInterval broken in mozilla x86_64 in some circumstances, see + // https://bugzilla.mozilla.org/show_bug.cgi?id=344439 + // using setTimeout instead + this.inFlightTimer = setTimeout("dojo.io.XMLHTTPTransport.watchInFlight();", 10); + } + } + + this.watchInFlight = function(){ + //summary: internal method that checks each inflight XMLHttpRequest to see + //if it has completed or if the timeout situation applies. + var now = null; + // make sure sync calls stay thread safe, if this callback is called during a sync call + // and this results in another sync call before the first sync call ends the browser hangs + if(!dojo.hostenv._blockAsync && !_this._blockAsync){ + for(var x=this.inFlight.length-1; x>=0; x--){ + try{ + var tif = this.inFlight[x]; + if(!tif || tif.http._aborted || !tif.http.readyState){ + this.inFlight.splice(x, 1); continue; + } + if(4==tif.http.readyState){ + // remove it so we can clean refs + this.inFlight.splice(x, 1); + doLoad(tif.req, tif.http, tif.url, tif.query, tif.useCache); + }else if (tif.startTime){ + //See if this is a timeout case. + if(!now){ + now = (new Date()).getTime(); + } + if(tif.startTime + (tif.req.timeoutSeconds * 1000) < now){ + //Stop the request. + if(typeof tif.http.abort == "function"){ + tif.http.abort(); + } + + // remove it so we can clean refs + this.inFlight.splice(x, 1); + tif.req[(typeof tif.req.timeout == "function") ? "timeout" : "handle"]("timeout", null, tif.http, tif.req); + } + } + }catch(e){ + try{ + var errObj = new dojo.io.Error("XMLHttpTransport.watchInFlight Error: " + e); + tif.req[(typeof tif.req.error == "function") ? "error" : "handle"]("error", errObj, tif.http, tif.req); + }catch(e2){ + dojo.debug("XMLHttpTransport error callback failed: " + e2); + } + } + } + } + + clearTimeout(this.inFlightTimer); + if(this.inFlight.length == 0){ + this.inFlightTimer = null; + return; + } + this.inFlightTimer = setTimeout("dojo.io.XMLHTTPTransport.watchInFlight();", 10); + } + + var hasXmlHttp = dojo.hostenv.getXmlhttpObject() ? true : false; + this.canHandle = function(/*dojo.io.Request*/kwArgs){ + //summary: Tells dojo.io.bind() if this is a good transport to + //use for the particular type of request. This type of transport cannot + //handle forms that have an input type="file" element. + + // FIXME: we need to determine when form values need to be + // multi-part mime encoded and avoid using this transport for those + // requests. + return hasXmlHttp + && dojo.lang.inArray(["text/plain", "text/html", "application/xml", "text/xml", "text/javascript", "text/json", "application/json"], (kwArgs["mimetype"].toLowerCase()||"")) + && !( kwArgs["formNode"] && dojo.io.formHasFile(kwArgs["formNode"]) ); //boolean + } + + this.multipartBoundary = "45309FFF-BD65-4d50-99C9-36986896A96F"; // unique guid as a boundary value for multipart posts + + this.bind = function(/*dojo.io.Request*/kwArgs){ + //summary: function that sends the request to the server. + + //This function will attach an abort() function to the kwArgs dojo.io.Request object, + //so if you need to abort the request, you can call that method on the request object. + //The following are acceptable properties in kwArgs (in addition to the + //normal dojo.io.Request object properties). + //url: String: URL the server URL to use for the request. + //method: String: the HTTP method to use (GET, POST, etc...). + //mimetype: Specifies what format the result data should be given to the load/handle callback. Valid values are: + // text/javascript, text/json, application/json, application/xml, text/xml. Any other mimetype will give back a text + // string. + //transport: String: specify "XMLHTTPTransport" to force the use of this XMLHttpRequest transport. + //headers: Object: The object property names and values will be sent as HTTP request header + // names and values. + //sendTransport: boolean: If true, then dojo.transport=xmlhttp will be added to the request. + //encoding: String: The type of encoding to use when dealing with the content kwArgs property. + //content: Object: The content object is converted into a name=value&name=value string, by + // using dojo.io.argsFromMap(). The encoding kwArgs property is passed to dojo.io.argsFromMap() + // for use in encoding the names and values. The resulting string is added to the request. + //formNode: DOMNode: a form element node. This should not normally be used. Use new dojo.io.FormBind() instead. + // If formNode is used, then the names and values of the form elements will be converted + // to a name=value&name=value string and added to the request. The encoding kwArgs property is used + // to encode the names and values. + //postContent: String: Raw name=value&name=value string to be included as part of the request. + //back or backButton: Function: A function to be called if the back button is pressed. If this kwArgs property + // is used, then back button support via dojo.undo.browser will be used. See notes for dojo.undo.browser on usage. + // You need to set djConfig.preventBackButtonFix = false to enable back button support. + //changeUrl: boolean or String: Used as part of back button support. See notes for dojo.undo.browser on usage. + //user: String: The user name. Used in conjuction with password. Passed to XMLHttpRequest.open(). + //password: String: The user's password. Used in conjuction with user. Passed to XMLHttpRequest.open(). + //file: Object or Array of Objects: an object simulating a file to be uploaded. file objects should have the following properties: + // name or fileName: the name of the file + // contentType: the MIME content type for the file. + // content: the actual content of the file. + //multipart: boolean: indicates whether this should be a multipart mime request. If kwArgs.file exists, then this + // property is set to true automatically. + //sync: boolean: if true, then a synchronous XMLHttpRequest call is done, + // if false (the default), then an asynchronous call is used. + //preventCache: boolean: If true, then a cache busting parameter is added to the request URL. + // default value is false. + //useCache: boolean: If true, then XMLHttpTransport will keep an internal cache of the server + // response and use that response if a similar request is done again. + // A similar request is one that has the same URL, query string and HTTP method value. + // default is false. + if(!kwArgs["url"]){ + // are we performing a history action? + if( !kwArgs["formNode"] + && (kwArgs["backButton"] || kwArgs["back"] || kwArgs["changeUrl"] || kwArgs["watchForURL"]) + && (!djConfig.preventBackButtonFix)) { + dojo.deprecated("Using dojo.io.XMLHTTPTransport.bind() to add to browser history without doing an IO request", + "Use dojo.undo.browser.addToHistory() instead.", "0.4"); + dojo.undo.browser.addToHistory(kwArgs); + return true; + } + } + + // build this first for cache purposes + var url = kwArgs.url; + var query = ""; + if(kwArgs["formNode"]){ + var ta = kwArgs.formNode.getAttribute("action"); + if((ta)&&(!kwArgs["url"])){ url = ta; } + var tp = kwArgs.formNode.getAttribute("method"); + if((tp)&&(!kwArgs["method"])){ kwArgs.method = tp; } + query += dojo.io.encodeForm(kwArgs.formNode, kwArgs.encoding, kwArgs["formFilter"]); + } + + if(url.indexOf("#") > -1) { + dojo.debug("Warning: dojo.io.bind: stripping hash values from url:", url); + url = url.split("#")[0]; + } + + if(kwArgs["file"]){ + // force post for file transfer + kwArgs.method = "post"; + } + + if(!kwArgs["method"]){ + kwArgs.method = "get"; + } + + // guess the multipart value + if(kwArgs.method.toLowerCase() == "get"){ + // GET cannot use multipart + kwArgs.multipart = false; + }else{ + if(kwArgs["file"]){ + // enforce multipart when sending files + kwArgs.multipart = true; + }else if(!kwArgs["multipart"]){ + // default + kwArgs.multipart = false; + } + } + + if(kwArgs["backButton"] || kwArgs["back"] || kwArgs["changeUrl"]){ + dojo.undo.browser.addToHistory(kwArgs); + } + + var content = kwArgs["content"] || {}; + + if(kwArgs.sendTransport) { + content["dojo.transport"] = "xmlhttp"; + } + + do { // break-block + if(kwArgs.postContent){ + query = kwArgs.postContent; + break; + } + + if(content) { + query += dojo.io.argsFromMap(content, kwArgs.encoding); + } + + if(kwArgs.method.toLowerCase() == "get" || !kwArgs.multipart){ + break; + } + + var t = []; + if(query.length){ + var q = query.split("&"); + for(var i = 0; i < q.length; ++i){ + if(q[i].length){ + var p = q[i].split("="); + t.push( "--" + this.multipartBoundary, + "Content-Disposition: form-data; name=\"" + p[0] + "\"", + "", + p[1]); + } + } + } + + if(kwArgs.file){ + if(dojo.lang.isArray(kwArgs.file)){ + for(var i = 0; i < kwArgs.file.length; ++i){ + var o = kwArgs.file[i]; + t.push( "--" + this.multipartBoundary, + "Content-Disposition: form-data; name=\"" + o.name + "\"; filename=\"" + ("fileName" in o ? o.fileName : o.name) + "\"", + "Content-Type: " + ("contentType" in o ? o.contentType : "application/octet-stream"), + "", + o.content); + } + }else{ + var o = kwArgs.file; + t.push( "--" + this.multipartBoundary, + "Content-Disposition: form-data; name=\"" + o.name + "\"; filename=\"" + ("fileName" in o ? o.fileName : o.name) + "\"", + "Content-Type: " + ("contentType" in o ? o.contentType : "application/octet-stream"), + "", + o.content); + } + } + + if(t.length){ + t.push("--"+this.multipartBoundary+"--", ""); + query = t.join("\r\n"); + } + }while(false); + + // kwArgs.Connection = "close"; + + var async = kwArgs["sync"] ? false : true; + + var preventCache = kwArgs["preventCache"] || + (this.preventCache == true && kwArgs["preventCache"] != false); + var useCache = kwArgs["useCache"] == true || + (this.useCache == true && kwArgs["useCache"] != false ); + + // preventCache is browser-level (add query string junk), useCache + // is for the local cache. If we say preventCache, then don't attempt + // to look in the cache, but if useCache is true, we still want to cache + // the response + if(!preventCache && useCache){ + var cachedHttp = getFromCache(url, query, kwArgs.method); + if(cachedHttp){ + doLoad(kwArgs, cachedHttp, url, query, false); + return; + } + } + + // much of this is from getText, but reproduced here because we need + // more flexibility + var http = dojo.hostenv.getXmlhttpObject(kwArgs); + var received = false; + + // build a handler function that calls back to the handler obj + if(async){ + var startTime = + // FIXME: setting up this callback handler leaks on IE!!! + this.inFlight.push({ + "req": kwArgs, + "http": http, + "url": url, + "query": query, + "useCache": useCache, + "startTime": kwArgs.timeoutSeconds ? (new Date()).getTime() : 0 + }); + this.startWatchingInFlight(); + }else{ + // block async callbacks until sync is in, needed in khtml, others? + _this._blockAsync = true; + } + + if(kwArgs.method.toLowerCase() == "post"){ + // FIXME: need to hack in more flexible Content-Type setting here! + if (!kwArgs.user) { + http.open("POST", url, async); + }else{ + http.open("POST", url, async, kwArgs.user, kwArgs.password); + } + setHeaders(http, kwArgs); + http.setRequestHeader("Content-Type", kwArgs.multipart ? ("multipart/form-data; boundary=" + this.multipartBoundary) : + (kwArgs.contentType || "application/x-www-form-urlencoded")); + try{ + http.send(query); + }catch(e){ + if(typeof http.abort == "function"){ + http.abort(); + } + doLoad(kwArgs, {status: 404}, url, query, useCache); + } + }else{ + var tmpUrl = url; + if(query != "") { + tmpUrl += (tmpUrl.indexOf("?") > -1 ? "&" : "?") + query; + } + if(preventCache) { + tmpUrl += (dojo.string.endsWithAny(tmpUrl, "?", "&") + ? "" : (tmpUrl.indexOf("?") > -1 ? "&" : "?")) + "dojo.preventCache=" + new Date().valueOf(); + } + if (!kwArgs.user) { + http.open(kwArgs.method.toUpperCase(), tmpUrl, async); + }else{ + http.open(kwArgs.method.toUpperCase(), tmpUrl, async, kwArgs.user, kwArgs.password); + } + setHeaders(http, kwArgs); + try { + http.send(null); + }catch(e) { + if(typeof http.abort == "function"){ + http.abort(); + } + doLoad(kwArgs, {status: 404}, url, query, useCache); + } + } + + if( !async ) { + doLoad(kwArgs, http, url, query, useCache); + _this._blockAsync = false; + } + + kwArgs.abort = function(){ + try{// khtml doesent reset readyState on abort, need this workaround + http._aborted = true; + }catch(e){/*squelsh*/} + return http.abort(); + } + + return; + } + dojo.io.transports.addTransport("XMLHTTPTransport"); +} + +} \ No newline at end of file Propchange: ofbiz/trunk/framework/images/webapp/images/dojo/src/io/BrowserIO.js ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/framework/images/webapp/images/dojo/src/io/BrowserIO.js ------------------------------------------------------------------------------ svn:keywords = "Date Rev Author URL Id" Propchange: ofbiz/trunk/framework/images/webapp/images/dojo/src/io/BrowserIO.js ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: ofbiz/trunk/framework/images/webapp/images/dojo/src/io/IframeIO.js URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/images/webapp/images/dojo/src/io/IframeIO.js?view=auto&rev=509273 ============================================================================== --- ofbiz/trunk/framework/images/webapp/images/dojo/src/io/IframeIO.js (added) +++ ofbiz/trunk/framework/images/webapp/images/dojo/src/io/IframeIO.js Mon Feb 19 09:56:06 2007 @@ -0,0 +1,298 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.io.IframeIO"); +dojo.require("dojo.io.BrowserIO"); +dojo.require("dojo.uri.*"); + +// FIXME: is it possible to use the Google htmlfile hack to prevent the +// background click with this transport? + +dojo.io.createIFrame = function(/*String*/fname, /*String*/onloadstr, /*String?*/uri){ + //summary: Creates a hidden iframe in the page. Used mostly for data transports. + //fname: String + // The name of the iframe. Used for the name attribute on the iframe. + //onloadstr: String + // A string of Javascript that will be executed when the content in the iframe loads. + //uri: String + // The value of the src attribute on the iframe element. If a value is not + // given, then iframe_history.html will be used. + if(window[fname]){ return window[fname]; } + if(window.frames[fname]){ return window.frames[fname]; } + var r = dojo.render.html; + var cframe = null; + var turi = uri||dojo.uri.dojoUri("iframe_history.html?noInit=true"); + var ifrstr = ((r.ie)&&(dojo.render.os.win)) ? '<iframe name="'+fname+'" src="'+turi+'" onload="'+onloadstr+'">' : 'iframe'; + cframe = document.createElement(ifrstr); + with(cframe){ + name = fname; + setAttribute("name", fname); + id = fname; + } + dojo.body().appendChild(cframe); + window[fname] = cframe; + + with(cframe.style){ + if(!r.safari){ + //We can't change the src in Safari 2.0.3 if absolute position. Bizarro. + position = "absolute"; + } + left = top = "0px"; + height = width = "1px"; + visibility = "hidden"; + /* + if(djConfig.isDebug){ + position = "relative"; + height = "300px"; + width = "600px"; + visibility = "visible"; + } + */ + } + + if(!r.ie){ + dojo.io.setIFrameSrc(cframe, turi, true); + cframe.onload = new Function(onloadstr); + } + + return cframe; +} + +dojo.io.IframeTransport = new function(){ + //summary: The object that implements the dojo.io.bind transport that + //uses an iframe to communicate to the server. + var _this = this; + this.currentRequest = null; + this.requestQueue = []; + this.iframeName = "dojoIoIframe"; + + this.fireNextRequest = function(){ + //summary: Internal method used to fire the next request in the bind queue. + try{ + if((this.currentRequest)||(this.requestQueue.length == 0)){ return; } + // dojo.debug("fireNextRequest"); + var cr = this.currentRequest = this.requestQueue.shift(); + cr._contentToClean = []; + var fn = cr["formNode"]; + var content = cr["content"] || {}; + if(cr.sendTransport) { + content["dojo.transport"] = "iframe"; + } + if(fn){ + if(content){ + // if we have things in content, we need to add them to the form + // before submission + for(var x in content){ + if(!fn[x]){ + var tn; + if(dojo.render.html.ie){ + tn = document.createElement("<input type='hidden' name='"+x+"' value='"+content[x]+"'>"); + fn.appendChild(tn); + }else{ + tn = document.createElement("input"); + fn.appendChild(tn); + tn.type = "hidden"; + tn.name = x; + tn.value = content[x]; + } + cr._contentToClean.push(x); + }else{ + fn[x].value = content[x]; + } + } + } + if(cr["url"]){ + cr._originalAction = fn.getAttribute("action"); + fn.setAttribute("action", cr.url); + } + if(!fn.getAttribute("method")){ + fn.setAttribute("method", (cr["method"]) ? cr["method"] : "post"); + } + cr._originalTarget = fn.getAttribute("target"); + fn.setAttribute("target", this.iframeName); + fn.target = this.iframeName; + fn.submit(); + }else{ + // otherwise we post a GET string by changing URL location for the + // iframe + var query = dojo.io.argsFromMap(this.currentRequest.content); + var tmpUrl = cr.url + (cr.url.indexOf("?") > -1 ? "&" : "?") + query; + dojo.io.setIFrameSrc(this.iframe, tmpUrl, true); + } + }catch(e){ + this.iframeOnload(e); + } + } + + this.canHandle = function(/*dojo.io.Request*/kwArgs){ + //summary: Tells dojo.io.bind() if this is a good transport to + //use for the particular type of request. + //description: This type of transport cannot + //handle text/xml or application/xml return types, is limited to GET + //or POST requests, and cannot do synchronous binds. + return ( + ( + dojo.lang.inArray([ "text/plain", "text/html", "text/javascript", "text/json", "application/json"], kwArgs["mimetype"]) + )&&( + dojo.lang.inArray(["post", "get"], kwArgs["method"].toLowerCase()) + )&&( + // never handle a sync request + ! ((kwArgs["sync"])&&(kwArgs["sync"] == true)) + ) + ); //boolean + } + + this.bind = function(/*dojo.io.Request*/kwArgs){ + //summary: function that sends the request to the server. + + //This transport can only process one bind request at a time, so if bind is called + //multiple times, it will queue up the calls and only process one at a time. + //The following are acceptable properties in kwArgs (in addition to the + //normal dojo.io.Request object properties). + //url: String: URL the server URL to use for the request. + //transport: String: specify "IframeTransport" to force the use of this transport. + //sendTransport: boolean: If true, then dojo.transport=iframe will be added to the request. + //formNode: DOMNode: a form element node. The form elements' names and values will be used in + // the request. This makes it possible to upload files using this transport. + //method: String: the HTTP method to use. Must be GET or POST. Default is POST. + //mimetype: Specifies what format the result data should be given to the load/handle callback. Valid values are: + // text/plain, text/html, text/javascript, text/json, application/json. IMPORTANT: For all values EXCEPT text/html, + // The server response should be an HTML file with a textarea element. The response data should be inside the textarea + // element. Using an HTML document the only reliable, cross-browser way this transport can know + // when the response has loaded. For the text/html mimetype, just return a normal HTML document. + //content: Object: If a formNode is one of the other kwArgs properties, then the content + // object properties become hidden form form elements. For instance, a content + // object of {name1 : "value1"} is converted to a hidden form element with a name + // of "name1" and a value of "value1". If there is not a formNode property, then + // the content object is converted into a name=value&name=value string, by + // using dojo.io.argsFromMap(). No encoding is passed to that method, so the + // names and values will be encoded using dojo.string.encodeAscii(). + if(!this["iframe"]){ this.setUpIframe(); } + this.requestQueue.push(kwArgs); + this.fireNextRequest(); + return; + } + + this.setUpIframe = function(){ + + // NOTE: IE 5.0 and earlier Mozilla's don't support an onload event for + // iframes. OTOH, we don't care. + this.iframe = dojo.io.createIFrame(this.iframeName, "dojo.io.IframeTransport.iframeOnload();"); + } + + this.iframeOnload = function(errorObject /* Object */){ + if(!_this.currentRequest){ + _this.fireNextRequest(); + return; + } + + var req = _this.currentRequest; + + if(req.formNode){ + // remove all the hidden content inputs + var toClean = req._contentToClean; + for(var i = 0; i < toClean.length; i++) { + var key = toClean[i]; + if(dojo.render.html.safari){ + //In Safari (at least 2.0.3), can't use formNode[key] syntax to find the node, + //for nodes that were dynamically added. + var fNode = req.formNode; + for(var j = 0; j < fNode.childNodes.length; j++){ + var chNode = fNode.childNodes[j]; + if(chNode.name == key){ + var pNode = chNode.parentNode; + pNode.removeChild(chNode); + break; + } + } + }else{ + var input = req.formNode[key]; + req.formNode.removeChild(input); + req.formNode[key] = null; + } + } + + // restore original action + target + if(req["_originalAction"]){ + req.formNode.setAttribute("action", req._originalAction); + } + if(req["_originalTarget"]){ + req.formNode.setAttribute("target", req._originalTarget); + req.formNode.target = req._originalTarget; + } + } + + var contentDoc = function(iframe_el){ + var doc = iframe_el.contentDocument || // W3 + ( + (iframe_el.contentWindow)&&(iframe_el.contentWindow.document) + ) || // IE + ( + (iframe_el.name)&&(document.frames[iframe_el.name])&& + (document.frames[iframe_el.name].document) + ) || null; + return doc; + }; + + var value; + var success = false; + + if (errorObject){ + this._callError(req, "IframeTransport Request Error: " + errorObject); + }else{ + var ifd = contentDoc(_this.iframe); + // handle successful returns + // FIXME: how do we determine success for iframes? Is there an equiv of + // the "status" property? + + try{ + var cmt = req.mimetype; + if((cmt == "text/javascript")||(cmt == "text/json")||(cmt == "application/json")){ + // FIXME: not sure what to do here? try to pull some evalulable + // text from a textarea or cdata section? + // how should we set up the contract for that? + var js = ifd.getElementsByTagName("textarea")[0].value; + if(cmt == "text/json" || cmt == "application/json") { js = "(" + js + ")"; } + value = dj_eval(js); + }else if(cmt == "text/html"){ + value = ifd; + }else{ // text/plain + value = ifd.getElementsByTagName("textarea")[0].value; + } + success = true; + }catch(e){ + // looks like we didn't get what we wanted! + this._callError(req, "IframeTransport Error: " + e); + } + } + + // don't want to mix load function errors with processing errors, thus + // a separate try..catch + try { + if(success && dojo.lang.isFunction(req["load"])){ + req.load("load", value, req); + } + } catch(e) { + throw e; + } finally { + _this.currentRequest = null; + _this.fireNextRequest(); + } + } + + this._callError = function(req /* Object */, message /* String */){ + var errObj = new dojo.io.Error(message); + if(dojo.lang.isFunction(req["error"])){ + req.error("error", errObj, req); + } + } + + dojo.io.transports.addTransport("IframeTransport"); +} Propchange: ofbiz/trunk/framework/images/webapp/images/dojo/src/io/IframeIO.js ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/framework/images/webapp/images/dojo/src/io/IframeIO.js ------------------------------------------------------------------------------ svn:keywords = "Date Rev Author URL Id" Propchange: ofbiz/trunk/framework/images/webapp/images/dojo/src/io/IframeIO.js ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: ofbiz/trunk/framework/images/webapp/images/dojo/src/io/RepubsubIO.js URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/images/webapp/images/dojo/src/io/RepubsubIO.js?view=auto&rev=509273 ============================================================================== --- ofbiz/trunk/framework/images/webapp/images/dojo/src/io/RepubsubIO.js (added) +++ ofbiz/trunk/framework/images/webapp/images/dojo/src/io/RepubsubIO.js Mon Feb 19 09:56:06 2007 @@ -0,0 +1,520 @@ +// Copyright (c) 2004 Friendster Inc., Licensed under the Academic Free +// License version 2.0 or later + +dojo.require("dojo.event.*"); +dojo.require("dojo.io.BrowserIO"); + +dojo.provide("dojo.io.RepubsubIO"); + +dojo.io.repubsubTranport = new function(){ + var rps = dojo.io.repubsub; + this.canHandle = function(/*dojo.io.Request*/kwArgs){ + //summary: Tells dojo.io.bind() if this is a good transport to + //use for the particular type of request. This is a legacy transport + //and should not be used unless you are dealing with repubsub. + //Consider a comet transport instead. + if((kwArgs["mimetype"] == "text/javascript")&&(kwArgs["method"] == "repubsub")){ + return true; + } + return false; + } + + this.bind = function(/*dojo.io.Request*/kwArgs){ + //summary: This is a legacy transport and should not be used unless you are dealing with repubsub. + //Consider a comet transport instead. + if(!rps.isInitialized){ + // open up our tunnel, queue up requests anyway + rps.init(); + } + // FIXME: we need to turn this into a topic subscription + // var tgtURL = kwArgs.url+"?"+dojo.io.argsFromMap(kwArgs.content); + // sampleTransport.sendRequest(tgtURL, hdlrFunc); + + // a normal "bind()" call in a request-response transport layer is + // something that (usually) encodes most of it's payload with the + // request. Multi-event systems like repubsub are a bit more complex, + // and repubsub in particular distinguishes the publish and subscribe + // portions of thep rocess with different method calls to handle each. + // Therefore, a "bind" in the sense of repubsub must first determine if + // we have an open subscription to a channel provided by the server, + // and then "publish" the request payload if there is any. We therefore + // must take care not to incorrectly or too agressively register or + // file event handlers which are provided with the kwArgs method. + + // NOTE: we ONLY pay attention to those event handlers that are + // registered with the bind request that subscribes to the channel. If + // event handlers are provided with subsequent requests, we might in + // the future support some additive or replacement syntax, but for now + // they get dropped on the floor. + + // NOTE: in this case, url MUST be the "topic" to which we + // subscribe/publish for this channel + if(!rps.topics[kwArgs.url]){ + kwArgs.rpsLoad = function(evt){ + kwArgs.load("load", evt); + } + rps.subscribe(kwArgs.url, kwArgs, "rpsLoad"); + } + + if(kwArgs["content"]){ + // what we wanted to send + var cEvt = dojo.io.repubsubEvent.initFromProperties(kwArgs.content); + rps.publish(kwArgs.url, cEvt); + } + } + + dojo.io.transports.addTransport("repubsubTranport"); +} + +dojo.io.repubsub = new function(){ + this.initDoc = "init.html"; + this.isInitialized = false; + this.subscriptionBacklog = []; + this.debug = true; + this.rcvNodeName = null; + this.sndNodeName = null; + this.rcvNode = null; + this.sndNode = null; + this.canRcv = false; + this.canSnd = false; + this.canLog = false; + this.sndTimer = null; + this.windowRef = window; + this.backlog = []; + this.tunnelInitCount = 0; + this.tunnelFrameKey = "tunnel_frame"; + this.serverBaseURL = location.protocol+"//"+location.host+location.pathname; + this.logBacklog = []; + this.getRandStr = function(){ + return Math.random().toString().substring(2, 10); + } + this.userid = "guest"; + this.tunnelID = this.getRandStr(); + this.attachPathList = []; + this.topics = []; // list of topics we have listeners to + + // actually, now that I think about it a little bit more, it would sure be + // useful to parse out the <script> src attributes. We're looking for + // something with a "do_method=lib", since that's what would have included + // us in the first place (in the common case). + this.parseGetStr = function(){ + var baseUrl = document.location.toString(); + var params = baseUrl.split("?", 2); + if(params.length > 1){ + var paramStr = params[1]; + var pairs = paramStr.split("&"); + var opts = []; + for(var x in pairs){ + var sp = pairs[x].split("="); + // FIXME: is this eval dangerous? + try{ + opts[sp[0]]=eval(sp[1]); + }catch(e){ + opts[sp[0]]=sp[1]; + } + } + return opts; + }else{ + return []; + } + } + + // parse URL params and use them as default vals + var getOpts = this.parseGetStr(); + for(var x in getOpts){ + // FIXME: should I be checking for undefined here before setting? Does + // that buy me anything? + this[x] = getOpts[x]; + } + + if(!this["tunnelURI"]){ + this.tunnelURI = [ "/who/", escape(this.userid), "/s/", + this.getRandStr(), "/kn_journal"].join(""); + // this.tunnelURI = this.absoluteTopicURI(this.tunnelURI); + } + + /* + if (self.kn_tunnelID) kn.tunnelID = self.kn_tunnelID; // the server says + if (kn._argv.kn_tunnelID) kn.tunnelID = kn._argv.kn_tunnelID; // the url says + */ + + // check the options object if it exists and use its properties as an + // over-ride + if(window["repubsubOpts"]||window["rpsOpts"]){ + var optObj = window["repubsubOpts"]||window["rpsOpts"]; + for(var x in optObj){ + this[x] = optObj[x]; // copy the option object properties + } + } + + // things that get called directly from our iframe to inform us of events + this.tunnelCloseCallback = function(){ + // when we get this callback, we should immediately attempt to re-start + // our tunnel connection + dojo.io.setIFrameSrc(this.rcvNode, this.initDoc+"?callback=repubsub.rcvNodeReady&domain="+document.domain); + } + + this.receiveEventFromTunnel = function(evt, srcWindow){ + // we should never be getting events from windows we didn't create + // NOTE: events sourced from the local window are also supported for + // debugging purposes + + // any event object MUST have a an "elements" property + if(!evt["elements"]){ + this.log("bailing! event received without elements!", "error"); + return; + } + + // if the event passes some minimal sanity tests, we need to attempt to + // dispatch it! + + // first, it seems we have to munge the event object a bit + var e = {}; + for(var i=0; i<evt.elements.length; i++){ + var ee = evt.elements[i]; + e[ee.name||ee.nameU] = (ee.value||ee.valueU); + // FIXME: need to enable this only in some extreme debugging mode! + this.log("[event]: "+(ee.name||ee.nameU)+": "+e[ee.name||ee.nameU]); + } + + // NOTE: the previous version of this library put a bunch of code here + // to manage state that tried to make sure that we never, ever, lost + // any info about an event. If we unload RIGHT HERE, I don't think it's + // going to make a huge difference one way or another. Time will tell. + + // and with THAT out of the way, dispatch it! + this.dispatch(e); + + // TODO: remove the script block that created the event obj to save + // memory, etc. + } + + this.widenDomain = function(domainStr){ + // the purpose of this is to set the most liberal domain policy + // available + var cd = domainStr||document.domain; + if(cd.indexOf(".")==-1){ return; } // probably file:/// or localhost + var dps = cd.split("."); + if(dps.length<=2){ return; } // probably file:/// or an RFC 1918 address + dps = dps.slice(dps.length-2); + document.domain = dps.join("."); + } + + // FIXME: parseCookie and setCookie should be methods that are more broadly + // available. Perhaps in htmlUtils? + + this.parseCookie = function(){ + var cs = document.cookie; + var keypairs = cs.split(";"); + for(var x=0; x<keypairs.length; x++){ + keypairs[x] = keypairs[x].split("="); + if(x!=keypairs.length-1){ cs+=";"; } + } + return keypairs; + } + + this.setCookie = function(keypairs, clobber){ + // NOTE: we want to only ever set session cookies, so never provide an + // expires date + if((clobber)&&(clobber==true)){ document.cookie = ""; } + var cs = ""; + for(var x=0; x<keypairs.length; x++){ + cs += keypairs[x][0]+"="+keypairs[x][1]; + if(x!=keypairs.length-1){ cs+=";"; } + } + document.cookie = cs; + } + + // FIXME: need to replace w/ dojo.log.* + this.log = function(str, lvl){ + if(!this.debug){ return; } // we of course only care if we're in debug mode + while(this.logBacklog.length>0){ + if(!this.canLog){ break; } + var blo = this.logBacklog.shift(); + this.writeLog("["+blo[0]+"]: "+blo[1], blo[2]); + } + this.writeLog(str, lvl); + } + + this.writeLog = function(str, lvl){ + dojo.debug(((new Date()).toLocaleTimeString())+": "+str); + } + + this.init = function(){ + this.widenDomain(); + // this.findPeers(); + this.openTunnel(); + this.isInitialized = true; + // FIXME: this seems like entirely the wrong place to replay the backlog + while(this.subscriptionBacklog.length){ + this.subscribe.apply(this, this.subscriptionBacklog.shift()); + } + } + + this.clobber = function(){ + if(this.rcvNode){ + this.setCookie( [ + [this.tunnelFrameKey,"closed"], + ["path","/"] + ], false + ); + } + } + + this.openTunnel = function(){ + // We create two iframes here: + + // one for getting data + this.rcvNodeName = "rcvIFrame_"+this.getRandStr(); + // set cookie that can be used to find the receiving iframe + this.setCookie( [ + [this.tunnelFrameKey,this.rcvNodeName], + ["path","/"] + ], false + ); + + this.rcvNode = dojo.io.createIFrame(this.rcvNodeName); + // FIXME: set the src attribute here to the initialization URL + dojo.io.setIFrameSrc(this.rcvNode, this.initDoc+"?callback=repubsub.rcvNodeReady&domain="+document.domain); + + // the other for posting data in reply + + this.sndNodeName = "sndIFrame_"+this.getRandStr(); + this.sndNode = dojo.io.createIFrame(this.sndNodeName); + // FIXME: set the src attribute here to the initialization URL + dojo.io.setIFrameSrc(this.sndNode, this.initDoc+"?callback=repubsub.sndNodeReady&domain="+document.domain); + + } + + this.rcvNodeReady = function(){ + // FIXME: why is this sequence number needed? Why isn't the UID gen + // function enough? + var statusURI = [this.tunnelURI, '/kn_status/', this.getRandStr(), '_', + String(this.tunnelInitCount++)].join(""); + // (kn._seqNum++); // FIXME: !!!! + // this.canRcv = true; + this.log("rcvNodeReady"); + // FIXME: initialize receiver and request the base topic + // dojo.io.setIFrameSrc(this.rcvNode, this.serverBaseURL+"/kn?do_method=blank"); + var initURIArr = [ this.serverBaseURL, "/kn?kn_from=", escape(this.tunnelURI), + "&kn_id=", escape(this.tunnelID), "&kn_status_from=", + escape(statusURI)]; + // FIXME: does the above really need a kn_response_flush? won't the + // server already know? If not, what good is it anyway? + dojo.io.setIFrameSrc(this.rcvNode, initURIArr.join("")); + + // setup a status path listener, but don't tell the server about it, + // since it already knows we're itnerested in our own tunnel status + this.subscribe(statusURI, this, "statusListener", true); + + this.log(initURIArr.join("")); + } + + this.sndNodeReady = function(){ + this.canSnd = true; + this.log("sndNodeReady"); + this.log(this.backlog.length); + // FIXME: handle any pent-up send commands + if(this.backlog.length > 0){ + this.dequeueEvent(); + } + } + + this.statusListener = function(evt){ + this.log("status listener called"); + this.log(evt.status, "info"); + } + + // this handles local event propigation + this.dispatch = function(evt){ + // figure out what topic it came from + if(evt["to"]||evt["kn_routed_from"]){ + var rf = evt["to"]||evt["kn_routed_from"]; + // split off the base server URL + var topic = rf.split(this.serverBaseURL, 2)[1]; + if(!topic){ + // FIXME: how do we recover when we don't get a sane "from"? Do + // we try to route to it anyway? + topic = rf; + } + this.log("[topic] "+topic); + if(topic.length>3){ + if(topic.slice(0, 3)=="/kn"){ + topic = topic.slice(3); + } + } + if(this.attachPathList[topic]){ + this.attachPathList[topic](evt); + } + } + } + + this.subscribe = function( topic /* kn_from in the old terminilogy */, + toObj, toFunc, dontTellServer){ + if(!this.isInitialized){ + this.subscriptionBacklog.push([topic, toObj, toFunc, dontTellServer]); + return; + } + if(!this.attachPathList[topic]){ + this.attachPathList[topic] = function(){ return true; } + this.log("subscribing to: "+topic); + this.topics.push(topic); + } + var revt = new dojo.io.repubsubEvent(this.tunnelURI, topic, "route"); + var rstr = [this.serverBaseURL+"/kn", revt.toGetString()].join(""); + dojo.event.kwConnect({ + once: true, + srcObj: this.attachPathList, + srcFunc: topic, + adviceObj: toObj, + adviceFunc: toFunc + }); + // NOTE: the above is a local mapping, if we're not the leader, we + // should connect our mapping to the topic handler of the peer + // leader, this ensures that not matter what happens to the + // leader, we don't really loose our heads if/when the leader + // goes away. + if(!this.rcvNode){ /* this should be an error! */ } + if(dontTellServer){ + return; + } + this.log("sending subscription to: "+topic); + // create a subscription event object and give it all the props we need + // to updates on the specified topic + + // FIXME: we should only enqueue if this is our first subscription! + this.sendTopicSubToServer(topic, rstr); + } + + this.sendTopicSubToServer = function(topic, str){ + if(!this.attachPathList[topic]["subscriptions"]){ + this.enqueueEventStr(str); + this.attachPathList[topic].subscriptions = 0; + } + this.attachPathList[topic].subscriptions++; + } + + this.unSubscribe = function(topic, toObj, toFunc){ + // first, locally disconnect + dojo.event.kwDisconnect({ + srcObj: this.attachPathList, + srcFunc: topic, + adviceObj: toObj, + adviceFunc: toFunc + }); + + // FIXME: figure out if there are any remaining listeners to the topic, + // and if not, inform the server of our desire not to be + // notified of updates to the topic + } + + // the "publish" method is really a misnomer, since it really means "take + // this event and send it to the server". Note that the "dispatch" method + // handles local event promigulation, and therefore we emulate both sides + // of a real event router without having to swallow all of the complexity. + this.publish = function(topic, event){ + var evt = dojo.io.repubsubEvent.initFromProperties(event); + // FIXME: need to make sure we have from and to set correctly + // before we serialize and send off to the great blue + // younder. + evt.to = topic; + // evt.from = this.tunnelURI; + + var evtURLParts = []; + evtURLParts.push(this.serverBaseURL+"/kn"); + + // serialize the event to a string and then post it to the correct + // topic + evtURLParts.push(evt.toGetString()); + this.enqueueEventStr(evtURLParts.join("")); + } + + this.enqueueEventStr = function(evtStr){ + this.log("enqueueEventStr"); + this.backlog.push(evtStr); + this.dequeueEvent(); + } + + this.dequeueEvent = function(force){ + this.log("dequeueEvent"); + if(this.backlog.length <= 0){ return; } + if((this.canSnd)||(force)){ + dojo.io.setIFrameSrc(this.sndNode, this.backlog.shift()+"&callback=repubsub.sndNodeReady"); + this.canSnd = false; + }else{ + this.log("sndNode not available yet!", "debug"); + } + } +} + +dojo.io.repubsubEvent = function(to, from, method, id, routeURI, payload, dispname, uid){ + this.to = to; + this.from = from; + this.method = method||"route"; + this.id = id||repubsub.getRandStr(); + this.uri = routeURI; + this.displayname = dispname||repubsub.displayname; + this.userid = uid||repubsub.userid; + this.payload = payload||""; + this.flushChars = 4096; + + this.initFromProperties = function(evt){ + if(evt.constructor = dojo.io.repubsubEvent){ + for(var x in evt){ + this[x] = evt[x]; + } + }else{ + // we want to copy all the properties of the evt object, and transform + // those that are "stock" properties of dojo.io.repubsubEvent. All others should + // be copied as-is + for(var x in evt){ + if(typeof this.forwardPropertiesMap[x] == "string"){ + this[this.forwardPropertiesMap[x]] = evt[x]; + }else{ + this[x] = evt[x]; + } + } + } + } + + this.toGetString = function(noQmark){ + var qs = [ ((noQmark) ? "" : "?") ]; + for(var x=0; x<this.properties.length; x++){ + var tp = this.properties[x]; + if(this[tp[0]]){ + qs.push(tp[1]+"="+encodeURIComponent(String(this[tp[0]]))); + } + // FIXME: we need to be able to serialize non-stock properties!!! + } + return qs.join("&"); + } + +} + +dojo.io.repubsubEvent.prototype.properties = [["from", "kn_from"], ["to", "kn_to"], + ["method", "do_method"], ["id", "kn_id"], + ["uri", "kn_uri"], + ["displayname", "kn_displayname"], + ["userid", "kn_userid"], + ["payload", "kn_payload"], + ["flushChars", "kn_response_flush"], + ["responseFormat", "kn_response_format"] ]; + +// maps properties from their old names to their new names... +dojo.io.repubsubEvent.prototype.forwardPropertiesMap = {}; +// ...and vice versa... +dojo.io.repubsubEvent.prototype.reversePropertiesMap = {}; + +// and we then populate them both from the properties list +for(var x=0; x<dojo.io.repubsubEvent.prototype.properties.length; x++){ + var tp = dojo.io.repubsubEvent.prototype.properties[x]; + dojo.io.repubsubEvent.prototype.reversePropertiesMap[tp[0]] = tp[1]; + dojo.io.repubsubEvent.prototype.forwardPropertiesMap[tp[1]] = tp[0]; +} +// static version of initFromProperties, creates new event and object and +// returns it after init +dojo.io.repubsubEvent.initFromProperties = function(evt){ + var eventObj = new dojo.io.repubsubEvent(); + eventObj.initFromProperties(evt); + return eventObj; +} Propchange: ofbiz/trunk/framework/images/webapp/images/dojo/src/io/RepubsubIO.js ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/framework/images/webapp/images/dojo/src/io/RepubsubIO.js ------------------------------------------------------------------------------ svn:keywords = "Date Rev Author URL Id" Propchange: ofbiz/trunk/framework/images/webapp/images/dojo/src/io/RepubsubIO.js ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: ofbiz/trunk/framework/images/webapp/images/dojo/src/io/RhinoIO.js URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/images/webapp/images/dojo/src/io/RhinoIO.js?view=auto&rev=509273 ============================================================================== --- ofbiz/trunk/framework/images/webapp/images/dojo/src/io/RhinoIO.js (added) +++ ofbiz/trunk/framework/images/webapp/images/dojo/src/io/RhinoIO.js Mon Feb 19 09:56:06 2007 @@ -0,0 +1,172 @@ +/* + Copyright (c) 2004-2006, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +dojo.provide("dojo.io.RhinoIO"); + +dojo.require("dojo.io.common"); +dojo.require("dojo.lang.func"); +dojo.require("dojo.lang.array"); +dojo.require("dojo.string.extras"); + +dojo.io.RhinoHTTPTransport = new function(){ + this.canHandle = function(/*dojo.io.Request*/req){ + //summary: Tells dojo.io.bind() if this is a good transport to + //use for the particular type of request. This type of transport can + //only be used inside the Rhino JavaScript engine. + + // We have to limit to text types because Rhino doesnt support + // a W3C dom implementation out of the box. In the future we + // should provide some kind of hook to inject your own, because + // in all my projects I use XML for Script to provide a W3C DOM. + if(dojo.lang.find(["text/plain", "text/html", "text/xml", "text/javascript", "text/json", "application/json"], + (req.mimetype.toLowerCase() || "")) < 0){ + return false; + } + + // We only handle http requests! Unfortunately, because the method is + // protected, I can't directly create a java.net.HttpURLConnection, so + // this is the only way to test. + if(req.url.substr(0, 7) != "http://"){ + return false; + } + + return true; + } + + function doLoad(req, conn){ + var ret; + if (req.method.toLowerCase() == "head"){ + // TODO: return the headers + }else{ + var stream = conn.getContent(); + var reader = new java.io.BufferedReader(new java.io.InputStreamReader(stream)); + + // read line-by-line because why not? + var text = ""; + var line = null; + while((line = reader.readLine()) != null){ + text += line; + } + + if(req.mimetype == "text/javascript"){ + try{ + ret = dj_eval(text); + }catch(e){ + dojo.debug(e); + dojo.debug(text); + ret = null; + } + }else if(req.mimetype == "text/json" || req.mimetype == "application/json"){ + try{ + ret = dj_eval("("+text+")"); + }catch(e){ + dojo.debug(e); + dojo.debug(text); + ret = false; + } + }else{ + ret = text; + } + } + + req.load("load", ret, req); + } + + function connect(req){ + var content = req.content || {}; + var query; + + if (req.sendTransport){ + content["dojo.transport"] = "rhinohttp"; + } + + if(req.postContent){ + query = req.postContent; + }else{ + query = dojo.io.argsFromMap(content, req.encoding); + } + + var url_text = req.url; + if(req.method.toLowerCase() == "get" && query != ""){ + url_text = url_text + "?" + query; + } + + var url = new java.net.URL(url_text); + var conn = url.openConnection(); + + // + // configure the connection + // + + conn.setRequestMethod(req.method.toUpperCase()); + + if(req.headers){ + for(var header in req.headers){ + if(header.toLowerCase() == "content-type" && !req.contentType){ + req.contentType = req.headers[header]; + }else{ + conn.setRequestProperty(header, req.headers[header]); + } + } + } + if(req.contentType){ + conn.setRequestProperty("Content-Type", req.contentType); + } + + if(req.method.toLowerCase() == "post"){ + conn.setDoOutput(true); + + // write the post data + var output_stream = conn.getOutputStream(); + var byte_array = (new java.lang.String(query)).getBytes(); + output_stream.write(byte_array, 0, byte_array.length); + } + + // do it to it! + conn.connect(); + + // perform the load + doLoad(req, conn); + } + + this.bind = function(req){ + //summary: function that sends the request to the server. + + //The following are acceptable properties in kwArgs (in addition to the + //normal dojo.io.Request object properties). + //url: String: URL the server URL to use for the request. + //method: String: the HTTP method to use (GET, POST, etc...). + //mimetype: Specifies what format the result data should be given to the load/handle callback. Values of + // text/javascript, text/json, and application/json will cause the transport + // to evaluate the response as JavaScript/JSON. Any other mimetype will give back a text + // string. + //transport: String: specify "RhinoHTTPTransport" to force the use of this transport. + //sync: boolean: if true, then a synchronous XMLHttpRequest call is done, + // if false (the default), then an asynchronous call is used. + //headers: Object: The object property names and values will be sent as HTTP request header + // names and values. + //encoding: String: The type of e |
Free forum by Nabble | Edit this page |