176 lines
5.5 KiB
Text
176 lines
5.5 KiB
Text
<script type="text/x-template" id="pagination">
|
|
<div class="pagination-container" v-if="!isInfinite">
|
|
<button
|
|
class="md-btn page-btn"
|
|
:disabled="effectivePage === 1"
|
|
@click="goToPage(1)"
|
|
>
|
|
<img class="md-ico-first" />
|
|
</button>
|
|
<button
|
|
class="md-btn page-btn prev"
|
|
:disabled="effectivePage === 1"
|
|
@click="goToPrevious()"
|
|
>
|
|
<img class="md-ico-prev" />
|
|
</button>
|
|
<button
|
|
:class="`md-btn page-btn${ isCurrentPage(page) ? ' md-btn-primary': ''}`"
|
|
@click="goToPage(page)"
|
|
v-for="page in pagesToShow"
|
|
>{{ page }}
|
|
</button>
|
|
<button
|
|
class="md-btn page-btn next"
|
|
:disabled="effectivePage === numPages"
|
|
@click="goToNext()"
|
|
>
|
|
<img class="md-ico-next" />
|
|
</button>
|
|
<button
|
|
class="md-btn page-btn last"
|
|
:disabled="effectivePage === numPages"
|
|
@click="goToEnd()"
|
|
>
|
|
<img class="md-ico-last" />
|
|
</button>
|
|
<div class="page-btn md-input-number">
|
|
<input type="number" min="1" :max="numPages" :value="effectivePage" @change="changePage" />
|
|
<span>/ {{ numPages }}</span>
|
|
</div>
|
|
</div>
|
|
</script>
|
|
|
|
<script>
|
|
Vue.component('pagination', {
|
|
template: "#pagination",
|
|
props: {
|
|
'length': { type: Number, required: true },
|
|
'pageSize': { type: Number, required: true },
|
|
'scroll': { type: String, required: true },
|
|
'scrollSelector': { type: String, required: true }
|
|
},
|
|
data: function() {
|
|
return { currentPage: 1 }
|
|
},
|
|
mounted() {
|
|
document.querySelector(this.scrollSelector)
|
|
.addEventListener("scroll", this.handleScroll)
|
|
},
|
|
destroyed() {
|
|
document.querySelector(this.scrollSelector)
|
|
.removeEventListener("scroll", this.handleScroll)
|
|
},
|
|
watch: {
|
|
'length': function() {
|
|
if (this.isInfinite) {
|
|
// If a search reduces the number of things to show, we want to limit
|
|
// the number of songs shown as well. This is to prevent you scrolling
|
|
// to load your entire library, searching for one song, and then having
|
|
// th re-render the entire library
|
|
if (this.currentPage > this.numPages) {
|
|
this.currentPage = this.numPages;
|
|
this.$emit("onRangeChange", this.currentRange);
|
|
}
|
|
} else {
|
|
this.$emit("onRangeChange", this.currentRange);
|
|
}
|
|
},
|
|
'scroll': function() {
|
|
// When changing modes, set the page to 1. This is primarily to
|
|
// prevent going to a high page (e.g., 50) and then switching to infinite
|
|
// and showing 12.5k songs
|
|
this.currentPage = 1;
|
|
this.$emit("onRangeChange", this.currentRange);
|
|
}
|
|
},
|
|
computed: {
|
|
isInfinite: function() {
|
|
return this.scroll === "infinite"
|
|
},
|
|
currentRange: function() {
|
|
if (this.isInfinite) {
|
|
return [0, this.currentPage * this.pageSize];
|
|
} else {
|
|
const startingPage = Math.min(this.numPages, this.currentPage);
|
|
|
|
return [
|
|
(startingPage - 1) * this.pageSize,
|
|
startingPage * this.pageSize
|
|
];
|
|
}
|
|
},
|
|
effectivePage: function() {
|
|
return Math.min(this.currentPage, this.numPages)
|
|
},
|
|
numPages: function() {
|
|
return Math.ceil(this.length / this.pageSize) || 1;
|
|
},
|
|
pagesToShow: function() {
|
|
let start = this.currentPage - 2;
|
|
let end = this.currentPage + 2;
|
|
|
|
if (start < 1) {
|
|
end += (1 - start);
|
|
start = 1;
|
|
}
|
|
|
|
const endDifference = end - this.numPages;
|
|
if (endDifference > 0) {
|
|
end = this.numPages;
|
|
start = Math.max(1, start - endDifference);
|
|
}
|
|
|
|
const array = [];
|
|
for (let idx = start; idx <= end; idx++) {
|
|
array.push(idx);
|
|
}
|
|
return array;
|
|
}
|
|
},
|
|
methods: {
|
|
// Infinite Scrolling
|
|
handleScroll: function(event) {
|
|
if (this.isInfinite &&
|
|
this.currentPage < this.numPages &&
|
|
event.target.scrollTop >= event.target.scrollHeight - event.target.clientHeight) {
|
|
this.currentPage += 1;
|
|
this.$emit("onRangeChange", this.currentRange);
|
|
}
|
|
},
|
|
// Pagination
|
|
isCurrentPage: function(idx) {
|
|
return idx === this.currentPage ||
|
|
(idx === this.numPages && this.currentPage > this.numPages);
|
|
},
|
|
changePage: function(event) {
|
|
const value = event.target.valueAsNumber;
|
|
|
|
if (!isNaN(value) && value >= 1 && value <= this.numPages) {
|
|
this.currentPage = value;
|
|
this.$emit("onRangeChange", this.currentRange);
|
|
}
|
|
},
|
|
goToPage: function(page) {
|
|
this.currentPage = page;
|
|
this.$emit("onRangeChange", this.currentRange);
|
|
},
|
|
goToPrevious: function() {
|
|
if (this.currentPage > 1) {
|
|
this.currentPage -= 1;
|
|
this.$emit("onRangeChange", this.currentRange);
|
|
}
|
|
},
|
|
goToNext: function() {
|
|
if (this.currentPage < this.numPages) {
|
|
this.currentPage += 1;
|
|
this.$emit("onRangeChange", this.currentRange);
|
|
}
|
|
},
|
|
goToEnd: function() {
|
|
this.currentPage = this.numPages;
|
|
this.$emit("onRangeChange", this.currentRange);
|
|
}
|
|
}
|
|
})
|
|
</script>
|