Skip to content

Commit

Permalink
Asynchronous control rendering trait + js for instant loading
Browse files Browse the repository at this point in the history
  • Loading branch information
vitkutny committed Mar 7, 2017
1 parent 8accba5 commit a5690e5
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/vendor
/composer.lock
/composer.phar
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
run-tests:
make composer.phar
php composer.phar install --no-interaction
vendor/bin/phpstan analyse -l 5 src

composer.phar:
# Download Composer https://getcomposer.org/download/
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
php -r "unlink('composer-setup.php');"
61 changes: 60 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,60 @@
# AsyncControl
# AsyncControl

Trait for asynchronous control rendering.

## Usage

### Trait

```php
<?php
class CommentsControl extends Nette\Application\UI\Control {

use Pd\AsyncControl\UI\AsyncControlTrait;

public function render() {
//control rendering
}
}
```

If you want to call different method than `render` set custom render callback:

```php
<?php
$this->setAsyncRenderer([$this, 'customRender']);
//or
$this->setAsyncRenderer(function () {
//control rendering
});
```

### Template

```latte
{control comments:async}
```

or with custom message

```latte
{control comments:async 'Show comments'}
```

## Configuring

You can set default message and attributes used for loading link in `bootstrap.php`

```php
<?php
Pd\AsyncControl\UI\AsyncControlLink::setDefault('Load content', ['class' => ['btn', 'ajax']]);
```

or in application setup

```neon
services:
application:
setup:
- Pd\AsyncControl\UI\AsyncControlLink::setDefault('Load content', {class: [btn, ajax]})
```
14 changes: 14 additions & 0 deletions bower.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "async.nette.ajax.js",
"homepage": "https://github.com/peckadesign/AsyncControl",
"authors": [
"PeckaDesign <support@peckadesign.cz>",
"Vít Kutný <vit.kutny@peckadesign.cz>"
],
"main": "src/assets/async.nette.ajax.js",
"license": "MIT",
"dependencies": {
"jquery": ">=1.7",
"nette.ajax.js": ">=2.0"
}
}
35 changes: 35 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "pd/async-control",
"description": "Trait for asynchronous control rendering",
"keywords": [
"async",
"control",
"nette"
],
"homepage": "https://github.com/peckadesign/AsyncControl",
"license": [
"MIT"
],
"authors": [
{
"name": "PeckaDesign",
"homepage": "http://www.peckadesign.cz"
},
{
"name": "Vít Kutný",
"homepage": "https://github.com/vitkutny"
}
],
"require": {
"php": "~7.0",
"nette/application": "^2.2"
},
"require-dev": {
"phpstan/phpstan": "~0.6.0"
},
"autoload": {
"psr-4": {
"Pd\\AsyncControl\\": "src/"
}
}
}
46 changes: 46 additions & 0 deletions src/UI/AsyncControlLink.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php declare(strict_types = 1);

namespace Pd\AsyncControl\UI;

final class AsyncControlLink
{

private static $defaultMessage = 'Load content';
private static $defaultAttributes = [];
/**
* @var string
*/
private $message;
/**
* @var array
*/
private $attributes;


public function __construct(
string $message = NULL,
array $attributes = NULL
) {
$this->message = $message === NULL ? self::$defaultMessage : $message;
$this->attributes = $attributes === NULL ? self::$defaultAttributes : $attributes;
}


public static function setDefault(string $message, array $attributes = [])
{
self::$defaultMessage = $message;
self::$defaultAttributes = $attributes;
}


public function getMessage(): string
{
return $this->message;
}


public function getAttributes(): array
{
return $this->attributes;
}
}
63 changes: 63 additions & 0 deletions src/UI/AsyncControlTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php declare(strict_types = 1);

namespace Pd\AsyncControl\UI;

use Nette\Application\UI\Control;
use Nette\Application\UI\Presenter;
use Nette\Application\UI\PresenterComponent;


/**
* @method render
*/
trait AsyncControlTrait
{

/**
* @var callable
*/
protected $asyncRenderer;


public function handleAsyncLoad()
{
if ( ! $this instanceof PresenterComponent || ! ($presenter = $this->getPresenter(FALSE)) || ! $presenter->isAjax()) {
return;
}
ob_start(function () {
});
try {
$this->renderAsync();
} catch (\Throwable $e) {
ob_end_clean();
throw $e;
} catch (\Exception $e) {
ob_end_clean();
throw $e;
}
$content = ob_get_clean();
$presenter->getPayload()->snippets[$this->getSnippetId('async')] = $content;
$presenter->sendPayload();
}


public function renderAsync(string $linkMessage = NULL, array $linkAttributes = NULL)
{
if ($this instanceof Control && strpos((string) $this->getPresenter()->getParameter(Presenter::SIGNAL_KEY), sprintf('%s-', $this->getUniqueId())) !== 0) {
$template = $this->createTemplate();
$template->link = new AsyncControlLink($linkMessage, $linkAttributes);
$template->setFile(__DIR__ . '/templates/asyncLoadLink.latte');
$template->render();
} elseif (is_callable($this->asyncRenderer)) {
call_user_func($this->asyncRenderer);
} else {
$this->render();
}
}


public function setAsyncRenderer(callable $renderer)
{
$this->asyncRenderer = $renderer;
}
}
5 changes: 5 additions & 0 deletions src/UI/templates/asyncLoadLink.latte
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div n:snippet="async">
<a n:href="asyncLoad!" n:attr="(expand) $link->getAttributes()" data-async>
{$link->getMessage()|translate}
</a>
</div>
24 changes: 24 additions & 0 deletions src/assets/async.nette.ajax.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
(function ($) {
$.nette.ext({
init: function () {
this.init();
},
success: function () {
this.init();
}
}, {
init: function () {
$('[data-async]').each(function () {
var $this = $(this);
if ($this.data('asyncInitialized')) {
return;
}
$this.data('asyncInitialized', true);
$.nette.ajax({
url: $this.data('asyncLink') || $this.attr('href'),
off: ['history', 'unique']
});
});
}
});
})(window.jQuery);

0 comments on commit a5690e5

Please sign in to comment.