Retrieving the actual DOM/css state of a web page through javascript - javascript

As you know, a web page is the union of a html file, one or more css files and one or more javascript files: the first two elements are parsed by the browser to generate the DOM and other data structures useful for the rendering of the page .
Javascript files are executed by an engine, and they can change the value of the DOM or of the data structures related to css, so that, after the execution of a javascript, the "actual status" of a web page can be different from what was statically described by the original html and css code.
I need to develop a firefox add-on that grabs the "actual status" of a web page and stores it to disk, as a couple html + css file.
For the html file is quite easy, i need to serialize the DOM. My concerns are about the css: I can traverse the DOM and for each element get its stylesheet, but it will be
extremely slow and produces a not optimized css code.
Let's make an example
I have this html code:
<html>
<head>
<title>Test</title>
<link type="text/css" rel="stylesheet" href="style.css" />
<script type='text/javascript' src="changebackground.js" > </script>
</head>
<body>
<div class="divclass" >
<form>
<h2>click to change the background</h2>
<input type="button" value="version" onclick="changebg()" />
</form>
</div>
</body>
Style.css has this definitions:
.divclass{
margin: .5in;
height: 400px;
}
body{
background-color: white;
color: blueviolet;
}
and changebackground has this code:
function changebg() {
document.body.style.backgroundColor = 'black';
}
Obviously, after clicking the button the background's color becomes black.
My goal is to write an add-on that , after this change, gives me back the css with the style's modification, i.e.:
.divclass{
margin: .5in;
height: 400px;
}
body{
background-color: black;
color: blueviolet;
}
Any ideas?

