Completed
Pull Request — master (#21)
by
unknown
02:32
created

class.FlipPage.php (2 issues)

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);
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/2.1.4/jquery.js',
57
                'min' => '//ajax.googleapis.com/ajax/libs/jquery/2.1.4/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.11.4/jquery-ui.js',
67
                'min' => '//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/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.6/js/bootstrap.js',
77
                'min' => '//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/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'  => '//ajax.aspnetcdn.com/ajax/jquery.validate/1.13.1/jquery.validate.js',
87
                'min' => '//ajax.aspnetcdn.com/ajax/jquery.validate/1.13.1/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_TINYNAV => array(
101
            'no' => array(
102
                'no'  => '/js/common/tinynav.js',
103
                'min' => '/js/common/tinynav.min.js'
104
            ),
105
            'cdn' => array(
106
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/TinyNav.js/1.2.0/tinynav.js',
107
                'min' => '//cdnjs.cloudflare.com/ajax/libs/TinyNav.js/1.2.0/tinynav.min.js'
108
            )
109
        ),
110
        JS_BOOTSTRAP_FH => array(
111
            'no' => array(
112
                'no'  => '/js/common/bootstrap-formhelpers.js',
113
                'min' => '/js/common/bootstrap-formhelpers.min.js'
114
            ),
115
            'cdn' => array(
116
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-formhelpers/2.3.0/js/bootstrap-formhelpers.js',
117
                'min' => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-formhelpers/2.3.0/js/bootstrap-formhelpers.min.js'
118
            )
119
        ),
120
        JS_BOOTSTRAP_SW => array(
121
            'no' => array(
122
                'no'  => '/js/common/bootstrap-switch.js',
123
                'min' => '/js/common/bootstrap-switch.min.js'
124
            ),
125
            'cdn' => array(
126
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/js/bootstrap-switch.js',
127
                'min' => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/js/bootstrap-switch.min.js'
128
            )
129
        ),
130
        JS_DATATABLE => array(
131
            'no' => array(
132
                'no'  => '/js/common/jquery.dataTables.js',
133
                'min' => '/js/common/jquery.dataTables.min.js'
134
            ),
135
            'cdn' => array(
136
                'no'  => '//cdn.datatables.net/1.10.7/js/jquery.dataTables.js',
137
                'min' => '//cdn.datatables.net/1.10.7/js/jquery.dataTables.min.js'
138
            )
139
        ),
140
        JS_CHART => array(
141
            'no' => array(
142
                'no'  => '/js/common/Chart.js',
143
                'min' => '/js/common/Chart.min.js'
144
            ),
145
            'cdn' => array(
146
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.js',
147
                'min' => '//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js'
148
            )
149
        ),
150
        JS_METISMENU => array(
151
            'no' => array(
152
                'no'  => '/js/common/metisMenu.js',
153
                'min' => '/js/common/metisMenu.min.js'
154
            ),
155
            'cdn' => array(
156
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/metisMenu/2.0.2/metisMenu.js',
157
                'min' => '//cdnjs.cloudflare.com/ajax/libs/metisMenu/2.0.2/metisMenu.min.js'
158
            )
159
        ),
160
        JS_BOOTBOX => array(
161
            'no' => array(
162
                'no'  => '/js/common/bootbox.js',
163
                'min' => '/js/common/bootbox.min.js'
164
            ),
165
            'cdn' => array(
166
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.3.0/bootbox.js',
167
                'min' => '//cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.3.0/bootbox.min.js'
168
            )
169
        ),
170
        JS_DATATABLE_ODATA => array(
171
            'no' => array(
172
                'no'  => '/js/common/jquery.dataTables.odata.js',
173
                'min' => '/js/common/jquery.dataTables.odata.js',
174
            ),
175
            'cdn' => array(
176
                'no'  => '/js/common/jquery.dataTables.odata.js',
177
                'min' => '/js/common/jquery.dataTables.odata.js',
178
            )
179
        ),
180
        JS_CRYPTO_MD5_JS => array(
181
            'no' => array(
182
                'no'  => '/js/common/md5.js',
183
                'min' => '/js/common/md5.js',
184
            ),
185
            'cdn' => array(
186
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/md5.js',
187
                'min' => '//cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/md5.js',
188
            )
189
        ),
