feat: enhance drag-and-drop functionality to support multiple file paths and URLs
This commit is contained in:
parent
1e848e84b2
commit
c612072dc8
5 changed files with 384 additions and 480 deletions
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
console.log('%c[WebDrop Intercept] Script loaded - INTERCEPT_ENABLED=' + INTERCEPT_ENABLED, 'background: #2196F3; color: white; font-weight: bold; padding: 4px 8px;');
|
||||
|
||||
var currentDragUrl = null;
|
||||
var currentDragUrls = []; // Array to support multiple URLs
|
||||
var angularDragHandlers = [];
|
||||
var originalAddEventListener = EventTarget.prototype.addEventListener;
|
||||
var listenerPatchActive = true;
|
||||
|
|
@ -60,8 +60,14 @@
|
|||
|
||||
DataTransfer.prototype.setData = function(format, data) {
|
||||
if (format === 'text/plain' || format === 'text/uri-list') {
|
||||
currentDragUrl = data;
|
||||
console.log('%c[Intercept] Captured URL:', 'color: #4CAF50; font-weight: bold;', data.substring(0, 80));
|
||||
// text/uri-list contains newline-separated URLs
|
||||
// text/plain may be single URL or multiple newline-separated URLs
|
||||
currentDragUrls = data.trim().split('\n').filter(function(url) {
|
||||
return url.trim().length > 0;
|
||||
}).map(function(url) {
|
||||
return url.trim();
|
||||
});
|
||||
console.log('%c[Intercept] Captured ' + currentDragUrls.length + ' URL(s)', 'color: #4CAF50; font-weight: bold;', currentDragUrls[0].substring(0, 60));
|
||||
}
|
||||
return originalSetData.call(this, format, data);
|
||||
};
|
||||
|
|
@ -94,7 +100,7 @@
|
|||
|
||||
// Register OUR handler in capture phase
|
||||
originalAddEventListener.call(document, 'dragstart', function(e) {
|
||||
currentDragUrl = null; // Reset
|
||||
currentDragUrls = []; // Reset
|
||||
|
||||
// Call Angular's handlers first to let them set the data
|
||||
var handled = 0;
|
||||
|
|
@ -111,33 +117,41 @@
|
|||
}
|
||||
}
|
||||
|
||||
console.log('[Intercept] Called', handled, 'Angular handlers, URL:', currentDragUrl ? currentDragUrl.substring(0, 60) : 'none');
|
||||
console.log('[Intercept] Called', handled, 'Angular handlers, URLs:', currentDragUrls.length, 'URL(s)', currentDragUrls.length > 0 ? currentDragUrls[0].substring(0, 60) : 'none');
|
||||
|
||||
// NOW check if we should intercept
|
||||
// Intercept any drag with a URL that matches our configured mappings
|
||||
if (currentDragUrl) {
|
||||
// Intercept any drag with URLs that match our configured mappings
|
||||
if (currentDragUrls.length > 0) {
|
||||
var shouldIntercept = false;
|
||||
|
||||
// Check against configured URL mappings
|
||||
// Check each URL against configured URL mappings
|
||||
// Intercept if ANY URL matches
|
||||
if (window.webdropConfig && window.webdropConfig.urlMappings) {
|
||||
for (var j = 0; j < window.webdropConfig.urlMappings.length; j++) {
|
||||
var mapping = window.webdropConfig.urlMappings[j];
|
||||
if (currentDragUrl.toLowerCase().startsWith(mapping.url_prefix.toLowerCase())) {
|
||||
shouldIntercept = true;
|
||||
console.log('[Intercept] URL matches mapping for:', mapping.local_path);
|
||||
break;
|
||||
for (var k = 0; k < currentDragUrls.length; k++) {
|
||||
var dragUrl = currentDragUrls[k];
|
||||
for (var j = 0; j < window.webdropConfig.urlMappings.length; j++) {
|
||||
var mapping = window.webdropConfig.urlMappings[j];
|
||||
if (dragUrl.toLowerCase().startsWith(mapping.url_prefix.toLowerCase())) {
|
||||
shouldIntercept = true;
|
||||
console.log('[Intercept] URL #' + (k+1) + ' matches mapping for:', mapping.local_path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shouldIntercept) break;
|
||||
}
|
||||
} else {
|
||||
// Fallback: Check for legacy Z: drive pattern if no config available
|
||||
shouldIntercept = /^z:/i.test(currentDragUrl);
|
||||
if (shouldIntercept) {
|
||||
console.warn('[Intercept] Using fallback Z: drive pattern (no URL mappings configured)');
|
||||
for (var k = 0; k < currentDragUrls.length; k++) {
|
||||
if (/^z:/i.test(currentDragUrls[k])) {
|
||||
shouldIntercept = true;
|
||||
console.warn('[Intercept] Using fallback Z: drive pattern (no URL mappings configured)');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldIntercept) {
|
||||
console.log('%c[Intercept] PREVENTING browser drag, using Qt',
|
||||
console.log('%c[Intercept] PREVENTING browser drag, using Qt for ' + currentDragUrls.length + ' file(s)',
|
||||
'background: #F44336; color: white; font-weight: bold; padding: 4px 8px;');
|
||||
|
||||
e.preventDefault();
|
||||
|
|
@ -145,14 +159,15 @@
|
|||
|
||||
ensureChannel(function() {
|
||||
if (window.bridge && typeof window.bridge.start_file_drag === 'function') {
|
||||
console.log('%c[Intercept] → Qt: start_file_drag', 'color: #9C27B0; font-weight: bold;');
|
||||
window.bridge.start_file_drag(currentDragUrl);
|
||||
console.log('%c[Intercept] → Qt: start_file_drag with ' + currentDragUrls.length + ' file(s)', 'color: #9C27B0; font-weight: bold;');
|
||||
// Pass as JSON string to avoid Qt WebChannel array conversion issues
|
||||
window.bridge.start_file_drag(JSON.stringify(currentDragUrls));
|
||||
} else {
|
||||
console.error('[Intercept] bridge.start_file_drag not available!');
|
||||
}
|
||||
});
|
||||
|
||||
currentDragUrl = null;
|
||||
currentDragUrls = [];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import re
|
|||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from typing import Optional, Union
|
||||
|
||||
from PySide6.QtCore import (
|
||||
QEvent,
|
||||
|
|
@ -312,21 +312,34 @@ class _DragBridge(QObject):
|
|||
self.window = window
|
||||
|
||||
@Slot(str)
|
||||
def start_file_drag(self, path_text: str) -> None:
|
||||
"""Start a native file drag for the given path or Azure URL.
|
||||
def start_file_drag(self, paths_text: str) -> None:
|
||||
"""Start a native file drag for the given path(s) or Azure URL(s).
|
||||
|
||||
Called from JavaScript when user drags item(s).
|
||||
Accepts either:
|
||||
- Single file path string or Azure URL
|
||||
- JSON array string of file paths or Azure URLs (multiple drag support)
|
||||
|
||||
Called from JavaScript when user drags an item.
|
||||
Accepts either local file paths or Azure Blob Storage URLs.
|
||||
Defers execution to avoid Qt drag manager state issues.
|
||||
|
||||
Args:
|
||||
path_text: File path string or Azure URL to drag
|
||||
paths_text: String (single path/URL) or JSON array string (multiple paths/URLs)
|
||||
"""
|
||||
logger.debug(f"Bridge: start_file_drag called for {path_text}")
|
||||
logger.debug(f"Bridge: start_file_drag called with {len(paths_text)} chars")
|
||||
|
||||
# Defer to avoid drag manager state issues
|
||||
# handle_drag() handles URL conversion and validation internally
|
||||
QTimer.singleShot(0, lambda: self.window.drag_interceptor.handle_drag(path_text))
|
||||
# Try to parse as JSON array first (for multiple-drag support)
|
||||
paths_list: Union[str, list] = paths_text
|
||||
if paths_text.startswith("["):
|
||||
try:
|
||||
parsed = json.loads(paths_text)
|
||||
if isinstance(parsed, list):
|
||||
paths_list = parsed
|
||||
logger.debug(f"Parsed JSON array with {len(parsed)} item(s)")
|
||||
except (json.JSONDecodeError, TypeError) as e:
|
||||
logger.warning(f"Failed to parse JSON array: {e}, treating as single string")
|
||||
|
||||
# Handle both single string and list
|
||||
QTimer.singleShot(0, lambda: self.window.drag_interceptor.handle_drag(paths_list))
|
||||
|
||||
@Slot(str)
|
||||
def debug_log(self, message: str) -> None:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue