UNPKG

quasar-framework

Version:

Build responsive SPA, SSR, PWA, Hybrid Mobile Apps and Electron apps, all simultaneously using the same codebase

335 lines (326 loc) 8.06 kB
import { between } from '../../utils/format.js' import QBtn from '../btn/QBtn.js' import QInput from '../input/QInput.js' import { getEventKey } from '../../utils/event.js' export default { name: 'QPagination', props: { value: { type: Number, required: true }, min: { type: Number, default: 1 }, max: { type: Number, required: true }, color: { type: String, default: 'primary' }, textColor: String, size: String, disable: Boolean, input: Boolean, 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 => { if (v < 0) { console.error('maxPages should not be negative') return false } return true } } }, data () { return { newPage: null } }, watch: { min (value) { this.model = this.value }, max (value) { this.model = this.value } }, computed: { model: { get () { return this.value }, set (val) { if (this.disable || !val || isNaN(val)) { return } const value = between(parseInt(val, 10), this.min, this.max) this.$emit('input', value) this.$nextTick(() => { if (JSON.stringify(value) !== JSON.stringify(this.value)) { this.$emit('change', 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.$q.icon.pagination.first, this.$q.icon.pagination.prev, this.$q.icon.pagination.next, this.$q.icon.pagination.last ] return this.$q.i18n.rtl ? ico.reverse() : ico } }, 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) { data.props = Object.assign({ color: this.color, flat: true, size: this.size }, props) return h(QBtn, data) } }, render (h) { const contentStart = [], contentEnd = [], contentMiddle = [] if (this.__boundaryLinks) { contentStart.push(this.__getBtn(h, { key: 'bls', on: { click: () => this.set(this.min) } }, { disable: this.disable || this.value <= this.min, icon: this.icons[0] })) contentEnd.unshift(this.__getBtn(h, { key: 'ble', on: { click: () => this.set(this.max) } }, { disable: this.disable || this.value >= this.max, icon: this.icons[3] })) } if (this.__directionLinks) { contentStart.push(this.__getBtn(h, { key: 'bdp', on: { click: () => this.setByOffset(-1) } }, { disable: this.disable || this.value <= this.min, icon: this.icons[1] })) contentEnd.unshift(this.__getBtn(h, { key: 'bdn', on: { click: () => this.setByOffset(1) } }, { disable: this.disable || this.value >= this.max, icon: this.icons[2] })) } if (this.input) { contentMiddle.push(h(QInput, { staticClass: 'inline no-padding', style: { width: `${this.inputPlaceholder.length}rem` }, props: { type: 'number', value: this.newPage, noNumberToggle: true, min: this.min, max: this.max, color: this.color, placeholder: this.inputPlaceholder, disable: this.disable, hideUnderline: true }, on: { input: value => (this.newPage = value), keydown: e => (getEventKey(e) === 13 && 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, on: { click: () => this.set(this.min) } }, { disable: this.disable, flat: !active, textColor: active ? this.textColor : null, label: this.min, noRipple: true })) } if (boundaryEnd) { const active = this.max === this.value contentEnd.unshift(this.__getBtn(h, { key: 'bne', style, on: { click: () => this.set(this.max) } }, { disable: this.disable, flat: !active, textColor: active ? this.textColor : null, label: this.max, noRipple: true })) } if (ellipsesStart) { contentStart.push(this.__getBtn(h, { key: 'bes', style, on: { click: () => this.set(pgFrom - 1) } }, { disable: this.disable, label: '…' })) } if (ellipsesEnd) { contentEnd.unshift(this.__getBtn(h, { key: 'bee', style, on: { click: () => this.set(pgTo + 1) } }, { disable: this.disable, label: '…' })) } for (let i = pgFrom; i <= pgTo; i++) { const active = i === this.value contentMiddle.push(this.__getBtn(h, { key: `bpg${i}`, style, on: { click: () => this.set(i) } }, { disable: this.disable, flat: !active, textColor: active ? this.textColor : null, label: i, noRipple: true })) } } return h('div', { staticClass: 'q-pagination row no-wrap items-center', 'class': { disabled: this.disable } }, [ contentStart, h('div', { staticClass: 'row justify-center' }, [ contentMiddle ]), contentEnd ]) } }