1<?php
2/**
3 * EGroupware API - CSS Includes
4 *
5 * @link http://www.egroupware.org
6 * @author Ralf Becker <RalfBecker-AT-outdoor-training.de> rewrite in 12/2006
7 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
8 * @package api
9 * @subpackage framework
10 * @access public
11 * @version $Id$
12 */
13
14namespace EGroupware\Api\Framework;
15
16/**
17 * CSS includes
18 */
19class CssIncludes
20{
21	/**
22	 * Content from add calls
23	 *
24	 * @var array
25	 */
26	protected static $files = array();
27
28	/**
29	 * Include a css file, either speicified by it's path (relative to EGW_SERVER_ROOT) or appname and css file name
30	 *
31	 * @param string $app path (relative to EGW_SERVER_ROOT) or appname (if !is_null($name))
32	 * @param string $name =null name of css file in $app/templates/{default|$this->template}/$name.css
33	 * @param boolean $append =true true append file, false prepend (add as first) file used eg. for template itself
34	 * @param boolean $clear_includes =false true: clear all previous includes
35	 * @return boolean false: css file not found, true: file found
36	 */
37	public static function add($app, $name=null, $append=true, $clear_includes=false)
38	{
39		if ($clear_includes)
40		{
41			self::$files = array();
42		}
43
44		if (!is_null($name))
45		{
46			foreach($GLOBALS['egw']->framework->template_dirs as $dir)
47			{
48				if (file_exists(EGW_SERVER_ROOT.($path = '/'.$app.'/templates/'.$dir.'/'.$name.'.css')))
49				{
50					break;
51				}
52			}
53		}
54		else
55		{
56			$path = $app;
57		}
58		if (!file_exists(EGW_SERVER_ROOT.$path) && !file_exists(EGW_SERVER_ROOT . parse_url($path,PHP_URL_PATH)))
59		{
60			//error_log(__METHOD__."($app,$name) $path NOT found!");
61			return false;
62		}
63		if (!in_array($path,self::$files))
64		{
65			if ($append)
66			{
67				self::$files[] = $path;
68			}
69			else
70			{
71				self::$files = array_merge(array($path), self::$files);
72			}
73		}
74		return true;
75	}
76
77	/**
78	 * Get all css files included with add
79	 *
80	 * @return string
81	 */
82	public static function get($resolve=false)
83	{
84		if (!$resolve)
85		{
86			return self::$files;
87		}
88		$files = array();
89		foreach(self::$files as $path)
90		{
91			foreach(self::resolve_css_includes($path) as $path)
92			{
93				$files[] = $path;
94			}
95		}
96		return $files;
97	}
98
99	/**
100	 * Return link tags for all included css files incl. minifying
101	 *
102	 * @return string
103	 */
104	public static function tags()
105	{
106		// add all css files from self::includeCSS
107		$max_modified = 0;
108		//no more dynamic minifying: $debug_minify = $GLOBALS['egw_info']['server']['debug_minify'] === 'True';
109		$base_path = $GLOBALS['egw_info']['server']['webserver_url'];
110		if ($base_path[0] != '/') $base_path = parse_url($base_path, PHP_URL_PATH);
111		$css_files = '';
112		foreach(self::$files as $path)
113		{
114			foreach(self::resolve_css_includes($path) as $path)
115			{
116				list($file,$query) = explode('?',$path,2);
117				if (($mod = filemtime(EGW_SERVER_ROOT.$file)) > $max_modified) $max_modified = $mod;
118
119				// do NOT include app.css or categories.php, as it changes from app to app
120				//no more dynamic minifying: if ($debug_minify || substr($path, -8) == '/app.css' || substr($file,-14) == 'categories.php')
121				{
122					$css_files .= '<link href="'.$GLOBALS['egw_info']['server']['webserver_url'].$path.($query ? '&' : '?').$mod.'" type="text/css" rel="StyleSheet" />'."\n";
123				}
124				/* no more dynamic minifying
125				else
126				{
127					$css_file .= ($css_file ? ',' : '').substr($path, 1);
128				}*/
129			}
130		}
131		/* no more dynamic minifying
132		if (!$debug_minify)
133		{
134			$css = $GLOBALS['egw_info']['server']['webserver_url'].'/phpgwapi/inc/min/?';
135			if ($base_path && $base_path != '/') $css .= 'b='.substr($base_path, 1).'&';
136			$css .= 'f='.$css_file .
137				($GLOBALS['egw_info']['server']['debug_minify'] === 'debug' ? '&debug' : '').
138				'&'.$max_modified;
139			$css_files = '<link href="'.$css.'" type="text/css" rel="StyleSheet" />'."\n".$css_files;
140		}*/
141		return $css_files;
142	}
143
144	/**
145	 * Parse beginning of given CSS file for /*@import url("...") statements
146	 *
147	 * @param string $path EGroupware relative path eg. /phpgwapi/templates/default/some.css
148	 * @return array parsed pathes (EGroupware relative) including $path itself
149	 */
150	protected static function resolve_css_includes($path, &$pathes=array())
151	{
152		$matches = null;
153
154		list($file) = explode('?',$path,2);
155		if (($to_check = file_get_contents (EGW_SERVER_ROOT.$file, false, null, 0, 1024)) &&
156			stripos($to_check, '/*@import') !== false && preg_match_all('|/\*@import url\("([^"]+)"|i', $to_check, $matches))
157		{
158			foreach($matches[1] as $import_path)
159			{
160				if ($import_path[0] != '/')
161				{
162					$dir = dirname($path);
163					while(substr($import_path,0,3) == '../')
164					{
165						$dir = dirname($dir);
166						$import_path = substr($import_path, 3);
167					}
168					$import_path = ($dir != '/' ? $dir : '').'/'.$import_path;
169				}
170				self::resolve_css_includes($import_path, $pathes);
171			}
172		}
173		$pathes[] = $path;
174
175		return $pathes;
176	}
177}
178