Completed
Pull Request — master (#21)
by Patrick
02:35
created

FlipPage::printPage()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 2
nop 1
dl 0
loc 12
rs 9.4285
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.js',
193
                'min' => '/js/common/jquery.Jcrop.min.js'
194
            ),
195
            'cdn' => array(
196
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/0.9.12/js/jquery.Jcrop.js',
197
                'min' => '//cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/0.9.12/js/jquery.Jcrop.min.js'
198
            )
199
        ),
200
        JS_TYPEAHEAD => array(
201
            'no' => array(
202
                'no'  => '/js/common/typeahead.bundle.js',
203
                'min' => '/js/common/typeahead.bundle.min.js'
204
            ),
205
            'cdn' => array(
206
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.bundle.js',
207
                'min' => '//cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.bundle.min.js'
208
            )
209
        ),
210
        JS_CHEET => array(
211
            'no' => array(
212
                'no'  => '/js/common/cheet.js',
213
                'min' => '/js/common/cheer.min.js'
214
            ),
215
            'cdn' => array(
216
                'no'  => '//cdn.rawgit.com/namuol/cheet.js/master/cheet.min.js',
217
                'min' => '//cdn.rawgit.com/namuol/cheet.js/master/cheet.min.js'
218
            )
219
        ),
220
        JS_FLIPSIDE => array(
221
            'no' => array(
222
                'no'  => '/js/common/flipside.js',
223
                'min' => '/js/common/flipside.min.js'
224
            ),
225
            'cdn' => array(
226
                'no'  => '/js/common/flipside.js',
227
                'min' => '/js/common/flipside.min.js'
228
            )
229
        ),
230
        JS_LOGIN => array(
231
            'no' => array(
232
                'no'  => '/js/common/login.js',
233
                'min' => '/js/common/login.min.js'
234
            ),
235
            'cdn' => array(
236
                'no'  => '/js/common/login.js',
237
                'min' => '/js/common/login.min.js'
238
            )
239
        )
240
);
241
242
global $cssArray;
243
$cssArray = array(
244
    CSS_JQUERY_UI => array(
245
        'no' => array(
246
                'no'  => '/css/common/jquery-ui.css',
247
                'min' => '/css/common/jquery-ui.min.css'
248
            ),
249
            'cdn' => array(
250
                'no'  => '//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css',
251
                'min' => '//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.min.css'
252
            )
253
    ),
254
    CSS_BOOTSTRAP => array(
255
            'no' => array(
256
                'no'  => '/css/common/bootstrap.css',
257
                'min' => '/css/common/bootstrap.min.css'
258
            ),
259
            'cdn' => array(
260
                'no'  => '//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css',
261
                'min' => '//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css'
262
            )
263
    ),
264
    CSS_BOOTSTRAP_FH => array(
265
        'no' => array(
266
                'no'  => '/css/common/bootstrap-formhelpers.css',
267
                'min' => '/css/common/bootstrap-formhelpers.min.css'
268
            ),
269
            'cdn' => array(
270
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-formhelpers/2.3.0/css/bootstrap-formhelpers.css',
271
                'min' => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-formhelpers/2.3.0/css/bootstrap-formhelpers.min.css'
272
            )
273
    ),
274
    CSS_BOOTSTRAP_SW => array(
275
            'no' => array(
276
                'no'  => '/css/common/bootstrap-switch.css',
277
                'min' => '/css/common/bootstrap-switch.min.css'
278
            ),
279
            'cdn' => array(
280
                'no'  => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/css/bootstrap3/bootstrap-switch.css',
281
                'min' => '//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/css/bootstrap3/bootstrap-switch.min.css'
282
            )
283
    ),
284
    CSS_DATATABLE => array(
285
        'no' => array(
286
                'no'  => '/css/common/jquery.dataTables.css',
287
                'min' => '/css/common/jquery.dataTables.min.css'
288
            ),
289
            'cdn' => array(
290
                'no'  => '//cdn.datatables.net/1.10.7/css/jquery.dataTables.css',
291
                'min' => '//cdn.datatables.net/1.10.7/css/jquery.dataTables.min.css'
292
            )
293
    ),
294
    CSS_JCROP => array(
295
        'no'  => array(
296
            'no'  => '/css/common/jquery.Jcrop.css',
297
            'min' => '/css/common/jquery.Jcrop.min.css'
298
        ),
299
        'cdn' => array(
300
            'no'  => '//cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/0.9.12/css/jquery.Jcrop.css',
301
            'min' => '//cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/0.9.12/css/jquery.Jcrop.min.css'
302
        )
303
    ),
304
    CSS_FONTAWESOME => array(
305
        'no'  => array(
306
            'no'  => '/css/common/font-awesome.css',
307
            'min' => '/css/common/font-awesome.min.css'
308
        ),
309
        'cdn' => array(
310
            'no'  => '//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.css',
311
            'min' => '//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css'
312
        )
313
    )
314
);
315
316
/**
317
 * A framework specific webpage abstraction layer
318
 *
319
 * This class abstracts out some basic webpage creation with JQuery, Bootstrap, and other helpers
320
 */
321
class FlipPage extends WebPage
322
{
323
    /** The currently logged in user or null if no user is logged in */
324
    public $user;
325
    /** An array of links to put in the header */
326
    public $links;
327
    /** An array of notifications to draw on the page */
328
    public $notifications;
329
    /** Should we draw the header? */
330
    public $header;
331
    /** The login page URL */
332
    public $loginUrl;
333
    /** The logout page URL */
334
    public $logoutUrl;
335
    /** Should we use minified JS/CSS? */
336
    protected $minified = null;
337
    /** Should we use local JS/CSS or Content Delivery Networks? */
338
    protected $cdn = null;
339
    /** Draw the analytics scripts */
340
    protected $analytics = true;
341
    /** An instance of the Settings class */
342
    protected $settings;
343
344
    /**
345
     * Create a webpage with JQuery, Bootstrap, etc
346
     *
347
     * @param string $title The webpage title
348
     * @param boolean $header Draw the header bar?
349
     *
350
     * @SuppressWarnings("StaticAccess")
351
     */
352
    public function __construct($title, $header = true)
353
    {
354
        $this->settings = \Settings::getInstance();
355
        parent::__construct($title);
356
        $this->setupVars();
357
        $this->addWellKnownJS(JS_JQUERY, false);
358
        $this->addWellKnownJS(JS_FLIPSIDE, false);
359
        $this->addBootstrap();
360
        $this->header = $header;
361
        $this->links = array();
362
        $this->notifications = array();
363
        $this->aboutUrl = $this->settings->getGlobalSetting('about_url', 'https://www.burningflipside.com/about');
0 ignored issues
show
Bug introduced by
The property aboutUrl does not exist. Did you maybe forget to declare it?

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

class MyClass { }

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

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

class MyClass {
    public $foo;
}

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

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

class MyClass { }

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

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

class MyClass {
    public $foo;
}

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