1
0
mirror of https://github.com/morris/vanilla-todo.git synced 2025-08-21 13:21:29 +02:00

refactor save on blur

This commit is contained in:
Morris Brodersen
2020-10-22 12:55:25 +02:00
parent 7f1038bef3
commit d16e8d70b0
7 changed files with 106 additions and 112 deletions

View File

@@ -33,7 +33,6 @@
<script src="scripts/AppFlip.js"></script> <script src="scripts/AppFlip.js"></script>
<script src="scripts/AppFps.js"></script> <script src="scripts/AppFps.js"></script>
<script src="scripts/AppIcon.js"></script> <script src="scripts/AppIcon.js"></script>
<script src="scripts/AppLateBlur.js"></script>
<script src="scripts/AppSortable.js"></script> <script src="scripts/AppSortable.js"></script>
<script src="scripts/TodoApp.js"></script> <script src="scripts/TodoApp.js"></script>
<script src="scripts/TodoCustomList.js"></script> <script src="scripts/TodoCustomList.js"></script>

View File

@@ -17,14 +17,8 @@ VT.AppDraggable = function (el, options) {
var imageX, imageY; var imageX, imageY;
var currentTarget; var currentTarget;
if (window.navigator.pointerEnabled) { el.addEventListener('touchstart', start);
el.addEventListener('pointerdown', start); el.addEventListener('mousedown', start);
} else if (window.navigator.msPointerEnabled) {
el.addEventListener('MSPointerDown', start);
} else {
el.addEventListener('mousedown', start);
el.addEventListener('touchstart', start);
}
// maybe prevent click // maybe prevent click
el.addEventListener( el.addEventListener(
@@ -90,7 +84,6 @@ VT.AppDraggable = function (el, options) {
function end(e) { function end(e) {
e.preventDefault(); e.preventDefault();
e.stopImmediatePropagation();
if (!dragging) { if (!dragging) {
e.target.click(); e.target.click();
@@ -110,33 +103,17 @@ VT.AppDraggable = function (el, options) {
} }
function startListening() { function startListening() {
if (window.navigator.pointerEnabled) { el.addEventListener('touchmove', move);
el.addEventListener('pointermove', move); el.addEventListener('touchend', end);
el.addEventListener('pointerup', end); window.addEventListener('mousemove', move);
} else if (window.navigator.msPointerEnabled) { window.addEventListener('mouseup', end);
el.addEventListener('MSPointerMove', move);
el.addEventListener('MSPointerUp', end);
} else {
window.addEventListener('mousemove', move);
window.addEventListener('mouseup', end);
el.addEventListener('touchmove', move);
el.addEventListener('touchend', end);
}
} }
function stopListening() { function stopListening() {
if (window.navigator.pointerEnabled) { el.removeEventListener('touchmove', move);
el.removeEventListener('pointermove', move); el.removeEventListener('touchend', end);
el.removeEventListener('pointerup', end); window.removeEventListener('mousemove', move);
} else if (window.navigator.msPointerEnabled) { window.removeEventListener('mouseup', end);
el.removeEventListener('MSPointerMove', move);
el.removeEventListener('MSPointerUp', end);
} else {
window.removeEventListener('mousemove', move);
window.removeEventListener('mouseup', end);
el.removeEventListener('touchmove', move);
el.removeEventListener('touchend', end);
}
} }
// //

View File

@@ -1,39 +0,0 @@
/* global VT */
window.VT = window.VT || {};
/**
* Enables `lateBlur` events on the target element.
* After an actual `blur` event, subsequent interactions with the window
* (e.g. focus, select, mouseup etc.) will dispatch a `lateBlur` event.
*/
VT.AppLateBlur = function (el) {
el.addEventListener('blur', function () {
window.addEventListener('focus', dispatch);
window.addEventListener('select', dispatch);
if (window.navigator.pointerEnabled) {
window.addEventListener('pointerup', dispatch);
} else if (window.navigator.msPointerEnabled) {
window.addEventListener('MSPointerUp', dispatch);
} else {
window.addEventListener('mouseup', dispatch);
window.addEventListener('touchend', dispatch);
}
});
function dispatch() {
window.removeEventListener('focus', dispatch);
window.removeEventListener('select', dispatch);
if (window.navigator.pointerEnabled) {
window.removeEventListener('pointerup', dispatch);
} else if (window.navigator.msPointerEnabled) {
window.removeEventListener('MSPointerUp', dispatch);
} else {
window.removeEventListener('mouseup', dispatch);
window.removeEventListener('touchend', dispatch);
}
el.dispatchEvent(new CustomEvent('lateBlur', { bubbles: true }));
}
};

View File

@@ -6,7 +6,8 @@ VT.TodoCustomList = function (el) {
list: null, list: null,
editing: false, editing: false,
}; };
var focus = false; var startEditing = false;
var saveOnBlur = true;
el.innerHTML = [ el.innerHTML = [
'<div class="header">', '<div class="header">',
@@ -26,31 +27,35 @@ VT.TodoCustomList = function (el) {
VT.AppDraggable(titleEl, { VT.AppDraggable(titleEl, {
dropSelector: '.todo-frame.-custom .container', dropSelector: '.todo-frame.-custom .container',
}); });
VT.AppLateBlur(inputEl);
VT.TodoList(el.querySelector('.todo-list')); VT.TodoList(el.querySelector('.todo-list'));
el.querySelectorAll('.app-icon').forEach(VT.AppIcon); el.querySelectorAll('.app-icon').forEach(VT.AppIcon);
titleEl.addEventListener('click', function () { titleEl.addEventListener('click', function () {
focus = true; startEditing = true;
update({ editing: true }); update({ editing: true });
}); });
inputEl.addEventListener('input', function () { deleteEl.addEventListener('touchstart', function () {
el.dispatchEvent( saveOnBlur = false;
new CustomEvent('saveList', {
detail: { list: state.list, title: inputEl.value.trim() },
bubbles: true,
})
);
}); });
inputEl.addEventListener('lateBlur', function () { deleteEl.addEventListener('mousedown', function () {
update({ editing: false }); saveOnBlur = false;
}); });
inputEl.addEventListener('keypress', function (e) { inputEl.addEventListener('blur', function () {
if (e.keyCode === 13) { if (saveOnBlur) save();
update({ editing: false }); saveOnBlur = true;
});
inputEl.addEventListener('keyup', function (e) {
switch (e.keyCode) {
case 13: // enter
save();
break;
case 27: // escape
cancelEdit();
break;
} }
}); });
@@ -103,11 +108,26 @@ VT.TodoCustomList = function (el) {
update: update, update: update,
}; };
function save() {
el.dispatchEvent(
new CustomEvent('saveList', {
detail: { list: state.list, title: inputEl.value.trim() },
bubbles: true,
})
);
update({ editing: false });
}
function cancelEdit() {
saveOnBlur = false;
update({ editing: false });
}
function update(next) { function update(next) {
Object.assign(state, next); Object.assign(state, next);
titleEl.innerText = state.list.title || '...'; titleEl.innerText = state.list.title || '...';
inputEl.value = state.list.title;
el.querySelector('.todo-list').todoList.update({ items: state.list.items }); el.querySelector('.todo-list').todoList.update({ items: state.list.items });
el.querySelector('.todo-list > .todo-item-input').setAttribute( el.querySelector('.todo-list > .todo-item-input').setAttribute(
'data-key', 'data-key',
@@ -116,10 +136,11 @@ VT.TodoCustomList = function (el) {
el.classList.toggle('-editing', state.editing); el.classList.toggle('-editing', state.editing);
if (state.editing && focus) { if (state.editing && startEditing) {
inputEl.value = state.list.title;
inputEl.focus(); inputEl.focus();
inputEl.select(); inputEl.select();
focus = false; startEditing = false;
} }
} }
}; };

View File

@@ -6,7 +6,8 @@ VT.TodoItem = function (el) {
item: null, item: null,
editing: false, editing: false,
}; };
var focus = false; var startEditing = false;
var saveOnBlur = true;
el.innerHTML = [ el.innerHTML = [
'<div class="checkbox">', '<div class="checkbox">',
@@ -19,17 +20,28 @@ VT.TodoItem = function (el) {
'</p>', '</p>',
].join('\n'); ].join('\n');
var inputEl = el.querySelector('.input'); var checkboxEl = el.querySelector('.checkbox');
var labelEl = el.querySelector('.label'); var labelEl = el.querySelector('.label');
var inputEl = el.querySelector('.input');
var saveEl = el.querySelector('.save');
VT.AppDraggable(el, { VT.AppDraggable(el, {
dropSelector: '.todo-list > .items', dropSelector: '.todo-list > .items',
}); });
VT.AppLateBlur(inputEl);
el.querySelectorAll('.app-icon').forEach(VT.AppIcon); el.querySelectorAll('.app-icon').forEach(VT.AppIcon);
el.querySelector('.checkbox').addEventListener('click', function () { checkboxEl.addEventListener('touchstart', function () {
saveOnBlur = false;
});
checkboxEl.addEventListener('mousedown', function () {
saveOnBlur = false;
});
checkboxEl.addEventListener('click', function () {
if (state.editing) save();
el.dispatchEvent( el.dispatchEvent(
new CustomEvent('checkItem', { new CustomEvent('checkItem', {
detail: { detail: {
@@ -42,23 +54,32 @@ VT.TodoItem = function (el) {
}); });
labelEl.addEventListener('click', function () { labelEl.addEventListener('click', function () {
focus = true; startEditing = true;
update({ editing: true }); update({ editing: true });
}); });
el.querySelector('.save').addEventListener('click', function () { inputEl.addEventListener('keyup', function (e) {
save(); switch (e.keyCode) {
case 13: // enter
save();
break;
case 27: // escape
cancelEdit();
break;
}
}); });
inputEl.addEventListener('keypress', function (e) { inputEl.addEventListener('blur', function () {
if (e.keyCode === 13) save(); if (saveOnBlur) save();
saveOnBlur = true;
}); });
inputEl.addEventListener('lateBlur', function () { saveEl.addEventListener('mousedown', function () {
save(); saveOnBlur = false;
update({ editing: false });
}); });
saveEl.addEventListener('click', save);
el.addEventListener('draggableStart', function (e) { el.addEventListener('draggableStart', function (e) {
e.detail.data.item = state.item; e.detail.data.item = state.item;
e.detail.data.key = state.item.id; e.detail.data.key = state.item.id;
@@ -95,21 +116,27 @@ VT.TodoItem = function (el) {
update({ editing: false }); update({ editing: false });
} }
function cancelEdit() {
saveOnBlur = false;
update({ editing: false });
}
function update(next) { function update(next) {
// TODO optimize // TODO optimize
Object.assign(state, next); Object.assign(state, next);
el.classList.toggle('-done', state.item.done); el.classList.toggle('-done', state.item.done);
el.querySelector('.checkbox > input').checked = state.item.done; checkboxEl.querySelector('input').checked = state.item.done;
labelEl.innerText = state.item.label; labelEl.innerText = state.item.label;
inputEl.value = state.item.label;
el.classList.toggle('-editing', state.editing); el.classList.toggle('-editing', state.editing);
el.classList.toggle('_nodrag', state.editing); el.classList.toggle('_nodrag', state.editing);
if (state.editing && focus) { if (state.editing && startEditing) {
el.querySelector('.input').focus(); inputEl.value = state.item.label;
el.querySelector('.input').select(); inputEl.focus();
focus = false; inputEl.select();
startEditing = false;
} }
} }
}; };

View File

@@ -2,6 +2,8 @@
window.VT = window.VT || {}; window.VT = window.VT || {};
VT.TodoItemInput = function (el) { VT.TodoItemInput = function (el) {
var saveOnBlur = true;
el.innerHTML = [ el.innerHTML = [
'<input class="input" type="text">', '<input class="input" type="text">',
'<button class="app-button save"><i class="app-icon" data-id="plus-24"></i></button>', '<button class="app-button save"><i class="app-icon" data-id="plus-24"></i></button>',
@@ -10,10 +12,9 @@ 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);
inputEl.addEventListener('keypress', function (e) { inputEl.addEventListener('keyup', function (e) {
switch (e.keyCode) { switch (e.keyCode) {
case 13: // enter case 13: // enter
save(); save();
@@ -24,7 +25,14 @@ VT.TodoItemInput = function (el) {
} }
}); });
inputEl.addEventListener('lateBlur', save); inputEl.addEventListener('blur', function () {
if (saveOnBlur) save();
saveOnBlur = true;
});
saveEl.addEventListener('mousedown', function () {
saveOnBlur = false;
});
saveEl.addEventListener('click', function () { saveEl.addEventListener('click', function () {
save(); save();

View File

@@ -53,6 +53,7 @@
font-family: inherit; font-family: inherit;
font-size: inherit; font-size: inherit;
line-height: 1.5em; line-height: 1.5em;
background: transparent;
} }
.todo-item > .form > .save { .todo-item > .form > .save {