Fixed #109 - Keyboard accessibility for Calendar
parent
c2d5dc321a
commit
b2415a18f5
|
@ -5,15 +5,12 @@
|
||||||
<transition name="p-input-overlay" @enter="onOverlayEnter" @after-enter="onOverlayEnterComplete" @leave="onOverlayLeave">
|
<transition name="p-input-overlay" @enter="onOverlayEnter" @after-enter="onOverlayEnterComplete" @leave="onOverlayLeave">
|
||||||
<div ref="overlay" :class="panelStyleClass" v-if="inline ? true : overlayVisible">
|
<div ref="overlay" :class="panelStyleClass" v-if="inline ? true : overlayVisible">
|
||||||
<template v-if="!timeOnly">
|
<template v-if="!timeOnly">
|
||||||
<div class="p-datepicker-group" v-for="(month,i) of months" :key="month.month + month.year">
|
<div class="p-datepicker-group" v-for="(month,groupIndex) of months" :key="month.month + month.year">
|
||||||
<div class="p-datepicker-header">
|
<div class="p-datepicker-header">
|
||||||
<slot name="header"></slot>
|
<slot name="header"></slot>
|
||||||
<button class="p-datepicker-prev p-link" v-if="i === 0" @click="navBackward($event)" type="button">
|
<button class="p-datepicker-prev p-link" v-if="groupIndex === 0" @click="onPrevButtonClick" type="button" @keydown="onContainerButtonKeydown">
|
||||||
<span class="p-datepicker-prev-icon pi pi-chevron-left"></span>
|
<span class="p-datepicker-prev-icon pi pi-chevron-left"></span>
|
||||||
</button>
|
</button>
|
||||||
<button class="p-datepicker-next p-link" v-if="numberOfMonths === 1 ? true : (i === numberOfMonths - 1)" @click="navForward($event)" type="button">
|
|
||||||
<span class="p-datepicker-next-icon pi pi-chevron-right"></span>
|
|
||||||
</button>
|
|
||||||
<div class="p-datepicker-title">
|
<div class="p-datepicker-title">
|
||||||
<span class="p-datepicker-month" v-if="!monthNavigator && (view !== 'month')">{{locale.monthNames[month.month]}}</span>
|
<span class="p-datepicker-month" v-if="!monthNavigator && (view !== 'month')">{{locale.monthNames[month.month]}}</span>
|
||||||
<select class="p-datepicker-month" v-if="monthNavigator && (view !== 'month') && numberOfMonths === 1" @change="onMonthDropdownChange($event.target.value)">
|
<select class="p-datepicker-month" v-if="monthNavigator && (view !== 'month') && numberOfMonths === 1" @change="onMonthDropdownChange($event.target.value)">
|
||||||
|
@ -24,6 +21,10 @@
|
||||||
<option :value="year" v-for="year of yearOptions" :key="year" :selected="year === currentYear">{{year}}</option>
|
<option :value="year" v-for="year of yearOptions" :key="year" :selected="year === currentYear">{{year}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<button class="p-datepicker-next p-link" v-if="numberOfMonths === 1 ? true : (groupIndex === numberOfMonths - 1)"
|
||||||
|
@click="onNextButtonClick" type="button" @keydown="onContainerButtonKeydown">
|
||||||
|
<span class="p-datepicker-next-icon pi pi-chevron-right"></span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-datepicker-calendar-container" v-if="view ==='date'">
|
<div class="p-datepicker-calendar-container" v-if="view ==='date'">
|
||||||
<table class="p-datepicker-calendar">
|
<table class="p-datepicker-calendar">
|
||||||
|
@ -41,11 +42,12 @@
|
||||||
<tr v-for="(week,i) of month.dates" :key="week[0].day + '' + week[0].month">
|
<tr v-for="(week,i) of month.dates" :key="week[0].day + '' + week[0].month">
|
||||||
<td v-if="showWeek" class="p-datepicker-weeknumber">
|
<td v-if="showWeek" class="p-datepicker-weeknumber">
|
||||||
<span class="p-disabled">
|
<span class="p-disabled">
|
||||||
|
<span style="visibility:hidden" v-if="month.weekNumbers[i] < 10">0</span>
|
||||||
{{month.weekNumbers[i]}}
|
{{month.weekNumbers[i]}}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td v-for="date of week" :key="date.day + '' + date.month" :class="{'p-datepicker-other-month': date.otherMonth, 'p-datepicker-today': date.today}">
|
<td v-for="date of week" :key="date.day + '' + date.month" :class="{'p-datepicker-other-month': date.otherMonth, 'p-datepicker-today': date.today}">
|
||||||
<span :class="{'p-highlight': isSelected(date), 'p-disabled': !date.selectable}" @click="onDateSelect(date)" draggable="false">
|
<span :class="{'p-highlight': isSelected(date), 'p-disabled': !date.selectable}" @click="onDateSelect($event, date)" draggable="false" @keydown="onDateCellKeydown($event,date,groupIndex)">
|
||||||
<slot name="date" :date="date">{{date.day}}</slot>
|
<slot name="date" :date="date">{{date.day}}</slot>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
@ -55,7 +57,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-monthpicker" v-if="view === 'month'">
|
<div class="p-monthpicker" v-if="view === 'month'">
|
||||||
<span v-for="(m,i) of monthPickerValues" :key="m" @click="onMonthSelect(i)" class="p-monthpicker-month" :class="{'p-highlight': isMonthSelected(i)}">
|
<span v-for="(m,i) of monthPickerValues" :key="m" @click="onMonthSelect($event, i)" @keydown="onMonthCellKeydown($event,i)" class="p-monthpicker-month" :class="{'p-highlight': isMonthSelected(i)}">
|
||||||
{{m}}
|
{{m}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -63,12 +65,12 @@
|
||||||
<div class="p-timepicker" v-if="showTime||timeOnly">
|
<div class="p-timepicker" v-if="showTime||timeOnly">
|
||||||
<div class="p-hour-picker">
|
<div class="p-hour-picker">
|
||||||
<button class="p-link" @mousedown="onTimePickerElementMouseDown($event, 0, 1)" @mouseup="onTimePickerElementMouseUp($event)"
|
<button class="p-link" @mousedown="onTimePickerElementMouseDown($event, 0, 1)" @mouseup="onTimePickerElementMouseUp($event)"
|
||||||
@mouseleave="onTimePickerElementMouseLeave()" type="button">
|
@mouseleave="onTimePickerElementMouseLeave()" @keydown.enter="onTimePickerElementMouseDown($event, 0, 1)" @keyup.enter="onTimePickerElementMouseUp($event)" type="button">
|
||||||
<span class="pi pi-chevron-up"></span>
|
<span class="pi pi-chevron-up"></span>
|
||||||
</button>
|
</button>
|
||||||
<span :style="{'display': currentHour < 10 ? 'inline': 'none'}">0</span><span>{{currentHour}}</span>
|
<span :style="{'display': currentHour < 10 ? 'inline': 'none'}">0</span><span>{{currentHour}}</span>
|
||||||
<button class="p-link" @mousedown="onTimePickerElementMouseDown($event, 0, -1)" @mouseup="onTimePickerElementMouseUp($event)"
|
<button class="p-link" @mousedown="onTimePickerElementMouseDown($event, 0, -1)" @mouseup="onTimePickerElementMouseUp($event)"
|
||||||
@mouseleave="onTimePickerElementMouseLeave()" type="button">
|
@mouseleave="onTimePickerElementMouseLeave()" @keydown.enter="onTimePickerElementMouseDown($event, 0, -1)" @keyup.enter="onTimePickerElementMouseUp($event)" type="button">
|
||||||
<span class="pi pi-chevron-down"></span>
|
<span class="pi pi-chevron-down"></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -83,12 +85,12 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="p-minute-picker">
|
<div class="p-minute-picker">
|
||||||
<button class="p-link" @mousedown="onTimePickerElementMouseDown($event, 1, 1)" @mouseup="onTimePickerElementMouseUp($event)"
|
<button class="p-link" @mousedown="onTimePickerElementMouseDown($event, 1, 1)" @mouseup="onTimePickerElementMouseUp($event)"
|
||||||
@mouseleave="onTimePickerElementMouseLeave()" type="button">
|
@mouseleave="onTimePickerElementMouseLeave()" @keydown.enter="onTimePickerElementMouseDown($event, 1, 1)" @keyup.enter="onTimePickerElementMouseUp($event)" type="button">
|
||||||
<span class="pi pi-chevron-up"></span>
|
<span class="pi pi-chevron-up"></span>
|
||||||
</button>
|
</button>
|
||||||
<span :style="{'display': currentMinute < 10 ? 'inline': 'none'}">0</span><span>{{currentMinute}}</span>
|
<span :style="{'display': currentMinute < 10 ? 'inline': 'none'}">0</span><span>{{currentMinute}}</span>
|
||||||
<button class="p-link" @mousedown="onTimePickerElementMouseDown($event, 1, -1)" @mouseup="onTimePickerElementMouseUp($event)"
|
<button class="p-link" @mousedown="onTimePickerElementMouseDown($event, 1, -1)" @mouseup="onTimePickerElementMouseUp($event)"
|
||||||
@mouseleave="onTimePickerElementMouseLeave()" type="button">
|
@mouseleave="onTimePickerElementMouseLeave()" @keydown.enter="onTimePickerElementMouseDown($event, 1, -1)" @keyup.enter="onTimePickerElementMouseUp($event)" type="button">
|
||||||
<span class="pi pi-chevron-down"></span>
|
<span class="pi pi-chevron-down"></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -103,12 +105,12 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="p-second-picker" v-if="showSeconds">
|
<div class="p-second-picker" v-if="showSeconds">
|
||||||
<button class="p-link" @mousedown="onTimePickerElementMouseDown($event, 2, 1)" @mouseup="onTimePickerElementMouseUp($event)"
|
<button class="p-link" @mousedown="onTimePickerElementMouseDown($event, 2, 1)" @mouseup="onTimePickerElementMouseUp($event)"
|
||||||
@mouseleave="onTimePickerElementMouseLeave()" type="button">
|
@mouseleave="onTimePickerElementMouseLeave()" @keydown.enter="onTimePickerElementMouseDown($event, 2, 1)" @keyup.enter="onTimePickerElementMouseUp($event)" type="button">
|
||||||
<span class="pi pi-chevron-up"></span>
|
<span class="pi pi-chevron-up"></span>
|
||||||
</button>
|
</button>
|
||||||
<span :style="{'display': currentSecond < 10 ? 'inline': 'none'}">0</span><span>{{currentSecond}}</span>
|
<span :style="{'display': currentSecond < 10 ? 'inline': 'none'}">0</span><span>{{currentSecond}}</span>
|
||||||
<button class="p-link" @mousedown="onTimePickerElementMouseDown($event, 2, -1)" @mouseup="onTimePickerElementMouseUp($event)"
|
<button class="p-link" @mousedown="onTimePickerElementMouseDown($event, 2, -1)" @mouseup="onTimePickerElementMouseUp($event)"
|
||||||
@mouseleave="onTimePickerElementMouseLeave()" type="button">
|
@mouseleave="onTimePickerElementMouseLeave()" @keydown.enter="onTimePickerElementMouseDown($event, 2, -1)" @keyup.enter="onTimePickerElementMouseUp($event)" type="button">
|
||||||
<span class="pi pi-chevron-down"></span>
|
<span class="pi pi-chevron-down"></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -132,8 +134,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-datepicker-buttonbar" v-if="showButtonBar">
|
<div class="p-datepicker-buttonbar" v-if="showButtonBar">
|
||||||
<CalendarButton type="button" :label="locale['today']" @click="onTodayButtonClick($event)" class="p-button-secondary" />
|
<CalendarButton type="button" :label="locale['today']" @click="onTodayButtonClick($event)" class="p-button-secondary" @keydown="onContainerButtonKeydown"/>
|
||||||
<CalendarButton type="button" :label="locale['clear']" @click="onClearButtonClick($event)" class="p-button-secondary" />
|
<CalendarButton type="button" :label="locale['clear']" @click="onClearButtonClick($event)" class="p-button-secondary" @keydown="onContainerButtonKeydown"/>
|
||||||
</div>
|
</div>
|
||||||
<slot name="footer"></slot>
|
<slot name="footer"></slot>
|
||||||
</div>
|
</div>
|
||||||
|
@ -317,10 +319,21 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
oldViewDate: null,
|
oldViewDate: null,
|
||||||
|
navigationState: null,
|
||||||
created() {
|
created() {
|
||||||
this.updateCurrentMetaData();
|
this.updateCurrentMetaData();
|
||||||
this.updateInputFieldValue(this.value);
|
this.updateInputFieldValue(this.value);
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.inline) {
|
||||||
|
this.initFocusableCell();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updated() {
|
||||||
|
if (this.$refs.overlay) {
|
||||||
|
this.updateFocus();
|
||||||
|
}
|
||||||
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.timePickerTimer) {
|
if (this.timePickerTimer) {
|
||||||
clearTimeout(this.timePickerTimer);
|
clearTimeout(this.timePickerTimer);
|
||||||
|
@ -527,6 +540,14 @@ export default {
|
||||||
this.unbindOutsideClickListener();
|
this.unbindOutsideClickListener();
|
||||||
this.$emit('hide');
|
this.$emit('hide');
|
||||||
},
|
},
|
||||||
|
onPrevButtonClick(event) {
|
||||||
|
this.navigationState = {backward: true, button: true};
|
||||||
|
this.navBackward(event);
|
||||||
|
},
|
||||||
|
onNextButtonClick(event) {
|
||||||
|
this.navigationState = {backward: false, button: true};
|
||||||
|
this.navForward(event);
|
||||||
|
},
|
||||||
navBackward(event) {
|
navBackward(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
|
@ -668,11 +689,14 @@ export default {
|
||||||
this.currentYear = parseInt(value);
|
this.currentYear = parseInt(value);
|
||||||
this.$emit('year-change', {month: this.currentMonth + 1, year: this.currentYear});
|
this.$emit('year-change', {month: this.currentMonth + 1, year: this.currentYear});
|
||||||
},
|
},
|
||||||
onDateSelect(dateMeta) {
|
onDateSelect(event, dateMeta) {
|
||||||
if (this.$attrs.disabled || !dateMeta.selectable) {
|
if (this.$attrs.disabled || !dateMeta.selectable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DomHandler.find(this.$refs.overlay, '.p-datepicker-calendar td span:not(.p-disabled)').forEach(cell => cell.tabIndex = -1);
|
||||||
|
event.currentTarget.focus();
|
||||||
|
|
||||||
if (this.isMultipleSelection() && this.isSelected(dateMeta)) {
|
if (this.isMultipleSelection() && this.isSelected(dateMeta)) {
|
||||||
let newValue = this.value.filter(date => !this.isDateEquals(date, dateMeta));
|
let newValue = this.value.filter(date => !this.isDateEquals(date, dateMeta));
|
||||||
this.updateModel(newValue);
|
this.updateModel(newValue);
|
||||||
|
@ -956,7 +980,7 @@ export default {
|
||||||
selectable: true
|
selectable: true
|
||||||
};
|
};
|
||||||
|
|
||||||
this.onDateSelect(dateMeta);
|
this.onDateSelect(null, dateMeta);
|
||||||
this.$emit('today-click', date);
|
this.$emit('today-click', date);
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
},
|
},
|
||||||
|
@ -1209,8 +1233,8 @@ export default {
|
||||||
clearInterval(this.timePickerTimer);
|
clearInterval(this.timePickerTimer);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onMonthSelect(index) {
|
onMonthSelect(event, index) {
|
||||||
this.onDateSelect({year: this.currentYear, month: index, day: 1, selectable: true});
|
this.onDateSelect(event, {year: this.currentYear, month: index, day: 1, selectable: true});
|
||||||
},
|
},
|
||||||
enableModality() {
|
enableModality() {
|
||||||
if (!this.mask) {
|
if (!this.mask) {
|
||||||
|
@ -1526,6 +1550,320 @@ export default {
|
||||||
checkDate.setMonth( 0 );
|
checkDate.setMonth( 0 );
|
||||||
checkDate.setDate( 1 );
|
checkDate.setDate( 1 );
|
||||||
return Math.floor( Math.round((time - checkDate.getTime()) / 86400000 ) / 7 ) + 1;
|
return Math.floor( Math.round((time - checkDate.getTime()) / 86400000 ) / 7 ) + 1;
|
||||||
|
},
|
||||||
|
onDateCellKeydown(event, date, groupIndex) {
|
||||||
|
const cellContent = event.currentTarget;
|
||||||
|
const cell = cellContent.parentElement;
|
||||||
|
|
||||||
|
switch (event.which) {
|
||||||
|
//down arrow
|
||||||
|
case 40: {
|
||||||
|
cellContent.tabIndex = '-1';
|
||||||
|
let cellIndex = DomHandler.index(cell);
|
||||||
|
let nextRow = cell.parentElement.nextElementSibling;
|
||||||
|
if (nextRow) {
|
||||||
|
let focusCell = nextRow.children[cellIndex].children[0];
|
||||||
|
if (DomHandler.hasClass(focusCell, 'p-disabled')) {
|
||||||
|
this.navigationState = {backward: false};
|
||||||
|
this.navForward(event);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nextRow.children[cellIndex].children[0].tabIndex = '0';
|
||||||
|
nextRow.children[cellIndex].children[0].focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.navigationState = {backward: false};
|
||||||
|
this.navForward(event);
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//up arrow
|
||||||
|
case 38: {
|
||||||
|
cellContent.tabIndex = '-1';
|
||||||
|
let cellIndex = DomHandler.index(cell);
|
||||||
|
let prevRow = cell.parentElement.previousElementSibling;
|
||||||
|
if (prevRow) {
|
||||||
|
let focusCell = prevRow.children[cellIndex].children[0];
|
||||||
|
if (DomHandler.hasClass(focusCell, 'p-disabled')) {
|
||||||
|
this.navigationState = {backward: true};
|
||||||
|
this.navBackward(event);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
focusCell.tabIndex = '0';
|
||||||
|
focusCell.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.navigationState = {backward: true};
|
||||||
|
this.navBackward(event);
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//left arrow
|
||||||
|
case 37: {
|
||||||
|
cellContent.tabIndex = '-1';
|
||||||
|
let prevCell = cell.previousElementSibling;
|
||||||
|
if (prevCell) {
|
||||||
|
let focusCell = prevCell.children[0];
|
||||||
|
if (DomHandler.hasClass(focusCell, 'p-disabled')) {
|
||||||
|
this.navigateToMonth(true, groupIndex);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
focusCell.tabIndex = '0';
|
||||||
|
focusCell.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.navigateToMonth(true, groupIndex);
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//right arrow
|
||||||
|
case 39: {
|
||||||
|
cellContent.tabIndex = '-1';
|
||||||
|
let nextCell = cell.nextElementSibling;
|
||||||
|
if (nextCell) {
|
||||||
|
let focusCell = nextCell.children[0];
|
||||||
|
if (DomHandler.hasClass(focusCell, 'p-disabled')) {
|
||||||
|
this.navigateToMonth(false, groupIndex);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
focusCell.tabIndex = '0';
|
||||||
|
focusCell.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.navigateToMonth(false, groupIndex);
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//enter
|
||||||
|
case 13: {
|
||||||
|
this.onDateSelect(event, date);
|
||||||
|
event.preventDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//escape
|
||||||
|
case 27: {
|
||||||
|
this.overlayVisible = false;
|
||||||
|
event.preventDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//tab
|
||||||
|
case 9: {
|
||||||
|
this.trapFocus(event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
//no op
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
navigateToMonth(prev, groupIndex) {
|
||||||
|
if (prev) {
|
||||||
|
if (this.numberOfMonths === 1 || (groupIndex === 0)) {
|
||||||
|
this.navigationState = {backward: true};
|
||||||
|
this.navBackward(event);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let prevMonthContainer = this.$refs.overlay.children[groupIndex - 1];
|
||||||
|
let cells = DomHandler.find(prevMonthContainer, '.p-datepicker-calendar td span:not(.p-disabled)');
|
||||||
|
let focusCell = cells[cells.length - 1];
|
||||||
|
focusCell.tabIndex = '0';
|
||||||
|
focusCell.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (this.numberOfMonths === 1 || (groupIndex === this.numberOfMonths - 1)) {
|
||||||
|
this.navigationState = {backward: false};
|
||||||
|
this.navForward(event);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let nextMonthContainer = this.$refs.overlay.children[groupIndex + 1];
|
||||||
|
let focusCell = DomHandler.findSingle(nextMonthContainer, '.p-datepicker-calendar td span:not(.p-disabled)');
|
||||||
|
focusCell.tabIndex = '0';
|
||||||
|
focusCell.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onMonthCellKeydown(event, index) {
|
||||||
|
const cell = event.currentTarget;
|
||||||
|
|
||||||
|
switch (event.which) {
|
||||||
|
//arrows
|
||||||
|
case 38:
|
||||||
|
case 40: {
|
||||||
|
cell.tabIndex = '-1';
|
||||||
|
var cells = cell.parentElement.children;
|
||||||
|
var cellIndex = DomHandler.index(cell);
|
||||||
|
let nextCell = cells[event.which === 40 ? cellIndex + 3 : cellIndex -3];
|
||||||
|
if (nextCell) {
|
||||||
|
nextCell.tabIndex = '0';
|
||||||
|
nextCell.focus();
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//left arrow
|
||||||
|
case 37: {
|
||||||
|
cell.tabIndex = '-1';
|
||||||
|
let prevCell = cell.previousElementSibling;
|
||||||
|
if (prevCell) {
|
||||||
|
prevCell.tabIndex = '0';
|
||||||
|
prevCell.focus();
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//right arrow
|
||||||
|
case 39: {
|
||||||
|
cell.tabIndex = '-1';
|
||||||
|
let nextCell = cell.nextElementSibling;
|
||||||
|
if (nextCell) {
|
||||||
|
nextCell.tabIndex = '0';
|
||||||
|
nextCell.focus();
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//enter
|
||||||
|
case 13: {
|
||||||
|
this.onMonthSelect(event, index);
|
||||||
|
event.preventDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//escape
|
||||||
|
case 27: {
|
||||||
|
this.overlayVisible = false;
|
||||||
|
event.preventDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//tab
|
||||||
|
case 9: {
|
||||||
|
this.trapFocus(event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
//no op
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateFocus() {
|
||||||
|
let cell;
|
||||||
|
if (this.navigationState) {
|
||||||
|
if (this.navigationState.button) {
|
||||||
|
this.initFocusableCell();
|
||||||
|
|
||||||
|
if (this.navigationState.backward)
|
||||||
|
DomHandler.findSingle(this.$refs.overlay, '.p-datepicker-prev').focus();
|
||||||
|
else
|
||||||
|
DomHandler.findSingle(this.$refs.overlay, '.p-datepicker-next').focus();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (this.navigationState.backward) {
|
||||||
|
let cells = DomHandler.find(this.$refs.overlay, '.p-datepicker-calendar td span:not(.p-disabled)');
|
||||||
|
cell = cells[cells.length - 1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cell = DomHandler.findSingle(this.$refs.overlay, '.p-datepicker-calendar td span:not(.p-disabled)');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell) {
|
||||||
|
cell.tabIndex = '0';
|
||||||
|
cell.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.navigationState = null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.initFocusableCell();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
initFocusableCell() {
|
||||||
|
let cell;
|
||||||
|
if (this.view === 'month') {
|
||||||
|
let cells = DomHandler.find(this.$refs.overlay, '.p-monthpicker .p-monthpicker-month');
|
||||||
|
let selectedCell= DomHandler.findSingle(this.$refs.overlay, '.p-monthpicker .p-monthpicker-month.p-highlight');
|
||||||
|
cells.forEach(cell => cell.tabIndex = -1);
|
||||||
|
cell = selectedCell || cells[0];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cell = DomHandler.findSingle(this.$refs.overlay, 'span.p-highlight');
|
||||||
|
if (!cell) {
|
||||||
|
let todayCell = DomHandler.findSingle(this.$refs.overlay, 'td.p-datepicker-today');
|
||||||
|
if (todayCell)
|
||||||
|
cell = todayCell.children[0];
|
||||||
|
else
|
||||||
|
cell = DomHandler.findSingle(this.$refs.overlay, '.p-datepicker-calendar td span:not(.p-disabled)');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell) {
|
||||||
|
cell.tabIndex = '0';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trapFocus(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
let focusableElements = DomHandler.getFocusableElements(this.$refs.overlay);
|
||||||
|
|
||||||
|
if (focusableElements && focusableElements.length > 0) {
|
||||||
|
if (!document.activeElement) {
|
||||||
|
focusableElements[0].focus();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let focusedIndex = focusableElements.indexOf(document.activeElement);
|
||||||
|
|
||||||
|
if (event.shiftKey) {
|
||||||
|
if (focusedIndex == -1 || focusedIndex === 0)
|
||||||
|
focusableElements[focusableElements.length - 1].focus();
|
||||||
|
else
|
||||||
|
focusableElements[focusedIndex - 1].focus();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (focusedIndex == -1 || focusedIndex === (focusableElements.length - 1))
|
||||||
|
focusableElements[0].focus();
|
||||||
|
else
|
||||||
|
focusableElements[focusedIndex + 1].focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onContainerButtonKeydown(event) {
|
||||||
|
switch (event.which) {
|
||||||
|
//tab
|
||||||
|
case 9:
|
||||||
|
this.trapFocus(event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//escape
|
||||||
|
case 27:
|
||||||
|
this.overlayVisible = false;
|
||||||
|
event.preventDefault();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
//Noop
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -1576,12 +1914,29 @@ export default {
|
||||||
$vm.$emit('blur', event);
|
$vm.$emit('blur', event);
|
||||||
},
|
},
|
||||||
keydown: event => {
|
keydown: event => {
|
||||||
$vm.isKeydown = true;
|
switch (event.which) {
|
||||||
if (event.keyCode === 9) {
|
//escape
|
||||||
if ($vm.touchUI)
|
case 27: {
|
||||||
$vm.disableModality();
|
|
||||||
else
|
|
||||||
$vm.overlayVisible = false;
|
$vm.overlayVisible = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//tab
|
||||||
|
case 9: {
|
||||||
|
if ($vm.touchUI) {
|
||||||
|
$vm.disableModality();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.shiftKey) {
|
||||||
|
$vm.overlayVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
//no op
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$vm.$emit('keydown', event);
|
$vm.$emit('keydown', event);
|
||||||
|
@ -1645,7 +2000,6 @@ export default {
|
||||||
let weekNumbers = [];
|
let weekNumbers = [];
|
||||||
let monthRows = Math.ceil((daysLength + firstDay) / 7);
|
let monthRows = Math.ceil((daysLength + firstDay) / 7);
|
||||||
|
|
||||||
|
|
||||||
for (let i = 0; i < monthRows; i++) {
|
for (let i = 0; i < monthRows; i++) {
|
||||||
let week = [];
|
let week = [];
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue