Make services reorderable (drag and drop)

This commit is contained in:
Alice Gaudon 2020-01-21 13:03:32 +01:00
parent d723dc2511
commit c05b2eca8d
4 changed files with 160 additions and 2 deletions

View File

@ -21,6 +21,7 @@
</div> </div>
<ul id="service-selector"></ul> <ul id="service-selector"></ul>
<div id="service-last-drag-position" class="hidden"></div>
<button id="add-button"><i class="fa fa-plus"></i></button> <button id="add-button"><i class="fa fa-plus"></i></button>

View File

@ -96,6 +96,19 @@ ipcRenderer.on('data', (event, appData, brandIcons, solidIcons, actualServices,
createService(i); createService(i);
} }
// Init drag last position
const lastDragPosition = document.getElementById('service-last-drag-position');
lastDragPosition.addEventListener('dragover', () => {
const index = services.length;
if (draggedId !== index && draggedId !== index - 1) {
resetDrag();
lastDragTarget = dragTargetId = index;
lastDragPosition.classList.remove('hidden');
lastDragPosition.classList.add('drag-target');
}
});
// Set active service
if (actualSelectedService < 0 || actualSelectedService >= services.length) { if (actualSelectedService < 0 || actualSelectedService >= services.length) {
actualSelectedService = 0; actualSelectedService = 0;
} }
@ -129,6 +142,31 @@ ipcRenderer.on('updateService', (e, id, data) => {
} }
}); });
ipcRenderer.on('reorderService', (e, serviceId, targetId) => {
const oldServices = services;
services = [];
for (let i = 0; i < targetId; i++) {
if (i !== serviceId) {
services.push(oldServices[i]);
}
}
services.push(oldServices[serviceId]);
const newId = services.length - 1;
for (let i = targetId; i < oldServices.length; i++) {
if (i !== serviceId) {
services.push(oldServices[i]);
}
}
document.getElementById('service-selector').innerHTML = '';
for (let i = 0; i < services.length; i++) {
services[i].li = undefined;
createService(i);
}
setActiveService(newId);
});
ipcRenderer.on('deleteService', (e, id) => { ipcRenderer.on('deleteService', (e, id) => {
const nav = document.querySelector('#service-selector'); const nav = document.querySelector('#service-selector');
@ -199,6 +237,55 @@ function createService(index, nextNavButton) {
if (service.autoLoad) { if (service.autoLoad) {
loadService(index, service); loadService(index, service);
} }
initDrag(index, li);
}
let draggedId;
let lastDragTarget = -1;
let dragTargetId = -1;
let dragTargetCount = 0;
function initDrag(index, li) {
li.serviceId = index;
li.draggable = true;
li.addEventListener('dragstart', (event) => {
draggedId = index;
event.dataTransfer.dropEffect = 'move';
document.getElementById('service-last-drag-position').classList.remove('hidden');
});
li.addEventListener('dragover', () => {
if (draggedId !== index && draggedId !== index - 1) {
resetDrag();
lastDragTarget = dragTargetId = index;
document.getElementById('service-last-drag-position').classList.remove('hidden');
li.classList.add('drag-target');
}
});
li.addEventListener('dragend', () => {
reorderService(draggedId, lastDragTarget);
resetDrag();
});
}
function resetDrag() {
lastDragTarget = -1;
dragTargetId = -1;
dragTargetCount = 0;
document.getElementById('service-selector').querySelectorAll('li').forEach(li => {
li.classList.remove('drag-target');
});
const lastDragPosition = document.getElementById('service-last-drag-position');
lastDragPosition.classList.remove('drag-target');
lastDragPosition.classList.add('hidden');
}
function reorderService(serviceId, targetId) {
console.log('Reordering service', serviceId, targetId);
if (targetId >= 0) {
setActiveService(null);
ipcRenderer.send('reorderService', serviceId, targetId);
}
} }
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
@ -215,7 +302,9 @@ document.addEventListener('DOMContentLoaded', () => {
function setActiveService(serviceId) { function setActiveService(serviceId) {
const currentService = services[serviceId]; const currentService = services[serviceId];
process.nextTick(() => { process.nextTick(() => {
if (currentService) {
loadService(serviceId, currentService); loadService(serviceId, currentService);
}
// Hide previous service // Hide previous service
if (services[selectedService] && services[selectedService].view) { if (services[selectedService] && services[selectedService].view) {
@ -223,7 +312,9 @@ function setActiveService(serviceId) {
} }
// Show service // Show service
if (currentService) {
currentService.view.classList.add('active'); currentService.view.classList.add('active');
}
// Save active service ID // Save active service ID
selectedService = serviceId; selectedService = serviceId;

View File

@ -10,6 +10,51 @@ body {
padding: 0; padding: 0;
} }
#service-selector [draggable] {
user-select: none;
background-color: rgb(43, 43, 43);
}
#service-selector [draggable] img {
-webkit-user-drag: none;
user-drag: none;
}
#service-selector .drag-target button {
height: 144px;
padding-top: 88px;
}
#service-selector .drag-target button::after,
#service-last-drag-position.drag-target {
content: "";
height: 72px;
border: 1px dashed #fff;
box-sizing: border-box;
background-color: rgb(43, 43, 43);
}
#service-selector .drag-target button::after {
position: absolute;
left: 0;
top: 0;
width: 100%;
}
#service-last-drag-position:not(.hidden):not(.drag-target) {
display: block;
padding: 16px 4px;
background-color: #fff5;
}
#service-last-drag-position:not(.drag-target)::after {
content: "";
display: block;
border-bottom: 1px solid #fff;
}
#service-selector .drag-target::after {
top: 75% !important;
}
*:focus { *:focus {
outline-color: rgb(118, 93, 176); outline-color: rgb(118, 93, 176);
} }

View File

@ -158,6 +158,27 @@ function createWindow() {
window.webContents.send('deleteService', id); window.webContents.send('deleteService', id);
}); });
ipcMain.on('reorderService', (e, serviceId, targetId) => {
console.log('Reordering services', serviceId, targetId);
const oldServices = config.services;
config.services = [];
for (let i = 0; i < targetId; i++) {
if (i !== serviceId) {
config.services.push(oldServices[i]);
}
}
config.services.push(oldServices[serviceId]);
for (let i = targetId; i < oldServices.length; i++) {
if (i !== serviceId) {
config.services.push(oldServices[i]);
}
}
e.reply('reorderService', serviceId, targetId);
});
ipcMain.on('updateWindowTitle', (event, serviceId, viewTitle) => { ipcMain.on('updateWindowTitle', (event, serviceId, viewTitle) => {
if (serviceId === null) { if (serviceId === null) {
window.setTitle(Meta.title); window.setTitle(Meta.title);