diff --git a/src/modules/a11y/a11y.js b/src/modules/a11y/a11y.js
index 8fe823697..cfed3f1e3 100644
--- a/src/modules/a11y/a11y.js
+++ b/src/modules/a11y/a11y.js
@@ -1,54 +1,72 @@
import $ from '../../shared/dom.js';
-import { bindModuleMethods, classesToSelector } from '../../shared/utils.js';
+import { classesToSelector } from '../../shared/utils.js';
-const A11y = {
- getRandomNumber(size = 16) {
+export default function A11y({ swiper, extendParams, on }) {
+ extendParams({
+ a11y: {
+ enabled: true,
+ notificationClass: 'swiper-notification',
+ prevSlideMessage: 'Previous slide',
+ nextSlideMessage: 'Next slide',
+ firstSlideMessage: 'This is the first slide',
+ lastSlideMessage: 'This is the last slide',
+ paginationBulletMessage: 'Go to slide {{index}}',
+ slideLabelMessage: '{{index}} / {{slidesLength}}',
+ containerMessage: null,
+ containerRoleDescriptionMessage: null,
+ itemRoleDescriptionMessage: null,
+ slideRole: 'group',
+ },
+ });
+
+ const liveRegion = $(
+ ``,
+ );
+
+ function notify(message) {
+ const notification = liveRegion;
+ if (notification.length === 0) return;
+ notification.html('');
+ notification.html(message);
+ }
+
+ function getRandomNumber(size = 16) {
const randomChar = () => Math.round(16 * Math.random()).toString(16);
return 'x'.repeat(size).replace(/x/g, randomChar);
- },
- makeElFocusable($el) {
+ }
+ function makeElFocusable($el) {
$el.attr('tabIndex', '0');
- return $el;
- },
- makeElNotFocusable($el) {
+ }
+ function makeElNotFocusable($el) {
$el.attr('tabIndex', '-1');
- return $el;
- },
- addElRole($el, role) {
+ }
+ function addElRole($el, role) {
$el.attr('role', role);
- return $el;
- },
- addElRoleDescription($el, description) {
+ }
+ function addElRoleDescription($el, description) {
$el.attr('aria-roledescription', description);
- return $el;
- },
- addElControls($el, controls) {
+ }
+ function addElControls($el, controls) {
$el.attr('aria-controls', controls);
- return $el;
- },
- addElLabel($el, label) {
+ }
+ function addElLabel($el, label) {
$el.attr('aria-label', label);
- return $el;
- },
- addElId($el, id) {
+ }
+ function addElId($el, id) {
$el.attr('id', id);
- return $el;
- },
- addElLive($el, live) {
+ }
+ function addElLive($el, live) {
$el.attr('aria-live', live);
- return $el;
- },
- disableEl($el) {
+ }
+ function disableEl($el) {
$el.attr('aria-disabled', true);
- return $el;
- },
- enableEl($el) {
+ }
+ function enableEl($el) {
$el.attr('aria-disabled', false);
- return $el;
- },
- onEnterOrSpaceKey(e) {
+ }
+
+ function onEnterOrSpaceKey(e) {
if (e.keyCode !== 13 && e.keyCode !== 32) return;
- const swiper = this;
const params = swiper.params.a11y;
const $targetEl = $(e.target);
if (swiper.navigation && swiper.navigation.$nextEl && $targetEl.is(swiper.navigation.$nextEl)) {
@@ -56,9 +74,9 @@ const A11y = {
swiper.slideNext();
}
if (swiper.isEnd) {
- swiper.a11y.notify(params.lastSlideMessage);
+ notify(params.lastSlideMessage);
} else {
- swiper.a11y.notify(params.nextSlideMessage);
+ notify(params.nextSlideMessage);
}
}
if (swiper.navigation && swiper.navigation.$prevEl && $targetEl.is(swiper.navigation.$prevEl)) {
@@ -66,9 +84,9 @@ const A11y = {
swiper.slidePrev();
}
if (swiper.isBeginning) {
- swiper.a11y.notify(params.firstSlideMessage);
+ notify(params.firstSlideMessage);
} else {
- swiper.a11y.notify(params.prevSlideMessage);
+ notify(params.prevSlideMessage);
}
}
@@ -78,88 +96,94 @@ const A11y = {
) {
$targetEl[0].click();
}
- },
- notify(message) {
- const swiper = this;
- const notification = swiper.a11y.liveRegion;
- if (notification.length === 0) return;
- notification.html('');
- notification.html(message);
- },
- updateNavigation() {
- const swiper = this;
+ }
+ function updateNavigation() {
if (swiper.params.loop || !swiper.navigation) return;
const { $nextEl, $prevEl } = swiper.navigation;
if ($prevEl && $prevEl.length > 0) {
if (swiper.isBeginning) {
- swiper.a11y.disableEl($prevEl);
- swiper.a11y.makeElNotFocusable($prevEl);
+ disableEl($prevEl);
+ makeElNotFocusable($prevEl);
} else {
- swiper.a11y.enableEl($prevEl);
- swiper.a11y.makeElFocusable($prevEl);
+ enableEl($prevEl);
+ makeElFocusable($prevEl);
}
}
if ($nextEl && $nextEl.length > 0) {
if (swiper.isEnd) {
- swiper.a11y.disableEl($nextEl);
- swiper.a11y.makeElNotFocusable($nextEl);
+ disableEl($nextEl);
+ makeElNotFocusable($nextEl);
} else {
- swiper.a11y.enableEl($nextEl);
- swiper.a11y.makeElFocusable($nextEl);
+ enableEl($nextEl);
+ makeElFocusable($nextEl);
}
}
- },
- updatePagination() {
- const swiper = this;
- const params = swiper.params.a11y;
- if (
+ }
+
+ function hasPagination() {
+ return (
swiper.pagination &&
swiper.params.pagination.clickable &&
swiper.pagination.bullets &&
swiper.pagination.bullets.length
- ) {
+ );
+ }
+
+ function updatePagination() {
+ const params = swiper.params.a11y;
+ if (hasPagination()) {
swiper.pagination.bullets.each((bulletEl) => {
const $bulletEl = $(bulletEl);
- swiper.a11y.makeElFocusable($bulletEl);
+ makeElFocusable($bulletEl);
if (!swiper.params.pagination.renderBullet) {
- swiper.a11y.addElRole($bulletEl, 'button');
- swiper.a11y.addElLabel(
+ addElRole($bulletEl, 'button');
+ addElLabel(
$bulletEl,
params.paginationBulletMessage.replace(/\{\{index\}\}/, $bulletEl.index() + 1),
);
}
});
}
- },
- init() {
- const swiper = this;
+ }
+
+ const initNavEl = ($el, wrapperId, message) => {
+ makeElFocusable($el);
+ if ($el[0].tagName !== 'BUTTON') {
+ addElRole($el, 'button');
+ $el.on('keydown', onEnterOrSpaceKey);
+ }
+ addElLabel($el, message);
+ addElControls($el, wrapperId);
+ };
+
+ function init() {
const params = swiper.params.a11y;
- swiper.$el.append(swiper.a11y.liveRegion);
+ swiper.$el.append(liveRegion);
// Container
const $containerEl = swiper.$el;
if (params.containerRoleDescriptionMessage) {
- swiper.a11y.addElRoleDescription($containerEl, params.containerRoleDescriptionMessage);
+ addElRoleDescription($containerEl, params.containerRoleDescriptionMessage);
}
if (params.containerMessage) {
- swiper.a11y.addElLabel($containerEl, params.containerMessage);
+ addElLabel($containerEl, params.containerMessage);
}
// Wrapper
const $wrapperEl = swiper.$wrapperEl;
- const wrapperId = $wrapperEl.attr('id') || `swiper-wrapper-${swiper.a11y.getRandomNumber(16)}`;
+ const wrapperId = $wrapperEl.attr('id') || `swiper-wrapper-${getRandomNumber(16)}`;
const live = swiper.params.autoplay && swiper.params.autoplay.enabled ? 'off' : 'polite';
- swiper.a11y.addElId($wrapperEl, wrapperId);
- swiper.a11y.addElLive($wrapperEl, live);
+ addElId($wrapperEl, wrapperId);
+ addElLive($wrapperEl, live);
// Slide
if (params.itemRoleDescriptionMessage) {
- swiper.a11y.addElRoleDescription($(swiper.slides), params.itemRoleDescriptionMessage);
+ addElRoleDescription($(swiper.slides), params.itemRoleDescriptionMessage);
}
- swiper.a11y.addElRole($(swiper.slides), params.slideRole);
+ addElRole($(swiper.slides), params.slideRole);
const slidesLength = swiper.params.loop
? swiper.slides.filter((el) => !el.classList.contains(swiper.params.slideDuplicateClass))
@@ -173,7 +197,7 @@ const A11y = {
const ariaLabelMessage = params.slideLabelMessage
.replace(/\{\{index\}\}/, slideIndex + 1)
.replace(/\{\{slidesLength\}\}/, slidesLength);
- swiper.a11y.addElLabel($slideEl, ariaLabelMessage);
+ addElLabel($slideEl, ariaLabelMessage);
});
// Navigation
@@ -187,42 +211,23 @@ const A11y = {
}
if ($nextEl && $nextEl.length) {
- swiper.a11y.makeElFocusable($nextEl);
- if ($nextEl[0].tagName !== 'BUTTON') {
- swiper.a11y.addElRole($nextEl, 'button');
- $nextEl.on('keydown', swiper.a11y.onEnterOrSpaceKey);
- }
- swiper.a11y.addElLabel($nextEl, params.nextSlideMessage);
- swiper.a11y.addElControls($nextEl, wrapperId);
+ initNavEl($nextEl, params.nextSlideMessage);
}
if ($prevEl && $prevEl.length) {
- swiper.a11y.makeElFocusable($prevEl);
- if ($prevEl[0].tagName !== 'BUTTON') {
- swiper.a11y.addElRole($prevEl, 'button');
- $prevEl.on('keydown', swiper.a11y.onEnterOrSpaceKey);
- }
- swiper.a11y.addElLabel($prevEl, params.prevSlideMessage);
- swiper.a11y.addElControls($prevEl, wrapperId);
+ initNavEl($prevEl, params.prevSlideMessage);
}
// Pagination
- if (
- swiper.pagination &&
- swiper.params.pagination.clickable &&
- swiper.pagination.bullets &&
- swiper.pagination.bullets.length
- ) {
+ if (hasPagination()) {
swiper.pagination.$el.on(
'keydown',
classesToSelector(swiper.params.pagination.bulletClass),
- swiper.a11y.onEnterOrSpaceKey,
+ onEnterOrSpaceKey,
);
}
- },
- destroy() {
- const swiper = this;
- if (swiper.a11y.liveRegion && swiper.a11y.liveRegion.length > 0)
- swiper.a11y.liveRegion.remove();
+ }
+ function destroy() {
+ if (liveRegion && liveRegion.length > 0) liveRegion.remove();
let $nextEl;
let $prevEl;
@@ -233,77 +238,41 @@ const A11y = {
$prevEl = swiper.navigation.$prevEl;
}
if ($nextEl) {
- $nextEl.off('keydown', swiper.a11y.onEnterOrSpaceKey);
+ $nextEl.off('keydown', onEnterOrSpaceKey);
}
if ($prevEl) {
- $prevEl.off('keydown', swiper.a11y.onEnterOrSpaceKey);
+ $prevEl.off('keydown', onEnterOrSpaceKey);
}
// Pagination
- if (
- swiper.pagination &&
- swiper.params.pagination.clickable &&
- swiper.pagination.bullets &&
- swiper.pagination.bullets.length
- ) {
+ if (hasPagination()) {
swiper.pagination.$el.off(
'keydown',
classesToSelector(swiper.params.pagination.bulletClass),
- swiper.a11y.onEnterOrSpaceKey,
+ onEnterOrSpaceKey,
);
}
- },
-};
-export default {
- name: 'a11y',
- params: {
- a11y: {
- enabled: true,
- notificationClass: 'swiper-notification',
- prevSlideMessage: 'Previous slide',
- nextSlideMessage: 'Next slide',
- firstSlideMessage: 'This is the first slide',
- lastSlideMessage: 'This is the last slide',
- paginationBulletMessage: 'Go to slide {{index}}',
- slideLabelMessage: '{{index}} / {{slidesLength}}',
- containerMessage: null,
- containerRoleDescriptionMessage: null,
- itemRoleDescriptionMessage: null,
- slideRole: 'group',
- },
- },
- create() {
- const swiper = this;
- bindModuleMethods(swiper, {
- a11y: {
- ...A11y,
- liveRegion: $(
- ``,
- ),
- },
- });
- },
- on: {
- afterInit(swiper) {
- if (!swiper.params.a11y.enabled) return;
- swiper.a11y.init();
- swiper.a11y.updateNavigation();
- },
- toEdge(swiper) {
- if (!swiper.params.a11y.enabled) return;
- swiper.a11y.updateNavigation();
- },
- fromEdge(swiper) {
- if (!swiper.params.a11y.enabled) return;
- swiper.a11y.updateNavigation();
- },
- paginationUpdate(swiper) {
- if (!swiper.params.a11y.enabled) return;
- swiper.a11y.updatePagination();
- },
- destroy(swiper) {
- if (!swiper.params.a11y.enabled) return;
- swiper.a11y.destroy();
- },
- },
-};
+ }
+
+ on('afterInit', () => {
+ if (!swiper.params.a11y.enabled) return;
+ init();
+ updateNavigation();
+ });
+ on('toEdge', () => {
+ if (!swiper.params.a11y.enabled) return;
+ updateNavigation();
+ });
+ on('fromEdge', () => {
+ if (!swiper.params.a11y.enabled) return;
+ updateNavigation();
+ });
+ on('paginationUpdate', () => {
+ if (!swiper.params.a11y.enabled) return;
+ updatePagination();
+ });
+ on('destroy', () => {
+ if (!swiper.params.a11y.enabled) return;
+ destroy();
+ });
+}