mirror of
https://github.com/salesagility/SuiteCRM.git
synced 2024-11-21 23:47:57 +00:00
1236 lines
42 KiB
PHP
Executable File
1236 lines
42 KiB
PHP
Executable File
<?php
|
|
if (!defined('sugarEntry') || !sugarEntry) {
|
|
die('Not A Valid Entry Point');
|
|
}
|
|
/**
|
|
*
|
|
* SugarCRM Community Edition is a customer relationship management program developed by
|
|
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
|
|
*
|
|
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
|
|
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU Affero General Public License version 3 as published by the
|
|
* Free Software Foundation with the addition of the following permission added
|
|
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
|
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
|
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License along with
|
|
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301 USA.
|
|
*
|
|
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
|
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
|
*
|
|
* The interactive user interfaces in modified source and object code versions
|
|
* of this program must display Appropriate Legal Notices, as required under
|
|
* Section 5 of the GNU Affero General Public License version 3.
|
|
*
|
|
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
|
* these Appropriate Legal Notices must retain the display of the "Powered by
|
|
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
|
|
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
|
|
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
|
|
*/
|
|
|
|
|
|
/**
|
|
|
|
* Description: Contains a variety of utility functions used to display UI
|
|
* components such as form headers and footers. Intended to be modified on a per
|
|
* theme basis.
|
|
*/
|
|
|
|
include_once __DIR__ . '/SugarThemeRegistry.php';
|
|
|
|
if (!defined('JSMIN_AS_LIB')) {
|
|
define('JSMIN_AS_LIB', true);
|
|
}
|
|
|
|
require_once("include/SugarTheme/cssmin.php");
|
|
require_once("jssource/SugarMin.php");
|
|
require_once('include/utils/sugar_file_utils.php');
|
|
|
|
/**
|
|
* Class that provides tools for working with a theme.
|
|
* @api
|
|
*/
|
|
class SugarTheme
|
|
{
|
|
/**
|
|
* Theme name
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $name;
|
|
|
|
/**
|
|
* Theme description
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $description;
|
|
|
|
/**
|
|
* Defines which parent files to not include
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $ignoreParentFiles = array();
|
|
|
|
/**
|
|
* Defines which parent files to not include
|
|
*
|
|
* @var string
|
|
*/
|
|
public $directionality = 'ltr';
|
|
/**
|
|
* Theme directory name
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $dirName;
|
|
|
|
/**
|
|
* Parent theme name
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $parentTheme;
|
|
|
|
/**
|
|
* Colors sets provided by the theme
|
|
*
|
|
* @deprecated only here for BC during upgrades
|
|
* @var array
|
|
*/
|
|
protected $colors = array();
|
|
|
|
/**
|
|
* Font sets provided by the theme
|
|
*
|
|
* @deprecated only here for BC during upgrades
|
|
* @var array
|
|
*/
|
|
protected $fonts = array();
|
|
|
|
/**
|
|
* Maximum sugar version this theme is for; defaults to 5.5.1 as all the themes without this
|
|
* parameter as assumed to work thru 5.5.1
|
|
*
|
|
* @var int
|
|
*/
|
|
protected $version = '5.5.1';
|
|
|
|
/**
|
|
* Colors used in bar charts
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $barChartColors = array(
|
|
"docBorder" => "0xffffff",
|
|
"docBg1" => "0xffffff",
|
|
"docBg2" => "0xffffff",
|
|
"xText" => "0x33485c",
|
|
"yText" => "0x33485c",
|
|
"title" => "0x333333",
|
|
"misc" => "0x999999",
|
|
"altBorder" => "0xffffff",
|
|
"altBg" => "0xffffff",
|
|
"altText" => "0x666666",
|
|
"graphBorder" => "0xcccccc",
|
|
"graphBg1" => "0xf6f6f6",
|
|
"graphBg2" => "0xf6f6f6",
|
|
"graphLines" => "0xcccccc",
|
|
"graphText" => "0x333333",
|
|
"graphTextShadow" => "0xf9f9f9",
|
|
"barBorder" => "0xeeeeee",
|
|
"barBorderHilite" => "0x333333",
|
|
"legendBorder" => "0xffffff",
|
|
"legendBg1" => "0xffffff",
|
|
"legendBg2" => "0xffffff",
|
|
"legendText" => "0x444444",
|
|
"legendColorKeyBorder" => "0x777777",
|
|
"scrollBar" => "0xcccccc",
|
|
"scrollBarBorder" => "0xeeeeee",
|
|
"scrollBarTrack" => "0xeeeeee",
|
|
"scrollBarTrackBorder" => "0xcccccc",
|
|
);
|
|
|
|
/**
|
|
* Colors used in pie charts
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $pieChartColors = array(
|
|
"docBorder" => "0xffffff",
|
|
"docBg1" => "0xffffff",
|
|
"docBg2" => "0xffffff",
|
|
"title" => "0x333333",
|
|
"subtitle" => "0x666666",
|
|
"misc" => "0x999999",
|
|
"altBorder" => "0xffffff",
|
|
"altBg" => "0xffffff",
|
|
"altText" => "0x666666",
|
|
"graphText" => "0x33485c",
|
|
"graphTextShadow" => "0xf9f9f9",
|
|
"pieBorder" => "0xffffff",
|
|
"pieBorderHilite" => "0x333333",
|
|
"legendBorder" => "0xffffff",
|
|
"legendBg1" => "0xffffff",
|
|
"legendBg2" => "0xffffff",
|
|
"legendText" => "0x444444",
|
|
"legendColorKeyBorder" => "0x777777",
|
|
"scrollBar" => "0xdfdfdf",
|
|
"scrollBarBorder" => "0xfafafa",
|
|
"scrollBarTrack" => "0xeeeeee",
|
|
"scrollBarTrackBorder" => "0xcccccc",
|
|
);
|
|
|
|
/**
|
|
* Does this theme support group tabs
|
|
*
|
|
* @var bool
|
|
*/
|
|
public $group_tabs;
|
|
|
|
/**
|
|
* Support for classic themes
|
|
*
|
|
* @var bool
|
|
*/
|
|
public $classic;
|
|
|
|
/**
|
|
* Is this theme configurable
|
|
*
|
|
* @var bool
|
|
*/
|
|
public $configurable;
|
|
|
|
/**
|
|
* theme config options
|
|
*
|
|
* @var bool
|
|
*/
|
|
public $config_options = array();
|
|
|
|
|
|
/**
|
|
* Cache built of all css files locations
|
|
*
|
|
* @var array
|
|
*/
|
|
private $_cssCache = array();
|
|
|
|
/**
|
|
* Cache built of all image files locations
|
|
*
|
|
* @var array
|
|
*/
|
|
private $_imageCache = array();
|
|
|
|
/**
|
|
* Cache built of all javascript files locations
|
|
*
|
|
* @var array
|
|
*/
|
|
private $_jsCache = array();
|
|
|
|
/**
|
|
* Cache built of all template files locations
|
|
*
|
|
* @var array
|
|
*/
|
|
private $_templateCache = array();
|
|
|
|
/**
|
|
* Cache built of sprite meta data
|
|
*
|
|
* @var array
|
|
*/
|
|
private $_spriteCache = array();
|
|
|
|
/**
|
|
* Size of the caches after the are initialized in the constructor
|
|
*
|
|
* @var array
|
|
*/
|
|
private $_initialCacheSize = array(
|
|
'cssCache' => 0,
|
|
'imageCache' => 0,
|
|
'jsCache' => 0,
|
|
'templateCache' => 0,
|
|
'spriteCache' => 0,
|
|
);
|
|
|
|
/**
|
|
* Controls whether or not to clear the cache on destroy; defaults to false
|
|
*/
|
|
private $_clearCacheOnDestroy = false;
|
|
|
|
private $imageExtensions = array(
|
|
'svg' => 'image/svg+xml',
|
|
'gif' => 'image/gif',
|
|
'png' => 'image/png',
|
|
'jpg' => 'image/jpeg',
|
|
'tif' => 'image/tiff',
|
|
'bmp' => 'image/bmp',
|
|
);
|
|
|
|
/**
|
|
* Returns the mime type for the image extension in case it is supported.
|
|
* In case the extension isn't supported returns null.
|
|
*
|
|
* @param $extension The extension name, e.g. 'png'
|
|
* @return string|null
|
|
*/
|
|
public function getMimeType($extension)
|
|
{
|
|
if (!isset($this->imageExtensions[$extension])) {
|
|
return null;
|
|
}
|
|
|
|
return $this->imageExtensions[$extension];
|
|
}
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* Sets the theme properties from the defaults passed to it, and loads the file path cache from an external cache
|
|
*
|
|
* @param $defaults string defaults for the current theme
|
|
*/
|
|
public function __construct(
|
|
$defaults
|
|
) {
|
|
// apply parent theme's properties first
|
|
if (isset($defaults['parentTheme'])) {
|
|
$themedef = array();
|
|
include("themes/{$defaults['parentTheme']}/themedef.php");
|
|
foreach ($themedef as $key => $value) {
|
|
if (property_exists(__CLASS__, $key)) {
|
|
// For all arrays ( except colors and fonts ) you can just specify the items
|
|
// to change instead of all of the values
|
|
if (is_array($this->$key) && !in_array($key, array('colors','fonts'))) {
|
|
$this->$key = array_merge($this->$key, $value);
|
|
} else {
|
|
$this->$key = $value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
foreach ($defaults as $key => $value) {
|
|
if (property_exists(__CLASS__, $key)) {
|
|
// For all arrays ( except colors and fonts ) you can just specify the items
|
|
// to change instead of all of the values
|
|
if (is_array($this->$key) && !in_array($key, array('colors','fonts'))) {
|
|
$this->$key = array_merge($this->$key, $value);
|
|
} else {
|
|
$this->$key = $value;
|
|
}
|
|
}
|
|
}
|
|
if (!inDeveloperMode()) {
|
|
if (is_file($cachedfile = sugar_cached($this->getFilePath().'/pathCache.php'))) {
|
|
$caches = unserialize(file_get_contents($cachedfile));
|
|
if (isset($caches['jsCache'])) {
|
|
$this->_jsCache = $caches['jsCache'];
|
|
}
|
|
if (isset($caches['cssCache'])) {
|
|
$this->_cssCache = $caches['cssCache'];
|
|
}
|
|
if (isset($caches['imageCache'])) {
|
|
$this->_imageCache = $caches['imageCache'];
|
|
}
|
|
if (isset($caches['templateCache'])) {
|
|
$this->_templateCache = $caches['templateCache'];
|
|
}
|
|
}
|
|
$cachedfile = sugar_cached($this->getFilePath().'/spriteCache.php');
|
|
if (!empty($GLOBALS['sugar_config']['use_sprites']) && is_file($cachedfile)) {
|
|
$this->_spriteCache = unserialize(sugar_file_get_contents($cachedfile));
|
|
}
|
|
}
|
|
$this->_initialCacheSize = array(
|
|
'jsCache' => count($this->_jsCache),
|
|
'cssCache' => count($this->_cssCache),
|
|
'imageCache' => count($this->_imageCache),
|
|
'templateCache' => count($this->_templateCache),
|
|
'spriteCache' => count($this->_spriteCache),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* This is needed to prevent unserialize vulnerability
|
|
*/
|
|
public function __wakeup()
|
|
{
|
|
// clean all properties
|
|
foreach (get_object_vars($this) as $k => $v) {
|
|
$this->$k = null;
|
|
}
|
|
throw new Exception("Not a serializable object");
|
|
}
|
|
|
|
/**
|
|
* Destructor
|
|
* Here we'll write out the internal file path caches to an external cache of some sort.
|
|
*/
|
|
public function __destruct()
|
|
{
|
|
// Set the current directory to one which we expect it to be (i.e. the root directory of the install
|
|
$dir = realpath(dirname(__FILE__) . '/../..');
|
|
static $includePathIsPatched = false;
|
|
if ($includePathIsPatched == false) {
|
|
$path = explode(PATH_SEPARATOR, get_include_path());
|
|
if (in_array($dir, $path) == false) {
|
|
set_include_path($dir . PATH_SEPARATOR . get_include_path());
|
|
}
|
|
$includePathIsPatched = true;
|
|
}
|
|
chdir($dir); // destruct can be called late, and chdir could change
|
|
$cachedir = sugar_cached($this->getFilePath());
|
|
sugar_mkdir($cachedir, 0775, true);
|
|
// clear out the cache on destroy if we are asked to
|
|
if ($this->_clearCacheOnDestroy) {
|
|
if (is_file("$cachedir/pathCache.php")) {
|
|
unlink("$cachedir/pathCache.php");
|
|
}
|
|
if (is_file("$cachedir/spriteCache.php")) {
|
|
unlink("$cachedir/spriteCache.php");
|
|
}
|
|
|
|
if (($cachedir) && is_dir($cachedir . '/modules') && (!rmdir_recursive($cachedir . '/modules'))) {
|
|
throw new Exception("Unable to clear cache: $cachedir . '/modules'");
|
|
}
|
|
} elseif (!inDeveloperMode()) {
|
|
// only update the caches if they have been changed in this request
|
|
if (count($this->_jsCache) != $this->_initialCacheSize['jsCache']
|
|
|| count($this->_cssCache) != $this->_initialCacheSize['cssCache']
|
|
|| count($this->_imageCache) != $this->_initialCacheSize['imageCache']
|
|
|| count($this->_templateCache) != $this->_initialCacheSize['templateCache']
|
|
) {
|
|
sugar_file_put_contents(
|
|
"$cachedir/pathCache.php",
|
|
serialize(
|
|
array(
|
|
'jsCache' => $this->_jsCache,
|
|
'cssCache' => $this->_cssCache,
|
|
'imageCache' => $this->_imageCache,
|
|
'templateCache' => $this->_templateCache,
|
|
)
|
|
)
|
|
);
|
|
}
|
|
if (count($this->_spriteCache) != $this->_initialCacheSize['spriteCache']) {
|
|
sugar_file_put_contents(
|
|
"$cachedir/spriteCache.php",
|
|
serialize($this->_spriteCache)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Specifies what is returned when the object is cast to a string, in this case it will be the
|
|
* theme directory name.
|
|
*
|
|
* @return string theme directory name
|
|
*/
|
|
public function __toString()
|
|
{
|
|
return $this->dirName;
|
|
}
|
|
|
|
/**
|
|
* Generic public accessor method for all the properties of the theme ( which are kept protected )
|
|
*
|
|
* @return string
|
|
*/
|
|
public function __get(
|
|
$key
|
|
) {
|
|
if (isset($this->$key)) {
|
|
return $this->$key;
|
|
}
|
|
}
|
|
|
|
public function __isset($key)
|
|
{
|
|
return isset($this->$key);
|
|
}
|
|
|
|
public function clearJSCache()
|
|
{
|
|
$this->_jsCache = array();
|
|
}
|
|
|
|
/**
|
|
* Clears out the caches used for this themes
|
|
*/
|
|
public function clearCache()
|
|
{
|
|
$this->_clearCacheOnDestroy = true;
|
|
}
|
|
|
|
/**
|
|
* Return array of all valid fields that can be specified in the themedef.php file
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function getThemeDefFields()
|
|
{
|
|
return array(
|
|
'name',
|
|
'description',
|
|
'directionality',
|
|
'dirName',
|
|
'parentTheme',
|
|
'version',
|
|
'colors',
|
|
'fonts',
|
|
'barChartColors',
|
|
'pieChartColors',
|
|
'group_tabs',
|
|
'classic',
|
|
'configurable',
|
|
'config_options',
|
|
'ignoreParentFiles',
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns the file path of the current theme
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getFilePath()
|
|
{
|
|
return 'themes/'.$this->dirName;
|
|
}
|
|
|
|
/**
|
|
* Returns the image path of the current theme
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getImagePath()
|
|
{
|
|
return $this->getFilePath().'/images';
|
|
}
|
|
|
|
/**
|
|
* Returns the css path of the current theme
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getCSSPath()
|
|
{
|
|
return $this->getFilePath().'/css';
|
|
}
|
|
|
|
/**
|
|
* Returns the javascript path of the current theme
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getJSPath()
|
|
{
|
|
return $this->getFilePath().'/js';
|
|
}
|
|
|
|
/**
|
|
* Returns the tpl path of the current theme
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getTemplatePath()
|
|
{
|
|
return $this->getFilePath().'/tpls';
|
|
}
|
|
|
|
/**
|
|
* Returns the file path of the theme defaults
|
|
*
|
|
* @return string
|
|
*/
|
|
final public function getDefaultFilePath()
|
|
{
|
|
return 'themes/default';
|
|
}
|
|
|
|
/**
|
|
* Returns the image path of the theme defaults
|
|
*
|
|
* @return string
|
|
*/
|
|
final public function getDefaultImagePath()
|
|
{
|
|
return $this->getDefaultFilePath().'/images';
|
|
}
|
|
|
|
/**
|
|
* Returns the css path of the theme defaults
|
|
*
|
|
* @return string
|
|
*/
|
|
final public function getDefaultCSSPath()
|
|
{
|
|
return $this->getDefaultFilePath().'/css';
|
|
}
|
|
|
|
/**
|
|
* Returns the template path of the theme defaults
|
|
*
|
|
* @return string
|
|
*/
|
|
final public function getDefaultTemplatePath()
|
|
{
|
|
return $this->getDefaultFilePath().'/tpls';
|
|
}
|
|
|
|
/**
|
|
* Returns the javascript path of the theme defaults
|
|
*
|
|
* @return string
|
|
*/
|
|
final public function getDefaultJSPath()
|
|
{
|
|
return $this->getDefaultFilePath().'/js';
|
|
}
|
|
|
|
/**
|
|
* Returns CSS for the current theme.
|
|
*
|
|
* @param $color string optional, specifies the css color file to use if the theme supports it; defaults to cookie value or theme default
|
|
* @param $font string optional, specifies the css font file to use if the theme supports it; defaults to cookie value or theme default
|
|
* @return string HTML code
|
|
*/
|
|
public function getCSS(
|
|
$color = null,
|
|
$font = null
|
|
) {
|
|
// include style.css file
|
|
$html = '
|
|
<!-- qtip & suggestion box -->
|
|
<link rel="stylesheet" type="text/css" href="include/javascript/qtip/jquery.qtip.min.css" />';
|
|
$html .= '<link rel="stylesheet" type="text/css" href="'.$this->getCSSURL('yui.css').'" />';
|
|
$html .= '<link rel="stylesheet" type="text/css" href="include/javascript/jquery/themes/base/jquery.ui.all.css" />';
|
|
|
|
// sprites
|
|
if (!empty($GLOBALS['sugar_config']['use_sprites']) && $GLOBALS['sugar_config']['use_sprites']) {
|
|
|
|
// system wide sprites
|
|
if (file_exists("cache/sprites/default/sprites.css")) {
|
|
$html .= '<link rel="stylesheet" type="text/css" href="'.getJSPath('cache/sprites/default/sprites.css').'" />';
|
|
}
|
|
|
|
// theme specific sprites
|
|
if (file_exists("cache/sprites/{$this->dirName}/sprites.css")) {
|
|
$html .= '<link rel="stylesheet" type="text/css" href="'.getJSPath('cache/sprites/'.$this->dirName.'/sprites.css').'" />';
|
|
}
|
|
|
|
// parent sprites
|
|
if ($this->parentTheme && $parent = SugarThemeRegistry::get($this->parentTheme)) {
|
|
if (file_exists("cache/sprites/{$parent->dirName}/sprites.css")) {
|
|
$html .= '<link rel="stylesheet" type="text/css" href="'.getJSPath('cache/sprites/'.$parent->dirName.'/sprites.css').'" />';
|
|
}
|
|
}
|
|
|
|
// repeatable sprites
|
|
if (file_exists("cache/sprites/Repeatable/sprites.css")) {
|
|
$html .= '<link rel="stylesheet" type="text/css" href="'.getJSPath('cache/sprites/Repeatable/sprites.css').'" />';
|
|
}
|
|
}
|
|
|
|
// for BC during upgrade
|
|
if (!empty($this->colors)) {
|
|
if (isset($_SESSION['authenticated_user_theme_color']) && in_array($_SESSION['authenticated_user_theme_color'], $this->colors)) {
|
|
$color = $_SESSION['authenticated_user_theme_color'];
|
|
} else {
|
|
$color = $this->colors[0];
|
|
}
|
|
$html .= '<link rel="stylesheet" type="text/css" href="'.$this->getCSSURL('colors.'.$color.'.css').'" id="current_color_style" />';
|
|
}
|
|
|
|
if (!empty($this->fonts)) {
|
|
if (isset($_SESSION['authenticated_user_theme_font']) && in_array($_SESSION['authenticated_user_theme_font'], $this->fonts)) {
|
|
$font = $_SESSION['authenticated_user_theme_font'];
|
|
} else {
|
|
$font = $this->fonts[0];
|
|
}
|
|
$html .= '<link rel="stylesheet" type="text/css" href="'.$this->getCSSURL('fonts.'.$font.'.css').'" id="current_font_style" />';
|
|
}
|
|
|
|
|
|
$html .= '<link rel="stylesheet" type="text/css" href="'.$this->getCSSURL('style.css').'" />';
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* Returns javascript for the current theme
|
|
*
|
|
* @return string HTML code
|
|
*/
|
|
public function getJS()
|
|
{
|
|
$styleJS = $this->getJSURL('style.js');
|
|
return <<<EOHTML
|
|
<script type="text/javascript" src="$styleJS"></script>
|
|
EOHTML;
|
|
}
|
|
|
|
/**
|
|
* Returns the path for the tpl file in the current theme. If not found in the current theme, will revert
|
|
* to looking in the base theme.
|
|
*
|
|
* @param string $templateName tpl file name
|
|
* @return string path of tpl file to include
|
|
*/
|
|
public function getTemplate(
|
|
$templateName
|
|
) {
|
|
if (isset($this->_templateCache[$templateName])) {
|
|
return $this->_templateCache[$templateName];
|
|
}
|
|
|
|
$templatePath = '';
|
|
if (is_file('custom/'.$this->getTemplatePath().'/'.$templateName)) {
|
|
$templatePath = 'custom/'.$this->getTemplatePath().'/'.$templateName;
|
|
} elseif (is_file($this->getTemplatePath().'/'.$templateName)) {
|
|
$templatePath = $this->getTemplatePath().'/'.$templateName;
|
|
} elseif (isset($this->parentTheme)
|
|
&& SugarThemeRegistry::get($this->parentTheme) instanceof SugarTheme
|
|
&& ($filename = SugarThemeRegistry::get($this->parentTheme)->getTemplate($templateName)) != '') {
|
|
$templatePath = $filename;
|
|
} elseif (is_file('custom/'.$this->getDefaultTemplatePath().'/'.$templateName)) {
|
|
$templatePath = 'custom/'.$this->getDefaultTemplatePath().'/'.$templateName;
|
|
} elseif (is_file($this->getDefaultTemplatePath().'/'.$templateName)) {
|
|
$templatePath = $this->getDefaultTemplatePath().'/'.$templateName;
|
|
} else {
|
|
$GLOBALS['log']->warn("Template $templateName not found");
|
|
return false;
|
|
}
|
|
|
|
$this->_imageCache[$templateName] = $templatePath;
|
|
|
|
return $templatePath;
|
|
}
|
|
|
|
/**
|
|
* Returns an image tag for the given image.
|
|
*
|
|
* @param string $image image name
|
|
* @param string $other_attributes optional, other attributes to add to the image tag, not cached
|
|
* @param string $width optional, defaults to the actual image's width
|
|
* @param string $height optional, defaults to the actual image's height
|
|
* @param string $ext optional, image extension (TODO can we deprecate this one ?)
|
|
* @param string $alt optional, only used when image contains something useful, i.e. "Sally's profile pic"
|
|
* @param string $imageJSONEncode optional, some of template javascript need the exact image-html-string to build HTML contents so this parameter make a json_encode call on the return SVG or image source
|
|
* @param string $forceExt optional, force image extension
|
|
* @return string HTML image tag or sprite
|
|
*/
|
|
public function getImage($imageName, $other_attributes = '', $width = null, $height = null, $ext = null, $alt = '', $imageJSONEncode = false, $forceExt = null)
|
|
{
|
|
static $cached_results = array();
|
|
|
|
// look for .svg first
|
|
if (strpos($imageName, '.svg') !== false) {
|
|
$ext = '';
|
|
} else {
|
|
// Look for SVG first
|
|
$imagePath = SugarThemeRegistry::current()->getImagePath().DIRECTORY_SEPARATOR.$imageName.'.svg';
|
|
if (file_exists($imagePath)) {
|
|
$ext = '.svg';
|
|
}
|
|
}
|
|
|
|
if ($forceExt) {
|
|
$ext = $forceExt;
|
|
}
|
|
|
|
|
|
// trap deprecated use of image extension
|
|
if (is_null($ext)) {
|
|
$imageNameExp = explode('.', $imageName);
|
|
if (count($imageNameExp) == 1) {
|
|
$imageName .= '.gif';
|
|
}
|
|
} else {
|
|
$imageName .= $ext;
|
|
}
|
|
|
|
// trap alt attributes in other_attributes
|
|
if (preg_match('/alt=["\']([^\'"]+)["\']/i', $other_attributes)) {
|
|
$GLOBALS['log']->debug("Sprites: alt attribute detected for $imageName");
|
|
}
|
|
// sprite handler, makes use of own caching mechanism
|
|
if (!empty($GLOBALS['sugar_config']['use_sprites']) && $GLOBALS['sugar_config']['use_sprites']) {
|
|
// get sprite metadata
|
|
if ($sp = $this->getSpriteMeta($imageName)) {
|
|
// requested size should match
|
|
if ((!is_null($width) && $sp['width'] == $width) || (is_null($width)) &&
|
|
(!is_null($height) && $sp['height'] == $height) || (is_null($height))) {
|
|
$other_attributes .= ' data-orig="'.$imageName.'"';
|
|
if ($sprite = $this->getSprite($sp['class'], $other_attributes, $alt)) {
|
|
return $imageJSONEncode ? json_encode($sprite) : $sprite;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// img caching
|
|
if (empty($cached_results[$imageName])) {
|
|
$imageURL = $this->getImageURL($imageName, false);
|
|
if (empty($imageURL)) {
|
|
return false;
|
|
}
|
|
if (strpos($imageURL, '.svg', strlen($imageURL)-4)) {
|
|
$cached_results[$imageName] = file_get_contents($imageURL);
|
|
} else {
|
|
$cached_results[$imageName] = '<img src="'.getJSPath($imageURL).'" ';
|
|
}
|
|
}
|
|
|
|
$attr_width = (is_null($width)) ? "" : "width=\"$width\"";
|
|
$attr_height = (is_null($height)) ? "" : "height=\"$height\"";
|
|
|
|
if (strpos($cached_results[$imageName], 'svg') !== false) {
|
|
return $imageJSONEncode ? json_encode($cached_results[$imageName]) : $cached_results[$imageName];
|
|
}
|
|
$ret = $cached_results[$imageName] . " $attr_width $attr_height $other_attributes alt=\"$alt\" />";
|
|
return $imageJSONEncode ? json_encode($ret) : $ret;
|
|
}
|
|
|
|
/**
|
|
* Returns sprite meta data
|
|
*
|
|
* @param string $imageName Image filename including extension
|
|
* @return array Sprite meta data
|
|
*/
|
|
public function getSpriteMeta($imageName)
|
|
{
|
|
|
|
// return from cache
|
|
if (isset($this->_spriteCache[$imageName])) {
|
|
return $this->_spriteCache[$imageName];
|
|
}
|
|
|
|
// sprite keys are base on imageURL
|
|
$imageURL = $this->getImageURL($imageName, false);
|
|
if (empty($imageURL)) {
|
|
$this->_spriteCache[$imageName] = false;
|
|
return false;
|
|
}
|
|
|
|
// load meta data, includes default images
|
|
require_once("include/SugarTheme/SugarSprites.php");
|
|
$meta = SugarSprites::getInstance();
|
|
// add current theme dir
|
|
$meta->loadSpriteMeta($this->dirName);
|
|
// add parent theme dir
|
|
if ($this->parentTheme && $parent = SugarThemeRegistry::get($this->parentTheme)) {
|
|
$meta->loadSpriteMeta($parent->dirName);
|
|
}
|
|
|
|
// add to cache
|
|
if (isset($meta->sprites[$imageURL])) {
|
|
$this->_spriteCache[$imageName] = $meta->sprites[$imageURL];
|
|
// add imageURL to cache
|
|
//$this->_spriteCache[$imageName]['imageURL'] = $imageURL;
|
|
} else {
|
|
$this->_spriteCache[$imageName] = false;
|
|
$GLOBALS['log']->debug("Sprites: miss for $imageURL");
|
|
}
|
|
return $this->_spriteCache[$imageName];
|
|
}
|
|
|
|
/**
|
|
* Returns sprite HTML span tag
|
|
*
|
|
* @param string class The md5 id used in the CSS sprites class
|
|
* @param string attr optional, list of additional html attributes
|
|
* @param string title optional, the title (equivalent to alt on img)
|
|
* @return string HTML span tag
|
|
*/
|
|
public function getSprite($class, $attr, $title)
|
|
{
|
|
|
|
// handle multiple class tags
|
|
$class_regex = '/class=["\']([^\'"]+)["\']/i';
|
|
preg_match($class_regex, $attr, $match);
|
|
if (isset($match[1])) {
|
|
$attr = preg_replace($class_regex, 'class="spr_'.$class.' ${1}"', $attr);
|
|
|
|
// single class
|
|
} else {
|
|
$attr .= ' class="spr_'.$class.'"';
|
|
}
|
|
|
|
if ($title) {
|
|
$attr .= ' title="'.$title.'"';
|
|
}
|
|
|
|
// use </span> instead of /> to prevent weird UI results
|
|
$GLOBALS['log']->debug("Sprites: generated sprite -> $attr");
|
|
return "<span {$attr}></span>";
|
|
}
|
|
|
|
/**
|
|
* Returns a link HTML tag with or without an embedded image
|
|
*/
|
|
public function getLink(
|
|
$url,
|
|
$title,
|
|
$other_attributes = '',
|
|
$img_name = '',
|
|
$img_other_attributes = '',
|
|
$img_width = null,
|
|
$img_height = null,
|
|
$img_alt = '',
|
|
$img_placement = 'imageonly'
|
|
) {
|
|
if ($img_name) {
|
|
$img = $this->getImage($img_name, $img_other_attributes, $img_width, $img_height, null, $img_alt);
|
|
if ($img == false) {
|
|
$GLOBALS['log']->debug('Sprites: unknown image getLink');
|
|
$img = 'unknown';
|
|
}
|
|
switch ($img_placement) {
|
|
case 'left': $inner_html = $img."<span class='title'>".$title."</span>"; break;
|
|
case 'right': $inner_html = "<span class='title'>".$title."</span>".$img; break;
|
|
default: $inner_html = $img; break;
|
|
}
|
|
} else {
|
|
$inner_html = $title;
|
|
}
|
|
|
|
return '<a href="'.$url.'" title="'.$title.'" '.$other_attributes.'>'.$inner_html.'</a>';
|
|
}
|
|
|
|
/**
|
|
* Returns the URL for an image in the current theme. If not found in the current theme, will revert
|
|
* to looking in the base theme.
|
|
* @param string $imageName image file name
|
|
* @param bool $addJSPath call getJSPath() with the results to add some unique image tracking support
|
|
* @return string|bool path to image or false if image not found
|
|
*/
|
|
public function getImageURL(
|
|
$imageName,
|
|
$addJSPath = true
|
|
) {
|
|
if (isset($this->_imageCache[$imageName])) {
|
|
if ($addJSPath) {
|
|
return getJSPath($this->_imageCache[$imageName]);
|
|
} else {
|
|
return $this->_imageCache[$imageName];
|
|
}
|
|
}
|
|
$imagePath = '';
|
|
if (($filename = $this->_getImageFileName('custom/'.$this->getImagePath().'/'.$imageName)) != '') {
|
|
$imagePath = $filename;
|
|
} elseif (($filename = $this->_getImageFileName($this->getImagePath().'/'.$imageName)) != '') {
|
|
$imagePath = $filename;
|
|
} elseif (isset($this->parentTheme)
|
|
&& SugarThemeRegistry::get($this->parentTheme) instanceof SugarTheme
|
|
&& ($filename = SugarThemeRegistry::get($this->parentTheme)->getImageURL($imageName, false)) != '') {
|
|
$imagePath = $filename;
|
|
} elseif (($filename = $this->_getImageFileName('custom/'.$this->getDefaultImagePath().'/'.$imageName)) != '') {
|
|
$imagePath = $filename;
|
|
} elseif (($filename = $this->_getImageFileName($this->getDefaultImagePath().'/'.$imageName)) != '') {
|
|
$imagePath = $filename;
|
|
} elseif (($filename = $this->_getImageFileName('include/images/'.$imageName)) != '') {
|
|
$imagePath = $filename;
|
|
} else {
|
|
$imagePath = false;
|
|
}
|
|
|
|
|
|
if ($imagePath) {
|
|
$this->_imageCache[$imageName] = $imagePath;
|
|
|
|
if ($addJSPath) {
|
|
return getJSPath($imagePath);
|
|
}
|
|
}
|
|
|
|
return $imagePath;
|
|
}
|
|
|
|
/**
|
|
* Checks for an image using all of the accepted image extensions
|
|
*
|
|
* @param string $imageName image file name
|
|
* @return string path to image
|
|
*/
|
|
protected function _getImageFileName(
|
|
$imageName
|
|
) {
|
|
// return now if the extension matches that of which we are looking for
|
|
if (is_file($imageName)) {
|
|
return $imageName;
|
|
}
|
|
$pathParts = pathinfo($imageName);
|
|
foreach (array_keys($this->imageExtensions) as $extension) {
|
|
if (isset($pathParts['extension'])) {
|
|
if (($extension != $pathParts['extension'])
|
|
&& is_file($pathParts['dirname'].'/'.$pathParts['filename'].'.'.$extension)) {
|
|
return $pathParts['dirname'].'/'.$pathParts['filename'].'.'.$extension;
|
|
}
|
|
}
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Returns the URL for the css file in the current theme. If not found in the current theme, will revert
|
|
* to looking in the base theme.
|
|
*
|
|
* @param string $cssFileName css file name
|
|
* @param bool $returnURL if true, returns URL with unique image mark, otherwise returns path to the file
|
|
* @return string path of css file to include
|
|
*/
|
|
public function getCSSURL($cssFileName, $returnURL = true)
|
|
{
|
|
if (preg_match('/.css$/', $cssFileName)) {
|
|
global $current_user;
|
|
if (method_exists($current_user, 'getSubTheme')) {
|
|
$subTheme = $current_user->getSubTheme();
|
|
$cssFileName = $subTheme . '/' . $cssFileName;
|
|
}
|
|
}
|
|
|
|
if (isset($this->_cssCache[$cssFileName]) && is_file(sugar_cached($this->_cssCache[$cssFileName]))) {
|
|
if ($returnURL) {
|
|
return getJSPath("cache/".$this->_cssCache[$cssFileName]);
|
|
} else {
|
|
return sugar_cached($this->_cssCache[$cssFileName]);
|
|
}
|
|
}
|
|
|
|
$cssFileContents = '';
|
|
$defaultFileName = $this->getDefaultCSSPath().'/'.$cssFileName;
|
|
$fullFileName = $this->getCSSPath().'/'.$cssFileName;
|
|
if (isset($this->parentTheme)
|
|
&& SugarThemeRegistry::get($this->parentTheme) instanceof SugarTheme
|
|
&& ($filename = SugarThemeRegistry::get($this->parentTheme)->getCSSURL($cssFileName, false)) != '') {
|
|
$cssFileContents .= file_get_contents($filename);
|
|
} else {
|
|
if (is_file($defaultFileName)) {
|
|
$cssFileContents .= file_get_contents($defaultFileName);
|
|
}
|
|
if (is_file('custom/'.$defaultFileName)) {
|
|
$cssFileContents .= file_get_contents('custom/'.$defaultFileName);
|
|
}
|
|
}
|
|
if (is_file($fullFileName)) {
|
|
$cssFileContents .= file_get_contents($fullFileName);
|
|
}
|
|
if (is_file('custom/'.$fullFileName)) {
|
|
$cssFileContents .= file_get_contents('custom/'.$fullFileName);
|
|
}
|
|
if (empty($cssFileContents)) {
|
|
$GLOBALS['log']->warn("CSS File $cssFileName not found");
|
|
return false;
|
|
}
|
|
|
|
// fix any image references that may be defined in css files
|
|
$cssFileContents = str_ireplace(
|
|
"entryPoint=getImage&",
|
|
"entryPoint=getImage&themeName={$this->dirName}&",
|
|
$cssFileContents
|
|
);
|
|
|
|
// create the cached file location
|
|
$cssFilePath = create_cache_directory($fullFileName);
|
|
|
|
// if this is the style.css file, prepend the base.css and calendar-win2k-cold-1.css
|
|
// files before the theme styles
|
|
if ($cssFileName == 'style.css' && !isset($this->parentTheme)) {
|
|
if (inDeveloperMode()) {
|
|
$cssFileContents = file_get_contents('include/javascript/yui/build/base/base.css') . $cssFileContents;
|
|
} else {
|
|
$cssFileContents = file_get_contents('include/javascript/yui/build/base/base-min.css') . $cssFileContents;
|
|
}
|
|
}
|
|
|
|
// minify the css
|
|
if (!inDeveloperMode() && !is_file($cssFilePath)) {
|
|
$cssFileContents = cssmin::minify($cssFileContents);
|
|
}
|
|
|
|
// now write the css to cache
|
|
sugar_file_put_contents($cssFilePath, $cssFileContents);
|
|
|
|
$this->_cssCache[$cssFileName] = $fullFileName;
|
|
|
|
if ($returnURL) {
|
|
return getJSPath("cache/".$fullFileName);
|
|
}
|
|
|
|
return sugar_cached($fullFileName);
|
|
}
|
|
|
|
/**
|
|
* Returns the URL for an image in the current theme. If not found in the current theme, will revert
|
|
* to looking in the base theme.
|
|
*
|
|
* @param string $jsFileName js file name
|
|
* @param bool $returnURL if true, returns URL with unique image mark, otherwise returns path to the file
|
|
* @return string path to js file
|
|
*/
|
|
public function getJSURL($jsFileName, $returnURL = true)
|
|
{
|
|
if (isset($this->_jsCache[$jsFileName]) && is_file(sugar_cached($this->_jsCache[$jsFileName]))) {
|
|
if ($returnURL) {
|
|
return getJSPath("cache/".$this->_jsCache[$jsFileName]);
|
|
} else {
|
|
return sugar_cached($this->_jsCache[$jsFileName]);
|
|
}
|
|
}
|
|
|
|
$jsFileContents = '';
|
|
$fullFileName = $this->getJSPath().'/'.$jsFileName;
|
|
$defaultFileName = $this->getDefaultJSPath().'/'.$jsFileName;
|
|
if (isset($this->parentTheme)
|
|
&& SugarThemeRegistry::get($this->parentTheme) instanceof SugarTheme
|
|
&& ($filename = SugarThemeRegistry::get($this->parentTheme)->getJSURL($jsFileName, false)) != '' && !in_array($jsFileName, $this->ignoreParentFiles)) {
|
|
$jsFileContents .= file_get_contents($filename);
|
|
} else {
|
|
if (is_file($defaultFileName)) {
|
|
$jsFileContents .= file_get_contents($defaultFileName);
|
|
}
|
|
if (is_file('custom/'.$defaultFileName)) {
|
|
$jsFileContents .= file_get_contents('custom/'.$defaultFileName);
|
|
}
|
|
}
|
|
if (is_file($fullFileName)) {
|
|
$jsFileContents .= file_get_contents($fullFileName);
|
|
}
|
|
if (is_file('custom/'.$fullFileName)) {
|
|
$jsFileContents .= file_get_contents('custom/'.$fullFileName);
|
|
}
|
|
if (empty($jsFileContents)) {
|
|
$GLOBALS['log']->warn("Javascript File $jsFileName not found");
|
|
return false;
|
|
}
|
|
|
|
// create the cached file location
|
|
$jsFilePath = create_cache_directory($fullFileName);
|
|
|
|
// minify the js
|
|
if (!inDeveloperMode()&& !is_file(str_replace('.js', '-min.js', $jsFilePath))) {
|
|
$jsFileContents = SugarMin::minify($jsFileContents);
|
|
$jsFilePath = str_replace('.js', '-min.js', $jsFilePath);
|
|
$fullFileName = str_replace('.js', '-min.js', $fullFileName);
|
|
}
|
|
|
|
// now write the js to cache
|
|
sugar_file_put_contents($jsFilePath, $jsFileContents);
|
|
|
|
$this->_jsCache[$jsFileName] = $fullFileName;
|
|
|
|
if ($returnURL) {
|
|
return getJSPath("cache/".$fullFileName);
|
|
}
|
|
|
|
return sugar_cached($fullFileName);
|
|
}
|
|
|
|
/**
|
|
* Returns an array of all of the images available for the current theme
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getAllImages()
|
|
{
|
|
// first, lets get all the paths of where to look
|
|
$pathsToSearch = array($this->getImagePath());
|
|
$theme = $this;
|
|
while (isset($theme->parentTheme) && SugarThemeRegistry::get($theme->parentTheme) instanceof SugarTheme) {
|
|
$theme = SugarThemeRegistry::get($theme->parentTheme);
|
|
$pathsToSearch[] = $theme->getImagePath();
|
|
}
|
|
$pathsToSearch[] = $this->getDefaultImagePath();
|
|
|
|
// now build the array
|
|
$imageArray = array();
|
|
foreach ($pathsToSearch as $path) {
|
|
if (!is_dir($path)) {
|
|
$path = "custom/$path";
|
|
}
|
|
if (is_dir($path) && is_readable($path) && $dir = opendir($path)) {
|
|
while (($file = readdir($dir)) !== false) {
|
|
if ($file == ".."
|
|
|| $file == "."
|
|
|| $file == ".svn"
|
|
|| $file == "CVS"
|
|
|| $file == "Attic"
|
|
) {
|
|
continue;
|
|
}
|
|
if (!isset($imageArray[$file])) {
|
|
$imageArray[$file] = $this->getImageURL($file, false);
|
|
}
|
|
}
|
|
closedir($dir);
|
|
}
|
|
}
|
|
|
|
ksort($imageArray);
|
|
|
|
return $imageArray;
|
|
}
|
|
|
|
/**
|
|
* Returns an array of all of the config values for the current theme
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getConfig()
|
|
{
|
|
global $sugar_config;
|
|
|
|
$config = array();
|
|
|
|
foreach ($this->config_options as $name => $def) {
|
|
$config[$name] = $def;
|
|
|
|
$value = '';
|
|
if (isset($sugar_config['theme_settings'][$this->dirName][$name])) {
|
|
$value = $sugar_config['theme_settings'][$this->dirName][$name];
|
|
} else {
|
|
if (isset($def['default'])) {
|
|
$value = $def['default'];
|
|
}
|
|
}
|
|
$config[$name] = $value;
|
|
}
|
|
|
|
return $config;
|
|
}
|
|
|
|
|
|
public function getSubThemes()
|
|
{
|
|
$subThemes = SugarThemeRegistry::getSubThemes();
|
|
return $subThemes;
|
|
}
|
|
|
|
public function getSubThemeDefault()
|
|
{
|
|
$subThemeDefault = SugarThemeRegistry::getSubThemeDefault();
|
|
return $subThemeDefault;
|
|
}
|
|
}
|