You don't actually need to traverse anything. Inline styles are already part of the, so you get that for free, e.g.:
elem.style.width = "100px";
elem.outerHTML == '<elem style="width: 100px;>";
So to produce a "dump" of the current DOM, incl. inline styles, etc. do:
var html = document.documentElement.outerHTML;
You may also want to serialize document.doctype.
In the unlikely event that a script actually messes with external stylesheets (<link rel="stylesheet">, you may do something like what I described in "Get text of a modified stylesheet" to get the current set of rules. Again, inline styles (<style> and style= attributes) are already present in .outerHTML.
EDIT: What you ask now is not possible, because this is not how inline styles work.
Consider the following html fragment:
<div>first div</div>
<div>second div</div>
Now the following code runs:
document.querySelector("div").style.background = "black";
This will cause the first div to have an inline style:
<div style="background: none repeat scroll 0% 0% black;">first div</div>
<div>second div</div>
Demo Fiddle
How would that rule look like? div { background: black; } is obviously wrong, as this would affect all divs.
You could generate new classes and/or ids, but then you need to manipulate and store the DOM, and could have used my original answer in the first place.

Related

Update style of already rendered webpage by using js to load a css stylesheet

I'm currently trying to load some CSS file into a page that has already been loaded and rendered by the browser and apply it's styling to the page without reloading it as a whole.
I can't modify the original page too much, so the CSS has to be linked/included in the html at a later moment using JavaScript. I tried adding a <link> element referring to the CSS file in the header, as well as adding <style> with the CSS itself.
The modification of the html does work fine, but the layout of the page isn't affected at all. Probably because the browser doesn't re-render the page at this point?
I saw some answers here suggesting that it would work like described above, but for me it does nothing. What could be the reason here?
As requested, some of the JavaScript i'm using to update the HTML of the page. Both ways work fine, the elements are added to the page. So I presume the error lies somewhere else.
1.) Adding actual CSS by reading it with XHR from file:
var promptCSS= document.createElement('style');
promptCSS.type="text/css";
var cssPromptFileSelectStyleURL= 'promptFileSelectStyle.css';
//add css of prompt into current page html
var cssFile = new XMLHttpRequest();
cssFile.open("GET",cssPromptFileSelectStyleURL,true);
cssFile.send();
cssFile.onreadystatechange = function(){
if (cssFile.readyState== 4 && cssFile.status == 200){
promptCSS.innerHTML=cssFile.responseText;
}};
var head=document.querySelectorAll("head")[0];
head.appendChild(promptCSS);
2.) adding <link> referencing CSS file
var promptCSS= document.createElement('link');
promptCSS.rel = 'stylesheet';
promptCSS.type = 'text/css';
promptCSS.href = 'promptFileSelectStyle.css';
var head=document.querySelectorAll("head")[0];
head.appendChild(promptCSS);
Inline CSS isn't set between <script> tags, but between <style> tags.
Also here is a Fiddle that tests your method : https://jsfiddle.net/sLpfLsLc/
It waits 2 seconds before loading a new CSS file containing
*{
background: red;
}
As you can see, it works fine !
Maybe this will point you in the right direction. I am not 100% sure I understood what you need. So if this is the case you can try appending a link tag with the css file url in it whenever you need. For instance you can trigger that script when you scroll X height or a click happened or whatever. For this case I am appending a style tag to the head every 2 seconds and then removing it so it won't keep appending every 2 seconds. Instead of style maybe you can do a <link rel="stylesheet" type="text/css" href="promptFileSelectStyle.css"/>
Hope this helps.
function remover(){
$(".style-tag").remove();
}
function x(){
var style = $('<style class="style-tag">.columns {justify-content: space-around;} </style>');
$('html > head').append(style);
$(".parent").toggleClass("columns");
}
$(document).ready(function(){
setInterval(function(){
remover();
x();
}, 2000);
});
.parent{
display:flex;
justify-content: center;
flex-wrap: wrap;
width: 100%;
}
.box{
background: red;
border: 1px solid black;
width: 100px;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent">
<div class="box">content</div>
<div class="box">content</div>
<div class="box">content</div>
<div class="box">content</div>
<div class="box">content</div>
</div>

CSS - Isolate elements inside div from global page styles as if it were an iFrame?

Is it possible to isolate elements inside a div as if it were in an iFrame?
I have an app inside SharePoint that is all jacked up from the global SharePoint styles which I want to turn off completely so my app uses only the css it contains.
EG: Let's say there is a global stylesheet for the page. Let's say I put a div on that page with it's own embed css. Can I somehow ignore the global stylesheet entirely?
https://plnkr.co/edit/2H2TJJz6rNZK18OK6VLW?p=preview
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Global parent element - red</h1>
<div class="self-contained-css">
<style type="text/css">
h1 {
color:red;
border: 1px solid blue;
}
</style>
<h1>Self contained css element - blue</h1>
<p>Self contained css should behave as if it was inside an iFrame. This is to isolate from SharePoint css ultimately.</p>
</div>
</body>
</html>
Web Components would be your only option for encapsulation similar to an iframe. You can get pretty good coverage with a polyfill like webcomponents.js
Polymer is a great framework for making Web Components easier.
This would make your code look like this:
... HTML here that uses your global styles ...
<my-element></my-element> <!-- this element would not inherit the global CSS -->
And inside of your my-element component (which would just be another file in your file system that you import into the page - see docs above), you can include unique styles to the content of my-element.
The problem is your global styles have a !important declaration in them. While I don't normally advise this, you'd have to add it to your declaration to be able to override them. i.e.
/* Global parent styles go here */
h1 {
color:red;
border: 5px solid red !important;
}
h1 {
color:red;
border: 1px solid blue !important;
}
<body>
<h1>Global parent element - red</h1>
<div class="self-contained-css">
<style type="text/css">
h1 {
color:red;
border: 1px solid blue !important;
}
</style>
<h1>Self contained css element - blue</h1>
<p>Self contained css should behave as if it was inside an iFrame. This is to isolate from SharePoint css ultimately.</p>
</div>
use shadow dom in my case i use angular 1 so i used an iframe but in angular 2 we can play with shadow dom
Use an iFrame with the srcdoc attribute set to your html.
var myIframe = document.createElement('iframe');
myIframe.src = 'about:blank';
var info = `<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Global parent element - red</h1>
<div class="self-contained-css">
<style type="text/css">
h1 {
color:red;
border: 1px solid blue;
}
</style>
<h1>Self contained css element - blue</h1>
<p>Self contained css should behave as if it was inside an iFrame. This is to isolate from SharePoint css ultimately.</p>
</div>
</body>
</html>`;
myIframe.srcdoc = info;
var body = window.document.querySelector('body');
body.insertBefore(myIframe, body.firstChild);
I needed to dynamically inject my html content without being impacted by the pages css so that is why my iframe was created with js, but shouldn't be any reason that yours couldn't be written in html only. Although the srcdoc might be a little messy, so it might be cleaner to write it (the srcdoc) as a js variable and then attach it.

javascript - How to use a image file relative to a url path?

Is there a way to use a image url relative path in a javascript file (just like the css files)?
for testing i used 2 divs and displayed a gif in background using css in 1st and using js in second:
-my file directory is:
root/index.html
root/module1/test.css
root/module1/test.js
root/module1/img.gif
-index.html code:
<html>
<head>
<link href="module1/test.css" rel="stylesheet" type="text/css">
</head>
<body>
<P id="p1"> Line 1 </P>
<P id="p2"> Line 2 </P>
<script type="text/javascript" src="module1/test.js"></script>
</body>
</html>
-test.css code:
#p2 {background: url('img.gif')}
in the css I can use the relative path.
-test.js code:
document.getElementById("p1").style.backgroundImage = 'url(./module1/img.gif)';
but in the js I have to use the absolute path or it doesn't work.
-img.gif - you can use any gif image.
I've tried to search the web but I was just getting confused :(
plz help :)
Ps: if you know a solution in jquery i also appreciate.
In a CSS style sheet, the path is interpreted relative to the style sheet.
If you specify a path later, using JavaScript, it will be interpreted relative to the document.
You can still use relative paths, but, as said, they will have to be relative to the document. So it would have to be
url("module1/img.gif");
But you already know that.
I don't know a way of building paths relative to the style sheet outside the style sheet.
The only workaround that comes to my mind is to define a class inside the style sheet and, instead of specifying a background image using javaScript, changing the element's class.
In the style sheet:
.p2_img_gif {background: url('img.gif')}
and when the time comes for the paragraph to get the background image, do a
document.getElementById("p2").className = "p2_img_gif";
if you need to toggle classes, or specify multiple ones, consider using jQuery's addClass() and removeClass().
As variant use element inline style
var element = document.getElementById("p1");
var imageUrl = './module1/img.gif';
element.setAttribute('style', 'background-image: url(' + imageUrl +');');
This works for me with Firefox 3.6.
<!doctype html>
<style>
div { background: red; width: 80px; height: 80px }
</style>
<script>
window.onload = function() {
document.getElementById("test").style.backgroundImage = 'url("green.png")';
}
</script>
<p>There should be no red.</p>
<div id="test"></div>
where green.png is a green pixel. Which browser are you using?

