Skip to content

Commit

Permalink
Add ‘reorderHoldInterval’ option for Long Press Reordering
Browse files Browse the repository at this point in the history
The `reorderHoldInterval` option allows people to opt-into “long press” / “press and hold” on a file to reorder. This feature is disabled by default, and there are no backwards compatibility issues.

Currently, on small touch-screen devices the native scroll experience can be hijacked by the reorder feature. Enabling “long press” to reorder dramatically improves the UX for these users.

**Usage***
```js
FilePond.create(inputElement, {
    allowMultiple: true,
    allowReorder: true,
    reorderHoldInterval: 100,
});
```

Resolves pqina#865
  • Loading branch information
jakejackson1 committed Oct 16, 2023
1 parent 97bcbca commit c68d743
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 22 deletions.
2 changes: 1 addition & 1 deletion dist/filepond.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* FilePond 4.30.4
* FilePond 4.30.5
* Licensed under MIT, https://opensource.org/licenses/MIT/
* Please visit https://pqina.nl/filepond/ for details.
*/
Expand Down
35 changes: 31 additions & 4 deletions dist/filepond.esm.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* FilePond 4.30.4
* FilePond 4.30.5
* Licensed under MIT, https://opensource.org/licenses/MIT/
* Please visit https://pqina.nl/filepond/ for details.
*/
Expand Down Expand Up @@ -1831,6 +1831,7 @@ const defaultOptions = {
allowRemove: [true, Type.BOOLEAN], // Allow user to remove a file
allowProcess: [true, Type.BOOLEAN], // Allows user to process a file, when set to false, this removes the file upload button
allowReorder: [false, Type.BOOLEAN], // Allow reordering of files
reorderHoldInterval: [0, Type.INT], // The hold (long press) interval to wait before reordering the file
allowDirectoriesOnly: [false, Type.BOOLEAN], // Allow only selecting directories with browse (no support for filtering dnd at this point)

// Try store file if `server` not set
Expand Down Expand Up @@ -5966,6 +5967,24 @@ const createDragHelper = items => {
};
};

const onLongPress = (element, callback, interval) => {
let timer;

element.addEventListener('pointerdown', e => {
timer = setTimeout(() => {
timer = null;
callback(e);
}, interval);
});

function cancel() {
clearTimeout(timer);
}

element.addEventListener('pointerup', cancel);
element.addEventListener('pointermove', cancel);
};

