quasar
Version:
Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
408 lines (359 loc) • 9.09 kB
JavaScript
import Vue from 'vue'
import QBtn from '../btn/QBtn.js'
import QInput from '../input/QInput.js'
import DarkMixin from '../../mixins/dark.js'
import ListenersMixin from '../../mixins/listeners.js'
import { stop } from '../../utils/event.js'
import { between } from '../../utils/format.js'
import { isKeyCode } from '../../utils/key-composition.js'
import cache from '../../utils/cache.js'
export default Vue.extend({
name: 'QPagination',
mixins: [ DarkMixin, ListenersMixin ],
props: {
value: {
type: Number,
required: true
},
min: {
type: Number,
default: 1
},
max: {
type: Number,
required: true
},
color: {
type: String,
default: 'primary'
},
textColor: String,
inputStyle: [Array, String, Object],
inputClass: [Array, String, Object],
size: String,
disable: Boolean,
input: Boolean,
iconPrev: String,
iconNext: String,
iconFirst: String,
iconLast: String,
toFn: Function,
boundaryLinks: {
type: Boolean,
default: null
},
boundaryNumbers: {
type: Boolean,
default: null
},
directionLinks: {
type: Boolean,
default: null
},
ellipses: {
type: Boolean,
default: null
},
maxPages: {
type: Number,
default: 0,
validator: v => v >= 0
},
ripple: {
type: [Boolean, Object],
default: null
},
round: Boolean,
rounded: Boolean,
outline: Boolean,
unelevated: Boolean,
push: Boolean,
glossy: Boolean,
dense: Boolean,
padding: {
type: String,
default: '6px 5px'
}
},
data () {
return {
newPage: null
}
},
watch: {
min () {
this.model = this.value
},
max () {
this.model = this.value
}
},
computed: {
model: {
get () {
return this.value
},
set (val) {
val = parseInt(val, 10)
if (this.disable || isNaN(val) || val === 0) {
return
}
const value = between(val, this.min, this.max)
this.$emit('input', value)
}
},
inputPlaceholder () {
return this.model + ' / ' + this.max
},
__boundaryLinks () {
return this.__getBool(this.boundaryLinks, this.input)
},
__boundaryNumbers () {
return this.__getBool(this.boundaryNumbers, !this.input)
},
__directionLinks () {
return this.__getBool(this.directionLinks, this.input)
},
__ellipses () {
return this.__getBool(this.ellipses, !this.input)
},
icons () {
const ico = [
this.iconFirst || this.$q.iconSet.pagination.first,
this.iconPrev || this.$q.iconSet.pagination.prev,
this.iconNext || this.$q.iconSet.pagination.next,
this.iconLast || this.$q.iconSet.pagination.last
]
return this.$q.lang.rtl === true ? ico.reverse() : ico
},
attrs () {
if (this.disable === true) {
return {
'aria-disabled': 'true'
}
}
},
btnProps () {
return {
round: this.round,
rounded: this.rounded,
outline: this.outline,
unelevated: this.unelevated,
push: this.push,
glossy: this.glossy,
dense: this.dense,
padding: this.padding,
color: this.color,
flat: true,
size: this.size,
ripple: this.ripple !== null
? this.ripple
: true
}
}
},
methods: {
set (value) {
this.model = value
},
setByOffset (offset) {
this.model = this.model + offset
},
__update () {
this.model = this.newPage
this.newPage = null
},
__getBool (val, otherwise) {
return [true, false].includes(val)
? val
: otherwise
},
__getBtn (h, data, props, page) {
data.props = {
...this.btnProps,
...props
}
if (page !== void 0) {
if (this.toFn !== void 0) {
data.props.to = this.toFn(page)
}
else {
data.on = { click: () => this.set(page) }
}
}
return h(QBtn, data)
}
},
render (h) {
const
contentStart = [],
contentEnd = [],
contentMiddle = []
if (this.__boundaryLinks) {
contentStart.push(this.__getBtn(h, {
key: 'bls'
}, {
disable: this.disable || this.value <= this.min,
icon: this.icons[0]
}, this.min))
contentEnd.unshift(this.__getBtn(h, {
key: 'ble'
}, {
disable: this.disable || this.value >= this.max,
icon: this.icons[3]
}, this.max))
}
if (this.__directionLinks) {
contentStart.push(this.__getBtn(h, {
key: 'bdp'
}, {
disable: this.disable || this.value <= this.min,
icon: this.icons[1]
}, this.value - 1))
contentEnd.unshift(this.__getBtn(h, {
key: 'bdn'
}, {
disable: this.disable || this.value >= this.max,
icon: this.icons[2]
}, this.value + 1))
}
if (this.input === true) {
contentMiddle.push(h(QInput, {
staticClass: 'inline',
style: {
width: `${this.inputPlaceholder.length / 1.5}em`
},
props: {
type: 'number',
dense: true,
value: this.newPage,
disable: this.disable,
dark: this.isDark,
borderless: true,
inputClass: this.inputClass,
inputStyle: this.inputStyle
},
attrs: {
placeholder: this.inputPlaceholder,
min: this.min,
max: this.max
},
on: cache(this, 'inp', {
input: value => { this.newPage = value },
keyup: e => { isKeyCode(e, 13) === true && this.__update() },
blur: this.__update
})
}))
}
else { // is type select
let
maxPages = Math.max(
this.maxPages,
1 + (this.__ellipses ? 2 : 0) + (this.__boundaryNumbers ? 2 : 0)
),
pgFrom = this.min,
pgTo = this.max,
ellipsesStart = false,
ellipsesEnd = false,
boundaryStart = false,
boundaryEnd = false
if (this.maxPages && maxPages < (this.max - this.min + 1)) {
maxPages = 1 + Math.floor(maxPages / 2) * 2
pgFrom = Math.max(this.min, Math.min(this.max - maxPages + 1, this.value - Math.floor(maxPages / 2)))
pgTo = Math.min(this.max, pgFrom + maxPages - 1)
if (this.__boundaryNumbers) {
boundaryStart = true
pgFrom += 1
}
if (this.__ellipses && pgFrom > (this.min + (this.__boundaryNumbers ? 1 : 0))) {
ellipsesStart = true
pgFrom += 1
}
if (this.__boundaryNumbers) {
boundaryEnd = true
pgTo -= 1
}
if (this.__ellipses && pgTo < (this.max - (this.__boundaryNumbers ? 1 : 0))) {
ellipsesEnd = true
pgTo -= 1
}
}
const style = {
minWidth: `${Math.max(2, String(this.max).length)}em`
}
if (boundaryStart) {
const active = this.min === this.value
contentStart.push(this.__getBtn(h, {
key: 'bns',
style
}, {
disable: this.disable,
flat: !active,
textColor: active ? this.textColor : null,
label: this.min
}, this.min))
}
if (boundaryEnd) {
const active = this.max === this.value
contentEnd.unshift(this.__getBtn(h, {
key: 'bne',
style
}, {
disable: this.disable,
flat: !active,
textColor: active ? this.textColor : null,
label: this.max
}, this.max))
}
if (ellipsesStart) {
contentStart.push(this.__getBtn(h, {
key: 'bes',
style
}, {
disable: this.disable,
label: '…',
ripple: false
}, pgFrom - 1))
}
if (ellipsesEnd) {
contentEnd.unshift(this.__getBtn(h, {
key: 'bee',
style
}, {
disable: this.disable,
label: '…',
ripple: false
}, pgTo + 1))
}
for (let i = pgFrom; i <= pgTo; i++) {
const active = i === this.value
contentMiddle.push(this.__getBtn(h, {
key: `bpg${i}`,
style
}, {
disable: this.disable,
flat: !active,
textColor: active ? this.textColor : null,
label: i
}, i))
}
}
return h('div', {
staticClass: 'q-pagination row no-wrap items-center',
class: { disabled: this.disable },
attrs: this.attrs,
on: { ...this.qListeners }
}, [
contentStart,
h('div', {
staticClass: 'row justify-center',
on: this.input === true
? cache(this, 'stop', { input: stop })
: null
}, [
contentMiddle
]),
contentEnd
])
}
})