Skip to content

Instantly share code, notes, and snippets.

@DeathStapler
Last active November 8, 2022 22:23
Show Gist options
  • Save DeathStapler/1a0e7374f4a760f05e58dc0ac80449a8 to your computer and use it in GitHub Desktop.
Save DeathStapler/1a0e7374f4a760f05e58dc0ac80449a8 to your computer and use it in GitHub Desktop.
Making JetSmartFilters checkbox, radio, and visual filters more accessible
<script>
var radioGroupClass='.jet-radio-list';
var radioClass='.jet-radio-list__button';
var radioInputClass='.jet-radio-list__input';
var visualGroupClass='.jet-color-image-list';
var visualClass='.jet-color-image-list__button';
var visualInputClass='.jet-color-image-list__input';
var checkboxGroupClass='.jet-checkboxes-list';
var checkboxClass='.jet-checkboxes-list__button';
var checkboxInputClass='.jet-checkboxes-list__input';
jQuery(document).ready(function($ ) {
filterRadioWidgetInit();
filterCheckboxWidgetInit();
filterVisualWidgetInit();
$(document).on('jet-filter-content-rendered', function() {
setTimeout(function () {
filterRadioWidgetInit();
filterCheckboxWidgetInit();
filterVisualWidgetInit();
}, 1);
});
////////////////////////////////
// RADIO BUTTON
function filterRadioWidgetInit() {
$(radioGroupClass).each(function () {
$(this).attr('role', 'radiogroup');
$(this).find(radioClass).each(function () {
$(this).attr('role', 'radio');
initAttr(this, 'aria-checked');
});
if ($(this).find(radioClass + '.aria-checked').length > 0) {
$(this).find(radioClass).each(function () {
initTabIndex(this, 'aria-checked');
});
}
else {
$(this).find(radioClass).each(function () {
$(this).attr('tabindex', '-1');
});
$(this).find(radioClass).first().attr('tabindex', '0');
}
});
$(radioClass).off('keydown').on('keydown', function(e) {
switch (e.which) {
case 37:
case 38:
e.preventDefault();
gotoPrevElement($(this), '.jet-filter-row', radioClass).focus();
break;
case 39:
case 40:
e.preventDefault();
gotoNextElement($(this), '.jet-filter-row', radioClass).focus();
break;
case 13:
case 32:
e.preventDefault();
var input=$(this).parent().find(radioInputClass);
// Reset aria-press for radios. They will be reset after filter update
$(this).closest(radioGroupClass).find(radioClass).each(function() {
$(this).removeClass('aria-checked');
$(this).attr('aria-checked', 'false');
$(this).attr('tabindex', '-1');
});
$(this).attr('tabindex', '0');
simulateClick(this, input, 'aria-checked', 'checked');
break;
}
});
$(radioClass).off('click').on('click', function() {
var input=$(this).parent().find(radioInputClass);
$(this).closest(radioGroupClass).find(radioClass).each(function() {
$(this).removeClass('aria-checked');
$(this).attr('aria-checked', 'false');
$(this).attr('tabindex', '-1');
});
$(this).attr('tabindex', '0');
setClassAndAriaFromInput(this, input, 'checked', 'aria-checked');
});
}
////////////////////////////////
// CHECKBOX
function filterCheckboxWidgetInit() {
$(checkboxGroupClass).each(function () {
$(this).attr('role', 'group');
});
$(checkboxClass).each(function() {
$(this).attr('role', 'checkbox');
$(this).attr('tabindex', '0');
initAttr(this, 'aria-checked');
});
$(checkboxClass).off('keydown').on('keydown', function(e) {
switch (e.which) {
case 37:
case 38:
e.preventDefault();
gotoPrevElement($(this), '.jet-filter-row', checkboxClass).focus();
break;
case 39:
case 40:
e.preventDefault();
gotoNextElement($(this), '.jet-filter-row', checkboxClass).focus();
break;
case 13:
case 32:
e.preventDefault();
var input=$(this).parent().find(checkboxInputClass);
simulateClick(this, input, 'aria-checked', 'checked');
break;
}
});
$(checkboxClass).off('click').on('click', function() {
var input=$(this).parent().find(checkboxInputClass);
setClassAndAriaFromInput(this, input, 'checked', 'aria-checked');
});
}
////////////////////////////////
// VISUAL FILTER
function filterVisualWidgetInit() {
$(visualGroupClass).each(function () {
$(this).attr('role', 'radiogroup');
$(this).find(visualClass).each(function () {
$(this).attr('role', 'radio');
initAttr(this, 'aria-checked');
});
if ($(this).find(visualClass + '.aria-checked').length > 0) {
$(this).find(radioClass).each(function () {
initTabIndex(this, 'aria-checked');
});
} else {
$(this).find(visualClass).each(function () {
$(this).attr('tabindex', '-1');
});
$(this).find(visualClass).first().attr('tabindex', '0');
}
});
$(visualClass).off('keydown').on('keydown', function(e) {
switch (e.which) {
case 37:
case 38:
e.preventDefault();
gotoPrevElement($(this), '.jet-filter-row', visualClass).focus();
break;
case 39:
case 40:
e.preventDefault();
gotoNextElement($(this), '.jet-filter-row', visualClass).focus();
break;
case 13:
case 32:
e.preventDefault();
var input=$(this).parent().find(visualInputClass);
// Reset aria-press for radios. They will be reset after filter update
$(this).closest(visualGroupClass).find(visualClass).each(function() {
$(this).removeClass('aria-checked');
$(this).attr('aria-checked', 'false');
$(this).attr('tabindex', '-1');
});
$(this).attr('tabindex', '0');
simulateClick(this, input, 'aria-checked', 'checked');
break;
}
});
$(visualClass).off('click').on('click', function() {
var input=$(this).parent().find(visualInputClass);
$(this).closest(visualGroupClass).find(visualClass).each(function() {
$(this).removeClass('aria-checked');
$(this).attr('aria-checked', 'false');
$(this).attr('tabindex', '-1');
});
$(this).attr('tabindex', '0');
setClassAndAriaFromInput(this, input, 'checked', 'aria-checked');
});
}
//////////////////// SUPPORT FUNCTIONS ////////////////////////////
function gotoNextElement(t, closestElem, findElem) {
var next=t.closest(closestElem).next()[0];
if (next===undefined) {
next = t.closest(closestElem).prevAll().last()[0];
}
if (next !==undefined) {
return $(next).find(findElem);
}
return undefined;
}
function gotoPrevElement(t, closestElem, findElem) {
var prev=t.closest(closestElem).prev()[0];
if (prev===undefined) {
prev = t.closest(closestElem).nextAll().last()[0];
}
if (prev !==undefined) {
return $(prev).find(findElem);
}
return undefined;
}
function initTabIndex(t, attr) {
if ($(t).hasClass(attr)) {
$(t).attr('tabindex', '0');
} else {
$(t).attr('tabindex', '-1');
}
}
function initAttr(t, attr) {
if ($(t).hasClass(attr)) {
$(t).attr(attr, 'true');
} else {
$(t).attr(attr, 'false');
}
}
function simulateClick(t, input, attr, prop) {
setClassAndAriaFromInput(t, input, prop, attr);
input.trigger('click');
}
function setClassAndAriaFromInput(t, input, prop, attr) {
if (input.prop(prop)===true) {
$(t).removeClass(attr);
$(t).attr(attr, 'false');
} else {
$(t).attr(attr, 'true');
$(t).addClass(attr);
}
}
});
</script>
@DeathStapler
Copy link
Author

Does not support Tri-state checkboxes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment