Skip to content

Instantly share code, notes, and snippets.

@cbaconnier
Created September 4, 2020 08:35
Show Gist options
  • Select an option

  • Save cbaconnier/86f9d18f7a457a1bde7a3ce6e83cfa5b to your computer and use it in GitHub Desktop.

Select an option

Save cbaconnier/86f9d18f7a457a1bde7a3ce6e83cfa5b to your computer and use it in GitHub Desktop.

Revisions

  1. cbaconnier created this gist Sep 4, 2020.
    98 changes: 98 additions & 0 deletions sortable.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,98 @@
    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();
    }
    })
    })