Как использовать innerHTML для простых текстовых файлов в Firefox?

Если вы откроете текстовый файл (.txt, .js, .css, ...) в своем браузере, он будет заключен в красивое дерево DOM.

Например, откройте этот файл .txt и введите

javascript:alert(document.documentElement.innerHTML);

в адресную строку. Отлично... каждый основной браузер поддерживает манипулирование DOM с этими обернутыми текстовыми файлами, что отлично подходит для написания мощных букмарклетов или пользовательских скриптов. .

Однако Firefox не может назначить значение innerHTML любого элемента. Например,

javascript: document.body.innerHTML = document.body.innerHTML.replace(/(\d+\s+\w+(?=\s+\d+))/g, '<span style="color:red">$1</span>'); void 0;

будет работать в любом браузере, кроме Firefox.

Есть ли способ обойти эту проблему?

(Нет, я не хочу анализировать строку innerHTML вручную, и нет, это также не работает с jQuery.)


person user123444555621    schedule 11.04.2009    source источник
comment
DOM был разработан для работы с HTML и XML. Текстовый документ не является ни тем, ни другим. en.wikipedia.org/wiki/Document_Object_Model Текстовый документ с несколькими произвольными тегами HTML. остается текстовым документом.   -  person Calvin    schedule 11.04.2009


Ответы (4)


Это не удается, потому что нет body - даже файл, который вы связали, является просто текстовым файлом без тела (возможно, вы смотрите на него в firebug?).

Лучше всего заменить регулярное выражение, поскольку вы работаете с текстом.

person Andrew Hare    schedule 11.04.2009

Я думаю, что нашел рабочее решение. Прежде всего, позвольте мне подробнее остановиться на вопросе.

Проблема в том, что Firefox создает что-то вроде

[some wrapper]
+---document
    +---<html>[=documentElement]
        +---<body>
            +---<head/>
            +---<pre>
                +---[actual plain text contents]

но обернутый объект документа не поддерживает правильную настройку innerHTML. Итак, основная идея состоит в том, чтобы создать новый объект документа с полной поддержкой innerHTML. Вот как это работает:

var setInnerHTML = function(el, string) {
    if (typeof window.supportsInnerHTML == 'undefined') {
        var testParent = document.createElement('div');
        testParent.innerHTML = '<br/>';
        window.supportsInnerHTML = (testParent.firstChild.nodeType == 1);
    }
    if (window.supportsInnerHTML) {
        el.innerHTML = string;
    } else {
        if (!window.cleanDocumentObject) {
            /* this is where we get a 'clean' document object */
            var f = document.createElement('iframe');
            f.style.setProperty('display', 'none', 'important');
            f.src = 'data:text/html,<!DOCTYPE html><html><title></title></html>';
            document.body.appendChild(f); /* <- this is where FF creates f.contentDocument */
            window.cleanDocumentObject = f.contentDocument;
            document.body.removeChild(f);
        }

        /* let browser do the parsing */
        var div = window.cleanDocumentObject.createElement('div');
        div.innerHTML = string; /* this does work */

        /* copy childNodes */
        while(el.firstChild) {
            el.removeChild(el.firstChild); /* cleanup */
        }
        for (var i = 0; i < div.childNodes.length; i++) {
            el.appendChild(div.childNodes[i].cloneNode(true));
        }
        delete div;
    }
}

редактировать:

Эта версия лучше и быстрее; используя XSLTProcessor вместо iFrame.

var setInnerHTML = function(el, string) {
    // element.innerHTML does not work on plain text files in FF; this restriction is similar to
    // http://groups.google.com/group/mozilla.dev.extensions/t/55662db3ea44a198
    var self = arguments.callee;
    if (typeof self.supportsInnerHTML == 'undefined') {
        var testParent = document.createElement('div');
        testParent.innerHTML = '<p/>';
        self.supportsInnerHTML = (testParent.firstChild.nodeType == 1);
    }
    if (self.supportsInnerHTML) {
        el.innerHTML = string;
        return el;
    } else if (typeof XSLTProcessor == 'undefined') {
        return undefined;
    } else {
        if (typeof self.cleanDocument == 'undefined')
            self.cleanDocument = createHTMLDocument();

        if (el.parentNode) {
            var cleanEl = self.cleanDocument.importNode(el, false);
            cleanEl.innerHTML = string;
            el.parentNode.replaceChild(document.adoptNode(cleanEl), el);
        } else {
            var cleanEl = self.cleanDocument.adoptNode(el);
            cleanEl.innerHTML = string;
            el = document.adoptNode(cleanEl);
        }

        return el;
    }

    function createHTMLDocument() {
        // Firefox does not support document.implementation.createHTMLDocument()
        // cf. http://www.quirksmode.org/dom/w3c_html.html#t12
        // the following is taken from http://gist.github.com/49453
        var xmlDoc = document.implementation.createDocument('', 'fooblar', null);
        var templ = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">'
                + '<xsl:output method="html"/><xsl:template match="/">'
                + '<html><title/><body/></html>'
                + '</xsl:template></xsl:stylesheet>';
        var proc = new XSLTProcessor();
        proc.importStylesheet(new DOMParser().parseFromString(templ,'text/xml'));
        return proc.transformToDocument(xmlDoc);
    }
};
person user123444555621    schedule 12.04.2009

использовать GreaseMonkey

person Itay Moav -Malimovka    schedule 11.04.2009

Похоже, что в текстовом документе в Firefox 3 назначение innerHTML любого узла действует так, как если бы вы присваивали значение innerText (с добавлением «‹html>‹body>‹pre>»).

(Поскольку DOM-скрипты в документах, отличных от XML/HTML, полностью не определены, Firefox, безусловно, имеет на это право; похоже, это быстрый хак для отображения текстовых файлов на HTML-странице.)

Таким образом, вы не можете использовать innerHTML в Firefox, но другие методы DOM работают:

var span= createElement('span');
span.style.color= 'red';
span.appendChild(document.createTextNode(match));
person bobince    schedule 11.04.2009
comment
Правильно. Дело в том, что для того, чтобы это заработало, вам нужен парсер. Либо используйте код, написанный на JavaScript (например, ejohn.org/blog/pure-javascript- html-parser ), который медленный и громоздкий, или - найти способ выполнить синтаксический анализ с помощью Firefox, что я предпочитаю - person user123444555621; 12.04.2009
comment
Не совсем, вы можете просто выполнить поиск по данным текстового узла и использовать splitText(), чтобы разделить каждое найденное совпадение и вставить указанный выше элемент span. Без разбора. - person bobince; 13.04.2009