Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: table pagination #166

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions conf/default.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@
$conf['sort'] = 0;
$conf['rsort'] = 0;
$conf['sortby'] = '';
$conf['pagination'] = 0;
$conf['rowsperpage'] = 10;
$conf['buttonsposition'] = 'bottom';
$conf['buttonswindow'] = 3;
4 changes: 4 additions & 0 deletions conf/metadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@
$meta['sort'] = array('onoff');
$meta['rsort'] = array('onoff');
$meta['sortby'] = array('string', '_pattern' => '/^([^&=]*)$/');
$meta['pagination'] = array('onoff');
$meta['rowsperpage'] = array('string', '_pattern' => '/^\d+$/');
$meta['buttonsposition'] = array('multichoice', '_choices' => array('top', 'bottom'));
$meta['buttonswindow'] = array('string', '_pattern' => '/^-?\d+$/');
40 changes: 39 additions & 1 deletion helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ public function __construct()
if($this->sortKey) {
$this->sort = true;
}
//Pagination flags
$this->pagination = $this->getConf('pagination'); //on-off
$this->rowsPerPage = $this->getConf('rowsperpage'); //string
$this->buttonsPosition = $this->getConf('buttonsposition'); //string (top, bottom)
$this->buttonsWindow = $this->getConf('buttonswindow'); //string

$this->plugins = [
'discussion' => ['comments'],
Expand Down Expand Up @@ -291,6 +296,8 @@ public function setFlags($flags)
case 'showdiff':
$flag = 'diff';
break;
case 'pagination':
$this->pagination = true;
}

// it is not required to set the sort flag, rsort flag will reverse.
Expand All @@ -315,6 +322,27 @@ public function setFlags($flags)
$value = true;
}

/**Pagination params. Rows per page */
if (substr($flag, 0, 12) == 'rowsperpage=') {
$this->rowsPerPage = (int) substr($flag, 12);
$this->pagination = true;
}

/**Pagination params. Navigation buttons position (top/bottom) */
if (substr($flag, 0, 16) == 'buttonsposition=') {
$this->buttonsPosition = substr($flag, 16);
if ($this->buttonsPosition != 'top' && $this->buttonsPosition != 'bottom') {
$this->buttonsPosition = 'bottom';
}
$this->pagination = true;
}

//**Pagination params. Regulate the max number of navigation show at the same time. Min possible value 2. Use -1 to disable*/
if (substr($flag, 0, 14) == 'buttonswindow=') {
$this->buttonsWindow = (int) substr($flag, 14);
$this->pagination = true;
}

if (isset($this->column[$flag]) && $flag !== 'page') {
$this->column[$flag] = $value;
}
Expand Down Expand Up @@ -354,7 +382,12 @@ public function startList($callerClass = null)
if ($callerClass) {
$class .= ' ' . $callerClass;
}
$this->doc = '<div class="table"><table class="' . $class . '">';
$this->doc = '<div class="table"><table class="' . $class;
//If pagination is active, add class and embedded data to the table tag
if($this->pagination) {
$this->doc .= ' table-with-pagination" data-rowsPerPage="' . $this->rowsPerPage . '" data-buttonsPosition="' . $this->buttonsPosition . '" data-buttonwindow="' . $this->buttonsWindow;
}
$this->doc .= '">';
} else {
// Simplelist is enabled; Skip header and firsthl
$this->showheader = false;
Expand Down Expand Up @@ -549,6 +582,11 @@ protected function renderPageRow($page)
$class .= $this->page['class'];
}

//If pagination is in use, all the rows start hidden (for fix 'flickering' onload)
if ($this->pagination) {
$class .= 'hidden ';
}