190
        JS_JCROP => array(
191
            'no' => array(
192
                'no'  => '/js/common/jquery.Jcrop.js',
193
                'min' => '/js/common/jquery.Jcrop.min.js'
194
            ),
195
            'cdn' => array(
196
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/0.9.12/js/jquery.Jcrop.js',
197
                'min' => '//cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/0.9.12/js/jquery.Jcrop.min.js'
198
            )
199
        ),
200
        JS_TYPEAHEAD => array(
201
            'no' => array(
202
                'no'  => '/js/common/typeahead.bundle.js',
203
                'min' => '/js/common/typeahead.bundle.min.js'
204
            ),
205
            'cdn' => array(
206
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.bundle.js',
207
                'min' => '//cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.bundle.min.js'
208
            )
209
        ),
210
        JS_CHEET => array(
211
            'no' => array(
212
                'no'  => '/js/common/cheet.js',
213
                'min' => '/js/common/cheer.min.js'
214
            ),
215
            'cdn' => array(
216
                'no'  => '//cdn.rawgit.com/namuol/cheet.js/master/cheet.min.js',
217
                'min' => '//cdn.rawgit.com/namuol/cheet.js/master/cheet.min.js'
218
            )
219
        ),
220
        JS_FLIPSIDE => array(
221
            'no' => array(
222
                'no'  => '/js/common/flipside.js',
223
                'min' => '/js/common/flipside.min.js'
224
            ),
225
            'cdn' => array(
226
                'no'  => '/js/common/flipside.js',
227
                'min' => '/js/common/flipside.min.js'
228
            )
229
        ),
230
        JS_LOGIN => array(
231
            'no' => array(
232
                'no'  => '/js/common/login.js',
233
                'min' => '/js/common/login.min.js'
234
            ),
235
            'cdn' => array(
236
                'no'  => '/js/common/login.js',
237
                'min' => '/js/common/login.min.js'
238
            )
239
        )
240
);
241
242
global $cssArray;
243
$cssArray = array(
244
    CSS_JQUERY_UI => array(
245
        'no' => array(
246
                'no'  => '/css/common/jquery-ui.css',
247
                'min' => '/css/common/jquery-ui.min.css'
248
            ),
249
            'cdn' => array(
250
                'no'  => '//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css',
251
                'min' => '//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.min.css'
252
            )
253
    ),
254
    CSS_BOOTSTRAP => array(
255
            'no' => array(
256
                'no'  => '/css/common/bootstrap.css',
257
                'min' => '/css/common/bootstrap.min.css'
258
            ),
259
            'cdn' => array(
260
                'no'  => '//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css',
261
                'min' => '//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css'
262
            )
263
    ),
264
    CSS_BOOTSTRAP_FH => array(
265
        'no' => array(
266
                'no'  => '/css/common/bootstrap-formhelpers.css',
267
                'min' => '/css/common/bootstrap-formhelpers.min.css'
268
            ),
269
            'cdn' => array(
270
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-formhelpers/2.3.0/css/bootstrap-formhelpers.css',
271
                'min' => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-formhelpers/2.3.0/css/bootstrap-formhelpers.min.css'
272
            )
273
    ),
274
    CSS_BOOTSTRAP_SW => array(
275
            'no' => array(
276
                'no'  => '/css/common/bootstrap-switch.css',
277
                'min' => '/css/common/bootstrap-switch.min.css'
278
            ),
279
            'cdn' => array(
280
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/css/bootstrap3/bootstrap-switch.css',
281
                'min' => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/css/bootstrap3/bootstrap-switch.min.css'
282
            )
283
    ),
284
    CSS_DATATABLE => array(
285
        'no' => array(
286
                'no'  => '/css/common/jquery.dataTables.css',
287
                'min' => '/css/common/jquery.dataTables.min.css'
288
            ),
289
            'cdn' => array(
290
                'no'  => '//cdn.datatables.net/1.10.7/css/jquery.dataTables.css',
291
                'min' => '//cdn.datatables.net/1.10.7/css/jquery.dataTables.min.css'
292
            )
293
    ),
294
    CSS_JCROP => array(
295
        'no'  => array(
296
            'no'  => '/css/common/jquery.Jcrop.css',
297
            'min' => '/css/common/jquery.Jcrop.min.css'
298
        ),
299
        'cdn' => array(
300
            'no'  => '//cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/0.9.12/css/jquery.Jcrop.css',
301
            'min' => '//cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/0.9.12/css/jquery.Jcrop.min.css'
302
        )
303
    ),
304
    CSS_FONTAWESOME => array(
305
        'no'  => array(
306
            'no'  => '/css/common/font-awesome.css',
307
            'min' => '/css/common/font-awesome.min.css'
308
        ),
309
        'cdn' => array(
310
            'no'  => '//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.css',
311
            'min' => '//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css'
312
        )
313
    )
314
);
315
316
/**
317
 * A framework specific webpage abstraction layer
318
 *
319
 * This class abstracts out some basic webpage creation with JQuery, Bootstrap, and other helpers
320
 */
