Giter Club home page Giter Club logo

slip's Introduction

Slip

A tiny library for interactive swiping and reordering of elements in lists on touch screens. No dependencies. BSD Licensed.

Try live demo (best on a touchscreen device)

Supports iOS Safari, Firefox Mobile, Chrome Mobile, Opera Mobile (Presto and Blink).

Demo

Usage

You interact with the library via custom DOM events for swipes/reordering. Call new Slip(<element>) to make element's children swipeable and add event listeners for any of the following events:

  • slip:swipe

    When swipe has been done and user has lifted finger off the screen. If you execute event.preventDefault() the element will be animated back to original position. Otherwise it will be animated off the list and set to display:none.

  • slip:beforeswipe

    Fired before first swipe movement starts. If you execute event.preventDefault() then the element will not move at all. Parent element will have class slip-swiping-container for duration of the animation.

  • slip:cancelswipe

    Fired after the user has started to swipe, but lets go without actually swiping left or right.

  • slip:animateswipe

    Fired while swiping, before the user has let go of the element. event.detail.x contains the amount of movement in the x direction. If you execute event.preventDefault() then the element will not move to this position. This can be useful for saturating the amount of swipe, or preventing movement in one direction, but allowing it in the other.

  • slip:reorder

    Element has been dropped in new location. event.detail contains the following:

    • insertBefore: DOM node before which element has been dropped (null is the end of the list). Use with node.insertBefore().
    • spliceIndex: Index of element before which current element has been dropped, not counting the element iself. For use with Array.splice() if the list is reflecting objects in some array.
    • originalIndex: The original index of the element before it was reordered.

    You can use it to keep an array of items in sync with their display order:

    const movedItem = itemsArray[event.detail.originalIndex];
    itemsArray.splice(event.detail.originalIndex, 1); // Remove item from the previous position
    itemsArray.splice(event.detail.spliceIndex, 0, movedItem); // Insert item in the new position
    
    // And update the DOM:
    e.target.parentNode.insertBefore(e.target, e.detail.insertBefore);
  • slip:beforereorder

    When reordering movement starts. Element being reordered gets class slip-reordering. If you execute event.preventDefault() then the element will not move at all.

  • slip:beforewait

    If you execute event.preventDefault() then reordering will begin immediately, blocking ability to scroll the page. You can check event.target to limit that behavior to drag handles.

  • slip:tap

    When element was tapped without being swiped/reordered.

Example

var list = document.querySelector('ul#slippylist');
new Slip(list);

list.addEventListener('slip:beforeswipe', function(e) {
    if (shouldNotSwipe(e.target)) {
        e.preventDefault(); // won't move sideways if prevented
    }
});

list.addEventListener('slip:swipe', function(e) {
    // e.target list item swiped
    if (thatWasSwipeToRemove) {
        // list will collapse over that element
        e.target.parentNode.removeChild(e.target);
    } else {
        e.preventDefault(); // will animate back to original position
    }
});

list.addEventListener('slip:beforereorder', function(e) {
    if (shouldNotReorder(e.target)) {
        // if prevented element won't move vertically
        e.preventDefault();
    }
});

list.addEventListener('slip:beforewait', function(e) {
    if (isScrollingKnob(e.target)) {
        // if prevented element will be dragged (instead of page scrolling)
        e.preventDefault();
    }
});

list.addEventListener('slip:reorder', function(e) {
    // e.target list item reordered.
    if (reorderedOK) {
        e.target.parentNode.insertBefore(e.target, e.detail.insertBefore);
    } else {
        // element will fly back to original position
        e.preventDefault();
    }
});

See live example.

CSS

The library doesn't need any special CSS, but there are some tweaks that can make it nicer.

If you don't need text selection you can disable it to make dragging easier:

li {
    user-select: none;
}

You probably don't want horizontal scrollbar when elements are swiped off the list (slip-swiping-container class is set on container element only when necessary):

.slip-swiping-container {
    overflow-x: hidden;
}

Class slip-reordering is set on list element that is being dragged:

.slip-reordering {
    box-shadow: 0 2px 10px rgba(0,0,0,0.45);
}

When an item is dragged, z-index is set to 99999 on the element, so that it floats above the other elements in the list. In order to make this effective in some browsers, you'll need to set position: relative on the list items.

li {
    position: relative;
}

iOS also tends to add highlight color to tapped areas. If that bothers you, apply -webkit-tap-highlight-color: rgba(0,0,0,0); to tappable elements.

Configuration

You can also provide an options object when initialising Slip:

new Slip(element, {
    ignoredElements: '#imnothere' // Allows you to provide any valid CSS selector, elements matching it will be ignored by Slip.
        // Useful when you have invisible elements in your container but will cause bugs when used on visible items.
})

Accessibility and focus management

