xos_opal_Theme::addStylesheet()   A
last analyzed

Complexity

Conditions 6
Paths 32

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 12
dl 0
loc 19
rs 9.2222
c 0
b 0
f 0
cc 6
nc 32
nop 4
1
<?php
2
/**
3
 * xos_opal_Theme component class file
4
 *
5
 * You may not change or alter any portion of this comment or credits
6
 * of supporting developers from this source code or any supporting source code
7
 * which is considered copyrighted (c) material of the original comment or credit authors.
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * @copyright       (c) 2000-2020 XOOPS Project (https://xoops.org)
13
 * @license             GNU GPL 2 (https://www.gnu.org/licenses/gpl-2.0.html)
14
 * @author              Skalpa Keo <[email protected]>
15
 * @author              Taiwen Jiang <[email protected]>
16
 * @since               2.3.0
17
 * @package             kernel
18
 * @subpackage          xos_opal_Theme
19
 */
20
21
use Xmf\Request;
22
23
defined('XOOPS_ROOT_PATH') || exit('Restricted access');
24
25
/**
26
 * xos_opal_ThemeFactory
27
 *
28
 * @author     Skalpa Keo
29
 * @package    xos_opal
30
 * @subpackage xos_opal_Theme
31
 * @since      2.3.0
32
 */
33
class xos_opal_ThemeFactory
34
{
35
    public $xoBundleIdentifier = 'xos_opal_ThemeFactory';
36
    /**
37
     * Currently enabled themes (if empty, all the themes in themes/ are allowed)
38
     *
39
     * @var array
40
     */
41
    public $allowedThemes = array();
42
    /**
43
     * Default theme to instantiate if none specified
44
     *
45
     * @var string
46
     */
47
    public $defaultTheme = 'default';
48
    /**
49
     * If users are allowed to choose a custom theme
50
     *
51
     * @var bool
52
     */
53
    public $allowUserSelection = true;
54
55
    /**
56
     * Instantiate the specified theme
57
     * @param  array $options
58
     * @param  array $initArgs
59
     * @return null|xos_opal_Theme
60
     */
61
    public function createInstance($options = array(), $initArgs = array())
62
    {
63
        // Grab the theme folder from request vars if present
64
        if (empty($options['folderName'])) {
65
            if (isset($_REQUEST['xoops_theme_select']) && ($req = $_REQUEST['xoops_theme_select']) && $this->isThemeAllowed($req)) {
66
                $options['folderName'] = $req;
67
                if (isset($_SESSION) && $this->allowUserSelection) {
68
                    $_SESSION[$this->xoBundleIdentifier]['defaultTheme'] = $req;
69
                }
70
            } elseif (isset($_SESSION[$this->xoBundleIdentifier]['defaultTheme'])) {
71
                $options['folderName'] = $_SESSION[$this->xoBundleIdentifier]['defaultTheme'];
72
            } elseif (empty($options['folderName']) || !$this->isThemeAllowed($options['folderName'])) {
73
                $options['folderName'] = $this->defaultTheme;
74
            }
75
            $GLOBALS['xoopsConfig']['theme_set'] = $options['folderName'];
76
        }
77
        $testPath = isset($options['themesPath'])
78
            ? XOOPS_ROOT_PATH  . '/' . $options['themesPath'] . '/' . $options['folderName']
79
            : XOOPS_THEME_PATH . '/' . $options['folderName'];
80
        if (!(file_exists($testPath  . '/theme.tpl')
81
            || file_exists($testPath . '/theme.html'))
82
        ) {
83
            trigger_error('Theme not found -- ' . $options['folderName']);
84
            $this->defaultTheme = 'default';
85
            $options['folderName'] = $this->defaultTheme;
86
            $GLOBALS['xoopsConfig']['theme_set'] = $options['folderName'];
87
        }
88
        $options['path'] = XOOPS_THEME_PATH . '/' . $options['folderName'];
89
        $inst            = new xos_opal_Theme();
90
        foreach ($options as $k => $v) {
91
            $inst->$k = $v;
92
        }
93
        $inst->xoInit();
94
95
        return $inst;
96
    }
97
98
    /**
99
     * Checks if the specified theme is enabled or not
100
     *
101
     * @param  string $name
102
     * @return bool
103
     */
104
    public function isThemeAllowed($name)
105
    {
106
        return (empty($this->allowedThemes) || in_array($name, $this->allowedThemes));
107
    }
108
}
109
110
/**
111
 * xos_opal_AdminThemeFactory
112
 *
113
 * @author     Andricq Nicolas (AKA MusS)
114
 * @author     trabis
115
 * @package    xos_opal
116
 * @subpackage xos_opal_Theme
117
 * @since      2.4.0
118
 */
