Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to know if there is a link element within the selection

In Javascript, I'd like determine whether an element, say an A element, exists inside a given range/textRange. The aim is to determine if the user's current selection contains a link. I am building a rich text editor control.

The range object has a commonAncestorContainer (W3C) or parentElement() (Microsoft) method which returns the closest common anscestor of all elements in the range. However, looking inside this element for A elements won't work, since this common ancestor may also contain elements that aren't in the range, since the range can start or end part way through a parent.

How would you achieve this?

like image 230
thomasrutter Avatar asked Dec 28 '22 20:12

thomasrutter


2 Answers

How about selection.containsNode? https://developer.mozilla.org/en/DOM/Selection/containsNode

something like:

var selection = window.getSelection();
var range = selection.getRangeAt(0);
var result = $('a', range.commonAncestorContainer).filter(function() {
  return selection.containsNode(this);
});
console.log(result);
like image 173
sharp johnny Avatar answered Dec 31 '22 13:12

sharp johnny


I ended up going with a solution like this:

        var findinselection = function(tagname, container) {
            var
                i, len, el,
                rng = getrange(),
                comprng,
                selparent;
            if (rng) {
                selparent = rng.commonAncestorContainer || rng.parentElement();
                // Look for an element *around* the selected range
                for (el = selparent; el !== container; el = el.parentNode) {
                    if (el.tagName && el.tagName.toLowerCase() === tagname) {
                        return el;
                    }
                }
                // Look for an element *within* the selected range
                if (!rng.collapsed && (rng.text === undefined || rng.text) &&
                    selparent.getElementsByTagName) {
                    el = selparent.getElementsByTagName(tagname);
                    comprng = document.createRange ?
                        document.createRange() : document.body.createTextRange();
                    for (i = 0, len = el.length; i < len; i++) {

                        // determine if element el[i] is within the range
                        if (document.createRange) { // w3c
                            comprng.selectNodeContents(el[i]);
                            if (rng.compareBoundaryPoints(Range.END_TO_START, comprng) < 0 &&
                                rng.compareBoundaryPoints(Range.START_TO_END, comprng) > 0) {
                                return el[i];
                            }
                        }
                        else { // microsoft
                            comprng.moveToElementText(el[i]);
                            if (rng.compareEndPoints("StartToEnd", comprng) < 0 &&
                                rng.compareEndPoints("EndToStart", comprng) > 0) {
                                return el[i];
                            }
                        }
                    }
                }
            }
        };

Where getrange() is another function of mine to get the current selection as a range object.

To use, call it like

var link = findselection('a', editor);

Where editor is the contenteditable element, or body in a designmode iframe.

like image 38
thomasrutter Avatar answered Dec 31 '22 13:12

thomasrutter