JSResourceLocator.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace OC\Template;
  8. use OCP\App\AppPathNotFoundException;
  9. use OCP\App\IAppManager;
  10. use Psr\Log\LoggerInterface;
  11. class JSResourceLocator extends ResourceLocator {
  12. protected JSCombiner $jsCombiner;
  13. protected IAppManager $appManager;
  14. public function __construct(LoggerInterface $logger, JSCombiner $JSCombiner, IAppManager $appManager) {
  15. parent::__construct($logger);
  16. $this->jsCombiner = $JSCombiner;
  17. $this->appManager = $appManager;
  18. }
  19. /**
  20. * @param string $script
  21. */
  22. public function doFind($script) {
  23. $theme_dir = 'themes/' . $this->theme . '/';
  24. // Extracting the appId and the script file name
  25. $app = substr($script, 0, strpos($script, '/'));
  26. $scriptName = basename($script);
  27. // Get the app root path
  28. $appRoot = $this->serverroot . '/apps/';
  29. $appWebRoot = null;
  30. try {
  31. // We need the dir name as getAppPath appends the appid
  32. $appRoot = dirname($this->appManager->getAppPath($app));
  33. // Only do this if $app_path is set, because an empty argument to realpath gets turned into cwd.
  34. if ($appRoot) {
  35. // Handle symlinks
  36. $appRoot = realpath($appRoot);
  37. }
  38. // Get the app webroot
  39. $appWebRoot = dirname($this->appManager->getAppWebPath($app));
  40. } catch (AppPathNotFoundException $e) {
  41. // ignore
  42. }
  43. if (str_contains($script, '/l10n/')) {
  44. // For language files we try to load them all, so themes can overwrite
  45. // single l10n strings without having to translate all of them.
  46. $found = 0;
  47. $found += $this->appendScriptIfExist($this->serverroot, 'core/' . $script);
  48. $found += $this->appendScriptIfExist($this->serverroot, $theme_dir . 'core/' . $script);
  49. $found += $this->appendScriptIfExist($this->serverroot, $script);
  50. $found += $this->appendScriptIfExist($this->serverroot, $theme_dir . $script);
  51. $found += $this->appendScriptIfExist($appRoot, $script, $appWebRoot);
  52. $found += $this->appendScriptIfExist($this->serverroot, $theme_dir . 'apps/' . $script);
  53. if ($found) {
  54. return;
  55. }
  56. } elseif ($this->appendScriptIfExist($this->serverroot, $theme_dir . 'apps/' . $script)
  57. || $this->appendScriptIfExist($this->serverroot, $theme_dir . $script)
  58. || $this->appendScriptIfExist($this->serverroot, $script)
  59. || $this->appendScriptIfExist($this->serverroot, $theme_dir . "dist/$app-$scriptName")
  60. || $this->appendScriptIfExist($this->serverroot, "dist/$app-$scriptName")
  61. || $this->appendScriptIfExist($appRoot, $script, $appWebRoot)
  62. || $this->cacheAndAppendCombineJsonIfExist($this->serverroot, $script . '.json')
  63. || $this->cacheAndAppendCombineJsonIfExist($appRoot, $script . '.json', $appWebRoot)
  64. || $this->appendScriptIfExist($this->serverroot, $theme_dir . 'core/' . $script)
  65. || $this->appendScriptIfExist($this->serverroot, 'core/' . $script)
  66. || (strpos($scriptName, '/') === -1 && ($this->appendScriptIfExist($this->serverroot, $theme_dir . "dist/core-$scriptName")
  67. || $this->appendScriptIfExist($this->serverroot, "dist/core-$scriptName")))
  68. || $this->cacheAndAppendCombineJsonIfExist($this->serverroot, 'core/' . $script . '.json')
  69. ) {
  70. return;
  71. }
  72. // missing translations files will be ignored
  73. if (str_contains($script, '/l10n/')) {
  74. return;
  75. }
  76. $this->logger->error('Could not find resource {resource} to load', [
  77. 'resource' => $script . '.js',
  78. 'app' => 'jsresourceloader',
  79. ]);
  80. }
  81. /**
  82. * @param string $script
  83. */
  84. public function doFindTheme($script) {
  85. }
  86. /**
  87. * Try to find ES6 script file (`.mjs`) with fallback to plain javascript (`.js`)
  88. * @see appendIfExist()
  89. */
  90. protected function appendScriptIfExist(string $root, string $file, ?string $webRoot = null) {
  91. if (!$this->appendIfExist($root, $file . '.mjs', $webRoot)) {
  92. return $this->appendIfExist($root, $file . '.js', $webRoot);
  93. }
  94. return true;
  95. }
  96. protected function cacheAndAppendCombineJsonIfExist($root, $file, $app = 'core') {
  97. if (is_file($root . '/' . $file)) {
  98. if ($this->jsCombiner->process($root, $file, $app)) {
  99. $this->append($this->serverroot, $this->jsCombiner->getCachedJS($app, $file), false, false);
  100. } else {
  101. // Add all the files from the json
  102. $files = $this->jsCombiner->getContent($root, $file);
  103. $app_url = null;
  104. try {
  105. $app_url = $this->appManager->getAppWebPath($app);
  106. } catch (AppPathNotFoundException) {
  107. // pass
  108. }
  109. foreach ($files as $jsFile) {
  110. $this->append($root, $jsFile, $app_url);
  111. }
  112. }
  113. return true;
  114. }
  115. return false;
  116. }
  117. }