+ * @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;
+ }
+ });
+ });
+ });
+})();
\ No newline at end of file
diff --git a/etemplate/inc/class.etemplate_old.inc.php b/etemplate/inc/class.etemplate_old.inc.php
index 6438d9ce93..b1c1ff01b4 100644
--- a/etemplate/inc/class.etemplate_old.inc.php
+++ b/etemplate/inc/class.etemplate_old.inc.php
@@ -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']);
diff --git a/etemplate/inc/class.etemplate_widget_htmlarea.inc.php b/etemplate/inc/class.etemplate_widget_htmlarea.inc.php
index d4821a7e8f..5075f6a988 100644
--- a/etemplate/inc/class.etemplate_widget_htmlarea.inc.php
+++ b/etemplate/inc/class.etemplate_widget_htmlarea.inc.php
@@ -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']
);
diff --git a/phpgwapi/inc/class.egw_framework.inc.php b/phpgwapi/inc/class.egw_framework.inc.php
index e236d25634..4366832891 100644
--- a/phpgwapi/inc/class.egw_framework.inc.php
+++ b/phpgwapi/inc/class.egw_framework.inc.php
@@ -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
*/
diff --git a/phpgwapi/inc/class.html.inc.php b/phpgwapi/inc/class.html.inc.php
index 3f6cfceae0..b4b43f55ea 100644
--- a/phpgwapi/inc/class.html.inc.php
+++ b/phpgwapi/inc/class.html.inc.php
@@ -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');
diff --git a/phpgwapi/inc/class.uiaccountsel.inc.php b/phpgwapi/inc/class.uiaccountsel.inc.php
index 8dcbd27820..709d507043 100644
--- a/phpgwapi/inc/class.uiaccountsel.inc.php
+++ b/phpgwapi/inc/class.uiaccountsel.inc.php
@@ -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 "html::select('$name',".print_r($selected,True).",".print_r($select,True).",True,'$options')
\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 .= "";
- if($need_js_popup && !$GLOBALS['egw_info']['flags']['uiaccountsel']['addOption_installed'])
- {
- $html .= '';
- $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'] : ' ',
'lastname' => $user['account_lastname'] ? $user['account_lastname'] : ' ',
- '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);
diff --git a/phpgwapi/js/jsapi/jsapi.js b/phpgwapi/js/jsapi/jsapi.js
index 3b873394d0..69ef07c780 100644
--- a/phpgwapi/js/jsapi/jsapi.js
+++ b/phpgwapi/js/jsapi/jsapi.js
@@ -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();
+ }
+ });
+});
+
diff --git a/phpgwapi/templates/default/uiaccountsel.tpl b/phpgwapi/templates/default/uiaccountsel.tpl
index c75147b404..b33bb81889 100644
--- a/phpgwapi/templates/default/uiaccountsel.tpl
+++ b/phpgwapi/templates/default/uiaccountsel.tpl
@@ -3,7 +3,7 @@
",
+ 'text' => $selectbox,
'no_lang' => True,
'link' => False
)