mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-21 23:43:17 +01:00
ability to queue ajax requests on the client and send them as a single ajax request every N ms to the server
a) instead of a single request like: new egw_json_request(menuaction, params).sendRequest(true, callback, context); b) you call: egw.jsonq(menuaction,params,callback,context) The server callback is identical for both kinds of requests. All egw_json_response methods can be used and the callback is optional.
This commit is contained in:
parent
077acb3fb0
commit
516b977472
2
json.php
2
json.php
@ -100,7 +100,7 @@ if (isset($_GET['menuaction']))
|
|||||||
{
|
{
|
||||||
throw new egw_exception_assertion_failed("JSON Data contains script tags. Aborting...");
|
throw new egw_exception_assertion_failed("JSON Data contains script tags. Aborting...");
|
||||||
}
|
}
|
||||||
$json->parseRequest($_GET['menuaction'], (array)$_POST['json_data']);
|
$json->parseRequest($_GET['menuaction'], $_POST['json_data']);
|
||||||
egw_json_response::get();
|
egw_json_response::get();
|
||||||
common::egw_exit();
|
common::egw_exit();
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@ class egw_json_request
|
|||||||
* Parses the raw input data supplied with the input_data parameter and calls the menuaction
|
* Parses the raw input data supplied with the input_data parameter and calls the menuaction
|
||||||
* passing all parameters supplied in the request to it.
|
* passing all parameters supplied in the request to it.
|
||||||
*
|
*
|
||||||
|
* Also handle queued requests (menuaction == 'home.queue') containing multiple requests
|
||||||
|
*
|
||||||
* @param string menuaction to call
|
* @param string menuaction to call
|
||||||
* @param string $input_data is the RAW input data as it was received from the client
|
* @param string $input_data is the RAW input data as it was received from the client
|
||||||
*/
|
*/
|
||||||
@ -35,36 +37,34 @@ class egw_json_request
|
|||||||
// Remember that we currently are in a JSON request - e.g. used in the redirect code
|
// Remember that we currently are in a JSON request - e.g. used in the redirect code
|
||||||
self::$_hadJSONRequest = true;
|
self::$_hadJSONRequest = true;
|
||||||
|
|
||||||
if (empty($input_data))
|
if (get_magic_quotes_gpc()) $input_data = stripslashes($input_data);
|
||||||
|
|
||||||
|
$json_data = json_decode($input_data,true);
|
||||||
|
if (is_array($json_data) && isset($json_data['request']) && isset($json_data['request']['parameters']))
|
||||||
{
|
{
|
||||||
$this->handleRequest($menuaction, array());
|
$parameters =& $json_data['request']['parameters'];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (get_magic_quotes_gpc())
|
$parameters = array();
|
||||||
|
}
|
||||||
|
// do we have a single request or an array of queued requests
|
||||||
|
if ($menuaction == 'home.queue')
|
||||||
|
{
|
||||||
|
$responses = array();
|
||||||
|
$response = egw_json_response::get();
|
||||||
|
foreach($parameters as $uid => $data)
|
||||||
{
|
{
|
||||||
$input_data[0] = stripslashes($input_data[0]);
|
//error_log("$uid: menuaction=$data[menuaction], parameters=".array2string($data['parameters']));
|
||||||
}
|
$this->handleRequest($data['menuaction'], $data['parameters']);
|
||||||
|
$responses[$uid] = $response->initResponseArray();
|
||||||
//Decode the JSON input data into associative arrays
|
//error_log("responses[$uid]=".array2string($responses[$uid]));
|
||||||
if (($json = json_decode($input_data[0], true)) !== false)
|
|
||||||
{
|
|
||||||
$parameters = array();
|
|
||||||
|
|
||||||
//Get the request array
|
|
||||||
if (isset($json['request']))
|
|
||||||
{
|
|
||||||
$request = $json['request'];
|
|
||||||
|
|
||||||
//Check whether any parameters were supplied along with the request
|
|
||||||
if (isset($request['parameters']))
|
|
||||||
{
|
|
||||||
$parameters = $request['parameters'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Call the supplied callback function along with the menuaction and the passed parameters
|
|
||||||
$this->handleRequest($menuaction, $parameters);
|
|
||||||
}
|
}
|
||||||
|
$response->data($responses); // send all responses as data
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->handleRequest($menuaction, $parameters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,6 +246,20 @@ class egw_json_response
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init responseArray
|
||||||
|
*
|
||||||
|
* @param array $arr
|
||||||
|
* @return array previous content
|
||||||
|
*/
|
||||||
|
public function initResponseArray()
|
||||||
|
{
|
||||||
|
$return = $this->responseArray;
|
||||||
|
$this->responseArray = array();
|
||||||
|
$this->hasData = false;
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a "data" response to the json response.
|
* Adds a "data" response to the json response.
|
||||||
*
|
*
|
||||||
@ -309,9 +323,56 @@ class egw_json_response
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows to add a global javascript function with giben parameters
|
* Allows to call a global javascript function with given parameters: window[$func].apply(window, $parameters)
|
||||||
*
|
*
|
||||||
* @param string $script the script code which should be executed upon receiving
|
* @param string $func name of the global (window) javascript function to call
|
||||||
|
* @param array $parameters=array()
|
||||||
|
*/
|
||||||
|
public function apply($function,array $parameters=array())
|
||||||
|
{
|
||||||
|
if (is_string($function))
|
||||||
|
{
|
||||||
|
$this->addGeneric('apply', array(
|
||||||
|
'func' => $function,
|
||||||
|
'parms' => $parameters,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Invalid parameters supplied.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to call a global javascript function with given parameters: window[$func].call(window[, $param1[, ...]])
|
||||||
|
*
|
||||||
|
* @param string $func name of the global (window) javascript function to call
|
||||||
|
* @param mixed $parameters variable number of parameters
|
||||||
|
*/
|
||||||
|
public function call($function)
|
||||||
|
{
|
||||||
|
$parameters = func_get_args();
|
||||||
|
array_shift($parameters); // shift off $function
|
||||||
|
|
||||||
|
if (is_string($function))
|
||||||
|
{
|
||||||
|
$this->addGeneric('apply', array(
|
||||||
|
'func' => $function,
|
||||||
|
'parms' => $parameters,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Invalid parameters supplied.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to call a jquery function on a selector with given parameters: $j($selector).$func($parmeters)
|
||||||
|
*
|
||||||
|
* @param string $selector jquery selector
|
||||||
|
* @param string $method name of the jquery to call
|
||||||
|
* @param array $parameters=array()
|
||||||
*/
|
*/
|
||||||
public function jquery($selector,$method,array $parameters=array())
|
public function jquery($selector,$method,array $parameters=array())
|
||||||
{
|
{
|
||||||
@ -498,7 +559,7 @@ class xajaxResponse extends egw_json_response
|
|||||||
$args = func_get_args();
|
$args = func_get_args();
|
||||||
$func = array_shift($args);
|
$func = array_shift($args);
|
||||||
|
|
||||||
$this->script("try{window['".$func."'].apply(window, ".json_encode($args).");} catch(e) {_egw_json_debug_log(e);}");
|
$this->apply($func, $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addIncludeCSS($url)
|
public function addIncludeCSS($url)
|
||||||
|
@ -223,7 +223,7 @@ function egw_json_request(_menuaction, _parameters, _context)
|
|||||||
if (_menuaction.match(/json.php\?menuaction=[a-z_0-9]*\.[a-z_0-9]*\.[a-z_0-9]*/i))
|
if (_menuaction.match(/json.php\?menuaction=[a-z_0-9]*\.[a-z_0-9]*\.[a-z_0-9]*/i))
|
||||||
{
|
{
|
||||||
// Menuaction is a full featured url
|
// Menuaction is a full featured url
|
||||||
this.url = _menuaction
|
this.url = _menuaction;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -401,7 +401,7 @@ egw_json_request.prototype.handleResponse = function(data, textStatus, XMLHttpRe
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var func = function() {eval(res.data);};
|
var func = new Function(res.data);
|
||||||
func.call(window);
|
func.call(window);
|
||||||
}
|
}
|
||||||
catch (e)
|
catch (e)
|
||||||
@ -413,6 +413,22 @@ egw_json_request.prototype.handleResponse = function(data, textStatus, XMLHttpRe
|
|||||||
} else
|
} else
|
||||||
throw 'Invalid parameters';
|
throw 'Invalid parameters';
|
||||||
break;
|
break;
|
||||||
|
case 'apply':
|
||||||
|
if (typeof res.data.func == 'string' && typeof window[res.data.func] == 'function')
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
window[res.data.func].apply(window, res.data.parameters);
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
e.code = res.data.func;
|
||||||
|
_egw_json_debug_log(e);
|
||||||
|
}
|
||||||
|
hasResponse = true;
|
||||||
|
} else
|
||||||
|
throw 'Invalid parameters';
|
||||||
|
break;
|
||||||
case 'jquery':
|
case 'jquery':
|
||||||
if (typeof res.data.select == 'string' &&
|
if (typeof res.data.select == 'string' &&
|
||||||
typeof res.data.func == 'string')
|
typeof res.data.func == 'string')
|
||||||
|
@ -639,6 +639,117 @@ else
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return query.length ? _url+'?'+query.join('&') : _url;
|
return query.length ? _url+'?'+query.join('&') : _url;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queued json requests (objects with attributes menuaction, parameters, context, callback, sender and callbeforesend)
|
||||||
|
*
|
||||||
|
* @access private, use jsonq method to queue requests
|
||||||
|
*/
|
||||||
|
jsonq_queue: {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Next uid (index) in queue
|
||||||
|
*/
|
||||||
|
jsonq_uid: 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Running timer for next send of queued items
|
||||||
|
*/
|
||||||
|
jsonq_timer: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a queued JSON call to the server
|
||||||
|
*
|
||||||
|
* @param string _menuaction the menuaction function which should be called and
|
||||||
|
* which handles the actual request. If the menuaction is a full featured
|
||||||
|
* url, this one will be used instead.
|
||||||
|
* @param array _parameters which should be passed to the menuaction function.
|
||||||
|
* @param _callback callback function which should be called upon a "data" response is received
|
||||||
|
* @param _sender is the reference object the callback function should get
|
||||||
|
* @param _callbeforesend optional callback function which can modify the parameters, eg. to do some own queuing
|
||||||
|
*/
|
||||||
|
jsonq: function(_menuaction, _parameters, _callback, _sender, _callbeforesend)
|
||||||
|
{
|
||||||
|
this.jsonq_queue['u'+(this.jsonq_uid++)] = {
|
||||||
|
menuaction: _menuaction,
|
||||||
|
parameters: _parameters,
|
||||||
|
callback: _callback,
|
||||||
|
sender: _sender,
|
||||||
|
callbeforesend: _callbeforesend
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.jsonq_time == null)
|
||||||
|
{
|
||||||
|
// check / send queue every N ms
|
||||||
|
var self = this;
|
||||||
|
this.jsonq_timer = window.setInterval(function(){ self.jsonq_send();}, 100);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the whole job-queue to the server in a single json request with menuaction=queue
|
||||||
|
*/
|
||||||
|
jsonq_send: function()
|
||||||
|
{
|
||||||
|
if (this.jsonq_uid > 0 && typeof this.jsonq_queue['u'+(this.jsonq_uid-1)] == 'object')
|
||||||
|
{
|
||||||
|
var jobs_to_send = {};
|
||||||
|
var something_to_send = false;
|
||||||
|
for(var uid in this.jsonq_queue)
|
||||||
|
{
|
||||||
|
var job = this.jsonq_queue[uid];
|
||||||
|
|
||||||
|
if (job.menuaction == 'send') continue; // already send to server
|
||||||
|
|
||||||
|
// if job has a callbeforesend callback, call it to allow it to modify pararmeters
|
||||||
|
if (typeof job.callbeforesend == 'function')
|
||||||
|
{
|
||||||
|
job.callbeforesend.apply(job.context, job.parameters);
|
||||||
|
}
|
||||||
|
jobs_to_send[uid] = {
|
||||||
|
menuaction: job.menuaction,
|
||||||
|
parameters: job.parameters
|
||||||
|
};
|
||||||
|
job.menuaction = 'send';
|
||||||
|
job.parameters = null;
|
||||||
|
something_to_send = true;
|
||||||
|
}
|
||||||
|
if (something_to_send)
|
||||||
|
{
|
||||||
|
new egw_json_request('home.queue', jobs_to_send, this).sendRequest(true, this.jsonq_callback, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch responses received
|
||||||
|
*
|
||||||
|
* @param object _data uid => response pairs
|
||||||
|
*/
|
||||||
|
jsonq_callback: function(_data)
|
||||||
|
{
|
||||||
|
if (typeof _data != 'object') throw "jsonq_callback called with NO object as parameter!";
|
||||||
|
|
||||||
|
var json = new egw_json_request('none');
|
||||||
|
for(var uid in _data)
|
||||||
|
{
|
||||||
|
if (typeof this.jsonq_queue[uid] == 'undefined')
|
||||||
|
{
|
||||||
|
console.log("jsonq_callback received response for not existing queue uid="+uid+"!");
|
||||||
|
console.log(_data[uid]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var job = this.jsonq_queue[uid];
|
||||||
|
var response = _data[uid];
|
||||||
|
|
||||||
|
// fake egw_json_request object, to call it with the current response
|
||||||
|
json.callback = job.callback;
|
||||||
|
json.sender = job.sender;
|
||||||
|
json.handleResponse({response: response});
|
||||||
|
|
||||||
|
delete this.jsonq_queue[uid];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user