summaryrefslogtreecommitdiff
path: root/app/php/web/ClientScriptManager.php
diff options
context:
space:
mode:
Diffstat (limited to 'app/php/web/ClientScriptManager.php')
-rw-r--r--app/php/web/ClientScriptManager.php119
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;