在uiwebview中使用JavaScript将样式应用于文本范围 [英] apply style to range of text with javascript in uiwebview

查看:122
本文介绍了在uiwebview中使用JavaScript将样式应用于文本范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在iPhone上的UIWebView中显示一些简单的样式文本为html。它基本上是一系列段落与偶尔强或强调的短语。在运行时,我需要将样式应用到文本范围。

I am displaying some simple styled text as html in a UIWebView on iPhone. It is basically a series of paragraphs with the occasional strong or emphasized phrase. At runtime I need to apply styles to ranges of text.

有几个类似的场景,其中之一是突出显示搜索结果。如果用户搜索了某物,我想更改背后出现的单词的背景颜色,然后稍后恢复原始背景。

There are a few similar scenarios, one of which is highlighting search results. If the user has searched for "something" I would like to change the background color behind occurrences of the word, then later restore the original background.

是否可以应用样式到使用javascript的文本范围?这个的一个关键部分也可以取消设置样式。

Is it possible to apply styles to ranges of text using javascript? A key part of this is also being able to unset the styles.

似乎有两个可能的路径。一个会修改一些html在Objective-C,并通过javascript作为一个新的innerHTML的一些容器。另一个是使用javascript来直接操作DOM节点。

There seem to be two likely paths to follow. One would be modifying some html in Objective-C and passing it through javascript as the new innerHTML of some container. The other would be to use javascript to directly manipulate DOM nodes.

我可以操纵html,但在Objective-C中听起来很乏味,所以我宁愿操纵DOM,如果是一种合理的方法。我不熟悉javascript和DOM,所以我不知道它是否是一个合理的方法。

I could manipulate html, but that sounds tedious in Objective-C so I would rather manipulate the DOM if that is a reasonable approach. I am not that familiar with javascript and DOM so I do not know if it is a reasonable approach.

我写了一些例程来翻译文本范围和节点范围与偏移。因此,如果我从文本范围100-200开始,并且从一个段落开始并在第三个结束,我可以获得文本节点和代表给定文本范围的节点内的偏移量。我只需要一种方式在文本中的偏移处分割文本节点。目前我只是对包含文本范围的段落应用样式。

I wrote some routines to translate between text ranges and node ranges with offsets. So if I start with text range 100-200 and that starts in one paragraph and ends in a third, I can get the text nodes and the offsets within the nodes that represent the given text range. I just need a way to split a text node at an offset in the text. Currently I just apply styles to the paragraphs containing the text range.

一些注释:


  • 直接javascript,没有外部框架如jquery。

  • 更改永远不需要写入磁盘。

  • 可撤消或至少可移除。

  • 必须在iPhone 3.0和向前版本中使用。

  • 应用的样式已存在于css文件中。 / li>
  • 所有源文件都随应用程序一起提供。

  • 请详细。

  • straight javascript please, no external frameworks like jquery.
  • the changes never need to be written to disk.
  • the changes should be undoable or at least removable.
  • the styles to apply already exist in a css file.
  • it needs to work in iPhone 3.0 and forward.
  • all the source files are shipped with the app.
  • please be verbose.

感谢您的任何建议。

推荐答案

我想你要求很多解决方案,但它似乎有趣,所以我实现了它。以下适用于最近的WebKit浏览器,包括运行OS 3.0的iPhone上的Safari。它使用非标准但方便的 intersectsNode 方法 Range ,它存在于WebKit中,但在3.0中已从Firefox中删除,因此它在最新版本的Firefox中不起作用,但可以这样做。

I think you're asking a lot to get a complete solution for this, but it seemed interesting so I've implemented it. The following works in recent WebKit browsers, including Safari on iPhone running OS 3.0. It uses the non-standard but convenient intersectsNode method of Range, which exists in WebKit but was removed from Firefox in 3.0, so it doesn't work in recent versions of Firefox but could be made to do so trivially.

下面将用< span> 元素,具有someclass类,也是一个允许轻松撤消的唯一类。 applyClassToSelection 返回此唯一类;将此类传递到 removeSpansWithClass 中以删除跨度。

The following will surround each selected text node with a <span> element with a class of "someclass" and also a unique class to allow easy undoing. applyClassToSelection returns this unique class; pass this class into removeSpansWithClass to remove the spans.

UPDATE:选择完全包含在单个文本节点中

UPDATE: Fixed problem when selection is entirely contained within a single text node

UPDATE 2:现已在运行OS 3.0的iPhone上测试和运行。

UPDATE 2: Now tested and works in iPhone running OS 3.0.

UPDATE 3:添加了 rangeIntersectsNode 函数以添加对Firefox 3.0及更高版本的支持。此代码现在应该可以在Firefox 1.0+,Safari 3.1+,谷歌浏览器,Opera 9.6+和可能的其他(迄今未测试)。 它在Internet Explorer中根本不起作用,并且会在该浏览器中给出错误。我计划很快在IE版本上工作。

UPDATE 3: Added rangeIntersectsNode function to add support for Firefox 3.0 and later. This code should now work in Firefox 1.0+, Safari 3.1+, Google Chrome, Opera 9.6+ and possibly others (untested so far). It does not work at all in Internet Explorer and will give errors in that browser. I plan to work on an IE version soon.

<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">

这篇关于在uiwebview中使用JavaScript将样式应用于文本范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