最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Use javascript to extend a DOM Range to cover partially selected nodes - Stack Overflow

programmeradmin1浏览0评论

I'm working on a rich text editor like web application, basically a XML editor written in javascript.

My javascript code needs to wrap a selection of nodes from the contentEditable div container. I'm using the methods described at MDC. But since I need to synchronize the div containers content to my XML DOM I would like to avoid partial selections as described in w3c ranges:

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

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

This selection starts inside H1 and ends inside P, I'd like it to include H1,P pletely.

Is there an easy way to extend the selection to cover partially selected children pletely? Basically I want to use range.surroundContents() without running into an exception.

(The code doesn't need to work with opera/IE)

I'm working on a rich text editor like web application, basically a XML editor written in javascript.

My javascript code needs to wrap a selection of nodes from the contentEditable div container. I'm using the methods described at MDC. But since I need to synchronize the div containers content to my XML DOM I would like to avoid partial selections as described in w3c ranges:

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

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

This selection starts inside H1 and ends inside P, I'd like it to include H1,P pletely.

Is there an easy way to extend the selection to cover partially selected children pletely? Basically I want to use range.surroundContents() without running into an exception.

(The code doesn't need to work with opera/IE)

Share Improve this question edited Mar 19, 2010 at 13:22 ko-dos asked Mar 19, 2010 at 12:29 ko-dosko-dos 1,43012 silver badges11 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 10

Looking at the MDC documentation, I manage do something like this:

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

You can try it here : http://jsfiddle/GFuX6/9/

edit: Updated to have the browser display correctly the augmented selection. It does what you asked for, even if the selection contains several ranges (with Ctrl).

To make several partial nodes Bold, here is a solution:

Selection.prototype.boldinize = function() {
    this.coverAll();
    for(var i=0; i<this.rangeCount; i++) {
        var range = this.getRangeAt(i);
        var parent = range.monAncestorContainer;
        var b = document.createElement('b');
        if(parent.nodeType == 3) {
            range.surroundContents(b);
        } else {
            var content = range.extractContents();
            b.appendChild(content);
            range.insertNode(b);
        }
    }
};

Thanks to Alsciende I finally came up with the code at http://jsfiddle/wesUV/21/. This method isn't as greedy as the other one. After coverAll(), surroundContents() should always work.

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

And the boldinize function:

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

If you mean you want to include the tags H1 and P (i.e., the valid markup), don't worry. You get that for free. If you mean you want to it to include all the content within the (partial) selection, you need to access the Selection object. Read about it on Quirksmode's introduction to Range.

发布评论

评论列表(0)

  1. 暂无评论