2010-05-22 11 views
8

Tôi đang hiển thị một số văn bản được tạo kiểu đơn giản dưới dạng html trong UIWebView trên iPhone. Về cơ bản, nó là một loạt các đoạn văn với cụm từ mạnh hoặc không được nhấn mạnh. Khi chạy, tôi cần áp dụng kiểu cho phạm vi văn bản.áp dụng kiểu cho phạm vi văn bản bằng javascript trong uiwebview

Có một vài trường hợp tương tự, một trong số đó là làm nổi bật kết quả tìm kiếm. Nếu người dùng đã tìm kiếm "cái gì đó" tôi muốn thay đổi màu nền sau các lần xuất hiện của từ đó, sau đó khôi phục lại nền gốc.

Có thể áp dụng kiểu cho phạm vi văn bản bằng javascript không? Một phần quan trọng của việc này cũng có thể bỏ đặt các kiểu.

Dường như có hai con đường có thể đi theo. Một trong những sẽ được sửa đổi một số html trong Objective-C và đi qua nó thông qua javascript là innerHTML mới của một số container. Cách khác là sử dụng javascript để thao tác trực tiếp các nút DOM.

Tôi có thể thao tác html, nhưng điều đó nghe có vẻ tẻ nhạt trong Objective-C vì vậy tôi sẽ thay đổi thao tác DOM nếu đó là một cách tiếp cận hợp lý. Tôi không quen thuộc với javascript và DOM vì vậy tôi không biết nếu nó là một cách tiếp cận hợp lý.

Tôi đã viết một số thủ tục để dịch giữa các phạm vi văn bản và các phạm vi nút có bù trừ. Vì vậy, nếu tôi bắt đầu với phạm vi văn bản 100-200 và bắt đầu trong một đoạn văn và kết thúc bằng một đoạn thứ ba, tôi có thể nhận được các nút văn bản và các khoảng trống trong các nút đại diện cho phạm vi văn bản đã cho. Tôi chỉ cần một cách để tách một nút văn bản tại một bù đắp trong văn bản. Hiện tại tôi chỉ áp dụng kiểu cho các đoạn có chứa phạm vi văn bản.

Một vài lưu ý:

  • javascript thẳng xin vui lòng, không có khung bên ngoài như jquery.
  • các thay đổi không bao giờ cần phải được ghi vào đĩa.
  • các thay đổi phải được hoàn tác hoặc ít nhất là có thể tháo rời.
  • các kiểu áp dụng đã tồn tại trong tệp css.
  • nó cần phải hoạt động trong iPhone 3.0 và chuyển tiếp.
  • tất cả các tệp nguồn được gửi cùng với ứng dụng.
  • hãy tiết lộ chi tiết.

Cảm ơn mọi đề xuất.

Trả lời

19

Tôi nghĩ rằng bạn đang yêu cầu rất nhiều để có được một giải pháp hoàn chỉnh cho điều này, nhưng nó có vẻ thú vị vì vậy tôi đã thực hiện nó. Các công trình sau đây trong các trình duyệt WebKit gần đây, bao gồm Safari trên iPhone chạy OS 3.0. Nó sử dụng phương pháp intersectsNode không chuẩn nhưng thuận tiện của Range, tồn tại trong WebKit nhưng đã bị xóa khỏi Firefox ở 3.0, do đó, nó không hoạt động trong các phiên bản Firefox gần đây nhưng có thể được thực hiện để làm như vậy một cách tầm thường.

Phần sau sẽ bao quanh mỗi nút văn bản đã chọn với phần tử <span> có lớp "someclass" và cũng là lớp duy nhất để cho phép dễ dàng hoàn tác. applyClassToSelection trả về lớp duy nhất này; chuyển lớp này vào removeSpansWithClass để loại bỏ các nhịp.

UPDATE: Cố định vấn đề khi lựa chọn là hoàn toàn chứa trong một nút văn bản duy nhất

UPDATE 2: Bây giờ kiểm tra và làm việc tại iPhone chạy hệ điều hành 3.0.

