Skip to content

Commit c68d743

Browse files
committed
Add ‘reorderHoldInterval’ option for Long Press Reordering
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
1 parent 97bcbca commit c68d743

11 files changed

+102
-22
lines changed

dist/filepond.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*!
2-
* FilePond 4.30.4
2+
* FilePond 4.30.5
33
* Licensed under MIT, https://opensource.org/licenses/MIT/
44
* Please visit https://pqina.nl/filepond/ for details.
55
*/

dist/filepond.esm.js

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*!
2-
* FilePond 4.30.4
2+
* FilePond 4.30.5
33
* Licensed under MIT, https://opensource.org/licenses/MIT/
44
* Please visit https://pqina.nl/filepond/ for details.
55
*/
@@ -1831,6 +1831,7 @@ const defaultOptions = {
18311831
allowRemove: [true, Type.BOOLEAN], // Allow user to remove a file
18321832
allowProcess: [true, Type.BOOLEAN], // Allows user to process a file, when set to false, this removes the file upload button
18331833
allowReorder: [false, Type.BOOLEAN], // Allow reordering of files
1834+
reorderHoldInterval: [0, Type.INT], // The hold (long press) interval to wait before reordering the file
18341835
allowDirectoriesOnly: [false, Type.BOOLEAN], // Allow only selecting directories with browse (no support for filtering dnd at this point)
18351836

18361837
// Try store file if `server` not set
@@ -5966,6 +5967,24 @@ const createDragHelper = items => {
59665967
};
59675968
};
59685969

