-
Notifications
You must be signed in to change notification settings - Fork 19
/
scripts.class.php
677 lines (575 loc) · 25.4 KB
/
scripts.class.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
<?php
/* Reminder: always indent with 4 spaces (no tabs). */
// +---------------------------------------------------------------------------+
// | Geeklog 2.1 |
// +---------------------------------------------------------------------------+
// | scripts.class.php |
// | |
// | Geeklog class to include javascript, javascript files and css files. |
// +---------------------------------------------------------------------------+
// | Copyright (C) 2000-2011 by the following authors: |
// | |
// | Authors: Tom Homer, tomhomer AT gmail DOT com |
// +---------------------------------------------------------------------------+
// | |
// | This program is free software; you can redistribute it and/or |
// | modify it under the terms of the GNU General Public License |
// | as published by the Free Software Foundation; either version 2 |
// | of the License, or (at your option) any later version. |
// | |
// | This program is distributed in the hope that it will be useful, |
// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// | GNU General Public License for more details. |
// | |
// | You should have received a copy of the GNU General Public License |
// | along with this program; if not, write to the Free Software Foundation, |
// | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
// | |
// +---------------------------------------------------------------------------+
/**
* This class is used to set JavaScript, JavaScript Files, jQuery JavaScript Libraries
* and CSS files that need to be loaded either in the header of the footer.
*
* @author Tom Homer
*/
class Scripts
{
private $library_files; // Array of available jQuery library files that can be loaded
private $library_files_footer; // Location of loading library files
private $jquery_cdn; // Flag to use jQuery file from CDN-hosted source (Google)
private $jquery_cdn_file; // Location of jQuery file at Google
private $jquery_ui_cdn; // Flag to use jQuery UI file from CDN-hosted source (Google)
private $jquery_ui_cdn_file; // Location of jQuery UI file at Google
private $script_files; // Array of JavaScript files set to be loaded either in the header or footer
private $css_files; // Array of CSS files set to be loaded
private $scripts; // Array of JavaScript set to be loaded either in the header or footer
private $restricted_names; // Restricted names list for JavaScript files
private $header_set; // Flag to know if Header Code already has been retrieved
private $javascript_set; // Flag to know if ANY JavaScript has been set yet
private $css_set; // Flag to know if ANY css has been set yet
private $lang; // Array of language variables used in JavaScript
/**
* Constructor
* This initializes the scriptsobject
*/
public function __construct()
{
$this->library_files = array();
$this->library_files_footer = true;
$this->jquery_ui_cdn = false;
$this->script_files = array();
$this->css_files = array();
$this->scripts = array();
$this->css = array();
$this->restricted_names = array();
$this->lang = array();
$this->header_set = false;
$this->javascript_set = false;
$this->jquery_cdn = false;
$this->jquery_ui_cdn = false;
// Find available JavaScript libraries
$this->findJavaScriptLibraries();
// Automatically set Common library since we have not updated core yet to set it when needed
$this->setJavaScriptLibrary('common');
// Setup restricted names after setting main libraries (do not want plugins messing with them)
$this->restricted_names = array('core', 'jquery');
}
/**
* Build a list of available JavaScript Libraries
*
* @return boolean
*/
private function findJavaScriptLibraries()
{
global $_CONF;
$theme_path = '/layout/' . $_CONF['theme'];
// Add Geeklog Specific JavaScript files. Treat them as library files since other plugins may try to load them
$name = 'common';
$this->library_files[$name]['file'] = 'javascript/common.js';
$this->library_files[$name]['load'] = false;
// jQuery (http://jquery.com/download/)
// Find available jQuery library files
$version_jQuery = '3.1.1'; // '1.11.3'; // '1.11.2'; // '1.10.2'; // '1.9.1'; // '1.9.0'; // '1.7.2'; // '1.6.3';
$this->jquery_cdn_file = 'https://ajax.googleapis.com/ajax/libs/jquery/' . $version_jQuery . '/jquery.min.js';
$name = 'jquery';
// $this->library_files[$name]['file'] = 'javascript/jquery-' . $version_jQuery . '.min.js';
$this->library_files[$name]['file'] = 'javascript/jquery.min.js';
$this->library_files[$name]['load'] = false;
// jQuery UI (http://plugins.jquery.com/ui.core/ and https://github.com/jquery/jquery-ui/releases)
// When upgrading jQuery UI include the Redmond theme and all Core, Interactions and Widgets
// Include minified version only of js
// After Upgrade Test: Story Editor Topic Control, Story Editor Date & Time Picker, Submissions Help Pop up box, Admin Configuration Search and Tabs, Etc..
$version_jQuery_ui = '1.12.1'; // '1.11.4'; // '1.11.2'; // '1.10.3'; // '1.10.1'; // '1.10.0'; // '1.8.20'; // '1.8.11';
$this->jquery_ui_cdn_file = 'https://ajax.googleapis.com/ajax/libs/jqueryui/' . $version_jQuery_ui . '/jquery-ui.min.js';
// Set jQuery UI CSS
$this->setCSSFilePrivate('jquery-ui', $theme_path . '/jquery_ui/jquery-ui.min.css', 0.1, false);
$this->setCSSFilePrivate('jquery-ui.structure', $theme_path . '/jquery_ui/jquery-ui.structure.min.css', 0.2, false);
$this->setCSSFilePrivate('jquery-ui.theme', $theme_path . '/jquery_ui/jquery-ui.theme.min.css', 0.3, false);
$this->setCSSFilePrivate('jquery-ui.geeklog', $theme_path . '/jquery_ui/jquery-ui.geeklog.css', 0.4, false);
// Set jQuery UI
$names[] = 'jquery-ui';
// Set jQuery UI Widgets (not included with core)
$names[] = 'jquery-ui-i18n'; // extra included in core plugin under i18n directory (used by calendar and article dates)
// jQuery Timepicker Addon (https://github.com/trentrichardson/jQuery-Timepicker-Addon and http://trentrichardson.com/examples/timepicker/)
// Version 1.5.4
$names[] = 'jquery-ui-timepicker-addon';
$names[] = 'jquery-ui-timepicker-addon-i18n';
$names[] = 'jquery-ui-slideraccess';
foreach ($names as $name) {
$this->library_files[$name]['file'] = 'javascript/jquery_ui/' . $name . '.min.js';
$this->library_files[$name]['load'] = false;
}
}
/**
* Set JavaScript Libraries to load
*
* @param string $name name of JavaScript library to flag for loading
* @param boolean $footer set to true to include script in footer, else script placed in header
* @return boolean
*/
public function setJavaScriptLibrary($name, $footer = true)
{
global $_CONF;
$name = strtolower($name);
if (!$footer) {
// If something wants a library in the header then all in the header
$this->library_files_footer = false;
}
// For backwards compatible (Geeklog v2.1.1 and lower plugins)with jquery ui library when we specified individual widgets, effects, etc...
if (substr($name, 0, 10) == 'jquery.ui.') {
$name = 'jquery-ui'; // Instead we now load entire library
}
if (isset($this->library_files[$name])) {
if (!$this->library_files[$name]['load']) {
$this->library_files[$name]['load'] = true;
// If name is subset of jQuery (. or - can be used) make sure all Core UI libraries are loaded
if ((substr($name, 0, 7) == 'jquery-' || substr($name, 0, 7) == 'jquery.') && !$this->jquery_ui_cdn) {
// Check that file exists, if not use Google version
if (!file_exists($_CONF['path_html'] . $this->library_files[$name]['file'])) {
$this->jquery_ui_cdn = true;
$this->css_files['jquery-ui']['load'] = false;
} else {
$this->css_files['jquery-ui']['load'] = true;
}
$this->css_files['jquery-ui.structure']['load'] = true;
$this->css_files['jquery-ui.theme']['load'] = true;
// Geeklog specific css overrides for jQuery (includes timepicker-addon css)
$this->css_files['jquery-ui.geeklog']['load'] = true;
$this->library_files['jquery']['load'] = true;
$this->library_files['jquery-ui']['load'] = true;
if ($_CONF['cdn_hosted']) {
$this->jquery_cdn = true;
$this->jquery_ui_cdn = true;
}
} elseif ($name == 'jquery' && $_CONF['cdn_hosted']) {
$this->jquery_cdn = true;
}
}
$this->javascript_set = true;
return true;
} else {
return false;
}
}
/**
* Set Libraries file to load. Used only by class.
*
* @access private
* @return boolean
*/
private function setJavaScriptLibraries()
{
global $_CONF;
$librarycode = '';
if ($this->jquery_cdn) {
$librarycode .= '<script type="text/javascript" src="' . $this->jquery_cdn_file . '"></script>' . LB;
$this->library_files['jquery']['load'] = false; // Set to false so not reloaded
if ($this->jquery_ui_cdn) {
$librarycode .= '<script type="text/javascript" src="' . $this->jquery_ui_cdn_file . '"></script>' . LB;
// Since using CDN file reset loading of jQuery UI
foreach ($this->library_files as $key => &$file) {
if (substr($key, 0, 7) == 'jquery.') {
$file['load'] = false;
}
}
}
} elseif ($this->jquery_ui_cdn) { // This might happen if a jQuery UI file is not found
$librarycode .= '<script type="text/javascript" src="' . $_CONF['site_url'] . '/' . $this->library_files['jquery']['file'] . '"></script>' . LB;
$this->library_files['jquery']['load'] = false; // Set to false so not reloaded
$librarycode .= '<script type="text/javascript" src="' . $this->jquery_ui_cdn_file . '"></script>' . LB;
// Since using CDN file reset loading of jQuery UI
foreach ($this->library_files as $key => &$file) {
if (substr($key, 0, 7) == 'jquery.') {
$file['load'] = false;
}
}
}
// Now load in the rest of the libraries
foreach ($this->library_files as $file) {
if ($file['load']) {
$librarycode .= '<script type="text/javascript" src="' . $_CONF['site_url'] . '/' . $file['file'] . '"></script>' . LB;
}
}
return $librarycode;
}
/**
* Set JavaScript to load
*
* @param string $script script to include in page
* @param boolean $wrap set to true to place script tags around contents of $script
* @param boolean $footer set to true to include script in footer, else script placed in header
* @return boolean
*/
public function setJavaScript($script, $wrap = false, $footer = true)
{
// If header code make sure header not already set
if ($this->header_set && !$footer) {
return false;
}
$location = $footer ? 'footer' : 'header';
if ($wrap) {
$script = '<script type="text/javascript">' . $script . '</script>';
}
$this->scripts[$location][] = $script;
$this->javascript_set = true;
return true;
}
/**
* Set JavaScript file to load
*
* @param string $name name of JavaScript file
* @param string $file location of file relative to public_html directory. Include '/' at beginning
* @param boolean $footer set to true to include script in footer, else script placed in header
* @param int $priority In what order the script should be loaded in
* @return boolean
*/
public function setJavaScriptFile($name, $file, $footer = true, $priority = 100)
{
global $_CONF;
// If header code make sure header not already set
if ($this->header_set && !$footer) {
return false;
}
// Make sure valid name
if (in_array(strtolower($name), $this->restricted_names, true)) {
return false;
}
// Make sure file exists and is readable. We don't want any 403 or 404, right?
$path = substr($_CONF['path_html'], 0, -1) . $file;
// Strip parameters
if (strrpos($path, '?') !== false) {
$path = substr($path, 0, strrpos($path, '?'));
}
if (!is_file($path) || !is_readable($path)) {
return false;
}
$this->script_files[$name]['file'] = $file;
$this->script_files[$name]['footer'] = $footer;
$this->script_files[$name]['priority'] = $priority;
$this->javascript_set = true;
return true;
}
/**
* Set CSS file to load. Used only by class.
* This function is used to include any CSS needed by the JavaScript Libraries
*
* @param string $name name of CSS file
* @param string $file location of file relative to public_html directory. Include '/' at beginning
* @param int $priority In what order the script should be loaded in
* @param boolean $load set to true to load script right away. Should only be loaded when related script is loaded
* @return boolean
*/
private function setCSSFilePrivate($name, $file, $priority = 100, $load = true)
{
global $_CONF;
// If header code make sure header not already set
if ($this->header_set) {
return false;
}
// Make sure valid name
if (in_array(strtolower($name), $this->restricted_names, true)) {
return false;
}
// Make sure file exists and is readable. We don't want any 403 or 404, right?
$path = substr($_CONF['path_html'], 0, -1) . $file;
if (!is_file($path) || !is_readable($path)) {
return false;
}
$this->css_files[$name]['file'] = $file;
$this->css_files[$name]['extra'] = '';
$this->css_files[$name]['priority'] = $priority; // Default is 100
$this->css_files[$name]['constant'] = false;
$this->css_files[$name]['load'] = $load;
return true;
}
/**
* Set language variables used in JavaScript.
*
* @param array $lang_array array of language variables
* @return boolean
*/
public function setLang($lang_array)
{
$this->lang = array_merge($this->lang, $lang_array);
return true;
}
/**
* Set CSS file to load
*
* @param string $name name of CSS file
* @param string $file location of file relative to public_html directory. Include '/' at beginning
* @param boolean $constant Future use. Set to true if file is planned to be loaded all the time (Caching/Compression)
* @param array $attributes (optional) array of extra attributes
* @param int $priority In what order the script should be loaded in
* @param string $type Type of css file (current possible choices are theme or other)
* @return boolean
*/
public function setCSSFile($name, $file, $constant = true, $attributes = array(), $priority = 100, $type = '')
{
global $_CONF;
// If header code make sure header not already set
if ($this->header_set) {
return false;
}
// Make sure valid name
if (in_array(strtolower($name), $this->restricted_names, true)) {
return false;
}
// Make sure file exists and is readable. We don't want any 403 or 404, right?
$path = substr($_CONF['path_html'], 0, -1) . $file;
// Strip parameters
if (strrpos($path, '?') !== false) {
$path = substr($path, 0, strrpos($path, '?'));
}
if (!is_file($path) || !is_readable($path)) {
return false;
}
$extra = '';
foreach ($attributes as $key => $value) {
if (in_array($key, array('rel', 'type', 'href'))) {
$this->css_files[$name][$key] = $value;
} else {
$extra .= " $key=\"$value\"";
}
}
$this->css_files[$name]['name'] = $name;
$this->css_files[$name]['file'] = $file;
$this->css_files[$name]['extra'] = $extra;
$this->css_files[$name]['priority'] = $priority;
$this->css_files[$name]['constant'] = $constant;
if ($_CONF['theme_etag'] && ($type === 'theme')) {
// Don't load css regular way for themes with eTag enabled
$this->css_files[$name]['load'] = false;
} else {
$this->css_files[$name]['load'] = true;
}
return true;
}
/**
* Set CSS in header using style tag
*
* @param string $css css to include in head
* @return boolean
*/
public function setCSS($css)
{
// If header code make sure header not already set
if ($this->header_set) {
return false;
}
$this->css[] = $css;
$this->css_set = true;
return true;
}
/**
* Returns header code (JavaScript and CSS) to include in the Head of the webpage
*
* @return string
*/
public function getHeader()
{
global $_CONF, $MESSAGE, $LANG_DIRECTION;
$this->header_set = true;
$headercode = '';
// Sort CSS Files based on priority
$priority = array();
foreach ($this->css_files as $k => $d) {
$priority[$k] = $d['priority'];
}
array_multisort($priority, SORT_ASC, $this->css_files);
// See if theme uses ETag, if so load first
if ($_CONF['theme_etag']) {
$csslink = '<link rel="stylesheet" type="text/css" href="'
. $_CONF['layout_url'] . '/style.css.php?theme=' . $_CONF['theme'] . '&dir=' . $LANG_DIRECTION . '" media="all"' . XHTML . '>' . LB;
$headercode = $csslink . $headercode;
}
// Set CSS Files
foreach ($this->css_files as $file) {
$rel = 'stylesheet';
if (!empty($file['rel'])) {
$rel = $file['rel'];
}
$type = 'text/css';
if (!empty($file['type'])) {
$type = $file['type'];
}
$href = '';
if (!empty($file['file'])) {
$href = $_CONF['site_url'] . $file['file'];
}
if (!empty($file['href'])) {
$href = $file['href'];
}
if ($file['load'] && !empty($href)) {
$csslink = '<link rel="' . $rel
. '" type="' . $type
. '" href="' . $href
. '"' . $file['extra'] . XHTML . '>' . LB;
if (isset($file['name']) && $file['name'] == 'theme') { // load theme css first
$headercode = $csslink . $headercode;
} else {
$headercode .= $csslink;
}
}
}
// Set CSS
if ($this->css_set) {
$headercode .= '<style type="text/css">' . LB;
foreach ($this->css as $css) {
$headercode .= $css . LB;
}
$headercode .= '</style>' . LB;
}
// Set JavaScript Library files first incase other scripts need them
if (!$this->library_files_footer) { // // Do we load jQuery now?
$headercode .= $this->setJavaScriptLibraries();
}
// Set JavaScript Variables (do this before file in case variables are needed)
$iso639Code = COM_getLangIso639Code();
$lang = array(
'iso639Code' => $iso639Code,
'tooltip_loading' => $MESSAGE[116],
'tooltip_not_found' => $MESSAGE[117],
'tooltip_select_date' => $MESSAGE[118],
'tabs_more' => $MESSAGE[119],
'confirm_delete' => $MESSAGE[76],
'confirm_send' => $MESSAGE[120],
);
if (!empty($this->lang)) {
$lang = array_merge($lang, $this->lang);
}
require_once __DIR__ . '/mobiledetect/Mobile_Detect.php';
$detect = new Mobile_Detect;
$device = array(
'isMobile' => $detect->isMobile(),
'isTablet' => $detect->isTablet(),
);
$src = array(
'site_url' => $_CONF['site_url'],
'site_admin_url' => $_CONF['site_admin_url'],
'layout_url' => $_CONF['layout_url'],
'xhtml' => XHTML,
'lang' => $lang,
'device' => $device,
'theme_options' => $_CONF['theme_options'],
);
$str = $this->_array_to_jsobj($src);
// Strip '{' and '}' from both ends of $str
$str = substr($str, 1);
$str = substr($str, 0, strlen($str) - 1);
$headercode .= <<<EOD
<script type="text/javascript">
var geeklog = {
doc: document,
win: window,
$: function (id) {
return this.doc.getElementById(id);
},
{$str}
};
</script>
EOD;
if (isset($this->scripts['header'])) {
foreach ($this->scripts['header'] as $script) {
$headercode .= $script . LB;
}
}
// Sort JavaScript Files based on priority (this is for both header and footer)
$priority = array();
foreach ($this->script_files as $k => $d) {
$priority[$k] = $d['priority'];
}
array_multisort($priority, SORT_ASC, $this->script_files);
// Set JavaScript Files
foreach ($this->script_files as $file) {
if (!$file['footer']) {
$headercode .= '<script type="text/javascript" src="' . $_CONF['site_url'] . $file['file'] . '"></script>' . LB;
}
}
return $headercode;
}
/**
* Convert from array to JavaScript object format string
*
* @param array $src
* @return string
*/
private function _array_to_jsobj($src)
{
$retval = '{';
foreach ($src as $key => $val) {
$retval .= "$key:";
switch (gettype($val)) {
case 'array':
$retval .= $this->_array_to_jsobj($val) . ',';
break;
case 'boolean':
$retval .= $val ? 'true,' : 'false,';
break;
case 'NULL':
$retval .= 'null,';
break;
case 'integer':
case 'double':
$retval .= $val . ',';
break;
default:
$retval .= '"' . $val . '",';
break;
}
}
$retval = rtrim($retval, ',') . '}';
return $retval;
}
/**
* Returns JavaScript footer code to be placed just before </body>
*
* @return string
*/
public function getFooter()
{
global $_CONF;
$footercode = '';
// Do we need to set JavaScript
if ($this->javascript_set) {
// Set JavaScript Library files first incase other scripts need them
if ($this->library_files_footer) { // Has jQuery already been loaded in header?
$footercode .= $this->setJavaScriptLibraries();
}
// Set JavaScript (do this before file incase variables are needed)
if (isset($this->scripts['footer'])) {
foreach ($this->scripts['footer'] as $script) {
$footercode .= $script . LB;
}
}
// Set JavaScript Files
foreach ($this->script_files as $file) {
if ($file['footer']) {
$footercode .= '<script type="text/javascript" src="' . $_CONF['site_url'] . $file['file'] . '"></script>' . LB;
}
}
}
return $footercode;
}
}