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
This commit is contained in:
parent
fb710d5b00
commit
ae5c86814f
6 changed files with 0 additions and 1363 deletions
|
|
@ -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
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
@ -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;');
|
|
||||||
})();
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue