Skip to content

Instantly share code, notes, and snippets.

@cbaconnier
Created September 4, 2020 08:35
Show Gist options
  • Save cbaconnier/86f9d18f7a457a1bde7a3ce6e83cfa5b to your computer and use it in GitHub Desktop.
Save cbaconnier/86f9d18f7a457a1bde7a3ce6e83cfa5b to your computer and use it in GitHub Desktop.
import Sortable from '@shopify/draggable/lib/sortable'
if (typeof window.livewire === 'undefined') {
throw 'Livewire Sortable Plugin: window.livewire is undefined. Make sure @livewireScripts is placed above this script include'
}
window.livewire.directive('sortable-group', (el, directive, component) => {
if (directive.modifiers.includes('item-group')) {
// This will take care of new items added from Livewire during runtime.
el.closest('[wire\\:sortable-group]').livewire_sortable.addContainer(el)
}
// Only fire the rest of this handler on the "root" directive.
if (directive.modifiers.length > 0) return
let options = {draggable: '[wire\\:sortable-group\\.item]'}
if (el.querySelector('[wire\\:sortable-group\\.handle]')) {
options.handle = '[wire\\:sortable-group\\.handle]'
}
const sortable = el.livewire_sortable = new Sortable([], options);
sortable.on('sortable:stop', () => {
setTimeout(() => {
let groups = []
el.querySelectorAll('[wire\\:sortable-group\\.item-group]').forEach((el, index) => {
let items = []
el.querySelectorAll('[wire\\:sortable-group\\.item]').forEach((el, index) => {
items.push({order: index + 1, value: el.getAttribute('wire:sortable-group.item')})
})
groups.push({
order: index + 1,
value: el.getAttribute('wire:sortable-group.item-group'),
items: items,
})
})
component.call(directive.method, groups)
}, 1)
})
})
window.livewire.directive('sortable', (el, directive, component) => {
// element: HTMLElement<any>
// classesToPrevent: Array<string>
const isPrevented = (element, classesToPrevent) => {
let currentElem = element;
let isParent = false;
while (currentElem) {
const hasClass = Array.from(currentElem.classList).some((cls) => classesToPrevent.includes(cls));
if (hasClass) {
isParent = true;
currentElem = undefined;
} else {
currentElem = currentElem.parentElement;
}
}
return isParent;
}
// Only fire this handler on the "root" directive.
if (directive.modifiers.length > 0) return
let options = {draggable: '[wire\\:sortable\\.item]'}
if (el.querySelector('[wire\\:sortable\\.handle]')) {
options.handle = '[wire\\:sortable\\.handle]'
}
const sortable = new Sortable(el, options);
sortable.on('sortable:stop', () => {
setTimeout(() => {
let items = []
el.querySelectorAll('[wire\\:sortable\\.item]').forEach((el, index) => {
items.push({order: index + 1, value: el.getAttribute('wire:sortable.item')})
})
component.call(directive.method, items)
}, 1)
})
sortable.on('drag:start', (event) => {
const currentTarget = event.originalEvent.target;
if (isPrevented(currentTarget, ['prevent-drag'])) {
event.cancel();
}
})
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment