JavaScript: Select multiple elements by z-index number (in dynamic DOM) - javascript

I would like to select ALL elements in DOM that have the z-index = 2147483647 using 100% JavaScript (NO jQuery)
The DOM is constantly dynamically changing; adding and removing
elements. The code to remove elements by z-index ### MUST have a DOM event listener
I've tried so many iterations of similar codes without success. This is my last iteration attempt and for some reason it is not working
window.addEventListener('change', function() {
var varElements = document.querySelectorAll("[style='z-index: 2147483647']");
if(varElements) { for(let varElement of varElements) { varElement.remove(); } }
} //function
}) //window.

check below code
const check = () => {
var varElements = document.querySelectorAll("*");
for(let varElement of varElements) {
if(varElement.style['z-index'] == 10) {
var node = document.createElement("LI");
var textnode = document.createTextNode(varElement.className);
node.appendChild(textnode);
document.getElementById('list').appendChild(node)
}
}
}
window.addEventListener('change', check )
window.addEventListener('load', check);
<div class="top" style="z-index:10">
<div class="inner1" style="display:'block';z-index:10">
<div class="inner2" style="z-index:10">
</div>
</div>
<div class="inner3" style="z-index:12">
</div>
</div>
<ul id="list">
</ul>

There are some things that come into play here i.e. it has to be positioned to get a z-index. Here I show some examples and how to find stuff that has a z-index not "auto";
You can then loop the list to find a z-index you desire. Here, I just pushed all elements with a z-index not "auto" but you could use your selected index value to filter those out in the conditional for example if (!isNaN(zIndex) && zIndex != "auto" && zIndex == 4042) for those with 4042 value;
Once you have your elements, you can do what you desire which is to set an event handler on each of them.
This specifically answers the question of finding the elements by z-index, not the ultimate desire which is another question of how to manage the changes to the DOM and adding/removing on mutation.
var getZIndex = function(checkelement) {
let compStyles = window.getComputedStyle(checkelement);
let z = compStyles.getPropertyValue('z-index');
if (typeof z == "object" || (isNaN(z) && checkelement.parentNode != document.body)) {
return getZIndex(checkelement.parentNode);
} else {
return z;
}
};
let evallist = document.querySelectorAll("div");
let zthings = [];
for (let item of evallist) {
let zIndex = getZIndex(item);
if (!isNaN(zIndex) && zIndex != "auto") {
zthings.push(item);
}
}
console.log(zthings);
.sureThing {
z-index: 4242;
position: absolute;
background: gold;
top: 4em;
}
<div class="mything">Howddy</div>
<div class="sureThing">Here I am</div>
<div class="onelink">https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle</div>
<div class="otherthing" style="z-index:4040;">other thing set internal woops Ihave no position so I am not in list</div>
<div class="otherthing" style="z-index:4040;position: absolute;top:5em;">other thing set internal OK</div>

You cannot select an element based on css in css. So you cannot use the querySelectorAll. This code works if the css is set by the inline style attribute. Here is the code explained:
Get all element using *.
Turn the NodeList into an array.
Filter out the elements that do not have a specific css property.
get the css properties using: window.getComputedStyle()
window.addEventListener( 'load', () => {
let all = document.querySelectorAll('*');
all = Array.from(all);
const filtered = all.filter( zindex_filter )
console.log( filtered )
})
function zindex_filter (element) {
const style = window.getComputedStyle(element);
console.log( style.getPropertyValue('z-index') )
if( style.getPropertyValue('z-index') == 100 ) return true;
else return false;
}
.div {
width: 100px;
height: 100px;
margin: 10px;
}
.zindex {
position: relative;
z-index: 100;
}
<div class='zindex div'></div>
<div class='div'></div>
<div class='div' style='position: relative; z-index: 100; width: 100px;'></div>
Notes:
window.getComputedStyle() docs
note that the z-indexed must be positioned correctly to return a value other than auto.

