_page = $page; parent::__construct($page); } private function _getBasePath() { $assetManager = $this->Application->AssetManager; return preg_replace( '#' . preg_quote($assetManager->BaseUrl) . '$#', '', $assetManager->BasePath ); } private function _getBasePaths($urls) { $basePath = $this->_getBasePath(); return array_map( function($path) use($basePath) { return $basePath . DIRECTORY_SEPARATOR . $path; }, $urls ); } private function _getCachePath($subdir = 'assets') { $cachePath = $this->Application->RuntimePath . DIRECTORY_SEPARATOR . $subdir; if (!is_dir($cachePath)) { if (file_exists($cachePath)) { throw new TIOException( 'Client script manager cache path "' . $cachePath . ' "exists and is not a directory' ); } else { mkdir($cachePath); } } return $cachePath; } private function _getCacheFilePath($path, $type) { return $this->_getCachePath($type) . DIRECTORY_SEPARATOR . $path; } private function _getFileCollectionCacheKey($files) { sort($files); return md5(implode(PHP_EOL, $files)); } private function _getFileCollectionMTime($files) { return max(array_map('filemtime', $files)); } private $_renderedScriptsInitialized = FALSE; private function _getRenderedScripts() { if ($this->_page->IsCallBack || $this->_renderedScriptsInitialized) { return $this->Session->itemAt('RenderedScripts') ?: []; } else { $this->Session->remove('RenderedScripts'); $this->_renderedScriptsInitialized = TRUE; return []; } } private function _appendRenderedScripts(array $newScripts, $compiledFileKey) { $scripts = $this->_getRenderedScripts(); if (!isset($scripts[$compiledFileKey])) { $scripts[$compiledFileKey] = []; } $scripts[$compiledFileKey] = array_unique( array_merge( $scripts[$compiledFileKey], $newScripts ) ); $this->Session->add('RenderedScripts', $scripts); } private function _compileFiles($files) { foreach ($files as $file) { $this->markScriptFileAsRendered($file); } $paths = $this->_getBasePaths($files); $cacheKey = $this->_getFileCollectionCacheKey($paths); $cacheFile = $this->_getCacheFilePath($cacheKey . '.js', 'scripts'); $this->_appendRenderedScripts($files, $cacheFile); if (!file_exists($cacheFile) || (filemtime($cacheFile) < $this->_getFileCollectionMTime($paths))) { $scriptContent = implode( PHP_EOL, array_map('file_get_contents', $paths) ); file_put_contents($cacheFile, $scriptContent); } return $this->Application->AssetManager->publishFilePath($cacheFile); } private function _determineLocalScriptFiles($files) { $basePath = $this->_getBasePath(); return array_filter( $files, function($file) use($basePath) { return file_exists($basePath . DIRECTORY_SEPARATOR . $file); } ); } private function _renderLocalScriptFiles($writer, $localFiles) { if ($localFiles) { $assetPath = $this->_compileFiles($localFiles); $writer->write(TJavascript::renderScriptFile($assetPath)); } } private function _renderExternalScriptFiles($writer, $externalFiles) { if ($externalFiles) { foreach ($externalFiles as $file) { $this->markScriptFileAsRendered($file); $this->_appendRenderedScripts([$file], $file); } parent::renderScriptFiles($writer, $externalFiles); } } public function renderScriptFiles($writer, Array $files) { if ($this->getApplication()->getMode() !== TApplicationMode::Debug) { if ($files) { $localFiles = $this->_determineLocalScriptFiles($files); $this->_renderLocalScriptFiles($writer, $localFiles); $externalFiles = array_diff($files, $localFiles); $this->_renderExternalScriptFiles($writer, $externalFiles); } } else { parent::renderScriptFiles($writer, $files); } } private function _getRenderedScriptUrl($registeredScript) { $renderedScripts = $this->_getRenderedScripts(); foreach ($renderedScripts as $compiledFile => $scripts) { if (in_array($registeredScript, $scripts)) { if (file_exists($compiledFile)) { return $this->Application->AssetManager->getPublishedUrl( $compiledFile ); } else { return $registeredScript; } } } return FALSE; } public function getScriptUrls() { if ($this->getApplication()->getMode() !== TApplicationMode::Debug) { $registeredScripts = array_unique( array_merge( $this->_scripts, $this->_headScripts ) ); $scriptUrls = []; $newScripts = []; foreach ($registeredScripts as $registeredScript) { $renderedScriptUrl = $this->_getRenderedScriptUrl( $registeredScript ); if ($renderedScriptUrl) { $scriptUrls[] = $renderedScriptUrl; } else { $newScripts[] = $registeredScript; } } $newLocalScripts = $this->_determineLocalScriptFiles($newScripts); $newRemoteScripts = array_diff($newScripts, $newLocalScripts); if ($newLocalScripts) { $scriptUrls[] = $this->_compileFiles($newLocalScripts); } $scriptUrls = array_values( array_unique(array_merge($scriptUrls, $newRemoteScripts)) ); return $scriptUrls; } else { return parent::getScriptUrls(); } } private $_scripts = []; private $_headScripts = []; public function registerScriptFile($key, $file) { $this->_scripts[$key] = $file; return parent::registerScriptFile($key, $file); } public function registerHeadScriptFile($key, $file) { $this->_headScripts[$key] = $file; return parent::registerHeadScriptFile($key, $file); } } ?>