From 4962c59833c7dd402e335477f2418692d777f1b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lehrke?= Date: Mon, 12 Apr 2010 06:36:07 +0000 Subject: [PATCH] Fix vCard export issue --- .../inc/class.addressbook_vcal.inc.php | 3 +- phpgwapi/inc/class.html.inc.php | 284 +++++++++++++++--- 2 files changed, 244 insertions(+), 43 deletions(-) diff --git a/addressbook/inc/class.addressbook_vcal.inc.php b/addressbook/inc/class.addressbook_vcal.inc.php index ed87ad0a20..5deb2368dd 100644 --- a/addressbook/inc/class.addressbook_vcal.inc.php +++ b/addressbook/inc/class.addressbook_vcal.inc.php @@ -969,8 +969,7 @@ class addressbook_vcal extends addressbook_bo { if (!$file) { - $browser =& CreateObject('phpgwapi.browser'); - $browser->content_header('addressbook.vcf','text/x-vcard'); + html::content_header('addressbook.vcf','text/x-vcard'); } if (!($fp = fopen($file ? $file : 'php://output','w'))) { diff --git a/phpgwapi/inc/class.html.inc.php b/phpgwapi/inc/class.html.inc.php index f899d6949f..f90e6b03ec 100644 --- a/phpgwapi/inc/class.html.inc.php +++ b/phpgwapi/inc/class.html.inc.php @@ -6,7 +6,7 @@ * @author Ralf Becker complete rewrite in 6/2006 and earlier modifications * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @author RalfBecker-AT-outdoor-training.de - * @copyright 2001-2008 by RalfBecker@outdoor-training.de + * @copyright 2001-2009 by RalfBecker@outdoor-training.de * @package api * @subpackage html * @version $Id$ @@ -15,13 +15,12 @@ /** * Generates html with methods representing html-tags or higher widgets * - * The class has only static methods now, so there's no need to instanciate the object anymore! - * + * The class has only static methods now, so there's no need to instanciate as object anymore! */ class html { /** - * user-agent: 'mozilla','msie','konqueror', 'safari', 'opera' + * user-agent: 'firefox', 'msie', 'safari' (incl. iPhone, Chrome), 'opera', 'konqueror', 'mozilla' * @var string */ static $user_agent; @@ -58,17 +57,17 @@ class html static function _init_static() { // should be Ok for all HTML 4 compatible browsers - if (!preg_match('/(Safari)\/([0-9.]+)/i',$_SERVER['HTTP_USER_AGENT'],$parts) && - !preg_match('/compatible; ([a-z_]+)[\/ ]+([0-9.]+)/i',$_SERVER['HTTP_USER_AGENT'],$parts)) + if(!preg_match('/compatible; ([a-z]+)[\/ ]+([0-9.]+)/i',$_SERVER['HTTP_USER_AGENT'],$parts)) { - preg_match('/^([a-z_]+)\/([0-9.]+)/i',$_SERVER['HTTP_USER_AGENT'],$parts); + preg_match_all('/([a-z]+)\/([0-9.]+)/i',$_SERVER['HTTP_USER_AGENT'],$parts,PREG_SET_ORDER); + $parts = array_pop($parts); } list(,self::$user_agent,self::$ua_version) = $parts; - self::$user_agent = strtolower(self::$user_agent); + if ((self::$user_agent = strtolower(self::$user_agent)) == 'version') self::$user_agent = 'opera'; self::$netscape4 = self::$user_agent == 'mozilla' && self::$ua_version < 5; self::$prefered_img_title = self::$netscape4 ? 'alt' : 'title'; - //echo "

HTTP_USER_AGENT='$_SERVER[HTTP_USER_AGENT]', UserAgent: 'self::$user_agent', Version: 'self::$ua_version', img_title: 'self::$prefered_img_title'

\n"; + //echo "

HTTP_USER_AGENT='$_SERVER[HTTP_USER_AGENT]', UserAgent: '".self::$user_agent."', Version: '".self::$ua_version."', img_title: '".self::$prefered_img_title."'

\n"; if ($GLOBALS['egw']->translation) { @@ -80,7 +79,7 @@ class html /** * Created an input-field with an attached color-picker * - * Please note: it need to be called before the call to phpgw_header() !!! + * Please note: it need to be called before the call to egw_header() !!! * * @param string $name the name of the input-field * @param string $value the actual value for the input-field, default '' @@ -90,8 +89,8 @@ class html static function inputColor($name,$value='',$title='') { $id = str_replace(array('[',']'),array('_',''),$name).'_colorpicker'; - $onclick = "javascript:window.open('".self::$api_js_url.'/colorpicker/select_color.html?id='.urlencode($id)."&color='+document.getElementById('$id').value,'colorPicker','width=240,height=187,scrollbars=no,resizable=no,toolbar=no');"; - return ' '. + $onclick = "javascript:window.open('".self::$api_js_url.'/colorpicker/select_color.html?id='.urlencode($id)."&color='+encodeURIComponent(document.getElementById('$id').value),'colorPicker','width=240,height=187,scrollbars=no,resizable=no,toolbar=no');"; + return ' '. ''. '"; } @@ -101,8 +100,7 @@ class html * * Note: The wz_tooltip.js file gets automaticaly loaded at the end of the page * - * @param string/boolean $text text or html for the tooltip, all chars allowed, they will be quoted approperiate - * Or if False the content (innerHTML) of the element itself is used. + * @param string $text text or html for the tooltip, all chars allowed, they will be quoted approperiate * @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: * title (string) gives extra title-row, width (int,'auto') , padding (int), above (bool), bgcolor (color), bgimg (URL) @@ -111,28 +109,35 @@ class html */ static function tooltip($text,$do_lang=False,$options=False) { - if (!self::$wz_tooltip_included) - { - if (strpos($GLOBALS['egw_info']['flags']['need_footer'],'wz_tooltip')===false) - { - $GLOBALS['egw_info']['flags']['need_footer'] .= ''."\n"; - } - self::$wz_tooltip_included = True; - } if ($do_lang) $text = lang($text); - $opt_out = 'this.T_WIDTH = 200;'; + $ttip = ' onmouseover="Tip(\''.str_replace(array("\n","\r","'",'"'),array('','',"\\'",'"'),$text).'\''; + + $sticky = false; if (is_array($options)) { foreach($options as $option => $value) { - $opt_out .= 'this.T_'.strtoupper($option).'='.(is_bool($value)?($value?'true':'false'): - (is_numeric($value)?$value:"'".str_replace(array("'",'"'),array("\\'",'"'),$value)."'")).'; '; + $option = strtoupper($option); + if ($option == 'STICKY') $sticky = (bool)$value; + + switch(gettype($value)) + { + case 'boolean': + $value = $value ? 'true' : 'false'; + break; + case 'string': + if (stripos($value,"'")===false) $value = "'$value'"; + break; + } + $ttip .= ','.$option.','.$value; } } - if ($text === False) return ' onmouseover="'.$opt_out.'return escape(this.innerHTML);"'; + $ttip .= ')"'; - return ' onmouseover="'.$opt_out.'return escape(\''.str_replace(array("\n","\r","'",'"'),array('','',"\\'",'"'),$text).'\')"'; + $ttip .= ' onmouseout="UnTip()"'; + + return $ttip; } /** @@ -144,7 +149,7 @@ class html static function activate_links($content) { if (!$content || strlen($content) < 20) return $content; // performance - + // Exclude everything which is already a link $NotAnchor = '(?$0", $result ); } + /** + * activates URLs in a text, URLs get replaced by html-links using htmlpurify + * + * @param string $content text containing URLs + * @return string html with activated links + */ + static function activateLinks($content) + { + if (!$content || strlen($content) < 20) return $content; // performance + + // spamsaver emailaddress + $result = preg_replace('/'.$NotAnchor.'mailto:([a-z0-9._-]+)@([a-z0-9_-]+)\.([a-z0-9._-]+)/i', + '\\1 AT \\2 DOT \\3', + $content); + + $config = self::purifyCreateDefaultConfig(); + $config->set('Core.Encoding', (self::$charset?self::$charset:'UTF-8')); + // maybe the two following lines are useful for caching??? + $config->set('HTML.DefinitionID', 'activatelinks'); + $config->set('HTML.DefinitionRev', 1); + // doctype and tidylevel + $config->set('HTML.Doctype', 'XHTML 1.0 Transitional'); + $config->set('HTML.TidyLevel', 'light'); + // EnableID is needed for anchor tags + $config->set('Attr.EnableID',true); + // actual allowed tags and attributes + $config->set('URI.AllowedSchemes', array('http'=>true, 'https'=>true, 'ftp'=>true, 'file'=>true, 'cid'=>true)); + $config->set('AutoFormat.RemoveEmpty', true); + $config->set('HTML.Allowed', 'br,p[align],b,i,u,s,em,pre,tt,strong,strike,center,div[align],hr[class|style],'. + 'font[size|color],'. + 'ul[type],ol[type|start],li,'. + 'h1,h2,h3,'. + 'span[class|style],'. + 'table[class|border|cellpadding|cellspacing|width|style|align|bgcolor|align],'. + 'tbody,thead,tfoot,colgroup,'. + 'col[width|span],'. + 'blockquote[class|cite|dir],'. + 'tr[class|style|align|bgcolor|align|valign],'. + 'td[class|colspan|rowspan|width|style|align|bgcolor|align|valign|nowrap],'. + 'th[class|colspan|rowspan|width|style|align|bgcolor|align|valign|nowrap],'. + 'a[href|target|name|title],'. + 'img[src|alt|title]'); + $config->set('Attr.DefaultInvalidImage', 'Image removed by htmlpurify'); + $config->set('Cache.SerializerPath', ($GLOBALS['egw_info']['server']['temp_dir']?$GLOBALS['egw_info']['server']['temp_dir']:sys_get_temp_dir())); + $config->set('AutoFormat.Linkify',true); + return self::purify($result,$config); + } + + /** + * deactivates URLs in a text, URLs get replaced by html-links using htmlpurify + * + * @param string $content text containing URLs + * @return string html with activated links + */ + static function deactivateLinks($_html) + { + $config = self::purifyCreateDefaultConfig(); + $config->set('Core.Encoding', (self::$charset?self::$charset:'UTF-8')); + // maybe the two following lines are useful for caching??? + $config->set('HTML.DefinitionID', 'deactivatelinks'); + $config->set('HTML.DefinitionRev', 1); + // doctype and tidylevel + $config->set('HTML.Doctype', 'XHTML 1.0 Transitional'); + $config->set('HTML.TidyLevel', 'light'); + // EnableID is needed for anchor tags + $config->set('Attr.EnableID',true); + // actual allowed tags and attributes + $config->set('URI.AllowedSchemes', array('http'=>true, 'https'=>true, 'ftp'=>true, 'file'=>true, 'cid'=>true)); + $config->set('AutoFormat.RemoveEmpty', true); + $config->set('HTML.Allowed', 'br,p[align],b,i,u,s,em,pre,tt,strong,strike,center,div[align],hr[class|style],'. + 'font[size|color],'. + 'ul[type],ol[type|start],li,'. + 'h1,h2,h3,'. + 'span[class|style],'. + 'table[class|border|cellpadding|cellspacing|width|style|align|bgcolor|align],'. + 'tbody,thead,tfoot,colgroup,'. + 'col[width|span],'. + 'blockquote[class|cite|dir],'. + 'tr[class|style|align|bgcolor|align|valign],'. + 'td[class|colspan|rowspan|width|style|align|bgcolor|align|valign|nowrap],'. + 'th[class|colspan|rowspan|width|style|align|bgcolor|align|valign|nowrap],'. + 'a[href|target|name|title],'. + 'img[src|alt|title]'); + $config->set('Attr.DefaultInvalidImage', 'Image removed by htmlpurify'); + $config->set('Cache.SerializerPath', ($GLOBALS['egw_info']['server']['temp_dir']?$GLOBALS['egw_info']['server']['temp_dir']:sys_get_temp_dir())); + + $config->set('AutoFormat.DisplayLinkURI',true); + $_html = self::purify($_html,$config); + return $_html; + } + /** * escapes chars with special meaning in html as entities * @@ -221,6 +317,18 @@ class html { $options .= ' size="'.abs($multiple).'"'; } + // fix width for MSIE in/for selectboxes + if (self::$user_agent == 'msie') + { + if (stripos($options,'onfocus="') === false) + { + $options .= ' onfocus="window.dropdown_menu_hack(this);" '; + } + else + { + $options = str_ireplace('onfocus="','onfocus="window.dropdown_menu_hack(this);',$options); + } + } $out = "