import { VNode } from 'vue' import { Component, Prop, Watch } from 'vue-property-decorator' import VsIconsArrow from '../../../icons/arrow' import VsComponent from '../../../mixins/component' @Component export default class VsPagination extends VsComponent { val: number = 0 leftActive: number = 42 activeClassMove: boolean = false @Prop({}) value: number @Prop({ default: false, type: Boolean }) infinite: boolean @Prop({ default: false, type: Boolean }) progress: boolean @Prop({ default: false, type: Boolean }) notMargin: boolean @Prop({ default: false, type: Boolean }) buttonsDotted: boolean @Prop({ default: false, type: Boolean }) notArrows: boolean @Prop({ default: false, type: Boolean }) onlyArrows: boolean @Prop({ default: false, type: Boolean }) circle: boolean @Prop({ default: false, type: Boolean }) square: boolean @Prop({ default: false, type: Boolean }) disabled: boolean @Prop({ default: false, type: Boolean }) rtl: boolean @Prop({ default: (): any => [], type: Array }) disabledItems: number[] @Prop({ default: (): any => [], type: Array }) loadingItems: number[] @Prop({ default: 0, type: Number }) length: number @Prop({ default: 9, type: Number }) max: number @Prop({ default: 5, type: Number }) dottedNumber: number @Watch('value') handleValue(val: number, prevValue: number) { if (this.isDisabledItem(val) || this.isLoadingItem(val)) { let newVal = val if (val > prevValue) { newVal += 1 } else { newVal -= 1 } if (newVal > this.length) { newVal = this.infinite ? 1 : prevValue } else if (newVal <= 0) { newVal = this.infinite ? this.length : prevValue } this.val = newVal this.setValuePage(newVal) } else { this.val = val if (this.$refs.pagination) { this.activeClassMove = true this.$nextTick(() => { this.setActivePosition(val) setTimeout(() => { this.activeClassMove = false }, 300) }) } } } @Watch('length') handleLength() { if (this.$refs.pagination) { this.activeClassMove = true this.$nextTick(() => { this.setActivePosition(this.val) setTimeout(() => { this.activeClassMove = false }, 300) }) } } @Watch('onlyArrows') handleOnlyArrows() { setTimeout(() => { this.setActivePosition(this.val) }, 500) } setActivePosition(val: number){ if(this.$refs.pagination && this.$refs[`btn${val}`]){ const offsetLeftPagination = (this.$refs.pagination as HTMLElement).offsetLeft this.leftActive = (this.$refs[`btn${val}`] as HTMLElement).offsetLeft + offsetLeftPagination } } setValuePage(NumberPage: number) { this.$emit('input', NumberPage) } convertNumber(Number: number) { return Number.toString() .replace(/0/g,'۰') .replace(/1/g,'۱') .replace(/2/g,'۲') .replace(/3/g,'۳') .replace(/4/g,'۴') .replace(/5/g,'۵') .replace(/6/g,'۶') .replace(/7/g,'۷') .replace(/8/g,'۸') .replace(/9/g,'۹') } renderDotted(text: string = '...') { const h = this.$createElement const dotted = h('div', { staticClass: 'vs-pagination__dotted', class: { next: this.value == this.length ? false : text == '...>' }, on: { click: (evt: any) => { let newVal = (this.value == this.length ? false : text == '...>') ? this.val += this.dottedNumber : this.val -= this.dottedNumber if (newVal > this.length) { newVal = this.length } else if (newVal < 1) { newVal = 1 } this.setValuePage(newVal) } } }, [ h('span', { staticClass: 'dotted' }, [`...`]), h('span', { staticClass: 'con-arrows' }, [ h(VsIconsArrow), h(VsIconsArrow) ]), ]) return dotted } isDisabledItem(item: number) { return this.disabledItems.indexOf(item) !== -1 } isLoadingItem(item: number) { return this.loadingItems.indexOf(item) !== -1 } renderButton(NumberPage: number = 1) { const h = this.$createElement const button = h('button', { ref: `btn${NumberPage}`, staticClass: 'vs-pagination__button', class: { active: NumberPage == this.value, prevActive: NumberPage == this.value - 1, nextActive: NumberPage == this.value + 1, disabled: this.isDisabledItem(NumberPage), loading: this.isLoadingItem(NumberPage) }, on: { click: (evt: any) => { this.setValuePage(NumberPage) } } }, this.buttonsDotted ? '' : `${this.rtl ? this.convertNumber(NumberPage) : NumberPage}`) return button } renderButtons(array: any) { const buttons: any[] = [] array.forEach((item: any) => { if (item === '...>' || item === '<...') { buttons.push(this.renderDotted(item)) } else { buttons.push(this.renderButton(item)) } }) return buttons } getButtons(start: number = 1, end: number = 6) { const buttons = [] for (start > 0 ? start : 1; start <= end; start++) { buttons.push(start) } return buttons } get isMobile() { let isMobile = false if (!this.$isServer) { if (window.innerWidth < 600) { isMobile = true } } return isMobile } get getPages() { const length = Number(this.length) const max = this.isMobile ? 5 : this.max const even = max % 2 === 0 ? 1 : 0 const prevRange = Math.floor(max / 2) const nextRange = length - prevRange + 1 + even if (this.value >= prevRange && this.value <= nextRange && !this.buttonsDotted) { const start = this.value - prevRange + 2 const end = this.value + prevRange - 2 - even return this.renderButtons([1, '<...', ...this.getButtons(start, end), '...>', this.length]) } else if (!this.buttonsDotted && this.length > 6) { return this.renderButtons([ ...this.getButtons(1, prevRange), '...>', ...this.getButtons(nextRange, length) ]) } else if (this.buttonsDotted || this.length <= 6) { return this.renderButtons([ ...this.getButtons(1, this.length), ]) } return [] } get getProgress() { let percent = 0 percent = this.value * 100 / this.length return percent } mounted() { this.val = this.value this.handleValue(this.value, (this.val += 1)) } public render(h: any): VNode { const active = h('div', { staticClass: 'vs-pagination__active', style: { left: `${this.leftActive}px`, }, class: { move: this.activeClassMove } }, this.buttonsDotted ? '' : this.rtl ? this.convertNumber(this.value) : this.value) const pagination = h('div', { staticClass: 'vs-pagination', ref: 'pagination' }, [ this.getPages ]) const prev = h('button', { staticClass: 'vs-pagination__arrow', attrs: { disabled: this.infinite ? false : this.val <= 1 }, class: [ 'prev' ], on: { click: () => { const newVal = this.val -= 1 if (newVal > 0) { this.setValuePage(newVal) } else if (this.infinite) { this.setValuePage(this.length) } } } }, [ this.$slots.arrowPrev ? this.$slots.arrowPrev : h(VsIconsArrow) ]) const next = h('button', { staticClass: 'vs-pagination__arrow', attrs: { disabled: this.infinite ? false : this.val >= this.length }, class: [ 'next', ], on: { click: () => { const newVal = this.val += 1 if (newVal <= this.length) { this.setValuePage(newVal) } else if (this.infinite) { this.setValuePage(1) } } } }, [ this.$slots.arrowNext ? this.$slots.arrowNext : h(VsIconsArrow) ]) const slot = h('div', { staticClass: 'vs-pagination__slot', }, [ this.$slots.default ]) const progress = h('div', { staticClass: 'vs-pagination__progress' }, [ h('div', { staticClass: 'progress', style: { width: `${this.getProgress}%` } }) ]) return h('div', { staticClass: 'vs-pagination-content', class: [ { buttonsDotted: this.buttonsDotted, circle: this.circle, square: this.square, disabled: this.disabled, notMargin: this.notMargin }, { [`vs-pagination--rtl`] : !!this.rtl } ] }, [ (!this.onlyArrows && !this.$slots.default) && active, !this.notArrows && prev, this.$slots.default && slot, (!this.onlyArrows && !this.$slots.default) && pagination, !this.notArrows && next, this.progress && progress ]) } }