Completed
Pull Request — master (#11)
by Patrick
03:26
created

FlipPage::getSites()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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