In the source code there's an accessibility object with settings for enabling ARIA roles on elements and focus when elements are used. Set focus: true in that array for potentially improved screen reader use.

Please note that Slip does not support keyboard interaction (pull requests are welcome), so you need to provide your own keyboard-accessible alternative.

TODO

  • ARIA roles and screen reader testing. Please note that drag'n'drop is very tricky to do with VoiceOver, and for accessibility you need a backup method.
  • Customizable delays and animations.
  • Using swipe to reveal UI beneath the element.

Old browsers

  • Closure Compiler by default doesn't support ES5. Add --language_in ECMASCRIPT5 or switch to UglifyJS2.
  • For very old WebKit add Function.bind polyfill.
  • PointerEvents are not supported, so only IE versions with TouchEvents (mobile 11+) are supported.

Moving between two lists

For sake of simplicity of implementation and interaction dragging works only within a single list. If you need complex drag'n'drop, consider another, more generic library.

If you only need sorting between two lists (positioned one under another), then you can cheat a little by adding a non-draggable item to the list and styling it to look like a gap between the two lists.

slip's People

Contributors

carter-thaxton avatar deqing avatar henrikhermansen avatar jayaddison avatar jenselme avatar joellord avatar jvhellemond avatar kkirsche avatar kornelski avatar lievenjanssen avatar mathiasbynens avatar myfrom avatar pandeiro avatar pasvaz avatar swalke16 avatar valyouw avatar vincentrohde avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

slip's Issues

Suggestion: stop propagation of events to prevent collision with other libraries

Currently all events are propagated through the DOM tree elements.

Using other libraries is complicated, because events collide with each other.
Good example is using https://github.com/mango/slideout together with current version of slip is impossible.

I've made changes to slip to stop propagation of touch/mouse events, so using slip with other libs is possible. Basically, what needs to be done is:

ev.stopPropagation();

Limit drag to scroll height

Is there a possibility in slip.js to limit drag to scroll height? That is, element drags within the scroll container.

No working on ie8 or ie9

I really like you solution, however addEventListener is no supported on ie 8 or ie9.
Any ideas on how to make your JS works on those browsers?

Slip doesn't work in IE9

Hey pornel,

Just did a drag and drop test in IE9 and it doesn't work.

You're not able to drag an item - and it shows no erros in the console. I think it either should work in IE9 or it should be feature-detectable, so a proper fallback can be used.

Also -ms-user-select: none; should be added to your demo for improved IE support :)

Bug: chrome android click is not prevented

Expected:
onTouchStart event set usingTouch to true, which should prevent extra click event in chrome for android.

Actual:
After touchend event usingTouch is set to false and click event is fired. As result callback is called twice (tap + click)

The problem is that idleStateInit is called for unknown reason and this.usingTouch is set there to false. So next onMouseUp event is fired, usingTouch is false and as result callback is called twice (once by touchstart and once by mouseup)

Following call stack in chrome for android confirms that:

idleStateInit (slip3.js:207)
window.Slip.Slip.setState (slip3.js:508)
window.Slip.Slip.states.undecided.onEnd (slip3.js:265)
window.Slip.Slip.onTouchEnd (slip3.js:694)

No-swipe (animation) isn't working

Hi, I'm working with this beautiful code, but now I was wondering that the no-swipe class isn't working.
I only want people to swipe it up and down, and don't swipe it away.

I really don't know how to fix this animation.

Thanks!

Bug: slip:tap fires on reorder on mobile Safari

On desktop browsers: If slip:reorder fires then slip:tap will not fire (correct)
On mobile safari: If slip:reorder fires then slip:tap will ALSO fire (incorrect)

I'll see if I can find more info about this, will add it here later.

New release for bower

Bower seems to use github releases, so last version of slip is referenced by commit #37916eab5acc2e663c5d9ce9cce5486709feab91. But there are new commits with many fixes and improvements after this commit.

Can you please release new version of slip. Let's say 1.3.0? Thanks.

List item 'bounces' as it moves into new position, when reordering list with latest slip.js

On 1/26/16, I downloaded the most recent version of slip.js. When reordering my list, the list item being moved did not go into its new position smoothly. Instead, there was a 'bounce' of about 50px. This behavior did not occur when using the demo at https://kornel.ski/slip/. I downloaded the slip.js code being used in the demo, used that version in my project, and the 'bouncing' behavior no longer occurred. I can use the older slip.js for my needs, but wanted to let you know about this issue.

First and last element is not work properly in iphone.

Hi,

First and last element is not dragging properly in iphone. When we dragging last element in bottom it take lots of blank space in bottom area.

Can we drag element within container just like jquery UI (containment: 'parent')

Thanks
Bali

Destroy Slip object

Hi!
I have a list that you can reorder if a button is pressed
When that happend I create the slip object and set the slip:beforereorder and the slip:reorder events in the container and so on
It works as expected