321
class FlipPage extends WebPage
322
{
323
    /** The currently logged in user or null if no user is logged in */
324
    public $user;
325
    /** An array of links to put in the header */
326
    public $links;
327
    /** An array of notifications to draw on the page */
328
    public $notifications;
329
    /** Should we draw the header? */
330
    public $header;
331
    /** The login page URL */
332
    public $loginUrl;
333
    /** The logout page URL */
334
    public $logoutUrl;
335
    /** Should we use minified JS/CSS? */
336
    protected $minified = null;
337
    /** Should we use local JS/CSS or Content Delivery Networks? */
338
    protected $cdn = null;
339
    /** Draw the analytics scripts */
340
    protected $analytics = true;
341
    /** An instance of the Settings class */
342
    protected $settings;
343
344
    /**
345
     * Create a webpage with JQuery, Bootstrap, etc
346
     *
347
     * @param string $title The webpage title
348
     * @param boolean $header Draw the header bar?
349
     *
350
     * @SuppressWarnings("StaticAccess")
351
     */
352
    public function __construct($title, $header = true)
353
    {
354
        $this->settings = \Settings::getInstance();
355
        parent::__construct($title);
356
        $this->setupVars();
357
        $this->addWellKnownJS(JS_JQUERY, false);
358
        $this->addWellKnownJS(JS_FLIPSIDE, false);
359
        $this->addBootstrap();
360
        $this->header = $header;
361
        $this->links = array();
362
        $this->notifications = array();
363
        $this->aboutUrl = $this->settings->getGlobalSetting('about_url', 'https://www.burningflipside.com/about');
0 ignored issues
show
The property aboutUrl does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
364
        $this->aboutMenu = $this->settings->getGlobalSetting('event_menu', array(
0 ignored issues
show
The property aboutMenu does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
365
            'Burning Flipside'=>'https://www.burningflipside.com/about/event',
366
            'AAR, LLC'=>'https://www.burningflipside.com/organization/aar',
367
            'Privacy Policy'=>'https://www.burningflipside.com/about/privacy'
368
        ));
369
        $this->loginUrl = $this->settings->getGlobalSetting('login_url', 'https://profiles.burningflipside.com/login.php');
370
        $this->logoutUrl = $this->settings->getGlobalSetting('logout_url', 'https://profiles.burningflipside.com/logout.php');
371
        $this->user = FlipSession::getUser();
372
        $this->addAllLinks();
373
    }
374
375
    /**
376
     * Get the external site links for this page
377
     *
378
     */
379
    protected function getSites()
380
    {
381
        return $this->settings->getSiteLinks();
382
    }
383
384
    /**
385
     * Add the links to be used in the header
386
     *
387
     * @SuppressWarnings("Superglobals")
388
     *
389
     * @todo Consider pulling the about menu from the settings file or a DB
390
     */
391
    protected function addAllLinks()
392
    {
393
        if($this->user === false || $this->user === null)
394
        {
395
            if(isset($_SERVER['REQUEST_URI']) && strstr($_SERVER['REQUEST_URI'], 'logout.php') === false)
396
            {
397
                $this->addLink('Login', $this->loginUrl);
398
            }
399
        }
400
        else
401
        {
402
            $this->add_links();
403
            $this->addLink('Logout', $this->logoutUrl);
404
        }
405
        if($this->aboutUrl !== false)
406
        {
407
            if(!empty($this->aboutMenu))
408
            {
409
                $this->addLink('About', $this->aboutUrl, $this->aboutMenu);
410
            }
411
            else
412
            {
413
                $this->addLink('About', $this->aboutUrl);
414
            }
415
        }
416
    }
417
418
    /**
419
     * Setup minified and cdn class varibles from defaults or the settings file
420
     */
421
    private function setupVars()
422
    {
423
        if($this->minified !== null && $this->cdn !== null)
424
        {
425
            return;
426
        }
427
        $this->minified = 'min';
428
        $this->cdn      = 'cdn';
429
        if($this->settings->getGlobalSetting('use_minified', true) == false)
430
        {
431
            $this->minified = 'no';
432
        }
433
        if($this->settings->getGlobalSetting('use_cdn', true) == false)
434
        {
435
            $this->cdn = 'no';
436
        }
437
    }
438
439
    /**
440
     * Add a JavaScript file from its src URI
441
     *
442
     * @param string $uri The webpath to the JavaScript file
443
     * @param boolean $async Can the JavaScript be loaded asynchronously?
444
     */
445
    public function addJSByURI($uri, $async = true)
446
    {
447
        $attributes = array('src'=>$uri, 'type'=>'text/javascript');
448
        if($async === true)
449
        {
450
            $attributes['async'] = true;
451
        }
452
        $jsTag = $this->createOpenTag('script', $attributes);
453
        $closeTag = $this->createCloseTag('script');
454
        $this->addHeadTag($jsTag);
455
        $this->addHeadTag($closeTag);
456
    }
457
458
    /**
459
     * Add a Cascading Style Sheet file from its src URI
460
     *
461
     * @param string $uri The webpath to the Cascading Style Sheet file
462
     * @param boolean $async Can the CSS be loaded asynchronously?
463
     */
464
    public function addCSSByURI($uri, $async = false)
465
    {
466
        $attributes = array('rel'=>'stylesheet', 'href'=>$uri, 'type'=>'text/css');
467
        if($async === true && $this->importSupport === true)
468
        {
469
            $attributes['rel'] = 'import';
470
        }
471
        $cssTag = $this->createOpenTag('link', $attributes, true);
472
        $this->addHeadTag($cssTag);
473
    }
474
475
    /**
476
     * Add a JavaScript file from a set of files known to the framework
477
     *
478
     * @param string $jsFileID the ID of the JS file
479
     * @param boolean $async Can the JS file be loaded asynchronously?
480
     */
481
    public function addWellKnownJS($jsFileID, $async = true)
482
    {
483
        global $jsArray;
484
        $this->setupVars();
485
        $src = $jsArray[$jsFileID][$this->cdn][$this->minified];
486
        $this->addJSByURI($src, $async);
487
    }
488
489
    /**
490
     * Add a CSS file from a set of files known to the framework
491
     *
492
     * @param string $cssFileID the ID of the CSS file
493
     * @param boolean $async Can the CSS file be loaded asynchronously?
494
     */
495
    public function addWellKnownCSS($cssFileID, $async = true)
496
    {
497
        global $cssArray;
498
        $this->setupVars();
499
        $src = $cssArray[$cssFileID][$this->cdn][$this->minified];
500
        $this->addCSSByURI($src, $async);
501
    }
502
503
    /**
504
     * Add files needed by the Bootstrap framework
505
     */
506
    private function addBootstrap()
507
    {
508
        $this->addWellKnownJS(JS_BOOTSTRAP, false);
509
        $this->addWellKnownCSS(CSS_BOOTSTRAP);
510
        $this->addWellKnownCSS(CSS_FONTAWESOME);
511
    }
512
513
    protected function getSiteLinksForHeader()
514
    {
515
        $sites = $this->getSites();
516
        $names = array_keys($sites);
517
        $ret = '';
518
        foreach($names as $name)
519
        {
520
            $ret .= '<li>'.$this->createLink($name, $sites[$name]).'</li>';
521
        }
522
        return $ret;
523
    }
524
525
    /**
526
     * Get the link for the HREF
527
     *
528
     * @return string The HREF for the dropdown
529
     */
530
    protected function getHrefForDropdown(&$link)
531
    {
532
        if(isset($link['_']))
533
        {
534
            $ret = $link['_'];
535
            unset($link['_']);
536
            return $ret;
537
        }
538
        return '#';
539
    }
540
541
    protected function getDropdown($link, $name)
542
    {
543
        $ret = '<li class="dropdown">';
544
        $href = $this->getHrefForDropdown($link);
545
        $ret .= '<a href="'.$href.'" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">'.$name.' <span class="caret"></span></a>';
546
        $ret .= '<ul class="dropdown-menu">';
547
        $subNames = array_keys($link);
548
        foreach($subNames as $subName)
549
        {
550
            $ret .= $this->getLinkByName($subName, $link);
551
        }
552
        $ret .= '</ul></li>';
553
        return $ret;
554
    }
555
556
    protected function getLinkByName($name, $links)
557
    {
558
        if(is_array($links[$name]))
559
        {
560
            return $this->getDropdown($links[$name], $name);
561
        }
562
        if($links[$name] === false)
563
        {
564
            return '<li>'.$name.'</li>';
565
        }
566
        return '<li>'.$this->createLink($name, $links[$name]).'</li>';
567
    }
568
569
    protected function getLinksMenus()
570
    {
571
        $names = array_keys($this->links);
572
        $ret = '';
573
        foreach($names as $name)
574
        {
575
            $ret .= $this->getLinkByName($name, $this->links);
576
        }
577
        return $ret;
578
    }
579
580
    /**
581
     * Draw the header for the page
582
     */
583
    protected function addHeader()
584
    {
585
        $sites = $this->getSiteLinksForHeader();
586
        $links = $this->getLinksMenus();
587
        $header = '<nav class="navbar navbar-default navbar-fixed-top">
588
                      <div class="container-fluid">
589
                          <!-- Brand and toggle get grouped for better mobile display -->
590
                          <div class="navbar-header">
591
                          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse" aria-expanded="false">
592
                              <span class="sr-only">Toggle navigation</span>
593
                              <span class="icon-bar"></span>
594
                              <span class="icon-bar"></span>
595
                              <span class="icon-bar"></span>
596
                          </button>
597
                          <a class="navbar-brand" href="#">
598
                              <picture>
599
                                  <source srcset="/img/common/logo.svg" style="width: 30px; height:30px"/>
600
                                  <img alt="Burning Flipside" src="/img/common/logo.png" style="width: 30px; height:30px"/>
601
                              </picture>
602
                          </a>
603
                          </div>
604
                          <!-- Collect the nav links, forms, and other content for toggling -->
605
                          <div class="collapse navbar-collapse" id="navbar-collapse">
606
                              <ul id="site_nav" class="nav navbar-nav">
607
                              '.$sites.'
608
                              </ul>
609
                              <ul class="nav navbar-nav navbar-right">
610
                              '.$links.'
611
                              </ul>
612
                          </div>
613
                      </div>
614
                  </nav>';
615
        $this->body = $header.$this->body;
616
        $this->body_tags .= 'style="padding-top: 60px;"';
617
    }
618
619
    /** Notification that is green for success */
620
    const NOTIFICATION_SUCCESS = 'alert-success';
621
    /** Notification that is blue for infomrational messages */
622
    const NOTIFICATION_INFO    = 'alert-info';
623
    /** Notification that is yellow for warning */
624
    const NOTIFICATION_WARNING = 'alert-warning';
625
    /** Notification that is red for error */
626
    const NOTIFICATION_FAILED  = 'alert-danger';
627
628
    /**
629
     * Add a notification to the page
630
     *
631
     * @param string $message The message to show in the notifcation
632
     * @param string $severity The severity of the notifcation
633
     * @param boolean $dismissible Can the user dismiss the notificaton?
634
     */
635
    public function addNotification($message, $severity = self::NOTIFICATION_INFO, $dismissible = true)
636
    {
637
        array_push($this->notifications, array('msg'=>$message, 'sev'=>$severity, 'dismissible'=>$dismissible));
638
    }
639
640
    /**
641
     * Draw all notifications to the page
642
     */
643
    private function renderNotifications()
644
    {
645
        $count = count($this->notifications);
646
        if($count === 0)
647
        {
648
            return;
649
        }
650
        for($i = 0; $i < $count; $i++)
651
        {
652
            $class = 'alert '.$this->notifications[$i]['sev'];
653
            $button = '';
654
            if($this->notifications[$i]['dismissible'])
655
            {
656
                $class .= ' alert-dismissible';
657
                $button = '<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>';
658
            }
659
            $prefix = '';
660
            switch($this->notifications[$i]['sev'])
661
            {
662
                case self::NOTIFICATION_INFO:
663
                    $prefix = '<strong>Notice:</strong> ';
664
                    break;
665
                case self::NOTIFICATION_WARNING:
666
                    $prefix = '<strong>Warning!</strong> ';
667
                    break;
668
                case self::NOTIFICATION_FAILED:
669
                    $prefix = '<strong>Warning!</strong> ';
670
                    break;
671
            }
672
            $style = '';
673
            if(($i + 1) < count($this->notifications))
674
            {
675
                //Not the last notification, remove the end margin
676
                $style = 'style="margin: 0px;"';
677
            }
678
            $this->body = '
679
                <div class="'.$class.'" role="alert" '.$style.'>
680
                    '.$button.$prefix.$this->notifications[$i]['msg'].'
681
                </div>
682
            '.$this->body;
683
        }
684
    }
685
686
    /**
687
     * Add the no script block
688
     */
689
    private function addNoScript()
690
    {
691
        $this->body = '<noscript>
692
                <div class="alert alert-danger alert-dismissible" role="alert">
693
                    <button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
694
                    <strong>Error!</strong> This site makes extensive use of JavaScript. Please enable JavaScript or this site will not function.
695
                </div>
696
            </noscript>'.$this->body;
697
    }
698
699
    /**
700
     * Add the analytics script block
701
     */
702
    private function addAnalyticsBlock()
703
    {
704
        if($this->analytics === false)
705
        {
706
            return;
707
        }
708
        $this->body = $this->body.'<script>
709
  (function(i,s,o,g,r,a,m){i[\'GoogleAnalyticsObject\']=r;i[r]=i[r]||function(){
710
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
711
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
712
  })(window,document,\'script\',\'//www.google-analytics.com/analytics.js\',\'ga\');
713
714
  ga(\'create\', \'UA-64901342-1\', \'auto\');
715
  ga(\'send\', \'pageview\');
716
717
</script>';
718
    }
719
720
    /**
721
     * Add some global js vars
722
     */
723
    private function addJSGlobals()
724
    {
725
      $this->body = $this->body.'<script>
726
var loginUrl = \''.$this->loginUrl.'\'
727
var logoutUrl = \''.$this->logoutUrl.'\'
728
</script>';
729
    }
730
731
    /**
732
     * Draw the page
733
     *
734
     * @param boolean $header Draw the header
735
     */
736
    public function printPage($header = true)
737
    {
738
        $this->renderNotifications();
739
        $this->addNoScript();
740
        $this->addAnalyticsBlock();
741
        $this->addJSGlobals();
742
        if($this->header || $header)
743
        {
744
            $this->addHeader();
745
        }
746
        parent::printPage();
747
    }
748
749
    /**
750
     * Add a link to the header
751
     *
752
     * @param string $name The name of the link
753
     * @param boolean|string $url The URL to link to
754
     * @param boolean|array $submenu Any submenu items for the dropdown
755
     */
756
    public function addLink($name, $url = false, $submenu = false)
757
    {
758
        if(is_array($submenu))
759
        {
760
            $submenu['_'] = $url;
761
            $this->links[$name] = $submenu;
762
            return;
763
        }
764
        $this->links[$name] = $url;
765
    }
766
767
    /**
768
     * Add the login form to the page
769
     *
770
     * @SuppressWarnings("StaticAccess")
771
     */
772
    public function add_login_form()
773
    {
774
        $auth = \AuthProvider::getInstance();
775
        $authLinks = $auth->getSupplementaryLinks();
776
        $authLinksStr = '';
777
        $count = count($authLinks);
778
        for($i = 0; $i < $count; $i++)
779
        {
780
            $authLinksStr .= $authLinks[$i];
781
        }
782
        if($count > 0)
783
        {
784
            $authLinksStr = 'Sign in with '.$authLinksStr;
785
        }
786
        $this->body .= '<div class="modal fade" role="dialog" id="login-dialog" title="Login" aria-hidden="true">
787
                            <div class="modal-dialog">
788
                                <div class="modal-content">
789
                                    <div class="modal-header">
790
                                        <button type="button" class="close" data-dismiss="modal">
791
                                            <span aria-hidden="true">&times;</span>
792
                                            <span class="sr-only">Close</span>
793
                                        </button>
794
                                        <h4 class="modal-title">Login</h4>
795
                                    </div>
796
                                    <div class="modal-body">
797
                                        <form id="login_dialog_form" role="form">
798
                                            <input class="form-control" type="text" name="username" placeholder="Username or Email" required autofocus/>
799
                                            <input class="form-control" type="password" name="password" placeholder="Password" required/>
800
                                            <input type="hidden" name="return" value="'.$this->currentUrl().'"/>
801
                                            <button class="btn btn-lg btn-primary btn-block" type="submit">Login</button>
802
                                        </form>
803
                                        '.$authLinksStr.'
804
                                    </div>
805
                                </div>
806
                            </div>
807
                        </div>';
808
    }
809
810
    /**
811
     * Add additional links
812
     */
813
    public function add_links()
814
    {
815
    }
816
}
817
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
818