Completed
Push — master ( 240d70...17e2af )
by Patrick
08:45
created

class.FlipPage.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * A WebPage class specific to this framework
4
 *
5
 * This file describes an abstraction for creating a webpage with JQuery, Bootstrap,
6
 * and other framework specific abilities
7
 *
8
 * PHP version 5 and 7
9
 *
10
 * @author Patrick Boyd / [email protected]
11
 * @copyright Copyright (c) 2015, Austin Artistic Reconstruction
12
 * @license http://www.apache.org/licenses/ Apache 2.0 License
13
 */
14
15
/**
16
 * We need the parent class
17
 */
18
require_once('class.WebPage.php');
19
20
define('JS_JQUERY', 0);
21
define('JS_JQUERY_UI', 1);
22
define('JS_BOOTSTRAP', 2);
23
define('JQUERY_VALIDATE', 3);
24
define('JQUERY_TOUCH', 4);
25
//define('JS_TINYNAV', 5);
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
26
define('JS_BOOTSTRAP_FH', 6);
27
define('JS_BOOTSTRAP_SW', 7);
28
define('JS_DATATABLE', 8);
29
define('JS_CHART', 9);
30
define('JS_METISMENU', 10);
31
define('JS_BOOTBOX', 11);
32
define('JS_DATATABLE_ODATA', 12);
33
define('JS_CRYPTO_MD5_JS', 13);
34
define('JS_JCROP', 14);
35
define('JS_TYPEAHEAD', 15);
36
define('JS_CHEET', 16);
37
define('JS_FLIPSIDE', 20);
38
define('JS_LOGIN', 21);
39
40
define('CSS_JQUERY_UI', 0);
41
define('CSS_BOOTSTRAP', 1);
42
define('CSS_BOOTSTRAP_FH', 2);
43
define('CSS_BOOTSTRAP_SW', 3);
44
define('CSS_DATATABLE', 4);
45
define('CSS_JCROP', 5);
46
define('CSS_FONTAWESOME', 6);
47
48
global $jsArray;
49
$jsArray = array(
50
        JS_JQUERY => array(
51
            'no' => array(
52
                'no'  => '/js/common/jquery.js',
53
                'min' => '/js/common/jquery.min.js'
54
            ),
55
            'cdn' => array(
56
                'no'  => '//ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.js',
57
                'min' => '//ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'
58
            )
59
        ),
60
        JS_JQUERY_UI => array(
61
            'no' => array(
62
                'no'  => '/js/common/jquery-ui.js',
63
                'min' => '/js/common/jquery-ui.min.js'
64
            ),
65
            'cdn' => array(
66
                'no'  => '//ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js',
67
                'min' => '//ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js'
68
            )
69
        ),
70
        JS_BOOTSTRAP => array(
71
            'no' => array(
72
                'no'  => '/js/common/bootstrap.js',
73
                'min' => '/js/common/bootstrap.min.js'
74
            ),
75
            'cdn' => array(
76
                'no'  => '//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js',
77
                'min' => '//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js'
78
            )
79
        ),
80
        JQUERY_VALIDATE => array(
81
            'no' => array(
82
                'no'  => '/js/common/jquery.validate.js',
83
                'min' => '/js/common/jquery.validate.min.js'
84
            ),
85
            'cdn' => array(
86
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.16.0/jquery.validate.js',
87
                'min' => '//cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.16.0/jquery.validate.min.js'
88
            )
89
        ),
90
        JQUERY_TOUCH => array(
91
            'no' => array(
92
                'no'  => '/js/common/jquery.ui.touch-punch.min.js',
93
                'min' => '/js/common/jquery.ui.touch-punch.min.js'
94
            ),
95
            'cdn' => array(
96
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js',
97
                'min' => '//cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js'
98
            )
99
        ),
100
        JS_BOOTSTRAP_FH => array(
101
            'no' => array(
102
                'no'  => '/js/common/bootstrap-formhelpers.js',
103
                'min' => '/js/common/bootstrap-formhelpers.min.js'
104
            ),
105
            'cdn' => array(
106
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-formhelpers/2.3.0/js/bootstrap-formhelpers.js',
107
                'min' => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-formhelpers/2.3.0/js/bootstrap-formhelpers.min.js'
108
            )
109
        ),
110
        JS_BOOTSTRAP_SW => array(
111
            'no' => array(
112
                'no'  => '/js/common/bootstrap-switch.js',
113
                'min' => '/js/common/bootstrap-switch.min.js'
114
            ),
115
            'cdn' => array(
116
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/js/bootstrap-switch.js',
117
                'min' => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/js/bootstrap-switch.min.js'
118
            )
119
        ),
120
        JS_DATATABLE => array(
121
            'no' => array(
122
                'no'  => '/js/common/jquery.dataTables.js',
123
                'min' => '/js/common/jquery.dataTables.min.js'
124
            ),
125
            'cdn' => array(
126
                'no'  => '//cdn.datatables.net/1.10.15/js/jquery.dataTables.js',
127
                'min' => '//cdn.datatables.net/1.10.15/js/jquery.dataTables.min.js'
128
            )
129
        ),
130
        JS_CHART => array(
131
            'no' => array(
132
                'no'  => '/js/common/Chart.js',
133
                'min' => '/js/common/Chart.min.js'
134
            ),
135
            'cdn' => array(
136
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.js',
137
                'min' => '//cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js'
138
            )
139
        ),
140
        JS_METISMENU => array(
141
            'no' => array(
142
                'no'  => '/js/common/metisMenu.js',
143
                'min' => '/js/common/metisMenu.min.js'
144
            ),
145
            'cdn' => array(
146
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/metisMenu/2.7.0/metisMenu.js',
147
                'min' => '//cdnjs.cloudflare.com/ajax/libs/metisMenu/2.7.0/metisMenu.min.js'
148
            )
149
        ),
150
        JS_BOOTBOX => array(
151
            'no' => array(
152
                'no'  => '/js/common/bootbox.js',
153
                'min' => '/js/common/bootbox.min.js'
154
            ),
155
            'cdn' => array(
156
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.js',
157
                'min' => '//cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js'
158
            )
159
        ),
160
        JS_DATATABLE_ODATA => array(
161
            'no' => array(
162
                'no'  => '/js/common/jquery.dataTables.odata.js',
163
                'min' => '/js/common/jquery.dataTables.odata.js',
164
            ),
165
            'cdn' => array(
166
                'no'  => '/js/common/jquery.dataTables.odata.js',
167
                'min' => '/js/common/jquery.dataTables.odata.js',
168
            )
169
        ),
170
        JS_CRYPTO_MD5_JS => array(
171
            'no' => array(
172
                'no'  => '/js/common/md5.js',
173
                'min' => '/js/common/md5.js',
174
            ),
175
            'cdn' => array(
176
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/md5.js',
177
                'min' => '//cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/md5.min.js',
178
            )
179
        ),
180
        JS_JCROP => array(
181
            'no' => array(
182
                'no'  => '/js/common/jquery.Jcrop.js',
183
                'min' => '/js/common/jquery.Jcrop.min.js'
184
            ),
185
            'cdn' => array(
186
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/2.0.4/js/jquery.Jcrop.js',
187
                'min' => '//cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/2.0.4/js/jquery.Jcrop.min.js'
188
            )
189
        ),
190
        JS_TYPEAHEAD => array(
191
            'no' => array(
192
                'no'  => '/js/common/typeahead.bundle.js',
193
                'min' => '/js/common/typeahead.bundle.min.js'
194
            ),
195
            'cdn' => array(
196
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.bundle.js',
197
                'min' => '//cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.bundle.min.js'
198
            )
199
        ),
200
        JS_CHEET => array(
201
            'no' => array(
202
                'no'  => '/js/common/cheet.js',
203
                'min' => '/js/common/cheer.min.js'
204
            ),
205
            'cdn' => array(
206
                'no'  => '//cdn.rawgit.com/namuol/cheet.js/master/cheet.min.js',
207
                'min' => '//cdn.rawgit.com/namuol/cheet.js/master/cheet.min.js'
208
            )
209
        ),
210
        JS_FLIPSIDE => array(
211
            'no' => array(
212
                'no'  => '/js/common/flipside.js',
213
                'min' => '/js/common/flipside.min.js'
214
            ),
215
            'cdn' => array(
216
                'no'  => '/js/common/flipside.js',
217
                'min' => '/js/common/flipside.min.js'
218
            )
219
        ),
220
        JS_LOGIN => array(
221
            'no' => array(
222
                'no'  => '/js/common/login.js',
223
                'min' => '/js/common/login.min.js'
224
            ),
225
            'cdn' => array(
226
                'no'  => '/js/common/login.js',
227
                'min' => '/js/common/login.min.js'
228
            )
229
        )
230
);
231
232
global $cssArray;
233
$cssArray = array(
234
    CSS_JQUERY_UI => array(
235
        'no' => array(
236
                'no'  => '/css/common/jquery-ui.css',
237
                'min' => '/css/common/jquery-ui.min.css'
238
            ),
239
            'cdn' => array(
240
                'no'  => '//ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css',
241
                'min' => '//ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.min.css'
242
            )
243
    ),
244
    CSS_BOOTSTRAP => array(
245
            'no' => array(
246
                'no'  => '/css/common/bootstrap.css',
247
                'min' => '/css/common/bootstrap.min.css'
248
            ),
249
            'cdn' => array(
250
                'no'  => '//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.css',
251
                'min' => '//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css'
252
            )
253
    ),
254
    CSS_BOOTSTRAP_FH => array(
255
        'no' => array(
256
                'no'  => '/css/common/bootstrap-formhelpers.css',
257
                'min' => '/css/common/bootstrap-formhelpers.min.css'
258
            ),
259
            'cdn' => array(
260
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-formhelpers/2.3.0/css/bootstrap-formhelpers.css',
261
                'min' => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-formhelpers/2.3.0/css/bootstrap-formhelpers.min.css'
262
            )
263
    ),
264
    CSS_BOOTSTRAP_SW => array(
265
            'no' => array(
266
                'no'  => '/css/common/bootstrap-switch.css',
267
                'min' => '/css/common/bootstrap-switch.min.css'
268
            ),
269
            'cdn' => array(
270
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/css/bootstrap3/bootstrap-switch.css',
271
                'min' => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.4/css/bootstrap3/bootstrap-switch.min.css'
272
            )
273
    ),
274
    CSS_DATATABLE => array(
275
        'no' => array(
276
                'no'  => '/css/common/jquery.dataTables.css',
277
                'min' => '/css/common/jquery.dataTables.min.css'
278
            ),
279
            'cdn' => array(
280
                'no'  => '//cdn.datatables.net/1.10.15/css/jquery.dataTables.css',
281
                'min' => '//cdn.datatables.net/1.10.15/css/jquery.dataTables.min.css'
282
            )
283
    ),
284
    CSS_JCROP => array(
285
        'no'  => array(
286
            'no'  => '/css/common/jquery.Jcrop.css',
287
            'min' => '/css/common/jquery.Jcrop.min.css'
288
        ),
289
        'cdn' => array(
290
            'no'  => '//cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/2.0.4/css/jquery.Jcrop.css',
291
            'min' => '//cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/2.0.4/css/jquery.Jcrop.min.css'
292
        )
293
    ),
294
    CSS_FONTAWESOME => array(
295
        'no'  => array(
296
            'no'  => '/css/common/font-awesome.css',
297
            'min' => '/css/common/font-awesome.min.css'
298
        ),
299
        'cdn' => array(
300
            'no'  => '//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.css',
301
            'min' => '//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css'
302
        )
303
    )
304
);
305
306
/**
307
 * A framework specific webpage abstraction layer
308
 *
309
 * This class abstracts out some basic webpage creation with JQuery, Bootstrap, and other helpers
310
 */
