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
Related
I've got the following bit of code (using JQuery) that I've written for a project. The idea is to have a function that you can attach to an element within an "item" div and it will return the id of that div. In this case, the div id would be item-[some item primary key value]. This function works probably 9/10 times, but every once in a while it will get to the else else case and return false. I've verified through the console that the input for selector is the exact same JQuery $() item in both the success and fail cases.
I'm relatively new to JavaScript, so there may be something obvious I'm missing, but this is some really unusual behavior.
var recursionCounter = 0;
function getElementID(selector, recursionDepth, searchString){
console.log(selector);
var elementID = selector.attr("id");
if(elementID === undefined){
elementID = "";
}
if(elementID.indexOf(searchString) !== -1){
elementID = elementID.split("-")[1];
return elementID;
} else {
if(recursionCounter < recursionDepth){
recursionCounter++;
return getElementID(selector.parent(), recursionDepth, searchString);
} else {
recursionCounter = 0;
alert("The element clicked does not have an associated key.");
return false;
}
}
}
Here is an example of code that calls this function, for some context.
$(document).on("click", ".edit-pencil-item", function(event) {
//Use helper function to get the id of the surrounding div then pass it to the function
var itemID = getElementID($(this), 10, "item-");
jsEditItem(itemID);
return false;
});
Thanks in advance for any help!
If you want to get the encapsulating element of your clicked element, and you know it should have an id starting with "item-" you should be able to do something along the lines of
$(this).closest('[id^="item-"]').attr('id')
Which says find this elements closest parent that has an id starting with "item-" and tell me its id.
I need to have a if/else statement inside a function. How do you check if an element (e.g. #cadrage) has a display style property? This is what I have found around the net and yet, it is not working..
if( $('#cadrage').attr('style').display == 'block' ) {
// do something
} else {
// do something
}
The jQuery .css() function seems to be what you want.
if( $('#cadrage').css('display') == 'block' ) {
console.log('It equal block');
} else {
console.log('It did not equal block');
}
http://jsfiddle.net/SamMonk/FtP6W/
Your code doesn't work because style property only contains inline styles, not those coming from a stylesheet.
To get the computed style, you can use css method:
$('#cadrage').css('display') == 'block'
Try this:
if( $('#cadrage').css('display')== 'block' ) {
// do something
} else {
// do something
}
You can get your element display property with the following code snippet
$('#cadrage').css('display');
Note that the css method can return any css property of your element so it is very handy.
Therefore your statement code will be:
if( $('#cadrage').css('display').display == 'block' ) {
// do something
} else {
// do something
}
Not exactly what you ask for, but perhaps what you are looking for...
You can use the :visible pseudo selector to check if the element is visible:
if( $('#cadrage').is(':visible')) {
// do something
} else {
// do something
}
Note that this doesn't actually check the display style, but rather if the element has a size so that it could be seen in the page.
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 !")
I created this code a few days, but I believe it is possible to improve it, someone could help me create a smarter way?
// Hide registered or customized field if not checked.
function checkUserType(value) {
if (value == 2) {
$('#registered').hide();
$('#customized').show();
} else if (value == 1) {
$('#registered').show();
$('#customized').hide();
}
}
checkUserType($('input:radio[name="jform[place_type]"]:checked').val());
$('#jform_place_type').on('click', function () {
checkUserType($('input:radio[name="jform[place_type]"]:checked').val());
});
Demo: http://jsbin.com/emisat/3
// Hide registered or customized field if not checked.
function checkUserType(value) {
}
var t = function () {
var value = $('input:radio[name="jform[place_type]"]:checked').val();
if (value == 2) {
$('#registered').hide();
$('#customized').show();
} else if (value == 1) {
$('#registered').show();
$('#customized').hide();
}
};
$('#jform_place_type').on('click', t);
You can improve the Jquery (for the performance) by storing the DOM element and cache the rest. This is the maximum stuff you can reach I guess.
function checkUserType(value) {
var r = $("#registered");
var c = $("#customized");
if (value == 2) {
r.hide();
c.show();
} else if (value == 1) {
r.show();
c.hide();
}
}
var func = function () {
checkUserType($('input:radio[name="jform[place_type]"]:checked').val());
};
$('#jform_place_type').on('click', func);
For any further reading check this JQuery Performance
In particular read the third paragraph of the document
Cache jQuery Objects
Get in the habit of saving your jQuery objects to a variable (much like our examples above). For example, never (eeeehhhhver) do this:
$('#traffic_light input.on').bind('click', function(){...});
$('#traffic_light input.on').css('border', '3px dashed yellow');
$('#traffic_light input.on').css('background-color', 'orange');
$('#traffic_light input.on').fadeIn('slow');
Instead, first save the object to a local variable, and continue your operations:
var $active_light = $('#traffic_light input.on');
$active_light.bind('click', function(){...});
$active_light.css('border', '3px dashed yellow');
$active_light.css('background-color', 'orange');
$active_light.fadeIn('slow');
Tip: Since we want to remember that our local variable is a jQuery wrapped set, we are using $ as a prefix. Remember, never repeat a jQuery selection operation more than once in your application.
http://api.jquery.com/toggle/
$('#jform_place_type').on('click', function () {
//show is true if the val() of your jquery selector equals 1
// false if it's not
var show= ($('input:radio[name="jform[place_type]"]:checked')
.val()==1);
//set both divs to visible invisible / show !show(=not show)
// (not show) means that if show=true then !show would be false
$('#registered').toggle(show);
$('#customized').toggle(!show);
});
If you need a selector more than once then cache it I think it's called object caching as Claudio allready mentioned, thats why you see a lot of:
$this=$(this);
$myDivs=$("some selector");
The convention for a variable holding results of jquery function (jquery objects) is that they start with $ but as it is only a variable name you can call it anything you like, the following would work just as well:
me=$(this);
myDivs=$("some selector");
A page contains a link with the text "Open Help". How to get the anchor containing that text with YUI?
YUI2 provides therefore the getElementsBy function. It has a filter methode attribute and with it you can check if the current element matches your purpose. Notice that you get an array with all matched elements. So you can pick the first if there was a hit.
http://developer.yahoo.com/yui/docs/YAHOO.util.Dom.html#method_getElementsBy
var elements,
searchText = "Open Help";
elements = YAHOO.util.Dom.getElementsBy(function (element) {
return (element.innerHTML === searchText) ? true : false;
}, "a", document);
if (elements.length > 0) {
//do something with elements[0]
}
On the other hand the YUI3 solution is in my opinion a cleaner way:
var searchText = "Open Help";
Y.all("a").each(function (el) {
if (el.getContent() === searchText) {
//do something with the el
}
});