Skip to content

Commit

Permalink
XWIKI-22280: Object editor dropdowns are not keyboard accessible
Browse files Browse the repository at this point in the history
* Added basic keyboard support to the reorder tool as an alternative to drag and drop
* Removed titles from the toggling buttons, they only conveyed repetitive info and would need some additional (very similar) translations
* Updated style to use current bootstrap button styles (btn-default instead of btn-secondary...)
* Refined a bit more the style to fit better with what it used to be and better UI navigability.
* Updated translation to reflect the new functionality of the reorder button.
  • Loading branch information
Sereza7 committed Jul 5, 2024
1 parent 3684a39 commit e030e84
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ $xwiki.jsfx.use('js/xwiki/editors/dataeditors.js', true)##
<div id="xproperty_${field.name}" class="xproperty #if($field.disabled)disabled#end">
<div id="xproperty_${field.name}_title" class="xproperty-title ${field.type}">
<h3>
<button type="button" class="btn btn-secondary" title="$escapetool.xml($services.localization.render('core.editors.class.property.toggleDisplay.tooltip'))">
<button type="button" class="btn btn-default btn-xs">
<span class="sr-only">$escapetool.xml($services.localization.render('core.editors.class.property.toggleDisplay.tooltip'))</span>
<span class="toggle-collapsable" role="presentation">$services.icon.renderHTML('caret-down')</span>
<span class="iconHolder"></span>
Expand Down Expand Up @@ -181,7 +181,7 @@ $xwiki.jsfx.use('js/xwiki/editors/dataeditors.js', true)##
<div id="xclass_${escapetool.xml($class.name)}" class="xclass">
<div id="xclass_${escapetool.xml($class.name)}_title" class="xclass-title">
<h2>
<button type="button" class="btn btn-secondary" title="$escapetool.xml($services.localization.render('core.editors.class.toggleDisplay.tooltip'))">
<button type="button" class="btn btn-default">
<span class="sr-only">$escapetool.xml($services.localization.render('core.editors.class.toggleDisplay.tooltip'))</span>
<span class="toggle-collapsable" role="presentation">$services.icon.renderHTML('caret-down')</span>
${escapetool.xml($class.name)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
#getFieldSummary($obj $firstField $firstFieldSummary)
<div id="xobject_${escapetool.xml($class.name)}_${obj.number}_title" class="xobject-title">
<h3>
<button type="button" class="btn btn-secondary" title="$escapetool.xml($services.localization.render('core.editors.object.toggleDisplay.tooltip'))">
<button type="button" class="btn btn-default btn-xs">
<span class="sr-only">$escapetool.xml($services.localization.render('core.editors.object.toggleDisplay.tooltip'))</span>
<span class="toggle-collapsable" role="presentation">$services.icon.renderHTML('caret-down')</span>
#cleanClassname(${class.name}) <span class="editor-objectNumber">${obj.number}</span>#if ($firstField): $firstFieldSummary#end
Expand Down Expand Up @@ -157,7 +157,7 @@
#if ($object)
<div id="xclass_${escapetool.xml($class.name)}_title" class="xclass-title">
<h2>
<button type="button" class="btn btn-secondary" title="$escapetool.xml($services.localization.render('core.editors.class.toggleDisplay.tooltip'))">
<button type="button" class="btn btn-default">
<span class="sr-only">$escapetool.xml($services.localization.render('core.editors.class.toggleDisplay.tooltip'))</span>
<span class="toggle-collapsable" role="presentation">$services.icon.renderHTML('caret-down')</span>
${escapetool.xml($class.name)}
Expand All @@ -183,7 +183,7 @@
#set ($objectCount = $objects.size())
<div id="xclass_${escapetool.xml($class.name)}_title" class="xclass-title">
<h2>
<button type="button" class="btn btn-secondary" title="$escapetool.xml($services.localization.render('core.editors.class.toggleDisplay.tooltip'))">
<button type="button" class="btn btn-secondary">
<span class="sr-only">$escapetool.xml($services.localization.render('core.editors.class.toggleDisplay.tooltip'))</span>
<span class="toggle-collapsable" role="presentation">$services.icon.renderHTML('caret-down')</span>
$services.localization.render('core.editors.object.objectsForClass', [${escapetool.xml($class.name)}])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1328,7 +1328,7 @@ core.editors.class.addProperty.inProgress=Adding property...
core.editors.class.addProperty.done=Property added
core.editors.class.addProperty.failed=Failed:

core.editors.class.moveProperty.handle.label=Drag and drop to change the order
core.editors.class.moveProperty.handle.label=Drag and drop or use up/down arrows to change the order of this property.

core.editors.class.deleteProperty.text=delete
core.editors.class.deleteProperty.tooltip=Delete property {0}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ div#xwikiobjects input[type="radio"], div#xwikiclassproperties input[type="radio
/* XProperty definition */
.xproperty {
border: none;
margin-top: .5em;
margin-top: .1rem;
}

.xproperty-content {
Expand Down Expand Up @@ -131,8 +131,6 @@ div#xwikiobjects input[type="radio"], div#xwikiclassproperties input[type="radio
.xproperty-title h3 button {
padding-bottom: 0;
padding-top: 0;
margin-bottom: 0;
margin-top: 0;
}

/* Default state for the icon representing the property. */
Expand Down Expand Up @@ -179,21 +177,29 @@ div#xwikiobjects input[type="radio"], div#xwikiclassproperties input[type="radio
.xobject-title h3 button,
.xproperty-title h3 button {
border: none;
margin: 0;
background: transparent;
width: 100%;
text-align: left;
/* We overwrite the small font size that is set with btn-xs. */
font-size: 1em;
}

.xclass-title h2 button:hover,
.xobject .xobject-title h3 button:hover,
.xproperty .xproperty-title h3 button:hover {
.xclass-title h2 button:focus,
.xobject .xobject-title:hover h3 button,
.xobject .xobject-title:focus-within h3 button,
.xproperty .xproperty-title:hover h3 button,
.xproperty .xproperty-title:focus-within h3 button {
border: none;
background-color: $theme.highlightColor;
color: $theme.textPrimaryColor;
}

.xclass-title h2 button:active,
.xobject .xobject-title h3 button:active,
.xproperty .xproperty-title h3 button:active {
border: none;
box-shadow: none;
}

Expand Down Expand Up @@ -252,6 +258,11 @@ The default state is collapsed for xobjects and xproperties, but expanded for xc
font-weight: 900;
}

.xproperty-title .tools {
display: inline-flex;
align-items: baseline;
}

.xproperty-title .tools .tool {
width: 16px;
height: 16px;
Expand All @@ -261,6 +272,7 @@ The default state is collapsed for xobjects and xproperties, but expanded for xc
.xproperty-title .tools .move {
cursor: move;
color: $theme.linkColor;
margin: 0;
}

.xproperty-title .tools .delete {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -750,15 +750,43 @@ editors.XDataEditors = Class.create({
});
// Create and insert move button
element.select('.xproperty-title .tools').each(function(item) {
var movebutton = new Element('span', {
'class': 'tool move',
var movebutton = new Element('button', {
'class': 'btn btn-secondary btn-xs tool move',
title: $jsontool.serialize($services.localization.render('core.editors.class.moveProperty.handle.label'))
}).update($jsontool.serialize($services.icon.renderHTML('reposition')));
}).update('<span class="sr-only">' +
$jsontool.serialize($services.localization.render('core.editors.class.moveProperty.handle.label')) +
'</span>' +
$jsontool.serialize($services.icon.renderHTML('reposition')));
item.makePositioned();
item.appendChild(movebutton);
movebutton.observe('click', function(event) {
event.stop();
}.bindAsEventListener());
// Extend the Sortable items with arrow keys support
movebutton.observe('keydown', function(event){
if (![38, 40].includes(event.keyCode)) { return; }
var sequence = Sortable.sequence($('xclassContent'));
var sequenceLength = sequence.length;
var item = event.target.parentElement.parentElement.parentElement;
/* We need to recompute the name of the entry similarly to what's done in scriptaculous
to make sure it matches the one we get in the sequence. */
let format = /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/;
let currentElementName = item.id.match(format) ? item.id.match(format)[1] : '';
let currentElementIndex = sequence.indexOf(currentElementName);
let swapWithIndex;
if (event.keyCode === 38) { // UP ARROW
swapWithIndex = (currentElementIndex + sequenceLength - 1) % sequenceLength;
} else if (event.keyCode === 40) { // DOWN ARROW
swapWithIndex = (currentElementIndex + sequenceLength + 1) % sequenceLength;
}
[ sequence[currentElementIndex], sequence[swapWithIndex] ] = [ sequence[swapWithIndex], sequence[currentElementIndex] ];
/* We update the content of the sortable object.*/
Sortable.setSequence($('xclassContent'), sequence);
/* We make sure to trigger the listener that should be called with such an update. */
Sortable.sortables['xclassContent'].onUpdate(Sortable.sortables['xclassContent'].containment);
/* We refocus the element, so that the focus isn't lost when moving it. */
event.target.focus();
}.bindAsEventListener());
});
// Attach behavior to the move buttons
Sortable.create($('xclassContent'), {
Expand Down

0 comments on commit e030e84

Please sign in to comment.