Skip to content

Commit a5690e5

Browse files
committed
Asynchronous control rendering trait + js for instant loading
1 parent 8accba5 commit a5690e5

9 files changed

+260
-1
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/vendor
2+
/composer.lock
3+
/composer.phar

Makefile

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
run-tests:
2+
make composer.phar
3+
php composer.phar install --no-interaction
4+
vendor/bin/phpstan analyse -l 5 src
5+
6+
composer.phar:
7+
# Download Composer https://getcomposer.org/download/
8+
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
9+
php composer-setup.php
10+
php -r "unlink('composer-setup.php');"

README.md

+60-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,60 @@
1-
# AsyncControl
1+
# AsyncControl
2+
3+
Trait for asynchronous control rendering.
4+
5+
## Usage
6+
7+
### Trait
8+
9+
```php
10+
<?php
11+
class CommentsControl extends Nette\Application\UI\Control {
12+
13+
use Pd\AsyncControl\UI\AsyncControlTrait;
14+
15+
public function render() {
16+
//control rendering
17+
}
18+
}
19+
```
20+
21+
If you want to call different method than `render` set custom render callback:
22+
23+
```php
24+
<?php
25+
$this->setAsyncRenderer([$this, 'customRender']);
26+
//or
27+
$this->setAsyncRenderer(function () {
28+
//control rendering
29+
});
30+
```
31+
32+
### Template
33+
34+
```latte
35+
{control comments:async}
36+
```
37+
38+
or with custom message
39+
40+
```latte
41+
{control comments:async 'Show comments'}
42+
```
43+
44+
## Configuring
45+
46+
You can set default message and attributes used for loading link in `bootstrap.php`
47+
48+
```php
49+
<?php
50+
Pd\AsyncControl\UI\AsyncControlLink::setDefault('Load content', ['class' => ['btn', 'ajax']]);
51+
```
52+
53+
or in application setup
54+
55+
```neon
56+
services:
57+
application:
58+
setup:
59+
- Pd\AsyncControl\UI\AsyncControlLink::setDefault('Load content', {class: [btn, ajax]})
60+
```

bower.json

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "async.nette.ajax.js",
3+
"homepage": "https://github.com/peckadesign/AsyncControl",
4+
"authors": [
5+
"PeckaDesign <[email protected]>",
6+
"Vít Kutný <[email protected]>"
7+
],
8+
"main": "src/assets/async.nette.ajax.js",
9+
"license": "MIT",
10+
"dependencies": {
11+
"jquery": ">=1.7",
12+
"nette.ajax.js": ">=2.0"
13+
}
14+
}

composer.json

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "pd/async-control",
3+
"description": "Trait for asynchronous control rendering",
4+
"keywords": [
5+
"async",
6+
"control",
7+
"nette"
8+
],
9+
"homepage": "https://github.com/peckadesign/AsyncControl",
10+
"license": [
11+
"MIT"
12+
],
13+
"authors": [
14+
{
15+
"name": "PeckaDesign",
16+
"homepage": "http://www.peckadesign.cz"
17+
},
18+
{
19+
"name": "Vít Kutný",
20+
"homepage": "https://github.com/vitkutny"
21+
}
22+
],
23+
"require": {
24+
"php": "~7.0",
25+
"nette/application": "^2.2"
26+
},
27+
"require-dev": {
28+
"phpstan/phpstan": "~0.6.0"
29+
},
30+
"autoload": {
31+
"psr-4": {
32+
"Pd\\AsyncControl\\": "src/"
33+
}
34+
}
35+
}

src/UI/AsyncControlLink.php

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Pd\AsyncControl\UI;
4+
5+
final class AsyncControlLink
6+
{
7+
8+
private static $defaultMessage = 'Load content';
9+
private static $defaultAttributes = [];
10+
/**
11+
* @var string
12+
*/
13+
private $message;
14+
/**
15+
* @var array
16+
*/
17+
private $attributes;
18+
19+
20+
public function __construct(
21+
string $message = NULL,
22+
array $attributes = NULL
23+
) {
24+
$this->message = $message === NULL ? self::$defaultMessage : $message;
25+
$this->attributes = $attributes === NULL ? self::$defaultAttributes : $attributes;
26+
}
27+
28+
29+
public static function setDefault(string $message, array $attributes = [])
30+
{
31+
self::$defaultMessage = $message;
32+
self::$defaultAttributes = $attributes;
33+
}
34+
35+
36+
public function getMessage(): string
37+
{
38+
return $this->message;
39+
}
40+
41+
42+
public function getAttributes(): array
43+
{
44+
return $this->attributes;
45+
}
46+
}

src/UI/AsyncControlTrait.php

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Pd\AsyncControl\UI;
4+
5+
use Nette\Application\UI\Control;
6+
use Nette\Application\UI\Presenter;
7+
use Nette\Application\UI\PresenterComponent;
8+
9+
10+
/**
11+
* @method render
12+
*/
13+
trait AsyncControlTrait
14+
{
15+
16+
/**
17+
* @var callable
18+
*/
19+
protected $asyncRenderer;
20+
21+
22+
public function handleAsyncLoad()
23+
{
24+
if ( ! $this instanceof PresenterComponent || ! ($presenter = $this->getPresenter(FALSE)) || ! $presenter->isAjax()) {
25+
return;
26+
}
27+
ob_start(function () {
28+
});
29+
try {
30+
$this->renderAsync();
31+
} catch (\Throwable $e) {
32+
ob_end_clean();
33+
throw $e;
34+
} catch (\Exception $e) {
35+
ob_end_clean();
36+
throw $e;
37+
}
38+
$content = ob_get_clean();
39+
$presenter->getPayload()->snippets[$this->getSnippetId('async')] = $content;
40+
$presenter->sendPayload();
41+
}
42+
43+
44+
public function renderAsync(string $linkMessage = NULL, array $linkAttributes = NULL)
45+
{
46+
if ($this instanceof Control && strpos((string) $this->getPresenter()->getParameter(Presenter::SIGNAL_KEY), sprintf('%s-', $this->getUniqueId())) !== 0) {
47+
$template = $this->createTemplate();
48+
$template->link = new AsyncControlLink($linkMessage, $linkAttributes);
49+
$template->setFile(__DIR__ . '/templates/asyncLoadLink.latte');
50+
$template->render();
51+
} elseif (is_callable($this->asyncRenderer)) {
52+
call_user_func($this->asyncRenderer);
53+
} else {
54+
$this->render();
55+
}
56+
}
57+
58+
59+
public function setAsyncRenderer(callable $renderer)
60+
{
61+
$this->asyncRenderer = $renderer;
62+
}
63+
}

src/UI/templates/asyncLoadLink.latte

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div n:snippet="async">
2+
<a n:href="asyncLoad!" n:attr="(expand) $link->getAttributes()" data-async>
3+
{$link->getMessage()|translate}
4+
</a>
5+
</div>

src/assets/async.nette.ajax.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
(function ($) {
2+
$.nette.ext({
3+
init: function () {
4+
this.init();
5+
},
6+
success: function () {
7+
this.init();
8+
}
9+
}, {
10+
init: function () {
11+
$('[data-async]').each(function () {
12+
var $this = $(this);
13+
if ($this.data('asyncInitialized')) {
14+
return;
15+
}
16+
$this.data('asyncInitialized', true);
17+
$.nette.ajax({
18+
url: $this.data('asyncLink') || $this.attr('href'),
19+
off: ['history', 'unique']
20+
});
21+
});
22+
}
23+
});
24+
})(window.jQuery);

0 commit comments

Comments
 (0)