diff --git a/coral-component-masonry/examples/index.html b/coral-component-masonry/examples/index.html
index c1b9f69c73..fcc2262461 100644
--- a/coral-component-masonry/examples/index.html
+++ b/coral-component-masonry/examples/index.html
@@ -145,7 +145,7 @@
Usage notes
With image
-
+
@@ -234,7 +234,6 @@ Usage notes
item.id = getUID();
}
article.id = article.id || item.id + '-content';
- item.setAttribute('aria-labelledby', article.id);
});
const ariaGridSelector = document.getElementById('ariaGrid');
@@ -301,11 +300,10 @@ Usage notes
const contentId = id + '-content';
const width = randomSize();
const height = randomSize();
- const url = 'http://via.placeholder.com/' + width + 'x' + height;
+ const url = 'https://via.placeholder.com/' + width + 'x' + height;
const item = document.createElement('coral-masonry-item');
item.id = id;
- item.setAttribute('aria-labelledby', contentId);
item.classList.add('coral-Well');
item.content.innerHTML = '
';
@@ -320,7 +318,6 @@ Usage notes
const item = document.createElement('coral-masonry-item');
item.id = id;
- item.setAttribute('aria-labelledby', contentId);
item.classList.add('coral-Well');
item.content.innerHTML = '' + html + '';
return item;
diff --git a/coral-component-masonry/src/scripts/Masonry.js b/coral-component-masonry/src/scripts/Masonry.js
index 5f2f1dc51f..def1a92eb7 100644
--- a/coral-component-masonry/src/scripts/Masonry.js
+++ b/coral-component-masonry/src/scripts/Masonry.js
@@ -301,7 +301,7 @@ const Masonry = Decorator(class extends BaseComponent(HTMLElement) {
// @a11y only persist the checked state on macOS,
// where VoiceOver does not announce the selected state for a gridcell.
- accessibilityState.hidden = true;
+ accessibilityState.hidden = !isMacLike || !self.selected;
if (!isMacLike || !self.selected) {
accessibilityState.innerHTML = '';
}
@@ -598,9 +598,15 @@ const Masonry = Decorator(class extends BaseComponent(HTMLElement) {
if (activateAriaGrid === ariaGrid.ON) {
item.setAttribute('role', 'gridcell');
item.setAttribute('aria-colindex', columnIndex);
+
+ // communicate aria-selected state of all cells
+ if (this.selectionMode !== selectionMode.NONE || this.parentElement.hasAttribute('aria-multiselectable')) {
+ item.setAttribute('aria-selected', item.selected);
+ }
} else {
item.removeAttribute('role');
item.removeAttribute('aria-colindex');
+ item.removeAttribute('aria-selected');
}
}
@@ -621,10 +627,13 @@ const Masonry = Decorator(class extends BaseComponent(HTMLElement) {
const selectedItems = this.selectedItems;
if (this.selectionMode === selectionMode.NONE) {
- selectedItems.forEach((selectedItem) => {
+ this.items.getAll().forEach((item) => {
// Don't trigger change events
this._preventTriggeringEvents = true;
- selectedItem.removeAttribute('selected');
+ if (item.selected) {
+ item.removeAttribute('selected');
+ }
+ item.removeAttribute('aria-selected');
});
} else if (this.selectionMode === selectionMode.SINGLE) {
// Last selected item wins if multiple selection while not allowed
diff --git a/coral-component-masonry/src/scripts/MasonryItem.js b/coral-component-masonry/src/scripts/MasonryItem.js
index 56e27e19a5..fc63794a0b 100644
--- a/coral-component-masonry/src/scripts/MasonryItem.js
+++ b/coral-component-masonry/src/scripts/MasonryItem.js
@@ -246,18 +246,18 @@ const MasonryItem = Decorator(class extends BaseComponent(HTMLElement) {
if (!accessibilityState.parentNode) {
this.appendChild(accessibilityState);
}
+
+ // @a11y Item should be labelled by accessibility state.
+ if (isMacLike) {
+ const ariaLabelledby = this.getAttribute('aria-labelledby');
+ if (ariaLabelledby) {
+ this.setAttribute('aria-labelledby', ariaLabelledby + ' ' + accessibilityState.id);
+ }
+ }
});
this._elements.accessibilityState = accessibilityState;
- // @a11y Item should be labelled by accessibility state.
- if (isMacLike) {
- const ariaLabelledby = this.getAttribute('aria-labelledby');
- if (ariaLabelledby) {
- this.setAttribute('aria-labelledby', ariaLabelledby + ' ' + accessibilityState.id);
- }
- }
-
// Support cloneNode
const template = this.querySelector('._coral-Masonry-item-quickActions');
if (template) {
@@ -266,6 +266,7 @@ const MasonryItem = Decorator(class extends BaseComponent(HTMLElement) {
this.insertBefore(this._elements.quickactions, this.firstChild);
// todo workaround to not give user possibility to tab into checkbox
this._elements.check._labellableElement.tabIndex = -1;
+ this._elements.check.setAttribute('aria-hidden', 'true');
}
/** @ignore */
diff --git a/coral-component-masonry/src/tests/test.Masonry.js b/coral-component-masonry/src/tests/test.Masonry.js
index 0d67493038..a9721c91e8 100644
--- a/coral-component-masonry/src/tests/test.Masonry.js
+++ b/coral-component-masonry/src/tests/test.Masonry.js
@@ -513,16 +513,16 @@ describe('Masonry', function () {
item.selected = true;
setTimeout(function() {
- expect(a11yState.textContent).to.equal(i18n.get('checked'));
+ expect(a11yState.textContent).to.equal(i18n.get('checked'), 'after ~275ms accessibilityState should read "checked"');
expect(a11yState.hidden).to.be.false;
expect(a11yState.hasAttribute('aria-live')).to.be.false;
setTimeout(function() {
- expect(a11yState.textContent).to.equal(isMacLike ? i18n.get('checked') : '');
- expect(a11yState.hidden).to.be.true;
+ expect(a11yState.textContent).to.equal(isMacLike ? i18n.get('checked') : '', 'after 1600ms accessibilityState should read "" or "checked" on macOS');
+ expect(a11yState.hidden).to.equal(!isMacLike, 'on macOS, the "checked" accessibilityState should not be hidden');
expect(a11yState.getAttribute('aria-live')).equal('off');
done();
- }, 1650);
- }, 220);
+ }, 1600);
+ }, 275);
});
});
@@ -541,16 +541,16 @@ describe('Masonry', function () {
item.selected = true;
item.selected = false;
setTimeout(function() {
- expect(a11yState.textContent).to.equal(i18n.get('not checked'));
+ expect(a11yState.textContent).to.equal(i18n.get('not checked'), 'after ~275ms accessibilityState should read "not checked"');
expect(a11yState.hidden).to.be.false;
expect(a11yState.hasAttribute('aria-live')).to.be.false;
setTimeout(function() {
- expect(a11yState.textContent).to.equal('');
+ expect(a11yState.textContent).to.equal('', 'after 1600ms accessibilityState should read ""');
expect(a11yState.hidden).to.be.true;
expect(a11yState.getAttribute('aria-live')).to.equal('off');
done();
- }, 1650);
- }, 210);
+ }, 1600);
+ }, 275);
});
});
});
@@ -571,6 +571,8 @@ describe('Masonry', function () {
.to.equal('gridcell', ' should have role="gridcell"');
expect(el.items.last().getAttribute('aria-colindex'))
.to.equal('3', 'last should have aria-colindex="3"');
+ expect(el.items.first().hasAttribute('aria-selected'))
+ .to.equal(false, ' should not have aria-selected when selectionMode="none"');
// Disable aria grid dynamically
el.ariaGrid = "off";
@@ -595,9 +597,31 @@ describe('Masonry', function () {
expect(el.parentElement.getAttribute('aria-label')).to.equal('Masonry Label', 'Masonry parent element should receive same aria-label as Masonry');
expect(el.parentElement.getAttribute('aria-labelledby')).to.equal('Masonry Labelledby', 'Masonry parent element should receive same aria-labelledby as Masonry');
});
+ it('masonry elements should have aria-selected when selectionMode is not "none"', function() {
+ const el = helpers.build(window.__html__['Masonry.items.selected.html']);
+
+ el.ariaGrid = "on";
+
+ expect(el.items.first().getAttribute('aria-selected'))
+ .to.equal('true', 'selected should have aria-selected="true" when selectionMode="single"');
+ expect(el.items.last().getAttribute('aria-selected'))
+ .to.equal('false', 'not selected should have aria-selected="false" when selectionMode="single"');
+
+ el.selectionMode = 'multiple';
+ expect(el.items.first().getAttribute('aria-selected'))
+ .to.equal('true', 'selected should have aria-selected="true" when selectionMode="multiple"');
+ expect(el.items.last().getAttribute('aria-selected'))
+ .to.equal('false', 'not selected should have aria-selected="false" when selectionMode="multiple"');
+
+ el.selectionMode = 'none';
+ expect(el.items.first().hasAttribute('aria-selected'))
+ .to.equal(false, 'selected should not have aria-selected when selectionMode="none"');
+ expect(el.items.last().hasAttribute('aria-selected'))
+ .to.equal(false, 'not selected should note have aria-selected="false" when selectionMode="none"');
+ })
});
- describe('Attach/Detch', function () {
+ describe('Attach/Detach', function () {
it('changing masonry parent should keep child intact', function (done) {
const el = helpers.build(window.__html__['Masonry.with.div.wrapper.html']);
const masonry = el.querySelector("coral-masonry");
diff --git a/coral-gulp/configs/karma.conf.js b/coral-gulp/configs/karma.conf.js
index 97815299fd..3f4bcf8bbc 100644
--- a/coral-gulp/configs/karma.conf.js
+++ b/coral-gulp/configs/karma.conf.js
@@ -159,6 +159,11 @@ module.exports = function (config) {
client: {
// Set to true for debugging via e.g console.debug
captureConsole: false
+ /* ,
+ // Override the timeout, should tests fail due to timeout errors.
+ mocha: {
+ timeout: 2500
+ } */
}
});
};