Javascript library implementing emulation of CSS selectors lookup, as document.querySelector.
View the Project on GitHub jeremiah-shaulov/joyquery
Selectors in joyquery are regular standard CSS selectors, with some features missing, and some features added (see Features).
Selector expression consists of one or more alternatives separated by commas.
alt1
/* OR */
alt1, alt2, alt3
Each alternative expresses path to follow to find desired elements.
section div a
This means, find element called "section", then inside it find "div", and then inside div find "a". So "a" elements will be returned if found.
In this case "div" can be placed anywhere inside section: as it's direct child, or as a far descendant.
If we want "div" to be related to "section" in some other way, we use axises.
There are 4 axises in standard CSS: descendant, child, following-sibling and , first-following-sibling.
section div /* descendant */
section > div /* child */
section ~ div /* following-sibling */
section + div /* first-following-sibling */
The joyquery library introduces more axises, inspired by XPATH axises.
section self::*.en /* self */
section > div /* child */
section child::div /* also child */
section div /* descendant */
section descendant::div /* also descendant */
section descendant-or-self::*.en /* descendant-or-self */
section parent::* /* parent */
section ancestor::* /* ancestor */
section ancestor-or-self::* /* ancestor-or-self */
section ~ div /* following-sibling */
section following-sibling::div /* also following-sibling */
section + div /* first-following-sibling */
section first-following-sibling::div /* also first-following-sibling */
section preceding-sibling::* /* preceding-sibling */
section first-preceding-sibling::* /* first-preceding-sibling */
Specifies another conditions for the current element.
Potential matches are children of current element.
Potential matches are children of current element, and all elements inside them, no matter the depth.
Among potential matches are the current element itself, and children of the current element, and all elements inside them, no matter the depth.
Selects parent of current element.
Selects parent and all grandparents of current element.
Selects current element, it's parent and all it's grandparents.
Selects elements belonging to the same parent as the current element, only those following the current element.
Selects one element belonging to the same parent as the current element, which follows the current element (if any).
Selects elements belonging to the same parent as the current element, only those preceding the current element.
Selects one element belonging to the same parent as the current element, which precedes the current element (if any).
Each part in complex selector is called simple selector. For example there are 3 simple selectors in "section div a".
Each simple selector consists of element name and conditions. To match any element name, "*" can be used, or name may be omitted. There can be any number of conditions.
[href^="https:"][alt].link
Selects element with any name.
*.cls
Selects element with specified name.
div.cls
Selects element that has attribute "foo" (possible empty).
option[selected]
Selects element that has attribute "foo" with value "bar".
a[target="_blank"]
Selects element that either don't have attribute "foo", or have it but with value other than "bar".
a[target!="_self"]
Selects element whose "foo" attribute value is a list of whitespace-separated values, one of which is exactly equal to "bar".
a[class~="external"]
Element <a class="first external highlighted">...</a> will match.
Element whose "foo" attribute value begins with string "bar".
a[target^="_bla"]
Element whose "foo" attribute value ends with string "bar".
a[target$="ank"]
Element whose "foo" attribute value contains string "bar".
a[target*="bla"]
Element whose "foo" attribute has a hyphen-separated list of values beginning with "en"
a[lang|="en"]
Matches if E is the root element, that is document.documentElement (the <html> tag in HTML documents)
*:root
An E element, the n-th child of its parent. N can be complex number like 2n+1. In this case will select each 2nd matching element with offset +1. In place of 2 and 1 can be any integer number.
.cls:nth-child(3)
.cls:nth-child(4n-1)
An E element, the n-th child of its parent, counting from the last one. N can be complex number like 2n+1. In this case will select each 2nd matching element with offset +1. In place of 2 and 1 can be any integer number.
.cls:nth-last-child(3)
.cls:nth-last-child(4n-1)
An E element, the n-th child of its parent, counting only elements with the same name as E. N can be complex number like 2n+1. In this case will select each 2nd matching element with offset +1. In place of 2 and 1 can be any integer number.
div:nth-of-type(3)
div:nth-of-type(4n-1)
An E element, the n-th child of its parent, counting from the last one, counting only elements with the same name as E. N can be complex number like 2n+1. In this case will select each 2nd matching element with offset +1. In place of 2 and 1 can be any integer number.
div:nth-last-of-type(3)
div:nth-last-of-type(4n-1)
An E element, first child of its parent.
div:first-child
An E element, last child of its parent.
div:last-child
An E element, first child name E of it's parent.
div:first-of-type
An E element, last child name E of it's parent.
div:last-of-type
An E element, only child of its parent.
div:only-child
An E element, only child named E of its parent.
div:only-of-type
Element E that doesn't have element children, and nonempty text children. A text child is considered non-empty if it contains spaces.
div:empty
Element currently focused in document (as result of user interaction).
input:focus
Element whose id attribute equals to text after "#" sign in URL of current page.
div:target
Enabled element, that means element on which interaction with user has not been disabled by doing element.disabled=true. I found that this selector works differently in Chrome and Firefox. Chrome considers <a> tags to be "active", while Firefox doesn't. Joyquery emulated algorythm behaves like Firefox.
*:enabled
Disabled element, which was disabled by doing element.disabled=true.
*:disabled
Only <input type="radio">, <input type="checkbox"> and <option> can be "checked".
*:checked
Class. Same as E[class~="class-name"].
*.class-name
Id. Same as E[id="value"].
#header
Element that doesn't match any another selector "s". The "s" can be complex selector. It's default axis is self::*. Joyquery implementation is compatible with standard, but extends it (standard says that "s" must be simple selector). But it's not the same as jQuery implementation.
#header:not(.compact + #footer.compact)
Means #header that doesn't have class .compact, and is not followed by #footer.compact. The default self::* axis can be overriden:
#header:not(parent::body[lang="en"])
Means #header, which is not a child of "body[lang="en"]".
Element E, which also matches selector "s". The "s" can be complex selector. It's default axis is self::*. This implementation is not the same as jQuery's one.
#header:has(* p)
Means #header, that contains p inside it. Without asterisk, it can also match p#header (because of the default axis).
Element E, which also matches any of given selectors s1, s2, ... The selectors can be complex selector. Their default axis is self::*.
*:any(input, textarea, select, button)
Element that doesn't occupy space (display:none, type="hidden", etc...).
*:hidden
Matches <input>, <select>, <textarea> and <button> elements.
*:input
From result set of current simple selector, select results starting from number n. Number n is 1-based, that is :from(1) is default for every simple selector. :from(2) means to skip first result. This is not the same as :nth-child(n) because result of simple selector can include elements belonging to different parent elements.
img:from(3)
From result set of current simple selector, select no more than n results.
img:from(3):limit(10)
If :from(n) and/or :limit(n) specified several times the last occurance wins, so it's meaningless. In other words, joyquery's :from(n) and :limit(n) work not the same way as jQuery's :gt(n) and :lt(n) do.