Created
January 16, 2020 12:44
-
-
Save celsowm/48227eb6c3d49648e435dcb46d1adf48 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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