From 99b820a5bf36158405208f140cf48f8aedf91fff Mon Sep 17 00:00:00 2001 From: xue <> Date: Mon, 14 Nov 2005 00:29:41 +0000 Subject: Added theme support. --- framework/Web/UI/TControl.php | 12 ++- framework/Web/UI/TPage.php | 6 +- framework/Web/UI/TTheme.php | 160 ++++++++++++++++++++++++----- framework/Web/UI/TThemeManager.php | 204 +++++++++++++++++++++++++++++++++++++ 4 files changed, 349 insertions(+), 33 deletions(-) create mode 100644 framework/Web/UI/TThemeManager.php (limited to 'framework') diff --git a/framework/Web/UI/TControl.php b/framework/Web/UI/TControl.php index b0d353f3..21c633c7 100644 --- a/framework/Web/UI/TControl.php +++ b/framework/Web/UI/TControl.php @@ -262,6 +262,14 @@ class TControl extends TComponent return Prado::getApplication(); } + /** + * @return TPageService the page service + */ + public function getService() + { + return Prado::getApplication()->getService(); + } + /** * @return THttpRequest the current user request */ @@ -296,12 +304,12 @@ class TControl extends TComponent public function publishFile($file) { - return Prado::getApplication()->getService()->getAssetManager()->publishFile($file); + return $this->getService()->getAssetManager()->publishFile($file); } public function publishDirectory($directory) { - return Prado::getApplication()->getService()->getAssetManager()->publishDirectory($directory); + return $this->getService()->getAssetManager()->publishDirectory($directory); } public function getAsset($assetName) diff --git a/framework/Web/UI/TPage.php b/framework/Web/UI/TPage.php index 08fbd2fe..232878da 100644 --- a/framework/Web/UI/TPage.php +++ b/framework/Web/UI/TPage.php @@ -66,7 +66,7 @@ class TPage extends TTemplateControl return parent::loadTemplate(); else { - $template=Prado::getApplication()->getService()->getTemplateManager()->loadTemplateByFileName(Prado::getPathOfNamespace($this->_templateFile,'.tpl')); + $template=Prado::getApplication()->getService()->getTemplateManager()->getTemplateByFileName(Prado::getPathOfNamespace($this->_templateFile,'.tpl')); $this->setTemplate($template); return $template; } @@ -326,9 +326,9 @@ EOD; private function initializeThemes() { if($this->_themeName!=='') - $this->_theme=new TTheme($this->_themeName); + $this->_theme=$this->getService()->getThemeManager()->getTheme($this->_themeName); if($this->_styleSheetName!=='') - $this->_styleSheet=new TTheme($this->_styleSheetName); + $this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheetName); } /** diff --git a/framework/Web/UI/TTheme.php b/framework/Web/UI/TTheme.php index 3d4d4e5d..452c473c 100644 --- a/framework/Web/UI/TTheme.php +++ b/framework/Web/UI/TTheme.php @@ -1,46 +1,129 @@ _themePath=$name; - $this->initialize(); + $this->_application=$application; + if($this->_themePath===null) + $this->_themePath=dirname($application->getConfigurationFile()).'/'.self::DEFAULT_THEME_PATH; + + $this->_initialized=true; } - private function initialize() + /** + * @return string id of this module + */ + public function getID() { - if(($theme=opendir($this->_themePath))===false) - throw new Exception("Invalid theme ".$this->_themePath); - while(($file=readdir($theme))!==false) + return $this->_id; + } + + /** + * @param string id of this module + */ + public function setID($value) + { + $this->_id=$value; + } + + public function getTheme($name) + { + $themePath=realpath($this->_themePath.'/'.$name); + if($themePath===false || !is_dir($this->_themePath)) + throw new TConfigurationException('thememanager_themepath_invalid',$themePath); + if(($cache=$this->_application->getCache())===null) + return new TTheme($themePath.'/'.self::THEME_FILE); + else { - if(basename($file,'.skin')!==$file) - $this->parseSkinFile($this->_themePath.'/'.$file); + $themeFile=$themePath.'/'.self::THEME_FILE; + $array=$cache->get(self::THEME_CACHE_PREFIX.$themePath); + if(is_array($array)) + { + list($theme,$timestamp)=$array; + if(filemtime($themeFile)<$timestamp) + return $theme; + } + $theme=new TTheme($themeFile); + $cache->set(self::THEME_CACHE_PREFIX.$themePath,array($theme,time())); + return $theme; } - closedir($theme); } - private function parseSkinFile($fileName) + public function getThemePath() { - if(($skin=simplexml_load_file($fileName))===false) - throw new Exception("Parsing $fileName failed."); - foreach($skin->children() as $type=>$control) + return $this->_themePath; + } + + public function setThemePath($value) + { + if($this->_initialized) + throw new TInvalidOperationException('thememanager_themepath_unchangeable'); + else + $this->_themePath=$value; + } +} + +class TTheme extends TTemplate +{ + private $_themePath; + private $_themeFile; + private $_skins=array(); + + public function __construct($themeFile) + { + $this->_themeFile=$themeFile; + $this->_themePath=dirname($themeFile); + if(is_file($themeFile) && is_readable($themeFile)) { - $attributes=array(); - foreach($control->attributes() as $name=>$value) + $theme=&$this->parse(file_get_contents($themeFile)); + foreach($theme as $skin) { - $attributes[strtolower($name)]=(string)$value; + if($skin[0]!==0) + throw new TConfigurationException('theme_control_nested',$skin[1]); + else if(!isset($skin[2])) // a text string, ignored + continue; + $type=$skin[1]; + $id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0; + unset($skin[2]['skinid']); + if(isset($this->_skins[$type][$id])) + throw new TConfigurationException('theme_skinid_duplicated',$type,$id); + foreach($skin[2] as $name=>$value) + { + if(is_array($value) && $value[0]===0) + throw new TConfigurationException('theme_databind_unsupported',$type,$id,$name); + } + $this->_skins[$type][$id]=$skin[2]; } - $skinID=isset($attributes['skinid'])?(string)$attributes['skinid']:0; - unset($attributes['skinid']); - if(isset($this->_skins[$type][$skinID])) - throw new Exception("Duplicated skin $type.$skinID"); - else - $this->_skins[$type][$skinID]=$attributes; } + else + throw new TIOException('theme_themefile_invalid',$themeFile); } public function applySkin($control) @@ -52,11 +135,32 @@ class TTheme extends TComponent { foreach($this->_skins[$type][$id] as $name=>$value) { - $control->setSubProperty($name,$value); + if(is_array($value)) + $value=$this->evaluateExpression($value); + if(strpos($name,'.')===false) // is simple property or custom attribute + { + if($control->hasProperty($name)) + { + if($control->canSetProperty($name)) + { + $setter='set'.$name; + $control->$setter($value); + } + else + throw new TConfigurationException('theme_property_readonly',get_class($control),$name); + } + else if($control->getAllowCustomAttributes()) + $control->getAttributes()->add($name,$value); + else + throw new TConfigurationException('theme_property_undefined',get_class($control),$name); + } + else // complex property + $control->setSubProperty($name,$value); } + return true; } else - return; + return false; } } diff --git a/framework/Web/UI/TThemeManager.php b/framework/Web/UI/TThemeManager.php new file mode 100644 index 00000000..8edae2e1 --- /dev/null +++ b/framework/Web/UI/TThemeManager.php @@ -0,0 +1,204 @@ +_application=$application; + if($this->_themePath===null) + $this->_themePath=dirname($application->getConfigurationFile()).'/'.self::DEFAULT_THEME_PATH; + + $this->_initialized=true; + } + + /** + * @return string id of this module + */ + public function getID() + { + return $this->_id; + } + + /** + * @param string id of this module + */ + public function setID($value) + { + $this->_id=$value; + } + + public function getTheme($name) + { + $themePath=realpath($this->_themePath.'/'.$name); + if($themePath===false || !is_dir($this->_themePath)) + throw new TConfigurationException('thememanager_themepath_invalid',$themePath); + if(($cache=$this->_application->getCache())!==null) + { + $array=$cache->get(self::THEME_CACHE_PREFIX.$themePath); + if(is_array($array)) + { + list($theme,$timestamp)=$array; + $cacheValid=true; + if(($dir=opendir($themePath))===false) + throw new TIOException('thememanager_themepath_invalid',$themePath); + while(($file=readdir($dir))!==false) + { + if(basename($file,'.skin')!==$file && filemtime($themePath.'/'.$file)>$timestamp) + { + $cacheValid=false; + break; + } + } + closedir($dir); + if($cacheValid) + return $theme; + } + } + // not cached, so we parse all skin files + $content=''; + if(($dir=opendir($themePath))===false) + throw new TIOException('thememanager_themepath_invalid',$themePath); + while(($file=readdir($dir))!==false) + { + if(basename($file,'.skin')!==$file) + $content.=file_get_contents($themePath.'/'.$file); + } + closedir($dir); + $theme=new TTheme($content,$themePath); + if($cache!==null) + $cache->set(self::THEME_CACHE_PREFIX.$themePath,array($theme,time())); + return $theme; + } + + public function getThemePath() + { + return $this->_themePath; + } + + public function setThemePath($value) + { + if($this->_initialized) + throw new TInvalidOperationException('thememanager_themepath_unchangeable'); + else + $this->_themePath=$value; + } +} + +class TTheme extends TTemplate +{ + const ASSET_PATH='assets'; + private $_themePath; + private $_themeFile; + private $_skins=array(); + + public function __construct($content,$themePath) + { + $this->_themePath=$themePath; + $theme=&$this->parse($content); + foreach($theme as $skin) + { + if($skin[0]!==-1) + throw new TConfigurationException('theme_control_nested',$skin[1]); + else if(!isset($skin[2])) // a text string, ignored + continue; + $type=$skin[1]; + $id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0; + unset($skin[2]['skinid']); + if(isset($this->_skins[$type][$id])) + throw new TConfigurationException('theme_skinid_duplicated',$type,$id); + foreach($skin[2] as $name=>$value) + { + if(is_array($value) && $value[0]===0) + throw new TConfigurationException('theme_databind_unsupported',$type,$id,$name); + } + $this->_skins[$type][$id]=$skin[2]; + } + } + + public function applySkin($control) + { + $type=get_class($control); + if(($id=$control->getSkinID())==='') + $id=0; + if(isset($this->_skins[$type][$id])) + { + foreach($this->_skins[$type][$id] as $name=>$value) + { + if(is_array($value)) + $value=$this->evaluateExpression($value); + if(strpos($name,'.')===false) // is simple property or custom attribute + { + if($control->hasProperty($name)) + { + if($control->canSetProperty($name)) + { + $setter='set'.$name; + $control->$setter($value); + } + else + throw new TConfigurationException('theme_property_readonly',get_class($control),$name); + } + else if($control->getAllowCustomAttributes()) + $control->getAttributes()->add($name,$value); + else + throw new TConfigurationException('theme_property_undefined',get_class($control),$name); + } + else // complex property + $control->setSubProperty($name,$value); + } + return true; + } + else + return false; + } + + public function publishFile($file) + { + return Prado::getApplication()->getService()->getAssetManager()->publishFile($file); + } + + public function publishDirectory($directory) + { + return Prado::getApplication()->getService()->getAssetManager()->publishDirectory($directory); + } + + public function getAsset($assetName) + { + $assetFile=$this->_themePath.'/'.self::ASSET_PATH.'/'.$assetName; + if(is_file($assetFile)) + return $this->publishFile($assetFile); + else if(is_dir($assetFile)) + return $this->publishDirectory($assetFile); + else + return ''; + } + +} + + +?> \ No newline at end of file -- cgit v1.2.3