diff --git a/phpgwapi/inc/class.egw_json.inc.php b/phpgwapi/inc/class.egw_json.inc.php index a40d50b329..758653240c 100644 --- a/phpgwapi/inc/class.egw_json.inc.php +++ b/phpgwapi/inc/class.egw_json.inc.php @@ -184,9 +184,10 @@ class egw_json_response */ public function sendResult() { - $this->sendHeader(); + $inst = self::get(); - echo $this->getJSON(); + $inst->sendHeader(); + echo $inst->getJSON(); } /** @@ -202,7 +203,7 @@ class egw_json_response */ protected function addGeneric($key, $data) { - $this->responseArray[] = array( + self::get()->responseArray[] = array( 'type' => $key, 'data' => $data, ); @@ -218,10 +219,11 @@ class egw_json_response public function data($data) { /* Only allow adding the data response once */ - if (!$this->hasData) + $inst = self::get(); + if (!$inst->hasData) { - $this->addGeneric('data', $data); - $this->hasData = true; + $inst->addGeneric('data', $data); + $inst->hasData = true; } else { @@ -317,6 +319,8 @@ class egw_json_response * Redirect to given url * * @param string $url + * @param boolean $global specifies whether to redirect the whole framework + * or only the current application */ public function redirect($url, $global = false) { @@ -330,6 +334,43 @@ class egw_json_response } } + /** + * Displays an error message on the client + */ + public function error($msg) + { + if (is_string($msg)) + { + $this->addGeneric('error', $msg); + } + } + + /** + * Includes the given CSS file. Every url can only be included once. + * + * @param string $url specifies the url to the css file to include + */ + public function includeCSS($url) + { + if (is_string($url)) + { + $this->addGeneric('css', $url); + } + } + + /** + * Includes the given JS file. Every url can only be included once. + * + * @param string $url specifies the url to the css file to include + */ + public function includeScript($url) + { + if (is_string($url)) + { + self::get()->addGeneric('js', $url); + } + } + /** * Returns the actual JSON code generated by calling the above "add" function. * @@ -337,8 +378,10 @@ class egw_json_response */ public function getJSON() { + $inst = self::get(); + /* Wrap the result array into a parent "response" Object */ - $res = array('response' => $this->responseArray); + $res = array('response' => $inst->responseArray); return json_encode($res); //PHP5.3+, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP); } @@ -348,7 +391,9 @@ class egw_json_response */ public function __destruct() { - $this->sendResult(); + //Only send the response if this instance is the singleton instance + if ($this == self::get()) + $this->sendResult(); } } @@ -382,7 +427,17 @@ class egw_json_response $args = func_get_args(); $func = array_shift($args); - $this->script("window['".$func."'].apply(window, ".json_encode($args).");"); + $this->script("try{window['".$func."'].apply(window, ".json_encode($args).");} catch(e) {_egw_json_debug_log(e);}"); + } + + public function addIncludeCSS($url) + { + $this->includeCSS($url); + } + + public function addIncludeScript($url) + { + $this->includeScript($url); } public function getXML() diff --git a/phpgwapi/js/egw_json.js b/phpgwapi/js/egw_json.js index 7cee892ca6..a479dabf64 100644 --- a/phpgwapi/js/egw_json.js +++ b/phpgwapi/js/egw_json.js @@ -116,15 +116,24 @@ function egw_json_encode(input) } -/* The constructor of the egw_json_request class. +/** + * Some variables needed to store which JS and CSS files have already be included + */ +var egw_json_files = {}; + +/** The constructor of the egw_json_request class. * @param string _menuaction the menuaction function which should be called and which handles the actual request * @param array _parameters which should be passed to the menuaction function. -*/ -function egw_json_request(_menuaction, _parameters) + */ +function egw_json_request(_menuaction, _parameters, _context) { //Copy the supplied parameters this.menuaction = _menuaction; + this.context = window.document; + if (typeof _context != 'undefined') + this.context = _context; + if (typeof _parameters != 'undefined') { this.parameters = _parameters; @@ -187,7 +196,9 @@ egw_json_request.prototype.sendRequest = function(_async, _callback, _sender) data: request_obj, dataType: 'json', type: 'POST', - success: this.handleResponse}); + success: this.handleResponse, + error: function(_xmlhttp,_err) { alert('Ajax request to '+this.url+'?menuaction='+this.menuaction+' failed: '+_err); } + }); } egw_json_request.prototype.alertFunc = function(_message, _details) @@ -195,14 +206,24 @@ egw_json_request.prototype.alertFunc = function(_message, _details) alert(_message); } -function _egw_json_debug_log(_msg) +function _egw_json_debug_log(_msg, _e) { if (typeof console != "undefined" && typeof console.log != "undefined") { - console.log(_msg); + console.log(_msg, _e); } } +/* Displays an json error message */ +egw_json_request.prototype.jsonError = function(_msg, _e) +{ + var msg = 'EGW JSON Error: '._msg; + + //Log and show the error message + _egw_json_bebug_log(msg, _e); + this.alertHandler(msg); +} + /* Internal function which handles the response from the server */ egw_json_request.prototype.handleResponse = function(data, textStatus, XMLHttpRequest) { @@ -211,93 +232,152 @@ egw_json_request.prototype.handleResponse = function(data, textStatus, XMLHttpRe var hasResponse = false; for (var i = 0; i < data.response.length; i++) { - var res = data.response[i]; - - switch (data.response[i].type) + try { - case 'alert': - //Check whether all needed parameters have been passed and call the alertHandler function - if ((typeof res.data.message != 'undefined') && - (typeof res.data.details != 'undefined')) - { - this.alertHandler( - res.data.message, - res.data.details) - hasResponse = true; - } - break; - case 'assign': - //Check whether all needed parameters have been passed and call the alertHandler function - if ((typeof res.data.id != 'undefined') && - (typeof res.data.key != 'undefined') && - (typeof res.data.value != 'undefined')) - { - var obj = document.getElementById(res.data.id); - if (obj) + var res = data.response[i]; + + switch (data.response[i].type) + { + case 'alert': + //Check whether all needed parameters have been passed and call the alertHandler function + if ((typeof res.data.message != 'undefined') && + (typeof res.data.details != 'undefined')) + { + this.alertHandler( + res.data.message, + res.data.details) + hasResponse = true; + } else + throw 'Invalid parameters'; + break; + case 'assign': + //Check whether all needed parameters have been passed and call the alertHandler function + if ((typeof res.data.id != 'undefined') && + (typeof res.data.key != 'undefined') && + (typeof res.data.value != 'undefined')) + { + var obj = document.getElementById(res.data.id); + if (obj) + { + obj[res.data.key] = res.data.value; + hasResponse = true; + } + } else + throw 'Invalid parameters'; + break; + case 'data': + //Callback the caller in order to allow him to handle the data + if (this.callback) { - obj[res.data.key] = res.data.value; + this.callback.call(this.sender, res.data); hasResponse = true; } - } - break; - case 'data': - //Callback the caller in order to allow him to handle the data - if (this.callback) - { - this.callback.call(this.sender, res.data); - hasResponse = true; - } - break; - case 'script': - if (typeof res.data == 'string') - { - try + break; + case 'script': + if (typeof res.data == 'string') { - var func = function() {eval(res.data);}; - func.call(window); - } - catch (e) + try + { + var func = function() {eval(res.data);}; + func.call(window); + } + catch (e) + { + e.code = res.data; + _egw_json_debug_log(e); + } + hasResponse = true; + } else + throw 'Invalid parameters'; + break; + case 'jquery': + if (typeof res.data.select == 'string' && + typeof res.data.func == 'string') { - e.code = res.data; - _egw_json_debug_log(e); - } - hasResponse = true; - } - break; - case 'jquery': - if (typeof res.data.select == 'string' && - typeof res.data.func == 'string') - { - try + try + { + var jQueryObject = $(res.data.select, this.context); + jQueryObject[res.data.func].apply(jQueryObject, res.data.parms); + } + catch (e) + { + _egw_json_debug_log(e); + } + hasResponse = true; + } else + throw 'Invalid parameters'; + break; + case 'redirect': + if (typeof res.data.url == 'string' && + typeof res.data.global == 'boolean') { - var jQueryObject = $(res.data.select); - jQueryObject[res.data.func].apply(jQueryObject, res.data.parms); - } - catch (e) - { - _egw_json_debug_log(e); - } - hasResponse = true; - } - break; - case 'redirect': - if (typeof res.data.url == 'string' && - typeof res.data.global == 'boolean') - { - //Special handling for framework reload - if (res.data.url.indexOf("?cd=10") > 0) - res.data.global = true; + //Special handling for framework reload + if (res.data.url.indexOf("?cd=10") > 0) + res.data.global = true; - if (res.data.global) + if (res.data.global) + { + egw_topWindow().location.href = res.data.url; + } + else + { + window.location.href = res.data.url; + } + + hasResponse = true; + } else + throw 'Invalid parameters'; + break; + case 'css': + if (typeof res.data == 'string') { - egw_topWindow().location.href = res.data.url; - } - else + //Check whether the requested file had already be included + if (!egw_json_files[res.data]) + { + egw_json_files[res.data] = true; + + //Get the head node and append a new link node with the stylesheet url to it + var headID = document.getElementsByTagName('head')[0]; + var cssnode = document.createElement('link'); + cssnode.type = "text/css"; + cssnode.rel = "stylesheet"; + cssnode.href = res.data; + headID.appendChild(cssnode); + } + hasResponse = true; + } else + throw 'Invalid parameters'; + break; + case 'js': + if (typeof res.data == 'string') { - window.location.href = res.data.url; - } - } - break; + //Check whether the requested file had already be included + if (!egw_json_files[res.data]) + { + egw_json_files[res.data] = true; + + //Get the head node and append a new script node with the js file to it + var headID = document.getElementsByTagName('head')[0]; + var scriptnode = document.createElement('script'); + scriptnode.type = "text/javascript"; + scriptnode.src = res.data; + headID.appendChild(scriptnode); + } + hasResponse = true; + } else + throw 'Invalid parameters'; + break; + case 'error': + if (typeof res.data == 'string') + { + this.jsonError(res.data); + hasResponse = true; + } else + throw 'Invalid parameters'; + break; + } + } catch(e) { + this.jsonError('Internal JSON handler error', e); } } diff --git a/phpgwapi/js/jsapi/jsapi.js b/phpgwapi/js/jsapi/jsapi.js index bfc3505515..b5d845eb9c 100644 --- a/phpgwapi/js/jsapi/jsapi.js +++ b/phpgwapi/js/jsapi/jsapi.js @@ -39,19 +39,53 @@ else if (document.layers) is_ns4 = true; } +/** + * Seperates all script tags from the given html code and returns the seperately + * @param object _html object that the html code from which the script should be seperated. The html code has to be stored in _html.html, the result js will be written to _html.js + */ + +egw_seperateJavaScript = function(_html) +{ + var html = _html.html; + + var in_pos = html.search(/ tag */ + var js_str = html.substring(in_pos, out_pos+9); + + /*Remove the initial tag */ + /*js_str = js_str.substring(js_str.search(/>/) + 1);*/ + _html.js += js_str; + + + html = html.substring(0, in_pos) + html.substring(out_pos + 9); + + var in_pos = html.search(/