/**
* Prado AJAX service. The default service provider is JPSpan.
*/
Prado.AJAX = { Service : 'Prototype' };
/**
* Parse and execute javascript embedded in html.
*/
Prado.AJAX.EvalScript = function(output)
{
var match = new RegExp(Ajax.Updater.ScriptFragment, 'img');
var scripts = output.match(match);
if (scripts)
{
match = new RegExp(Ajax.Updater.ScriptFragment, 'im');
setTimeout((function()
{
for (var i = 0; i < scripts.length; i++)
eval(scripts[i].match(match)[1]);
}).bind(this), 50);
}
}
/**
* AJAX service request using Prototype's AJAX request class.
*/
Prado.AJAX.Request = Class.create();
Prado.AJAX.Request.prototype = Object.extend(Ajax.Request.prototype,
{
/**
* Evaluate the respond JSON data, override parent implementing.
* If default eval fails, try parsing the JSON data (slower).
*/
evalJSON: function()
{
try
{
var json = this.transport.getResponseHeader('X-JSON'), object;
object = eval(json);
return object;
}
catch (e)
{
if(isString(json))
{
return Prado.AJAX.JSON.parse(json);
}
}
},
respondToReadyState: function(readyState) {
var event = Ajax.Request.Events[readyState];
var transport = this.transport, json = this.evalJSON();
if(event == 'Complete' && transport.status)
Ajax.Responders.dispatch('on' + transport.status, this, transport, json);
if (event == 'Complete')
(this.options['on' + this.transport.status]
|| this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
|| Prototype.emptyFunction)(transport, json);
(this.options['on' + event] || Prototype.emptyFunction)(transport, json);
Ajax.Responders.dispatch('on' + event, this, transport, json);
/* Avoid memory leak in MSIE: clean up the oncomplete event handler */
if (event == 'Complete')
this.transport.onreadystatechange = Prototype.emptyFunction;
}
});
Prado.AJAX.Error = function(e, code)
{
e.name = 'Prado.AJAX.Error';
e.code = code;
return e;
}
/**
* Post data builder, serialize the data using JSON.
*/
Prado.AJAX.RequestBuilder = Class.create();
Prado.AJAX.RequestBuilder.prototype =
{
initialize : function()
{
this.body = '';
this.data = [];
},
encode : function(data)
{
return Prado.AJAX.JSON.stringify(data);
},
build : function(data)
{
var sep = '';
for ( var argName in data)
{
if(isFunction(data[argName])) continue;
try
{
this.body += sep + argName + '=';
this.body += encodeURIComponent(this.encode(data[argName]));
} catch (e) {
throw Prado.AJAX.Error(e, 1006);
}
sep = '&';
}
},
getAll : function()
{
this.build(this.data);
return this.body;
}
}
Prado.AJAX.RemoteObject = function(){};
/**
* AJAX service request for Prado RemoteObjects
*/
Prado.AJAX.RemoteObject.Request = Class.create();
Prado.AJAX.RemoteObject.Request.prototype = Object.extend(Prado.AJAX.Request.prototype,
{
/**
* Initialize the RemoteObject Request, overrides parent
* implementation by delaying the request to invokeRemoteObject.
*/
initialize : function(options)
{
this.transport = Ajax.getTransport();
this.setOptions(options);
this.post = new Prado.AJAX.RequestBuilder();
},
/**
* Call the remote object,
* @param string the remote server url
* @param array additional arguments
*/
invokeRemoteObject : function(url, args)
{
this.initParameters(args);
this.options.postBody = this.post.getAll();
this.request(url);
},
/**
* Set the additional arguments as post data with key '__parameters'
*/
initParameters : function(args)
{
this.post.data['__parameters'] = [];
for(var i = 0; i<args.length; i++)
this.post.data['__parameters'][i] = args[i];
}
});
/**
* Base proxy class for Prado RemoteObjects via AJAX.
* e.g.
* <code>
* var TestObject1 = Class.create();
* TestObject1.prototype = Object.extend(new Prado.AJAX.RemoteObject(),
* {
* initialize : function(handlers, options)
* {
* this.__serverurl = 'http://127.0.0.1/.....';
* this.baseInitialize(handlers, options);
* }
*
* method1 : function()
* {
* return this.__call(this.__serverurl, 'method1', arguments);
* }
* });
*</code>
* And client usage,
* <code>
* var test1 = new TestObject1(); //create new remote object
* test1.method1(); //call the method, no onComplete hook
*
* var onComplete = { method1 : function(result){ alert(result) } };
* //create new remote object with onComplete callback
* var test2 = new TestObject1(onComplete);
* test2.method1(); //call it, on success, onComplete's method1 is called.
* </code>
*/
Prado.AJAX.RemoteObject.prototype =
{
baseInitialize : function(handlers, options)
{
this.__handlers = handlers || {};
this.__service = new Prado.AJAX.RemoteObject.Request(options);
},
__call : function(url, method, args)
{
this.__service.options.onSuccess = this.__onSuccess.bind(this);
this.__callback = method;
return this.__service.invokeRemoteObject(url+"/"+method, args);
},
__onSuccess : function(transport, json)
{
if(this.__handlers[this.__callback])
this.__handlers[this.__callback](json, transport.responseText);
}
};
/**
* Respond to Prado AJAX request exceptions.
*/
Prado.AJAX.Exception =
{
/**
* Server returns 505 exception. Just log it.
*/
"on505" : function(request, transport, e)
{
var msg = 'HTTP '+transport.status+" with response";
Logger.error(msg, transport.responseText);
Logger.exception(e);
},
onComplete : function(request, transport, e)
{
if(transport.status != 505)
{
var msg = 'HTTP '+transport.status+" with response : \n";
msg += transport.responseText + "\n";
msg += "Data : \n"+e;
Logger.warn(msg);
}
},
format : function(e)
{
var msg = e.type + " with message \""+e.message+"\"";
msg += " in "+e.file+"("+e.line+")\n";
msg += "Stack trace:\n";
var trace = e.trace;
for(var i = 0; i<trace.length; i++)
{
msg += " #"+i+" "+trace[i].file;
msg += "("+trace[i].line+"): ";
msg += trace[i]["class"]+"->"+trace[i]["function"]+"()"+"\n";
}
return msg;
},
logException : function(e)
{
var msg = Prado.AJAX.Exception.format(e);
Logger.error("Server Error "+e.code, msg);
}
}
//Add HTTP exception respones when logger is enabled.
Event.OnLoad(function()
{
if(typeof Logger != "undefined")
{
Logger.exception = Prado.AJAX.Exception.logException;
Ajax.Responders.register(Prado.AJAX.Exception);
}
});
/**
* Prado Callback service that provides component intergration,
* viewstate (read only), and automatic form data serialization.
* Usage: <code>new Prado.AJAX.Callback('MyPage.MyComponentID.raiseCallbackEvent', options)</code>
* These classes should be called by the components developers.
* For inline callback service, use <t>Prado.Callback(callbackID, params)</t>.
*/
Prado.AJAX.Callback = Class.create();
Prado.AJAX.Callback.prototype = Object.extend(new Prado.AJAX.RemoteObject(),
{
/**
* Create and request a new Prado callback service.
* @param string the callback ID, must be of the form, <t>ClassName.ComponentID.MethodName</t>
* @param list options with list key onCallbackReturn, and more.
*
*/
initialize : function(ID, options)
{
if(!isString(ID))
throw new Error('A Control ID must be specified');
this.baseInitialize(this, options);
this.options = options || [];
this.__service.post.data['__ID'] = ID;
this.requestCallback();
},
/**
* Get form data for components that implements IPostBackHandler.
*/
collectPostData : function()
{
var IDs = Prado.AJAX.Callback.IDs;
this.__service.post.data['__data'] = {};
for(var i = 0; i<IDs.length; i++)
this.__service.post.data['__data'][IDs[i]] = $F(IDs[i]);
},
/**
* Prepares and calls the AJAX request.
* Collects the data from components that implements IPostBackHandler
* and the viewstate as part of the request payload.
*/
requestCallback : function()
{
this.collectPostData();
return this.__call(Prado.AJAX.Callback.Server, 'handleCallback', this.options.params);
},
/**
* On callback request return, call the onSuccess function.
*/
handleCallback : function(result, output)
{
this.options.onSuccess(result, output);
}
});
//Available callback service
Prado.AJAX.Callback.Server = '';
//List of IDs that implements IPostBackHandler
Prado.AJAX.Callback.IDs = [];
/**
* Simple AJAX callback interface, suitable for inline javascript.
* e.g., <code><a href="..." onclick="Prado.Callback('..', 'Hello');">Click me</a></code>
* @param string callback ID
* @param array parameters to pass to the callback service
*/
Prado.Callback = function(ID, params, onSuccess)
{
var options =
{
'params' : [params] || [],
'onSuccess' : onSuccess || Prototype.emptyFunction
};
new Prado.AJAX.Callback(ID, options);
return false;
}