From 304c54cc6756e59811dda66f8c3557f63a9a4c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gu=CC=88nther?= Date: Mon, 18 Mar 2024 16:34:27 +0100 Subject: [PATCH 1/4] FEATURE: Apply migrations and adding Neos 8.x compatibilty --- composer.json | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index b178f83..8de8085 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "type": "neos-package", "name": "psmb/ajaxify", "require": { - "neos/neos": "^3.0 | ^4.0 | ^5.0 | ^7.0" + "neos/neos": "^7.0 | ^8.0" }, "license": "LGPL-3.0+", "autoload": { @@ -87,7 +87,20 @@ "Neos.Fusion-20180211175500", "Neos.Fusion-20180211184832", "Neos.Flow-20180415105700", - "Neos.Neos-20180907103800" + "Neos.Neos-20180907103800", + "Neos.SwiftMailer-20161130105617", + "Neos.Neos.Ui-20190319094900", + "Neos.Flow-20190425144900", + "Neos.Flow-20190515215000", + "Networkteam.Neos.MailObfuscator-20190919145400", + "Neos.Flow-20200813181400", + "Neos.Flow-20201003165200", + "Neos.Flow-20201109224100", + "Neos.Flow-20201205172733", + "Neos.Flow-20201207104500", + "Neos.Neos-20220318111600", + "Neos.Flow-20220318174300", + "Neos.Fusion-20220326120900" ] } -} +} \ No newline at end of file From dbb1cbaa8cbbdf7b3493886d9379723d7faa2b7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gu=CC=88nther?= Date: Mon, 18 Mar 2024 19:17:37 +0100 Subject: [PATCH 2/4] TASK: Little cleanup and modernization --- Classes/Fusion/RenderPathImplementation.php | 1 - Classes/Fusion/RendererImplementation.php | 1 - Resources/Public/ajax.js | 42 +++++++++------------ Resources/Public/loader.css | 22 +++-------- 4 files changed, 24 insertions(+), 42 deletions(-) diff --git a/Classes/Fusion/RenderPathImplementation.php b/Classes/Fusion/RenderPathImplementation.php index ec671ea..cea73d5 100644 --- a/Classes/Fusion/RenderPathImplementation.php +++ b/Classes/Fusion/RenderPathImplementation.php @@ -3,7 +3,6 @@ use Neos\Flow\Annotations as Flow; use Neos\Fusion\FusionObjects\AbstractFusionObject; -use Neos\Neos\Exception as NeosException; /** * Returns the path to the parent Fusion object diff --git a/Classes/Fusion/RendererImplementation.php b/Classes/Fusion/RendererImplementation.php index 0e36851..cd35953 100644 --- a/Classes/Fusion/RendererImplementation.php +++ b/Classes/Fusion/RendererImplementation.php @@ -4,7 +4,6 @@ use Neos\Flow\Annotations as Flow; use Neos\Neos\View\FusionView; use Neos\Fusion\FusionObjects\AbstractFusionObject; -use Neos\Neos\Exception as NeosException; /** * Renders a Fusion view based on a path diff --git a/Resources/Public/ajax.js b/Resources/Public/ajax.js index 1a04423..7f2d31d 100644 --- a/Resources/Public/ajax.js +++ b/Resources/Public/ajax.js @@ -1,27 +1,21 @@ -(function () { - var containers = document.querySelectorAll('[data-ajaxify]'); +(() => { + const containers = document.querySelectorAll('[data-ajaxify]'); - [].slice.call(containers).forEach(function(el) { - loadContainer(el); - }); + containers.forEach(container => { + loadContainer(container); + }); - function loadContainer(container) { - var request = new XMLHttpRequest(); - var url = container.href; - request.open('GET', url, true); - - request.onload = function() { - if (request.status >= 200 && request.status < 400) { - container.outerHTML = request.responseText; - } else { - container.innerHTML = 'Content failed to load, please refresh the page'; - } - }; - - request.onerror = function() { - container.innerHTML = 'Content failed to load, please refresh the page'; - }; - - request.send(); - } + async function loadContainer(container) { + const url = container.href; + try { + const response = await fetch(url); + if (response.ok) { + container.outerHTML = await response.text(); + } else { + container.innerHTML = 'Content failed to load, please refresh the page'; + } + } catch (error) { + container.innerHTML = 'Content failed to load, please refresh the page'; + } + } })(); diff --git a/Resources/Public/loader.css b/Resources/Public/loader.css index 758ddce..6cda8b9 100644 --- a/Resources/Public/loader.css +++ b/Resources/Public/loader.css @@ -8,34 +8,24 @@ width: 16px; height: 16px; background-color: #666; - - border-radius: 100%; + border-radius: 50%; display: inline-block; - -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both; - animation: sk-bouncedelay 1.4s infinite ease-in-out both; + animation: bounce 1.4s infinite ease-in-out both; } .spinner .bounce1 { - -webkit-animation-delay: -0.32s; animation-delay: -0.32s; } .spinner .bounce2 { - -webkit-animation-delay: -0.16s; animation-delay: -0.16s; } -@-webkit-keyframes sk-bouncedelay { - 0%, 80%, 100% { -webkit-transform: scale(0) } - 40% { -webkit-transform: scale(1.0) } -} - -@keyframes sk-bouncedelay { +@keyframes bounce { 0%, 80%, 100% { - -webkit-transform: scale(0); transform: scale(0); - } 40% { - -webkit-transform: scale(1.0); - transform: scale(1.0); + } + 40% { + transform: scale(1); } } From 7b27b9ef29f250e90b8b5c660a281f9b851d54d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gu=CC=88nther?= Date: Tue, 19 Mar 2024 09:41:51 +0100 Subject: [PATCH 3/4] TASK: Adjust documentation Restructure the README, removes the unavailable realworl example and adds a version matrix. --- README.md | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 4a15d2c..4e5df1c 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,50 @@ # Psmb.Ajaxify -This package allows you to mark any part of page for asynchronous loading via AJAX with just one line of Fusion code. -Why? It helps you to speed up initial page load by delaying the load of some less relevant parts of the page, e.g. comments. +Enhance your NeosCMS experience with Psmb.Ajaxify, a powerful package that streamlines asynchronous loading of specific page components through AJAX, all with just one line of Fusion code. Why bother? It significantly accelerates the initial page load by deferring the loading of less critical parts, such as comments. -![demo](https://cloud.githubusercontent.com/assets/837032/25178402/5b011f40-250e-11e7-9e6c-462b8e912893.gif) +![See it in action](https://cloud.githubusercontent.com/assets/837032/25178402/5b011f40-250e-11e7-9e6c-462b8e912893.gif) ## TL;DR -1. Install the package +### **Installation**: -``` +```bash composer require psmb/ajaxify ``` -2. Add `@process.myUniqueKey = Psmb.Ajaxify:Ajaxify` on any Fusion path. **The `myUniqueKey` key of the processor MUST be globally unique.** +### Integration: +Add `@process.myUniqueKey = Psmb.Ajaxify:Ajaxify` to any Fusion path. Ensure that the `myUniqueKey` remains globally unique. -3. Add this anywhere in your Fusion code to include the sample AJAX loading script: +Incorporate the sample AJAX loading script into your Fusion code: -``` +```fusion prototype(Neos.Neos:Page).head.ajaxLoader = Psmb.Ajaxify:CssTag prototype(Neos.Neos:Page).body.javascripts.ajax = Psmb.Ajaxify:JsTag ``` -Or include these assets via your build tool. Or just write your own loader. +Alternatively, integrate these assets via your preferred build tool or craft your custom loader. + +### Completion: + +Done. Now part of your pages will be lazily loaded via an AJAX request. + +**Note**: Ensure that your Fusion component doesn't rely on any context variables apart from the standard ones. If you need to reuse an EEL expression, refrain from embedding it into context. Instead, encapsulate it within a `Neos.Fusion:Value` object for universal usage. + +### Customization: -4. Done. Now part of your pages will be lazily loaded via an AJAX request. +Feel free to override the `Psmb.Ajaxify:Loader` object to tailor the loader according to your requirements. -**Note:** the Fusion component should not depend on any context variables, other than the standard ones. -If you want to reuse some EEL expression in your code base, don't put it into context, rather wrap it into `Neos.Fusion:Value` object and use it everywhere you like. +## Compatibility and Maintenance -5. You may override the `Psmb.Ajaxify:Loader` object in order to customize the loader. +This package is currently being maintained for the following versions: +| Neos Version | Version | Maintained | +|--------------------|---------|------------| +| Neos 7.3 and above | 1.x | Yes | +| Neos 3.3 - 7.2 | 0.4 | No | -## Usage in the Wild +## Contribution -- https://pokayanie1917.ru/ -- If you use it, submit yours via a PR! +Feel free to tweak and optimize your NeosCMS setup with Psmb.Ajaxify. Streamline your page loads and provide a smoother user experience effortlessly. From 1d2a3bb83fd2b3d69d400aa7845929097c12a65e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gu=CC=88nther?= Date: Tue, 19 Mar 2024 10:06:52 +0100 Subject: [PATCH 4/4] TASK: Declutter the root.fusion Move the prototypes of the root.fusion file into separate fusion files. --- .../Private/Fusion/Component/Ajaxify.fusion | 12 ++++ .../Private/Fusion/Component/Loader.fusion | 9 +++ .../Private/Fusion/Component/Renderer.fusion | 17 +++++ .../Fusion/Component/UnindexedResponse.fusion | 7 ++ Resources/Private/Fusion/Helper/CssTag.fusion | 7 ++ Resources/Private/Fusion/Helper/JsTag.fusion | 6 ++ Resources/Private/Fusion/Override.fusion | 1 - .../Override/GlobalCacheIdentifiers.fusion | 3 + Resources/Private/Fusion/Root.fusion | 65 ++----------------- 9 files changed, 65 insertions(+), 62 deletions(-) create mode 100644 Resources/Private/Fusion/Component/Ajaxify.fusion create mode 100644 Resources/Private/Fusion/Component/Loader.fusion create mode 100644 Resources/Private/Fusion/Component/Renderer.fusion create mode 100644 Resources/Private/Fusion/Component/UnindexedResponse.fusion create mode 100644 Resources/Private/Fusion/Helper/CssTag.fusion create mode 100644 Resources/Private/Fusion/Helper/JsTag.fusion delete mode 100644 Resources/Private/Fusion/Override.fusion create mode 100644 Resources/Private/Fusion/Override/GlobalCacheIdentifiers.fusion diff --git a/Resources/Private/Fusion/Component/Ajaxify.fusion b/Resources/Private/Fusion/Component/Ajaxify.fusion new file mode 100644 index 0000000..2fa6b7c --- /dev/null +++ b/Resources/Private/Fusion/Component/Ajaxify.fusion @@ -0,0 +1,12 @@ +# Use this object as a processor on any path +prototype(Psmb.Ajaxify:Ajaxify) < prototype(Neos.Fusion:Tag) { + # The processor is disabled in BE or when rendering the AJAX request + @if.disableProcessor = ${!request.arguments.ajaxPathKey && !documentNode.context.inBackend} + tagName = 'a' + attributes.data-ajaxify = ${true} + attributes.href = Neos.Neos:NodeUri { + node = ${documentNode} + additionalParams.ajaxPathKey = Psmb.Ajaxify:RenderPath + } + content = Psmb.Ajaxify:Loader +} diff --git a/Resources/Private/Fusion/Component/Loader.fusion b/Resources/Private/Fusion/Component/Loader.fusion new file mode 100644 index 0000000..62bf57f --- /dev/null +++ b/Resources/Private/Fusion/Component/Loader.fusion @@ -0,0 +1,9 @@ +prototype(Psmb.Ajaxify:Loader) < prototype(Neos.Fusion:Component) { + renderer = afx` +
+
+
+
+
+ ` +} diff --git a/Resources/Private/Fusion/Component/Renderer.fusion b/Resources/Private/Fusion/Component/Renderer.fusion new file mode 100644 index 0000000..eccaa20 --- /dev/null +++ b/Resources/Private/Fusion/Component/Renderer.fusion @@ -0,0 +1,17 @@ +# TODO: Watch out, this is hardcoded to be used with Psmb.Ajaxify:Ajaxify +prototype(Psmb.Ajaxify:Renderer) { + @class = 'Psmb\\Ajaxify\\Fusion\\RendererImplementation' + node = ${documentNode} + pathKey = ${request.arguments.ajaxPathKey} + @cache { + mode = 'uncached' + context { + 1 = 'documentNode' + 2 = 'node' + } + } +} + +prototype(Psmb.Ajaxify:RenderPath) { + @class = 'Psmb\\Ajaxify\\Fusion\\RenderPathImplementation' +} diff --git a/Resources/Private/Fusion/Component/UnindexedResponse.fusion b/Resources/Private/Fusion/Component/UnindexedResponse.fusion new file mode 100644 index 0000000..db4e517 --- /dev/null +++ b/Resources/Private/Fusion/Component/UnindexedResponse.fusion @@ -0,0 +1,7 @@ +# Prevents search engines from indexing the partly rendered document content +prototype(Psmb.Ajaxify:UnindexedResponse) < prototype(Neos.Fusion:Http.Message) { + httpResponseHead.headers { + X-Robots-Tag = 'noindex, follow' + } + content = Psmb.Ajaxify:Renderer +} diff --git a/Resources/Private/Fusion/Helper/CssTag.fusion b/Resources/Private/Fusion/Helper/CssTag.fusion new file mode 100644 index 0000000..5bcf43e --- /dev/null +++ b/Resources/Private/Fusion/Helper/CssTag.fusion @@ -0,0 +1,7 @@ +prototype(Psmb.Ajaxify:CssTag) < prototype(Neos.Fusion:Tag) { + tagName = 'link' + attributes.rel = 'stylesheet' + attributes.href = Neos.Fusion:ResourceUri { + path = 'resource://Psmb.Ajaxify/Public/loader.css' + } +} diff --git a/Resources/Private/Fusion/Helper/JsTag.fusion b/Resources/Private/Fusion/Helper/JsTag.fusion new file mode 100644 index 0000000..0dcd68b --- /dev/null +++ b/Resources/Private/Fusion/Helper/JsTag.fusion @@ -0,0 +1,6 @@ +prototype(Psmb.Ajaxify:JsTag) < prototype(Neos.Fusion:Tag) { + tagName = 'script' + attributes.src = Neos.Fusion:ResourceUri { + path = 'resource://Psmb.Ajaxify/Public/ajax.js' + } +} diff --git a/Resources/Private/Fusion/Override.fusion b/Resources/Private/Fusion/Override.fusion deleted file mode 100644 index c913976..0000000 --- a/Resources/Private/Fusion/Override.fusion +++ /dev/null @@ -1 +0,0 @@ -prototype(Neos.Fusion:GlobalCacheIdentifiers).ajaxPathKey = ${request.arguments.ajaxPathKey} diff --git a/Resources/Private/Fusion/Override/GlobalCacheIdentifiers.fusion b/Resources/Private/Fusion/Override/GlobalCacheIdentifiers.fusion new file mode 100644 index 0000000..dd3974b --- /dev/null +++ b/Resources/Private/Fusion/Override/GlobalCacheIdentifiers.fusion @@ -0,0 +1,3 @@ +prototype(Neos.Fusion:GlobalCacheIdentifiers) { + ajaxPathKey = ${request.arguments.ajaxPathKey} +} diff --git a/Resources/Private/Fusion/Root.fusion b/Resources/Private/Fusion/Root.fusion index 42b67b5..c44a845 100644 --- a/Resources/Private/Fusion/Root.fusion +++ b/Resources/Private/Fusion/Root.fusion @@ -1,64 +1,7 @@ -include: Override.fusion - -# TODO: Watch out, this is hardcoded to be used with Psmb.Ajaxify:Ajaxify -prototype(Psmb.Ajaxify:RenderPath) { - @class = 'Psmb\\Ajaxify\\Fusion\\RenderPathImplementation' -} - -prototype(Psmb.Ajaxify:Loader) < prototype(Neos.Fusion:Value) { - value = ${'
'} -} - -# Use this object as a processor on any path -prototype(Psmb.Ajaxify:Ajaxify) < prototype(Neos.Fusion:Tag) { - # The processor is disabled in BE or when rendering the AJAX request - @if.disableProcessor = ${!request.arguments.ajaxPathKey && !documentNode.context.inBackend} - tagName = 'a' - attributes.data-ajaxify = ${true} - attributes.href = Neos.Neos:NodeUri { - node = ${documentNode} - additionalParams.ajaxPathKey = Psmb.Ajaxify:RenderPath - } - content = Psmb.Ajaxify:Loader -} - -prototype(Psmb.Ajaxify:Renderer) { - @class = 'Psmb\\Ajaxify\\Fusion\\RendererImplementation' - node = ${documentNode} - pathKey = ${request.arguments.ajaxPathKey} - @cache { - mode = 'uncached' - context { - 1 = 'documentNode' - 2 = 'node' - } - } -} - -# Prevents search engines from indexing the partly rendered document content -prototype(Psmb.Ajaxify:UnindexedResponse) < prototype(Neos.Fusion:Http.Message) { - httpResponseHead.headers { - X-Robots-Tag = 'noindex, follow' - } - content = Psmb.Ajaxify:Renderer -} +include: **/*.fusion root.ajaxify { - @position = 'start' - condition = ${request.arguments.ajaxPathKey} - renderer = Psmb.Ajaxify:UnindexedResponse -} - -prototype(Psmb.Ajaxify:JsTag) < prototype(Neos.Fusion:Tag) { - tagName = 'script' - attributes.src = Neos.Fusion:ResourceUri { - path = 'resource://Psmb.Ajaxify/Public/ajax.js' - } -} -prototype(Psmb.Ajaxify:CssTag) < prototype(Neos.Fusion:Tag) { - tagName = 'link' - attributes.rel = 'stylesheet' - attributes.href = Neos.Fusion:ResourceUri { - path = 'resource://Psmb.Ajaxify/Public/loader.css' - } + @position = 'start' + condition = ${request.arguments.ajaxPathKey} + renderer = Psmb.Ajaxify:UnindexedResponse }