Completed
Push — master ( 9337f8...1eee69 )
by Patrick
03:28
created

FlipPage::add_links()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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