From 1c4f65120c7532b8944e5b6fba9bcf403a108e5c Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Tue, 20 Aug 2013 12:06:41 +0000 Subject: [PATCH] new egw_framework methods refresh_opener and window_close to call egw_refresh on opener or close popup window in a content security save way --- etemplate/inc/class.etemplate.inc.php | 18 +++---- etemplate/js/etemplate2.js | 30 +++++++++++ phpgwapi/inc/class.egw_framework.inc.php | 64 ++++++++++++++++++++++-- timesheet/inc/class.timesheet_ui.inc.php | 18 ++----- timesheet/templates/default/index.xet | 33 ++---------- 5 files changed, 107 insertions(+), 56 deletions(-) diff --git a/etemplate/inc/class.etemplate.inc.php b/etemplate/inc/class.etemplate.inc.php index 3e78434abf..426cf61699 100644 --- a/etemplate/inc/class.etemplate.inc.php +++ b/etemplate/inc/class.etemplate.inc.php @@ -133,7 +133,7 @@ class etemplate_new extends etemplate_widget_template 'modifications' => self::$request->modifications, 'validation_errors' => self::$validation_errors, ); - + // Info required to load the etemplate client-side $dom_id = str_replace('.','-',$this->name); $load_array = array( @@ -145,7 +145,7 @@ class etemplate_new extends etemplate_widget_template if (self::$response) // call is within an ajax event / form submit { //error_log("Ajax " . __LINE__); - self::$response->generic('et2_load', $load_array); + self::$response->generic('et2_load', $load_array+egw_framework::get_extra()); } else // first call { @@ -197,7 +197,7 @@ class etemplate_new extends etemplate_widget_template $GLOBALS['egw']->framework->footer(); } ob_flush(); - + // Send any accumulated json responses - after flush to avoid sending the buffer as a response if(egw_json_response::isJSONResponse()) { @@ -216,10 +216,10 @@ class etemplate_new extends etemplate_widget_template */ static public function ajax_process_content($etemplate_exec_id, array $content) { - error_log(__METHOD__."(".array2string($etemplate_exec_id).', '.array2string($content).")"); + //error_log(__METHOD__."(".array2string($etemplate_exec_id).', '.array2string($content).")"); self::$request = etemplate_request::read($etemplate_exec_id); - error_log('request='.array2string(self::$request)); + //error_log('request='.array2string(self::$request)); self::$response = egw_json_response::get(); @@ -246,17 +246,17 @@ class etemplate_new extends etemplate_widget_template self::$response->generic('et2_validation_error', self::$validation_errors); exit; } - error_log(__METHOD__."(,".array2string($content).')'); - error_log(' validated='.array2string($validated)); + //error_log(__METHOD__."(,".array2string($content).')'); + //error_log(' validated='.array2string($validated)); $content = ExecMethod(self::$request->method, self::complete_array_merge(self::$request->preserv, $validated)); if (isset($GLOBALS['egw_info']['flags']['java_script'])) { // Strip out any script tags $GLOBALS['egw_info']['flags']['java_script'] = preg_replace(array('/(]*>)([^<]*)/is','/<\/script>/'),array('$2',''),$GLOBALS['egw_info']['flags']['java_script']); self::$response->script($GLOBALS['egw_info']['flags']['java_script']); - error_log($app .' added javascript to $GLOBALS[egw_info][flags][java_script] - use egw_json_response->script() instead.'); + //error_log($app .' added javascript to $GLOBALS[egw_info][flags][java_script] - use egw_json_response->script() instead.'); } - + return $content; } diff --git a/etemplate/js/etemplate2.js b/etemplate/js/etemplate2.js index 7544c33258..4f1ff02e2a 100644 --- a/etemplate/js/etemplate2.js +++ b/etemplate/js/etemplate2.js @@ -597,10 +597,34 @@ etemplate2.getByApplication = function(app) return list; }; +/** + * Plugin for egw.json type "et2_load" + * + * @param _type + * @param _response + * @returns {Boolean} + */ function etemplate2_handle_load(_type, _response) { // Check the parameters var data = _response.data; + + // handle egw_framework::refresh_opener() + if (jQuery.isArray(data['refresh-opener'])) + { + if (window.opener && typeof window.opener.egw_refresh == 'function') + { + window.opener.egw_refresh.apply(window.opener, data['refresh-opener']); + } + } + + // handle egw_framework::close_window(), this will terminate execution + if (data['window-close']) + { + window.close(); + } + + // regular et2 re-load if (typeof data.url == "string" && typeof data.data === 'object') { if(typeof this.load == 'function') @@ -629,6 +653,12 @@ function etemplate2_handle_load(_type, _response) throw("Error while parsing et2_load response"); } +/** + * Plugin for egw.json type "et2_validation_error" + * + * @param _type + * @param _response + */ function etemplate2_handle_validation_error(_type, _response) { // Display validation errors diff --git a/phpgwapi/inc/class.egw_framework.inc.php b/phpgwapi/inc/class.egw_framework.inc.php index f67f279867..481252094b 100644 --- a/phpgwapi/inc/class.egw_framework.inc.php +++ b/phpgwapi/inc/class.egw_framework.inc.php @@ -156,12 +156,68 @@ abstract class egw_framework if (!isset($GLOBALS['egw_info']['flags']['nonavbar']) || !$GLOBALS['egw_info']['flags']['nonavbar']) { - echo $this->navbar(); + echo $this->navbar(); } echo $content; echo $this->footer(); - } + } + + /** + * Extra values send as data attributes to script tag of egw.js + * + * @var array + */ + protected static $extra = array(); + + /** + * Refresh given application $targetapp display of entry $app $id, incl. outputting $msg + * + * Calling egw_refresh on opener in a content security save way + * + * @param string $msg message (already translated) to show, eg. 'Entry deleted' + * @param string $app application name + * @param string|int $id=null id of entry to refresh + * @param string $type=null either 'edit', 'delete', 'add' or null + * @param string $targetapp=null which app's window should be refreshed, default current + * @param string|RegExp $replace=null regular expression to replace in url + * @param string $with=null + */ + public static function refresh_opener($msg, $app, $id=null, $type=null, $targetapp=null, $replace=null, $with=null) + { + error_log(__METHOD__.'('.array2string(func_get_args()).')'); + self::$extra['refresh-opener'] = func_get_args(); + } + + /** + * Close (popup) window, use to replace egw_framework::onload('window.close()') in a content security save way + */ + public static function window_close() + { + error_log(__METHOD__."()"); + self::$extra['window-close'] = true; + + if ($_GET['menuaction'] === 'etemplate_new::ajax_process_content') + { + $response = egw_json_response::get(); + $response->generic('et2_load', egw_framework::get_extra()); + } + else + { + $GLOBALS['egw']->framework->render('', false, false); + } + common::egw_exit(); + } + + /** + * Allow eg. ajax to query content set via refresh_opener or window_close + * + * @return array content of egw_framework::$extra + */ + public static function get_extra() + { + return self::$extra; + } /** * Returns the html-header incl. the opening body tag @@ -823,7 +879,9 @@ abstract class egw_framework // Load LABjs ONCE here $java_script .= '\n". '\n\n\n"; - common::egw_exit(); - break; + egw_framework::window_close(); } } $preserv = $this->data + array( @@ -316,7 +313,6 @@ class timesheet_ui extends timesheet_bo 'to_id' => $this->data['ts_id'] ? $this->data['ts_id'] : $content['link_to']['to_id'], 'to_app' => TIMESHEET_APP, ), - 'js' => "\n", 'ts_quantity_blur' => $this->data['ts_duration'] ? round($this->data['ts_duration'] / 60.0,3) : '', 'start_time' => egw_time::to($this->data['ts_start'],'H:i'), 'pm_integration' => $this->pm_integration, @@ -396,16 +392,10 @@ class timesheet_ui extends timesheet_bo ), ); $sel_options['status'] = $this->field2label; - if (empty($content['ts_title'])) - { - $content['ts_title'] = $content['ts_title_blur'] = ($preserv['ts_title_blur'] ? $preserv['ts_title_blur'] : $preserv['ts_project_blur']); - } // the actual title-blur is either the preserved title blur (if we are called from infolog entry), // or the preserved project-blur comming from the current selected project $content['ts_title_blur'] = $preserv['ts_title_blur'] ? $preserv['ts_title_blur'] : $preserv['ts_project_blur']; - // make sure that ts_title is shown (if set), by unsetting the blur text - if (!empty($content['ts_title']) && $content['ts_title']==$content['ts_title_blur']) unset($content['ts_title_blur']); $readonlys = array( 'button[delete]' => !$this->data['ts_id'] || !$this->check_acl(EGW_ACL_DELETE) || $this->data['ts_status'] == self::DELETED_STATUS, 'button[undelete]' => $this->data['ts_status'] != self::DELETED_STATUS, diff --git a/timesheet/templates/default/index.xet b/timesheet/templates/default/index.xet index 273730de0e..4dbebb6177 100644 --- a/timesheet/templates/default/index.xet +++ b/timesheet/templates/default/index.xet @@ -13,7 +13,7 @@