Now I need to deactivate this feature if the user clicks the button again

How can I do so? Is there a destroy mechanism or something

Thanks!

Cannot read property 'scrollContainer' of null

when use it on chrome Mac version with iPhone mode, the console prints out the following error:

Uncaught TypeError: Cannot read property 'scrollContainer' of null   slip.js:634
window.Slip.Slip.updatePosition                                                          slip.js:634
window.Slip.Slip.onTouchMove                                                           slip.js:672

Highlights elements in IE

In my testing, elements I drag past in IE9, IE10, and IE11 are all highlighted. Any idea why this would be?

Simulating IOS swipe to delete

I'd like to use Slide to emulate an IOS-style list with swipe left to reveal a red delete button. Before I do it myself, I was wondering if anyone knows of an implementation like that.

Support table rows

Hi kornel,

first of all, congratz to slip.js - works really nice.

I was wondering though if there's a way to make table rows (bootstrap 3 table-responsive in particular) drag & droppable, too?

Sorry if I'm wrong starting this as an "issue" since I guess it isn't one. But I don't know where to ask here else.

thx in advance,
elmcrest

But the way, so far I've found this http://jsfiddle.net/martyk/Kzf62/85/ which should work with touch punch on mobile, too.

Help on scroll near edge of screen

Not sure where else to put this, so here goes: Are you currently working on this? I had to do this for another project recently and might be able to help out if you need the extra hands.

Swipe issue in child elements when having an element inside

Child elements can be swiped (move sideways) again when another element is inside it even if you call the preventDefault() method in the custom DOM event.

<ul id="listId">
<li class="demo-no-swipe">
<h3>Some Heading</h3>
<p>Some text</p>
</li>
</ul>

Autoscrolling issue when html/body set to 100%

I am seeing issues with autoscrolling when the height of the html and body elements is set to 100% (so that the body fills the whole viewport). I have fixed this by modifying updatePosition() to include scrollable.scrollTop in the calculation of bottomOffset:

bottomOffset = Math.min(scrollable.scrollTop + containerRect.bottom, window.innerHeight) - targetRect.bottom,

This seems to fix the problem.

Does this look correct?

Slip.js for ReactJS

Do you have any plans to implement a version of this library for ReactJS?

add bower.json

Thanks for the awesome work ... please add bower.json to be easier for us to include the library ... thanks,

slip:tap fires twice

I think it's bug.

slip:tap fires two kinds of events

Slip.Slip.onTouchEnd
Slip.Slip.onMouseUp

it makes toggling (eg. toggleClass) unusable
as one cancels another

Device: Nexus 4
OS: Android 4.4
Browser: Chrome 33

Odd jump if I only move an item down one spot

Hi - this is a great library, so first off, thanks!

I'm using Slip to add reordering to meteoric, the meteor port of the ionic framework, but I have a small glitch. When I move an item down only one spot, it animates up at the last second, after I let go. You can see the issue here (click the upper right-hand corner to enable re-ordering).

The implementation is here.

I noticed your demo doesn't have this issue, so I understand this is probably an implementation issue, but if someone could give me a hint about where to start looking, I'd definitely appreciate it.

Keyboard and screen reader accessibility

I'd love to hear advice how to implement this properly.

VoiceOver on iOS

"select, tap-then-hold" gesture works, so it allows swiping and reordering, but it's hard to preform - both VoiceOver and Slip have their timer to detect hold, so to swipe you have to hold just the right amount of time :(

Any ideas how to improve that?

Keyboard accessibility

What are conventions for such UI? I'd like to avoid inventing something "weird". I'm thinking about:

  • grabbing focused element by pressing Enter
  • moving it up/down with arrow keys
  • dropping with Enter

Should I use other keys? Are there different approaches (like pressing a numeric key to select nth element?) Should I use clipboard analogy (cut, paste) and how to do that without breaking actual clipboard?

