7

Update #2

Okay, more testing ensues. It looks like the code works fine when I use a faux spacer, but the regex eventually fails. Specifically, the following scenarios work:

  1. Select words above or below the a tag
  2. You select only one line either directly above or below the a tag
  3. You select more than one line above/below the a tag
  4. You select more than one line specifically below any a tag

The following scenarios do not work:

  1. You select the line/more lines above the a tag, and then the line/more lines below the a tag

What happens when it "doesn't work" is that it removes the a tag spacer from the DOM. This is probably a problem with the regex...

Basically, it fails when you select text around the a tag.


Update:

I don't need to wrap each line in a p tag, I can instead use an inline element, such as an a, span, or label tag, with display:inline-block and a height + width to act as a new line element (<br />). This should make it easier to modify the code, as the only part that should have to change is where I get the text in between the bounds. I should only have to change that part, selectedText.textContent, to retrieve the HTML that is also within the bounds instead of just the text.


I am creating a Phonegap that requires the user to select text. I need fine control over the text selection, however, and can no longer plop the entire text content in a pre styled p tag. Instead, I need represent a linebreak with something like <a class="space"></a>, so that the correct words can be highlighted precisely. When my text looks like this:

<p class="text">This is line one

Line two

Line three
</p>

And has .text{ white-space:pre-wrap }, the following code allows me to select words, then wrap the text with span elements to show that the text is highlighted:

$("p").on("copy", highlight);

function highlight() {
    var text = window.getSelection().toString();
    var selection = window.getSelection().getRangeAt(0);
    var selectedText = selection.extractContents();
    var span = $("<span class='highlight'>" + selectedText.textContent + "</span>");
    selection.insertNode(span[0]);
    if (selectedText.childNodes[1] != undefined) {
        $(selectedText.childNodes[1]).remove();
    }
    var txt = $('.text').html();
    $('.text').html(txt.replace(/<\/span>(?:\s)*<span class="highlight">/g, ''));
    $(".output ul").html("");
    $(".text .highlight").each(function () {
        $(".output ul").append("<li>" + $(this).text() + "</li>");
    });
    clearSelection();
}

function clearSelection() {
    if (document.selection) {
        document.selection.empty();
    } else if (window.getSelection) {
        window.getSelection().removeAllRanges();
    }
}

This code works beautifully, but not when each line is separated by a spacer tag. The new text looks like this:

<p class="text">
    Line one
    <a class="space"></a>
    Line two
    <a class="space"></a>
    Line three
</p>

When I modify the above code to work with have new lines represented by <a class="space"></a>, the code fails. It only retrieves the text of the selection, and not the HTML (selectedText.textContent). I'm not sure if the regex will also fail with an a element acting as a new line either. The a element could be a span or label, or any normally inline positioned element, to trick iOS into allowing me to select letters instead of block elements.

Is there anyway to change the code to preserve the new line elements?

jsFiddle: http://jsfiddle.net/charlescarver/39TZ9/3/

The desired output should look like this:

If the text "Line one" was highlighted:

<p class="text">
    <span class="highlight">Line one</span>
    <a class="space"></a>
    Line two
    <a class="space"></a>
    Line three
</p>

If the text "Line one Line two" was highlighted:

<p class="text">
    <span class="highlight">Line one
    <a class="space"></a>
    Line two</span>
    <a class="space"></a>
    Line three
</p>

Of course different parts and individual letters can and will be highlighted as well instead of full lines.

4

2 に答える 2

-1

まあ、私は解決策を思いつきましたかなり簡単です。

次のようになっている場合.text:

<p class="text">Line one
<a class="space"></a>Line two
<a class="space"></a>Line three</p>

上記の正確なマークアップと改行を使用すると、それぞれを見つけ\nてスペーサー要素に置き換えることができます。

if (textStr.indexOf("\n") >= 0) {
    textStr = textStr.replace(/\n/g, "\n<a class='space'></a>");
}

これはまったく用途が広くなく、改行が複数ある場合やタグが異なる場合などに失敗します。そんなに難しいことではありません、私はそれを理解しました。

于 2013-04-03T05:57:48.687 に答える