Skip to content

Commit ca95dbd

Browse files
update
1 parent 36a2348 commit ca95dbd

File tree

4 files changed

+101
-4
lines changed

4 files changed

+101
-4
lines changed

src/Schema/Pagination/Paginator.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ private function paginationViews(?array $options = [])
228228
$this->pagination_css = $this->asset->views('simple');
229229
} elseif($view == $this->asset->views('loading')){
230230
$this->pagination_css = $this->asset->views('loading');
231+
} elseif($view == $this->asset->views('onloading')){
232+
$this->pagination_css = $this->asset->views('onloading');
231233
} else{
232234
$this->pagination_css = $this->asset->views('cursor');
233235
}

src/Schema/Pagination/PaginatorAsset.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public static function views($mode = null)
4646
'simple' => 'simple',
4747
'cursor' => 'cursor',
4848
'loading' => 'loading',
49+
'onloading' => 'onloading',
4950
];
5051

5152
return $data[$mode] ?? $data;
@@ -81,7 +82,7 @@ public static function getStyles(?string $mode = 'simple')
8182
return self::getSimpleCss();
8283
} elseif($mode == self::views('bootstrap')){
8384
return self::getBootstrapCss();
84-
} elseif($mode == self::views('loading')){
85+
} elseif($mode == self::views('loading') || $mode == self::views('onloading')){
8586
return self::getLoadingCss();
8687
} else {
8788
return self::getCursorCss();
@@ -91,7 +92,7 @@ public static function getStyles(?string $mode = 'simple')
9192
return self::getSimpleCss();
9293
} elseif($mode == self::views('bootstrap')){
9394
return self::getBootstrapCss();
94-
} elseif($mode == self::views('loading')){
95+
} elseif($mode == self::views('loading') || $mode == self::views('onloading')){
9596
return self::getLoadingCss();
9697
} else {
9798
return self::getCursorCss();
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<div class="onload-container" data-pagination-scope style="text-align: center; margin: 20px 0;">
2+
<?php
3+
// Prepare variables
4+
$page = $this->pagination->page;
5+
$totalPages = $this->pagination->pageCount;
6+
$isLast = $page >= $totalPages;
7+
$nextPage = min($totalPages, $page + 1);
8+
$nextUrl = $this->pagination->createUrl($nextPage);
9+
?>
10+
11+
<div class="onload-status" aria-live="polite" aria-atomic="true" style="margin:10px 0;">
12+
<?php if(!$isLast): ?>
13+
<span class="onload-text">Loading on scroll...</span>
14+
<?php else: ?>
15+
<span class="onload-text">No more content to load.</span>
16+
<?php endif; ?>
17+
</div>
18+
19+
<?php if(!$isLast): ?>
20+
<a <?=$linkAttributes?> href="<?=$nextUrl?>" class="onload-trigger" data-page="<?=$nextPage?>" data-mode="append" data-target="[data-pagination-append]" data-history="push" style="display:none;">Next</a>
21+
<?php endif; ?>
22+
</div>
23+
<script>
24+
// Infinite scroll (onloading view)
25+
(function(){
26+
if(window.__TAME_PAGINATION_ONLOADING_INITED__) return; // Guard against multiple inits
27+
window.__TAME_PAGINATION_ONLOADING_INITED__ = true;
28+
29+
function closestAnchor(el){
30+
while(el && el !== document){ if(el.tagName === 'A') return el; el = el.parentNode; }
31+
return null;
32+
}
33+
34+
function setupInfinite(scope){
35+
var link = scope.querySelector('.onload-trigger');
36+
if(!link) return;
37+
38+
var sentinel = document.createElement('div');
39+
sentinel.setAttribute('data-onload-sentinel', '');
40+
sentinel.style.cssText = 'height: 1px;';
41+
42+
var targetSelector = link.getAttribute('data-target') || '[data-pagination-content]';
43+
var container = document.querySelector(targetSelector);
44+
if(!container){ return; }
45+
46+
// place sentinel after container to detect end of list
47+
container.parentNode.insertBefore(sentinel, container.nextSibling);
48+
49+
var loading = false;
50+
var observer = new IntersectionObserver(function(entries){
51+
entries.forEach(function(entry){
52+
if(entry.isIntersecting && !loading){
53+
loading = true;
54+
link.click(); // reuse existing click/AJAX logic
55+
setTimeout(function(){ loading = false; }, 50);
56+
}
57+
});
58+
}, { rootMargin: '0px 0px 200px 0px' });
59+
60+
observer.observe(sentinel);
61+
62+
// Cleanup if controls are replaced
63+
scope.addEventListener('DOMNodeRemoved', function(ev){
64+
if(ev.target === scope){ try{ observer.disconnect(); }catch(_e){} }
65+
});
66+
}
67+
68+
// Delegate click to reuse loading view behavior with history
69+
document.addEventListener('click', function(e){
70+
var a = closestAnchor(e.target);
71+
if(!a) return;
72+
if(a.classList.contains('onload-trigger')){
73+
// Ensure it is treated as AJAX pagination
74+
a.setAttribute('data-pagination', 'ajax');
75+
}
76+
});
77+
78+
// Initialize for current scope
79+
document.querySelectorAll('[data-pagination-scope]').forEach(function(scope){
80+
if(scope.closest('.onload-container')){ setupInfinite(scope); }
81+
});
82+
83+
// After AJAX replacement, re-init when new scope appears
84+
var mo = new MutationObserver(function(){
85+
document.querySelectorAll('[data-pagination-scope]').forEach(function(scope){
86+
if(scope.closest('.onload-container') && !scope.__onloadInited){
87+
scope.__onloadInited = true;
88+
setupInfinite(scope);
89+
}
90+
});
91+
});
92+
mo.observe(document.documentElement, { childList: true, subtree: true });
93+
})();
94+
</script>

tests/testLoop.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99

1010
config_pagination([
1111
'allow' => true,
12-
'view' => 'cursor' //bootstrap|loading|cursor| simple[default]
12+
'view' => 'onloading' //bootstrap|loading|onloading|cursor| simple[default]
1313
]);
1414

1515
$wallets = $database->table('wallet')
1616
->where('amount', '>', 0)
1717
->join('user', 'user.user_id', '=', 'wallet.user_id')
1818
->latest('date')
19-
->paginate(3);
19+
->paginate(6);
2020
?>
2121

2222

0 commit comments

Comments
 (0)