Related

How to convert JavaScript code to jQuery?

symbolen.parent = object;
object.element.onclick = function() {
this.parent.position.x = 0;
this.parent.position.y = 0;
this.parent.position.z = 0;
this.parent.scale.x = 4,
this.parent.scale.y = 4;
};
i want to convert the javascript code to jquery.
Because i want to use "siblings".
how can i change it ?
is there any website for that?
for example i tried this code with scale first , there is no error message, but it is not working...
$('object').click(function(event) {
$(this).parent().css('scale', '4');
$(this).parent().siblings().css('scale', '0');
event.preventDefault();
});
You can wrap element(s) in a jQuery object with $(element). Then you can do any jQuery functionality with it. I changed 'object' selector into object.element. You don't use quotes here because you use the element in the variable directly instead of using a selector. Also scale is not a css attribute so i assume you mean transform: scale()
//Mimic your object.element
var object = {};
object.element = document.getElementsByClassName('scale');
//Add on click handler and set scale on click.
$(object.element).click(function() {
$(this).css("transform", "scale(4, 4)");
$(this).siblings().css("transform", "scale(1)");
});
div#parent {
text-align: center;
}
div#scale {
width: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="parent">
<br>
<div class="scale">Scale on click</div>
<br>
<br>
<br>
<div class="scale">Scale on click</div>
<br>
</div>

Know when flex-box puts item to new row [duplicate]

