2009-10-19 11 views
20

Ich muss eine absolut positionierte Schaltfläche neben dem ausgewählten Text des Benutzers positionieren. genau wie das, was IE8 intern tut.Wie kann ich ein Element neben der Benutzertextauswahl positionieren?

Ich bin ein jQuery mouseup Ereignis an das Dokument binden, und den ausgewählten Text, aber ich bin derzeit aus Ideen, wie man wissen, wo die tatsächliche Auswahl positioniert ist, ohne es in ein Element, weil die Auswahl von Text über mehrere Elemente hinweg möglich ist und die Struktur durcheinander gebracht würde, wenn ich sie umbrechen würde.

+0

die http: //www.nytimes.com tut dies in ihren Artikeln – vsync

Antwort

23

Sie könnten einen Marker Spanne am Ende der Auswahl positionieren, bekommen seine Koordinaten Verwenden Sie jQuery, platzieren Sie Ihre Schaltfläche an diesen Koordinaten und entfernen Sie die Markerspanne.

Folgendes sollten Sie den Einstieg:

var markSelection = (function() { 
    var markerTextChar = "\ufeff"; 
    var markerTextCharEntity = ""; 

    var markerEl, markerId = "sel_" + new Date().getTime() + "_" + Math.random().toString().substr(2); 

    var selectionEl; 

    return function() { 
     var sel, range; 

     if (document.selection && document.selection.createRange) { 
      // Clone the TextRange and collapse 
      range = document.selection.createRange().duplicate(); 
      range.collapse(false); 

      // Create the marker element containing a single invisible character by creating literal HTML and insert it 
      range.pasteHTML('<span id="' + markerId + '" style="position: relative;">' + markerTextCharEntity + '</span>'); 
      markerEl = document.getElementById(markerId); 
     } else if (window.getSelection) { 
      sel = window.getSelection(); 

      if (sel.getRangeAt) { 
       range = sel.getRangeAt(0).cloneRange(); 
      } else { 
       // Older WebKit doesn't have getRangeAt 
       range = document.createRange(); 
       range.setStart(sel.anchorNode, sel.anchorOffset); 
       range.setEnd(sel.focusNode, sel.focusOffset); 

       // Handle the case when the selection was selected backwards (from the end to the start in the 
       // document) 
       if (range.collapsed !== sel.isCollapsed) { 
        range.setStart(sel.focusNode, sel.focusOffset); 
        range.setEnd(sel.anchorNode, sel.anchorOffset); 
       } 
      } 

      range.collapse(false); 

      // Create the marker element containing a single invisible character using DOM methods and insert it 
      markerEl = document.createElement("span"); 
      markerEl.id = markerId; 
      markerEl.appendChild(document.createTextNode(markerTextChar)); 
      range.insertNode(markerEl); 
     } 

     if (markerEl) { 
      // Lazily create element to be placed next to the selection 
      if (!selectionEl) { 
       selectionEl = document.createElement("div"); 
       selectionEl.style.border = "solid darkblue 1px"; 
       selectionEl.style.backgroundColor = "lightgoldenrodyellow"; 
       selectionEl.innerHTML = "&lt;- selection"; 
       selectionEl.style.position = "absolute"; 

       document.body.appendChild(selectionEl); 
      } 

      // Find markerEl position http://www.quirksmode.org/js/findpos.html 
     var obj = markerEl; 
     var left = 0, top = 0; 
     do { 
      left += obj.offsetLeft; 
      top += obj.offsetTop; 
     } while (obj = obj.offsetParent); 

      // Move the button into place. 
      // Substitute your jQuery stuff in here 
      selectionEl.style.left = left + "px"; 
      selectionEl.style.top = top + "px"; 

      markerEl.parentNode.removeChild(markerEl); 
     } 
    }; 
})(); 
+0

Als ich diesen Code ausführte, war die oberste Variable ein Objekt. Wahrscheinlich gab es eine globale Variable namens top. Es ist besser, var left = 0 zu schreiben; var top = 0; anstelle von var left = top = 0; –

+0

