Dev #4
@@ -246,9 +246,9 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const ensureLock = async (): Promise<boolean> => {
|
||||
const ensureLock = async (force = false): Promise<boolean> => {
|
||||
if (!selectedDoc || selectedDoc.permission === 'read') return false;
|
||||
if (holdsLockRef.current) {
|
||||
if (holdsLockRef.current && !force) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
@@ -287,10 +287,14 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
||||
if (idleUnlockTimerRef.current) {
|
||||
clearTimeout(idleUnlockTimerRef.current);
|
||||
}
|
||||
// If a block is currently being dragged, do not schedule an unlock
|
||||
if (isDraggingBlockRef.current) {
|
||||
return;
|
||||
}
|
||||
// Short grace period: if user clicked into another block in the doc, focus will cancel this.
|
||||
// If user clicked outside or stopped editing, save and release the lock immediately!
|
||||
idleUnlockTimerRef.current = setTimeout(async () => {
|
||||
if (!isEditorFocusedRef.current && holdsLockRef.current) {
|
||||
if (!isEditorFocusedRef.current && !isDraggingBlockRef.current && holdsLockRef.current) {
|
||||
await flushPendingSave();
|
||||
await releaseMyLock();
|
||||
}
|
||||
@@ -523,13 +527,13 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
||||
// Window blur / visibility change listener: release lock when user leaves tab/window
|
||||
useEffect(() => {
|
||||
const handleWindowBlur = () => {
|
||||
if (!isEditorFocusedRef.current && holdsLockRef.current) {
|
||||
if (!isEditorFocusedRef.current && !isDraggingBlockRef.current && holdsLockRef.current) {
|
||||
flushPendingSave();
|
||||
releaseMyLock();
|
||||
}
|
||||
};
|
||||
const handleVisibilityChange = () => {
|
||||
if (document.visibilityState === 'hidden') {
|
||||
if (document.visibilityState === 'hidden' && !isDraggingBlockRef.current) {
|
||||
isEditorFocusedRef.current = false;
|
||||
flushPendingSave();
|
||||
releaseMyLock();
|
||||
@@ -1957,8 +1961,9 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
||||
clearTimeout(idleUnlockTimerRef.current);
|
||||
idleUnlockTimerRef.current = null;
|
||||
}
|
||||
// Activate write lock immediately upon dragging
|
||||
ensureLock();
|
||||
// Activate write lock immediately upon dragging (optimistic UI + backend broadcast)
|
||||
setHoldsLock(true);
|
||||
ensureLock(true);
|
||||
|
||||
e.dataTransfer.setData('application/mindsift-block-id', blockId);
|
||||
e.dataTransfer.setData('text/plain', blockId);
|
||||
@@ -1966,6 +1971,21 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
||||
setDraggingBlockId(blockId);
|
||||
};
|
||||
|
||||
const handleBlockDragEnd = () => {
|
||||
isDraggingBlockRef.current = false;
|
||||
setDraggingBlockId(null);
|
||||
setDragOverBlockTarget(null);
|
||||
if (idleUnlockTimerRef.current) {
|
||||
clearTimeout(idleUnlockTimerRef.current);
|
||||
}
|
||||
idleUnlockTimerRef.current = setTimeout(async () => {
|
||||
if (!isEditorFocusedRef.current && !isDraggingBlockRef.current && holdsLockRef.current) {
|
||||
await flushPendingSave();
|
||||
await releaseMyLock();
|
||||
}
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
const handleBlockDragOver = (e: React.DragEvent, targetBlockId: string) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -3596,25 +3616,11 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
||||
clearTimeout(idleUnlockTimerRef.current);
|
||||
idleUnlockTimerRef.current = null;
|
||||
}
|
||||
isDraggingBlockRef.current = true;
|
||||
ensureLock();
|
||||
ensureLock(true);
|
||||
}
|
||||
}}
|
||||
onDragStart={(e) => !isReadOnly && handleBlockDragStart(e, block.id)}
|
||||
onDragEnd={() => {
|
||||
isDraggingBlockRef.current = false;
|
||||
setDraggingBlockId(null);
|
||||
setDragOverBlockTarget(null);
|
||||
if (idleUnlockTimerRef.current) {
|
||||
clearTimeout(idleUnlockTimerRef.current);
|
||||
}
|
||||
idleUnlockTimerRef.current = setTimeout(async () => {
|
||||
if (!isEditorFocusedRef.current && !isDraggingBlockRef.current && holdsLockRef.current) {
|
||||
await flushPendingSave();
|
||||
await releaseMyLock();
|
||||
}
|
||||
}, 2500);
|
||||
}}
|
||||
onDragEnd={handleBlockDragEnd}
|
||||
className="opacity-0 group-hover:opacity-100 flex items-center pt-1 text-faint hover:text-accent cursor-grab active:cursor-grabbing flex-shrink-0 -ml-1 mr-0.5"
|
||||
title="Ziehen zum Verschieben"
|
||||
>
|
||||
@@ -3648,25 +3654,11 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
||||
clearTimeout(idleUnlockTimerRef.current);
|
||||
idleUnlockTimerRef.current = null;
|
||||
}
|
||||
isDraggingBlockRef.current = true;
|
||||
ensureLock();
|
||||
ensureLock(true);
|
||||
}
|
||||
}}
|
||||
onDragStart={(e) => !isReadOnly && handleBlockDragStart(e, block.id)}
|
||||
onDragEnd={() => {
|
||||
isDraggingBlockRef.current = false;
|
||||
setDraggingBlockId(null);
|
||||
setDragOverBlockTarget(null);
|
||||
if (idleUnlockTimerRef.current) {
|
||||
clearTimeout(idleUnlockTimerRef.current);
|
||||
}
|
||||
idleUnlockTimerRef.current = setTimeout(async () => {
|
||||
if (!isEditorFocusedRef.current && !isDraggingBlockRef.current && holdsLockRef.current) {
|
||||
await flushPendingSave();
|
||||
await releaseMyLock();
|
||||
}
|
||||
}, 2500);
|
||||
}}
|
||||
onDragEnd={handleBlockDragEnd}
|
||||
onDragOver={(e) => {
|
||||
if (!isReadOnly && draggingBlockId && draggingBlockId !== block.id) {
|
||||
e.preventDefault();
|
||||
|
||||
Reference in new issue
Block a user