[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/lib/exe/ -> js.php (source)

   1  <?php
   2  
   3  /**
   4   * DokuWiki JavaScript creator
   5   *
   6   * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
   7   * @author     Andreas Gohr <andi@splitbrain.org>
   8   */
   9  
  10  use dokuwiki\Utf8\PhpString;
  11  use dokuwiki\Cache\Cache;
  12  use dokuwiki\Extension\Event;
  13  use splitbrain\JSStrip\Exception as JSStripException;
  14  use splitbrain\JSStrip\JSStrip;
  15  
  16  if (!defined('DOKU_INC')) define('DOKU_INC', __DIR__ . '/../../');
  17  if (!defined('NOSESSION')) define('NOSESSION', true); // we do not use a session or authentication here (better caching)
  18  if (!defined('NL')) define('NL', "\n");
  19  if (!defined('DOKU_DISABLE_GZIP_OUTPUT')) define('DOKU_DISABLE_GZIP_OUTPUT', 1); // we gzip ourself here
  20  require_once (DOKU_INC . 'inc/init.php');
  21  
  22  // Main (don't run when UNIT test)
  23  if (!defined('SIMPLE_TEST')) {
  24      header('Content-Type: application/javascript; charset=utf-8');
  25      js_out();
  26  }
  27  
  28  
  29  // ---------------------- functions ------------------------------
  30  
  31  /**
  32   * Output all needed JavaScript
  33   *
  34   * @author Andreas Gohr <andi@splitbrain.org>
  35   */
  36  function js_out()
  37  {
  38      global $conf;
  39      global $lang;
  40      global $config_cascade;
  41      global $INPUT;
  42  
  43      // decide from where to get the template
  44      $tpl = trim(preg_replace('/[^\w-]+/', '', $INPUT->str('t')));
  45      if (!$tpl) $tpl = $conf['template'];
  46  
  47      // array of core files
  48      $files = [
  49          DOKU_INC . 'lib/scripts/jquery/jquery.cookie.js',
  50          DOKU_INC . 'inc/lang/' . $conf['lang'] . '/jquery.ui.datepicker.js',
  51          DOKU_INC . "lib/scripts/fileuploader.js",
  52          DOKU_INC . "lib/scripts/fileuploaderextended.js",
  53          DOKU_INC . 'lib/scripts/helpers.js',
  54          DOKU_INC . 'lib/scripts/delay.js',
  55          DOKU_INC . 'lib/scripts/cookie.js',
  56          DOKU_INC . 'lib/scripts/script.js',
  57          DOKU_INC . 'lib/scripts/qsearch.js',
  58          DOKU_INC . 'lib/scripts/search.js',
  59          DOKU_INC . 'lib/scripts/tree.js',
  60          DOKU_INC . 'lib/scripts/index.js',
  61          DOKU_INC . 'lib/scripts/textselection.js',
  62          DOKU_INC . 'lib/scripts/toolbar.js',
  63          DOKU_INC . 'lib/scripts/edit.js',
  64          DOKU_INC . 'lib/scripts/editor.js',
  65          DOKU_INC . 'lib/scripts/locktimer.js',
  66          DOKU_INC . 'lib/scripts/linkwiz.js',
  67          DOKU_INC . 'lib/scripts/media.js',
  68          DOKU_INC . 'lib/scripts/compatibility.js',
  69          # disabled for FS#1958                DOKU_INC.'lib/scripts/hotkeys.js',
  70          DOKU_INC . 'lib/scripts/behaviour.js',
  71          DOKU_INC . 'lib/scripts/page.js',
  72          tpl_incdir($tpl) . 'script.js',
  73      ];
  74  
  75      // add possible plugin scripts and userscript
  76      $files = array_merge($files, js_pluginscripts());
  77      if (is_array($config_cascade['userscript']['default'])) {
  78          foreach ($config_cascade['userscript']['default'] as $userscript) {
  79              $files[] = $userscript;
  80          }
  81      }
  82  
  83      // Let plugins decide to either put more scripts here or to remove some
  84      Event::createAndTrigger('JS_SCRIPT_LIST', $files);
  85  
  86      // The generated script depends on some dynamic options
  87      $cache = new Cache('scripts' . $_SERVER['HTTP_HOST'] . $_SERVER['SERVER_PORT'] . md5(serialize($files)), '.js');
  88      $cache->setEvent('JS_CACHE_USE');
  89  
  90      $cache_files = array_merge($files, getConfigFiles('main'));
  91      $cache_files[] = __FILE__;
  92  
  93      // check cache age & handle conditional request
  94      // This may exit if a cache can be used
  95      $cache_ok = $cache->useCache(['files' => $cache_files]);
  96      http_cached($cache->cache, $cache_ok);
  97  
  98      // start output buffering and build the script
  99      ob_start();
 100  
 101      // add some global variables
 102      echo "var DOKU_BASE   = '" . DOKU_BASE . "';";
 103      echo "var DOKU_TPL    = '" . tpl_basedir($tpl) . "';";
 104      echo "var DOKU_COOKIE_PARAM = " . json_encode([
 105              'path' => empty($conf['cookiedir']) ? DOKU_REL : $conf['cookiedir'],
 106              'secure' => $conf['securecookie'] && is_ssl()
 107          ], JSON_THROW_ON_ERROR) . ";";
 108      // FIXME: Move those to JSINFO
 109      echo "Object.defineProperty(window, 'DOKU_UHN', { get: function() {" .
 110          "console.warn('Using DOKU_UHN is deprecated. Please use JSINFO.useHeadingNavigation instead');" .
 111          "return JSINFO.useHeadingNavigation; } });";
 112      echo "Object.defineProperty(window, 'DOKU_UHC', { get: function() {" .
 113          "console.warn('Using DOKU_UHC is deprecated. Please use JSINFO.useHeadingContent instead');" .
 114          "return JSINFO.useHeadingContent; } });";
 115  
 116      // load JS specific translations
 117      $lang['js']['plugins'] = js_pluginstrings();
 118      $templatestrings = js_templatestrings($tpl);
 119      if (!empty($templatestrings)) {
 120          $lang['js']['template'] = $templatestrings;
 121      }
 122      echo 'LANG = ' . json_encode($lang['js'], JSON_THROW_ON_ERROR) . ";\n";
 123  
 124      // load toolbar
 125      toolbar_JSdefines('toolbar');
 126  
 127      // load files
 128      foreach ($files as $file) {
 129          if (!file_exists($file)) continue;
 130          $ismin = str_ends_with($file, '.min.js');
 131          $debugjs = ($conf['allowdebug'] && strpos($file, DOKU_INC . 'lib/scripts/') !== 0);
 132  
 133          echo "\n\n/* XXXXXXXXXX begin of " . str_replace(DOKU_INC, '', $file) . " XXXXXXXXXX */\n\n";
 134          if ($ismin) echo "\n/* BEGIN NOCOMPRESS */\n";
 135          if ($debugjs) echo "\ntry {\n";
 136          js_load($file);
 137          if ($debugjs) echo "\n} catch (e) {\n   logError(e, '" . str_replace(DOKU_INC, '', $file) . "');\n}\n";
 138          if ($ismin) echo "\n/* END NOCOMPRESS */\n";
 139          echo "\n\n/* XXXXXXXXXX end of " . str_replace(DOKU_INC, '', $file) . " XXXXXXXXXX */\n\n";
 140      }
 141  
 142      // init stuff
 143      if ($conf['locktime'] != 0) {
 144          js_runonstart("dw_locktimer.init(" . ($conf['locktime'] - 60) . "," . $conf['usedraft'] . ")");
 145      }
 146      // init hotkeys - must have been done after init of toolbar
 147      # disabled for FS#1958    js_runonstart('initializeHotkeys()');
 148  
 149      // end output buffering and get contents
 150      $js = ob_get_contents();
 151      ob_end_clean();
 152  
 153      // strip any source maps
 154      stripsourcemaps($js);
 155  
 156      // compress whitespace and comments
 157      if ($conf['compress']) {
 158          try {
 159              $js = (new JSStrip())->compress($js);
 160          } catch (JSStripException $e) {
 161              $js .= "\nconsole.error(" . json_encode($e->getMessage(), JSON_THROW_ON_ERROR) . ");\n";
 162          }
 163      }
 164  
 165      $js .= "\n"; // https://bugzilla.mozilla.org/show_bug.cgi?id=316033
 166  
 167      http_cached_finish($cache->cache, $js);
 168  }
 169  
 170  /**
 171   * Load the given file, handle include calls and print it
 172   *
 173   * @param string $file filename path to file
 174   *
 175   * @author Andreas Gohr <andi@splitbrain.org>
 176   */
 177  function js_load($file)
 178  {
 179      if (!file_exists($file)) return;
 180      static $loaded = [];
 181  
 182      $data = io_readFile($file);
 183      while (preg_match('#/\*\s*DOKUWIKI:include(_once)?\s+([\w\.\-_/]+)\s*\*/#', $data, $match)) {
 184          $ifile = $match[2];
 185  
 186          // is it a include_once?
 187          if ($match[1]) {
 188              $base = PhpString::basename($ifile);
 189              if (array_key_exists($base, $loaded) && $loaded[$base] === true) {
 190                  $data = str_replace($match[0], '', $data);
 191                  continue;
 192              }
 193              $loaded[$base] = true;
 194          }
 195  
 196          if ($ifile[0] != '/') $ifile = dirname($file) . '/' . $ifile;
 197  
 198          $idata = '';
 199          if (file_exists($ifile)) {
 200              $ismin = str_ends_with($ifile, '.min.js');
 201              if ($ismin) $idata .= "\n/* BEGIN NOCOMPRESS */\n";
 202              $idata .= io_readFile($ifile);
 203              if ($ismin) $idata .= "\n/* END NOCOMPRESS */\n";
 204          }
 205          $data = str_replace($match[0], $idata, $data);
 206      }
 207      echo "$data\n";
 208  }
 209  
 210  /**
 211   * Returns a list of possible Plugin Scripts (no existance check here)
 212   *
 213   * @return array
 214   *
 215   * @author Andreas Gohr <andi@splitbrain.org>
 216   */
 217  function js_pluginscripts()
 218  {
 219      $list = [];
 220      $plugins = plugin_list();
 221      foreach ($plugins as $p) {
 222          $list[] = DOKU_PLUGIN . "$p/script.js";
 223      }
 224      return $list;
 225  }
 226  
 227  /**
 228   * Return an two-dimensional array with strings from the language file of each plugin.
 229   *
 230   * - $lang['js'] must be an array.
 231   * - Nothing is returned for plugins without an entry for $lang['js']
 232   *
 233   * @return array
 234   * @author Gabriel Birke <birke@d-scribe.de>
 235   *
 236   */
 237  function js_pluginstrings()
 238  {
 239      global $conf, $config_cascade;
 240      $pluginstrings = [];
 241      $plugins = plugin_list();
 242      foreach ($plugins as $p) {
 243          $path = DOKU_PLUGIN . $p . '/lang/';
 244  
 245          if (isset($lang)) unset($lang);
 246          if (file_exists($path . "en/lang.php")) {
 247              include $path . "en/lang.php";
 248          }
 249          foreach ($config_cascade['lang']['plugin'] as $config_file) {
 250              if (file_exists($config_file . $p . '/en/lang.php')) {
 251                  include($config_file . $p . '/en/lang.php');
 252              }
 253          }
 254          if (isset($conf['lang']) && $conf['lang'] != 'en') {
 255              if (file_exists($path . $conf['lang'] . "/lang.php")) {
 256                  include($path . $conf['lang'] . '/lang.php');
 257              }
 258              foreach ($config_cascade['lang']['plugin'] as $config_file) {
 259                  if (file_exists($config_file . $p . '/' . $conf['lang'] . '/lang.php')) {
 260                      include($config_file . $p . '/' . $conf['lang'] . '/lang.php');
 261                  }
 262              }
 263          }
 264  
 265          if (isset($lang['js'])) {
 266              $pluginstrings[$p] = $lang['js'];
 267          }
 268      }
 269      return $pluginstrings;
 270  }
 271  
 272  /**
 273   * Return an two-dimensional array with strings from the language file of current active template.
 274   *
 275   * - $lang['js'] must be an array.
 276   * - Nothing is returned for template without an entry for $lang['js']
 277   *
 278   * @param string $tpl
 279   * @return array
 280   */
 281  function js_templatestrings($tpl)
 282  {
 283      global $conf, $config_cascade;
 284  
 285      $path = tpl_incdir() . 'lang/';
 286  
 287      $templatestrings = [];
 288      if (file_exists($path . "en/lang.php")) {
 289          include $path . "en/lang.php";
 290      }
 291      foreach ($config_cascade['lang']['template'] as $config_file) {
 292          if (file_exists($config_file . $conf['template'] . '/en/lang.php')) {
 293              include($config_file . $conf['template'] . '/en/lang.php');
 294          }
 295      }
 296      if (isset($conf['lang']) && $conf['lang'] != 'en' && file_exists($path . $conf['lang'] . "/lang.php")) {
 297          include $path . $conf['lang'] . "/lang.php";
 298      }
 299      if (isset($conf['lang']) && $conf['lang'] != 'en') {
 300          if (file_exists($path . $conf['lang'] . "/lang.php")) {
 301              include $path . $conf['lang'] . "/lang.php";
 302          }
 303          foreach ($config_cascade['lang']['template'] as $config_file) {
 304              if (file_exists($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php')) {
 305                  include($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php');
 306              }
 307          }
 308      }
 309  
 310      if (isset($lang['js'])) {
 311          $templatestrings[$tpl] = $lang['js'];
 312      }
 313      return $templatestrings;
 314  }
 315  
 316  /**
 317   * Escapes a String to be embedded in a JavaScript call, keeps \n
 318   * as newline
 319   *
 320   * @param string $string
 321   * @return string
 322   *
 323   * @author Andreas Gohr <andi@splitbrain.org>
 324   */
 325  function js_escape($string)
 326  {
 327      return str_replace('\\\\n', '\\n', addslashes($string));
 328  }
 329  
 330  /**
 331   * Adds the given JavaScript code to the window.onload() event
 332   *
 333   * @param string $func
 334   *
 335   * @author Andreas Gohr <andi@splitbrain.org>
 336   */
 337  function js_runonstart($func)
 338  {
 339      echo "jQuery(function(){ $func; });" . NL;
 340  }