Reputation: 45702
I have: Simple block of html text:
<p>
The future of manned space exploration and development of space depends critically on the
creation of a dramatically more proficient propulsion architecture for in-space transportation.
A very persuasive reason for investigating the applicability of nuclear power in rockets is the
vast energy density gain of nuclear fuel when compared to chemical combustion energy...
</p>
I want: wrap word into span when user click on it.
I.e. User clicked at manned word, than I should get
<p>
The future of <span class="touched">manned</span> space exploration and development of space depends critically on the
creation of a ....
Question: How to do that? Is there way more efficient that just wrap all words into span at loading stage?
P.S. I'm not interested in window.getSelection()
because I want to imply some specific styling for touched words and also keep collection of touched words
Special for @DavidThomas: example where I get selected text, but do not know how to wrap it into span.
Upvotes: 3
Views: 991
Reputation: 1945
use
range.surroundContents(node)
$('.your-div').unbind("dblclick").dblclick(function(e) {
e.preventDefault();
// unwrap .touched spans for each dblclick.
$(this).find('.touched').contents().unwrap();
var t = getWord();
if (t.startContainer.nodeName == '#text' && t.endContainer.nodeName == '#text') {
var newNode = document.createElement("span");
newNode.setAttribute('class', 'touched');
t.surroundContents(newNode);
}
e.stopPropagation();
});
function getWord() {
var txt = document.getSelection();
var txtRange = txt.getRangeAt(0);
return txtRange;
}
Upvotes: 0
Reputation: 45702
Your answers inspired me to the next solution:
$(document).ready(function()
{
var p = $('p');
p.css({ cursor: 'pointer' });
p.dblclick(function(e) {
debugger;
var html = p.html();
var range = window.getSelection() || document.getSelection() || document.selection.createRange();
var startPos = range.focusOffset; //Prob: isn't precise +- few symbols
var selectedWord = $.trim(range.toString());
var newHtml = html.substring(0, startPos) + '<span class=\"touched\">' + selectedWord + '</span>' + html.substring(startPos + selectedWord.length);
p.html(newHtml);
range.collapse(p);
e.stopPropagation();
});
});
We haven't there wrap each word in span
. Instead we wrap word only on click.
Upvotes: 0
Reputation: 236082
I were you, I'd wrap all words with <span>
tags beforehand and just change the class
on click. This might look like
$( 'p' ).html(function( _, html ) {
return html.split( /\s+/ ).reduce(function( c, n ) {
return c + '<span>' + n + ' </span>'
});
});
and then we could have a global handler, which listens for click events
on <span>
nodes
$( document.body ).on('click', 'span', function( event ) {
$( event.target ).addClass( 'touch' );
});
Example: http://jsfiddle.net/z54kehzp/
I modified @Jonast92 solution slightly, I like his approach also. It might even be better for huge data amounts. Only caveat there, you have to live with a doubleclick to select a word.
Example: http://jsfiddle.net/5D4d3/106/
Upvotes: 6
Reputation: 4967
I modified a previous answer to almost get what you're looking for, as demonstrated in this demo.
It finds the currently clicked word and wraps a span with that specific class around the string and replaced the content of the paragraph with a new content which's previously clicked word is replaced with the newly wrapped string.
It's limited a bit though because if you click on a substring of another word, let's say 'is' then it will attempt to replace the first instance of that string within the paragraph.
You can probably play around with it to achieve what you're looking for, but the main thing is to look around.
The modified code:
$(document).ready(function()
{
var p = $('p');
p.css({ cursor: 'pointer' });
p.dblclick(function(e) {
var org = p.html();
var range = window.getSelection() || document.getSelection() || document.selection.createRange();
var word = $.trim(range.toString());
if(word != '')
{
var newWord = "<span class='touched'>"+word+"</span>";
var replaced = org.replace(word, newWord);
$('p').html(replaced);
}
range.collapse();
e.stopPropagation();
});
});
Then again, @jAndy's answer looks very promising.
Upvotes: 2