fx-compat: Make color picker CE accessible via keyboard and VoiceOver (#2933)
This commit is contained in:
parent
ffdfc73d47
commit
0a94e8fdf0
4 changed files with 114 additions and 32 deletions
|
@ -67,6 +67,38 @@
|
|||
set colors(colors) {
|
||||
this.setAttribute('colors', colors.join(','));
|
||||
}
|
||||
|
||||
get colorLabels() {
|
||||
if (this.hasAttribute('color-labels')) {
|
||||
return this.getAttribute('color-labels').split(',').map((label) => {
|
||||
let localized;
|
||||
try {
|
||||
localized = Zotero.getString(label);
|
||||
}
|
||||
catch (e) {}
|
||||
if (!localized || localized == label) {
|
||||
return label;
|
||||
}
|
||||
else {
|
||||
return localized;
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (this.hasAttribute('colors')) {
|
||||
Zotero.debug('WARNING: <color-picker> CE: Set color-labels when setting colors');
|
||||
}
|
||||
return [
|
||||
'general.red', 'general.orange', 'general.gray',
|
||||
'general.green', 'general.teal', 'general.blue',
|
||||
'general.purple', 'general.violet', 'general.maroon'
|
||||
].map(label => Zotero.getString(label));
|
||||
}
|
||||
}
|
||||
|
||||
set colorLabels(colorLabels) {
|
||||
this.setAttribute('color-labels', colorLabels.join(','));
|
||||
}
|
||||
|
||||
get cols() {
|
||||
return this.getAttribute('cols') || 3;
|
||||
|
@ -75,6 +107,10 @@
|
|||
set cols(cols) {
|
||||
this.setAttribute('cols', cols);
|
||||
}
|
||||
|
||||
get rows() {
|
||||
return Math.ceil(this.colors.length / this.cols);
|
||||
}
|
||||
|
||||
get tileWidth() {
|
||||
return this.getAttribute('tileWidth') || 24;
|
||||
|
@ -102,13 +138,78 @@
|
|||
|
||||
init() {
|
||||
let button = this.querySelector('.button');
|
||||
let panel = this.querySelector('.panel');
|
||||
let grid = this.querySelector('.grid');
|
||||
|
||||
button.addEventListener('keydown', (event) => {
|
||||
if (event.key == ' ' || event.key == 'Enter' || event.key == 'ArrowDown') {
|
||||
event.preventDefault();
|
||||
this.openPopup(true);
|
||||
}
|
||||
});
|
||||
|
||||
button.addEventListener('click', () => {
|
||||
grid.style.gridTemplateColumns = `repeat(${this.cols}, ${this.tileWidth}px)`;
|
||||
grid.style.gridAutoRows = `${this.tileHeight}px`;
|
||||
panel.openPopup(button, 'after_start', 0, 0, false, false);
|
||||
this.openPopup(false);
|
||||
});
|
||||
}
|
||||
|
||||
openPopup(focus = false) {
|
||||
this.buildGrid();
|
||||
|
||||
let button = this.querySelector('.button');
|
||||
let panel = this.querySelector('.panel');
|
||||
let grid = this.querySelector('.grid');
|
||||
grid.style.gridTemplateColumns = `repeat(${this.cols}, ${this.tileWidth}px)`;
|
||||
grid.style.gridAutoRows = `${this.tileHeight}px`;
|
||||
|
||||
if (focus) {
|
||||
panel.addEventListener('popupshown', () => {
|
||||
grid.querySelector('.grid-tile').focus();
|
||||
}, { once: true });
|
||||
}
|
||||
panel.openPopup(button, 'after_start', 0, 0, false, false);
|
||||
}
|
||||
|
||||
buildGrid() {
|
||||
let grid = this.querySelector('.grid');
|
||||
grid.innerHTML = '';
|
||||
let colors = this.colors;
|
||||
let colorLabels = this.colorLabels;
|
||||
colors.forEach((color, i) => {
|
||||
let tile = document.createElement('button');
|
||||
tile.setAttribute('aria-label', colorLabels[i]);
|
||||
tile.classList.add('grid-tile');
|
||||
tile.style.backgroundColor = color;
|
||||
|
||||
tile.addEventListener('click', () => {
|
||||
this.color = color;
|
||||
this.querySelector('.panel').hidePopup();
|
||||
});
|
||||
tile.addEventListener('keydown', (event) => {
|
||||
switch (event.key) {
|
||||
case 'ArrowLeft':
|
||||
(tile.previousElementSibling || tile.parentElement.lastElementChild).focus();
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
(tile.nextElementSibling || tile.parentElement.firstElementChild).focus();
|
||||
break;
|
||||
case 'ArrowUp': {
|
||||
let upIndex = (Array.from(tile.parentElement.children).indexOf(tile) - this.cols)
|
||||
% (this.rows * this.cols);
|
||||
if (upIndex < 0) {
|
||||
upIndex += this.rows * this.cols;
|
||||
}
|
||||
tile.parentElement.children[upIndex].focus();
|
||||
break;
|
||||
}
|
||||
case 'ArrowDown': {
|
||||
let downIndex = (Array.from(tile.parentElement.children).indexOf(tile) + this.cols)
|
||||
% (this.rows * this.cols);
|
||||
tile.parentElement.children[downIndex].focus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
grid.append(tile);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -120,20 +221,6 @@
|
|||
if (attrName == 'color') {
|
||||
this.querySelector('.button-tile').style.backgroundColor = newVal;
|
||||
}
|
||||
else if (attrName == 'colors') {
|
||||
let grid = this.querySelector('.grid');
|
||||
grid.innerHTML = '';
|
||||
for (let color of newVal.split(',')) {
|
||||
let tile = document.createElement('div');
|
||||
tile.classList.add('grid-tile');
|
||||
tile.style.backgroundColor = color;
|
||||
tile.addEventListener('click', () => {
|
||||
this.color = color;
|
||||
this.querySelector('.panel').hidePopup();
|
||||
});
|
||||
grid.append(tile);
|
||||
}
|
||||
}
|
||||
else if (attrName == 'disabled') {
|
||||
this.querySelector('.button').disabled = !!newVal;
|
||||
}
|
||||
|
|
|
@ -52,15 +52,6 @@ var Zotero_Tag_Color_Chooser = new function() {
|
|||
var colorPicker = document.getElementById('color-picker');
|
||||
var tagPosition = document.getElementById('tag-position');
|
||||
|
||||
colorPicker.setAttribute('cols', 3);
|
||||
colorPicker.setAttribute('tileWidth', 24);
|
||||
colorPicker.setAttribute('tileHeight', 24);
|
||||
colorPicker.colors = [
|
||||
'#FF6666', '#FF8C19', '#999999',
|
||||
'#5FB236', '#009980', '#2EA8E5',
|
||||
'#576DD9', '#A28AE5', '#A6507B'
|
||||
];
|
||||
|
||||
var maxTags = document.getElementById('max-tags');
|
||||
maxTags.value = Zotero.getString('tagColorChooser.maxTags', Zotero.Tags.MAX_COLORED_TAGS);
|
||||
|
||||
|
|
|
@ -97,13 +97,16 @@ general.insert = Insert
|
|||
general.username = Username
|
||||
general.password = Password
|
||||
|
||||
general.yellow = Yellow
|
||||
general.red = Red
|
||||
general.orange = Orange
|
||||
general.yellow = Yellow
|
||||
general.green = Green
|
||||
general.teal = Teal
|
||||
general.blue = Blue
|
||||
general.purple = Purple
|
||||
general.magenta = Magenta
|
||||
general.orange = Orange
|
||||
general.violet = Violet
|
||||
general.maroon = Maroon
|
||||
general.gray = Gray
|
||||
|
||||
general.operationInProgress = A Zotero operation is currently in progress.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
color-picker {
|
||||
button {
|
||||
.button {
|
||||
width: 38px;
|
||||
height: 24px;
|
||||
appearance: none;
|
||||
|
@ -25,7 +25,8 @@ color-picker {
|
|||
gap: 2px;
|
||||
}
|
||||
|
||||
.grid-tile:hover {
|
||||
.grid-tile, .grid-tile:hover {
|
||||
appearance: none;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue