1
0
mirror of https://github.com/morris/vanilla-todo.git synced 2025-08-11 08:33:58 +02:00

mobile improvements

This commit is contained in:
Morris Brodersen
2020-10-21 20:18:12 +02:00
parent 0174686516
commit 7f1038bef3
5 changed files with 122 additions and 81 deletions

View File

@@ -738,3 +738,7 @@ Projects I've inspected for drag & drop architecture:
- [React DnD](https://react-dnd.github.io) - [React DnD](https://react-dnd.github.io)
- [react-beautiful-dnd](https://github.com/atlassian/react-beautiful-dnd) - [react-beautiful-dnd](https://github.com/atlassian/react-beautiful-dnd)
- [dragula](https://github.com/bevacqua/dragula) - [dragula](https://github.com/bevacqua/dragula)
Other interesting articles:
- [The case for vanilla front-end development (pushdata.io)](https://pushdata.io/blog/1)

View File

@@ -8,6 +8,7 @@ VT.AppDraggable = function (el, options) {
var originX, originY; var originX, originY;
var clientX, clientY; var clientX, clientY;
var startTime;
var dragging = false; var dragging = false;
var clicked = false; var clicked = false;
var data; var data;
@@ -40,13 +41,75 @@ VT.AppDraggable = function (el, options) {
function start(e) { function start(e) {
if (el.classList.contains('_nodrag')) return; if (el.classList.contains('_nodrag')) return;
if (e.type === 'mousedown' && e.button !== 0) return; if (e.type === 'mousedown' && e.button !== 0) return;
if (e.touches && e.touches.length > 1) return;
e.preventDefault(); e.preventDefault();
var p = getPositionHost(e); var p = getPositionHost(e);
clientX = originX = p.clientX || p.pageX; clientX = originX = p.clientX || p.pageX;
clientY = originY = p.clientY || p.pageY; clientY = originY = p.clientY || p.pageY;
startTime = Date.now();
startListening();
}
function move(e) {
e.preventDefault();
var p = getPositionHost(e);
clientX = p.clientX || p.pageX;
clientY = p.clientY || p.pageY;
if (dragging) {
dispatchDrag();
dispatchTarget();
return;
}
var deltaX = clientX - originX;
var deltaY = clientY - originY;
if (Math.abs(deltaX) < dragThreshold && Math.abs(deltaY) < dragThreshold) {
return;
}
// prevent unintentional dragging on touch devices
if (e.touches && Date.now() - startTime < 50) {
stopListening();
return;
}
dragging = true;
data = {};
dispatchStart();
dispatchDrag();
dispatchTarget();
dispatchOverContinuously();
}
function end(e) {
e.preventDefault();
e.stopImmediatePropagation();
if (!dragging) {
e.target.click();
clicked = true;
}
stopListening();
requestAnimationFrame(function () {
clicked = false;
if (dragging) {
dispatchTarget();
dispatchEnd();
}
});
}
function startListening() {
if (window.navigator.pointerEnabled) { if (window.navigator.pointerEnabled) {
el.addEventListener('pointermove', move); el.addEventListener('pointermove', move);
el.addEventListener('pointerup', end); el.addEventListener('pointerup', end);
@@ -61,40 +124,7 @@ VT.AppDraggable = function (el, options) {
} }
} }
function move(e) { function stopListening() {
e.preventDefault();
var p = getPositionHost(e);
clientX = p.clientX || p.pageX;
clientY = p.clientY || p.pageY;
if (dragging) return;
var deltaX = clientX - originX;
var deltaY = clientY - originY;
if (Math.abs(deltaX) < dragThreshold && Math.abs(deltaY) < dragThreshold) {
return;
}
dispatchStart();
dispatchLoop();
dispatchOver();
}
function end(e) {
e.preventDefault();
e.stopImmediatePropagation();
if (!dragging) {
e.target.click();
clicked = true;
}
requestAnimationFrame(function () {
dragging = false;
clicked = false;
if (window.navigator.pointerEnabled) { if (window.navigator.pointerEnabled) {
el.removeEventListener('pointermove', move); el.removeEventListener('pointermove', move);
el.removeEventListener('pointerup', end); el.removeEventListener('pointerup', end);
@@ -107,15 +137,11 @@ VT.AppDraggable = function (el, options) {
el.removeEventListener('touchmove', move); el.removeEventListener('touchmove', move);
el.removeEventListener('touchend', end); el.removeEventListener('touchend', end);
} }
});
} }
// //
function dispatchStart() { function dispatchStart() {
dragging = true;
data = {};
setImage(el); setImage(el);
el.dispatchEvent( el.dispatchEvent(
@@ -126,17 +152,6 @@ VT.AppDraggable = function (el, options) {
); );
} }
function dispatchLoop() {
dispatchDrag();
dispatchTarget();
if (dragging) {
requestAnimationFrame(dispatchLoop);
} else {
dispatchEnd();
}
}
function dispatchDrag() { function dispatchDrag() {
image.dispatchEvent( image.dispatchEvent(
new CustomEvent('draggableDrag', { new CustomEvent('draggableDrag', {
@@ -147,6 +162,8 @@ VT.AppDraggable = function (el, options) {
} }
function dispatchTarget() { function dispatchTarget() {
if (!dragging) return;
var nextTarget = getTarget(); var nextTarget = getTarget();
if (nextTarget === currentTarget) return; if (nextTarget === currentTarget) return;
@@ -174,6 +191,26 @@ VT.AppDraggable = function (el, options) {
currentTarget = nextTarget; currentTarget = nextTarget;
} }
function dispatchOverContinuously() {
if (!dragging) return;
dispatchOver();
setTimeout(dispatchOver, 50);
}
function dispatchOver() {
if (currentTarget) {
currentTarget.dispatchEvent(
new CustomEvent('draggableOver', {
detail: buildDetail(),
bubbles: true,
})
);
}
setTimeout(dispatchOver, 50);
}
function dispatchEnd() { function dispatchEnd() {
if (currentTarget) { if (currentTarget) {
currentTarget.addEventListener('draggableDrop', cleanUpOnce); currentTarget.addEventListener('draggableDrop', cleanUpOnce);
@@ -193,21 +230,6 @@ VT.AppDraggable = function (el, options) {
} }
} }
function dispatchOver() {
if (!dragging) return;
if (currentTarget) {
currentTarget.dispatchEvent(
new CustomEvent('draggableOver', {
detail: buildDetail(),
bubbles: true,
})
);
}
setTimeout(dispatchOver, 50);
}
// //
function buildDetail() { function buildDetail() {

View File

@@ -10,12 +10,10 @@ VT.TodoItemInput = function (el) {
var inputEl = el.querySelector('.input'); var inputEl = el.querySelector('.input');
var saveEl = el.querySelector('.save'); var saveEl = el.querySelector('.save');
VT.AppLateBlur(inputEl);
el.querySelectorAll('.app-icon').forEach(VT.AppIcon); el.querySelectorAll('.app-icon').forEach(VT.AppIcon);
saveEl.addEventListener('click', save); inputEl.addEventListener('keypress', function (e) {
inputEl.addEventListener('keypress', handleKeypress);
function handleKeypress(e) {
switch (e.keyCode) { switch (e.keyCode) {
case 13: // enter case 13: // enter
save(); save();
@@ -24,7 +22,14 @@ VT.TodoItemInput = function (el) {
clear(); clear();
break; break;
} }
} });
inputEl.addEventListener('lateBlur', save);
saveEl.addEventListener('click', function () {
save();
inputEl.focus();
});
function save() { function save() {
var label = inputEl.value.trim(); var label = inputEl.value.trim();
@@ -39,7 +44,6 @@ VT.TodoItemInput = function (el) {
); );
inputEl.value = ''; inputEl.value = '';
inputEl.focus();
} }
function clear() { function clear() {

View File

@@ -1,6 +1,11 @@
.todo-frame { .todo-frame {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none; user-select: none;
} }

View File

@@ -7,6 +7,12 @@
background: #fff; background: #fff;
transition: transform 0.2s ease-out, opacity 0.2s ease-out; transition: transform 0.2s ease-out, opacity 0.2s ease-out;
cursor: pointer; cursor: pointer;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
} }
.todo-item > .checkbox { .todo-item > .checkbox {