The encoding of innerHTML is exclusive to Chrome browsers

When I incorporate external SVG files, I define some styles within them like so :

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

To add more style dynamically using JavaScript, I implemented the following approach :

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\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);

This method works as expected in Firefox with the modified inner HTML showing the added style correctly.

However, when tested in Chrome, it doesn't render properly and displays:

&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;

The issue seems to be with how Chrome handles the <and > characters, replacing them with &lt; and &gt; entities specifically on this browser.

Answer №1

The issue you are experiencing is a result of the differences in how various browsers handle DOM nodes when using the method Element.innerHTML(). This discrepancy becomes evident when examining the <style> node prior to any modifications. Across all browsers, this node consists of three child nodes: [text, cdata-section, text]. The two nodes of type text contain whitespace surrounding the cdata-section.

When the method Element.innerHTML() is utilized, Firefox and Internet Explorer will maintain this DOM structure by replacing it with an updated <style> element that retains the original subtree structure. However, Chrome interprets the updated styleContent string as character data, resulting in only one node of type text. Since the <style> element only allows character data content, Chrome escapes any markup present within it. Subsequently, the style in Chrome will consist of just one text node, rendering it unsuitable for further processing.

To address this issue, I have created a Plunk demonstrating a more reliable solution:

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

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

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

// Update the 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 following this approach, you can access the node of type cdata-section and easily modify its textContent. Without forcing the browser to reconstruct part of its DOM tree using Element.innerHTML(), the structure of the <style> DOM subtree remains consistent across browsers, ensuring uniform outcomes.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Expanding interfaces dynamically in Typescript

Currently, I am facing a challenge while attempting to integrate an existing React Native module equipped with the following props: useComponent1: boolean useComponent2: boolean This is how the implementation looks like: render(){ if(useComponent1){ ...

Fb.UI Dialogs now appearing in Popups rather than an iframe (part 2)

Here is a related issue that I came across: With the assistance of OffBySome, I managed to display my FB.ui dialog boxes in an iframe rather than as pop-ups. However, now I am experiencing an issue where the dialog appears but the loading throbber continu ...

when an element is hovered over, it activates a reaction on a different element

I've been struggling with the Events assignment we were given. I tried writing my own code, but it had so many errors when I got it checked. I couldn't quite grasp all the explanations of what went wrong, so now I feel a bit embarrassed to share ...

Can a Chrome extension display a webpage in a separate window using only JS, HTML, and CSS?

I am currently working on creating a custom Google Chrome extension. My goal is to have a small window appear when the user clicks on the extension button, without using window.open or traditional pop-ups, to display a specific web page. I have a basic un ...

Locate the ID of the element targeted by the cursor in a contenteditable field

Within a contenteditable div, I have various child elements with different ids. When the cursor is moved inside the contenteditable tag, I want to retrieve the id of the element at the cursor position. For example: If the cursor is on the word "one," th ...

Issue with Material-UI: Inability to Activate the onChangeCommitted Event while Testing

I am encountering issues while testing the onChangeCommitted event with the slider from Mui. I have set up a basic implementation of the slider in a code sandbox environment. You can view the code in this sandbox. The main problem lies in my inability to ...

Storing form information into a collection with the help of meteor methods

With Meteor, I am attempting to gather and store data (name, email, and age) using a form. This information should be saved in a new Meteor collection called "Subscribers". Below is my code: Template Events (client\views\subscribe_form\subs ...

Recognize when the DOM undergoes modifications

After taking Matt's suggestion, I have made changes to the .ready() call. In my workflow, I utilize jQuery to set up certain configurations like this: $(function () { $('.myThing').each(function() { ... configuring happens he ...

The size attributes on <img> tags do not function as expected

I'm facing an issue with the following code: $("#myId").html( "<img src='" + $(xml).find("picture").text() + "' height="42" width="42"></img>" ); Everything works perfectly until I include the 'height="42" wid ...

How to keep a div element fixed on the page's border vertically and horizontally adhered

Would you mind visiting the following link: and observing the layout of the page? My goal is to affix or "attach" a small div element to the right side of the page, just slightly outside of the right frame of the page. Vertically, I want this div to be ...

Ways to conceal and reveal an item within a three.js environment

In my scene, I have an object made up of spheres and a hide/show button. The process in my program goes like this: when I choose one of the spheres using raycasting and then press the hide button, that particular sphere becomes hidden. Clicking on the sh ...

Transfer all the child nodes to the parent using the spread operator or Object.assign while preventing duplicate properties from being overwritten

I'm trying to transfer all the nodes of a child node to the parent using the spread operator or Object.assign (without relying on Lodash) while avoiding overwriting existing properties. My initial thought was to simply append the childArray to the ro ...

Tips on sorting ID strings that include a specific substring

I have a user input that may include a street, postal code, city, or a combination of them. How can I filter an array of objects to find those that contain any of these strings in the corresponding fields? getFilteredCentersSuggestions(searchTerm: string) ...

AngularJS bidirectional binding with numerous select choices

I am faced with a unique challenge - I have a list of non-exclusive fields that users want to see presented in a select box allowing multiple selections, rather than individual checkboxes bound to Boolean values in the model. While I know how to create t ...

What could be causing the frequent client disconnections and reconnections in a basic node, express, socket.io, and jade application?

For my project, I decided to create a basic application that combines node, express, socket.io, and jade. The concept is simple: the user types in a string (referred to as "tool ID") into a text input field and then clicks on a submit button. The entered t ...

Dynamically inserting templates into directives

I've been attempting to dynamically add a template within my Angular directive. Following the guidance in this answer, I utilized the link function to compile the variable into an HTML element. However, despite my efforts, I haven't been success ...

JQuery Navigation Bar Functions Properly on the Homepage

Hey there! I've been struggling with a simple issue for quite some time now. I have a menu with a toggle function using plus/minus signs, but it only seems to work on the homepage and not on any other pages. Here's the code snippet: $(document). ...

CSS for a navigation menu with underlined links

I am attempting to create an underline effect when hovering over a link. However, I am facing an issue where the underline does not align perfectly with the line below it. Can someone please guide me on how to modify this CSS so that when the link is hov ...

"A curious situation arose when using Axios in a Firebase function, where a pending promise was unexpectedly returned even within the confines

My asynchronous problem with async/await has been baffling me. Both my child and HOF functions are declared as async, and I await the returned results before trying to log them. However, all I get is 'pending'. The function hangs for 60s and time ...

Creating a fresh shortcut on the selenium IDE

Is there a way to customize shortcuts in Selenium IDE by modifying its code? For instance, I would like to set the shortcut ctrl + p for the action run test case, similar to how the save action is assigned ctrl + s. I've searched for the JavaScript ...