2011-12-10 11 views
12

desidero posizionare un div elemento galleggiante in una iframe con contentEditable, nel caso l'utente inserisce una certa combinazione di tasti (per scopi di completamento automatico) .Come ottenere il pixel compensato dalla posizione corrente del cursore in un iframe con contentEditable

so come ottenere la posizione del punto di inserimento: document.getElementById('elm1_ifr').contentWindow.getSelection().anchorOffset

posso usare questo per calcolare la proprietà left del div, ma io non riesco a capire come ottenere il top.

Un'altra possibilità ho pensato stava usando: document.getElementById('elm1_ifr').contentWindow.getSelection().anchorNode.parentNode

E utilizzando jQuery per ottenere l'offset, ma se quel genitore ha una lunga riga di testo, vorrei solo essere in grado di estrarre la prima posizione della prima linea .

Qualcuno può aiutarmi con questo?

risposta

12

L'unico modo affidabile per fare ciò è inserire un elemento temporaneo nel punto di inserimento (assicurandosi che sia larghezza zero), ottenere la sua posizione e rimuoverlo. Dovresti anche incollare le due estremità del nodo di testo (se si trattasse di un nodo di testo che conteneva il cursore) per garantire che il DOM sia come prima di inserire il nodo. Si noti, tuttavia, che questa operazione (o qualsiasi altra manipolazione manuale del DOM sul contenuto modificabile) interrompe lo stack di annullamento interno del browser.

La ragione di ciò è che un'attenta lettura di the spec for the getBoundingClientRect() method of Range mostra che getBoundingClientRect() non è obbligato a restituire un Rect per un intervallo compresso. Concettualmente, non tutte le posizioni nel documento hanno un rettangolo di delimitazione ben definito. Il punto d'accesso, tuttavia, ha una posizione fisica sullo schermo che a mio parere dovrebbe essere fornita dall'API di selezione, ma attualmente non c'è nulla nei browser per fornire questo.

+2

non potevi impostare l'intervallo di essere da 0 alla posizione corrente del cursore, quindi utilizzare 'getBoundingClientRect()' per ottenere gli offset di sinistra + larghezza e top + altezza, quindi ripristinare il cursore alla sua precedente ambientazione? – Mottie

+3

Vecchio thread sì, ma vale la pena che l'inserimento di un elemento [usando 'execCommand ('insertHTML')'] e rimuovendolo rovina lo stack di annullamento/ripetizione. Non importa se annullare/ripristinare è insignificante. – techfoobar

+0

@techfoobar: buon punto, grazie. Ho aggiunto una nota alla risposta. –

7

Sono venuto in questo problema oggi. Dopo alcuni test, ho funzionato, senza usare elementi temorari.

In IE, è facile lavorarlo con offsetLeft e offsetTop proprietà di un oggetto TextRange. Alcuni sforzi sono necessari per il webkit.

Ecco un test, è possibile visualizzare il risultato. http://jsfiddle.net/gliheng/vbucs/12/

var getCaretPixelPos = function ($node, offsetx, offsety){ 
    offsetx = offsetx || 0; 
    offsety = offsety || 0; 

    var nodeLeft = 0, 
     nodeTop = 0; 
    if ($node){ 
     nodeLeft = $node.offsetLeft; 
     nodeTop = $node.offsetTop; 
    } 

    var pos = {left: 0, top: 0}; 

    if (document.selection){ 
     var range = document.selection.createRange(); 
     pos.left = range.offsetLeft + offsetx - nodeLeft + 'px'; 
     pos.top = range.offsetTop + offsety - nodeTop + 'px'; 
    }else if (window.getSelection){ 
     var sel = window.getSelection(); 
     var range = sel.getRangeAt(0).cloneRange(); 
     try{ 
      range.setStart(range.startContainer, range.startOffset-1); 
     }catch(e){} 
     var rect = range.getBoundingClientRect(); 
     if (range.endOffset == 0 || range.toString() === ''){ 
      // first char of line 
      if (range.startContainer == $node){ 
       // empty div 
       if (range.endOffset == 0){ 
        pos.top = '0px'; 
        pos.left = '0px'; 
       }else{ 
        // firefox need this 
        var range2 = range.cloneRange(); 
        range2.setStart(range2.startContainer, 0); 
        var rect2 = range2.getBoundingClientRect(); 
        pos.left = rect2.left + offsetx - nodeLeft + 'px'; 
        pos.top = rect2.top + rect2.height + offsety - nodeTop + 'px'; 
       } 
      }else{ 
       pos.top = range.startContainer.offsetTop+'px'; 
       pos.left = range.startContainer.offsetLeft+'px'; 
      } 
     }else{ 
      pos.left = rect.left + rect.width + offsetx - nodeLeft + 'px'; 
      pos.top = rect.top + offsety - nodeTop + 'px'; 
     } 
    } 
    return pos; 
}; 
+0

Bella risposta amica! –

+0

Il problema con questo, come ho accennato nella mia risposta, è che 'range.getBoundingClientRect()' in Firefox e altri browser a volte restituisce un Rect che contiene tutti gli zeri per un intervallo compresso. Vedi http://jsfiddle.net/CK3e8/ per un esempio. –

+0

È vero, tim. Ho provato a spostare la selezione di un carattere indietro e a elaborare la posizione del cursore da lì. – osamu

Problemi correlati