272 lines
10 KiB
Vue
Executable File
272 lines
10 KiB
Vue
Executable File
<template>
|
|
<div :class="cx('itemWrapper')" v-bind="ptm('itemWrapper')">
|
|
<div :class="cx('itemContainer')" v-bind="ptm('itemContainer')">
|
|
<button v-if="showItemNavigators" v-ripple type="button" :class="cx('previousItemButton')" @click="navBackward($event)" :disabled="isNavBackwardDisabled()" v-bind="ptm('previousItemButton')" data-pc-group-section="itemnavigator">
|
|
<component :is="templates.previousitemicon || 'ChevronLeftIcon'" :class="cx('previousItemIcon')" v-bind="ptm('previousItemIcon')" />
|
|
</button>
|
|
<div :id="id + '_item_' + activeIndex" :class="cx('item')" role="group" :aria-label="ariaSlideNumber(activeIndex + 1)" :aria-roledescription="ariaSlideLabel" v-bind="ptm('item')">
|
|
<component v-if="templates.item" :is="templates.item" :item="activeItem" />
|
|
</div>
|
|
<button v-if="showItemNavigators" v-ripple type="button" :class="cx('nextItemButton')" @click="navForward($event)" :disabled="isNavForwardDisabled()" v-bind="ptm('nextItemButton')" data-pc-group-section="itemnavigator">
|
|
<component :is="templates.nextitemicon || 'ChevronRightIcon'" :class="cx('nextItemIcon')" v-bind="ptm('nextItemIcon')" />
|
|
</button>
|
|
<div v-if="templates['caption']" :class="cx('caption')" v-bind="ptm('caption')">
|
|
<component v-if="templates.caption" :is="templates.caption" :item="activeItem" />
|
|
</div>
|
|
</div>
|
|
<ul v-if="showIndicators" ref="indicatorContent" :class="cx('indicators')" v-bind="ptm('indicators')">
|
|
<li
|
|
v-for="(item, index) of value"
|
|
:key="`p-galleria-indicator-${index}`"
|
|
:class="cx('indicator', { index })"
|
|
:aria-label="ariaPageLabel(index + 1)"
|
|
:aria-selected="activeIndex === index"
|
|
:aria-controls="id + '_item_' + index"
|
|
@click="onIndicatorClick(index)"
|
|
@mouseenter="onIndicatorMouseEnter(index)"
|
|
@keydown="onIndicatorKeyDown($event, index)"
|
|
v-bind="ptm('indicator', getIndicatorPTOptions(index))"
|
|
:data-p-highlight="isIndicatorItemActive(index)"
|
|
>
|
|
<button v-if="!templates['indicator']" type="button" :tabindex="activeIndex === index ? '0' : '-1'" :class="cx('indicatorButton')" v-bind="ptm('indicatorButton', getIndicatorPTOptions(index))"></button>
|
|
<component v-if="templates.indicator" :is="templates.indicator" :index="index" />
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import BaseComponent from 'primevue/basecomponent';
|
|
import ChevronLeftIcon from 'primevue/icons/chevronleft';
|
|
import ChevronRightIcon from 'primevue/icons/chevronright';
|
|
import Ripple from 'primevue/ripple';
|
|
import { DomHandler } from 'primevue/utils';
|
|
|
|
export default {
|
|
name: 'GalleriaItem',
|
|
hostName: 'Galleria',
|
|
extends: BaseComponent,
|
|
emits: ['start-slideshow', 'stop-slideshow', 'update:activeIndex'],
|
|
props: {
|
|
circular: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
activeIndex: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
value: {
|
|
type: Array,
|
|
default: null
|
|
},
|
|
showItemNavigators: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
showIndicators: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
slideShowActive: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
changeItemOnIndicatorHover: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
autoPlay: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
templates: {
|
|
type: null,
|
|
default: null
|
|
},
|
|
id: {
|
|
type: String,
|
|
default: null
|
|
}
|
|
},
|
|
mounted() {
|
|
if (this.autoPlay) {
|
|
this.$emit('start-slideshow');
|
|
}
|
|
},
|
|
methods: {
|
|
getIndicatorPTOptions(index) {
|
|
return {
|
|
context: {
|
|
highlighted: this.activeIndex === index
|
|
}
|
|
};
|
|
},
|
|
next() {
|
|
let nextItemIndex = this.activeIndex + 1;
|
|
let activeIndex = this.circular && this.value.length - 1 === this.activeIndex ? 0 : nextItemIndex;
|
|
|
|
this.$emit('update:activeIndex', activeIndex);
|
|
},
|
|
prev() {
|
|
let prevItemIndex = this.activeIndex !== 0 ? this.activeIndex - 1 : 0;
|
|
let activeIndex = this.circular && this.activeIndex === 0 ? this.value.length - 1 : prevItemIndex;
|
|
|
|
this.$emit('update:activeIndex', activeIndex);
|
|
},
|
|
stopSlideShow() {
|
|
if (this.slideShowActive && this.stopSlideShow) {
|
|
this.$emit('stop-slideshow');
|
|
}
|
|
},
|
|
navBackward(e) {
|
|
this.stopSlideShow();
|
|
this.prev();
|
|
|
|
if (e && e.cancelable) {
|
|
e.preventDefault();
|
|
}
|
|
},
|
|
navForward(e) {
|
|
this.stopSlideShow();
|
|
this.next();
|
|
|
|
if (e && e.cancelable) {
|
|
e.preventDefault();
|
|
}
|
|
},
|
|
onIndicatorClick(index) {
|
|
this.stopSlideShow();
|
|
this.$emit('update:activeIndex', index);
|
|
},
|
|
onIndicatorMouseEnter(index) {
|
|
if (this.changeItemOnIndicatorHover) {
|
|
this.stopSlideShow();
|
|
|
|
this.$emit('update:activeIndex', index);
|
|
}
|
|
},
|
|
onIndicatorKeyDown(event, index) {
|
|
switch (event.code) {
|
|
case 'Enter':
|
|
case 'NumpadEnter':
|
|
case 'Space':
|
|
this.stopSlideShow();
|
|
|
|
this.$emit('update:activeIndex', index);
|
|
event.preventDefault();
|
|
break;
|
|
|
|
case 'ArrowRight':
|
|
this.onRightKey();
|
|
break;
|
|
|
|
case 'ArrowLeft':
|
|
this.onLeftKey();
|
|
break;
|
|
|
|
case 'Home':
|
|
this.onHomeKey();
|
|
event.preventDefault();
|
|
break;
|
|
|
|
case 'End':
|
|
this.onEndKey();
|
|
event.preventDefault();
|
|
break;
|
|
|
|
case 'Tab':
|
|
this.onTabKey();
|
|
break;
|
|
|
|
case 'ArrowDown':
|
|
case 'ArrowUp':
|
|
case 'PageUp':
|
|
case 'PageDown':
|
|
event.preventDefault();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
},
|
|
onRightKey() {
|
|
const indicators = [...DomHandler.find(this.$refs.indicatorContent, '[data-pc-section="indicator"]')];
|
|
const activeIndex = this.findFocusedIndicatorIndex();
|
|
|
|
this.changedFocusedIndicator(activeIndex, activeIndex + 1 === indicators.length ? indicators.length - 1 : activeIndex + 1);
|
|
},
|
|
onLeftKey() {
|
|
const activeIndex = this.findFocusedIndicatorIndex();
|
|
|
|
this.changedFocusedIndicator(activeIndex, activeIndex - 1 <= 0 ? 0 : activeIndex - 1);
|
|
},
|
|
onHomeKey() {
|
|
const activeIndex = this.findFocusedIndicatorIndex();
|
|
|
|
this.changedFocusedIndicator(activeIndex, 0);
|
|
},
|
|
onEndKey() {
|
|
const indicators = [...DomHandler.find(this.$refs.indicatorContent, '[data-pc-section="indicator"]')];
|
|
const activeIndex = this.findFocusedIndicatorIndex();
|
|
|
|
this.changedFocusedIndicator(activeIndex, indicators.length - 1);
|
|
},
|
|
onTabKey() {
|
|
const indicators = [...DomHandler.find(this.$refs.indicatorContent, '[data-pc-section="indicator"]')];
|
|
const highlightedIndex = indicators.findIndex((ind) => DomHandler.getAttribute(ind, 'data-p-highlight') === true);
|
|
|
|
const activeIndicator = DomHandler.findSingle(this.$refs.indicatorContent, '[data-pc-section="indicator"] > button[tabindex="0"]');
|
|
const activeIndex = indicators.findIndex((ind) => ind === activeIndicator.parentElement);
|
|
|
|
indicators[activeIndex].children[0].tabIndex = '-1';
|
|
indicators[highlightedIndex].children[0].tabIndex = '0';
|
|
},
|
|
findFocusedIndicatorIndex() {
|
|
const indicators = [...DomHandler.find(this.$refs.indicatorContent, '[data-pc-section="indicator"]')];
|
|
const activeIndicator = DomHandler.findSingle(this.$refs.indicatorContent, '[data-pc-section="indicator"] > button[tabindex="0"]');
|
|
|
|
return indicators.findIndex((ind) => ind === activeIndicator.parentElement);
|
|
},
|
|
changedFocusedIndicator(prevInd, nextInd) {
|
|
const indicators = [...DomHandler.find(this.$refs.indicatorContent, '[data-pc-section="indicator"]')];
|
|
|
|
indicators[prevInd].children[0].tabIndex = '-1';
|
|
indicators[nextInd].children[0].tabIndex = '0';
|
|
indicators[nextInd].children[0].focus();
|
|
},
|
|
isIndicatorItemActive(index) {
|
|
return this.activeIndex === index;
|
|
},
|
|
isNavBackwardDisabled() {
|
|
return !this.circular && this.activeIndex === 0;
|
|
},
|
|
isNavForwardDisabled() {
|
|
return !this.circular && this.activeIndex === this.value.length - 1;
|
|
},
|
|
ariaSlideNumber(value) {
|
|
return this.$primevue.config.locale.aria ? this.$primevue.config.locale.aria.slideNumber.replace(/{slideNumber}/g, value) : undefined;
|
|
},
|
|
ariaPageLabel(value) {
|
|
return this.$primevue.config.locale.aria ? this.$primevue.config.locale.aria.pageLabel.replace(/{page}/g, value) : undefined;
|
|
}
|
|
},
|
|
computed: {
|
|
activeItem() {
|
|
return this.value[this.activeIndex];
|
|
},
|
|
|
|
ariaSlideLabel() {
|
|
return this.$primevue.config.locale.aria ? this.$primevue.config.locale.aria.slide : undefined;
|
|
}
|
|
},
|
|
components: {
|
|
ChevronLeftIcon: ChevronLeftIcon,
|
|
ChevronRightIcon: ChevronRightIcon
|
|
},
|
|
directives: {
|
|
ripple: Ripple
|
|
}
|
|
};
|
|
</script>
|