Bryan
Bryan

Reputation: 33

Using JavaScript, insert a line break into a HTML textContent attribute (IE specific)

I am generating a dynamic SVG image using JavaScript. My intention is for specific regions to have information contained in a ToolTip. What I have so far works in both Chrome and Firefox, but only partially in IE 11.

If I use textContent, "\r\n" is ignored in IE and <br /> is displayed literally.

innerHTML appears to be the answer from previously asked similar questions:
Question 9330671
Question 9980416

Typically, switching to innerHTML would solve this, but IE does not support innerHTML for this particular use, so no text is displayed at all.

Using either innerHTML or textContent works for Chrome or Firefox, so again, this is only an issue in IE (tested with IE 11). Apologies to anyone who has to use this browser in the testing of the code provided.

Interactive code is available at http://jsfiddle.net/rnhy9pus/.

Alternatively, full code is included below:

function createPathContent(svgID, popupText, pathDirections)
{
  var path = document.createElementNS("http://www.w3.org/2000/svg","path");
  path.setAttribute("d",pathDirections);
  var popup = document.createElementNS("http://www.w3.org/2000/svg","title");
  popup.textContent = popupText; // <-- LINE TO FOCUS ON
  path.appendChild(popup);
  document.getElementById(svgID).appendChild(path);
}
function createPathHTML(svgID, popupText, pathDirections)
{
  var path = document.createElementNS("http://www.w3.org/2000/svg","path");
  path.setAttribute("d",pathDirections);
  var popup = document.createElementNS("http://www.w3.org/2000/svg","title");
  popup.innerHTML = popupText; // <-- LINE TO FOCUS ON
  path.appendChild(popup);
  document.getElementById(svgID).appendChild(path);
}
function createExample(svgID)
{
  document.getElementById(svgID).setAttribute("xmlns", "http://www.w3.org/2000/svg");
  document.getElementById(svgID).setAttribute("version", "1.1");
  document.getElementById(svgID).setAttribute("width", "300");
  document.getElementById(svgID).setAttribute("viewBox", "0 0 100 100");
  document.getElementById(svgID).setAttribute("preserveAspectRatio", "xMinYMin meet");

  var style = document.createElement("style");
  style.setAttribute("type","text/css");
  style.innerHTML = "path { fill: #ccc; } path:hover { fill: #ff0; }";
  document.getElementById(svgID).appendChild(style);

  var NEW_LINE = "\r\n";
  //var NEW_LINE = "<br />"; // This displays literally in textContent and as a new line in innerHTML.

  createPathContent(svgID, "Tooltip text using textContent:" + NEW_LINE + "New Line", "M 10 10 L 90 10 L 90 45 L 10 45 Z");
  // Works correctly in Chrome or Firefox.  Displays in IE 11, but only on a single line.

  createPathHTML(svgID,    "Tooltip text using innerHTML:"   + NEW_LINE + "New Line", "M 10 55 L 90 55 L 90 90 L 10 90 Z");
  // Works correctly in Chrome or Firefox.  Does not display in IE 11.
}

createExample("exampleSVG");
<svg id="exampleSVG" xmlns="http://www.w3.org/2000/svg"></svg>

Upvotes: 3

Views: 1892

Answers (2)

Sampson
Sampson

Reputation: 268326

As far as SVG is concerned, the innerHTML property hasn't quite landed yet, but it's close. Currently Chrome and Firefox both support it on the Element interface, but Internet Explorer does not. Given its condition, the Mozilla Developer Network provides the following warning:

This is an experimental API that should not be used in production code.

The Internet Explorer team does have an internal ticket filed to consider adding similar support in future builds of Internet Explorer. Until that happens, there is a way you can achieve the line-break in IE, Chrome, and Firefox.

I must warn you though; behind this point lie dragons (we're about to do some non-standard stuff that could totally break in the future. We shall never again speak of this.).

Let's start by creating a document fragment with at least three elements: Two lines of text, separated by a <br> element.

var fragment = document.createDocumentFragment();

fragment.appendChild(document.createTextNode("First Line\r"));
fragment.appendChild(document.createElement("br"));
fragment.appendChild(document.createTextNode("Second Line"));

Next, let's pass that fragment directly into the createPathContent method:

createPathContent(svgID, fragment, "M 10 10 L 90 10 L 90 45 L 10 45 Z");

Lastly, let's append the fragment as a child to the <title> element:

popup.appendChild(popupText);

The above gives a consistent representation of the lines when you mouse over the element. Again, note that the tooltip rendered is a largely unpredictable beast. The results we see today could change in the future.

Fiddle: http://jsfiddle.net/rnhy9pus/4/

Upvotes: 2

user4290478
user4290478

Reputation:

    function createPathContent(svgID, popupText, pathDirections)
    {
        var path = document.createElementNS("http://www.w3.org/2000/svg","path");
        path.setAttribute("d",pathDirections);
        var popup = document.createElementNS("http://www.w3.org/2000/svg","title");
     // popup.textContent = popupText; // <-- LINE TO FOCUS ON
popup.textContent=" "
//popup.firstChild.nodeValue=popupText
popup.firstChild.nodeValue='Edgar'
Node.prototype.appendChild.call(popup, document.createElement("br"))
Node.prototype.appendChild.call(popup, document.createTextNode('Allen Poe.'))
        path.appendChild(popup);
        document.getElementById(svgID).appendChild(path);
    }


It always makes my head spin when I try to figure out if textContent is officially supposed to interpret \n (\x0A \u000A ...) as anything except whitespace.

textContent:
http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Node3-textContent

Interface Text:
http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1312295772

Interface CharacterData:
http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-FF21A306

Anyway, I made an exercise with some primitives, above. I hope you'll find this as instructive as I did. It produces the tooltip with "Edgar" on one line, and "Allen Poe." on the next.


function createPathContent(svgID, popupText, pathDirections)
{
    var path = document.createElementNS("http://www.w3.org/2000/svg","path");
    path.setAttribute("d",pathDirections);
    var popup = document.createElementNS("http://www.w3.org/2000/svg","title");
    //popup.textContent = popupText; // <-- LINE TO FOCUS ON

          popupText= popupText.split('\n')                                                  // note: firefox needs "\r" passed in "\r\n".
          while (true) { popup.appendChild(document.createTextNode(popupText.shift()))      // note: "" here is ok, will be appended as empty #text node
                         if (popupText.length) popup.appendChild(document.createElement("br"))
                         else break }

    path.appendChild(popup);
    document.getElementById(svgID).appendChild(path);
}


Here's a working patch within the function itself. It makes use of Jonathan's slick trick, that Firefox needs the "\r" whereas IE and Chrome are happy with <br>.

Upvotes: 1

Related Questions