switching on Content-Security-Policy: script-src 'self' 'unsafe-eval' for all templates, old non-et2 apps can call egw_framework::csp_script_src_attrs('unsafe-inline') to enable inline scripts in their scope, et2 does it for CK editor which does not support CSP currently and old etemplate does it for all apps using it

This commit is contained in:
Ralf Becker 2013-10-05 13:33:28 +00:00
parent b1d5dad6b9
commit 43e1bfcc12
13 changed files with 279 additions and 151 deletions

View File

@ -477,16 +477,7 @@ class calendar_ui
*/
function _select_box($title,$name,$options,$baseurl='')
{
if ($baseurl) // we append the value to the baseurl
{
if (substr($baseurl,-1) != '=') $baseurl .= strpos($baseurl,'?') === False ? '?' : '&';
$onchange="egw_appWindow('calendar').location='$baseurl'+this.value;";
}
else // we add $name=value to the actual location
{
$onchange="var win=egw_appWindow('calendar'); win.location=win.location+(win.location.search.length ? '&' : '?')+'".$name."='+this.value;";
}
$select = ' <select style="width: 100%;" name="'.$name.'" onchange="'.$onchange.'" title="'.
$select = ' <select style="width: 100%;" name="'.$name.'" id="calendar_'.$name.'" title="'.
lang('Select a %1',lang($title)).'">'.
$options."</select>\n";
@ -665,11 +656,10 @@ class calendar_ui
// Search
$blur = addslashes(html::htmlspecialchars(lang('Search').'...'));
$value = @$_POST['keywords'] ? html::htmlspecialchars($_POST['keywords']) : $blur;
$value = @$_POST['keywords'] ? html::htmlspecialchars($_POST['keywords']) : '';
$file[++$n] = array(
'text' => html::form('<input name="keywords" value="'.$value.'" style="width: 97.5%;"'.
' onFocus="if(this.value==\''.$blur.'\') this.value=\'\';"'.
' onBlur="if(this.value==\'\') this.value=\''.$blur.'\';" title="'.lang('Search').'">',
' placeholder="'.$blur.'" title="'.lang('Search').'">',
'','/index.php',array('menuaction'=>'calendar.calendar_uilist.listview')),
'no_lang' => True,
'link' => False,
@ -717,34 +707,13 @@ class calendar_ui
}
// Category Selection
$onchange = "var value = '';
if(selectBox = document.getElementById('cat_id')) {
for(i=0; i < selectBox.length; ++i) {
if (selectBox.options[i].selected) {
value += (value ? ',' : '') + selectBox.options[i].value;
}
}
}";
if ($baseurl) // we append the value to the baseurl
{
$cat_baseurl = $baseurl ? $baseurl.'&cat_id=' : '';
if (substr($cat_baseurl,-1) != '=') $cat_baseurl .= strpos($cat_baseurl,'?') === False ? '?' : '&';
$onchange.="egw_appWindow('calendar').location='$cat_baseurl'+value;";
}
else // we add $name=value to the actual location
{
$onchange.="var win=egw_appWindow('calendar'); win.location=win.location+(win.location.search.length ? '&' : '?')+'cat_id='+value;";
}
$cat_id = explode(',',$this->cat_id);
$options = '<option value="0">'.lang('All categories').'</option>'.
$this->categories->formatted_list('select','all',$cat_id,'True');
$icon_onclick = "if(selectBox = document.getElementById('cat_id')) {
if (!selectBox.multiple) {selectBox.size=4; selectBox.multiple=true;}}";
$select = ' <select style="width: 87%;" id="cat_id" name="cat_id" onchange="'.$onchange.'" title="'.
$select = ' <select style="width: 87%;" id="calendar_cat_id" name="cat_id" title="'.
lang('Select a %1',lang('Category')). '"'.($cat_id && count($cat_id) > 1 ? ' multiple=true size=4':''). '>'.
$options."</select>\n" . html::image('phpgwapi','attach','','onclick="'.$icon_onclick.'"');
$options."</select>\n" . html::image('phpgwapi','attach','','id="calendar_cat_id_multiple"');
$file[++$n] = array(
'text' => $select,
@ -790,32 +759,17 @@ class calendar_ui
}
// we no longer exclude non-accounts from the account-selection: it shows all types of participants
$accounts = explode(',',$this->owner);
$current_view_url = egw::link('/index.php',array(
'menuaction' => $this->view_menuaction,
'date' => $this->date,
),false);
$file[] = array(
'text' => "
<script type=\"text/javascript\">
function load_cal(url,id,no_reset) {
var owner='';
var i = 0;
selectBox = document.getElementById(id);
for(i=0; i < selectBox.length; ++i) {
if (selectBox.options[i].selected) {
owner += (owner ? ',' : '') + selectBox.options[i].value;
}
}
if (owner) {
if (typeof no_reset == 'unknown') no_reset = false;
egw_appWindow('calendar').location=url+'&owner='+(no_reset?'':'0,')+owner;
}
}
</script>
".
<script type=\"text/javascript\" src=\"{$GLOBALS['egw_info']['server']['webserver_url']}/calendar/js/navigation.js\" id=\"calendar-navigation-script\" data-current-view-url=\"".htmlspecialchars($current_view_url)."\"/></script>\n".
$this->accountsel->selection('owner','uical_select_owner',$accounts,'calendar+',count($accounts) > 1 ? 4 : 1,False,
' style="width: '.(count($accounts) > 1 && in_array($this->common_prefs['account_selection'],array('selectbox','groupmembers')) ? '100%' : '87%').';"'.
' title="'.lang('select a %1',lang('user')).'" onchange="load_cal(\''.
egw::link('/index.php',array(
'menuaction' => $this->view_menuaction,
'date' => $this->date,
),false).'\',\'uical_select_owner\');"','',$grants,false,array($this->bo,'participant_name')),
' title="'.lang('select a %1',lang('user')).'"','',$grants,false,array($this->bo,'participant_name')),
'no_lang' => True,
'link' => False
);
@ -839,10 +793,8 @@ function load_cal(url,id,no_reset) {
}
if($options != '') {
$options = '<option value="">'.lang('Insert in document')."</option>\n" . $options;
$name = 'merge';
$onchange="var win=egw_appWindow('calendar'); win.location=win.location+(win.location.search.length ? '&' : '?')+'".$name."='+this.value;this.value='';";
$select = ' <select style="width: 100%;" name="'.$name.'" onchange="'.$onchange.'" title="'.
lang('Select a %1',lang('merge document...')).'">'.
$select = ' <select style="width: 100%;" name="merge" id="calendar_merge" title="'.
html::htmlspecialchars(lang('Select a %1',lang('merge document...'))).'">'.
$options."</select>\n";
$file[] = array(

View File

@ -146,6 +146,9 @@ class calendar_uiviews extends calendar_ui
*/
function __construct($set_states=null)
{
// tell framework calendar needs eval and inline javascript :(
egw_framework::csp_script_src_attrs(array('unsafe-eval', 'unsafe-inline'));
parent::__construct(false,$set_states); // call the parent's constructor
$this->extraRowsOriginal = $this->extraRows; //save original extraRows value

76
calendar/js/navigation.js Normal file
View File

@ -0,0 +1,76 @@
/**
* Calendar - sidebox navigation
*
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker@stylite.de>
* @package calendar
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
/**
* Sidebox navigation for calendar
*
* @todo add code from jscalendar->flat(), or better replace it altogether ...
*/
(function()
{
var script_tag = document.getElementById('calendar-navigation-script');
var current_view_url;
if (script_tag)
{
current_view_url = script_tag.getAttribute('data-current-view-url');
}
function load_cal(url,id,no_reset) {
var owner='';
var i = 0;
selectBox = document.getElementById(id);
for(i=0; i < selectBox.length; ++i) {
if (selectBox.options[i].selected) {
owner += (owner ? ',' : '') + selectBox.options[i].value;
}
}
if (owner) {
if (typeof no_reset == 'unknown') no_reset = false;
egw_appWindow('calendar').location=url+'&owner='+(no_reset?'':'0,')+owner;
}
}
/**
* Initialisation after DOM *and* jQuery is loaded
*/
egw_LAB.wait(function() {
$j(function(){
var calendar_window = egw_appWindow('calendar');
// change handlers setting a certain url, eg. view
$j('#calendar_view').change(function(){
calendar_window.location = egw_webserverUrl+'/index.php?'+this.value;
});
// calendar owner selection change
$j('#uical_select_owner,#uical_select_resource').change(function(e){
if (this.value != 'popup')
{
load_cal(current_view_url, this.id, this.id != 'uical_select_owner');
e.preventDefault();
}
});
// diverse change handlers appending a name=value to url
$j('#calendar_merge,#calendar_filter,#calendar_cat_id').change(function(){
var val = $j(this).val();
if ($j.isArray(val)) val = val.join(',');
calendar_window.location = current_view_url+
(current_view_url.search.length ? '&' : '?')+this.name+'='+val;
if (this.name == 'merge') this.value='';
});
// click handler to switch selectbox to multiple
$j('#calendar_cat_id_multiple').click(function(){
var selectBox = document.getElementById(this.id.replace('_multiple', ''));
if (selectBox && !selectBox.multiple)
{
selectBox.size=4;
selectBox.multiple=true;
}
});
});
});
})();

View File

@ -136,6 +136,9 @@ class etemplate_old extends boetemplate
*/
function __construct($name='',$load_via='')
{
// tell framework old eTemplate apps needs eval and inline javascript :(
egw_framework::csp_script_src_attrs(array('unsafe-eval', 'unsafe-inline'));
parent::__construct($name,$load_via);
$this->sitemgr = isset($GLOBALS['Common_BO']) && is_object($GLOBALS['Common_BO']);

View File

@ -31,8 +31,10 @@ class etemplate_widget_htmlarea extends etemplate_widget
public function beforeSendToClient($cname)
{
$form_name = self::form_name($cname, $this->id);
// tell framework CK Editor needs eval and inline javascript :(
egw_framework::csp_script_src_attrs(array('unsafe-eval', 'unsafe-inline'));
$config = egw_ckeditor_config::get_ckeditor_config_array($this->attrs['mode'], $this->attrs['height'],
$this->attrs['expand_toolbar'],$this->attrs['base_href']
);

View File

@ -83,6 +83,59 @@ abstract class egw_framework
$this->template_dir = '/phpgwapi/templates/'.$template;
}
/**
* Additional attributes for CSP script-src 'self'
*
* @var array
*/
private static $csp_script_src_attrs = array('unsafe-eval');
/**
* Set/get Content-Security-Policy attributes for script-src: 'unsafe-eval' and/or 'unsafe-inline'
*
* Using CK-Editor currently requires both to be set :(
*
* Old pre-et2 apps might need to call egw_framework::csp_script_src_attrs(array('unsafe-eval','unsafe-inline'))
*
* EGroupware itself currently still requires 'unsafe-eval'!
*
* @param string|array $set=array() 'unsafe-eval' and/or 'unsafe-inline' (without quotes!)
* @return string with attributes eg. "'unsafe-eval' 'unsafe-inline'"
*/
public static function csp_script_src_attrs($set=null)
{
foreach((array)$set as $attr)
{
if (!in_array($attr, self::$csp_script_src_attrs))
{
self::$csp_script_src_attrs[] = $attr;
//error_log(__METHOD__."() swiching CSP OFF for script-src '$attr' ".function_backtrace());
}
}
return self::$csp_script_src_attrs ? "'".implode("' '", self::$csp_script_src_attrs)."'" : '';
}
/**
* Send HTTP headers: Content-Type and Content-Security-Policy
*/
protected function _send_headers()
{
// add a content-type header to overwrite an existing default charset in apache (AddDefaultCharset directiv)
header('Content-type: text/html; charset='.translation::charset());
// content-security-policy header:
// - "script-src 'self' 'unsafe-eval'" allows only self and eval (eg. ckeditor), but forbids inline scripts, onchange, etc
// - "connect-src 'self'" allows ajax requests only to self
// - "style-src 'self' 'unsave-inline'" allows only self and inline style, which we need
// - "frame-src 'self' manual.egroupware.org" allows frame and iframe content only for self or manual.egroupware.org
$csp = "script-src 'self' ".($script_attrs=self::csp_script_src_attrs())."; connect-src 'self'; style-src 'self' 'unsafe-inline'; frame-src 'self' manual.egroupware.org";
//error_log(__METHOD__."() script_attrs=$script_attrs");
//$csp = "default-src * 'unsafe-eval' 'unsafe-inline'"; // allow everything
header("Content-Security-Policy: $csp");
header("X-Webkit-CSP: $csp"); // Chrome: <= 24, Safari incl. iOS
header("X-Content-Security-Policy: $csp"); // FF <= 22
}
/**
* Constructor for static variables
*/

View File

@ -531,6 +531,9 @@ class html
return self::textarea($_name,$_content,'style="width: '.$_width.'; height: '.$_height.';" id="'.htmlspecialchars($_name).'"');
}
// tell framework CK Editor needs eval and inline javascript :(
egw_framework::csp_script_src_attrs(array('unsafe-eval', 'unsafe-inline'));
//include the ckeditor js file
egw_framework::validate_file('ckeditor','ckeditor','phpgwapi');

View File

@ -52,10 +52,6 @@ class uiaccountsel
{
$this->account_selection = 'primary_group';
}
// Include these here, framework may have already sent header by the time the account select is made
egw_framework::validate_file('/phpgwapi/js/jquery/chosen/chosen.jquery.js');
egw_framework::includeCSS('/phpgwapi/js/jquery/chosen/chosen.css',null,false);
}
/**
@ -96,6 +92,8 @@ class uiaccountsel
$multi_size = abs($lines);
$lines = 1;
}
$options .= ' class="uiaccountselection '.$this->account_selection.'"'; // to be able to style and select it with jQuery
if ($this->account_selection == 'none') // dont show user-selection at all!
{
return html::input_hidden($name,$selected);
@ -249,26 +247,16 @@ class uiaccountsel
'element_id' => $element_id,
'multiple' => $lines, // single selection (multiple=0), closes after the first selection
),false);
$popup_options = 'width=600,height=420,toolbar=no,scrollbars=yes,resizable=yes';
$app = $GLOBALS['egw_info']['flags']['currentapp'];
if (!$only_groups && ($lines <= 1 && $this->account_selection == 'popup' || !$lines && $this->account_selection == 'primary_group'))
{
if (!$lines)
{
$options .= ' onchange="if (this.value==\'popup\') '."window.open('$link','uiaccountsel','$popup_options');".
($onchange ? " else { $onchange }" : '' ).'" onclick="if (this.value==\'popup\') '."window.open('$link','uiaccountsel','$popup_options');\"";
$select['popup'] = lang('Search').' ...';
}
elseif ($onchange)
{
$options .= ' onchange="if (this.value[0]!=\',\') { '.$onchange.' }"';
}
$need_js_popup = True;
}
elseif ($onchange)
{
$options .= ' onchange="'.$onchange.'"';
}
if ($onchange) $options .= ' onchange="'.$onchange.'"'; // no working under CSP without 'unsafe-inline'
if ($extra_label)
{
//in php5 this put's the extra-label at the end: $select = array($extra_label) + $select;
@ -286,77 +274,30 @@ class uiaccountsel
);
}
//echo "<p>html::select('$name',".print_r($selected,True).",".print_r($select,True).",True,'$options')</p>\n";
$html = html::select($name,$selected,$select,True,$options.' id="'.$element_id.'"',$lines > 1 ? $lines : 0,true);
$html = html::select($name,$selected,$select,True,$options.' id="'.$element_id.
'" data-popup-link="'.htmlspecialchars($link).'"',$lines > 1 ? $lines : 0,false);
if (!$only_groups && ($lines > 0 && $this->account_selection == 'popup' || $lines > 1 && $this->account_selection == 'primary_group'))
{
$js = "window.open('$link','uiaccountsel','$popup_options'); return false;";
$html .= html::submit_button('search','Search accounts',$js,false,
' title="'.html::htmlspecialchars(lang('Search accounts')).'"','search','phpgwapi');
' title="'.html::htmlspecialchars(lang('Search accounts')).
'" class="uiaccountselection_trigger" id="'.$element_id.'_popup"','search','phpgwapi','button');
$need_js_popup = True;
}
elseif (!$only_groups && ($lines == 1 || $lines > 0 && $this->account_selection == 'primary_group'))
{
$js = "if (selectBox = document.getElementById('$element_id')) if (!selectBox.multiple) { if(\$j(selectBox).unchosen) \$j(selectBox).unchosen(); selectBox.size=$multi_size; selectBox.multiple=true; if (selectBox.options[0].value=='') selectBox.options[0] = null;";
if(count($select) > html::SELECT_ENHANCED_ROW_COUNT || true)
{
$js .= "\$j(selectBox).css('width','100%'); ";
}
if (!in_array($this->account_selection,array('groupmembers','selectbox'))) // no popup!
{
$js .= " this.src='".common::image('phpgwapi','search')."'; this.title='".
html::htmlspecialchars(lang('Search accounts'))."';} else {window.open('$link','uiaccountsel','$popup_options');";
$need_js_popup = True;
}
else
{
$js .= "this.style.display='none'; selectBox.style.width='100%';";
}
$js .= "} return false;";
$html .= html::submit_button('search','Select multiple accounts',$js,false,
' title="'.html::htmlspecialchars(lang('Select multiple accounts')).'"','users','phpgwapi');
}
// jDots needs a little re-do, since it plays with the layout
$html .= "<script>
egw_LAB.wait(function() {
if (\$j().chosen)
window.setTimeout(function() {
\$j('#$element_id').unchosen().chosen({width:'90%', placeholder_text: '".lang('Select multiple accounts')."'});
},200);
});
</script>";
if($need_js_popup && !$GLOBALS['egw_info']['flags']['uiaccountsel']['addOption_installed'])
{
$html .= '<script language="JavaScript">
function addOption(id,label,value,do_onchange)
{
selectBox = document.getElementById(id);
for (i=0; i < selectBox.length; i++) {
'.// check existing entries if they're already there and only select them in that case
' if (selectBox.options[i].value == value) {
selectBox.options[i].selected = true;
break;
}
}
if (i >= selectBox.length) {
if (!do_onchange) {
if (selectBox.length && selectBox.options[0].value=="") selectBox.options[0] = null;
selectBox.multiple=true;
selectBox.size='.$multi_size.';
}
selectBox.options[selectBox.length] = new Option(label,value,false,true);
}
if (selectBox.onchange && do_onchange) selectBox.onchange();
$j(selectBox).trigger("liszt:updated");
}
</script>';
$GLOBALS['egw_info']['flags']['uiaccountsel']['addOption_installed'] = True;
$html .= html::submit_button('search','Select multiple accounts','',false,
' title="'.html::htmlspecialchars(lang('Select multiple accounts')).
'" class="uiaccountselection_trigger" id="'.$element_id.'_multiple"','users','phpgwapi','button');
}
return $html;
}
function popup()
{
// switch CSP to script-src 'unsafe-inline', until code get fixed here to work without
egw_framework::csp_script_src_attrs('unsafe-inline');
global $query; // nextmatch requires that !!!
$app = get_var('app',array('POST','GET'));
@ -477,7 +418,7 @@ function addOption(id,label,value,do_onchange)
{
$link_data['group_id'] = $group['account_id'];
$GLOBALS['egw']->template->set_var('onclick',"addOption('$element_id','".
$GLOBALS['egw']->template->set_var('onclick',"ownAddOption('$element_id','".
addslashes(common::grab_owner_name($group['account_id']))."','$group[account_id]',".(int)($multiple==1).")".
(!$multiple ? '; window.close()' : ''));
@ -491,7 +432,7 @@ function addOption(id,label,value,do_onchange)
if($use == 'both') // allow selection of groups
{
$GLOBALS['egw']->template->fp('cal','group_cal',True);
$GLOBALS['egw']->template->set_var('js_addAllGroups',"addOption('$element_id','".
$GLOBALS['egw']->template->set_var('js_addAllGroups',"ownAddOption('$element_id','".
addslashes(common::grab_owner_name($group['account_id']))."','$group[account_id]',".(int)($multiple==1).")".
(!$multiple ? '; window.close();' : ';'));
$GLOBALS['egw']->template->fp('selectAllGroups','group_selectAll',True);
@ -555,12 +496,12 @@ function addOption(id,label,value,do_onchange)
'lid' => $user['account_lid'],
'firstname' => $user['account_firstname'] ? $user['account_firstname'] : '&nbsp;',
'lastname' => $user['account_lastname'] ? $user['account_lastname'] : '&nbsp;',
'onclick' => "addOption('$element_id','".
'onclick' => "ownAddOption('$element_id','".
addslashes(common::grab_owner_name($user['account_id']))."','$user[account_id]',".(int)($multiple==1).")".
(!$multiple ? '; window.close()' : ''),
));
$GLOBALS['egw']->template->fp('list','accounts_list',True);
$GLOBALS['egw']->template->set_var('js_addAllAccounts',"addOption('$element_id','".
$GLOBALS['egw']->template->set_var('js_addAllAccounts',"ownAddOption('$element_id','".
addslashes(common::grab_owner_name($user['account_id']))."','$user[account_id]',".(int)($multiple==1).")".
(!$multiple ? '; window.close()' : ';'));
$GLOBALS['egw']->template->fp('selectAllAccounts','accounts_selectAll',True);

View File

@ -794,7 +794,14 @@ function dropdown_menu_hack(el)
*/
function egw_link_handler(_link, _app)
{
window.location.href = _link;
if (window.framework)
{
window.framework.linkHandler(_link, _app);
}
else
{
window.location.href = _link;
}
}
/**
@ -843,3 +850,72 @@ function egw_preferences(name, apps)
egw_link_handler(egw_webserverUrl+url, current_app);
}
}
/**
* Support functions for uiaccountselection class
*
* @ToDo: should be removed if uiaccountsel class is no longer in use
*/
function addOption(id,label,value,do_onchange)
{
selectBox = document.getElementById(id);
for (var i=0; i < selectBox.length; i++) {
// check existing entries if they're already there and only select them in that case
if (selectBox.options[i].value == value) {
selectBox.options[i].selected = true;
break;
}
}
if (i >= selectBox.length) {
if (!do_onchange) {
if (selectBox.length && selectBox.options[0].value=='') selectBox.options[0] = null;
selectBox.multiple=true;
selectBox.size=4;
}
selectBox.options[selectBox.length] = new Option(label,value,false,true);
}
if (selectBox.onchange && do_onchange) selectBox.onchange();
}
/**
* Install click handlers for popup and multiple triggers of uiaccountselection
*/
$j(function(){
$j(document).on('click', 'input.uiaccountselection_trigger',function(){
var selectBox = document.getElementById(this.id.replace(/(_multiple|_popup)$/, ''));
if (selectBox)
{
var link = selectBox.getAttribute('data-popup-link');
if (selectBox.multiple || this.id.match(/_popup$/))
{
window.open(link, 'uiaccountsel', 'width=600,height=420,toolbar=no,scrollbars=yes,resizable=yes');
}
else
{
selectBox.size = 4;
selectBox.multiple = true;
if (selectBox.options[0].value=='') selectBox.options[0] = null;
if (!$j(selectBox).hasClass('groupmembers') && !$j(selectBox).hasClass('selectbox')) // no popup!
{
this.src = egw.image('search');
this.title = egw.lang('Search accounts');
}
else
{
this.style.display = 'none';
selectBox.style.width = '100%';
}
}
}
});
$j(document).on('change', 'select.uiaccountselection',function(e){
if (this.value == 'popup')
{
var link = this.getAttribute('data-popup-link');
window.open(link, 'uiaccountsel', 'width=600,height=420,toolbar=no,scrollbars=yes,resizable=yes');
e.preventDefault();
}
});
});

View File

@ -3,7 +3,7 @@
<script LANGUAGE="JavaScript">
window.focus();
function addOption(id,label,value,multiple)
function ownAddOption(id,label,value,multiple)
{
openerSelectBox = opener.document.getElementById(id);
@ -99,7 +99,7 @@
border: 1px solid white;
text-align: center;
cursor: pointer;
cusror: hand;
cursor: hand;
}
.letter_box_active {
font-weight: bold;

View File

@ -91,8 +91,7 @@ class idots_framework extends egw_framework
if (self::$header_done) return '';
self::$header_done = true;
// add a content-type header to overwrite an existing default charset in apache (AddDefaultCharset directiv)
header('Content-type: text/html; charset='.translation::charset());
self::_send_headers();
// catch error echo'ed before the header, ob_start'ed in the header.inc.php
$content = ob_get_contents();

View File

@ -43,10 +43,11 @@
}
/**
* Installing resize handler for divAppbox and et2_container, as et2 otherwise can not correctly size nextmatch
* Initialisation, when DOM is ready
*/
$j(function()
{
// Installing resize handler for divAppbox and et2_container, as et2 otherwise can not correctly size nextmatch
$j(window).resize(function(){
var appbox_height = $j(window).height()-$j('#topmenu').height()-$j('#divAppIconBar').height()-
$j('#divStatusBar').height()-$j('#divAppboxHeader').height()-$j('#divPoweredBy').height()-20;
@ -55,5 +56,25 @@
$j('.et2_container').height(appbox_height);
});
$j(window).resize();
$j(window).load(function(){ // fixes sometimes not called resize, probably due to timing issues
$j(window).resize();
});
// allowing javascript urls in topmenu and sidebox only under CSP by binding click handlers to them
var href_regexp = /^javascript:([^\(]+)\((.*)?\);?$/;
jQuery('#topmenu_items,#thesideboxcolumn').on('click','a[href^="javascript:"]',function(){
var matches = this.href.match(href_regexp);
if (matches && typeof window[matches[1]] == 'function') {
var args = [];
if (matches.length > 1 && matches[2] !== undefined) args = JSON.parse('['+matches[2].replace(/'/g,'"')+']');
window[matches[1]].apply(window.framework, args);
}
else
{
alert('Do NOT know how to execute '+this.href);
}
// return false to not execute link itself, which would violate CSP
return false;
});
});
})();

View File

@ -838,15 +838,14 @@ class resources_ui
$selected,
array_merge($resources,$res_cats),
$no_lang=true,
$options='data-placeholder="'.lang('select resources').'" style="width: 100%;" onchange="load_cal(\''.
egw::link('/index.php',$param,false).'\',\'uical_select_resource\',true);" id="uical_select_resource"',
$options=' style="width: 100%;" id="uical_select_resource"',
$multiple=4,
true
false
);
return array(
array(
// Add some jQuery to make sure dropdown is displayed
'text' => $selectbox . "<script>var lab = egw_LAB || \$LAB; lab.wait(function(){ \$j('select[name=\"owner\[\]\"]').parent('td').css('overflow','visible').parents('div.divSidebox').css('overflow','visible');});</script>",
'text' => $selectbox,
'no_lang' => True,
'link' => False
)