If I have an HTML element <input type="submit" value="Search" /> a css selector needs to be case-sensitive:
input[value='Search'] matches
input[value='search'] does not match
I need a solution where the case-insensitive approach works too. I am using Selenium 2 and Jquery, so answers for both are welcome.
CSS4 (CSS Selector Level 4) adds support for it:
input[value='search' i]
It's the "i" at the end which does the trick.
Broader adoption started mid-2016: Chrome (since v49), Firefox (from v47?), Opera and some others have it. IE not and Edge since it uses Blink. See “Can I use”...
It now exists in CSS4, see this answer.
Otherwise, for jQuery, you can use...
$(':input[name]').filter(function() {
return this.value.toLowerCase() == 'search';
});
jsFiddle.
You could also make a custom selector...
$.expr[':'].valueCaseInsensitive = function(node, stackIndex, properties){
return node.value.toLowerCase() == properties[3];
};
var searchInputs = $(':input:valueCaseInsensitive("Search")');
jsFiddle.
The custom selector is a bit of overkill if doing this once, but if you need to use it many times in your application, it may be a good idea.
Update
Is it possible to have that kind of custom selector for any attribute?
Sure, check out the following example. It's a little convoluted (syntax such as :input[value:toLowerCase="search"] may have been more intuitive), but it works :)
$.expr[':'].attrCaseInsensitive = function(node, stackIndex, properties){
var args = properties[3].split(',').map(function(arg) {
return arg.replace(/^\s*["']|["']\s*$/g, '');
});
return $(node).attr(args[0]).toLowerCase() == args[1];
};
var searchInputs = $('input:attrCaseInsensitive(value, "search")');
jsFiddle.
You could probably use eval() to make that string an array, but I find doing it this way more comfortable (and you won't accidentally execute any code you place in your selector).
Instead, I am splitting the string on , delimiter, and then stripping whitespace, ' and " either side of each array member. Note that a , inside a quote won't be treated literally. There is no reason one should be required literally, but you could always code against this possibility. I'll leave that up to you. :)
I don't think map() has the best browser support, so you can explictly iterate over the args array or augment the Array object.
input[value='Search'] matches
input[value='search' i] Also matches in latest browsers
Support:
version : Chrome >= 49.0, Firefox (Gecko) >= 47.0, Safari >= 9
You can't do it with selectors alone, try:
$('input').filter(function() {
return $(this).attr('value').toLowerCase() == 'search';
});
Related
I've tried to google my question but it makes me even more confused. My question is:
Here's the jQuery code:
$(document).ready(function() {
$(window).resize(function() {
if ($(this).width() < 200) {
$("p").css("color", "red");
} else {
$("p").css("color", "green");
}
});
}
Why do we write (this) and not ("this") ?
How do I know if (document) and (window) should be written with " " - and why's that?
Maybe you could link me somewhere that explains my issue. My code apparently works either way, I'm just curious about the why.
In JavaScript namespace, this is reserved [source].
The JavaScript object literal this refers to the inherited object from the present state in the current execution.
Another example of this we can see is when we are looping through an array and the object this would symbolize the current array object. You may, for example, see this.title, or this.description if we were iterating through a database array of blog posts.
this in jQuery refers to the inherited object. When we add the quotation marks, and it becomes a string, such as "this". This makes jQuery parse it as a DOM selector.
Then we are now looking for the HTML DOM selector <this>, which to my knowledge, does not actually exist in the accepted HTML syntax standards.
As otherwise stated, the concept of this will become tricky when you are working in other JavaScript environments, such as React or Angular. Within the context of a functional component, this becomes the state, such as handling user sessions.
I've looked through a number of posts all pointing towards different ways of using the autocomplete property, but I have yet to have this work in all my browsers. I've seen some really ugly workarounds such as this, but I'm looking for something that is clean and easy.
What is a good way to disable text field autofill on all (or at least, most) common browsers?
The following code will disable autocomplete in FF, IE, and Chrome.
<script>
$(document).ready(function () {
// IE & FF
$('input').attr('autocomplete', 'off');
// Chrome
if ( $.browser.webkit ) {
$('input').attr('autocomplete', 'new-password');
}});
</script>
Enabling Autocomplete on both form and input fields (with the "off" value) for the sake of those law-abiding browsers that do play by the rules is always a good beginning - also for the unlikely event that one day "other" browser...s may feel like compliance isn't all bad.
Until that day hacks are needed. I've noticed that Chrome looks for matching data in at least three places: Labels (contexts), Names and Placeholders. If the Name field is missing from input fields it will look in both Labels and placeholders, but if the Name field is present it will only look in Name and Placeholder.
This script utilize the "form-control" class from Bootstrap on input fields that must be guarded from Autocomplete. Use any other class or filter you like. Also assuming that Placeholders are in use - just remove that part if not.
$(document).ready(function() {
// Begin
var this_obj = null, this_placeholder = null, this_name = null;
$(".form-control").focus(function() {
this_obj = this;
this_name = $(this).prop("name");
this_placeholder = $(this).attr("placeholder");
$(this).prop("name", "NaN" + Math.random());
$(this).attr("placeholder", "...");
}).blur(function() {
$(this_obj).prop("name", this_name);
$(This_obj).attr("placeholder", this_placeholder);
});
// End
});
Note: Leaving the Placeholder empty might actually inadvertently trigger the Autocomplete function as empty assignments are apparently ignored.
The two variables this_name and this_placeholder may be avoided as they are accessible through this_obj, but I like to keep them around for the sake of readability and clarity.
The Script is erm.. quite unobtrusive, as it cleans up after itself and it only requires one matching class or attribute.
It works in Version 68.0.3440.106 (Officiel version) (64-bit), IE11 11.228.17134.0 and Firefox 61.0.2 (64-bit). Sorry, haven't tested others.
Add a class to all your input tags, suppose no-complete
And in your js file add following code:
setTimeout(function (){
$('.no-complete').val ("");
},1);
To set the html of elements on my site, I use mostly
$('elementId').innerHTML = "<p>text</p>";
Looking through the mootools docs, I found this example given:
$('myElement').set('html', '<div></div><p></p>');
Is there any difference between these? Should I go through and change .innerHTML to the mootools method, or doesn't it make a difference?
the reason why the first one works is because - as it stands - a $ selector (document.id) in mootools returns the actual element. this - in normal browsers - is identical to document.getElementById() and the element object exposes any and all of its attributes/properties for you to edit.
the problems with NOT using .set are:
when mootools 2.0 aka MILK gets released, it won't work as it will be wrapped like jQuery and the selector won't return the object (mootools is becoming AMD hence it won't modify native Types - Element, Array, Number, String, Function(maybe!) - prototypes).
you cannot chain this. with set you can: $('someid').set("html", "loading...").highlight();, for example.
set is overloaded - it can set either a single property or multiples by means of passing an object. eg, element.set({html: "hello", href: "#", events: boundObj});
look at https://github.com/mootools/mootools-core/blob/master/Source/Element/Element.js#L936-942 - you can pass an array as an argument and it will join it for you, this makes it easy to work with multi-line strings and ensures performance in IE
edit: the BBT fan has kind of opened a separate topic: should the framework try to block you / prevent you from doing things that break the browser?
if you want to, you can add disallowed elements by changing that setter Element.Properties.html.set = function() { var tag = this.get("tag"); ... check tag }; - isn't mootools great?
mootools - by default - will NOT try to prevent you from doing stupid shit [tm] - that's your responsibility :) try setting height on an element to a negative value in IE, for example. should the Fx class prevent you from doing that? No. Should the setter prevent you? No. The footprint of constant checks to see if you are not breaking means it will slow everything down in performance-critical cases like animations.
Custom data attributes: http://dev.w3.org/html5/spec/Overview.html#embedding-custom-non-visible-data
When I say “work”, I mean, if I’ve got HTML like this:
<div id="geoff" data-geoff="geoff de geoff">
will the following JavaScript:
var geoff = document.getElementById('geoff');
alert(geoff.dataGeoff);
produce, in IE 6, an alert with “geoff de geoff” in it?
You can retrieve values of custom (or your own) attributes using getAttribute. Following your example with
<div id="geoff" data-geoff="geoff de geoff">
I can get the value of data-geoff using
var geoff = document.getElementById("geoff");
alert(geoff.getAttribute("data-geoff"));
See MSDN. And although it is mentioned there that you need IE7 to get this to work, I tested this a while ago with IE6 and it functioned correctly (even in quirks mode).
But this has nothing to do with HTML5-specific attributes, of course.
Yes, they work.
IE has supported getAttribute() from IE4 which is what jQuery uses internally for data().
data = elem.getAttribute( "data-" + key ); // Line 1606, jQuery.1.5.2.js
So you can either use jQuery's .data() method or plain vanilla JavaScript:
Sample HTML
<div id="some-data" data-name="Tom"></div>
Javascript
var el = document.getElementById("some-data");
var name = el.getAttribute("data-name");
alert(name);
jQuery
var name = $("#some-data").data("name");
Not only does IE6 not support the HTML5 Data Attribute feature, in fact virtually no current browser supports them! The only exception at the moment is Chrome.
You are perfectly at liberty to use data-geoff="geoff de geoff" as an attribute, but only Chrome of the current browser versions will give you the .dataGeoff property.
Fortunately, all current browsers - including IE6 - can reference unknown attributes using the standard DOM .getAttribute() method, so .getAttribute("data-geoff") will work everywhere.
In the very near future, new versions of Firefox and Safari will start to support the data attributes, but given that there's a perfectly good way of accessessing it that works in all browsers, then there's really no reason to be using the HTML5 method that will only work for some of your visitors.
You can see more about the current state of support for this feature at CanIUse.com.
Hope that helps.
I think IE has always supported this (at least starting from IE4) and you can access them from JS. They were called 'expando properties'. See old MSDN article
This behaviour can be disabled by setting the expando property to false on a DOM element (it's true by default, so the expando properties work by default).
Edit: fixed the URL
If you wanted to retrieve all of the custom data attributes at once like the dataset property in newer browsers, you could do the following. This is what I did and works great for me in ie7+.
function getDataSet(node) {
var dataset = {};
var attrs = node.attributes;
for (var i = 0; i < attrs.length; i++) {
var attr = attrs.item(i);
// make sure it is a data attribute
if(attr.nodeName.match(new RegExp(/^data-/))) {
// remove the 'data-' from the string
dataset[attr.nodeName.replace(new RegExp('^data-'), '')] = attr.nodeValue;
}
}
return dataset;
}
In IE6, it may not work. For reference: MSDN
I suggest using jQuery to handle most of the cases:
var geoff = $("#geoff").data("data-geoff");
alert(geoff);
Try this in your coding.
I'm looking for a definitive list of HTML elements which are allowed to take focus, i.e. which elements will be put into focus when focus() is called on them?
I'm writing a jQuery extension which works on elements that can be brought into focus. I hope the answer to this question will allow me to be specific about the elements I target.
There isn't a definite list, it's up to the browser. The only standard we have is DOM Level 2 HTML, according to which the only elements that have a focus() method are
HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement and HTMLAnchorElement. This notably omits HTMLButtonElement and HTMLAreaElement.
Today's browsers define focus() on HTMLElement, but an element won't actually take focus unless it's one of:
HTMLAnchorElement/HTMLAreaElement with an href
HTMLInputElement/HTMLSelectElement/HTMLTextAreaElement/HTMLButtonElement but not with disabled (IE actually gives you an error if you try), and file uploads have unusual behaviour for security reasons
HTMLIFrameElement (though focusing it doesn't do anything useful). Other embedding elements also, maybe, I haven't tested them all.
Any element with a tabindex
There are likely to be other subtle exceptions and additions to this behaviour depending on browser.
Here I have a CSS-selector based on bobince's answer to select any focusable HTML element:
a[href]:not([tabindex='-1']),
area[href]:not([tabindex='-1']),
input:not([disabled]):not([tabindex='-1']),
select:not([disabled]):not([tabindex='-1']),
textarea:not([disabled]):not([tabindex='-1']),
button:not([disabled]):not([tabindex='-1']),
iframe:not([tabindex='-1']),
[tabindex]:not([tabindex='-1']),
[contentEditable=true]:not([tabindex='-1'])
{
/* your CSS for focusable elements goes here */
}
or a little more beautiful in SASS:
a[href],
area[href],
input:not([disabled]),
select:not([disabled]),
textarea:not([disabled]),
button:not([disabled]),
iframe,
[tabindex],
[contentEditable=true]
{
&:not([tabindex='-1'])
{
/* your SCSS for focusable elements goes here */
}
}
I've added it as an answer, because that was, what I was looking for, when Google redirected me to this Stackoverflow question.
EDIT: There is one more selector, which is focusable:
[contentEditable=true]
However, this is used very rarely.
$focusable:
'a[href]',
'area[href]',
'button',
'details',
'input',
'iframe',
'select',
'textarea',
// these are actually case sensitive but i'm not listing out all the possible variants
'[contentEditable=""]',
'[contentEditable="true"]',
'[contentEditable="TRUE"]',
'[tabindex]:not([tabindex^="-"])',
':not([disabled])';
I'm creating a SCSS list of all focusable elements and I thought this might help someone due to this question's Google rank.
A few things to note:
I changed :not([tabindex="-1"]) to :not([tabindex^="-"]) because it's perfectly plausible to generate -2 somehow. Better safe than sorry right?
Adding :not([tabindex^="-"]) to all the other focusable selectors is completely pointless. When using [tabindex]:not([tabindex^="-"]) it already includes all elements that you'd be negating with :not!
I included :not([disabled]) because disabled elements can never be focusable. So again it's useless to add it to every single element.
The ally.js accessibility library provides an unofficial, test-based list here:
https://allyjs.io/data-tables/focusable.html
(NB: Their page doesn't say how often tests were performed.)
Maybe this one can help:
function focus(el){
el.focus();
return el==document.activeElement;
}
return value: true = success, false = failed
Reff:
https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/activeElement
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus
There is a much more elegant way to handle this:
Extend the element prototype like the sample below.
Then you can use it like:
element.isFocusable()
*Returns true if "element" is focusable and false if not.
/**
* Determining if an element can be focused on
* #return {Boolean}
*/
HTMLElement.prototype.isFocusable = function () {
var current = document.activeElement
if (current === this) return true
var protectEvent = (e) => e.stopImmediatePropagation()
this.addEventListener("focus", protectEvent, true)
this.addEventListener("blur", protectEvent, true)
this.focus({preventScroll:true})
var result = document.activeElement === this
this.blur()
if (current) current.focus({preventScroll:true})
this.removeEventListener("focus", protectEvent, true)
this.removeEventListener("blur", protectEvent, true)
return result
}
// A SIMPLE TEST
console.log(document.querySelector('a').isFocusable())
console.log(document.querySelector('a[href]').isFocusable())
<a>Not focusable</a>
Focusable