include css styles of shadowed elements into extracted print content - javascript

I want to print only a part of a website for this I construct a seconds window like follows:
const prtStyles = document.getElementsByTagName('style');
const prtContent = document.getElementsByTagName('some-container')[0];
const WinPrint = window.open('', '', 'left=0,top=0,width=800,height=900,toolbar=0,scrollbars=0,status=0');
WinPrint.document.write(extractStyles(prtStyles) + prtContent.innerHTML);
WinPrint.document.close();
WinPrint.focus();
WinPrint.print();
WinPrint.close();
function extractStyles(prtStyles) {
let styles = '';
for (let i = 0; i < prtStyles.length; i++) {
styles += prtStyles[i].outerHTML;
}
return styles;
}
This works quite fine but now, because I use WebComponents with shadowedRoot to display certain parts like headings or buttons those stylings added to these components are inside a constructed Stylesheet.
Is it possible to access those shadowed styles in some way and include them into new print window?
I can't find those styles rendered inside the dom itself.

Related

How to remove all tags from the head section with a same attribute and tag name

I am making a JS function, which will change the icon of the document. Now, I know that this sounds simple, but it is not. I am trying to make a Library, so I need a function that can change the default icon to the desired icon and vice versa. It works fine if I try to change the default icon to the desired icon, but if I try to change the icon to the default one(the one with a gray globe), it does not work.
icon = function(dir){
if(typeof(dir)==="string"){
var elem = doc.createElement('link');
elem.rel = "icon";
elem.href = dir;
doc.head.append(elem);
}else if(typeof(dir)==="boolean"&&dir===false){
var toBeDel = [];
var currElems = document.querySelectorAll('link');
var i = 0; var f = 0;
while(currElems.length>=0){
if(currElems[i].rel=="icon"){
toBeDel.push(currElems[i]);
currElems.length--;
i++;
}
}
while(toBeDel.length>=0){
doc.head.removeChild(toBeDel[f]);
toBeDel.length--;
f++;
}
var elem = doc.createElement('link');
elem.rel = "icon";
elem.href = "/default/noimage.png";
doc.head.append(elem);
window.setTimeout(function(){
console.clear();
var len = efun.logs.length;
var sen;
var i = 0;
while(len>=0){
sen = efun.logs[i];
efun.gh = sen[0];
console.defaultLog(sen[0]);
len--;
i++;
}
},10);
}
else{
efun.cons("Error in icon() function, the parameter you have entered is not a string directory.");
}
}
Note: efun object is the main library object, efun.cons() is a shortcut to console.log(), efun.logs is an array which contains all console.logs() done. Note that I called the console.clear() function to remove the error which comes when I try to set the default icon since it does not exist. console.deafultLog() is a function, which console.logs() with it not being pushed into the efun.logs array. But the error is that I want to remove all the <link rel="icon" href="<!---directory here-->" elements from the head tag. There can be many elements with icons, so I want to remove all of them. For this, I used document.querySelectorAll() in an array, and did several while loops. But still, even though a new link element gets appended into the <head> tag, the previous ones which I want to remove remains there, so how can I remove all tags with <link> tag and rel="icon" attribute. Is there any fix to this?
I think you may have overcomplicated this.
You can delete all existing <link> tags with just one line
document.querySelectorAll('link[rel="icon"]').forEach(link => link.remove());
To revert back to the "globe" icon, you just need to change the url to something that doesnt exist.
var link = document.createElement('link');
link.rel = 'icon';
link.href = 'https://fake.url.com/';
document.getElementsByTagName('head')[0].appendChild(link);
If you want to handle errors better, you can use try catch blocks.

Javascript: Open new window and copy over css references from the current window

