Cross-domain Ext.Ajax/Ext.data.Connection
Here, I've extended Ext.data.Connection (and therefore Ext.Ajax, because that is an instance of Ext.data.Connection) to retrieve data, and pass it to your callback function from another domain.
Of course, since it uses a script tag, the server-side script you invoke must wrap the returned data in a call to a callback function. So text must be passed back as a quoted string parameter to a function.
Also, the method is always GET, so all parameters are sent on the URL.
HTTP headers cannot be set on the request, or read from the response.
It creates a bogus XHR containing responseText and responseXML by parsing the resulting data object.
I have successfully retrieved an XML document through this. The servlet quoted the string according to javascript conventions, and wrapped it thus:
Code:
w = response.getWriter();
w.write(callback + "('");
byte[] buffer = getReportXML();
w.write(Utils.javascriptString(buffer.toString()));
w.write("');");
It still needs some work on aborting transactions because the abort code in Ext.data.Connection assumes XHR transport. I can fix that to test what the "trans" object looks like and do different things. But this works:
Code:
Ext.Ajax.request({
url: 'http://localhost:8080/aspicio/getxml.do',
params: {
listId: 'CountryListManager141Grid509',
format: 'xml'
},
scriptTag: true, // Use script tag transport
success: function(r) {
console.log(r);
}
});
Here is the override:
Code:
Ext.lib.Ajax.isCrossDomain = function(u) {
var match = /(?:(\w*:)\/\/)?([\w\.]*(?::\d*)?)/.exec(u);
if (!match[1]) return false; // No protocol, not cross-domain
return (match[1] != location.protocol) || (match[2] != location.host);
};
Ext.override(Ext.data.Connection, {
request : function(o){
if(this.fireEvent("beforerequest", this, o) !== false){
var p = o.params;
if(typeof p == "function"){
p = p.call(o.scope||window, o);
}
if(typeof p == "object"){
p = Ext.urlEncode(p);
}
if(this.extraParams){
var extras = Ext.urlEncode(this.extraParams);
p = p ? (p + '&' + extras) : extras;
}
var url = o.url || this.url;
if(typeof url == 'function'){
url = url.call(o.scope||window, o);
}
if(o.form){
var form = Ext.getDom(o.form);
url = url || form.action;
var enctype = form.getAttribute("enctype");
if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
return this.doFormUpload(o, p, url);
}
var f = Ext.lib.Ajax.serializeForm(form);
p = p ? (p + '&' + f) : f;
}
var hs = o.headers;
if(this.defaultHeaders){
hs = Ext.apply(hs || {}, this.defaultHeaders);
if(!o.headers){
o.headers = hs;
}
}
var cb = {
success: this.handleResponse,
failure: this.handleFailure,
scope: this,
argument: {options: o},
timeout : this.timeout
};
var method = o.method||this.method||(p ? "POST" : "GET");
if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
}
if(typeof o.autoAbort == 'boolean'){ // options gets top priority
if(o.autoAbort){
this.abort();
}
}else if(this.autoAbort !== false){
this.abort();
}
if((method == 'GET' && p) || o.xmlData || o.jsonData){
url += (url.indexOf('?') != -1 ? '&' : '?') + p;
p = '';
}
if (o.scriptTag || this.scriptTag || Ext.lib.Ajax.isCrossDomain(url)) {
this.transId = this.scriptRequest(method, url, cb, p, o);
} else {
this.transId = Ext.lib.Ajax.request(method, url, cb, p, o);
}
return this.transId;
}else{
Ext.callback(o.callback, o.scope, [o, null, null]);
return null;
}
},
scriptRequest : function(method, url, cb, data, options) {
var transId = ++Ext.data.ScriptTagProxy.TRANS_ID;
var trans = {
id : transId,
cb : options.callbackName || "stcCallback"+transId,
scriptId : "stcScript"+transId,
options : options
};
url += (url.indexOf("?") != -1 ? "&" : "?") + data + String.format("&{0}={1}", options.callbackParam || this.callbackParam || 'callback', trans.cb);
var conn = this;
window[trans.cb] = function(o){
conn.handleScriptResponse(o, trans);
};
// Set up the timeout handler
trans.timeoutId = this.handleScriptFailure.defer(cb.timeout, this, [trans]);
var script = document.createElement("script");
script.setAttribute("src", url);
script.setAttribute("type", "text/javascript");
script.setAttribute("id", trans.scriptId);
document.getElementsByTagName("head")[0].appendChild(script);
return trans;
},
handleScriptResponse : function(o, trans){
this.transId = false;
this.destroyScriptTrans(trans, true);
var options = trans.options;
// Attempt to parse a string parameter as XML.
var doc;
if (typeof o == 'string') {
if (window.ActiveXObject) {
doc = new ActiveXObject("Microsoft.XMLDOM");
doc.async = "false";
doc.loadXML(o);
} else {
doc = new DOMParser().parseFromString(o,"text/xml");
}
}
// Create the bogus XHR
response = {
responseObject: o,
responseText: (typeof o == "object") ? Ext.util.JSON.encode(o) : String(o),
responseXML: doc,
argument: options.argument
}
this.fireEvent("requestcomplete", this, response, options);
Ext.callback(options.success, options.scope, [response, options]);
Ext.callback(options.callback, options.scope, [options, true, response]);
},
handleScriptFailure: function(trans) {
this.transId = false;
this.destroyScriptTrans(trans, false);
var options = trans.options;
response = {
argument: options.argument,
status: 500,
statusText: 'Server failed to respond',
responseText: ''
};
this.fireEvent("requestexception", this, response, options, {
status: -1,
statusText: 'communication failure'
});
Ext.callback(options.failure, options.scope, [response, options]);
Ext.callback(options.callback, options.scope, [options, false, response]);
},
// private
destroyScriptTrans : function(trans, isLoaded){
document.getElementsByTagName("head")[0].removeChild(document.getElementById(trans.scriptId));
clearTimeout(trans.timeoutId);
if(isLoaded){
window[trans.cb] = undefined;
try{
delete window[trans.cb];
}catch(e){}
}else{
// if hasn't been loaded, wait for load to remove it to prevent script error
window[trans.cb] = function(){
window[trans.cb] = undefined;
try{
delete window[trans.cb];
}catch(e){}
};
}
}
});