Как узнать, есть ли элемент ссылки в выделении - PullRequest
4 голосов
/ 19 мая 2011

В Javascript я хотел бы определить, существует ли элемент, скажем, элемент A, внутри данного диапазона / textRange.Цель состоит в том, чтобы определить, содержит ли текущий выбор пользователя ссылку.Я создаю элемент управления редактора форматированного текста.

Объект диапазона имеет метод commonAncestorContainer (W3C) или parentElement () (Microsoft), который возвращает ближайшего общего предка всех элементов в диапазоне.Однако поиск внутри этого элемента для A элементов не будет работать, поскольку этот общий предок также может содержать элементы, которые не находятся в диапазоне, поскольку диапазон может начинаться или заканчиваться частично через родительский элемент.

Как бы вы достигли этого?

Ответы [ 5 ]

5 голосов
/ 19 мая 2011

Как насчет selection.containsNode?https://developer.mozilla.org/en/DOM/Selection/containsNode

что-то вроде:

var selection = window.getSelection();
var range = selection.getRangeAt(0);
var result = $('a', range.commonAncestorContainer).filter(function() {
  return selection.containsNode(this);
});
console.log(result);
3 голосов
/ 25 мая 2011

В итоге я выбрал решение, подобное этому:

        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];
                            }
                        }
                    }
                }
            }
        };

Где getrange () - моя другая функция для получения текущего выбора в качестве объекта диапазона.

Для использования,назовите его как

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

, где редактор - это contenteditable элемент, или тело в iframe режима дизайна.

2 голосов
/ 19 мая 2011

Это немного тяжело в заднице делать кросс-браузер.Вы можете использовать мою библиотеку Rangy , которая, вероятно, излишня для этой задачи, но делает ее более простой и работает во всех основных браузерах.В следующем коде предполагается, что выбран только один диапазон:

var sel = rangy.getSelection();
if (sel.rangeCount) {
    var range = sel.getRangeAt(0);
    var links = range.getNodes([1], function(node) {
        return node.tagName.toLowerCase() == "a" && range.containsNode(node);
    });
}
0 голосов
/ 14 июня 2019

В случае диапазона для искомого элемента, то, что я написал, полезно.(Но только для этого случая!)

Сначала я написал функцию, которая возвращает узел, найденный в диапазоне: getNodeFromRange (rangeObject).Используя эту функцию, было уже легко написать функцию, которая возвращает желаемый Node: findTagInRange (tagName).

function getNodeFromRange(range) {
    if(range.endContainer.nodeType==Node.ELEMENT_NODE) {
        return range.endContainer;
    }
    if(range.endContainer.nodeType==Node.TEXT_NODE) {
        return range.endContainer.parentNode;
    }
    else {
        // the 'startContainer' it isn't on an Element (<p>, <div>, etc...)
        return;
    }
}

function findTagInRange(tagName, range) {
    var node = getNodeFromRange(range);
    if(node && typeof(node.tagName)!='undefiend' && node.tagName.toLowerCase()==tagName.toLowerCase()) {
        return $(node);
    }
    return;
}

И тогда я могу использовать ее следующим образом:Я вижу определение диапазона , которое вы уже решили.:)

0 голосов
/ 07 мая 2015

Я использую этот код, который работает с IE / Chrome / FF: (Я использую его для выбора строк

в таблице)
// yourLink is the DOM element you want to check
var selection = window.getSelection().getRangeAt(0)
var node = document.createRange()
node.selectNode(yourLink)
var s2s = selection.compareBoundaryPoints(Range.START_TO_END, node)
var s2e = selection.compareBoundaryPoints(Range.START_TO_START, node)
var e2s = selection.compareBoundaryPoints(Range.END_TO_START, node)
var e2e = selection.compareBoundaryPoints(Range.END_TO_END, node)
if ((s2s != s2e) || (e2s != e2e) || (s2s!=e2e))
    console.log("your node is inside selection")
...