Skip to content

Instantly share code, notes, and snippets.

@rxhanson
Last active January 5, 2021 21:10
Show Gist options
  • Save rxhanson/d43a457f1c3370f96f842edb2af64fe5 to your computer and use it in GitHub Desktop.
Save rxhanson/d43a457f1c3370f96f842edb2af64fe5 to your computer and use it in GitHub Desktop.
// working one pulled from https://github.com/nytimes/svg-crowbar/issues/31#issuecomment-421054505
// Changing that to ss.hasOwnProperty('cssRules') fixed the issue for me.
!function(){var t='<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';window.URL=window.URL||window.webkitURL;var e,n,o=document.body,l={xmlns:"http://www.w3.org/2000/xmlns/",xlink:"http://www.w3.org/1999/xlink",svg:"http://www.w3.org/2000/svg"};function s(t){var e="untitled";t.id?e=t.id:t.class?e=t.class:window.document.title&&(e=window.document.title.replace(/[^a-z0-9]/gi,"-").toLowerCase());var n=window.URL.createObjectURL(new Blob(t.source,{type:"text/xml"})),l=document.createElement("a");o.appendChild(l),l.setAttribute("class","svg-crowbar"),l.setAttribute("download",e+".svg"),l.setAttribute("href",n),l.style.display="none",l.click(),setTimeout(function(){window.URL.revokeObjectURL(n)},10)}e=[window.document],n=[],iframes=document.querySelectorAll("iframe"),objects=document.querySelectorAll("object"),[].forEach.call(iframes,function(t){try{t.contentDocument&&e.push(t.contentDocument)}catch(t){console.log(t)}}),[].forEach.call(objects,function(t){try{t.contentDocument&&e.push(t.contentDocument)}catch(t){console.log(t)}}),e.forEach(function(e){for(var o,s,r,i=function(t){var e="",n=t.styleSheets;if(n)for(var o=0;o<n.length;o++)l(n[o]);function l(t){if(t.hasOwnProperty("cssRules"))for(var n=0;n<t.cssRules.length;n++){var o=t.cssRules[n];3===o.type?l(o.styleSheet):o.selectorText&&-1===o.selectorText.indexOf(">")&&(e+="\n"+o.cssText)}}return e}(e),c=(o=i,s=[],r=e.querySelectorAll("svg"),o=void 0===o?"":o,[].forEach.call(r,function(e){e.setAttribute("version","1.1");var n=document.createElement("defs");e.insertBefore(n,e.firstChild);var r=document.createElement("style");n.appendChild(r),r.setAttribute("type","text/css"),e.removeAttribute("xmlns"),e.removeAttribute("xlink"),e.hasAttributeNS(l.xmlns,"xmlns")||e.setAttributeNS(l.xmlns,"xmlns",l.svg),e.hasAttributeNS(l.xmlns,"xmlns:xlink")||e.setAttributeNS(l.xmlns,"xmlns:xlink",l.xlink);var i=(new XMLSerializer).serializeToString(e).replace("</style>","<![CDATA["+o+"]]></style>"),c=e.getBoundingClientRect();s.push({top:c.top,left:c.left,width:c.width,height:c.height,class:e.getAttribute("class"),id:e.getAttribute("id"),childElementCount:e.childElementCount,source:[t+i]})}),s),a=0;a<c.length;a++)n.push(c[a])}),n.length>1?function(t){var e;e=document.querySelectorAll(".svg-crowbar"),[].forEach.call(e,function(t){t.parentNode.removeChild(t)}),t.forEach(function(e){t.forEach(function(t){e!==t&&Math.abs(e.top-t.top)<38&&Math.abs(e.left-t.left)<38&&(t.top+=38,t.left+=38)})});var n=document.createElement("div");o.appendChild(n),n.setAttribute("class","svg-crowbar"),n.style["z-index"]=1e7,n.style.position="absolute",n.style.top=0,n.style.left=0;var l=document.createElement("div");o.appendChild(l),l.setAttribute("class","svg-crowbar"),l.style.background="rgba(255, 255, 255, 0.7)",l.style.position="fixed",l.style.left=0,l.style.top=0,l.style.width="100%",l.style.height="100%",t.forEach(function(t,e){var o=document.createElement("div");n.appendChild(o),o.setAttribute("class","svg-crowbar"),o.style.position="absolute",o.style.top=t.top+document.body.scrollTop+"px",o.style.left=document.body.scrollLeft+t.left+"px",o.style.padding="4px",o.style["border-radius"]="3px",o.style.color="white",o.style["text-align"]="center",o.style["font-family"]="'Helvetica Neue'",o.style.background="rgba(0, 0, 0, 0.8)",o.style["box-shadow"]="0px 4px 18px rgba(0, 0, 0, 0.4)",o.style.cursor="move",o.textContent="SVG #"+e+": "+(t.id?"#"+t.id:"")+(t.class?"."+t.class:"");var l=document.createElement("button");o.appendChild(l),l.setAttribute("data-source-id",e),l.style.width="150px",l.style["font-size"]="12px",l.style["line-height"]="1.4em",l.style.margin="5px 0 0 0",l.textContent="Download",l.onclick=function(e){s(t)}})}(n):n.length>0?s(n[0]):alert("The Crowbar couldn’t find any SVG nodes.")}();
// original
(function() {
var doctype = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';
window.URL = (window.URL || window.webkitURL);
var body = document.body;
var prefix = {
xmlns: "http://www.w3.org/2000/xmlns/",
xlink: "http://www.w3.org/1999/xlink",
svg: "http://www.w3.org/2000/svg"
}
initialize();
function initialize() {
var documents = [window.document],
SVGSources = [];
iframes = document.querySelectorAll("iframe"),
objects = document.querySelectorAll("object");
[].forEach.call(iframes, function(el) {
try {
if (el.contentDocument) {
documents.push(el.contentDocument);
}
} catch(err) {
console.log(err)
}
});
[].forEach.call(objects, function(el) {
try {
if (el.contentDocument) {
documents.push(el.contentDocument);
}
} catch(err) {
console.log(err)
}
});
documents.forEach(function(doc) {
var styles = getStyles(doc);
var newSources = getSources(doc, styles);
// because of prototype on NYT pages
for (var i = 0; i < newSources.length; i++) {
SVGSources.push(newSources[i]);
};
})
if (SVGSources.length > 1) {
createPopover(SVGSources);
} else if (SVGSources.length > 0) {
download(SVGSources[0]);
} else {
alert("The Crowbar couldn’t find any SVG nodes.");
}
}
function createPopover(sources) {
cleanup();
sources.forEach(function(s1) {
sources.forEach(function(s2) {
if (s1 !== s2) {
if ((Math.abs(s1.top - s2.top) < 38) && (Math.abs(s1.left - s2.left) < 38)) {
s2.top += 38;
s2.left += 38;
}
}
})
});
var buttonsContainer = document.createElement("div");
body.appendChild(buttonsContainer);
buttonsContainer.setAttribute("class", "svg-crowbar");
buttonsContainer.style["z-index"] = 1e7;
buttonsContainer.style["position"] = "absolute";
buttonsContainer.style["top"] = 0;
buttonsContainer.style["left"] = 0;
var background = document.createElement("div");
body.appendChild(background);
background.setAttribute("class", "svg-crowbar");
background.style["background"] = "rgba(255, 255, 255, 0.7)";
background.style["position"] = "fixed";
background.style["left"] = 0;
background.style["top"] = 0;
background.style["width"] = "100%";
background.style["height"] = "100%";
sources.forEach(function(d, i) {
var buttonWrapper = document.createElement("div");
buttonsContainer.appendChild(buttonWrapper);
buttonWrapper.setAttribute("class", "svg-crowbar");
buttonWrapper.style["position"] = "absolute";
buttonWrapper.style["top"] = (d.top + document.body.scrollTop) + "px";
buttonWrapper.style["left"] = (document.body.scrollLeft + d.left) + "px";
buttonWrapper.style["padding"] = "4px";
buttonWrapper.style["border-radius"] = "3px";
buttonWrapper.style["color"] = "white";
buttonWrapper.style["text-align"] = "center";
buttonWrapper.style["font-family"] = "'Helvetica Neue'";
buttonWrapper.style["background"] = "rgba(0, 0, 0, 0.8)";
buttonWrapper.style["box-shadow"] = "0px 4px 18px rgba(0, 0, 0, 0.4)";
buttonWrapper.style["cursor"] = "move";
buttonWrapper.textContent = "SVG #" + i + ": " + (d.id ? "#" + d.id : "") + (d.class ? "." + d.class : "");
var button = document.createElement("button");
buttonWrapper.appendChild(button);
button.setAttribute("data-source-id", i)
button.style["width"] = "150px";
button.style["font-size"] = "12px";
button.style["line-height"] = "1.4em";
button.style["margin"] = "5px 0 0 0";
button.textContent = "Download";
button.onclick = function(el) {
// console.log(el, d, i, sources)
download(d);
};
});
}
function cleanup() {
var crowbarElements = document.querySelectorAll(".svg-crowbar");
[].forEach.call(crowbarElements, function(el) {
el.parentNode.removeChild(el);
});
}
function getSources(doc, styles) {
var svgInfo = [],
svgs = doc.querySelectorAll("svg");
styles = (styles === undefined) ? "" : styles;
[].forEach.call(svgs, function (svg) {
svg.setAttribute("version", "1.1");
var defsEl = document.createElement("defs");
svg.insertBefore(defsEl, svg.firstChild); //TODO .insert("defs", ":first-child")
// defsEl.setAttribute("class", "svg-crowbar");
var styleEl = document.createElement("style")
defsEl.appendChild(styleEl);
styleEl.setAttribute("type", "text/css");
// removing attributes so they aren't doubled up
svg.removeAttribute("xmlns");
svg.removeAttribute("xlink");
// These are needed for the svg
if (!svg.hasAttributeNS(prefix.xmlns, "xmlns")) {
svg.setAttributeNS(prefix.xmlns, "xmlns", prefix.svg);
}
if (!svg.hasAttributeNS(prefix.xmlns, "xmlns:xlink")) {
svg.setAttributeNS(prefix.xmlns, "xmlns:xlink", prefix.xlink);
}
var source = (new XMLSerializer()).serializeToString(svg).replace('</style>', '<![CDATA[' + styles + ']]></style>');
var rect = svg.getBoundingClientRect();
svgInfo.push({
top: rect.top,
left: rect.left,
width: rect.width,
height: rect.height,
class: svg.getAttribute("class"),
id: svg.getAttribute("id"),
childElementCount: svg.childElementCount,
source: [doctype + source]
});
});
return svgInfo;
}
function download(source) {
var filename = "untitled";
if (source.id) {
filename = source.id;
} else if (source.class) {
filename = source.class;
} else if (window.document.title) {
filename = window.document.title.replace(/[^a-z0-9]/gi, '-').toLowerCase();
}
var url = window.URL.createObjectURL(new Blob(source.source, { "type" : "text\/xml" }));
var a = document.createElement("a");
body.appendChild(a);
a.setAttribute("class", "svg-crowbar");
a.setAttribute("download", filename + ".svg");
a.setAttribute("href", url);
a.style["display"] = "none";
a.click();
setTimeout(function() {
window.URL.revokeObjectURL(url);
}, 10);
}
function getStyles(doc) {
var styles = "",
styleSheets = doc.styleSheets;
if (styleSheets) {
for (var i = 0; i < styleSheets.length; i++) {
processStyleSheet(styleSheets[i]);
}
}
function processStyleSheet(ss) {
if (ss.cssRules) {
for (var i = 0; i < ss.cssRules.length; i++) {
var rule = ss.cssRules[i];
if (rule.type === 3) {
// Import Rule
processStyleSheet(rule.styleSheet);
} else {
// hack for illustrator crashing on descendent selectors
if (rule.selectorText) {
if (rule.selectorText.indexOf(">") === -1) {
styles += "\n" + rule.cssText;
}
}
}
}
}
}
return styles;
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment