Replace messages jQuery drag/drop with native HTML5

This commit is contained in:
djmaze 2020-09-18 14:01:27 +02:00
parent d88c183112
commit c282e2c9b5
10 changed files with 91 additions and 149 deletions

View file

@ -1,5 +1,7 @@
const ko = window.ko,
$ = jQuery;
$ = jQuery,
validTransfer = data => ('move' === data.dropEffect || 'copy' === data.dropEffect) // effectAllowed
&& data.getData('text/x-rainloop-json');
ko.bindingHandlers.editor = {
init: (element, fValueAccessor) => {
@ -89,106 +91,40 @@ ko.bindingHandlers.emailsTags = {
};
ko.bindingHandlers.draggable = {
init: (element, fValueAccessor, fAllBindingsAccessor) => {
init: (element, fValueAccessor) => {
if (!rl.settings.app('mobile')) {
const triggerZone = 50,
scrollSpeed = 3,
fAllValueFunc = fAllBindingsAccessor(),
selector = fAllValueFunc ? fAllValueFunc.droppableSelector : '',
droppable = selector ? document.querySelector(selector) : null,
conf = {
distance: 20,
handle: '.dragHandle',
cursorAt: { top: 22, left: 3 },
refreshPositions: true,
scroll: true,
drag: null,
stop: null,
helper: null
};
let bcr;
if (droppable) {
conf.drag = event => {
if (droppable.scrollTopMax) {
clearInterval(droppable.timerScroll);
if (droppable.scrollTop
&& bcr.top < event.clientY
&& bcr.top + triggerZone > event.clientY)
{
droppable.timerScroll = setInterval(() => droppable.scrollTop -= scrollSpeed, 10);
}
else if (droppable.scrollTop < droppable.scrollTopMax
&& bcr.bottom > event.clientY
&& bcr.bottom - triggerZone < event.clientY)
{
droppable.timerScroll = setInterval(() => droppable.scrollTop += scrollSpeed, 10);
}
else {
clearInterval(droppable.timerScroll);
}
}
};
conf.stop = () => clearInterval(droppable.timerScroll);
}
conf.helper = event => fValueAccessor()(event && event.target ? ko.dataFor(event.target) : null);
$(element)
.draggable(conf)
.on('mousedown.koDraggable', () => {
require('Common/Utils').removeInFocus();
bcr = droppable ? droppable.getBoundingClientRect() : null;
});
ko.utils.domNodeDisposal.addDisposeCallback(element, () =>
$(element)
.off('mousedown.koDraggable')
.draggable('destroy')
);
element.addEventListener("dragstart", e => fValueAccessor()(e));
}
}
};
ko.bindingHandlers.droppable = {
init: (element, fValueAccessor, fAllBindingsAccessor) => {
init: (element, fValueAccessor) => {
if (!rl.settings.app('mobile')) {
const fValueFunc = fValueAccessor(),
fAllValueFunc = fAllBindingsAccessor(),
fOverCallback = fAllValueFunc && fAllValueFunc.droppableOver ? fAllValueFunc.droppableOver : null,
fOutCallback = fAllValueFunc && fAllValueFunc.droppableOut ? fAllValueFunc.droppableOut : null,
conf = {
tolerance: 'pointer',
hoverClass: 'droppableHover',
drop: null,
over: null,
out: null
const FolderList = fValueAccessor(),
folder = ko.dataFor(element),
fnHover = e => {
if (validTransfer(e.dataTransfer)) {
e.preventDefault();
element.classList.add('droppableHover');
FolderList.messagesDropOver(folder);
}
};
if (fValueFunc) {
conf.drop = (event, ui) => {
fValueFunc(event, ui);
};
if (fOverCallback) {
conf.over = (event, ui) => {
fOverCallback(event, ui);
};
element.addEventListener("dragenter", fnHover);
element.addEventListener("dragover", fnHover);
element.addEventListener("dragleave", e => {
e.preventDefault();
element.classList.remove('droppableHover');
FolderList.messagesDropOut();
});
element.addEventListener("drop", e => {
const data = JSON.parse(validTransfer(e.dataTransfer));
if (data) {
data.copy = data.copy && event.ctrlKey;
e.preventDefault();
FolderList.messagesDrop(folder, data);
}
if (fOutCallback) {
conf.out = (event, ui) => {
fOutCallback(event, ui);
};
}
$(element).droppable(conf);
ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
$(element).droppable('destroy');
});
}
});
}
}
};

View file

@ -138,6 +138,10 @@
color: #fff;
}
&.droppableHover * {
pointer-events: none;
}
&.focused {
color: #fff;
}

View file

@ -621,16 +621,15 @@ html .messageList .line-loading {
height: 5px !important;
}
.draggablePlace {
z-index: 10003;
#messagesDragImage {
color: #fff;
background-color: #333;
background-color: rgba(0,0,0,0.5);
padding: 4px 10px;
min-width: 30px;
background-color: #000;
height: 20px;
cursor: pointer;
cursor: move;
min-width: 30px;
padding: 4px 10px;
position: fixed;
right: -100px;
top: 0;
}
html.rl-mobile {

View file

@ -1,7 +1,7 @@
import ko from 'ko';
import { Capa, Focused, Layout, KeyState } from 'Common/Enums';
import { $htmlCL, leftPanelDisabled, moveAction } from 'Common/Globals';
import { leftPanelDisabled, moveAction } from 'Common/Globals';
import { mailBox, settings } from 'Common/Links';
import { setFolderHash } from 'Common/Cache';
@ -218,18 +218,12 @@ class FolderListMailBoxUserView extends AbstractViewNext {
/**
* @param {FolderModel} toFolder
* @param {{helper:jQuery}} ui
* @param {Array} data
* @returns {void}
*/
messagesDrop(toFolder, ui) {
if (toFolder && ui && ui.helper) {
const fromFolderFullNameRaw = ui.helper.rlFolder,
copy = $htmlCL.contains('rl-ctrl-key-pressed'),
uids = ui.helper.rlUids;
if (fromFolderFullNameRaw && Array.isArray(uids)) {
rl.app.moveMessagesToFolder(fromFolderFullNameRaw, uids, toFolder.fullNameRaw, copy);
}
messagesDrop(toFolder, data) {
if (toFolder && data && data.folder && Array.isArray(data.uids)) {
rl.app.moveMessagesToFolder(data.folder, data.uids, toFolder.fullNameRaw, data.copy);
}
}

View file

@ -45,6 +45,8 @@ const
canBeMovedHelper = (self) => self.canBeMoved(),
ifvisible = window.ifvisible;
let dragImage;
@view({
name: 'View/User/MailBox/MessageList',
type: ViewType.Right,
@ -479,30 +481,38 @@ class MessageListMailBoxUserView extends AbstractViewNext {
return false;
}
dragAndDronHelper(oMessageListItem) {
if (oMessageListItem) {
oMessageListItem.checked(true);
dragStart(event) {
const item = ko.dataFor(document.elementFromPoint(event.clientX, event.clientY));
item && item.checked(true);
dragImage || (dragImage = document.getElementById('messagesDragImage'));
const uids = MessageStore.messageListCheckedOrSelectedUidsWithSubMails();
if (dragImage && uids.length) {
dragImage.querySelector('.text').textContent = uids.length;
let img = dragImage.querySelector('.icon-white');
img.classList.toggle('icon-copy', event.ctrlKey);
img.classList.toggle('icon-mail', !event.ctrlKey);
// Else Chrome doesn't show it
dragImage.style.left = event.clientX + 'px';
dragImage.style.top = event.clientY + 'px';
dragImage.style.right = 'auto';
let action = event.ctrlKey ? 'copy' : 'move';
event.dataTransfer.setData('text/x-rainloop-json', JSON.stringify({
copy: event.ctrlKey,
folder: FolderStore.currentFolderFullNameRaw(),
uids: uids
}));
event.dataTransfer.setDragImage(dragImage, 0, 0);
event.dataTransfer.effectAllowed = action;
// Remove the Chrome visibility
dragImage.style.cssText = '';
} else {
event.preventDefault();
}
const el = Element.fromHTML('<div class="draggablePlace">' +
'<span class="text"></span>&nbsp;' +
'<i class="icon-copy icon-white visible-on-ctrl"></i>' +
'<i class="icon-mail icon-white hidden-on-ctrl"></i>' +
'</div>'),
updateUidsInfo = () => {
const uids = MessageStore.messageListCheckedOrSelectedUidsWithSubMails();
el.rlUids = uids;
el.querySelector('.text').textContent = uids.length;
};
document.getElementById('rl-hidden').append(el);
el.rlFolder = FolderStore.currentFolderFullNameRaw();
updateUidsInfo();
setTimeout(updateUidsInfo,1);
return el;
}
/**