примените стиль к диапазону текста с JavaScript в uiwebview

Я отображаю некоторый простой стилизованный текст как HTML в UIWebView на iPhone. Это - в основном ряд абзацев со случайной сильной или подчеркнутой фразой. Во времени выполнения я должен применить стили к диапазонам текста.

Существует несколько подобных сценариев, один из которых выделяет результаты поиска. Если бы пользователь искал "что-то", что я хотел бы изменить цвет фона позади случаев слова, то позже восстанавливают исходный фон.

Действительно ли возможно применить стили к диапазонам текста с помощью JavaScript? Ключевая роль этого является также способностью сбросить стили.

Кажется, существует два вероятных пути для следования. Можно было бы изменить некоторый HTML в Objective C и передал бы его через JavaScript как новый innerHTML некоторого контейнера. Другой должен был бы использовать JavaScript для прямого управления узлами DOM.

Я мог управлять HTML, но это звучит утомительным в Objective C, таким образом, я управлял бы DOM, если это - разумный подход. Я не настолько знаком с JavaScript и DOM, таким образом, я не знаю, является ли это разумный подход.

Я записал некоторые стандартные программы для перевода между текстовыми диапазонами и диапазонами узла со смещениями. Таким образом, если я запускаю с текстового диапазона 100-200, и это запускается в одном абзаце и концах в одной трети, я могу получить текстовые узлы и смещения в узлах, которые представляют данный текстовый диапазон. Мне просто нужен способ разделить текстовый узел при смещении в тексте. В настоящее время я просто применяю стили к абзацам, содержащим текстовый диапазон.

Несколько примечаний:

  • прямой JavaScript, никакие внешние платформы как jQuery.
  • изменения никогда не должны писаться в диск.
  • изменения должны быть невозможными или по крайней мере съемными.
  • стили для применения уже существуют в файле CSS.
  • это должно работать в iPhone 3.0 и вперед.
  • все исходные файлы поставляются с приложением.
  • будьте подробными.

Спасибо за любые предложения.

8
задан drawnonward 22 May 2010 в 05:45
поделиться

1 ответ

​​Я думаю, вы многого просите, чтобы получить для этого полное решение, но это показалось интересным, поэтому я реализовал его. Следующее работает в последних версиях браузеров WebKit, включая Safari на iPhone под управлением OS 3.0. Он использует нестандартный, но удобный метод intersectsNode из Range , который существует в WebKit, но был удален из Firefox в версии 3.0, поэтому он не работает в последних версиях Firefox, но может сделать это тривиально.

Следующее будет окружать каждый выбранный текстовый узел элементом с классом «someclass», а также уникальным классом, позволяющим легко отменить. applyClassToSelection возвращает этот уникальный класс; передайте этот класс в removeSpansWithClass , чтобы удалить промежутки.

ОБНОВЛЕНИЕ: Исправлена ​​проблема, когда выделение полностью содержится в одном текстовом узле.

ОБНОВЛЕНИЕ 2: Теперь протестировано и работает в iPhone под управлением OS 3.0.

ОБНОВЛЕНИЕ 3: Добавлена ​​функция rangeIntersectsNode для добавления поддержки Firefox 3.0 и новее. Этот код теперь должен работать в Firefox 1.0+, Safari 3.1+, Google Chrome, Opera 9.6+ и, возможно, в других (пока не проверено). Он вообще не работает в Internet Explorer и выдает ошибки в этом браузере. Я планирую вскоре поработать над версией 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">
19
ответ дан 5 December 2019 в 08:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: