226 lines
9.3 KiB
JavaScript
226 lines
9.3 KiB
JavaScript
var repoindex = (function(repoindex) {
|
|
|
|
// Adds a bootstrap pagination to the HTML element with the specified id
|
|
repoindex.Pagination = function(containerId) {
|
|
// basic initialization
|
|
this.containerId = containerId;
|
|
this.containerElement = document.getElementById(containerId);
|
|
this.currentElement = undefined;
|
|
this.elements = [];
|
|
this.entriesPerPage = 20;
|
|
this.entryCount = 0;
|
|
this.visibleElementsBeforeAfter = 7;
|
|
|
|
// define a default function which will be called when a pageElement is selected
|
|
this.pageSelected = function() {};
|
|
|
|
this.internalPageSelected = function(pageElement) {
|
|
repoindex.pageManager.rehash(pageElement && pageElement.pageIndex > 0 ? function(hash) {
|
|
hash[1].p = pageElement.pageIndex;
|
|
} : function(hash) {
|
|
delete hash[1].p;
|
|
});
|
|
this.pageSelected(pageElement);
|
|
};
|
|
|
|
// define a function to create page elements
|
|
this.createPageElement = function() {
|
|
var pageElement = document.createElement("li");
|
|
pageElement.pagination = this;
|
|
var aElement = document.createElement("a");
|
|
aElement.href = "#";
|
|
aElement.pageElement = pageElement;
|
|
pageElement.appendChild(aElement);
|
|
pageElement.setVisible = function(visible) {
|
|
this.style.display = visible ? "inline" : "none";
|
|
};
|
|
pageElement.setEnabled = function(enabled) {
|
|
this.className = enabled ? "" : "disabled";
|
|
};
|
|
pageElement.setActive = function(active) {
|
|
this.className = active ? "active" : "";
|
|
};
|
|
pageElement.setVisible(false);
|
|
return pageElement;
|
|
};
|
|
|
|
// initialize the "previous element"
|
|
this.previousElement = this.createPageElement();
|
|
this.previousElement.firstChild.setAttribute("aria-label", "Previous");
|
|
this.previousElement.firstChild.innerHTML = '<span aria-hidden="true">«</span>';
|
|
this.previousElement.select = function() {
|
|
var currentElement = this.pagination.currentElement;
|
|
if(currentElement && currentElement.previousElement) {
|
|
currentElement.previousElement.select();
|
|
}
|
|
};
|
|
|
|
this.previousElement.firstChild.onclick = function() {
|
|
this.pageElement.select();
|
|
return false;
|
|
};
|
|
this.previousElement.setVisible(true);
|
|
this.containerElement.appendChild(this.previousElement);
|
|
|
|
// initialize the "next element"
|
|
this.nextElement = this.createPageElement();
|
|
this.nextElement.firstChild.setAttribute("aria-label", "Next");
|
|
this.nextElement.firstChild.innerHTML = '<span aria-hidden="true">»</span>';
|
|
this.nextElement.select = function() {
|
|
var currentElement = this.pagination.currentElement;
|
|
if(currentElement && currentElement.nextElement) {
|
|
currentElement.nextElement.select();
|
|
}
|
|
};
|
|
|
|
// initialize the "settings element"
|
|
|
|
|
|
this.nextElement.firstChild.onclick = function() {
|
|
this.pageElement.select();
|
|
return false;
|
|
};
|
|
this.nextElement.setVisible(true);
|
|
this.containerElement.appendChild(this.nextElement);
|
|
|
|
// provide a function to append a page element
|
|
this.appendPage = function(name) {
|
|
// create and initiate the new page element
|
|
var pageElement = this.createPageElement();
|
|
|
|
// provide a select function for the page element (will be called when the page element
|
|
// is clicked)
|
|
pageElement.select = function() {
|
|
// update active/inactive status and visibility of all page elements
|
|
var pagination = this.pagination;
|
|
var updateVisibility = function(index, visible) {
|
|
var lowest = 0;
|
|
var highest = pagination.elements.length - 1;
|
|
var low = index - pagination.visibleElementsBeforeAfter;
|
|
var high = index + pagination.visibleElementsBeforeAfter;
|
|
if(low < lowest) {
|
|
high = Math.min(highest, high + lowest - low);
|
|
low = lowest;
|
|
} else if(high > highest) {
|
|
low = Math.max(lowest, low + highest - high);
|
|
high = highest;
|
|
}
|
|
for(var i = low; i <= high; ++i) {
|
|
pagination.elements[i].setVisible(visible);
|
|
}
|
|
}
|
|
if(pagination.currentElement) {
|
|
updateVisibility(pagination.currentElement.pageIndex, false);
|
|
pagination.currentElement.setActive(false);
|
|
}
|
|
updateVisibility(this.pageIndex, true);
|
|
this.setActive(true);
|
|
|
|
// update status of the containing pagination object
|
|
pagination.currentElement = this;
|
|
pagination.previousElement.setEnabled(this !== pagination.elements.first());
|
|
pagination.nextElement.setEnabled(this !== pagination.elements.last());
|
|
// call the pageSelected function to allow the managing objects to handle the page selection
|
|
pagination.internalPageSelected(this);
|
|
};
|
|
|
|
// invokes the specified function for each index of the currently visible range
|
|
pageElement.forRange = function(func, maxIndex) {
|
|
for(var i = this.pageIndex * this.pagination.entriesPerPage, pagesLeft = this.pagination.entriesPerPage;
|
|
pagesLeft > 0 && i < maxIndex; ++i, --pagesLeft) {
|
|
func(i);
|
|
}
|
|
};
|
|
|
|
// further initialization of the page element
|
|
pageElement.pageName = name;
|
|
var aElement = pageElement.firstChild;
|
|
aElement.appendChild(document.createTextNode(name));
|
|
// invoke the select method of the page element when clicked
|
|
aElement.onclick = function() {
|
|
this.pageElement.select();
|
|
return false;
|
|
};
|
|
|
|
if((pageElement.previousElement = this.elements.last())) {
|
|
pageElement.pageIndex = pageElement.previousElement.pageIndex + 1;
|
|
pageElement.previousElement.nextElement = pageElement;
|
|
} else {
|
|
pageElement.pageIndex = 0;
|
|
}
|
|
|
|
this.containerElement.insertBefore(pageElement, this.nextElement);
|
|
this.elements.push(pageElement);
|
|
};
|
|
|
|
// provide a function to append a range of page elements
|
|
this.appendPageRange = function(from, to) {
|
|
for(var i = from; i <= to; ++i) {
|
|
this.appendPage(i);
|
|
}
|
|
};
|
|
|
|
// provide a function to void selection
|
|
this.voidSelection = function() {
|
|
this.currentElement = undefined;
|
|
this.previousElement.setEnabled(false);
|
|
this.nextElement.setEnabled(false);
|
|
this.internalPageSelected();
|
|
}
|
|
|
|
// provide a function to remove all page elements
|
|
this.removePages = function(startIndex) {
|
|
if(!startIndex) {
|
|
startIndex = 0;
|
|
}
|
|
for(var i = startIndex, end = this.elements.length; i < end; ++i) {
|
|
this.containerElement.removeChild(this.elements[i]);
|
|
}
|
|
if(startIndex !== 0) {
|
|
this.elements.splice(startIndex, this.elements.length - startIndex);
|
|
this.elements.last().nextElement = null; // ensure the last element has no next element anymore
|
|
} else {
|
|
this.elements = [];
|
|
}
|
|
this.currentElement = undefined;
|
|
};
|
|
|
|
// provide a function to update the pagination (after properties such as the entryCount have been changed)
|
|
this.update = function() {
|
|
var requiredPages = Math.ceil(this.entryCount / this.entriesPerPage);
|
|
var currentPages = this.elements.length;
|
|
if(requiredPages < currentPages) {
|
|
this.removePages(requiredPages);
|
|
} else if(currentPages < requiredPages) {
|
|
this.appendPageRange(currentPages + 1, requiredPages);
|
|
}
|
|
// select the noted page or first element or void selection if there are no pages
|
|
if(this.notedPageIndex && (this.notedPageIndex < this.elements.length)) {
|
|
this.elements[this.notedPageIndex].select();
|
|
} else if(this.elements.first()) {
|
|
this.elements.first().select();
|
|
} else {
|
|
this.voidSelection();
|
|
}
|
|
};
|
|
|
|
this.currentPageIndex = function() {
|
|
if(this.currentElement && this.currentElement.pageIndex > 0) {
|
|
return this.currentElement.pageIndex;
|
|
}
|
|
};
|
|
|
|
this.selectPage = function(pageIndex) {
|
|
if(pageIndex && pageIndex >= 0) {
|
|
this.notedPageIndex = pageIndex;
|
|
if(pageIndex < this.elements.length) {
|
|
this.elements[pageIndex].select();
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
return repoindex;
|
|
|
|
})(repoindex || {});
|