NullVoxPopuli
NullVoxPopuli

Reputation: 65143

Javascript: How do I expand a user selection based on html tags?

Le Code: http://jsfiddle.net/frf7w/12/

So right now, the current method will take the selected text exactly as... selected, and add tags so that when it is displayed, the page doesn't blow up.

But what I want to do: Is to, when a user selects a portion of a page, if there are un-matched tags within the selection, the selection will either jump forward or backward (depending on what unmatched tag is in the selection) to the tag(s) that make the selection valid html.

The reason why I want to do this, is because I want a user to be able te select text on a page, and be able to edit that text in a WYSIWYG editor (I can currently do this with the linked code), and then put what they've edited back into the page (currently can't do this, because the method I use adds tags).

Upvotes: 5

Views: 1637

Answers (3)

Narendra Yadala
Narendra Yadala

Reputation: 9664

The coverAll method in this SO answer has exactly what you want Use javascript to extend a DOM Range to cover partially selected nodes. For some reason extending Selection prototype does not work for me on my chrome, so I extracted the code and substituted this with window.getSelection(). Final code looks like this:

function coverAll() {
    var ranges = [];
    for(var i=0; i<window.getSelection().rangeCount; i++) {
        var range = window.getSelection().getRangeAt(i);
        while(range.startContainer.nodeType == 3
              || range.startContainer.childNodes.length == 1)
            range.setStartBefore(range.startContainer);
        while(range.endContainer.nodeType == 3
              || range.endContainer.childNodes.length == 1)
            range.setEndAfter(range.endContainer);
        ranges.push(range);
    }
    window.getSelection().removeAllRanges();
    for(var i=0; i<ranges.length; i++) {
        window.getSelection().addRange(ranges[i]);
    }
    return;
}

Upvotes: 3

Deebster
Deebster

Reputation: 2839

You can change the boundaries of the selection by adding a range:

var sel = window.getSelection(),
    range = sel.getRangeAt(0);

var startEl = sel.anchorNode;
if (startEl != range.commonAncestorContainer) {
    while (startEl.parentNode != range.commonAncestorContainer) {
        startEl = startEl.parentNode;
    }
}
var endEl = sel.focusNode;
if (endEl != range.commonAncestorContainer) {
    while (endEl.parentNode != range.commonAncestorContainer) {
        endEl = endEl.parentNode;
    }
}

range.setStartBefore(startEl);
range.setEndAfter(endEl);

sel.addRange(range);

The above example will give you a selection that is expanded to cover the entire of the tree between the start and end nodes, inclusive (thanks to commonAncestorContainer()).

This treats text nodes as equal to dom elements, but this shouldn't be a problem for you.

Demo: http://jsfiddle.net/Nq6hr/2/

Upvotes: 2

bobylito
bobylito

Reputation: 3392

You should work with the nodes given by the selection. It seems extentNode and anchorNode represents the end and the beginning of nodes of the selection both can help you having the "full" selection. https://developer.mozilla.org/fr/DOM/Selection

For the inline editing you should give a try to contentEditable attribute. You can surround the elements of your selection with a span containing this attribute https://developer.mozilla.org/en/DOM/element.contentEditable

Upvotes: 0

Related Questions