I suppose the list elements have to be focusable (the library would add tabindex). Is there a way to make it usable without focus? (Users who don't need keyboard accessibility may dislike the focus ring and some subtle changes in behavior that focusability brings).

Should the list have aria-live? If not, do I need to somehow announce that the order has been changed?

initial drag doesn't happen when focus is on an input element

First off, this is a cool library and works really well. One issue I'm finding is that when the focus is on an input element, the initial drag doesn't happen. Let me know if you need a fiddle for this, or if this description is sufficient enough.

Page height grows when dragging item beyond page bottom

When testing on desktop browsers (Chrome, FF) I found that trying to drag an item beyond the bottom of the page quickly makes the page height grow out of control (the page height will keep growing as long as you keep dragging the item beyond the page bottom). This can be seen in the live demo at http://pornel.net/slip

The following fix in updatePosition() avoids this problem:

        if (bottomOffset < triggerOffset){
            offset = triggerOffset - bottomOffset;

            // Don't apply offset if it would scroll beyond the end of the page
            var rootEl = document.documentElement,
                bodyEl = document.body,
                scrollTop = (rootEl && rootEl.scrollTop) || bodyEl.scrollTop,
                scrollHeight = (rootEl && rootEl.scrollHeight) || bodyEl.scrollHeight;

            if ((scrollTop + window.innerHeight + offset) >= scrollHeight) {
                offset = 0;
            }
        }
        else if (topOffset < triggerOffset){
            offset = topOffset - triggerOffset;
        }

Callout when long tap on Android and IE

I am using -webkit-touch-callout:none to avoid the default callout menu when doing a long tap on an item for reordering. This works as expected on iPhone and iPad. However it does not seem to work for Android, and I don't know of any equivalent for mobile IE (touch-action:none does not work either). Any hints?

I am testing with Android 4.4 and mobile IE 11.

Bug when scrolling on Mobile Safari IOS 8.1

Heya,

Found this small bug when implementing and it's also present in your example https://pornel.net/slip/ - so should be easy to reproduce. If you scroll the list on IOS it will output the error seen in the screenshot many times. You have to scroll the list buy touching the list itself (if you scroll by grabbing on the page footer for example, then the error won't appear). Also does NOT happen on desktop browsers (including Safari).

Totally love your lib!

The screenshots:

image

image

Problem with an Ember js object and Slip.js

Hi, very nice plugin btw.
I'm using it on an Ember JS application for Drag & Drop dynamic div elements that reflects an Ember js object.
I face the problem that when taking the first element on the list for putting it as the last element, then the element was duplicated. I found out that your function for "reorder":

list.addEventListener('slip:reorder', function(e) {
    // e.target list item reordered.
    if (reorderedOK) {
        e.target.parentNode.insertBefore(e.target, e.detail.insertBefore);
    } else {
        // element will fly back to original position
        e.preventDefault();
    }
});

when taking any element of the list to move it as last element, e.detail.insertBefore = null and it seems that insertBefore do not handle that situation properly, so I need it to implemented this way:

if (e.detail.insertBefore != null) {
     e.target.parentNode.insertBefore(e.target, e.detail.insertBefore);
} else {
     e.target.parentNode.insertBefore(e.target, e.target.nextSibling);
}

don't know if it's the best approach but I think you should take a look at what is happening when e.detail.insertBefore = null.
Best ;)

Slip does not work in Edge browser

Hey pornel,

Just did a drag and drop test in Microsoft Edge and it doesn't work.

You're not able to drag an item - and it shows no erros in the console.

Grey highlight on iOS

Sometimes you get a grey highlight on the container while reordering on iOS. Check out https://pornel.net/slip/ in portrait mode on an iPad to see the 'effect'. This can be prevented by adding '-webkit-tap-highlight-color: rgba(0,0,0,0);' to the container element ie. 'slippylist'.

Scrolling is unfriendly

Scrolling seems to work by looking at how close the cursor is to the viewable part of a scrollable parent on each mousemove event. The closer it is to the edge, the more it scrolls for that single fire of the event. It is intuitive that the scroll speed is based upon proximity to the edge, but it is not intuitive that scrolling happens only after each pixel-by-pixel move of the cursor.

That means that holding an element steady at the edge of a scrollable parent does not scroll at all, but dragging the element back into the center of the scrollable parent (which usually indicates that you have found what you were looking for and want to stop scrolling) will cause you to scroll away.

Is there a way to make the scrolling smooth, so it will continuously scroll at some constant speed depending upon where the element is held, instead of only scrolling as the mouse continues to move?

This is especially troublesome when you pick up an element near the edge, because just the act of picking it up and moving it toward the middle of the scrollable area will cause it to scroll.

Items fly away to outside the bottom

im using slip.js for the first time.
i tested on many devices and i found a creepy behavior.
if i grab an item from the list and pull it all the way down there comes a point where the items "flys" to the down and outside the bottom. this happens on moving it up or down.

Multiple drop targets

I'm working on a project that I think Slip would be perfect for, except I'm really looking for the ability to use multiple lists and to move items between them. Any suggestions on how to go about accomplishing that using Slip?

Sortable horizontaly

It is possible to make it work with a list of horizontal divs and sort them ?

Event for cancelled swipe

Hi,

it would be nice if there was an event like 'cancelswipe', to be fired when the user stops
dragging the list item and the item returns to it's original position.

Thanks for the awesome lib!

Click events not working on Android Chrome

I have Chrome v 35.0.191.141 on my Android phone.
I have elements inside the lists that listen to a click event. These events are not getting triggered on mobile browser. They are working on desktop Chrome however.
Is this a known issue?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.