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

This commit is contained in:
Ralf Becker 2013-08-20 12:06:41 +00:00
parent 8c2bdf8d0f
commit 1c4f65120c
5 changed files with 107 additions and 56 deletions

View File

@ -145,7 +145,7 @@ class etemplate_new extends etemplate_widget_template
if (self::$response) // call is within an ajax event / form submit if (self::$response) // call is within an ajax event / form submit
{ {
//error_log("Ajax " . __LINE__); //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 else // first call
{ {
@ -216,10 +216,10 @@ class etemplate_new extends etemplate_widget_template
*/ */
static public function ajax_process_content($etemplate_exec_id, array $content) 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); 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(); self::$response = egw_json_response::get();
@ -246,15 +246,15 @@ class etemplate_new extends etemplate_widget_template
self::$response->generic('et2_validation_error', self::$validation_errors); self::$response->generic('et2_validation_error', self::$validation_errors);
exit; exit;
} }
error_log(__METHOD__."(,".array2string($content).')'); //error_log(__METHOD__."(,".array2string($content).')');
error_log(' validated='.array2string($validated)); //error_log(' validated='.array2string($validated));
$content = ExecMethod(self::$request->method, self::complete_array_merge(self::$request->preserv, $validated)); $content = ExecMethod(self::$request->method, self::complete_array_merge(self::$request->preserv, $validated));
if (isset($GLOBALS['egw_info']['flags']['java_script'])) if (isset($GLOBALS['egw_info']['flags']['java_script']))
{ {
// Strip out any script tags // Strip out any script tags
$GLOBALS['egw_info']['flags']['java_script'] = preg_replace(array('/(<script[^>]*>)([^<]*)/is','/<\/script>/'),array('$2',''),$GLOBALS['egw_info']['flags']['java_script']); $GLOBALS['egw_info']['flags']['java_script'] = preg_replace(array('/(<script[^>]*>)([^<]*)/is','/<\/script>/'),array('$2',''),$GLOBALS['egw_info']['flags']['java_script']);
self::$response->script($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; return $content;

View File

@ -597,10 +597,34 @@ etemplate2.getByApplication = function(app)
return list; return list;
}; };
/**
* Plugin for egw.json type "et2_load"
*
* @param _type
* @param _response
* @returns {Boolean}
*/
function etemplate2_handle_load(_type, _response) function etemplate2_handle_load(_type, _response)
{ {
// Check the parameters // Check the parameters
var data = _response.data; 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 data.url == "string" && typeof data.data === 'object')
{ {
if(typeof this.load == 'function') if(typeof this.load == 'function')
@ -629,6 +653,12 @@ function etemplate2_handle_load(_type, _response)
throw("Error while parsing et2_load 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) function etemplate2_handle_validation_error(_type, _response)
{ {
// Display validation errors // Display validation errors

View File

@ -156,12 +156,68 @@ abstract class egw_framework
if (!isset($GLOBALS['egw_info']['flags']['nonavbar']) || !$GLOBALS['egw_info']['flags']['nonavbar']) if (!isset($GLOBALS['egw_info']['flags']['nonavbar']) || !$GLOBALS['egw_info']['flags']['nonavbar'])
{ {
echo $this->navbar(); echo $this->navbar();
} }
echo $content; echo $content;
echo $this->footer(); 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 * Returns the html-header incl. the opening body tag
@ -823,7 +879,9 @@ abstract class egw_framework
// Load LABjs ONCE here // Load LABjs ONCE here
$java_script .= '<script type="text/javascript" src="'. $GLOBALS['egw_info']['server']['webserver_url'].'/phpgwapi/js/labjs/LAB.src.js"'." ></script>\n". $java_script .= '<script type="text/javascript" src="'. $GLOBALS['egw_info']['server']['webserver_url'].'/phpgwapi/js/labjs/LAB.src.js"'." ></script>\n".
'<script type="text/javascript" src="'. $GLOBALS['egw_info']['server']['webserver_url'].'/phpgwapi/js/jsapi/egw.js" id="egw_script_id"'; '<script type="text/javascript" src="'. $GLOBALS['egw_info']['server']['webserver_url'].'/phpgwapi/js/jsapi/egw.js" id="egw_script_id"';
foreach($extra as $name => $value)
// add values of extra parameter and class var as data attributes to script tag of egw.js
foreach($extra+self::$extra as $name => $value)
{ {
if (is_array($value)) $value = json_encode($value); if (is_array($value)) $value = json_encode($value);
// we need to double encode (html::htmlspecialchars( , TRUE)), as otherwise we get invalid json, eg. for quotes // we need to double encode (html::htmlspecialchars( , TRUE)), as otherwise we get invalid json, eg. for quotes

View File

@ -5,7 +5,7 @@
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package timesheet * @package timesheet
* @copyright (c) 2005-11 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @copyright (c) 2005-13 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$ * @version $Id$
*/ */
@ -256,7 +256,7 @@ class timesheet_ui extends timesheet_bo
egw_link::link(TIMESHEET_APP,$this->data['ts_id'],$content['link_to']['to_id']); egw_link::link(TIMESHEET_APP,$this->data['ts_id'],$content['link_to']['to_id']);
} }
} }
$js = "opener.egw_refresh('$msg','timesheet','{$this->data['ts_id']}', '" . ($content['ts_id'] ? 'update' : 'add')."');"; egw_framework::refresh_opener($msg, 'timesheet', $this->data['ts_id'], $content['ts_id'] ? 'update' : 'add');
if ($button == 'apply') break; if ($button == 'apply') break;
if ($button == 'save_new') if ($button == 'save_new')
{ {
@ -287,7 +287,7 @@ class timesheet_ui extends timesheet_bo
if ($this->delete()) if ($this->delete())
{ {
$msg = lang('Entry deleted'); $msg = lang('Entry deleted');
$js = "opener.egw_refresh('$msg','timesheet','{$this->data['ts_id']}', 'delete');"; egw_framework::refresh_opener($msg, 'timesheet', $this->data['ts_id'], 'delete');
} }
else else
{ {
@ -297,10 +297,7 @@ class timesheet_ui extends timesheet_bo
} }
// fall-through for save // fall-through for save
case 'cancel': case 'cancel':
$js .= 'window.close();'; egw_framework::window_close();
echo "<html>\n<body>\n<script>\n$js\n</script>\n</body>\n</html>\n";
common::egw_exit();
break;
} }
} }
$preserv = $this->data + array( $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_id' => $this->data['ts_id'] ? $this->data['ts_id'] : $content['link_to']['to_id'],
'to_app' => TIMESHEET_APP, 'to_app' => TIMESHEET_APP,
), ),
'js' => "<script>\n$js\n</script>\n",
'ts_quantity_blur' => $this->data['ts_duration'] ? round($this->data['ts_duration'] / 60.0,3) : '', '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'), 'start_time' => egw_time::to($this->data['ts_start'],'H:i'),
'pm_integration' => $this->pm_integration, 'pm_integration' => $this->pm_integration,
@ -396,16 +392,10 @@ class timesheet_ui extends timesheet_bo
), ),
); );
$sel_options['status'] = $this->field2label; $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), // 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 // 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']; $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( $readonlys = array(
'button[delete]' => !$this->data['ts_id'] || !$this->check_acl(EGW_ACL_DELETE) || $this->data['ts_status'] == self::DELETED_STATUS, '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, 'button[undelete]' => $this->data['ts_status'] != self::DELETED_STATUS,

