From ae5c86814f65da02fd6e2480f0e70fd5739e0842 Mon Sep 17 00:00:00 2001 From: claudi Date: Wed, 18 Feb 2026 09:29:33 +0100 Subject: [PATCH] Remove obsolete WebDrop Bridge scripts: bridge_script.js, bridge_script_debug.js, bridge_script_drop_intercept.js, bridge_script_hybrid.js, bridge_script_v2.js --- docs/SCRIPT_VARIANTS.md | 171 --------- src/webdrop_bridge/ui/bridge_script.js | 325 ----------------- src/webdrop_bridge/ui/bridge_script_debug.js | 333 ------------------ .../ui/bridge_script_drop_intercept.js | 211 ----------- src/webdrop_bridge/ui/bridge_script_hybrid.js | 109 ------ src/webdrop_bridge/ui/bridge_script_v2.js | 214 ----------- 6 files changed, 1363 deletions(-) delete mode 100644 docs/SCRIPT_VARIANTS.md delete mode 100644 src/webdrop_bridge/ui/bridge_script.js delete mode 100644 src/webdrop_bridge/ui/bridge_script_debug.js delete mode 100644 src/webdrop_bridge/ui/bridge_script_drop_intercept.js delete mode 100644 src/webdrop_bridge/ui/bridge_script_hybrid.js delete mode 100644 src/webdrop_bridge/ui/bridge_script_v2.js diff --git a/docs/SCRIPT_VARIANTS.md b/docs/SCRIPT_VARIANTS.md deleted file mode 100644 index cd21eed..0000000 --- a/docs/SCRIPT_VARIANTS.md +++ /dev/null @@ -1,171 +0,0 @@ -# WebDrop Bridge - Drag & Drop Script Varianten - -## Verfügbare JavaScript-Scripte - -### 1. `bridge_script.js` (CURRENT - Original) -**Status:** Versucht Drag zu ersetzen, verhindert Popup -**Verwendung:** Testing, zeigt dass File-Drop prinzipiell funktioniert -**Problem:** Web-App Popup erscheint nicht - -### 2. `bridge_script_debug.js` (DEBUG - **EMPFOHLEN ZUM START**) -**Status:** Umfangreiches Logging, keine Manipulation -**Verwendung:** Herausfinden wie Popup ausgelöst wird -**Funktionen:** -- Loggt ALLE Drag/Drop Events -- Überwacht DataTransfer.setData -- Überwacht Network-Requests (API-Calls) -- Erkennt Angular Components -- Erkennt Modal/Popup Öffnungen -- Bietet Helper-Funktionen in Console - -**So verwenden:** -```python -# In main_window.py Zeile ~433 ändern: -script_path = Path(__file__).parent / "bridge_script_debug.js" # <-- DEBUG aktivieren -``` - -**Im Browser:** -1. F12 → Console öffnen -2. ALT-Drag+Drop durchführen -3. Logs analysieren: - - `[MODAL OPENED]` → Popup-Trigger gefunden! - - `[FETCH]` oder `[XHR]` → API-Call gefunden! - - `[EVENT]` → Drag-Flow verstehen - -### 3. `bridge_script_v2.js` (EXTEND - Experimentell) -**Status:** Versuch DataTransfer zu erweitern -**Problem:** Browser-Sicherheit verhindert Files hinzufügen - -### 4. `bridge_script_hybrid.js` (HYBRID - Experimentell) -**Status:** Versuch parallele Drags -**Problem:** Nur ein Drag zur Zeit möglich - -### 5. `bridge_script_drop_intercept.js` (DROP - Experimentell) -**Status:** Drop-Event abfangen und manipulieren -**Problem:** DataTransfer kann nicht mit Files erstellt werden - -## 🎯 Empfohlener Workflow - -### Phase 1: Debugging (JETZT) - -1. **Debug-Script aktivieren:** - ```python - # main_window.py, _install_bridge_script() - script_path = Path(__file__).parent / "bridge_script_debug.js" - ``` - -2. **Anwendung starten und testen:** - ```powershell - python -m webdrop_bridge.main - ``` - -3. **In Browser (F12 Console):** - - ALT-Drag+Drop durchführen - - Logs kopieren und analysieren - - Nach `[MODAL OPENED]` oder API-Calls suchen - -4. **Herausfinden:** - - ✅ Wie wird Popup ausgelöst? (API-Call, Event, Component-Methode) - - ✅ Welche Asset-ID wird verwendet? - - ✅ Wo im DOM befindet sich die Popup-Logik? - -### Phase 2: Implementation (DANACH) - -Basierend auf Debug-Ergebnissen: - -**Fall A: Popup wird durch API-Call ausgelöst** -```javascript -// In bridge_script.js nach erfolgreichem Drop: -fetch('/api/assets/' + assetId + '/checkout', { - method: 'POST', - headers: {'Content-Type': 'application/json'} -}).then(response => { - console.log('Checkout popup triggered'); -}); -``` - -**Fall B: Popup wird durch Angular-Event ausgelöst** -```javascript -// Trigger Angular CDK Event -var dropList = document.querySelector('[cdkdroplist]'); -if (dropList && window.ng) { - var component = ng.getComponent(dropList); - component.onDrop({assetId: assetId}); -} -``` - -**Fall C: Popup wird durch Component-Methode ausgelöst** -```javascript -// Direkter Methoden-Aufruf -var assetCard = document.getElementById(assetId); -if (assetCard && window.ng) { - var component = ng.getComponent(assetCard); - component.showCheckoutDialog(); -} -``` - -### Phase 3: Testing (FINAL) - -1. Implementation in `bridge_script.js` integrieren -2. Beide Funktionen testen: - - ✅ File wird gedroppt (Z:\ Laufwerk) - - ✅ Popup erscheint (Auschecken-Dialog) - -## 🔧 Script-Wechsel in Code - -```python -# src/webdrop_bridge/ui/main_window.py -# Zeile ~433 in _install_bridge_script() - -# ORIGINAL (funktioniert, aber kein Popup): -script_path = Path(__file__).parent / "bridge_script.js" - -# DEBUG (für Analyse): -script_path = Path(__file__).parent / "bridge_script_debug.js" - -# Oder via Konfiguration: -script_name = self.config.bridge_script or "bridge_script.js" -script_path = Path(__file__).parent / script_name -``` - -## 📝 Debug-Checkliste - -Beim Testen mit Debug-Script, notieren Sie: - -- [ ] Wann erscheint das Popup? (Nach Drop, nach Verzögerung, sofort?) -- [ ] Gibt es API-Calls? (Welche URL, Parameter, Zeitpunkt?) -- [ ] Welche Angular-Events feuern? (CDK Events, Custom Events?) -- [ ] Wo wird Modal/Dialog erstellt? (DOM-Position, Klassen, Component) -- [ ] Welche Asset-Informationen werden benötigt? (ID, Name, URL?) -- [ ] Stack-Trace beim Modal-Öffnen? (console.trace Ausgabe) - -## 🚀 Quick Commands - -```powershell -# App mit Debug-Script starten -python -m webdrop_bridge.main - -# In Browser Console (F12): -webdrop_debug.getEventCounts() # Event-Statistiken -webdrop_debug.resetCounters() # Zähler zurücksetzen -webdrop_debug.getListeners(element) # Event-Listener auflisten -webdrop_debug.getComponent(element) # Angular Component anzeigen - -# Logs filtern: -# Console Filter: "[MODAL]" → Nur Popup-Logs -# Console Filter: "[EVENT]" → Nur Event-Logs -# Console Filter: "[FETCH]|[XHR]" → Nur Network-Logs -``` - -## ⚠️ Bekannte Limitationen - -1. **Angular DevTools benötigt:** Für `ng.getComponent()` Installation nötig -2. **Chrome/Edge:** Einige Features funktionieren nur in Chromium-Browsern -3. **CSP:** Bei strengen Content-Security-Policies können Logs blockiert werden -4. **Performance:** Debug-Script hat deutlichen Performance-Overhead - -## 📚 Weiterführende Dokumentation - -- [ANGULAR_CDK_ANALYSIS.md](ANGULAR_CDK_ANALYSIS.md) - Angular Framework Details -- [DRAG_DROP_PROBLEM_ANALYSIS.md](DRAG_DROP_PROBLEM_ANALYSIS.md) - Problem-Analyse + Lösungen -- [ARCHITECTURE.md](ARCHITECTURE.md) - Gesamtarchitektur diff --git a/src/webdrop_bridge/ui/bridge_script.js b/src/webdrop_bridge/ui/bridge_script.js deleted file mode 100644 index ad8d4ce..0000000 --- a/src/webdrop_bridge/ui/bridge_script.js +++ /dev/null @@ -1,325 +0,0 @@ -// WebDrop Bridge - Injected Script -// Automatically converts Z:\ path drags to native file drags via QWebChannel bridge - -(function() { - if (window.__webdrop_bridge_injected) return; - window.__webdrop_bridge_injected = true; - - console.log('[WebDrop Bridge] Script loaded'); - - // Store web app's dragstart handlers by intercepting addEventListener - var webAppDragHandlers = []; - var originalAddEventListener = EventTarget.prototype.addEventListener; - var listenerPatchActive = true; - - // Patch addEventListener to intercept dragstart registrations - EventTarget.prototype.addEventListener = function(type, listener, options) { - if (listenerPatchActive && type === 'dragstart' && listener) { - // Store the web app's dragstart handler instead of registering it - console.log('[WebDrop Bridge] Intercepted dragstart listener registration on', this.tagName || this.constructor.name); - webAppDragHandlers.push({ - target: this, - listener: listener, - options: options - }); - return; - } - // All other events: use original - return originalAddEventListener.call(this, type, listener, options); - }; - - // Patch DataTransfer.setData to intercept URL setting by the web app - var originalSetData = null; - var currentDragData = null; - - try { - if (DataTransfer.prototype.setData) { - originalSetData = DataTransfer.prototype.setData; - - DataTransfer.prototype.setData = function(format, data) { - // Store the data for our analysis - if (format === 'text/plain' || format === 'text/uri-list') { - currentDragData = data; - console.log('[WebDrop Bridge] DataTransfer.setData intercepted:', format, '=', data.substring(0, 80)); - - // Log via bridge if available - if (window.bridge && typeof window.bridge.debug_log === 'function') { - window.bridge.debug_log('setData intercepted: ' + format + ' = ' + data.substring(0, 60)); - } - } - // Call original to maintain web app functionality - return originalSetData.call(this, format, data); - }; - - console.log('[WebDrop Bridge] DataTransfer.setData patched'); - } - } catch(e) { - console.error('[WebDrop Bridge] Failed to patch DataTransfer:', e); - } - - function ensureChannel(cb) { - if (window.bridge) { cb(); return; } - - function init() { - if (window.QWebChannel && window.qt && window.qt.webChannelTransport) { - new QWebChannel(window.qt.webChannelTransport, function(channel) { - window.bridge = channel.objects.bridge; - console.log('[WebDrop Bridge] QWebChannel connected'); - cb(); - }); - } else { - // If QWebChannel is not available, log error - console.error('[WebDrop Bridge] QWebChannel not available! Check if qwebchannel.js was loaded.'); - } - } - - // QWebChannel should already be loaded inline (no need to load from qrc://) - if (window.QWebChannel) { - init(); - } else { - console.error('[WebDrop Bridge] QWebChannel not found! Cannot initialize bridge.'); - } - } - - function hook() { - console.log('[WebDrop Bridge] Installing hook, have ' + webAppDragHandlers.length + ' intercepted handlers'); - - if (window.bridge && typeof window.bridge.debug_log === 'function') { - window.bridge.debug_log('Installing drag interceptor with ' + webAppDragHandlers.length + ' intercepted handlers'); - } - - // Stop intercepting addEventListener - from now on, listeners register normally - listenerPatchActive = false; - - // Register OUR dragstart handler using capture phase on document - originalAddEventListener.call(document, 'dragstart', function(e) { - try { - console.log('[WebDrop Bridge] >>> DRAGSTART fired on:', e.target.tagName, 'altKey:', e.altKey, 'currentDragData:', currentDragData); - - if (window.bridge && typeof window.bridge.debug_log === 'function') { - window.bridge.debug_log('dragstart fired on ' + e.target.tagName + ' altKey=' + e.altKey); - } - - // Only intercept if ALT key is pressed (web app's text drag mode) - if (!e.altKey) { - console.log('[WebDrop Bridge] ALT not pressed, ignoring drag (normal web app drag)'); - return; // Let web app handle normal drags - } - - console.log('[WebDrop Bridge] ALT pressed - processing for file drag conversion'); - - // Manually invoke all the web app's dragstart handlers - var handlersInvoked = 0; - console.log('[WebDrop Bridge] About to invoke', webAppDragHandlers.length, 'stored handlers'); - - for (var i = 0; i < webAppDragHandlers.length; i++) { - try { - var handler = webAppDragHandlers[i]; - // Check if this handler should be called for this target - if (handler.target === document || - handler.target === e.target || - (handler.target.contains && handler.target.contains(e.target))) { - - console.log('[WebDrop Bridge] Calling stored handler #' + i); - handler.listener.call(e.target, e); - handlersInvoked++; - } - } catch (err) { - console.error('[WebDrop Bridge] Error calling web app handler #' + i + ':', err); - } - } - - console.log('[WebDrop Bridge] Invoked', handlersInvoked, 'handlers, currentDragData:', currentDragData ? currentDragData.substring(0, 60) : 'null'); - - // NOW check if we have a convertible URL - if (currentDragData) { - console.log('[WebDrop Bridge] Checking currentDragData:', currentDragData.substring(0, 80)); - var path = currentDragData; - var isZDrive = /^z:/i.test(path); - var isAzureUrl = /^https?:\/\/.+\.file\.core\.windows\.net\//i.test(path); - - console.log('[WebDrop Bridge] isZDrive:', isZDrive, 'isAzureUrl:', isAzureUrl); - - if (isZDrive || isAzureUrl) { - console.log('[WebDrop Bridge] >>> CONVERTING URL TO NATIVE DRAG (DELAYED)'); - - if (window.bridge && typeof window.bridge.debug_log === 'function') { - window.bridge.debug_log('Convertible URL detected - delaying Qt drag for Angular events'); - } - - // DON'T prevent immediately - let Angular process dragstart for ~200ms - // This allows web app to register the drag and prepare popup - - // Store URL and element for later - window.__lastDraggedUrl = path; - var originalTarget = e.target; - - // After 200ms: Cancel browser drag and start Qt drag - setTimeout(function() { - console.log('[WebDrop Bridge] Starting Qt drag now, browser drag will be cancelled'); - - // Try to cancel browser drag by creating a fake drop on same element - try { - var dropEvent = new DragEvent('drop', { - bubbles: true, - cancelable: true, - view: window - }); - originalTarget.dispatchEvent(dropEvent); - } catch(err) { - console.log('[WebDrop Bridge] Could not dispatch drop event:', err); - } - - // Hide Angular CDK overlays - var style = document.createElement('style'); - style.id = 'webdrop-bridge-hide-overlay'; - style.textContent = ` - .cdk-drag-animating, - .cdk-drag-preview, - .cdk-drag-placeholder, - [cdkdroplist].cdk-drop-list-dragging, - #root-collection-drop-area, - [id*="drop-area"] { - opacity: 0 !important; - pointer-events: none !important; - display: none !important; - } - `; - document.head.appendChild(style); - - // Start Qt drag - ensureChannel(function() { - if (window.bridge && typeof window.bridge.start_file_drag === 'function') { - console.log('[WebDrop Bridge] Calling start_file_drag:', path.substring(0, 60)); - window.bridge.start_file_drag(path); - currentDragData = null; - - // Cleanup after 5 seconds - setTimeout(function() { - var hideStyle = document.getElementById('webdrop-bridge-hide-overlay'); - if (hideStyle) hideStyle.remove(); - }, 5000); - } else { - console.error('[WebDrop Bridge] bridge.start_file_drag not available!'); - } - }); - }, 200); // 200ms delay - - // Let the browser drag start naturally (no preventDefault yet) - - return false; - } else { - console.log('[WebDrop Bridge] URL not convertible:', path.substring(0, 60)); - } - } else { - console.log('[WebDrop Bridge] No currentDragData set'); - } - } catch (mainError) { - console.error('[WebDrop Bridge] CRITICAL ERROR in dragstart handler:', mainError); - if (window.bridge && typeof window.bridge.debug_log === 'function') { - window.bridge.debug_log('ERROR in dragstart: ' + mainError.message); - } - } - }, true); // CAPTURE PHASE - intercept early - - // Reset state on dragend - originalAddEventListener.call(document, 'dragend', function(e) { - currentDragData = null; - }, false); - - console.log('[WebDrop Bridge] Drag listener registered on document (capture phase)'); - } - - // Wait for DOMContentLoaded and then a bit more before installing hook - // This gives the web app time to register its handlers - function installHook() { - console.log('[WebDrop Bridge] DOM ready, waiting 2 seconds for web app to register handlers...'); - console.log('[WebDrop Bridge] Currently have', webAppDragHandlers.length, 'intercepted handlers'); - - setTimeout(function() { - console.log('[WebDrop Bridge] Installing hook now, have', webAppDragHandlers.length, 'intercepted handlers'); - hook(); - - ensureChannel(function() { - if (window.bridge && typeof window.bridge.debug_log === 'function') { - window.bridge.debug_log('Hook installed with ' + webAppDragHandlers.length + ' captured handlers'); - } - }); - }, 2000); // Wait 2 seconds after DOM ready - } - - // Global function to trigger checkout after successful file drop - window.trigger_checkout_for_asset = function(azure_url) { - console.log('[WebDrop Bridge] trigger_checkout_for_asset called for:', azure_url); - - // Extract asset ID from Azure URL - // Format: https://devagravitystg.file.core.windows.net/devagravitysync/{assetId}/{filename} - var match = azure_url.match(/\/devagravitysync\/([^\/]+)\//); - if (!match) { - console.error('[WebDrop Bridge] Could not extract asset ID from URL:', azure_url); - return; - } - - var assetId = match[1]; - console.log('[WebDrop Bridge] Extracted asset ID:', assetId); - console.log('[WebDrop Bridge] Calling checkout API directly...'); - - // Direct API call to checkout asset (skip popup, auto-checkout) - var apiUrl = 'https://devagravityprivate.azurewebsites.net/api/assets/' + assetId + '/checkout'; - - fetch(apiUrl, { - method: 'POST', - credentials: 'include', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - // Empty body or add checkout parameters if needed - }) - }).then(function(response) { - if (response.ok) { - console.log('[WebDrop Bridge] ✅ Asset checked out successfully:', assetId); - return response.json(); - } else { - console.warn('[WebDrop Bridge] ⚠️ Checkout API returned status:', response.status); - // Try alternative: Mark as checked out without confirmation - return tryAlternativeCheckout(assetId); - } - }).then(function(data) { - console.log('[WebDrop Bridge] Checkout response:', data); - }).catch(function(err) { - console.error('[WebDrop Bridge] ❌ Checkout API error:', err); - // Fallback: Try alternative checkout method - tryAlternativeCheckout(assetId); - }); - }; - - // Alternative checkout method if direct API fails - function tryAlternativeCheckout(assetId) { - console.log('[WebDrop Bridge] Trying alternative checkout for:', assetId); - - // Option 1: Try GET to fetch asset status, might trigger checkout tracking - var statusUrl = 'https://devagravityprivate.azurewebsites.net/api/assets/' + assetId; - - return fetch(statusUrl, { - method: 'GET', - credentials: 'include' - }).then(function(response) { - if (response.ok) { - console.log('[WebDrop Bridge] Asset status fetched, might have logged usage'); - } - return response.json(); - }).catch(function(err) { - console.error('[WebDrop Bridge] Alternative checkout also failed:', err); - }); - } - - // Install after DOM is ready - if (document.readyState === 'loading') { - console.log('[WebDrop Bridge] Waiting for DOMContentLoaded...'); - originalAddEventListener.call(document, 'DOMContentLoaded', installHook); - } else { - console.log('[WebDrop Bridge] DOM already ready, installing hook...'); - installHook(); - } -})(); diff --git a/src/webdrop_bridge/ui/bridge_script_debug.js b/src/webdrop_bridge/ui/bridge_script_debug.js deleted file mode 100644 index 3fe16a1..0000000 --- a/src/webdrop_bridge/ui/bridge_script_debug.js +++ /dev/null @@ -1,333 +0,0 @@ -// WebDrop Bridge - DEBUG Version -// Heavy logging to understand web app's drag&drop behavior -// -// Usage: -// 1. Load this script -// 2. Perform ALT-drag+drop in web app -// 3. Check console for detailed logs -// 4. Look for: API calls, events names, component methods - -(function() { - if (window.__webdrop_debug_injected) return; - window.__webdrop_debug_injected = true; - - console.log('%c[WebDrop DEBUG] Script loaded', 'background: #222; color: #bada55; font-size: 14px; font-weight: bold;'); - - // ============================================================================ - // PART 1: Event Monitoring - see ALL drag/drop related events - // ============================================================================ - - var allEvents = ['dragstart', 'drag', 'dragenter', 'dragover', 'dragleave', 'drop', 'dragend']; - var eventCounts = {}; - - allEvents.forEach(function(eventName) { - eventCounts[eventName] = 0; - - document.addEventListener(eventName, function(e) { - eventCounts[eventName]++; - - // Only log dragstart, drop, dragend fully (others are noisy) - if (eventName === 'dragstart' || eventName === 'drop' || eventName === 'dragend') { - console.group('%c[EVENT] ' + eventName.toUpperCase(), 'color: #FF6B6B; font-weight: bold;'); - console.log('Target:', e.target.tagName, e.target.className, e.target.id); - console.log('DataTransfer:', { - types: Array.from(e.dataTransfer.types), - effectAllowed: e.dataTransfer.effectAllowed, - dropEffect: e.dataTransfer.dropEffect, - files: e.dataTransfer.files.length - }); - console.log('Keys:', { - alt: e.altKey, - ctrl: e.ctrlKey, - shift: e.shiftKey - }); - console.log('Position:', {x: e.clientX, y: e.clientY}); - - // Try to read data (only works in drop/dragstart) - if (eventName === 'drop' || eventName === 'dragstart') { - try { - var plainText = e.dataTransfer.getData('text/plain'); - var uriList = e.dataTransfer.getData('text/uri-list'); - console.log('Data:', { - 'text/plain': plainText ? plainText.substring(0, 100) : null, - 'text/uri-list': uriList ? uriList.substring(0, 100) : null - }); - } catch(err) { - console.warn('Could not read DataTransfer data:', err.message); - } - } - - console.groupEnd(); - } - }, true); // Capture phase - }); - - // Log event summary every 5 seconds - setInterval(function() { - var hasEvents = Object.keys(eventCounts).some(function(k) { return eventCounts[k] > 0; }); - if (hasEvents) { - console.log('%c[EVENT SUMMARY]', 'color: #4ECDC4; font-weight: bold;', eventCounts); - } - }, 5000); - - // ============================================================================ - // PART 2: DataTransfer.setData Interception - // ============================================================================ - - try { - var originalSetData = DataTransfer.prototype.setData; - - DataTransfer.prototype.setData = function(format, data) { - console.log('%c[DataTransfer.setData]', 'color: #FFE66D; font-weight: bold;', format, '=', - typeof data === 'string' ? data.substring(0, 100) : data); - return originalSetData.call(this, format, data); - }; - - console.log('[WebDrop DEBUG] DataTransfer.setData patched ✓'); - } catch(e) { - console.error('[WebDrop DEBUG] Failed to patch DataTransfer:', e); - } - - // ============================================================================ - // PART 3: Network Monitor - detect API calls (with request bodies) - // ============================================================================ - - var originalFetch = window.fetch; - window.fetch = function() { - var url = arguments[0]; - var options = arguments[1] || {}; - - console.log('%c🌐 Fetch called:', 'color: #95E1D3; font-weight: bold;', url); - - // Log headers if present - if (options.headers) { - console.log('%c[FETCH HEADERS]', 'color: #FFB6C1; font-weight: bold;'); - console.log(JSON.stringify(options.headers, null, 2)); - } - - // Log request body if present - if (options.body) { - try { - var bodyPreview = typeof options.body === 'string' ? options.body : JSON.stringify(options.body); - if (bodyPreview.length > 200) { - bodyPreview = bodyPreview.substring(0, 200) + '... (truncated)'; - } - console.log('%c[FETCH BODY]', 'color: #FFE66D; font-weight: bold;', bodyPreview); - } catch(e) { - console.log('%c[FETCH BODY]', 'color: #FFE66D; font-weight: bold;', '[Could not stringify]'); - } - } - - return originalFetch.apply(this, arguments); - }; - - var originalXHROpen = XMLHttpRequest.prototype.open; - var originalXHRSend = XMLHttpRequest.prototype.send; - var originalXHRSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader; - - XMLHttpRequest.prototype.open = function(method, url) { - this._webdrop_method = method; - this._webdrop_url = url; - this._webdrop_headers = {}; - console.log('%c[XHR]', 'color: #95E1D3; font-weight: bold;', method, url); - return originalXHROpen.apply(this, arguments); - }; - - XMLHttpRequest.prototype.setRequestHeader = function(header, value) { - this._webdrop_headers = this._webdrop_headers || {}; - this._webdrop_headers[header] = value; - return originalXHRSetRequestHeader.apply(this, arguments); - }; - - XMLHttpRequest.prototype.send = function(body) { - // Log headers if present - if (this._webdrop_headers && Object.keys(this._webdrop_headers).length > 0) { - if (this._webdrop_url && this._webdrop_url.includes('checkout')) { - console.log('%c[XHR HEADERS - CHECKOUT]', 'background: #FF6B6B; color: white; font-weight: bold; padding: 2px 6px;'); - console.log(JSON.stringify(this._webdrop_headers, null, 2)); - } else { - console.log('%c[XHR HEADERS]', 'color: #FFB6C1; font-weight: bold;'); - console.log(JSON.stringify(this._webdrop_headers, null, 2)); - } - } - - // Log request body if present - if (body) { - try { - var bodyPreview = typeof body === 'string' ? body : JSON.stringify(body); - if (bodyPreview.length > 200) { - bodyPreview = bodyPreview.substring(0, 200) + '... (truncated)'; - } - - // Highlight checkout API calls - if (this._webdrop_url && this._webdrop_url.includes('checkout')) { - console.log('%c[XHR BODY - CHECKOUT]', 'background: #FF6B6B; color: white; font-weight: bold; padding: 2px 6px;', - this._webdrop_method, this._webdrop_url); - console.log('%c[CHECKOUT PAYLOAD]', 'color: #00FF00; font-weight: bold;', bodyPreview); - } else { - console.log('%c[XHR BODY]', 'color: #FFE66D; font-weight: bold;', bodyPreview); - } - } catch(e) { - console.log('%c[XHR BODY]', 'color: #FFE66D; font-weight: bold;', '[Could not stringify]'); - } - } - - return originalXHRSend.apply(this, arguments); - }; - - console.log('[WebDrop DEBUG] Network interceptors installed ✓ (with request body logging)'); - - // ============================================================================ - // PART 4: Angular Event Detection (if Angular is used) - // ============================================================================ - - setTimeout(function() { - // Try to detect Angular - if (window.ng) { - console.log('%c[ANGULAR DETECTED]', 'color: #DD2C00; font-weight: bold;', 'Version:', window.ng.version?.full); - - // Try to find Angular components - var cards = document.querySelectorAll('ay-asset-card'); - console.log('[ANGULAR] Found', cards.length, 'asset cards'); - - if (cards.length > 0 && window.ng.getComponent) { - try { - var component = window.ng.getComponent(cards[0]); - console.log('%c[ANGULAR COMPONENT]', 'color: #DD2C00; font-weight: bold;', component); - console.log('Methods:', Object.getOwnPropertyNames(Object.getPrototypeOf(component))); - } catch(e) { - console.warn('[ANGULAR] Could not get component:', e); - } - } - } else { - console.log('[WebDrop DEBUG] Angular not detected or DevTools required'); - } - - // Try to detect CDK - if (document.querySelector('[cdkdrag]')) { - console.log('%c[ANGULAR CDK] Detected', 'color: #FF6F00; font-weight: bold;'); - - // Monitor CDK specific events (if we can access them) - // Note: CDK events are often internal, we might need to monkey-patch - console.log('[CDK] Drag elements found:', document.querySelectorAll('[cdkdrag]').length); - console.log('[CDK] Drop lists found:', document.querySelectorAll('[cdkdroplist]').length); - } - }, 2000); - - // ============================================================================ - // PART 5: Modal/Dialog Detection - // ============================================================================ - - var modalObserver = new MutationObserver(function(mutations) { - mutations.forEach(function(mutation) { - mutation.addedNodes.forEach(function(node) { - if (node.nodeType === 1) { // Element node - // Check for common modal/dialog patterns - // Safely get className as string (handles SVG elements and undefined) - var className = typeof node.className === 'string' - ? node.className - : (node.className && node.className.baseVal) ? node.className.baseVal : ''; - - var isModal = className && ( - className.includes('modal') || - className.includes('dialog') || - className.includes('popup') || - className.includes('overlay') - ); - - if (isModal) { - console.log('%c[MODAL OPENED]', 'color: #FF6B6B; font-size: 16px; font-weight: bold;'); - console.log('Modal element:', node); - console.log('Classes:', className); - console.log('Content:', node.textContent.substring(0, 200)); - - // Log the stack trace to see what triggered it - console.trace('Modal opened from:'); - } - } - }); - }); - }); - - // Start observer when body is ready - function startModalObserver() { - if (document.body) { - modalObserver.observe(document.body, { - childList: true, - subtree: true - }); - console.log('[WebDrop DEBUG] Modal observer installed ✓'); - } else { - console.warn('[WebDrop DEBUG] document.body not ready, modal observer skipped'); - } - } - - // Wait for DOM to be ready - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', startModalObserver); - } else { - startModalObserver(); - } - - // ============================================================================ - // PART 6: Helper Functions for Manual Testing - // ============================================================================ - - window.webdrop_debug = { - // Get all event listeners on an element - getListeners: function(element) { - if (typeof getEventListeners === 'function') { - return getEventListeners(element || document); - } else { - console.warn('getEventListeners not available. Open Chrome DevTools Console.'); - return null; - } - }, - - // Find Angular component for an element - getComponent: function(element) { - if (window.ng && window.ng.getComponent) { - return window.ng.getComponent(element); - } else { - console.warn('Angular DevTools not available. Install Angular DevTools extension.'); - return null; - } - }, - - // Simulate a drop at coordinates - simulateDrop: function(x, y, data) { - var dropEvent = new DragEvent('drop', { - bubbles: true, - cancelable: true, - clientX: x, - clientY: y - }); - - // Can't set dataTransfer, but element can be used for testing - var target = document.elementFromPoint(x, y); - target.dispatchEvent(dropEvent); - console.log('Simulated drop at', x, y, 'on', target); - }, - - // Get event counts - getEventCounts: function() { - return eventCounts; - }, - - // Reset counters - resetCounters: function() { - Object.keys(eventCounts).forEach(function(k) { eventCounts[k] = 0; }); - console.log('Counters reset'); - } - }; - - console.log('%c[WebDrop DEBUG] Helper functions available as window.webdrop_debug', 'color: #95E1D3; font-weight: bold;'); - console.log('Try: webdrop_debug.getListeners(), webdrop_debug.getComponent(element)'); - - // ============================================================================ - // READY - // ============================================================================ - - console.log('%c[WebDrop DEBUG] Ready! Perform ALT-drag+drop and watch the logs.', - 'background: #222; color: #00FF00; font-size: 14px; font-weight: bold; padding: 4px;'); -})(); diff --git a/src/webdrop_bridge/ui/bridge_script_drop_intercept.js b/src/webdrop_bridge/ui/bridge_script_drop_intercept.js deleted file mode 100644 index 8b49201..0000000 --- a/src/webdrop_bridge/ui/bridge_script_drop_intercept.js +++ /dev/null @@ -1,211 +0,0 @@ -// WebDrop Bridge - Drop Event Interception Strategy -// Strategy: -// 1. Let browser drag proceed normally (web app sets URL in DataTransfer) -// 2. Intercept DROP event in capture phase -// 3. Convert URL to local file path -// 4. Synthesize new DROP event with file data -// 5. Dispatch synthetic event (web app receives it and shows popup) -// 6. File gets dropped correctly - -(function() { - if (window.__webdrop_bridge_drop_intercept) return; - window.__webdrop_bridge_drop_intercept = true; - - console.log('[WebDrop Bridge DROP] Script loaded - Drop interception strategy'); - - var dragState = { - url: null, - localPath: null, - isConvertible: false, - altKeyPressed: false, - dragElement: null - }; - - // Patch DataTransfer.setData to capture URLs during drag - try { - var originalSetData = DataTransfer.prototype.setData; - - DataTransfer.prototype.setData = function(format, data) { - if (format === 'text/plain' || format === 'text/uri-list') { - console.log('[WebDrop Bridge DROP] Captured data:', format, '=', data.substring(0, 80)); - - if (dragState.altKeyPressed) { - dragState.url = data; - - // Check if convertible - dragState.isConvertible = /^z:/i.test(data) || - /^https?:\/\/.+\.file\.core\.windows\.net\//i.test(data); - - if (dragState.isConvertible) { - console.log('[WebDrop Bridge DROP] >>> CONVERTIBLE URL - will intercept drop'); - - // Request conversion NOW (synchronously if possible) - ensureChannel(function() { - if (window.bridge && typeof window.bridge.convert_url_sync === 'function') { - // Synchronous conversion - dragState.localPath = window.bridge.convert_url_sync(data); - console.log('[WebDrop Bridge DROP] Converted to:', dragState.localPath); - } else if (window.bridge && typeof window.bridge.convert_url_to_path === 'function') { - // Async conversion (fallback) - window.bridge.convert_url_to_path(data); - console.log('[WebDrop Bridge DROP] Async conversion requested'); - } - }); - } - } - } - - // Always call original - return originalSetData.call(this, format, data); - }; - - console.log('[WebDrop Bridge DROP] DataTransfer patched'); - } catch(e) { - console.error('[WebDrop Bridge DROP] Patch failed:', e); - } - - // Callback for async conversion - window.webdrop_set_local_path = function(path) { - dragState.localPath = path; - console.log('[WebDrop Bridge DROP] Local path received:', path); - }; - - function ensureChannel(cb) { - if (window.bridge) { cb(); return; } - - if (window.QWebChannel && window.qt && window.qt.webChannelTransport) { - new QWebChannel(window.qt.webChannelTransport, function(channel) { - window.bridge = channel.objects.bridge; - console.log('[WebDrop Bridge DROP] QWebChannel connected'); - cb(); - }); - } - } - - function createSyntheticDropEvent(originalEvent, localPath) { - console.log('[WebDrop Bridge DROP] Creating synthetic drop event with file:', localPath); - - try { - // Create a new DataTransfer with file - // NOTE: This is complex because DataTransfer can't be created directly - // We'll create a new DragEvent and try to set files - - var newEvent = new DragEvent('drop', { - bubbles: true, - cancelable: true, - composed: true, - view: window, - detail: originalEvent.detail, - screenX: originalEvent.screenX, - screenY: originalEvent.screenY, - clientX: originalEvent.clientX, - clientY: originalEvent.clientY, - ctrlKey: originalEvent.ctrlKey, - altKey: originalEvent.altKey, - shiftKey: originalEvent.shiftKey, - metaKey: originalEvent.metaKey, - button: originalEvent.button, - buttons: originalEvent.buttons, - relatedTarget: originalEvent.relatedTarget, - // We can't directly set dataTransfer, it's read-only - }); - - // This is a limitation: We can't create a DataTransfer with files from JavaScript - // The only way is to use a real file input or drag a real file - - console.warn('[WebDrop Bridge DROP] Cannot create DataTransfer with files from JS'); - console.log('[WebDrop Bridge DROP] Will use workaround: modify original DataTransfer'); - - return null; // Cannot create synthetic event with files - - } catch(error) { - console.error('[WebDrop Bridge DROP] Synthetic event creation failed:', error); - return null; - } - } - - function installHooks() { - console.log('[WebDrop Bridge DROP] Installing hooks'); - - // Monitor dragstart - document.addEventListener('dragstart', function(e) { - dragState.altKeyPressed = e.altKey; - dragState.url = null; - dragState.localPath = null; - dragState.isConvertible = false; - dragState.dragElement = e.target; - - console.log('[WebDrop Bridge DROP] dragstart, altKey:', e.altKey); - - // Let it proceed - }, true); - - // Intercept DROP event - document.addEventListener('drop', function(e) { - console.log('[WebDrop Bridge DROP] drop event, isConvertible:', dragState.isConvertible); - - if (!dragState.isConvertible || !dragState.localPath) { - console.log('[WebDrop Bridge DROP] Not convertible or no path, letting through'); - return; // Let normal drop proceed - } - - console.log('[WebDrop Bridge DROP] >>> INTERCEPTING DROP for conversion'); - - // This is the problem: We can't modify the DataTransfer at this point - // And we can't create a new one with files from JavaScript - - // WORKAROUND: Tell Qt to handle the drop natively - e.preventDefault(); // Prevent browser handling - e.stopPropagation(); - - // Get drop coordinates - var dropX = e.clientX; - var dropY = e.clientY; - - console.log('[WebDrop Bridge DROP] Drop at:', dropX, dropY); - - // Tell Qt to perform native file drop at these coordinates - ensureChannel(function() { - if (window.bridge && typeof window.bridge.handle_native_drop === 'function') { - window.bridge.handle_native_drop(dragState.localPath, dropX, dropY); - } - }); - - // THEN manually trigger the web app's drop handler - // This is tricky and app-specific - // For Angular CDK, we might need to trigger cdkDropListDropped - - console.warn('[WebDrop Bridge DROP] Web app popup might not appear - investigating...'); - - return false; - - }, true); // Capture phase - - // Clean up - document.addEventListener('dragend', function(e) { - console.log('[WebDrop Bridge DROP] dragend, cleaning up'); - dragState = { - url: null, - localPath: null, - isConvertible: false, - altKeyPressed: false, - dragElement: null - }; - }, false); - - console.log('[WebDrop Bridge DROP] Hooks installed'); - } - - // Initialize - ensureChannel(function() { - installHooks(); - }); - - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', function() { - if (!window.bridge) ensureChannel(installHooks); - }); - } else if (!window.bridge) { - ensureChannel(installHooks); - } -})(); diff --git a/src/webdrop_bridge/ui/bridge_script_hybrid.js b/src/webdrop_bridge/ui/bridge_script_hybrid.js deleted file mode 100644 index 9727648..0000000 --- a/src/webdrop_bridge/ui/bridge_script_hybrid.js +++ /dev/null @@ -1,109 +0,0 @@ -// WebDrop Bridge - Hybrid Strategy v3 -// Allow web-app drag to proceed normally (for popups) -// BUT notify Qt to start a PARALLEL native file drag -// Windows supports concurrent drag sources - drop target chooses which to use - -(function() { - if (window.__webdrop_bridge_hybrid_injected) return; - window.__webdrop_bridge_hybrid_injected = true; - - console.log('[WebDrop Bridge HYBRID] Script loaded'); - - var dragState = { - url: null, - inProgress: false, - altKeyPressed: false - }; - - // Patch DataTransfer.setData to capture URLs - try { - var originalSetData = DataTransfer.prototype.setData; - - DataTransfer.prototype.setData = function(format, data) { - if ((format === 'text/plain' || format === 'text/uri-list') && dragState.inProgress) { - dragState.url = data; - console.log('[WebDrop Bridge HYBRID] Captured URL:', data.substring(0, 80)); - - // Check if convertible - var isConvertible = /^z:/i.test(data) || - /^https?:\/\/.+\.file\.core\.windows\.net\//i.test(data); - - if (isConvertible && dragState.altKeyPressed) { - console.log('[WebDrop Bridge HYBRID] >>> CONVERTIBLE - Triggering Qt native drag'); - - // Notify Qt to start PARALLEL native drag - ensureChannel(function() { - if (window.bridge && typeof window.bridge.start_parallel_drag === 'function') { - console.log('[WebDrop Bridge HYBRID] Calling start_parallel_drag'); - window.bridge.start_parallel_drag(data); - } else if (window.bridge && typeof window.bridge.start_file_drag === 'function') { - // Fallback to old method - console.log('[WebDrop Bridge HYBRID] Using start_file_drag (fallback)'); - window.bridge.start_file_drag(data); - } - }); - } - } - - // ALWAYS call original - web app functionality must work - return originalSetData.call(this, format, data); - }; - - console.log('[WebDrop Bridge HYBRID] DataTransfer patched'); - } catch(e) { - console.error('[WebDrop Bridge HYBRID] Patch failed:', e); - } - - function ensureChannel(cb) { - if (window.bridge) { cb(); return; } - - if (window.QWebChannel && window.qt && window.qt.webChannelTransport) { - new QWebChannel(window.qt.webChannelTransport, function(channel) { - window.bridge = channel.objects.bridge; - console.log('[WebDrop Bridge HYBRID] QWebChannel connected'); - cb(); - }); - } else { - console.error('[WebDrop Bridge HYBRID] QWebChannel not available'); - } - } - - function installHook() { - console.log('[WebDrop Bridge HYBRID] Installing hooks'); - - // Monitor dragstart - document.addEventListener('dragstart', function(e) { - dragState.inProgress = true; - dragState.altKeyPressed = e.altKey; - dragState.url = null; - - console.log('[WebDrop Bridge HYBRID] dragstart, altKey:', e.altKey); - - // NO preventDefault() - let web app proceed normally! - - }, true); // Capture phase - - // Clean up on dragend - document.addEventListener('dragend', function(e) { - console.log('[WebDrop Bridge HYBRID] dragend'); - dragState.inProgress = false; - dragState.url = null; - dragState.altKeyPressed = false; - }, false); - - console.log('[WebDrop Bridge HYBRID] Installed'); - } - - // Initialize - ensureChannel(function() { - installHook(); - }); - - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', function() { - if (!window.bridge) ensureChannel(installHook); - }); - } else if (!window.bridge) { - ensureChannel(installHook); - } -})(); diff --git a/src/webdrop_bridge/ui/bridge_script_v2.js b/src/webdrop_bridge/ui/bridge_script_v2.js deleted file mode 100644 index 33ceccd..0000000 --- a/src/webdrop_bridge/ui/bridge_script_v2.js +++ /dev/null @@ -1,214 +0,0 @@ -// WebDrop Bridge - Enhanced Script v2 -// Strategy: EXTEND DataTransfer instead of REPLACING the drag -// This allows both file-drop AND web-app functionality (popups) - -(function() { - if (window.__webdrop_bridge_v2_injected) return; - window.__webdrop_bridge_v2_injected = true; - - console.log('[WebDrop Bridge v2] Script loaded - EXTEND strategy'); - - var currentDragUrl = null; - var currentLocalPath = null; - var dragInProgress = false; - - // Patch DataTransfer.setData to capture URLs set by web app - var originalSetData = null; - - try { - if (DataTransfer.prototype.setData) { - originalSetData = DataTransfer.prototype.setData; - - DataTransfer.prototype.setData = function(format, data) { - // Capture text/plain or text/uri-list for our conversion - if ((format === 'text/plain' || format === 'text/uri-list') && dragInProgress) { - currentDragUrl = data; - console.log('[WebDrop Bridge v2] Captured drag URL:', data.substring(0, 80)); - - // Check if this is convertible (Z:\ or Azure) - var isZDrive = /^z:/i.test(data); - var isAzureUrl = /^https?:\/\/.+\.file\.core\.windows\.net\//i.test(data); - - if (isZDrive || isAzureUrl) { - console.log('[WebDrop Bridge v2] >>> CONVERTIBLE URL DETECTED - Will add file data'); - - // Request conversion from Qt backend - if (window.bridge && typeof window.bridge.convert_url_to_path === 'function') { - console.log('[WebDrop Bridge v2] Requesting path conversion...'); - window.bridge.convert_url_to_path(data); - // Note: Conversion happens async, local path will be set via callback - } - } - } - - // ALWAYS call original - don't break web app - return originalSetData.call(this, format, data); - }; - - console.log('[WebDrop Bridge v2] DataTransfer.setData patched'); - } - } catch(e) { - console.error('[WebDrop Bridge v2] Failed to patch DataTransfer:', e); - } - - // Enhanced DataTransfer with file support - // This is called AFTER web app sets its data - function enhanceDataTransfer(e) { - if (!currentLocalPath) { - console.log('[WebDrop Bridge v2] No local path available, cannot enhance'); - return; - } - - console.log('[WebDrop Bridge v2] Enhancing DataTransfer with file:', currentLocalPath); - - try { - var dt = e.dataTransfer; - - // Strategy 1: Add Windows-specific file drop formats - // These are recognized by Windows Explorer and other drop targets - if (originalSetData) { - // Add FileNameW (Unicode file path for Windows) - var fileNameW = currentLocalPath; - - // Try to add custom Windows file drop formats - try { - originalSetData.call(dt, 'application/x-qt-windows-mime;value="FileNameW"', fileNameW); - console.log('[WebDrop Bridge v2] Added FileNameW format'); - } catch (e1) { - console.warn('[WebDrop Bridge v2] FileNameW format failed:', e1); - } - - // Add FileName (ANSI) - try { - originalSetData.call(dt, 'application/x-qt-windows-mime;value="FileName"', fileNameW); - console.log('[WebDrop Bridge v2] Added FileName format'); - } catch (e2) { - console.warn('[WebDrop Bridge v2] FileName format failed:', e2); - } - - // Add FileDrop format - try { - originalSetData.call(dt, 'application/x-qt-windows-mime;value="FileDrop"', fileNameW); - console.log('[WebDrop Bridge v2] Added FileDrop format'); - } catch (e3) { - console.warn('[WebDrop Bridge v2] FileDrop format failed:', e3); - } - } - - // Set effect to allow copy/link - if (dt.effectAllowed === 'uninitialized' || dt.effectAllowed === 'none') { - dt.effectAllowed = 'copyLink'; - console.log('[WebDrop Bridge v2] Set effectAllowed to copyLink'); - } - - } catch (error) { - console.error('[WebDrop Bridge v2] Error enhancing DataTransfer:', error); - } - } - - function ensureChannel(cb) { - if (window.bridge) { cb(); return; } - - function init() { - if (window.QWebChannel && window.qt && window.qt.webChannelTransport) { - new QWebChannel(window.qt.webChannelTransport, function(channel) { - window.bridge = channel.objects.bridge; - console.log('[WebDrop Bridge v2] QWebChannel connected'); - - // Expose callback for Qt to set the converted path - window.setLocalPath = function(path) { - currentLocalPath = path; - console.log('[WebDrop Bridge v2] Local path set from Qt:', path); - }; - - cb(); - }); - } else { - console.error('[WebDrop Bridge v2] QWebChannel not available!'); - } - } - - if (window.QWebChannel) { - init(); - } else { - console.error('[WebDrop Bridge v2] QWebChannel not found!'); - } - } - - function installHook() { - console.log('[WebDrop Bridge v2] Installing drag interceptor (EXTEND mode)'); - - // Use CAPTURE PHASE to intercept early - document.addEventListener('dragstart', function(e) { - try { - dragInProgress = true; - currentDragUrl = null; - currentLocalPath = null; - - console.log('[WebDrop Bridge v2] dragstart on:', e.target.tagName, 'altKey:', e.altKey); - - // Only process ALT-drags (web app's URL drag mode) - if (!e.altKey) { - console.log('[WebDrop Bridge v2] No ALT key, ignoring'); - dragInProgress = false; - return; - } - - console.log('[WebDrop Bridge v2] ALT-drag detected, will monitor for convertible URL'); - - // NOTE: We DON'T call preventDefault() here! - // This allows web app's drag to proceed normally - - // Web app will call setData() which we've patched - // After a short delay, we check if we got a convertible URL - setTimeout(function() { - if (currentDragUrl) { - console.log('[WebDrop Bridge v2] Drag URL set:', currentDragUrl.substring(0, 60)); - // enhanceDataTransfer will be called when we have the path - // For now, we just wait - the drag is already in progress - } - }, 10); - - } catch (error) { - console.error('[WebDrop Bridge v2] Error in dragstart:', error); - dragInProgress = false; - } - }, true); // CAPTURE phase - - // Clean up on dragend - document.addEventListener('dragend', function(e) { - console.log('[WebDrop Bridge v2] dragend, cleaning up state'); - dragInProgress = false; - currentDragUrl = null; - currentLocalPath = null; - }, false); - - // Alternative strategy: Use 'drag' event to continuously update DataTransfer - // This fires many times during the drag - document.addEventListener('drag', function(e) { - if (!dragInProgress || !currentLocalPath) return; - - // Try to enhance on every drag event - enhanceDataTransfer(e); - }, false); - - console.log('[WebDrop Bridge v2] Hooks installed'); - } - - // Initialize - ensureChannel(function() { - console.log('[WebDrop Bridge v2] Channel ready, installing hooks'); - installHook(); - }); - - // Also install on DOM ready as fallback - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', function() { - if (!window.bridge) { - ensureChannel(installHook); - } - }); - } else if (!window.bridge) { - ensureChannel(installHook); - } -})();