From f8a352afcea56e70ad56129e24dddf325162bbf6 Mon Sep 17 00:00:00 2001 From: Ruben Date: Fri, 6 Feb 2026 18:47:17 +0100 Subject: [PATCH] Add JavaScript support to page templates Add support for page-specific JavaScript files with cache busting via MD5 hash. The script is loaded at the end of the body with defer attribute. The JavaScript file must be named script.js and located in the same directory as the page content. --- app/default/templates/base.php | 3 +++ app/helpers.php | 16 ++++++++++++++++ app/rendering.php | 8 ++++++++ app/router.php | 11 ++++++++++- 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/app/default/templates/base.php b/app/default/templates/base.php index ce25bfd..d739dbe 100644 --- a/app/default/templates/base.php +++ b/app/default/templates/base.php @@ -54,5 +54,8 @@

+ + + diff --git a/app/helpers.php b/app/helpers.php index 489202e..c9c722c 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -132,6 +132,22 @@ function findPageCss(string $dirPath, string $contentDir): ?array { ]; } +function findPageJs(string $dirPath, string $contentDir): ?array { + $jsFile = "$dirPath/script.js"; + if (!file_exists($jsFile) || !is_file($jsFile)) { + return null; + } + + $relativePath = str_replace($contentDir, '', $dirPath); + $relativePath = trim($relativePath, '/'); + $jsUrl = '/' . ($relativePath ? $relativePath . '/' : '') . 'script.js'; + + return [ + 'url' => $jsUrl, + 'hash' => hash_file('md5', $jsFile) + ]; +} + function extractMetaDescription(string $dirPath, ?array $metadata): ?string { // 1. Check for search_description in metadata if ($metadata && isset($metadata['search_description'])) { diff --git a/app/rendering.php b/app/rendering.php index ef4e57a..c4a099a 100644 --- a/app/rendering.php +++ b/app/rendering.php @@ -57,6 +57,8 @@ function renderTemplate(Context $ctx, string $content, int $statusCode = 200): v 'metaDescription' => $ctx->get('metaDescription'), 'pageCssUrl' => $ctx->get('pageCssUrl'), 'pageCssHash' => $ctx->get('pageCssHash'), + 'pageJsUrl' => $ctx->get('pageJsUrl'), + 'pageJsHash' => $ctx->get('pageJsHash'), 'feedUrl' => $ctx->get('feedUrl') ], $ctx); @@ -88,6 +90,10 @@ function renderMultipleFiles(Context $ctx, array $files, string $pageDir): void $pageCssUrl = $pageCss['url'] ?? null; $pageCssHash = $pageCss['hash'] ?? null; + $pageJs = findPageJs($pageDir, $ctx->contentDir); + $pageJsUrl = $pageJs['url'] ?? null; + $pageJsHash = $pageJs['hash'] ?? null; + $coverImage = findCoverImage($pageDir); $socialImageUrl = null; if ($coverImage) { @@ -104,6 +110,8 @@ function renderMultipleFiles(Context $ctx, array $files, string $pageDir): void 'metaDescription' => $metaDescription, 'pageCssUrl' => $pageCssUrl, 'pageCssHash' => $pageCssHash, + 'pageJsUrl' => $pageJsUrl, + 'pageJsHash' => $pageJsHash, 'socialImageUrl' => $socialImageUrl ], $ctx); diff --git a/app/router.php b/app/router.php index d9710e0..9772872 100644 --- a/app/router.php +++ b/app/router.php @@ -42,6 +42,7 @@ if (file_exists($contentAssetPath) && is_file($contentAssetPath)) { 'woff2' => 'font/woff2', 'ttf' => 'font/ttf', 'otf' => 'font/otf', + 'js' => 'application/javascript', ]; $extLower = strtolower($ext); @@ -205,10 +206,14 @@ switch ($parsedPath['type']) { $pageTitle = $metadata['title'] ?? null; $metaDescription = extractMetaDescription($dir, $metadata); - // Check for page-specific CSS + // Check for page-specific CSS and JS $pageCss = findPageCss($dir, $ctx->contentDir); $pageCssUrl = $pageCss['url'] ?? null; $pageCssHash = $pageCss['hash'] ?? null; + + $pageJs = findPageJs($dir, $ctx->contentDir); + $pageJsUrl = $pageJs['url'] ?? null; + $pageJsHash = $pageJs['hash'] ?? null; // Build feed URL if feed is enabled $langPrefix = $ctx->get('langPrefix', ''); @@ -221,6 +226,8 @@ switch ($parsedPath['type']) { $ctx->set('metaDescription', $metaDescription); $ctx->set('pageCssUrl', $pageCssUrl); $ctx->set('pageCssHash', $pageCssHash); + $ctx->set('pageJsUrl', $pageJsUrl); + $ctx->set('pageJsHash', $pageJsHash); $ctx->set('feedUrl', $feedUrl); // Let plugins add template variables @@ -231,6 +238,8 @@ switch ($parsedPath['type']) { 'metaDescription' => $metaDescription, 'pageCssUrl' => $pageCssUrl, 'pageCssHash' => $pageCssHash, + 'pageJsUrl' => $pageJsUrl, + 'pageJsHash' => $pageJsHash, 'items' => $items, 'pageContent' => $pageContent, 'feedUrl' => $feedUrl