JavaScript question

It is possible not to show html page in user browser until some JavaScript(built-in or in separate file) will be loaded and executed(for page DOM manipulation)?
The easiest thing to do is to set the css variable
display: none;
to the whole page.
then when everything is loaded you can set the display to
display: block; // or something else that suits.
If you make sure that piece of CSS is loaded at the very start of your document it will be active before any html is shown.
if you use a javascript library like jQuery you'll have access to the $(document).ready() function, and can implement a switch over like this:
<html>
<head>
<title>test</title>
<style type="text/css">
body > div {
display: none;
}
</style>
<script type="text/javascript">
$(document).ready(function() {
$('body > div').css('display', 'block');
});
</head>
<body>
<div>
This will initially be hidden.
</div>
</body>
</html>
Not in the classical way you'd distribute a page. Browsers will (usually) start to display chunks of the base HTML file as it arrives.
Of course, you could simulate this by generating all the HTML on the fly from some included Javascript file. But that doesn't sound like a good plan as it will degrade horribly for people without JS enabled, or if you have a minor bug in your script. A better option might be to style the body tag to display: none and restyle it from the script to make certain parts visible again.
What is it you're actually trying to achieve? It sounds like there's likely to be a better way to do this...
Place the content of HTML page in a DIV, make its diplay none and on load of body diplay it.
<script type="text/javascript">
function showContent() {
var divBody=document.getElementById('divBody');
divBody.style.display= 'block';
}
</script>
<body onload="showContent()">
<div id="divBody" style="display: none;">
<--HTML of the page-->
</div>
</body>
Examples of what you might want to do:
Facebook's "BigPipe": http://www.facebook.com/notes/facebook-engineering/bigpipe-pipelining-web-pages-for-high-performance/389414033919
This method allows you to load JS first then ASYNC+inject all DOM content.
GMail
Zimbra (open-source web app similar to MS Outlook/Exchange)
My understanding is that you want to run some javascript code before you load the page. In the js file you write your init function and add the eventlistener to the window on "load" event. This will ensure that the init code gets executed first and then you can start displaying the HTML content.
var Yourdomain = {};
YourDomain.initPage = function(){
/* Your init code goes here*/
}
window.addEventListener("load", YourDomain.initPage, false);
All You really need to do is give your element an ID or CLASS and use the dislay: none; property. When your ready to show it just delete it.
CSS:
#div_1 {
display: none;
}
HTML:
<div id="div_1">
<p>This will be the hidden DIV element until you choose to display it.</p>
<p id="js_1"></p>
<script>
var x = "Some Test ";
var y = "Javascript";
document.getElementById("js_1").innerHTML = x + y;
</script>
</div>

How to change font color inside an existing script?

I get a script from a website to put it into my website, but the font color is not what I want.
The script is:
<script language="javascript" src="http://www.parstools.net/calendar/?type=2"></script>
and now I want to change the font color of it. What should I do?
I would really appreciate your help, thanks.
Examining the source of that script, it is simply writing an anchor link with document.write():
document.write("<a href='http://www.ParsTools.com/'>1389/1/31</a>");
You may want to include that script inside a <div>, and then style the anchor links within that <div> using CSS:
<div id="calendar">
<script src="http://www.parstools.net/calendar/?type=2"></script>
</div>
Then you should also add the following CSS class definition:
div#calendar a {
color: red;
}
The following is a full example:
<!DOCTYPE html>
<html>
<head>
<title>Simple Demo</title>
<style type="text/css">
div#calendar a {
color: red;
}
</style>
</head>
<body>
<div id="calendar">
<script src="http://www.parstools.net/calendar/?type=2"></script>
</div>
</body>
</html>
I assume you want to change the font colour of the HTML code produced by the script? If so, just use normal CSS in your external stylesheet and it will apply to the added content.
For example, if you want to make the text inside the element myElement a nice blue colour:
#myElement {
font-color: #0099FF;
}
If the script is not your own, then you will want to analyse the code produced by it to work out which elements you need to style in order to change the colour of the text. Many external scripts that you embed in your website contain inline CSS rules, meaning that you will have to override many elements in your external CSS stylesheet to change simple things like text colour. You may also have to add !important to the end of your CSS rule in order to override the inline styling:
#myElement {
font-color: #0099FF !important;
}

Categories