311
class FlipPage extends WebPage
312
{
313
    /** The currently logged in user or null if no user is logged in */
314
    public $user;
315
    /** An array of links to put in the header */
316
    public $links;
317
    /** An array of notifications to draw on the page */
318
    public $notifications;
319
    /** Should we draw the header? */
320
    public $header;
321
    /** The login page URL */
322
    public $loginUrl;
323
    /** The logout page URL */
324
    public $logoutUrl;
325
    /** Should we use minified JS/CSS? */
326
    protected $minified = null;
327
    /** Should we use local JS/CSS or Content Delivery Networks? */
328
    protected $cdn = null;
329
    /** Draw the analytics scripts */
330
    protected $analytics = true;
331
    /** An instance of the Settings class */
332
    protected $settings;
333
334
    public $wwwUrl;
335
    public $wikiUrl;
336
    public $profilesUrl;
337
    public $secureUrl;
338
339
    /**
340
     * Create a webpage with JQuery, Bootstrap, etc
341
     *
342
     * @param string $title The webpage title
343
     * @param boolean $header Draw the header bar?
344
     *
345
     * @SuppressWarnings("StaticAccess")
346
     */
347
    public function __construct($title, $header = true)
348
    {
349
        $this->settings = \Settings::getInstance();
350
        parent::__construct($title);
351
        $this->setupVars();
352
        $this->addWellKnownJS(JS_JQUERY, false);
353
        $this->addWellKnownJS(JS_FLIPSIDE, false);
354
        $this->addBootstrap();
355
        $this->header = $header;
356
        $this->links = array();
357
        $this->notifications = array();
358
359
        $this->wwwUrl = $this->settings->getGlobalSetting('www_url', 'https://www.burningflipside.com');
360
361
        $this->wikiUrl = $this->settings->getGlobalSetting('wiki_url', 'https://wiki.burningflipside.com');
362
363
        $this->aboutUrl = $this->settings->getGlobalSetting('about_url', $this->wwwUrl.'/about');
364
        $this->aboutMenu = $this->settings->getGlobalSetting('about_menu', array(
365
            'Burning Flipside' => $this->wwwUrl.'/about/event',
366
            'AAR, LLC' => $this->wwwUrl.'/organization/aar',
367
            'Privacy Policy' => $this->wwwUrl.'/about/privacy'
368
        ));
369
370
        $this->profilesUrl = $this->settings->getGlobalSetting('profiles_url', 'https://profiles.burningflipside.com/');
371
        $this->loginUrl = $this->settings->getGlobalSetting('login_url', $this->profilesUrl.'/login.php');
372
        $this->logoutUrl = $this->settings->getGlobalSetting('logout_url', $this->profilesUrl.'/logout.php');
373
        $this->registerUrl = $this->settings->getGlobalSetting('register_url', $this->profilesUrl.'/register.php');
374
        $this->resetUrl = $this->settings->getGlobalSetting('reset_url', $this->profilesUrl.'/reset.php');
375
376
        $this->secureUrl = $this->settings->getGlobalSetting('secure_url', 'https://secure.burningflipside.com/');
377
378
        $this->user = FlipSession::getUser();
379
        $this->addAllLinks();
380
    }
381
382
    /**
383
     * Get the external site links for this page
384
     *
385
     */
386
    protected function getSites()
387
    {
388
        return $this->settings->getSiteLinks();
389
    }
390
391
    /**
392
     * Add the links to be used in the header
393
     *
394
     * @SuppressWarnings("Superglobals")
395
     *
396
     * @todo Consider pulling the about menu from the settings file or a DB
397
     */
398
    protected function addAllLinks()
399
    {
400
        if($this->user === false || $this->user === null)
401
        {
402
            if(isset($_SERVER['REQUEST_URI']) && strstr($_SERVER['REQUEST_URI'], 'logout.php') === false)
403
            {
404
                $this->addLink('Login', $this->loginUrl);
405
            }
406
        }
407
        else
408
        {
409
            $this->add_links();
410
            $this->addLink('Logout', $this->logoutUrl);
411
        }
412
        if($this->aboutUrl !== false)
413
        {
414
            if(!empty($this->aboutMenu))
415
            {
416
                $this->addLink('About', $this->aboutUrl, $this->aboutMenu);
417
            }
418
            else
419
            {
420
                $this->addLink('About', $this->aboutUrl);
421
            }
422
        }
423
    }
424
425
    /**
426
     * Setup minified and cdn class varibles from defaults or the settings file
427
     */
428
    private function setupVars()
429
    {
430
        if($this->minified !== null && $this->cdn !== null)
431
        {
432
            return;
433
        }
434
        $this->minified = 'min';
435
        $this->cdn      = 'cdn';
436
        if($this->settings->getGlobalSetting('use_minified', true) == false)
437
        {
438
            $this->minified = 'no';
439
        }
440
        if($this->settings->getGlobalSetting('use_cdn', true) == false)
441
        {
442
            $this->cdn = 'no';
443
        }
444
    }
445
446
    /**
447
     * Add a JavaScript file from its src URI
448
     *
449
     * @param string $uri The webpath to the JavaScript file
450
     * @param boolean $async Can the JavaScript be loaded asynchronously?
451
     */
452
    public function addJSByURI($uri, $async = true)
453
    {
454
        $attributes = array('src'=>$uri, 'type'=>'text/javascript');
455
        if($async === true)
456
        {
457
            $attributes['async'] = true;
458
        }
459
        $jsTag = $this->createOpenTag('script', $attributes);
460
        $closeTag = $this->createCloseTag('script');
461
        $this->addHeadTag($jsTag);
462
        $this->addHeadTag($closeTag);
463
    }
464
465
    /**
466
     * Add a Cascading Style Sheet file from its src URI
467
     *
468
     * @param string $uri The webpath to the Cascading Style Sheet file
469
     * @param boolean $async Can the CSS be loaded asynchronously?
470
     */
471
    public function addCSSByURI($uri, $async = false)
472
    {
473
        $attributes = array('rel'=>'stylesheet', 'href'=>$uri, 'type'=>'text/css');
474
        if($async === true && $this->importSupport === true)
475
        {
476
            $attributes['rel'] = 'import';
477
        }
478
        $cssTag = $this->createOpenTag('link', $attributes, true);
479
        $this->addHeadTag($cssTag);
480
    }
481
482
    /**
483
     * Add a JavaScript file from a set of files known to the framework
484
     *
485
     * @param string $jsFileID the ID of the JS file
486
     * @param boolean $async Can the JS file be loaded asynchronously?
487
     */
488
    public function addWellKnownJS($jsFileID, $async = false)
489
    {
490
        global $jsArray;
491
        $this->setupVars();
492
        $src = $jsArray[$jsFileID][$this->cdn][$this->minified];
493
        $this->addJSByURI($src, $async);
494
    }
495
496
    /**
497
     * Add a CSS file from a set of files known to the framework
498
     *
499
     * @param string $cssFileID the ID of the CSS file
500
     * @param boolean $async Can the CSS file be loaded asynchronously?
501
     */
502
    public function addWellKnownCSS($cssFileID, $async = false)
503
    {
504
        global $cssArray;
505
        $this->setupVars();
506
        $src = $cssArray[$cssFileID][$this->cdn][$this->minified];
507
        $this->addCSSByURI($src, $async);
508
    }
509
510
    /**
511
     * Add files needed by the Bootstrap framework
512
     */
513
    private function addBootstrap()
514
    {
515
        $this->addWellKnownJS(JS_BOOTSTRAP);
516
        $this->addWellKnownCSS(CSS_BOOTSTRAP);
517
        $this->addWellKnownCSS(CSS_FONTAWESOME);
518
519
    }
520
521
    protected function getSiteLinksForHeader()
522
    {
523
        $sites = $this->getSites();
524
        $names = array_keys($sites);
525
        $ret = '';
526
        foreach($names as $name)
527
        {
528
            $ret .= '<li>'.$this->createLink($name, $sites[$name]).'</li>';
529
        }
530
        return $ret;
531
    }
532
533
    /**
534
     * Get the link for the HREF
535
     *
536
     * @return string The HREF for the dropdown
537
     */
538
    protected function getHrefForDropdown(&$link)
539
    {
540
        if(isset($link['_']))
541
        {
542
            $ret = $link['_'];
543
            unset($link['_']);
544
            return $ret;
545
        }
546
        return '#';
547
    }
548
549
    protected function getDropdown($link, $name)
550
    {
551
        $ret = '<li class="dropdown">';
552
        $href = $this->getHrefForDropdown($link);
553
        $ret .= '<a href="'.$href.'" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">'.$name.' <span class="caret"></span></a>';
554
        $ret .= '<ul class="dropdown-menu">';
555
        $subNames = array_keys($link);
556
        foreach($subNames as $subName)
557
        {
558
            $ret .= $this->getLinkByName($subName, $link);
559
        }
560
        $ret .= '</ul></li>';
561
        return $ret;
562
    }
563
564
    protected function getLinkByName($name, $links)
565
    {
566
        if(is_array($links[$name]))
567
        {
568
            return $this->getDropdown($links[$name], $name);
569
        }
570
        if($links[$name] === false)
571
        {
572
            return '<li>'.$name.'</li>';
573
        }
574
        return '<li>'.$this->createLink($name, $links[$name]).'</li>';
575
    }
576
577
    protected function getLinksMenus()
578
    {
579
        $names = array_keys($this->links);
580
        $ret = '';
581
        foreach($names as $name)
582
        {
583
            $ret .= $this->getLinkByName($name, $this->links);
584
        }
585
        return $ret;
586
    }
587
588
    /**
589
     * Draw the header for the page
590
     */
591
    protected function addHeader()
592
    {
593
        $sites = $this->getSiteLinksForHeader();
594
        $links = $this->getLinksMenus();
595
        $header = '<nav class="navbar navbar-default navbar-fixed-top">
596
                      <div class="container-fluid">
597
                          <!-- Brand and toggle get grouped for better mobile display -->
598
                          <div class="navbar-header">
599
                          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse" aria-expanded="false">
600
                              <span class="sr-only">Toggle navigation</span>
601
                              <span class="icon-bar"></span>
602
                              <span class="icon-bar"></span>
603
                              <span class="icon-bar"></span>
604
                          </button>
605
                          <a class="navbar-brand" href="#">
606
                              <picture>
607
                                  <source srcset="/img/common/logo.svg" style="width: 30px; height:30px"/>
608
                                  <img alt="Burning Flipside" src="/img/common/logo.png" style="width: 30px; height:30px"/>
609
                              </picture>
610
                          </a>
611
                          </div>
612
                          <!-- Collect the nav links, forms, and other content for toggling -->
613
                          <div class="collapse navbar-collapse" id="navbar-collapse">
614
                              <ul id="site_nav" class="nav navbar-nav">
615
                              '.$sites.'
616
                              </ul>
617
                              <ul class="nav navbar-nav navbar-right">
618
                              '.$links.'
619
                              </ul>
620
                          </div>
621
                      </div>
622
                  </nav>';
623
        $this->body = $header.$this->body;
624
        $this->body_tags .= 'style="padding-top: 60px;"';
625
    }
626
627
    /** Notification that is green for success */
628
    const NOTIFICATION_SUCCESS = 'alert-success';
629
    /** Notification that is blue for infomrational messages */
630
    const NOTIFICATION_INFO    = 'alert-info';
631
    /** Notification that is yellow for warning */
632
    const NOTIFICATION_WARNING = 'alert-warning';
633
    /** Notification that is red for error */
634
    const NOTIFICATION_FAILED  = 'alert-danger';
635
636
    /**
637
     * Add a notification to the page
638
     *
639
     * @param string $message The message to show in the notifcation
640
     * @param string $severity The severity of the notifcation
641
     * @param boolean $dismissible Can the user dismiss the notificaton?
642
     */
643
    public function addNotification($message, $severity = self::NOTIFICATION_INFO, $dismissible = true)
644
    {
645
        array_push($this->notifications, array('msg'=>$message, 'sev'=>$severity, 'dismissible'=>$dismissible));
646
    }
647
648
    /**
649
     * Draw all notifications to the page
650
     */
651
    private function renderNotifications()
652
    {
653
        $count = count($this->notifications);
654
        if($count === 0)
655
        {
656
            return;
657
        }
658
        for($i = 0; $i < $count; $i++)
659
        {
660
            $class = 'alert '.$this->notifications[$i]['sev'];
661
            $button = '';
662
            if($this->notifications[$i]['dismissible'])
663
            {
664
                $class .= ' alert-dismissible';
665
                $button = '<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>';
666
            }
667
            $prefix = '';
668
            switch($this->notifications[$i]['sev'])
669
            {
670
                case self::NOTIFICATION_INFO:
671
                    $prefix = '<strong>Notice:</strong> ';
672
                    break;
673
                case self::NOTIFICATION_WARNING:
674
                    $prefix = '<strong>Warning!</strong> ';
675
                    break;
676
                case self::NOTIFICATION_FAILED:
677
                    $prefix = '<strong>Warning!</strong> ';
678
                    break;
679
            }
680
            $style = '';
681
            if(($i + 1) < count($this->notifications))
682
            {
683
                //Not the last notification, remove the end margin
684
                $style = 'style="margin: 0px;"';
685
            }
686
            $this->body = '
687
                <div class="'.$class.'" role="alert" '.$style.'>
688
                    '.$button.$prefix.$this->notifications[$i]['msg'].'
689
                </div>
690
            '.$this->body;
691
        }
692
    }
693
694
    /**
695
     * Add the no script block
696
     */
697
    private function addNoScript()
698
    {
699
        $this->body = '<noscript>
700
                <div class="alert alert-danger alert-dismissible" role="alert">
701
                    <button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
702
                    <strong>Error!</strong> This site makes extensive use of JavaScript. Please enable JavaScript or this site will not function.
703
                </div>
704
            </noscript>'.$this->body;
705
    }
706
707
    /**
708
     * Add the analytics script block
709
     */
710
    private function addAnalyticsBlock()
711
    {
712
        if($this->analytics === false)
713
        {
714
            return;
715
        }
716
        $this->body = $this->body.'<script>
717
  (function(i,s,o,g,r,a,m){i[\'GoogleAnalyticsObject\']=r;i[r]=i[r]||function(){
718
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
719
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
720
  })(window,document,\'script\',\'//www.google-analytics.com/analytics.js\',\'ga\');
721
722
  ga(\'create\', \'UA-64901342-1\', \'auto\');
723
  ga(\'send\', \'pageview\');
724
725
</script>';
726
    }
727
728
    /**
729
     * Add some global js vars
730
     */
731
    private function addJSGlobals()
732
    {
733
      $this->body = $this->body.'<script>
734
var profilesUrl = \''.$this->profilesUrl.'\'
735
var loginUrl = \''.$this->loginUrl.'\'
736
var logoutUrl = \''.$this->logoutUrl.'\'
737
</script>';
738
    }
739
740
    /**
741
     * Draw the page
742
     *
743
     * @param boolean $header Draw the header
744
     */
745
    public function printPage($header = true)
746
    {
747
        $this->renderNotifications();
748
        $this->addNoScript();
749
        $this->addAnalyticsBlock();
750
        $this->addJSGlobals();
751
        if($this->header || $header)
752
        {
753
            $this->addHeader();
754
        }
755
        parent::printPage();
756
    }
757
758
    /**
759
     * Add a link to the header
760
     *
761
     * @param string $name The name of the link
762
     * @param boolean|string $url The URL to link to
763
     * @param boolean|array $submenu Any submenu items for the dropdown
764
     */
765
    public function addLink($name, $url = false, $submenu = false)
766
    {
767
        if(is_array($submenu))
768
        {
769
            $submenu['_'] = $url;
770
            $this->links[$name] = $submenu;
771
            return;
772
        }
773
        $this->links[$name] = $url;
774
    }
775
776
    /**
777
     * Add the login form to the page
778
     *
779
     * @SuppressWarnings("StaticAccess")
780
     */
781
    public function add_login_form()
782
    {
783
        $auth = \AuthProvider::getInstance();
784
        $authLinks = $auth->getSupplementaryLinks();
785
        $authLinksStr = '';
786
        $count = count($authLinks);
787
        for($i = 0; $i < $count; $i++)
788
        {
789
            $authLinksStr .= $authLinks[$i];
790
        }
791
        if($count > 0)
792
        {
793
            $authLinksStr = 'Sign in with '.$authLinksStr;
794
        }
795
        $this->body .= '<div class="modal fade" role="dialog" id="login-dialog" title="Login" aria-hidden="true">
796
                            <div class="modal-dialog">
797
                                <div class="modal-content">
798
                                    <div class="modal-header">
799
                                        <button type="button" class="close" data-dismiss="modal">
800
                                            <span aria-hidden="true">&times;</span>
801
                                            <span class="sr-only">Close</span>
802
                                        </button>
803
                                        <h4 class="modal-title">Login</h4>
804
                                    </div>
805
                                    <div class="modal-body">
806
                                        <form id="login_dialog_form" role="form">
807
                                            <input class="form-control" type="text" name="username" placeholder="Username or Email" required autofocus/>
808
                                            <input class="form-control" type="password" name="password" placeholder="Password" required/>
809
                                            <input type="hidden" name="return" value="'.$this->currentUrl().'"/>
810
                                            <button class="btn btn-lg btn-primary btn-block" type="submit">Login</button>
811
                                        </form>
812
                                        '.$authLinksStr.'
813
                                    </div>
814
                                </div>
815
                            </div>
816
                        </div>';
817
    }
818
819
    /**
820
     * Add additional links
821
     */
822
    public function add_links()
823
    {
824
    }
825
}
826
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
827