1*78a6aeb1SAndreas Gohr<?php 2*78a6aeb1SAndreas Gohr/** 3*78a6aeb1SAndreas Gohr * DokuWiki JavaScript creator 4*78a6aeb1SAndreas Gohr * 5*78a6aeb1SAndreas Gohr * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6*78a6aeb1SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 7*78a6aeb1SAndreas Gohr */ 8*78a6aeb1SAndreas Gohr 9*78a6aeb1SAndreas Gohrif(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); 10*78a6aeb1SAndreas Gohrdefine('NOSESSION',true); // we do not use a session or authentication here (better caching) 11*78a6aeb1SAndreas Gohrrequire_once(DOKU_INC.'inc/init.php'); 12*78a6aeb1SAndreas Gohrrequire_once(DOKU_INC.'inc/pageutils.php'); 13*78a6aeb1SAndreas Gohrrequire_once(DOKU_INC.'inc/io.php'); 14*78a6aeb1SAndreas Gohr 15*78a6aeb1SAndreas Gohr// Main (don't run when UNIT test) 16*78a6aeb1SAndreas Gohrif(!defined('SIMPLE_TEST')){ 17*78a6aeb1SAndreas Gohr header('Content-Type: text/javascript; charset=utf-8'); 18*78a6aeb1SAndreas Gohr js_out(); 19*78a6aeb1SAndreas Gohr js_dynamicout(); 20*78a6aeb1SAndreas Gohr} 21*78a6aeb1SAndreas Gohr 22*78a6aeb1SAndreas Gohr 23*78a6aeb1SAndreas Gohr// ---------------------- functions ------------------------------ 24*78a6aeb1SAndreas Gohr 25*78a6aeb1SAndreas Gohr/** 26*78a6aeb1SAndreas Gohr * Output all needed JavaScript 27*78a6aeb1SAndreas Gohr * 28*78a6aeb1SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 29*78a6aeb1SAndreas Gohr */ 30*78a6aeb1SAndreas Gohrfunction js_out(){ 31*78a6aeb1SAndreas Gohr global $conf; 32*78a6aeb1SAndreas Gohr global $lang; 33*78a6aeb1SAndreas Gohr $edit = (bool) $_REQUEST['edit']; // edit or preview mode? 34*78a6aeb1SAndreas Gohr $write = (bool) $_REQUEST['write']; // writable? 35*78a6aeb1SAndreas Gohr 36*78a6aeb1SAndreas Gohr // The generated script depends on some dynamic options 37*78a6aeb1SAndreas Gohr $cache = getCacheName('scripts'.$edit.$write,'.js'); 38*78a6aeb1SAndreas Gohr 39*78a6aeb1SAndreas Gohr // Array of needed files 40*78a6aeb1SAndreas Gohr $files = array( 41*78a6aeb1SAndreas Gohr DOKU_INC.'lib/scripts/events.js', 42*78a6aeb1SAndreas Gohr DOKU_INC.'lib/scripts/script.js', 43*78a6aeb1SAndreas Gohr DOKU_INC.'lib/scripts/tw-sack.js', 44*78a6aeb1SAndreas Gohr DOKU_INC.'lib/scripts/ajax.js', 45*78a6aeb1SAndreas Gohr DOKU_INC.'lib/scripts/domLib.js', 46*78a6aeb1SAndreas Gohr DOKU_INC.'lib/scripts/domTT.js', 47*78a6aeb1SAndreas Gohr ); 48*78a6aeb1SAndreas Gohr if($edit && $write){ 49*78a6aeb1SAndreas Gohr $files[] = DOKU_INC.'lib/scripts/edit.js'; 50*78a6aeb1SAndreas Gohr if($conf['spellchecker']){ 51*78a6aeb1SAndreas Gohr $files[] = DOKU_INC.'lib/scripts/spellcheck.js'; 52*78a6aeb1SAndreas Gohr } 53*78a6aeb1SAndreas Gohr } 54*78a6aeb1SAndreas Gohr 55*78a6aeb1SAndreas Gohr // get possible plugin scripts 56*78a6aeb1SAndreas Gohr $plugins = js_pluginscripts(); 57*78a6aeb1SAndreas Gohr 58*78a6aeb1SAndreas Gohr // check cache age here 59*78a6aeb1SAndreas Gohr if(js_cacheok($cache,array_merge($files,$plugins))){ 60*78a6aeb1SAndreas Gohr readfile($cache); 61*78a6aeb1SAndreas Gohr return; 62*78a6aeb1SAndreas Gohr } 63*78a6aeb1SAndreas Gohr 64*78a6aeb1SAndreas Gohr // start output buffering and build the script 65*78a6aeb1SAndreas Gohr ob_start(); 66*78a6aeb1SAndreas Gohr 67*78a6aeb1SAndreas Gohr // add some translation strings and global variables 68*78a6aeb1SAndreas Gohr print "var alertText = '".str_replace('\\\\n','\\n',addslashes($lang['qb_alert']))."';"; 69*78a6aeb1SAndreas Gohr print "var notSavedYet = '".str_replace('\\\\n','\\n',addslashes($lang['notsavedyet']))."';"; 70*78a6aeb1SAndreas Gohr print "var DOKU_BASE = '".DOKU_BASE."';"; 71*78a6aeb1SAndreas Gohr 72*78a6aeb1SAndreas Gohr // load files 73*78a6aeb1SAndreas Gohr foreach($files as $file){ 74*78a6aeb1SAndreas Gohr readfile($file); 75*78a6aeb1SAndreas Gohr } 76*78a6aeb1SAndreas Gohr 77*78a6aeb1SAndreas Gohr // init stuff 78*78a6aeb1SAndreas Gohr js_runonstart("ajax_qsearch.init('qsearch_in','qsearch_out')"); 79*78a6aeb1SAndreas Gohr js_runonstart("addEvent(document,'click',closePopups)"); 80*78a6aeb1SAndreas Gohr 81*78a6aeb1SAndreas Gohr if($edit){ 82*78a6aeb1SAndreas Gohr // size controls 83*78a6aeb1SAndreas Gohr js_runonstart("initSizeCtl('sizectl','wikitext')"); 84*78a6aeb1SAndreas Gohr 85*78a6aeb1SAndreas Gohr if($write){ 86*78a6aeb1SAndreas Gohr require_once(DOKU_INC.'inc/toolbar.php'); 87*78a6aeb1SAndreas Gohr toolbar_JSdefines('toolbar'); 88*78a6aeb1SAndreas Gohr js_runonstart("initToolbar('toolbar','wikitext',toolbar)"); 89*78a6aeb1SAndreas Gohr 90*78a6aeb1SAndreas Gohr // add pageleave check 91*78a6aeb1SAndreas Gohr js_runonstart("initChangeCheck('".js_escape($lang['notsavedyet'])."')"); 92*78a6aeb1SAndreas Gohr 93*78a6aeb1SAndreas Gohr // add lock timer 94*78a6aeb1SAndreas Gohr js_runonstart("init_locktimer(".($conf['locktime']-60).",'".js_escape($lang['willexpire'])."')"); 95*78a6aeb1SAndreas Gohr 96*78a6aeb1SAndreas Gohr // load spell checker 97*78a6aeb1SAndreas Gohr if($conf['spellchecker']){ 98*78a6aeb1SAndreas Gohr js_runonstart("ajax_spell.init('". 99*78a6aeb1SAndreas Gohr js_escape($lang['spell_start'])."','". 100*78a6aeb1SAndreas Gohr js_escape($lang['spell_stop'])."','". 101*78a6aeb1SAndreas Gohr js_escape($lang['spell_wait'])."','". 102*78a6aeb1SAndreas Gohr js_escape($lang['spell_noerr'])."','". 103*78a6aeb1SAndreas Gohr js_escape($lang['spell_nosug'])."','". 104*78a6aeb1SAndreas Gohr js_escape($lang['spell_change'])."')"); 105*78a6aeb1SAndreas Gohr } 106*78a6aeb1SAndreas Gohr } 107*78a6aeb1SAndreas Gohr } 108*78a6aeb1SAndreas Gohr 109*78a6aeb1SAndreas Gohr // load plugin scripts (suppress warnings for missing ones) 110*78a6aeb1SAndreas Gohr foreach($plugins as $plugin){ 111*78a6aeb1SAndreas Gohr @readfile($plugin); 112*78a6aeb1SAndreas Gohr } 113*78a6aeb1SAndreas Gohr 114*78a6aeb1SAndreas Gohr // load user script 115*78a6aeb1SAndreas Gohr @readfile(DOKU_CONF.'userscript.js'); 116*78a6aeb1SAndreas Gohr 117*78a6aeb1SAndreas Gohr // end output buffering and get contents 118*78a6aeb1SAndreas Gohr $js = ob_get_contents(); 119*78a6aeb1SAndreas Gohr ob_end_clean(); 120*78a6aeb1SAndreas Gohr 121*78a6aeb1SAndreas Gohr // compress whitespace and comments 122*78a6aeb1SAndreas Gohr if($conf['compress']){ 123*78a6aeb1SAndreas Gohr $js = js_compress($js); 124*78a6aeb1SAndreas Gohr } 125*78a6aeb1SAndreas Gohr 126*78a6aeb1SAndreas Gohr // save cache file 127*78a6aeb1SAndreas Gohr io_saveFile($cache,$js); 128*78a6aeb1SAndreas Gohr 129*78a6aeb1SAndreas Gohr // finally send output 130*78a6aeb1SAndreas Gohr print $js; 131*78a6aeb1SAndreas Gohr} 132*78a6aeb1SAndreas Gohr 133*78a6aeb1SAndreas Gohr/** 134*78a6aeb1SAndreas Gohr * Adds some dynamic JavaScript using the readonly Session 135*78a6aeb1SAndreas Gohr * 136*78a6aeb1SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 137*78a6aeb1SAndreas Gohr */ 138*78a6aeb1SAndreas Gohrfunction js_dynamicout(){ 139*78a6aeb1SAndreas Gohr $edit = (bool) $_REQUEST['edit']; // edit or preview mode? 140*78a6aeb1SAndreas Gohr $write = (bool) $_REQUEST['write']; // writable? 141*78a6aeb1SAndreas Gohr $sig = (bool) $_REQUEST['sig']; // show sig button? 142*78a6aeb1SAndreas Gohr if($edit && $write && $sig){ 143*78a6aeb1SAndreas Gohr require_once(DOKU_INC.'inc/toolbar.php'); 144*78a6aeb1SAndreas Gohr toolbar_addsigbutton('toolbar'); 145*78a6aeb1SAndreas Gohr } 146*78a6aeb1SAndreas Gohr} 147*78a6aeb1SAndreas Gohr 148*78a6aeb1SAndreas Gohr/** 149*78a6aeb1SAndreas Gohr * Checks if a JavaScript Cache file still is valid 150*78a6aeb1SAndreas Gohr * 151*78a6aeb1SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 152*78a6aeb1SAndreas Gohr */ 153*78a6aeb1SAndreas Gohrfunction js_cacheok($cache,$files){ 154*78a6aeb1SAndreas Gohr $ctime = @filemtime($cache); 155*78a6aeb1SAndreas Gohr if(!$ctime) return false; //There is no cache 156*78a6aeb1SAndreas Gohr 157*78a6aeb1SAndreas Gohr // some additional files to check 158*78a6aeb1SAndreas Gohr $files[] = DOKU_CONF.'dokuwiki.conf'; 159*78a6aeb1SAndreas Gohr $files[] = DOKU_CONF.'local.conf'; 160*78a6aeb1SAndreas Gohr $files[] = DOKU_CONF.'userscript.js'; 161*78a6aeb1SAndreas Gohr $files[] = __FILE__; 162*78a6aeb1SAndreas Gohr 163*78a6aeb1SAndreas Gohr // now walk the files 164*78a6aeb1SAndreas Gohr foreach($files as $file){ 165*78a6aeb1SAndreas Gohr if(@filemtime($file) > $ctime){ 166*78a6aeb1SAndreas Gohr return false; 167*78a6aeb1SAndreas Gohr } 168*78a6aeb1SAndreas Gohr } 169*78a6aeb1SAndreas Gohr return true; 170*78a6aeb1SAndreas Gohr} 171*78a6aeb1SAndreas Gohr 172*78a6aeb1SAndreas Gohr/** 173*78a6aeb1SAndreas Gohr * Returns a list of possible Plugin Scripts (no existance check here) 174*78a6aeb1SAndreas Gohr * 175*78a6aeb1SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 176*78a6aeb1SAndreas Gohr */ 177*78a6aeb1SAndreas Gohrfunction js_pluginscripts(){ 178*78a6aeb1SAndreas Gohr $list = array(); 179*78a6aeb1SAndreas Gohr $plugins = plugin_list(); 180*78a6aeb1SAndreas Gohr foreach ($plugins as $p){ 181*78a6aeb1SAndreas Gohr $list[] = DOKU_PLUGIN."$p/script.js"; 182*78a6aeb1SAndreas Gohr } 183*78a6aeb1SAndreas Gohr return $list; 184*78a6aeb1SAndreas Gohr} 185*78a6aeb1SAndreas Gohr 186*78a6aeb1SAndreas Gohr/** 187*78a6aeb1SAndreas Gohr * Escapes a String to be embedded in a JavaScript call, keeps \n 188*78a6aeb1SAndreas Gohr * as newline 189*78a6aeb1SAndreas Gohr * 190*78a6aeb1SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 191*78a6aeb1SAndreas Gohr */ 192*78a6aeb1SAndreas Gohrfunction js_escape($string){ 193*78a6aeb1SAndreas Gohr return str_replace('\\\\n','\\n',addslashes($string)); 194*78a6aeb1SAndreas Gohr} 195*78a6aeb1SAndreas Gohr 196*78a6aeb1SAndreas Gohr/** 197*78a6aeb1SAndreas Gohr * Adds the given JavaScript code to the window.onload() event 198*78a6aeb1SAndreas Gohr * 199*78a6aeb1SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 200*78a6aeb1SAndreas Gohr */ 201*78a6aeb1SAndreas Gohrfunction js_runonstart($func){ 202*78a6aeb1SAndreas Gohr print "addEvent(window,'load',function(){ $func; });"; 203*78a6aeb1SAndreas Gohr} 204*78a6aeb1SAndreas Gohr 205*78a6aeb1SAndreas Gohr/** 206*78a6aeb1SAndreas Gohr * Strip comments and whitespaces from given JavaScript Code 207*78a6aeb1SAndreas Gohr * 208*78a6aeb1SAndreas Gohr * This is a rewrite of Nick Galbreaths python tool jsstrip.py which is 209*78a6aeb1SAndreas Gohr * released under BSD license. See link for original code. 210*78a6aeb1SAndreas Gohr * 211*78a6aeb1SAndreas Gohr * @author Nick Galbreath <nickg@modp.com> 212*78a6aeb1SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 213*78a6aeb1SAndreas Gohr * @link http://modp.com/release/jsstrip/ 214*78a6aeb1SAndreas Gohr */ 215*78a6aeb1SAndreas Gohrfunction js_compress($s){ 216*78a6aeb1SAndreas Gohr $i = 0; 217*78a6aeb1SAndreas Gohr $line = 0; 218*78a6aeb1SAndreas Gohr $s .= "\n"; 219*78a6aeb1SAndreas Gohr $len = strlen($s); 220*78a6aeb1SAndreas Gohr 221*78a6aeb1SAndreas Gohr // items that don't need spaces next to them 222*78a6aeb1SAndreas Gohr $chars = '^&|!+\-*\/%=:;,{}()<>% \t\n\r'; 223*78a6aeb1SAndreas Gohr 224*78a6aeb1SAndreas Gohr ob_start(); 225*78a6aeb1SAndreas Gohr while($i < $len){ 226*78a6aeb1SAndreas Gohr $ch = $s{$i}; 227*78a6aeb1SAndreas Gohr 228*78a6aeb1SAndreas Gohr // multiline comments 229*78a6aeb1SAndreas Gohr if($ch == '/' && $s{$i+1} == '*'){ 230*78a6aeb1SAndreas Gohr $endC = strpos($s,'*/',$i+2); 231*78a6aeb1SAndreas Gohr if($endC === false) trigger_error('Found invalid /*..*/ comment', E_USER_ERROR); 232*78a6aeb1SAndreas Gohr $i = $endC + 2; 233*78a6aeb1SAndreas Gohr continue; 234*78a6aeb1SAndreas Gohr } 235*78a6aeb1SAndreas Gohr 236*78a6aeb1SAndreas Gohr // singleline 237*78a6aeb1SAndreas Gohr if($ch == '/' && $s{$i+1} == '/'){ 238*78a6aeb1SAndreas Gohr $endC = strpos($s,"\n",$i+2); 239*78a6aeb1SAndreas Gohr if($endC === false) trigger_error('Invalid comment', E_USER_ERROR); 240*78a6aeb1SAndreas Gohr $i = $endC; 241*78a6aeb1SAndreas Gohr continue; 242*78a6aeb1SAndreas Gohr } 243*78a6aeb1SAndreas Gohr 244*78a6aeb1SAndreas Gohr // tricky. might be an RE 245*78a6aeb1SAndreas Gohr if($ch == '/'){ 246*78a6aeb1SAndreas Gohr // rewind, skip white space 247*78a6aeb1SAndreas Gohr $j = 1; 248*78a6aeb1SAndreas Gohr while($s{$i-$j} == ' '){ 249*78a6aeb1SAndreas Gohr $j = $j + 1; 250*78a6aeb1SAndreas Gohr } 251*78a6aeb1SAndreas Gohr if( ($s{$i-$j} == '=') || ($s{$i-$j} == '(') ){ 252*78a6aeb1SAndreas Gohr // yes, this is an re 253*78a6aeb1SAndreas Gohr // now move forward and find the end of it 254*78a6aeb1SAndreas Gohr $j = 1; 255*78a6aeb1SAndreas Gohr while($s{$i+$j} != '/'){ 256*78a6aeb1SAndreas Gohr while( ($s{$i+$j} != '\\') && ($s{$i+$j} != '/')){ 257*78a6aeb1SAndreas Gohr $j = $j + 1; 258*78a6aeb1SAndreas Gohr } 259*78a6aeb1SAndreas Gohr if($s{$i+$j} == '\\') $j = $j + 2; 260*78a6aeb1SAndreas Gohr } 261*78a6aeb1SAndreas Gohr echo substr($s,$i,$j+1); 262*78a6aeb1SAndreas Gohr $i = $i + $j + 1; 263*78a6aeb1SAndreas Gohr continue; 264*78a6aeb1SAndreas Gohr } 265*78a6aeb1SAndreas Gohr } 266*78a6aeb1SAndreas Gohr 267*78a6aeb1SAndreas Gohr // double quote strings 268*78a6aeb1SAndreas Gohr if($ch == '"'){ 269*78a6aeb1SAndreas Gohr $j = 1; 270*78a6aeb1SAndreas Gohr while( $s{$i+$j} != '"' ){ 271*78a6aeb1SAndreas Gohr while( ($s{$i+$j} != '\\') && ($s{$i+$j} != '"') ){ 272*78a6aeb1SAndreas Gohr $j = $j + 1; 273*78a6aeb1SAndreas Gohr } 274*78a6aeb1SAndreas Gohr if($s{$i+$j} == '\\') $j = $j + 2; 275*78a6aeb1SAndreas Gohr } 276*78a6aeb1SAndreas Gohr echo substr($s,$i,$j+1); 277*78a6aeb1SAndreas Gohr $i = $i + $j + 1; 278*78a6aeb1SAndreas Gohr continue; 279*78a6aeb1SAndreas Gohr } 280*78a6aeb1SAndreas Gohr 281*78a6aeb1SAndreas Gohr // single quote strings 282*78a6aeb1SAndreas Gohr if($ch == "'"){ 283*78a6aeb1SAndreas Gohr $j = 1; 284*78a6aeb1SAndreas Gohr while( $s{$i+$j} != "'" ){ 285*78a6aeb1SAndreas Gohr while( ($s{$i+$j} != '\\') && ($s{$i+$j} != "'") ){ 286*78a6aeb1SAndreas Gohr $j = $j + 1; 287*78a6aeb1SAndreas Gohr } 288*78a6aeb1SAndreas Gohr if ($s{$i+$j} == '\\') $j = $j + 2; 289*78a6aeb1SAndreas Gohr } 290*78a6aeb1SAndreas Gohr echo substr($s,$i,$j+1); 291*78a6aeb1SAndreas Gohr $i = $i + $j + 1; 292*78a6aeb1SAndreas Gohr continue; 293*78a6aeb1SAndreas Gohr } 294*78a6aeb1SAndreas Gohr 295*78a6aeb1SAndreas Gohr // newlines 296*78a6aeb1SAndreas Gohr if($ch == "\n" || $ch == "\r"){ 297*78a6aeb1SAndreas Gohr $i = $i+1; 298*78a6aeb1SAndreas Gohr continue; 299*78a6aeb1SAndreas Gohr } 300*78a6aeb1SAndreas Gohr 301*78a6aeb1SAndreas Gohr // leading spaces 302*78a6aeb1SAndreas Gohr if( ( $ch == ' ' || 303*78a6aeb1SAndreas Gohr $ch == "\n" || 304*78a6aeb1SAndreas Gohr $ch == "\t" ) && 305*78a6aeb1SAndreas Gohr !preg_match('/['.$chars.']/',$s{$i+1}) ){ 306*78a6aeb1SAndreas Gohr $i = $i+1; 307*78a6aeb1SAndreas Gohr continue; 308*78a6aeb1SAndreas Gohr } 309*78a6aeb1SAndreas Gohr 310*78a6aeb1SAndreas Gohr // trailing spaces 311*78a6aeb1SAndreas Gohr if( ( $ch == ' ' || 312*78a6aeb1SAndreas Gohr $ch == "\n" || 313*78a6aeb1SAndreas Gohr $ch == "\t" ) && 314*78a6aeb1SAndreas Gohr !preg_match('/['.$chars.']/',$s{$i-1}) ){ 315*78a6aeb1SAndreas Gohr $i = $i+1; 316*78a6aeb1SAndreas Gohr continue; 317*78a6aeb1SAndreas Gohr } 318*78a6aeb1SAndreas Gohr 319*78a6aeb1SAndreas Gohr // other chars 320*78a6aeb1SAndreas Gohr echo $ch; 321*78a6aeb1SAndreas Gohr $i = $i + 1; 322*78a6aeb1SAndreas Gohr } 323*78a6aeb1SAndreas Gohr 324*78a6aeb1SAndreas Gohr 325*78a6aeb1SAndreas Gohr $out = ob_get_contents(); 326*78a6aeb1SAndreas Gohr ob_end_clean(); 327*78a6aeb1SAndreas Gohr return $out; 328*78a6aeb1SAndreas Gohr} 329*78a6aeb1SAndreas Gohr 330*78a6aeb1SAndreas Gohr//Setup VIM: ex: et ts=4 enc=utf-8 : 331*78a6aeb1SAndreas Gohr?> 332