2006-12-11 00:44:18 +01:00
< ? php
/**
2011-08-31 09:50:28 +02:00
* EGroupware API - framework baseclass
2008-07-21 16:40:54 +02:00
*
2006-12-11 00:44:18 +01:00
* @ link http :// www . egroupware . org
* @ author Ralf Becker < RalfBecker - AT - outdoor - training . de > rewrite in 12 / 2006
* @ author Pim Snel < pim @ lingewoud . nl > author of the idots template set
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
* @ package api
* @ subpackage framework
* @ access public
* @ version $Id $
*/
/**
* eGW API - framework : virtual base class for all template sets
2008-07-21 16:40:54 +02:00
*
2006-12-11 00:44:18 +01:00
* This class creates / renders the eGW framework :
* a ) html header
* b ) navbar
* c ) sidebox menu
* d ) main application area
* e ) footer
* It replaces several methods in the common class and the diverse templates .
2008-07-21 16:40:54 +02:00
*
2009-10-12 11:41:46 +02:00
* Existing apps either set $GLOBALS [ 'egw_info' ][ 'flags' ][ 'noheader' ] and call common :: egw_header () and
2006-12-11 00:44:18 +01:00
* ( if $GLOBALS [ 'egw_info' ][ 'flags' ][ 'nonavbar' ] is true ) parse_navbar () or it ' s done by the header . inc . php include .
* The app ' s hook_sidebox then calls the public function display_sidebox () .
2009-10-12 11:41:46 +02:00
* And the app calls common :: egw_footer () .
2008-07-21 16:40:54 +02:00
*
2006-12-11 00:44:18 +01:00
* This are the authors ( and their copyrights ) of the original egw_header , egw_footer methods of the common class :
* This file written by Dan Kuykendall < seek3r @ phpgroupware . org >
* and Joseph Engo < jengo @ phpgroupware . org >
* and Mark Peters < skeeter @ phpgroupware . org >
* and Lars Kneschke < lkneschke @ linux - at - work . de >
* Copyright ( C ) 2000 , 2001 Dan Kuykendall
* Copyright ( C ) 2003 Lars Kneschke
*/
2008-08-18 11:00:19 +02:00
abstract class egw_framework
2006-12-11 00:44:18 +01:00
{
/**
* Name of the template set , eg . 'idots'
*
* @ var string
*/
var $template ;
2010-06-02 11:20:55 +02:00
/**
* Path relative to EGW_SERVER_ROOT for the template directory
*
* @ var string
*/
var $template_dir ;
2016-02-17 17:50:54 +01:00
/**
* Application specific template directories to try in given order for CSS
*
* @ var string
*/
var $template_dirs = array ();
2010-01-17 04:20:45 +01:00
/**
* true if $this -> header () was called
*
* @ var boolean
*/
static $header_done = false ;
/**
* true if $this -> navbar () was called
*
* @ var boolean
*/
static $navbar_done = false ;
2006-12-11 00:44:18 +01:00
/**
* Constructor
2008-07-21 16:40:54 +02:00
*
2006-12-11 00:44:18 +01:00
* The constructor instanciates the class in $GLOBALS [ 'egw' ] -> framework , from where it should be used
*
* @ return egw_framework
*/
2010-06-01 23:38:00 +02:00
function __construct ( $template )
2006-12-11 00:44:18 +01:00
{
$this -> template = $template ;
2010-01-17 04:20:45 +01:00
if ( ! isset ( $GLOBALS [ 'egw' ] -> framework ))
2006-12-11 00:44:18 +01:00
{
2008-03-21 21:11:59 +01:00
$GLOBALS [ 'egw' ] -> framework = $this ;
2006-12-11 00:44:18 +01:00
}
2010-06-02 11:20:55 +02:00
$this -> template_dir = '/phpgwapi/templates/' . $template ;
2016-02-17 17:50:54 +01:00
$this -> template_dirs [] = $template ;
$this -> template_dirs [] = 'default' ;
2006-12-11 00:44:18 +01:00
}
2008-07-21 16:40:54 +02:00
2015-05-27 16:01:32 +02:00
/**
* Factory method to instanciate framework object
*
* @ return egw_framwork
*/
public static function factory ()
{
if (( html :: $ua_mobile || $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'theme' ] == 'mobile' ) &&
file_exists ( EGW_SERVER_ROOT . '/pixelegg' ))
{
$GLOBALS [ 'egw_info' ][ 'server' ][ 'template_set' ] = 'pixelegg' ;
}
// default to idots, if no template_set set, to eg. not stall installations if settings use egw::link
if ( empty ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'template_set' ])) $GLOBALS [ 'egw_info' ][ 'server' ][ 'template_set' ] = 'idots' ;
// setup the new eGW framework (template sets)
$class = $GLOBALS [ 'egw_info' ][ 'server' ][ 'template_set' ] . '_framework' ;
if ( ! class_exists ( $class )) // first try to autoload the class
{
require_once ( $file = EGW_INCLUDE_ROOT . '/phpgwapi/templates/' . $GLOBALS [ 'egw_info' ][ 'server' ][ 'template_set' ] . '/class.' . $class . '.inc.php' );
if ( ! in_array ( $file ,( array ) $_SESSION [ 'egw_required_files' ]))
{
$_SESSION [ 'egw_required_files' ][] = $file ; // automatic load the used framework class, when the object get's restored
}
}
// fall back to idots if a template does NOT support current user-agent
if ( $class != 'idots_framework' && method_exists ( $class , 'is_supported_user_agent' ) &&
! call_user_func ( array ( $class , 'is_supported_user_agent' )))
{
$GLOBALS [ 'egw_info' ][ 'server' ][ 'template_set' ] = 'idots' ;
return self :: factory ();
}
return new $class ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'template_set' ]);
}
2013-10-05 15:33:28 +02:00
/**
2013-10-14 12:42:36 +02:00
* Additional attributes or urls for CSP script - src 'self'
*
* 'unsafe-eval' is currently allways added , as it is used in a couple of places .
2013-10-05 15:33:28 +02:00
*
* @ var array
*/
2013-10-14 12:42:36 +02:00
private static $csp_script_src_attrs = array ( " 'unsafe-eval' " );
2013-10-05 15:33:28 +02:00
/**
* 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' !
*
2014-09-04 11:58:48 +02:00
* @ param string | array $set = array () 'unsafe-eval' and / or 'unsafe-inline' ( without quotes ! ) or URL ( incl . protocol ! )
2013-10-05 15:33:28 +02:00
* @ return string with attributes eg . " 'unsafe-eval' 'unsafe-inline' "
*/
public static function csp_script_src_attrs ( $set = null )
{
foreach (( array ) $set as $attr )
{
2013-10-14 12:42:36 +02:00
if ( in_array ( $attr , array ( 'none' , 'self' , 'unsafe-eval' , 'unsafe-inline' )))
{
$attr = " ' $attr ' " ; // automatic add quotes
}
2013-10-05 15:33:28 +02:00
if ( ! in_array ( $attr , self :: $csp_script_src_attrs ))
{
self :: $csp_script_src_attrs [] = $attr ;
2013-10-14 12:42:36 +02:00
//error_log(__METHOD__."() setting CSP script-src $attr ".function_backtrace());
2013-10-05 15:33:28 +02:00
}
}
2013-10-14 12:42:36 +02:00
//error_log(__METHOD__."(".array2string($set).") returned ".array2string(implode(' ', self::$csp_script_src_attrs)).' '.function_backtrace());
return implode ( ' ' , self :: $csp_script_src_attrs );
2013-10-05 15:33:28 +02:00
}
2014-09-04 11:58:48 +02:00
/**
* Additional attributes or urls for CSP style - src 'self'
*
* 'unsafe-inline' is currently allways added , as it is used in a couple of places .
*
* @ var array
*/
private static $csp_style_src_attrs = array ( " 'unsafe-inline' " );
/**
* Set / get Content - Security - Policy attributes for style - src : 'unsafe-inline'
*
* EGroupware itself currently still requires 'unsafe-inline' !
*
* @ param string | array $set = array () 'unsafe-inline' ( without quotes ! ) and / or URL ( incl . protocol ! )
* @ return string with attributes eg . " 'unsafe-inline' "
*/
public static function csp_style_src_attrs ( $set = null )
{
foreach (( array ) $set as $attr )
{
if ( in_array ( $attr , array ( 'none' , 'self' , 'unsafe-inline' )))
{
$attr = " ' $attr ' " ; // automatic add quotes
}
if ( ! in_array ( $attr , self :: $csp_style_src_attrs ))
{
self :: $csp_style_src_attrs [] = $attr ;
//error_log(__METHOD__."() setting CSP script-src $attr ".function_backtrace());
}
}
//error_log(__METHOD__."(".array2string($set).") returned ".array2string(implode(' ', self::$csp_script_src_attrs)).' '.function_backtrace());
return implode ( ' ' , self :: $csp_style_src_attrs );
}
2014-10-09 22:32:59 +02:00
/**
* Additional attributes or urls for CSP connect - src 'self'
*
* @ var array
*/
private static $csp_connect_src_attrs = array ();
/**
* Set / get Content - Security - Policy attributes for connect - src :
*
* @ param string | array $set = array () URL ( incl . protocol ! )
* @ return string with attributes eg . " 'unsafe-inline' "
*/
public static function csp_connect_src_attrs ( $set = null )
{
foreach (( array ) $set as $attr )
{
if ( ! in_array ( $attr , self :: $csp_connect_src_attrs ))
{
self :: $csp_connect_src_attrs [] = $attr ;
//error_log(__METHOD__."() setting CSP script-src $attr ".function_backtrace());
}
}
2015-02-21 14:29:10 +01:00
//error_log(__METHOD__."(".array2string($set).") returned ".array2string(implode(' ', self::$csp_connect_src_attrs)).' '.function_backtrace());
2014-10-09 22:32:59 +02:00
return implode ( ' ' , self :: $csp_connect_src_attrs );
}
2014-02-21 18:06:11 +01:00
/**
2015-02-21 14:29:10 +01:00
* Additional attributes or urls for CSP frame - src 'self'
2014-02-21 18:06:11 +01:00
*
2015-02-21 14:29:10 +01:00
* @ var array
2014-02-21 18:06:11 +01:00
*/
2015-02-21 14:29:10 +01:00
private static $csp_frame_src_attrs ;
/**
* Set / get Content - Security - Policy attributes for frame - src :
*
* Calling this method with an empty array sets no frame - src , but " 'self' " !
*
* @ param string | array $set = array () URL ( incl . protocol ! )
* @ return string with attributes eg . " 'unsafe-inline' "
*/
public static function csp_frame_src_attrs ( $set = null )
2014-02-21 18:06:11 +01:00
{
2015-02-21 14:29:10 +01:00
// set frame-src attrs of API and apps via hook
if ( ! isset ( self :: $csp_frame_src_attrs ) && ! isset ( $set ))
{
$frame_src = array ( 'manual.egroupware.org' , 'www.egroupware.org' );
2015-03-13 13:51:36 +01:00
if (( $app_additional = $GLOBALS [ 'egw' ] -> hooks -> process ( 'csp-frame-src' )))
2015-02-21 14:29:10 +01:00
{
2015-03-13 13:51:36 +01:00
foreach ( $app_additional as $addtional )
{
if ( $addtional ) $frame_src = array_unique ( array_merge ( $frame_src , $addtional ));
}
2015-02-21 14:29:10 +01:00
}
return self :: csp_frame_src_attrs ( $frame_src );
}
if ( ! isset ( self :: $csp_frame_src_attrs )) self :: $csp_frame_src_attrs = array ();
foreach (( array ) $set as $attr )
{
if ( ! in_array ( $attr , self :: $csp_frame_src_attrs ))
{
self :: $csp_frame_src_attrs [] = $attr ;
//error_log(__METHOD__."() setting CSP script-src $attr ".function_backtrace());
}
}
//error_log(__METHOD__."(".array2string($set).") returned ".array2string(implode(' ', self::$csp_frame_src_attrs)).' '.function_backtrace());
return implode ( ' ' , self :: $csp_frame_src_attrs );
2014-02-21 18:06:11 +01:00
}
2013-10-05 15:33:28 +02:00
/**
* Send HTTP headers : Content - Type and Content - Security - Policy
*/
2014-03-03 15:54:03 +01:00
public function send_headers ()
2013-10-05 15:33:28 +02:00
{
// 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
2014-09-04 11:58:48 +02:00
$csp = " script-src 'self' " . self :: csp_script_src_attrs () .
2014-10-13 16:06:20 +02:00
" ; connect-src 'self' " . self :: csp_connect_src_attrs () .
2014-09-04 11:58:48 +02:00
" ; style-src 'self' " . self :: csp_style_src_attrs () .
2015-02-21 14:29:10 +01:00
" ; frame-src 'self' " . self :: csp_frame_src_attrs ();
2014-02-21 18:06:11 +01:00
2013-10-05 15:33:28 +02:00
//$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
2015-10-19 12:26:00 +02:00
// allow client-side to detect first load aka just logged in
$reload_count =& egw_cache :: getSession ( __CLASS__ , 'framework-reload' );
self :: $extra [ 'framework-reload' ] = ( int )( bool ) $reload_count ++ ;
2013-10-05 15:33:28 +02:00
}
2011-08-03 16:03:31 +02:00
/**
* Constructor for static variables
*/
2012-03-04 14:33:10 +01:00
public static function init_static ()
2011-08-03 16:03:31 +02:00
{
self :: $js_include_mgr = new egw_include_mgr ( array (
2013-04-01 21:14:52 +02:00
// We need LABjs, but putting it through egw_include_mgr causes it to re-load itself
//'/phpgwapi/js/labjs/LAB.src.js',
2011-08-03 16:03:31 +02:00
// allways load jquery (not -ui) and egw_json first
'/phpgwapi/js/jquery/jquery.js' ,
// always include javascript helper functions
'/phpgwapi/js/jsapi/jsapi.js' ,
2012-03-12 13:05:14 +01:00
'/phpgwapi/js/jsapi/egw.js' ,
2011-08-03 16:03:31 +02:00
));
}
2010-06-01 23:38:00 +02:00
/**
* PHP4 - Constructor
*
* The constructor instanciates the class in $GLOBALS [ 'egw' ] -> framework , from where it should be used
*
* @ deprecated use __construct ()
*/
function egw_framework ( $template )
{
self :: __construct ( $template );
}
2010-11-09 15:44:18 +01:00
2010-06-01 23:38:00 +02:00
/**
* Link url generator
*
2011-11-30 21:32:45 +01:00
* @ param string $url The url the link is for
2014-01-28 12:00:39 +01:00
* @ param string | array $extravars Extra params to be passed to the url
2014-10-09 22:32:59 +02:00
* @ param string $link_app = null if appname or true , some templates generate a special link - handler url
2010-06-01 23:38:00 +02:00
* @ return string The full url after processing
*/
2014-01-28 12:00:39 +01:00
static function link ( $url , $extravars = '' , $link_app = null )
2010-06-01 23:38:00 +02:00
{
2014-10-09 22:32:59 +02:00
unset ( $link_app ); // not used by required by function signature
2010-06-01 23:38:00 +02:00
return $GLOBALS [ 'egw' ] -> session -> link ( $url , $extravars );
}
/**
* Redirects direct to a generated link
*
2011-11-30 21:32:45 +01:00
* @ param string $url The url the link is for
2014-01-28 12:00:39 +01:00
* @ param string | array $extravars Extra params to be passed to the url
2014-10-09 22:32:59 +02:00
* @ param string $link_app = null if appname or true , some templates generate a special link - handler url
2010-06-01 23:38:00 +02:00
* @ return string The full url after processing
*/
2014-01-28 12:00:39 +01:00
static function redirect_link ( $url , $extravars = '' , $link_app = null )
2010-06-01 23:38:00 +02:00
{
2014-01-28 12:00:39 +01:00
egw :: redirect ( self :: link ( $url , $extravars ), $link_app );
2010-06-01 23:38:00 +02:00
}
2006-12-11 00:44:18 +01:00
/**
* Renders an applicaton page with the complete eGW framework ( header , navigation and menu )
2008-07-21 16:40:54 +02:00
*
2006-12-11 00:44:18 +01:00
* This is the ( new ) prefered way to render a page in eGW !
*
* @ param string $content html of the main application area
2014-10-09 22:32:59 +02:00
* @ param string $app_header = null application header , default what 's set in $GLOBALS[' egw_info '][' flags '][' app_header ' ]
* @ param string $navbar = null show the navigation , default ! $GLOBALS [ 'egw_info' ][ 'flags' ][ 'nonavbar' ], false gives a typical popu
2008-07-21 16:40:54 +02:00
*
2006-12-11 00:44:18 +01:00
*/
function render ( $content , $app_header = null , $navbar = null )
{
if ( ! is_null ( $app_header )) $GLOBALS [ 'egw_info' ][ 'flags' ][ 'app_header' ] = $app_header ;
if ( ! is_null ( $navbar )) $GLOBALS [ 'egw_info' ][ 'flags' ][ 'nonavbar' ] = ! $navbar ;
2008-07-21 16:40:54 +02:00
2006-12-11 00:44:18 +01:00
echo $this -> header ();
2008-07-21 16:40:54 +02:00
2006-12-11 00:44:18 +01:00
if ( ! isset ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'nonavbar' ]) || ! $GLOBALS [ 'egw_info' ][ 'flags' ][ 'nonavbar' ])
{
2013-08-20 14:06:41 +02:00
echo $this -> navbar ();
2006-12-11 00:44:18 +01:00
}
echo $content ;
2007-01-05 15:06:34 +01:00
2006-12-11 00:44:18 +01:00
echo $this -> footer ();
2013-08-20 14:06:41 +02:00
}
/**
* 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
*
2013-09-05 13:53:25 +02:00
* Calling egw_refresh and egw_message on opener in a content security save way
2013-08-20 14:06:41 +02:00
*
2014-05-26 15:29:35 +02:00
* To provide more information about necessary refresh an automatic 9 th parameter is added
* containing an object with application - name as attributes containing an array of linked ids
* ( adding happens in get_extras to give apps time to link new entries ! ) .
*
2013-08-20 14:06:41 +02:00
* @ param string $msg message ( already translated ) to show , eg . 'Entry deleted'
* @ param string $app application name
2014-10-09 22:32:59 +02:00
* @ param string | int $id = null id of entry to refresh
* @ param string $type = null either 'update' , 'edit' , 'delete' , 'add' or null
2014-06-25 18:10:43 +02:00
* - update : request just modified data from given rows .
* Sorting and filtering are not considered , so if the sort field is changed ,
* the row will not be moved . If the current filtering could include or exclude
* the record , use edit .
* - edit : rows changed , but sorting or filtering may be affected . Requires full reload .
2014-01-13 10:40:23 +01:00
* - delete : just delete the given rows clientside ( no server interaction neccessary )
* - add : requires full reload for proper sorting
* - null : full reload
2014-10-09 22:32:59 +02:00
* @ 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
* @ param string $msg_type = null 'error' , 'warning' or 'success' ( default )
2013-08-20 14:06:41 +02:00
*/
2013-09-05 13:53:25 +02:00
public static function refresh_opener ( $msg , $app , $id = null , $type = null , $targetapp = null , $replace = null , $with = null , $msg_type = null )
2013-08-20 14:06:41 +02:00
{
2014-10-09 22:32:59 +02:00
unset ( $msg , $app , $id , $type , $targetapp , $replace , $with , $msg_type ); // used only via func_get_args();
2013-08-20 15:25:36 +02:00
//error_log(__METHOD__.'('.array2string(func_get_args()).')');
2013-08-20 14:06:41 +02:00
self :: $extra [ 'refresh-opener' ] = func_get_args ();
}
2013-09-05 13:53:25 +02:00
/**
* Display an error or regular message
*
* Calls egw_message on client - side in a content security save way
*
* @ param string $msg message to show
2014-10-09 22:32:59 +02:00
* @ param string $type = 'success' 'error' , 'warning' or 'success' ( default )
2013-09-05 13:53:25 +02:00
*/
2013-10-03 11:23:18 +02:00
public static function message ( $msg , $type = 'success' )
2013-09-05 13:53:25 +02:00
{
2014-10-09 22:32:59 +02:00
unset ( $msg , $type ); // used only via func_get_args();
2013-09-05 13:53:25 +02:00
self :: $extra [ 'message' ] = func_get_args ();
}
2014-06-18 15:57:15 +02:00
/**
* Open a popup independent if we run as json or regular request
*
* @ param string $link
* @ param string $target
* @ param string $popup
*/
public static function popup ( $link , $target = '_blank' , $popup = '640x480' )
{
2014-10-09 22:32:59 +02:00
unset ( $link , $target , $popup ); // used only via func_get_args()
2014-06-18 15:57:15 +02:00
// default params are not returned by func_get_args!
$args = func_get_args () + array ( null , '_blank' , '640x480' );
if ( egw_json_request :: isJSONRequest ())
{
egw_json_response :: get () -> apply ( 'egw.open_link' , $args );
}
else
{
self :: $extra [ 'popup' ] = $args ;
}
}
2013-08-20 14:06:41 +02:00
/**
* Close ( popup ) window , use to replace egw_framework :: onload ( 'window.close()' ) in a content security save way
2013-08-26 12:24:11 +02:00
*
2014-10-09 22:32:59 +02:00
* @ param string $alert_msg = '' optional message to display as alert , before closing the window
2013-08-20 14:06:41 +02:00
*/
2013-08-26 12:24:11 +02:00
public static function window_close ( $alert_msg = '' )
2013-08-20 14:06:41 +02:00
{
2013-08-20 15:25:36 +02:00
//error_log(__METHOD__."()");
2013-08-26 12:24:11 +02:00
self :: $extra [ 'window-close' ] = $alert_msg ? $alert_msg : true ;
2013-08-20 14:06:41 +02:00
2013-11-15 14:03:09 +01:00
// are we in ajax_process_content -> just return extra data, with close instructions
if ( preg_match ( '/etemplate(_new)?(::|\.)ajax_process_content/' , $_GET [ 'menuaction' ]))
2013-08-20 14:06:41 +02:00
{
$response = egw_json_response :: get ();
$response -> generic ( 'et2_load' , egw_framework :: get_extra ());
}
else
{
$GLOBALS [ 'egw' ] -> framework -> render ( '' , false , false );
}
common :: egw_exit ();
}
2013-08-20 15:25:36 +02:00
/**
* Close ( popup ) window , use to replace egw_framework :: onload ( 'window.close()' ) in a content security save way
*/
public static function window_focus ()
{
//error_log(__METHOD__."()");
self :: $extra [ 'window-focus' ] = true ;
}
2013-12-05 00:28:31 +01:00
/**
* Allow app to store arbitray values in egw script tag
*
* Attribute name will be " data- $app - $name " and value will be json serialized , if not scalar .
*
* @ param string $app
* @ param string $name
* @ param mixed $value
*/
public static function set_extra ( $app , $name , $value )
{
self :: $extra [ $app . '-' . $name ] = $value ;
}
2014-03-10 16:20:27 +01:00
/**
* Clear all extra data
*/
public static function clear_extra ()
{
self :: $extra = array ();
}
2013-08-20 14:06:41 +02:00
/**
* 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 ()
{
2014-05-26 15:29:35 +02:00
// adding links of refreshed entry, to give others apps more information about necessity to refresh
if ( isset ( self :: $extra [ 'refresh-opener' ]) && count ( self :: $extra [ 'refresh-opener' ]) <= 8 && // do not run twice
! empty ( self :: $extra [ 'refresh-opener' ][ 1 ]) && ! empty ( self :: $extra [ 'refresh-opener' ][ 2 ])) // app/id given
{
$links = egw_link :: get_links ( self :: $extra [ 'refresh-opener' ][ 1 ], self :: $extra [ 'refresh-opener' ][ 2 ]);
$apps = array ();
foreach ( $links as $link )
{
$apps [ $link [ 'app' ]][] = $link [ 'id' ];
}
while ( count ( self :: $extra [ 'refresh-opener' ]) < 8 )
{
self :: $extra [ 'refresh-opener' ][] = null ;
}
self :: $extra [ 'refresh-opener' ][] = $apps ;
}
2013-08-20 14:06:41 +02:00
return self :: $extra ;
}
2007-01-05 15:06:34 +01:00
2006-12-11 00:44:18 +01:00
/**
* Returns the html - header incl . the opening body tag
*
* @ return string with html
*/
2013-07-19 19:07:05 +02:00
abstract function header ( array $extra = array ());
2006-12-11 00:44:18 +01:00
/**
* Returns the html from the body - tag til the main application area ( incl . opening div tag )
2010-11-09 15:44:18 +01:00
*
2010-10-18 12:46:47 +02:00
* If header has NOT been called , also return header content !
* No need to manually call header , this allows to postpone header so navbar / sidebox can include JS or CSS .
2006-12-11 00:44:18 +01:00
*
* @ return string with html
*/
2008-08-18 11:00:19 +02:00
abstract function navbar ();
2008-07-21 16:40:54 +02:00
2012-03-07 09:45:57 +01:00
/**
* Return true if we are rendering the top - level EGroupware window
*
* A top - level EGroupware window has a navbar : eg . no popup and for a framed template ( jdots ) only frameset itself
*
* @ return boolean $consider_navbar_not_yet_called_as_true = true
* @ return boolean
*/
abstract function isTop ( $consider_navbar_not_yet_called_as_true = true );
2006-12-11 00:44:18 +01:00
/**
* Returns the content of one sidebox
*
* @ param string $appname
* @ param string $menu_title
* @ param array $file
2014-10-09 22:32:59 +02:00
* @ param string $type = null 'admin' , 'preferences' , 'favorites' , ...
2006-12-11 00:44:18 +01:00
*/
2013-10-15 18:53:43 +02:00
abstract function sidebox ( $appname , $menu_title , $file , $type = null );
2008-07-21 16:40:54 +02:00
2006-12-11 00:44:18 +01:00
/**
* Returns the html from the closing div of the main application area to the closing html - tag
*
* @ return string
*/
2008-08-18 11:00:19 +02:00
abstract function footer ();
2008-07-21 16:40:54 +02:00
2006-12-25 12:05:44 +01:00
/**
2015-07-01 14:44:34 +02:00
* Displays the login screen
*
* @ param string $extra_vars for login url
* @ param string $change_passwd = null string with message to render input fields for password change
2013-11-14 14:52:50 +01:00
*/
2015-07-01 14:44:34 +02:00
function login_screen ( $extra_vars , $change_passwd = null )
2013-11-14 14:52:50 +01:00
{
2015-02-21 14:29:10 +01:00
self :: csp_frame_src_attrs ( array ()); // array() no external frame-sources
2014-09-04 11:58:48 +02:00
2015-05-27 16:01:32 +02:00
//error_log(__METHOD__."() this->template=$this->template, this->template_dir=$this->template_dir, get_class(this)=".get_class($this));
$tmpl = new Template ( EGW_SERVER_ROOT . $this -> template_dir );
2013-11-14 14:52:50 +01:00
2015-11-16 16:45:04 +01:00
$tmpl -> set_file ( array ( 'login_form' => html :: $ua_mobile ? 'login_mobile.tpl' : 'login.tpl' ));
2013-11-14 14:52:50 +01:00
$tmpl -> set_var ( 'lang_message' , $GLOBALS [ 'loginscreenmessage' ]);
2015-07-01 14:44:34 +02:00
// hide change-password fields, if not requested
if ( ! $change_passwd )
{
$tmpl -> set_block ( 'login_form' , 'change_password' );
$tmpl -> set_var ( 'change_password' , '' );
$tmpl -> set_var ( 'lang_password' , lang ( 'password' ));
$tmpl -> set_var ( 'cd' , check_logoutcode ( $_GET [ 'cd' ]));
$tmpl -> set_var ( 'cd_class' , isset ( $_GET [ 'cd' ]) && $_GET [ 'cd' ] != 1 ? 'error' : '' );
$last_loginid = $_COOKIE [ 'last_loginid' ];
$last_domain = $_COOKIE [ 'last_domain' ];
$tmpl -> set_var ( 'passwd' , '' );
$tmpl -> set_var ( 'autofocus_login' , 'autofocus' );
}
else
{
$tmpl -> set_var ( 'lang_password' , lang ( 'Old password' ));
$tmpl -> set_var ( 'lang_new_password' , lang ( 'New password' ));
$tmpl -> set_var ( 'lang_repeat_password' , lang ( 'Repeat password' ));
$tmpl -> set_var ( 'cd' , $change_passwd );
$tmpl -> set_var ( 'cd_class' , 'error' );
$last_loginid = $_POST [ 'login' ];
$last_domain = $_POST [ 'domain' ];
$tmpl -> set_var ( 'passwd' , $_POST [ 'passwd' ]);
$tmpl -> set_var ( 'autofocus_login' , '' );
$tmpl -> set_var ( 'autofocus_new_passwd' , 'autofocus' );
}
2013-11-14 14:52:50 +01:00
if ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'show_domain_selectbox' ])
{
2014-10-09 22:32:59 +02:00
foreach ( array_keys ( $GLOBALS [ 'egw_domain' ]) as $domain )
2013-11-14 14:52:50 +01:00
{
$domains [ $domain ] = $domain ;
}
$tmpl -> set_var ( array (
'lang_domain' => lang ( 'domain' ),
2015-07-01 14:44:34 +02:00
'select_domain' => html :: select ( 'logindomain' , $last_domain , $domains , true , 'tabindex="2"' , 0 , false ),
2013-11-14 14:52:50 +01:00
));
}
else
{
/* trick to make domain section disapear */
$tmpl -> set_block ( 'login_form' , 'domain_selection' );
$tmpl -> set_var ( 'domain_selection' , $GLOBALS [ 'egw_info' ][ 'user' ][ 'domain' ] ?
html :: input_hidden ( 'logindomain' , $GLOBALS [ 'egw_info' ][ 'user' ][ 'domain' ]) : '' );
if ( $last_loginid !== '' )
{
reset ( $GLOBALS [ 'egw_domain' ]);
list ( $default_domain ) = each ( $GLOBALS [ 'egw_domain' ]);
2015-07-01 14:44:34 +02:00
if ( ! empty ( $last_domain ) && $last_domain != $default_domain )
2013-11-14 14:52:50 +01:00
{
2015-07-01 14:44:34 +02:00
$last_loginid .= '@' . $last_domain ;
2013-11-14 14:52:50 +01:00
}
}
}
$config_reg = config :: read ( 'registration' );
if ( $config_reg [ 'enable_registration' ])
{
if ( $config_reg [ 'register_link' ])
{
2013-11-18 17:23:12 +01:00
$reg_link = ' <a href="' . egw :: link ( '/registration/index.php' , 'lang_code=' . $_GET [ 'lang' ]) . '">' . lang ( 'Not a user yet? Register now' ) . '</a><br/>' ;
2013-11-14 14:52:50 +01:00
}
if ( $config_reg [ 'lostpassword_link' ])
{
2013-11-18 17:23:12 +01:00
$lostpw_link = ' <a href="' . egw :: link ( '/registration/index.php' , 'menuaction=registration.registration_ui.lost_password&lang_code=' . $_GET [ 'lang' ]) . '">' . lang ( 'Lost password' ) . '</a><br/>' ;
2013-11-14 14:52:50 +01:00
}
if ( $config_reg [ 'lostid_link' ])
{
2013-11-18 17:23:12 +01:00
$lostid_link = ' <a href="' . egw :: link ( '/registration/index.php' , 'menuaction=registration.registration_ui.lost_username&lang_code=' . $_GET [ 'lang' ]) . '">' . lang ( 'Lost Login Id' ) . '</a><br/>' ;
2013-11-14 14:52:50 +01:00
}
/* if at least one option of "registration" is activated display the registration section */
if ( $config_reg [ 'register_link' ] || $config_reg [ 'lostpassword_link' ] || $config_reg [ 'lostid_link' ] )
{
$tmpl -> set_var ( array (
'register_link' => $reg_link ,
'lostpassword_link' => $lostpw_link ,
'lostid_link' => $lostid_link ,
));
}
else
{
/* trick to make registration section disapear */
$tmpl -> set_block ( 'login_form' , 'registration' );
$tmpl -> set_var ( 'registration' , '' );
}
}
$tmpl -> set_var ( 'login_url' , $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ] . '/login.php' . $extra_vars );
2015-07-01 14:44:34 +02:00
$tmpl -> set_var ( 'version' , $GLOBALS [ 'egw_info' ][ 'server' ][ 'versions' ][ 'phpgwapi' ]);
$tmpl -> set_var ( 'login' , $last_loginid );
2013-11-14 14:52:50 +01:00
$tmpl -> set_var ( 'lang_username' , lang ( 'username' ));
$tmpl -> set_var ( 'lang_login' , lang ( 'login' ));
$tmpl -> set_var ( 'website_title' , $GLOBALS [ 'egw_info' ][ 'server' ][ 'site_title' ]);
$tmpl -> set_var ( 'template_set' , $this -> template );
if ( substr ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_file' ], 0 , 4 ) == 'http' ||
2014-09-27 19:11:05 +02:00
$GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_file' ][ 0 ] == '/' )
2013-11-14 14:52:50 +01:00
{
$var [ 'logo_file' ] = $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_file' ];
}
else
{
2014-02-12 09:14:07 +01:00
$var [ 'logo_file' ] = common :: image ( 'phpgwapi' , $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_file' ] ? $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_file' ] : 'logo' , '' , null ); // null=explicit allow svg
2013-11-14 14:52:50 +01:00
}
$var [ 'logo_url' ] = $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_url' ] ? $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_url' ] : 'http://www.eGroupWare.org' ;
if ( substr ( $var [ 'logo_url' ], 0 , 4 ) != 'http' )
{
$var [ 'logo_url' ] = 'http://' . $var [ 'logo_url' ];
}
$var [ 'logo_title' ] = $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_title' ] ? $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_title' ] : 'www.eGroupWare.org' ;
$tmpl -> set_var ( $var );
/* language section if activated in site config */
if ( @ $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_show_language_selection' ])
{
$tmpl -> set_var ( array (
'lang_language' => lang ( 'Language' ),
'select_language' => html :: select ( 'lang' , $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'lang' ],
2013-11-18 17:40:51 +01:00
translation :: get_installed_langs (), true , 'tabindex="1"' , 0 , false ),
2013-11-14 14:52:50 +01:00
));
}
else
{
$tmpl -> set_block ( 'login_form' , 'language_select' );
$tmpl -> set_var ( 'language_select' , '' );
}
/******************************************************** \
* Check if authentification via cookies is allowed *
* and place a time selectbox , how long cookie is valid *
\ ********************************************************/
if ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'allow_cookie_auth' ])
{
$tmpl -> set_block ( 'login_form' , 'remember_me_selection' );
$tmpl -> set_var ( 'lang_remember_me' , lang ( 'Remember me' ));
$tmpl -> set_var ( 'select_remember_me' , html :: select ( 'remember_me' , '' , array (
'' => lang ( 'not' ),
'1hour' => lang ( '1 Hour' ),
'1day' => lang ( '1 Day' ),
'1week' => lang ( '1 Week' ),
'1month' => lang ( '1 Month' ),
'forever' => lang ( 'Forever' ),
2013-11-18 17:40:51 +01:00
), true , 'tabindex="3"' , 0 , false ));
2013-11-14 14:52:50 +01:00
}
else
{
/* trick to make remember_me section disapear */
$tmpl -> set_block ( 'login_form' , 'remember_me_selection' );
$tmpl -> set_var ( 'remember_me_selection' , '' );
}
$tmpl -> set_var ( 'autocomplete' , ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'autocomplete_login' ] ? 'autocomplete="off"' : '' ));
2013-11-18 17:23:12 +01:00
// load jquery for login screen too
self :: validate_file ( 'jquery' , 'jquery' );
2013-11-14 14:52:50 +01:00
$this -> render ( $tmpl -> fp ( 'loginout' , 'login_form' ), false , false );
}
2008-07-21 16:40:54 +02:00
2006-12-25 12:05:44 +01:00
/**
2013-11-14 14:52:50 +01:00
* displays a login denied message
*/
function denylogin_screen ()
{
2015-05-27 16:01:32 +02:00
$tmpl = new Template ( EGW_SERVER_ROOT . $this -> template_dir );
2013-11-14 14:52:50 +01:00
$tmpl -> set_file ( array (
'login_form' => 'login_denylogin.tpl'
));
$tmpl -> set_var ( array (
'template_set' => 'default' ,
'deny_msg' => lang ( 'Oops! You caught us in the middle of system maintainance.' ) .
'<br />' . lang ( 'Please, check back with us shortly.' ),
));
2013-11-18 17:23:12 +01:00
// load jquery for deny-login screen too
self :: validate_file ( 'jquery' , 'jquery' );
2013-11-14 14:52:50 +01:00
$this -> render ( $tmpl -> fp ( 'loginout' , 'login_form' ), false , false );
}
2008-07-21 16:40:54 +02:00
2006-12-11 00:44:18 +01:00
/**
* Get footer as array to eg . set as vars for a template ( from idots ' head . inc . php )
*
* @ return array
*/
2014-01-09 13:20:13 +01:00
public function _get_footer ()
2006-12-11 00:44:18 +01:00
{
$var = Array (
2010-06-03 00:43:41 +02:00
'img_root' => $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ] . $this -> template_dir . '/images' ,
2006-12-11 00:44:18 +01:00
'version' => $GLOBALS [ 'egw_info' ][ 'server' ][ 'versions' ][ 'phpgwapi' ]
);
2010-06-10 17:37:47 +02:00
$var [ 'page_generation_time' ] = '' ;
2006-12-11 00:44:18 +01:00
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'show_generation_time' ])
{
2008-07-21 16:40:54 +02:00
$totaltime = sprintf ( '%4.2lf' , microtime ( true ) - $GLOBALS [ 'egw_info' ][ 'flags' ][ 'page_start_time' ]);
2006-12-11 00:44:18 +01:00
2014-01-09 13:20:13 +01:00
$var [ 'page_generation_time' ] = '<div class="pageGenTime" id="divGenTime_' . $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ] . '"><span>' . lang ( 'Page was generated in %1 seconds' , $totaltime );
2008-03-22 17:22:11 +01:00
if ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'session_restore_time' ])
{
$var [ 'page_generation_time' ] .= ' ' . lang ( '(session restored in %1 seconds)' ,
sprintf ( '%4.2lf' , $GLOBALS [ 'egw_info' ][ 'flags' ][ 'session_restore_time' ]));
}
$var [ 'page_generation_time' ] .= '</span></div>' ;
2006-12-11 00:44:18 +01:00
}
2014-06-25 21:02:06 +02:00
$var [ 'powered_by' ] = '<a href="http://www.egroupware.org/" target="_blank">' .
lang ( 'Powered by' ) . ' Stylite\'s EGroupware ' .
$GLOBALS [ 'egw_info' ][ 'server' ][ 'versions' ][ 'phpgwapi' ] . '</a>' ;
2008-07-21 16:40:54 +02:00
2006-12-11 00:44:18 +01:00
return $var ;
}
/**
* Get the ( depricated ) application footer
*
* @ return string html
*/
2008-08-18 11:00:19 +02:00
protected static function _get_app_footer ()
2006-12-11 00:44:18 +01:00
{
ob_start ();
// Include the apps footer files if it exists
2008-07-21 16:40:54 +02:00
if ( EGW_APP_INC != EGW_API_INC && // this prevents an endless inclusion on the homepage
2006-12-11 00:44:18 +01:00
// (some apps set currentapp in hook_home => it's not releyable)
( file_exists ( EGW_APP_INC . '/footer.inc.php' ) || isset ( $_GET [ 'menuaction' ])) &&
$GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ] != 'home' &&
$GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ] != 'login' &&
$GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ] != 'logout' &&
!@ $GLOBALS [ 'egw_info' ][ 'flags' ][ 'noappfooter' ])
{
2014-10-09 22:32:59 +02:00
list (, $class ) = explode ( '.' ,( string ) $_GET [ 'menuaction' ]);
2008-07-21 16:40:54 +02:00
if ( $class && is_object ( $GLOBALS [ $class ]) && is_array ( $GLOBALS [ $class ] -> public_functions ) &&
2006-12-11 00:44:18 +01:00
isset ( $GLOBALS [ $class ] -> public_functions [ 'footer' ]))
{
$GLOBALS [ $class ] -> footer ();
}
elseif ( file_exists ( EGW_APP_INC . '/footer.inc.php' ))
{
include ( EGW_APP_INC . '/footer.inc.php' );
}
}
$content = ob_get_contents ();
ob_end_clean ();
2008-07-21 16:40:54 +02:00
return $content ;
2006-12-11 00:44:18 +01:00
}
/**
* Get header as array to eg . set as vars for a template ( from idots ' head . inc . php )
*
2014-10-09 22:32:59 +02:00
* @ param array $extra = array () extra attributes passed as data - attribute to egw . js
2006-12-11 00:44:18 +01:00
* @ return array
*/
2013-07-19 10:45:26 +02:00
protected function _get_header ( array $extra = array ())
2006-12-11 00:44:18 +01:00
{
2015-07-01 19:51:56 +02:00
// display password expires in N days message once per session
$message = null ;
if ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ] != 'login' &&
auth :: check_password_change ( $message ) !== true )
{
self :: message ( $message , 'info' );
}
2010-02-13 03:57:22 +01:00
// get used language code (with a little xss check, if someone tries to sneak something in)
if ( preg_match ( '/^[a-z]{2}(-[a-z]{2})?$/' , $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'lang' ]))
{
$lang_code = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'lang' ];
}
2010-11-10 11:49:16 +01:00
// IE specific fixes
if ( html :: $user_agent == 'msie' )
2006-12-11 00:44:18 +01:00
{
2010-11-10 11:49:16 +01:00
// tell IE to use it's own mode, not old compatibility modes (set eg. via group policy for all intranet sites)
// has to be before any other header tags, but meta and title!!!
$pngfix = '<meta http-equiv="X-UA-Compatible" content="IE=edge" />' . " \n " ;
// pngfix for IE6 defaults to yes
if ( ! $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'disable_pngfix' ] && html :: $ua_version < 7 )
{
$pngfix_src = $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ] . '/phpgwapi/templates/idots/js/pngfix.js' ;
$pngfix .= ' <!-- This solves the Internet Explorer PNG - transparency bug , but only for IE 5.5 - 6.0 and higher -->
<!-- [ if lt IE 7.0 ] >
< script src = " '. $pngfix_src .' " type = " text/javascript " >
</ script >
<! [ endif ] --> ' ;
}
2010-11-09 15:44:18 +01:00
}
2008-07-21 16:40:54 +02:00
2013-09-05 13:53:25 +02:00
$app = $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ];
$app_title = isset ( $GLOBALS [ 'egw_info' ][ 'apps' ][ $app ]) ? $GLOBALS [ 'egw_info' ][ 'apps' ][ $app ][ 'title' ] : lang ( $app );
$app_header = $GLOBALS [ 'egw_info' ][ 'flags' ][ 'app_header' ] ? $GLOBALS [ 'egw_info' ][ 'flags' ][ 'app_header' ] : $app_title ;
$site_title = strip_tags ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'site_title' ] . ' [' . ( $app_header ? $app_header : $app_title ) . ']' );
// send appheader to clientside
$extra [ 'app-header' ] = $app_header ;
if ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ] != 'wiki' ) $robots = '<meta name="robots" content="none" />' ;
2009-05-13 16:33:36 +02:00
if ( substr ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'favicon_file' ], 0 , 4 ) == 'http' )
{
$var [ 'favicon_file' ] = $GLOBALS [ 'egw_info' ][ 'server' ][ 'favicon_file' ];
}
else
{
2009-10-12 11:41:46 +02:00
$var [ 'favicon_file' ] = common :: image ( 'phpgwapi' , $GLOBALS [ 'egw_info' ][ 'server' ][ 'favicon_file' ] ? $GLOBALS [ 'egw_info' ][ 'server' ][ 'favicon_file' ] : 'favicon.ico' );
2009-05-13 16:33:36 +02:00
}
2008-07-21 16:40:54 +02:00
2012-04-04 15:05:58 +02:00
if ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'include_wz_tooltip' ] &&
file_exists ( EGW_SERVER_ROOT . ( $wz_tooltip = '/phpgwapi/js/wz_tooltip/wz_tooltip.js' )))
2010-01-17 04:20:45 +01:00
{
$include_wz_tooltip = '<script src="' . $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ] .
$wz_tooltip . '?' . filemtime ( EGW_SERVER_ROOT . $wz_tooltip ) . '" type="text/javascript"></script>' ;
}
2006-12-17 14:14:16 +01:00
return $this -> _get_css () + array (
2009-05-13 16:33:36 +02:00
'img_icon' => $var [ 'favicon_file' ],
'img_shortcut' => $var [ 'favicon_file' ],
2006-12-11 00:44:18 +01:00
'pngfix' => $pngfix ,
'lang_code' => $lang_code ,
2009-10-12 11:41:46 +02:00
'charset' => translation :: charset (),
2013-09-05 13:53:25 +02:00
'website_title' => $site_title ,
2008-08-18 11:00:19 +02:00
'body_tags' => self :: _get_body_attribs (),
2013-07-19 10:45:26 +02:00
'java_script' => self :: _get_js ( $extra ),
2006-12-11 00:44:18 +01:00
'meta_robots' => $robots ,
'dir_code' => lang ( 'language_direction_rtl' ) != 'rtl' ? '' : ' dir="rtl"' ,
2010-01-17 04:20:45 +01:00
'include_wz_tooltip' => $include_wz_tooltip ,
2010-06-02 10:10:43 +02:00
'webserver_url' => $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ],
2006-12-11 00:44:18 +01:00
);
}
/**
* Get navbar as array to eg . set as vars for a template ( from idots ' navbar . inc . php )
*
* @ param array $apps navbar apps from _get_navbar_apps
* @ return array
*/
2008-08-18 11:00:19 +02:00
protected function _get_navbar ( $apps )
2006-12-11 00:44:18 +01:00
{
$var [ 'img_root' ] = $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ] . '/phpgwapi/templates/' . $this -> template . '/images' ;
if ( isset ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'app_header' ]))
{
$var [ 'current_app_title' ] = $GLOBALS [ 'egw_info' ][ 'flags' ][ 'app_header' ];
}
else
{
$var [ 'current_app_title' ] = $apps [ $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ]][ 'title' ];
2009-11-18 21:00:26 +01:00
}
$var [ 'currentapp' ] = $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ];
2007-01-10 00:14:21 +01:00
2006-12-11 00:44:18 +01:00
// current users for admins
2008-08-07 23:12:44 +02:00
$var [ 'current_users' ] = $this -> _current_users ();
2008-07-21 16:40:54 +02:00
2006-12-11 00:44:18 +01:00
// quick add selectbox
$var [ 'quick_add' ] = $this -> _get_quick_add ();
2007-01-05 15:06:34 +01:00
$var [ 'user_info' ] = $this -> _user_time_info ();
2010-11-09 15:44:18 +01:00
2010-09-22 11:48:27 +02:00
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_lastpwd_change' ] == 0 )
2006-12-11 00:44:18 +01:00
{
$api_messages = lang ( 'You are required to change your password during your first login' ) . '<br />' .
2009-10-12 11:41:46 +02:00
lang ( 'Click this image on the navbar: %1' , '<img src="' . common :: image ( 'preferences' , 'navbar.gif' ) . '">' );
2006-12-11 00:44:18 +01:00
}
2010-09-22 11:48:27 +02:00
elseif ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'change_pwd_every_x_days' ] && $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_lastpwd_change' ] < time () - ( 86400 * $GLOBALS [ 'egw_info' ][ 'server' ][ 'change_pwd_every_x_days' ]))
2006-12-11 00:44:18 +01:00
{
2010-09-22 11:48:27 +02:00
$api_messages = lang ( 'it has been more then %1 days since you changed your password' , $GLOBALS [ 'egw_info' ][ 'server' ][ 'change_pwd_every_x_days' ]);
2006-12-11 00:44:18 +01:00
}
2010-06-02 23:28:07 +02:00
if ( substr ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_file' ], 0 , 4 ) == 'http' ||
$GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_file' ][ 0 ] == '/' )
2006-12-11 00:44:18 +01:00
{
$var [ 'logo_file' ] = $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_file' ];
}
else
{
2014-02-12 09:34:33 +01:00
$var [ 'logo_file' ] = common :: image ( 'phpgwapi' , $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_file' ] ? $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_file' ] : 'logo' , '' , null ); // null=explicit allow svg
2006-12-11 00:44:18 +01:00
}
$var [ 'logo_url' ] = $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_url' ] ? $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_url' ] : 'http://www.eGroupWare.org' ;
2008-07-21 16:40:54 +02:00
2006-12-11 00:44:18 +01:00
if ( substr ( $var [ 'logo_url' ], 0 , 4 ) != 'http' )
{
$var [ 'logo_url' ] = 'http://' . $var [ 'logo_url' ];
}
$var [ 'logo_title' ] = $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_title' ] ? $GLOBALS [ 'egw_info' ][ 'server' ][ 'login_logo_title' ] : 'www.eGroupWare.org' ;
2008-07-21 16:40:54 +02:00
2006-12-11 00:44:18 +01:00
return $var ;
}
2007-01-05 15:06:34 +01:00
/**
2008-08-18 11:00:19 +02:00
* Returns html with user and time
*
* @ return void
*/
protected static function _user_time_info ()
2007-01-05 15:06:34 +01:00
{
2009-10-12 11:41:46 +02:00
$now = new egw_time ();
$user_info = '<b>' . common :: display_fullname () . '</b>' . ' - ' . lang ( $now -> format ( 'l' )) . ' ' . $now -> format ( true );
2007-01-05 15:06:34 +01:00
2009-11-01 13:48:25 +01:00
$user_tzs = egw_time :: getUserTimezones ();
if ( count ( $user_tzs ) > 1 )
2009-10-12 11:41:46 +02:00
{
2009-11-01 13:48:25 +01:00
$tz = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'tz' ];
2014-06-13 13:16:04 +02:00
$user_info .= html :: form ( html :: select ( 'tz' , $tz , $user_tzs , true ), array (),
2009-10-12 11:41:46 +02:00
'/index.php' , '' , 'tz_selection' , ' style="display: inline;"' , 'GET' );
}
return $user_info ;
2007-01-05 15:06:34 +01:00
}
2008-08-18 11:00:19 +02:00
/**
* Prepare the current users
*
* @ return string
*/
protected static function _current_users ()
2007-01-10 00:14:21 +01:00
{
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'admin' ] && $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'show_currentusers' ])
{
2011-04-13 16:11:09 +02:00
$current_users = '<a href="' . egw :: link ( '/index.php' , 'menuaction=admin.admin_accesslog.sessions' ) . '">' .
2011-04-14 11:50:35 +02:00
lang ( 'Current users' ) . ': <span id="currentusers">' . $GLOBALS [ 'egw' ] -> session -> session_count () . '</span></a>' ;
2007-01-10 00:14:21 +01:00
return $current_users ;
}
}
2006-12-11 00:44:18 +01:00
/**
* Prepare the quick add selectbox
*
* @ return string
*/
2008-08-18 11:00:19 +02:00
protected static function _get_quick_add ()
2006-12-11 00:44:18 +01:00
{
2014-02-19 12:49:53 +01:00
return '<span id="quick_add"></span>' ;
2006-12-11 00:44:18 +01:00
}
2008-07-21 16:40:54 +02:00
2008-08-18 11:00:19 +02:00
/**
* Prepare notification signal ( blinking bell )
*
* @ return string
*/
protected static function _get_notification_bell ()
2008-03-21 21:11:59 +01:00
{
2013-07-22 15:29:20 +02:00
return html :: image ( 'notifications' , 'notificationbell' , lang ( 'notifications' ),
'id="notificationbell" style="display: none"' );
2007-11-22 09:29:16 +01:00
}
2008-07-21 16:40:54 +02:00
2014-07-17 11:22:54 +02:00
/**
* URL to check for security or maintenance updates
*/
const CURRENT_VERSION_URL = 'http://www.egroupware.org/currentversion' ;
/**
* How long to cache ( in secs ) / often to check for updates
*/
const VERSIONS_CACHE_TIMEOUT = 7200 ;
/**
* After how many days of not applied security updates , start warning non - admins too
*/
const WARN_USERS_DAYS = 3 ;
/**
* Check update status
*
* @ return string
* @ todo Check from client - side , if server - side check fails
*/
protected static function _get_update_notification ()
{
$versions = egw_cache :: getTree ( __CLASS__ , 'versions' , function ()
{
$versions = array ();
$security = null ;
2014-09-25 08:21:21 +02:00
if (( $remote = file_get_contents ( egw_framework :: CURRENT_VERSION_URL , false , egw_framework :: proxy_context ())))
2014-07-17 11:22:54 +02:00
{
list ( $current , $security ) = explode ( " \n " , $remote );
if ( empty ( $security )) $security = $current ;
$versions = array (
'current' => $current , // last maintenance update
'security' => $security , // last security update
);
}
return $versions ;
}, array (), self :: VERSIONS_CACHE_TIMEOUT );
$api = self :: api_version ();
if ( $versions )
{
if ( version_compare ( $api , $versions [ 'security' ], '<' ))
{
if ( ! $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'admin' ] && ! self :: update_older ( $versions [ 'security' ], self :: WARN_USERS_DAYS ))
{
return null ;
}
return html :: a_href ( html :: image ( 'phpgwapi' , 'security-update' , lang ( 'EGroupware security update %1 needs to be installed!' , $versions [ 'security' ])),
'http://www.egroupware.org/changelog' , null , ' target="_blank"' );
}
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'admin' ] && version_compare ( $api , $versions [ 'current' ], '<' ))
{
return html :: a_href ( html :: image ( 'phpgwapi' , 'update' , lang ( 'EGroupware maintenance update %1 available' , $versions [ 'current' ])),
'http://www.egroupware.org/changelog' , null , ' target="_blank"' );
}
}
elseif ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'admin' ])
{
2014-12-15 15:29:56 +01:00
$error = lang ( 'Automatic update check failed, you need to check manually!' );
if ( ! ini_get ( 'allow_url_fopen' ))
{
$error .= " \n " . lang ( '%1 setting "%2" = %3 disallows access via http!' ,
'php.ini' , 'allow_url_fopen' , array2string ( ini_get ( 'allow_url_fopen' )));
}
return html :: a_href ( html :: image ( 'phpgwapi' , 'update' , $error ),
2014-07-17 11:22:54 +02:00
'http://www.egroupware.org/changelog' , null , ' target="_blank" data-api-version="' . $api . '"' );
}
return null ;
}
2014-09-22 21:43:38 +02:00
/**
* Get context to use with file_get_context or fopen to use our proxy settings from setup
*
* @ param string $username = null username for regular basic auth
* @ param string $password = null password --------- " ----------
* @ return resource | null context to use with file_get_context / fopen or null if no proxy configured
*/
public static function proxy_context ( $username = null , $password = null )
{
2014-09-23 15:43:09 +02:00
$opts = array (
2014-09-22 21:43:38 +02:00
'method' => 'GET' ,
);
2014-09-23 15:43:09 +02:00
if ( ! empty ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'httpproxy_server' ]))
2014-09-22 21:43:38 +02:00
{
2014-09-23 15:43:09 +02:00
$opts += array (
'proxy' => 'tcp://' . $GLOBALS [ 'egw_info' ][ 'server' ][ 'httpproxy_server' ] . ':' .
( $GLOBALS [ 'egw_info' ][ 'server' ][ 'httpproxy_port' ] ? $GLOBALS [ 'egw_info' ][ 'server' ][ 'httpproxy_port' ] : 8080 ),
'request_fulluri' => true ,
);
// proxy authentication
if ( ! empty ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'httpproxy_server_username' ]))
{
$opts [ 'header' ][] = 'Proxy-Authorization: Basic ' . base64_encode ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'httpproxy_server_username' ] . ':' .
$GLOBALS [ 'egw_info' ][ 'server' ][ 'httpproxy_server_password' ]);
}
2014-09-22 21:43:38 +02:00
}
// optional authentication
if ( isset ( $username ))
{
$opts [ 'header' ][] = 'Authorization: Basic ' . base64_encode ( $username . ':' . $password );
}
return stream_context_create ( array (
'http' => $opts ,
'https' => $opts ,
));
}
2014-07-17 11:22:54 +02:00
/**
* Check if version is older then $days days
*
* @ param string $version eg . " 14.1.20140715 " last part is checked ( only if > 20140000 ! )
* @ param int $days
* @ return boolean
*/
protected static function update_older ( $version , $days )
{
list (,, $date ) = explode ( '.' , $version );
if ( $date < 20140000 ) return false ;
$version_timestamp = mktime ( 0 , 0 , 0 , ( int ) substr ( $date , 4 , 2 ), ( int ) substr ( $date , - 2 ), ( int ) substr ( $date , 0 , 4 ));
return ( time () - $version_timestamp ) / 86400 > $days ;
}
/**
* Get API version from changelog or database , whichever is bigger
*
* @ param string & $changelog on return path to changelog
* @ return string
*/
public static function api_version ( & $changelog = null )
{
$changelog = EGW_SERVER_ROOT . '/doc/rpm-build/debian.changes' ;
2015-11-05 15:18:17 +01:00
return egw_cache :: getTree ( __CLASS__ , 'api_version' , function () use ( $changelog )
2014-07-17 11:22:54 +02:00
{
2015-11-05 15:18:17 +01:00
$version = preg_replace ( '/[^0-9.]/' , '' , $GLOBALS [ 'egw_info' ][ 'server' ][ 'versions' ][ 'phpgwapi' ]);
// parse version from changelog
$matches = null ;
if (( $f = fopen ( $changelog , 'r' )) && preg_match ( '/egroupware-epl \(([0-9.]+)/' , fread ( $f , 80 ), $matches ) &&
version_compare ( $version , $matches [ 1 ], '<' ))
{
$version = $matches [ 1 ];
fclose ( $f );
}
return $version ;
}, array (), 300 );
2014-07-17 11:22:54 +02:00
}
2008-08-18 11:00:19 +02:00
/**
* Get the link to an application ' s index page
*
* @ param string $app
* @ return string
*/
2010-06-09 17:30:53 +02:00
public static function index ( $app )
2008-08-18 11:00:19 +02:00
{
$data =& $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ $app ];
if ( ! isset ( $data ))
{
throw new egw_exception_wrong_parameter ( " ' $app ' not a valid app for this user! " );
}
$index = '/' . $app . '/index.php' ;
if ( isset ( $data [ 'index' ]))
{
if ( $data [ 'index' ][ 0 ] == '/' )
{
$index = $data [ 'index' ];
}
else
{
$index = '/index.php?menuaction=' . $data [ 'index' ];
}
}
2009-10-12 11:41:46 +02:00
return egw :: link ( $index , $GLOBALS [ 'egw_info' ][ 'flags' ][ 'params' ][ $app ]);
2008-08-18 11:00:19 +02:00
}
2006-12-11 00:44:18 +01:00
2010-06-16 14:48:17 +02:00
/**
* Used internally to store unserialized value of $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'user_apporder' ]
*/
private static $user_apporder = array ();
2010-06-16 14:07:50 +02:00
/**
* Internal usort callback function used to sort an array according to the
* user sort order
*/
private static function _sort_apparray ( $a , $b )
{
//Unserialize the user_apporder array
2010-06-16 14:48:17 +02:00
$arr = self :: $user_apporder ;
2010-06-16 14:07:50 +02:00
$ind_a = isset ( $arr [ $a [ 'name' ]]) ? $arr [ $a [ 'name' ]] : null ;
$ind_b = isset ( $arr [ $b [ 'name' ]]) ? $arr [ $b [ 'name' ]] : null ;
if ( $ind_a == $ind_b )
return 0 ;
if ( $ind_a == null )
return - 1 ;
if ( $ind_b == null )
return 1 ;
return $ind_a > $ind_b ? 1 : - 1 ;
}
2006-12-11 00:44:18 +01:00
/**
* Prepare an array with apps used to render the navbar
2008-07-21 16:40:54 +02:00
*
2006-12-11 00:44:18 +01:00
* This is similar to the former common :: navbar () method - though it returns the vars and does not place them in global scope .
*
2014-10-09 22:32:59 +02:00
* @ param boolean $svg = false should svg images be returned or not :
2014-02-16 10:12:08 +01:00
* true : always return svg , false : never return svg ( current default ), null : browser dependent , see svg_usable ()
2006-12-11 00:44:18 +01:00
* @ return array
*/
2014-02-16 10:12:08 +01:00
protected static function _get_navbar_apps ( $svg = false )
2006-12-11 00:44:18 +01:00
{
list ( $first ) = each ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ]);
if ( is_array ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'admin' ]) && $first != 'admin' )
{
$newarray [ 'admin' ] = $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'admin' ];
foreach ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ] as $index => $value )
{
if ( $index != 'admin' )
{
$newarray [ $index ] = $value ;
}
}
$GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ] = $newarray ;
reset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ]);
}
unset ( $index );
unset ( $value );
unset ( $newarray );
2008-07-21 16:40:54 +02:00
2006-12-11 00:44:18 +01:00
$apps = array ();
foreach ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ] as $app => $data )
{
if ( is_long ( $app ))
{
continue ;
}
if ( $app == 'preferences' || $GLOBALS [ 'egw_info' ][ 'apps' ][ $app ][ 'status' ] != 2 && $GLOBALS [ 'egw_info' ][ 'apps' ][ $app ][ 'status' ] != 3 )
{
$apps [ $app ][ 'title' ] = $GLOBALS [ 'egw_info' ][ 'apps' ][ $app ][ 'title' ];
2008-08-18 11:00:19 +02:00
$apps [ $app ][ 'url' ] = self :: index ( $app );
2006-12-11 00:44:18 +01:00
$apps [ $app ][ 'name' ] = $app ;
// create popup target
if ( $data [ 'status' ] == 4 )
{
$apps [ $app ][ 'target' ] = ' target="' . $app . '" onClick="' . " if (this != '') { window.open(this+' " .
2007-04-30 07:42:05 +02:00
( strpos ( $apps [ $app ][ 'url' ], '?' ) !== false ? '&' : '?' ) .
2007-06-08 12:24:20 +02:00
" referer='+encodeURIComponent(location),this.target,'width=800,height=600,scrollbars=yes,resizable=yes'); return false; } else { return true; } " . '"' ;
2006-12-11 00:44:18 +01:00
}
elseif ( isset ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'navbar_target' ]) && $GLOBALS [ 'egw_info' ][ 'flags' ][ 'navbar_target' ])
{
$apps [ $app ][ 'target' ] = 'target="' . $GLOBALS [ 'egw_info' ][ 'flags' ][ 'navbar_target' ] . '"' ;
}
else
{
$apps [ $app ][ 'target' ] = '' ;
}
2008-08-18 11:00:19 +02:00
$icon = isset ( $data [ 'icon' ]) ? $data [ 'icon' ] : 'navbar' ;
$icon_app = isset ( $data [ 'icon_app' ]) ? $data [ 'icon_app' ] : $app ;
2006-12-11 00:44:18 +01:00
if ( $app != $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ])
{
2014-02-16 10:12:08 +01:00
$apps [ $app ][ 'icon' ] = common :: image ( $icon_app , Array ( $icon , 'nonav' ), '' , $svg );
$apps [ $app ][ 'icon_hover' ] = common :: image_on ( $icon_app , Array ( $icon , 'nonav' ), '-over' , $svg );
2006-12-11 00:44:18 +01:00
}
else
{
2014-02-16 10:12:08 +01:00
$apps [ $app ][ 'icon' ] = common :: image_on ( $icon_app , Array ( $icon , 'nonav' ), '-over' , $svg );
$apps [ $app ][ 'icon_hover' ] = common :: image ( $icon_app , Array ( $icon , 'nonav' ), '' , $svg );
2006-12-11 00:44:18 +01:00
}
}
}
2010-06-16 14:07:50 +02:00
//Sort the applications accordingly to their user sort setting
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'user_apporder' ])
{
//Sort the application array using the user_apporder array as sort index
2010-06-16 14:48:17 +02:00
self :: $user_apporder =
unserialize ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'user_apporder' ]);
2010-06-16 14:07:50 +02:00
uasort ( $apps , 'egw_framework::_sort_apparray' );
}
2006-12-11 00:44:18 +01:00
if ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ] == 'preferences' || $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ] == 'about' )
{
2010-06-03 00:43:41 +02:00
$app = $app_title = 'EGroupware' ;
2006-12-11 00:44:18 +01:00
}
else
{
$app = $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ];
$app_title = $GLOBALS [ 'egw_info' ][ 'apps' ][ $app ][ 'title' ];
}
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'preferences' ]) // preferences last
{
$prefs = $apps [ 'preferences' ];
unset ( $apps [ 'preferences' ]);
$apps [ 'preferences' ] = $prefs ;
}
// We handle this here becuase its special
2011-06-03 20:36:47 +02:00
$apps [ 'about' ][ 'title' ] = 'EGroupware' ;
2006-12-11 00:44:18 +01:00
2010-11-21 14:37:09 +01:00
$apps [ 'about' ][ 'url' ] = egw :: link ( '/about.php' );
2009-10-12 11:41:46 +02:00
$apps [ 'about' ][ 'icon' ] = common :: image ( 'phpgwapi' , Array ( 'about' , 'nonav' ));
$apps [ 'about' ][ 'icon_hover' ] = common :: image_on ( 'phpgwapi' , Array ( 'about' , 'nonav' ), '-over' );
2010-06-04 10:06:02 +02:00
$apps [ 'about' ][ 'name' ] = 'about' ;
2006-12-11 00:44:18 +01:00
$apps [ 'logout' ][ 'title' ] = lang ( 'Logout' );
2013-12-17 21:21:48 +01:00
$apps [ 'logout' ][ 'name' ] = 'logout' ;
2009-10-12 11:41:46 +02:00
$apps [ 'logout' ][ 'url' ] = egw :: link ( '/logout.php' );
$apps [ 'logout' ][ 'icon' ] = common :: image ( 'phpgwapi' , Array ( 'logout' , 'nonav' ));
$apps [ 'logout' ][ 'icon_hover' ] = common :: image_on ( 'phpgwapi' , Array ( 'logout' , 'nonav' ), '-over' );
2008-07-21 16:40:54 +02:00
2006-12-11 00:44:18 +01:00
return $apps ;
}
2008-07-21 16:40:54 +02:00
2006-12-11 00:44:18 +01:00
/**
* Used by template headers for including CSS in the header
*
2006-12-17 14:14:16 +01:00
* 'app_css' - css styles from a ) the menuaction 's css-method and b) the $GLOBALS[' egw_info '][' flags '][' css ' ]
* 'file_css' - link tag of the app . css file of the current app
* 'theme_css' - url of the theme css file
* 'print_css' - url of the print css file
2008-07-21 16:40:54 +02:00
*
2006-12-11 00:44:18 +01:00
* @ author Dave Hall ( * based * on verdilak ? css inclusion code )
2006-12-17 14:14:16 +01:00
* @ return array with keys 'app_css' from the css method of the menuaction - class and 'file_css' ( app . css file of the application )
2006-12-11 00:44:18 +01:00
*/
2011-01-06 21:47:21 +01:00
public function _get_css ()
2006-12-11 00:44:18 +01:00
{
$app_css = '' ;
if ( isset ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'css' ]))
{
2014-03-03 15:54:03 +01:00
$app_css = $GLOBALS [ 'egw_info' ][ 'flags' ][ 'css' ];
2006-12-11 00:44:18 +01:00
}
2014-03-03 15:54:03 +01:00
if ( self :: $load_default_css )
2006-12-17 14:14:16 +01:00
{
2014-03-03 15:54:03 +01:00
// Load these first
// Cascade should go:
2014-03-18 16:29:03 +01:00
// Libs < etemplate2 < framework/theme < app < print
2014-03-03 15:54:03 +01:00
// Enhanced selectboxes (et1)
self :: includeCSS ( '/phpgwapi/js/jquery/chosen/chosen.css' );
// eTemplate2 uses jQueryUI, so load it first so et2 can override if needed
2015-02-03 10:26:34 +01:00
self :: includeCSS ( " /phpgwapi/js/jquery/jquery-ui/redmond/jquery-ui.css " );
2012-10-14 21:38:32 +02:00
2014-03-03 15:54:03 +01:00
// eTemplate2 - load in top so sidebox has styles too
self :: includeCSS ( '/etemplate/templates/default/etemplate2.css' );
2008-07-21 16:40:54 +02:00
2015-10-15 19:28:56 +02:00
// Category styles
2015-10-20 00:26:09 +02:00
categories :: css ( categories :: GLOBAL_APPNAME );
2015-10-15 19:28:56 +02:00
2014-12-01 09:43:07 +01:00
// For mobile user-agent we prefer mobile theme over selected one with a final fallback to theme named as template
$themes_to_check = array ();
2016-02-18 17:27:15 +01:00
if ( html :: $ua_mobile ) $themes_to_check [] = $this -> template_dir . '/mobile/fw_mobile.css' ;
2014-12-01 09:43:07 +01:00
$themes_to_check [] = $this -> template_dir . '/css/' . $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'theme' ] . '.css' ;
$themes_to_check [] = $this -> template_dir . '/css/' . $this -> template . '.css' ;
foreach ( $themes_to_check as $theme_css )
2014-03-03 15:54:03 +01:00
{
2014-12-01 09:43:07 +01:00
if ( file_exists ( EGW_SERVER_ROOT . $theme_css )) break ;
2014-03-03 15:54:03 +01:00
}
2014-03-18 16:29:03 +01:00
self :: includeCSS ( $theme_css );
// search for app specific css file, so it can customize the theme
2015-09-18 17:53:20 +02:00
self :: includeCSS ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ], 'app-' . $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'theme' ]) ||
self :: includeCSS ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ], 'app' );
2014-03-18 16:29:03 +01:00
// sending print css last, so it can overwrite anything
2014-03-03 15:54:03 +01:00
$print_css = $this -> template_dir . '/print.css' ;
if ( ! file_exists ( EGW_SERVER_ROOT . $print_css ))
{
$print_css = '/phpgwapi/templates/idots/print.css' ;
}
self :: includeCSS ( $print_css );
}
2012-10-14 21:38:32 +02:00
// add all css files from self::includeCSS
$max_modified = 0 ;
2014-01-10 17:08:13 +01:00
$debug_minify = $GLOBALS [ 'egw_info' ][ 'server' ][ 'debug_minify' ] === 'True' ;
2012-10-14 21:38:32 +02:00
$base_path = $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ];
2012-10-15 08:51:54 +02:00
if ( $base_path [ 0 ] != '/' ) $base_path = parse_url ( $base_path , PHP_URL_PATH );
2014-01-10 17:08:13 +01:00
$css_files = '' ;
2014-10-09 22:32:59 +02:00
foreach ( self :: $css_include_files as $path )
2012-10-14 21:38:32 +02:00
{
foreach ( self :: resolve_css_includes ( $path ) as $path )
{
2015-10-15 19:28:56 +02:00
list ( $file , $query ) = explode ( '?' , $path , 2 );
if (( $mod = filemtime ( EGW_SERVER_ROOT . $file )) > $max_modified ) $max_modified = $mod ;
2012-10-14 21:38:32 +02:00
2015-10-15 19:28:56 +02:00
// do NOT include app.css or categories.php, as it changes from app to app
if ( $debug_minify || substr ( $path , - 8 ) == '/app.css' || substr ( $file , - 14 ) == 'categories.php' )
2012-10-14 21:38:32 +02:00
{
2015-10-15 19:28:56 +02:00
$css_files .= '<link href="' . $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ] . $path . ( $query ? '&' : '?' ) . $mod . '" type="text/css" rel="StyleSheet" />' . " \n " ;
2012-10-14 21:38:32 +02:00
}
else
{
$css_file .= ( $css_file ? ',' : '' ) . substr ( $path , 1 );
}
}
}
if ( ! $debug_minify )
{
2012-10-26 11:24:39 +02:00
$css = $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ] . '/phpgwapi/inc/min/?' ;
if ( $base_path && $base_path != '/' ) $css .= 'b=' . substr ( $base_path , 1 ) . '&' ;
2014-01-10 17:08:13 +01:00
$css .= 'f=' . $css_file .
( $GLOBALS [ 'egw_info' ][ 'server' ][ 'debug_minify' ] === 'debug' ? '&debug' : '' ) .
'&' . $max_modified ;
$css_files = '<link href="' . $css . '" type="text/css" rel="StyleSheet" />' . " \n " . $css_files ;
2012-10-14 21:38:32 +02:00
}
2006-12-17 14:14:16 +01:00
return array (
'app_css' => $app_css ,
2014-01-10 17:08:13 +01:00
'css_file' => $css_files ,
2006-12-17 14:14:16 +01:00
);
2006-12-11 00:44:18 +01:00
}
2012-10-14 21:38:32 +02:00
/**
* Parse beginning of given CSS file for /*@ import url ( " ... " ) statements
*
* @ param string $path EGroupware relative path eg . / phpgwapi / templates / default / some . css
* @ return array parsed pathes ( EGroupware relative ) including $path itself
*/
protected static function resolve_css_includes ( $path , & $pathes = array ())
{
2014-10-09 22:32:59 +02:00
$matches = null ;
2015-10-15 19:28:56 +02:00
2015-10-19 12:26:00 +02:00
list ( $file ) = explode ( '?' , $path , 2 );
2015-10-15 19:28:56 +02:00
if (( $to_check = file_get_contents ( EGW_SERVER_ROOT . $file , false , null , - 1 , 1024 )) &&
2012-10-14 21:38:32 +02:00
stripos ( $to_check , '/*@import' ) !== false && preg_match_all ( '|/\*@import url\("([^"]+)"|i' , $to_check , $matches ))
{
foreach ( $matches [ 1 ] as $import_path )
{
if ( $import_path [ 0 ] != '/' )
{
$dir = dirname ( $path );
while ( substr ( $import_path , 0 , 3 ) == '../' )
{
$dir = dirname ( $dir );
$import_path = substr ( $import_path , 3 );
}
$import_path = ( $dir != '/' ? $dir : '' ) . '/' . $import_path ;
}
self :: resolve_css_includes ( $import_path , $pathes );
}
}
$pathes [] = $path ;
return $pathes ;
}
2006-12-11 00:44:18 +01:00
/**
* Used by the template headers for including javascript in the header
*
* The method is included here to make it easier to change the js support
* in eGW . One change then all templates will support it ( as long as they
* include a call to this method ) .
*
2014-10-09 22:32:59 +02:00
* @ param array $extra = array () extra data to pass to egw . js as data - parameter
2006-12-11 00:44:18 +01:00
* @ return string the javascript to be included
*/
2013-07-19 10:45:26 +02:00
public static function _get_js ( array $extra = array ())
2006-12-11 00:44:18 +01:00
{
$java_script = '' ;
2008-07-21 16:40:54 +02:00
2011-08-23 16:29:56 +02:00
/* this flag is for all javascript code that has to be put before other jscode .
Think of conf vars etc ... ( pim @ lingewoud . nl ) */
if ( isset ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'java_script_thirst' ]))
{
$java_script .= $GLOBALS [ 'egw_info' ][ 'flags' ][ 'java_script_thirst' ] . " \n " ;
}
2013-07-19 17:22:00 +02:00
// add configuration, link-registry, images, user-data and -perferences for non-popup windows
2014-01-18 18:43:15 +01:00
// specifying etag in url to force reload, as we send expires header
2011-08-26 18:27:57 +02:00
if ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'js_link_registry' ])
{
2014-01-18 18:43:15 +01:00
self :: validate_file ( '/phpgwapi/config.php' , array (
'etag' => md5 ( json_encode ( config :: clientConfigs ()) . egw_link :: json_registry ()),
));
self :: validate_file ( '/phpgwapi/images.php' , array (
2014-03-03 18:35:48 +01:00
'template' => $GLOBALS [ 'egw_info' ][ 'server' ][ 'template_set' ],
'etag' => md5 ( json_encode ( common :: image_map ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'template_set' ]))),
2016-02-24 17:47:32 +01:00
'svg' => html :: $ua_mobile , // always load non-svg image map, ATM we use svg icons only for mobile theme
2014-01-18 18:43:15 +01:00
));
self :: validate_file ( '/phpgwapi/user.php' , array (
'user' => $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_lid' ],
'lang' => $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'lang' ],
// add etag on url, so we can set an expires header
'etag' => md5 ( json_encode ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ]) .
$GLOBALS [ 'egw' ] -> accounts -> json ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ])),
));
2011-08-26 18:27:57 +02:00
}
2011-08-23 16:29:56 +02:00
2013-07-19 10:45:26 +02:00
$extra [ 'url' ] = $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ];
$extra [ 'include' ] = array_map ( function ( $str ){ return substr ( $str , 1 );}, self :: get_script_links ( true ), array ( 1 ));
$extra [ 'app' ] = $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ];
2011-06-02 13:13:41 +02:00
2013-04-01 21:14:52 +02:00
// Load LABjs ONCE here
2014-11-27 09:51:31 +01:00
$java_script .= '<script type="text/javascript" src="' . $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ] .
'/phpgwapi/js/labjs/LAB.src.js?' . filemtime ( EGW_SERVER_ROOT . '/phpgwapi/js/labjs/LAB.src.js' ) . " \" ></script> \n " .
'<script type="text/javascript" src="' . $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ] .
'/phpgwapi/js/jsapi/egw.js?' . filemtime ( EGW_SERVER_ROOT . '/phpgwapi/js/jsapi/egw.js' ) . '" id="egw_script_id"' ;
2013-08-20 14:06:41 +02:00
// add values of extra parameter and class var as data attributes to script tag of egw.js
foreach ( $extra + self :: $extra as $name => $value )
2013-07-19 10:45:26 +02:00
{
if ( is_array ( $value )) $value = json_encode ( $value );
2013-08-01 08:36:18 +02:00
// we need to double encode (html::htmlspecialchars( , TRUE)), as otherwise we get invalid json, eg. for quotes
$java_script .= ' data-' . $name . " = \" " . html :: htmlspecialchars ( $value , true ) . " \" " ;
2013-07-19 10:45:26 +02:00
}
$java_script .= " ></script> \n " ;
2010-11-09 15:44:18 +01:00
2006-12-11 00:44:18 +01:00
if ( @ isset ( $_GET [ 'menuaction' ]))
{
2014-10-09 22:32:59 +02:00
list (, $class ) = explode ( '.' , $_GET [ 'menuaction' ]);
2006-12-11 00:44:18 +01:00
if ( is_array ( $GLOBALS [ $class ] -> public_functions ) &&
$GLOBALS [ $class ] -> public_functions [ 'java_script' ])
{
$java_script .= $GLOBALS [ $class ] -> java_script ();
}
}
if ( isset ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'java_script' ]))
{
2013-04-01 21:14:52 +02:00
// Strip out any script tags, this needs to be executed as anonymous function
2013-04-09 14:47:44 +02:00
$GLOBALS [ 'egw_info' ][ 'flags' ][ 'java_script' ] = preg_replace ( array ( '/(<script[^>]*>)([^<]*)/is' , '/<\/script>/' ), array ( '$2' , '' ), $GLOBALS [ 'egw_info' ][ 'flags' ][ 'java_script' ]);
2013-04-01 21:14:52 +02:00
if ( trim ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'java_script' ]) != '' )
{
2013-07-17 14:47:21 +02:00
$java_script .= '<script type="text/javascript">window.egw_LAB.wait(function() {' . $GLOBALS [ 'egw_info' ][ 'flags' ][ 'java_script' ] . " });</script> \n " ;
2013-04-01 21:14:52 +02:00
}
2006-12-11 00:44:18 +01:00
}
2013-04-01 21:14:52 +02:00
2006-12-11 00:44:18 +01:00
return $java_script ;
}
2010-06-02 12:59:58 +02:00
/**
* List available themes
*
* Themes are css file in the template directory
2010-11-09 15:44:18 +01:00
*
2014-10-09 22:32:59 +02:00
* @ param string $themes_dir = 'css'
2010-06-02 12:59:58 +02:00
*/
function list_themes ()
{
$list = array ();
if (( $dh = @ opendir ( EGW_SERVER_ROOT . $this -> template_dir . SEP . 'css' )))
{
while (( $file = readdir ( $dh )))
{
if ( preg_match ( '/' . " \ .css $ " . '/i' , $file ))
{
list ( $name ) = explode ( '.' , $file );
$list [ $name ] = $name ;
}
}
closedir ( $dh );
}
return $list ;
}
/**
* List available templates
*
2014-10-09 22:32:59 +02:00
* @ param boolean $full_data = false true : value is array with values for keys 'name' , 'title' , ...
2010-06-02 12:59:58 +02:00
* @ returns array alphabetically sorted list of templates
*/
2010-06-03 00:43:41 +02:00
static function list_templates ( $full_data = false )
2010-06-02 12:59:58 +02:00
{
2014-06-25 21:02:06 +02:00
$list = array ( 'pixelegg' => null , 'jdots' => null , 'idots' => null );
2010-06-02 12:59:58 +02:00
// templates packaged in the api
$d = dir ( EGW_SERVER_ROOT . '/phpgwapi/templates' );
while (( $entry = $d -> read ()))
{
if ( $entry != '..' && file_exists ( EGW_SERVER_ROOT . '/phpgwapi/templates/' . $entry . '/class.' . $entry . '_framework.inc.php' ))
{
if ( file_exists ( $f = EGW_SERVER_ROOT . '/phpgwapi/templates/' . $entry . '/setup/setup.inc.php' ))
{
include ( $f );
2010-11-09 15:44:18 +01:00
$list [ $entry ] = $full_data ? $GLOBALS [ 'egw_info' ][ 'template' ][ $entry ] :
2010-06-03 00:43:41 +02:00
$GLOBALS [ 'egw_info' ][ 'template' ][ $entry ][ 'title' ];
2010-06-02 12:59:58 +02:00
}
else
{
2010-06-03 00:43:41 +02:00
$list [ $entry ] = $full_data ? array (
'name' => $entry ,
'title' => $entry ,
) : $entry ;
2010-06-02 12:59:58 +02:00
}
}
}
$d -> close ();
// templates packaged like apps in own directories (containing as setup/setup.inc.php file!)
2014-10-09 22:32:59 +02:00
$dr = dir ( EGW_SERVER_ROOT );
while (( $entry = $dr -> read ()))
2010-06-02 12:59:58 +02:00
{
2011-06-07 09:02:08 +02:00
if ( $entry != '..' && ! isset ( $GLOBALS [ 'egw_info' ][ 'apps' ][ $entry ]) && is_dir ( EGW_SERVER_ROOT . '/' . $entry ) &&
2010-06-02 19:33:26 +02:00
file_exists ( $f = EGW_SERVER_ROOT . '/' . $entry . '/setup/setup.inc.php' ))
2010-06-02 12:59:58 +02:00
{
include ( $f );
if ( isset ( $GLOBALS [ 'egw_info' ][ 'template' ][ $entry ]))
{
2010-11-09 15:44:18 +01:00
$list [ $entry ] = $full_data ? $GLOBALS [ 'egw_info' ][ 'template' ][ $entry ] :
2010-06-03 00:43:41 +02:00
$GLOBALS [ 'egw_info' ][ 'template' ][ $entry ][ 'title' ];
2010-06-02 12:59:58 +02:00
}
}
}
2014-10-09 22:32:59 +02:00
$dr -> close ();
2010-06-02 12:59:58 +02:00
2014-06-25 21:02:06 +02:00
return array_filter ( $list );
2010-06-02 12:59:58 +02:00
}
2010-06-07 13:49:16 +02:00
/**
* Compile entries for topmenu :
* - regular items : links
* - info items
*
* @ param array $vars
* @ param array $apps
*/
function topmenu ( array $vars , array $apps )
{
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'home' ] && isset ( $apps [ 'home' ]))
{
$this -> _add_topmenu_item ( $apps [ 'home' ]);
}
2013-10-03 11:23:18 +02:00
2010-06-07 13:49:16 +02:00
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'preferences' ])
{
2013-10-03 11:23:18 +02:00
$this -> add_preferences_topmenu ( 'prefs' );
$this -> add_preferences_topmenu ( 'acl' );
$this -> add_preferences_topmenu ( 'cats' );
2010-06-07 13:49:16 +02:00
}
2013-10-03 11:23:18 +02:00
2012-06-29 09:14:46 +02:00
// allways display password in topmenu, if user has rights to change it
2014-04-17 09:37:21 +02:00
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'preferences' ] &&
2012-06-29 09:14:46 +02:00
! $GLOBALS [ 'egw' ] -> acl -> check ( 'nopasswordchange' , 1 , 'preferences' ))
2010-07-27 16:29:20 +02:00
{
$this -> _add_topmenu_item ( array (
2014-04-17 09:37:21 +02:00
'id' => 'password' ,
'name' => 'preferences' ,
2011-06-03 20:36:47 +02:00
'title' => lang ( 'Password' ),
2015-03-16 18:43:42 +01:00
'url' => " javascript:egw.open_link(' " .
egw :: link ( '/index.php?menuaction=preferences.preferences_password.change' ) . " ','_blank','400x270') " ,
2010-07-27 16:29:20 +02:00
));
}
2014-04-24 07:56:41 +02:00
/* disable help until content is reworked
2010-06-07 13:49:16 +02:00
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'manual' ] && isset ( $apps [ 'manual' ]))
{
2011-06-03 20:36:47 +02:00
$this -> _add_topmenu_item ( array_merge ( $apps [ 'manual' ], array ( 'title' => lang ( 'Help' ))));
2014-04-24 07:56:41 +02:00
} */
2010-06-07 13:49:16 +02:00
$GLOBALS [ 'egw' ] -> hooks -> process ( 'topmenu_info' , array (), true );
// Add extra items added by hooks
foreach ( self :: $top_menu_extra as $extra_item ) {
$this -> _add_topmenu_item ( $extra_item );
}
$this -> _add_topmenu_item ( $apps [ 'logout' ]);
2014-07-17 11:22:54 +02:00
if (( $update = self :: _get_update_notification ()))
{
$this -> _add_topmenu_info_item ( $update , 'update' );
}
2010-06-07 13:49:16 +02:00
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'notifications' ])
{
2014-01-17 10:23:23 +01:00
$this -> _add_topmenu_info_item ( self :: _get_notification_bell (), 'notifications' );
2010-06-07 13:49:16 +02:00
}
2014-01-17 10:23:23 +01:00
$this -> _add_topmenu_info_item ( $vars [ 'user_info' ], 'user_info' );
$this -> _add_topmenu_info_item ( $vars [ 'current_users' ], 'current_users' );
$this -> _add_topmenu_info_item ( $vars [ 'quick_add' ], 'quick_add' );
2010-06-07 13:49:16 +02:00
}
2013-10-02 18:29:08 +02:00
/**
2013-10-03 11:23:18 +02:00
* Add preferences link to topmenu using settings - hook to know if an app supports preferences
2013-10-02 18:29:08 +02:00
*/
2013-10-03 11:23:18 +02:00
protected function add_preferences_topmenu ( $type = 'prefs' )
2013-10-02 18:29:08 +02:00
{
2014-10-09 22:32:59 +02:00
static $memberships = null ;
2013-10-03 11:23:18 +02:00
if ( ! isset ( $memberships )) $memberships = $GLOBALS [ 'egw' ] -> accounts -> memberships ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ], true );
static $types = array (
'prefs' => array (
'title' => 'Preferences' ,
'hook' => 'settings' ,
),
'acl' => array (
'title' => 'Access' ,
'hook' => 'acl_rights' ,
),
'cats' => array (
'title' => 'Categories' ,
'hook' => 'categories' ,
'run_hook' => true , // acturally run hook, not just look it's implemented
),
);
if ( ! $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'preferences' ] || $GLOBALS [ 'egw_info' ][ 'server' ][ 'deny_' . $type ] &&
2014-07-14 18:26:03 +02:00
array_intersect ( $memberships , ( array ) $GLOBALS [ 'egw_info' ][ 'server' ][ 'deny_' . $type ]) &&
! $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'admin' ])
2013-10-02 18:29:08 +02:00
{
return ; // user has no access to preferences app
}
2013-10-03 11:23:18 +02:00
if ( isset ( $types [ $type ][ 'run_hook' ]))
2013-10-02 18:29:08 +02:00
{
2013-10-03 11:23:18 +02:00
$apps = $GLOBALS [ 'egw' ] -> hooks -> process ( $types [ $type ][ 'hook' ]);
// as all apps answer, we need to remove none-true responses
foreach ( $apps as $app => $val )
{
if ( ! $val ) unset ( $apps [ $app ]);
}
2013-10-02 18:29:08 +02:00
}
2013-10-03 11:23:18 +02:00
else
{
$apps = $GLOBALS [ 'egw' ] -> hooks -> hook_implemented ( $types [ $type ][ 'hook' ]);
}
$this -> _add_topmenu_item ( array (
2013-12-17 21:21:48 +01:00
'id' => $type ,
2013-10-02 18:29:08 +02:00
'name' => 'preferences' ,
2013-10-03 11:23:18 +02:00
'title' => lang ( $types [ $type ][ 'title' ]),
2014-02-07 15:04:12 +01:00
'url' => " javascript:egw.show_preferences( \" $type\ " , " .json_encode( $apps ).')',
2013-10-03 11:23:18 +02:00
));
2013-10-02 18:29:08 +02:00
}
2010-06-07 13:49:16 +02:00
/**
* Add menu items to the topmenu template class to be displayed
*
* @ param array $app application data
* @ param mixed $alt_label string with alternative menu item label default value = null
* @ param string $urlextra string with alternate additional code inside < a >- tag
* @ access protected
* @ return void
*/
abstract function _add_topmenu_item ( array $app_data , $alt_label = null );
/**
* Add info items to the topmenu template class to be displayed
*
* @ param string $content html of item
2014-10-09 22:32:59 +02:00
* @ param string $id = null
2010-06-07 13:49:16 +02:00
* @ access protected
* @ return void
*/
2014-01-17 10:23:23 +01:00
abstract function _add_topmenu_info_item ( $content , $id = null );
2010-06-07 13:49:16 +02:00
2010-06-10 09:35:16 +02:00
static $top_menu_extra = array ();
2010-06-07 13:49:16 +02:00
/**
* Called by hooks to add an entry in the topmenu location .
* Extra entries will be added just before Logout .
*
* @ param string $id unique element id
* @ param string $url Address for the entry to link to
* @ param string $title Text displayed for the entry
* @ param string $target Optional , so the entry can open in a new page or popup
* @ access public
* @ return void
*/
public static function add_topmenu_item ( $id , $url , $title , $target = '' )
{
$entry [ 'name' ] = $id ;
$entry [ 'url' ] = $url ;
$entry [ 'title' ] = $title ;
$entry [ 'target' ] = $target ;
self :: $top_menu_extra [ $id ] = $entry ;
}
2010-09-07 21:08:13 +02:00
/**
* called by hooks to add an icon in the topmenu info location
*
* @ param string $id unique element id
* @ param string $icon_src src of the icon image . Make sure this nog height then 18 pixels
* @ param string $iconlink where the icon links to
* @ param booleon $blink set true to make the icon blink
* @ param mixed $tooltip string containing the tooltip html , or null of no tooltip
* @ access public
* @ return void
*/
abstract function topmenu_info_icon ( $id , $icon_src , $iconlink , $blink = false , $tooltip = null );
2010-06-07 19:31:43 +02:00
/**
* Call and return content of 'after_navbar' hook
2010-11-09 15:44:18 +01:00
*
2010-06-07 19:31:43 +02:00
* @ return string
*/
protected function _get_after_navbar ()
{
ob_start ();
$GLOBALS [ 'egw' ] -> hooks -> process ( 'after_navbar' , null , true );
$content = ob_get_contents ();
ob_end_clean ();
return $content ;
}
2010-11-09 15:44:18 +01:00
2010-06-08 00:06:35 +02:00
/**
* Return javascript ( eg . for onClick ) to open manual with given url
2010-11-09 15:44:18 +01:00
*
2010-06-08 00:06:35 +02:00
* @ param string $url
*/
abstract function open_manual_js ( $url );
2010-11-09 15:44:18 +01:00
2010-06-09 17:30:53 +02:00
/**
* Methods to add javascript to framework
*/
/**
* Body tags for onLoad , onUnload and onResize
2010-11-09 15:44:18 +01:00
*
2014-10-13 14:49:14 +02:00
* @ deprecated since 14.1 use app . js et2_ready method instead to execute code or bind a handler ( CSP will stop onXXX attributes ! )
2010-06-09 17:30:53 +02:00
* @ var array
*/
protected static $body_tags = array ();
2010-11-09 15:44:18 +01:00
2010-06-09 17:30:53 +02:00
/**
2010-06-15 18:08:10 +02:00
* Sets an onLoad action for a page
*
2014-10-09 22:32:59 +02:00
* @ param string $code = '' javascript to be used
* @ param boolean $replace = false false : append to existing , true : replace existing tag
2014-10-13 14:49:14 +02:00
* @ deprecated since 14.1 use app . js et2_ready method instead to execute code or bind a handler ( CSP will stop onXXX attributes ! )
2010-06-15 18:08:10 +02:00
* @ return string content of onXXX tag after adding code
*/
static function set_onload ( $code = '' , $replace = false )
2010-06-09 17:30:53 +02:00
{
2011-12-20 16:57:03 +01:00
if ( $replace || empty ( self :: $body_tags [ 'onLoad' ]))
2010-06-15 18:08:10 +02:00
{
self :: $body_tags [ 'onLoad' ] = $code ;
}
else
{
self :: $body_tags [ 'onLoad' ] .= $code ;
}
return self :: $body_tags [ 'onLoad' ];
2010-06-09 17:30:53 +02:00
}
/**
2010-06-15 18:08:10 +02:00
* Sets an onUnload action for a page
*
2014-10-09 22:32:59 +02:00
* @ param string $code = '' javascript to be used
* @ param boolean $replace = false false : append to existing , true : replace existing tag
2014-10-13 14:49:14 +02:00
* @ deprecated since 14.1 use app . js et2_ready method instead to execute code or bind a handler ( CSP will stop onXXX attributes ! )
2010-06-15 18:08:10 +02:00
* @ return string content of onXXX tag after adding code
*/
static function set_onunload ( $code = '' , $replace = false )
2010-06-09 17:30:53 +02:00
{
2011-12-20 16:57:03 +01:00
if ( $replace || empty ( self :: $body_tags [ 'onUnload' ]))
2010-06-15 18:08:10 +02:00
{
self :: $body_tags [ 'onUnload' ] = $code ;
}
else
{
self :: $body_tags [ 'onUnload' ] .= $code ;
}
return self :: $body_tags [ 'onUnload' ];
2010-06-09 17:30:53 +02:00
}
2012-03-21 09:25:17 +01:00
/**
* Sets an onBeforeUnload action for a page
*
2014-10-09 22:32:59 +02:00
* @ param string $code = '' javascript to be used
* @ param boolean $replace = false false : append to existing , true : replace existing tag
2014-10-13 14:49:14 +02:00
* @ deprecated since 14.1 use app . js et2_ready method instead to execute code or bind a handler ( CSP will stop onXXX attributes ! )
2012-03-21 09:25:17 +01:00
* @ return string content of onXXX tag after adding code
*/
static function set_onbeforeunload ( $code = '' , $replace = false )
{
if ( $replace || empty ( self :: $body_tags [ 'onBeforeUnload' ]))
{
self :: $body_tags [ 'onBeforeUnload' ] = $code ;
}
else
{
self :: $body_tags [ 'onBeforeUnload' ] .= $code ;
}
return self :: $body_tags [ 'onBeforeUnload' ];
}
2010-06-09 17:30:53 +02:00
/**
2014-10-13 14:49:14 +02:00
* Sets an onResize action for a page
*
* @ param string $code = '' javascript to be used
* @ param boolean $replace = false false : append to existing , true : replace existing tag
* @ deprecated since 14.1 use app . js et2_ready method instead to execute code or bind a handler ( CSP will stop onXXX attributes ! )
* @ return string content of onXXX tag after adding code
*/
2010-06-15 18:08:10 +02:00
static function set_onresize ( $code = '' , $replace = false )
2010-06-09 17:30:53 +02:00
{
2011-12-20 16:57:03 +01:00
if ( $replace || empty ( self :: $body_tags [ 'onResize' ]))
2010-06-15 18:08:10 +02:00
{
self :: $body_tags [ 'onResize' ] = $code ;
}
else
{
self :: $body_tags [ 'onResize' ] .= $code ;
}
return self :: $body_tags [ 'onResize' ];
2010-06-09 17:30:53 +02:00
}
2010-06-15 18:08:10 +02:00
2010-06-09 17:30:53 +02:00
/**
2010-06-15 18:08:10 +02:00
* Adds on ( Un ) Load = attributes to the body tag of a page
*
2014-10-13 14:49:14 +02:00
* @ deprecated since 14.1 use app . js et2_ready method instead to execute code or bind a handler ( CSP will stop onXXX attributes ! )
2010-06-15 18:08:10 +02:00
* @ returns string the attributes to be used
*/
2011-01-06 21:47:21 +01:00
static public function _get_body_attribs ()
2010-06-09 17:30:53 +02:00
{
$js = '' ;
foreach ( self :: $body_tags as $what => $data )
{
if ( ! empty ( $data ))
{
2013-04-02 00:19:10 +02:00
if ( $what == 'onLoad' )
{
2013-07-17 14:47:21 +02:00
$js .= 'onLoad="egw_LAB.wait(function() {' . htmlspecialchars ( $data ) . '})"' ;
2013-04-02 00:19:10 +02:00
continue ;
}
2010-06-10 16:31:30 +02:00
$js .= ' ' . $what . '="' . htmlspecialchars ( $data ) . '"' ;
2010-06-09 17:30:53 +02:00
}
}
return $js ;
}
2010-11-09 15:44:18 +01:00
2010-06-09 17:30:53 +02:00
/**
2011-08-03 16:03:31 +02:00
* The include manager manages including js files and their dependencies
2010-06-09 17:30:53 +02:00
*/
2011-08-03 16:03:31 +02:00
protected static $js_include_mgr ;
2010-06-09 17:30:53 +02:00
/**
* Checks to make sure a valid package and file name is provided
*
2010-06-24 01:01:57 +02:00
* Example call syntax :
2010-11-09 15:44:18 +01:00
* a ) egw_framework :: validate_file ( 'jscalendar' , 'calendar' )
2010-06-24 01:01:57 +02:00
* --> / phpgwapi / js / jscalendar / calendar . js
* b ) egw_framework :: validate_file ( '/phpgwapi/inc/calendar-setup.js' , array ( 'lang' => 'de' ))
* --> / phpgwapi / inc / calendar - setup . js ? lang = de
2010-11-09 15:44:18 +01:00
*
2010-06-24 01:01:57 +02:00
* @ param string $package package or complete path ( relative to EGW_SERVER_ROOT ) to be included
2014-10-09 22:32:59 +02:00
* @ param string | array $file = null file to be included - no " .js " on the end or array with get params
* @ param string $app = 'phpgwapi' application directory to search - default = phpgwapi
* @ param boolean $append = true should the file be added
2010-06-09 17:30:53 +02:00
*
* @ discuss The browser specific option loads the file which is in the correct
* browser folder . Supported folder are those supported by class . browser . inc . php
*
* @ returns bool was the file found ?
*/
2010-06-24 01:01:57 +02:00
static function validate_file ( $package , $file = null , $app = 'phpgwapi' )
2010-06-09 17:30:53 +02:00
{
2011-08-03 16:03:31 +02:00
self :: $js_include_mgr -> include_js_file ( $package , $file , $app );
2010-06-09 17:30:53 +02:00
}
2010-11-09 15:44:18 +01:00
2010-06-15 18:08:10 +02:00
/**
2013-02-13 17:28:39 +01:00
* Set or return all javascript files set via validate_file , optionally clear all files
2010-11-09 15:44:18 +01:00
*
2014-10-09 22:32:59 +02:00
* @ param array $files = null array with pathes relative to EGW_SERVER_ROOT , eg . / phpgwapi / js / jquery / jquery . js
* @ param boolean $clear_files = false true clear files after returning them
2010-06-15 18:08:10 +02:00
* @ return array with pathes relative to EGW_SERVER_ROOT
*/
2013-02-13 17:28:39 +01:00
static function js_files ( array $files = null , $clear_files = false )
2010-06-15 18:08:10 +02:00
{
if ( isset ( $files ) && is_array ( $files ))
{
2011-08-03 16:03:31 +02:00
self :: $js_include_mgr -> include_files ( $files );
2010-06-15 18:08:10 +02:00
}
2013-02-13 17:28:39 +01:00
return self :: $js_include_mgr -> get_included_files ( $clear_files );
2010-06-15 18:08:10 +02:00
}
2010-11-09 15:44:18 +01:00
2010-06-09 17:30:53 +02:00
/**
2013-02-13 17:28:39 +01:00
* Used for generating the list of external js files to be included in the head of a page
*
* NOTE : This method should only be called by the template class .
* The validation is done when the file is added so we don ' t have to worry now
*
2014-10-09 22:32:59 +02:00
* @ param boolean $return_pathes = false false : return html script tags , true : return array of file pathes relative to webserver_url
* @ param boolean $clear_files = false true clear files after returning them
2013-02-13 17:28:39 +01:00
* @ return string | array see $return_pathes parameter
*/
static public function get_script_links ( $return_pathes = false , $clear_files = false )
2010-06-09 17:30:53 +02:00
{
2014-01-11 19:49:51 +01:00
$to_include = self :: bundle_js_includes ( self :: $js_include_mgr -> get_included_files ( $clear_files ));
if ( $return_pathes )
{
return $to_include ;
}
$start = '<script type="text/javascript" src="' . $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ];
$end = '">' . " </script> \n " ;
return " \n " . $start . implode ( $end . $start , $to_include ) . $end ;
}
2016-03-01 21:45:31 +01:00
/**
* Url of minified version of bundle
*
* @ var array
*/
static $bundle2minurl = array (
'api' => '/phpgwapi/js/jsapi.min.js' ,
'et2' => '/etemplate/js/etemplate2.min.js' ,
'et21' => '/etemplate/js/etemplate2.min.js' ,
'pixelegg' => '/pixelegg/js/fw_pixelegg.min.js' ,
'jdots' => '/jdots/js/fw_jdots.min.js' ,
'mobile' => '/jdots/js/fw_mobile.min.js' ,
);
2014-01-11 19:49:51 +01:00
/**
* Devide js - includes in bundles of javascript files to include eg . api or etemplate2 , if minifying is enabled
*
* @ param array $js_includes files to include with egw relative url
* @ return array egw relative urls to include incl . bundels / minify urls , if enabled
*/
public static function bundle_js_includes ( array $js_includes )
{
$file2bundle = array ();
2014-01-14 18:59:33 +01:00
if ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'debug_minify' ] !== 'True' )
2014-01-11 19:49:51 +01:00
{
2014-01-14 18:59:33 +01:00
// get used bundles and cache them on tree-level for 2h
2014-02-17 18:15:37 +01:00
//$bundles = self::get_bundles(); egw_cache::setTree(__CLASS__, 'bundles', $bundles, 7200);
2014-01-14 18:59:33 +01:00
$bundles = egw_cache :: getTree ( __CLASS__ , 'bundles' , array ( __CLASS__ , 'get_bundles' ), array (), 7200 );
$bundles_ts = $bundles [ '.ts' ];
unset ( $bundles [ '.ts' ]);
foreach ( $bundles as $name => $files )
{
2016-03-01 21:45:31 +01:00
// ignore bundles of not used templates, as they can contain identical files
if ( in_array ( $name , array ( 'api' , 'et2' , 'et21' )) ||
$name == ( html :: $ua_mobile ? 'mobile' : $GLOBALS [ 'egw_info' ][ 'server' ][ 'template_set' ]) ||
isset ( $GLOBALS [ 'egw_info' ][ 'apps' ][ $name ]))
{
$file2bundle += array_combine ( $files , array_fill ( 0 , count ( $files ), $name ));
}
2014-01-14 18:59:33 +01:00
}
2014-01-11 19:49:51 +01:00
}
$to_include = $included_bundles = array ();
2014-10-09 22:32:59 +02:00
$query = null ;
2014-01-11 19:49:51 +01:00
foreach ( $js_includes as $file )
{
if ( ! isset ( $to_include [ $file ]))
{
if (( $bundle = $file2bundle [ $file ]))
{
2016-03-01 21:45:31 +01:00
//error_log(__METHOD__."() requiring bundle $bundle for $file");
2014-01-11 19:49:51 +01:00
if ( ! in_array ( $bundle , $included_bundles ))
{
$included_bundles [] = $bundle ;
2016-03-01 21:45:31 +01:00
$minurl = self :: $bundle2minurl [ $bundle ];
if ( ! isset ( $minurl ) && isset ( $GLOBALS [ 'egw_info' ][ 'apps' ][ $bundle ]))
2014-01-11 19:49:51 +01:00
{
2016-03-01 21:45:31 +01:00
$minurl = '/' . $bundle . '/js/app.min.js' ;
}
2016-03-02 15:34:01 +01:00
$max_modified = 0 ;
$to_include = array_merge ( $to_include , self :: bundle_urls ( $bundles [ $bundle ], $max_modified , $minurl ));
// check if bundle-config is more recent then
if ( $max_modified > $bundles_ts )
2016-03-01 21:45:31 +01:00
{
2016-03-02 15:34:01 +01:00
// force new bundle config by deleting cached one and call ourself again
egw_cache :: unsetTree ( __CLASS__ , 'bundles' );
return self :: bundle_js_includes ( $js_includes );
2014-01-11 19:49:51 +01:00
}
}
}
else
{
2014-10-09 22:32:59 +02:00
unset ( $query );
2014-01-11 19:49:51 +01:00
list ( $path , $query ) = explode ( '?' , $file , 2 );
$mod = filemtime ( EGW_SERVER_ROOT . $path );
2016-03-01 21:45:31 +01:00
// check if we have a more recent minified version of the file and use it
if ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'debug_minify' ] !== 'True' &&
substr ( $path , - 3 ) == '.js' && file_exists ( EGW_SERVER_ROOT . ( $min_path = substr ( $path , 0 , - 3 ) . '.min.js' )) &&
(( $min_mod = filemtime ( EGW_SERVER_ROOT . $min_path )) >= $mod ))
{
$path = $min_path ;
$mod = $min_mod ;
}
2014-01-11 19:49:51 +01:00
$to_include [ $file ] = $path . '?' . $mod . ( $query ? '&' . $query : '' );
}
}
}
/* _debug_array ( $js_includes );
_debug_array ( array_values ( $to_include ));
die ( 'STOP' ); */
return array_values ( $to_include );
}
/**
* Generate bundle url ( s ) for given js files
*
* @ param array $js_includes
2014-10-09 22:32:59 +02:00
* @ param int & $max_modified = null on return maximum modification time of bundle
2016-03-02 15:34:01 +01:00
* @ param string $minurl = null url of minified bundle , to be used , if existing and recent
2014-01-11 19:49:51 +01:00
* @ return array js - files ( can be more then one , if one of given files can not be bundeled )
*/
2016-03-02 15:34:01 +01:00
protected static function bundle_urls ( array $js_includes , & $max_modified = null , $minurl = null )
2014-01-11 19:49:51 +01:00
{
2014-01-10 17:08:13 +01:00
$debug_minify = $GLOBALS [ 'egw_info' ][ 'server' ][ 'debug_minify' ] === 'True' ;
2016-03-02 15:34:01 +01:00
// ignore not existing minurl
$to_include_first = $to_include = $to_minify = array ();
2012-10-15 19:22:44 +02:00
$max_modified = 0 ;
2014-10-09 22:32:59 +02:00
$query = null ;
2014-01-11 19:49:51 +01:00
foreach ( $js_includes as $path )
2010-06-09 17:30:53 +02:00
{
2014-01-10 17:58:50 +01:00
if ( $path == '/phpgwapi/js/jsapi/egw.js' ) continue ; // loaded via own tag, and we must not load it twice!
2014-03-04 10:10:58 +01:00
unset ( $query );
2011-08-03 16:03:31 +02:00
list ( $path , $query ) = explode ( '?' , $path , 2 );
2014-01-11 19:49:51 +01:00
$mod = filemtime ( EGW_SERVER_ROOT . $path );
2012-10-15 19:22:44 +02:00
2016-03-02 15:34:01 +01:00
// ckeditor must be included before bundled files, as they depend on it!
if ( strpos ( $path , '/ckeditor/ckeditor.js' ) !== false )
{
$to_include_first [] = $path . '?' . $mod ;
}
2012-10-15 19:22:44 +02:00
// for now minify does NOT support query parameters, nor php files generating javascript
2016-03-02 15:34:01 +01:00
elseif ( $debug_minify || $query || substr ( $path , - 3 ) != '.js' ||
2014-01-10 17:08:13 +01:00
substr ( $path , - 7 ) == '/app.js' ) // do NOT include app.js, as it changes from app to app
2012-10-15 19:22:44 +02:00
{
$path .= '?' . $mod . ( $query ? '&' . $query : '' );
2013-02-13 17:28:39 +01:00
$to_include [] = $path ;
2012-10-15 19:22:44 +02:00
}
else
{
2014-01-11 19:49:51 +01:00
if ( $mod > $max_modified ) $max_modified = $mod ;
2013-02-13 17:28:39 +01:00
$to_minify [] = substr ( $path , 1 );
2012-10-15 19:22:44 +02:00
}
}
2013-02-13 17:28:39 +01:00
if ( ! $debug_minify && $to_minify )
2012-10-15 19:22:44 +02:00
{
2016-03-02 15:34:01 +01:00
if ( ! empty ( $minurl ) && file_exists ( EGW_SERVER_ROOT . $minurl ) &&
( $mod = filemtime ( EGW_SERVER_ROOT . $minurl )) >= $max_modified )
{
$path = $minurl . '?' . $mod ;
}
else
{
$base_path = $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ];
if ( $base_path [ 0 ] != '/' ) $base_path = parse_url ( $base_path , PHP_URL_PATH );
$path = '/phpgwapi/inc/min/?' . ( $base_path && $base_path != '/' ? 'b=' . substr ( $base_path , 1 ) . '&' : '' ) .
'f=' . implode ( ',' , $to_minify ) .
( $GLOBALS [ 'egw_info' ][ 'server' ][ 'debug_minify' ] === 'debug' ? '&debug' : '' ) .
'&' . $max_modified ;
}
2012-10-26 11:24:39 +02:00
// need to include minified javascript before not minified stuff like jscalendar-setup, as it might depend on it
2013-02-13 17:28:39 +01:00
array_unshift ( $to_include , $path );
}
2016-03-02 15:34:01 +01:00
if ( $to_include_first ) $to_include = array_merge ( $to_include_first , $to_include );
//error_log(__METHOD__."("./*array2string($js_includes).*/", $max_modified, $minurl) returning ".array2string($to_include));
2014-01-11 19:49:51 +01:00
return $to_include ;
}
2014-02-17 18:15:37 +01:00
/**
* Maximum number of files in a bundle
*
* We split bundles , if they contain more then these number of files ,
* because IE silently stops caching them , if Content - Length get ' s too big .
*
* IE11 cached 142 kb compressed api bundle , but not 190 kb et2 bundle .
* Splitting et2 bundle in max 50 files chunks , got IE11 to cache both bundles .
*/
const MAX_BUNDLE_FILES = 50 ;
2014-01-11 19:49:51 +01:00
/**
* Return typical bundes we use :
* - api stuff phpgwapi / js / jsapi /* and it ' s dependencies incl . jquery
* - etemplate2 stuff not including api bundle , but jquery - ui
*
* @ return array bundle - url => array of contained files
*/
public static function get_bundles ()
{
$inc_mgr = new egw_include_mgr ();
$bundles = array ();
2016-03-01 21:45:31 +01:00
$max_mod = array ();
2014-11-07 11:33:46 +01:00
2014-01-11 19:49:51 +01:00
// generate api bundle
$inc_mgr -> include_js_file ( '/phpgwapi/js/jquery/jquery.js' );
2014-03-04 10:10:58 +01:00
$inc_mgr -> include_js_file ( '/phpgwapi/js/jquery/jquery-ui.js' );
2014-01-11 19:49:51 +01:00
$inc_mgr -> include_js_file ( '/phpgwapi/js/jsapi/jsapi.js' );
$inc_mgr -> include_js_file ( '/phpgwapi/js/egw_json.js' );
$inc_mgr -> include_js_file ( '/phpgwapi/js/jsapi/egw.js' );
2014-06-03 10:17:43 +02:00
// dhtmlxTree (dhtmlxMenu get loaded via dependency in egw_menu_dhtmlx.js)
$inc_mgr -> include_js_file ( '/phpgwapi/js/dhtmlxtree/codebase/dhtmlxcommon.js' );
$inc_mgr -> include_js_file ( '/phpgwapi/js/dhtmlxtree/sources/dhtmlxtree.js' );
$inc_mgr -> include_js_file ( '/phpgwapi/js/dhtmlxtree/sources/ext/dhtmlxtree_json.js' );
2014-03-04 10:10:58 +01:00
// actions
$inc_mgr -> include_js_file ( '/phpgwapi/js/egw_action/egw_action.js' );
$inc_mgr -> include_js_file ( '/phpgwapi/js/egw_action/egw_keymanager.js' );
$inc_mgr -> include_js_file ( '/phpgwapi/js/egw_action/egw_action_popup.js' );
$inc_mgr -> include_js_file ( '/phpgwapi/js/egw_action/egw_action_dragdrop.js' );
$inc_mgr -> include_js_file ( '/phpgwapi/js/egw_action/egw_dragdrop_dhtmlx_tree.js' );
$inc_mgr -> include_js_file ( '/phpgwapi/js/egw_action/egw_menu.js' );
$inc_mgr -> include_js_file ( '/phpgwapi/js/egw_action/egw_menu_dhtmlx.js' );
2015-06-08 16:33:57 +02:00
// include choosen in api, as old eTemplate uses it and fail if it pulls in half of et2
$inc_mgr -> include_js_file ( '/phpgwapi/js/jquery/chosen/chosen.jquery.js' );
// include CKEditor in api, as old eTemplate uses it too
$inc_mgr -> include_js_file ( '/phpgwapi/js/ckeditor/ckeditor.js' );
$inc_mgr -> include_js_file ( '/phpgwapi/js/ckeditor/config.js' );
2014-01-11 19:49:51 +01:00
$bundles [ 'api' ] = $inc_mgr -> get_included_files ();
2016-03-01 21:45:31 +01:00
self :: bundle_urls ( $bundles [ 'api' ], $max_mod [ 'api' ]);
2014-01-11 19:49:51 +01:00
// generate et2 bundle (excluding files in api bundle)
//$inc_mgr->include_js_file('/etemplate/js/lib/jsdifflib/difflib.js'); // it does not work with "use strict" therefore included in front
$inc_mgr -> include_js_file ( '/etemplate/js/etemplate2.js' );
$bundles [ 'et2' ] = array_diff ( $inc_mgr -> get_included_files (), $bundles [ 'api' ]);
2016-03-01 21:45:31 +01:00
self :: bundle_urls ( $bundles [ 'et2' ], $max_mod [ 'et2' ]);
$stock_files = call_user_func_array ( 'array_merge' , $bundles );
2014-01-11 19:49:51 +01:00
2016-03-01 21:45:31 +01:00
// generate template and app bundles, if installed
foreach ( array (
'jdots' => '/jdots/js/fw_jdots.js' ,
'mobile' => '/jdots/js/fw_mobile.js' ,
'pixelegg' => '/pixelegg/js/fw_pixelegg.js' ,
'calendar' => '/calendar/js/app.js' ,
'mail' => '/mail/js/app.js' ,
) as $bundle => $file )
2013-02-13 17:28:39 +01:00
{
2016-03-01 21:45:31 +01:00
if ( @ file_exists ( EGW_SERVER_ROOT . $file ))
{
$inc_mgr = new egw_include_mgr ( $stock_files ); // reset loaded files to stock files
$inc_mgr -> include_js_file ( $file );
$bundles [ $bundle ] = array_diff ( $inc_mgr -> get_included_files (), $stock_files );
self :: bundle_urls ( $bundles [ $bundle ], $max_mod [ $bundle ]);
}
}
2013-02-15 16:30:35 +01:00
2014-02-17 18:15:37 +01:00
// automatic split bundles with more then MAX_BUNDLE_FILES (=50) files
foreach ( $bundles as $name => $files )
{
$n = '' ;
while ( count ( $files ) > self :: MAX_BUNDLE_FILES * ( int ) $n )
{
$files80 = array_slice ( $files , self :: MAX_BUNDLE_FILES * ( int ) $n , self :: MAX_BUNDLE_FILES , true );
$bundles [ $name . $n ++ ] = $files80 ;
}
}
2014-11-07 11:33:46 +01:00
// store max modification time of all files in all bundles
2016-03-01 21:45:31 +01:00
$bundles [ '.ts' ] = max ( $max_mod );
2014-01-11 19:49:51 +01:00
2014-02-17 18:15:37 +01:00
//error_log(__METHOD__."() returning ".array2string($bundles));
2014-01-11 19:49:51 +01:00
return $bundles ;
2010-06-09 17:30:53 +02:00
}
2010-11-09 15:44:18 +01:00
2010-06-18 13:19:24 +02:00
/**
* Content from includeCSS calls
2010-11-09 15:44:18 +01:00
*
2010-06-18 13:19:24 +02:00
* @ var array
*/
protected static $css_include_files = array ();
2014-03-03 15:54:03 +01:00
/**
*
* @ var boolean
*/
protected static $load_default_css = true ;
2010-06-18 13:19:24 +02:00
/**
* Include a css file , either speicified by it ' s path ( relative to EGW_SERVER_ROOT ) or appname and css file name
2010-11-09 15:44:18 +01:00
*
2010-06-24 01:01:57 +02:00
* @ param string $app path ( relative to EGW_SERVER_ROOT ) or appname ( if ! is_null ( $name ))
2014-10-09 22:32:59 +02:00
* @ param string $name = null name of css file in $app / templates / { default | $this -> template } / $name . css
* @ param boolean $append = true true append file , false prepend ( add as first ) file used eg . for template itself
* @ param boolean $no_default_css = false true do NOT load any default css , only what app explicitly includes
2010-06-18 13:19:24 +02:00
* @ return boolean false : css file not found , true : file found
*/
2014-03-03 15:54:03 +01:00
public static function includeCSS ( $app , $name = null , $append = true , $no_default_css = false )
2010-06-18 13:19:24 +02:00
{
2014-03-03 15:54:03 +01:00
if ( $no_default_css )
{
self :: $load_default_css = false ;
self :: $css_include_files = array ();
}
2010-06-18 13:19:24 +02:00
if ( ! is_null ( $name ))
{
2016-02-17 17:50:54 +01:00
foreach ( $GLOBALS [ 'egw' ] -> framework -> template_dirs as $dir )
2010-06-18 13:19:24 +02:00
{
2016-02-17 17:50:54 +01:00
if ( file_exists ( EGW_SERVER_ROOT . ( $path = '/' . $app . '/templates/' . $dir . '/' . $name . '.css' )))
{
break ;
}
2010-06-18 13:19:24 +02:00
}
}
2010-06-24 01:01:57 +02:00
else
{
$path = $app ;
}
2015-10-15 19:28:56 +02:00
if ( ! file_exists ( EGW_SERVER_ROOT . $path ) && ! file_exists ( EGW_SERVER_ROOT . parse_url ( $path , PHP_URL_PATH )))
2010-06-18 13:19:24 +02:00
{
2010-07-30 15:38:49 +02:00
//error_log(__METHOD__."($app,$name) $path NOT found!");
2010-06-18 13:19:24 +02:00
return false ;
}
if ( ! in_array ( $path , self :: $css_include_files ))
{
2012-10-14 21:38:32 +02:00
if ( $append )
{
self :: $css_include_files [] = $path ;
}
else
{
self :: $css_include_files = array_merge ( array ( $path ), self :: $css_include_files );
}
2010-06-18 13:19:24 +02:00
}
return true ;
}
2010-11-09 15:44:18 +01:00
2010-06-24 01:01:57 +02:00
/**
* Add registered CSS and javascript to ajax response
*/
public static function include_css_js_response ()
{
$response = egw_json_response :: get ();
$app = $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ];
2010-11-09 15:44:18 +01:00
2010-06-24 01:01:57 +02:00
// try to add app specific css file
2015-10-09 13:46:45 +02:00
self :: includeCSS ( $app , 'app-' . $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'theme' ]) ||
self :: includeCSS ( $app , 'app' );
2010-06-24 01:01:57 +02:00
// add all css files from egw_framework::includeCSS()
2014-10-09 22:32:59 +02:00
$query = null ;
2010-06-24 01:01:57 +02:00
foreach ( self :: $css_include_files as $path )
{
2014-10-09 22:32:59 +02:00
unset ( $query );
2010-06-24 12:51:02 +02:00
list ( $path , $query ) = explode ( '?' , $path , 2 );
2015-10-20 00:26:09 +02:00
$path .= '?' . ( $query ? $query : filemtime ( EGW_SERVER_ROOT . $path ));
2010-06-24 01:01:57 +02:00
$response -> includeCSS ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ] . $path );
}
2010-11-09 15:44:18 +01:00
2010-06-24 01:01:57 +02:00
// try to add app specific js file
self :: validate_file ( '.' , 'app' , $app );
// add all js files from egw_framework::validate_file()
2014-10-09 22:32:59 +02:00
$files = self :: bundle_js_includes ( self :: $js_include_mgr -> get_included_files ());
2011-08-03 16:03:31 +02:00
foreach ( $files as $path )
2010-06-24 01:01:57 +02:00
{
$response -> includeScript ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ] . $path );
}
}
2011-08-26 11:34:18 +02:00
/**
* Set a preference via ajax
*
* @ param string $app
* @ param string $name
* @ param string $value
*/
public static function ajax_set_preference ( $app , $name , $value )
{
2014-02-13 17:34:09 +01:00
$GLOBALS [ 'egw' ] -> preferences -> read_repository ();
2015-01-08 14:13:02 +01:00
if (( string ) $value === '' )
{
$GLOBALS [ 'egw' ] -> preferences -> delete ( $app , $name );
}
else
{
$GLOBALS [ 'egw' ] -> preferences -> add ( $app , $name , $value );
}
2014-02-13 17:34:09 +01:00
$GLOBALS [ 'egw' ] -> preferences -> save_repository ( True );
2011-08-26 11:34:18 +02:00
}
/**
* Get preferences of a certain application via ajax
*
* @ param string $app
*/
public static function ajax_get_preference ( $app )
{
if ( preg_match ( '/^[a-z0-9_]+$/i' , $app ))
{
2014-01-18 18:43:15 +01:00
// send etag header, if we are directly called (not via jsonq!)
if ( strpos ( $_GET [ 'menuaction' ], __FUNCTION__ ) !== false )
{
2014-02-11 13:16:16 +01:00
$etag = '"' . $app . '-' . md5 ( json_encode ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ $app ])) . '"' ;
2014-01-18 18:43:15 +01:00
if ( isset ( $_SERVER [ 'HTTP_IF_NONE_MATCH' ]) && $_SERVER [ 'HTTP_IF_NONE_MATCH' ] == $etag )
{
header ( " HTTP/1.1 304 Not Modified " );
common :: egw_exit ();
}
header ( 'ETag: ' . $etag );
}
2014-02-11 13:16:16 +01:00
$response = egw_json_response :: get ();
$response -> call ( 'egw.set_preferences' , ( array ) $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ $app ], $app );
2011-08-26 11:34:18 +02:00
}
}
2013-12-06 00:22:54 +01:00
2014-02-14 14:48:45 +01:00
/**
2013-12-06 00:22:54 +01:00
* Include favorites when generating the page server - side
*
2014-02-12 22:51:25 +01:00
* @ param string $app application , needed to find preferences
2014-10-09 22:32:59 +02:00
* @ param string $default = null preference name for default favorite , default " nextmatch- $app .index.rows-favorite "
2014-02-14 14:48:45 +01:00
* @ deprecated use egw_favorites :: favorite_list
2014-02-12 22:51:25 +01:00
* @ return array with a single sidebox menu item ( array ) containing html for favorites
2013-12-06 00:22:54 +01:00
*/
2014-02-12 22:51:25 +01:00
public static function favorite_list ( $app , $default = null )
2013-12-06 00:22:54 +01:00
{
2014-02-14 14:48:45 +01:00
return egw_favorites :: list_favorites ( $app , $default );
2013-12-06 00:22:54 +01:00
}
/**
* Create or delete a favorite for multiple users
*
2014-02-14 14:48:45 +01:00
* Need to be in egw_framework to be called with . template postfix from json . php !
2013-12-06 00:22:54 +01:00
*
2014-02-14 14:48:45 +01:00
* @ param string $app Current application , needed to save preference
* @ param string $name Name of the favorite
* @ param string $action " add " or " delete "
* @ param boolean | int | string $group ID of the group to create the favorite for , or 'all' for all users
2014-10-09 22:32:59 +02:00
* @ param array $filters = array () key => value pairs for the filter
2013-12-06 00:22:54 +01:00
* @ return boolean Success
*/
public static function ajax_set_favorite ( $app , $name , $action , $group , $filters = array ())
{
2014-02-14 14:48:45 +01:00
return egw_favorites :: set_favorite ( $app , $name , $action , $group , $filters );
2013-12-06 00:22:54 +01:00
}
2014-04-23 21:00:59 +02:00
/**
* Get a cachable list of users for the client
*
* The account source takes care of access and filtering according to preference
*/
public static function ajax_user_list ()
{
$list = array ( 'accounts' => array (), 'groups' => array (), 'owngroups' => array ());
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'account_selection' ] == 'primary_group' )
{
$list [ 'accounts' ][ 'filter' ][ 'group' ] = $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_primary_group' ];
}
foreach ( $list as $type => & $accounts )
{
$options = array ( 'account_type' => $type ) + $accounts ;
2014-05-06 22:33:40 +02:00
$key_pair = accounts :: link_query ( '' , $options );
$accounts = array ();
foreach ( $key_pair as $account_id => $name )
{
$accounts [] = array ( 'value' => $account_id , 'label' => $name );
}
2014-04-23 21:00:59 +02:00
}
2014-05-26 15:29:35 +02:00
2014-04-23 21:00:59 +02:00
egw_json_response :: get () -> data ( $list );
return $list ;
}
2015-05-28 16:40:33 +02:00
/**
* Get certain account - data of given account - id ( s )
*
* @ param string | array $_account_ids
* @ param string $_field = 'account_email'
* @ param boolean $_resolve_groups = false true : return attribute for all members , false return attribute for group itself
* @ return array account_id => data pairs
*/
public static function ajax_account_data ( $_account_ids , $_field , $_resolve_groups = false )
{
$list = array ();
foreach (( array ) $_account_ids as $account_id )
{
foreach ( $account_id < 0 && $_resolve_groups ?
$GLOBALS [ 'egw' ] -> accounts -> members ( $account_id , true ) : array ( $account_id ) as $account_id )
{
2015-11-16 18:32:37 +01:00
// Make sure name is formatted according to preference
if ( $_field == 'account_fullname' )
{
$list [ $account_id ] = common :: display_fullname (
2015-11-17 19:25:58 +01:00
$GLOBALS [ 'egw' ] -> accounts -> id2name ( $account_id , 'account_lid' ),
2015-11-16 18:32:37 +01:00
$GLOBALS [ 'egw' ] -> accounts -> id2name ( $account_id , 'account_firstname' ),
$GLOBALS [ 'egw' ] -> accounts -> id2name ( $account_id , 'account_lastname' ),
$account_id
);
}
else
{
$list [ $account_id ] = $GLOBALS [ 'egw' ] -> accounts -> id2name ( $account_id , $_field );
}
2015-05-28 16:40:33 +02:00
}
}
egw_json_response :: get () -> data ( $list );
return $list ;
}
2006-12-11 00:44:18 +01:00
}
2011-08-03 16:03:31 +02:00
// Init all static variables
egw_framework :: init_static ();
2006-12-11 00:44:18 +01:00
/**
* Public functions to be compatible with the exiting eGW framework
*/
if ( ! function_exists ( 'parse_navbar' ))
{
/**
* echo ' s out the navbar
*
2010-10-18 12:46:47 +02:00
* @ deprecated use $GLOBALS [ 'egw' ] -> framework -> navbar () or $GLOBALS [ 'egw' ] -> framework :: render ()
2006-12-11 00:44:18 +01:00
*/
function parse_navbar ()
{
echo $GLOBALS [ 'egw' ] -> framework -> navbar ();
}
}
if ( ! function_exists ( 'display_sidebox' ))
{
/**
* echo ' s out a sidebox menu
*
2013-05-10 18:39:42 +02:00
* @ deprecated use $GLOBALS [ 'egw' ] -> framework -> sidebox ()
2006-12-11 00:44:18 +01:00
*/
2014-10-09 22:32:59 +02:00
function display_sidebox ( $appname , $menu_title , $_file )
2006-12-11 00:44:18 +01:00
{
2014-10-09 22:32:59 +02:00
$file = str_replace ( 'preferences.uisettings.index' , 'preferences.preferences_settings.index' , $_file );
2006-12-11 00:44:18 +01:00
$GLOBALS [ 'egw' ] -> framework -> sidebox ( $appname , $menu_title , $file );
}
2007-01-09 23:42:01 +01:00
}