<?php /**************************************************************************\ * eGroupWare - HTML creation class * * http://www.eGroupWare.org * * Written and (c) by Ralf Becker <RalfBecker@outdoor-training.de> * * -------------------------------------------- * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 2 of the License, or (at your * * option) any later version. * \**************************************************************************/ /* $Id$ */ class html { var $user_agent,$ua_version; // 'mozilla','msie','konqueror' var $prefered_img_title; var $charset,$phpgwapi_js_url; function html() { // should be Ok for all HTML 4 compatible browsers if (!eregi('compatible; ([a-z_]+)[/ ]+([0-9.]+)',$_SERVER['HTTP_USER_AGENT'],$parts)) { eregi('^([a-z_]+)/([0-9.]+)',$_SERVER['HTTP_USER_AGENT'],$parts); } list(,$this->user_agent,$this->ua_version) = $parts; $this->user_agent = strtolower($this->user_agent); $this->netscape4 = $this->user_agent == 'mozilla' && $this->ua_version < 5; $this->prefered_img_title = $this->netscape4 ? 'alt' : 'title'; //echo "<p>HTTP_USER_AGENT='$_SERVER[HTTP_USER_AGENT]', UserAgent: '$this->user_agent', Version: '$this->ua_version', img_title: '$this->prefered_img_title'</p>\n"; if ($GLOBALS['phpgw']->translation) { $this->charset = $GLOBALS['phpgw']->translation->charset(); } $this->phpgwapi_js_url = $GLOBALS['phpgw_info']['server']['webserver_url'].'/phpgwapi/js'; } function activate_links($content) { // Exclude everything which is already a link $NotAnchor = '(?<!"|href=|href\s=\s|href=\s|href\s=)'; // spamsaver emailaddress $result = preg_replace('/'.$NotAnchor.'mailto:([a-z0-9._-]+)@([a-z0-9_-]+)\.([a-z0-9._-]+)/i', '<a href="#" onclick="document.location=\'mai\'+\'lto:\\1\'+unescape(\'%40\')+\'\\2.\\3\'; return false;">\\1 AT \\2 DOT \\3</a>', $content); // First match things beginning with http:// (or other protocols) $Protocol = '(http|ftp|https):\/\/'; $Domain = '([\w]+.[\w]+)'; $Subdir = '([\w\-\.,@?^=%&:\/~\+#]*[\w\-\@?^=%&\/~\+#])?'; $Expr = '/' . $NotAnchor . $Protocol . $Domain . $Subdir . '/i'; $result = preg_replace( $Expr, "<a href=\"$0\" target=\"_blank\">$2$3</a>", $result ); // Now match things beginning with www. $NotHTTP = '(?<!:\/\/)'; $Domain = 'www(.[\w]+)'; $Subdir = '([\w\-\.,@?^=%&:\/~\+#]*[\w\-\@?^=%&\/~\+#])?'; $Expr = '/' . $NotAnchor . $NotHTTP . $Domain . $Subdir . '/i'; return preg_replace( $Expr, "<a href=\"http://$0\" target=\"_blank\">$0</a>", $result ); } function htmlspecialchars($str) { // add @ by lkneschke to supress warning about unknown charset return @htmlspecialchars($str,ENT_COMPAT,$this->charset); } /*! @function select @abstract allows to show and select one item from an array @param $name string with name of the submitted var which holds the key of the selected item form array @param $key key(s) of already selected item(s) from $arr, eg. '1' or '1,2' or array with keys @param $arr array with items to select, eg. $arr = array ( 'y' => 'yes','n' => 'no','m' => 'maybe'); @param $no_lang if !$no_lang send items through lang() @param $options additional options (e.g. 'width') @param $multiple number of lines for a multiselect, default 0 = no multiselect @returns string to set for a template or to echo into html page */ function select($name, $key, $arr=0,$no_lang=0,$options='',$multiple=0) { // should be in class common.sbox if (!is_array($arr)) { $arr = array('no','yes'); } if ((int)$multiple > 0) { $options .= ' multiple size="'.(int)$multiple.'"'; if (substr($name,-2) != '[]') { $name .= '[]'; } } $out = "<select name=\"$name\" $options>\n"; if (is_array($key)) { $key = implode(',',$key); } foreach($arr as $k => $text) { $out .= '<option value="'.$this->htmlspecialchars($k).'"'; if("$k" == "$key" || strstr(",$key,",",$k,")) { $out .= ' selected="1"'; } $out .= ">" . ($no_lang || $text == '' ? $text : lang($text)) . "</option>\n"; } $out .= "</select>\n"; return $out; } function div($content,$options='') { return "<div $options>\n$content</div>\n"; } function input_hidden($vars,$value='',$ignore_empty=True) { if (!is_array($vars)) { $vars = array( $vars => $value ); } foreach($vars as $name => $value) { if (is_array($value)) { $value = serialize($value); } if (!$ignore_empty || $value && !($name == 'filter' && $value == 'none')) // dont need to send all the empty vars { $html .= "<input type=\"hidden\" name=\"$name\" value=\"".$this->htmlspecialchars($value)."\" />\n"; } } return $html; } function textarea($name,$value='',$options='' ) { return "<textarea name=\"$name\" $options>".$this->htmlspecialchars($value)."</textarea>\n"; } /*! @function htmlarea_avalible @author ralfbecker @abstract Checks if HTMLarea (or an other richtext editor) is availible for the used browser */ function htmlarea_availible() { switch($this->user_agent) { case 'msie': return $this->ua_version >= 5.5; case 'mozilla': return $this->ua_version >= 1.3; default: return False; } } /*! @function htmlarea @syntax htmlarea( $name,$content='',$style='width:100%; min-width:500px; height:300px;' ) @author ralfbecker @abstract creates a textarea inputfield for the htmlarea js-widget (returns the necessary html and js) @param $name string name and id of the input-field @param $content string of the htmlarea (will be run through htmlspecialchars !!!), default '' @param $style string inline styles, eg. dimension of textarea element */ function htmlarea($name,$content='',$style='',$base_href='') { if (!$style) $style = 'width:100%; min-width:500px; height:300px;'; if (!is_object($GLOBALS['phpgw']->js)) { $GLOBALS['phpgw']->js = CreateObject('phpgwapi.javascript'); } if (!strstr($GLOBALS['phpgw_info']['flags']['java_script'],'htmlarea')) { $GLOBALS['phpgw']->js->validate_file('htmlarea','htmlarea'); $GLOBALS['phpgw']->js->validate_file('htmlarea','dialog'); $lang = $GLOBALS['phpgw_info']['user']['preferences']['common']['lang']; if ($lang == 'en') // other lang-files are utf-8 only and incomplete (crashes htmlarea as of 3.0beta) { $GLOBALS['phpgw']->js->validate_file('htmlarea',"lang/$lang"); } else { $GLOBALS['phpgw_info']['flags']['java_script'] .= '<script type="text/javascript" src="'.ereg_replace('[?&]*click_history=[0-9a-f]*','',$GLOBALS['phpgw']->link('/phpgwapi/inc/htmlarea-lang.php',array('lang'=>$lang))).'"></script>'."\n"; } $GLOBALS['phpgw_info']['flags']['java_script_thirst'] .= '<style type="text/css">@import url(/egroupware/phpgwapi/js/htmlarea/htmlarea.css);</style> <script type="text/javascript"> _editor_url = "'."$this->phpgwapi_js_url/htmlarea/".'"; // var htmlareaConfig = new HTMLArea.Config(); // htmlareaConfig.editorURL = '."'$this->phpgwapi_js_url/htmlarea/'; </script>\n"; // set a base href to get relative image-pathes working if ($base_href && $this->user_agent != 'msie') // HTMLarea does not work in IE with base href set !!! { $GLOBALS['phpgw_info']['flags']['java_script_thirst'] .= '<base href="'. ($base_href[0] != '/' && substr($base_href,0,4) != 'http' ? $GLOBALS['phpgw_info']['server']['webserver_url'].'/' : ''). $base_href.'" />'."\n"; } $GLOBALS['phpgw_info']['flags']['java_script'] .= '<script type="text/javascript"> var htmlareaConfig = new HTMLArea.Config(); htmlareaConfig.editorURL = '."'$this->phpgwapi_js_url/htmlarea/'; </script>\n"; } $id = str_replace(array('[',']'),array('_',''),$name); // no brakets in the id allowed by js $GLOBALS['phpgw']->js->set_onload("HTMLArea.replace('$id',htmlareaConfig);"); if (!empty($style)) $style = " style=\"$style\""; return "<textarea name=\"$name\" id=\"$id\"$style>".$this->htmlspecialchars($content)."</textarea>\n"; } function input($name,$value='',$type='',$options='' ) { if ($type) { $type = 'type="'.$type.'"'; } return "<input $type name=\"$name\" value=\"".$this->htmlspecialchars($value)."\" $options />\n"; } function submit_button($name,$lang,$onClick='',$no_lang=0,$options='',$image='',$app='') { // workaround for idots and IE button problem (wrong cursor-image) $options .= ' style="cursor: hand;"'; if ($image != '') { $image = str_replace(array('.gif','.GIF','.png','.PNG'),'',$image); if (!($path = $GLOBALS['phpgw']->common->image($app,$image))) { $path = $image; // name may already contain absolut path } $image = ' src="'.$path.'"'; } if (!$no_lang) { $lang = lang($lang); } if (($accesskey = strstr($lang,'&')) && $accesskey[1] != ' ' && (($pos = strpos($accesskey,';')) === False || $pos > 5)) { $lang_u = str_replace('&'.$accesskey[1],'<u>'.$accesskey[1].'</u>',$lang); $lang = str_replace('&','',$lang); $options = 'accesskey="'.$accesskey[1].'" '.$options; } else { $accesskey = ''; $lang_u = $lang; } if ($onClick) $options .= " onclick=\"$onClick\""; // <button> is not working in all cases if ($this->user_agent == 'mozilla' && $this->ua_version < 5 || $image) { return $this->input($name,$lang,$image != '' ? 'image' : 'submit',$options.$image); } return '<button type="submit" name="'.$name.'" value="'.$lang.'" '.$options.' />'. ($image != '' ? "<img$image $this->prefered_img_title=\"$lang\"> " : ''). ($image == '' || $accesskey ? $lang_u : '').'</button>'; } /*! @function link @abstract creates an absolut link + the query / get-variables @param $url phpgw-relative link, may include query / get-vars @parm $vars query or array ('name' => 'value', ...) with query @example link('/index.php?menuaction=infolog.uiinfolog.get_list',array('info_id' => 123)) @example = 'http://domain/phpgw-path/index.php?menuaction=infolog.uiinfolog.get_list&info_id=123' @result absolut link already run through $phpgw->link */ function link($url,$vars='') { //echo "<p>html::link(url='$url',vars='"; print_r($vars); echo "')</p>\n"; if (!is_array($vars)) { parse_str($vars,$vars); } list($url,$v) = explode('?',$url); // url may contain additional vars if ($v) { parse_str($v,$v); $vars += $v; } return $GLOBALS['phpgw']->link($url,$vars); } function checkbox($name,$value='') { return "<input type=\"checkbox\" name=\"$name\" value=\"True\"" .($value ? ' checked="1"' : '') . " />\n"; } function form($content,$hidden_vars,$url,$url_vars='',$name='',$options='',$method='POST') { $html = "<form method=\"$method\" ".($name != '' ? "name=\"$name\" " : '')."action=\"".$this->link($url,$url_vars)."\" $options>\n"; $html .= $this->input_hidden($hidden_vars); if ($content) { $html .= $content; $html .= "</form>\n"; } return $html; } function form_1button($name,$lang,$hidden_vars,$url,$url_vars='',$form_name='',$method='POST') { return $this->form($this->submit_button($name,$lang),$hidden_vars,$url,$url_vars,$form_name,'',$method); } /*! @function table @abstracts creates table from array with rows @discussion abstract the html stuff @param $rows array with rows, each row is an array of the cols @param $options options for the table-tag @example $rows = array ( '1' => array( 1 => 'cell1', '.1' => 'colspan=3', @example 2 => 'cell2', 3 => 'cell3', '.3' => 'width="10%"' ), @example '.1' => 'BGCOLOR="#0000FF"' ); @example table($rows,'WIDTH="100%"') = '<table WIDTH="100%"><tr><td colspan=3>cell1</td><td>cell2</td><td width="10%">cell3</td></tr></table>' @result string with html-code of the table */ function table($rows,$options = '',$no_table_tr=False) { $html = $no_table_tr ? '' : "<table $options>\n"; foreach($rows as $key => $row) { if (!is_array($row)) { continue; // parameter } $html .= $no_table_tr && $key == 1 ? '' : "\t<tr ".$rows['.'.$key].">\n"; foreach($row as $key => $cell) { 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"; } } $html .= "\t</tr>\n"; } $html .= "</table>\n"; if ($no_table_tr) { $html = substr($html,0,-16); } return $html; } function sbox_submit( $sbox,$no_script=0 ) { $html = str_replace('<select','<select onchange="this.form.submit()" ', $sbox); if ($no_script) { $html .= '<noscript>'.$this->submit_button('send','>').'</noscript>'; } return $html; } function progressbar( $percent,$title='',$options='',$width='',$color='',$height='' ) { $percent = (int) $percent; if (!$width) $width = '30px'; if (!$height)$height= '5px'; if (!$color) $color = '#D00000'; $title = $title ? $this->htmlspecialchars($title) : $percent.'%'; if ($this->netscape4) { return $title; } return '<div title="'.$title.'" '.$options. ' style="height: '.$height.'; width: '.$width.'; border: 1px solid black; padding: 1px;'. (stristr($options,'onclick="') ? ' cursor: pointer; cursor: hand;' : '').'">'."\n\t". '<div style="height: '.$height.'; width: '.$percent.'%; background: '.$color.';" />'."\n</div>\n"; } function image( $app,$name,$title='',$options='' ) { $name = str_replace(array('.gif','.GIF','.png','.PNG'),'',$name); if (!($path = $GLOBALS['phpgw']->common->image($app,$name))) { $path = $name; // name may already contain absolut path } if (!@is_readable(str_replace($GLOBALS['phpgw_info']['server']['webserver_url'],PHPGW_SERVER_ROOT,$path))) { // if the image-name is a percentage, use a progressbar if (substr($name,-1) == '%' && is_numeric($percent = substr($name,0,-1))) { return $this->progressbar($percent,$title); } return $title; } if ($title) { $options .= " $this->prefered_img_title=\"".$this->htmlspecialchars($title).'"'; } return "<img src=\"$path\" $options />"; } function a_href( $content,$url,$vars='',$options='') { if (!strstr($url,'/') && count(explode('.',$url)) == 3) { $url = "/index.php?menuaction=$url"; } if (is_array($url)) { $vars = $url; $url = '/index.php'; } return '<a href="'.$this->link($url,$vars).'" '.$options.'>'.$content.'</a>'; } function bold($content) { return '<b>'.$content.'</b>'; } function italic($content) { return '<i>'.$content.'</i>'; } function hr($width,$options='') { if ($width) $options .= " width=\"$width\""; return "<hr $options />\n"; } /*! @function formatOptions @abstract formats option-string for most of the above functions @param $options String (or Array) with option-values eg. '100%,,1' @param $names String (or Array) with the option-names eg. 'WIDTH,HEIGHT,BORDER' @example formatOptions('100%,,1','WIDTH,HEIGHT,BORDER') = ' WIDTH="100%" BORDER="1"' @result option string */ function formatOptions($options,$names) { if (!is_array($options)) $options = explode(',',$options); if (!is_array($names)) $names = explode(',',$names); foreach($options as $n => $val) { if ($val != '' && $names[$n] != '') { $html .= ' '.strtolower($names[$n]).'="'.$val.'"'; } } return $html; } /*! @function themeStyles @abstract returns simple stylesheet (incl. <STYLE> tags) for nextmatch row-colors @result the classes 'th' = nextmatch header, 'row_on'+'row_off' = alternating rows */ function themeStyles() { return $this->style($this->theme2css()); } /*! @function theme2css @abstract returns simple stylesheet for nextmatch row-colors @result the classes 'th' = nextmatch header, 'row_on'+'row_off' = alternating rows */ function theme2css() { return ".th { background: ".$GLOBALS['phpgw_info']['theme']['th_bg']."; }\n". ".row_on,.th_bright { background: ".$GLOBALS['phpgw_info']['theme']['row_on']."; }\n". ".row_off { background: ".$GLOBALS['phpgw_info']['theme']['row_off']."; }\n"; } function style($styles) { return $styles ? "<style type=\"text/css\">\n<!--\n$styles\n-->\n</style>" : ''; } function label($content,$id='',$accesskey='',$options='') { if ($id != '') { $id = " for=\"$id\""; } if ($accesskey != '') { $accesskey = " accesskey=\"$accesskey\""; } return "<label$id$accesskey $options>$content</label>"; } }