InnerHTML is only encoded in Chrome

Ok, so I am showing some svg using external svg files in which I have some style like this:

    <style type="text/css">
<![CDATA[
    .st1 {fill:#ffffff;stroke:#808080;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.5;stroke-width:0.75}
    .st2 {fill:#444444;font-family:Calibri;font-size:0.833336em;font-weight:bold}
    .st3 {fill:#f8eccc;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
    .st4 {fill:#444444;font-family:Calibri;font-size:0.75em;font-weight:bold}
]]>
</style>

      

I want to add some style using javascript by doing like this:

    console.log("style innerHTML before :\n" + document.querySelector(elementOrSelector).contentDocument.querySelector("style").innerHTML);
    var styleContent = document.querySelector(elementOrSelector).contentDocument.querySelector("style").innerHTML;
    styleContent = styleContent.slice(0, styleContent.lastIndexOf("}") + 1) + "\n\t\trect:hover {fill:#698B89}\n\t]]>\n";
    document.querySelector(elementOrSelector).contentDocument.querySelector("style").innerHTML = styleContent;
    console.log("style innerHTML after :\n" + document.querySelector(elementOrSelector).contentDocument.querySelector("style").innerHTML);

      

It works fine in Firefox, my console shows internal HTML after change:

<![CDATA[
.st1 {fill:#ffffff;stroke:#808080;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.5;stroke-width:0.75}
.st2 {fill:#444444;font-family:Calibri;font-size:0.833336em;font-weight:bold}
.st3 {fill:#f8eccc;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
.st4 {fill:#444444;font-family:Calibri;font-size:0.75em;font-weight:bold}
rect:hover {fill:#698B89}
]]>

      

But in Chrome this fails, the console shows:

&lt;![CDATA[
.st1 {fill:#ffffff;stroke:#808080;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.5;stroke-width:0.75}
.st2 {fill:#444444;font-family:Calibri;font-size:0.833336em;font-weight:bold}
.st3 {fill:#f8eccc;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
.st4 {fill:#444444;font-family:Calibri;font-size:0.75em;font-weight:bold}
rect:hover {fill:#698B89}
]]&gt;

      

so mine <

and are >

not set properly, I have entities &lt;

and &gt;

, and this is only in Chrome.

+3


source to share


1 answer


Your problem has to do with differences in different browsers when handling DOM nodes with the method Element.innerHTML()

. This becomes apparent when checking the <style>

node before any manipulation occurs. This node has three child nodes in all browsers: [text, cdata-section, text]

. If two type nodes text

just contain spaces around cdata-section

.

Using the method will Element.innerHTML()

preserve this DOM structure in FF and IE, replacing it with an updated element <style>

that has the same DOM subtree structure. However, Chrome will parse the updated string styleContent

as character data and only create one node of type text

. Since the element <style>

only allows character data content, Chrome seems to also avoid any markup contained within it as well. Hence yours style

will subsequently only be one text node in Chrome, which is useless for further processing.

I created Plunk demonstrating a more robust solution:



// Get style node.
var style = document.querySelector("object").contentDocument.querySelector("style");

// Extract CDATA-Section from style childNodes.
var cdata = getCDATA(style.childNodes);

// Manipulate CDATA content.
var styleContent = cdata.textContent;
styleContent += "\n\t\tpath:hover {fill:#698B89;}";

// Update CDATA-section node.
cdata.textContent = styleContent;

function getCDATA(nodelist) {
    for (var i=0; i < nodelist.length; i++) {
        var node = nodelist.item(i);
        if (node.nodeType == Element.CDATA_SECTION_NODE) {
            return node;
        }
    }
}

      

By doing this, you will get a reference to a node of the type cdata-section

, making it easy to manipulate textContent

. Since you are not forcing the browser to regenerate a portion of its DOM tree with Element.innerHTML()

, the structure of the <style>

DOM subtree will remain unchanged across browsers, giving consistent results.

+3


source







All Articles