Reputation: 2251
I'm trying to make a web page "static", with all styles as inline. For this I first save all computed styles, then remove all applied style (class and css files), check the difference with saved styles and add inline for missing styles. This is my function:
var allstyles=null;
var allelms=null;
function FixHTML()
{
if (!allstyles)
{
console.log("remove scripts");
var elms=document.getElementsByTagName('SCRIPT');
for(var i=elms.length-1;i>-1;i--)
{
var elm=elms[i];
if (elm.tagName=="SCRIPT" && !elm.innerHTML.match(/FixHTML/))
{
elm.parentElement.removeChild(elm);
}
}
//sauvegarde des styles
console.log("save styles");
allstyles=[];
allelms=document.getElementsByTagName('*');
for(i=0;i<allelms.length;i++)
{
elm=allelms[i];
if (!elm.id)
elm.id="tmpid"+i;
var id=elm.id;
allstyles[id]=[];
var style=getStyleObject(elm);
for(var key in style)
{
allstyles[id][key]=style[key];
}
if (elm.className)
elm.className="";
}
console.log("delete stylesheet links");
elms=document.getElementsByTagName('LINK');
for(i=elms.length-1;i>-1;i--)
{
elm=elms[i];
console.log(elm.href);
if (elm.rel="stylesheet")
elm.href="nowhere";
}
}
setTimeout(RestoreClassStyles,2000);
}
function RestoreClassStyles()
{
console.log("restore class styles",allstyles);
allelms=document.getElementsByTagName('*');
for(var i=0;i<allelms.length;i++)
{
var elm=allelms[i];
var id=elm.id;
var style=getStyleObject(elm);
for(var key in allstyles[id])
{
if (allstyles[id][key]!=style[key])
{
console.log(key);
elm.style[key]=allstyles[id][key];
}
}
}
}
function getStyleObject(dom){
var style;
var returns = {};
if(window.getComputedStyle){
var camelize = function(a,b){
return b.toUpperCase();
};
style = window.getComputedStyle(dom, null);
for(var i = 0, l = style.length; i < l; i++){
var prop = style[i];
var camel = prop.replace(/\-([a-z])/g, camelize);
var val = style.getPropertyValue(prop);
returns[camel] = val;
};
return returns;
};
console.log("not found",elm);
return "";
}
It "works a bit" but some styles are incorrect so I need help to find what I'm missing in that code. Working example: http://jsfiddle.net/owecfdr2/
Upvotes: 1
Views: 613
Reputation: 1074495
Instead of using inline styles, I would convert the link
elements to style
elements. You can do that like this (I've stuck to ES5 because it looked like you were doing so in your code):
function linkToStyle(link) {
var css = [];
var sheet = link.sheet;
var rules = sheet.cssRules || sheet.rules;
for (var i = 0; i < rules.length; ++i) {
var rule = rules[i];
css.push(rule.cssText);
}
var style = document.createElement("style");
style.type = "text/css";
style.appendChild(
document.createTextNode(css.join("\r\n"))
);
return style;
}
document.querySelectorAll("link[rel=stylesheet]").forEach(function(link) {
var style = linkToStyle(link);
var parent = link.parentNode;
parent.insertBefore(style, link);
parent.removeChild(link);
});
That finds all the link
elements with rel="stylesheet"
and replaces them with style
elements with the same CSS text, by getting the CSS stylesheet object from the link
element, looping through its CSS rules, and using the cssText
of each rule.
As misorude points out in a comment, any URLs in the linked CSS stylesheets are relative to the stylesheet, not the page linking to the style sheet, so if your stylesheets and page are not in the same place from a URL perspective (e.g., same directory), it gets a bit more complicated: you'll have to adjust the URLs to account for that. A simple version would just handle rules of type CSSRule.STYLE_RULE
(which are CSSStyleRule
s), looping through the properties to find and adjust URLs. (If there are imports, it gets more complicated.)
That code relies on forEach
on the NodeList
returned by querySelectorAll
. Most browsers have that now; this answer shows how to detect if the browser doesn't and polyfill it.
Upvotes: 4