How can I best do an inline drag range in a paragraph of text?
I have a paragraph of text where the user can place a "contact" to mark a position. Once the contact has been placed, I would like to allow the user to move their position by dragging and dropping them to a new location in the paragraph. This is easy to do with block elements, but I have yet to see a good way to do it with inline elements. How can i do this?
I've already implemented it using window.selection to find the location of the cursor in a paragraph, but it's not as smooth as I would like.
As a side note, I'm using the Rangy library to wrap my own Range and Selection functionality, but it works the same as the native functions.
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 (normally), but the user can see the selected selection. Any ideas on how to move the span without selecting it? I'll also settle for an alternative method that doesn't use selection at all. The goal is to allow the span to move as much as possible.
source to share
You can do this using ranges, instead using code similar to this answer . Unfortunately the code is a little longer than ideal because IE hasn't implemented it yet document.caretPositionFromPoint()
. However, an old rescue object TextRange
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 + '"> </span>');
var span = document.getElementById(spanId);
//place the new pin
span.parentNode.replaceChild(el, span);
}
if (range) {
//place the new pin
range.insertNode(el);
}
source to share