reallyvisible selector - javascript

The jquery :visible and :hidden selectors are a little misleading, they select elements that consume space in the document, therefore something with visibility:hidden is classed as :visible even though it's not o_O
I need to be able to select only elements that are :reallyvisible, that I can see with my eyes eg, not opacity:0 or visibility:hidden
Obviously for an element to be visually visible all it's ancestors must also be visible so I assume a recursive look up the tree would be necessary.
Is this just too expensive?
Can anyone suggest a reliable efficient way to achieve this?

How about:
$.expr[':'].reallyVisible = function(node, idx){
while(true){
// should be faster than $(node).css()
var css = document.defaultView.getComputedStyle(node, null);
if(css.opacity == 0 || css.visibility == 'hidden')
return false;
node = node.parentNode;
if(!node || node === document)
break;
}
return true;
}
http://jsfiddle.net/jxEFk/

Try this code :
function isVisible(el){
if (el.css('opacity') != '0' && el.css('visibility') != 'hidden') {
return true
}
return false
}
$('myelement').filter(function () {
visible = true
if (isVisible($(this)) == false)
visible = false
$(this).parents().each(function(){
if (isVisible($(this)) == false)
visible = false
})
return visible == true
}).html("I'm really visible !")

Related

check if element has css position property setted up

How to be sure if parent element has css position property setted up ?
if(!$('#element').parent().css('position')){
//here I need to be sure to avoid no rewrite the old position if position is already setted up
//absolute fixed etc....
$('#element').parent().css('position','relative')
}
Some like this work on cross browsers ?
Please follow the below method :
function elementOrParentIsFixed(element) {
var $element = $(element);
var $checkElements = $element.add($element.parents());
var isFixed = false;
$checkElements.each(function(){
if ($(this).css("position") === "relative") {
isFixed = true;
return false;
}
});
return
}
So based on #Danish suggestion (copy-pasted from : Detect whether an element has position:fixed (possibly by parent element) via jQuery )
I write this:
function parentHasPosition(element){
var parent = element.parent();
if(
parent.css('position') === 'static' ||
parent.css('position') === 'absolute' ||
parent.css('position') === 'fixed' ||
parent.css('position') === 'sticky'
){
return true;
}
return false;
}

hide dropdown when something else is clicked except dropdown itself

I have a dropdown on a website and i want to hide it when something else is clicked except the dropdown elements themselves. Right now what i have works with jquery but would love to have the same logic with vanilla javascript. i feel like my jquery logic is clunky, i have been thinking for a long time and i would love some input.
thank you so much.
$(document).on('click', function(e) {
if ( $(e.target).closest('.icon').length ) {
$('.dropdown').css('top','30px');
$('.dropdown').css('opacity','1');
}else if ( ! $(e.target).closest('.icon').length && !$(e.target).closest('.dropdown').length) {
$('.dropdown').css('opacity','0');
$('.dropdown').css('top','-530px');
}
});
Try this, I would suggest modifying classes instead of manually modifying the css in your code.
http://jsfiddle.net/dlizik/xeLbrnob/
(function(box, faded) {
var elem = document.querySelector("."+box);
var settings = {
elem: elem,
classes: elem.className.split(" "),
toggle: faded
};
window.addEventListener("click", clickHandler, false);
function clickHandler(e) {
if (e.target !== elem) modifyClass.call(settings, false);
if (e.target == elem) modifyClass.call(settings, true);
}
function modifyClass(bool) {
var index = this.classes.indexOf(this.toggle);
if (bool === true && index > -1) this.classes.splice(index, 1);
if (bool === false && index < 0) this.classes.push(this.toggle);
this.elem.className = this.classes.join(" ");
}
})("box", "faded");

jQuery 'OR' not working when looping through required input elements

