2010-03-19 27 views
10

Tôi đang làm việc trên một trình soạn thảo văn bản phong phú như ứng dụng web, về cơ bản là trình soạn thảo XML được viết bằng javascript.Sử dụng javascript để mở rộng Phạm vi DOM để bao gồm các nút được chọn một phần

Mã javascript của tôi cần bao bọc một lựa chọn các nút từ vùng chứa div có thể chỉnh sửa nội dung. Tôi đang sử dụng các phương pháp được mô tả tại MDC. Nhưng kể từ khi tôi cần phải đồng bộ hóa container div nội dung XML của tôi DOM Tôi muốn tránh lựa chọn một phần như mô tả trong w3c ranges:

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

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

lựa chọn này sẽ khởi động bên trong H1 và kết thúc bên trong P, Tôi muốn nó bao gồm H1, P hoàn toàn.

Có cách nào dễ dàng để mở rộng lựa chọn để bao gồm một phần trẻ em được chọn hoàn toàn không? Về cơ bản tôi muốn sử dụng range.surroundContents() mà không cần chạy vào một ngoại lệ.

(mã này không cần phải làm việc với opera/IE)

Trả lời

8

Nhìn vào các tài liệu MDC, tôi quản lý làm một cái gì đó như thế này:

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

Bạn có thể thử nó ở đây: http://jsfiddle.net/GFuX6/9/

chỉnh sửa: cập nhật để có màn hình hiển thị trình duyệt một cách chính xác các lựa chọn tăng cường. Nó làm những gì bạn yêu cầu, ngay cả khi lựa chọn có chứa một số phạm vi (với Ctrl).

Để thực hiện một số các nút phần Bold, đây là một giải pháp:

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

Thật vậy, nhưng tôi nghĩ rằng đây là theo dõi đúng. Tôi sẽ cố gắng tạo một lựa chọn tùy chỉnh từ bản gốc có các thuộc tính này. –

+0

Tôi sẽ mở rộng câu hỏi của mình để làm cho nó rõ ràng hơn. Ngoài ra tôi đã cập nhật ví dụ tại http://jsfiddle.net/GFuX6/5/ –

+0

Chọn một số văn bản, nhấn thoát và văn bản trở nên đậm. Có một dòng dài trong fiddle: 'window.getSelection(). GetRangeAt (0) .surroundContents (tag);' Fiddle hiện tại mở rộng ranh giới các nút văn bản, nhưng tôi không thể tìm cách che một phần bao gồm các nút. –

0

Nếu bạn có nghĩa là bạn muốn bao gồm các thẻ H1 và P (ví dụ, đánh dấu hợp lệ), đừng lo lắng. Bạn nhận được điều đó miễn phí. Nếu bạn muốn bao gồm tất cả nội dung trong phần lựa chọn (một phần), bạn cần truy cập đối tượng Selection. Đọc về nó trên Quirksmode's introduction to Range.

+0

Giống như các quốc gia Điều quirksmode, trình duyệt sẽ sửa chữa lên HTML 'hợp lệ': "các trình duyệt thêm số tiền tối thiểu của HTML để làm cho Phạm vi hợp lệ". Tôi muốn không có lựa chọn không hợp lệ để bắt đầu với;) –

0

Nhờ Alsciende Cuối cùng tôi đã đưa ra các mã tại http://jsfiddle.net/wesUV/21/. Phương pháp này không tham lam như cách khác. Sau khi coverAll(), surroundContents() luôn hoạt động.

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

Và chức năng 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); 
    } 
    } 
}; 
Các vấn đề liên quan