-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f68d049
commit 24f1c2d
Showing
2 changed files
with
289 additions
and
31 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,266 @@ | ||
|
||
function pagination_helper() { | ||
let _current_page = 1; | ||
let _data = {} | ||
let _num_total_items = 1; | ||
let _dom_element = ''; // The DOM element where the data will be put in | ||
let _items_per_page = 1; | ||
let _total_pages = 1; | ||
let _item_creation_callback; | ||
let _is_initialized = false; | ||
const NUM_PAGES_SHOW_ELLIPSIS = 2 | ||
|
||
|
||
function _calculate_num_pages() { | ||
_total_pages = Math.ceil(_num_total_items / _items_per_page); | ||
} | ||
|
||
/* Helper function for adding CSS classes to a paginato page button */ | ||
function _add_bootstrap_classes_to_page_li(el) { | ||
el.classList.add('page-item') | ||
el.firstChild.classList.add('page-link') | ||
return el | ||
} | ||
|
||
/* Callback to run when clicking the next page button */ | ||
function _goto_next_page() { | ||
if (_current_page + 1 > _total_pages) { | ||
_current_page = _total_pages; | ||
} | ||
else { | ||
_current_page += 1; | ||
} | ||
_goto_specific_page(_current_page) | ||
} | ||
|
||
/* Callback to run when clicking the previous page button */ | ||
function _goto_prev_page() { | ||
if (_current_page - 1 < 1) { | ||
_current_page = 1; | ||
} | ||
else { | ||
_current_page -= 1; | ||
} | ||
_goto_specific_page(_current_page) | ||
} | ||
|
||
/* Callback to run when clicking on a page button */ | ||
function _goto_specific_page(page_num) { | ||
if (page_num <= _total_pages && page_num >= 1) { | ||
_current_page = page_num; | ||
_clear_pagination_el() | ||
_create_pages() | ||
_clear_data() | ||
_fill_data() | ||
} | ||
} | ||
|
||
/* | ||
Function that crates a paginator button for a single page. | ||
content: can be either a DOM Element (in which case it is appended directly | ||
into the button), or a text/number, in which case it replaces the innerHTML. | ||
additional classes: a string of CSS classes to be added to the button (e.g., "class1 class2") | ||
onclick: the function to run when the button is clicked. It will be passed the | ||
DOM Element as an argument. | ||
title: the string to display on button mouse hover. | ||
*/ | ||
function _create_page_el(content, additional_classes, onclick, title) { | ||
let li = document.createElement('li') | ||
if (additional_classes) { | ||
li.classList.add(additional_classes) | ||
} | ||
if (title) { | ||
li.setAttribute('title', title) | ||
} | ||
let a = document.createElement('a') | ||
a.setAttribute.href = '#' | ||
if (content instanceof Element) { | ||
a.appendChild(content) | ||
} else if (typeof content === 'string' || typeof content === 'number') { | ||
a.innerHTML = content | ||
if (!title) { | ||
li.setAttribute('title', `Go to page ${content}`) | ||
} | ||
} | ||
if (typeof onclick === 'function') { | ||
li.onclick = onclick | ||
} | ||
li.appendChild(a) | ||
return _add_bootstrap_classes_to_page_li(li) | ||
} | ||
|
||
function _create_first_page_el() { | ||
let i = document.createElement('i') | ||
i.classList.add('bi', 'bi-chevron-double-left') | ||
|
||
return _create_page_el(i, _current_page === 1 ? "disabled" : "", | ||
() => { _goto_specific_page(1) }, "First page") | ||
} | ||
|
||
function _create_previous_page_el() { | ||
let i = document.createElement('i') | ||
i.classList.add('bi', 'bi-chevron-left') | ||
return _create_page_el(i, _current_page === 1 ? "disabled" : "", | ||
_goto_prev_page, "Previous page") | ||
} | ||
|
||
function _create_last_page_el() { | ||
let i = document.createElement('i') | ||
i.classList.add('bi', 'bi-chevron-double-right') | ||
return _create_page_el(i, (_current_page === _total_pages || _total_pages === 0) ? | ||
"disabled" : "", | ||
() => { _goto_specific_page(_total_pages) }, | ||
'Last page') | ||
} | ||
|
||
function _create_next_page_el() { | ||
let i = document.createElement('i') | ||
i.classList.add('bi', 'bi-chevron-right') | ||
return _create_page_el(i, (_current_page === _total_pages || _total_pages === 0) ? | ||
"disabled" : "", | ||
_goto_next_page, | ||
"Next page") | ||
} | ||
|
||
/* Create a single page button for a specific page */ | ||
function _create_page_number_el(page_num) { | ||
return _create_page_el( | ||
String(page_num), | ||
_current_page === page_num ? "active" : "", | ||
() => { _goto_specific_page(page_num) } | ||
) | ||
} | ||
|
||
/* Get the DOM element id where page buttons will be added */ | ||
function _get_pagination_el_id() { | ||
return `${_dom_element}_pagination` | ||
} | ||
|
||
/* Clear the pagination buttons completely */ | ||
function _clear_pagination_el() { | ||
let pagination_el = document.getElementById(_get_pagination_el_id()) | ||
if (pagination_el) { | ||
pagination_el.innerHTML = '' | ||
} | ||
} | ||
|
||
/* | ||
Create the pagination element under the same parent as the | ||
_dom_element passed at initialization. | ||
*/ | ||
function _create_pagination_el() { | ||
let base_el = document.getElementById(_dom_element).parentElement; | ||
let pagination_el = document.createElement('nav'); | ||
let ul_el = document.createElement('ul'); | ||
ul_el.classList.add('pagination', 'mt-2') | ||
ul_el.setAttribute('id', _get_pagination_el_id()) | ||
pagination_el.appendChild(ul_el) | ||
base_el.appendChild(pagination_el); | ||
} | ||
|
||
/* | ||
Create the page links inside the pagination DOM element. | ||
*/ | ||
function _create_pages() { | ||
let pagination_el = document.getElementById(_get_pagination_el_id()) | ||
pagination_el.appendChild(_create_first_page_el()) | ||
pagination_el.appendChild(_create_previous_page_el()) | ||
if (_total_pages < 3) { | ||
for (i = 1; i <= _total_pages; i++) { | ||
pagination_el.appendChild(_create_page_number_el(i)) | ||
} | ||
} | ||
else { | ||
if (_current_page - 1 <= NUM_PAGES_SHOW_ELLIPSIS) { | ||
for (let i = 1; i <= _current_page - 1; i++) { | ||
pagination_el.appendChild(_create_page_number_el(i)) | ||
} | ||
} | ||
else { | ||
pagination_el.appendChild(_create_page_el('...', 'disabled')) | ||
pagination_el.appendChild(_create_page_number_el(_current_page - 1)) | ||
} | ||
|
||
pagination_el.appendChild(_create_page_number_el(_current_page)) | ||
|
||
if (_total_pages - _current_page <= NUM_PAGES_SHOW_ELLIPSIS) { | ||
for (let i = _current_page + 1; i <= _total_pages; i++) { | ||
pagination_el.appendChild(_create_page_number_el(i)) | ||
} | ||
} | ||
else { | ||
pagination_el.appendChild(_create_page_number_el(_current_page + 1)) | ||
pagination_el.appendChild(_create_page_el('...', 'disabled')) | ||
|
||
} | ||
} | ||
pagination_el.appendChild(_create_next_page_el()) | ||
pagination_el.appendChild(_create_last_page_el()) | ||
} | ||
|
||
// Create a single li element for a single comparison report. | ||
function _create_result_list_element(data) { | ||
let li = document.createElement("li"); | ||
|
||
if (typeof _item_creation_callback === 'function') { | ||
li = _item_creation_callback(li, data) | ||
} | ||
return li; | ||
} | ||
|
||
function _clear_data() { | ||
let data_el = document.getElementById(_dom_element) | ||
data_el.innerHTML = '' | ||
} | ||
function _fill_data() { | ||
let data_el = document.getElementById(_dom_element) | ||
let index_start = (_current_page - 1) * _items_per_page | ||
let page_data = _data.slice(index_start, index_start + _items_per_page) | ||
page_data.forEach(element => { | ||
data_el.appendChild(_create_result_list_element(element)) | ||
}); | ||
} | ||
function _paginate(data, dom_element, item_creation_callback, items_per_page) { | ||
if (typeof data !== 'object' || !data.hasOwnProperty('length')) { | ||
throw Error(`data passed should be array-like, cannot initialize pagination`) | ||
} | ||
_data = data; | ||
_num_total_items = data.length; | ||
if (typeof dom_element !== 'string' || !document.getElementById(dom_element)) { | ||
throw Error(`Could not find DOM element "${dom_element}" to attach pagination to`) | ||
} | ||
_dom_element = dom_element; | ||
|
||
_items_per_page = Number(items_per_page) | ||
if (isNaN(_items_per_page)) { | ||
throw Error(`items_per_page should be a number, received ${typeof items_per_page}: ${items_per_page}`) | ||
} | ||
|
||
if (typeof item_creation_callback === 'function') { | ||
_item_creation_callback = item_creation_callback | ||
} | ||
_calculate_num_pages() | ||
_clear_pagination_el() | ||
_create_pagination_el() | ||
_create_pages() | ||
_clear_data() | ||
_fill_data() | ||
} | ||
/* "Public" methods are returned as an object with functions */ | ||
return { | ||
paginate: (data, dom_element, item_creation_callback, items_per_page = _items_per_page) => { | ||
_paginate(data, dom_element, item_creation_callback, items_per_page) | ||
_is_initialized = true | ||
}, | ||
data: (data) => { | ||
if (!_is_initialized) { | ||
throw Error(`Paginator has not been initialized!`) | ||
} | ||
_paginate(data, _dom_element, _item_creation_callback, _items_per_page) | ||
} | ||
} | ||
}; |
This file contains 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