mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
New build scripts
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5282 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
680
source/web/scripts/ajax/dojo/src/io/BrowserIO.js
Normal file
680
source/web/scripts/ajax/dojo/src/io/BrowserIO.js
Normal file
@@ -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");
|
||||
}
|
||||
|
||||
}
|
298
source/web/scripts/ajax/dojo/src/io/IframeIO.js
Normal file
298
source/web/scripts/ajax/dojo/src/io/IframeIO.js
Normal file
@@ -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");
|
||||
}
|
520
source/web/scripts/ajax/dojo/src/io/RepubsubIO.js
Normal file
520
source/web/scripts/ajax/dojo/src/io/RepubsubIO.js
Normal file
@@ -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;
|
||||
}
|
172
source/web/scripts/ajax/dojo/src/io/RhinoIO.js
Normal file
172
source/web/scripts/ajax/dojo/src/io/RhinoIO.js
Normal file
@@ -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 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.
|
||||
//postContent: String: Raw name=value&name=value string to be included as part of the request.
|
||||
|
||||
var async = req["sync"] ? false : true;
|
||||
if (async){
|
||||
setTimeout(dojo.lang.hitch(this, function(){
|
||||
connect(req);
|
||||
}), 1);
|
||||
} else {
|
||||
connect(req);
|
||||
}
|
||||
}
|
||||
|
||||
dojo.io.transports.addTransport("RhinoHTTPTransport");
|
||||
}
|
469
source/web/scripts/ajax/dojo/src/io/ScriptSrcIO.js
Normal file
469
source/web/scripts/ajax/dojo/src/io/ScriptSrcIO.js
Normal file
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
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.ScriptSrcIO");
|
||||
dojo.require("dojo.io.BrowserIO");
|
||||
dojo.require("dojo.undo.browser");
|
||||
|
||||
//FIXME: should constantParams be JS object?
|
||||
//FIXME: check dojo.io calls. Can we move the BrowserIO defined calls somewhere
|
||||
// else so that we don't depend on BrowserIO at all? The dependent calls
|
||||
// have to do with dealing with forms and making query params from JS object.
|
||||
/**
|
||||
* See test_ScriptSrcIO.html for usage information.
|
||||
* Notes:
|
||||
* - The watchInFlight timer is set to 100 ms instead of 10ms (which is what BrowserIO.js uses).
|
||||
*/
|
||||
dojo.io.ScriptSrcTransport = new function(){
|
||||
this.preventCache = false; // if this is true, we'll always force GET requests to not cache
|
||||
this.maxUrlLength = 1000; //Used to calculate if script request should be multipart.
|
||||
this.inFlightTimer = null;
|
||||
|
||||
this.DsrStatusCodes = {
|
||||
Continue: 100,
|
||||
Ok: 200,
|
||||
Error: 500
|
||||
};
|
||||
|
||||
this.startWatchingInFlight = function(){
|
||||
//summary: Internal method to start the process of watching for in-flight requests.
|
||||
if(!this.inFlightTimer){
|
||||
this.inFlightTimer = setInterval("dojo.io.ScriptSrcTransport.watchInFlight();", 100);
|
||||
}
|
||||
}
|
||||
|
||||
this.watchInFlight = function(){
|
||||
//summary: Internal method to watch for in-flight requests.
|
||||
var totalCount = 0;
|
||||
var doneCount = 0;
|
||||
for(var param in this._state){
|
||||
totalCount++;
|
||||
var currentState = this._state[param];
|
||||
if(currentState.isDone){
|
||||
doneCount++;
|
||||
delete this._state[param];
|
||||
}else if(!currentState.isFinishing){
|
||||
var listener = currentState.kwArgs;
|
||||
try{
|
||||
if(currentState.checkString && eval("typeof(" + currentState.checkString + ") != 'undefined'")){
|
||||
currentState.isFinishing = true;
|
||||
this._finish(currentState, "load");
|
||||
doneCount++;
|
||||
delete this._state[param];
|
||||
}else if(listener.timeoutSeconds && listener.timeout){
|
||||
if(currentState.startTime + (listener.timeoutSeconds * 1000) < (new Date()).getTime()){
|
||||
currentState.isFinishing = true;
|
||||
this._finish(currentState, "timeout");
|
||||
doneCount++;
|
||||
delete this._state[param];
|
||||
}
|
||||
}else if(!listener.timeoutSeconds){
|
||||
//Increment the done count if no timeout is specified, so
|
||||
//that we turn off the timer if all that is left in the state
|
||||
//list are things we can't clean up because they fail without
|
||||
//getting a callback.
|
||||
doneCount++;
|
||||
}
|
||||
}catch(e){
|
||||
currentState.isFinishing = true;
|
||||
this._finish(currentState, "error", {status: this.DsrStatusCodes.Error, response: e});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(doneCount >= totalCount){
|
||||
clearInterval(this.inFlightTimer);
|
||||
this.inFlightTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
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 can only
|
||||
//handle responses that are JavaScript or JSON that is passed to a JavaScript
|
||||
//callback. It can only do asynchronous binds, is limited to GET HTTP method
|
||||
//requests, and cannot handle formNodes. However, it has the advantage of being
|
||||
//able to do cross-domain requests.
|
||||
|
||||
return dojo.lang.inArray(["text/javascript", "text/json", "application/json"], (kwArgs["mimetype"].toLowerCase()))
|
||||
&& (kwArgs["method"].toLowerCase() == "get")
|
||||
&& !(kwArgs["formNode"] && dojo.io.formHasFile(kwArgs["formNode"]))
|
||||
&& (!kwArgs["sync"] || kwArgs["sync"] == false)
|
||||
&& !kwArgs["file"]
|
||||
&& !kwArgs["multipart"];
|
||||
}
|
||||
|
||||
this.removeScripts = function(){
|
||||
//summary: Removes any script tags from the DOM that may have been added by ScriptSrcTransport.
|
||||
//description: Be careful though, by removing them from the script, you may invalidate some
|
||||
//script objects that were defined by the js file that was pulled in as the
|
||||
//src of the script tag. Test carefully if you decide to call this method.
|
||||
//In MSIE 6 (and probably 5.x), if you remove the script element while
|
||||
//part of the response script is still executing, the browser might crash.
|
||||
var scripts = document.getElementsByTagName("script");
|
||||
for(var i = 0; scripts && i < scripts.length; i++){
|
||||
var scriptTag = scripts[i];
|
||||
if(scriptTag.className == "ScriptSrcTransport"){
|
||||
var parent = scriptTag.parentNode;
|
||||
parent.removeChild(scriptTag);
|
||||
i--; //Set the index back one since we removed an item.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.bind = function(/*dojo.io.Request*/kwArgs){
|
||||
//summary: function that sends the request to the server.
|
||||
//description: See the Dojo Book page on this transport for a full
|
||||
//description of supported kwArgs properties and usage:
|
||||
//http://manual.dojotoolkit.org/WikiHome/DojoDotBook/Book25
|
||||
|
||||
//START duplication from BrowserIO.js (some changes made)
|
||||
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];
|
||||
}
|
||||
|
||||
//Break off the domain/path of the URL.
|
||||
var urlParts = url.split("?");
|
||||
if(urlParts && urlParts.length == 2){
|
||||
url = urlParts[0];
|
||||
query += (query ? "&" : "") + urlParts[1];
|
||||
}
|
||||
|
||||
if(kwArgs["backButton"] || kwArgs["back"] || kwArgs["changeUrl"]){
|
||||
dojo.undo.browser.addToHistory(kwArgs);
|
||||
}
|
||||
|
||||
//Create an ID for the request.
|
||||
var id = kwArgs["apiId"] ? kwArgs["apiId"] : "id" + this._counter++;
|
||||
|
||||
//Fill out any other content pieces.
|
||||
var content = kwArgs["content"];
|
||||
var jsonpName = kwArgs.jsonParamName;
|
||||
if(kwArgs.sendTransport || jsonpName) {
|
||||
if (!content){
|
||||
content = {};
|
||||
}
|
||||
if(kwArgs.sendTransport){
|
||||
content["dojo.transport"] = "scriptsrc";
|
||||
}
|
||||
|
||||
if(jsonpName){
|
||||
content[jsonpName] = "dojo.io.ScriptSrcTransport._state." + id + ".jsonpCall";
|
||||
}
|
||||
}
|
||||
|
||||
if(kwArgs.postContent){
|
||||
query = kwArgs.postContent;
|
||||
}else if(content){
|
||||
query += ((query) ? "&" : "") + dojo.io.argsFromMap(content, kwArgs.encoding, jsonpName);
|
||||
}
|
||||
//END duplication from BrowserIO.js
|
||||
|
||||
//START DSR
|
||||
|
||||
//If an apiId is specified, then we want to make sure useRequestId is true.
|
||||
if(kwArgs["apiId"]){
|
||||
kwArgs["useRequestId"] = true;
|
||||
}
|
||||
|
||||
//Set up the state for this request.
|
||||
var state = {
|
||||
"id": id,
|
||||
"idParam": "_dsrid=" + id,
|
||||
"url": url,
|
||||
"query": query,
|
||||
"kwArgs": kwArgs,
|
||||
"startTime": (new Date()).getTime(),
|
||||
"isFinishing": false
|
||||
};
|
||||
|
||||
if(!url){
|
||||
//Error. An URL is needed.
|
||||
this._finish(state, "error", {status: this.DsrStatusCodes.Error, statusText: "url.none"});
|
||||
return;
|
||||
}
|
||||
|
||||
//If this is a jsonp request, intercept the jsonp callback
|
||||
if(content && content[jsonpName]){
|
||||
state.jsonp = content[jsonpName];
|
||||
state.jsonpCall = function(data){
|
||||
if(data["Error"]||data["error"]){
|
||||
if(dojo["json"] && dojo["json"]["serialize"]){
|
||||
dojo.debug(dojo.json.serialize(data));
|
||||
}
|
||||
dojo.io.ScriptSrcTransport._finish(this, "error", data);
|
||||
}else{
|
||||
dojo.io.ScriptSrcTransport._finish(this, "load", data);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//Only store the request state on the state tracking object if a callback
|
||||
//is expected or if polling on a checkString will be done.
|
||||
if(kwArgs["useRequestId"] || kwArgs["checkString"] || state["jsonp"]){
|
||||
this._state[id] = state;
|
||||
}
|
||||
|
||||
//A checkstring is a string that if evaled will not be undefined once the
|
||||
//script src loads. Used as an alternative to depending on a callback from
|
||||
//the script file. If this is set, then multipart is not assumed to be used,
|
||||
//since multipart requires a specific callback. With checkString we will be doing
|
||||
//polling.
|
||||
if(kwArgs["checkString"]){
|
||||
state.checkString = kwArgs["checkString"];
|
||||
}
|
||||
|
||||
//Constant params are parameters that should always be sent with each
|
||||
//part of a multipart URL.
|
||||
state.constantParams = (kwArgs["constantParams"] == null ? "" : kwArgs["constantParams"]);
|
||||
|
||||
if(kwArgs["preventCache"] ||
|
||||
(this.preventCache == true && kwArgs["preventCache"] != false)){
|
||||
state.nocacheParam = "dojo.preventCache=" + new Date().valueOf();
|
||||
}else{
|
||||
state.nocacheParam = "";
|
||||
}
|
||||
|
||||
//Get total length URL, if we were to do it as one URL.
|
||||
//Add some padding, extra & separators.
|
||||
var urlLength = state.url.length + state.query.length + state.constantParams.length
|
||||
+ state.nocacheParam.length + this._extraPaddingLength;
|
||||
|
||||
if(kwArgs["useRequestId"]){
|
||||
urlLength += state.idParam.length;
|
||||
}
|
||||
|
||||
if(!kwArgs["checkString"] && kwArgs["useRequestId"]
|
||||
&& !state["jsonp"] && !kwArgs["forceSingleRequest"]
|
||||
&& urlLength > this.maxUrlLength){
|
||||
if(url > this.maxUrlLength){
|
||||
//Error. The URL domain and path are too long. We can't
|
||||
//segment that, so return an error.
|
||||
this._finish(state, "error", {status: this.DsrStatusCodes.Error, statusText: "url.tooBig"});
|
||||
return;
|
||||
}else{
|
||||
//Start the multiple requests.
|
||||
this._multiAttach(state, 1);
|
||||
}
|
||||
}else{
|
||||
//Send one URL.
|
||||
var queryParams = [state.constantParams, state.nocacheParam, state.query];
|
||||
if(kwArgs["useRequestId"] && !state["jsonp"]){
|
||||
queryParams.unshift(state.idParam);
|
||||
}
|
||||
var finalUrl = this._buildUrl(state.url, queryParams);
|
||||
|
||||
//Track the final URL in case we need to use that instead of api ID when receiving
|
||||
//the load callback.
|
||||
state.finalUrl = finalUrl;
|
||||
|
||||
this._attach(state.id, finalUrl);
|
||||
}
|
||||
//END DSR
|
||||
|
||||
this.startWatchingInFlight();
|
||||
}
|
||||
|
||||
//Private properties/methods
|
||||
this._counter = 1;
|
||||
this._state = {};
|
||||
this._extraPaddingLength = 16;
|
||||
|
||||
//Is there a dojo function for this already?
|
||||
this._buildUrl = function(url, nameValueArray){
|
||||
var finalUrl = url;
|
||||
var joiner = "?";
|
||||
for(var i = 0; i < nameValueArray.length; i++){
|
||||
if(nameValueArray[i]){
|
||||
finalUrl += joiner + nameValueArray[i];
|
||||
joiner = "&";
|
||||
}
|
||||
}
|
||||
|
||||
return finalUrl;
|
||||
}
|
||||
|
||||
this._attach = function(id, url){
|
||||
//Attach the script to the DOM.
|
||||
var element = document.createElement("script");
|
||||
element.type = "text/javascript";
|
||||
element.src = url;
|
||||
element.id = id;
|
||||
element.className = "ScriptSrcTransport";
|
||||
document.getElementsByTagName("head")[0].appendChild(element);
|
||||
}
|
||||
|
||||
this._multiAttach = function(state, part){
|
||||
//Check to make sure we still have a query to send up. This is mostly
|
||||
//a protection from a goof on the server side when it sends a part OK
|
||||
//response instead of a final response.
|
||||
if(state.query == null){
|
||||
this._finish(state, "error", {status: this.DsrStatusCodes.Error, statusText: "query.null"});
|
||||
return;
|
||||
}
|
||||
|
||||
if(!state.constantParams){
|
||||
state.constantParams = "";
|
||||
}
|
||||
|
||||
//How much of the query can we take?
|
||||
//Add a padding constant to account for _part and a couple extra amperstands.
|
||||
//Also add space for id since we'll need it now.
|
||||
var queryMax = this.maxUrlLength - state.idParam.length
|
||||
- state.constantParams.length - state.url.length
|
||||
- state.nocacheParam.length - this._extraPaddingLength;
|
||||
|
||||
//Figure out if this is the last part.
|
||||
var isDone = state.query.length < queryMax;
|
||||
|
||||
//Break up the query string if necessary.
|
||||
var currentQuery;
|
||||
if(isDone){
|
||||
currentQuery = state.query;
|
||||
state.query = null;
|
||||
}else{
|
||||
//Find the & or = nearest the max url length.
|
||||
var ampEnd = state.query.lastIndexOf("&", queryMax - 1);
|
||||
var eqEnd = state.query.lastIndexOf("=", queryMax - 1);
|
||||
|
||||
//See if & is closer, or if = is right at the edge,
|
||||
//which means we should put it on the next URL.
|
||||
if(ampEnd > eqEnd || eqEnd == queryMax - 1){
|
||||
//& is nearer the end. So just chop off from there.
|
||||
currentQuery = state.query.substring(0, ampEnd);
|
||||
state.query = state.query.substring(ampEnd + 1, state.query.length) //strip off amperstand with the + 1.
|
||||
}else{
|
||||
//= is nearer the end. Take the max amount possible.
|
||||
currentQuery = state.query.substring(0, queryMax);
|
||||
|
||||
//Find the last query name in the currentQuery so we can prepend it to
|
||||
//ampEnd. Could be -1 (not there), so account for that.
|
||||
var queryName = currentQuery.substring((ampEnd == -1 ? 0 : ampEnd + 1), eqEnd);
|
||||
state.query = queryName + "=" + state.query.substring(queryMax, state.query.length);
|
||||
}
|
||||
}
|
||||
|
||||
//Now send a part of the script
|
||||
var queryParams = [currentQuery, state.idParam, state.constantParams, state.nocacheParam];
|
||||
if(!isDone){
|
||||
queryParams.push("_part=" + part);
|
||||
}
|
||||
|
||||
var url = this._buildUrl(state.url, queryParams);
|
||||
|
||||
this._attach(state.id + "_" + part, url);
|
||||
}
|
||||
|
||||
this._finish = function(state, callback, event){
|
||||
if(callback != "partOk" && !state.kwArgs[callback] && !state.kwArgs["handle"]){
|
||||
//Ignore "partOk" because that is an internal callback.
|
||||
if(callback == "error"){
|
||||
state.isDone = true;
|
||||
throw event;
|
||||
}
|
||||
}else{
|
||||
switch(callback){
|
||||
case "load":
|
||||
var response = event ? event.response : null;
|
||||
if(!response){
|
||||
response = event;
|
||||
}
|
||||
state.kwArgs[(typeof state.kwArgs.load == "function") ? "load" : "handle"]("load", response, event, state.kwArgs);
|
||||
state.isDone = true;
|
||||
break;
|
||||
case "partOk":
|
||||
var part = parseInt(event.response.part, 10) + 1;
|
||||
//Update the constant params, if any.
|
||||
if(event.response.constantParams){
|
||||
state.constantParams = event.response.constantParams;
|
||||
}
|
||||
this._multiAttach(state, part);
|
||||
state.isDone = false;
|
||||
break;
|
||||
case "error":
|
||||
state.kwArgs[(typeof state.kwArgs.error == "function") ? "error" : "handle"]("error", event.response, event, state.kwArgs);
|
||||
state.isDone = true;
|
||||
break;
|
||||
default:
|
||||
state.kwArgs[(typeof state.kwArgs[callback] == "function") ? callback : "handle"](callback, event, event, state.kwArgs);
|
||||
state.isDone = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dojo.io.transports.addTransport("ScriptSrcTransport");
|
||||
}
|
||||
|
||||
//Define callback handler.
|
||||
window.onscriptload = function(event){
|
||||
var state = null;
|
||||
var transport = dojo.io.ScriptSrcTransport;
|
||||
|
||||
//Find the matching state object for event ID.
|
||||
if(transport._state[event.id]){
|
||||
state = transport._state[event.id];
|
||||
}else{
|
||||
//The ID did not match directly to an entry in the state list.
|
||||
//Try searching the state objects for a matching original URL.
|
||||
var tempState;
|
||||
for(var param in transport._state){
|
||||
tempState = transport._state[param];
|
||||
if(tempState.finalUrl && tempState.finalUrl == event.id){
|
||||
state = tempState;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//If no matching original URL is found, then use the URL that was actually used
|
||||
//in the SCRIPT SRC attribute.
|
||||
if(state == null){
|
||||
var scripts = document.getElementsByTagName("script");
|
||||
for(var i = 0; scripts && i < scripts.length; i++){
|
||||
var scriptTag = scripts[i];
|
||||
if(scriptTag.getAttribute("class") == "ScriptSrcTransport"
|
||||
&& scriptTag.src == event.id){
|
||||
state = transport._state[scriptTag.id];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//If state is still null, then throw an error.
|
||||
if(state == null){
|
||||
throw "No matching state for onscriptload event.id: " + event.id;
|
||||
}
|
||||
}
|
||||
|
||||
var callbackName = "error";
|
||||
switch(event.status){
|
||||
case dojo.io.ScriptSrcTransport.DsrStatusCodes.Continue:
|
||||
//A part of a multipart request.
|
||||
callbackName = "partOk";
|
||||
break;
|
||||
case dojo.io.ScriptSrcTransport.DsrStatusCodes.Ok:
|
||||
//Successful reponse.
|
||||
callbackName = "load";
|
||||
break;
|
||||
}
|
||||
|
||||
transport._finish(state, callbackName, event);
|
||||
};
|
239
source/web/scripts/ajax/dojo/src/io/XhrIframeProxy.js
Normal file
239
source/web/scripts/ajax/dojo/src/io/XhrIframeProxy.js
Normal file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
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.XhrIframeProxy");
|
||||
|
||||
dojo.require("dojo.experimental");
|
||||
dojo.experimental("dojo.io.XhrIframeProxy");
|
||||
|
||||
dojo.require("dojo.io.IframeIO");
|
||||
dojo.require("dojo.dom");
|
||||
dojo.require("dojo.uri.Uri");
|
||||
|
||||
dojo.io.XhrIframeProxy = {
|
||||
//summary: Object that implements the iframe handling for XMLHttpRequest
|
||||
//IFrame Proxying.
|
||||
//description: Do not use this object directly. See the Dojo Book page
|
||||
//on XMLHttpRequest IFrame Proxying:
|
||||
//http://manual.dojotoolkit.org/WikiHome/DojoDotBook/Book75
|
||||
//Usage of XHR IFrame Proxying does not work from local disk in Safari.
|
||||
|
||||
xipClientUrl: djConfig["xipClientUrl"] || dojo.uri.dojoUri("src/io/xip_client.html"),
|
||||
|
||||
_state: {},
|
||||
_stateIdCounter: 0,
|
||||
|
||||
needFrameRecursion: function(){
|
||||
return (true == dojo.render.html.ie70);
|
||||
},
|
||||
|
||||
send: function(facade){
|
||||
var stateId = "XhrIframeProxy" + (this._stateIdCounter++);
|
||||
facade._stateId = stateId;
|
||||
|
||||
|
||||
var frameUrl = this.xipClientUrl + "#0:init:id=" + stateId + "&server="
|
||||
+ encodeURIComponent(facade._ifpServerUrl) + "&fr=false";
|
||||
if(this.needFrameRecursion()){
|
||||
//IE7 hack. Need to load server URL, and have that load the xip_client.html.
|
||||
//Also, this server URL needs to different from the one eventually loaded by xip_client.html
|
||||
//Otherwise, IE7 will not load it. Funky.
|
||||
var fullClientUrl = window.location.href.substring(0, window.location.href.lastIndexOf("/") + 1);
|
||||
fullClientUrl += this.xipClientUrl;
|
||||
|
||||
var serverUrl = facade._ifpServerUrl
|
||||
+ (facade._ifpServerUrl.indexOf("?") == -1 ? "?" : "&") + "dojo.fr=1";
|
||||
|
||||
frameUrl = serverUrl + "#0:init:id=" + stateId + "&client="
|
||||
+ encodeURIComponent(fullClientUrl) + "&fr=" + this.needFrameRecursion(); //fr is for Frame Recursion
|
||||
}
|
||||
|
||||
this._state[stateId] = {
|
||||
facade: facade,
|
||||
stateId: stateId,
|
||||
clientFrame: dojo.io.createIFrame(stateId, "", frameUrl)
|
||||
};
|
||||
|
||||
return stateId;
|
||||
},
|
||||
|
||||
receive: function(/*String*/stateId, /*String*/urlEncodedData){
|
||||
/* urlEncodedData should have the following params:
|
||||
- responseHeaders
|
||||
- status
|
||||
- statusText
|
||||
- responseText
|
||||
*/
|
||||
//Decode response data.
|
||||
var response = {};
|
||||
var nvPairs = urlEncodedData.split("&");
|
||||
for(var i = 0; i < nvPairs.length; i++){
|
||||
if(nvPairs[i]){
|
||||
var nameValue = nvPairs[i].split("=");
|
||||
response[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]);
|
||||
}
|
||||
}
|
||||
|
||||
//Set data on facade object.
|
||||
var state = this._state[stateId];
|
||||
var facade = state.facade;
|
||||
|
||||
facade._setResponseHeaders(response.responseHeaders);
|
||||
if(response.status == 0 || response.status){
|
||||
facade.status = parseInt(response.status, 10);
|
||||
}
|
||||
if(response.statusText){
|
||||
facade.statusText = response.statusText;
|
||||
}
|
||||
if(response.responseText){
|
||||
facade.responseText = response.responseText;
|
||||
|
||||
//Fix responseXML.
|
||||
var contentType = facade.getResponseHeader("Content-Type");
|
||||
if(contentType && (contentType == "application/xml" || contentType == "text/xml")){
|
||||
facade.responseXML = dojo.dom.createDocumentFromText(response.responseText, contentType);
|
||||
}
|
||||
}
|
||||
facade.readyState = 4;
|
||||
|
||||
this.destroyState(stateId);
|
||||
},
|
||||
|
||||
clientFrameLoaded: function(/*String*/stateId){
|
||||
var state = this._state[stateId];
|
||||
var facade = state.facade;
|
||||
|
||||
if(this.needFrameRecursion()){
|
||||
var clientWindow = window.open("", state.stateId + "_clientEndPoint");
|
||||
}else{
|
||||
var clientWindow = state.clientFrame.contentWindow;
|
||||
}
|
||||
|
||||
var reqHeaders = [];
|
||||
for(var param in facade._requestHeaders){
|
||||
reqHeaders.push(param + ": " + facade._requestHeaders[param]);
|
||||
}
|
||||
|
||||
var requestData = {
|
||||
uri: facade._uri
|
||||
};
|
||||
if(reqHeaders.length > 0){
|
||||
requestData.requestHeaders = reqHeaders.join("\r\n");
|
||||
}
|
||||
if(facade._method){
|
||||
requestData.method = facade._method;
|
||||
}
|
||||
if(facade._bodyData){
|
||||
requestData.data = facade._bodyData;
|
||||
}
|
||||
|
||||
clientWindow.send(dojo.io.argsFromMap(requestData, "utf8"));
|
||||
},
|
||||
|
||||
destroyState: function(/*String*/stateId){
|
||||
var state = this._state[stateId];
|
||||
if(state){
|
||||
delete this._state[stateId];
|
||||
var parentNode = state.clientFrame.parentNode;
|
||||
parentNode.removeChild(state.clientFrame);
|
||||
state.clientFrame = null;
|
||||
state = null;
|
||||
}
|
||||
},
|
||||
|
||||
createFacade: function(){
|
||||
if(arguments && arguments[0] && arguments[0]["iframeProxyUrl"]){
|
||||
return new dojo.io.XhrIframeFacade(arguments[0]["iframeProxyUrl"]);
|
||||
}else{
|
||||
return dojo.io.XhrIframeProxy.oldGetXmlhttpObject.apply(dojo.hostenv, arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Replace the normal XHR factory with the proxy one.
|
||||
dojo.io.XhrIframeProxy.oldGetXmlhttpObject = dojo.hostenv.getXmlhttpObject;
|
||||
dojo.hostenv.getXmlhttpObject = dojo.io.XhrIframeProxy.createFacade;
|
||||
|
||||
/**
|
||||
Using this a reference: http://www.w3.org/TR/XMLHttpRequest/
|
||||
|
||||
Does not implement the onreadystate callback since dojo.io.BrowserIO does
|
||||
not use it.
|
||||
*/
|
||||
dojo.io.XhrIframeFacade = function(ifpServerUrl){
|
||||
//summary: XMLHttpRequest facade object used by dojo.io.XhrIframeProxy.
|
||||
|
||||
//description: Do not use this object directly. See the Dojo Book page
|
||||
//on XMLHttpRequest IFrame Proxying:
|
||||
//http://manual.dojotoolkit.org/WikiHome/DojoDotBook/Book75
|
||||
this._requestHeaders = {};
|
||||
this._allResponseHeaders = null;
|
||||
this._responseHeaders = {};
|
||||
this._method = null;
|
||||
this._uri = null;
|
||||
this._bodyData = null;
|
||||
this.responseText = null;
|
||||
this.responseXML = null;
|
||||
this.status = null;
|
||||
this.statusText = null;
|
||||
this.readyState = 0;
|
||||
|
||||
this._ifpServerUrl = ifpServerUrl;
|
||||
this._stateId = null;
|
||||
}
|
||||
|
||||
dojo.lang.extend(dojo.io.XhrIframeFacade, {
|
||||
//The open method does not properly reset since Dojo does not reuse XHR objects.
|
||||
open: function(/*String*/method, /*String*/uri){
|
||||
this._method = method;
|
||||
this._uri = uri;
|
||||
|
||||
this.readyState = 1;
|
||||
},
|
||||
|
||||
setRequestHeader: function(/*String*/header, /*String*/value){
|
||||
this._requestHeaders[header] = value;
|
||||
},
|
||||
|
||||
send: function(/*String*/stringData){
|
||||
this._bodyData = stringData;
|
||||
|
||||
this._stateId = dojo.io.XhrIframeProxy.send(this);
|
||||
|
||||
this.readyState = 2;
|
||||
},
|
||||
abort: function(){
|
||||
dojo.io.XhrIframeProxy.destroyState(this._stateId);
|
||||
},
|
||||
|
||||
getAllResponseHeaders: function(){
|
||||
return this._allResponseHeaders; //String
|
||||
},
|
||||
|
||||
getResponseHeader: function(/*String*/header){
|
||||
return this._responseHeaders[header]; //String
|
||||
},
|
||||
|
||||
_setResponseHeaders: function(/*String*/allHeaders){
|
||||
if(allHeaders){
|
||||
this._allResponseHeaders = allHeaders;
|
||||
|
||||
//Make sure ther are now CR characters in the headers.
|
||||
allHeaders = allHeaders.replace(/\r/g, "");
|
||||
var nvPairs = allHeaders.split("\n");
|
||||
for(var i = 0; i < nvPairs.length; i++){
|
||||
if(nvPairs[i]){
|
||||
var nameValue = nvPairs[i].split(": ");
|
||||
this._responseHeaders[nameValue[0]] = nameValue[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
17
source/web/scripts/ajax/dojo/src/io/__package__.js
Normal file
17
source/web/scripts/ajax/dojo/src/io/__package__.js
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
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.kwCompoundRequire({
|
||||
common: ["dojo.io.common"],
|
||||
rhino: ["dojo.io.RhinoIO"],
|
||||
browser: ["dojo.io.BrowserIO", "dojo.io.cookie"],
|
||||
dashboard: ["dojo.io.BrowserIO", "dojo.io.cookie"]
|
||||
});
|
||||
dojo.provide("dojo.io.*");
|
929
source/web/scripts/ajax/dojo/src/io/cometd.js
Normal file
929
source/web/scripts/ajax/dojo/src/io/cometd.js
Normal file
@@ -0,0 +1,929 @@
|
||||
/*
|
||||
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.require("dojo.io.common"); // io/common.js provides setIFrameSrc and the IO module
|
||||
dojo.provide("dojo.io.cometd");
|
||||
dojo.require("dojo.AdapterRegistry");
|
||||
dojo.require("dojo.json");
|
||||
dojo.require("dojo.io.BrowserIO"); // we need XHR for the handshake, etc.
|
||||
// FIXME: determine if we can use XMLHTTP to make x-domain posts despite not
|
||||
// being able to hear back about the result
|
||||
dojo.require("dojo.io.IframeIO");
|
||||
dojo.require("dojo.io.ScriptSrcIO"); // for x-domain long polling
|
||||
dojo.require("dojo.io.cookie"); // for peering
|
||||
dojo.require("dojo.event.*");
|
||||
dojo.require("dojo.lang.common");
|
||||
dojo.require("dojo.lang.func");
|
||||
|
||||
/*
|
||||
* this file defines Comet protocol client. Actual message transport is
|
||||
* deferred to one of several connection type implementations. The default is a
|
||||
* forever-frame implementation. A single global object named "cometd" is
|
||||
* used to mediate for these connection types in order to provide a stable
|
||||
* interface.
|
||||
*/
|
||||
|
||||
// TODO: the auth handling in this file is a *mess*. It should probably live in
|
||||
// the cometd object with the ability to mix in or call down to an auth-handler
|
||||
// object, the prototypical variant of which is a no-op
|
||||
|
||||
cometd = new function(){
|
||||
|
||||
this.initialized = false;
|
||||
this.connected = false;
|
||||
|
||||
this.connectionTypes = new dojo.AdapterRegistry(true);
|
||||
|
||||
this.version = 0.1;
|
||||
this.minimumVersion = 0.1;
|
||||
this.clientId = null;
|
||||
|
||||
this._isXD = false;
|
||||
this.handshakeReturn = null;
|
||||
this.currentTransport = null;
|
||||
this.url = null;
|
||||
this.lastMessage = null;
|
||||
this.globalTopicChannels = {};
|
||||
this.backlog = [];
|
||||
|
||||
this.tunnelInit = function(childLocation, childDomain){
|
||||
// placeholder
|
||||
}
|
||||
|
||||
this.tunnelCollapse = function(){
|
||||
dojo.debug("tunnel collapsed!");
|
||||
// placeholder
|
||||
}
|
||||
|
||||
this.init = function(props, root, bargs){
|
||||
// FIXME: if the root isn't from the same host, we should automatically
|
||||
// try to select an XD-capable transport
|
||||
props = props||{};
|
||||
// go ask the short bus server what we can support
|
||||
props.version = this.version;
|
||||
props.minimumVersion = this.minimumVersion;
|
||||
props.channel = "/meta/handshake";
|
||||
// FIXME: do we just assume that the props knows
|
||||
// everything we care about WRT to auth? Should we be trying to
|
||||
// call back into it for subsequent auth actions? Should we fire
|
||||
// local auth functions to ask for/get auth data?
|
||||
|
||||
// FIXME: what about ScriptSrcIO for x-domain comet?
|
||||
this.url = root||djConfig["cometdRoot"];
|
||||
if(!this.url){
|
||||
dojo.debug("no cometd root specified in djConfig and no root passed");
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: we need to select a way to handle JSONP-style stuff
|
||||
// generically here. We already know if the server is gonna be on
|
||||
// another domain (or can know it), so we should select appropriate
|
||||
// negotiation methods here as well as in final transport type
|
||||
// selection.
|
||||
var bindArgs = {
|
||||
url: this.url,
|
||||
method: "POST",
|
||||
mimetype: "text/json",
|
||||
load: dojo.lang.hitch(this, "finishInit"),
|
||||
content: { "message": dojo.json.serialize([props]) }
|
||||
};
|
||||
|
||||
// borrowed from dojo.uri.Uri in lieu of fixed host and port properties
|
||||
var regexp = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$";
|
||||
var r = (""+window.location).match(new RegExp(regexp));
|
||||
if(r[4]){
|
||||
var tmp = r[4].split(":");
|
||||
var thisHost = tmp[0];
|
||||
var thisPort = tmp[1]||"80"; // FIXME: match 443
|
||||
|
||||
r = this.url.match(new RegExp(regexp));
|
||||
if(r[4]){
|
||||
tmp = r[4].split(":");
|
||||
var urlHost = tmp[0];
|
||||
var urlPort = tmp[1]||"80";
|
||||
if( (urlHost != thisHost)||
|
||||
(urlPort != thisPort) ){
|
||||
dojo.debug(thisHost, urlHost);
|
||||
dojo.debug(thisPort, urlPort);
|
||||
|
||||
this._isXD = true;
|
||||
bindArgs.transport = "ScriptSrcTransport";
|
||||
bindArgs.jsonParamName = "jsonp";
|
||||
bindArgs.method = "GET";
|
||||
}
|
||||
}
|
||||
}
|
||||
if(bargs){
|
||||
dojo.lang.mixin(bindArgs, bargs);
|
||||
}
|
||||
return dojo.io.bind(bindArgs);
|
||||
}
|
||||
|
||||
this.finishInit = function(type, data, evt, request){
|
||||
data = data[0];
|
||||
this.handshakeReturn = data;
|
||||
// pick a transport
|
||||
if(data["authSuccessful"] == false){
|
||||
dojo.debug("cometd authentication failed");
|
||||
return;
|
||||
}
|
||||
if(data.version < this.minimumVersion){
|
||||
dojo.debug("cometd protocol version mismatch. We wanted", this.minimumVersion, "but got", data.version);
|
||||
return;
|
||||
}
|
||||
this.currentTransport = this.connectionTypes.match(
|
||||
data.supportedConnectionTypes,
|
||||
data.version,
|
||||
this._isXD
|
||||
);
|
||||
this.currentTransport.version = data.version;
|
||||
this.clientId = data.clientId;
|
||||
this.tunnelInit = dojo.lang.hitch(this.currentTransport, "tunnelInit");
|
||||
this.tunnelCollapse = dojo.lang.hitch(this.currentTransport, "tunnelCollapse");
|
||||
this.initialized = true;
|
||||
this.currentTransport.startup(data);
|
||||
while(this.backlog.length != 0){
|
||||
var cur = this.backlog.shift();
|
||||
var fn = cur.shift();
|
||||
this[fn].apply(this, cur);
|
||||
}
|
||||
}
|
||||
|
||||
this._getRandStr = function(){
|
||||
return Math.random().toString().substring(2, 10);
|
||||
}
|
||||
|
||||
// public API functions called by cometd or by the transport classes
|
||||
this.deliver = function(messages){
|
||||
dojo.lang.forEach(messages, this._deliver, this);
|
||||
}
|
||||
|
||||
this._deliver = function(message){
|
||||
// dipatch events along the specified path
|
||||
if(!message["channel"]){
|
||||
dojo.debug("cometd error: no channel for message!");
|
||||
return;
|
||||
}
|
||||
if(!this.currentTransport){
|
||||
this.backlog.push(["deliver", message]);
|
||||
return;
|
||||
}
|
||||
this.lastMessage = message;
|
||||
// check to see if we got a /meta channel message that we care about
|
||||
if( (message.channel.length > 5)&&
|
||||
(message.channel.substr(0, 5) == "/meta")){
|
||||
// check for various meta topic actions that we need to respond to
|
||||
switch(message.channel){
|
||||
case "/meta/subscribe":
|
||||
if(!message.successful){
|
||||
dojo.debug("cometd subscription error for channel", message.channel, ":", message.error);
|
||||
return;
|
||||
}
|
||||
this.subscribed(message.subscription, message);
|
||||
break;
|
||||
case "/meta/unsubscribe":
|
||||
if(!message.successful){
|
||||
dojo.debug("cometd unsubscription error for channel", message.channel, ":", message.error);
|
||||
return;
|
||||
}
|
||||
this.unsubscribed(message.subscription, message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// send the message down for processing by the transport
|
||||
this.currentTransport.deliver(message);
|
||||
|
||||
// dispatch the message to any locally subscribed listeners
|
||||
var tname = (this.globalTopicChannels[message.channel]) ? message.channel : "/cometd"+message.channel;
|
||||
dojo.event.topic.publish(tname, message);
|
||||
}
|
||||
|
||||
this.disconnect = function(){
|
||||
if(!this.currentTransport){
|
||||
dojo.debug("no current transport to disconnect from");
|
||||
return;
|
||||
}
|
||||
this.currentTransport.disconnect();
|
||||
}
|
||||
|
||||
// public API functions called by end users
|
||||
this.publish = function(/*string*/channel, /*object*/data, /*object*/properties){
|
||||
// summary:
|
||||
// publishes the passed message to the cometd server for delivery
|
||||
// on the specified topic
|
||||
// channel:
|
||||
// the destination channel for the message
|
||||
// data:
|
||||
// a JSON object containing the message "payload"
|
||||
// properties:
|
||||
// Optional. Other meta-data to be mixed into the top-level of the
|
||||
// message
|
||||
if(!this.currentTransport){
|
||||
this.backlog.push(["publish", channel, data, properties]);
|
||||
return;
|
||||
}
|
||||
var message = {
|
||||
data: data,
|
||||
channel: channel
|
||||
};
|
||||
if(properties){
|
||||
dojo.lang.mixin(message, properties);
|
||||
}
|
||||
return this.currentTransport.sendMessage(message);
|
||||
}
|
||||
|
||||
this.subscribe = function( /*string*/ channel,
|
||||
/*boolean, optional*/ useLocalTopics,
|
||||
/*object, optional*/ objOrFunc,
|
||||
/*string, optional*/ funcName){ // return: boolean
|
||||
// summary:
|
||||
// inform the server of this client's interest in channel
|
||||
// channel:
|
||||
// name of the cometd channel to subscribe to
|
||||
// useLocalTopics:
|
||||
// Determines if up a local event topic subscription to the passed
|
||||
// function using the channel name that was passed is constructed,
|
||||
// or if the topic name will be prefixed with some other
|
||||
// identifier for local message distribution. Setting this to
|
||||
// "true" is a good way to hook up server-sent message delivery to
|
||||
// pre-existing local topics.
|
||||
// objOrFunc:
|
||||
// an object scope for funcName or the name or reference to a
|
||||
// function to be called when messages are delivered to the
|
||||
// channel
|
||||
// funcName:
|
||||
// the second half of the objOrFunc/funcName pair for identifying
|
||||
// a callback function to notifiy upon channel message delivery
|
||||
if(!this.currentTransport){
|
||||
this.backlog.push(["subscribe", channel, useLocalTopics, objOrFunc, funcName]);
|
||||
return;
|
||||
}
|
||||
if(objOrFunc){
|
||||
var tname = (useLocalTopics) ? channel : "/cometd"+channel;
|
||||
if(useLocalTopics){
|
||||
this.globalTopicChannels[channel] = true;
|
||||
}
|
||||
dojo.event.topic.subscribe(tname, objOrFunc, funcName);
|
||||
}
|
||||
// FIXME: would we handle queuing of the subscription if not connected?
|
||||
// Or should the transport object?
|
||||
return this.currentTransport.sendMessage({
|
||||
channel: "/meta/subscribe",
|
||||
subscription: channel
|
||||
});
|
||||
}
|
||||
|
||||
this.subscribed = function( /*string*/ channel,
|
||||
/*obj*/ message){
|
||||
dojo.debug(channel);
|
||||
dojo.debugShallow(message);
|
||||
}
|
||||
|
||||
this.unsubscribe = function(/*string*/ channel,
|
||||
/*boolean, optional*/ useLocalTopics,
|
||||
/*object, optional*/ objOrFunc,
|
||||
/*string, optional*/ funcName){ // return: boolean
|
||||
// summary:
|
||||
// inform the server of this client's disinterest in channel
|
||||
// channel:
|
||||
// name of the cometd channel to subscribe to
|
||||
// useLocalTopics:
|
||||
// Determines if up a local event topic subscription to the passed
|
||||
// function using the channel name that was passed is destroyed,
|
||||
// or if the topic name will be prefixed with some other
|
||||
// identifier for stopping message distribution.
|
||||
// objOrFunc:
|
||||
// an object scope for funcName or the name or reference to a
|
||||
// function to be called when messages are delivered to the
|
||||
// channel
|
||||
// funcName:
|
||||
// the second half of the objOrFunc/funcName pair for identifying
|
||||
if(!this.currentTransport){
|
||||
this.backlog.push(["unsubscribe", channel, useLocalTopics, objOrFunc, funcName]);
|
||||
return;
|
||||
}
|
||||
// a callback function to notifiy upon channel message delivery
|
||||
if(objOrFunc){
|
||||
// FIXME: should actual local topic unsubscription be delayed for
|
||||
// successful unsubcribe notices from the other end? (guessing "no")
|
||||
// FIXME: if useLocalTopics is false, should we go ahead and
|
||||
// destroy the local topic?
|
||||
var tname = (useLocalTopics) ? channel : "/cometd"+channel;
|
||||
dojo.event.topic.unsubscribe(tname, objOrFunc, funcName);
|
||||
}
|
||||
return this.currentTransport.sendMessage({
|
||||
channel: "/meta/unsubscribe",
|
||||
subscription: channel
|
||||
});
|
||||
}
|
||||
|
||||
this.unsubscribed = function(/*string*/ channel,
|
||||
/*obj*/ message){
|
||||
dojo.debug(channel);
|
||||
dojo.debugShallow(message);
|
||||
}
|
||||
|
||||
// FIXME: add an "addPublisher" function
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
transport objects MUST expose the following methods:
|
||||
- check
|
||||
- startup
|
||||
- sendMessage
|
||||
- deliver
|
||||
- disconnect
|
||||
optional, standard but transport dependent methods are:
|
||||
- tunnelCollapse
|
||||
- tunnelInit
|
||||
|
||||
Transports SHOULD be namespaced under the cometd object and transports MUST
|
||||
register themselves with cometd.connectionTypes
|
||||
|
||||
here's a stub transport defintion:
|
||||
|
||||
cometd.blahTransport = new function(){
|
||||
this.connected = false;
|
||||
this.connectionId = null;
|
||||
this.authToken = null;
|
||||
this.lastTimestamp = null;
|
||||
this.lastId = null;
|
||||
|
||||
this.check = function(types, version, xdomain){
|
||||
// summary:
|
||||
// determines whether or not this transport is suitable given a
|
||||
// list of transport types that the server supports
|
||||
return dojo.lang.inArray(types, "blah");
|
||||
}
|
||||
|
||||
this.startup = function(){
|
||||
if(this.connected){ return; }
|
||||
// FIXME: fill in startup routine here
|
||||
this.connected = true;
|
||||
}
|
||||
|
||||
this.sendMessage = function(message){
|
||||
// FIXME: fill in message sending logic
|
||||
}
|
||||
|
||||
this.deliver = function(message){
|
||||
if(message["timestamp"]){
|
||||
this.lastTimestamp = message.timestamp;
|
||||
}
|
||||
if(message["id"]){
|
||||
this.lastId = message.id;
|
||||
}
|
||||
if( (message.channel.length > 5)&&
|
||||
(message.channel.substr(0, 5) == "/meta")){
|
||||
// check for various meta topic actions that we need to respond to
|
||||
// switch(message.channel){
|
||||
// case "/meta/connect":
|
||||
// // FIXME: fill in logic here
|
||||
// break;
|
||||
// // case ...: ...
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
this.disconnect = function(){
|
||||
if(!this.connected){ return; }
|
||||
// FIXME: fill in shutdown routine here
|
||||
this.connected = false;
|
||||
}
|
||||
}
|
||||
cometd.connectionTypes.register("blah", cometd.blahTransport.check, cometd.blahTransport);
|
||||
*/
|
||||
|
||||
cometd.iframeTransport = new function(){
|
||||
this.connected = false;
|
||||
this.connectionId = null;
|
||||
|
||||
this.rcvNode = null;
|
||||
this.rcvNodeName = "";
|
||||
this.phonyForm = null;
|
||||
this.authToken = null;
|
||||
this.lastTimestamp = null;
|
||||
this.lastId = null;
|
||||
this.backlog = [];
|
||||
|
||||
this.check = function(types, version, xdomain){
|
||||
return ((!xdomain)&&
|
||||
(!dojo.render.html.safari)&&
|
||||
(dojo.lang.inArray(types, "iframe")));
|
||||
}
|
||||
|
||||
this.tunnelInit = function(){
|
||||
// we've gotten our initialization document back in the iframe, so
|
||||
// now open up a connection and start passing data!
|
||||
this.postToIframe({
|
||||
message: dojo.json.serialize([
|
||||
{
|
||||
channel: "/meta/connect",
|
||||
clientId: cometd.clientId,
|
||||
connectionType: "iframe"
|
||||
// FIXME: auth not passed here!
|
||||
// "authToken": this.authToken
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
|
||||
this.tunnelCollapse = function(){
|
||||
if(this.connected){
|
||||
// try to restart the tunnel
|
||||
this.connected = false;
|
||||
|
||||
this.postToIframe({
|
||||
message: dojo.json.serialize([
|
||||
{
|
||||
channel: "/meta/reconnect",
|
||||
clientId: cometd.clientId,
|
||||
connectionId: this.connectionId,
|
||||
timestamp: this.lastTimestamp,
|
||||
id: this.lastId
|
||||
// FIXME: no authToken provision!
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.deliver = function(message){
|
||||
// handle delivery details that this transport particularly cares
|
||||
// about. Most functions of should be handled by the main cometd object
|
||||
// with only transport-specific details and state being tracked here.
|
||||
if(message["timestamp"]){
|
||||
this.lastTimestamp = message.timestamp;
|
||||
}
|
||||
if(message["id"]){
|
||||
this.lastId = message.id;
|
||||
}
|
||||
// check to see if we got a /meta channel message that we care about
|
||||
if( (message.channel.length > 5)&&
|
||||
(message.channel.substr(0, 5) == "/meta")){
|
||||
// check for various meta topic actions that we need to respond to
|
||||
switch(message.channel){
|
||||
case "/meta/connect":
|
||||
if(!message.successful){
|
||||
dojo.debug("cometd connection error:", message.error);
|
||||
return;
|
||||
}
|
||||
this.connectionId = message.connectionId;
|
||||
this.connected = true;
|
||||
this.processBacklog();
|
||||
break;
|
||||
case "/meta/reconnect":
|
||||
if(!message.successful){
|
||||
dojo.debug("cometd reconnection error:", message.error);
|
||||
return;
|
||||
}
|
||||
this.connected = true;
|
||||
break;
|
||||
case "/meta/subscribe":
|
||||
if(!message.successful){
|
||||
dojo.debug("cometd subscription error for channel", message.channel, ":", message.error);
|
||||
return;
|
||||
}
|
||||
// this.subscribed(message.channel);
|
||||
dojo.debug(message.channel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.widenDomain = function(domainStr){
|
||||
// allow us to make reqests to the TLD
|
||||
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(".");
|
||||
return document.domain;
|
||||
}
|
||||
|
||||
this.postToIframe = function(content, url){
|
||||
if(!this.phonyForm){
|
||||
if(dojo.render.html.ie){
|
||||
this.phonyForm = document.createElement("<form enctype='application/x-www-form-urlencoded' method='POST' style='display: none;'>");
|
||||
dojo.body().appendChild(this.phonyForm);
|
||||
}else{
|
||||
this.phonyForm = document.createElement("form");
|
||||
this.phonyForm.style.display = "none"; // FIXME: will this still work?
|
||||
dojo.body().appendChild(this.phonyForm);
|
||||
this.phonyForm.enctype = "application/x-www-form-urlencoded";
|
||||
this.phonyForm.method = "POST";
|
||||
}
|
||||
}
|
||||
|
||||
this.phonyForm.action = url||cometd.url;
|
||||
this.phonyForm.target = this.rcvNodeName;
|
||||
this.phonyForm.setAttribute("target", this.rcvNodeName);
|
||||
|
||||
while(this.phonyForm.firstChild){
|
||||
this.phonyForm.removeChild(this.phonyForm.firstChild);
|
||||
}
|
||||
|
||||
for(var x in content){
|
||||
var tn;
|
||||
if(dojo.render.html.ie){
|
||||
tn = document.createElement("<input type='hidden' name='"+x+"' value='"+content[x]+"'>");
|
||||
this.phonyForm.appendChild(tn);
|
||||
}else{
|
||||
tn = document.createElement("input");
|
||||
this.phonyForm.appendChild(tn);
|
||||
tn.type = "hidden";
|
||||
tn.name = x;
|
||||
tn.value = content[x];
|
||||
}
|
||||
}
|
||||
this.phonyForm.submit();
|
||||
}
|
||||
|
||||
this.processBacklog = function(){
|
||||
while(this.backlog.length > 0){
|
||||
this.sendMessage(this.backlog.shift(), true);
|
||||
}
|
||||
}
|
||||
|
||||
this.sendMessage = function(message, bypassBacklog){
|
||||
// FIXME: what about auth fields?
|
||||
if((bypassBacklog)||(this.connected)){
|
||||
message.connectionId = this.connectionId;
|
||||
message.clientId = cometd.clientId;
|
||||
var bindArgs = {
|
||||
url: cometd.url||djConfig["cometdRoot"],
|
||||
method: "POST",
|
||||
mimetype: "text/json",
|
||||
// FIXME: we should be able to do better than this given that we're sending an array!
|
||||
content: { message: dojo.json.serialize([ message ]) }
|
||||
};
|
||||
return dojo.io.bind(bindArgs);
|
||||
}else{
|
||||
this.backlog.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
this.startup = function(handshakeData){
|
||||
dojo.debug("startup!");
|
||||
dojo.debug(dojo.json.serialize(handshakeData));
|
||||
|
||||
if(this.connected){ return; }
|
||||
|
||||
// this.widenDomain();
|
||||
|
||||
// NOTE: we require the server to cooperate by hosting
|
||||
// cometdInit.html at the designated endpoint
|
||||
this.rcvNodeName = "cometdRcv_"+cometd._getRandStr();
|
||||
// the "forever frame" approach
|
||||
|
||||
var initUrl = cometd.url+"/?tunnelInit=iframe"; // &domain="+document.domain;
|
||||
if(false && dojo.render.html.ie){ // FIXME: DISALBED FOR NOW
|
||||
// use the "htmlfile hack" to prevent the background click junk
|
||||
this.rcvNode = new ActiveXObject("htmlfile");
|
||||
this.rcvNode.open();
|
||||
this.rcvNode.write("<html>");
|
||||
this.rcvNode.write("<script>document.domain = '"+document.domain+"'");
|
||||
this.rcvNode.write("</html>");
|
||||
this.rcvNode.close();
|
||||
|
||||
var ifrDiv = this.rcvNode.createElement("div");
|
||||
this.rcvNode.appendChild(ifrDiv);
|
||||
this.rcvNode.parentWindow.dojo = dojo;
|
||||
ifrDiv.innerHTML = "<iframe src='"+initUrl+"'></iframe>"
|
||||
}else{
|
||||
this.rcvNode = dojo.io.createIFrame(this.rcvNodeName, "", initUrl);
|
||||
// dojo.io.setIFrameSrc(this.rcvNode, initUrl);
|
||||
// we're still waiting on the iframe to call back up to use and
|
||||
// advertise that it's been initialized via tunnelInit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cometd.mimeReplaceTransport = new function(){
|
||||
this.connected = false;
|
||||
this.connectionId = null;
|
||||
this.xhr = null;
|
||||
|
||||
this.authToken = null;
|
||||
this.lastTimestamp = null;
|
||||
this.lastId = null;
|
||||
this.backlog = [];
|
||||
|
||||
this.check = function(types, version, xdomain){
|
||||
return ((!xdomain)&&
|
||||
(dojo.render.html.mozilla)&& // seems only Moz really supports this right now = (
|
||||
(dojo.lang.inArray(types, "mime-message-block")));
|
||||
}
|
||||
|
||||
this.tunnelInit = function(){
|
||||
if(this.connected){ return; }
|
||||
// FIXME: open up the connection here
|
||||
this.openTunnelWith({
|
||||
message: dojo.json.serialize([
|
||||
{
|
||||
channel: "/meta/connect",
|
||||
clientId: cometd.clientId,
|
||||
connectionType: "mime-message-block"
|
||||
// FIXME: auth not passed here!
|
||||
// "authToken": this.authToken
|
||||
}
|
||||
])
|
||||
});
|
||||
this.connected = true;
|
||||
}
|
||||
|
||||
this.tunnelCollapse = function(){
|
||||
if(this.connected){
|
||||
// try to restart the tunnel
|
||||
this.connected = false;
|
||||
this.openTunnelWith({
|
||||
message: dojo.json.serialize([
|
||||
{
|
||||
channel: "/meta/reconnect",
|
||||
clientId: cometd.clientId,
|
||||
connectionId: this.connectionId,
|
||||
timestamp: this.lastTimestamp,
|
||||
id: this.lastId
|
||||
// FIXME: no authToken provision!
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.deliver = cometd.iframeTransport.deliver;
|
||||
// the logic appears to be the same
|
||||
|
||||
this.handleOnLoad = function(resp){
|
||||
cometd.deliver(dojo.json.evalJson(this.xhr.responseText));
|
||||
}
|
||||
|
||||
this.openTunnelWith = function(content, url){
|
||||
// set up the XHR object and register the multipart callbacks
|
||||
this.xhr = dojo.hostenv.getXmlhttpObject();
|
||||
this.xhr.multipart = true; // FIXME: do Opera and Safari support this flag?
|
||||
if(dojo.render.html.mozilla){
|
||||
this.xhr.addEventListener("load", dojo.lang.hitch(this, "handleOnLoad"), false);
|
||||
}else if(dojo.render.html.safari){
|
||||
// Blah. WebKit doesn't actually populate responseText and/or responseXML. Useless.
|
||||
dojo.debug("Webkit is broken with multipart responses over XHR = (");
|
||||
this.xhr.onreadystatechange = dojo.lang.hitch(this, "handleOnLoad");
|
||||
}else{
|
||||
this.xhr.onload = dojo.lang.hitch(this, "handleOnLoad");
|
||||
}
|
||||
this.xhr.open("POST", (url||cometd.url), true); // async post
|
||||
this.xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
dojo.debug(dojo.json.serialize(content));
|
||||
this.xhr.send(dojo.io.argsFromMap(content, "utf8"));
|
||||
}
|
||||
|
||||
this.processBacklog = function(){
|
||||
while(this.backlog.length > 0){
|
||||
this.sendMessage(this.backlog.shift(), true);
|
||||
}
|
||||
}
|
||||
|
||||
this.sendMessage = function(message, bypassBacklog){
|
||||
// FIXME: what about auth fields?
|
||||
if((bypassBacklog)||(this.connected)){
|
||||
message.connectionId = this.connectionId;
|
||||
message.clientId = cometd.clientId;
|
||||
var bindArgs = {
|
||||
url: cometd.url||djConfig["cometdRoot"],
|
||||
method: "POST",
|
||||
mimetype: "text/json",
|
||||
content: { message: dojo.json.serialize([ message ]) }
|
||||
};
|
||||
return dojo.io.bind(bindArgs);
|
||||
}else{
|
||||
this.backlog.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
this.startup = function(handshakeData){
|
||||
dojo.debugShallow(handshakeData);
|
||||
if(this.connected){ return; }
|
||||
this.tunnelInit();
|
||||
}
|
||||
}
|
||||
|
||||
cometd.longPollTransport = new function(){
|
||||
this.connected = false;
|
||||
this.connectionId = null;
|
||||
|
||||
this.authToken = null;
|
||||
this.lastTimestamp = null;
|
||||
this.lastId = null;
|
||||
this.backlog = [];
|
||||
|
||||
this.check = function(types, version, xdomain){
|
||||
return ((!xdomain)&&(dojo.lang.inArray(types, "long-polling")));
|
||||
}
|
||||
|
||||
this.tunnelInit = function(){
|
||||
if(this.connected){ return; }
|
||||
// FIXME: open up the connection here
|
||||
this.openTunnelWith({
|
||||
message: dojo.json.serialize([
|
||||
{
|
||||
channel: "/meta/connect",
|
||||
clientId: cometd.clientId,
|
||||
connectionType: "long-polling"
|
||||
// FIXME: auth not passed here!
|
||||
// "authToken": this.authToken
|
||||
}
|
||||
])
|
||||
});
|
||||
this.connected = true;
|
||||
}
|
||||
|
||||
this.tunnelCollapse = function(){
|
||||
if(!this.connected){
|
||||
// try to restart the tunnel
|
||||
this.connected = false;
|
||||
dojo.debug("clientId:", cometd.clientId);
|
||||
this.openTunnelWith({
|
||||
message: dojo.json.serialize([
|
||||
{
|
||||
channel: "/meta/reconnect",
|
||||
connectionType: "long-polling",
|
||||
clientId: cometd.clientId,
|
||||
connectionId: this.connectionId,
|
||||
timestamp: this.lastTimestamp,
|
||||
id: this.lastId
|
||||
// FIXME: no authToken provision!
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.deliver = cometd.iframeTransport.deliver;
|
||||
// the logic appears to be the same
|
||||
|
||||
this.openTunnelWith = function(content, url){
|
||||
dojo.io.bind({
|
||||
url: (url||cometd.url),
|
||||
method: "post",
|
||||
content: content,
|
||||
mimetype: "text/json",
|
||||
load: dojo.lang.hitch(this, function(type, data, evt, args){
|
||||
// dojo.debug(evt.responseText);
|
||||
cometd.deliver(data);
|
||||
this.connected = false;
|
||||
this.tunnelCollapse();
|
||||
}),
|
||||
error: function(){ dojo.debug("tunnel opening failed"); }
|
||||
});
|
||||
this.connected = true;
|
||||
}
|
||||
|
||||
this.processBacklog = function(){
|
||||
while(this.backlog.length > 0){
|
||||
this.sendMessage(this.backlog.shift(), true);
|
||||
}
|
||||
}
|
||||
|
||||
this.sendMessage = function(message, bypassBacklog){
|
||||
// FIXME: what about auth fields?
|
||||
if((bypassBacklog)||(this.connected)){
|
||||
message.connectionId = this.connectionId;
|
||||
message.clientId = cometd.clientId;
|
||||
var bindArgs = {
|
||||
url: cometd.url||djConfig["cometdRoot"],
|
||||
method: "post",
|
||||
mimetype: "text/json",
|
||||
content: { message: dojo.json.serialize([ message ]) }
|
||||
};
|
||||
return dojo.io.bind(bindArgs);
|
||||
}else{
|
||||
this.backlog.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
this.startup = function(handshakeData){
|
||||
if(this.connected){ return; }
|
||||
this.tunnelInit();
|
||||
}
|
||||
}
|
||||
|
||||
cometd.callbackPollTransport = new function(){
|
||||
this.connected = false;
|
||||
this.connectionId = null;
|
||||
|
||||
this.authToken = null;
|
||||
this.lastTimestamp = null;
|
||||
this.lastId = null;
|
||||
this.backlog = [];
|
||||
|
||||
this.check = function(types, version, xdomain){
|
||||
// we handle x-domain!
|
||||
return dojo.lang.inArray(types, "callback-polling");
|
||||
}
|
||||
|
||||
this.tunnelInit = function(){
|
||||
if(this.connected){ return; }
|
||||
// FIXME: open up the connection here
|
||||
this.openTunnelWith({
|
||||
message: dojo.json.serialize([
|
||||
{
|
||||
channel: "/meta/connect",
|
||||
clientId: cometd.clientId,
|
||||
connectionType: "callback-polling"
|
||||
// FIXME: auth not passed here!
|
||||
// "authToken": this.authToken
|
||||
}
|
||||
])
|
||||
});
|
||||
this.connected = true;
|
||||
}
|
||||
|
||||
this.tunnelCollapse = function(){
|
||||
if(!this.connected){
|
||||
// try to restart the tunnel
|
||||
this.connected = false;
|
||||
this.openTunnelWith({
|
||||
message: dojo.json.serialize([
|
||||
{
|
||||
channel: "/meta/reconnect",
|
||||
connectionType: "long-polling",
|
||||
clientId: cometd.clientId,
|
||||
connectionId: this.connectionId,
|
||||
timestamp: this.lastTimestamp,
|
||||
id: this.lastId
|
||||
// FIXME: no authToken provision!
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.deliver = cometd.iframeTransport.deliver;
|
||||
// the logic appears to be the same
|
||||
|
||||
this.openTunnelWith = function(content, url){
|
||||
// create a <script> element to generate the request
|
||||
var req = dojo.io.bind({
|
||||
url: (url||cometd.url),
|
||||
content: content,
|
||||
mimetype: "text/json",
|
||||
transport: "ScriptSrcTransport",
|
||||
jsonParamName: "jsonp",
|
||||
load: dojo.lang.hitch(this, function(type, data, evt, args){
|
||||
dojo.debug(dojo.json.serialize(data));
|
||||
cometd.deliver(data);
|
||||
this.connected = false;
|
||||
this.tunnelCollapse();
|
||||
}),
|
||||
error: function(){ dojo.debug("tunnel opening failed"); }
|
||||
});
|
||||
this.connected = true;
|
||||
}
|
||||
|
||||
this.processBacklog = function(){
|
||||
while(this.backlog.length > 0){
|
||||
this.sendMessage(this.backlog.shift(), true);
|
||||
}
|
||||
}
|
||||
|
||||
this.sendMessage = function(message, bypassBacklog){
|
||||
// FIXME: what about auth fields?
|
||||
if((bypassBacklog)||(this.connected)){
|
||||
message.connectionId = this.connectionId;
|
||||
message.clientId = cometd.clientId;
|
||||
var bindArgs = {
|
||||
url: cometd.url||djConfig["cometdRoot"],
|
||||
mimetype: "text/json",
|
||||
transport: "ScriptSrcTransport",
|
||||
jsonParamName: "jsonp",
|
||||
content: { message: dojo.json.serialize([ message ]) }
|
||||
};
|
||||
return dojo.io.bind(bindArgs);
|
||||
}else{
|
||||
this.backlog.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
this.startup = function(handshakeData){
|
||||
if(this.connected){ return; }
|
||||
this.tunnelInit();
|
||||
}
|
||||
}
|
||||
|
||||
cometd.connectionTypes.register("mime-message-block", cometd.mimeReplaceTransport.check, cometd.mimeReplaceTransport);
|
||||
cometd.connectionTypes.register("long-polling", cometd.longPollTransport.check, cometd.longPollTransport);
|
||||
cometd.connectionTypes.register("callback-polling", cometd.callbackPollTransport.check, cometd.callbackPollTransport);
|
||||
cometd.connectionTypes.register("iframe", cometd.iframeTransport.check, cometd.iframeTransport);
|
||||
|
||||
// FIXME: need to implement fallback-polling, IE XML block
|
||||
|
||||
dojo.io.cometd = cometd;
|
517
source/web/scripts/ajax/dojo/src/io/common.js
Normal file
517
source/web/scripts/ajax/dojo/src/io/common.js
Normal file
@@ -0,0 +1,517 @@
|
||||
/*
|
||||
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.common");
|
||||
dojo.require("dojo.string");
|
||||
dojo.require("dojo.lang.extras");
|
||||
|
||||
/******************************************************************************
|
||||
* Notes about dojo.io design:
|
||||
*
|
||||
* The dojo.io.* package has the unenviable task of making a lot of different
|
||||
* types of I/O feel natural, despite a universal lack of good (or even
|
||||
* reasonable!) I/O capability in the host environment. So lets pin this down
|
||||
* a little bit further.
|
||||
*
|
||||
* Rhino:
|
||||
* perhaps the best situation anywhere. Access to Java classes allows you
|
||||
* to do anything one might want in terms of I/O, both synchronously and
|
||||
* async. Can open TCP sockets and perform low-latency client/server
|
||||
* interactions. HTTP transport is available through Java HTTP client and
|
||||
* server classes. Wish it were always this easy.
|
||||
*
|
||||
* xpcshell:
|
||||
* XPCOM for I/O.
|
||||
*
|
||||
* spidermonkey:
|
||||
* S.O.L.
|
||||
*
|
||||
* Browsers:
|
||||
* Browsers generally do not provide any useable filesystem access. We are
|
||||
* therefore limited to HTTP for moving information to and from Dojo
|
||||
* instances living in a browser.
|
||||
*
|
||||
* XMLHTTP:
|
||||
* Sync or async, allows reading of arbitrary text files (including
|
||||
* JS, which can then be eval()'d), writing requires server
|
||||
* cooperation and is limited to HTTP mechanisms (POST and GET).
|
||||
*
|
||||
* <iframe> hacks:
|
||||
* iframe document hacks allow browsers to communicate asynchronously
|
||||
* with a server via HTTP POST and GET operations. With significant
|
||||
* effort and server cooperation, low-latency data transit between
|
||||
* client and server can be acheived via iframe mechanisms (repubsub).
|
||||
*
|
||||
* SVG:
|
||||
* Adobe's SVG viewer implements helpful primitives for XML-based
|
||||
* requests, but receipt of arbitrary text data seems unlikely w/o
|
||||
* <![CDATA[]]> sections.
|
||||
*
|
||||
*
|
||||
* A discussion between Dylan, Mark, Tom, and Alex helped to lay down a lot
|
||||
* the IO API interface. A transcript of it can be found at:
|
||||
* http://dojotoolkit.org/viewcvs/viewcvs.py/documents/irc/irc_io_api_log.txt?rev=307&view=auto
|
||||
*
|
||||
* Also referenced in the design of the API was the DOM 3 L&S spec:
|
||||
* http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407/load-save.html
|
||||
******************************************************************************/
|
||||
|
||||
// a map of the available transport options. Transports should add themselves
|
||||
// by calling add(name)
|
||||
dojo.io.transports = [];
|
||||
dojo.io.hdlrFuncNames = [ "load", "error", "timeout" ]; // we're omitting a progress() event for now
|
||||
|
||||
dojo.io.Request = function(/*String*/ url, /*String*/ mimetype, /*String*/ transport, /*String or Boolean*/ changeUrl){
|
||||
// summary:
|
||||
// Constructs a Request object that is used by dojo.io.bind().
|
||||
// description:
|
||||
// dojo.io.bind() will create one of these for you if
|
||||
// you call dojo.io.bind() with an plain object containing the bind parameters.
|
||||
// This method can either take the arguments specified, or an Object containing all of the parameters that you
|
||||
// want to use to create the dojo.io.Request (similar to how dojo.io.bind() is called.
|
||||
// The named parameters to this constructor represent the minimum set of parameters need
|
||||
if((arguments.length == 1)&&(arguments[0].constructor == Object)){
|
||||
this.fromKwArgs(arguments[0]);
|
||||
}else{
|
||||
this.url = url;
|
||||
if(mimetype){ this.mimetype = mimetype; }
|
||||
if(transport){ this.transport = transport; }
|
||||
if(arguments.length >= 4){ this.changeUrl = changeUrl; }
|
||||
}
|
||||
}
|
||||
|
||||
dojo.lang.extend(dojo.io.Request, {
|
||||
|
||||
/** The URL to hit */
|
||||
url: "",
|
||||
|
||||
/** The mime type used to interrpret the response body */
|
||||
mimetype: "text/plain",
|
||||
|
||||
/** The HTTP method to use */
|
||||
method: "GET",
|
||||
|
||||
/** An Object containing key-value pairs to be included with the request */
|
||||
content: undefined, // Object
|
||||
|
||||
/** The transport medium to use */
|
||||
transport: undefined, // String
|
||||
|
||||
/** If defined the URL of the page is physically changed */
|
||||
changeUrl: undefined, // String
|
||||
|
||||
/** A form node to use in the request */
|
||||
formNode: undefined, // HTMLFormElement
|
||||
|
||||
/** Whether the request should be made synchronously */
|
||||
sync: false,
|
||||
|
||||
bindSuccess: false,
|
||||
|
||||
/** Cache/look for the request in the cache before attempting to request?
|
||||
* NOTE: this isn't a browser cache, this is internal and would only cache in-page
|
||||
*/
|
||||
useCache: false,
|
||||
|
||||
/** Prevent the browser from caching this by adding a query string argument to the URL */
|
||||
preventCache: false,
|
||||
|
||||
// events stuff
|
||||
load: function(/*String*/type, /*Object*/data, /*Object*/transportImplementation, /*Object*/kwArgs){
|
||||
// summary:
|
||||
// Called on successful completion of a bind.
|
||||
// type: String
|
||||
// A string with value "load"
|
||||
// data: Object
|
||||
// The object representing the result of the bind. The actual structure
|
||||
// of the data object will depend on the mimetype that was given to bind
|
||||
// in the bind arguments.
|
||||
// transportImplementation: Object
|
||||
// The object that implements a particular transport. Structure is depedent
|
||||
// on the transport. For XMLHTTPTransport (dojo.io.BrowserIO), it will be the
|
||||
// XMLHttpRequest object from the browser.
|
||||
// kwArgs: Object
|
||||
// Object that contains the request parameters that were given to the
|
||||
// bind call. Useful for storing and retrieving state from when bind
|
||||
// was called.
|
||||
},
|
||||
error: function(/*String*/type, /*Object*/error, /*Object*/transportImplementation, /*Object*/kwArgs){
|
||||
// summary:
|
||||
// Called when there is an error with a bind.
|
||||
// type: String
|
||||
// A string with value "error"
|
||||
// error: Object
|
||||
// The error object. Should be a dojo.io.Error object, but not guaranteed.
|
||||
// transportImplementation: Object
|
||||
// The object that implements a particular transport. Structure is depedent
|
||||
// on the transport. For XMLHTTPTransport (dojo.io.BrowserIO), it will be the
|
||||
// XMLHttpRequest object from the browser.
|
||||
// kwArgs: Object
|
||||
// Object that contains the request parameters that were given to the
|
||||
// bind call. Useful for storing and retrieving state from when bind
|
||||
// was called.
|
||||
},
|
||||
timeout: function(/*String*/type, /*Object*/empty, /*Object*/transportImplementation, /*Object*/kwArgs){
|
||||
// summary:
|
||||
// Called when there is an error with a bind. Only implemented in certain transports at this time.
|
||||
// type: String
|
||||
// A string with value "timeout"
|
||||
// empty: Object
|
||||
// Should be null. Just a spacer argument so that load, error, timeout and handle have the
|
||||
// same signatures.
|
||||
// transportImplementation: Object
|
||||
// The object that implements a particular transport. Structure is depedent
|
||||
// on the transport. For XMLHTTPTransport (dojo.io.BrowserIO), it will be the
|
||||
// XMLHttpRequest object from the browser. May be null for the timeout case for
|
||||
// some transports.
|
||||
// kwArgs: Object
|
||||
// Object that contains the request parameters that were given to the
|
||||
// bind call. Useful for storing and retrieving state from when bind
|
||||
// was called.
|
||||
},
|
||||
handle: function(/*String*/type, /*Object*/data, /*Object*/transportImplementation, /*Object*/kwArgs){
|
||||
// summary:
|
||||
// The handle method can be defined instead of defining separate load, error and timeout
|
||||
// callbacks.
|
||||
// type: String
|
||||
// A string with the type of callback: "load", "error", or "timeout".
|
||||
// data: Object
|
||||
// See the above callbacks for what this parameter could be.
|
||||
// transportImplementation: Object
|
||||
// The object that implements a particular transport. Structure is depedent
|
||||
// on the transport. For XMLHTTPTransport (dojo.io.BrowserIO), it will be the
|
||||
// XMLHttpRequest object from the browser.
|
||||
// kwArgs: Object
|
||||
// Object that contains the request parameters that were given to the
|
||||
// bind call. Useful for storing and retrieving state from when bind
|
||||
// was called.
|
||||
},
|
||||
|
||||
//FIXME: change IframeIO.js to use timeouts?
|
||||
// The number of seconds to wait until firing a timeout callback.
|
||||
// If it is zero, that means, don't do a timeout check.
|
||||
timeoutSeconds: 0,
|
||||
|
||||
// the abort method needs to be filled in by the transport that accepts the
|
||||
// bind() request
|
||||
abort: function(){ },
|
||||
|
||||
// backButton: function(){ },
|
||||
// forwardButton: function(){ },
|
||||
|
||||
fromKwArgs: function(/*Object*/ kwArgs){
|
||||
// summary:
|
||||
// Creates a dojo.io.Request from a simple object (kwArgs object).
|
||||
|
||||
// normalize args
|
||||
if(kwArgs["url"]){ kwArgs.url = kwArgs.url.toString(); }
|
||||
if(kwArgs["formNode"]) { kwArgs.formNode = dojo.byId(kwArgs.formNode); }
|
||||
if(!kwArgs["method"] && kwArgs["formNode"] && kwArgs["formNode"].method) {
|
||||
kwArgs.method = kwArgs["formNode"].method;
|
||||
}
|
||||
|
||||
// backwards compatibility
|
||||
if(!kwArgs["handle"] && kwArgs["handler"]){ kwArgs.handle = kwArgs.handler; }
|
||||
if(!kwArgs["load"] && kwArgs["loaded"]){ kwArgs.load = kwArgs.loaded; }
|
||||
if(!kwArgs["changeUrl"] && kwArgs["changeURL"]) { kwArgs.changeUrl = kwArgs.changeURL; }
|
||||
|
||||
// encoding fun!
|
||||
kwArgs.encoding = dojo.lang.firstValued(kwArgs["encoding"], djConfig["bindEncoding"], "");
|
||||
|
||||
kwArgs.sendTransport = dojo.lang.firstValued(kwArgs["sendTransport"], djConfig["ioSendTransport"], false);
|
||||
|
||||
var isFunction = dojo.lang.isFunction;
|
||||
for(var x=0; x<dojo.io.hdlrFuncNames.length; x++){
|
||||
var fn = dojo.io.hdlrFuncNames[x];
|
||||
if(kwArgs[fn] && isFunction(kwArgs[fn])){ continue; }
|
||||
if(kwArgs["handle"] && isFunction(kwArgs["handle"])){
|
||||
kwArgs[fn] = kwArgs.handle;
|
||||
}
|
||||
// handler is aliased above, shouldn't need this check
|
||||
/* else if(dojo.lang.isObject(kwArgs.handler)){
|
||||
if(isFunction(kwArgs.handler[fn])){
|
||||
kwArgs[fn] = kwArgs.handler[fn]||kwArgs.handler["handle"]||function(){};
|
||||
}
|
||||
}*/
|
||||
}
|
||||
dojo.lang.mixin(this, kwArgs);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
dojo.io.Error = function(/*String*/ msg, /*String*/ type, /*Number*/num){
|
||||
// summary:
|
||||
// Constructs an object representing a bind error.
|
||||
this.message = msg;
|
||||
this.type = type || "unknown"; // must be one of "io", "parse", "unknown"
|
||||
this.number = num || 0; // per-substrate error number, not normalized
|
||||
}
|
||||
|
||||
dojo.io.transports.addTransport = function(/*String*/name){
|
||||
// summary:
|
||||
// Used to register transports that can support bind calls.
|
||||
this.push(name);
|
||||
// FIXME: do we need to handle things that aren't direct children of the
|
||||
// dojo.io module? (say, dojo.io.foo.fooTransport?)
|
||||
this[name] = dojo.io[name];
|
||||
}
|
||||
|
||||
// binding interface, the various implementations register their capabilities
|
||||
// and the bind() method dispatches
|
||||
dojo.io.bind = function(/*dojo.io.Request or Object*/request){
|
||||
// summary:
|
||||
// Binding interface for IO. Loading different IO transports, like
|
||||
// dojo.io.BrowserIO or dojo.io.IframeIO, will register with bind
|
||||
// to handle particular types of bind calls.
|
||||
// request: Object
|
||||
// Object containing bind arguments. This object is converted to
|
||||
// a dojo.io.Request object, and that request object is the return
|
||||
// value for this method.
|
||||
if(!(request instanceof dojo.io.Request)){
|
||||
try{
|
||||
request = new dojo.io.Request(request);
|
||||
}catch(e){ dojo.debug(e); }
|
||||
}
|
||||
|
||||
// if the request asks for a particular implementation, use it
|
||||
var tsName = "";
|
||||
if(request["transport"]){
|
||||
tsName = request["transport"];
|
||||
if(!this[tsName]){
|
||||
dojo.io.sendBindError(request, "No dojo.io.bind() transport with name '"
|
||||
+ request["transport"] + "'.");
|
||||
return request; //dojo.io.Request
|
||||
}
|
||||
if(!this[tsName].canHandle(request)){
|
||||
dojo.io.sendBindError(request, "dojo.io.bind() transport with name '"
|
||||
+ request["transport"] + "' cannot handle this type of request.");
|
||||
return request; //dojo.io.Request
|
||||
}
|
||||
}else{
|
||||
// otherwise we do our best to auto-detect what available transports
|
||||
// will handle
|
||||
for(var x=0; x<dojo.io.transports.length; x++){
|
||||
var tmp = dojo.io.transports[x];
|
||||
if((this[tmp])&&(this[tmp].canHandle(request))){
|
||||
tsName = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(tsName == ""){
|
||||
dojo.io.sendBindError(request, "None of the loaded transports for dojo.io.bind()"
|
||||
+ " can handle the request.");
|
||||
return request; //dojo.io.Request
|
||||
}
|
||||
}
|
||||
this[tsName].bind(request);
|
||||
request.bindSuccess = true;
|
||||
return request; //dojo.io.Request
|
||||
}
|
||||
|
||||
dojo.io.sendBindError = function(/* Object */request, /* String */message){
|
||||
// summary:
|
||||
// Used internally by dojo.io.bind() to return/raise a bind error.
|
||||
|
||||
//Need to be careful since not all hostenvs support setTimeout.
|
||||
if((typeof request.error == "function" || typeof request.handle == "function")
|
||||
&& (typeof setTimeout == "function" || typeof setTimeout == "object")){
|
||||
var errorObject = new dojo.io.Error(message);
|
||||
setTimeout(function(){
|
||||
request[(typeof request.error == "function") ? "error" : "handle"]("error", errorObject, null, request);
|
||||
}, 50);
|
||||
}else{
|
||||
dojo.raise(message);
|
||||
}
|
||||
}
|
||||
|
||||
dojo.io.queueBind = function(/*dojo.io.Request or Object*/request){
|
||||
// summary:
|
||||
// queueBind will use dojo.io.bind() but guarantee that only one bind
|
||||
// call is handled at a time.
|
||||
// description:
|
||||
// If queueBind is called while a bind call
|
||||
// is in process, it will queue up the other calls to bind and call them
|
||||
// in order as bind calls complete.
|
||||
// request: Object
|
||||
// Same sort of request object as used for dojo.io.bind().
|
||||
if(!(request instanceof dojo.io.Request)){
|
||||
try{
|
||||
request = new dojo.io.Request(request);
|
||||
}catch(e){ dojo.debug(e); }
|
||||
}
|
||||
|
||||
// make sure we get called if/when we get a response
|
||||
var oldLoad = request.load;
|
||||
request.load = function(){
|
||||
dojo.io._queueBindInFlight = false;
|
||||
var ret = oldLoad.apply(this, arguments);
|
||||
dojo.io._dispatchNextQueueBind();
|
||||
return ret;
|
||||
}
|
||||
|
||||
var oldErr = request.error;
|
||||
request.error = function(){
|
||||
dojo.io._queueBindInFlight = false;
|
||||
var ret = oldErr.apply(this, arguments);
|
||||
dojo.io._dispatchNextQueueBind();
|
||||
return ret;
|
||||
}
|
||||
|
||||
dojo.io._bindQueue.push(request);
|
||||
dojo.io._dispatchNextQueueBind();
|
||||
return request; //dojo.io.Request
|
||||
}
|
||||
|
||||
dojo.io._dispatchNextQueueBind = function(){
|
||||
// summary:
|
||||
// Private method used by dojo.io.queueBind().
|
||||
if(!dojo.io._queueBindInFlight){
|
||||
dojo.io._queueBindInFlight = true;
|
||||
if(dojo.io._bindQueue.length > 0){
|
||||
dojo.io.bind(dojo.io._bindQueue.shift());
|
||||
}else{
|
||||
dojo.io._queueBindInFlight = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
dojo.io._bindQueue = [];
|
||||
dojo.io._queueBindInFlight = false;
|
||||
|
||||
dojo.io.argsFromMap = function(/*Object*/map, /*String?*/encoding, /*String?*/last){
|
||||
// summary:
|
||||
// Converts name/values pairs in the map object to an URL-encoded string
|
||||
// with format of name1=value1&name2=value2...
|
||||
// map: Object
|
||||
// Object that has the contains the names and values.
|
||||
// encoding: String?
|
||||
// String to specify how to encode the name and value. If the encoding string
|
||||
// contains "utf" (case-insensitive), then encodeURIComponent is used. Otherwise
|
||||
// dojo.string.encodeAscii is used.
|
||||
// last: String?
|
||||
// The last parameter in the list. Helps with final string formatting?
|
||||
var enc = /utf/i.test(encoding||"") ? encodeURIComponent : dojo.string.encodeAscii;
|
||||
var mapped = [];
|
||||
var control = new Object();
|
||||
for(var name in map){
|
||||
var domap = function(elt){
|
||||
var val = enc(name)+"="+enc(elt);
|
||||
mapped[(last == name) ? "push" : "unshift"](val);
|
||||
}
|
||||
if(!control[name]){
|
||||
var value = map[name];
|
||||
// FIXME: should be isArrayLike?
|
||||
if (dojo.lang.isArray(value)){
|
||||
dojo.lang.forEach(value, domap);
|
||||
}else{
|
||||
domap(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return mapped.join("&"); //String
|
||||
}
|
||||
|
||||
dojo.io.setIFrameSrc = function(/*DOMNode*/ iframe, /*String*/ src, /*Boolean*/ replace){
|
||||
//summary:
|
||||
// Sets the URL that is loaded in an IFrame. The replace parameter indicates whether
|
||||
// location.replace() should be used when changing the location of the iframe.
|
||||
try{
|
||||
var r = dojo.render.html;
|
||||
// dojo.debug(iframe);
|
||||
if(!replace){
|
||||
if(r.safari){
|
||||
iframe.location = src;
|
||||
}else{
|
||||
frames[iframe.name].location = src;
|
||||
}
|
||||
}else{
|
||||
// Fun with DOM 0 incompatibilities!
|
||||
var idoc;
|
||||
if(r.ie){
|
||||
idoc = iframe.contentWindow.document;
|
||||
}else if(r.safari){
|
||||
idoc = iframe.document;
|
||||
}else{ // if(r.moz){
|
||||
idoc = iframe.contentWindow;
|
||||
}
|
||||
|
||||
//For Safari (at least 2.0.3) and Opera, if the iframe
|
||||
//has just been created but it doesn't have content
|
||||
//yet, then iframe.document may be null. In that case,
|
||||
//use iframe.location and return.
|
||||
if(!idoc){
|
||||
iframe.location = src;
|
||||
return;
|
||||
}else{
|
||||
idoc.location.replace(src);
|
||||
}
|
||||
}
|
||||
}catch(e){
|
||||
dojo.debug(e);
|
||||
dojo.debug("setIFrameSrc: "+e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
dojo.io.sampleTranport = new function(){
|
||||
this.canHandle = function(kwArgs){
|
||||
// canHandle just tells dojo.io.bind() if this is a good transport to
|
||||
// use for the particular type of request.
|
||||
if(
|
||||
(
|
||||
(kwArgs["mimetype"] == "text/plain") ||
|
||||
(kwArgs["mimetype"] == "text/html") ||
|
||||
(kwArgs["mimetype"] == "text/javascript")
|
||||
)&&(
|
||||
(kwArgs["method"] == "get") ||
|
||||
( (kwArgs["method"] == "post") && (!kwArgs["formNode"]) )
|
||||
)
|
||||
){
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
this.bind = function(kwArgs){
|
||||
var hdlrObj = {};
|
||||
|
||||
// set up a handler object
|
||||
for(var x=0; x<dojo.io.hdlrFuncNames.length; x++){
|
||||
var fn = dojo.io.hdlrFuncNames[x];
|
||||
if(typeof kwArgs.handler == "object"){
|
||||
if(typeof kwArgs.handler[fn] == "function"){
|
||||
hdlrObj[fn] = kwArgs.handler[fn]||kwArgs.handler["handle"];
|
||||
}
|
||||
}else if(typeof kwArgs[fn] == "function"){
|
||||
hdlrObj[fn] = kwArgs[fn];
|
||||
}else{
|
||||
hdlrObj[fn] = kwArgs["handle"]||function(){};
|
||||
}
|
||||
}
|
||||
|
||||
// build a handler function that calls back to the handler obj
|
||||
var hdlrFunc = function(evt){
|
||||
if(evt.type == "onload"){
|
||||
hdlrObj.load("load", evt.data, evt);
|
||||
}else if(evt.type == "onerr"){
|
||||
var errObj = new dojo.io.Error("sampleTransport Error: "+evt.msg);
|
||||
hdlrObj.error("error", errObj);
|
||||
}
|
||||
}
|
||||
|
||||
// the sample transport would attach the hdlrFunc() when sending the
|
||||
// request down the pipe at this point
|
||||
var tgtURL = kwArgs.url+"?"+dojo.io.argsFromMap(kwArgs.content);
|
||||
// sampleTransport.sendRequest(tgtURL, hdlrFunc);
|
||||
}
|
||||
|
||||
dojo.io.transports.addTransport("sampleTranport");
|
||||
}
|
||||
*/
|
130
source/web/scripts/ajax/dojo/src/io/cookie.js
Normal file
130
source/web/scripts/ajax/dojo/src/io/cookie.js
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
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.cookie");
|
||||
|
||||
dojo.io.cookie.setCookie = function(/*String*/name, /*String*/value,
|
||||
/*Number?*/days, /*String?*/path,
|
||||
/*String?*/domain, /*boolean?*/secure){
|
||||
//summary: sets a cookie.
|
||||
var expires = -1;
|
||||
if((typeof days == "number")&&(days >= 0)){
|
||||
var d = new Date();
|
||||
d.setTime(d.getTime()+(days*24*60*60*1000));
|
||||
expires = d.toGMTString();
|
||||
}
|
||||
value = escape(value);
|
||||
document.cookie = name + "=" + value + ";"
|
||||
+ (expires != -1 ? " expires=" + expires + ";" : "")
|
||||
+ (path ? "path=" + path : "")
|
||||
+ (domain ? "; domain=" + domain : "")
|
||||
+ (secure ? "; secure" : "");
|
||||
}
|
||||
|
||||
dojo.io.cookie.set = dojo.io.cookie.setCookie;
|
||||
|
||||
dojo.io.cookie.getCookie = function(/*String*/name){
|
||||
//summary: Gets a cookie with the given name.
|
||||
|
||||
// FIXME: Which cookie should we return?
|
||||
// If there are cookies set for different sub domains in the current
|
||||
// scope there could be more than one cookie with the same name.
|
||||
// I think taking the last one in the list takes the one from the
|
||||
// deepest subdomain, which is what we're doing here.
|
||||
var idx = document.cookie.lastIndexOf(name+'=');
|
||||
if(idx == -1) { return null; }
|
||||
var value = document.cookie.substring(idx+name.length+1);
|
||||
var end = value.indexOf(';');
|
||||
if(end == -1) { end = value.length; }
|
||||
value = value.substring(0, end);
|
||||
value = unescape(value);
|
||||
return value; //String
|
||||
}
|
||||
|
||||
dojo.io.cookie.get = dojo.io.cookie.getCookie;
|
||||
|
||||
dojo.io.cookie.deleteCookie = function(/*String*/name){
|
||||
//summary: Deletes a cookie with the given name.
|
||||
dojo.io.cookie.setCookie(name, "-", 0);
|
||||
}
|
||||
|
||||
dojo.io.cookie.setObjectCookie = function( /*String*/name, /*Object*/obj,
|
||||
/*Number?*/days, /*String?*/path,
|
||||
/*String?*/domain, /*boolean?*/secure,
|
||||
/*boolean?*/clearCurrent){
|
||||
//summary: Takes an object, serializes it to a cookie value, and either
|
||||
//sets a cookie with the serialized value.
|
||||
//description: If clearCurrent is true, then any current cookie value
|
||||
//for this object will be replaced with the the new serialized object value.
|
||||
//If clearCurrent is false, then the existing cookie value will be modified
|
||||
//with any changes from the new object value.
|
||||
//Objects must be simple name/value pairs where the value is either a string
|
||||
//or a number. Any other value will be ignored.
|
||||
if(arguments.length == 5){ // for backwards compat
|
||||
clearCurrent = domain;
|
||||
domain = null;
|
||||
secure = null;
|
||||
}
|
||||
var pairs = [], cookie, value = "";
|
||||
if(!clearCurrent){
|
||||
cookie = dojo.io.cookie.getObjectCookie(name);
|
||||
}
|
||||
if(days >= 0){
|
||||
if(!cookie){ cookie = {}; }
|
||||
for(var prop in obj){
|
||||
if(obj[prop] == null){
|
||||
delete cookie[prop];
|
||||
}else if((typeof obj[prop] == "string")||(typeof obj[prop] == "number")){
|
||||
cookie[prop] = obj[prop];
|
||||
}
|
||||
}
|
||||
prop = null;
|
||||
for(var prop in cookie){
|
||||
pairs.push(escape(prop) + "=" + escape(cookie[prop]));
|
||||
}
|
||||
value = pairs.join("&");
|
||||
}
|
||||
dojo.io.cookie.setCookie(name, value, days, path, domain, secure);
|
||||
}
|
||||
|
||||
dojo.io.cookie.getObjectCookie = function(/*String*/name){
|
||||
//summary: Gets an object value for the given cookie name. The complement of
|
||||
//dojo.io.cookie.setObjectCookie().
|
||||
var values = null, cookie = dojo.io.cookie.getCookie(name);
|
||||
if(cookie){
|
||||
values = {};
|
||||
var pairs = cookie.split("&");
|
||||
for(var i = 0; i < pairs.length; i++){
|
||||
var pair = pairs[i].split("=");
|
||||
var value = pair[1];
|
||||
if( isNaN(value) ){ value = unescape(pair[1]); }
|
||||
values[ unescape(pair[0]) ] = value;
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
dojo.io.cookie.isSupported = function(){
|
||||
//summary: Tests the browser to see if cookies are enabled.
|
||||
if(typeof navigator.cookieEnabled != "boolean"){
|
||||
dojo.io.cookie.setCookie("__TestingYourBrowserForCookieSupport__",
|
||||
"CookiesAllowed", 90, null);
|
||||
var cookieVal = dojo.io.cookie.getCookie("__TestingYourBrowserForCookieSupport__");
|
||||
navigator.cookieEnabled = (cookieVal == "CookiesAllowed");
|
||||
if(navigator.cookieEnabled){
|
||||
// FIXME: should we leave this around?
|
||||
this.deleteCookie("__TestingYourBrowserForCookieSupport__");
|
||||
}
|
||||
}
|
||||
return navigator.cookieEnabled; //boolean
|
||||
}
|
||||
|
||||
// need to leave this in for backwards-compat from 0.1 for when it gets pulled in by dojo.io.*
|
||||
if(!dojo.io.cookies){ dojo.io.cookies = dojo.io.cookie; }
|
254
source/web/scripts/ajax/dojo/src/io/xip_client.html
Normal file
254
source/web/scripts/ajax/dojo/src/io/xip_client.html
Normal file
@@ -0,0 +1,254 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title></title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
|
||||
<script type="text/javascript">
|
||||
// <!--
|
||||
/*
|
||||
This file is really focused on just sending one message to the server, and
|
||||
receiving one response. The code does not expect to be re-used for multiple messages.
|
||||
This might be reworked later if performance indicates a need for it.
|
||||
|
||||
xip fragment identifier/hash values have the form:
|
||||
#id:cmd:realEncodedMessage
|
||||
|
||||
id: some ID that should be unique among messages. No inherent meaning,
|
||||
just something to make sure the hash value is unique so the message
|
||||
receiver knows a new message is available.
|
||||
|
||||
cmd: command to the receiver. Valid values are:
|
||||
- init: message used to init the frame. Sent as the first URL when loading
|
||||
the page. Contains some config parameters.
|
||||
- loaded: the remote frame is loaded. Only sent from server to client.
|
||||
- ok: the message that this page sent was received OK. The next message may
|
||||
now be sent.
|
||||
- start: the start message of a block of messages (a complete message may
|
||||
need to be segmented into many messages to get around the limitiations
|
||||
of the size of an URL that a browser accepts.
|
||||
- part: indicates this is a part of a message.
|
||||
- end: the end message of a block of messages. The message can now be acted upon.
|
||||
If the message is small enough that it doesn't need to be segmented, then
|
||||
just one hash value message can be sent with "end" as the command.
|
||||
|
||||
To reassemble a segmented message, the realEncodedMessage parts just have to be concatenated
|
||||
together.
|
||||
*/
|
||||
|
||||
//MSIE has the lowest limit for URLs with fragment identifiers,
|
||||
//at around 4K. Choosing a slightly smaller number for good measure.
|
||||
xipUrlLimit = 4000;
|
||||
xipIdCounter = 1;
|
||||
|
||||
function xipInit(){
|
||||
xipStateId = "";
|
||||
xipIsSending = false;
|
||||
xipServerUrl = null;
|
||||
xipStateId = null;
|
||||
xipRequestData = null;
|
||||
xipCurrentHash = "";
|
||||
xipResponseMessage = "";
|
||||
xipRequestParts = [];
|
||||
xipPartIndex = 0;
|
||||
xipServerWindow = null;
|
||||
xipUseFrameRecursion = false;
|
||||
}
|
||||
xipInit();
|
||||
|
||||
function send(encodedData){
|
||||
if(xipUseFrameRecursion == "true"){
|
||||
var clientEndPoint = window.open(xipStateId + "_clientEndPoint");
|
||||
clientEndPoint.send(encodedData);
|
||||
}else{
|
||||
if(!xipIsSending){
|
||||
xipIsSending = true;
|
||||
|
||||
xipRequestData = encodedData || "";
|
||||
|
||||
//Get a handle to the server iframe.
|
||||
xipServerWindow = frames[xipStateId + "_frame"];
|
||||
if (!xipServerWindow){
|
||||
xipServerWindow = document.getElementById(xipStateId + "_frame").contentWindow;
|
||||
}
|
||||
|
||||
sendRequestStart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Modify the server URL if it is a local path and
|
||||
//This is done for local/same domain testing.
|
||||
function fixServerUrl(ifpServerUrl){
|
||||
if(ifpServerUrl.indexOf("..") == 0){
|
||||
var parts = ifpServerUrl.split("/");
|
||||
ifpServerUrl = parts[parts.length - 1];
|
||||
}
|
||||
return ifpServerUrl;
|
||||
}
|
||||
|
||||
|
||||
function pollHash(){
|
||||
//Can't use location.hash because at least Firefox does a decodeURIComponent on it.
|
||||
var urlParts = window.location.href.split("#");
|
||||
if(urlParts.length == 2){
|
||||
var newHash = urlParts[1];
|
||||
if(newHash != xipCurrentHash){
|
||||
try{
|
||||
messageReceived(newHash);
|
||||
}catch(e){
|
||||
//Make sure to not keep processing the error hash value.
|
||||
xipCurrentHash = newHash;
|
||||
throw e;
|
||||
}
|
||||
xipCurrentHash = newHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function messageReceived(encodedData){
|
||||
var msg = unpackMessage(encodedData);
|
||||
|
||||
switch(msg.command){
|
||||
case "loaded":
|
||||
xipMasterFrame.dojo.io.XhrIframeProxy.clientFrameLoaded(xipStateId);
|
||||
break;
|
||||
case "ok":
|
||||
sendRequestPart();
|
||||
break;
|
||||
case "start":
|
||||
xipResponseMessage = "";
|
||||
xipResponseMessage += msg.message;
|
||||
setServerUrl("ok");
|
||||
break;
|
||||
case "part":
|
||||
xipResponseMessage += msg.message;
|
||||
setServerUrl("ok");
|
||||
break;
|
||||
case "end":
|
||||
setServerUrl("ok");
|
||||
xipResponseMessage += msg.message;
|
||||
xipMasterFrame.dojo.io.XhrIframeProxy.receive(xipStateId, xipResponseMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function sendRequestStart(){
|
||||
//Break the message into parts, if necessary.
|
||||
xipRequestParts = [];
|
||||
var reqData = xipRequestData;
|
||||
var urlLength = xipServerUrl.length;
|
||||
var partLength = xipUrlLimit - urlLength;
|
||||
var reqIndex = 0;
|
||||
|
||||
while((reqData.length - reqIndex) + urlLength > xipUrlLimit){
|
||||
xipRequestParts.push(reqData.substring(reqIndex, reqIndex + partLength));
|
||||
reqIndex += partLength;
|
||||
}
|
||||
xipRequestParts.push(reqData.substring(reqIndex, reqData.length));
|
||||
|
||||
xipPartIndex = 0;
|
||||
sendRequestPart();
|
||||
|
||||
}
|
||||
|
||||
function sendRequestPart(){
|
||||
if(xipPartIndex < xipRequestParts.length){
|
||||
//Get the message part.
|
||||
var partData = xipRequestParts[xipPartIndex];
|
||||
|
||||
//Get the command.
|
||||
var cmd = "part";
|
||||
if(xipPartIndex + 1 == xipRequestParts.length){
|
||||
cmd = "end";
|
||||
}else if (xipPartIndex == 0){
|
||||
cmd = "start";
|
||||
}
|
||||
|
||||
setServerUrl(cmd, partData);
|
||||
xipPartIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
function setServerUrl(cmd, message){
|
||||
var serverUrl = makeServerUrl(cmd, message);
|
||||
|
||||
//Safari won't let us replace across domains.
|
||||
if(navigator.userAgent.indexOf("Safari") == -1){
|
||||
xipServerWindow.location.replace(serverUrl);
|
||||
}else{
|
||||
xipServerWindow.location = serverUrl;
|
||||
}
|
||||
}
|
||||
|
||||
function makeServerUrl(cmd, message){
|
||||
var serverUrl = xipServerUrl + "#" + (xipIdCounter++) + ":" + cmd;
|
||||
if(message){
|
||||
serverUrl += ":" + message;
|
||||
}
|
||||
return serverUrl;
|
||||
}
|
||||
|
||||
function unpackMessage(encodedMessage){
|
||||
var parts = encodedMessage.split(":");
|
||||
var command = parts[1];
|
||||
encodedMessage = parts[2] || "";
|
||||
|
||||
var config = null;
|
||||
if(command == "init"){
|
||||
var configParts = encodedMessage.split("&");
|
||||
config = {};
|
||||
for(var i = 0; i < configParts.length; i++){
|
||||
var nameValue = configParts[i].split("=");
|
||||
config[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]);
|
||||
}
|
||||
}
|
||||
return {command: command, message: encodedMessage, config: config};
|
||||
}
|
||||
|
||||
function onClientLoad(){
|
||||
//Decode the init params
|
||||
var config = unpackMessage(window.location.href.split("#")[1]).config;
|
||||
|
||||
xipStateId = config.id;
|
||||
|
||||
//Remove the query param for the IE7 recursive case.
|
||||
xipServerUrl = fixServerUrl(config.server).replace(/(\?|\&)dojo\.fr\=1/, "");
|
||||
xipUseFrameRecursion = config["fr"];
|
||||
|
||||
if(xipUseFrameRecursion == "endpoint"){
|
||||
xipMasterFrame = parent.parent;
|
||||
}else{
|
||||
xipMasterFrame = parent;
|
||||
}
|
||||
|
||||
//Start counter to inspect hash value.
|
||||
setInterval(pollHash, 10);
|
||||
|
||||
var clientUrl = window.location.href.split("#")[0];
|
||||
document.getElementById("iframeHolder").innerHTML = '<iframe src="'
|
||||
+ makeServerUrl("init", 'id=' + xipStateId + '&client=' + encodeURIComponent(clientUrl)
|
||||
+ '&fr=' + xipUseFrameRecursion) + '" id="' + xipStateId + '_frame"></iframe>';
|
||||
|
||||
|
||||
}
|
||||
|
||||
if(typeof(window.addEventListener) == "undefined"){
|
||||
window.attachEvent("onload", onClientLoad);
|
||||
}else{
|
||||
window.addEventListener('load', onClientLoad, false);
|
||||
}
|
||||
|
||||
// -->
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h4>The Dojo Toolkit -- xip_client.html</h4>
|
||||
|
||||
<p>This file is used for Dojo's XMLHttpRequest Iframe Proxy. This is the "client" file used
|
||||
internally by dojo.io.XhrIframeProxy.</p>
|
||||
|
||||
<span id="iframeHolder"></span>
|
||||
</body>
|
||||
</html>
|
371
source/web/scripts/ajax/dojo/src/io/xip_server.html
Normal file
371
source/web/scripts/ajax/dojo/src/io/xip_server.html
Normal file
@@ -0,0 +1,371 @@
|
||||
<!--
|
||||
/*
|
||||
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
|
||||
*/
|
||||
Pieces taken from Dojo source to make this file stand-alone
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
|
||||
<script type="text/javascript" src="isAllowed.js"></script>
|
||||
<!--
|
||||
BY DEFAULT THIS FILE DOES NOT WORK SO THAT YOU DON'T ACCIDENTALLY EXPOSE
|
||||
ALL OF YOUR XHR-ENABLED SERVICES ON YOUR SITE.
|
||||
|
||||
In order for this file to work, you should define a function with the following signature:
|
||||
|
||||
function isAllowedRequest(request){
|
||||
return false;
|
||||
}
|
||||
|
||||
Return true out of the function if you want to allow the cross-domain request.
|
||||
|
||||
DON'T DEFINE THIS FUNCTION IN THIS FILE! Define it in a separate file called isAllowed.js
|
||||
and include it in this page with a script tag that has a src attribute pointing to the file.
|
||||
See the very first script tag in this file for an example. You do not have to place the
|
||||
script file in the same directory as this file, just update the path above if you move it
|
||||
somewhere else.
|
||||
|
||||
Customize the isAllowedRequest function to restrict what types of requests are allowed
|
||||
for this server. The request object has the following properties:
|
||||
- requestHeaders: an object with the request headers that are to be added to
|
||||
the XHR request.
|
||||
- method: the HTTP method (GET, POST, etc...)
|
||||
- uri: The URI for the request.
|
||||
- data: The URL-encoded data for the request. For a GET request, this would
|
||||
be the querystring parameters. For a POST request, it wll be the
|
||||
body data.
|
||||
|
||||
See xip_client.html for more info on the xip fragment identifier protocol.
|
||||
-->
|
||||
<script type="text/javascript">
|
||||
// <!--
|
||||
djConfig = {
|
||||
parseWidgets: false,
|
||||
baseScriptUri: "./"
|
||||
}
|
||||
// -->
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
// <!--
|
||||
//Core XHR handling taken from Dojo IO code.
|
||||
dojo = {};
|
||||
dojo.hostenv = {};
|
||||
// These are in order of decreasing likelihood; this will change in time.
|
||||
dojo.hostenv._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
|
||||
|
||||
dojo.hostenv.getXmlhttpObject = function(){
|
||||
var http = null;
|
||||
var last_e = null;
|
||||
try{ http = new XMLHttpRequest(); }catch(e){}
|
||||
if(!http){
|
||||
for(var i=0; i<3; ++i){
|
||||
var progid = dojo.hostenv._XMLHTTP_PROGIDS[i];
|
||||
try{
|
||||
http = new ActiveXObject(progid);
|
||||
}catch(e){
|
||||
last_e = e;
|
||||
}
|
||||
|
||||
if(http){
|
||||
dojo.hostenv._XMLHTTP_PROGIDS = [progid]; // so faster next time
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*if(http && !http.toString) {
|
||||
http.toString = function() { "[object XMLHttpRequest]"; }
|
||||
}*/
|
||||
}
|
||||
|
||||
if(!http){
|
||||
throw "xip_server.html: XMLHTTP not available: " + last_e;
|
||||
}
|
||||
|
||||
return http;
|
||||
}
|
||||
|
||||
dojo.setHeaders = function(http, headers){
|
||||
if(headers) {
|
||||
for(var header in headers) {
|
||||
var headerValue = headers[header];
|
||||
http.setRequestHeader(header, headerValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MSIE has the lowest limit for URLs with fragment identifiers,
|
||||
//at around 4K. Choosing a slightly smaller number for good measure.
|
||||
xipUrlLimit = 4000;
|
||||
xipIdCounter = 1;
|
||||
|
||||
function xipServerInit(){
|
||||
xipStateId = "";
|
||||
xipCurrentHash = "";
|
||||
xipRequestMessage = "";
|
||||
xipResponseParts = [];
|
||||
xipPartIndex = 0;
|
||||
}
|
||||
|
||||
function pollHash(){
|
||||
//Can't use location.hash because at least Firefox does a decodeURIComponent on it.
|
||||
var urlParts = window.location.href.split("#");
|
||||
if(urlParts.length == 2){
|
||||
var newHash = urlParts[1];
|
||||
if(newHash != xipCurrentHash){
|
||||
try{
|
||||
messageReceived(newHash);
|
||||
}catch(e){
|
||||
//Make sure to not keep processing the error hash value.
|
||||
xipCurrentHash = newHash;
|
||||
throw e;
|
||||
}
|
||||
xipCurrentHash = newHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function messageReceived(encodedData){
|
||||
var msg = unpackMessage(encodedData);
|
||||
|
||||
switch(msg.command){
|
||||
case "ok":
|
||||
sendResponsePart();
|
||||
break;
|
||||
case "start":
|
||||
xipRequestMessage = "";
|
||||
xipRequestMessage += msg.message;
|
||||
setClientUrl("ok");
|
||||
break;
|
||||
case "part":
|
||||
xipRequestMessage += msg.message;
|
||||
setClientUrl("ok");
|
||||
break;
|
||||
case "end":
|
||||
setClientUrl("ok");
|
||||
xipRequestMessage += msg.message;
|
||||
sendXhr();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function sendResponse(encodedData){
|
||||
//Break the message into parts, if necessary.
|
||||
xipResponseParts = [];
|
||||
var resData = encodedData;
|
||||
var urlLength = xipClientUrl.length;
|
||||
var partLength = xipUrlLimit - urlLength;
|
||||
var resIndex = 0;
|
||||
|
||||
while((resData.length - resIndex) + urlLength > xipUrlLimit){
|
||||
xipResponseParts.push(resData.substring(resIndex, resIndex + partLength));
|
||||
resIndex += partLength;
|
||||
}
|
||||
xipResponseParts.push(resData.substring(resIndex, resData.length));
|
||||
|
||||
xipPartIndex = 0;
|
||||
sendResponsePart();
|
||||
}
|
||||
|
||||
function sendResponsePart(){
|
||||
if(xipPartIndex < xipResponseParts.length){
|
||||
//Get the message part.
|
||||
var partData = xipResponseParts[xipPartIndex];
|
||||
|
||||
//Get the command.
|
||||
var cmd = "part";
|
||||
if(xipPartIndex + 1 == xipResponseParts.length){
|
||||
cmd = "end";
|
||||
}else if (xipPartIndex == 0){
|
||||
cmd = "start";
|
||||
}
|
||||
|
||||
setClientUrl(cmd, partData);
|
||||
xipPartIndex++;
|
||||
}else{
|
||||
xipServerInit();
|
||||
}
|
||||
}
|
||||
|
||||
function setClientUrl(cmd, message){
|
||||
var clientUrl = makeClientUrl(cmd, message);
|
||||
//Safari won't let us replace across domains.
|
||||
if(navigator.userAgent.indexOf("Safari") == -1){
|
||||
parent.location.replace(clientUrl);
|
||||
}else{
|
||||
parent.location = clientUrl;
|
||||
}
|
||||
}
|
||||
|
||||
function makeClientUrl(cmd, message){
|
||||
var clientUrl = xipClientUrl + "#" + (xipIdCounter++) + ":" + cmd;
|
||||
if(message){
|
||||
clientUrl += ":" + message;
|
||||
}
|
||||
return clientUrl
|
||||
}
|
||||
|
||||
function xhrDone(xhr){
|
||||
/* Need to pull off and return the following data:
|
||||
- responseHeaders
|
||||
- status
|
||||
- statusText
|
||||
- responseText
|
||||
*/
|
||||
var response = {};
|
||||
|
||||
if(typeof(xhr.getAllResponseHeaders) != "undefined"){
|
||||
var allHeaders = xhr.getAllResponseHeaders();
|
||||
if(allHeaders){
|
||||
response.responseHeaders = allHeaders;
|
||||
}
|
||||
}
|
||||
|
||||
if(xhr.status == 0 || xhr.status){
|
||||
response.status = xhr.status;
|
||||
}
|
||||
|
||||
if(xhr.statusText){
|
||||
response.statusText = xhr.statusText;
|
||||
}
|
||||
|
||||
if(xhr.responseText){
|
||||
response.responseText = xhr.responseText;
|
||||
}
|
||||
|
||||
//Build a string of the response object.
|
||||
var result = "";
|
||||
var isFirst = true;
|
||||
for (var param in response){
|
||||
if(isFirst){
|
||||
isFirst = false;
|
||||
}else{
|
||||
result += "&";
|
||||
}
|
||||
result += param + "=" + encodeURIComponent(response[param]);
|
||||
}
|
||||
sendResponse(result);
|
||||
}
|
||||
|
||||
function sendXhr(){
|
||||
var request = {};
|
||||
var nvPairs = xipRequestMessage.split("&");
|
||||
var i = 0;
|
||||
var nameValue = null;
|
||||
for(i = 0; i < nvPairs.length; i++){
|
||||
if(nvPairs[i]){
|
||||
var nameValue = nvPairs[i].split("=");
|
||||
request[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]);
|
||||
}
|
||||
}
|
||||
|
||||
//Split up the request headers, if any.
|
||||
var headers = {};
|
||||
if(request.requestHeaders){
|
||||
nvPairs = request.requestHeaders.split("\r\n");
|
||||
for(i = 0; i < nvPairs.length; i++){
|
||||
if(nvPairs[i]){
|
||||
nameValue = nvPairs[i].split(": ");
|
||||
headers[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]);
|
||||
}
|
||||
}
|
||||
|
||||
request.requestHeaders = headers;
|
||||
}
|
||||
|
||||
if(isAllowedRequest(request)){
|
||||
|
||||
//The request is allowed, so set up the XHR object.
|
||||
var xhr = dojo.hostenv.getXmlhttpObject();
|
||||
|
||||
//Start timer to look for readyState.
|
||||
var xhrIntervalId = setInterval(function(){
|
||||
|
||||
if(xhr.readyState == 4){
|
||||
clearInterval(xhrIntervalId);
|
||||
xhrDone(xhr);
|
||||
}
|
||||
}, 10);
|
||||
|
||||
//Actually start up the XHR request.
|
||||
xhr.open(request.method, request.uri, true);
|
||||
dojo.setHeaders(xhr, request.requestHeaders);
|
||||
|
||||
var content = "";
|
||||
if(request.data){
|
||||
content = request.data;
|
||||
}
|
||||
|
||||
try{
|
||||
xhr.send(content);
|
||||
}catch(e){
|
||||
if(typeof xhr.abort == "function"){
|
||||
xhr.abort();
|
||||
xhrDone({status: 404, statusText: "xip_server.html error: " + e});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function unpackMessage(encodedMessage){
|
||||
var parts = encodedMessage.split(":");
|
||||
var command = parts[1];
|
||||
encodedMessage = parts[2] || "";
|
||||
|
||||
var config = null;
|
||||
if(command == "init"){
|
||||
var configParts = encodedMessage.split("&");
|
||||
config = {};
|
||||
for(var i = 0; i < configParts.length; i++){
|
||||
var nameValue = configParts[i].split("=");
|
||||
config[decodeURIComponent(nameValue[0])] = decodeURIComponent(nameValue[1]);
|
||||
}
|
||||
}
|
||||
return {command: command, message: encodedMessage, config: config};
|
||||
}
|
||||
|
||||
function onServerLoad(){
|
||||
xipServerInit();
|
||||
|
||||
//Decode the init params
|
||||
var config = unpackMessage(window.location.href.split("#")[1]).config;
|
||||
|
||||
xipStateId = config.id;
|
||||
xipClientUrl = config.client;
|
||||
xipUseFrameRecursion = config["fr"];
|
||||
|
||||
setInterval(pollHash, 10);
|
||||
|
||||
if(xipUseFrameRecursion == "true"){
|
||||
var serverUrl = window.location.href.split("#")[0];
|
||||
document.getElementById("iframeHolder").innerHTML = '<iframe src="'
|
||||
+ makeClientUrl("init", 'id=' + xipStateId + '&server=' + encodeURIComponent(serverUrl)
|
||||
+ '&fr=endpoint') + '" name="' + xipStateId + '_clientEndPoint"></iframe>';
|
||||
}else{
|
||||
setClientUrl("loaded");
|
||||
}
|
||||
}
|
||||
|
||||
if(typeof(window.addEventListener) == "undefined"){
|
||||
window.attachEvent("onload", onServerLoad);
|
||||
}else{
|
||||
window.addEventListener('load', onServerLoad, false);
|
||||
}
|
||||
// -->
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h4>The Dojo Toolkit -- xip_server.html</h4>
|
||||
|
||||
<p>This file is used for Dojo's XMLHttpRequest Iframe Proxy. This is the the file
|
||||
that should go on the server that will actually be doing the XHR request.</p>
|
||||
<div id="iframeHolder"></div>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user