I'm writing a small required HTML5 attribute fallback for various inputs. It's going pretty well so far, but I'm having trouble when checking a radio button is ':checked' and using the 'OR' || operator in the loop:
if (self.val() === '' || self.is(':not(:checked)')) {
For some reason when I add this it breaks the script slightly and will indicate that the input fields (type=text) are empty when they're not. Is there a better way at all to loop through and indicate the difference between an input type 'text' and 'radio'?
Here's the loop:
var reqClass = $('.required')
reqClass.each(function(){
var self = $(this)
// if empty
if (self.val() === '' || self.is(':not(:checked)')) {
// if it doesn't have require-checked class
if (!self.hasClass('require-checked')) {
self.addClass('require-checked')
self.parent().append('<span class="form-error">This field is required.</span>')
}
e.preventDefault()
//$('.form-submit').attr('disabled', true)
// if it's been checked, but there is a value now
} else if (self.hasClass('require-checked') && !(self.val() === '')) {
self.siblings('.form-error').hide()
}
})
Classes are obviously present for 'fallback' browsers and changed on the fly. Here's a JSFiddle, thank you for any help:
http://jsfiddle.net/cyncV/2/
A text box is indeed :not(:checked) (even if it has text in it), so the text boxes are showing as empty when they are not.
Perhaps something like
if (self.val() === '' || self.is(':checkbox:not(:checked)') || self.is(':radio:not(:checked)')
var self = this;
var empty = self.type=='checkbox' ? !self.checked : self.value=='';
if (empty) {
// do stuff
}
FIDDLE
There is a solution :
var checked = (self.is(':checkbox') || self.is(':radio')) ? self.is(':not(:checked)') : false;
if (self.val() === '' || checked) {}
Just add a little condition that if input is checkbox or radio, it look if it's checked, else it return false. Then pass the result into the if condition.

Find all block elements

I need to find all block elements in a given node. Block elements are not just elements that have display:block in the CSS, but also default block elements like div and p.
I know I can just get computed style of the element and check for the display property, however, my code will execute in a long loop and getting computed styles flushes reflow stack every time, so it will be very expansive.
I'm looking for some trick to do this without getComputedStyle.
Edit
Here's my current code that I would like to improve:
var isBlockOrLineBreak = function(node)
{
if (!node) {
return false;
}
var nodeType = node.nodeType;
return nodeType == 1 && (!inlineDisplayRegex.test(getComputedStyleProperty(node, "display")) || node.tagName === "BR")
|| nodeType == 9 || nodeType == 11;
};
Another edit
jQuery's .css calls getComputedStyle under the hood. So that's not what I'm looking for.
My solution
Thanks everyone for suggestions. Unfortunately, none of them matched what I was looking for. After a lot of digging through documentation I realized that there's no real way to do this without getComputedStyle. However, I came up with the code that should avoid getComputedStyle as much as humanly possible. Here's the code:
$.extend($.expr[':'], {
block: function(a) {
var tagNames = {
"ADDRESS": true,"BLOCKQUOTE": true,"CENTER": true,"DIR": true,"DIV": true,
"DL": true,"FIELDSET": true,"FORM": true,"H1": true,"H2": true,"H3": true,
"H4": true,"H5": true,"H6": true,"HR": true,"ISINDEX": true,"MENU": true,
"NOFRAMES": true,"NOSCRIPT": true,"OL": true,"P": true,"PRE": true,"TABLE": true,
"UL": true,"DD": true,"DT": true,"FRAMESET": true,"LI": true,"TBODY": true,
"TD": true,"TFOOT": true,"TH": true,"THEAD": true,"TR": true
};
return $(a).is(function() {
if (tagNames[this.tagName.toUpperCase()]) {
if (this.style.display === "block")
{
return true;
}
if (this.style.display !== "" || this.style.float !== "")
{
return false;
}
else {
return $(this).css("display") === "block";
}
}
else {
if (this.style.display === "block") {
return
}
else {
return $(this).css("display") === "block";
}
}
});
}
});
Usage of this code is very simple just do $(":block") or $("form :block"). This will avoid using .css property in a lot of cases, and only fallback to it as a last resort.
Starx's answer was what gave me the idea to do this, so I'm going to mark his message as an answer.
For the answer to this problem, we take into account the universal CSS selector and the jQuery .filter() function:
$("*").filter(function(index) {
return $(this).css("display") == 'block';
});
This code looks at all elements it can find, and it returns a list of elements if they pass a filter. The element passes a filter if the filter function returns true for that element. In this case, the filter tests the display property of each found element and tests it against the desired value.
Now, you also mentioned that you want to find p and div elements. Luckily, we also have a way to find these in the filter function. Using jQuery's prop function, we can return a property of an element. In this case, we are interested in the tagName property of the DOM elements being filtered. Combining this feature with the above filter, we get:
$("*").filter(function(index) {
var $this = $(this);
var tagName = $this.prop("tagName").toLowerCase();
return $this.css("display") == 'block' || tagName == 'p' || tagName == 'div';
});
Notice how we set the tagName variable to lowercase, because we cannot expect a certain case for the tagName property (correct me if I'm wrong).
The best way I see is to
assign a common class to all the not-native block element and
using jQuery's mulitple-selector.
Then we can do it as simple as this this
CSS:
.block { display: block; }
jQuery:
var blockelements = $("div, p, table, ..., .block");
// ^ represents other block tags
If you want to include all the block elements. Here is a link
maybe this helps.
$('*').each( function(){
if ($(this).css("display") === "block")
$(this).css("background", "yellow") ;
});
jsfiddle

jquery statement not evaluating as true when setting two variables as the same dom element

I'm trying to handle mouseover / mouseout animations and a statement I have is not evaluating to true when you mouseover an element that you previously moused over. I'm trying to prevent a double rollover animation from happening. Here's my code:
var $chosenThumb = null;
var $lastThumb = null;
$('.thumb_img').mouseover(function(){
if ($chosenThumb != null){
$lastThumb = $chosenThumb;
$lastThumbContainer = $chosenThumb.parent();
$lastThumbOverlay = $lastThumbContainer.children('.thumb_overlay');
}
$chosenThumb = $(this);
console.log($lastThumb + "|" + $chosenThumb + "|" + ($lastThumb == $chosenThumb));
$chosenThumbContainer = $(this).parent();
$chosenThumbOverlay = $chosenThumbContainer.children('.thumb_overlay');
if ($lastThumb != null && $lastThumb != $chosenThumb){
$lastThumbOverlay.animate({ 'height' : '0px'}, 200);
$lastThumbContainer.children('.thumb_plus').animate({'height' :'0px', 'width' : '0px' },200);
}
if ($lastThumb != $chosenThumb) {
$chosenThumbOverlay.animate({ 'height' : '30px'}, 200);
$chosenThumbContainer.children('.thumb_plus').animate({'height' :'31px', 'width' : '31px' },200);
}
});
So the first time you mouse over a thumbnail, lastThumb will be null and chosenThumb will be the thumb you rolled over. Then the next time you mouse over that thumb, lastThumb should be equal to chosenThumb, but the log statement does not evaluate as true. Why?
Even with the same selector, every jQuery object is a new instance of jQuery. To compare elements, you have to compare the actual DOM element:
//$lastThumb[0] returns the first DOM element from the jQuery selector
$lastThumb[0] == $chosenThumb[0]
Generally it's unadvisable to extend DOM elements because of memory leaks but I might suggest you do it in this case if you don't have a large number of nodes.
This will prevent a mouseover event from firing if it has fired once:
$( "myselector" ).mouseover( function( )
{
if ( this.moused )
{
return;
}
else
{
this.moused = true;
}
// Do things here.
} );
May be you have two span or div with the same ids in your HTML

Categories