2003-09-14 12:19:42 +02:00
< ? php
2006-08-30 16:47:56 +02:00
/**
2008-03-09 15:35:48 +01:00
* eGroupWare API : generates html with methods representing html - tags or higher widgets
2006-08-30 16:47:56 +02:00
*
* @ link http :// www . egroupware . org
* @ author Ralf Becker < RalfBecker - AT - outdoor - training . de > complete rewrite in 6 / 2006 and earlier modifications
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
2008-03-09 15:35:48 +01:00
* @ author RalfBecker - AT - outdoor - training . de
2014-11-21 10:31:39 +01:00
* @ copyright 2001 - 2014 by RalfBecker @ outdoor - training . de
2008-03-09 15:35:48 +01:00
* @ package api
* @ subpackage html
2006-08-30 16:47:56 +02:00
* @ version $Id $
*/
2004-11-19 07:32:10 +01:00
2005-02-16 14:04:14 +01:00
/**
2008-03-09 15:35:48 +01:00
* Generates html with methods representing html - tags or higher widgets
*
2009-10-11 13:37:46 +02:00
* The class has only static methods now , so there ' s no need to instanciate as object anymore !
2005-02-16 14:04:14 +01:00
*/
2004-11-19 07:32:10 +01:00
class html
{
2005-02-16 14:04:14 +01:00
/**
2011-07-07 13:50:06 +02:00
* user - agent : 'firefox' , 'msie' , 'safari' ( incl . iPhone ), 'chrome' , 'opera' , 'konqueror' , 'mozilla'
2005-02-16 14:04:14 +01:00
* @ var string
*/
2008-03-09 15:35:48 +01:00
static $user_agent ;
2011-06-03 09:47:11 +02:00
/**
2014-11-21 10:31:39 +01:00
* User agent is mobile browser : " iphone " , " ipod " , " ipad " , " android " , " symbianos " , " blackberry " , " kindle " , " opera mobi " , " windows phone "
* @ var string with name of mobile browser or null , if not mobile browser
2011-06-03 09:47:11 +02:00
*/
static $ua_mobile ;
2005-02-16 14:04:14 +01:00
/**
* version of user - agent as specified by browser
* @ var string
*/
2008-03-09 15:35:48 +01:00
static $ua_version ;
2005-02-16 14:04:14 +01:00
/**
* what attribute to use for the title of an image : 'title' for everything but netscape4 = 'alt'
* @ var string
*/
2008-03-09 15:35:48 +01:00
static $netscape4 ;
static private $prefered_img_title ;
2005-02-16 14:04:14 +01:00
/**
2005-11-26 15:25:39 +01:00
* charset used by the page , as returned by $GLOBALS [ 'egw' ] -> translation -> charset ()
2005-02-16 14:04:14 +01:00
* @ var string
*/
2008-03-09 15:35:48 +01:00
static $charset ;
2005-02-16 14:04:14 +01:00
/**
* URL ( NOT path ) of the js directory in the api
* @ var string
*/
2008-03-09 15:35:48 +01:00
static $api_js_url ;
2005-06-30 11:10:15 +02:00
2012-11-13 23:14:00 +01:00
/**
* Automatically turn on enhanced selectboxes if there ' s more than this many options
*/
const SELECT_ENHANCED_ROW_COUNT = 12 ;
2005-02-16 14:04:14 +01:00
/**
2008-03-09 15:35:48 +01:00
* initialise our static vars
2005-02-16 14:04:14 +01:00
*/
2008-03-09 15:35:48 +01:00
static function _init_static ()
2004-11-19 07:32:10 +01:00
{
// should be Ok for all HTML 4 compatible browsers
2015-03-30 10:26:31 +02:00
$parts = $all_parts = null ;
2009-10-11 13:37:46 +02:00
if ( ! preg_match ( '/compatible; ([a-z]+)[\/ ]+([0-9.]+)/i' , $_SERVER [ 'HTTP_USER_AGENT' ], $parts ))
2004-11-19 07:32:10 +01:00
{
2015-03-30 10:26:31 +02:00
preg_match_all ( '/([a-z]+)\/([0-9.]+)/i' , $_SERVER [ 'HTTP_USER_AGENT' ], $all_parts , PREG_SET_ORDER );
$parts = array_pop ( $all_parts );
foreach ( $all_parts as $p )
{
2015-10-26 22:43:08 +01:00
if ( $p [ 1 ] == 'Chrome' && $parts [ 1 ] != 'Edge' )
2015-03-30 10:26:31 +02:00
{
$parts = $p ;
break ;
}
}
2004-11-19 07:32:10 +01:00
}
2008-03-09 15:35:48 +01:00
list (, self :: $user_agent , self :: $ua_version ) = $parts ;
2009-10-11 13:37:46 +02:00
if (( self :: $user_agent = strtolower ( self :: $user_agent )) == 'version' ) self :: $user_agent = 'opera' ;
2014-02-18 20:21:34 +01:00
// IE no longer reports MSIE, but "Trident/7.0; rv:11.0"
if ( self :: $user_agent == 'trident' )
{
self :: $user_agent = 'msie' ;
$matches = null ;
self :: $ua_version = preg_match ( '|Trident/[0-9.]+; rv:([0-9.]+)|i' , $_SERVER [ 'HTTP_USER_AGENT' ], $matches ) ?
$matches [ 1 ] : 11.0 ;
}
2015-03-31 15:55:05 +02:00
// iceweasel is based on mozilla and we treat it like as firefox
if ( self :: $user_agent == 'iceweasel' )
{
self :: $user_agent = 'firefox' ;
}
2015-10-26 22:43:08 +01:00
// MS Edge sometimes reports just "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
if ( self :: $user_agent == 'mozilla' && self :: $ua_version == '5.0' )
{
self :: $user_agent = 'edge' ;
self :: $ua_version = '12.0' ;
}
2014-11-21 10:31:39 +01:00
self :: $ua_mobile = preg_match ( '/(iPhone|iPod|iPad|Android|SymbianOS|Blackberry|Kindle|Opera Mobi|Windows Phone)/i' ,
$_SERVER [ 'HTTP_USER_AGENT' ], $matches ) ? strtolower ( $matches [ 1 ]) : null ;
2005-11-26 15:25:39 +01:00
2008-03-09 15:35:48 +01:00
self :: $netscape4 = self :: $user_agent == 'mozilla' && self :: $ua_version < 5 ;
self :: $prefered_img_title = self :: $netscape4 ? 'alt' : 'title' ;
2011-06-03 11:09:25 +02:00
//error_log("HTTP_USER_AGENT='$_SERVER[HTTP_USER_AGENT]', UserAgent: '".self::$user_agent."', Version: '".self::$ua_version."', isMobile=".array2string(self::$ua_mobile).", img_title: '".self::$prefered_img_title."'");
2005-11-26 15:25:39 +01:00
if ( $GLOBALS [ 'egw' ] -> translation )
2004-11-19 07:32:10 +01:00
{
2008-03-09 15:35:48 +01:00
self :: $charset = $GLOBALS [ 'egw' ] -> translation -> charset ();
2004-11-19 07:32:10 +01:00
}
2008-03-09 15:35:48 +01:00
self :: $api_js_url = $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ] . '/phpgwapi/js' ;
2004-11-19 07:32:10 +01:00
}
/**
2005-02-16 14:04:14 +01:00
* Created an input - field with an attached color - picker
2004-11-19 07:32:10 +01:00
*
2010-01-31 00:55:36 +01:00
* Please note : it need to be called before the call to egw_header () !!!
2004-11-19 07:32:10 +01:00
*
2005-02-16 14:04:14 +01:00
* @ param string $name the name of the input - field
2014-11-21 10:31:39 +01:00
* @ param string $value = '' the actual value for the input - field , default ''
* @ param string $title = '' tooltip / title for the picker - activation - icon
* @ param string $options = '' options for input
2005-02-16 14:04:14 +01:00
* @ return string the html
2004-11-19 07:32:10 +01:00
*/
2011-06-04 11:30:46 +02:00
static function inputColor ( $name , $value = '' , $title = '' , $options = '' )
2004-11-19 07:32:10 +01:00
{
2011-06-04 11:30:46 +02:00
$options .= ' id="' . htmlspecialchars ( $id = str_replace ( array ( '[' , ']' ), array ( '_' , '' ), $name ) . '_colorpicker' ) . '"' ;
$onclick = " javascript:egw_openWindowCentered2(' " . self :: $api_js_url . '/colorpicker/select_color.html?id=' . urlencode ( $id ) . " &color='+encodeURIComponent(document.getElementById(' $id ').value),'colorPicker',240,187); " ;
if ( preg_match ( '/^#[0-9A-F]{6}$/i' , $value ))
{
$options .= ' style="background-color: ' . $value . '"' ;
}
$options .= ' onChange="this.style.backgroundColor=this.value.match(/^(#[0-9A-F]+|[a-z]+)$/i)?this.value:\'#FFFFFF\'+(this.value=\'\')"' ;
return self :: input ( $name , $value , 'text' , $options . ' size="7" maxsize="7"' ) . ' ' .
2004-11-19 07:32:10 +01:00
'<a href="#" onclick="' . $onclick . '">' .
2008-03-09 15:35:48 +01:00
'<img src="' . self :: $api_js_url . '/colorpicker/ed_color_bg.gif' . '"' . ( $title ? ' title="' . self :: htmlspecialchars ( $title ) . '"' : '' ) . " /></a> " ;
2004-11-19 07:32:10 +01:00
}
2005-11-26 15:25:39 +01:00
2004-11-19 07:32:10 +01:00
/**
* Handles tooltips via the wz_tooltip class from Walter Zorn
*
2010-01-17 04:20:45 +01:00
* @ param string $text text or html for the tooltip , all chars allowed , they will be quoted approperiate
2005-02-16 14:04:14 +01:00
* @ param boolean $do_lang ( default False ) should the text be run though lang ()
* @ param array $options param / value pairs , eg . 'TITLE' => 'I am the title' . Some common parameters :
2004-11-19 07:32:10 +01:00
* title ( string ) gives extra title - row , width ( int , 'auto' ) , padding ( int ), above ( bool ), bgcolor ( color ), bgimg ( URL )
* For a complete list and description see http :// www . walterzorn . com / tooltip / tooltip_e . htm
2012-06-01 15:13:06 +02:00
* @ param boolean $return_as_attributes true to return array ( onmouseover , onmouseout ) attributes
* @ return string | array to be included in any tag , like '<p' . html :: tooltip ( 'Hello <b>Ralf</b>' ) . '>Text with tooltip</p>'
2004-11-19 07:32:10 +01:00
*/
2012-06-01 15:13:06 +02:00
static function tooltip ( $text , $do_lang = False , $options = False , $return_as_attributes = false )
2004-11-19 07:32:10 +01:00
{
2012-04-04 15:05:58 +02:00
// tell egw_framework to include wz_tooltip.js
$GLOBALS [ 'egw_info' ][ 'flags' ][ 'include_wz_tooltip' ] = true ;
2004-11-19 07:32:10 +01:00
if ( $do_lang ) $text = lang ( $text );
2005-11-26 15:25:39 +01:00
2012-06-01 15:13:06 +02:00
$ttip = 'Tip(\'' . str_replace ( array ( " \n " , " \r " , " ' " , '"' ), array ( '' , '' , " \\ ' " , '"' ), $text ) . '\'' ;
2010-04-13 17:12:09 +02:00
2010-01-24 04:15:12 +01:00
$sticky = false ;
2004-11-19 07:32:10 +01:00
if ( is_array ( $options ))
{
2004-05-08 23:09:44 +02:00
foreach ( $options as $option => $value )
{
2010-01-24 04:15:12 +01:00
$option = strtoupper ( $option );
if ( $option == 'STICKY' ) $sticky = ( bool ) $value ;
switch ( gettype ( $value ))
{
case 'boolean' :
$value = $value ? 'true' : 'false' ;
break ;
case 'string' :
2010-02-02 12:23:11 +01:00
if ( stripos ( $value , " ' " ) === false ) $value = " ' $value ' " ;
2010-01-24 04:15:12 +01:00
break ;
}
$ttip .= ',' . $option . ',' . $value ;
2004-05-08 23:09:44 +02:00
}
2004-11-19 07:32:10 +01:00
}
2012-06-01 15:13:06 +02:00
$ttip .= ')' ;
2010-01-24 04:15:12 +01:00
2012-06-01 15:13:06 +02:00
$untip = 'UnTip()' ;
2010-01-24 04:15:12 +01:00
2012-06-01 15:13:06 +02:00
return $return_as_attributes ? array ( $ttip , $untip ) :
' onmouseover="' . self :: htmlspecialchars ( $ttip ) . '" onmouseout="' . $untip . '"' ;
2004-11-19 07:32:10 +01:00
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* activates URLs in a text , URLs get replaced by html - links
*
* @ param string $content text containing URLs
* @ return string html with activated links
*/
2008-03-09 15:35:48 +01:00
static function activate_links ( $content )
2004-11-19 07:32:10 +01:00
{
2008-03-09 15:35:48 +01:00
if ( ! $content || strlen ( $content ) < 20 ) return $content ; // performance
2010-04-13 17:12:09 +02:00
2004-11-19 07:32:10 +01:00
// Exclude everything which is already a link
$NotAnchor = '(?<!"|href=|href\s=\s|href=\s|href\s=)' ;
2005-11-26 15:25:39 +01:00
2004-11-19 07:32:10 +01:00
// spamsaver emailaddress
$result = preg_replace ( '/' . $NotAnchor . 'mailto:([a-z0-9._-]+)@([a-z0-9_-]+)\.([a-z0-9._-]+)/i' ,
2016-01-08 16:05:04 +01:00
// '<a href="#" onclick="document.location=\'mai\'+\'lto:\\1\'+unescape(\'%40\')+\'\\2.\\3\'; return false;">\\1 AT \\2 DOT \\3</a>',
" <a href= \" mailto: $ 1@ $ 2. $ 3 \" target= \" _blank \" > $ 1 AT $ 2 DOT $ 3</a> " ,
2004-11-19 07:32:10 +01:00
$content );
2005-11-26 15:25:39 +01:00
2004-11-19 07:32:10 +01:00
// First match things beginning with http:// (or other protocols)
2016-01-08 16:05:04 +01:00
$optBracket0 = '(<|<)' ;
2007-04-26 14:32:03 +02:00
$Protocol = '(http:\/\/|(ftp:\/\/|https:\/\/))' ; // only http:// gets removed, other protocolls are shown
$Domain = '([\w-]+\.[\w-.]+)' ;
2005-02-09 17:48:30 +01:00
$Subdir = '([\w\-\.,@?^=%&;:\/~\+#]*[\w\-\@?^=%&\/~\+#])?' ;
2012-08-15 16:55:02 +02:00
$optBracket = '' ;
2016-01-08 16:05:04 +01:00
$optBracket = '(>|>)' ;
$Expr = '/' . $optBracket0 . $NotAnchor . $Protocol . $Domain . $Subdir . $optBracket . '/i' ;
2016-01-12 12:22:20 +01:00
// use preg_replace_callback as we experienced problems with https links
$result2 = preg_replace_callback ( $Expr , function ( $match ) {
//error_log(__METHOD__.__LINE__.array2string($match));
return $match [ 1 ] . " <a href= \" " . ( $match [ 2 ] &&! $match [ 3 ] ? $match [ 2 ] : '' ) . ( $match [ 3 ] ? $match [ 3 ] : '' ) . $match [ 4 ] . $match [ 5 ] . " \" target= \" _blank \" > " . $match [ 4 ] . $match [ 5 ] . " </a> " . $match [ 6 ];
}, $result );
2016-01-08 16:05:04 +01:00
//error_log(__METHOD__.__LINE__.array2string($Expr));
//error_log(__METHOD__.__LINE__.array2string($result2));
// First match things beginning with http:// (or other protocols)
$Protocol = '(http:\/\/|(ftp:\/\/|https:\/\/))' ; // only http:// gets removed, other protocolls are shown
$Domain = '([\w-]+\.[\w-.]+)' ;
$Subdir = '([\w\-\.,@?^=%&;:\/~\+#]*[\w\-\@?^=%&\/~\+#])?' ;
$Expr = '/' . $NotAnchor . $Protocol . $Domain . $Subdir . '/i' ;
2016-01-12 12:22:20 +01:00
// use preg_replace_callback as we experienced problems with https links
$result3 = preg_replace_callback ( $Expr , function ( $match ) {
//error_log(__METHOD__.__LINE__.array2string($match));
return " <a href= \" " . ( $match [ 1 ] &&! $match [ 2 ] ? $match [ 1 ] : '' ) . ( $match [ 2 ] ? $match [ 2 ] : '' ) . $match [ 3 ] . $match [ 4 ] . " \" target= \" _blank \" > " . $match [ 3 ] . $match [ 4 ] . " </a> " ;
}, $result2 );
2016-01-08 16:05:04 +01:00
//error_log(__METHOD__.__LINE__.array2string($Expr));
//error_log(__METHOD__.__LINE__.array2string($result3));
2004-11-19 07:32:10 +01:00
// Now match things beginning with www.
2016-01-08 16:05:04 +01:00
$optBracket0 = '(<|<)?' ;
2008-03-09 15:35:48 +01:00
$NotHTTP = '(?<!:\/\/|" target=\"_blank\">)' ; // avoid running again on http://www links already handled above
2014-02-18 20:21:34 +01:00
$Domain2 = 'www(\.[\w-.]+)' ;
$Subdir2 = '([\w\-\.,@?^=%&:\/~\+#]*[\w\-\@?^=%&\/~\+#])?' ;
2016-01-08 16:05:04 +01:00
$optBracket = '(>|>)?' ;
$Expr = '/' . $optBracket0 . $NotAnchor . $NotHTTP . $Domain2 . $Subdir2 . $optBracket . '/i' ;
2014-01-18 18:02:29 +01:00
//$Expr = '/' . $NotAnchor . $NotHTTP . $Domain . $Subdir . $optBracket . '/i';
2005-11-26 15:25:39 +01:00
2016-01-08 16:05:04 +01:00
$result4 = preg_replace ( $Expr , " $ 1<a href= \" http://www $ 2 $ 3 $ 4 $ 5 \" target= \" _blank \" >www $ 2 $ 3 $ 4 $ 5</a> $ 6 " , $result3 );
2014-01-18 18:02:29 +01:00
//return preg_replace( $Expr, "<a href=\"http://www$1$2\" target=\"_blank\">www$1$2</a>$3 ", $result );
2016-01-08 16:05:04 +01:00
//error_log(__METHOD__.__LINE__.array2string($Expr));
//error_log(__METHOD__.__LINE__.array2string($result4));
return $result4 ;
2004-11-19 07:32:10 +01:00
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* escapes chars with special meaning in html as entities
*
2010-10-20 15:16:21 +02:00
* Allows to use and char in the html - output and prevents XSS attacks .
2010-12-19 22:54:37 +01:00
* Some entities are allowed and get NOT escaped : -> prevented by 4 th param = doubleencode = false
2010-10-20 15:16:21 +02:00
* - & # some translations (AFAIK: the arabic ones) need this;
* - & nbsp ; & lt ; & gt ; for convenience -> should not happen anymore , as we do not doubleencode anymore ( 20101020 )
2005-02-16 14:04:14 +01:00
*
* @ param string $str string to escape
2014-11-21 10:31:39 +01:00
* @ param boolean $double_encoding = false do we want double encoding or not , default no
2005-02-16 14:04:14 +01:00
* @ return string
*/
2012-04-11 16:52:08 +02:00
static function htmlspecialchars ( $str , $double_encoding = false )
2004-11-19 07:32:10 +01:00
{
2011-06-03 09:47:11 +02:00
//if (!is_scalar($str) && !is_null($str)) error_log(__METHOD__.'('.array2string($str).') '.function_backtrace());
2010-10-20 15:16:21 +02:00
// as EGroupware supports only utf-8 we should not need to worry about wrong charsets
2012-01-09 15:45:24 +01:00
//if (is_array($str)) error_log(__METHOD__.__LINE__.' string expected -> array given:'.array2string($str).'->'.function_backtrace());
2012-04-11 16:52:08 +02:00
return htmlspecialchars ( $str , ENT_COMPAT , self :: $charset , $double_encoding );
2010-10-20 15:16:21 +02:00
// we need '&#' unchanged, so we translate it back -> this is provided by 4th param = false -> do not doubleencode
//$str = str_replace(array('&#','&nbsp;','&lt;','&gt;'),array('&#',' ','<','>'),$str);
2005-11-26 15:25:39 +01:00
2010-10-20 15:16:21 +02:00
//return $str;
2004-11-19 07:32:10 +01:00
}
2005-11-26 15:25:39 +01:00
2004-11-19 07:32:10 +01:00
/**
* allows to show and select one item from an array
*
* @ param string $name string with name of the submitted var which holds the key of the selected item form array
2014-11-21 10:31:39 +01:00
* @ param string | array $key key ( s ) of already selected item ( s ) from $arr , eg . '1' or '1,2' or array with keys
2004-11-19 07:32:10 +01:00
* @ param array $arr array with items to select , eg . $arr = array ( 'y' => 'yes' , 'n' => 'no' , 'm' => 'maybe' );
2005-02-16 14:04:14 +01:00
* @ param boolean $no_lang NOT run the labels of the options through lang (), default false = use lang ()
2004-11-19 07:32:10 +01:00
* @ param string $options additional options ( e . g . 'width' )
2006-07-08 22:18:36 +02:00
* @ param int $multiple number of lines for a multiselect , default 0 = no multiselect , < 0 sets size without multiple
2012-11-12 20:29:23 +01:00
* @ param boolean $enhanced Use enhanced selectbox with search . Null for default yes if more than 12 options .
2004-11-19 07:32:10 +01:00
* @ return string to set for a template or to echo into html page
*/
2012-11-12 20:29:23 +01:00
static function select ( $name , $key , $arr = 0 , $no_lang = false , $options = '' , $multiple = 0 , $enhanced = null )
2004-11-19 07:32:10 +01:00
{
2014-01-18 12:08:06 +01:00
if ( is_null ( $enhanced )) $enhanced = false ; //disabled by default (count($arr) > self::SELECT_ENHANCED_ROW_COUNT);
2012-11-12 20:29:23 +01:00
2004-11-19 07:32:10 +01:00
if ( ! is_array ( $arr ))
{
2004-04-20 19:19:14 +02:00
$arr = array ( 'no' , 'yes' );
2004-11-19 07:32:10 +01:00
}
if (( int ) $multiple > 0 )
{
2004-06-12 11:45:33 +02:00
$options .= ' multiple="1" size="' . ( int ) $multiple . '"' ;
2004-04-20 19:19:14 +02:00
if ( substr ( $name , - 2 ) != '[]' )
{
2004-11-19 07:32:10 +01:00
$name .= '[]' ;
2003-12-26 22:00:00 +01:00
}
2004-11-19 07:32:10 +01:00
}
2006-07-08 22:18:36 +02:00
elseif ( $multiple < 0 )
{
$options .= ' size="' . abs ( $multiple ) . '"' ;
}
2011-05-31 09:55:51 +02:00
// fix width for MSIE < 9 in/for selectboxes
if ( self :: $user_agent == 'msie' && self :: $ua_version < 9 )
2009-11-28 15:32:33 +01:00
{
if ( stripos ( $options , 'onfocus="' ) === false )
{
$options .= ' onfocus="window.dropdown_menu_hack(this);" ' ;
}
else
{
$options = str_ireplace ( 'onfocus="' , 'onfocus="window.dropdown_menu_hack(this);' , $options );
}
}
2004-11-19 07:32:10 +01:00
$out = " <select name= \" $name\ " $options > \n " ;
2005-11-26 15:25:39 +01:00
2004-11-19 07:32:10 +01:00
if ( ! is_array ( $key ))
{
// explode on ',' only if multiple values expected and the key contains just numbers and commas
2006-07-08 22:18:36 +02:00
$key = $multiple > 0 && preg_match ( '/^[,0-9]+$/' , $key ) ? explode ( ',' , $key ) : array ( $key );
2004-11-19 07:32:10 +01:00
}
2005-02-16 14:04:14 +01:00
foreach ( $arr as $k => $data )
2004-11-19 07:32:10 +01:00
{
2005-04-12 18:30:16 +02:00
if ( ! is_array ( $data ) || count ( $data ) == 2 && isset ( $data [ 'label' ]) && isset ( $data [ 'title' ]))
2005-02-16 14:04:14 +01:00
{
2008-03-09 15:35:48 +01:00
$out .= self :: select_option ( $k , is_array ( $data ) ? $data [ 'label' ] : $data , $key , $no_lang ,
2005-04-12 18:30:16 +02:00
is_array ( $data ) ? $data [ 'title' ] : '' );
2005-02-16 14:04:14 +01:00
}
else
2004-10-08 01:09:52 +02:00
{
2007-07-22 15:23:44 +02:00
if ( isset ( $data [ 'lable' ]))
{
$k = $data [ 'lable' ];
unset ( $data [ 'lable' ]);
}
2008-03-09 15:35:48 +01:00
$out .= '<optgroup label="' . self :: htmlspecialchars ( $no_lang || $k == '' ? $k : lang ( $k )) . " \" > \n " ;
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
foreach ( $data as $k => $label )
{
2008-03-09 15:35:48 +01:00
$out .= self :: select_option ( $k , is_array ( $label ) ? $label [ 'label' ] : $label , $key , $no_lang ,
2014-02-18 20:21:34 +01:00
is_array ( $label ) ? $label [ 'title' ] : '' );
2005-02-16 14:04:14 +01:00
}
$out .= " </optgroup> \n " ;
2004-10-08 01:09:52 +02:00
}
2004-11-19 07:32:10 +01:00
}
$out .= " </select> \n " ;
2005-11-26 15:25:39 +01:00
2012-11-12 20:29:23 +01:00
if ( $enhanced ) {
2012-11-13 23:14:00 +01:00
egw_framework :: validate_file ( '/phpgwapi/js/jquery/chosen/chosen.jquery.js' );
2012-11-12 20:29:23 +01:00
egw_framework :: includeCSS ( '/phpgwapi/js/jquery/chosen/chosen.css' , null , false );
2013-07-25 22:28:32 +02:00
$out .= " <script>var lab = egw_LAB || \$ LAB; lab.wait(function() { \$ j(function() { if( \$ j().chosen) \$ j('select[name= \" $name\ " ] ').chosen({width: ' 100 % ' });});}) </ script > \n " ;
2012-11-12 20:29:23 +01:00
}
2004-11-19 07:32:10 +01:00
return $out ;
}
2005-11-26 15:25:39 +01:00
2005-02-24 22:01:13 +01:00
/**
* emulating a multiselectbox using checkboxes
*
* Unfortunaly this is not in all aspects like a multi - selectbox , eg . you cant select options via javascript
* in the same way . Therefor I made it an extra function .
*
* @ param string $name string with name of the submitted var which holds the key of the selected item form array
2014-11-21 10:31:39 +01:00
* @ param string | array $key key ( s ) of already selected item ( s ) from $arr , eg . '1' or '1,2' or array with keys
2005-02-24 22:01:13 +01:00
* @ param array $arr array with items to select , eg . $arr = array ( 'y' => 'yes' , 'n' => 'no' , 'm' => 'maybe' );
* @ param boolean $no_lang NOT run the labels of the options through lang (), default false = use lang ()
* @ param string $options additional options ( e . g . 'width' )
* @ param int $multiple number of lines for a multiselect , default 3
2005-03-05 16:03:01 +01:00
* @ param boolean $selected_first show the selected items before the not selected ones , default true
2014-11-21 10:31:39 +01:00
* @ param string $style = '' extra style settings like " width: 100% " , default '' none
2005-02-24 22:01:13 +01:00
* @ return string to set for a template or to echo into html page
*/
2012-11-13 23:14:00 +01:00
static function checkbox_multiselect ( $name , $key , $arr = 0 , $no_lang = false , $options = '' , $multiple = 3 , $selected_first = true , $style = '' , $enhanced = null )
2005-02-24 22:01:13 +01:00
{
2010-12-19 22:54:37 +01:00
//echo "<p align=right>checkbox_multiselect('$name',".array2string($key).",".array2string($arr).",$no_lang,'$options',$multiple,$selected_first,'$style')</p>\n";
2012-11-13 23:14:00 +01:00
if ( is_null ( $enhanced )) $enhanced = ( count ( $arr ) > self :: SELECT_ENHANCED_ROW_COUNT );
2005-02-24 22:01:13 +01:00
if ( ! is_array ( $arr ))
{
$arr = array ( 'no' , 'yes' );
}
if (( int ) $multiple <= 0 ) $multiple = 1 ;
if ( substr ( $name , - 2 ) != '[]' )
{
$name .= '[]' ;
}
$base_name = substr ( $name , 0 , - 2 );
2005-11-26 15:25:39 +01:00
2012-12-04 23:21:59 +01:00
if ( $enhanced ) return self :: select ( $name , $key , $arr , $no_lang , $options . " style= \" $style\ " " , $multiple , $enhanced );
2012-11-13 23:14:00 +01:00
2005-02-24 22:01:13 +01:00
if ( ! is_array ( $key ))
{
// explode on ',' only if multiple values expected and the key contains just numbers and commas
$key = preg_match ( '/^[,0-9]+$/' , $key ) ? explode ( ',' , $key ) : array ( $key );
}
$html = '' ;
$options_no_id = preg_replace ( '/id="[^"]+"/i' , '' , $options );
2005-11-26 15:25:39 +01:00
2005-03-05 16:03:01 +01:00
if ( $selected_first )
{
$selected = $not_selected = array ();
foreach ( $arr as $val => $label )
{
2010-12-20 21:57:35 +01:00
if ( in_array (( string ) $val , $key ))
2005-03-05 16:03:01 +01:00
{
$selected [ $val ] = $label ;
}
else
{
$not_selected [ $val ] = $label ;
}
}
$arr = $selected + $not_selected ;
}
2014-02-18 20:21:34 +01:00
$max_len = 0 ;
2005-02-24 22:01:13 +01:00
foreach ( $arr as $val => $label )
{
2005-04-12 18:30:16 +02:00
if ( is_array ( $label ))
{
$title = $label [ 'title' ];
$label = $label [ 'label' ];
}
else
{
$title = '' ;
}
2005-02-24 22:01:13 +01:00
if ( $label && ! $no_lang ) $label = lang ( $label );
2005-04-12 18:30:16 +02:00
if ( $title && ! $no_lang ) $title = lang ( $title );
2005-11-26 15:25:39 +01:00
2005-02-24 22:01:13 +01:00
if ( strlen ( $label ) > $max_len ) $max_len = strlen ( $label );
2005-11-26 15:25:39 +01:00
2010-12-20 21:57:35 +01:00
$html .= self :: label ( self :: checkbox ( $name , in_array (( string ) $val , $key ), $val , $options_no_id .
2008-03-09 15:35:48 +01:00
' id="' . $base_name . '[' . $val . ']' . '"' ) . self :: htmlspecialchars ( $label ),
$base_name . '[' . $val . ']' , '' ,( $title ? 'title="' . self :: htmlspecialchars ( $title ) . '" ' : '' )) . " <br /> \n " ;
2005-02-24 22:01:13 +01:00
}
2006-03-20 22:51:55 +01:00
if ( $style && substr ( $style , - 1 ) != ';' ) $style .= '; ' ;
2006-12-07 13:46:08 +01:00
if ( strpos ( $style , 'height' ) === false ) $style .= 'height: ' . ( 1.7 * $multiple ) . 'em; ' ;
2008-03-09 15:35:48 +01:00
if ( strpos ( $style , 'width' ) === false ) $style .= 'width: ' . ( 4 + $max_len * ( $max_len < 15 ? 0.65 : 0.6 )) . 'em; ' ;
2007-06-07 12:29:56 +02:00
$style .= 'background-color: white; overflow: auto; border: lightgray 2px inset; text-align: left;' ;
2005-11-26 15:25:39 +01:00
2008-03-09 15:35:48 +01:00
return self :: div ( $html , $options , '' , $style );
2005-02-24 22:01:13 +01:00
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* generates an option - tag for a selectbox
*
* @ param string $value value
* @ param string $label label
* @ param mixed $selected value or array of values of options to mark as selected
* @ param boolean $no_lang NOT running the label through lang (), default false = use lang ()
2011-08-15 18:25:08 +02:00
* @ param string $extra extra text , e . g .: style = " " , default : ''
2005-02-16 14:04:14 +01:00
* @ return string html
*/
2011-08-15 18:25:08 +02:00
static function select_option ( $value , $label , $selected , $no_lang = 0 , $title = '' , $extra = '' )
2005-02-16 14:04:14 +01:00
{
2005-05-20 19:00:12 +02:00
// the following compares strict as strings, to archive: '0' == 0 != ''
// the first non-strict search via array_search, is for performance reasons, to not always search the whole array with php
2007-01-12 02:24:05 +01:00
if (( $found = ( $key = array_search ( $value , $selected )) !== false ) && ( string ) $value !== ( string ) $selected [ $key ])
2005-05-20 19:00:12 +02:00
{
2007-01-12 02:24:05 +01:00
$found = false ;
foreach ( $selected as $sel )
2005-05-20 19:00:12 +02:00
{
2014-02-18 20:21:34 +01:00
if (( $found = ((( string ) $value ) === (( string ) $selected [ $key ])))) break ;
2005-05-20 19:00:12 +02:00
}
2014-02-18 20:21:34 +01:00
unset ( $sel );
2005-05-20 19:00:12 +02:00
}
2008-03-09 15:35:48 +01:00
return '<option value="' . self :: htmlspecialchars ( $value ) . '"' . ( $found ? ' selected="selected"' : '' ) .
2011-08-15 18:25:08 +02:00
( $title ? ' title="' . self :: htmlspecialchars ( $no_lang ? $title : lang ( $title )) . '"' : '' ) .
( $extra ? ' ' . $extra : '' ) . '>' .
2008-03-09 15:35:48 +01:00
self :: htmlspecialchars ( $no_lang || $label == '' ? $label : lang ( $label )) . " </option> \n " ;
2005-02-16 14:04:14 +01:00
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* generates a div - tag
*
* @ param string $content of a div , or '' to generate only the opening tag
* @ param string $options to include in the tag , default '' = none
* @ param string $class css - class attribute , default '' = none
* @ param string $style css - styles attribute , default '' = none
* @ return string html
*/
2008-03-09 15:35:48 +01:00
static function div ( $content , $options = '' , $class = '' , $style = '' )
2004-11-19 07:32:10 +01:00
{
if ( $class ) $options .= ' class="' . $class . '"' ;
if ( $style ) $options .= ' style="' . $style . '"' ;
2005-11-26 15:25:39 +01:00
2004-11-19 07:32:10 +01:00
return " <div $options > \n " . ( $content ? " $content </div> \n " : '' );
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* generate one or more hidden input tag ( s )
*
2014-11-21 10:31:39 +01:00
* @ param array | string $vars var - name or array with name / value pairs
2005-02-16 14:04:14 +01:00
* @ param string $value value if $vars is no array , default ''
* @ param boolean $ignore_empty if true all empty , zero ( ! ) or unset values , plus filer = none
* @ param string html
*/
2008-03-09 15:35:48 +01:00
static function input_hidden ( $vars , $value = '' , $ignore_empty = True )
2004-11-19 07:32:10 +01:00
{
if ( ! is_array ( $vars ))
{
2004-04-20 19:19:14 +02:00
$vars = array ( $vars => $value );
2004-11-19 07:32:10 +01:00
}
foreach ( $vars as $name => $value )
{
2004-04-20 19:19:14 +02:00
if ( is_array ( $value ))
{
2014-02-04 14:50:23 +01:00
$value = json_encode ( $value );
2003-09-14 12:19:42 +02:00
}
2004-04-20 19:19:14 +02:00
if ( ! $ignore_empty || $value && ! ( $name == 'filter' && $value == 'none' )) // dont need to send all the empty vars
2003-09-14 12:19:42 +02:00
{
2008-03-09 15:35:48 +01:00
$html .= " <input type= \" hidden \" name= \" $name\ " value = \ " " . self :: htmlspecialchars ( $value ) . " \" /> \n " ;
2003-09-14 12:19:42 +02:00
}
2004-11-19 07:32:10 +01:00
}
return $html ;
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* generate a textarea tag
*
* @ param string $name name attr . of the tag
2005-11-26 15:25:39 +01:00
* @ param string $value default
2005-02-16 14:04:14 +01:00
* @ param boolean $ignore_empty if true all empty , zero ( ! ) or unset values , plus filer = none
2014-11-21 10:31:39 +01:00
* @ param boolean $double_encoding = false do we want double encoding or not , default no
2005-02-16 14:04:14 +01:00
* @ param string html
*/
2012-04-11 16:52:08 +02:00
static function textarea ( $name , $value = '' , $options = '' , $double_encoding = false )
2004-11-19 07:32:10 +01:00
{
2012-04-11 16:52:08 +02:00
return " <textarea name= \" $name\ " $options > " .self::htmlspecialchars( $value , $double_encoding ). " </ textarea > \n " ;
2004-11-19 07:32:10 +01:00
}
2005-11-26 15:25:39 +01:00
2004-11-19 07:32:10 +01:00
/**
2005-02-16 14:04:14 +01:00
* Checks if HTMLarea ( or an other richtext editor ) is availible for the used browser
*
* @ return boolean
2007-01-19 07:58:38 +01:00
*/
2008-03-09 15:35:48 +01:00
static function htmlarea_availible ()
2004-11-19 07:32:10 +01:00
{
2011-10-31 11:28:30 +01:00
// this one is for testing how it will turn out, if you do not have the device or agent ready at your fingertips
// if (stripos($_SERVER[HTTP_USER_AGENT],'mozilla') !== false) return false;
2010-05-25 09:47:57 +02:00
2014-01-18 18:02:29 +01:00
// CKeditor will doublecheck availability for us, but its fallback does not look nice, and you will get
2011-10-31 11:28:30 +01:00
// no conversion of html content to plain text, so we provide a check for known USER_AGENTS to fail the test
2010-05-25 09:47:57 +02:00
return true ;
2007-01-19 07:58:38 +01:00
}
2005-11-26 15:25:39 +01:00
2004-11-19 07:32:10 +01:00
/**
2008-03-09 15:35:48 +01:00
* compability static function for former used htmlarea . Please use static function fckeditor now !
2005-02-16 14:04:14 +01:00
*
2005-10-13 17:16:38 +02:00
* creates a textarea inputfield for the htmlarea js - widget ( returns the necessary html and js )
2005-02-16 14:04:14 +01:00
*/
2014-02-18 20:21:34 +01:00
static function htmlarea ( $name , $content = '' , $style = '' , $base_href = '' /*,$plugins='',$custom_toolbar='',$set_width_height_in_config=false*/ )
2004-11-19 07:32:10 +01:00
{
2010-05-25 09:47:57 +02:00
/* if ( ! self :: htmlarea_availible ())
2007-01-19 09:00:09 +01:00
{
2008-03-09 15:35:48 +01:00
return self :: textarea ( $name , $content , 'style="' . $style . '"' );
2010-05-25 09:47:57 +02:00
} */
2012-12-05 21:22:13 +01:00
return self :: fckEditor ( $name , $content , $style , array ( 'toolbar_expanded' => 'true' ), '400px' , '100%' , $base_href );
2004-11-19 07:32:10 +01:00
}
2007-01-18 18:59:28 +01:00
/**
2008-03-09 15:35:48 +01:00
* this static function is a wrapper for fckEditor to create some reuseable layouts
2007-01-18 18:59:28 +01:00
*
* @ param string $_name name and id of the input - field
2008-04-15 14:23:32 +02:00
* @ param string $_content of the tinymce ( will be run through htmlspecialchars !!! ), default ''
2007-01-18 18:59:28 +01:00
* @ param string $_mode display mode of the tinymce editor can be : simple , extended or advanced
* @ param array $_options ( toolbar_expanded true / false )
2014-11-21 10:31:39 +01:00
* @ param string $_height = '400px'
* @ param string $_width = '100%'
* @ param string $_start_path = '' if passed activates the browser for image at absolute path passed
* @ param boolean $_purify = true run $_content through htmlpurifier before handing it to fckEditor
2013-04-08 14:48:45 +02:00
* @ param mixed ( boolean / string ) $_focusToBody = false USED only for CKEDIOR true means yes , focus on top , you may specify TOP or BOTTOM ( to focus on the end of the editor area )
2014-11-21 10:31:39 +01:00
* @ param string $_executeJSAfterInit = '' Javascript to be executed after InstanceReady of CKEditor
2007-01-18 18:59:28 +01:00
* @ return string the necessary html for the textarea
*/
2009-05-19 21:23:38 +02:00
static function fckEditor ( $_name , $_content , $_mode , $_options = array ( 'toolbar_expanded' => 'true' ),
2013-04-08 14:48:45 +02:00
$_height = '400px' , $_width = '100%' , $_start_path = '' , $_purify = true , $_focusToBody = false , $_executeJSAfterInit = '' )
2007-04-14 18:57:57 +02:00
{
2008-03-09 15:35:48 +01:00
if ( ! self :: htmlarea_availible () || $_mode == 'ascii' )
2007-01-19 09:00:09 +01:00
{
2011-03-30 13:40:14 +02:00
return self :: textarea ( $_name , $_content , 'style="width: ' . $_width . '; height: ' . $_height . ';" id="' . htmlspecialchars ( $_name ) . '"' );
2007-01-19 09:00:09 +01:00
}
2008-04-15 14:23:32 +02:00
2010-06-25 12:01:53 +02:00
//include the ckeditor js file
2013-03-14 17:30:55 +01:00
egw_framework :: validate_file ( 'ckeditor' , 'ckeditor' , 'phpgwapi' );
2010-06-24 16:23:56 +02:00
2010-06-25 12:01:53 +02:00
// run content through htmlpurifier
if ( $_purify && ! empty ( $_content ))
$_content = self :: purify ( $_content );
2008-04-15 14:23:32 +02:00
2007-01-18 18:59:28 +01:00
// By default the editor start expanded
2010-07-21 13:45:05 +02:00
$expanded = isset ( $_options [ 'toolbar_expanded' ]) ?
$_options [ 'toolbar_expanded' ] == 'true' : true ;
2010-05-25 09:47:57 +02:00
2010-06-25 12:01:53 +02:00
//Get the height in pixels from the pixels parameter
$pxheight = ( strpos ( 'px' , $_height ) === false ) ?
( empty ( $_height ) ? 400 : $_height ) : str_replace ( 'px' , '' , $_height );
2010-12-19 22:54:37 +01:00
2012-12-04 23:21:59 +01:00
// User preferences
$font = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'rte_font' ];
2013-02-21 14:19:15 +01:00
$font_size = egw_ckeditor_config :: font_size_from_prefs ();
2013-02-22 10:27:35 +01:00
$font_span = '<span ' . ( $font || $font_size ? 'style=\"' : '' ) . ( $font ? 'font-family:' . $font . '; ' : '' ) . ( $font_size ? 'font-size:' . $font_size . '; ' : '' ) . '\">' ;
if ( empty ( $font ) && empty ( $font_size )) $font_span = '' ;
2012-12-04 23:21:59 +01:00
2012-04-11 16:52:08 +02:00
// we need to enable double encoding here, as ckEditor has to undo one level of encoding
// otherwise < and > chars eg. from html markup entered in regular (not source) input, will turn into html!
2014-01-18 18:02:29 +01:00
//error_log(__METHOD__.__LINE__.' '.self::$user_agent.','.self::$ua_version);
2012-04-11 16:52:08 +02:00
return self :: textarea ( $_name , $_content , 'id="' . htmlspecialchars ( $_name ) . '"' , true ) . // true = double encoding
'
2010-06-25 12:01:53 +02:00
< script type = " text/javascript " >
2013-04-02 14:13:27 +02:00
window . CKEDITOR_BASEPATH = " '. $GLOBALS['egw_info'] ['server']['webserver_url'].'/phpgwapi/js/ckeditor/ " ;
2013-07-17 14:47:21 +02:00
egw_LAB . wait ( function () {
2010-06-25 12:01:53 +02:00
CKEDITOR . replace ( " '. $_name .' " , ' . egw_ckeditor_config :: get_ckeditor_config ( $_mode ,
$pxheight , $expanded , $_start_path ) . ' );
2013-03-21 12:06:51 +01:00
CKEDITOR . addCss ( " body { margin: 5px; } " );
2010-06-25 12:01:53 +02:00
CKEDITOR . instances [ " '. $_name .' " ] . on (
" instanceReady " ,
function ( ev )
2007-12-20 07:15:56 +01:00
{
2013-04-08 14:48:45 +02:00
//alert("CKEditorLoad:"+"'.$_focusToBody.'");
2013-03-04 12:50:17 +01:00
'.($_focusToBody?'
2013-03-08 14:14:14 +01:00
ev . editor . focus (); ':' ').'
2013-03-04 12:50:17 +01:00
var d = ev . editor . document ;
var r = new CKEDITOR . dom . range ( d );
r . collapse ( true );
r . selectNodeContents ( d . getBody ());
r . collapse ( '.($_focusToBody===' BOTTOM '?' false ':' true ').' );
2013-03-06 10:17:21 +01:00
r . select (); '.($font_span?'
//this stuff is needed, as the above places the caret just before the span tag
var sN = r . startContainer . getNextSourceNode ();
//FF is selecting the span with getNextSourceNode, other browsers need to fetch it with getNext
r . selectNodeContents ((( typeof sN . getName === " function " ) && sN . getName () == " span " ? r . startContainer . getNextSourceNode () : r . startContainer . getNextSourceNode () . getNext ()));
r . collapse ( true );
2013-03-08 14:14:14 +01:00
r . select (); '.' ':' ').'
2010-06-25 12:01:53 +02:00
ev . editor . resize ( " 100% " , '.str_replace(' px ', ' ', $pxheight).' );
2013-04-08 14:48:45 +02:00
'.($_executeJSAfterInit?$_executeJSAfterInit:' ').'
2010-05-27 12:06:40 +02:00
}
2012-12-04 23:21:59 +01:00
); ' .
2013-02-22 10:27:35 +01:00
( trim ( $_content ) == '' && $font_span ? 'CKEDITOR.instances["' . $_name . '"].setData("' . $font_span . '​</span>");' : '' ) .
2013-04-02 14:13:27 +02:00
' });
</ script >
2010-06-25 12:01:53 +02:00
' ;
2007-01-18 18:59:28 +01:00
}
2006-11-07 19:18:22 +01:00
/**
2008-03-09 15:35:48 +01:00
* this static function is a wrapper for tinymce to create some reuseable layouts
2006-11-07 19:18:22 +01:00
*
2008-03-09 15:35:48 +01:00
* Please note : if you did not run init_tinymce already you this static function need to be called before the call to phpgw_header () !!!
2006-11-07 19:18:22 +01:00
*
* @ param string $_name name and id of the input - field
* @ param string $_mode display mode of the tinymce editor can be : simple , extended or advanced
2014-11-21 10:31:39 +01:00
* @ param string $_content = '' of the tinymce ( will be run through htmlspecialchars !!! ), default ''
* @ param string $_height = '400px'
* @ param string $_width = '100%'
* @ param boolean $_purify = true
* @ param string $_border = '0px' NOT used for CKEditor
2013-04-08 14:48:45 +02:00
* @ param mixed ( boolean / string ) $_focusToBody = false USED only for CKEDIOR true means yes , focus on top , you may specify TOP or BOTTOM ( to focus on the end of the editor area )
2014-11-21 10:31:39 +01:00
* @ param string $_executeJSAfterInit = '' Javascript to be executed after InstanceReady of CKEditor
2006-11-07 19:18:22 +01:00
* @ return string the necessary html for the textarea
*/
2013-04-08 14:48:45 +02:00
static function fckEditorQuick ( $_name , $_mode , $_content = '' , $_height = '400px' , $_width = '100%' , $_purify = true , $_border = '0px' , $_focusToBody = false , $_executeJSAfterInit = '' )
2007-04-14 18:57:57 +02:00
{
2008-03-09 15:35:48 +01:00
if ( ! self :: htmlarea_availible () || $_mode == 'ascii' )
2007-12-23 08:39:56 +01:00
{
2012-08-15 16:55:02 +02:00
//TODO: use self::textarea
return " <textarea name= \" $_name\ " style = \ " " . ( $_width ? " width: " . $_width . ';' : " width:100%; " ) . ( $_height ? " height: " . $_height . ';' : " height:400px; " ) . ( $_border ? " border: " . $_border . ';' : " border:0px; " ) . " \" > $_content </textarea> " ;
2006-11-07 19:18:22 +01:00
}
2007-12-23 08:39:56 +01:00
else
{
2013-04-08 14:48:45 +02:00
return self :: fckEditor ( $_name , $_content , $_mode , array (), $_height , $_width , '' , $_purify , $_focusToBody , $_executeJSAfterInit );
2008-04-15 14:23:32 +02:00
}
2006-11-07 19:18:22 +01:00
}
2008-04-15 14:23:32 +02:00
2005-02-16 14:04:14 +01:00
/**
* represents html ' s input tag
*
* @ param string $name name
* @ param string $value default value of the field
* @ param string $type type , default '' = not specified = text
* @ param string $options attributes for the tag , default '' = none
*/
2008-03-09 15:35:48 +01:00
static function input ( $name , $value = '' , $type = '' , $options = '' )
2004-11-19 07:32:10 +01:00
{
2011-06-04 11:30:46 +02:00
switch (( string ) $type )
2004-11-19 07:32:10 +01:00
{
2011-06-04 11:30:46 +02:00
case 'color' :
return self :: inputColor ( $name , $value , '' , $options );
case '' ;
break ;
default :
2011-06-30 17:19:08 +02:00
$type = 'type="' . htmlspecialchars ( $type ) . '"' ;
2004-11-19 07:32:10 +01:00
}
2008-03-09 15:35:48 +01:00
return " <input $type name= \" $name\ " value = \ " " . self :: htmlspecialchars ( $value ) . " \" $options /> \n " ;
2004-11-19 07:32:10 +01:00
}
2005-11-26 15:25:39 +01:00
2014-02-05 17:25:35 +01:00
static protected $default_background_images = array (
2014-02-12 16:36:47 +01:00
'save' => '/save(&|\]|$)/' ,
'apply' => '/apply(&|\]|$)/' ,
'cancel' => '/cancel(&|\]|$)/' ,
'delete' => '/delete(&|\]|$)/' ,
'edit' => '/edit(&|\]|$)/' ,
'next' => '/(next|continue)(&|\]|$)/' ,
'finish' => '/finish(&|\]|$)/' ,
'back' => '/(back|previous)(&|\]|$)/' ,
'copy' => '/copy(&|\]|$)/' ,
'more' => '/more(&|\]|$)/' ,
'check' => '/(yes|check)(&|\]|$)/' ,
2015-01-09 19:58:23 +01:00
'cancelled' => '/no(&|\]|$)/' ,
2014-02-12 16:36:47 +01:00
'ok' => '/ok(&|\]|$)/' ,
'close' => '/close(&|\]|$)/' ,
'add' => '/(add(&|\]|$)|create)/' , // customfields use create*
);
static protected $default_classes = array (
'et2_button_cancel' => '/cancel(&|\]|$)/' , // yellow
'et2_button_question' => '/(yes|no)(&|\]|$)/' , // yellow
'et2_button_delete' => '/delete(&|\]|$)/' // red
2014-02-05 17:25:35 +01:00
);
2005-02-16 14:04:14 +01:00
/**
2007-01-20 09:54:56 +01:00
* represents html ' s button ( input type submit or input type button or image )
2005-02-16 14:04:14 +01:00
*
* @ param string $name name
* @ param string $label label of the button
* @ param string $onClick javascript to call , when button is clicked
* @ param boolean $no_lang NOT running the label through lang (), default false = use lang ()
* @ param string $options attributes for the tag , default '' = none
* @ param string $image to show instead of the label , default '' = none
* @ param string $app app to search the image in
2007-01-20 09:54:56 +01:00
* @ param string $buttontype which type of html button ( button | submit ), default = 'submit'
2005-02-16 14:04:14 +01:00
* @ return string html
*/
2008-03-09 15:35:48 +01:00
static function submit_button ( $name , $label , $onClick = '' , $no_lang = false , $options = '' , $image = '' , $app = 'phpgwapi' , $buttontype = 'submit' )
2004-11-19 07:32:10 +01:00
{
// workaround for idots and IE button problem (wrong cursor-image)
2008-03-09 15:35:48 +01:00
if ( self :: $user_agent == 'msie' )
2004-11-19 07:32:10 +01:00
{
2006-08-30 16:47:56 +02:00
$options .= ' style="cursor: pointer;"' ;
2004-11-19 07:32:10 +01:00
}
2014-02-13 12:00:29 +01:00
// add et2_classes to "old" buttons
$classes = array ( 'et2_button' );
2004-11-19 07:32:10 +01:00
if ( $image != '' )
{
2004-04-20 19:19:14 +02:00
$image = str_replace ( array ( '.gif' , '.GIF' , '.png' , '.PNG' ), '' , $image );
2005-11-26 15:25:39 +01:00
2014-02-05 17:25:35 +01:00
if ( ! ( $path = common :: image ( $app , $image )))
2003-12-14 18:07:16 +01:00
{
2004-11-19 07:32:10 +01:00
$path = $image ; // name may already contain absolut path
2004-04-20 19:19:14 +02:00
}
$image = ' src="' . $path . '"' ;
2014-02-13 12:00:29 +01:00
$classes [] = 'image_button' ;
}
else
{
2016-01-25 10:43:14 +01:00
$classes [] = 'et2_button_text' ;
2004-11-19 07:32:10 +01:00
}
if ( ! $no_lang )
{
2005-02-16 14:04:14 +01:00
$label = lang ( $label );
2004-11-19 07:32:10 +01:00
}
2006-12-19 08:09:59 +01:00
if (( $accesskey = @ strstr ( $label , '&' )) && $accesskey [ 1 ] != ' ' &&
2006-12-07 13:46:08 +01:00
(( $pos = strpos ( $accesskey , ';' )) === false || $pos > 5 ))
2004-11-19 07:32:10 +01:00
{
2005-02-16 14:04:14 +01:00
$label_u = str_replace ( '&' . $accesskey [ 1 ], '<u>' . $accesskey [ 1 ] . '</u>' , $label );
$label = str_replace ( '&' , '' , $label );
2014-02-11 17:52:45 +01:00
$options .= ' accesskey="' . $accesskey [ 1 ] . '" ' . $options ;
2004-11-19 07:32:10 +01:00
}
else
{
2004-04-20 19:19:14 +02:00
$accesskey = '' ;
2005-02-16 14:04:14 +01:00
$label_u = $label ;
2004-11-19 07:32:10 +01:00
}
2005-02-20 22:47:14 +01:00
if ( $onClick ) $options .= ' onclick="' . str_replace ( '"' , '\\"' , $onClick ) . '"' ;
2005-11-26 15:25:39 +01:00
2014-02-05 17:25:35 +01:00
// add default background-image to get et2 like buttons
foreach ( self :: $default_background_images as $img => $reg_exp )
2004-11-19 07:32:10 +01:00
{
2014-02-05 17:25:35 +01:00
if ( preg_match ( $reg_exp , $name ) && ( $url = common :: image ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ], $img )))
{
2014-02-12 16:36:47 +01:00
$options .= ' style="background-image: url(' . $url . ');"' ;
$classes [] = 'et2_button_with_image' ;
break ;
}
}
// add default class for cancel, delete or yes/no buttons
foreach ( self :: $default_classes as $class => $reg_exp )
{
if ( preg_match ( $reg_exp , $name ))
{
$classes [] = $class ;
2014-02-05 17:25:35 +01:00
break ;
}
2004-11-19 07:32:10 +01:00
}
2014-02-13 12:00:29 +01:00
if ( strpos ( $options , 'class="' ) !== false )
2014-02-12 16:36:47 +01:00
{
2014-02-13 12:00:29 +01:00
$options = str_replace ( 'class="' , 'class="' . implode ( ' ' , $classes ) . ' ' , $options );
2014-02-12 16:36:47 +01:00
}
else
{
$options .= ' class="' . implode ( ' ' , $classes ) . '"' ;
}
2014-02-05 17:25:35 +01:00
return '<button type="' . $buttontype . '" name="' . htmlspecialchars ( $name ) .
'" value="' . htmlspecialchars ( $label ) .
'" ' . $options . '>' .
2008-03-20 09:32:29 +01:00
( $image != '' ? /*self::image($app,$image,$label,$options)*/ '<img' . $image . ' ' . self :: $prefered_img_title . '="' . $label . '"> ' : '' ) .
2014-02-05 17:25:35 +01:00
( $image == '' || $accesskey ? self :: htmlspecialchars ( $label_u ) : '' ) . '</button>' ;
2004-11-19 07:32:10 +01:00
}
2005-11-26 15:25:39 +01:00
2004-11-19 07:32:10 +01:00
/**
2005-02-16 14:04:14 +01:00
* creates an absolut link + the query / get - variables
*
* Example link ( '/index.php?menuaction=infolog.uiinfolog.get_list' , array ( 'info_id' => 123 ))
* gives 'http://domain/phpgw-path/index.php?menuaction=infolog.uiinfolog.get_list&info_id=123'
*
2014-11-21 10:31:39 +01:00
* @ param string $_url egw - relative link , may include query / get - vars
* @ param array | string $vars query or array ( 'name' => 'value' , ... ) with query
2005-02-16 14:04:14 +01:00
* @ return string absolut link already run through $phpgw -> link
*/
2014-11-21 10:31:39 +01:00
static function link ( $_url , $vars = '' )
2004-11-19 07:32:10 +01:00
{
//echo "<p>html::link(url='$url',vars='"; print_r($vars); echo "')</p>\n";
if ( ! is_array ( $vars ))
{
parse_str ( $vars , $vars );
}
2014-11-21 10:31:39 +01:00
list ( $url , $v ) = explode ( '?' , $_url ); // url may contain additional vars
2004-11-19 07:32:10 +01:00
if ( $v )
{
parse_str ( $v , $v );
$vars += $v ;
}
2014-11-21 10:31:39 +01:00
return egw :: link ( $url , $vars );
2004-11-19 07:32:10 +01:00
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* represents html checkbox
*
* @ param string $name name
* @ param boolean $checked box checked on display
* @ param string $value value the var should be set to , default 'True'
2005-02-24 22:01:13 +01:00
* @ param string $options attributes for the tag , default '' = none
2005-02-16 14:04:14 +01:00
* @ return string html
*/
2008-03-09 15:35:48 +01:00
static function checkbox ( $name , $checked = false , $value = 'True' , $options = '' )
2004-11-19 07:32:10 +01:00
{
2008-03-09 15:35:48 +01:00
return '<input type="checkbox" name="' . $name . '" value="' . self :: htmlspecialchars ( $value ) . '"' . ( $checked ? ' checked="1"' : '' ) . " $options /> \n " ;
2004-11-19 07:32:10 +01:00
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* represents a html form
*
* @ param string $content of the form , if '' only the opening tag gets returned
* @ param array $hidden_vars array with name - value pairs for hidden input fields
2014-11-21 10:31:39 +01:00
* @ param string $_url eGW relative URL , will be run through the link function , if empty the current url is used
* @ param string | array $url_vars parameters for the URL , send to link static function too
2005-02-16 14:04:14 +01:00
* @ param string $name name of the form , defaul '' = none
* @ param string $options attributes for the tag , default '' = none
* @ param string $method method of the form , default 'POST'
* @ return string html
*/
2014-11-21 10:31:39 +01:00
static function form ( $content , $hidden_vars , $_url , $url_vars = '' , $name = '' , $options = '' , $method = 'POST' )
2004-11-19 07:32:10 +01:00
{
2014-11-21 10:31:39 +01:00
$url = $_url ? self :: link ( $_url , $url_vars ) : $_SERVER [ 'PHP_SELF' ] . '?' . $_SERVER [ 'QUERY_STRING' ];
2005-05-03 16:55:24 +02:00
$html = " <form method= \" $method\ " " .( $name != '' ? " name = \ " $name\ " " : ''). " action = \ " $url\ " $options > \n " ;
2008-03-09 15:35:48 +01:00
$html .= self :: input_hidden ( $hidden_vars );
2005-11-26 15:25:39 +01:00
2004-11-19 07:32:10 +01:00
if ( $content )
{
$html .= $content ;
$html .= " </form> \n " ;
}
return $html ;
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* represents a html form with one button
*
* @ param string $name name of the button
* @ param string $label label of the button
* @ param array $hidden_vars array with name - value pairs for hidden input fields
* @ param string $url eGW relative URL , will be run through the link function
2014-11-21 10:31:39 +01:00
* @ param string | array $url_vars parameters for the URL , send to link static function too
2005-02-16 14:04:14 +01:00
* @ param string $options attributes for the tag , default '' = none
* @ param string $form_name name of the form , defaul '' = none
* @ param string $method method of the form , default 'POST'
* @ return string html
*/
2008-03-09 15:35:48 +01:00
static function form_1button ( $name , $label , $hidden_vars , $url , $url_vars = '' , $form_name = '' , $method = 'POST' )
2004-11-19 07:32:10 +01:00
{
2014-03-25 13:17:46 +01:00
return self :: form ( self :: submit_button ( $name , $label ), $hidden_vars , $url , $url_vars , $form_name , ' style="display: inline-block"' , $method );
2004-11-19 07:32:10 +01:00
}
2005-11-26 15:25:39 +01:00
2009-02-23 14:21:28 +01:00
const THEAD = 1 ;
const TFOOT = 2 ;
const TBODY = 3 ;
static $part2tag = array (
self :: THEAD => 'thead' ,
self :: TFOOT => 'tfoot' ,
self :: TBODY => 'tbody' ,
);
2004-11-19 07:32:10 +01:00
/**
2005-02-16 14:04:14 +01:00
* creates table from array of rows
*
* abstracts the html stuff for the table creation
* Example : $rows = array (
2009-02-23 14:21:28 +01:00
* 'h1' => array ( // optional header row(s)
* ),
* 'f1' => array ( // optional footer row(s)
* ),
2005-02-16 14:04:14 +01:00
* '1' => array (
* 1 => 'cell1' , '.1' => 'colspan=3' ,
* 2 => 'cell2' ,
* 3 => 'cell3' , '.3' => 'width="10%"'
* ), '.1' => 'BGCOLOR="#0000FF"' );
* table ( $rows , 'width="100%"' ) = '<table width="100%"><tr><td colspan=3>cell1</td><td>cell2</td><td width="10%">cell3</td></tr></table>'
*
* @ param array $rows with rows , each row is an array of the cols
* @ param string $options options for the table - tag
* @ param boolean $no_table_tr dont return the table - and outmost tr - tabs , default false = return table + tr
* @ return string with html - code of the table
*/
2008-03-09 15:35:48 +01:00
static function table ( $rows , $options = '' , $no_table_tr = False )
2004-11-19 07:32:10 +01:00
{
$html = $no_table_tr ? '' : " <table $options > \n " ;
2005-11-26 15:25:39 +01:00
2009-02-23 14:21:28 +01:00
$part = 0 ;
2004-11-19 07:32:10 +01:00
foreach ( $rows as $key => $row )
{
if ( ! is_array ( $row ))
2003-12-14 18:07:16 +01:00
{
2004-11-19 07:32:10 +01:00
continue ; // parameter
2003-12-14 18:07:16 +01:00
}
2009-02-23 14:21:28 +01:00
// get the current part from the optional 'h' or 'f' prefix of the key
$p = $key [ 0 ] == 'h' ? html :: THEAD : ( $key [ 0 ] == 'f' ? html :: TFOOT : html :: TBODY );
if ( $part < $p && ( $part || $p < self :: TBODY )) // add only allowed and neccessary transitions
{
if ( $part ) $html .= '</' . self :: $part2tag [ $part ] . " > \n " ;
$html .= '<' . self :: $part2tag [ $part = $p ] . " > \n " ;
}
2004-11-19 07:32:10 +01:00
$html .= $no_table_tr && $key == 1 ? '' : " \t <tr " . $rows [ '.' . $key ] . " > \n " ;
2005-11-26 15:25:39 +01:00
2004-11-19 07:32:10 +01:00
foreach ( $row as $key => $cell )
2003-12-14 18:07:16 +01:00
{
2004-11-19 07:32:10 +01:00
if ( $key [ 0 ] == '.' )
{
continue ; // parameter
}
$table_pos = strpos ( $cell , '<table' );
$td_pos = strpos ( $cell , '<td' );
if ( $td_pos !== False && ( $table_pos === False || $td_pos < $table_pos ))
{
$html .= $cell ;
}
else
{
$html .= " \t \t <td " . $row [ '.' . $key ] . " > $cell </td> \n " ;
}
2003-12-14 18:07:16 +01:00
}
2004-11-19 07:32:10 +01:00
$html .= " \t </tr> \n " ;
}
2005-02-06 16:42:31 +01:00
if ( ! is_array ( $rows ))
{
echo " <p> " . function_backtrace () . " </p> \n " ;
}
2009-02-23 14:21:28 +01:00
if ( $part ) // close current part
{
$html .= " </ " . self :: $part2tag [ $part ] . " > \n " ;
}
2004-11-19 07:32:10 +01:00
$html .= " </table> \n " ;
2005-11-26 15:25:39 +01:00
2004-11-19 07:32:10 +01:00
if ( $no_table_tr )
{
$html = substr ( $html , 0 , - 16 );
}
return $html ;
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* changes a selectbox to submit the form if it gets changed , to be used with the sbox - class
*
* @ param string $sbox html with the select - box
* @ param boolean $no_script if true generate a submit - button if javascript is off
* @ return string html
*/
2008-03-09 15:35:48 +01:00
static function sbox_submit ( $sbox , $no_script = false )
2004-11-19 07:32:10 +01:00
{
$html = str_replace ( '<select' , '<select onchange="this.form.submit()" ' , $sbox );
if ( $no_script )
{
2008-03-09 15:35:48 +01:00
$html .= '<noscript>' . self :: submit_button ( 'send' , '>' ) . '</noscript>' ;
2004-11-19 07:32:10 +01:00
}
return $html ;
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* html - widget showing progessbar with a view div ' s ( html4 only , textual percentage otherwise )
*
2014-11-21 10:31:39 +01:00
* @ param mixed $_percent percent - value , gets casted to int
* @ param string $_title title for the progressbar , default '' = the percentage itself
2005-02-16 14:04:14 +01:00
* @ param string $options attributes for the outmost div ( may include onclick = " ... " )
* @ param string $width width , default 30 px
* @ param string $color color , default '#D00000' ( dark red )
* @ param string $height height , default 5 px
* @ return string html
2005-11-26 15:25:39 +01:00
*/
2014-11-21 10:31:39 +01:00
static function progressbar ( $_percent , $_title = '' , $options = '' , $width = '' , $color = '' , $height = '' )
2004-11-19 07:32:10 +01:00
{
2014-11-21 10:31:39 +01:00
$percent = ( int ) $_percent ;
2004-11-19 07:32:10 +01:00
if ( ! $width ) $width = '30px' ;
if ( ! $height ) $height = '5px' ;
if ( ! $color ) $color = '#D00000' ;
2014-11-21 10:31:39 +01:00
$title = $_title ? self :: htmlspecialchars ( $_title ) : $percent . '%' ;
2005-11-26 15:25:39 +01:00
2008-03-09 15:35:48 +01:00
if ( self :: $netscape4 )
2004-11-19 07:32:10 +01:00
{
return $title ;
}
2006-03-27 00:19:24 +02:00
return '<div class="onlyPrint">' . $title . '</div><div class="noPrint" title="' . $title . '" ' . $options .
2005-04-12 18:30:16 +02:00
' style="height: ' . $height . '; width: ' . $width . '; border: 1px solid black; padding: 1px; text-align: left;' .
2006-12-19 08:09:59 +01:00
( @ stristr ( $options , 'onclick="' ) ? ' cursor: pointer;' : '' ) . '">' . " \n \t " .
2004-11-19 07:32:10 +01:00
'<div style="height: ' . $height . '; width: ' . $percent . '%; background: ' . $color . ';"></div>' . " \n </div> \n " ;
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* representates a html img tag , output a picture
*
* If the name ends with a '%' and the rest is numeric , a progressionbar is shown instead of an image .
* The vfs :/ pseudo protocoll allows to access images in the vfs , eg . vfs :/ home / ralf / me . png
* Instead of a name you specify an array with get - vars , it is passed to eGW ' s link function .
* This way session - information gets passed , eg . $name = array ( 'menuaction' => 'myapp.class.image' , 'id' => 123 ) .
*
* @ param string $app app - name to search the image
2014-11-21 10:31:39 +01:00
* @ param string | array $name image - name or URL ( incl . vfs :/ ) or array with get - vars
2005-02-16 14:04:14 +01:00
* @ param string $title tooltip , default '' = none
* @ param string $options further options for the tag , default '' = none
* @ return string the html
*/
2008-03-09 15:35:48 +01:00
static function image ( $app , $name , $title = '' , $options = '' )
2004-11-19 07:32:10 +01:00
{
2005-02-16 14:04:14 +01:00
if ( is_array ( $name )) // menuaction and other get-vars
2004-11-19 07:32:10 +01:00
{
2005-11-26 15:25:39 +01:00
$name = $GLOBALS [ 'egw' ] -> link ( '/index.php' , $name );
2004-11-19 07:32:10 +01:00
}
2009-06-08 18:21:14 +02:00
if ( substr ( $name , 0 , 5 ) == 'vfs:/' ) // vfs pseudo protocoll
{
2009-11-28 11:31:20 +01:00
$name = egw :: link ( egw_vfs :: download_url ( substr ( $name , 4 )));
2009-06-08 18:21:14 +02:00
}
2009-05-13 16:33:36 +02:00
if ( $name [ 0 ] == '/' || substr ( $name , 0 , 7 ) == 'http://' || substr ( $name , 0 , 8 ) == 'https://' || stripos ( $name , 'etemplate/thumbnail.php' ) )
2004-11-19 07:32:10 +01:00
{
2009-05-13 16:33:36 +02:00
if ( ! ( $name [ 0 ] == '/' || substr ( $name , 0 , 7 ) == 'http://' || substr ( $name , 0 , 8 ) == 'https://' )) $name = '/' . $name ;
2005-02-16 14:04:14 +01:00
$url = $name ;
2004-11-19 07:32:10 +01:00
}
2005-02-16 14:04:14 +01:00
else // no URL, so try searching the image
2004-11-19 07:32:10 +01:00
{
2005-02-16 14:04:14 +01:00
$name = str_replace ( array ( '.gif' , '.GIF' , '.png' , '.PNG' ), '' , $name );
2005-11-26 15:25:39 +01:00
if ( ! ( $url = $GLOBALS [ 'egw' ] -> common -> image ( $app , $name )))
2004-05-07 23:21:20 +02:00
{
2005-02-16 14:04:14 +01:00
$url = $name ; // name may already contain absolut path
}
2006-06-01 05:48:06 +02:00
if ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ])
2005-02-16 14:04:14 +01:00
{
2006-06-01 05:48:06 +02:00
list (, $path ) = explode ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ], $url );
2006-06-06 07:33:10 +02:00
if ( ! is_null ( $path )) $path = EGW_SERVER_ROOT . $path ;
2005-02-16 14:04:14 +01:00
}
2006-06-01 05:48:06 +02:00
else
{
$path = EGW_SERVER_ROOT . $url ;
}
2008-04-15 14:23:32 +02:00
2009-05-13 16:33:36 +02:00
if ( is_null ( $path ) || ( !@ is_readable ( $path ) && stripos ( $path , 'webdav.php' ) === false ))
2005-02-16 14:04:14 +01:00
{
// if the image-name is a percentage, use a progressbar
if ( substr ( $name , - 1 ) == '%' && is_numeric ( $percent = substr ( $name , 0 , - 1 )))
{
2008-03-09 15:35:48 +01:00
return self :: progressbar ( $percent , $title );
2005-02-16 14:04:14 +01:00
}
return $title ;
2004-10-08 01:09:52 +02:00
}
2004-11-19 07:32:10 +01:00
}
if ( $title )
{
2008-03-20 09:32:29 +01:00
$options .= ' ' . self :: $prefered_img_title . '="' . self :: htmlspecialchars ( $title ) . '"' ;
2004-11-19 07:32:10 +01:00
}
2008-01-09 19:15:42 +01:00
// This block makes pngfix.js useless, adding a check on disable_pngfix to have pngfix.js do its thing
2008-07-21 16:40:54 +02:00
if ( self :: $user_agent == 'msie' && self :: $ua_version < 7.0 && substr ( $url , - 4 ) == '.png' && ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'disable_pngfix' ] || ! isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'disable_pngfix' ])))
2007-01-12 02:24:05 +01:00
{
$extra_styles = " display: inline-block; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=' $url ',sizingMethod='image'); width: 1px; height: 1px; " ;
2007-02-28 07:06:35 +01:00
if ( false !== strpos ( $options , 'style="' ))
2007-01-12 02:24:05 +01:00
{
2007-02-27 07:41:36 +01:00
$options = str_replace ( 'style="' , 'style="' . $extra_styles , $options );
2007-01-12 02:24:05 +01:00
}
else
{
$options .= ' style="' . $extra_styles . '"' ;
}
return " <span $options ></span> " ;
}
2005-02-16 14:04:14 +01:00
return " <img src= \" $url\ " $options /> " ;
2004-11-19 07:32:10 +01:00
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* representates a html link
*
* @ param string $content of the link , if '' only the opening tag gets returned
* @ param string $url eGW relative URL , will be run through the link function
2014-11-21 10:31:39 +01:00
* @ param string | array $vars parameters for the URL , send to link static function too
2005-02-16 14:04:14 +01:00
* @ param string $options attributes for the tag , default '' = none
* @ return string the html
*/
2008-03-09 15:35:48 +01:00
static function a_href ( $content , $url , $vars = '' , $options = '' )
2004-11-19 07:32:10 +01:00
{
if ( is_array ( $url ))
{
$vars = $url ;
$url = '/index.php' ;
}
2008-04-15 14:23:32 +02:00
elseif ( strpos ( $url , '/' ) === false &&
count ( explode ( '.' , $url )) >= 3 &&
! ( strpos ( $url , 'mailto:' ) !== false ||
strpos ( $url , '://' ) !== false ||
2006-12-07 13:46:08 +01:00
strpos ( $url , 'javascript:' ) !== false ))
2006-04-30 20:04:14 +02:00
{
$url = " /index.php?menuaction= $url " ;
}
2009-05-19 21:23:38 +02:00
if ( $url [ 0 ] == '/' ) // link relative to eGW
2006-04-30 20:04:14 +02:00
{
2008-03-09 15:35:48 +01:00
$url = self :: link ( $url , $vars );
2006-04-30 20:04:14 +02:00
}
2011-08-26 10:21:04 +02:00
//echo "<p>html::a_href('".self::htmlspecialchars($content)."','$url',".print_r($vars,True).") = ".self::link($url,$vars)."</p>";
return '<a href="' . self :: htmlspecialchars ( $url ) . '" ' . $options . '>' . $content . '</a>' ;
2004-11-19 07:32:10 +01:00
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* representates a b tab ( bold )
*
* @ param string $content of the link , if '' only the opening tag gets returned
* @ return string the html
*/
2008-03-09 15:35:48 +01:00
static function bold ( $content )
2004-11-19 07:32:10 +01:00
{
return '<b>' . $content . '</b>' ;
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* representates a i tab ( bold )
*
* @ param string $content of the link , if '' only the opening tag gets returned
* @ return string the html
*/
2008-03-09 15:35:48 +01:00
static function italic ( $content )
2004-11-19 07:32:10 +01:00
{
return '<i>' . $content . '</i>' ;
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* representates a hr tag ( horizontal rule )
*
* @ param string $width default '' = none given
* @ param string $options attributes for the tag , default '' = none
* @ return string the html
*/
2008-03-09 15:35:48 +01:00
static function hr ( $width = '' , $options = '' )
2004-11-19 07:32:10 +01:00
{
if ( $width ) $options .= " width= \" $width\ " " ;
return " <hr $options /> \n " ;
}
2005-11-26 15:25:39 +01:00
2004-11-19 07:32:10 +01:00
/**
2005-02-16 14:04:14 +01:00
* formats option - string for most of the above functions
*
* Example : formatOptions ( '100%,,1' , 'width,height,border' ) = ' width="100%" border="1"'
*
* @ param mixed $options String ( or Array ) with option - values eg . '100%,,1'
* @ param mixed $names String ( or Array ) with the option - names eg . 'WIDTH,HEIGHT,BORDER'
* @ return string with options / attributes
*/
2008-03-09 15:35:48 +01:00
static function formatOptions ( $options , $names )
2004-11-19 07:32:10 +01:00
{
if ( ! is_array ( $options )) $options = explode ( ',' , $options );
if ( ! is_array ( $names )) $names = explode ( ',' , $names );
2005-11-26 15:25:39 +01:00
2004-11-19 07:32:10 +01:00
foreach ( $options as $n => $val )
{
if ( $val != '' && $names [ $n ] != '' )
{
$html .= ' ' . strtolower ( $names [ $n ]) . '="' . $val . '"' ;
2003-12-14 18:07:16 +01:00
}
2004-11-19 07:32:10 +01:00
}
return $html ;
}
2005-11-26 15:25:39 +01:00
2004-11-19 07:32:10 +01:00
/**
2005-02-16 14:04:14 +01:00
* returns simple stylesheet ( incl . < STYLE > tags ) for nextmatch row - colors
*
* @ deprecated included now always by the framework
* @ return string classes 'th' = nextmatch header , 'row_on' + 'row_off' = alternating rows
*/
2008-03-09 15:35:48 +01:00
static function themeStyles ()
2004-11-19 07:32:10 +01:00
{
2008-03-09 15:35:48 +01:00
return self :: style ( self :: theme2css ());
2004-11-19 07:32:10 +01:00
}
2005-11-26 15:25:39 +01:00
2004-11-19 07:32:10 +01:00
/**
2005-02-16 14:04:14 +01:00
* returns simple stylesheet for nextmatch row - colors
*
* @ deprecated included now always by the framework
* @ return string classes 'th' = nextmatch header , 'row_on' + 'row_off' = alternating rows
*/
2008-03-09 15:35:48 +01:00
static function theme2css ()
2004-11-19 07:32:10 +01:00
{
2005-11-26 15:25:39 +01:00
return " .th { background: " . $GLOBALS [ 'egw_info' ][ 'theme' ][ 'th_bg' ] . " ; } \n " .
" .row_on,.th_bright { background: " . $GLOBALS [ 'egw_info' ][ 'theme' ][ 'row_on' ] . " ; } \n " .
" .row_off { background: " . $GLOBALS [ 'egw_info' ][ 'theme' ][ 'row_off' ] . " ; } \n " ;
2004-11-19 07:32:10 +01:00
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* html style tag ( incl . type )
*
* @ param string $styles css - style definitions
* @ return string html
*/
2008-03-09 15:35:48 +01:00
static function style ( $styles )
2004-11-19 07:32:10 +01:00
{
return $styles ? " <style type= \" text/css \" > \n <!-- \n $styles\n --> \n </style> " : '' ;
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* html label tag
*
* @ param string $content the label
* @ param string $id for the for attribute , default '' = none
* @ param string $accesskey accesskey , default '' = none
* @ param string $options attributes for the tag , default '' = none
* @ return string the html
2005-11-26 15:25:39 +01:00
*/
2008-03-09 15:35:48 +01:00
static function label ( $content , $id = '' , $accesskey = '' , $options = '' )
2004-11-19 07:32:10 +01:00
{
if ( $id != '' )
{
$id = " for= \" $id\ " " ;
}
if ( $accesskey != '' )
{
$accesskey = " accesskey= \" $accesskey\ " " ;
}
return " <label $id $accesskey $options > $content </label> " ;
}
2005-11-26 15:25:39 +01:00
2005-02-16 14:04:14 +01:00
/**
* html fieldset , eg . groups a group of radiobuttons
*
* @ param string $content the content
* @ param string $legend legend / label of the fieldset , default '' = none
* @ param string $options attributes for the tag , default '' = none
* @ return string the html
2005-11-26 15:25:39 +01:00
*/
2008-03-09 15:35:48 +01:00
static function fieldset ( $content , $legend = '' , $options = '' )
2005-02-06 16:42:31 +01:00
{
2008-03-09 15:35:48 +01:00
$html = " <fieldset $options > " . ( $legend ? '<legend>' . self :: htmlspecialchars ( $legend ) . '</legend>' : '' ) . " \n " ;
2005-11-26 15:25:39 +01:00
2005-02-06 16:42:31 +01:00
if ( $content )
{
$html .= $content ;
$html .= " \n </fieldset> \n " ;
}
return $html ;
2005-11-26 15:25:39 +01:00
}
2008-04-15 14:23:32 +02:00
2006-03-19 18:55:36 +01:00
/**
2010-10-15 18:19:31 +02:00
* tree widget using dhtmlXtree
*
* Code inspired by Lars ' s Felamimail uiwidgets :: createFolderTree ()
*
* @ author Lars Kneschke < lars - AT - kneschke . de > original code in felamimail
* @ param array $_folders array of folders : pairs path => node ( string label or array with keys : label , ( optional ) image , ( optional ) title , ( optional ) checked )
* @ param string $_selected path of selected folder
2014-11-21 10:31:39 +01:00
* @ param mixed $_topFolder = false node of topFolder or false for none
* @ param string $_onNodeSelect = 'alert' js static function to call if node gets selected
* @ param string $tree = 'foldertree' id of the div and name of the variable containing the tree object
* @ param string $_divClass = '' css class of the div
* @ param string $_leafImage = '' default image of a leaf - node , '' = default of foldertree , set it eg . 'folderClosed.gif' to show leafs as folders
* @ param boolean | string $_onCheckHandler = false string with handler - name to display a checkbox for each folder , or false ( default ), 'null' switches checkboxes on without an handler !
* @ param string $delimiter = '/' path - delimiter , default /
* @ param string $folderImageDir = null string path to the tree menu images , null uses default path
* @ param string | array $autoLoading = null EGw relative path or array with get parameter , both send through egw :: link
* @ param string $dataMode = 'JSON' data type for autoloading : XML , JSON , CSV
* @ param boolean $dragndrop = false true to enable drag - n - drop ( must be before autoloading get enabled ! )
2010-10-15 18:19:31 +02:00
*
* @ return string the html code , to be added into the template
*/
static function tree ( $_folders , $_selected , $_topFolder = false , $_onNodeSelect = " null " , $tree = 'foldertree' , $_divClass = '' ,
2010-12-28 03:59:03 +01:00
$_leafImage = '' , $_onCheckHandler = false , $delimiter = '/' , $folderImageDir = null , $autoLoading = null , $dataMode = 'JSON' ,
$dragndrop = false )
2006-03-19 18:55:36 +01:00
{
2013-11-15 17:28:24 +01:00
$webserver_url = $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ];
if ( empty ( $folderImageDir ))
2007-07-22 15:23:44 +02:00
{
2013-11-15 17:28:24 +01:00
$folderImageDir = $webserver_url . '/phpgwapi/templates/default/images' ;
}
// check if we have template-set specific image path
$image_path = $folderImageDir ;
if ( $webserver_url && $webserver_url != '/' )
{
list (, $image_path ) = explode ( $webserver_url , $image_path , 2 );
}
$templated_path = strtr ( $image_path , array (
'/phpgwapi/templates/default' => $GLOBALS [ 'egw' ] -> framework -> template_dir ,
'/default/' => '/' . $GLOBALS [ 'egw' ] -> framework -> template . '/' ,
));
2013-11-18 23:05:04 +01:00
if ( file_exists ( EGW_SERVER_ROOT . $templated_path . '/dhtmlxtree' ))
2013-11-15 17:28:24 +01:00
{
$folderImageDir = ( $webserver_url != '/' ? $webserver_url : '' ) . $templated_path ;
//error_log(__METHOD__."() setting templated image-path: $folderImageDir");
2007-07-22 15:23:44 +02:00
}
2007-01-03 00:26:53 +01:00
2006-03-19 18:55:36 +01:00
static $tree_initialised = false ;
if ( ! $tree_initialised )
{
2014-06-03 10:17:43 +02:00
egw_framework :: includeCSS ( '/phpgwapi/js/dhtmlxtree/codebase/dhtmlxtree.css' );
egw_framework :: validate_file ( '/phpgwapi/js/dhtmlxtree/codebase/dhtmlxcommon.js' );
egw_framework :: validate_file ( '/phpgwapi/js/dhtmlxtree/sources/dhtmlxtree.js' );
if ( $autoLoading && $dataMode != 'XML' ) egw_framework :: validate_file ( '/phpgwapi/js/dhtmlxtree/sources/ext/dhtmlxtree_json.js' );
2006-03-19 18:55:36 +01:00
$tree_initialised = true ;
2014-02-18 20:21:34 +01:00
if ( ! $_folders && ! $autoLoading ) return null ;
2006-03-19 18:55:36 +01:00
}
2010-06-04 22:06:41 +02:00
$html = self :: div ( " \n " , 'id="' . $tree . '"' , $_divClass ) . $html ;
2006-03-19 18:55:36 +01:00
$html .= " <script type='text/javascript'> \n " ;
2013-04-02 15:36:58 +02:00
$html .= " var $tree ; " ;
2013-07-17 14:47:21 +02:00
$html .= " egw_LAB.wait(function() { " ;
2013-04-02 15:36:58 +02:00
$html .= " $tree = new dhtmlXTreeObject(' $tree ','100%','100%',0); \n " ;
2010-10-18 14:19:38 +02:00
$html .= " $tree .parentObject.style.overflow='auto'; \n " ; // dhtmlXTree constructor has hidden hardcoded
2010-10-15 18:19:31 +02:00
if ( translation :: charset () == 'utf-8' ) $html .= " if ( $tree .setEscapingMode) $tree .setEscapingMode('utf8'); \n " ;
2007-07-22 15:23:44 +02:00
$html .= " $tree .setImagePath(' $folderImageDir /dhtmlxtree/'); \n " ;
2010-12-19 22:54:37 +01:00
2006-03-19 18:55:36 +01:00
if ( $_onCheckHandler )
{
2007-07-22 15:23:44 +02:00
$html .= " $tree .enableCheckBoxes(1); \n " ;
$html .= " $tree .setOnCheckHandler(' $_onCheckHandler '); \n " ;
2006-03-19 18:55:36 +01:00
}
2008-04-15 14:23:32 +02:00
2010-12-28 03:59:03 +01:00
if ( $dragndrop ) $html .= " $tree .enableDragAndDrop(true); \n " ;
2010-10-15 18:19:31 +02:00
if ( $autoLoading )
{
2010-12-19 22:54:37 +01:00
$autoLoading = is_array ( $autoLoading ) ?
2010-10-15 18:19:31 +02:00
egw :: link ( '/index.php' , $autoLoading ) : egw :: link ( $autoLoading );
$html .= " $tree .setXMLAutoLoading(' $autoLoading '); \n " ;
if ( $dataMode != 'XML' ) $html .= " $tree .setDataMode(' $dataMode '); \n " ;
2010-12-19 22:54:37 +01:00
2010-10-15 18:19:31 +02:00
// if no folders given, use xml url to load root, incl. setting of selected folder
if ( ! $_folders )
{
if ( $_selected ) $autoLoading .= '&selected=' . urlencode ( $_selected );
unset ( $_selected );
$html .= " $tree .loadXML(' $autoLoading '); \n " ;
2013-04-02 15:36:58 +02:00
$html .= " }); " ;
2010-10-15 18:19:31 +02:00
return $html . " </script> \n " ;
}
}
2006-03-19 18:55:36 +01:00
$top = 0 ;
if ( $_topFolder )
{
$top = '--topfolder--' ;
$topImage = '' ;
if ( is_array ( $_topFolder ))
{
$label = $_topFolder [ 'label' ];
if ( isset ( $_topFolder [ 'image' ]))
{
$topImage = $_topFolder [ 'image' ];
}
}
else
{
$label = $_topFolder ;
2008-04-15 14:23:32 +02:00
}
2007-07-22 15:23:44 +02:00
$html .= " \n $tree .insertNewItem(0,' $top ',' " . addslashes ( $label ) . " ', $_onNodeSelect ,' $topImage ',' $topImage ',' $topImage ','CHILD,TOP'); \n " ;
2006-03-19 18:55:36 +01:00
if ( is_array ( $_topFolder ) && isset ( $_topFolder [ 'title' ]))
{
2007-07-22 15:23:44 +02:00
$html .= " $tree .setItemText(' $top ',' " . addslashes ( $label ) . " ',' " . addslashes ( $_topFolder [ 'title' ]) . " '); \n " ;
2006-03-19 18:55:36 +01:00
}
}
2010-10-15 18:19:31 +02:00
if ( is_string ( $_folders ))
2006-03-19 18:55:36 +01:00
{
2010-10-15 18:19:31 +02:00
switch ( $dataMode )
2006-03-19 18:55:36 +01:00
{
2010-10-15 18:19:31 +02:00
case 'JSON' :
$html .= " $tree .loadJSONObject( $_folders ); \n " ; break ;
case 'XML' :
$html .= " $tree .loadXMLString(' $_folders '); \n " ; break ;
2006-03-19 18:55:36 +01:00
}
2010-10-15 18:19:31 +02:00
}
else
{
2006-03-19 18:55:36 +01:00
// evtl. remove leading delimiter
2010-10-15 18:19:31 +02:00
if ( $_selected [ 0 ] == $delimiter ) $_selected = substr ( $_selected , 1 );
2010-12-19 22:54:37 +01:00
2010-10-15 18:19:31 +02:00
$n = 0 ;
foreach ( $_folders as $path => $data )
2006-03-19 18:55:36 +01:00
{
2010-10-15 18:19:31 +02:00
if ( ! is_array ( $data ))
{
$data = array ( 'label' => $data );
}
$image1 = $image2 = $image3 = '0' ;
2010-12-19 22:54:37 +01:00
2010-10-15 18:19:31 +02:00
// if _leafImage given, set it only for leaves, not for folders containing children
if ( $_leafImage )
{
$image1 = $image2 = $image3 = " ' " . $_leafImage . " ' " ;
2014-02-18 20:21:34 +01:00
if (( $next_item = array_slice ( $_folders , $n + 1 , 1 , true )))
2010-10-15 18:19:31 +02:00
{
list ( $next_path ) = each ( $next_item );
if ( substr ( $next_path , 0 , strlen ( $path ) + 1 ) == $path . '/' )
{
$image1 = $image2 = $image3 = '0' ;
}
}
}
if ( isset ( $data [ 'image' ]))
{
$image1 = $image2 = $image3 = " ' " . $data [ 'image' ] . " ' " ;
}
// evtl. remove leading delimiter
if ( $path [ 0 ] == $delimiter ) $path = substr ( $path , 1 );
$folderParts = explode ( $delimiter , $path );
2010-12-19 22:54:37 +01:00
2010-10-15 18:19:31 +02:00
//get rightmost folderpart
$label = array_pop ( $folderParts );
if ( isset ( $data [ 'label' ])) $label = $data [ 'label' ];
2010-12-19 22:54:37 +01:00
2010-10-15 18:19:31 +02:00
// the rest of the array is the name of the parent
$parentName = implode (( array ) $folderParts , $delimiter );
if ( empty ( $parentName )) $parentName = $top ;
2010-12-19 22:54:37 +01:00
2010-10-15 18:19:31 +02:00
$entryOptions = ! isset ( $data [ 'child' ]) || $data [ 'child' ] ? 'CHILD' : '' ;
if ( $_onCheckHandler && $_selected ) // check selected items on multi selection
{
if ( ! is_array ( $_selected )) $_selected = explode ( ',' , $_selected );
2012-01-09 15:45:24 +01:00
if ( array_search ( " $path " , $_selected ) !== false ) $entryOptions .= ',CHECKED' ;
2010-10-15 18:19:31 +02:00
//echo "<p>path=$path, _selected=".print_r($_selected,true).": $entryOptions</p>\n";
}
// highlight current item
elseif (( string ) $_selected === ( string ) $path )
{
$entryOptions .= ',SELECT' ;
}
$html .= " $tree .insertNewItem(' " . addslashes ( $parentName ) . " ',' " . addslashes ( $path ) . " ',' " . addslashes ( $label ) .
" ', $_onNodeSelect , $image1 , $image2 , $image3 ,' $entryOptions '); \n " ;
if ( isset ( $data [ 'title' ]))
{
$html .= " $tree .setItemText(' " . addslashes ( $path ) . " ',' " . addslashes ( $label ) . " ',' " . addslashes ( $data [ 'title' ]) . " '); \n " ;
}
++ $n ;
2006-03-19 18:55:36 +01:00
}
2007-07-22 15:23:44 +02:00
}
$html .= " $tree .closeAllItems(0); \n " ;
if ( $_selected )
{
foreach ( is_array ( $_selected ) ? $_selected : array ( $_selected ) as $path )
2006-03-19 18:55:36 +01:00
{
2007-07-22 15:23:44 +02:00
$html .= " $tree .openItem(' " . addslashes ( $path ) . " '); \n " ;
2006-03-19 18:55:36 +01:00
}
}
2007-07-22 15:23:44 +02:00
else
{
$html .= " $tree .openItem(' $top '); \n " ;
}
2013-04-02 15:36:58 +02:00
$html .= " }); " ;
2006-03-19 18:55:36 +01:00
$html .= " </script> \n " ;
2008-04-15 14:23:32 +02:00
2006-03-19 18:55:36 +01:00
return $html ;
}
2009-05-19 19:32:06 +02:00
/**
* Runs HTMLPurifier over supplied html to remove malicious code
*
* @ param string $html
2014-11-21 10:31:39 +01:00
* @ param array | string $config = null - config to influence the behavior of current purifying engine
* @ param array | string $spec = null - spec to influence the behavior of current purifying engine
2013-10-10 11:23:55 +02:00
* The $spec argument can be used to disallow an otherwise legal attribute for an element ,
* or to restrict the attribute ' s values
2014-11-21 10:31:39 +01:00
* @ param boolean $_force = null - force the config passed to be used without merging to the default
2009-05-19 19:32:06 +02:00
*/
2012-05-25 14:23:11 +02:00
static function purify ( $html , $config = null , $spec = array (), $_force = false )
2009-05-19 19:32:06 +02:00
{
2012-05-25 14:23:11 +02:00
$defaultConfig = array ( 'valid_xhtml' => 1 , 'safe' => 1 );
2012-12-11 00:10:58 +01:00
2009-05-19 21:23:38 +02:00
if ( empty ( $html )) return $html ; // no need to process further
2013-10-10 11:23:55 +02:00
if ( ! empty ( $config ) && is_string ( $config ))
{
2013-10-10 11:25:04 +02:00
//error_log(__METHOD__.__LINE__.$config);
2013-10-10 11:23:55 +02:00
$config = json_decode ( $config , true );
if ( is_null ( $config )) error_log ( __METHOD__ . __LINE__ . " decoding of config failed; standard will be applied " );
}
2012-12-11 00:10:58 +01:00
// User preferences
$font = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'rte_font' ];
$font_size = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'rte_font_size' ];
2013-02-21 12:32:46 +01:00
2012-12-11 00:10:58 +01:00
// Check for "blank" = just user preference span - for some reason we can't match on the entity, so approximate
2012-12-11 16:31:35 +01:00
$regex = '#^<span style="font-family:' . $font . ';font-size:' . $font_size . ';">.?</span>$#us' ;
if ( preg_match ( $regex , $html ))
2012-12-11 00:10:58 +01:00
{
return '' ;
}
2012-05-25 14:23:11 +02:00
$htmLawed = new egw_htmLawed ();
if ( is_array ( $config ) && $_force === false ) $config = array_merge ( $defaultConfig , $config );
if ( empty ( $config )) $config = $defaultConfig ;
//error_log(__METHOD__.__LINE__.array2string($config));
return $htmLawed -> egw_htmLawed ( $html , $config , $spec );
2009-05-19 19:32:06 +02:00
}
2009-10-11 13:37:46 +02:00
/**
2015-02-14 20:32:21 +01:00
* Output content headers for user - content , mitigating risk of javascript or html
*
* Mitigate risk of serving javascript or css from our domain ,
* which will get around same origin policy and CSP !
*
* Mitigate risk of html downloads by using CSP or force download for IE
*
* @ param resource | string & $content content might be changed by this call
* @ param string $path filename or path for content - disposition header
* @ param string & $mime = '' mimetype or '' ( default ) to detect it from filename , using mime_magic :: filename2mime ()
* on return used , maybe changed , mime - type
* @ param int $length = 0 content length , default 0 = skip that header
* on return changed size
* @ param boolean $nocache = true send headers to disallow browser / proxies to cache the download
* @ param boolean $force_download = true send content - disposition attachment header
* @ param boolean $no_content_type = false do not send actual content - type and content - length header , just content - disposition
*/
public static function safe_content_header ( & $content , $path , & $mime = '' , & $length = 0 , $nocache = true , $force_download = true , $no_content_type = false )
{
2015-10-20 18:22:08 +02:00
// change old/aliased mime-types to new one, eg. image/pdf to application/pdf
$mime = mime_magic :: fix_mime_type ( $mime );
2015-02-14 20:32:21 +01:00
// mitigate risk of serving javascript or css via webdav from our domain,
// which will get around same origin policy and CSP
list ( $type , $subtype ) = explode ( '/' , strtolower ( $mime ));
if ( ! $force_download && in_array ( $type , array ( 'application' , 'text' )) &&
in_array ( $subtype , array ( 'javascript' , 'x-javascript' , 'ecmascript' , 'jscript' , 'vbscript' , 'css' )))
{
// unfortunatly only Chrome and IE >= 8 allow to switch content-sniffing off with X-Content-Type-Options: nosniff
if ( html :: $user_agent == 'chrome' || html :: $user_agent == 'msie' && html :: $ua_version >= 8 )
{
$mime = 'text/plain' ;
header ( 'X-Content-Type-Options: nosniff' ); // stop IE & Chrome from content-type sniffing
}
// for the rest we change mime-type to text/html and let code below handle it safely
// this stops Safari and Firefox from using it as src attribute in a script tag
// but only for "real" browsers, we dont want to modify data for our WebDAV clients
elseif ( isset ( $_SERVER [ 'HTTP_REFERER' ]))
{
$mime = 'text/html' ;
if ( is_resource ( $content ))
{
$data = fread ( $content , $length );
fclose ( $content );
$content =& $data ;
unset ( $data );
}
$content = '<pre>' . $content ;
$length += 5 ;
}
}
// mitigate risk of html downloads by using CSP or force download for IE
if ( ! $force_download && in_array ( $mime , array ( 'text/html' , 'application/xhtml+xml' )))
{
// use CSP only for current user-agents/versions I was able to positivly test
if ( html :: $user_agent == 'chrome' && html :: $ua_version >= 24 ||
// mobile FF 24 on Android does NOT honor CSP!
html :: $user_agent == 'firefox' && ! html :: $ua_mobile && html :: $ua_version >= 24 ||
html :: $user_agent == 'safari' && ! html :: $ua_mobile && html :: $ua_version >= 536 || // OS X
html :: $user_agent == 'safari' && html :: $ua_mobile && html :: $ua_version >= 9537 ) // iOS 7
{
$csp = " script-src 'none' " ; // forbid to execute any javascript
header ( " Content-Security-Policy: $csp " );
header ( " X-Webkit-CSP: $csp " ); // Chrome: <= 24, Safari incl. iOS
//header("X-Content-Security-Policy: $csp"); // FF <= 22
//error_log(__METHOD__."('$options[path]') ".html::$user_agent.'/'.html::$ua_version.(html::$ua_mobile?'/mobile':'').": using Content-Security-Policy: $csp");
}
else // everything else get's a Content-dispostion: attachment, to be on save side
{
//error_log(__METHOD__."('$options[path]') ".html::$user_agent.'/'.html::$ua_version.(html::$ua_mobile?'/mobile':'').": using Content-disposition: attachment");
$force_download = true ;
}
}
if ( $no_content_type )
{
if ( $force_download ) self :: content_disposition_header ( egw_vfs :: basename ( $path ), $force_download );
}
else
{
self :: content_header ( egw_vfs :: basename ( $path ), $mime , $length , $nocache , $force_download );
}
}
/**
* Output content - type headers for file downloads
*
* This function should only be used for non - user supplied content !
* For uploaded files , mail attachmentes , etc , you have to use safe_content_header !
2009-10-11 13:37:46 +02:00
*
* @ author Miles Lott originally in browser class
* @ param string $fn filename
2014-11-21 10:31:39 +01:00
* @ param string $mime = '' mimetype or '' ( default ) to detect it from filename , using mime_magic :: filename2mime ()
* @ param int $length = 0 content length , default 0 = skip that header
* @ param boolean $nocache = true send headers to disallow browser / proxies to cache the download
* @ param boolean $forceDownload = true send headers to handle as attachment / download
2009-10-11 13:37:46 +02:00
*/
2014-02-25 16:48:23 +01:00
public static function content_header ( $fn , $mime = '' , $length = 0 , $nocache = True , $forceDownload = true )
2009-10-11 13:37:46 +02:00
{
// if no mime-type is given or it's the default binary-type, guess it from the extension
if ( empty ( $mime ) || $mime == 'application/octet-stream' )
{
$mime = mime_magic :: filename2mime ( $fn );
}
if ( $fn )
{
// Show this for all
2014-02-25 16:48:23 +01:00
self :: content_disposition_header ( $fn , $forceDownload );
2009-10-11 13:37:46 +02:00
header ( 'Content-type: ' . $mime );
if ( $length )
{
header ( 'Content-length: ' . $length );
}
if ( $nocache )
{
header ( 'Pragma: no-cache' );
header ( 'Pragma: public' );
header ( 'Expires: 0' );
header ( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' );
}
}
}
2010-08-31 16:23:58 +02:00
2014-02-25 16:48:23 +01:00
/**
* Output content - disposition header for file downloads
*
* @ param string $fn filename
2014-11-21 10:31:39 +01:00
* @ param boolean $forceDownload = true send headers to handle as attachment / download
2014-02-25 16:48:23 +01:00
*/
public static function content_disposition_header ( $fn , $forceDownload = true )
{
2015-04-02 09:19:37 +02:00
if ( $forceDownload )
2015-02-14 20:32:21 +01:00
{
$attachment = ' attachment;' ;
}
else
{
$attachment = ' inline;' ;
}
2014-02-25 16:48:23 +01:00
2015-02-14 20:32:21 +01:00
header ( 'Content-disposition:' . $attachment . ' filename="' . translation :: to_ascii ( $fn ) . '"; filename*=utf-8\'\'' . rawurlencode ( $fn ));
2014-02-25 16:48:23 +01:00
}
2010-08-31 16:23:58 +02:00
/**
* split html by PRE tag , return array with all content pre - sections isolated in array elements
* @ author Leithoff , Klaus
* @ param string html
2010-12-19 22:54:37 +01:00
* @ return mixed array of parts or unaffected html
2010-08-31 16:23:58 +02:00
*/
static function splithtmlByPRE ( $html )
{
2014-10-10 12:10:36 +02:00
$searchFor = '<pre ' ;
$pos = stripos ( $html , $searchFor );
if ( $pos === false )
{
$searchFor = '<pre>' ;
$pos = stripos ( $html , $searchFor );
}
if ( $pos === false )
2010-08-31 16:23:58 +02:00
{
return $html ;
}
$html2ret [] = substr ( $html , 0 , $pos );
while ( $pos !== false )
{
$endofpre = stripos ( $html , '</pre>' , $pos );
$length = $endofpre - $pos + 6 ;
$html2ret [] = substr ( $html , $pos , $length );
2014-10-10 12:10:36 +02:00
$searchFor = '<pre ' ;
$pos = stripos ( $html , $searchFor , $endofpre + 6 );
if ( $pos === false )
{
$searchFor = '<pre>' ;
$pos = stripos ( $html , $searchFor , $endofpre + 6 );
}
2010-08-31 16:23:58 +02:00
$html2ret [] = ( $pos ? substr ( $html , $endofpre + 6 , $pos - ( $endofpre + 6 )) : substr ( $html , $endofpre + 6 ));
//$pos=false;
}
2014-04-29 11:53:47 +02:00
//error_log(__METHOD__.__LINE__.array2string($html2ret));
2010-08-31 16:23:58 +02:00
return $html2ret ;
}
2014-01-18 18:02:29 +01:00
/**
* get all style tag definitions , < style > stuff </ style > of the html passed in
* and remove it from input
* @ author Leithoff , Klaus
* @ param string html
* @ return string the style css
*/
static function getStyles ( & $html )
{
$ct = 0 ;
2014-02-18 20:21:34 +01:00
$newStyle = null ;
2014-01-18 18:02:29 +01:00
if ( stripos ( $html , '<style' ) !== false ) $ct = preg_match_all ( '#<style(?:\s.*)?>(.+)</style>#isU' , $html , $newStyle );
if ( $ct > 0 )
{
//error_log(__METHOD__.__LINE__.array2string($newStyle[0]));
$style2buffer = implode ( '' , $newStyle [ 0 ]);
2014-04-14 17:09:07 +02:00
// only replace what we have found, we use it here, as we use the same routine in translation::replaceTagsCompletley
// no need to do the extra routine
$html = str_ireplace ( $newStyle [ 0 ], '' , $html );
2014-01-18 18:02:29 +01:00
}
if ( $style2buffer )
{
//error_log(__METHOD__.__LINE__.array2string($style2buffer));
$test = json_encode ( $style2buffer );
//error_log(__METHOD__.__LINE__.'#'.$test.'# ->'.strlen($style2buffer).' Error:'.json_last_error());
//if (json_last_error() != JSON_ERROR_NONE && strlen($style2buffer)>0)
if ( $test == " null " && strlen ( $style2buffer ) > 0 )
{
// this should not be needed, unless something fails with charset detection/ wrong charset passed
2014-02-18 20:21:34 +01:00
error_log ( __METHOD__ . __LINE__ . ' Found Invalid sequence for utf-8 in CSS:' . $style2buffer . ' Carset Detected:' . translation :: detect_encoding ( $style2buffer ));
2014-01-18 18:02:29 +01:00
$style2buffer = utf8_encode ( $style2buffer );
}
}
$style .= $style2buffer ;
// clean out comments and stuff
$search = array (
'@url\(http:\/\/[^\)].*?\)@si' , // url calls e.g. in style definitions
// '@<!--[\s\S]*?[ \t\n\r]*-->@', // Strip multi-line comments including CDATA
// '@<!--[\s\S]*?[ \t\n\r]*--@', // Strip broken multi-line comments including CDATA
);
$style = preg_replace ( $search , " " , $style );
// CSS Security
// http://code.google.com/p/browsersec/wiki/Part1#Cascading_stylesheets
$css = preg_replace ( '/(javascript|expession|-moz-binding)/i' , '' , $style );
if ( stripos ( $css , 'script' ) !== false ) translation :: replaceTagsCompletley ( $css , 'script' ); // Strip out script that may be included
// we need this, as styledefinitions are enclosed with curly brackets; and template stuff tries to replace everything between curly brackets that is having no horizontal whitespace
// as the comments as <!-- styledefinition --> in stylesheet are outdated, and ck-editor does not understand it, we remove it
2014-02-18 20:21:34 +01:00
$css_no_comment = str_replace ( array ( ':' , '<!--' , '-->' ), array ( ': ' , '' , '' ), $css );
2014-01-18 18:02:29 +01:00
//error_log(__METHOD__.__LINE__.$css);
2014-04-14 17:09:07 +02:00
// we already removed what we have found, above, as we used pretty much the same routine as in translation::replaceTagsCompletley
// no need to do the extra routine
2014-01-18 18:02:29 +01:00
// TODO: we may have to strip urls and maybe comments and ifs
2014-04-14 17:09:07 +02:00
//if (stripos($html,'style')!==false) translation::replaceTagsCompletley($html,'style'); // clean out empty or pagewide style definitions / left over tags
2014-02-18 20:21:34 +01:00
return $css_no_comment ;
2014-01-18 18:02:29 +01:00
}
2005-02-09 14:53:16 +01:00
}
2008-03-09 15:35:48 +01:00
html :: _init_static ();