do two DOM elements have the same id if their ids are set to an empty string?
example:
$('#something').attr('id', '');
$('#something-else').attr('id', '');
//do these now have the same id?
//is there a better way to unset an element's id?
and is this equal to an element that was declared without an id
<div></div>
<div id=''></div>
<div id></div>
<!--how do these compare??-->
The id attribute cannot legally contain an empty string in either HTML 4 or HTML5. That said, the selectors [id] and [id=""] will still match such elements should they appear in a non-conforming document. Note that an empty id attribute is not the same as the lack of an id attribute.
Setting an element's id attribute to the empty string in a script seems to work (DOM level 4 seems to forbid it, but this may be new as it is not specified in DOM level 3 or 2), allowing it to match the aforementioned selectors even when there are other elements with empty id attributes in the same document. This would imply that the elements now do all have the same ID, but considering that elements cannot have empty IDs in a conforming document in the first place I'm not sure how true that statement is. See the following example:
document.getElementById('something').id = '';
document.getElementById('something-else').id = '';
div[id=""] {
color: red;
}
#something {
color: blue;
}
<div>No id</div>
<div id=''>Empty id</div>
<div id='something'>#something</div>
<div id='something-else'>#something-else</div>
//is there a better way to unset an element's id?
To remove an element's id attribute, use removeAttribute() (or removeAttr() in jQuery):
document.getElementById('something').removeAttribute('id');
$('#something-else').removeAttr('id');
Related
I'm noot good in english, so the title may seem a bit odd.
I want to use css function attr() like this:
I mean i have a container <div> and an inner <div> that i want to have width depending on data-width attribute. For example this would be great, but this doesnt work:
<div class="container">
<div data-width="70%">
</div
</div>
.container {
width: 600px;
height: 200px;
}
.container div {
width: attr(data-width);
height: 100%;
}
Is there any noJS way to use attributes like that?
UPDATE: Guys convinced me that the JS is the only way to do this :)
That's not a big problem (but that's bad. CSS, why youre so illogical? Is the difference between content:attr(data-width) and width: attr(data-width) so big ?).
One of the guys had an idea to go through the all elements with jQuery.
That's ok, but it is very... local? Don't know how to say it in english.
Anyway, i remaked his code a little bit and here it is:
allowed = ['width','color','float'];
$(document).ready(function () {
$('div').each(function (i, el) {
var data = $(el).data(),style = '';
if (!$.isEmptyObject(data)) {
$.each(data, function (attr, value) {
if (allowed.indexOf(attr) != - 1) {
style += attr + ': ' + value + '; ';
}
})
if (style.length != 0) {
$(el).attr('style', style);
}
}
})
})
Idea is simple:
1. We suppose that style we want to add to an element is the only one. I mean there are no scripts that will try to add some other styles,
2. We create an array of allowed attribute names, we need to avoid using wrong names at the style attribute, for example style="answerid: 30671428;",
3. We go through each element, save its data attributes in an object, check if object is empty, and if not - check every attribute if it is allowed, create a string that contains all styles that we need, and - finally - add our style string to the element as the content of style attribute.
That's all, thanks everybody
I would not advise to use CSS alone since it will not allow you to do what you're looking for... instead use a scripting language (in my case jQuery) to accomplish this functionality for you like so: jsFiddle
jQuery
jQuery(document).ready(function(){
var dataElem; // to store each data attribute we come accross
jQuery('div').each(function(){ //loop through each div (can be changed to a class preferably)
dataElem = jQuery(this); //get the current div
if(dataElem.data('width')){ //make sure it exists before anything further
dataElem.width(dataElem.data('width')); //set the element's width to the data attribute's value
dataElem.css("background-color", "yellow");
}
});
});
HTML
<p>The links with a data-width attribute gets a yellow background:</p>
<div>
w3schools.com
</div>
<div class="me" data-width="50"> <!-- change value to see the difference -->
disney.com
</div>
<div>
wikipedia.org
</div>
Notes on the above:
each, data, width.
Instead of doing data-width, use a class attribute. An html tag can have mutliple classes separated by spaces, so if you wanted to be very precise, you could set up as many classes as you need. For instance:
<div class="w70 h100">
</div>
Then in your css:
.w70{
width: 70%;
}
.h100{
height: 100%;
}
And so on.
Is there any noJS way to use attributes like that?
No, you cannot use CSS to set the width of the element to it's data-width attribute. CSS does not allow for this as attr() is only currently available for the CSS content property which is only available on css pseudo elements (::before and ::after).
How can you achieve this with as little javascript as possible?
This is extremely easy to do using the native host provided DOM API.
Select the elements using Document.querySelectorAll().
Iterate the elements and apply the styles using Element.style which can be retrieved from the data-width attribute using Element.dataset
(Demo)
var items = document.querySelectorAll('#container div'), item, i;
for(i = 0; (item = items[i]); i++) item.style.width = item.dataset.width;
Select one part of text in div class:
<div class="enabled_disabled disabled">
<div class="enabled_disabled">
<div class="enabled_disabled">
<div class="enabled_disabled">
<div class="enabled_disabled disabled">
I have those div tags, is there any xpath syntax or fizzler CSS selectors syntax to select just those div tags which have enabled_disabled only (the 3 in the middle)? not those with enabled_disabled disabled
var html = new HtmlDocument();
html.LoadHtml(getitems);
var doc = html.DocumentNode;
var items = (from r in doc.QuerySelectorAll("div.enabled_disabled:not(.disabled)")
let Name = r.InnerHtml//QuerySelector("div.enabled_disabled div.title_bar div.rate_title span.name").InnerText.CleanInnerText()
select new {
CName = Name
}).ToArray();
Fizzler
To select an element with only the class enabled_disabled, you would use:
[class='enabled_disabled']
Using a :not selector is not available in vanilla Fizzler, but can be used if you grab FizzlerEx
XPath
To select an element with only the class enabled_disabled, you would use:
div[#class='enabled_disabled']
In plain old CSS
If the div's assigned classes starts with enabled_disabled:
div[class^=enabled_disabled ]
If the div's assigned classes contains enabled_disabled
div[class*=enabled_disabled ]
If the div only has the class enabled_disabled
div[class=enabled_disabled ]
If the div has the class enabled_disabled and not the class disabled
div.enabled_disabled:not(.disabled)
Given the HTML you list in your question, either of the last two will work for you.
more on attribute selectors from MDN, and, more on :not()
You could use this selector that will match the class and will avoid the other.
$(".enabled_disabled:not('.disabled')");
and you can take out contents out of $()
and it is valid css selector
.enabled_disabled:not(.disabled)
Use not() selector in css.The :not pseudo-class represents an element that is not represented by its argument.
.enabled_disabled:not(.disabled){
}
FIDDLE
More about
SEE THE LINK
I have a group of class name:
.hSpace5{padding-top:0.3125em;}
.hSpace10{padding-top:0.625em;}
.hSpace15{padding-top:0.9375em;}
.hSpace20{padding-top:1.25em;}
.hSpace25{padding-top:1.5625em;}
.hSpace30{padding-top:1.875em;}
.hSpace35{padding-top:2.1875em;}
.hSpace40{padding-top:2.5em;}
Is it possible to target all this class names by referring to the to the first few characters .hSapce--?
you can do it like this in css3
div[class^="hSpace"]
OR
div[class*="hSpace"]
Both are not similar but in your scenario both will work.
First is "starts with class name" and second is "contains class name".
You can use the below selector to select all elements whose class attribute contains the value hspace. Note that this is a contains selector and hence the string can be present anywhere in the class name.
div[class*='hspace'] {
/* styles */
}
div[class*='hspace'] {
color: red;
}
<div class='hspace1'>aa</div>
<div class='hspace2'>bb</div>
<div class='hspace-b'>ab</div>
<div class='c-hspace'>cd</div>
<div class='hvspace'>cd</div>
<!-- will not be selected -->
But check out for browser support.
As mentioned in Rab Nawaz's answer, you can use the below also.
div[class^='hspace'] { }
In-fact, this method might be more suitable for your case because it selects all div whose class starts with hspace.
More information can be found in this W3C Selectors Level 3 Spec in the table present under Section 2.
In my Selenium application i try to select an element which has the highest z-index. That value is not defined in the element itself, but on an ancestor node (the nesting level is not known). In addition if an ancestor is not visible by the use of display: none it shouldn't be returned.
Example HTML:
<div class="container" style="z-index: 10">
<div style="display: none">
<!-- this should not be selected because it is invisible (and the z-index is lower than the others) -->
<div myattr="example"></div>
</div>
</div>
<div class="container" style="z-index: 100">
<div>
<!-- this should not be selected because the z-index is lower than the others -->
<div myattr="example"></div>
</div>
</div>
<div class="container" style="z-index: 1000">
<div>
<!-- this should be selected because it is visible and has the highest z-index -->
<div myattr="example"></div>
</div>
</div>
Currently i have a regex that selects all elements with myattr="example" which do not have an ancestor with display: none:
//div[#myattr='example'
and not(ancestor::div[contains(#style,'display:none')])
and not(ancestor::div[contains(#style,'display: none')])]
I need an additional condition to select the element which has the highest z-index, so to speak which is visible on top of others. For each found node it has to be looked at all ancestors until a node with a specific class is found (container in this example). Then return only the element that has highest z-index ancestor.
Is that even possible with XPath?
I tried really hard, but I think you can't achieve this with a single XPath 1.0 expression. You can get close, but not quite there.
You'll need to use some other logic. There's like a thousand different approaches.
For example, get all the container elements, sort them by z-index and test their myattr="example" descendants for visibility:
// Gets all containers - could also be Gets all elements containing z-index
List<WebElement> containers = driver.findElements(By.className("container"));
// Sorts the containers in an descending order by their z-indexes
Collections.sort(containers, Collections.reverseOrder(new Comparator<WebElement>() {
#Override
public int compare(WebElement o1, WebElement o2) {
return getZindex(o1) - getZindex(o2);
}
private int getZindex(WebElement elem) {
String zindex = elem.getAttribute("style").toLowerCase().replace("z-index: ", "");
return Integer.parseInt(zindex);
}
}));
// look for a visible candidate to return as a result
for (WebElement container : containers) {
WebElement result = container.findElement(By.cssSelector("*[myattr='example']"));
if (result.isDisplayed()) {
return result;
}
}
throw new IllegalStateException("No element found.");
EDIT: After you accepted this answer, I returned to the question and came up with an XPath 1.0 solution. It's ugly as hell, will perform poorly and I can't verify its correctness (it works on your example and a few others I tried), so I suggest you to use the WebDriver approach above. Anyway, I'll share it:
Copypastable oneliner:
//div[#myattr='example' and not(ancestor::div[contains(#style,'display: none')])]/ancestor::div[#class='container' and substring-after(#style,'z-index:') > substring-after(../div[not(descendant::div[contains(#style,'display: none')])]/#style,'z-index:')]
Formatted version:
//div
[
#myattr='example'
and not(ancestor::div[contains(#style,'display: none')])
]
/ancestor::div
[
#class='container'
and substring-after(#style,'z-index:')
> substring-after(
../div[not(descendant::div[contains(#style,'display: none')])]/#style,
'z-index:')
]
And a free translation to human language (not a literal one!):
SELECT A VISIBLE <div #myattr='example'> NODE
//div
[
#myattr='example'
and not(ancestor::div[contains(#style,'display: none')])
]
THAT HAS A <div #class='container'> ANCESTOR
/ancestor::div
[
#class='container'
WHOSE z-index IS GREATER THAN z-index...
and substring-after(#style,'z-index:')
> substring-after(
...OF ALL VISIBLE SIBLINGS
../div[not(descendant::div[contains(#style,'display: none')])]/#style,
'z-index:')
]
I assumed you know the highest value of z-index, in that case xpath is
"//div[contains(#style,'1000')]/div[not(contains(#style,'none'))]/div"
Otherwise using below xpath get all style attributes of div
List<WebElement> divTags=driver.findElements(By.xpath("//div[not(contains(#style,'none'))]/parent::div[contains(#style,'z-index')]"))
for(WebElement ele:divTags)
{
ele.getAttribute("style");
}
Store the z-indexes in some variable
Parse stored z-indexes and get the numbers alone
Using some logic find the highest number among those
Doing all the above things have the hold on index of that elements.
After finding highest z-index, get the index of that element
Using that index construct xpath.
I hope above logic will help you to achieve your goal.
What's the regex which allows me to select all the attribute names from <form> and <input> tags but not from any other HTML tag?
For example:
<!-- all attribute names get selected -->
<input class="something" id="yes" type="text" name="my-field" value="Hello, world!">
<!-- class and id don't get selected because it's a div -->
<div class="something" id="no"></div>
<!-- class gets selected -->
<form class="my-form"></form>
I'm only after the attribute names
Such a regexp would be very complicated to build. Despite the fact that you can't match all HTML by regexes, it would need a very complicated lookbehind to check whether the attribute name which you want to match comes after a opening tag whose name is either "form" or "input". Don't try to build such a regex, you'd go crazy and/or end up with an unreadable, non-maintainable or -undestandable monster.
Instead, use a DOM parser (there will be one for your language) and apply DOM selectors and get the attribute names of the elements.
It is not easy task to do it with regex and actually it is not a good idea to do it with regex. But it is possible >>
input = '...';
var tmp = input, found, params = [];
var re = /(<(?:form|input)\b.*?\s)([\w\-]+)=(['"]).*?\3/gi;
do {
found = 0;
tmp = tmp.replace(re, function($0,$1,$2,$3) {
params.push($2);
found = 1;
return $1;
});
} while (found);
Check this demo.