Skip to content

Commit 8a5d56e

Browse files
committed
fix:#7 accessible action buttons
1 parent 5ac1686 commit 8a5d56e

File tree

2 files changed

+52
-25
lines changed

2 files changed

+52
-25
lines changed

code-component/PowerDragDrop/ControlManifest.Input.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest>
3-
<control namespace="CustomControl" constructor="PowerDragDrop" version="1.0.21" display-name-key="PowerDragDrop" description-key="PowerDragDrop_Desc" control-type="standard">
3+
<control namespace="CustomControl" constructor="PowerDragDrop" version="1.0.23" display-name-key="PowerDragDrop" description-key="PowerDragDrop_Desc" control-type="standard">
44
<!--external-service-usage node declares whether this 3rd party PCF control is using external service or not, if yes, this control will be considered as premium and please also add the external domain it is using.-->
55
<external-service-usage enabled="false"></external-service-usage>
66
<property name="DropZoneID" description-key="DropZoneID_Desc" display-name-key="DropZoneID" required="true" usage="input" of-type="SingleLine.Text"/>

code-component/PowerDragDrop/index.ts

+51-24
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ interface RegisteredZone {
3030
zoneId: string;
3131
maximumItems: number | undefined;
3232
sortable: Sortable;
33+
onActionClick: (ev: MouseEvent) => void;
3334
}
3435

3536
const defaultSortableOptions: Sortable.Options = {
@@ -321,21 +322,26 @@ export class PowerDragDrop implements ComponentFramework.StandardControl<IInputs
321322

322323
if (zoneElement !== null && (!existingZoneRegistration || registeredOnDifferentElement)) {
323324
this.trace('registerZones CREATE', zoneId);
324-
this.zonesRegistered[zoneId] = {
325+
const sortable = new Sortable(zoneElement, {
326+
...this.getDynamicSortableOptions(),
327+
group: masterDropZoneId,
328+
onChoose: this.onChoose,
329+
onUnchoose: this.onUnChoose,
330+
onEnd: this.onEnd,
331+
onMove: this.onMove,
332+
filter: this.actionFilter,
333+
});
334+
const zoneRegistration = {
325335
zoneId: zoneId,
326336
index: index,
327337
maximumItems: maximumItems[index],
328-
sortable: new Sortable(zoneElement, {
329-
...this.getDynamicSortableOptions(),
330-
group: masterDropZoneId,
331-
onChoose: this.onChoose,
332-
onUnchoose: this.onUnChoose,
333-
onEnd: this.onEnd,
334-
onFilter: this.onFilter,
335-
onMove: this.onMove,
336-
filter: this.actionFilter,
337-
}),
338+
onActionClick: (ev: MouseEvent) => {
339+
this.actionClick(ev, zoneElement);
340+
},
341+
sortable: sortable,
338342
};
343+
this.zonesRegistered[zoneId] = zoneRegistration;
344+
zoneElement.addEventListener('click', zoneRegistration.onActionClick);
339345
}
340346
});
341347

@@ -377,7 +383,12 @@ export class PowerDragDrop implements ComponentFramework.StandardControl<IInputs
377383
const zone = this.zonesRegistered[zoneId];
378384
// Prevent un-registering a zone if there is currently a drag happening
379385
if (this.currentItemZone === null) {
380-
zone.sortable.destroy();
386+
try {
387+
zone.sortable.destroy();
388+
zone.sortable.el.removeEventListener('click', zone.onActionClick);
389+
} catch (e) {
390+
this.trace('unRegisterZone Error', e);
391+
}
381392
} else {
382393
this.sortablesToDestroy.push(zone.sortable);
383394
}
@@ -417,18 +428,6 @@ export class PowerDragDrop implements ComponentFramework.StandardControl<IInputs
417428
}
418429
}
419430

420-
private onFilter = (event: Sortable.SortableEvent) => {
421-
const actionItemId = event.item.getAttribute(RECORD_ID_ATTRIBUTE);
422-
const actionName = this.getActionFromClass(event.target);
423-
if (actionItemId && actionName) {
424-
this.raiseOnActionScheduled = true;
425-
// Remove the action specifier
426-
this.actionName = actionName.replace(CSS_STYLE_CLASSES.ActionClassPrefix, '');
427-
this.actionItemId = actionItemId;
428-
this.notifyOutputChanged();
429-
}
430-
};
431-
432431
private removeSpaces(input: string) {
433432
return input.replace(/\s/gi, '');
434433
}
@@ -493,4 +492,32 @@ export class PowerDragDrop implements ComponentFramework.StandardControl<IInputs
493492
}
494493
return false;
495494
};
495+
496+
actionClick = (ev: MouseEvent, zoneElement: HTMLElement): void => {
497+
// For accessibility, action elements raise the OnAction event here
498+
// rather than the onFilter event which only fires for touch events
499+
if (ev.target && (ev.target as HTMLElement).className) {
500+
const actionName = this.getActionFromClass(ev.target as HTMLElement);
501+
// Actions have a class prefixed with action-
502+
if (actionName) {
503+
// Find the closest sortable item using the item class identifier
504+
const element = Sortable.utils.closest(
505+
ev.target as HTMLElement,
506+
'.' + CSS_STYLE_CLASSES.Item,
507+
zoneElement,
508+
);
509+
if (element) {
510+
// Get the item id from the data attribute
511+
const actionItemId = element.getAttribute(RECORD_ID_ATTRIBUTE);
512+
if (actionItemId) {
513+
this.raiseOnActionScheduled = true;
514+
// Remove the action specifier and raise the event
515+
this.actionName = actionName.replace(CSS_STYLE_CLASSES.ActionClassPrefix, '');
516+
this.actionItemId = actionItemId;
517+
this.notifyOutputChanged();
518+
}
519+
}
520+
}
521+
}
522+
};
496523
}

0 commit comments

Comments
 (0)