if (!empty($class)) {
$class = ' class="' . $class . '"';
}
Expand Down
122 changes: 122 additions & 0 deletions script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
document.addEventListener('DOMContentLoaded', function () {
//Get all tables with pagination class included
const tables = document.querySelectorAll('.table-with-pagination');

//Foreach table found in the wiki page
tables.forEach(table => {
const tableState = {
tableRef: table,
rowsRef: Array.from(table.getElementsByTagName('tr')).slice(1),
currentPage: 0,
rowsPerPage: Number(table.getAttribute('data-rowsperpage')) || 10, //Number of rows per page
buttonsPosition: table.getAttribute('data-buttonsposition') || 'bottom', //Position of buttons navigator
buttonsWindow: Number(table.getAttribute('data-buttonwindow')) || 3, //Number of max buttons in screen = buttonsWindow * 2 + 1 //Use -1 to disable
};
tableState.totalPages = Math.ceil(tableState.rowsRef.length / tableState.rowsPerPage);

createPageButtons(tableState); // Create the navigation buttons initially
showPage(tableState); // Set initial page state
});

function createPageButtons(tableState) {
const { totalPages, buttonsPosition, tableRef } = tableState;
const paginationTdContainer = document.createElement('td');

//Create buttons nodes
const buttonsRef = [];
for (let i = 0; i < totalPages; i++) {
buttonsRef.push(document.createElement('button'));
}

//Set style and evento for each button
for (let i = 0; i < totalPages; i++) {
buttonsRef[i].textContent = i + 1;
buttonsRef[i].classList.add('pagination-button');
//Event on click button
buttonsRef[i].addEventListener('click', () => {
tableState.currentPage = i;
showPage(tableState); //Set page content
setButtons(buttonsRef, tableState); //Set buttons state
});
paginationTdContainer.appendChild(buttonsRef[i]);
}

setButtons(buttonsRef, tableState); //Set buttons state

paginationTdContainer.classList.add('pagination-buttons-container');
paginationTdContainer.setAttribute('colspan', '99'); //to use all the width of the table
const paginationTrContainer = document.createElement('tr');
paginationTrContainer.appendChild(paginationTdContainer);

// Append the navigation buttons in the table
if (buttonsPosition == 'top') {
tableRef.insertBefore(paginationTrContainer, tableRef.firstChild);
} else {
tableRef.appendChild(paginationTrContainer);
}
}

//Set de buttons style and others elements of the navigation buttons
function setButtons(buttonsRef, tableState) {
const { currentPage, totalPages, buttonsWindow } = tableState;

for (let i = 0; i < totalPages; i++) {

//Set active class to the current page button
buttonsRef[i].classList.toggle('active', i == currentPage);

//Hidden extra buttons if buttonsWindow if set. Min value for buttonsWindow is 2.
if (buttonsWindow >= 2 && i >= 1 && i < totalPages - 1) {
const leftMargin = currentPage - buttonsWindow;
const rightMargin = currentPage + buttonsWindow;
const leftCompensation = leftMargin < 0 ? leftMargin : 0;
const rightCompensation = rightMargin - totalPages >= 0 ? rightMargin - totalPages + 1 : 0;

//Hide or reveal buttons base in current page
if ( leftMargin - rightCompensation < i && rightMargin - leftCompensation > i) {
buttonsRef[i].classList.toggle('hidden', false);
} else {
buttonsRef[i].classList.toggle('hidden', true);
}

//Hide or reveal space dots to limit the total number of buttons in screen
if ((currentPage - rightCompensation == i + buttonsWindow - 1) && i >= buttonsWindow - 1) {
deleteSpaceDots('left');
drawSpaceDots(buttonsRef, i, 'left')
} else if (currentPage - 1 < buttonsWindow) {
deleteSpaceDots('left');
}
if ((currentPage - leftCompensation + buttonsWindow - 1 == i) && i <= totalPages - buttonsWindow) {
deleteSpaceDots('right');
drawSpaceDots(buttonsRef, i, 'right')
} else if (currentPage + 1 >= totalPages - buttonsWindow) {
deleteSpaceDots('right');
}
}
}
}

//Draw space dots after or before a certain button
function drawSpaceDots(buttonsRef, i, side) {
const dotsRef = document.createElement('a');
dotsRef.textContent = " ..... ";
dotsRef.id = side == 'right' ? 'pagination_right_dots' : 'pagination_left_dots';
buttonsRef[i].insertAdjacentElement(side == 'right' ? 'afterend' : 'beforebegin', dotsRef);
}

//Delete left or right space dots
function deleteSpaceDots(side) {
const spaceDotsRef = document.getElementById( side == 'right' ? 'pagination_right_dots' : 'pagination_left_dots');
if (spaceDotsRef) spaceDotsRef.parentNode.removeChild(spaceDotsRef);
}

//Show and hide elements (rows) of a page
function showPage(tableState) {
const { currentPage, rowsPerPage, rowsRef } = tableState;
const startIndex = currentPage * rowsPerPage;
const endIndex = startIndex + rowsPerPage;
rowsRef.forEach((rowRef, index) => {
rowRef.classList.toggle('hidden', index < startIndex || index >= endIndex);
});
}
});
9 changes: 9 additions & 0 deletions style.css
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,12 @@ div.dokuwiki table.pagelist td.page,
div.dokuwiki table.ul td.page {
font-size: 100%;
}

div.dokuwiki button.pagination-button.active {
font-weight: bold;
}

td.pagination-buttons-container {
text-align: center;
background: none !important;
}