5970+
const onLongPress = (element, callback, interval) => {
5971+
let timer;
5972+
5973+
element.addEventListener('pointerdown', e => {
5974+
timer = setTimeout(() => {
5975+
timer = null;
5976+
callback(e);
5977+
}, interval);
5978+
});
5979+
5980+
function cancel() {
5981+
clearTimeout(timer);
5982+
}
5983+
5984+
element.addEventListener('pointerup', cancel);
5985+
element.addEventListener('pointermove', cancel);
5986+
};
5987+
59695988
const ITEM_TRANSLATE_SPRING = {
59705989
type: 'spring',
59715990
stiffness: 0.75,
@@ -6044,6 +6063,8 @@ const create$7 = ({ root, props }) => {
60446063

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

6066+
root.element.closest('.filepond--root').dataset.isReordering = '1';
6067+
60476068
root.dispatch('DID_GRAB_ITEM', { id: props.id, dragState });
60486069

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

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

6105+
delete root.element.closest('.filepond--root').dataset.isReordering;
6106+
60846107
// start listening to clicks again
60856108
if (removedActivateListener) {
60866109
setTimeout(() => root.element.addEventListener('click', root.ref.handleClick), 0);
@@ -6091,7 +6114,7 @@ const create$7 = ({ root, props }) => {
60916114
document.addEventListener('pointerup', drop);
60926115
};
60936116

6094-
root.element.addEventListener('pointerdown', grab);
6117+
onLongPress(root.element, grab, root.query('GET_REORDER_HOLD_INTERVAL'));
60956118
};
60966119

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

79627985
const MAX_FILES_LIMIT = 1000000;
79637986

7964-
const prevent = e => e.preventDefault();
7965-
79667987
const create$e = ({ root, props }) => {
79677988
// Add id
79687989
const id = root.query('GET_ID');
@@ -8033,6 +8054,12 @@ const create$e = ({ root, props }) => {
80338054
const canHover = window.matchMedia('(pointer: fine) and (hover: hover)').matches;
80348055
const hasPointerEvents = 'PointerEvent' in window;
80358056
if (root.query('GET_ALLOW_REORDER') && hasPointerEvents && !canHover) {
8057+
const prevent = e => {
8058+
if (root.element.dataset.isReordering) {
8059+
e.preventDefault();
8060+
}
8061+
};
8062+
80368063
root.element.addEventListener('touchmove', prevent, { passive: false });
80378064
root.element.addEventListener('gesturestart', prevent);
80388065
}

dist/filepond.esm.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/filepond.js

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

37623763
// Try store file if `server` not set
@@ -8506,6 +8507,24 @@
85068507
};
85078508
};
85088509

8510+
var onLongPress = function onLongPress(element, callback, interval) {
8511+
var timer;
8512+
8513+
element.addEventListener('pointerdown', function(e) {
8514+
timer = setTimeout(function() {
8515+
timer = null;
8516+
callback(e);
8517+
}, interval);
8518+
});
8519+
8520+
function cancel() {
8521+
clearTimeout(timer);
8522+
}
8523+
8524+
element.addEventListener('pointerup', cancel);
8525+
element.addEventListener('pointermove', cancel);
8526+
};
8527+
85098528
var ITEM_TRANSLATE_SPRING = {
85108529
type: 'spring',
85118530
stiffness: 0.75,
@@ -8591,6 +8610,8 @@
85918610

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

8613+
root.element.closest('.filepond--root').dataset.isReordering = '1';
8614+
85948615
root.dispatch('DID_GRAB_ITEM', { id: props.id, dragState: dragState });
85958616

85968617
var drag = function drag(e) {
@@ -8629,6 +8650,8 @@
86298650

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

8653+
delete root.element.closest('.filepond--root').dataset.isReordering;
8654+
86328655
// start listening to clicks again
86338656
if (removedActivateListener) {
86348657
setTimeout(function() {
@@ -8641,7 +8664,7 @@
86418664
document.addEventListener('pointerup', drop);
86428665
};
86438666

8644-
root.element.addEventListener('pointerdown', grab);
8667+
onLongPress(root.element, grab, root.query('GET_REORDER_HOLD_INTERVAL'));
86458668
};
86468669

86478670
var route$1 = createRoute({
@@ -10744,10 +10767,6 @@
1074410767

1074510768
var MAX_FILES_LIMIT = 1000000;
1074610769

10747-
var prevent = function prevent(e) {
10748-
return e.preventDefault();
10749-
};
10750-
1075110770
var create$e = function create(_ref) {
1075210771
var root = _ref.root,
1075310772
props = _ref.props;
@@ -10832,8 +10851,14 @@
1083210851
var canHover = window.matchMedia('(pointer: fine) and (hover: hover)').matches;
1083310852
var hasPointerEvents = 'PointerEvent' in window;
1083410853
if (root.query('GET_ALLOW_REORDER') && hasPointerEvents && !canHover) {
10835-
root.element.addEventListener('touchmove', prevent, { passive: false });
10836-
root.element.addEventListener('gesturestart', prevent);
10854+
var _prevent = function _prevent(e) {
10855+
if (root.element.dataset.isReordering) {
10856+
e.preventDefault();
10857+
}
10858+
};
10859+
10860+
root.element.addEventListener('touchmove', _prevent, { passive: false });
10861+
root.element.addEventListener('gesturestart', _prevent);
1083710862
}
1083810863

1083910864
// add credits

dist/filepond.min.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/filepond.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "filepond",
3-
"version": "4.30.4",
3+
"version": "4.30.5",
44
"description": "FilePond, Where files go to stretch their bits.",
55
"license": "MIT",
66
"author": {

src/js/app/options.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export const defaultOptions = {
6262
allowRemove: [true, Type.BOOLEAN], // Allow user to remove a file
6363
allowProcess: [true, Type.BOOLEAN], // Allows user to process a file, when set to false, this removes the file upload button
6464
allowReorder: [false, Type.BOOLEAN], // Allow reordering of files
65+
reorderHoldInterval: [0, Type.INT], // The hold (long press) interval to wait before reordering the file
6566
allowDirectoriesOnly: [false, Type.BOOLEAN], // Allow only selecting directories with browse (no support for filtering dnd at this point)
6667

6768
// Try store file if `server` not set

src/js/app/view/item.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { createView, createRoute } from '../frame/index';
22
import { fileWrapper } from './fileWrapper';
33
import { panel } from './panel';
44
import { createDragHelper } from '../utils/createDragHelper';
5+
import { onLongPress } from '../../utils/onLongPress'
56

67
const ITEM_TRANSLATE_SPRING = {
78
type: 'spring',
@@ -88,6 +89,8 @@ const create = ({ root, props }) => {
8889

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

92+
root.element.closest('.filepond--root').dataset.isReordering = '1';
93+
9194
root.dispatch('DID_GRAB_ITEM', { id: props.id, dragState });
9295

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

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

132+
delete root.element.closest('.filepond--root').dataset.isReordering;
133+
129134
// start listening to clicks again
130135
if (removedActivateListener) {
131136
setTimeout(() => root.element.addEventListener('click', root.ref.handleClick), 0);
@@ -134,9 +139,10 @@ const create = ({ root, props }) => {
134139

135140
document.addEventListener('pointermove', drag);
136141
document.addEventListener('pointerup', drop);
142+
137143
}
138144

139-
root.element.addEventListener('pointerdown', grab);
145+
onLongPress(root.element, grab, root.query('GET_REORDER_HOLD_INTERVAL'))
140146
};
141147

142148
const route = createRoute({

src/js/app/view/root.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ import getItemsPerRow from '../utils/getItemsPerRow';
2222

2323
const MAX_FILES_LIMIT = 1000000;
2424

25-
const prevent = e => e.preventDefault();
26-
2725
const create = ({ root, props }) => {
2826
// Add id
2927
const id = root.query('GET_ID');
@@ -94,6 +92,12 @@ const create = ({ root, props }) => {
9492
const canHover = window.matchMedia('(pointer: fine) and (hover: hover)').matches;
9593
const hasPointerEvents = 'PointerEvent' in window;
9694
if (root.query('GET_ALLOW_REORDER') && hasPointerEvents && !canHover) {
95+
const prevent = e => {
96+
if (root.element.dataset.isReordering) {
97+
e.preventDefault();
98+
}
99+
}
100+
97101
root.element.addEventListener('touchmove', prevent, { passive: false });
98102
root.element.addEventListener('gesturestart', prevent);
99103
}

src/js/utils/onLongPress.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export const onLongPress = (element, callback, interval) => {
2+
let timer;
3+
4+
element.addEventListener('pointerdown', (e) => {
5+
timer = setTimeout(() => {
6+
timer = null;
7+
callback(e);
8+
}, interval);
9+
});
10+
11+
function cancel() {
12+
clearTimeout(timer);
13+
}
14+
15+
element.addEventListener('pointerup', cancel);
16+
element.addEventListener('pointermove', cancel);
17+
};

0 commit comments

Comments
 (0)