Skip to content

Instantly share code, notes, and snippets.

@robby1066
Last active July 20, 2022 16:47
Show Gist options
  • Save robby1066/4ac279e415e682bc2ed6d266a049fc5d to your computer and use it in GitHub Desktop.
Save robby1066/4ac279e415e682bc2ed6d266a049fc5d to your computer and use it in GitHub Desktop.
Javascript for up and down keyboard-accessible controls on a sortable list with sortable.js
// Move the element either up or down in the list
// this piggybacks on Sortablejs's `sort` function
// This code needs to have access to the Sortablejs object that controls the list.
// A couple of things you'll need to customize
// LIST_CONTAINER is the DOM element that shoud contain the list
// LIST_ITEM_SELECTOR is the
// (e.g. The UL where the LI elements should be sortable)
// You will probably want to customize these, or use a different way to select your list and list items
const listContainerSelector = 'UL#my-sortable-list'
const listItemSelector = 'LI.sortable-list-item'
// If your code already has access to the sortablejs object,
// comment this part out and update any references to `sortable_list` below
// to reference your sortablejs object
var sortable_list = Sortable.create(document.querySelector(listContainerSelector), {
dataIdAttr: 'data-sortable-id', // required to calculate the custom sort
// Any other sortablejs configuration...
handle: '.drag-handle',
animation: 250
})
moveElement(element, direction) {
// bail out if we get input that we don't expect
if (["up", "down"].includes(direction) == false ) {
return false
}
if (typeof(element.dataset.sortableId) == 'undefined') {
return false
}
// `sortableId` is whatever you've set in your sortablejs config for `dataIdAttr`
let sortableId = element.dataset.sortableId
let order = sortable_list.toArray()
let index = order.indexOf(sortableId)
// pull the item we're moving out of the order
order.splice(index, 1)
// put it back in at the correct position
if (direction == 'down') {
order.splice(index+1, 0, sortableId)
} else if (direction == 'up') {
order.splice(index-1, 0, sortableId)
}
sortable_list.sort(order, true)
}
// Attached to the up control's `onKeyDown` event
moveElementUp(event) {
// only proceed if `ENTER` was pressed - keyCode 13
if (event.keyCode == 13) {
event.stopPropagation()
event.preventDefault()
// get the list item that contains the control that was activated
// (in this case, it matches the selector `DIV.topic-list-item`)
this.moveElement(event.currentTarget.closest(listItemSelector), 'up')
// Check the visibility of the control.
// If it's new place in the list caused 'up' or 'down' to be hidden, switch to the other one
if (window.getComputedStyle(event.currentTarget).display == 'none') {
event.currentTarget.parentNode.querySelector('A[data-direction=down]').focus()
} else {
event.currentTarget.focus()
}
}
}
// Attached to the down control's `onKeyDown` event
moveElementDown(event) {
if (event.keyCode == 13) {
event.stopPropagation()
event.preventDefault()
this.moveElement(event.currentTarget.closest(listItemSelector), 'down')
if (window.getComputedStyle(event.currentTarget).display == 'none') {
event.currentTarget.parentNode.querySelector('A[data-direction=up]').focus()
} else {
event.currentTarget.focus()
}
}
}
@elfeffe
Copy link

elfeffe commented Jul 9, 2021

@robby1066 Where do you put this code?
Do you modify Sortable's code or you add it as a plugin?

@robby1066
Copy link
Author

robby1066 commented Jul 9, 2021

This lives outside sortable, in a place that has access to the sortablejs object.

Upon re-reading it, I see a bug that will keep this code from just working in a general setting. (sorry, I pulled it from a Stimulusjs controller I was using it in)

this.sortable.sort(order, true) in line 28 needs to refer to the sortable object you defined for the list with Sortable.create(...

I'll refactor and update.

Aside from that, this code should be generally usable anywhere you have access to the sortable object.

@robby1066
Copy link
Author

Updated to something that should work more generically now. There's a section at the top to define the sortablejs list and set selectors for the list and the list items. Should be usable as-is, but depending on your existing code you may want to modify it to point to your existing sortablejs obj.

@elfeffe
Copy link

elfeffe commented Jul 10, 2021

Thank you

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