119
class xos_opal_AdminThemeFactory extends xos_opal_ThemeFactory
120
{
121
    /**
122
     * @param array $options
123
     * @param array $initArgs
124
     *
125
     * @return null|xos_opal_Theme
126
     */
127
    public function &createInstance($options = array(), $initArgs = array())
128
    {
129
        $options['plugins']      = array();
130
        $options['renderBanner'] = false;
131
        $inst                    = parent::createInstance($options, $initArgs);
132
        $inst->path              = XOOPS_ADMINTHEME_PATH . '/' . $inst->folderName;
133
        $inst->url               = XOOPS_ADMINTHEME_URL . '/' . $inst->folderName;
134
        $inst->template->assign(array(
135
                                    'theme_path'  => $inst->path,
136
                                    'theme_tpl'   => $inst->path . '/xotpl',
137
                                    'theme_url'   => $inst->url,
138
                                    'theme_img'   => $inst->url . '/img',
139
                                    'theme_icons' => $inst->url . '/icons',
140
                                    'theme_css'   => $inst->url . '/css',
141
                                    'theme_js'    => $inst->url . '/js',
142
                                    'theme_lang'  => $inst->url . '/language'));
143
144
        return $inst;
145
    }
146
}
147
148
/**
149
 * Class xos_opal_Theme
150
 */
