Skip to content

Commit

Permalink
Merge pull request #10 from markusguenther/task/neos9-compatibility
Browse files Browse the repository at this point in the history
FEATURE: Adds compatibility for Neos 8.x
  • Loading branch information
lorenzulrich authored Mar 26, 2024
2 parents f1f4667 + 1d2a3bb commit 8f69ce8
Show file tree
Hide file tree
Showing 15 changed files with 131 additions and 123 deletions.
1 change: 0 additions & 1 deletion Classes/Fusion/RenderPathImplementation.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion Classes/Fusion/RendererImplementation.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
42 changes: 26 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.
12 changes: 12 additions & 0 deletions Resources/Private/Fusion/Component/Ajaxify.fusion
Original file line number Diff line number Diff line change
@@ -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
}
9 changes: 9 additions & 0 deletions Resources/Private/Fusion/Component/Loader.fusion
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
prototype(Psmb.Ajaxify:Loader) < prototype(Neos.Fusion:Component) {
renderer = afx`
<div class="spinner">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
`
}
17 changes: 17 additions & 0 deletions Resources/Private/Fusion/Component/Renderer.fusion
Original file line number Diff line number Diff line change
@@ -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'
}
7 changes: 7 additions & 0 deletions Resources/Private/Fusion/Component/UnindexedResponse.fusion
Original file line number Diff line number Diff line change
@@ -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
}
7 changes: 7 additions & 0 deletions Resources/Private/Fusion/Helper/CssTag.fusion
Original file line number Diff line number Diff line change
@@ -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'
}
}
6 changes: 6 additions & 0 deletions Resources/Private/Fusion/Helper/JsTag.fusion
Original file line number Diff line number Diff line change
@@ -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'
}
}
1 change: 0 additions & 1 deletion Resources/Private/Fusion/Override.fusion

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
prototype(Neos.Fusion:GlobalCacheIdentifiers) {
ajaxPathKey = ${request.arguments.ajaxPathKey}
}
65 changes: 4 additions & 61 deletions Resources/Private/Fusion/Root.fusion
Original file line number Diff line number Diff line change
@@ -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 = ${'<div class="spinner"><div class="bounce1"></div><div class="bounce2"></div><div class="bounce3"></div></div>'}
}

# 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
}
42 changes: 18 additions & 24 deletions Resources/Public/ajax.js
Original file line number Diff line number Diff line change
@@ -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';
}
}
})();
22 changes: 6 additions & 16 deletions Resources/Public/loader.css
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
19 changes: 16 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down Expand Up @@ -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"
]
}
}
}

0 comments on commit 8f69ce8

Please sign in to comment.