I want to open a new window and copy over the css references from the current window so that my new window has the same styling. What I've tried is the following:
var externalWindow = window.open('', '', 'width=600,height=400,left=200,top=200');
var headElements = window.document.head.childNodes;
for(var i = 0; i < headElements.length; i++)
{
externalWindow.document.head.appendChild(headElements[i]);
}
However, when I inspect the head element using devTools in the new window, the head element is empty. Using a debugger I can see that headElements is correctly getting the head elements from the current page and appendChild is running on all of them.
If I run:
externalWindow.document.body.appendChild(window.document.getElementById("MyElement"));
It copies over an element to the body, so why can't I copy over elements in the head?
as simple as:
document.head.querySelectorAll('link, style').forEach(htmlElement => {
newWindow.document.head.appendChild(htmlElement.cloneNode(true));
});
Before opening the new document, you could create a STYLE tag in the existing document and populate that with all of the styles from either the LINK or STYLE tags in the header. You could then just copy that tag into the end of the new document.
Something like the following:
function showStyles() {
let ss = document.styleSheets;
let copycss = document.createElement("style");
// div just to show that styles are being found
let copydiv = document.getElementById("copiedstyles");
for (let i = 0; i < ss.length; i++) {
for (let j = 0; j < ss[i].cssRules.length; j++) {
let css = ss[i].cssRules[j].cssText;
copycss.innerHTML += css + "\n";
// Just for testing
copydiv.innerHTML += css + "<br>";
}
}
copycss.innerHTML += "button {color:purple;}\n";
copydiv.innerHTML += "button {color:purple;}<br>";
document.body.appendChild(copycss);
}
.blah {color:red;}
button {color:green;}
<button onclick="showStyles();">Show styles</button>
<div id="copiedstyles"></div>

How to add a style attribute to an element if it doesn't exist or just add the given styles to the pre-existing style attribute using Javascript?

