- Introduced multiple JavaScript scripts for handling drag & drop functionality: - `bridge_script.js`: Original implementation with popup prevention. - `bridge_script_debug.js`: Debug version with extensive logging for troubleshooting. - `bridge_script_v2.js`: Enhanced version extending DataTransfer for better integration. - `bridge_script_hybrid.js`: Hybrid approach allowing parallel native file drag. - `bridge_script_drop_intercept.js`: Intercepts drop events for custom handling. - `bridge_script_intercept.js`: Prevents browser drag for ALT+drag, using Qt for file drag. - Added detailed documentation in `SCRIPT_VARIANTS.md` outlining usage, status, and recommended workflows for each script. - Implemented logging features to capture drag events, DataTransfer modifications, and network requests for better debugging. - Enhanced DataTransfer handling to support Windows-specific file formats and improve user experience during drag & drop operations.
7.8 KiB
7.8 KiB
Angular CDK Drag & Drop Analysis - GlobalDAM
Framework Detection
Web Application: Agravity GlobalDAM
Framework: Angular 19.2.14
Drag & Drop: Angular CDK (Component Dev Kit)
Styling: TailwindCSS
Technical Findings
1. Angular CDK Implementation
<!-- Drag Group (oberste Ebene) -->
<div cdkdroplistgroup="" aydnd="" class="flex h-full flex-col">
<!-- Drop Zone (Collections) -->
<div cdkdroplist="" class="cdk-drop-list" id="collectioncsuaaDVNokl0...">
<!-- Draggable Element (Asset Card) -->
<li cdkdrag="" class="cdk-drag asset-list-item" draggable="false">
<img src="./GlobalDAM JRI_files/anPGZszKzgKaSz1SIx2HFgduy"
alt="weiss_ORIGINAL">
</li>
</div>
</div>
2. Key Observations
Native HTML5 Drag ist DEAKTIVIERT
draggable="false"
Bedeutung:
- Kein Zugriff auf native
dragstart,drag,dragendEvents - Kein
event.dataTransferAPI verfügbar - Angular CDK simuliert Drag & Drop komplett in JavaScript
- Daten werden NICHT über natives Clipboard/DataTransfer übertragen
Angular CDK Direktiven
cdkdroplistgroup- Gruppiert mehrere Drop-Zonencdkdroplist- Markiert Drop-Bereiche (Collections, Clipboard)cdkdrag- Markiert draggbare Elemente (Assets)cdkdroplistsortingdisabled- Sortierung deaktiviert
Asset Identifikation
<!-- Asset ID im Element-ID -->
<div id="anPGZszKzgKaSz1SIx2HFgduy">
<!-- Asset ID in der Bild-URL -->
<img src="./GlobalDAM JRI_files/anPGZszKzgKaSz1SIx2HFgduy">
<!-- Asset Name im alt-Attribut -->
<img alt="weiss_ORIGINAL">
Impact on WebDrop Bridge
❌ Bisheriger Ansatz funktioniert NICHT
Unser aktueller Ansatz basiert auf:
- Interception von nativen Drag-Events
- Manipulation von
event.dataTransfer.effectAllowedund.dropEffect - Setzen von URLs im DataTransfer
Das funktioniert NICHT mit Angular CDK, da:
- Angular CDK das native Drag & Drop komplett umgeht
- Keine nativen Events gefeuert werden
- DataTransfer API nicht verwendet wird
✅ Mögliche Lösungsansätze
Ansatz 1: JavaScript Injection zur Laufzeit
Injiziere JavaScript-Code, der Angular CDK Events abfängt:
// Überwache Angular CDK Event-Handler
document.addEventListener('cdkDragStarted', (event) => {
const assetId = event.source.element.nativeElement.id;
const assetName = event.source.element.nativeElement.querySelector('img')?.alt;
// Sende an Qt WebChannel
bridge.handleDragStart(assetId, assetName);
});
document.addEventListener('cdkDragDropped', (event) => {
// Verhindere das Standard-Verhalten
event.preventDefault();
// Starte nativen Drag von Qt aus
bridge.initNativeDrag();
});
Vorteile:
- ✅ Direkter Zugriff auf Angular CDK Events
- ✅ Kann Asset-Informationen extrahieren
- ✅ Kann Drag-Operationen abfangen
Nachteile:
- ⚠️ Erfordert genaue Kenntnis der Angular CDK Internals
- ⚠️ Könnte bei Angular CDK Updates brechen
- ⚠️ Komplexer zu implementieren
Ansatz 2: DOM Mutation Observer
Überwache DOM-Änderungen während des Drags:
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
// Suche nach CDK Drag-Elementen mit bestimmten Klassen
const dragElement = document.querySelector('.cdk-drag-preview');
if (dragElement) {
const assetId = dragElement.querySelector('[id^="a"]')?.id;
bridge.handleDrag(assetId);
}
});
});
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['class']
});
Vorteile:
- ✅ Robuster gegenüber Framework-Updates
- ✅ Funktioniert mit beliebigen Frameworks
Nachteile:
- ⚠️ Performance-Overhead
- ⚠️ Kann falsche Positive erzeugen
Ansatz 3: Qt WebChannel Bridge mit Custom Events
Nutze Qt WebChannel, um mit der Angular-Anwendung zu kommunizieren:
# Python-Seite (Qt)
class DragBridge(QObject):
@Slot(str, str)
def onAssetDragStart(self, asset_id: str, asset_name: str):
"""Called from JavaScript when Angular CDK drag starts."""
logger.info(f"Asset drag started: {asset_id} ({asset_name})")
self.convert_and_drag(asset_id, asset_name)
// JavaScript-Seite (injiziert via QWebEngineScript)
new QWebChannel(qt.webChannelTransport, (channel) => {
const dragBridge = channel.objects.dragBridge;
// Monkey-patch Angular CDK's DragRef
const originalStartDraggingSequence = CdkDrag.prototype._startDraggingSequence;
CdkDrag.prototype._startDraggingSequence = function(event) {
const assetElement = this.element.nativeElement;
const assetId = assetElement.id;
const assetName = assetElement.querySelector('img')?.alt;
// Benachrichtige Qt
dragBridge.onAssetDragStart(assetId, assetName);
// Rufe original Angular CDK Methode auf
return originalStartDraggingSequence.call(this, event);
};
});
Vorteile:
- ✅ Saubere Kommunikation zwischen Qt und Web
- ✅ Kann Asset-Informationen zuverlässig extrahieren
- ✅ Typensicher (Qt Signals/Slots)
Nachteile:
- ⚠️ Erfordert Monkey-Patching von Angular CDK
- ⚠️ Kann bei CDK Updates brechen
Ansatz 4: Browser DevTools Protocol (Chrome DevTools)
Nutze Chrome DevTools Protocol für tiefere Integration:
from PySide6.QtWebEngineCore import QWebEngineProfile
profile = QWebEngineProfile.defaultProfile()
profile.setRequestInterceptor(...)
# Intercepte Netzwerk-Requests und injiziere Header
# Überwache JavaScript-Execution via CDP
Vorteile:
- ✅ Sehr mächtig, kann JavaScript-Execution überwachen
- ✅ Kann Events auf niedrigerer Ebene abfangen
Nachteile:
- ⚠️ Sehr komplex
- ⚠️ Erfordert Chrome DevTools Protocol Kenntnisse
- ⚠️ Performance-Overhead
Empfohlener Ansatz
Ansatz 3: Qt WebChannel Bridge (BEVORZUGT)
Begründung:
- ✅ Saubere Architektur mit klarer Trennung
- ✅ Typsicher durch Qt Signals/Slots
- ✅ Kann Asset-IDs und -Namen zuverlässig extrahieren
- ✅ Funktioniert auch wenn Angular CDK interne Änderungen hat
- ✅ Ermöglicht bidirektionale Kommunikation
Implementierungsschritte:
Phase 1: Asset-Informationen extrahieren
- JavaScript via QWebEngineScript injizieren
- Qt WebChannel setuppen
- Angular CDK Events überwachen (ohne Monkey-Patching als Test)
- Asset-IDs und Namen an Qt senden
Phase 2: Native Drag initiieren
- Bei CDK Drag-Start: Extrahiere Asset-Informationen
- Sende Asset-ID an Backend/API
- Erhalte lokalen Dateipfad oder Azure Blob URL
- Konvertiere zu lokalem Pfad (wie aktuell)
- Initiiere nativen Drag mit QDrag
Phase 3: Drag-Feedback
- Zeige Drag-Preview in Qt (optional)
- Update Cursor während Drag
- Cleanup nach Drag-Ende
Asset-ID zu Dateipfad Mapping
Die Anwendung verwendet Asset-IDs in mehreren Formaten:
// Asset-ID: anPGZszKzgKaSz1SIx2HFgduy
// Mögliche URL-Konstruktion:
const assetUrl = `https://dev.agravity.io/api/assets/${assetId}`;
const downloadUrl = `https://dev.agravity.io/api/assets/${assetId}/download`;
const blobUrl = `https://static.agravity.io/${workspaceId}/${assetId}/${filename}`;
Für WebDrop Bridge:
- Asset-ID aus DOM extrahieren
- Asset-Metadaten via API abrufen (falls verfügbar)
- Blob-URL konstruieren
- URL Converter nutzen (bereits implementiert!)
Next Steps
- Proof of Concept: Qt WebChannel mit einfachem Event-Logger
- Asset-ID Extraction: JavaScript Injection testen
- API Research: GlobalDAM API untersuchen (Asset-Metadaten)
- Integration: Mit bestehendem URLConverter verbinden
- Testing: Mit echten Assets testen
Hinweise
- Angular CDK Version kann sich unterscheiden - Code muss robust sein
- Asset-IDs scheinen eindeutig zu sein (Base64-ähnlich)
- Die Anwendung nutzt Azure Blob Storage (basierend auf bisherigen URLs)
- Custom Components (
ay-*) deuten auf eine eigene Component Library hin