View File

@ -13,7 +13,7 @@
</styles> </styles>
</template> </template>
<template id="timesheet.index.add" template="" lang="" group="0" version="1.7.001"> <template id="timesheet.index.add" template="" lang="" group="0" version="1.7.001">
<buttononly label="Add" id="add" onclick="window.open(egw::link('/index.php','menuaction=timesheet.timesheet_ui.edit'),'_blank','dependent=yes,width=600,height=400,scrollbars=yes,status=yes'); return false;"/> <buttononly label="Add" id="add" onclick="egw.open('timesheet');"/>
</template> </template>
<template id="timesheet.index.rows" template="" lang="" group="0" version="1.9.001"> <template id="timesheet.index.rows" template="" lang="" group="0" version="1.9.001">
<grid width="100%"> <grid width="100%">
@ -107,34 +107,7 @@
</grid> </grid>
</template> </template>
<template id="timesheet.index" template="" lang="" group="0" version="1.9.001"> <template id="timesheet.index" template="" lang="" group="0" version="1.9.001">
<grid width="100%"> <description align="center" id="msg" no_lang="1" class="message"/>
<columns> <nextmatch id="nm" options="timesheet.index.rows" header_left="timesheet.index.dates" header_right="timesheet.index.add"/>
<column/>
<column/>
</columns>
<rows>
<row disabled="!@msg">
<description align="center" id="msg" no_lang="1" span="all" class="redItalic"/>
<description/>
</row>
<row disabled="1">
<hbox>
<template id="dates"/>
<template align="right" id="add"/>
</hbox>
<description/>
</row>
<row>
<nextmatch id="nm" options="timesheet.index.rows" span="all"/>
</row>
<row class="noPrint" disabled="!@nm[selectcols]=/legacy_actions/">
<button label="Add" id="add" onclick="window.open(egw::link('/index.php','menuaction=timesheet.timesheet_ui.edit'),'_blank','dependent=yes,width=600,height=400,scrollbars=yes,status=yes'); return false;"/>
<hbox align="right">
<buttononly statustext="Select action" label="Select action" id="legacy_actions" onclick="if (!egw_globalObjectManager.getObjectById('timesheet.index.rows').executeActionImplementation(this, 'popup')) alert(egw::lang('You need to select some entries first!')); return false;;"/>
<button statustext="Check all" label="Check all" id="check_all" needed="1" onclick="egw_globalObjectManager.getObjectById('timesheet.index.rows').toggleAllSelected(); return false;" image="arrow_ltr" class="checkAllArrow"/>
</hbox>
</row>
</rows>
</grid>
</template> </template>
</overlay> </overlay>