This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); |
||
3 | /********************************************************************************* |
||
4 | * SugarCRM Community Edition is a customer relationship management program developed by |
||
5 | * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. |
||
6 | |||
7 | * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd. |
||
8 | * Copyright (C) 2011 - 2014 Salesagility Ltd. |
||
9 | * |
||
10 | * This program is free software; you can redistribute it and/or modify it under |
||
11 | * the terms of the GNU Affero General Public License version 3 as published by the |
||
12 | * Free Software Foundation with the addition of the following permission added |
||
13 | * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK |
||
14 | * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY |
||
15 | * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. |
||
16 | * |
||
17 | * This program is distributed in the hope that it will be useful, but WITHOUT |
||
18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
||
19 | * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
||
20 | * details. |
||
21 | * |
||
22 | * You should have received a copy of the GNU Affero General Public License along with |
||
23 | * this program; if not, see http://www.gnu.org/licenses or write to the Free |
||
24 | * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
||
25 | * 02110-1301 USA. |
||
26 | * |
||
27 | * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, |
||
28 | * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected]. |
||
29 | * |
||
30 | * The interactive user interfaces in modified source and object code versions |
||
31 | * of this program must display Appropriate Legal Notices, as required under |
||
32 | * Section 5 of the GNU Affero General Public License version 3. |
||
33 | * |
||
34 | * In accordance with Section 7(b) of the GNU Affero General Public License version 3, |
||
35 | * these Appropriate Legal Notices must retain the display of the "Powered by |
||
36 | * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not |
||
37 | * reasonably feasible for technical reasons, the Appropriate Legal Notices must |
||
38 | * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". |
||
39 | ********************************************************************************/ |
||
40 | |||
41 | |||
42 | /********************************************************************************* |
||
43 | |||
44 | * Description: Contains a variety of utility functions used to display UI |
||
45 | * components such as form headers and footers. Intended to be modified on a per |
||
46 | * theme basis. |
||
47 | ********************************************************************************/ |
||
48 | |||
49 | if(!defined('JSMIN_AS_LIB')) |
||
50 | define('JSMIN_AS_LIB', true); |
||
51 | |||
52 | require_once("include/SugarTheme/cssmin.php"); |
||
53 | require_once("jssource/jsmin.php"); |
||
54 | require_once('include/utils/sugar_file_utils.php'); |
||
55 | |||
56 | /** |
||
57 | * Class that provides tools for working with a theme. |
||
58 | * @api |
||
59 | */ |
||
60 | class SugarTheme |
||
61 | { |
||
62 | /** |
||
63 | * Theme name |
||
64 | * |
||
65 | * @var string |
||
66 | */ |
||
67 | protected $name; |
||
68 | |||
69 | /** |
||
70 | * Theme description |
||
71 | * |
||
72 | * @var string |
||
73 | */ |
||
74 | protected $description; |
||
75 | |||
76 | /** |
||
77 | * Defines which parent files to not include |
||
78 | * |
||
79 | * @var string |
||
80 | */ |
||
81 | protected $ignoreParentFiles = array(); |
||
82 | |||
83 | /** |
||
84 | * Defines which parent files to not include |
||
85 | * |
||
86 | * @var string |
||
87 | */ |
||
88 | public $directionality = 'ltr'; |
||
89 | /** |
||
90 | * Theme directory name |
||
91 | * |
||
92 | * @var string |
||
93 | */ |
||
94 | protected $dirName; |
||
95 | |||
96 | /** |
||
97 | * Parent theme name |
||
98 | * |
||
99 | * @var string |
||
100 | */ |
||
101 | protected $parentTheme; |
||
102 | |||
103 | /** |
||
104 | * Colors sets provided by the theme |
||
105 | * |
||
106 | * @deprecated only here for BC during upgrades |
||
107 | * @var array |
||
108 | */ |
||
109 | protected $colors = array(); |
||
110 | |||
111 | /** |
||
112 | * Font sets provided by the theme |
||
113 | * |
||
114 | * @deprecated only here for BC during upgrades |
||
115 | * @var array |
||
116 | */ |
||
117 | protected $fonts = array(); |
||
118 | |||
119 | /** |
||
120 | * Maximum sugar version this theme is for; defaults to 5.5.1 as all the themes without this |
||
121 | * parameter as assumed to work thru 5.5.1 |
||
122 | * |
||
123 | * @var int |
||
124 | */ |
||
125 | protected $version = '5.5.1'; |
||
126 | |||
127 | /** |
||
128 | * Colors used in bar charts |
||
129 | * |
||
130 | * @var array |
||
131 | */ |
||
132 | protected $barChartColors = array( |
||
133 | "docBorder" => "0xffffff", |
||
134 | "docBg1" => "0xffffff", |
||
135 | "docBg2" => "0xffffff", |
||
136 | "xText" => "0x33485c", |
||
137 | "yText" => "0x33485c", |
||
138 | "title" => "0x333333", |
||
139 | "misc" => "0x999999", |
||
140 | "altBorder" => "0xffffff", |
||
141 | "altBg" => "0xffffff", |
||
142 | "altText" => "0x666666", |
||
143 | "graphBorder" => "0xcccccc", |
||
144 | "graphBg1" => "0xf6f6f6", |
||
145 | "graphBg2" => "0xf6f6f6", |
||
146 | "graphLines" => "0xcccccc", |
||
147 | "graphText" => "0x333333", |
||
148 | "graphTextShadow" => "0xf9f9f9", |
||
149 | "barBorder" => "0xeeeeee", |
||
150 | "barBorderHilite" => "0x333333", |
||
151 | "legendBorder" => "0xffffff", |
||
152 | "legendBg1" => "0xffffff", |
||
153 | "legendBg2" => "0xffffff", |
||
154 | "legendText" => "0x444444", |
||
155 | "legendColorKeyBorder" => "0x777777", |
||
156 | "scrollBar" => "0xcccccc", |
||
157 | "scrollBarBorder" => "0xeeeeee", |
||
158 | "scrollBarTrack" => "0xeeeeee", |
||
159 | "scrollBarTrackBorder" => "0xcccccc", |
||
160 | ); |
||
161 | |||
162 | /** |
||
163 | * Colors used in pie charts |
||
164 | * |
||
165 | * @var array |
||
166 | */ |
||
167 | protected $pieChartColors = array( |
||
168 | "docBorder" => "0xffffff", |
||
169 | "docBg1" => "0xffffff", |
||
170 | "docBg2" => "0xffffff", |
||
171 | "title" => "0x333333", |
||
172 | "subtitle" => "0x666666", |
||
173 | "misc" => "0x999999", |
||
174 | "altBorder" => "0xffffff", |
||
175 | "altBg" => "0xffffff", |
||
176 | "altText" => "0x666666", |
||
177 | "graphText" => "0x33485c", |
||
178 | "graphTextShadow" => "0xf9f9f9", |
||
179 | "pieBorder" => "0xffffff", |
||
180 | "pieBorderHilite" => "0x333333", |
||
181 | "legendBorder" => "0xffffff", |
||
182 | "legendBg1" => "0xffffff", |
||
183 | "legendBg2" => "0xffffff", |
||
184 | "legendText" => "0x444444", |
||
185 | "legendColorKeyBorder" => "0x777777", |
||
186 | "scrollBar" => "0xdfdfdf", |
||
187 | "scrollBarBorder" => "0xfafafa", |
||
188 | "scrollBarTrack" => "0xeeeeee", |
||
189 | "scrollBarTrackBorder" => "0xcccccc", |
||
190 | ); |
||
191 | |||
192 | /** |
||
193 | * Does this theme support group tabs |
||
194 | * |
||
195 | * @var bool |
||
196 | */ |
||
197 | public $group_tabs; |
||
198 | |||
199 | /** |
||
200 | * Support for classic themes |
||
201 | * |
||
202 | * @var bool |
||
203 | */ |
||
204 | public $classic; |
||
205 | |||
206 | /** |
||
207 | * Is this theme configurable |
||
208 | * |
||
209 | * @var bool |
||
210 | */ |
||
211 | public $configurable; |
||
212 | |||
213 | /** |
||
214 | * theme config options |
||
215 | * |
||
216 | * @var bool |
||
217 | */ |
||
218 | public $config_options = array(); |
||
219 | |||
220 | |||
221 | /** |
||
222 | * Cache built of all css files locations |
||
223 | * |
||
224 | * @var array |
||
225 | */ |
||
226 | private $_cssCache = array(); |
||
227 | |||
228 | /** |
||
229 | * Cache built of all image files locations |
||
230 | * |
||
231 | * @var array |
||
232 | */ |
||
233 | private $_imageCache = array(); |
||
234 | |||
235 | /** |
||
236 | * Cache built of all javascript files locations |
||
237 | * |
||
238 | * @var array |
||
239 | */ |
||
240 | private $_jsCache = array(); |
||
241 | |||
242 | /** |
||
243 | * Cache built of all template files locations |
||
244 | * |
||
245 | * @var array |
||
246 | */ |
||
247 | private $_templateCache = array(); |
||
248 | |||
249 | /** |
||
250 | * Cache built of sprite meta data |
||
251 | * |
||
252 | * @var array |
||
253 | */ |
||
254 | private $_spriteCache = array(); |
||
255 | |||
256 | /** |
||
257 | * Size of the caches after the are initialized in the constructor |
||
258 | * |
||
259 | * @var array |
||
260 | */ |
||
261 | private $_initialCacheSize = array( |
||
262 | 'cssCache' => 0, |
||
263 | 'imageCache' => 0, |
||
264 | 'jsCache' => 0, |
||
265 | 'templateCache' => 0, |
||
266 | 'spriteCache' => 0, |
||
267 | ); |
||
268 | |||
269 | /** |
||
270 | * Controls whether or not to clear the cache on destroy; defaults to false |
||
271 | */ |
||
272 | private $_clearCacheOnDestroy = false; |
||
273 | |||
274 | private $imageExtensions = array( |
||
275 | 'svg', |
||
276 | 'gif', |
||
277 | 'png', |
||
278 | 'jpg', |
||
279 | 'tif', |
||
280 | 'bmp', |
||
281 | ); |
||
282 | |||
283 | /** |
||
284 | * Constructor |
||
285 | * |
||
286 | * Sets the theme properties from the defaults passed to it, and loads the file path cache from an external cache |
||
287 | * |
||
288 | * @param $defaults string defaults for the current theme |
||
289 | */ |
||
290 | public function __construct( |
||
291 | $defaults |
||
292 | ) |
||
293 | { |
||
294 | // apply parent theme's properties first |
||
295 | if ( isset($defaults['parentTheme']) ) { |
||
296 | $themedef = array(); |
||
297 | include("themes/{$defaults['parentTheme']}/themedef.php"); |
||
298 | foreach ( $themedef as $key => $value ) { |
||
299 | if ( property_exists(__CLASS__,$key) ) { |
||
300 | // For all arrays ( except colors and fonts ) you can just specify the items |
||
301 | // to change instead of all of the values |
||
302 | if ( is_array($this->$key) && !in_array($key,array('colors','fonts')) ) |
||
303 | $this->$key = array_merge($this->$key,$value); |
||
304 | else |
||
305 | $this->$key = $value; |
||
306 | } |
||
307 | } |
||
308 | } |
||
309 | foreach ( $defaults as $key => $value ) { |
||
310 | if ( property_exists(__CLASS__,$key) ) { |
||
311 | // For all arrays ( except colors and fonts ) you can just specify the items |
||
312 | // to change instead of all of the values |
||
313 | if ( is_array($this->$key) && !in_array($key,array('colors','fonts')) ) |
||
314 | $this->$key = array_merge($this->$key,$value); |
||
315 | else |
||
316 | $this->$key = $value; |
||
317 | } |
||
318 | } |
||
319 | if ( !inDeveloperMode() ) { |
||
320 | if ( sugar_is_file($cachedfile = sugar_cached($this->getFilePath().'/pathCache.php'))) { |
||
321 | $caches = unserialize(file_get_contents($cachedfile)); |
||
322 | if ( isset($caches['jsCache']) ) |
||
323 | $this->_jsCache = $caches['jsCache']; |
||
324 | if ( isset($caches['cssCache']) ) |
||
325 | $this->_cssCache = $caches['cssCache']; |
||
326 | if ( isset($caches['imageCache']) ) |
||
327 | $this->_imageCache = $caches['imageCache']; |
||
328 | if ( isset($caches['templateCache']) ) |
||
329 | $this->_templateCache = $caches['templateCache']; |
||
330 | } |
||
331 | $cachedfile = sugar_cached($this->getFilePath().'/spriteCache.php'); |
||
332 | if(!empty($GLOBALS['sugar_config']['use_sprites']) && sugar_is_file($cachedfile)) { |
||
333 | $this->_spriteCache = unserialize(sugar_file_get_contents($cachedfile)); |
||
334 | } |
||
335 | } |
||
336 | $this->_initialCacheSize = array( |
||
337 | 'jsCache' => count($this->_jsCache), |
||
338 | 'cssCache' => count($this->_cssCache), |
||
339 | 'imageCache' => count($this->_imageCache), |
||
340 | 'templateCache' => count($this->_templateCache), |
||
341 | 'spriteCache' => count($this->_spriteCache), |
||
342 | ); |
||
343 | } |
||
344 | |||
345 | /** |
||
346 | * This is needed to prevent unserialize vulnerability |
||
347 | */ |
||
348 | public function __wakeup() |
||
349 | { |
||
350 | // clean all properties |
||
351 | foreach(get_object_vars($this) as $k => $v) { |
||
352 | $this->$k = null; |
||
353 | } |
||
354 | throw new Exception("Not a serializable object"); |
||
355 | } |
||
356 | |||
357 | /** |
||
358 | * Destructor |
||
359 | * Here we'll write out the internal file path caches to an external cache of some sort. |
||
360 | */ |
||
361 | public function __destruct() |
||
362 | { |
||
363 | // Set the current directory to one which we expect it to be (i.e. the root directory of the install |
||
364 | $dir = realpath(dirname(__FILE__) . '/../..'); |
||
365 | static $includePathIsPatched = false; |
||
366 | if ($includePathIsPatched == false) |
||
0 ignored issues
–
show
|
|||
367 | { |
||
368 | $path = explode(PATH_SEPARATOR, get_include_path()); |
||
369 | if (in_array($dir, $path) == false) |
||
0 ignored issues
–
show
|
|||
370 | { |
||
371 | set_include_path($dir . PATH_SEPARATOR . get_include_path()); |
||
372 | } |
||
373 | $includePathIsPatched = true; |
||
374 | } |
||
375 | chdir($dir); // destruct can be called late, and chdir could change |
||
376 | $cachedir = sugar_cached($this->getFilePath()); |
||
377 | sugar_mkdir($cachedir, 0775, true); |
||
378 | // clear out the cache on destroy if we are asked to |
||
379 | if ( $this->_clearCacheOnDestroy ) { |
||
380 | |||
381 | if (is_file("$cachedir/pathCache.php")) |
||
382 | unlink("$cachedir/pathCache.php"); |
||
383 | if (is_file("$cachedir/spriteCache.php")) |
||
384 | unlink("$cachedir/spriteCache.php"); |
||
385 | |||
386 | } |
||
387 | elseif ( !inDeveloperMode() ) { |
||
388 | // only update the caches if they have been changed in this request |
||
389 | if ( count($this->_jsCache) != $this->_initialCacheSize['jsCache'] |
||
390 | || count($this->_cssCache) != $this->_initialCacheSize['cssCache'] |
||
391 | || count($this->_imageCache) != $this->_initialCacheSize['imageCache'] |
||
392 | || count($this->_templateCache) != $this->_initialCacheSize['templateCache'] |
||
393 | ) { |
||
394 | sugar_file_put_contents( |
||
395 | "$cachedir/pathCache.php", |
||
396 | serialize( |
||
397 | array( |
||
398 | 'jsCache' => $this->_jsCache, |
||
399 | 'cssCache' => $this->_cssCache, |
||
400 | 'imageCache' => $this->_imageCache, |
||
401 | 'templateCache' => $this->_templateCache, |
||
402 | ) |
||
403 | ) |
||
404 | ); |
||
405 | |||
406 | } |
||
407 | if ( count($this->_spriteCache) != $this->_initialCacheSize['spriteCache']) { |
||
408 | sugar_file_put_contents( |
||
409 | "$cachedir/spriteCache.php", |
||
410 | serialize($this->_spriteCache) |
||
411 | ); |
||
412 | } |
||
413 | } |
||
414 | } |
||
415 | |||
416 | /** |
||
417 | * Specifies what is returned when the object is cast to a string, in this case it will be the |
||
418 | * theme directory name. |
||
419 | * |
||
420 | * @return string theme directory name |
||
421 | */ |
||
422 | 3 | public function __toString() |
|
423 | { |
||
424 | 3 | return $this->dirName; |
|
425 | } |
||
426 | |||
427 | /** |
||
428 | * Generic public accessor method for all the properties of the theme ( which are kept protected ) |
||
429 | * |
||
430 | * @return string |
||
431 | */ |
||
432 | 3 | public function __get( |
|
433 | $key |
||
434 | ) |
||
435 | { |
||
436 | 3 | if ( isset($this->$key) ) |
|
437 | 1 | return $this->$key; |
|
438 | 2 | } |
|
439 | |||
440 | 2 | public function __isset($key){ |
|
441 | 2 | return isset($this->$key); |
|
442 | |||
443 | } |
||
444 | |||
445 | public function clearJSCache() |
||
446 | { |
||
447 | $this->_jsCache = array(); |
||
448 | } |
||
449 | |||
450 | /** |
||
451 | * Clears out the caches used for this themes |
||
452 | */ |
||
453 | public function clearCache() |
||
454 | { |
||
455 | $this->_clearCacheOnDestroy = true; |
||
456 | } |
||
457 | |||
458 | /** |
||
459 | * Return array of all valid fields that can be specified in the themedef.php file |
||
460 | * |
||
461 | * @return array |
||
462 | */ |
||
463 | public static function getThemeDefFields() |
||
464 | { |
||
465 | return array( |
||
466 | 'name', |
||
467 | 'description', |
||
468 | 'directionality', |
||
469 | 'dirName', |
||
470 | 'parentTheme', |
||
471 | 'version', |
||
472 | 'colors', |
||
473 | 'fonts', |
||
474 | 'barChartColors', |
||
475 | 'pieChartColors', |
||
476 | 'group_tabs', |
||
477 | 'classic', |
||
478 | 'configurable', |
||
479 | 'config_options', |
||
480 | 'ignoreParentFiles', |
||
481 | ); |
||
482 | } |
||
483 | |||
484 | /** |
||
485 | * Returns the file path of the current theme |
||
486 | * |
||
487 | * @return string |
||
488 | */ |
||
489 | 23 | public function getFilePath() |
|
490 | { |
||
491 | 23 | return 'themes/'.$this->dirName; |
|
492 | } |
||
493 | |||
494 | /** |
||
495 | * Returns the image path of the current theme |
||
496 | * |
||
497 | * @return string |
||
498 | */ |
||
499 | 22 | public function getImagePath() |
|
500 | { |
||
501 | 22 | return $this->getFilePath().'/images'; |
|
502 | } |
||
503 | |||
504 | /** |
||
505 | * Returns the css path of the current theme |
||
506 | * |
||
507 | * @return string |
||
508 | */ |
||
509 | 1 | public function getCSSPath() |
|
510 | { |
||
511 | 1 | return $this->getFilePath().'/css'; |
|
512 | } |
||
513 | |||
514 | /** |
||
515 | * Returns the javascript path of the current theme |
||
516 | * |
||
517 | * @return string |
||
518 | */ |
||
519 | 1 | public function getJSPath() |
|
520 | { |
||
521 | 1 | return $this->getFilePath().'/js'; |
|
522 | } |
||
523 | |||
524 | /** |
||
525 | * Returns the tpl path of the current theme |
||
526 | * |
||
527 | * @return string |
||
528 | */ |
||
529 | 3 | public function getTemplatePath() |
|
530 | { |
||
531 | 3 | return $this->getFilePath().'/tpls'; |
|
532 | } |
||
533 | |||
534 | /** |
||
535 | * Returns the file path of the theme defaults |
||
536 | * |
||
537 | * @return string |
||
538 | */ |
||
539 | 16 | public final function getDefaultFilePath() |
|
0 ignored issues
–
show
|
|||
540 | { |
||
541 | 16 | return 'themes/default'; |
|
542 | } |
||
543 | |||
544 | /** |
||
545 | * Returns the image path of the theme defaults |
||
546 | * |
||
547 | * @return string |
||
548 | */ |
||
549 | 16 | public final function getDefaultImagePath() |
|
0 ignored issues
–
show
|
|||
550 | { |
||
551 | 16 | return $this->getDefaultFilePath().'/images'; |
|
552 | } |
||
553 | |||
554 | /** |
||
555 | * Returns the css path of the theme defaults |
||
556 | * |
||
557 | * @return string |
||
558 | */ |
||
559 | 1 | public final function getDefaultCSSPath() |
|
0 ignored issues
–
show
|
|||
560 | { |
||
561 | 1 | return $this->getDefaultFilePath().'/css'; |
|
562 | } |
||
563 | |||
564 | /** |
||
565 | * Returns the template path of the theme defaults |
||
566 | * |
||
567 | * @return string |
||
568 | */ |
||
569 | public final function getDefaultTemplatePath() |
||
0 ignored issues
–
show
|
|||
570 | { |
||
571 | return $this->getDefaultFilePath().'/tpls'; |
||
572 | } |
||
573 | |||
574 | /** |
||
575 | * Returns the javascript path of the theme defaults |
||
576 | * |
||
577 | * @return string |
||
578 | */ |
||
579 | 1 | public final function getDefaultJSPath() |
|
0 ignored issues
–
show
|
|||
580 | { |
||
581 | 1 | return $this->getDefaultFilePath().'/js'; |
|
582 | } |
||
583 | |||
584 | /** |
||
585 | * Returns CSS for the current theme. |
||
586 | * |
||
587 | * @param $color string optional, specifies the css color file to use if the theme supports it; defaults to cookie value or theme default |
||
588 | * @param $font string optional, specifies the css font file to use if the theme supports it; defaults to cookie value or theme default |
||
589 | * @return string HTML code |
||
590 | */ |
||
591 | 4 | public function getCSS( |
|
592 | $color = null, |
||
593 | $font = null |
||
594 | ) |
||
595 | { |
||
596 | // include style.css file |
||
597 | $html = ' |
||
598 | <!-- qtip & suggestion box --> |
||
599 | 4 | <link rel="stylesheet" type="text/css" href="include/javascript/qtip/jquery.qtip.min.css" />'; |
|
600 | 4 | $html .= '<link rel="stylesheet" type="text/css" href="'.$this->getCSSURL('yui.css').'" />'; |
|
601 | 4 | $html .= '<link rel="stylesheet" type="text/css" href="include/javascript/jquery/themes/base/jquery.ui.all.css" />'; |
|
602 | 4 | $html .= '<link rel="stylesheet" type="text/css" href="'.$this->getCSSURL('deprecated.css').'" />'; |
|
603 | 4 | $html .= '<link rel="stylesheet" type="text/css" href="'.$this->getCSSURL('style.css').'" />'; |
|
604 | |||
605 | |||
606 | // sprites |
||
607 | 4 | if(!empty($GLOBALS['sugar_config']['use_sprites']) && $GLOBALS['sugar_config']['use_sprites']) { |
|
608 | |||
609 | // system wide sprites |
||
610 | if(file_exists("cache/sprites/default/sprites.css")) |
||
611 | $html .= '<link rel="stylesheet" type="text/css" href="'.getJSPath('cache/sprites/default/sprites.css').'" />'; |
||
612 | |||
613 | // theme specific sprites |
||
614 | if(file_exists("cache/sprites/{$this->dirName}/sprites.css")) |
||
615 | $html .= '<link rel="stylesheet" type="text/css" href="'.getJSPath('cache/sprites/'.$this->dirName.'/sprites.css').'" />'; |
||
616 | |||
617 | // parent sprites |
||
618 | if($this->parentTheme && $parent = SugarThemeRegistry::get($this->parentTheme)) { |
||
619 | if(file_exists("cache/sprites/{$parent->dirName}/sprites.css")) |
||
620 | $html .= '<link rel="stylesheet" type="text/css" href="'.getJSPath('cache/sprites/'.$parent->dirName.'/sprites.css').'" />'; |
||
621 | } |
||
622 | |||
623 | // repeatable sprites |
||
624 | if(file_exists("cache/sprites/Repeatable/sprites.css")) |
||
625 | $html .= '<link rel="stylesheet" type="text/css" href="'.getJSPath('cache/sprites/Repeatable/sprites.css').'" />'; |
||
626 | } |
||
627 | |||
628 | // for BC during upgrade |
||
629 | 4 | if ( !empty($this->colors) ) { |
|
0 ignored issues
–
show
The property
SugarTheme::$colors has been deprecated with message: only here for BC during upgrades
This property has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead. ![]() |
|||
630 | if ( isset($_SESSION['authenticated_user_theme_color']) && in_array($_SESSION['authenticated_user_theme_color'], $this->colors)) |
||
0 ignored issues
–
show
The property
SugarTheme::$colors has been deprecated with message: only here for BC during upgrades
This property has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead. ![]() |
|||
631 | $color = $_SESSION['authenticated_user_theme_color']; |
||
632 | else |
||
633 | $color = $this->colors[0]; |
||
0 ignored issues
–
show
The property
SugarTheme::$colors has been deprecated with message: only here for BC during upgrades
This property has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead. ![]() |
|||
634 | $html .= '<link rel="stylesheet" type="text/css" href="'.$this->getCSSURL('colors.'.$color.'.css').'" id="current_color_style" />'; |
||
635 | } |
||
636 | |||
637 | 4 | if ( !empty($this->fonts) ) { |
|
0 ignored issues
–
show
The property
SugarTheme::$fonts has been deprecated with message: only here for BC during upgrades
This property has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead. ![]() |
|||
638 | if ( isset($_SESSION['authenticated_user_theme_font']) && in_array($_SESSION['authenticated_user_theme_font'], $this->fonts)) |
||
0 ignored issues
–
show
The property
SugarTheme::$fonts has been deprecated with message: only here for BC during upgrades
This property has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead. ![]() |
|||
639 | $font = $_SESSION['authenticated_user_theme_font']; |
||
640 | else |
||
641 | $font = $this->fonts[0]; |
||
0 ignored issues
–
show
The property
SugarTheme::$fonts has been deprecated with message: only here for BC during upgrades
This property has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead. ![]() |
|||
642 | $html .= '<link rel="stylesheet" type="text/css" href="'.$this->getCSSURL('fonts.'.$font.'.css').'" id="current_font_style" />'; |
||
643 | } |
||
644 | |||
645 | 4 | return $html; |
|
646 | } |
||
647 | |||
648 | /** |
||
649 | * Returns javascript for the current theme |
||
650 | * |
||
651 | * @return string HTML code |
||
652 | */ |
||
653 | 2 | public function getJS() |
|
654 | { |
||
655 | 2 | $styleJS = $this->getJSURL('style.js'); |
|
656 | return <<<EOHTML |
||
657 | 2 | <script type="text/javascript" src="$styleJS"></script> |
|
658 | EOHTML; |
||
659 | } |
||
660 | |||
661 | /** |
||
662 | * Returns the path for the tpl file in the current theme. If not found in the current theme, will revert |
||
663 | * to looking in the base theme. |
||
664 | * |
||
665 | * @param string $templateName tpl file name |
||
666 | * @return string path of tpl file to include |
||
667 | */ |
||
668 | 3 | public function getTemplate( |
|
669 | $templateName |
||
670 | ) |
||
671 | { |
||
672 | 3 | if ( isset($this->_templateCache[$templateName]) ) |
|
673 | return $this->_templateCache[$templateName]; |
||
674 | |||
675 | 3 | $templatePath = ''; |
|
676 | 3 | if (sugar_is_file('custom/'.$this->getTemplatePath().'/'.$templateName)) |
|
677 | $templatePath = 'custom/'.$this->getTemplatePath().'/'.$templateName; |
||
678 | 3 | elseif (sugar_is_file($this->getTemplatePath().'/'.$templateName)) |
|
679 | 3 | $templatePath = $this->getTemplatePath().'/'.$templateName; |
|
680 | elseif (isset($this->parentTheme) |
||
681 | && SugarThemeRegistry::get($this->parentTheme) instanceOf SugarTheme |
||
682 | && ($filename = SugarThemeRegistry::get($this->parentTheme)->getTemplate($templateName)) != '') |
||
683 | $templatePath = $filename; |
||
684 | elseif (sugar_is_file('custom/'.$this->getDefaultTemplatePath().'/'.$templateName)) |
||
685 | $templatePath = 'custom/'.$this->getDefaultTemplatePath().'/'.$templateName; |
||
686 | elseif (sugar_is_file($this->getDefaultTemplatePath().'/'.$templateName)) |
||
687 | $templatePath = $this->getDefaultTemplatePath().'/'.$templateName; |
||
688 | else { |
||
689 | $GLOBALS['log']->warn("Template $templateName not found"); |
||
690 | return false; |
||
691 | } |
||
692 | |||
693 | 3 | $this->_imageCache[$templateName] = $templatePath; |
|
694 | |||
695 | 3 | return $templatePath; |
|
696 | } |
||
697 | |||
698 | /** |
||
699 | * Returns an image tag for the given image. |
||
700 | * |
||
701 | * @param string $image image name |
||
0 ignored issues
–
show
There is no parameter named
$image . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
702 | * @param string $other_attributes optional, other attributes to add to the image tag, not cached |
||
703 | * @param string $width optional, defaults to the actual image's width |
||
704 | * @param string $height optional, defaults to the actual image's height |
||
705 | * @param string $ext optional, image extension (TODO can we deprecate this one ?) |
||
706 | * @param string $alt optional, only used when image contains something useful, i.e. "Sally's profile pic" |
||
707 | * @return string HTML image tag or sprite |
||
708 | */ |
||
709 | 26 | public function getImage( |
|
710 | $imageName, |
||
711 | $other_attributes = '', |
||
712 | $width = null, |
||
713 | $height = null, |
||
714 | $ext = null, |
||
715 | $alt = '' |
||
716 | ) |
||
717 | { |
||
718 | |||
719 | 26 | static $cached_results = array(); |
|
720 | |||
721 | // trap deprecated use of image extension |
||
722 | 26 | if(is_null($ext)) { |
|
723 | 7 | $imageNameExp = explode('.',$imageName); |
|
724 | 7 | if(count($imageNameExp) == 1) |
|
725 | 7 | $imageName .= '.gif'; |
|
726 | } else { |
||
727 | 23 | $imageName .= $ext; |
|
728 | } |
||
729 | |||
730 | // trap alt attributes in other_attributes |
||
731 | 26 | if(preg_match('/alt=["\']([^\'"]+)["\']/i', $other_attributes)) |
|
732 | $GLOBALS['log']->debug("Sprites: alt attribute detected for $imageName"); |
||
733 | // sprite handler, makes use of own caching mechanism |
||
734 | 26 | if(!empty($GLOBALS['sugar_config']['use_sprites']) && $GLOBALS['sugar_config']['use_sprites']) { |
|
735 | // get sprite metadata |
||
736 | if($sp = $this->getSpriteMeta($imageName)) { |
||
737 | // requested size should match |
||
738 | if( (!is_null($width) && $sp['width'] == $width) || (is_null($width)) && |
||
739 | (!is_null($height) && $sp['height'] == $height) || (is_null($height)) ) |
||
740 | { |
||
741 | $other_attributes .= ' data-orig="'.$imageName.'"'; |
||
742 | |||
743 | if($sprite = $this->getSprite($sp['class'], $other_attributes, $alt)) |
||
744 | { |
||
745 | return $sprite; |
||
746 | } |
||
747 | } |
||
748 | } |
||
749 | } |
||
750 | |||
751 | // img caching |
||
752 | 26 | if(empty($cached_results[$imageName])) { |
|
753 | 10 | $imageURL = $this->getImageURL($imageName,false); |
|
754 | 10 | if ( empty($imageURL) ) |
|
755 | return false; |
||
756 | 10 | if(strpos($imageURL, '.svg', strlen($imageURL)-4)){ |
|
757 | 2 | $cached_results[$imageName] = file_get_contents($imageURL); |
|
758 | } else { |
||
759 | 9 | $cached_results[$imageName] = '<img src="'.getJSPath($imageURL).'" '; |
|
760 | } |
||
761 | |||
762 | } |
||
763 | |||
764 | 26 | $attr_width = (is_null($width)) ? "" : "width=\"$width\""; |
|
765 | 26 | $attr_height = (is_null($height)) ? "" : "height=\"$height\""; |
|
766 | |||
767 | 26 | if(strpos($cached_results[$imageName], 'svg') !== false){ |
|
768 | 3 | return $cached_results[$imageName]; |
|
769 | } |
||
770 | 24 | return $cached_results[$imageName] . " $attr_width $attr_height $other_attributes alt=\"$alt\" />"; |
|
771 | } |
||
772 | |||
773 | /** |
||
774 | * Returns sprite meta data |
||
775 | * |
||
776 | * @param string $imageName Image filename including extension |
||
777 | * @return array Sprite meta data |
||
778 | */ |
||
779 | public function getSpriteMeta($imageName) { |
||
780 | |||
781 | // return from cache |
||
782 | if(isset($this->_spriteCache[$imageName])) |
||
783 | return $this->_spriteCache[$imageName]; |
||
784 | |||
785 | // sprite keys are base on imageURL |
||
786 | $imageURL = $this->getImageURL($imageName,false); |
||
787 | if(empty($imageURL)) { |
||
788 | $this->_spriteCache[$imageName] = false; |
||
789 | return false; |
||
790 | } |
||
791 | |||
792 | // load meta data, includes default images |
||
793 | require_once("include/SugarTheme/SugarSprites.php"); |
||
794 | $meta = SugarSprites::getInstance(); |
||
795 | // add current theme dir |
||
796 | $meta->loadSpriteMeta($this->dirName); |
||
797 | // add parent theme dir |
||
798 | if($this->parentTheme && $parent = SugarThemeRegistry::get($this->parentTheme)) { |
||
799 | $meta->loadSpriteMeta($parent->dirName); |
||
800 | } |
||
801 | |||
802 | // add to cache |
||
803 | if(isset($meta->sprites[$imageURL])) { |
||
804 | $this->_spriteCache[$imageName] = $meta->sprites[$imageURL]; |
||
805 | // add imageURL to cache |
||
806 | //$this->_spriteCache[$imageName]['imageURL'] = $imageURL; |
||
807 | } else { |
||
808 | $this->_spriteCache[$imageName] = false; |
||
809 | $GLOBALS['log']->debug("Sprites: miss for $imageURL"); |
||
810 | } |
||
811 | return $this->_spriteCache[$imageName]; |
||
812 | } |
||
813 | |||
814 | /** |
||
815 | * Returns sprite HTML span tag |
||
816 | * |
||
817 | * @param string class The md5 id used in the CSS sprites class |
||
818 | * @param string attr optional, list of additional html attributes |
||
819 | * @param string title optional, the title (equivalent to alt on img) |
||
820 | * @return string HTML span tag |
||
821 | */ |
||
822 | public function getSprite($class, $attr, $title) { |
||
823 | |||
824 | // handle multiple class tags |
||
825 | $class_regex = '/class=["\']([^\'"]+)["\']/i'; |
||
826 | preg_match($class_regex, $attr, $match); |
||
827 | if(isset($match[1])) { |
||
828 | $attr = preg_replace($class_regex, 'class="spr_'.$class.' ${1}"', $attr); |
||
829 | |||
830 | // single class |
||
831 | } else { |
||
832 | $attr .= ' class="spr_'.$class.'"'; |
||
833 | } |
||
834 | |||
835 | if($title) |
||
836 | $attr .= ' title="'.$title.'"'; |
||
837 | |||
838 | // use </span> instead of /> to prevent weird UI results |
||
839 | $GLOBALS['log']->debug("Sprites: generated sprite -> $attr"); |
||
840 | return "<span {$attr}></span>"; |
||
841 | } |
||
842 | |||
843 | /** |
||
844 | * Returns a link HTML tag with or without an embedded image |
||
845 | */ |
||
846 | 2 | public function getLink( |
|
847 | $url, |
||
848 | $title, |
||
849 | $other_attributes = '', |
||
850 | $img_name = '', |
||
851 | $img_other_attributes = '', |
||
852 | $img_width = null, |
||
853 | $img_height = null, |
||
854 | $img_alt = '', |
||
855 | $img_placement = 'imageonly' |
||
856 | ) |
||
857 | { |
||
858 | |||
859 | 2 | if($img_name) { |
|
860 | 2 | $img = $this->getImage($img_name, $img_other_attributes, $img_width, $img_height, null, $img_alt); |
|
861 | 2 | if($img == false) { |
|
0 ignored issues
–
show
|
|||
862 | $GLOBALS['log']->debug('Sprites: unknown image getLink'); |
||
863 | $img = 'unknown'; |
||
864 | } |
||
865 | switch($img_placement) { |
||
866 | 2 | case 'left': $inner_html = $img."<span class='title'>".$title."</span>"; break; |
|
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
867 | case 'right': $inner_html = "<span class='title'>".$title."</span>".$img; break; |
||
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
868 | 2 | default: $inner_html = $img; break; |
|
0 ignored issues
–
show
The default body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a default statement must start on the line immediately following the statement. switch ($expr) {
default:
doSomething(); //right
break;
}
switch ($expr) {
default:
doSomething(); //wrong
break;
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
869 | } |
||
870 | } else { |
||
871 | $inner_html = $title; |
||
872 | } |
||
873 | |||
874 | 2 | return '<a href="'.$url.'" title="'.$title.'" '.$other_attributes.'>'.$inner_html.'</a>'; |
|
875 | |||
876 | } |
||
877 | |||
878 | /** |
||
879 | * Returns the URL for an image in the current theme. If not found in the current theme, will revert |
||
880 | * to looking in the base theme. |
||
881 | * @param string $imageName image file name |
||
882 | * @param bool $addJSPath call getJSPath() with the results to add some unique image tracking support |
||
883 | * @return string path to image |
||
884 | */ |
||
885 | 30 | public function getImageURL( |
|
886 | $imageName, |
||
887 | $addJSPath = true |
||
888 | ){ |
||
889 | 30 | if ( isset($this->_imageCache[$imageName]) ) { |
|
890 | 23 | if ( $addJSPath ) |
|
891 | 22 | return getJSPath($this->_imageCache[$imageName]); |
|
892 | else |
||
893 | 9 | return $this->_imageCache[$imageName]; |
|
894 | } |
||
895 | 21 | $imagePath = ''; |
|
896 | 21 | if (($filename = $this->_getImageFileName('custom/'.$this->getImagePath().'/'.$imageName)) != '') |
|
897 | $imagePath = $filename; |
||
898 | 21 | elseif (($filename = $this->_getImageFileName($this->getImagePath().'/'.$imageName)) != '') |
|
899 | 10 | $imagePath = $filename; |
|
900 | 16 | elseif (isset($this->parentTheme) |
|
901 | 16 | && SugarThemeRegistry::get($this->parentTheme) instanceOf SugarTheme |
|
902 | 16 | && ($filename = SugarThemeRegistry::get($this->parentTheme)->getImageURL($imageName,false)) != '') |
|
903 | $imagePath = $filename; |
||
904 | 16 | elseif (($filename = $this->_getImageFileName('custom/'.$this->getDefaultImagePath().'/'.$imageName)) != '') |
|
905 | $imagePath = $filename; |
||
906 | 16 | elseif (($filename = $this->_getImageFileName($this->getDefaultImagePath().'/'.$imageName)) != '') |
|
907 | 5 | $imagePath = $filename; |
|
908 | 14 | elseif (($filename = $this->_getImageFileName('include/images/'.$imageName)) != '') |
|
909 | $imagePath = $filename; |
||
910 | else { |
||
911 | 14 | $GLOBALS['log']->warn("Image $imageName not found"); |
|
912 | 14 | return false; |
|
913 | } |
||
914 | |||
915 | 12 | $this->_imageCache[$imageName] = $imagePath; |
|
916 | |||
917 | 12 | if ( $addJSPath ) |
|
918 | 8 | return getJSPath($imagePath); |
|
919 | |||
920 | 9 | return $imagePath; |
|
921 | } |
||
922 | |||
923 | /** |
||
924 | * Checks for an image using all of the accepted image extensions |
||
925 | * |
||
926 | * @param string $imageName image file name |
||
927 | * @return string path to image |
||
928 | */ |
||
929 | 21 | protected function _getImageFileName( |
|
930 | $imageName |
||
931 | ) |
||
932 | { |
||
933 | // return now if the extension matches that of which we are looking for |
||
934 | 21 | if ( sugar_is_file($imageName) ) |
|
935 | 11 | return $imageName; |
|
936 | 21 | $pathParts = pathinfo($imageName); |
|
937 | 21 | foreach ( $this->imageExtensions as $extension ) |
|
938 | 21 | if ( isset($pathParts['extension']) ) |
|
939 | 21 | if ( ( $extension != $pathParts['extension'] ) |
|
940 | 21 | && sugar_is_file($pathParts['dirname'].'/'.$pathParts['filename'].'.'.$extension) ) |
|
941 | 21 | return $pathParts['dirname'].'/'.$pathParts['filename'].'.'.$extension; |
|
942 | |||
943 | 21 | return ''; |
|
944 | } |
||
945 | |||
946 | /** |
||
947 | * Returns the URL for the css file in the current theme. If not found in the current theme, will revert |
||
948 | * to looking in the base theme. |
||
949 | * |
||
950 | * @param string $cssFileName css file name |
||
951 | * @param bool $returnURL if true, returns URL with unique image mark, otherwise returns path to the file |
||
952 | * @return string path of css file to include |
||
953 | */ |
||
954 | 4 | public function getCSSURL($cssFileName, $returnURL = true) |
|
955 | { |
||
956 | 4 | if ( isset($this->_cssCache[$cssFileName]) && sugar_is_file(sugar_cached($this->_cssCache[$cssFileName])) ) { |
|
957 | 3 | if ( $returnURL ) |
|
958 | 3 | return getJSPath("cache/".$this->_cssCache[$cssFileName]); |
|
959 | else |
||
960 | return sugar_cached($this->_cssCache[$cssFileName]); |
||
961 | } |
||
962 | |||
963 | 1 | $cssFileContents = ''; |
|
964 | 1 | $defaultFileName = $this->getDefaultCSSPath().'/'.$cssFileName; |
|
965 | 1 | $fullFileName = $this->getCSSPath().'/'.$cssFileName; |
|
966 | 1 | if (isset($this->parentTheme) |
|
967 | 1 | && SugarThemeRegistry::get($this->parentTheme) instanceOf SugarTheme |
|
968 | 1 | && ($filename = SugarThemeRegistry::get($this->parentTheme)->getCSSURL($cssFileName,false)) != '') |
|
969 | $cssFileContents .= file_get_contents($filename); |
||
970 | else { |
||
971 | 1 | if (sugar_is_file($defaultFileName)) |
|
972 | 1 | $cssFileContents .= file_get_contents($defaultFileName); |
|
973 | 1 | if (sugar_is_file('custom/'.$defaultFileName)) |
|
974 | $cssFileContents .= file_get_contents('custom/'.$defaultFileName); |
||
975 | } |
||
976 | 1 | if (sugar_is_file($fullFileName)) { |
|
977 | 1 | $cssFileContents .= file_get_contents($fullFileName); |
|
978 | } |
||
979 | 1 | if (sugar_is_file('custom/'.$fullFileName)) { |
|
980 | $cssFileContents .= file_get_contents('custom/'.$fullFileName); |
||
981 | } |
||
982 | 1 | if (empty($cssFileContents)) { |
|
983 | $GLOBALS['log']->warn("CSS File $cssFileName not found"); |
||
984 | return false; |
||
985 | } |
||
986 | |||
987 | // fix any image references that may be defined in css files |
||
988 | 1 | $cssFileContents = str_ireplace("entryPoint=getImage&", |
|
989 | 1 | "entryPoint=getImage&themeName={$this->dirName}&", |
|
990 | $cssFileContents); |
||
991 | |||
992 | // create the cached file location |
||
993 | 1 | $cssFilePath = create_cache_directory($fullFileName); |
|
994 | |||
995 | // if this is the style.css file, prepend the base.css and calendar-win2k-cold-1.css |
||
996 | // files before the theme styles |
||
997 | 1 | if ( $cssFileName == 'style.css' && !isset($this->parentTheme) ) { |
|
998 | 1 | if ( inDeveloperMode() ) |
|
999 | $cssFileContents = file_get_contents('include/javascript/yui/build/base/base.css') . $cssFileContents; |
||
1000 | else |
||
1001 | 1 | $cssFileContents = file_get_contents('include/javascript/yui/build/base/base-min.css') . $cssFileContents; |
|
1002 | } |
||
1003 | |||
1004 | // minify the css |
||
1005 | 1 | if ( !inDeveloperMode() && !sugar_is_file($cssFilePath) ) { |
|
1006 | 1 | $cssFileContents = cssmin::minify($cssFileContents); |
|
1007 | } |
||
1008 | |||
1009 | // now write the css to cache |
||
1010 | 1 | sugar_file_put_contents($cssFilePath,$cssFileContents); |
|
1011 | |||
1012 | 1 | $this->_cssCache[$cssFileName] = $fullFileName; |
|
1013 | |||
1014 | 1 | if ( $returnURL ) |
|
1015 | 1 | return getJSPath("cache/".$fullFileName); |
|
1016 | |||
1017 | return sugar_cached($fullFileName); |
||
1018 | } |
||
1019 | |||
1020 | /** |
||
1021 | * Returns the URL for an image in the current theme. If not found in the current theme, will revert |
||
1022 | * to looking in the base theme. |
||
1023 | * |
||
1024 | * @param string $jsFileName js file name |
||
1025 | * @param bool $returnURL if true, returns URL with unique image mark, otherwise returns path to the file |
||
1026 | * @return string path to js file |
||
1027 | */ |
||
1028 | 2 | public function getJSURL($jsFileName, $returnURL = true) |
|
1029 | { |
||
1030 | 2 | if ( isset($this->_jsCache[$jsFileName]) && sugar_is_file(sugar_cached($this->_jsCache[$jsFileName])) ) { |
|
1031 | 1 | if ( $returnURL ) |
|
1032 | 1 | return getJSPath("cache/".$this->_jsCache[$jsFileName]); |
|
1033 | else |
||
1034 | return sugar_cached($this->_jsCache[$jsFileName]); |
||
1035 | } |
||
1036 | |||
1037 | 1 | $jsFileContents = ''; |
|
1038 | 1 | $fullFileName = $this->getJSPath().'/'.$jsFileName; |
|
1039 | 1 | $defaultFileName = $this->getDefaultJSPath().'/'.$jsFileName; |
|
1040 | 1 | if (isset($this->parentTheme) |
|
1041 | 1 | && SugarThemeRegistry::get($this->parentTheme) instanceOf SugarTheme |
|
1042 | 1 | && ($filename = SugarThemeRegistry::get($this->parentTheme)->getJSURL($jsFileName,false)) != '' && !in_array($jsFileName,$this->ignoreParentFiles)) { |
|
1043 | $jsFileContents .= file_get_contents($filename); |
||
1044 | } else { |
||
1045 | 1 | if (sugar_is_file($defaultFileName)) |
|
1046 | 1 | $jsFileContents .= file_get_contents($defaultFileName); |
|
1047 | 1 | if (sugar_is_file('custom/'.$defaultFileName)) |
|
1048 | $jsFileContents .= file_get_contents('custom/'.$defaultFileName); |
||
1049 | } |
||
1050 | 1 | if (sugar_is_file($fullFileName)) |
|
1051 | 1 | $jsFileContents .= file_get_contents($fullFileName); |
|
1052 | 1 | if (sugar_is_file('custom/'.$fullFileName)) |
|
1053 | $jsFileContents .= file_get_contents('custom/'.$fullFileName); |
||
1054 | 1 | if (empty($jsFileContents)) { |
|
1055 | $GLOBALS['log']->warn("Javascript File $jsFileName not found"); |
||
1056 | return false; |
||
1057 | } |
||
1058 | |||
1059 | // create the cached file location |
||
1060 | 1 | $jsFilePath = create_cache_directory($fullFileName); |
|
1061 | |||
1062 | // minify the js |
||
1063 | 1 | if ( !inDeveloperMode()&& !sugar_is_file(str_replace('.js','-min.js',$jsFilePath)) ) { |
|
1064 | 1 | $jsFileContents = SugarMin::minify($jsFileContents); |
|
1065 | 1 | $jsFilePath = str_replace('.js','-min.js',$jsFilePath); |
|
1066 | 1 | $fullFileName = str_replace('.js','-min.js',$fullFileName); |
|
1067 | } |
||
1068 | |||
1069 | // now write the js to cache |
||
1070 | 1 | sugar_file_put_contents($jsFilePath,$jsFileContents); |
|
1071 | |||
1072 | 1 | $this->_jsCache[$jsFileName] = $fullFileName; |
|
1073 | |||
1074 | 1 | if ( $returnURL ) |
|
1075 | 1 | return getJSPath("cache/".$fullFileName); |
|
1076 | |||
1077 | return sugar_cached($fullFileName); |
||
1078 | } |
||
1079 | |||
1080 | /** |
||
1081 | * Returns an array of all of the images available for the current theme |
||
1082 | * |
||
1083 | * @return array |
||
1084 | */ |
||
1085 | public function getAllImages() |
||
1086 | { |
||
1087 | // first, lets get all the paths of where to look |
||
1088 | $pathsToSearch = array($this->getImagePath()); |
||
1089 | $theme = $this; |
||
1090 | while (isset($theme->parentTheme) && SugarThemeRegistry::get($theme->parentTheme) instanceOf SugarTheme ) { |
||
1091 | $theme = SugarThemeRegistry::get($theme->parentTheme); |
||
1092 | $pathsToSearch[] = $theme->getImagePath(); |
||
1093 | } |
||
1094 | $pathsToSearch[] = $this->getDefaultImagePath(); |
||
1095 | |||
1096 | // now build the array |
||
1097 | $imageArray = array(); |
||
1098 | foreach ( $pathsToSearch as $path ) |
||
1099 | { |
||
1100 | if (!sugar_is_dir($path)) $path = "custom/$path"; |
||
1101 | if (sugar_is_dir($path) && is_readable($path) && $dir = opendir($path)) { |
||
1102 | while (($file = readdir($dir)) !== false) { |
||
1103 | if ($file == ".." |
||
1104 | || $file == "." |
||
1105 | || $file == ".svn" |
||
1106 | || $file == "CVS" |
||
1107 | || $file == "Attic" |
||
1108 | ) |
||
1109 | continue; |
||
1110 | if ( !isset($imageArray[$file]) ) |
||
1111 | $imageArray[$file] = $this->getImageURL($file,false); |
||
1112 | } |
||
1113 | closedir($dir); |
||
1114 | } |
||
1115 | } |
||
1116 | |||
1117 | ksort($imageArray); |
||
1118 | |||
1119 | return $imageArray; |
||
1120 | } |
||
1121 | |||
1122 | /** |
||
1123 | * Returns an array of all of the config values for the current theme |
||
1124 | * |
||
1125 | * @return array |
||
1126 | */ |
||
1127 | 2 | public function getConfig() |
|
1128 | { |
||
1129 | 2 | global $sugar_config; |
|
1130 | |||
1131 | 2 | $config = array(); |
|
1132 | |||
1133 | 2 | foreach($this->config_options as $name => $def){ |
|
0 ignored issues
–
show
|
|||
1134 | 2 | $config[$name] = $def; |
|
1135 | |||
1136 | 2 | $value = ''; |
|
1137 | 2 | if(isset($sugar_config['theme_settings'][$this->dirName][$name])){ |
|
1138 | $value = $sugar_config['theme_settings'][$this->dirName][$name]; |
||
1139 | 2 | } else if(isset($def['default'])){ |
|
1140 | 2 | $value = $def['default']; |
|
1141 | } |
||
1142 | 2 | $config[$name] = $value; |
|
1143 | |||
1144 | } |
||
1145 | |||
1146 | 2 | return $config; |
|
1147 | } |
||
1148 | |||
1149 | } |
||
1150 | |||
1151 | /** |
||
1152 | * Registry for all the current classes in the system |
||
1153 | */ |
||
1154 | class SugarThemeRegistry |
||
0 ignored issues
–
show
|
|||
1155 | { |
||
1156 | /** |
||
1157 | * Array of all themes and thier object |
||
1158 | * |
||
1159 | * @var array |
||
1160 | */ |
||
1161 | private static $_themes = array(); |
||
1162 | |||
1163 | /** |
||
1164 | * Name of the current theme; corresponds to an index key in SugarThemeRegistry::$_themes |
||
1165 | * |
||
1166 | * @var string |
||
1167 | */ |
||
1168 | private static $_currentTheme; |
||
1169 | |||
1170 | /** |
||
1171 | * Disable the constructor since this will be a singleton |
||
1172 | */ |
||
1173 | private function __construct() {} |
||
1174 | |||
1175 | /** |
||
1176 | * Adds a new theme to the registry |
||
1177 | * |
||
1178 | * @param $themedef array |
||
1179 | */ |
||
1180 | public static function add( |
||
1181 | array $themedef |
||
1182 | ) |
||
1183 | { |
||
1184 | // make sure the we know the sugar version |
||
1185 | global $sugar_version; |
||
1186 | if (empty($sugar_version)) |
||
1187 | { |
||
1188 | include('sugar_version.php'); |
||
1189 | } |
||
1190 | |||
1191 | // Assume theme is designed for 5.5.x if not specified otherwise |
||
1192 | if ( !isset($themedef['version']) ) |
||
1193 | $themedef['version']['regex_matches'] = array('5\.5\.*'); |
||
1194 | |||
1195 | // Check to see if theme is valid for this version of Sugar; return false if not |
||
1196 | $version_ok = false; |
||
1197 | if( isset($themedef['version']['exact_matches']) ){ |
||
1198 | $matches_empty = false; |
||
1199 | foreach( $themedef['version']['exact_matches'] as $match ){ |
||
1200 | if( $match == $GLOBALS['sugar_version'] ){ |
||
1201 | $version_ok = true; |
||
1202 | } |
||
1203 | } |
||
1204 | } |
||
1205 | if( !$version_ok && isset($themedef['version']['regex_matches']) ){ |
||
1206 | $matches_empty = false; |
||
1207 | foreach( $themedef['version']['regex_matches'] as $match ){ |
||
1208 | if( preg_match( "/$match/", $GLOBALS['sugar_version'] ) ){ |
||
1209 | $version_ok = true; |
||
1210 | } |
||
1211 | } |
||
1212 | } |
||
1213 | if ( !$version_ok ) |
||
1214 | return false; |
||
1215 | |||
1216 | $theme = new SugarTheme($themedef); |
||
1217 | self::$_themes[$theme->dirName] = $theme; |
||
0 ignored issues
–
show
The property
$dirName is declared protected in SugarTheme . Since you implemented __get() , maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property. ![]() |
|||
1218 | } |
||
1219 | |||
1220 | /** |
||
1221 | * Removes a new theme from the registry |
||
1222 | * |
||
1223 | * @param $themeName string |
||
1224 | */ |
||
1225 | public static function remove( |
||
1226 | $themeName |
||
1227 | ) |
||
1228 | { |
||
1229 | if ( self::exists($themeName) ) |
||
1230 | unset(self::$_themes[$themeName]); |
||
1231 | } |
||
1232 | |||
1233 | /** |
||
1234 | * Returns a theme object in the registry specified by the given $themeName |
||
1235 | * |
||
1236 | * @param $themeName string |
||
1237 | */ |
||
1238 | 1 | public static function get( |
|
1239 | $themeName |
||
1240 | ) |
||
1241 | { |
||
1242 | 1 | if ( isset(self::$_themes[$themeName]) ) |
|
1243 | 1 | return self::$_themes[$themeName]; |
|
1244 | } |
||
1245 | |||
1246 | /** |
||
1247 | * Returns the current theme object |
||
1248 | * |
||
1249 | * @return SugarTheme object |
||
1250 | */ |
||
1251 | 40 | public static function current() |
|
1252 | { |
||
1253 | 40 | if ( !isset(self::$_currentTheme) ) |
|
1254 | self::buildRegistry(); |
||
1255 | |||
1256 | 40 | return self::$_themes[self::$_currentTheme]; |
|
1257 | } |
||
1258 | |||
1259 | /** |
||
1260 | * Returns the default theme object |
||
1261 | * |
||
1262 | * @return SugarTheme object |
||
1263 | */ |
||
1264 | public static function getDefault() |
||
1265 | { |
||
1266 | if ( !isset(self::$_currentTheme) ) |
||
1267 | self::buildRegistry(); |
||
1268 | |||
1269 | if ( isset($GLOBALS['sugar_config']['default_theme']) && self::exists($GLOBALS['sugar_config']['default_theme']) ) { |
||
1270 | return self::get($GLOBALS['sugar_config']['default_theme']); |
||
1271 | } |
||
1272 | $array_keys = array_keys(self::availableThemes()); |
||
1273 | return self::get(array_pop($array_keys)); |
||
1274 | } |
||
1275 | |||
1276 | /** |
||
1277 | * Returns true if a theme object specified by the given $themeName exists in the registry |
||
1278 | * |
||
1279 | * @param $themeName string |
||
1280 | * @return bool |
||
1281 | */ |
||
1282 | 1 | public static function exists( |
|
1283 | $themeName |
||
1284 | ) |
||
1285 | { |
||
1286 | 1 | return (self::get($themeName) !== null); |
|
1287 | } |
||
1288 | |||
1289 | /** |
||
1290 | * Sets the given $themeName to be the current theme |
||
1291 | * |
||
1292 | * @param $themeName string |
||
1293 | */ |
||
1294 | 1 | public static function set( |
|
1295 | $themeName |
||
1296 | ) |
||
1297 | { |
||
1298 | 1 | if ( !self::exists($themeName) ) |
|
1299 | return false; |
||
1300 | |||
1301 | 1 | self::$_currentTheme = $themeName; |
|
1302 | |||
1303 | // set some of the expected globals |
||
1304 | 1 | $GLOBALS['barChartColors'] = self::current()->barChartColors; |
|
0 ignored issues
–
show
The property
$barChartColors is declared protected in SugarTheme . Since you implemented __get() , maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property. ![]() |
|||
1305 | 1 | $GLOBALS['pieChartColors'] = self::current()->pieChartColors; |
|
0 ignored issues
–
show
The property
$pieChartColors is declared protected in SugarTheme . Since you implemented __get() , maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property. ![]() |
|||
1306 | 1 | return true; |
|
1307 | } |
||
1308 | |||
1309 | /** |
||
1310 | * Builds the theme registry |
||
1311 | */ |
||
1312 | public static function buildRegistry() |
||
1313 | { |
||
1314 | self::$_themes = array(); |
||
1315 | $dirs = array("themes/","custom/themes/"); |
||
1316 | |||
1317 | // check for a default themedef file |
||
1318 | $themedefDefault = array(); |
||
1319 | if ( sugar_is_file("custom/themes/default/themedef.php") ) { |
||
1320 | $themedef = array(); |
||
1321 | require("custom/themes/default/themedef.php"); |
||
1322 | $themedefDefault = $themedef; |
||
1323 | } |
||
1324 | |||
1325 | foreach ($dirs as $dirPath ) { |
||
1326 | if (sugar_is_dir('./'.$dirPath) && is_readable('./'.$dirPath) && $dir = opendir('./'.$dirPath)) { |
||
1327 | while (($file = readdir($dir)) !== false) { |
||
1328 | if ($file == ".." |
||
1329 | || $file == "." |
||
1330 | || $file == ".svn" |
||
1331 | || $file == "CVS" |
||
1332 | || $file == "Attic" |
||
1333 | || $file == "default" |
||
1334 | || !sugar_is_dir("./$dirPath".$file) |
||
1335 | || !sugar_is_file("./{$dirPath}{$file}/themedef.php") |
||
1336 | ) |
||
1337 | continue; |
||
1338 | $themedef = array(); |
||
1339 | require("./{$dirPath}{$file}/themedef.php"); |
||
1340 | $themedef = array_merge($themedef,$themedefDefault); |
||
1341 | $themedef['dirName'] = $file; |
||
1342 | // check for theme already existing in the registry |
||
1343 | // if so, then it will override the current one |
||
1344 | if ( self::exists($themedef['dirName']) ) { |
||
1345 | $existingTheme = self::get($themedef['dirName']); |
||
1346 | foreach ( SugarTheme::getThemeDefFields() as $field ) |
||
1347 | if ( !isset($themedef[$field]) ) |
||
1348 | $themedef[$field] = $existingTheme->$field; |
||
1349 | self::remove($themedef['dirName']); |
||
1350 | } |
||
1351 | if ( isset($themedef['name']) ) { |
||
1352 | self::add($themedef); |
||
1353 | } |
||
1354 | } |
||
1355 | closedir($dir); |
||
1356 | } |
||
1357 | } |
||
1358 | // default to setting the default theme as the current theme |
||
1359 | if ( !isset($GLOBALS['sugar_config']['default_theme']) || !self::set($GLOBALS['sugar_config']['default_theme']) ) { |
||
1360 | if ( count(self::availableThemes()) == 0 ) |
||
1361 | { |
||
1362 | sugar_die('No valid themes are found on this instance'); |
||
1363 | } else { |
||
1364 | self::set(self::getDefaultThemeKey()); |
||
1365 | } |
||
1366 | } |
||
1367 | } |
||
1368 | |||
1369 | |||
1370 | /** |
||
1371 | * getDefaultThemeKey |
||
1372 | * |
||
1373 | * This function returns the default theme key. It takes into account string casing issues that may arise |
||
1374 | * from upgrades. It attempts to look for the Sugar theme and if not found, defaults to return the name of the last theme |
||
1375 | * in the array of available themes loaded. |
||
1376 | * |
||
1377 | * @return $defaultThemeKey String value of the default theme key to use |
||
0 ignored issues
–
show
The doc-type
$defaultThemeKey could not be parsed: Unknown type name "$defaultThemeKey" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
1378 | */ |
||
1379 | private static function getDefaultThemeKey() |
||
1380 | { |
||
1381 | $availableThemes = self::availableThemes(); |
||
1382 | foreach($availableThemes as $key=>$theme) |
||
1383 | { |
||
1384 | if(strtolower($key) == 'sugar') |
||
1385 | { |
||
1386 | return $key; |
||
1387 | } |
||
1388 | } |
||
1389 | $array_keys = array_keys($availableThemes); |
||
1390 | return array_pop($array_keys); |
||
1391 | } |
||
1392 | |||
1393 | |||
1394 | /** |
||
1395 | * Returns an array of available themes. Designed to be absorbed into get_select_options_with_id() |
||
1396 | * |
||
1397 | * @return array |
||
1398 | */ |
||
1399 | 1 | public static function availableThemes() |
|
1400 | { |
||
1401 | 1 | $themelist = array(); |
|
1402 | 1 | $disabledThemes = array(); |
|
1403 | 1 | if ( isset($GLOBALS['sugar_config']['disabled_themes']) ) |
|
1404 | $disabledThemes = explode(',',$GLOBALS['sugar_config']['disabled_themes']); |
||
1405 | |||
1406 | 1 | foreach ( self::$_themes as $themename => $themeobject ) { |
|
1407 | 1 | if ( in_array($themename,$disabledThemes) ) |
|
1408 | continue; |
||
1409 | 1 | $themelist[$themeobject->dirName] = $themeobject->name; |
|
1410 | } |
||
1411 | 1 | asort($themelist, SORT_STRING); |
|
1412 | 1 | return $themelist; |
|
1413 | } |
||
1414 | |||
1415 | /** |
||
1416 | * Returns an array of un-available themes. Designed used with the theme selector in the admin panel |
||
1417 | * |
||
1418 | * @return array |
||
1419 | */ |
||
1420 | public static function unAvailableThemes() |
||
1421 | { |
||
1422 | $themelist = array(); |
||
1423 | $disabledThemes = array(); |
||
1424 | if ( isset($GLOBALS['sugar_config']['disabled_themes']) ) |
||
1425 | $disabledThemes = explode(',',$GLOBALS['sugar_config']['disabled_themes']); |
||
1426 | |||
1427 | foreach ( self::$_themes as $themename => $themeobject ) { |
||
1428 | if ( in_array($themename,$disabledThemes) ) |
||
1429 | $themelist[$themeobject->dirName] = $themeobject->name; |
||
1430 | } |
||
1431 | |||
1432 | return $themelist; |
||
1433 | } |
||
1434 | |||
1435 | /** |
||
1436 | * Returns an array of all themes found in the current installation |
||
1437 | * |
||
1438 | * @return array |
||
1439 | */ |
||
1440 | public static function allThemes() |
||
1441 | { |
||
1442 | $themelist = array(); |
||
1443 | |||
1444 | foreach ( self::$_themes as $themename => $themeobject ) |
||
1445 | $themelist[$themeobject->dirName] = $themeobject->name; |
||
1446 | |||
1447 | return $themelist; |
||
1448 | } |
||
1449 | |||
1450 | /** |
||
1451 | * Returns an array of all themes def found in the current installation |
||
1452 | * |
||
1453 | * @return array |
||
1454 | */ |
||
1455 | public static function allThemesDefs() |
||
1456 | { |
||
1457 | $themelist = array(); |
||
1458 | $disabledThemes = array(); |
||
1459 | if (isset($GLOBALS['sugar_config']['disabled_themes'])) |
||
1460 | $disabledThemes = explode(',', $GLOBALS['sugar_config']['disabled_themes']); |
||
1461 | |||
1462 | foreach (self::$_themes as $themename => $themeobject) { |
||
1463 | $themearray['name'] = $themeobject->name; |
||
1464 | $themearray['configurable'] = $themeobject->configurable; |
||
1465 | $themearray['enabled'] = !in_array($themename, $disabledThemes); |
||
1466 | $themelist[$themeobject->dirName] = $themearray; |
||
1467 | } |
||
1468 | |||
1469 | return $themelist; |
||
1470 | } |
||
1471 | |||
1472 | /** |
||
1473 | * get the configurable options for $themeName |
||
1474 | * |
||
1475 | * @param $themeName string |
||
1476 | */ |
||
1477 | public static function getThemeConfig($themeName) |
||
1478 | { |
||
1479 | global $sugar_config; |
||
1480 | |||
1481 | if ( !self::exists($themeName) ) |
||
1482 | return false; |
||
1483 | |||
1484 | $config = array(); |
||
1485 | |||
1486 | foreach(self::$_themes[$themeName]->config_options as $name => $def){ |
||
1487 | $config[$name] = $def; |
||
1488 | |||
1489 | $value = ''; |
||
1490 | if(isset($sugar_config['theme_settings'][$themeName][$name])){ |
||
1491 | $value = $sugar_config['theme_settings'][$themeName][$name]; |
||
1492 | } else if(isset($def['default'])){ |
||
1493 | $value = $def['default']; |
||
1494 | } |
||
1495 | $config[$name]['value'] = $value; |
||
1496 | |||
1497 | } |
||
1498 | |||
1499 | return $config; |
||
1500 | |||
1501 | } |
||
1502 | |||
1503 | /** |
||
1504 | * Clears out the cached path locations for all themes |
||
1505 | */ |
||
1506 | public static function clearAllCaches() |
||
1507 | { |
||
1508 | foreach ( self::$_themes as $themeobject ) { |
||
1509 | $themeobject->clearCache(); |
||
1510 | } |
||
1511 | } |
||
1512 | } |
||
1513 |
When comparing two booleans, it is generally considered safer to use the strict comparison operator.