summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/php/application.xml4
-rw-r--r--app/php/components/ClientScriptManager.php168
2 files changed, 171 insertions, 1 deletions
diff --git a/app/php/application.xml b/app/php/application.xml
index 8b76f74..7c976e5 100644
--- a/app/php/application.xml
+++ b/app/php/application.xml
@@ -9,7 +9,9 @@
<include file="Application.controls.config" />
<services>
- <service id="page" class="TPageService" />
+ <service id="page"
+ class="TPageService"
+ ClientScriptManagerClass="Application.components.ClientScriptManager" />
</services>
<modules>
diff --git a/app/php/components/ClientScriptManager.php b/app/php/components/ClientScriptManager.php
new file mode 100644
index 0000000..64e5b58
--- /dev/null
+++ b/app/php/components/ClientScriptManager.php
@@ -0,0 +1,168 @@
+<?php
+
+class ClientScriptManager extends TClientScriptManager {
+
+ private $_page;
+ public function __construct(TPage $page) {
+ $this->_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);
+ }
+
+ public function renderScriptFiles($writer, Array $files) {
+ if ($this->getApplication()->getMode() !== TApplicationMode::Debug) {
+ if ($files) {
+ $assetPath = $this->_compileFiles($files);
+ $writer->write(TJavascript::renderScriptFile($assetPath));
+ }
+ } else {
+ parent::renderScriptFiles($writer, $files);
+ }
+ }
+
+ public function getScriptUrls() {
+ if ($this->getApplication()->getMode() !== TApplicationMode::Debug) {
+ $registeredScripts = array_unique(
+ array_merge(
+ $this->_scripts, $this->_headScripts
+ )
+ );
+ $renderedScripts = $this->_getRenderedScripts();
+ $scriptUrls = [];
+ $newScripts = [];
+ foreach ($registeredScripts as $registeredScript) {
+ $found = FALSE;
+ foreach ($renderedScripts as $compiledFile => $scripts) {
+ if (in_array($registeredScript, $scripts)) {
+ $scriptUrls[] = $this->Application->AssetManager->getPublishedUrl(
+ $compiledFile
+ );
+ $found = TRUE;
+ }
+ }
+ if (!$found) {
+ $newScripts[] = $registeredScript;
+ }
+ }
+ if ($newScripts) {
+ $scriptUrls[] = $this->_compileFiles($newScripts);
+ }
+ 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);
+ }
+
+}
+
+?>