I want to make a script such that it adds an attribute style to an element with the given styles if it doesn't exist or just simply add the given styles to the pre-existing style attribute. Here is a piece of the code I wrote :
var style = function(sel, styl) {
var rVselect = document.querySelector(sel);
rVselect.getAttributeNode("style").value += styl;
};
This works perfect but has a problem. This only works when there is a style attribute ( doesn't matter empty or have some content ) given to the element. I want it make a style attribute in absense of it and then insert the styles and in work as it is working now in presense of the style attribute i.e. just simply add the new styles to the pre-existing style attribute.
Thanks in advance !
Its very simple. Here is a piece of code :
var style = function(sel, styl) {
var rVselect = document.querySelector(sel);
rVselect.style += styl;
};
If you want to add this to all matching elements go for this :
var style = function(sel, styl) {
var rVselect = document.querySelectorAll(sel);
for( var i = 0; i < rVselect.length; ++i ) {
rVselect[i].style += styl;
};
};
function(sel, styl) {
var rVselect = document.querySelector(sel);
rVselect.style = rVselect.style + styl;
};
It takes existed styles and add styles passed to argument

Can't change html attribute via javascript

This is very odd, I'm getting videos via document.getElementsByTag('video') and I can't change their width nor any other value.
Here's the Javascript code I'm using -
window.onload = function() {
this.videos = document.getElementsByTagName('video');
var self = this;
for(var i=0;i<videos.length;i++) {
videos.item(i).addEventListener("loadedmetadata",
(function(index){
return function() {
console.log(self.videos[index].offsetWidth); //shows X
self.videos[index].offsetWidth = "480";
console.log(self.videos[index].offsetWidth); //shows X
}
})(i)
);
}
}
Example <video> tag -
<video><source src="videos/video_1.mp4" type="video/mp4"></video>
I have no idea what it is happening and I've never encountered such kind of problem.
Thanks
EDIT:
Using the setAttribute function just adds it to the live html, but the size isn't really changing
The offsetWidth is a read-only DOM property so you can not update it. However why not change the element width?
window.onload = function() {
this.videos = document.getElementsByTagName('video');
var self = this;
for(var i=0;i<videos.length;i++) {
videos.item(i).addEventListener("loadedmetadata",
(function(index){
return function() {
self.videos[index].width = "480";
}
})(i));
}
}
You can take into account the borders, paddings, margins...
Note there is a difference between three things you are conflating into one:
HTML attributes
DOM properties
CSS styles
This is an HTML attribute:
If you have a DOM element representing an HTML tag, you can modify the attributes like so:
var a = document.createElement('a')
a.setAttribute('href', "http://example.com")
This is a DOM property:
var a = document.createElement('a')
a.href = "http://example.com"
Note how a DOM property can be similarly named to an HTML attribute, but they are not the same thing. Oftentimes, changing an HTML attribute will modify the corresponding DOM property, but not vice versa. Also, not all attributes have matching properties, and so on.
CSS styles are accessed via the DOM property style(which corresponds to the HTML attribute style, but while the HTML attribute style is a string, the DOM property is an object):
var a = document.createElement('a');
a.style.width = "500px";
a.style.height = "20%";
There are HTML attributes "width" and "height", but their use is deprecated in favor of using styles. Also, "width" and "height" as HTML attributes can only be numerical values representing pixels - while a CSS style can be many variations(pixels, ems, percentages, etc)
In your specific case, just modify the width styling of your element to change its width.
Another thing in your code is the usage of this and self, which is entirely unneeded. this.videos is setting a property on the global object(window) for no reason. You can also avoid closing over the index property by using .bind():
window.onload = function() {
var videos = document.getElementsByTagName('video');
for (var i = 0; i < videos.length;i++) {
var video = videos.item(i);
video.addEventListener("loadedmetadata", (function () {
console.log(this.offsetWidth);
this.style.width = "480px";
console.log(this.offsetWidth);
}).bind(video));
}
}
Try using getAttribute and setAttribute, as in videos[index].setAttribute('offsetWidth', 480)
First off, this doesn't seem right:
for(var i=0;i<videos.length;i++) {
Shouldn't it be self.videos? Fix that.
Then, to change the video size, you can change the size of the element:
self.videos[index].width = "480";
or, even better, the CSS width:
self.videos[index].style.width = "480px";
The size of the video itself will automatically extend to the size of the video element.

javascript getComputedStyle, but not inherited ones (in chrome)

I want to get only the computed styles of the elements on a page, without all the inherited styles
var allElements = document.querySelectorAll( '*' );
for (var i=0;i<allElements.length;i++){
var element = allElements[i];
var css = getComputedStyle(element);
}
this obviously gets a gigantic list of all the styles.
I need only the 'computed styles' that would show up in Chrome's inspector thing when the "show inherited" checkbox is disabled.
What's the JS for this?
EDIT:
I'm basically looking to save all the css I've modified in Chrome inspector. I'm laying out things on a page and I'm playing with fonts and elements placement (dragging jquery draggables around). I want to save the positions and CSS of everything.
Maybe I went way too complex and there's a simple way to save all the modified styles in Chrome inspector?
Try getting computed styles of an element and its parent element, then remove identical properties:
var elems = document.getElementsByTagName('*');
var data = '';
for(var n=0;n<elems.length;n++){
if(elems[n].parentNode.tagName){
data+=elems[n].tagName + ': ' + elems[n].className+'\n';
var style = [];
var prStyle = [];
var result = [];
var css = window.getComputedStyle(elems[n], null);
var prCss = window.getComputedStyle(elems[n].parentNode, null);
for(var i=0;i<css.length;i++){
if(css.getPropertyValue(css[i])){
style[i] = css[i]+':'+css.getPropertyValue(css[i]);
}
}
for(var i=0;i<prCss.length;i++){
if(prCss.getPropertyValue(prCss[i])){
prStyle[i] = prCss[i]+':'+prCss.getPropertyValue(prCss[i]);
}
}
for(var i=0;i<style.length;i++){
if(style[i]!=prStyle[i]){
result.push(style[i]);
}
}
for(var i=0;i<result.length;i++) data+=i+':'+result[i]+'\n';
}
data+='-----------------------\n';
}
return data;

Categories