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

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