Completed
Push — remoteapiGetversions ( b2f4ab...f28a57 )
by Gerrit
12:56 queued 07:54
created

js.php ➔ js_templatestrings()   C

Complexity

Conditions 13
Paths 72

Size

Total Lines 33
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 13
eloc 20
c 1
b 0
f 0
nc 72
nop 1
dl 0
loc 33
rs 5.1234

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * DokuWiki JavaScript creator
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     Andreas Gohr <[email protected]>
7
 */
8
9
if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../');
10
if(!defined('NOSESSION')) define('NOSESSION',true); // we do not use a session or authentication here (better caching)
11
if(!defined('NL')) define('NL',"\n");
12
if(!defined('DOKU_DISABLE_GZIP_OUTPUT')) define('DOKU_DISABLE_GZIP_OUTPUT',1); // we gzip ourself here
13
require_once(DOKU_INC.'inc/init.php');
14
15
// Main (don't run when UNIT test)
16
if(!defined('SIMPLE_TEST')){
17
    header('Content-Type: application/javascript; charset=utf-8');
18
    js_out();
19
}
20
21
22
// ---------------------- functions ------------------------------
23
24
/**
25
 * Output all needed JavaScript
26
 *
27
 * @author Andreas Gohr <[email protected]>
28
 */
29
function js_out(){
30
    global $conf;
31
    global $lang;
32
    global $config_cascade;
33
    global $INPUT;
34
35
    // decide from where to get the template
36
    $tpl = trim(preg_replace('/[^\w-]+/','',$INPUT->str('t')));
37
    if(!$tpl) $tpl = $conf['template'];
38
39
    // The generated script depends on some dynamic options
40
    $cache = new cache('scripts'.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'].DOKU_BASE.$tpl,'.js');
41
    $cache->_event = 'JS_CACHE_USE';
0 ignored issues
show
Bug introduced by
The property _event cannot be accessed from this context as it is declared private in class cache.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
42
43
    // load minified version for some files
44
    $min = $conf['compress'] ? '.min' : '';
45
46
    // array of core files
47
    $files = array(
48
                DOKU_INC."lib/scripts/jquery/jquery$min.js",
49
                DOKU_INC.'lib/scripts/jquery/jquery.cookie.js',
50
                DOKU_INC."lib/scripts/jquery/jquery-ui$min.js",
51
                DOKU_INC."lib/scripts/jquery/jquery-migrate$min.js",
52
                DOKU_INC.'inc/lang/'.$conf['lang'].'/jquery.ui.datepicker.js',
53
                DOKU_INC."lib/scripts/fileuploader.js",
54
                DOKU_INC."lib/scripts/fileuploaderextended.js",
55
                DOKU_INC.'lib/scripts/helpers.js',
56
                DOKU_INC.'lib/scripts/delay.js',
57
                DOKU_INC.'lib/scripts/cookie.js',
58
                DOKU_INC.'lib/scripts/script.js',
59
                DOKU_INC.'lib/scripts/qsearch.js',
60
                DOKU_INC.'lib/scripts/tree.js',
61
                DOKU_INC.'lib/scripts/index.js',
62
                DOKU_INC.'lib/scripts/textselection.js',
63
                DOKU_INC.'lib/scripts/toolbar.js',
64
                DOKU_INC.'lib/scripts/edit.js',
65
                DOKU_INC.'lib/scripts/editor.js',
66
                DOKU_INC.'lib/scripts/locktimer.js',
67
                DOKU_INC.'lib/scripts/linkwiz.js',
68
                DOKU_INC.'lib/scripts/media.js',
69
                DOKU_INC.'lib/scripts/compatibility.js',
70
# disabled for FS#1958                DOKU_INC.'lib/scripts/hotkeys.js',
71
                DOKU_INC.'lib/scripts/behaviour.js',
72
                DOKU_INC.'lib/scripts/page.js',
73
                tpl_incdir($tpl).'script.js',
74
            );
75
76
    // add possible plugin scripts and userscript
77
    $files   = array_merge($files,js_pluginscripts());
78
    if(!empty($config_cascade['userscript']['default'])) {
79
        foreach($config_cascade['userscript']['default'] as $userscript) {
80
            $files[] = $userscript;
81
        }
82
    }
83
84
    $cache_files = array_merge($files, getConfigFiles('main'));
85
    $cache_files[] = __FILE__;
86
87
    // check cache age & handle conditional request
88
    // This may exit if a cache can be used
89
    $cache_ok = $cache->useCache(array('files' => $cache_files));
90
    http_cached($cache->cache, $cache_ok);
91
92
    // start output buffering and build the script
93
    ob_start();
94
95
    $json = new JSON();
96
    // add some global variables
97
    print "var DOKU_BASE   = '".DOKU_BASE."';";
98
    print "var DOKU_TPL    = '".tpl_basedir($tpl)."';";
99
    print "var DOKU_COOKIE_PARAM = " . $json->encode(
100
            array(
101
                 'path' => empty($conf['cookiedir']) ? DOKU_REL : $conf['cookiedir'],
102
                 'secure' => $conf['securecookie'] && is_ssl()
103
            )).";";
104
    // FIXME: Move those to JSINFO
105
    print "var DOKU_UHN    = ".((int) useHeading('navigation')).";";
106
    print "var DOKU_UHC    = ".((int) useHeading('content')).";";
107
108
    // load JS specific translations
109
    $lang['js']['plugins'] = js_pluginstrings();
110
    $templatestrings = js_templatestrings($tpl);
111
    if(!empty($templatestrings)) {
112
        $lang['js']['template'] = $templatestrings;
113
    }
114
    echo 'LANG = '.$json->encode($lang['js']).";\n";
115
116
    // load toolbar
117
    toolbar_JSdefines('toolbar');
118
119
    // load files
120
    foreach($files as $file){
121
        if(!file_exists($file)) continue;
122
        $ismin = (substr($file,-7) == '.min.js');
123
        $debugjs = ($conf['allowdebug'] && strpos($file, DOKU_INC.'lib/scripts/') !== 0);
124
125
        echo "\n\n/* XXXXXXXXXX begin of ".str_replace(DOKU_INC, '', $file) ." XXXXXXXXXX */\n\n";
126
        if($ismin) echo "\n/* BEGIN NOCOMPRESS */\n";
127
        if ($debugjs) echo "\ntry {\n";
128
        js_load($file);
129
        if ($debugjs) echo "\n} catch (e) {\n   logError(e, '".str_replace(DOKU_INC, '', $file)."');\n}\n";
130
        if($ismin) echo "\n/* END NOCOMPRESS */\n";
131
        echo "\n\n/* XXXXXXXXXX end of " . str_replace(DOKU_INC, '', $file) . " XXXXXXXXXX */\n\n";
132
    }
133
134
    // init stuff
135
    if($conf['locktime'] != 0){
136
        js_runonstart("dw_locktimer.init(".($conf['locktime'] - 60).",".$conf['usedraft'].")");
137
    }
138
    // init hotkeys - must have been done after init of toolbar
139
# disabled for FS#1958    js_runonstart('initializeHotkeys()');
140
141
    // end output buffering and get contents
142
    $js = ob_get_contents();
143
    ob_end_clean();
144
145
    // strip any source maps
146
    stripsourcemaps($js);
147
148
    // compress whitespace and comments
149
    if($conf['compress']){
150
        $js = js_compress($js);
151
    }
152
153
    $js .= "\n"; // https://bugzilla.mozilla.org/show_bug.cgi?id=316033
154
155
    http_cached_finish($cache->cache, $js);
156
}
157
158
/**
159
 * Load the given file, handle include calls and print it
160
 *
161
 * @author Andreas Gohr <[email protected]>
162
 *
163
 * @param string $file filename path to file
164
 */
165
function js_load($file){
166
    if(!file_exists($file)) return;
167
    static $loaded = array();
168
169
    $data = io_readFile($file);
170
    while(preg_match('#/\*\s*DOKUWIKI:include(_once)?\s+([\w\.\-_/]+)\s*\*/#',$data,$match)){
171
        $ifile = $match[2];
172
173
        // is it a include_once?
174
        if($match[1]){
175
            $base = utf8_basename($ifile);
176
            if(array_key_exists($base, $loaded) && $loaded[$base] === true){
177
                $data  = str_replace($match[0], '' ,$data);
178
                continue;
179
            }
180
            $loaded[$base] = true;
181
        }
182
183
        if($ifile{0} != '/') $ifile = dirname($file).'/'.$ifile;
184
185
        if(file_exists($ifile)){
186
            $idata = io_readFile($ifile);
187
        }else{
188
            $idata = '';
189
        }
190
        $data  = str_replace($match[0],$idata,$data);
191
    }
192
    echo "$data\n";
193
}
194
195
/**
196
 * Returns a list of possible Plugin Scripts (no existance check here)
197
 *
198
 * @author Andreas Gohr <[email protected]>
199
 *
200
 * @return array
201
 */
202
function js_pluginscripts(){
203
    $list = array();
204
    $plugins = plugin_list();
205
    foreach ($plugins as $p){
206
        $list[] = DOKU_PLUGIN."$p/script.js";
207
    }
208
    return $list;
209
}
210
211
/**
212
 * Return an two-dimensional array with strings from the language file of each plugin.
213
 *
214
 * - $lang['js'] must be an array.
215
 * - Nothing is returned for plugins without an entry for $lang['js']
216
 *
217
 * @author Gabriel Birke <[email protected]>
218
 *
219
 * @return array
220
 */
221
function js_pluginstrings() {
222
    global $conf, $config_cascade;
223
    $pluginstrings = array();
224
    $plugins = plugin_list();
225
    foreach($plugins as $p) {
226
        $path = DOKU_PLUGIN . $p . '/lang/';
227
228
        if(isset($lang)) unset($lang);
229
        if(file_exists($path . "en/lang.php")) {
230
            include $path . "en/lang.php";
231
        }
232
        foreach($config_cascade['lang']['plugin'] as $config_file) {
233
            if(file_exists($config_file . $p . '/en/lang.php')) {
234
                include($config_file . $p . '/en/lang.php');
235
            }
236
        }
237
        if(isset($conf['lang']) && $conf['lang'] != 'en') {
238
            if(file_exists($path . $conf['lang'] . "/lang.php")) {
239
                include($path . $conf['lang'] . '/lang.php');
240
            }
241
            foreach($config_cascade['lang']['plugin'] as $config_file) {
242
                if(file_exists($config_file . $p . '/' . $conf['lang'] . '/lang.php')) {
243
                    include($config_file . $p . '/' . $conf['lang'] . '/lang.php');
244
                }
245
            }
246
        }
247
248
        if(isset($lang['js'])) {
249
            $pluginstrings[$p] = $lang['js'];
250
        }
251
    }
252
    return $pluginstrings;
253
}
254
255
/**
256
 * Return an two-dimensional array with strings from the language file of current active template.
257
 *
258
 * - $lang['js'] must be an array.
259
 * - Nothing is returned for template without an entry for $lang['js']
260
 *
261
 * @param string $tpl
262
 * @return array
263
 */
264
function js_templatestrings($tpl) {
265
    global $conf, $config_cascade;
266
267
    $path = tpl_incdir() . 'lang/';
268
269
    $templatestrings = array();
270
    if(file_exists($path . "en/lang.php")) {
271
        include $path . "en/lang.php";
272
    }
273
    foreach($config_cascade['lang']['template'] as $config_file) {
274
        if(file_exists($config_file . $conf['template'] . '/en/lang.php')) {
275
            include($config_file . $conf['template'] . '/en/lang.php');
276
        }
277
    }
278
    if(isset($conf['lang']) && $conf['lang'] != 'en' && file_exists($path . $conf['lang'] . "/lang.php")) {
279
        include $path . $conf['lang'] . "/lang.php";
280
    }
281
    if(isset($conf['lang']) && $conf['lang'] != 'en') {
282
        if(file_exists($path . $conf['lang'] . "/lang.php")) {
283
            include $path . $conf['lang'] . "/lang.php";
284
        }
285
        foreach($config_cascade['lang']['template'] as $config_file) {
286
            if(file_exists($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php')) {
287
                include($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php');
288
            }
289
        }
290
    }
291
292
    if(isset($lang['js'])) {
0 ignored issues
show
Bug introduced by
The variable $lang seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
293
        $templatestrings[$tpl] = $lang['js'];
294
    }
295
    return $templatestrings;
296
}
297
298
/**
299
 * Escapes a String to be embedded in a JavaScript call, keeps \n
300
 * as newline
301
 *
302
 * @author Andreas Gohr <[email protected]>
303
 *
304
 * @param string $string
305
 * @return string
306
 */
307
function js_escape($string){
308
    return str_replace('\\\\n','\\n',addslashes($string));
309
}
310
311
/**
312
 * Adds the given JavaScript code to the window.onload() event
313
 *
314
 * @author Andreas Gohr <[email protected]>
315
 *
316
 * @param string $func
317
 */
318
function js_runonstart($func){
319
    echo "jQuery(function(){ $func; });".NL;
320
}
321
322
/**
323
 * Strip comments and whitespaces from given JavaScript Code
324
 *
325
 * This is a port of Nick Galbreath's python tool jsstrip.py which is
326
 * released under BSD license. See link for original code.
327
 *
328
 * @author Nick Galbreath <[email protected]>
329
 * @author Andreas Gohr <[email protected]>
330
 * @link   http://code.google.com/p/jsstrip/
331
 *
332
 * @param string $s
333
 * @return string
334
 */
335
function js_compress($s){
336
    $s = ltrim($s);     // strip all initial whitespace
337
    $s .= "\n";
338
    $i = 0;             // char index for input string
339
    $j = 0;             // char forward index for input string
0 ignored issues
show
Unused Code introduced by
$j is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
340
    $line = 0;          // line number of file (close to it anyways)
0 ignored issues
show
Unused Code introduced by
$line is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
341
    $slen = strlen($s); // size of input string
342
    $lch  = '';         // last char added
0 ignored issues
show
Unused Code introduced by
$lch is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
343
    $result = '';       // we store the final result here
344
345
    // items that don't need spaces next to them
346
    $chars = "^&|!+\-*\/%=\?:;,{}()<>% \t\n\r'\"[]";
347
348
    // items which need a space if the sign before and after whitespace is equal.
349
    // E.g. '+ ++' may not be compressed to '+++' --> syntax error.
350
    $ops = "+-";
351
352
    $regex_starters = array("(", "=", "[", "," , ":", "!", "&", "|");
353
354
    $whitespaces_chars = array(" ", "\t", "\n", "\r", "\0", "\x0B");
355
356
    while($i < $slen){
357
        // skip all "boring" characters.  This is either
358
        // reserved word (e.g. "for", "else", "if") or a
359
        // variable/object/method (e.g. "foo.color")
360
        while ($i < $slen && (strpos($chars,$s[$i]) === false) ){
361
            $result .= $s{$i};
362
            $i = $i + 1;
363
        }
364
365
        $ch = $s{$i};
366
        // multiline comments (keeping IE conditionals)
367
        if($ch == '/' && $s{$i+1} == '*' && $s{$i+2} != '@'){
368
            $endC = strpos($s,'*/',$i+2);
369
            if($endC === false) trigger_error('Found invalid /*..*/ comment', E_USER_ERROR);
370
371
            // check if this is a NOCOMPRESS comment
372
            if(substr($s, $i, $endC+2-$i) == '/* BEGIN NOCOMPRESS */'){
373
                $endNC = strpos($s, '/* END NOCOMPRESS */', $endC+2);
374
                if($endNC === false) trigger_error('Found invalid NOCOMPRESS comment', E_USER_ERROR);
375
376
                // verbatim copy contents, trimming but putting it on its own line
377
                $result .= "\n".trim(substr($s, $i + 22, $endNC - ($i + 22)))."\n"; // BEGIN comment = 22 chars
378
                $i = $endNC + 20; // END comment = 20 chars
379
            }else{
380
                $i = $endC + 2;
381
            }
382
            continue;
383
        }
384
385
        // singleline
386
        if($ch == '/' && $s{$i+1} == '/'){
387
            $endC = strpos($s,"\n",$i+2);
388
            if($endC === false) trigger_error('Invalid comment', E_USER_ERROR);
389
            $i = $endC;
390
            continue;
391
        }
392
393
        // tricky.  might be an RE
394
        if($ch == '/'){
395
            // rewind, skip white space
396
            $j = 1;
397
            while(in_array($s{$i-$j}, $whitespaces_chars)){
398
                $j = $j + 1;
399
            }
400
            if( in_array($s{$i-$j}, $regex_starters) ){
401
                // yes, this is an re
402
                // now move forward and find the end of it
403
                $j = 1;
404
                while($s{$i+$j} != '/'){
405
                    if($s{$i+$j} == '\\') $j = $j + 2;
406
                    else $j++;
407
                }
408
                $result .= substr($s,$i,$j+1);
409
                $i = $i + $j + 1;
410
                continue;
411
            }
412
        }
413
414
        // double quote strings
415
        if($ch == '"'){
416
            $j = 1;
417
            while( $s{$i+$j} != '"' && ($i+$j < $slen)){
418
                if( $s{$i+$j} == '\\' && ($s{$i+$j+1} == '"' || $s{$i+$j+1} == '\\') ){
419
                    $j += 2;
420
                }else{
421
                    $j += 1;
422
                }
423
            }
424
            $string  = substr($s,$i,$j+1);
425
            // remove multiline markers:
426
            $string  = str_replace("\\\n",'',$string);
427
            $result .= $string;
428
            $i = $i + $j + 1;
429
            continue;
430
        }
431
432
        // single quote strings
433
        if($ch == "'"){
434
            $j = 1;
435
            while( $s{$i+$j} != "'" && ($i+$j < $slen)){
436
                if( $s{$i+$j} == '\\' && ($s{$i+$j+1} == "'" || $s{$i+$j+1} == '\\') ){
437
                    $j += 2;
438
                }else{
439
                    $j += 1;
440
                }
441
            }
442
            $string = substr($s,$i,$j+1);
443
            // remove multiline markers:
444
            $string  = str_replace("\\\n",'',$string);
445
            $result .= $string;
446
            $i = $i + $j + 1;
447
            continue;
448
        }
449
450
        // whitespaces
451
        if( $ch == ' ' || $ch == "\r" || $ch == "\n" || $ch == "\t" ){
452
            $lch = substr($result,-1);
453
454
            // Only consider deleting whitespace if the signs before and after
455
            // are not equal and are not an operator which may not follow itself.
456
            if ($i+1 < $slen && ((!$lch || $s[$i+1] == ' ')
457
                || $lch != $s[$i+1]
458
                || strpos($ops,$s[$i+1]) === false)) {
459
                // leading spaces
460
                if($i+1 < $slen && (strpos($chars,$s[$i+1]) !== false)){
461
                    $i = $i + 1;
462
                    continue;
463
                }
464
                // trailing spaces
465
                //  if this ch is space AND the last char processed
466
                //  is special, then skip the space
467
                if($lch && (strpos($chars,$lch) !== false)){
468
                    $i = $i + 1;
469
                    continue;
470
                }
471
            }
472
473
            // else after all of this convert the "whitespace" to
474
            // a single space.  It will get appended below
475
            $ch = ' ';
476
        }
477
478
        // other chars
479
        $result .= $ch;
480
        $i = $i + 1;
481
    }
482
483
    return trim($result);
484
}
485
486
//Setup VIM: ex: et ts=4 :
487