I read this Replacing background image using jQuery not working and quite a few other things but I'm having issues with this one.
I'm trying to find all divs/elements that contain a background-image: url();. IF they contain a background image with https://website.com/imagepath/image.jpg I want to remove the "https://website.com" piece and leave it as a local url only i.e. "/imagepath/image.jpg"
I'd like to do this in pure JS but I'm not opposed to jQuery
This would be incredibly taxing on performance and I would not recommend doing it this way.
You would have to go through every single element on the page and check its computed style and then update that if it matches your provided string.
const searchStr = 'https://website.com/imagepath/image.jpg';
const replaceStr = 'https://website.com/newimage.jpg';
const body = document.getElementsByTagName('body')[0];
const elements = Array.from(body.getElementsByTagName('*'));
elements.map(element => {
const style = window.getComputedStyle(element);
if (!!style.backgroundImage.includes(searchStr)) {
element.style.backgroundImage = replaceStr;
}
});
Related
Objective
Get the url of each image and add that as a background to it's parent article, in a vuejs project
Question
How should I refactor the code originally written in jQuery?
JS - original from other author
$(".polaroid").wrap("<div class='polaroid-frame'><div class='polaroid-image'>");
$(".polaroid").each(function() {
var $this = $(this);
var imgLink = $this.attr("src");
var bg = "url("+imgLink+")";
$this.closest(".polaroid-image").css({
"background-image": bg
});
});
JS - refactored for my project
$(".polaroid article img").each(function() {
var $this = $(this);
var imgLink = $this.attr("src");
var bg = "url("+imgLink+")";
$this.closest("article").css({
"background-image": bg
});
});
My demo on codepen
Background
I am taking code from another project but it was written in jQuery. I don't want to use jQuery, instead i just need to write this in ES6, or just plain javascript.
I so far found one related question, Finding closest element without jQuery , but it was too different to be able to make much use of it.
I looked at the mozilla documentation https://developer.mozilla.org/en-US/docs/Web/API/Element/closest , which leads me to think my code should translate to
el.closest("article");
but then how would I wrap that in a way that would pass the CSS values. I looked up documentation from w3 https://www.w3schools.com/js/js_htmldom_css.asp and found this example
document.getElementById("p2").style.color = "blue";
So I think I should do
document.[unclear what to do here].style.background-image = /* what goes here for the variable? */;
From your refactored JS, to translate it into plain JS, you need to
(1) Iterate over the selected elements (can be done easily with querySelectorAll)
(2) Get the element's src attribute
(3) Set the closest article's background-image to that src
So, it should be pretty simple:
document.querySelectorAll('.polaroid article img').forEach((img) => {
const { src } = img;
img.closest('article').style.backgroundImage = `url(${src})`;
});
Note that when setting style properties directly, sometimes the CSS string you'd want to use (eg. background-image) wouldn't be valid syntax in Javascript. In these cases, generally turn the words-separated-by-dashes into camelCase. (backgroundImage)
This question is similar (I think) to this question on SO: How to move all computed CSS styles from one element and apply them to a different element using JavaScript?
What I want to do is find all styles that have been applied by way of css sheets and set the explicitly (as in using a style= attribute) on the element. The reason I want to do this is so that MS Word (2010) will pick up the styling if I open it there
Here's my code
var $this = $(this);
var styles = window.getComputedStyle(this, null);
$this.css(styles);
I also tried with
var styles = document.defaultView.getComputedStyle(this, null);
When I put a try catch around the last line ($this.css(styles), I am getting an error message "invalid calling object". I don't understand what the problem is
Well, the following snippet does what you want, though I don't think it's what you needed. MS Word is NOT a browser, I'm not sure if it supports all the styles or if jQuery works there...
var $this = $('b');
var styles = window.getComputedStyle($this[0]);
$this.css(
Object.values(styles).reduce(
(a, e) => 0*(a[e] = styles[e]) || a, {}
)
)
console.log(`style="${$this.attr('style')}"`)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<b>I have styles</b>
For creating new CSS rules in a stylesheet, as of now, I only know .insertRule() (excluding the non-standard ways).
Are there any other ways of creating more CSS rules? Something, for example:
Warning: this is not standard, it is just an example to display the intent
var rule = new CSSStyleRule();
rule.selectorText = '.selector';
rule.style.display = 'block';
rule.style.color = 'red';
ruleSet.append(rule);
Anything like or somewhat like the above works as an answer. Instead of new, it may be document.createCssRule() or stylesheet.createCssRule()...
I just this it would be useful for a piece of software I'm developing which left me if there's a programatically way of modifying values in such interface where to add new stuff is not restricted to a parsed string.
Do not worry about IE9 and below when answering, please.
Note: (to unclose) This is not about how to find and modify current CSS rules, this is about making new ones without using the text parser which is what .insertRule() is without building a complete CSS string like .insertRule() requires.
You can add an empty rule, get it, and modify it:
function appendRule(sheet) {
var len = sheet.cssRules.length;
sheet.insertRule('*{}', len);
return sheet.cssRules[len];
}
var rule = appendRule(document.styleSheets[0]);
rule.selectorText = '.selector';
rule.style.display = 'block';
rule.style.color = 'red';
<span class="selector">I should become red.</span>
<span>I should be at the next line and not become red.</span>
However, modifying selectorText does not seem to work on Firefox.
You could append a new style element to your head and just append rules to it:
function addStyle(newRules){
if(document.getElementById("jsAddedRules")){
document.getElementById("jsAddedRules").innerHTML+=newRules;
}else{
var style=document.createElement("style");
style.setAttribure("id","jsAddedRules");
style.innerHTML=newRules;
document.getElementsByTagName("head")[0].appendChild(style);
}
}
And then just call your function when you want to add rules:
addStyle(
".selector{\
display:block;\
color:red;\
}"
);
I need to use the web storage api to store style changes of the elements on one page.
I actually have no clue how to do this but I thought I'd start by getting the CSS attribute that's been changed and storing it in an array. Im trying to follow what's going here and tailoring it to my problem.
this is what i've tried in order to get the values but im not sure if it's correct:
function newItem(){
var bgImg = document.getElementsByTagName('body').bgImg[0].style.getPropertyValue('background');
var wideScreen = getElementById('sidebar').style.getPropertyValue('display');
var playerColor = getElementById('video_container').style.getPropertyValue('background-color');
}
I am not sure if the code i've written above grabs the information I need.
You can use getComputedStyle().
getComputedStyle() gives the final used values of all the CSS properties of an element.
var element = document.getElementById('sidebar'),
style = window.getComputedStyle(element),
display = style.getPropertyValue('display');
var element = document.getElementById('video_container'),
style = window.getComputedStyle(element),
bg = style.getPropertyValue('background-color');
Need help! I've been looking for a solution for this seemingly simple task but can't find an exact one. Anyway, I'm trying to add custom #id to the tag based on the page's URL. The script I'm using works ok when the URLs are like these below.
- http://localhost.com/index.html
- http://localhost.com/page1.html
- http://localhost.com/page2.html
-> on this level, <body> gets ids like #index, #page1, #page2, etc...
My question is, how can I make the body #id still as #page1 or #page2 even when viewing subpages like this?
- http://localhost.com/page1/subpage1
- http://localhost.com/page2/subpage2
Here's the JS code I'm using (found online)
$(document).ready(function() {
var pathname = window.location.pathname;
var getLast = pathname.match(/.*\/(.*)$/)[1];
var truePath = getLast.replace(".html","");
if(truePath === "") {
$("body").attr("id","index");
}
else {
$("body").attr("id",truePath);
}
});
Thanks in advance!
edit: Thanks for all the replies! Basically I just want to put custom background images on every pages based on their body#id. >> js noob here.
http://localhost.com/page2/subpage2 - > my only problem is how to make the id as #page2 and not #subpage2 on this link.
Using the javascript split function might be of help here. For example (untested, but the general idea):
var url = window.location.href.replace(/http[s]?:\/\//, '').replace('.html', '');
var segments = url.split('/');
$('body').id = segments[0];
Also, you might want to consider using classes instead of ID's. This way you could assign every segment as a class...
var url = window.location.href.replace(/http[s]?:\/\//, '').replace('.html', '');
var segments = url.split('/');
for (var i = 0; i < segments.length; i++) {
$('body').addClass(segments[i]);
}
EDIT:
Glad it worked. Couple of notes if you're planning on using this for-real: If you ever have an extension besides .html that will get picked up in the class name. You can account for this by changing that replace to a regex...
var url = window.location.href.replace(/http[s]?:\/\//, '');
// Trim extension
url = url.replace(/\.(htm[l]?|asp[x]?|php|jsp)$/,'');
If there will ever be querystrings on the URL you'll want to filter those out too (this is the one regex I'm not 100% on)...
url = url.replace(/\?.+$/,'');
Also, it's a bit inefficient to have the $('body') in every for loop "around" as this causes jQuery to have to re-find the body tag. A more performant way to do this, especially if the sub folders end up 2 or 3 deep would be to find it once, then "cache" it to a variable like so..
var $body = $('body');
for ( ... ) {
$body.addClass( ...
}
Your regex is only going to select the last part of the url.
var getLast = pathname.match(/./(.)$/)[1];
You're matching anything (.*), followed by a slash, followed by anything (this time, capturing this value) and then pulling out the first match, which is the only match.
If you really want to do this (and I have my doubts, this seems like a bad idea) then you could just use window.location.pathname, since that already has the fullpath in there.
edit: You really shouldn't need to do this because the URL for the page is already a unique identifier. I can't really think of any situation where you'd need to have a unique id attribute for the body element on a page. Anytime where you're dealing with that content (either from client side javascript, or from a scraper) you should already have a unique identifier - the URL.
What are you actually trying to do?
Try the following. Basically, it sets the id to whatever folder or filename appears after the domain, but won't include a file extension.
$(document).ready(function() {
$("body").attr("id",window.location.pathname.split("/")[1].split(".")[0]);
}
You want to get the first part of the path instead of the last:
var getFirst = pathname.match(/^\/([^\/]*)/)[1];
If your pages all have a common name as in your example ("page"), you could modify your script including changing your match pattern to include that part:
var getLast = pathname.match(/\/(page\d+)\//)[1];
The above would match "page" followed by a number of digits (omitting the 'html' ending too).