Completed
Pull Request — master (#29)
by
unknown
02:39
created

class.FlipPage.php (3 issues)

Labels
Severity

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