From 321971e611947bc3f0ccd2bcb6c58ba4047a6ff7 Mon Sep 17 00:00:00 2001 From: batram Date: Mon, 15 Apr 2019 16:28:10 +0200 Subject: [PATCH] fix(api): Fix css encoding in exported svg Encode all style elements before including them in export svg, to avoid XML special character problems. Added a test for export with "weird" css. Fix #843 Close #844 --- spec/api/api.export-spec.js | 14 ++++++++++++++ src/api/api.export.js | 18 +++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/spec/api/api.export-spec.js b/spec/api/api.export-spec.js index e71d4b48a..2edd776e2 100644 --- a/spec/api/api.export-spec.js +++ b/spec/api/api.export-spec.js @@ -101,4 +101,18 @@ describe("API export", () => { }); }, 500); }); + + it("should export valid svg even with weird css", () => { + document.body.innerHTML += ``; + + const dataURL = chart.export(); + + // test generated svg + const svg = atob(dataURL.split("base64,")[1]); + const oParser = new DOMParser(); + const doc = oParser.parseFromString(svg, "image/svg+xml"); + + // check that it does not start with error message + expect(doc.documentElement.nodeName === "svg").to.be.true; + }); }); diff --git a/src/api/api.export.js b/src/api/api.export.js index b373776c0..4102b4045 100644 --- a/src/api/api.export.js +++ b/src/api/api.export.js @@ -25,20 +25,28 @@ const b64EncodeUnicode = str => btoa( * @private */ const nodeToSvgDataUrl = (node, size) => { + const serializer = new XMLSerializer(); const clone = node.cloneNode(true); - const styleSheets = toArray(document.styleSheets); - const cssRules = getCssRules(styleSheets); - const cssText = cssRules.filter(r => r.cssText).map(r => r.cssText); + const cssText = getCssRules(toArray(document.styleSheets)) + .filter(r => r.cssText) + .map(r => r.cssText); clone.setAttribute("xmlns", d3Namespaces.xhtml); - const nodeXml = new XMLSerializer().serializeToString(clone); + const nodeXml = serializer.serializeToString(clone); + + // escape css for XML + const style = document.createElement("style"); + + style.appendChild(document.createTextNode(cssText.join("\n"))); + + const styleXml = serializer.serializeToString(style); // foreignObject not supported in IE11 and below // https://msdn.microsoft.com/en-us/library/hh834675(v=vs.85).aspx const dataStr = ` - + ${styleXml} ${nodeXml.replace(/(url\()[^#]+/g, "$1")} ` .replace("/\n/g", "%0A");