Используйте JavaScript для расширения диапазона DOM, чтобы охватить частично выбранные узлы - PullRequest
11 голосов
/ 19 марта 2010

Я работаю над таким текстовым редактором, как веб-приложение, в основном редактор XML, написанный на javascript.

Мой JavaScript-код должен обернуть выборку узлов из контейнера div ContentEditable. Я использую методы, описанные в MDC . Но так как мне нужно синхронизировать содержимое контейнеров div с моим XML DOM, я бы хотел избежать частичного выбора, как описано в w3c range :

<BODY><H1>Title</H1><P>Blah xyz.</P></BODY

............^----------------^............

Этот выбор начинается внутри H1 и заканчивается внутри P, я бы хотел, чтобы он полностью включал H1, P.

Существует ли простой способ расширить выборку, чтобы полностью охватить частично выбранных детей? В основном, я хочу использовать range.surroundContents () без исключения.

(Код не должен работать с Opera / IE)

Ответы [ 3 ]

9 голосов
/ 19 марта 2010

Глядя на документацию MDC, мне удается сделать что-то вроде этого:

Selection.prototype.coverAll = function() {
    var ranges = [];
    for(var i=0; i<this.rangeCount; i++) {
        var range = this.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);
    }
    this.removeAllRanges();
    for(var i=0; i<ranges.length; i++) {
        this.addRange(ranges[i]);
    }
    return;
};

Вы можете попробовать это здесь: http://jsfiddle.net/GFuX6/9/

редактирование: Обновлен, чтобы браузер правильно отображал расширенный выбор. Он делает то, что вы просили, даже если выделение содержит несколько диапазонов (с Ctrl).

Чтобы сделать несколько частичных узлов полужирным, вот решение:

Selection.prototype.boldinize = function() {
    this.coverAll();
    for(var i=0; i<this.rangeCount; i++) {
        var range = this.getRangeAt(i);
        var parent = range.commonAncestorContainer;
        var b = document.createElement('b');
        if(parent.nodeType == 3) {
            range.surroundContents(b);
        } else {
            var content = range.extractContents();
            b.appendChild(content);
            range.insertNode(b);
        }
    }
};
0 голосов
/ 20 марта 2010

Благодаря Альсиенде я наконец-то придумал код на http://jsfiddle.net/wesUV/21/. Этот метод не такой жадный, как другой.После coverAll () функцияroundContents () всегда должна работать.

Selection.prototype.coverAll = function() {
  var ranges = [];   
  for(var i=0; i<this.rangeCount; i++) {
    var range = this.getRangeAt(i);
    var ancestor = range.commonAncestorContainer;
    if (ancestor.nodeType == 1) {            
        if (range.startContainer.parentNode != ancestor && this.containsNode(range.startContainer.parentNode, true)) {
            range.setStartBefore(range.startContainer.parentNode);
        }
        if (range.endContainer.parentNode != ancestor && this.containsNode(range.endContainer.parentNode, true)) {
                range.setEndAfter(range.endContainer.parentNode);
        }
    }
    ranges.push(range);
  }
  this.removeAllRanges();
  for(var i=0; i<ranges.length; i++) {
    this.addRange(ranges[i]);
  }
  return;
};

и функция boldinize:

Selection.prototype.boldinize = function() {
  for(var i=0; i<this.rangeCount; i++) {        
    var range = this.getRangeAt(i);
    var b = document.createElement('b');
    try {
        range.surroundContents(b);
    } catch (e) {
        alert(e);
    }
  }
};
0 голосов
/ 19 марта 2010

Если вы хотите включить теги H1 и P (то есть действительную разметку), не беспокойтесь. Вы получаете это бесплатно. Если вы хотите, чтобы вы включили все содержимое в (частичное) выделение, вам необходимо получить доступ к объекту выделения. Читайте об этом на Введение Quirksmode в Range .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...