CẬP NHẬT 3: Thêm rangeIntersectsNode chức năng để thêm hỗ trợ cho Firefox 3.0 trở lên. Mã này giờ đây sẽ hoạt động trong Firefox 1.0+, Safari 3.1+, Google Chrome, Opera 9.6+ và có thể là các mã khác (chưa được kiểm tra). Nó không hoạt động ở tất cả trong Internet Explorer và sẽ cung cấp lỗi trong trình duyệt đó. Tôi dự định sẽ sớm làm việc trên một phiên bản IE.

<script type="text/javascript"> 
    var nextId = 0; 

    var rangeIntersectsNode = (typeof window.Range != "undefined" 
      && Range.prototype.intersectsNode) ? 

     function(range, node) { 
      return range.intersectsNode(node); 
     } : 

     function(range, node) { 
      var nodeRange = node.ownerDocument.createRange(); 
      try { 
       nodeRange.selectNode(node); 
      } catch (e) { 
       nodeRange.selectNodeContents(node); 
      } 

      return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 && 
       range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1; 
     }; 

    function applyClassToSelection(cssClass) { 
     var uniqueCssClass = "selection_" + (++nextId); 
     var sel = window.getSelection(); 
     if (sel.rangeCount < 1) { 
      return; 
     } 
     var range = sel.getRangeAt(0); 
     var startNode = range.startContainer, endNode = range.endContainer; 

     // Split the start and end container text nodes, if necessary 
     if (endNode.nodeType == 3) { 
      endNode.splitText(range.endOffset); 
      range.setEnd(endNode, endNode.length); 
     } 

     if (startNode.nodeType == 3) { 
      startNode = startNode.splitText(range.startOffset); 
      range.setStart(startNode, 0); 
     } 

     // Create an array of all the text nodes in the selection 
     // using a TreeWalker 
     var containerElement = range.commonAncestorContainer; 
     if (containerElement.nodeType != 1) { 
      containerElement = containerElement.parentNode; 
     } 

     var treeWalker = document.createTreeWalker(
      containerElement, 
      NodeFilter.SHOW_TEXT, 
      // Note that Range.intersectsNode is non-standard but 
      // implemented in WebKit 
      function(node) { 
       return rangeIntersectsNode(range, node) ? 
        NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT; 
      }, 
      false 
     ); 

     var selectedTextNodes = []; 
     while (treeWalker.nextNode()) { 
      selectedTextNodes.push(treeWalker.currentNode); 
     } 

     var textNode, span; 

     // Place each text node within range inside a <span> 
     // element with the desired class 
     for (var i = 0, len = selectedTextNodes.length; i < len; ++i) { 
      textNode = selectedTextNodes[i]; 
      span = document.createElement("span"); 
      span.className = cssClass + " " + uniqueCssClass; 
      textNode.parentNode.insertBefore(span, textNode); 
      span.appendChild(textNode); 
     } 

     return uniqueCssClass; 
    } 

    function removeSpansWithClass(cssClass) { 
     var spans = document.body.getElementsByClassName(cssClass), 
      span, parentNode; 

     // Convert spans to an array to prevent live updating of 
     // the list as we remove the spans 
     spans = Array.prototype.slice.call(spans, 0); 

     for (var i = 0, len = spans.length; i < len; ++i) { 
      span = spans[i]; 
      parentNode = span.parentNode; 
      parentNode.insertBefore(span.firstChild, span); 
      parentNode.removeChild(span); 

      // Glue any adjacent text nodes back together 
      parentNode.normalize(); 
     } 
    } 

    var c; 
</script> 

<input type="button" onclick="c = applyClassToSelection('someclass')" 
    value="Add class"> 
<input type="button" onclick="removeSpansWithClass(c)" 
    value="Remove class"> 
+0

Cảm ơn bạn. Đây là nhiều hơn tôi hy vọng. – drawnonward

+0

Có lẽ đặt nó trên github, vì vậy chúng tôi có thể làm theo ít nhất. – Mark

+1

Tôi đang làm việc trên thư viện phạm vi/lựa chọn đa trình duyệt sẽ bao gồm phiên bản cải tiến này. Chưa có nhiều tiến bộ, nhưng tôi đã tạo dự án Google Code: http://code.google.com/p/rangy/ –