2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
39 /*********************************************************************************
41 * Description: Contains a variety of utility functions used to display UI
42 * components such as form headers and footers. Intended to be modified on a per
44 ********************************************************************************/
46 if(!defined('JSMIN_AS_LIB'))
47 define('JSMIN_AS_LIB', true);
49 require_once("include/SugarTheme/cssmin.php");
50 require_once("jssource/jsmin.php");
51 require_once('include/utils/sugar_file_utils.php');
54 * Class that provides tools for working with a theme.
70 protected $description;
73 * Defines which parent files to not include
77 protected $ignoreParentFiles = array();
80 * Defines which parent files to not include
84 protected $directionality = 'ltr';
86 * Theme directory name
97 protected $parentTheme;
100 * Colors sets provided by the theme
102 * @deprecated only here for BC during upgrades
105 protected $colors = array();
108 * Font sets provided by the theme
110 * @deprecated only here for BC during upgrades
113 protected $fonts = array();
116 * Maximum sugar version this theme is for; defaults to 5.5.1 as all the themes without this
117 * parameter as assumed to work thru 5.5.1
121 protected $version = '5.5.1';
124 * Colors used in bar charts
128 protected $barChartColors = array(
129 "docBorder" => "0xffffff",
130 "docBg1" => "0xffffff",
131 "docBg2" => "0xffffff",
132 "xText" => "0x33485c",
133 "yText" => "0x33485c",
134 "title" => "0x333333",
135 "misc" => "0x999999",
136 "altBorder" => "0xffffff",
137 "altBg" => "0xffffff",
138 "altText" => "0x666666",
139 "graphBorder" => "0xcccccc",
140 "graphBg1" => "0xf6f6f6",
141 "graphBg2" => "0xf6f6f6",
142 "graphLines" => "0xcccccc",
143 "graphText" => "0x333333",
144 "graphTextShadow" => "0xf9f9f9",
145 "barBorder" => "0xeeeeee",
146 "barBorderHilite" => "0x333333",
147 "legendBorder" => "0xffffff",
148 "legendBg1" => "0xffffff",
149 "legendBg2" => "0xffffff",
150 "legendText" => "0x444444",
151 "legendColorKeyBorder" => "0x777777",
152 "scrollBar" => "0xcccccc",
153 "scrollBarBorder" => "0xeeeeee",
154 "scrollBarTrack" => "0xeeeeee",
155 "scrollBarTrackBorder" => "0xcccccc",
159 * Colors used in pie charts
163 protected $pieChartColors = array(
164 "docBorder" => "0xffffff",
165 "docBg1" => "0xffffff",
166 "docBg2" => "0xffffff",
167 "title" => "0x333333",
168 "subtitle" => "0x666666",
169 "misc" => "0x999999",
170 "altBorder" => "0xffffff",
171 "altBg" => "0xffffff",
172 "altText" => "0x666666",
173 "graphText" => "0x33485c",
174 "graphTextShadow" => "0xf9f9f9",
175 "pieBorder" => "0xffffff",
176 "pieBorderHilite" => "0x333333",
177 "legendBorder" => "0xffffff",
178 "legendBg1" => "0xffffff",
179 "legendBg2" => "0xffffff",
180 "legendText" => "0x444444",
181 "legendColorKeyBorder" => "0x777777",
182 "scrollBar" => "0xdfdfdf",
183 "scrollBarBorder" => "0xfafafa",
184 "scrollBarTrack" => "0xeeeeee",
185 "scrollBarTrackBorder" => "0xcccccc",
189 * Does this theme support group tabs
193 protected $group_tabs;
197 * Cache built of all css files locations
201 private $_cssCache = array();
204 * Cache built of all image files locations
208 private $_imageCache = array();
211 * Cache built of all javascript files locations
215 private $_jsCache = array();
218 * Cache built of all template files locations
222 private $_templateCache = array();
225 * Size of the caches after the are initialized in the constructor
229 private $_initialCacheSize = array(
233 'templateCache' => 0,
237 * Controls whether or not to clear the cache on destroy; defaults to false
239 private $_clearCacheOnDestroy = false;
241 private $imageExtensions = array(
252 * Sets the theme properties from the defaults passed to it, and loads the file path cache from an external cache
254 * @param $defaults string defaults for the current theme
256 public function __construct(
260 // apply parent theme's properties first
261 if ( isset($defaults['parentTheme']) ) {
263 include("themes/{$defaults['parentTheme']}/themedef.php");
264 foreach ( $themedef as $key => $value ) {
265 if ( property_exists(__CLASS__,$key) ) {
266 // For all arrays ( except colors and fonts ) you can just specify the items
267 // to change instead of all of the values
268 if ( is_array($this->$key) && !in_array($key,array('colors','fonts')) )
269 $this->$key = array_merge($this->$key,$value);
271 $this->$key = $value;
275 foreach ( $defaults as $key => $value ) {
276 if ( property_exists(__CLASS__,$key) ) {
277 // For all arrays ( except colors and fonts ) you can just specify the items
278 // to change instead of all of the values
279 if ( is_array($this->$key) && !in_array($key,array('colors','fonts')) )
280 $this->$key = array_merge($this->$key,$value);
282 $this->$key = $value;
285 if ( !inDeveloperMode() ) {
286 if ( sugar_is_file($GLOBALS['sugar_config']['cache_dir'].$this->getFilePath().'/pathCache.php') ) {
287 $caches = unserialize(sugar_file_get_contents($GLOBALS['sugar_config']['cache_dir'].$this->getFilePath().'/pathCache.php'));
288 if ( isset($caches['jsCache']) )
289 $this->_jsCache = $caches['jsCache'];
290 if ( isset($caches['cssCache']) )
291 $this->_cssCache = $caches['cssCache'];
292 if ( isset($caches['imageCache']) )
293 $this->_imageCache = $caches['imageCache'];
294 if ( isset($caches['templateCache']) )
295 $this->_templateCache = $caches['templateCache'];
298 $this->_initialCacheSize = array(
299 'jsCache' => count($this->_jsCache),
300 'cssCache' => count($this->_cssCache),
301 'imageCache' => count($this->_imageCache),
302 'templateCache' => count($this->_templateCache),
308 * Here we'll write out the internal file path caches to an external cache of some sort.
310 public function __destruct()
312 // Bug 28309 - Set the current directory to one which we expect it to be (i.e. the root directory of the install
313 set_include_path(realpath(dirname(__FILE__) . '/../..') . PATH_SEPARATOR . get_include_path());
314 chdir(realpath(dirname(__FILE__) . '/../..'));
316 // clear out the cache on destroy if we are asked to
317 if ( $this->_clearCacheOnDestroy ) {
318 if (is_file($GLOBALS['sugar_config']['cache_dir'].$this->getFilePath().'/pathCache.php'))
319 unlink($GLOBALS['sugar_config']['cache_dir'].$this->getFilePath().'/pathCache.php');
321 elseif ( !inDeveloperMode() ) {
322 // only update the caches if they have been changed in this request
323 if ( count($this->_jsCache) != $this->_initialCacheSize['jsCache']
324 || count($this->_cssCache) != $this->_initialCacheSize['cssCache']
325 || count($this->_imageCache) != $this->_initialCacheSize['imageCache']
326 || count($this->_templateCache) != $this->_initialCacheSize['templateCache']
328 sugar_file_put_contents(
329 create_cache_directory($this->getFilePath().'/pathCache.php'),
332 'jsCache' => $this->_jsCache,
333 'cssCache' => $this->_cssCache,
334 'imageCache' => $this->_imageCache,
335 'templateCache' => $this->_templateCache,
345 * Specifies what is returned when the object is cast to a string, in this case it will be the
346 * theme directory name.
348 * @return string theme directory name
350 public function __toString()
352 return $this->dirName;
356 * Generic public accessor method for all the properties of the theme ( which are kept protected )
360 public function __get(
364 if ( isset($this->$key) )
368 public function __isset($key){
369 return isset($this->$key);
374 * Clears out the caches used for this themes
376 public function clearCache()
378 $this->_clearCacheOnDestroy = true;
382 * Return array of all valid fields that can be specified in the themedef.php file
386 public static function getThemeDefFields()
405 * Returns the file path of the current theme
409 public function getFilePath()
411 return 'themes/'.$this->dirName;
415 * Returns the image path of the current theme
419 public function getImagePath()
421 return $this->getFilePath().'/images';
425 * Returns the css path of the current theme
429 public function getCSSPath()
431 return $this->getFilePath().'/css';
435 * Returns the javascript path of the current theme
439 public function getJSPath()
441 return $this->getFilePath().'/js';
445 * Returns the tpl path of the current theme
449 public function getTemplatePath()
451 return $this->getFilePath().'/tpls';
455 * Returns the file path of the theme defaults
459 public final function getDefaultFilePath()
461 return 'themes/default';
465 * Returns the image path of the theme defaults
469 public final function getDefaultImagePath()
471 return $this->getDefaultFilePath().'/images';
475 * Returns the css path of the theme defaults
479 public final function getDefaultCSSPath()
481 return $this->getDefaultFilePath().'/css';
485 * Returns the template path of the theme defaults
489 public final function getDefaultTemplatePath()
491 return $this->getDefaultFilePath().'/tpls';
495 * Returns the javascript path of the theme defaults
499 public final function getDefaultJSPath()
501 return $this->getDefaultFilePath().'/js';
505 * Returns CSS for the current theme.
507 * @param $color string optional, specifies the css color file to use if the theme supports it; defaults to cookie value or theme default
508 * @param $font string optional, specifies the css font file to use if the theme supports it; defaults to cookie value or theme default
509 * @return string HTML code
511 public function getCSS(
516 // include style.css file
517 $html = '<link rel="stylesheet" type="text/css" href="'.$this->getCSSURL('yui.css').'" />';
518 $html .= '<link rel="stylesheet" type="text/css" href="'.$this->getCSSURL('deprecated.css').'" />';
519 $html .= '<link rel="stylesheet" type="text/css" href="'.$this->getCSSURL('style.css').'" />';
521 // for BC during upgrade
522 if ( !empty($this->colors) ) {
523 if ( isset($_SESSION['authenticated_user_theme_color']) && in_array($_SESSION['authenticated_user_theme_color'], $this->colors))
524 $color = $_SESSION['authenticated_user_theme_color'];
526 $color = $this->colors[0];
527 $html .= '<link rel="stylesheet" type="text/css" href="'.$this->getCSSURL('colors.'.$color.'.css').'" id="current_color_style" />';
530 if ( !empty($this->fonts) ) {
531 if ( isset($_SESSION['authenticated_user_theme_font']) && in_array($_SESSION['authenticated_user_theme_font'], $this->fonts))
532 $font = $_SESSION['authenticated_user_theme_font'];
534 $font = $this->fonts[0];
535 $html .= '<link rel="stylesheet" type="text/css" href="'.$this->getCSSURL('fonts.'.$font.'.css').'" id="current_font_style" />';
542 * Returns javascript for the current theme
544 * @return string HTML code
546 public function getJS()
548 $styleJS = $this->getJSURL('style.js');
550 <script type="text/javascript" src="$styleJS"></script>
555 * Returns the path for the tpl file in the current theme. If not found in the current theme, will revert
556 * to looking in the base theme.
558 * @param string $templateName tpl file name
559 * @return string path of tpl file to include
561 public function getTemplate(
565 if ( isset($this->_templateCache[$templateName]) )
566 return $this->_templateCache[$templateName];
569 if (sugar_is_file('custom/'.$this->getTemplatePath().'/'.$templateName))
570 $templatePath = 'custom/'.$this->getTemplatePath().'/'.$templateName;
571 elseif (sugar_is_file($this->getTemplatePath().'/'.$templateName))
572 $templatePath = $this->getTemplatePath().'/'.$templateName;
573 elseif (isset($this->parentTheme)
574 && SugarThemeRegistry::get($this->parentTheme) instanceOf SugarTheme
575 && ($filename = SugarThemeRegistry::get($this->parentTheme)->getTemplate($templateName)) != '')
576 $templatePath = $filename;
577 elseif (sugar_is_file('custom/'.$this->getDefaultTemplatePath().'/'.$templateName))
578 $templatePath = 'custom/'.$this->getDefaultTemplatePath().'/'.$templateName;
579 elseif (sugar_is_file($this->getDefaultTemplatePath().'/'.$templateName))
580 $templatePath = $this->getDefaultTemplatePath().'/'.$templateName;
582 $GLOBALS['log']->warn("Template $templateName not found");
586 $this->_imageCache[$templateName] = $templatePath;
588 return $templatePath;
592 * Returns an image tag for the given image.
594 * @param string $image image name
595 * @param string $other_attributes optional, other attributes to add to the image tag, not cached
596 * @param string $width optional, defaults to the actual image's width
597 * @param string $height optional, defaults to the actual image's height
598 * @return string HTML image tag
600 public function getImage(
602 $other_attributes = '',
608 static $cached_results = array();
611 if(!empty($cached_results[$imageName]))
612 return $cached_results[$imageName]."$other_attributes />";
614 $imageURL = $this->getImageURL($imageName,false);
615 if ( empty($imageURL) )
618 $size = getimagesize($imageURL);
619 if ( is_null($width) )
621 if ( is_null($height) )
624 // Cache everything but the other attributes....
625 $cached_results[$imageName] = "<img src=\"". getJSPath($imageURL) ."\" width=\"$width\" height=\"$height\" ";
627 return $cached_results[$imageName] . "$other_attributes />";
631 * Returns the URL for an image in the current theme. If not found in the current theme, will revert
632 * to looking in the base theme.
634 * @param string $imageName image file name
635 * @param bool $addJSPath call getJSPath() with the results to add some unique image tracking support
636 * @return string path to image
638 public function getImageURL(
643 if ( isset($this->_imageCache[$imageName]) ) {
645 return getJSPath($this->_imageCache[$imageName]);
647 return $this->_imageCache[$imageName];
651 if (($filename = $this->_getImageFileName('custom/'.$this->getImagePath().'/'.$imageName)) != '')
652 $imagePath = $filename;
653 elseif (($filename = $this->_getImageFileName($this->getImagePath().'/'.$imageName)) != '')
654 $imagePath = $filename;
655 elseif (isset($this->parentTheme)
656 && SugarThemeRegistry::get($this->parentTheme) instanceOf SugarTheme
657 && ($filename = SugarThemeRegistry::get($this->parentTheme)->getImageURL($imageName,false)) != '')
658 $imagePath = $filename;
659 elseif (($filename = $this->_getImageFileName('custom/'.$this->getDefaultImagePath().'/'.$imageName)) != '')
660 $imagePath = $filename;
661 elseif (($filename = $this->_getImageFileName($this->getDefaultImagePath().'/'.$imageName)) != '')
662 $imagePath = $filename;
664 $GLOBALS['log']->warn("Image $imageName not found");
668 $this->_imageCache[$imageName] = $imagePath;
671 return getJSPath($imagePath);
677 * Checks for an image using all of the accepted image extensions
679 * @param string $imageName image file name
680 * @return string path to image
682 protected function _getImageFileName(
686 // return now if the extension matches that of which we are looking for
687 if ( sugar_is_file($imageName) )
689 $pathParts = pathinfo($imageName);
690 foreach ( $this->imageExtensions as $extension )
691 if ( isset($pathParts['extension']) )
692 if ( ( $extension != $pathParts['extension'] )
693 && sugar_is_file($pathParts['dirname'].'/'.$pathParts['filename'].'.'.$extension) )
694 return $pathParts['dirname'].'/'.$pathParts['filename'].'.'.$extension;
700 * Returns the URL for the css file in the current theme. If not found in the current theme, will revert
701 * to looking in the base theme.
703 * @param string $cssFileName css file name
704 * @param bool $addJSPath call getJSPath() with the results to add some unique image tracking support
705 * @return string path of css file to include
707 public function getCSSURL(
712 if ( isset($this->_cssCache[$cssFileName])) {
714 return getJSPath($this->_cssCache[$cssFileName]);
716 return $this->_cssCache[$cssFileName];
719 $cssFileContents = '';
720 if (isset($this->parentTheme)
721 && SugarThemeRegistry::get($this->parentTheme) instanceOf SugarTheme
722 && ($filename = SugarThemeRegistry::get($this->parentTheme)->getCSSURL($cssFileName,false)) != '')
723 $cssFileContents .= file_get_contents($filename);
725 if (sugar_is_file($this->getDefaultCSSPath().'/'.$cssFileName))
726 $cssFileContents .= file_get_contents($this->getDefaultCSSPath().'/'.$cssFileName);
727 if (sugar_is_file('custom/'.$this->getDefaultCSSPath().'/'.$cssFileName))
728 $cssFileContents .= file_get_contents('custom/'.$this->getDefaultCSSPath().'/'.$cssFileName);
730 if (sugar_is_file($this->getCSSPath().'/'.$cssFileName))
731 $cssFileContents .= file_get_contents($this->getCSSPath().'/'.$cssFileName);
732 if (sugar_is_file('custom/'.$this->getCSSPath().'/'.$cssFileName))
733 $cssFileContents .= file_get_contents('custom/'.$this->getCSSPath().'/'.$cssFileName);
734 if (empty($cssFileContents)) {
735 $GLOBALS['log']->warn("CSS File $cssFileName not found");
739 // fix any image references that may be defined in css files
740 $cssFileContents = str_ireplace("entryPoint=getImage&",
741 "entryPoint=getImage&themeName={$this->dirName}&",
744 // create the cached file location
745 $cssFilePath = create_cache_directory($this->getCSSPath()."/$cssFileName");
747 // if this is the style.css file, prepend the base.css and calendar-win2k-cold-1.css
748 // files before the theme styles
749 if ( $cssFileName == 'style.css' && !isset($this->parentTheme) ) {
750 if ( inDeveloperMode() )
751 $cssFileContents = file_get_contents('include/javascript/yui/build/base/base.css') . $cssFileContents;
753 $cssFileContents = file_get_contents('include/javascript/yui/build/base/base-min.css') . $cssFileContents;
757 if ( !inDeveloperMode() && !sugar_is_file($cssFilePath) ) {
758 $cssFileContents = cssmin::minify($cssFileContents);
761 // now write the css to cache
762 sugar_file_put_contents($cssFilePath,$cssFileContents);
764 $this->_cssCache[$cssFileName] = $cssFilePath;
767 return getJSPath($cssFilePath);
773 * Returns the URL for an image in the current theme. If not found in the current theme, will revert
774 * to looking in the base theme.
776 * @param string $jsFileName js file name
777 * @param bool $addJSPath call getJSPath() with the results to add some unique image tracking support
778 * @return string path to js file
780 public function getJSURL(
785 if ( isset($this->_jsCache[$jsFileName])) {
787 return getJSPath($this->_jsCache[$jsFileName]);
789 return $this->_jsCache[$jsFileName];
792 $jsFileContents = '';
794 if (isset($this->parentTheme)
795 && SugarThemeRegistry::get($this->parentTheme) instanceOf SugarTheme
796 && ($filename = SugarThemeRegistry::get($this->parentTheme)->getJSURL($jsFileName,false)) != '' && !in_array($jsFileName,$this->ignoreParentFiles))
797 $jsFileContents .= file_get_contents($filename);
799 if (sugar_is_file($this->getDefaultJSPath().'/'.$jsFileName))
800 $jsFileContents .= file_get_contents($this->getDefaultJSPath().'/'.$jsFileName);
801 if (sugar_is_file('custom/'.$this->getDefaultJSPath().'/'.$jsFileName))
802 $jsFileContents .= file_get_contents('custom/'.$this->getDefaultJSPath().'/'.$jsFileName);
804 if (sugar_is_file($this->getJSPath().'/'.$jsFileName))
805 $jsFileContents .= file_get_contents($this->getJSPath().'/'.$jsFileName);
806 if (sugar_is_file('custom/'.$this->getJSPath().'/'.$jsFileName))
807 $jsFileContents .= file_get_contents('custom/'.$this->getJSPath().'/'.$jsFileName);
808 if (empty($jsFileContents)) {
809 $GLOBALS['log']->warn("Javascript File $jsFileName not found");
813 // create the cached file location
814 $jsFilePath = create_cache_directory($this->getJSPath()."/$jsFileName");
817 if ( !inDeveloperMode()&& !sugar_is_file(str_replace('.js','-min.js',$jsFilePath)) ) {
818 $jsFileContents = JSMin::minify($jsFileContents);
819 $jsFilePath = str_replace('.js','-min.js',$jsFilePath);
822 // now write the js to cache
823 sugar_file_put_contents($jsFilePath,$jsFileContents);
825 $this->_jsCache[$jsFileName] = $jsFilePath;
828 return getJSPath($jsFilePath);
834 * Returns an array of all of the images available for the current theme
838 public function getAllImages()
840 // first, lets get all the paths of where to look
841 $pathsToSearch = array($this->getImagePath());
843 while (isset($theme->parentTheme) && SugarThemeRegistry::get($theme->parentTheme) instanceOf SugarTheme ) {
844 $theme = SugarThemeRegistry::get($theme->parentTheme);
845 $pathsToSearch[] = $theme->getImagePath();
847 $pathsToSearch[] = $this->getDefaultImagePath();
849 // now build the array
850 $imageArray = array();
851 foreach ( $pathsToSearch as $path )
853 if (!sugar_is_dir($path)) $path = "custom/$path";
854 if (sugar_is_dir($path) && is_readable($path) && $dir = opendir($path)) {
855 while (($file = readdir($dir)) !== false) {
863 if ( !isset($imageArray[$file]) )
864 $imageArray[$file] = $this->getImageURL($file,false);
878 * Registry for all the current classes in the system
880 class SugarThemeRegistry
883 * Array of all themes and thier object
887 private static $_themes = array();
890 * Name of the current theme; corresponds to an index key in SugarThemeRegistry::$_themes
894 private static $_currentTheme;
897 * Disable the constructor since this will be a singleton
899 private function __construct() {}
902 * Adds a new theme to the registry
904 * @param $themedef array
906 public static function add(
910 // make sure the we know the sugar version
911 if ( !isset($GLOBALS['sugar_version']) ) {
912 include('sugar_version.php');
913 $GLOBALS['sugar_version'] = $sugar_version;
916 // Assume theme is designed for 5.5.x if not specified otherwise
917 if ( !isset($themedef['version']) )
918 $themedef['version']['regex_matches'] = array('5\.5\.*');
920 // Check to see if theme is valid for this version of Sugar; return false if not
922 if( isset($themedef['version']['exact_matches']) ){
923 $matches_empty = false;
924 foreach( $themedef['version']['exact_matches'] as $match ){
925 if( $match == $GLOBALS['sugar_version'] ){
930 if( !$version_ok && isset($themedef['version']['regex_matches']) ){
931 $matches_empty = false;
932 foreach( $themedef['version']['regex_matches'] as $match ){
933 if( preg_match( "/$match/", $GLOBALS['sugar_version'] ) ){
941 $theme = new SugarTheme($themedef);
942 self::$_themes[$theme->dirName] = $theme;
946 * Removes a new theme from the registry
948 * @param $themeName string
950 public static function remove(
954 if ( self::exists($themeName) )
955 unset(self::$_themes[$themeName]);
959 * Returns a theme object in the registry specified by the given $themeName
961 * @param $themeName string
963 public static function get(
967 if ( isset(self::$_themes[$themeName]) )
968 return self::$_themes[$themeName];
972 * Returns the current theme object
974 * @return SugarTheme object
976 public static function current()
978 if ( !isset(self::$_currentTheme) )
979 self::buildRegistry();
981 return self::$_themes[self::$_currentTheme];
985 * Returns the default theme object
987 * @return SugarTheme object
989 public static function getDefault()
991 if ( !isset(self::$_currentTheme) )
992 self::buildRegistry();
994 if ( isset($GLOBALS['sugar_config']['default_theme']) && self::exists($GLOBALS['sugar_config']['default_theme']) ) {
995 return self::get($GLOBALS['sugar_config']['default_theme']);
998 return self::get(array_pop(array_keys(self::availableThemes())));
1002 * Returns true if a theme object specified by the given $themeName exists in the registry
1004 * @param $themeName string
1007 public static function exists(
1011 return (self::get($themeName) !== null);
1015 * Sets the given $themeName to be the current theme
1017 * @param $themeName string
1019 public static function set(
1023 if ( !self::exists($themeName) )
1026 self::$_currentTheme = $themeName;
1028 // set some of the expected globals
1029 $GLOBALS['barChartColors'] = self::current()->barChartColors;
1030 $GLOBALS['pieChartColors'] = self::current()->pieChartColors;
1034 * Builds the theme registry
1036 public static function buildRegistry()
1038 self::$_themes = array();
1039 $dirs = array("themes/","custom/themes/");
1041 // check for a default themedef file
1042 $themedefDefault = array();
1043 if ( sugar_is_file("custom/themes/default/themedef.php") ) {
1044 $themedef = array();
1045 require("custom/themes/default/themedef.php");
1046 $themedefDefault = $themedef;
1049 foreach ($dirs as $dirPath ) {
1050 if (sugar_is_dir('./'.$dirPath) && is_readable('./'.$dirPath) && $dir = opendir('./'.$dirPath)) {
1051 while (($file = readdir($dir)) !== false) {
1057 || $file == "default"
1058 || !sugar_is_dir("./$dirPath".$file)
1059 || !sugar_is_file("./{$dirPath}{$file}/themedef.php")
1062 $themedef = array();
1063 require("./{$dirPath}{$file}/themedef.php");
1064 $themedef = array_merge($themedef,$themedefDefault);
1065 $themedef['dirName'] = $file;
1066 // check for theme already existing in the registry
1067 // if so, then it will override the current one
1068 if ( self::exists($themedef['dirName']) ) {
1069 $existingTheme = self::get($themedef['dirName']);
1070 foreach ( SugarTheme::getThemeDefFields() as $field )
1071 if ( !isset($themedef[$field]) )
1072 $themedef[$field] = $existingTheme->$field;
1073 self::remove($themedef['dirName']);
1075 if ( isset($themedef['name']) ) {
1076 self::add($themedef);
1083 // default to setting the default theme as the current theme
1084 if ( !isset($GLOBALS['sugar_config']['default_theme']) || !self::set($GLOBALS['sugar_config']['default_theme']) ) {
1085 if ( count(self::availableThemes()) == 0 )
1086 sugar_die('No valid themes are found on this instance');
1088 self::set(array_pop(array_keys(self::availableThemes())));
1093 * Returns an array of available themes. Designed to be absorbed into get_select_options_with_id()
1097 public static function availableThemes()
1099 $themelist = array();
1100 $disabledThemes = array();
1101 if ( isset($GLOBALS['sugar_config']['disabled_themes']) )
1102 $disabledThemes = explode(',',$GLOBALS['sugar_config']['disabled_themes']);
1104 foreach ( self::$_themes as $themename => $themeobject ) {
1105 if ( in_array($themename,$disabledThemes) )
1107 $themelist[$themeobject->dirName] = $themeobject->name;
1109 asort($themelist, SORT_STRING);
1114 * Returns an array of un-available themes. Designed used with the theme selector in the admin panel
1118 public static function unAvailableThemes()
1120 $themelist = array();
1121 $disabledThemes = array();
1122 if ( isset($GLOBALS['sugar_config']['disabled_themes']) )
1123 $disabledThemes = explode(',',$GLOBALS['sugar_config']['disabled_themes']);
1125 foreach ( self::$_themes as $themename => $themeobject ) {
1126 if ( in_array($themename,$disabledThemes) )
1127 $themelist[$themeobject->dirName] = $themeobject->name;
1134 * Returns an array of all themes found in the current installation
1138 public static function allThemes()
1140 $themelist = array();
1142 foreach ( self::$_themes as $themename => $themeobject )
1143 $themelist[$themeobject->dirName] = $themeobject->name;
1149 * Clears out the cached path locations for all themes
1151 public static function clearAllCaches()
1153 foreach ( self::$_themes as $themeobject ) {
1154 $themeobject->clearCache();