3

I have a paragraph of text in which the user may place a "pin" to mark a position. Once a pin has been placed, I would like to allow the user to move its position by dragging it to a new location in the paragraph. This is simple to do with block elements, but I have yet to see a good way to do it with inline elements. How might I accomplish this?

I have already implemented it using window.selection as a way to find the cursor's location in the paragraph, but it is not as smooth as I would like.

As a note, I am using the Rangy library to wrap the native Range and Selection functionality, but it works the same way as the native functions do.

Here is the code:

$(document).on("mousedown", '.pin', function () {
    //define what a pin is
    var el = document.createElement("span");
    el.className = "pin";
    el.id = "test";
    //make it contain an empty space so we can color it
    el.appendChild(document.createTextNode("d"));
    $(document).on("mousemove", function () {
        //get the current selection
        var selection = rangy.getSelection();
        //collapse the selection to either the front
        //or back, since we do not want the user to see it.
        if (selection.isBackwards()) {
            selection.collapseToStart();
        } else {
            selection.collapseToEnd();
        }
        //remove the old pin
        $('.pin').remove();
        //place the new pin at the current selection
        selection.getAllRanges()[0].insertNode(el);
    });
    //remove the handler when the user has stopped dragging it
    $(document).on("mouseup", function () {
        $(document).off("mousemove");
    });
});

And here is a working demo: http://jsfiddle.net/j1LLmr5b/22/ .

As you can see, it works(usually), but the user can see the selection being made. Have any ideas on how to move the span without showing the selection highlight? I will also accept an alternate method that does not use the selection at all. The goal is to allow movement of the span as cleanly as possible.

3 Answers3

3

You can do this using ranges instead using code similar to this answer. Unfortunately the code is a bit longer than ideal because IE hasn't yet implemented document.caretPositionFromPoint(). However, the old proprietary TextRange object, still present in IE 11, comes to the rescue.

Here's a demo:

http://jsfiddle.net/j1LLmr5b/26/

Here's the relevant code:

var range, textRange, x = e.clientX, y = e.clientY;

//remove the old pin
$('.pin').remove();

// Try the standards-based way first
if (document.caretPositionFromPoint) {
    var pos = document.caretPositionFromPoint(x, y);
    range = document.createRange();
    range.setStart(pos.offsetNode, pos.offset);
    range.collapse();
}
// Next, the WebKit way
else if (document.caretRangeFromPoint) {
    range = document.caretRangeFromPoint(x, y);
}
// Finally, the IE way
else if (document.body.createTextRange) {
    textRange = document.body.createTextRange();
    textRange.moveToPoint(x, y);
    var spanId = "temp_" + ("" + Math.random()).slice(2);
    textRange.pasteHTML('<span id="' + spanId + '">&nbsp;</span>');
    var span = document.getElementById(spanId);
    //place the new pin
    span.parentNode.replaceChild(el, span);
}
if (range) {
    //place the new pin
    range.insertNode(el);
}
Community
  • 1
  • 1
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • This is perfect, thank you so much Tim. I had no idea that all of the caret-associated commands could work like that! This will help a ton. I've been spending a lot of time working with your Rangy library, thanks for all of your work on it. I hope that I'll be able to contribute back sometime. – Nathan Long Aug 13 '14 at 13:37
1

Try this my friend

el.appendChild(document.createTextNode("d"));

You have create empty span tag that's why you found empty.

Jain
  • 1,209
  • 10
  • 16
  • Thanks for the help! The issue is not that the span is empty, the issue is that the blue highlight of the user selection is visible when the user is moving the span. I will update my question to make the problem more clear. Nevertheless, I also made your suggested change and it did make it less likely that the pin would disappear in certain circumstances. Thank you for that! – Nathan Long Aug 12 '14 at 20:10
  • you have to use css to remove this selction or color their are many option in css to do this, but i just give you small idea :moz-selection like that – Jain Aug 12 '14 at 20:37
1

add after el.id = "test";

this

 var value = $('.pin').text();
 $(el).text(value);

You can hide selection with css

 ::selection {color:red;background:yellow;}
 ::-moz-selection {color:red;background:yellow;} 

that's all how i can help for a now

fearis
  • 424
  • 3
  • 15
  • Thank you for your help. About your first suggestion: see my response to Jain above, I was not clear enough in my original question about what the issue was. About using ::selection : I did take a look at this before but I would like to avoid using it as it is only experimental with no plans for inclusion within CSS (see the warning at the top of https://developer.mozilla.org/en-US/docs/Web/CSS/::selection). It's a good suggestion though, if I have nothing else I may resort to that. – Nathan Long Aug 12 '14 at 20:17