@ Z-CORE: Sie haben absolut Recht: 'top' ist ein Verweis auf das äußerste Fenster, das das aktuelle Dokument enthält. Es ist sehr ungewöhnlich für mich, Code von jemand anderem kopiert und eingefügt zu haben (von quirksmode.org in diesem Fall), aber zumindest ist es klar, dass der Fehler ursprünglich nicht mein ist. –

+0

Während es unwahrscheinlich ist, kann es CSS-Regeln geben, die von bestimmten abhängen Elementordnungen wie '#beispiel> span + span'. Das Einfügen des Marker-Bereichs in den Inhalt würde diese Regeln stören, wodurch das Layout möglicherweise verändert wird. Die range.getBoundingClientRect() könnte eine robustere Lösung sein. – Rick

2

Sie sollten wahrscheinlich ein absolutes Positionselement am Ende des Bereichs einfügen. Dies funktioniert in den verschiedenen Browsern anders, so dass Sie am besten schnüffeln können.

Und da Sie gefragt: Das ist, wie die New York Times hat es in ihrer ‚altClickToSearch.js‘ file:

function insertButton() { 

selectionButton = new Element(
     'span', { 
      'className':'nytd_selection_button', 
      'id':'nytd_selection_button', 
      'title':'Lookup Word', 
      'style': 'margin:-20px 0 0 -20px; position:absolute; background:url(http://graphics8.nytimes.com/images/global/word_reference/ref_bubble.png);width:25px;height:29px;cursor:pointer;_background-image: none;filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="http://graphics8.nytimes.com/images/global/word_reference/ref_bubble.png", sizingMethod="image");' 
     } 
    ) 

if (Prototype.Browser.IE) { 
    var tmp = new Element('div'); 
    tmp.appendChild(selectionButton); 
    newRange = selection.duplicate(); 
    newRange.setEndPoint("StartToEnd", selection); 
    newRange.pasteHTML(tmp.innerHTML); 
    selectionButton = $('nytd_selection_button'); 
} 
else { 
    var range = selection.getRangeAt(0); 
    newRange = document.createRange(); 
    newRange.setStart(selection.focusNode, range.endOffset); 
    newRange.insertNode(selectionButton); 
} 
} 
+0

Danke, ja, sie scheinen nur an diesem bestimmten Punkt in der Auswahl statt absolut zum Dokument selbst einzufügen. Vielen Dank! – vsync

+3

Da ist ein unnötiger Browser-Sniff drin. Sie können einfach nach den gewünschten Objekten/Methoden suchen. Auch das Selektionsobjekt in älteren WebKits (Safari 2, vielleicht 3, ich bin da ein bisschen verschwommen und ich habe nicht alle relevanten Browser zur Hand) hat keine 'getRangeAt' Methode. –

+0

Ich schlug den Code oben nicht als die beste Lösung vor, besonders mit dem Browser-Sniff. Er fragte nach den nächsten Malen in seinem Kommentar. Dies ist nur der Code von dieser Site. –

8

Ich benutze getBoundingClientRect(), wenn ich brauche, um den Inhalt ungestört zu bleiben, während zusätzliche Inhalte in der Nähe davon platzieren.

var r=window.getSelection().getRangeAt(0).getBoundingClientRect(); 
    var relative=document.body.parentNode.getBoundingClientRect(); 
    ele.style.top =(r.bottom -relative.top)+'px';//this will place ele below the selection 
    ele.style.right=-(r.right-relative.right)+'px';//this will align the right edges together 

das funktioniert in Chrome, aber IE mag seltsame Dinge zu geben, also hier ist eine Cross-Browser-Lösung: (getestet in Chrome und IE, arbeitet wahrscheinlich an anderer Stelle)

https://jsfiddle.net/joktrpkz/7/

+0

Hallo, kannst du erklären, warum benutzt du cal1/cal2 in deiner Geige? Vielen Dank. –

+0

@Guy Es sollte mit der Art und Weise umgehen, wie der IE Pixel verarbeitet, wenn er herangezoomt wird. Ich erinnere mich nicht, ob es in verschiedenen anderen Szenarien notwendig war oder nicht. – Rick

+0

meine Anforderung ist nur für meine Erweiterung unter Chrom arbeiten, so dass diese Lösung für mich funktioniert großartig. – SKYnine

Verwandte Themen