VB_
VB_

Reputation: 45702

How to wrap word into span on user click in javascript

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

Answers (4)

Gregory R.
Gregory R.

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

VB_
VB_

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

jAndy
jAndy

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

Jonast92
Jonast92

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

Related Questions