0

I am writing a document editor using JQuery, and have implemented basic formatting: select text, click a button and the text is surrounded in the appropriate tag.

To improve this, I now need to examine the text before and after the selection, to see whether a tag has already been opened etc. Is there any simple way of checking whether the selection is a part of a larger node?

For example, if I was to select "jumps" in the following text and click, the correct behaviour would be to de-<strong> it, as it is already in a <strong> node.

The <strong>quick brown fox jumps over the lazy dog</strong>.
tsvallender
  • 2,615
  • 6
  • 32
  • 42

3 Answers3

1

Wrap it in a temporary tag to make it a selectable DOM element

The <strong>quick brown fox <tmp>jumps</tmp> over the lazy dog</strong>.

Then call parent of the temporary tag and compare it to the tag being applied.

var $tmp = $('tmp');
var enclosingTagType = $tmp.parent()[0].tagName;
if (enclosingTagType == requestedTagType {
  ....profit...
}

or even

$tmp.closest(requestedTagType)

To see if its wrapped at all...

Kyle Macey
  • 8,074
  • 2
  • 38
  • 78
0

here , try this :

http://jsbin.com/asajuk/7/edit

var getSelectedNode = function ()
    {
        var node, selection;
        if (window.getSelection)
        {
            selection = getSelection();
            node = selection.anchorNode;
        }
        if (!node && document.selection)
        {
            selection = document.selection
            var range = selection.getRangeAt ? selection.getRangeAt(0) : selection.createRange();
            node = range.commonAncestorContainer ? range.commonAncestorContainer : range.parentElement ? range.parentElement() : range.item(0);
        }
        if (node)
        {
            return (node.nodeName == "#text" ? node.parentNode : node);
        }
    };
Royi Namir
  • 144,742
  • 138
  • 468
  • 792
0

To improve this, I now need to examine the text before and after the selection, to see whether a tag has already been opened etc. Is there any simple way of checking whether the selection is a part of a larger node?

(Tags are opened [in HTML, with <], but what you really mean is whether an element has been started. The difference is crucial for you to understand what you are doing here.)

Because a node in the document is part of the document tree, and a text node can be at most the child node of one non-text node, every text selection is "part of a larger node". However, whether you can find out what that node is, and whether it is easy to do depends both on your abilities and on the browser, as it depends on the DOM implementation used by the layout engine of the browser.

For example, in Gecko-based browsers such as Firefox and in WebCore-based browsers such as Chrome/Google Chrome, you could execute

var selection = window.getSelection();

on select. In selection you would then have a reference to an object implementing the Selection (Gecko) or DOMSelection (WebCore) interface, that has properties such as anchorNode that refer to an object implementing the Text interface (see the Gecko DOM Reference at MDN for that).

That object, which represents the text node that the start of the selection is part of, has a parentNode property which gets you the element node object, and through its tagName or nodeName property, the element type name:

var textParent = selection.anchorNode.parentNode;
var textParentType = textParent.nodeName;

The value of textParent.parentNode can then be used to traverse one more level up the document tree aso.

Extra care must be taken when the anchorNode and focusNode properties refer to different text node objects, for then the selection usually spans not only several text nodes but several elements. That is, in a table the user could have easily selected the text "foobar" as in <td>foo</td><td>bar</td>.

With runtime feature tests and exception handling you can determine which interface is supported without resorting to error-prone browser sniffing.

For example, if I was to select "jumps" in the following text and click, the correct behaviour would be to de-strong it, as it is already in a strong node.

You might want to reconsider that. Perhaps you just picked a bad example, but there can be value in a strong element within a strong element; the inner element's CSS properties are not necessarily redundant. Another example is emphasizing text already in an em element for which the user might want to use the strong element then.

Avoid jQuery; you do not need it and on closer inspection you would not even want it.

PointedEars
  • 14,752
  • 4
  • 34
  • 33
  • `anchorNode` and `focusNode` are not guaranteed to refer to text nodes, and for some selections in some browsers, they don't. – Tim Down Apr 09 '12 at 15:39
  • @TimDown Please be more specific so that I can perhaps update my answer. – PointedEars Apr 09 '12 at 21:02
  • OK. Open the following example in Firefox 11 and triple click the text: http://jsfiddle.net/timdown/8hs45/. This is not an isolated example. As far as I know, `anchorNode` and `focusNode` are in practice limited to being elements or text nodes, although I wouldn't rule out a browser reporting them in other node types if a range with boundaries in other node types was selected. – Tim Down Apr 09 '12 at 23:19