151
class xos_opal_Theme
152
{
153
    /**
154
     * Should we render banner? Not for redirect pages or admin side
155
     *
156
     * @var bool
157
     */
158
    public $renderBanner = true;
159
    /**
160
     * The name of this theme
161
     *
162
     * @var string
163
     */
164
    public $folderName = '';
165
    /**
166
     * Physical path of this theme folder
167
     *
168
     * @var string
169
     */
170
    public $path = '';
171
    public $url  = '';
172
173
    /**
174
     * Whether or not the theme engine should include the output generated by PHP
175
     *
176
     * @var string
177
     */
178
    public $bufferOutput = true;
179
    /**
180
     * Canvas-level template to use
181
     *
182
     * @var string
183
     */
184
    public $canvasTemplate = 'theme.tpl';
185
186
    /**
187
     * Theme folder path
188
     *
189
     * @var string
190
     */
191
    public $themesPath = 'themes';
192
193
    /**
194
     * Content-level template to use
195
     *
196
     * @var string
197
     */
198
    public $contentTemplate = '';
199
200
    public $contentCacheLifetime = 0;
201
    public $contentCacheId;
202
203
    /**
204
     * Text content to display right after the contentTemplate output
205
     *
206
     * @var string
207
     */
208
    public $content = '';
209
    /**
210
     * Page construction plug-ins to use
211
     *
212
     * @var array
213
     * @access public
214
     */
215
    public $plugins     = array(
216
        'xos_logos_PageBuilder');
217
    public $renderCount = 0;
218
    /**
219
     * Pointer to the theme template engine
220
     *
221
     * @var XoopsTpl
222
     */
223
    public $template = false;
224
225
    /**
226
     * Array containing the document meta-information
227
     *
228
     * @var array
229
     */
230
    public $metas = array(
231
        //'http' => array(
232
        //    'Content-Script-Type' => 'text/javascript' ,
233
        //    'Content-Style-Type' => 'text/css') ,
234
        'meta'   => array(),
235
        'link'   => array(),
236
        'script' => array());
237
238
    /**
239
     * Array of strings to be inserted in the head tag of HTML documents
240
     *
241
     * @var array
242
     */
243
    public $htmlHeadStrings = array();
244
    /**
245
     * Custom variables that will always be assigned to the template
246
     *
247
     * @var array
248
     */
249
    public $templateVars = array();
250
251
    /**
252
     * User extra information for cache id, like language, user groups
253
     *
254
     * @var boolean
255
     */
256
    public $use_extra_cache_id = true;
257
258
    /**
259
     * *#@-
260
     */
261
262
    /**
263
     * *#@+
264
     *
265
     * @tasktype 10 Initialization
266
     */
267
    /**
268
     * Initializes this theme
269
     *
270
     * Upon initialization, the theme creates its template engine and instantiates the
271
     * plug-ins from the specified {@link $plugins} list. If the theme is a 2.0 theme, that does not
272
     * display redirection messages, the HTTP redirections system is disabled to ensure users will
273
     * see the redirection screen.
274
     *
275
     * @param  array $options
276
     * @return bool
277
     */
278
    public function xoInit($options = array())
0 ignored issues
show
Unused Code introduced by
The parameter $options is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

278
    public function xoInit(/** @scrutinizer ignore-unused */ $options = array())

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
279
    {
280
        /** @var XoopsConfigHandler $configHandler */
281
        $configHandler = xoops_getHandler('config');
282
283
        $this->path                   = XOOPS_THEME_PATH . '/' . $this->folderName;
284
        $this->url                    = XOOPS_THEME_URL . '/' . $this->folderName;
285
        $this->template               = null;
286
        $this->template               = new XoopsTpl();
287
        $this->template->currentTheme = $this;
288
        $this->template->assignByRef('xoTheme', $this);
289
        $GLOBALS['xoTheme']  = $this;
290
        $GLOBALS['xoopsTpl'] = $this->template;
291
        $tempPath = str_replace('\\', '/', realpath(XOOPS_ROOT_PATH) . '/');
292
        $tempName = str_replace('\\', '/', realpath($_SERVER['SCRIPT_FILENAME']));
293
        $xoops_page = str_replace($tempPath, '', $tempName);
294
        if (strpos($xoops_page, 'modules') !== false) {
295
            $xoops_page = str_replace('modules/', '', $xoops_page);
296
        }
297
        $tempScriptname = str_replace('\\', '/', $_SERVER['SCRIPT_NAME']);
298
        $tempRequesturi = str_replace('\\', '/', Request::getString('REQUEST_URI', '', 'SERVER'));
299
        if (strlen($tempRequesturi) > strlen($tempScriptname)) {
300
            $xoops_modulepage =  $xoops_page . str_replace($tempScriptname, '', $tempRequesturi);
301
        } else {
302
            $xoops_modulepage =  '';
303
        }
304
        $xoops_page = str_replace('.php', '', $xoops_page);
305
        if (isset($GLOBALS['xoopsConfig']['startpage'])) {
306
            $xoops_startpage = $GLOBALS['xoopsConfig']['startpage'];
307
            if ($xoops_startpage == '--') {
308
                $xoops_startpage = 'system';
309
            }
310
        } else {
311
            $xoops_startpage = 'system';
312
        }
313
        // call the theme_autorun.php if the theme has one
314
        if (file_exists($this->path . "/theme_autorun.php")) {
315
            include_once($this->path . "/theme_autorun.php");
316
        }
317
318
        $searchConfig = $configHandler->getConfigsByCat(XOOPS_CONF_SEARCH);
319
        $xoops_search = (bool) (isset($searchConfig['enable_search']) && $searchConfig['enable_search'] === 1);
320
        $this->template->assign(array(
321
            'xoops_theme'      => $GLOBALS['xoopsConfig']['theme_set'],
322
            'xoops_imageurl'   => XOOPS_THEME_URL . '/' . $GLOBALS['xoopsConfig']['theme_set'] . '/',
323
            'xoops_themecss'   => xoops_getcss($GLOBALS['xoopsConfig']['theme_set']),
324
            'xoops_requesturi' => htmlspecialchars($_SERVER['REQUEST_URI'], ENT_QUOTES | ENT_HTML5),
325
            'xoops_sitename'   => htmlspecialchars($GLOBALS['xoopsConfig']['sitename'], ENT_QUOTES | ENT_HTML5),
326
            'xoops_slogan'     => htmlspecialchars($GLOBALS['xoopsConfig']['slogan'], ENT_QUOTES | ENT_HTML5),
327
            'xoops_dirname'    => isset($GLOBALS['xoopsModule']) && is_object($GLOBALS['xoopsModule'])
328
                ? $GLOBALS['xoopsModule']->getVar('dirname') : 'system',
329
            'xoops_page'       => $xoops_page,
330
            'xoops_startpage'  => $xoops_startpage,
331
            'xoops_modulepage' => $xoops_modulepage,
332
            'xoops_banner'     => ($GLOBALS['xoopsConfig']['banners'] && $this->renderBanner)
333
                ? xoops_getbanner() : '&nbsp;',
334
            'xoops_pagetitle'  => isset($GLOBALS['xoopsModule']) && is_object($GLOBALS['xoopsModule'])
335
                ? $GLOBALS['xoopsModule']->getVar('name')
336
                : htmlspecialchars($GLOBALS['xoopsConfig']['slogan'], ENT_QUOTES | ENT_HTML5),
337
            'xoops_search'     => $xoops_search,
338
        ));
339
        if (isset($GLOBALS['xoopsUser']) && is_object($GLOBALS['xoopsUser'])) {
340
            $this->template->assign(array(
341
                'xoops_isuser'     => true,
342
                'xoops_avatar'     => XOOPS_UPLOAD_URL . '/' . $GLOBALS['xoopsUser']->getVar('user_avatar'),
343
                'xoops_userid'     => $GLOBALS['xoopsUser']->getVar('uid'),
344
                'xoops_uname'      => $GLOBALS['xoopsUser']->getVar('uname'),
345
                'xoops_name'       => $GLOBALS['xoopsUser']->getVar('name'),
346
                'xoops_isadmin'    => $GLOBALS['xoopsUserIsAdmin'],
347
                'xoops_usergroups' => $GLOBALS['xoopsUser']->getGroups(),
348
            ));
349
        } else {
350
            $this->template->assign(array(
351
                'xoops_isuser'     => false,
352
                'xoops_isadmin'    => false,
353
                'xoops_usergroups' => array(XOOPS_GROUP_ANONYMOUS),
354
            ));
355
        }
356
357
        // Meta tags
358
        $criteria       = new CriteriaCompo(new Criteria('conf_modid', 0));
359
        $criteria->add(new Criteria('conf_catid', XOOPS_CONF_METAFOOTER));
360
        $config = $configHandler->getConfigs($criteria, true);
361
        foreach (array_keys($config) as $i) {
362
            $name = $config[$i]->getVar('conf_name', 'n');
363
            $value = $config[$i]->getVar('conf_value', 'n');
364
            // limited substitutions for {X_SITEURL} and {X_YEAR}
365
            if ($name === 'footer' || $name === 'meta_copyright') {
366
                $value = str_replace('{X_SITEURL}', XOOPS_URL . '/', $value);
367
                $value = str_replace('{X_YEAR}', date('Y', time()), $value);
368
            }
369
            if (substr($name, 0, 5) === 'meta_') {
370
                $this->addMeta('meta', substr($name, 5), $value);
371
            } else {
372
                // prefix each tag with 'xoops_'
373
                $this->template->assign("xoops_$name", $value);
374
            }
375
        }
376
        // Load global javascript
377
        $this->addScript('include/xoops.js');
378
        $this->loadLocalization();
379
380
        if ($this->bufferOutput) {
381
            ob_start();
382
        }
383
        // Instantiate and initialize all the theme plugins
384
        foreach ($this->plugins as $k => $bundleId) {
385
            if (!is_object($bundleId)) {
386
                $this->plugins[$bundleId]        = null;
387
                $this->plugins[$bundleId]        = new $bundleId();
388
                $this->plugins[$bundleId]->theme =& $this;
389
                $this->plugins[$bundleId]->xoInit();
390
                unset($this->plugins[$k]);
391
            }
392
        }
393
394
        return true;
395
    }
396
397
    /**
398
     * Generate cache id based on extra information of language and user groups
399
     *
400
     * User groups other than anonymous should be detected to avoid disclosing group sensitive contents
401
     *
402
     * @param  string $cache_id    raw cache id
403
     * @param  string $extraString extra string
404
     * @return string complete cache id
405
     */
406
    public function generateCacheId($cache_id, $extraString = '')
407
    {
408
        static $extra_string;
409
        if (!$this->use_extra_cache_id) {
410
            return $cache_id;
411
        }
412
413
        if (empty($extraString)) {
414
            if (empty($extra_string)) {
415
                // Generate language section
416
                $extra_string = $GLOBALS['xoopsConfig']['language'];
417
                // Generate group section
418
                if (!isset($GLOBALS['xoopsUser']) || !is_object($GLOBALS['xoopsUser'])) {
419
                    $extra_string .= '-' . XOOPS_GROUP_ANONYMOUS;
420
                } else {
421
                    $groups = $GLOBALS['xoopsUser']->getGroups();
422
                    sort($groups);
423
                    // Generate group string for non-anonymous groups,
424
                    // XOOPS_DB_PASS and XOOPS_DB_NAME (before we find better variables) are used to protect group sensitive contents
425
                    $extra_string .= '-' . substr(md5(implode('-', $groups)), 0, 8) . '-' . substr(md5(XOOPS_DB_PASS . XOOPS_DB_NAME . XOOPS_DB_USER), 0, 8);
426
                }
427
            }
428
            $extraString = $extra_string;
429
        }
430
        $cache_id .= '-' . $extraString;
431
432
        return $cache_id;
433
    }
434
435
    /**
436
     * xos_opal_Theme::checkCache()
437
     *
438
     * @return bool
439
     */
440
    public function checkCache()
441
    {
442
        if ($_SERVER['REQUEST_METHOD'] !== 'POST' && $this->contentCacheLifetime) {
443
            $template                       = $this->contentTemplate ?: 'db:system_dummy.tpl';
444
            $this->template->caching        = 2;
445
            $this->template->cache_lifetime = $this->contentCacheLifetime;
446
            $uri                            = str_replace(XOOPS_URL, '', $_SERVER['REQUEST_URI']);
447
            // Clean uri by removing session id
448
            if (defined('SID') && SID && strpos($uri, SID)) {
449
                $uri = preg_replace("/([\?&])(" . SID . "$|" . SID . '&)/', "\\1", $uri);
450
            }
451
            $this->contentCacheId = $this->generateCacheId('page_' . substr(md5($uri), 0, 8));
452
            if ($this->template->isCached($template, $this->contentCacheId)) {
453
                $xoopsLogger = XoopsLogger::getInstance();
454
                $xoopsLogger->addExtra($template, sprintf('Cached (regenerates every %d seconds)', $this->contentCacheLifetime));
455
                $this->render(null, null, $template);
456
457
                return true;
458
            }
459
        }
460
461
        return false;
462
    }
463
464
    /**
465
     * Render the page
466
     *
467
     * The theme engine builds pages from 2 templates: canvas and content.
468
     *
469
     * A module can call this method directly and specify what templates the theme engine must use.
470
     * If render() hasn't been called before, the theme defaults will be used for the canvas and
471
     * page template (and xoopsOption['template_main'] for the content).
472
     *
473
     * @param string $canvasTpl  The canvas template, if different from the theme default
474
     * @param string $pageTpl    The page template, if different from the theme default (unsupported, 2.3+ only)
475
     * @param string $contentTpl The content template
476
     * @param array  $vars       Template variables to send to the template engine
477
     *
478
     * @return bool
479
     */
480
    public function render($canvasTpl = null, $pageTpl = null, $contentTpl = null, $vars = array())
481
    {
482
        if ($this->renderCount) {
483
            return false;
484
        }
485
        $xoopsLogger = XoopsLogger::getInstance();
486
        $xoopsLogger->startTime('Page rendering');
487
488
        xoops_load('xoopscache');
489
        $cache = XoopsCache::getInstance();
490
491
        //Get meta information for cached pages
492
        if ($this->contentCacheLifetime && $this->contentCacheId && $content = $cache->read($this->contentCacheId)) {
493
            //we need to merge metas set by blocks, with the module cached meta
494
            $this->htmlHeadStrings = array_merge($this->htmlHeadStrings, $content['htmlHeadStrings']);
495
            foreach ($content['metas'] as $type => $value) {
496
                $this->metas[$type] = array_merge($this->metas[$type], $content['metas'][$type]);
497
            }
498
            $GLOBALS['xoopsOption']['xoops_pagetitle']     = $content['xoops_pagetitle'];
499
            $GLOBALS['xoopsOption']['xoops_module_header'] = $content['header'];
500
        }
501
        /** if cache was not found, define $content[] */
502
        if (!isset($content) || false === $content) {
503
            $content = array();
504
        }
505
        if (!empty($GLOBALS['xoopsOption']['xoops_pagetitle'])) {
506
            $this->template->assign('xoops_pagetitle', $GLOBALS['xoopsOption']['xoops_pagetitle']);
507
        }
508
        $header = empty($GLOBALS['xoopsOption']['xoops_module_header']) ? $this->template->getTemplateVars('xoops_module_header') : $GLOBALS['xoopsOption']['xoops_module_header'];
509
510
        //save meta information of cached pages
511
        if ($this->contentCacheLifetime && $this->contentCacheId && !$contentTpl) {
512
            $content['htmlHeadStrings'] = $this->htmlHeadStrings;
513
            $content['metas']           = $this->metas;
514
            $content['xoops_pagetitle'] = $this->template->getTemplateVars('xoops_pagetitle');
515
            $content['header']          = $header;
516
            $cache->write($this->contentCacheId, $content);
517
        }
518
519
        //  @internal : Lame fix to ensure the metas specified in the xoops config page don't appear twice
520
        $old = array(
521
            'robots',
522
            'keywords',
523
            'description',
524
            'rating',
525
            'author',
526
            'copyright');
527
        foreach ($this->metas['meta'] as $name => $value) {
528
            if (in_array($name, $old)) {
529
                $this->template->assign("xoops_meta_$name", htmlspecialchars($value, ENT_QUOTES | ENT_HTML5));
530
                unset($this->metas['meta'][$name]);
531
            }
532
        }
533
534
        // We assume no overlap between $GLOBALS['xoopsOption']['xoops_module_header'] and $this->template->getTemplateVars( 'xoops_module_header' ) ?
535
        $this->template->assign('xoops_module_header', $this->renderMetas(null, true) . "\n" . $header);
0 ignored issues
show
Bug introduced by
Are you sure $header of type array|mixed|null can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

535
        $this->template->assign('xoops_module_header', $this->renderMetas(null, true) . "\n" . /** @scrutinizer ignore-type */ $header);
Loading history...
536
537
        if ($canvasTpl) {
538
            $this->canvasTemplate = $canvasTpl;
539
        }
540
        if ($contentTpl) {
541
            $this->contentTemplate = $contentTpl;
542
        }
543
        if (!empty($vars)) {
544
            $this->template->assign($vars);
545
        }
546
        if ($this->contentTemplate) {
547
            $this->content = $this->template->fetch($this->contentTemplate, $this->contentCacheId);
548
        }
549
        if ($this->bufferOutput) {
550
            $this->content .= ob_get_contents();
551
            ob_end_clean();
552
        }
553
554
        $this->template->assignByRef('xoops_contents', $this->content);
555
556
        // Do not cache the main (theme.html) template output
557
        $this->template->caching = 0;
558
        if (file_exists($this->path . '/' . $this->canvasTemplate)) {
559
            $this->template->display($this->path . '/' . $this->canvasTemplate);
560
        } else {
561
            $this->template->display($this->path . '/theme.html');
562
        }
563
        $this->renderCount++;
564
        $xoopsLogger->stopTime('Page rendering');
565
566
        return true;
567
    }
568
569
    /**
570
     * Load localization information
571
     *
572
     * Folder structure for localization:
573
     * <ul>themes/themefolder/english
574
     *     <li>main.php - language definitions</li>
575
     *     <li>style.css - localization stylesheet</li>
576
     *     <li>script.js - localization script</li>
577
     * </ul>
578
     * @param  string $type
579
     * @return bool
580
     */
581
    public function loadLocalization($type = 'main')
582
    {
583
        $language = $GLOBALS['xoopsConfig']['language'];
584
        // Load global localization stylesheet if available
585
        if (file_exists($GLOBALS['xoops']->path('language/' . $language . '/style.css'))) {
586
            $this->addStylesheet($GLOBALS['xoops']->url('language/' . $language . '/style.css'));
587
        }
588
        $this->addLanguage($type, $language);
589
        // Load theme localization stylesheet and scripts if available
590
        if (file_exists($this->path . '/language/' . $language . '/script.js')) {
591
            $this->addScript($this->url . '/language/' . $language . '/script.js');
592
        }
593
        if (file_exists($this->path . '/language/' . $language . '/style.css')) {
594
            $this->addStylesheet($this->url . '/language/' . $language . '/style.css');
595
        }
596
597
        return true;
598
    }
599
600
    /**
601
     * Load theme specific language constants
602
     *
603
     * @param string $type     language type, like 'main', 'admin'; Needs to be declared in theme xo-info.php
604
     * @param string $language specific language
605
     *
606
     * @return bool|mixed
607
     */
608
    public function addLanguage($type = 'main', $language = null)
609
    {
610
        $language = (null === $language) ? $GLOBALS['xoopsConfig']['language'] : $language;
611
        if (!file_exists($fileinc = $this->path . "/language/{$language}/{$type}.php")) {
612
            if (!file_exists($fileinc = $this->path . "/language/english/{$type}.php")) {
613
                return false;
614
            }
615
        }
616
        $ret = include_once $fileinc;
617
618
        return $ret;
619
    }
620
621
    /**
622
     * *#@+
623
     *
624
     * @tasktype 20 Manipulating page meta-information
625
     */
626
    /**
627
     * Adds script code to the document head
628
     *
629
     * This methods allows the insertion of an external script file (if $src is provided), or
630
     * of a script snippet. The file URI is parsed to take benefit of the theme resource
631
     * overloading system.
632
     *
633
     * The $attributes parameter allows you to specify the attributes that will be added to the
634
     * inserted <script> tag. If unspecified, the <var>type</var> attribute value will default to
635
     * 'text/javascript'.
636
     *
637
     * <code>
638
     * // Add an external script using a physical path
639
     * $theme->addScript( 'www/script.js', null, '' );
640
     * $theme->addScript( 'modules/newbb/script.js', null, '' );
641
     * // Specify attributes for the <script> tag
642
     * $theme->addScript( 'mod_xoops_SiteManager#common.js', array( 'type' => 'application/x-javascript' ), '', 'mod_xoops_Sitemanager' );
643
     * // Insert a code snippet
644
     * $theme->addScript( null, array( 'type' => 'application/x-javascript' ), 'window.open("Hello world");', 'hello' );
645
     * </code>
646
     *
647
     * @param  string $src        path to an external script file
648
     * @param  array  $attributes hash of attributes to add to the <script> tag
649
     * @param  string $content    Code snippet to output within the <script> tag
650
     * @param  string $name       Element Name in array scripts are stored in.
651
     * @return void
652
     */
653
    public function addScript($src = '', $attributes = array(), $content = '', $name = '')
654
    {
655
        if (empty($attributes)) {
656
            $attributes = array();
657
        }
658
        if (!empty($src)) {
659
            $src               = $GLOBALS['xoops']->url($this->resourcePath($src));
660
            $attributes['src'] = $src;
661
        }
662
        if (!empty($content)) {
663
            $attributes['_'] = $content;
664
        }
665
        if (!isset($attributes['type'])) {
666
            $attributes['type'] = 'text/javascript';
667
        }
668
        if (empty($name)) {
669
            $name = md5(serialize($attributes));
670
        }
671
        $this->addMeta('script', $name, $attributes);
0 ignored issues
show
Bug introduced by
$attributes of type array is incompatible with the type string expected by parameter $value of xos_opal_Theme::addMeta(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

671
        $this->addMeta('script', $name, /** @scrutinizer ignore-type */ $attributes);
Loading history...
672
    }
673
674
    /**
675
     * Add StyleSheet or CSS code to the document head
676
     *
677
     * @param  string $src        path to .css file
678
     * @param  array  $attributes name => value paired array of attributes such as title
679
     * @param  string $content    CSS code to output between the <style> tags (in case $src is empty)
680
     * @param  string $name       Element Name in array stylesheets are stored in.
681
     * @return void
682
     */
683
    public function addStylesheet($src = '', $attributes = array(), $content = '', $name = '')
684
    {
685
        if (empty($attributes)) {
686
            $attributes = array();
687
        }
688
        if (!empty($src)) {
689
            $src                = $GLOBALS['xoops']->url($this->resourcePath($src));
690
            $attributes['href'] = $src;
691
        }
692
        if (!isset($attributes['type'])) {
693
            $attributes['type'] = 'text/css';
694
        }
695
        if (!empty($content)) {
696
            $attributes['_'] = $content;
697
        }
698
        if (empty($name)) {
699
            $name = md5(serialize($attributes));
700
        }
701
        $this->addMeta('stylesheet', $name, $attributes);
0 ignored issues
show
Bug introduced by
$attributes of type array is incompatible with the type string expected by parameter $value of xos_opal_Theme::addMeta(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

701
        $this->addMeta('stylesheet', $name, /** @scrutinizer ignore-type */ $attributes);
Loading history...
702
    }
703
704
    /**
705
     * Add a <link> to the header
706
     *
707
     * @param string $rel        Relationship from the current doc to the anchored one
708
     * @param string $href       URI of the anchored document
709
     * @param array  $attributes Additional attributes to add to the <link> element
710
     * @param string $name       Element Name in array links are stored in.
711
     */
712
    public function addLink($rel, $href = '', $attributes = array(), $name = '')
713
    {
714
        if (empty($attributes)) {
715
            $attributes = array();
716
        }
717
        if (!empty($href)) {
718
            $attributes['href'] = $href;
719
        }
720
        $attributes['rel'] = $rel;
721
        if (empty($name)) {
722
            $name = md5(serialize($attributes));
723
        }
724
        $this->addMeta('link', $name, $attributes);
0 ignored issues
show
Bug introduced by
$attributes of type array is incompatible with the type string expected by parameter $value of xos_opal_Theme::addMeta(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

724
        $this->addMeta('link', $name, /** @scrutinizer ignore-type */ $attributes);
Loading history...
725
    }
726
727
    /**
728
     * Set a meta http-equiv value
729
     * @param         $name
730
     * @param  null   $value
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $value is correct as it would always require null to be passed?
Loading history...
731
     * @return string
732
     */
733
    public function addHttpMeta($name, $value = null)
734
    {
735
        if (isset($value)) {
736
            return $this->addMeta('http', $name, $value);
737
        }
738
        unset($this->metas['http'][$name]);
739
        return null;
740
    }
741
742
    /**
743
     * Change output page meta-information
744
     * @param  string $type
745
     * @param  string $name
746
     * @param  string $value
747
     * @return string
748
     */
749
    public function addMeta($type = 'meta', $name = '', $value = '')
750
    {
751
        if (!isset($this->metas[$type])) {
752
            $this->metas[$type] = array();
753
        }
754
        if (!empty($name)) {
755
            $this->metas[$type][$name] = $value;
756
        } else {
757
            $this->metas[$type][md5(serialize(array($value)))] = $value;
758
        }
759
760
        return $value;
761
    }
762
763
    /**
764
     * xos_opal_Theme::headContent()
765
     *
766
     * @param mixed $params
767
     * @param mixed $content
768
     * @param mixed $smarty
769
     * @param mixed $repeat
770
     *
771
     * @return void
772
     */
773
    public function headContent($params, $content, &$smarty, &$repeat)
0 ignored issues
show
Unused Code introduced by
The parameter $params is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

773
    public function headContent(/** @scrutinizer ignore-unused */ $params, $content, &$smarty, &$repeat)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $smarty is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

773
    public function headContent($params, $content, /** @scrutinizer ignore-unused */ &$smarty, &$repeat)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
774
    {
775
        if (!$repeat) {
776
            $this->htmlHeadStrings[] = $content;
777
        }
778
    }
779
780
    /**
781
     * xos_opal_Theme::renderMetas()
782
     *
783
     * @param  mixed $type
784
     * @param  mixed $return
785
     * @return bool|string
786
     */
787
    public function renderMetas($type = null, $return = false)
788
    {
789
        $str = '';
790
        if (!isset($type)) {
791
            foreach (array_keys($this->metas) as $type) {
792
                $str .= $this->renderMetas($type, true);
793
            }
794
            $str .= implode("\n", $this->htmlHeadStrings);
795
        } else {
796
            switch ($type) {
797
                case 'script':
798
                    foreach ($this->metas[$type] as $attrs) {
799
                        $str .= '<script' . $this->renderAttributes($attrs) . '>';
800
                        if (isset($attrs['_'])) {
801
                            $str .= "\n//<![CDATA[\n" . $attrs['_'] . "\n//]]>";
802
                        }
803
                        $str .= "</script>\n";
804
                    }
805
                    break;
806
                case 'link':
807
                    foreach ($this->metas[$type] as $attrs) {
808
                        $rel = $attrs['rel'];
809
                        unset($attrs['rel']);
810
                        $str .= '<link rel="' . $rel . '"' . $this->renderAttributes($attrs) . " />\n";
811
                    }
812
                    break;
813
                case 'stylesheet':
814
                    foreach ($this->metas[$type] as $attrs) {
815
                        if (isset($attrs['_'])) {
816
                            $str .= '<style' . $this->renderAttributes($attrs) . ">\n/* <![CDATA[ */\n" . (isset($attrs['_'])?$attrs['_']:'') . "\n/* //]]> */\n</style>";
817
                        } else {
818
                            $str .= '<link rel="stylesheet"' . $this->renderAttributes($attrs) . " />\n";
819
                        }
820
                    }
821
                    break;
822
                case 'http':
823
                    foreach ($this->metas[$type] as $name => $content) {
824
                        $str .= '<meta http-equiv="' . htmlspecialchars($name, ENT_QUOTES | ENT_HTML5) . '" content="' . htmlspecialchars($content, ENT_QUOTES | ENT_HTML5) . "\" />\n";
825
                    }
826
                    break;
827
                default:
828
                    foreach ($this->metas[$type] as $name => $content) {
829
                        $str .= '<meta name="' . htmlspecialchars($name, ENT_QUOTES | ENT_HTML5) . '" content="' . htmlspecialchars($content, ENT_QUOTES | ENT_HTML5) . "\" />\n";
830
                    }
831
                    break;
832
            }
833
        }
834
        if ($return) {
835
            return $str;
836
        }
837
        echo $str;
838
839
        return true;
840
    }
841
842
    /**
843
     * Generates a unique element ID
844
     *
845
     * @param  string $tagName
846
     * @return string
847
     */
848
    public function genElementId($tagName = 'xos')
849
    {
850
        static $cache = array();
851
        if (!isset($cache[$tagName])) {
852
            $cache[$tagName] = 1;
853
        }
854
855
        return $tagName . '-' . $cache[$tagName]++;
856
    }
857
858
    /**
859
     * Transform an attribute collection to an XML string
860
     *
861
     * @param  array $coll
862
     * @return string
863
     */
864
    public function renderAttributes($coll)
865
    {
866
        $str = '';
867
        foreach ($coll as $name => $val) {
868
            if ($name !== '_') {
869
                $str .= ' ' . $name . '="' . htmlspecialchars($val, ENT_QUOTES | ENT_HTML5) . '"';
870
            }
871
        }
872
873
        return $str;
874
    }
875
876
    /**
877
     * Return a themeable file resource path
878
     *
879
     * @param  string $path
880
     * @return string
881
     */
882
    public function resourcePath($path)
883
    {
884
        $path = (string) $path;
885
        if (substr($path, 0, 1) === '/') {
886
            $path = substr($path, 1);
887
        }
888
889
        if (file_exists(XOOPS_ROOT_PATH . "/{$this->themesPath}/{$this->folderName}/{$path}")) {
890
            return "{$this->themesPath}/{$this->folderName}/{$path}";
891
        }
892
893
        if (file_exists(XOOPS_ROOT_PATH . "/themes/{$this->folderName}/{$path}")) {
894
            return "themes/{$this->folderName}/{$path}";
895
        }
896
897
        return $path;
898
    }
899
}
900