webdrop-bridge/docs/ANGULAR_CDK_ANALYSIS.md
claudi dee02ad600 Add drag & drop script variants and enhanced debugging tools
- 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.
2026-02-17 19:19:14 +01:00

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, dragend Events
  • Kein event.dataTransfer API 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-Zonen
  • cdkdroplist - 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:

  1. Interception von nativen Drag-Events
  2. Manipulation von event.dataTransfer.effectAllowed und .dropEffect
  3. 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:

  1. Saubere Architektur mit klarer Trennung
  2. Typsicher durch Qt Signals/Slots
  3. Kann Asset-IDs und -Namen zuverlässig extrahieren
  4. Funktioniert auch wenn Angular CDK interne Änderungen hat
  5. Ermöglicht bidirektionale Kommunikation

Implementierungsschritte:

Phase 1: Asset-Informationen extrahieren

  1. JavaScript via QWebEngineScript injizieren
  2. Qt WebChannel setuppen
  3. Angular CDK Events überwachen (ohne Monkey-Patching als Test)
  4. Asset-IDs und Namen an Qt senden

Phase 2: Native Drag initiieren

  1. Bei CDK Drag-Start: Extrahiere Asset-Informationen
  2. Sende Asset-ID an Backend/API
  3. Erhalte lokalen Dateipfad oder Azure Blob URL
  4. Konvertiere zu lokalem Pfad (wie aktuell)
  5. Initiiere nativen Drag mit QDrag

Phase 3: Drag-Feedback

  1. Zeige Drag-Preview in Qt (optional)
  2. Update Cursor während Drag
  3. 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

  1. Proof of Concept: Qt WebChannel mit einfachem Event-Logger
  2. Asset-ID Extraction: JavaScript Injection testen
  3. API Research: GlobalDAM API untersuchen (Asset-Metadaten)
  4. Integration: Mit bestehendem URLConverter verbinden
  5. 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