Skip to content

Instantly share code, notes, and snippets.

@celsowm
Created January 16, 2020 12:44
Show Gist options
  • Save celsowm/48227eb6c3d49648e435dcb46d1adf48 to your computer and use it in GitHub Desktop.
Save celsowm/48227eb6c3d49648e435dcb46d1adf48 to your computer and use it in GitHub Desktop.
<?php
namespace App\View\Helper;
use Cake\View\Helper\PaginatorHelper;
class AjaxPaginatorHelper extends PaginatorHelper {
private $formId;
private $responseId;
public $helpers = ['Url', 'Number', 'Html', 'Form', 'Text'];
const REGEX_HREF = '/href="(?P<url>.*?)"/mi';
private function getLoadingCSS(){
return <<<JS
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = `
#spinner:not([hidden]) {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
}
#spinner::after {
content: '';
width: 80px;
height: 80px;
border: 4px solid #88ccf1;
border-top: 3px solid #b8ebff;
border-radius: 100%;
will-change: transform;
animation: spin 1s infinite linear;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
`;
document.getElementsByTagName('head')[0].appendChild(style);
JS;
}
private function getJsFetch($url) {
$this->testResponseId();
//não alterar a identação do NOWDOC por compatibilidade com PHP <=7.2
$js = <<<JS
const spinner = document.getElementById('spinner');
spinner.removeAttribute('hidden');
window.fetch('$url', {
method: 'get'
}).then(function (response) {
return response.text();
}).then(function (text) {
spinner.setAttribute('hidden', '');
document.getElementById('{$this->responseId}')
.innerHTML = text;
});
JS;
return $js;
}
private function testResponseId() {
if (!$this->responseId) {
throw new \Exception("Id da div para resposta do fetch não foi setada, "
. "use o método \$this->AjaxPaginator->setDivResponseId() neste .ctp");
}
}
public function setFormId(string $formId) {
$this->formId = $formId;
return $this;
}
public function setDivResponseId(string $responseId) {
$this->responseId = $responseId;
return $this;
}
public function submit(string $caption, array $options = []) {
if (!$this->formId) {
throw new \Exception("Id do formulário não foi setado, use o método setFormId");
}
$this->testResponseId();
//não alterar a identação do NOWDOC por compatibilidade com PHP <=7.2
$js = $this->Html->scriptBlock(
<<<JS
document.addEventListener('DOMContentLoaded', function() {
{$this->getLoadingCSS()}
const form = document.getElementById('{$this->formId}');
const spinner = document.getElementById('spinner');
form.addEventListener('submit', function (event) {
event.preventDefault();
spinner.removeAttribute('hidden');
let queryString = new URLSearchParams(new FormData(this))
.toString();
let url = this.getAttribute("action") + "?" + queryString;
window.fetch(url, {
method: 'get'
}).then(function (response) {
return response.text();
}).then(function (text) {
spinner.setAttribute('hidden', '');
document.getElementById('{$this->responseId}')
.innerHTML = text;
});
});
let queryString = new URLSearchParams(new FormData(form))
.toString();
let url = form.getAttribute("action") + "?" + queryString;
spinner.removeAttribute('hidden');
window.fetch(url, {
method: 'get'
}).then(function (response) {
return response.text();
}).then(function (text) {
spinner.setAttribute('hidden', '');
document.getElementById('{$this->responseId}')
.innerHTML = text;
});
});
JS
);
$button = $this->Form->submit($caption, $options);
$div = $this->Html->tag('div', ' ', ['hidden', 'id'=>'spinner']);
return $js . "\n" . $button. "\n" .$div;
}
public function asyncLinks($method, $title, $options, $key = null) {
if($key === null){
$original = parent::{$method}($title, $options);
}else{
$original = parent::{$method}($key, $title, $options);
}
preg_match(self::REGEX_HREF, $original, $matches);
if (isset($matches['url'])) {
$url = $matches['url'];
}
$js = $this->getJsFetch($url);
$newNext = preg_replace(self::REGEX_HREF, "href=\"#\" onclick=\"$js\"", $original);
return $newNext;
}
public function next($title = 'Next >>', array $options = array()) {
return $this->asyncLinks(__FUNCTION__, $title, $options);
}
public function prev($title = '<< Previous', array $options = array()) {
return $this->asyncLinks(__FUNCTION__, $title, $options);
}
public function first($title = '<< first', array $options = array()) {
return $this->asyncLinks(__FUNCTION__, $title, $options);
}
public function last($title = 'last >>', array $options = array()) {
return $this->asyncLinks(__FUNCTION__, $title, $options);
}
public function numbers(array $options = array()) {
$original = parent::numbers($options);
$matches = [];
preg_match_all(self::REGEX_HREF, $original, $matches);
if (isset($matches['url'])) {
foreach ($matches['url'] as $key => $match) {
if(trim($match) && isset($matches[0][$key])){
$url = $match;
$js = $this->getJsFetch($url);
$original = str_ireplace(
$matches[0][$key],
"href=\"#\" onclick=\"$js\"",
$original);
}
}
}
return $original;
}
public function sort($key, $title = null, array $options = []){
return $this->asyncLinks(__FUNCTION__, $title, $options, $key);
}
public function paginatorLinks() {
$this->options([
'url' => array_merge($_GET, $this->request->params['pass'])
]);
return $this->Html->nestedList([
$this->prev('<< Anterior'),
$this->numbers(),
$this->next('>> Próximo')
], ['class' => 'pagination']);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment