PageRenderTime 35ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/exe/js.php

https://gitlab.com/michield/dokuwiki
PHP | 378 lines | 267 code | 35 blank | 76 comment | 38 complexity | 0da4571ea68da911937667ac1d195d8f MD5 | raw file
  1. <?php
  2. /**
  3. * DokuWiki JavaScript creator
  4. *
  5. * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
  6. * @author Andreas Gohr <andi@splitbrain.org>
  7. */
  8. if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../');
  9. if(!defined('NOSESSION')) define('NOSESSION',true); // we do not use a session or authentication here (better caching)
  10. if(!defined('NL')) define('NL',"\n");
  11. if(!defined('DOKU_DISABLE_GZIP_OUTPUT')) define('DOKU_DISABLE_GZIP_OUTPUT',1); // we gzip ourself here
  12. require_once(DOKU_INC.'inc/init.php');
  13. // Main (don't run when UNIT test)
  14. if(!defined('SIMPLE_TEST')){
  15. header('Content-Type: text/javascript; charset=utf-8');
  16. js_out();
  17. }
  18. // ---------------------- functions ------------------------------
  19. /**
  20. * Output all needed JavaScript
  21. *
  22. * @author Andreas Gohr <andi@splitbrain.org>
  23. */
  24. function js_out(){
  25. global $conf;
  26. global $lang;
  27. global $config_cascade;
  28. // The generated script depends on some dynamic options
  29. $cache = new cache('scripts'.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'],'.js');
  30. $cache->_event = 'JS_CACHE_USE';
  31. // load minified version for some files
  32. $min = $conf['compress'] ? '.min' : '';
  33. // array of core files
  34. $files = array(
  35. DOKU_INC."lib/scripts/jquery/jquery$min.js",
  36. DOKU_INC.'lib/scripts/jquery/jquery.cookie.js',
  37. DOKU_INC."lib/scripts/jquery/jquery-ui$min.js",
  38. DOKU_INC."lib/scripts/jquery/jquery-migrate$min.js",
  39. DOKU_INC."lib/scripts/fileuploader.js",
  40. DOKU_INC."lib/scripts/fileuploaderextended.js",
  41. DOKU_INC.'lib/scripts/helpers.js',
  42. DOKU_INC.'lib/scripts/delay.js',
  43. DOKU_INC.'lib/scripts/cookie.js',
  44. DOKU_INC.'lib/scripts/script.js',
  45. DOKU_INC.'lib/scripts/tw-sack.js',
  46. DOKU_INC.'lib/scripts/qsearch.js',
  47. DOKU_INC.'lib/scripts/tree.js',
  48. DOKU_INC.'lib/scripts/index.js',
  49. DOKU_INC.'lib/scripts/drag.js',
  50. DOKU_INC.'lib/scripts/textselection.js',
  51. DOKU_INC.'lib/scripts/toolbar.js',
  52. DOKU_INC.'lib/scripts/edit.js',
  53. DOKU_INC.'lib/scripts/editor.js',
  54. DOKU_INC.'lib/scripts/locktimer.js',
  55. DOKU_INC.'lib/scripts/linkwiz.js',
  56. DOKU_INC.'lib/scripts/media.js',
  57. # deprecated DOKU_INC.'lib/scripts/compatibility.js',
  58. # disabled for FS#1958 DOKU_INC.'lib/scripts/hotkeys.js',
  59. DOKU_INC.'lib/scripts/behaviour.js',
  60. DOKU_INC.'lib/scripts/page.js',
  61. tpl_incdir().'script.js',
  62. );
  63. // add possible plugin scripts and userscript
  64. $files = array_merge($files,js_pluginscripts());
  65. if(isset($config_cascade['userscript']['default'])){
  66. $files[] = $config_cascade['userscript']['default'];
  67. }
  68. $cache_files = array_merge($files, getConfigFiles('main'));
  69. $cache_files[] = __FILE__;
  70. // check cache age & handle conditional request
  71. // This may exit if a cache can be used
  72. $cache_ok = $cache->useCache(array('files' => $cache_files));
  73. http_cached($cache->cache, $cache_ok);
  74. // start output buffering and build the script
  75. ob_start();
  76. // add some global variables
  77. print "var DOKU_BASE = '".DOKU_BASE."';";
  78. print "var DOKU_TPL = '".tpl_basedir()."';";
  79. // FIXME: Move those to JSINFO
  80. print "var DOKU_UHN = ".((int) useHeading('navigation')).";";
  81. print "var DOKU_UHC = ".((int) useHeading('content')).";";
  82. // load JS specific translations
  83. $json = new JSON();
  84. $lang['js']['plugins'] = js_pluginstrings();
  85. echo 'LANG = '.$json->encode($lang['js']).";\n";
  86. // load toolbar
  87. toolbar_JSdefines('toolbar');
  88. // load files
  89. foreach($files as $file){
  90. $ismin = (substr($file,-7) == '.min.js');
  91. echo "\n\n/* XXXXXXXXXX begin of ".str_replace(DOKU_INC, '', $file) ." XXXXXXXXXX */\n\n";
  92. if($ismin) echo "\n/* BEGIN NOCOMPRESS */\n";
  93. js_load($file);
  94. if($ismin) echo "\n/* END NOCOMPRESS */\n";
  95. echo "\n\n/* XXXXXXXXXX end of " . str_replace(DOKU_INC, '', $file) . " XXXXXXXXXX */\n\n";
  96. }
  97. // init stuff
  98. if($conf['locktime'] != 0){
  99. js_runonstart("dw_locktimer.init(".($conf['locktime'] - 60).",".$conf['usedraft'].")");
  100. }
  101. // init hotkeys - must have been done after init of toolbar
  102. # disabled for FS#1958 js_runonstart('initializeHotkeys()');
  103. // end output buffering and get contents
  104. $js = ob_get_contents();
  105. ob_end_clean();
  106. // compress whitespace and comments
  107. if($conf['compress']){
  108. $js = js_compress($js);
  109. }
  110. $js .= "\n"; // https://bugzilla.mozilla.org/show_bug.cgi?id=316033
  111. http_cached_finish($cache->cache, $js);
  112. }
  113. /**
  114. * Load the given file, handle include calls and print it
  115. *
  116. * @author Andreas Gohr <andi@splitbrain.org>
  117. */
  118. function js_load($file){
  119. if(!@file_exists($file)) return;
  120. static $loaded = array();
  121. $data = io_readFile($file);
  122. while(preg_match('#/\*\s*DOKUWIKI:include(_once)?\s+([\w\.\-_/]+)\s*\*/#',$data,$match)){
  123. $ifile = $match[2];
  124. // is it a include_once?
  125. if($match[1]){
  126. $base = utf8_basename($ifile);
  127. if($loaded[$base]) continue;
  128. $loaded[$base] = true;
  129. }
  130. if($ifile{0} != '/') $ifile = dirname($file).'/'.$ifile;
  131. if(@file_exists($ifile)){
  132. $idata = io_readFile($ifile);
  133. }else{
  134. $idata = '';
  135. }
  136. $data = str_replace($match[0],$idata,$data);
  137. }
  138. echo "$data\n";
  139. }
  140. /**
  141. * Returns a list of possible Plugin Scripts (no existance check here)
  142. *
  143. * @author Andreas Gohr <andi@splitbrain.org>
  144. */
  145. function js_pluginscripts(){
  146. $list = array();
  147. $plugins = plugin_list();
  148. foreach ($plugins as $p){
  149. $list[] = DOKU_PLUGIN."$p/script.js";
  150. }
  151. return $list;
  152. }
  153. /**
  154. * Return an two-dimensional array with strings from the language file of each plugin.
  155. *
  156. * - $lang['js'] must be an array.
  157. * - Nothing is returned for plugins without an entry for $lang['js']
  158. *
  159. * @author Gabriel Birke <birke@d-scribe.de>
  160. */
  161. function js_pluginstrings()
  162. {
  163. global $conf;
  164. $pluginstrings = array();
  165. $plugins = plugin_list();
  166. foreach ($plugins as $p){
  167. if (isset($lang)) unset($lang);
  168. if (@file_exists(DOKU_PLUGIN."$p/lang/en/lang.php")) {
  169. include DOKU_PLUGIN."$p/lang/en/lang.php";
  170. }
  171. if (isset($conf['lang']) && $conf['lang']!='en' && @file_exists(DOKU_PLUGIN."$p/lang/".$conf['lang']."/lang.php")) {
  172. include DOKU_PLUGIN."$p/lang/".$conf['lang']."/lang.php";
  173. }
  174. if (isset($lang['js'])) {
  175. $pluginstrings[$p] = $lang['js'];
  176. }
  177. }
  178. return $pluginstrings;
  179. }
  180. /**
  181. * Escapes a String to be embedded in a JavaScript call, keeps \n
  182. * as newline
  183. *
  184. * @author Andreas Gohr <andi@splitbrain.org>
  185. */
  186. function js_escape($string){
  187. return str_replace('\\\\n','\\n',addslashes($string));
  188. }
  189. /**
  190. * Adds the given JavaScript code to the window.onload() event
  191. *
  192. * @author Andreas Gohr <andi@splitbrain.org>
  193. */
  194. function js_runonstart($func){
  195. echo "jQuery(function(){ $func; });".NL;
  196. }
  197. /**
  198. * Strip comments and whitespaces from given JavaScript Code
  199. *
  200. * This is a port of Nick Galbreath's python tool jsstrip.py which is
  201. * released under BSD license. See link for original code.
  202. *
  203. * @author Nick Galbreath <nickg@modp.com>
  204. * @author Andreas Gohr <andi@splitbrain.org>
  205. * @link http://code.google.com/p/jsstrip/
  206. */
  207. function js_compress($s){
  208. $s = ltrim($s); // strip all initial whitespace
  209. $s .= "\n";
  210. $i = 0; // char index for input string
  211. $j = 0; // char forward index for input string
  212. $line = 0; // line number of file (close to it anyways)
  213. $slen = strlen($s); // size of input string
  214. $lch = ''; // last char added
  215. $result = ''; // we store the final result here
  216. // items that don't need spaces next to them
  217. $chars = "^&|!+\-*\/%=\?:;,{}()<>% \t\n\r'\"[]";
  218. $regex_starters = array("(", "=", "[", "," , ":", "!");
  219. $whitespaces_chars = array(" ", "\t", "\n", "\r", "\0", "\x0B");
  220. while($i < $slen){
  221. // skip all "boring" characters. This is either
  222. // reserved word (e.g. "for", "else", "if") or a
  223. // variable/object/method (e.g. "foo.color")
  224. while ($i < $slen && (strpos($chars,$s[$i]) === false) ){
  225. $result .= $s{$i};
  226. $i = $i + 1;
  227. }
  228. $ch = $s{$i};
  229. // multiline comments (keeping IE conditionals)
  230. if($ch == '/' && $s{$i+1} == '*' && $s{$i+2} != '@'){
  231. $endC = strpos($s,'*/',$i+2);
  232. if($endC === false) trigger_error('Found invalid /*..*/ comment', E_USER_ERROR);
  233. // check if this is a NOCOMPRESS comment
  234. if(substr($s, $i, $endC+2-$i) == '/* BEGIN NOCOMPRESS */'){
  235. $endNC = strpos($s, '/* END NOCOMPRESS */', $endC+2);
  236. if($endNC === false) trigger_error('Found invalid NOCOMPRESS comment', E_USER_ERROR);
  237. // verbatim copy contents, trimming but putting it on its own line
  238. $result .= "\n".trim(substr($s, $i + 22, $endNC - ($i + 22)))."\n"; // BEGIN comment = 22 chars
  239. $i = $endNC + 20; // END comment = 20 chars
  240. }else{
  241. $i = $endC + 2;
  242. }
  243. continue;
  244. }
  245. // singleline
  246. if($ch == '/' && $s{$i+1} == '/'){
  247. $endC = strpos($s,"\n",$i+2);
  248. if($endC === false) trigger_error('Invalid comment', E_USER_ERROR);
  249. $i = $endC;
  250. continue;
  251. }
  252. // tricky. might be an RE
  253. if($ch == '/'){
  254. // rewind, skip white space
  255. $j = 1;
  256. while(in_array($s{$i-$j}, $whitespaces_chars)){
  257. $j = $j + 1;
  258. }
  259. if( in_array($s{$i-$j}, $regex_starters) ){
  260. // yes, this is an re
  261. // now move forward and find the end of it
  262. $j = 1;
  263. while($s{$i+$j} != '/'){
  264. if($s{$i+$j} == '\\') $j = $j + 2;
  265. else $j++;
  266. }
  267. $result .= substr($s,$i,$j+1);
  268. $i = $i + $j + 1;
  269. continue;
  270. }
  271. }
  272. // double quote strings
  273. if($ch == '"'){
  274. $j = 1;
  275. while( $s{$i+$j} != '"' && ($i+$j < $slen)){
  276. if( $s{$i+$j} == '\\' && ($s{$i+$j+1} == '"' || $s{$i+$j+1} == '\\') ){
  277. $j += 2;
  278. }else{
  279. $j += 1;
  280. }
  281. }
  282. $string = substr($s,$i,$j+1);
  283. // remove multiline markers:
  284. $string = str_replace("\\\n",'',$string);
  285. $result .= $string;
  286. $i = $i + $j + 1;
  287. continue;
  288. }
  289. // single quote strings
  290. if($ch == "'"){
  291. $j = 1;
  292. while( $s{$i+$j} != "'" && ($i+$j < $slen)){
  293. if( $s{$i+$j} == '\\' && ($s{$i+$j+1} == "'" || $s{$i+$j+1} == '\\') ){
  294. $j += 2;
  295. }else{
  296. $j += 1;
  297. }
  298. }
  299. $string = substr($s,$i,$j+1);
  300. // remove multiline markers:
  301. $string = str_replace("\\\n",'',$string);
  302. $result .= $string;
  303. $i = $i + $j + 1;
  304. continue;
  305. }
  306. // whitespaces
  307. if( $ch == ' ' || $ch == "\r" || $ch == "\n" || $ch == "\t" ){
  308. // leading spaces
  309. if($i+1 < $slen && (strpos($chars,$s[$i+1]) !== false)){
  310. $i = $i + 1;
  311. continue;
  312. }
  313. // trailing spaces
  314. // if this ch is space AND the last char processed
  315. // is special, then skip the space
  316. $lch = substr($result,-1);
  317. if($lch && (strpos($chars,$lch) !== false)){
  318. $i = $i + 1;
  319. continue;
  320. }
  321. // else after all of this convert the "whitespace" to
  322. // a single space. It will get appended below
  323. $ch = ' ';
  324. }
  325. // other chars
  326. $result .= $ch;
  327. $i = $i + 1;
  328. }
  329. return trim($result);
  330. }
  331. //Setup VIM: ex: et ts=4 :