diff options
Diffstat (limited to 'app/php/web/ClientScriptManager.php')
-rw-r--r-- | app/php/web/ClientScriptManager.php | 119 |
1 files changed, 87 insertions, 32 deletions
diff --git a/app/php/web/ClientScriptManager.php b/app/php/web/ClientScriptManager.php index 1ebd8c3..64cfa76 100644 --- a/app/php/web/ClientScriptManager.php +++ b/app/php/web/ClientScriptManager.php @@ -10,10 +10,12 @@ class ClientScriptManager extends TClientScriptManager { parent::__construct($page); } + // Base path of the entire application private function _getBasePath() { return Prado::getPathOfNamespace('Web'); } + // Translate URLs to filesystem paths, index return array by URLs private function _getBasePaths($urls) { $basePath = $this->_getBasePath(); return array_combine( @@ -27,6 +29,7 @@ class ClientScriptManager extends TClientScriptManager { ); } + // Base cache path, suffixed with subdirectory, create on demand private function _getCachePath($subdir = 'assets') { $cachePath = $this->Application->RuntimePath . DIRECTORY_SEPARATOR @@ -46,12 +49,14 @@ class ClientScriptManager extends TClientScriptManager { return $cachePath; } + // Cache path for a file of specified type private function _getCacheFilePath($path, $type) { return $this->_getCachePath($type) . DIRECTORY_SEPARATOR . $path; } + // Cache key for specific file set, including current theme private function _getFileCollectionCacheKey($files) { sort($files); if ($this->_page->Theme) { @@ -60,10 +65,13 @@ class ClientScriptManager extends TClientScriptManager { return md5(implode(PHP_EOL, $files)); } + // Last modification time of a file set private function _getFileCollectionMTime($files) { return max(array_map('filemtime', $files)); } + // Storage (application cache) key for list of rendered assets of specified type + // Rendered[ASSET_TYPE].[VIEW_ID] (VIEW_ID as rendered in Layout hidden field) private function _getRenderedAssetsStoreKey($type) { $template = $this->_page->Master; if (!$template instanceof Layout) { @@ -74,14 +82,17 @@ class ClientScriptManager extends TClientScriptManager { return sprintf('Rendered%s.%s', $type, $template->generateViewID()); } + // Shorthand for JS assets cache key private function _getRenderedScriptsStoreKey() { return $this->_getRenderedAssetsStoreKey('Scripts'); } + // Shorthand for CSS assets cache key private function _getRenderedSheetsStoreKey() { return $this->_getRenderedAssetsStoreKey('Sheets'); } + // Application (primary) cache module, required to keep track of assets rendered on current page private function _getCache() { $cache = $this->Application->Cache; if (!$cache) { @@ -92,26 +103,31 @@ class ClientScriptManager extends TClientScriptManager { return $cache; } + // Check cache file validity, comparing to source file set private function _isCacheValid($cacheFile, $paths) { return file_exists($cacheFile) && (filemtime($cacheFile) >= $this->_getFileCollectionMTime($paths)); } + // Determine whether specific URL points to a local asset (i.e. existing on the filesystem) private function _isFileLocal($file) { $basePath = $this->_getBasePath(); return file_exists($basePath . DIRECTORY_SEPARATOR . $file); } + // Filter URL set to leave only local assets private function _determineLocalFiles($files) { return array_filter( $files, [$this, '_isFileLocal'] ); } - // Scripts + // Scripts - internal methods private $_renderedScriptsInitialized = FALSE; + // Retrieve scripts already rendered on current page from application cache, + // maintaining the state over callbacks private function _getRenderedScripts() { $sessionKey = $this->_getRenderedScriptsStoreKey(); if ($this->_page->IsCallBack || $this->_renderedScriptsInitialized) { @@ -123,6 +139,7 @@ class ClientScriptManager extends TClientScriptManager { } } + // Store information on rendered scripts in application cache private function _appendRenderedScripts(array $newScripts, $compiledFileKey) { $scripts = $this->_getRenderedScripts(); if (!isset($scripts[$compiledFileKey])) { @@ -140,12 +157,14 @@ class ClientScriptManager extends TClientScriptManager { ); } + // Compress JS file and return its content private function _getCompressedScript($path) { return trim(TJavaScript::JSMin( file_get_contents($path) )); } + // Join multiple script files into single asset, mark all of them as rendered in parent private function _compileScriptFiles($files) { foreach ($files as $file) { $this->markScriptFileAsRendered($file); @@ -169,6 +188,7 @@ class ClientScriptManager extends TClientScriptManager { return $this->Application->AssetManager->publishFilePath($cacheFile); } + // Write output tag for a single, compiled JS asset, consisting of multiple local assets private function _renderLocalScriptFiles($writer, $localFiles) { if ($localFiles) { $assetPath = $this->_compileScriptFiles($localFiles); @@ -176,6 +196,7 @@ class ClientScriptManager extends TClientScriptManager { } } + // Keep track of external JS scripts rendered on the page private function _renderExternalScriptFiles($writer, $externalFiles) { if ($externalFiles) { foreach ($externalFiles as $file) { @@ -186,19 +207,8 @@ class ClientScriptManager extends TClientScriptManager { } } - public function renderScriptFiles($writer, Array $files) { - if ($this->getApplication()->getMode() !== TApplicationMode::Debug) { - if ($files) { - $localFiles = $this->_determineLocalFiles($files); - $this->_renderLocalScriptFiles($writer, $localFiles); - $externalFiles = array_diff($files, $localFiles); - $this->_renderExternalScriptFiles($writer, $externalFiles); - } - } else { - parent::renderScriptFiles($writer, $files); - } - } - + // Determine actual asset URL that a source JS file was rendered as (after compilation/compression) + // FALSE means script wasn't rendered at all (i.e. was just registered in current callback) private function _getRenderedScriptUrl($registeredScript) { $renderedScripts = $this->_getRenderedScripts(); foreach ($renderedScripts as $compiledFile => $scripts) { @@ -215,6 +225,25 @@ class ClientScriptManager extends TClientScriptManager { return FALSE; } + // Scripts - public interface overrides + + // In application modes "higher" than Debug, compile JS assets to as few files as possible + public function renderScriptFiles($writer, Array $files) { + if ($this->getApplication()->getMode() !== TApplicationMode::Debug) { + if ($files) { + $localFiles = $this->_determineLocalFiles($files); + $this->_renderLocalScriptFiles($writer, $localFiles); + $externalFiles = array_diff($files, $localFiles); + $this->_renderExternalScriptFiles($writer, $externalFiles); + } + } else { + parent::renderScriptFiles($writer, $files); + } + } + + // When above compilation occurs, list of JS URLs a callback requires + // significantly deviates from parent implementation. + // Also, new scripts that have been registered in current callback may need compiling, too. public function getScriptUrls() { if ($this->getApplication()->getMode() !== TApplicationMode::Debug) { $registeredScripts = array_unique( @@ -250,20 +279,24 @@ class ClientScriptManager extends TClientScriptManager { private $_scripts = []; private $_headScripts = []; + // Keep track of what we're registering public function registerScriptFile($key, $file) { $this->_scripts[$key] = $file; return parent::registerScriptFile($key, $file); } + // Keep track of what we're registering public function registerHeadScriptFile($key, $file) { $this->_headScripts[$key] = $file; return parent::registerHeadScriptFile($key, $file); } - // Stylesheets + // Stylesheets - internal methods private $_renderedSheetsInitialized = FALSE; + // Retrieve stylesheets already rendered on current page from application cache, + // maintaining the state over callbacks private function _getRenderedSheets() { $sessionKey = $this->_getRenderedSheetsStoreKey(); if ($this->_page->IsCallBack || $this->_renderedSheetsInitialized) { @@ -275,6 +308,7 @@ class ClientScriptManager extends TClientScriptManager { } } + // Store information on rendered stylesheets in application cache private function _appendRenderedSheets(array $newSheets, $compiledFileKey) { $sheets = $this->_getRenderedSheets(); if (!isset($sheets[$compiledFileKey])) { @@ -309,6 +343,7 @@ class ClientScriptManager extends TClientScriptManager { ); } + // Compress CSS file and return its content private function _getCompressedSheet($origPath, $path) { Prado::using('Lib.cssmin.CssMin'); return trim(CssMin::minify( @@ -319,10 +354,12 @@ class ClientScriptManager extends TClientScriptManager { )); } + // Join multiple stylesheet files into single asset private function _compileSheetFiles($files) { $paths = $this->_getBasePaths( array_map('reset', $files) ); + // determine if file was registered as a themed sheet $correctedPaths = []; foreach ($paths as $url => $path) { $correctedPaths[ @@ -348,6 +385,7 @@ class ClientScriptManager extends TClientScriptManager { return $this->Application->AssetManager->publishFilePath($cacheFile); } + // Filter only local stylesheet file entries private function _determineLocalSheetFiles($files) { $basePath = $this->_getBasePath(); return array_filter( @@ -358,6 +396,7 @@ class ClientScriptManager extends TClientScriptManager { ); } + // Write HTML markup for CSS stylesheet private function _renderSheetFileTag(THtmlWriter $writer, $href, $media) { $writer->addAttribute('rel', 'stylesheet'); $writer->addAttribute('type', 'text/css'); @@ -367,6 +406,7 @@ class ClientScriptManager extends TClientScriptManager { $writer->write(PHP_EOL); } + // Group registered local CSS assets by media query string and render markup for compiled sheets private function _renderLocalSheetFiles(THtmlWriter $writer, $localFiles) { if ($localFiles) { $fileTypes = []; @@ -384,6 +424,7 @@ class ClientScriptManager extends TClientScriptManager { } } + // Render markup for external stylesheets private function _renderExternalSheetFiles(THtmlWriter $writer, $externalFiles) { if ($externalFiles) { foreach ($externalFiles as $file) { @@ -393,20 +434,9 @@ class ClientScriptManager extends TClientScriptManager { } } - public function renderStyleSheetFiles($writer) { - if ($this->getApplication()->getMode() !== TApplicationMode::Debug) { - $files = $this->_styles; - if ($files) { - $localFiles = $this->_determineLocalSheetFiles($files); - $this->_renderLocalSheetFiles($writer, $localFiles); - $externalFiles = array_diff_key($files, $localFiles); - $this->_renderExternalSheetFiles($writer, $externalFiles); - } - } else { - parent::renderStyleSheetFiles($writer); - } - } - + // Determine actual asset URL that a source CSS file was rendered as (after compilation/compression) + // FALSE means sheet wasn't rendered at all (i.e. was just registered in current callback) + // Media query types can easily be ignored in a callback request, only URLs matter private function _getRenderedSheetUrl($registeredSheet) { $renderedSheets = $this->_getRenderedSheets(); foreach ($renderedSheets as $compiledFile => $sheets) { @@ -425,6 +455,26 @@ class ClientScriptManager extends TClientScriptManager { return FALSE; } + // Stylesheets - public interface overrides + + // In application modes "higher" than Debug, compile CSS assets to as few files as possible + public function renderStyleSheetFiles($writer) { + if ($this->getApplication()->getMode() !== TApplicationMode::Debug) { + $files = $this->_styles; + if ($files) { + $localFiles = $this->_determineLocalSheetFiles($files); + $this->_renderLocalSheetFiles($writer, $localFiles); + $externalFiles = array_diff_key($files, $localFiles); + $this->_renderExternalSheetFiles($writer, $externalFiles); + } + } else { + parent::renderStyleSheetFiles($writer); + } + } + + // When above compilation occurs, list of CSS URLs a callback requires + // significantly deviates from parent implementation. + // New stylesheets may need compiling, as well. public function getStyleSheetUrls() { if ($this->getApplication()->getMode() !== TApplicationMode::Debug) { $registeredSheets = $this->_styles; @@ -457,9 +507,9 @@ class ClientScriptManager extends TClientScriptManager { ); return $sheetUrls; } - // in Debug mode, theme sheets before fixing paths + // And even in Debug mode, theme sheets before fixing paths // might also have been published via assets manager, - // so we have to discard these from parent list + // so we have to discard these from parent list. return array_diff( parent::getStyleSheetUrls(), $this->_fixedStyleFiles @@ -467,15 +517,20 @@ class ClientScriptManager extends TClientScriptManager { } private $_styles = []; - private $_themeStyles = []; + // Keep track of what we're registering public function registerStyleSheetFile($key, $file, $media = '') { $this->_styles[$key] = [$file, $media]; return parent::registerStyleSheetFile($key, $file, $media ?: 'all'); } + private $_themeStyles = []; private $_fixedStyleFiles = []; + // New method, automatically corrects URLs within stylesheet to current page theme + // when sheets are not compiled (when they are, it's done on compilation anyways). + // Such files are rewritten (not in place, though) and registered so that they don't show up + // within published assets returned from asset manager, as they don't end up in the markup. public function registerThemeStyleSheetFile($key, $file, $media = '') { if ($this->getApplication()->getMode() !== TApplicationMode::Debug) { $this->_themeStyles[$key] = $file; |