const ITEM_TRANSLATE_SPRING = {
type: 'spring',
stiffness: 0.75,
Expand Down Expand Up @@ -6044,6 +6063,8 @@ const create$7 = ({ root, props }) => {

const dragState = createDragHelper(root.query('GET_ACTIVE_ITEMS'));

root.element.closest('.filepond--root').dataset.isReordering = '1';

root.dispatch('DID_GRAB_ITEM', { id: props.id, dragState });

const drag = e => {
Expand Down Expand Up @@ -6081,6 +6102,8 @@ const create$7 = ({ root, props }) => {

root.dispatch('DID_DROP_ITEM', { id: props.id, dragState });

delete root.element.closest('.filepond--root').dataset.isReordering;

// start listening to clicks again
if (removedActivateListener) {
setTimeout(() => root.element.addEventListener('click', root.ref.handleClick), 0);
Expand All @@ -6091,7 +6114,7 @@ const create$7 = ({ root, props }) => {
document.addEventListener('pointerup', drop);
};

root.element.addEventListener('pointerdown', grab);
onLongPress(root.element, grab, root.query('GET_REORDER_HOLD_INTERVAL'));
};

const route$1 = createRoute({
Expand Down Expand Up @@ -7961,8 +7984,6 @@ const debounce = (func, interval = 16, immidiateOnly = true) => {

const MAX_FILES_LIMIT = 1000000;

const prevent = e => e.preventDefault();

const create$e = ({ root, props }) => {
// Add id
const id = root.query('GET_ID');
Expand Down Expand Up @@ -8033,6 +8054,12 @@ const create$e = ({ root, props }) => {
const canHover = window.matchMedia('(pointer: fine) and (hover: hover)').matches;
const hasPointerEvents = 'PointerEvent' in window;
if (root.query('GET_ALLOW_REORDER') && hasPointerEvents && !canHover) {
const prevent = e => {
if (root.element.dataset.isReordering) {
e.preventDefault();
}
};

root.element.addEventListener('touchmove', prevent, { passive: false });
root.element.addEventListener('gesturestart', prevent);
}
Expand Down
4 changes: 2 additions & 2 deletions dist/filepond.esm.min.js

Large diffs are not rendered by default.

41 changes: 33 additions & 8 deletions dist/filepond.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* FilePond 4.30.4
* FilePond 4.30.5
* Licensed under MIT, https://opensource.org/licenses/MIT/
* Please visit https://pqina.nl/filepond/ for details.
*/
Expand Down Expand Up @@ -3757,6 +3757,7 @@
allowRemove: [true, Type.BOOLEAN], // Allow user to remove a file
allowProcess: [true, Type.BOOLEAN], // Allows user to process a file, when set to false, this removes the file upload button
allowReorder: [false, Type.BOOLEAN], // Allow reordering of files
reorderHoldInterval: [0, Type.INT], // The hold (long press) interval to wait before reordering the file
allowDirectoriesOnly: [false, Type.BOOLEAN], // Allow only selecting directories with browse (no support for filtering dnd at this point)

// Try store file if `server` not set
Expand Down Expand Up @@ -8506,6 +8507,24 @@
};
};

var onLongPress = function onLongPress(element, callback, interval) {
var timer;

element.addEventListener('pointerdown', function(e) {
timer = setTimeout(function() {
timer = null;
callback(e);
}, interval);
});

function cancel() {
clearTimeout(timer);
}

element.addEventListener('pointerup', cancel);
element.addEventListener('pointermove', cancel);
};

var ITEM_TRANSLATE_SPRING = {
type: 'spring',
stiffness: 0.75,
Expand Down Expand Up @@ -8591,6 +8610,8 @@

var dragState = createDragHelper(root.query('GET_ACTIVE_ITEMS'));

root.element.closest('.filepond--root').dataset.isReordering = '1';

root.dispatch('DID_GRAB_ITEM', { id: props.id, dragState: dragState });

var drag = function drag(e) {
Expand Down Expand Up @@ -8629,6 +8650,8 @@

root.dispatch('DID_DROP_ITEM', { id: props.id, dragState: dragState });

delete root.element.closest('.filepond--root').dataset.isReordering;

// start listening to clicks again
if (removedActivateListener) {
setTimeout(function() {
Expand All @@ -8641,7 +8664,7 @@
document.addEventListener('pointerup', drop);
};

root.element.addEventListener('pointerdown', grab);
onLongPress(root.element, grab, root.query('GET_REORDER_HOLD_INTERVAL'));
};

var route$1 = createRoute({
Expand Down Expand Up @@ -10744,10 +10767,6 @@

var MAX_FILES_LIMIT = 1000000;

var prevent = function prevent(e) {
return e.preventDefault();
};

var create$e = function create(_ref) {
var root = _ref.root,
props = _ref.props;
Expand Down Expand Up @@ -10832,8 +10851,14 @@
var canHover = window.matchMedia('(pointer: fine) and (hover: hover)').matches;
var hasPointerEvents = 'PointerEvent' in window;
if (root.query('GET_ALLOW_REORDER') && hasPointerEvents && !canHover) {
root.element.addEventListener('touchmove', prevent, { passive: false });
root.element.addEventListener('gesturestart', prevent);
var _prevent = function _prevent(e) {
if (root.element.dataset.isReordering) {
e.preventDefault();
}
};

root.element.addEventListener('touchmove', _prevent, { passive: false });
root.element.addEventListener('gesturestart', _prevent);
}

// add credits
Expand Down
2 changes: 1 addition & 1 deletion dist/filepond.min.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions dist/filepond.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "filepond",
"version": "4.30.4",
"version": "4.30.5",
"description": "FilePond, Where files go to stretch their bits.",
"license": "MIT",
"author": {
Expand Down
1 change: 1 addition & 0 deletions src/js/app/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export const defaultOptions = {
allowRemove: [true, Type.BOOLEAN], // Allow user to remove a file
allowProcess: [true, Type.BOOLEAN], // Allows user to process a file, when set to false, this removes the file upload button
allowReorder: [false, Type.BOOLEAN], // Allow reordering of files
reorderHoldInterval: [0, Type.INT], // The hold (long press) interval to wait before reordering the file
allowDirectoriesOnly: [false, Type.BOOLEAN], // Allow only selecting directories with browse (no support for filtering dnd at this point)

// Try store file if `server` not set
Expand Down
8 changes: 7 additions & 1 deletion src/js/app/view/item.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createView, createRoute } from '../frame/index';
import { fileWrapper } from './fileWrapper';
import { panel } from './panel';
import { createDragHelper } from '../utils/createDragHelper';
import { onLongPress } from '../../utils/onLongPress'

const ITEM_TRANSLATE_SPRING = {
type: 'spring',
Expand Down Expand Up @@ -88,6 +89,8 @@ const create = ({ root, props }) => {

const dragState = createDragHelper(root.query('GET_ACTIVE_ITEMS'));

root.element.closest('.filepond--root').dataset.isReordering = '1';

root.dispatch('DID_GRAB_ITEM', { id: props.id, dragState });

const drag = e => {
Expand Down Expand Up @@ -126,6 +129,8 @@ const create = ({ root, props }) => {

root.dispatch('DID_DROP_ITEM', { id: props.id, dragState });

delete root.element.closest('.filepond--root').dataset.isReordering;

// start listening to clicks again
if (removedActivateListener) {
setTimeout(() => root.element.addEventListener('click', root.ref.handleClick), 0);
Expand All @@ -134,9 +139,10 @@ const create = ({ root, props }) => {

document.addEventListener('pointermove', drag);
document.addEventListener('pointerup', drop);

}

root.element.addEventListener('pointerdown', grab);
onLongPress(root.element, grab, root.query('GET_REORDER_HOLD_INTERVAL'))
};

const route = createRoute({
Expand Down
8 changes: 6 additions & 2 deletions src/js/app/view/root.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ import getItemsPerRow from '../utils/getItemsPerRow';

const MAX_FILES_LIMIT = 1000000;

const prevent = e => e.preventDefault();

const create = ({ root, props }) => {
// Add id
const id = root.query('GET_ID');
Expand Down Expand Up @@ -94,6 +92,12 @@ const create = ({ root, props }) => {
const canHover = window.matchMedia('(pointer: fine) and (hover: hover)').matches;
const hasPointerEvents = 'PointerEvent' in window;
if (root.query('GET_ALLOW_REORDER') && hasPointerEvents && !canHover) {
const prevent = e => {
if (root.element.dataset.isReordering) {
e.preventDefault();
}
}

root.element.addEventListener('touchmove', prevent, { passive: false });
root.element.addEventListener('gesturestart', prevent);
}
Expand Down
17 changes: 17 additions & 0 deletions src/js/utils/onLongPress.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const onLongPress = (element, callback, interval) => {
let timer;

element.addEventListener('pointerdown', (e) => {
timer = setTimeout(() => {
timer = null;
callback(e);
}, interval);
});

function cancel() {
clearTimeout(timer);
}

element.addEventListener('pointerup', cancel);
element.addEventListener('pointermove', cancel);
};

0 comments on commit c68d743

Please sign in to comment.