xos_opal_AdminThemeFactory   A
last analyzed

Complexity

Total Complexity 1

Size/Duplication

Total Lines 26
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 1
eloc 17
dl 0
loc 26
rs 10
c 0
b 0
f 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A createInstance() 0 18 1
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 (($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 mambax7
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;
0 ignored issues
show
Bug introduced by geekwright
The property currentTheme does not seem to exist on XoopsTpl.
Loading history...
288
        $this->template->assign_by_ref('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),
325
            'xoops_sitename'   => htmlspecialchars($GLOBALS['xoopsConfig']['sitename'], ENT_QUOTES),
326
            'xoops_slogan'     => htmlspecialchars($GLOBALS['xoopsConfig']['slogan'], ENT_QUOTES),
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),
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->is_cached($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
502
        if (!empty($GLOBALS['xoopsOption']['xoops_pagetitle'])) {
503
            $this->template->assign('xoops_pagetitle', $GLOBALS['xoopsOption']['xoops_pagetitle']);
504
        }
505
        $header = empty($GLOBALS['xoopsOption']['xoops_module_header']) ? $this->template->get_template_vars('xoops_module_header') : $GLOBALS['xoopsOption']['xoops_module_header'];
506
507
        //save meta information of cached pages
508
        if ($this->contentCacheLifetime && $this->contentCacheId && !$contentTpl) {
509
            $content['htmlHeadStrings'] = $this->htmlHeadStrings;
510
            $content['metas']           = $this->metas;
511
            $content['xoops_pagetitle'] =& $this->template->get_template_vars('xoops_pagetitle');
512
            $content['header']          = $header;
513
            $cache->write($this->contentCacheId, $content);
514
        }
515
516
        //  @internal : Lame fix to ensure the metas specified in the xoops config page don't appear twice
517
        $old = array(
518
            'robots',
519
            'keywords',
520
            'description',
521
            'rating',
522
            'author',
523
            'copyright');
524
        foreach ($this->metas['meta'] as $name => $value) {
525
            if (in_array($name, $old)) {
526
                $this->template->assign("xoops_meta_$name", htmlspecialchars($value, ENT_QUOTES));
527
                unset($this->metas['meta'][$name]);
528
            }
529
        }
530
531
        // We assume no overlap between $GLOBALS['xoopsOption']['xoops_module_header'] and $this->template->get_template_vars( 'xoops_module_header' ) ?
532
        $this->template->assign('xoops_module_header', $this->renderMetas(null, true) . "\n" . $header);
0 ignored issues
show
Bug introduced by beckmi
Are you sure $header of type array|mixed 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

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

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

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

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

770
    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...
Unused Code introduced by mambax7
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

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