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:
- Select words above or below the
a
tag - You select only one line either directly above or below the
a
tag - You select more than one line above/below the
a
tag - You select more than one line specifically below any
a
tag
The following scenarios do not work:
- You select the line/more lines above the
a
tag, and then the line/more lines below thea
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.