I have flex container with items inside. How to detect flex wrap event? I want to apply some new css to elements that have been wrapped. I suppose that it is impossible to detect wrap event by pure css. But it would be very powerful feature! I can try to "catch" this break point event by media query when element wraps into new line/row. But this is a terrible approach. I can try to detect it by script, but it's also not very good.
I am very surprised, but simple $("#element").resize() doesn't work to detect height or width changes of flex container to apply appropriate css to child elements. LOL.
I have found that only this example of jquery code works
jquery event listen on position changed
But still terribly.
Here's one potential solution. There might be other gotchas and edge cases you need to check for.
The basic idea is to loop through the flex items and test their top position against the previous sibling. If the top value is greater (hence further down the page) then the item has wrapped.
The function detectWrap returns an array of DOM elements that have wrapped, and could be used to style as desired.
The function could ideally be used with a ResizeObserver (while using window's resize event as a fallback) as a trigger to check for wrapping as the window is resized or as elements in the page change due to scripts and other user-interaction. Because the StackOverflow code window doesn't resize it won't work here.
Here's a CodePen that works with a screen resize.
var detectWrap = function(className) {
var wrappedItems = [];
var prevItem = {};
var currItem = {};
var items = document.getElementsByClassName(className);
for (var i = 0; i < items.length; i++) {
currItem = items[i].getBoundingClientRect();
if (prevItem && prevItem.top < currItem.top) {
wrappedItems.push(items[i]);
}
prevItem = currItem;
};
return wrappedItems;
}
window.onload = function(event){
var wrappedItems = detectWrap('item');
for (var k = 0; k < wrappedItems.length; k++) {
wrappedItems[k].className = "wrapped";
}
};
div {
display: flex;
flex-wrap: wrap;
}
div > div {
flex-grow: 1;
flex-shrink: 1;
justify-content: center;
background-color: #222222;
padding: 20px 0px;
color: #FFFFFF;
font-family: Arial;
min-width: 300px;
}
div.wrapped {
background-color: red;
}
<div>
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
</div>
Little bit improved snippet on jQuery for this purpose.
wrapped();
$(window).resize(function() {
wrapped();
});
function wrapped() {
var offset_top_prev;
$('.flex-item').each(function() {
var offset_top = $(this).offset().top;
if (offset_top > offset_top_prev) {
$(this).addClass('wrapped');
} else if (offset_top == offset_top_prev) {
$(this).removeClass('wrapped');
}
offset_top_prev = offset_top;
});
}
I've modified sansSpoon's code to work even if the element isn't at the absolute top of the page. Codepen: https://codepen.io/tropix126/pen/poEwpVd
function detectWrap(node) {
for (const container of node) {
for (const child of container.children) {
if (child.offsetTop > container.offsetTop) {
child.classList.add("wrapped");
} else {
child.classList.remove("wrapped");
}
}
}
}
Note that margin-top shouldn't be applied to items since it's factored into getBoundingClientRect and will trigger the wrapped class to apply on all items.
I'm using a similar approach in determining if a <li> has been wrapped in an <ul> that has it's display set to flex.
ul = document.querySelectorAll('.list');
function wrapped(ul) {
// loops over all found lists on the page - HTML Collection
for (var i=0; i<ul.length; i++) {
//Children gets all the list items as another HTML Collection
li = ul[i].children;
for (var j=0; j<li.length; j++) {
// offsetTop will get the vertical distance of the li from the ul.
// if > 0 it has been wrapped.
loc = li[j].offsetTop;
if (loc > 0) {
li[j].className = 'wrapped';
} else {
li[j].className = 'unwrapped';
}
}
}
}
I noticed elements will typically wrap in relation to the first element. Comparing offset top of each element to the first element is a simpler approach. This works for wrap and wrap-reverse. (Probably won't work if elements use flex order)
var wrappers = $('.flex[class*="flex-wrap"]'); //select flex wrap and wrap-reverse elements
if (wrappers.length) { //don't add listener if no flex elements
$(window)
.on('resize', function() {
wrappers.each(function() {
var prnt = $(this),
chldrn = prnt.children(':not(:first-child)'), //select flex items
frst = prnt.children().first();
chldrn.each(function(i, e) { $(e).toggleClass('flex-wrapped', $(e).offset().top != frst.offset().top); }); //element has wrapped
prnt.toggleClass('flex-wrapping', !!prnt.find('.flex-wrapped').length); //wrapping has started
frst.toggleClass('flex-wrapped', !!!chldrn.filter(':not(.flex-wrapped)').length); //all are wrapped
});
})
.trigger('resize'); //lazy way to initially call the above
}
.flex {
display: flex;
}
.flex.flex-wrap {
flex-wrap: wrap;
}
.flex.flex-wrap-reverse {
flex-wrap: wrap-reverse;
}
.flex.flex-1 > * { /*make items equal width*/
flex: 1;
}
.flex > * {
flex-grow: 1;
}
.cc-min-width-200 > * { /*child combinator*/
min-width: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="flex flex-1 flex-wrap-reverse cc-min-width-200">
<div>Hello</div>
<div>There</div>
<div>World</div>
</div>
If someone wants to find the last element of the row from where wrapped elements started can use the below logic. It's applicable for multiple lines as well
window.onresize = function (event) {
const elements = document.querySelectorAll('.borrower-detail');
let previousElement = {};
let rowTop = elements[0].getBoundingClientRect().top;
elements.forEach(el => el.classList.remove('last-el-of-row'))
elements.forEach(el => {
const elementTop = el.getBoundingClientRect().top;
if (rowTop < elementTop) {
previousElement.classList.add('last-el-of-row');
rowTop = elementTop;
}
previousElement = el;
})
};

Retrieve CSS percentage value with jQuery

Currently the width() method and all of it's variations in jQuery return pixel values. The same happens when calling the css('width') method.
I have elements, which are styled in .css files, and I have no way of knowing if they're styled in percentages or pixels, but in case it's in percentage or no width is explicitly set on the element, I need to get a percent value.
For example if I have the following:
.seventy { width: 70%; }
.pixels { width: 350px; }
<div class="seventy"></div>
<div class="pixels"></div>
<div class="regular"></div>
I would need these results.
$('.seventy').method() //=> '70%'
$('.pixels').method() //=> '350px'
$('.regular').method() //=> '100%' since that's how block elements behave
Is there anything in jQuery I can use to achieve this effect? Or a custom approach to it?
You can parse the document.stylesheets to find a match. Note, this will only return the actual style after the browser has parsed it so is of no use for getting raw unadulterated CSS as written in file. For that you'd need to parse the file itself rather than the document.stylesheets.
This code is old and untested so your mileage may vary. I have no idea how well it performs with inherited values or more complicated selectors.
//TEST PARSE CSS
var CSS = function () {
var _sheet;
var _rules;
function CSS() {
_sheet = document.styleSheets[0];
if (_sheet.rules) {
_rules = _sheet.rules; // IE
} else {
_rules = _sheet.cssRules; // Standards
}
this.find = function (selector) {
var i = _rules.length;
while(i--){
if (_rules[i].selectorText == selector) {
break;
}
if(i==0){break;}
}
//return _rules[i].cssText;
return _rules[i].style;
}
this.set = function (foo) {
//to do
}
};
return new CSS();
};
//init
var css = new CSS();
//view the console.
console.log(css.find(".regular"));//Note how the width property is blank
//update elements with the results
document.querySelector(".seventy").innerHTML = css.find(".seventy").width;
document.querySelector(".pixels").innerHTML = css.find(".pixels").width;
document.querySelector(".regular").innerHTML = css.find(".regular").width;
//other tests
document.getElementById("a").innerHTML = css.find("body").color;
document.getElementById("b").innerHTML = css.find("h1").color;
document.getElementById("c").innerHTML = css.find("h1").width;
document.getElementById("d").innerHTML = css.find(".notInDom").color;
body {
font-family:sans-serif;
color:black;
background-color:#cccccc;
}
h1 {
color:blue;
font-size:1.5em;
font-weight:400;
width:70%;
}
.seventy, .pixels, .regular {display:block; border:1px solid red;}
.seventy {display:block; border:1px solid red; width: 70%; }
.pixels { width: 350px; }
.regular {}
.notInDom {
color:red;
}
<h1>Find and Read Style Attributes Directly from the Stylesheet.</h1>
<div class="seventy"></div>
<div class="pixels"></div>
<div class="regular"></div>
<ul>
<li>css.find("body").color = <span id='a'></span></li>
<li>css.find("h1").color = <span id='b'></span></li>
<li>css.find("h1").width = <span id='c'></span></li>
<li>css.find(".notInDom").color = <span id='d'></span></li>
</ul>
<p>This is a work in progress and hasn't been tested in any meaningful way. Its messy and very limited.</p>
function getStyle(className) {
var classes = document.styleSheets[0].rules || document.styleSheets[0].cssRules;
for (var x = 0; x < classes.length; x++) {
if (classes[x].selectorText == className) {
(classes[x].cssText) ? alert(classes[x].cssText) : alert(classes[x].style.cssText);
}
}
}
getStyle('.test');

How to detect CSS flex wrap event

I have flex container with items inside. How to detect flex wrap event? I want to apply some new css to elements that have been wrapped. I suppose that it is impossible to detect wrap event by pure css. But it would be very powerful feature! I can try to "catch" this break point event by media query when element wraps into new line/row. But this is a terrible approach. I can try to detect it by script, but it's also not very good.
I am very surprised, but simple $("#element").resize() doesn't work to detect height or width changes of flex container to apply appropriate css to child elements. LOL.
I have found that only this example of jquery code works
jquery event listen on position changed
But still terribly.
Here's one potential solution. There might be other gotchas and edge cases you need to check for.
The basic idea is to loop through the flex items and test their top position against the previous sibling. If the top value is greater (hence further down the page) then the item has wrapped.
The function detectWrap returns an array of DOM elements that have wrapped, and could be used to style as desired.
The function could ideally be used with a ResizeObserver (while using window's resize event as a fallback) as a trigger to check for wrapping as the window is resized or as elements in the page change due to scripts and other user-interaction. Because the StackOverflow code window doesn't resize it won't work here.
Here's a CodePen that works with a screen resize.
var detectWrap = function(className) {
var wrappedItems = [];
var prevItem = {};
var currItem = {};
var items = document.getElementsByClassName(className);
for (var i = 0; i < items.length; i++) {
currItem = items[i].getBoundingClientRect();
if (prevItem && prevItem.top < currItem.top) {
wrappedItems.push(items[i]);
}
prevItem = currItem;
};
return wrappedItems;
}
window.onload = function(event){
var wrappedItems = detectWrap('item');
for (var k = 0; k < wrappedItems.length; k++) {
wrappedItems[k].className = "wrapped";
}
};
div {
display: flex;
flex-wrap: wrap;
}
div > div {
flex-grow: 1;
flex-shrink: 1;
justify-content: center;
background-color: #222222;
padding: 20px 0px;
color: #FFFFFF;
font-family: Arial;
min-width: 300px;
}
div.wrapped {
background-color: red;
}
<div>
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
</div>
Little bit improved snippet on jQuery for this purpose.
wrapped();
$(window).resize(function() {
wrapped();
});
function wrapped() {
var offset_top_prev;
$('.flex-item').each(function() {
var offset_top = $(this).offset().top;
if (offset_top > offset_top_prev) {
$(this).addClass('wrapped');
} else if (offset_top == offset_top_prev) {
$(this).removeClass('wrapped');
}
offset_top_prev = offset_top;
});
}
I've modified sansSpoon's code to work even if the element isn't at the absolute top of the page. Codepen: https://codepen.io/tropix126/pen/poEwpVd
function detectWrap(node) {
for (const container of node) {
for (const child of container.children) {
if (child.offsetTop > container.offsetTop) {
child.classList.add("wrapped");
} else {
child.classList.remove("wrapped");
}
}
}
}
Note that margin-top shouldn't be applied to items since it's factored into getBoundingClientRect and will trigger the wrapped class to apply on all items.
I'm using a similar approach in determining if a <li> has been wrapped in an <ul> that has it's display set to flex.
ul = document.querySelectorAll('.list');
function wrapped(ul) {
// loops over all found lists on the page - HTML Collection
for (var i=0; i<ul.length; i++) {
//Children gets all the list items as another HTML Collection
li = ul[i].children;
for (var j=0; j<li.length; j++) {
// offsetTop will get the vertical distance of the li from the ul.
// if > 0 it has been wrapped.
loc = li[j].offsetTop;
if (loc > 0) {
li[j].className = 'wrapped';
} else {
li[j].className = 'unwrapped';
}
}
}
}
I noticed elements will typically wrap in relation to the first element. Comparing offset top of each element to the first element is a simpler approach. This works for wrap and wrap-reverse. (Probably won't work if elements use flex order)
var wrappers = $('.flex[class*="flex-wrap"]'); //select flex wrap and wrap-reverse elements
if (wrappers.length) { //don't add listener if no flex elements
$(window)
.on('resize', function() {
wrappers.each(function() {
var prnt = $(this),
chldrn = prnt.children(':not(:first-child)'), //select flex items
frst = prnt.children().first();
chldrn.each(function(i, e) { $(e).toggleClass('flex-wrapped', $(e).offset().top != frst.offset().top); }); //element has wrapped
prnt.toggleClass('flex-wrapping', !!prnt.find('.flex-wrapped').length); //wrapping has started
frst.toggleClass('flex-wrapped', !!!chldrn.filter(':not(.flex-wrapped)').length); //all are wrapped
});
})
.trigger('resize'); //lazy way to initially call the above
}
.flex {
display: flex;
}
.flex.flex-wrap {
flex-wrap: wrap;
}
.flex.flex-wrap-reverse {
flex-wrap: wrap-reverse;
}
.flex.flex-1 > * { /*make items equal width*/
flex: 1;
}
.flex > * {
flex-grow: 1;
}
.cc-min-width-200 > * { /*child combinator*/
min-width: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="flex flex-1 flex-wrap-reverse cc-min-width-200">
<div>Hello</div>
<div>There</div>
<div>World</div>
</div>
If someone wants to find the last element of the row from where wrapped elements started can use the below logic. It's applicable for multiple lines as well
window.onresize = function (event) {
const elements = document.querySelectorAll('.borrower-detail');
let previousElement = {};
let rowTop = elements[0].getBoundingClientRect().top;
elements.forEach(el => el.classList.remove('last-el-of-row'))
elements.forEach(el => {
const elementTop = el.getBoundingClientRect().top;
if (rowTop < elementTop) {
previousElement.classList.add('last-el-of-row');
rowTop = elementTop;
}
previousElement = el;
})
};

CSS style to inline style via JavaScript

I want to add all CSS styles of a specific element to its inline style attribute. For example:
I have:
<div id="d"></div>
and:
#d { background: #444444; width: 50px; height: 20px; display: inline-block; }
Now I want a JavaScript function that turns my div into this:
<div id="d" style="background: #444444; width: 50px; height: 20px; display: inline-block;"></div>
Please help me. And, by the way, I don't want any CSS styles to re-write any existing inline style.
You can do something like this:
function applyStyle(el) {
s = getComputedStyle(el);
for (let key in s) {
let prop = key.replace(/\-([a-z])/g, v => v[1].toUpperCase());
el.style[prop] = s[key];
}
}
let x = document.getElementById('my-id');
applyStyle(x);
Where x is the element you want to apply the style to.
Basically this function gets the computed style of the element and then copies each property (like padding, background, color, etc.) to the inline style of the element.
I don't know why you need to do this, but it's a really dirty approach in my opinion. I would personally advise against it.
It appears this library will do what you're looking for: https://github.com/lukehorvat/computed-style-to-inline-style
Convert a HTML element's computed CSS to inline CSS.
Uses Window.getComputedStyle internally.
This one?
function transferComputedStyle(node) {
var cs = getComputedStyle(node, null);
var i;
for (i = 0; i < cs.length; i++) {
var s = cs[i] + "";
node.style[s] = cs[s];
}
}
function transferAll() {
var all = document.getElementsByTagName("*");
var i;
for (i = 0; i < all.length; i++) {
transferComputedStyle(all[i]);
}
}
Simply call transferAll onload, or whereever.
I think the issue with the accepted answer (thank you for that!) is that one of the properties it tries to transfer on the element style from the Computed Style is the cssText.
If we exclude from the transfer cssText and also other properties that are actually methods, it works!
So building on the accepted answer and this answer, I've got:
var el = document.querySelector("#answer-25097808 > div > div.answercell.post-layout--right > div.s-prose.js-post-body > pre"); // change yourId to id of your element, or you can write “body” and it will convert all document
var els = el.getElementsByTagName("*");
for(var i = -1, l = els.length; ++i < l;){
el = els[i]
s = getComputedStyle(el)
for (let styleKey in el.style) {
for (let computedStyleKey in s) {
let computedStyleKeyCamelCase = computedStyleKey.replace(/\-([a-z])/g, v => v[1].toUpperCase());
if ((typeof el.style[styleKey] != "function") && (styleKey != 'cssText')){
if(styleKey == computedStyleKeyCamelCase) {
el.style[styleKey] = s[computedStyleKey];
}
}
}
}
}
P.S.: the above code should run in the Developer Tools console (tried it in Chrome)
Using jQuery it can be done easily. Here is the sample code:
If you are new in jQuery and you don't know how to add and work then follow this link
$(document).ready(function(){
$("#d").css('background-color', '#444444').css('width', '50px').css('height', '20px').css('display', 'inline-block');
});
For javascript code I am not confident but for jQuery I am sure that it will work.
Correct me if I am wrong.

Categories

Resources