Test Failed
Push — master ( 398493...d4ef72 )
by Michael
11:04
created

xos_opal_Theme::genElementId()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 31 and the first side effect is on line 21.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
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-2016 XOOPS Project (www.xoops.org)
13
 * @license             GNU GPL 2 (http://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
defined('XOOPS_ROOT_PATH') || exit('Restricted access');
22
23
/**
24
 * xos_opal_ThemeFactory
25
 *
26
 * @author     Skalpa Keo
27
 * @package    xos_opal
28
 * @subpackage xos_opal_Theme
29
 * @since      2.3.0
30
 */
31
class xos_opal_ThemeFactory
32
{
33
    public $xoBundleIdentifier = 'xos_opal_ThemeFactory';
34
    /**
35
     * Currently enabled themes (if empty, all the themes in themes/ are allowed)
36
     *
37
     * @var array
38
     */
39
    public $allowedThemes = array();
40
    /**
41
     * Default theme to instanciate if none specified
42
     *
43
     * @var string
44
     */
45
    public $defaultTheme = 'default';
46
    /**
47
     * If users are allowed to choose a custom theme
48
     *
49
     * @var bool
50
     */
51
    public $allowUserSelection = true;
52
53
    /**
54
     * Instanciate the specified theme
55
     * @param  array $options
56
     * @param  array $initArgs
57
     * @return null|xos_opal_Theme
58
     */
59
    public function createInstance($options = array(), $initArgs = array())
60
    {
61
        // Grab the theme folder from request vars if present
62
        if (empty($options['folderName'])) {
63
            if (($req = @$_REQUEST['xoops_theme_select']) && $this->isThemeAllowed($req)) {
64
                $options['folderName'] = $req;
65
                if (isset($_SESSION) && $this->allowUserSelection) {
66
                    $_SESSION[$this->xoBundleIdentifier]['defaultTheme'] = $req;
67
                }
68
            } elseif (isset($_SESSION[$this->xoBundleIdentifier]['defaultTheme'])) {
69
                $options['folderName'] = $_SESSION[$this->xoBundleIdentifier]['defaultTheme'];
70
            } elseif (empty($options['folderName']) || !$this->isThemeAllowed($options['folderName'])) {
71
                $options['folderName'] = $this->defaultTheme;
72
            }
73
            $GLOBALS['xoopsConfig']['theme_set'] = $options['folderName'];
74
        }
75
        $options['path'] = XOOPS_THEME_PATH . '/' . $options['folderName'];
76
        $inst            = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $inst is dead and can be removed.
Loading history...
77
        $inst            = new xos_opal_Theme();
78
        foreach ($options as $k => $v) {
79
            $inst->$k = $v;
80
        }
81
        $inst->xoInit();
82
83
        return $inst;
84
    }
85
86
    /**
87
     * Checks if the specified theme is enabled or not
88
     *
89
     * @param  string $name
90
     * @return bool
91
     */
92
    public function isThemeAllowed($name)
93
    {
94
        return (empty($this->allowedThemes) || in_array($name, $this->allowedThemes));
95
    }
96
}
97
98
/**
99
 * xos_opal_AdminThemeFactory
100
 *
101
 * @author     Andricq Nicolas (AKA MusS)
102
 * @author     trabis
103
 * @package    xos_opal
104
 * @subpackage xos_opal_Theme
105
 * @since      2.4.0
106
 */
107
class xos_opal_AdminThemeFactory extends xos_opal_ThemeFactory
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
108
{
109
    /**
110
     * @param array $options
111
     * @param array $initArgs
112
     *
113
     * @return null|xos_opal_Theme
114
     */
115
    public function &createInstance($options = array(), $initArgs = array())
116
    {
117
        $options['plugins']      = array();
118
        $options['renderBanner'] = false;
119
        $inst                    = parent::createInstance($options, $initArgs);
120
        $inst->path              = XOOPS_ADMINTHEME_PATH . '/' . $inst->folderName;
121
        $inst->url               = XOOPS_ADMINTHEME_URL . '/' . $inst->folderName;
122
        $inst->template->assign(array(
123
                                    'theme_path'  => $inst->path,
124
                                    'theme_tpl'   => $inst->path . '/xotpl',
125
                                    'theme_url'   => $inst->url,
126
                                    'theme_img'   => $inst->url . '/img',
127
                                    'theme_icons' => $inst->url . '/icons',
128
                                    'theme_css'   => $inst->url . '/css',
129
                                    'theme_js'    => $inst->url . '/js',
130
                                    'theme_lang'  => $inst->url . '/language'));
131
132
        return $inst;
133
    }
134
}
135
136
/**
137
 * Class xos_opal_Theme
138
 */
139
class xos_opal_Theme
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
140
{
141
    /**
142
     * Should we render banner? Not for redirect pages or admin side
143
     *
144
     * @var bool
145
     */
146
    public $renderBanner = true;
147
    /**
148
     * The name of this theme
149
     *
150
     * @var string
151
     */
152
    public $folderName = '';
153
    /**
154
     * Physical path of this theme folder
155
     *
156
     * @var string
157
     */
158
    public $path = '';
159
    public $url  = '';
160
161
    /**
162
     * Whether or not the theme engine should include the output generated by php
163
     *
164
     * @var string
165
     */
166
    public $bufferOutput = true;
167
    /**
168
     * Canvas-level template to use
169
     *
170
     * @var string
171
     */
172
    public $canvasTemplate = 'theme.tpl';
173
174
    /**
175
     * Theme folder path
176
     *
177
     * @var string
178
     */
179
    public $themesPath = 'themes';
180
181
    /**
182
     * Content-level template to use
183
     *
184
     * @var string
185
     */
186
    public $contentTemplate = '';
187
188
    public $contentCacheLifetime = 0;
189
    public $contentCacheId;
190
191
    /**
192
     * Text content to display right after the contentTemplate output
193
     *
194
     * @var string
195
     */
196
    public $content = '';
197
    /**
198
     * Page construction plug-ins to use
199
     *
200
     * @var array
201
     * @access public
202
     */
203
    public $plugins     = array(
204
        'xos_logos_PageBuilder');
205
    public $renderCount = 0;
206
    /**
207
     * Pointer to the theme template engine
208
     *
209
     * @var XoopsTpl
210
     */
211
    public $template = false;
212
213
    /**
214
     * Array containing the document meta-information
215
     *
216
     * @var array
217
     */
218
    public $metas = array(
219
        //'http' => array(
220
        //    'Content-Script-Type' => 'text/javascript' ,
221
        //    'Content-Style-Type' => 'text/css') ,
222
        'meta'   => array(),
223
        'link'   => array(),
224
        'script' => array());
225
226
    /**
227
     * Array of strings to be inserted in the head tag of HTML documents
228
     *
229
     * @var array
230
     */
231
    public $htmlHeadStrings = array();
232
    /**
233
     * Custom variables that will always be assigned to the template
234
     *
235
     * @var array
236
     */
237
    public $templateVars = array();
238
239
    /**
240
     * User extra information for cache id, like language, user groups
241
     *
242
     * @var boolean
243
     */
244
    public $use_extra_cache_id = true;
245
246
    /**
247
     * *#@-
248
     */
249
250
    /**
251
     * *#@+
252
     *
253
     * @tasktype 10 Initialization
254
     */
255
    /**
256
     * Initializes this theme
257
     *
258
     * Upon initialization, the theme creates its template engine and instantiates the
259
     * plug-ins from the specified {@link $plugins} list. If the theme is a 2.0 theme, that does not
260
     * display redirection messages, the HTTP redirections system is disabled to ensure users will
261
     * see the redirection screen.
262
     *
263
     * @param  array $options
264
     * @return bool
265
     */
266
    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

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

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

643
        $this->addMeta('script', $name, /** @scrutinizer ignore-type */ $attributes);
Loading history...
644
    }
645
646
    /**
647
     * Add StyleSheet or CSS code to the document head
648
     *
649
     * @param  string $src        path to .css file
650
     * @param  array  $attributes name => value paired array of attributes such as title
651
     * @param  string $content    CSS code to output between the <style> tags (in case $src is empty)
652
     * @param  string $name       Element Name in array stylesheets are stored in.
653
     * @return void
654
     */
655
    public function addStylesheet($src = '', $attributes = array(), $content = '', $name = '')
656
    {
657
        if (empty($attributes)) {
658
            $attributes = array();
659
        }
660
        if (!empty($src)) {
661
            $src                = $GLOBALS['xoops']->url($this->resourcePath($src));
662
            $attributes['href'] = $src;
663
        }
664
        if (!isset($attributes['type'])) {
665
            $attributes['type'] = 'text/css';
666
        }
667
        if (!empty($content)) {
668
            $attributes['_'] = $content;
669
        }
670
        if (empty($name)) {
671
            $name = md5(serialize($attributes));
672
        }
673
        $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

673
        $this->addMeta('stylesheet', $name, /** @scrutinizer ignore-type */ $attributes);
Loading history...
674
    }
675
676
    /**
677
     * Add a <link> to the header
678
     *
679
     * @param string $rel        Relationship from the current doc to the anchored one
680
     * @param string $href       URI of the anchored document
681
     * @param array  $attributes Additional attributes to add to the <link> element
682
     * @param string $name       Element Name in array links are stored in.
683
     */
684
    public function addLink($rel, $href = '', $attributes = array(), $name = '')
685
    {
686
        if (empty($attributes)) {
687
            $attributes = array();
688
        }
689
        if (!empty($href)) {
690
            $attributes['href'] = $href;
691
        }
692
        $attributes['rel'] = $rel;
693
        if (empty($name)) {
694
            $name = md5(serialize($attributes));
695
        }
696
        $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

696
        $this->addMeta('link', $name, /** @scrutinizer ignore-type */ $attributes);
Loading history...
697
    }
698
699
    /**
700
     * Set a meta http-equiv value
701
     * @param         $name
702
     * @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...
703
     * @return string
704
     */
705
    public function addHttpMeta($name, $value = null)
706
    {
707
        if (isset($value)) {
708
            return $this->addMeta('http', $name, $value);
709
        }
710
        unset($this->metas['http'][$name]);
711
        return null;
712
    }
713
714
    /**
715
     * Change output page meta-information
716
     * @param  string $type
717
     * @param  string $name
718
     * @param  string $value
719
     * @return string
720
     */
721
    public function addMeta($type = 'meta', $name = '', $value = '')
722
    {
723
        if (!isset($this->metas[$type])) {
724
            $this->metas[$type] = array();
725
        }
726
        if (!empty($name)) {
727
            $this->metas[$type][$name] = $value;
728
        } else {
729
            $this->metas[$type][md5(serialize(array($value)))] = $value;
730
        }
731
732
        return $value;
733
    }
734
735
    /**
736
     * xos_opal_Theme::headContent()
737
     *
738
     * @param mixed $params
739
     * @param mixed $content
740
     * @param mixed $smarty
741
     * @param mixed $repeat
742
     *
743
     * @return void
744
     */
745
    public function headContent($params, $content, &$smarty, &$repeat)
0 ignored issues
show
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

745
    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
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

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