Reputation: 111
I want to be able to double-click to select some text in a div, which then triggers a JavaScript function that inserts some HTML after the selected text, much like the 'edit/reply' feature in Google Wave.
I have already established how to trigger a function on double-clicking, it is locating the selection and subsequently inserting HTML after it that is the problem.
Upvotes: 11
Views: 15509
Reputation: 324567
The following function will insert a DOM node (element or text node) at the end of the selection in all major browsers (note that Firefox now allows multiple selections by default; the following uses only the first selection):
function insertNodeAfterSelection(node) {
var sel, range, html;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.collapse(false);
range.insertNode(node);
}
} else if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
range.collapse(false);
html = (node.nodeType == 3) ? node.data : node.outerHTML;
range.pasteHTML(html);
}
}
If you would rather insert an HTML string:
function insertHtmlAfterSelection(html) {
var sel, range, node;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = window.getSelection().getRangeAt(0);
range.collapse(false);
// Range.createContextualFragment() would be useful here but is
// non-standard and not supported in all browsers (IE9, for one)
var el = document.createElement("div");
el.innerHTML = html;
var frag = document.createDocumentFragment(), node, lastNode;
while ( (node = el.firstChild) ) {
lastNode = frag.appendChild(node);
}
range.insertNode(frag);
}
} else if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
range.collapse(false);
range.pasteHTML(html);
}
}
Update 18 January 2012
Finally, here's a version that inserts HTML and preserves the selection (i.e. expands the selection to include the originally selected content plus the inserted content).
Live demo: http://jsfiddle.net/timdown/JPb75/1/
Code:
function insertHtmlAfterSelection(html) {
var sel, range, expandedSelRange, node;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = window.getSelection().getRangeAt(0);
expandedSelRange = range.cloneRange();
range.collapse(false);
// Range.createContextualFragment() would be useful here but is
// non-standard and not supported in all browsers (IE9, for one)
var el = document.createElement("div");
el.innerHTML = html;
var frag = document.createDocumentFragment(), node, lastNode;
while ( (node = el.firstChild) ) {
lastNode = frag.appendChild(node);
}
range.insertNode(frag);
// Preserve the selection
if (lastNode) {
expandedSelRange.setEndAfter(lastNode);
sel.removeAllRanges();
sel.addRange(expandedSelRange);
}
}
} else if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
expandedSelRange = range.duplicate();
range.collapse(false);
range.pasteHTML(html);
expandedSelRange.setEndPoint("EndToEnd", range);
expandedSelRange.select();
}
}
Upvotes: 18
Reputation: 3084
window.getSelection() will get you the selected text (Documentation). You can use the jQuery.after() (Documentation) to insert new html after an element.
On your selected text function call you will have to loop through all your DOM elements checking their x&y positions to the current cursor position - get the closest element and insert after or use the function .elementFromPoint(x,y) (Documentation)
This is the best way I can currently think of. It's not perfect, but it is somewhere to start.
Upvotes: 1
Reputation: 100321
I don't know if it is possible, but I though of a partial solution.
On your double click event you can get the event object and access the property target
.
Having the target element, you can get the selected text.
Now get the target element html and find the index of the selected text and it's length, inject your html on the index + length
position.
I think you already saw the problem, it could match the text in multiple places. To solve it you might have to find the position of the cursor and compare to the element, I don't know how to do that...
Hope I could help a bit.
Upvotes: 0