4

How to show a little image after selecting some text when we using the window.getSelection() code?

The most similar thing I found was this How can I position an element next to user text selection? but cant seem to get it to work properly :-s Being kinda new to this also doesn't help.

Just need some simple code to do it, doesn't matter much where the image shows up, aslong as its near the selected text

-edit-

As I said in comment, the idea is to show a button (thought of image first but a button is better) floating near the selected text (after the selection is made), with link to quote what was selected, and if we clear what was selected the button doesn't show anymore.

And would this be possible by pulling mouse coords when finishing text selection and adding the x,y coords to the style of the button to be shown?

-edit-

got it working just like I wanted, having that coords idea in mind. Found this http://motyar.blogspot.pt/2010/02/get-user-selected-text-with-jquery-and.html and with it I came up with this:

function getSelected() {
if (window.getSelection) {
    return window.getSelection();
}
else if (document.getSelection) {
    return document.getSelection();
}
else {
    var selection = document.selection && document.selection.createRange();
    if (selection.text) {
        return selection.text;
    }
    return false;
}
return false;
}

$(document).ready(function() {
var blank = '',
    selectionImage;
$('#mensagem').mouseup(function(e) {
    var selection = getSelected();

    if (!selectionImage) {
        selectionImage = $('<button>').attr({
            type: 'button',
            title: 'Citar Texto seleccionado',
            id: 'quote-place'

        }).html("Citar").css({
            "color": "red"
        }).hide();

        $(document.body).append(selectionImage);

    }
    $("#quote-place").click(function quote() {
        var txt = '';
        if (window.getSelection) {
            txt = window.getSelection();
        }
        else if (document.getSelection) {
            txt = document.getSelection();
        }
        else if (document.selection) {
            txt = document.selection.createRange().text;
        }
        else {
            return;
        }
        document.aform.selectedtext.value = txt;

    }).mousedown(function() {

        if (selectionImage) {
            selectionImage.fadeOut();
        }
    });

    selectionImage.css({
        top: e.pageY - 30,
        //offsets
        left: e.pageX - 13 //offsets
    }).fadeIn();
});
});​

http://jsfiddle.net/ordhor/2Gc8c/

The problem now lies on when we click on the <div> without selecting text the button keeps showing. It should only appear when selecting text and I cant find how to fix it...

Community
  • 1
  • 1
ordhor
  • 41
  • 1
  • 3

2 Answers2

2

Let's suppose that image is the image element you want to insert. The idea is to place a place-holder <span> element after the selected text, since we can't compute the position of text nodes. So, we start with this CSS:

.place-holder {position: relative;}
.quote-image {
    position: absolute;
    top: 0;
    left: 0;
}

The place-holder class is for our <span> element, and the position property for the image we want to put in, which is absolutely positioned in order to keep a zero-width <span>.

Now we want to check whether a selection is made or not. Unfortunately, there's no standard event raised when a selection is made. The onselect event is fired only if a selection is made in text fields, and not even when the selection is canceled.

But since the selection is usually made using mouse and keyboard events, we can listen to them and check if a selection is made.

var prevRng;
function checkSelection() {
    var s = getSelection(), r = s.rangeCount && s.getRangeAt(0);
    if (prevRng) {
        if (!r || r.endContainer !== prevRng.endContainer
                || r.endOffset !== prevRng.endOffset) {
            // The selection has changed or been cleared
            selectionClear();
        }
    }
    if (r) setPlaceHolder(r);
}
document.addEventListener("mouseup", checkSelection);
// mousedown usually clears the selection
document.addEventListener("mousedown", checkSelection);
// You can use the keyboard to extend the selection, or select all (Ctrl+A)
document.addEventListener("keyup", checkSelection);

prevRng is a variable in the function scope to store the selection made. Now we can make our working code:

function setPlaceHolder(range) {
    if (range.startContainer === range.endContainer
            && range.startOffset === range.endOffset) {
        // The selection is clear
        prevRng = null;
        return;
    }
    prevRng = range;
    var endc = range.endContainer, span = document.createElement("span");
    span.className = "place-holder";
    span.appendChild(image);
    if (endc.nodeType === Node.TEXT_NODE) { // Node.TEXT_NODE === 3
        var p1 = endc.nodeValue.substring(0, range.endOffset),
            p2 = endc.nodeValue.substring(range.endOffset);
        endc.nodeValue = p1;
        if (p2)
            endc.parentNode.insertBefore(document.createTextNode(p2),
                    endc.nextSibling);
    }
    endc.parentNode.insertBefore(image, endc.nextSibling);
}

function selectionClear() {
    if (!prevRng) return;
    var endc = prevRng.endContainer;
    if (endc.nextSibling.className === "place-holder") {
        endc.parentNode.removeChild(endc.nextSibling);
        if (endc.nodeType === Node.TEXT_NODE
                && endc.nextSibling.nodeType === Node.TEXT_NODE) {
            // Joining previously divided text nodes
            endc.nodeValue += endc.nextSibling.nodeValue;
            endc.parentNode.removeChild(endc.nextSibling);
        }
    }
}

Edit: it seems I've misunderstood your question. I thought you wanted to insert the image after the selection... So, you want to know when the selection is actually made?

Edit 2: changed more or less everything to match the request.

MaxArt
  • 22,200
  • 10
  • 82
  • 81
  • the idea is to show a image floating near the selected text (after the selection is made), with link to quote what was selected, and if we clear what was selected the image doesn't show anymore – ordhor May 28 '12 at 04:25
  • @ordhor Here you go, tell me if this answers your question. It hasn't been tested yet, though. I'll make a jsfiddle later. – MaxArt May 28 '12 at 07:37
  • Your code seems to be what I need but I cant get it to work... [link](http://jsfiddle.net/ordhor/Jbxsm/) tried to work the code but cant see whats wrong... seems to be something in the `function setPlaceHolder` – ordhor May 29 '12 at 02:09
  • also, something that I thought that could replace this would be pulling mouse coords when finishing text selection and adding the x,y coords to the style of the element to be shown, and swapping to hidden when not selecting text. Getting mouse coords is easy but couldn't find if rest is possible tho – ordhor May 29 '12 at 02:44
0

For example:

$("div.rte").on("mouseup",function(){ // event binding on the div 
if(window.getSelection().toString().length>0) //check length if >0 then only proceed
{
 // do processing 
}

this should resolve your problem from my understanding of the problem

I have been trying to implement similar functionality , my problem is that the document can be edited as well. The way of saving the annotation is a challenge, currently Im thinking to save the start and end index of the annotion in the db, when document content changes , using mutation observers , I will calculate the new char count of the annotation and then save again in db

Please let me know are there any other ways of storing and retrieving from db

shab
  • 1
  • 3