W3C: “Selectors API Level 1” is out but …

"Selectors API Level 1" document started in 2006 has reached status of W3C Recommendation these days. Which means we may see it implemented uniformly across all browsers ( those browsers that are alive yet 😉 ).  

But I am disappointed by features provided by this API. It de-facto contains 6 methods but only two of them (first two in the table below) are really useful.

jQuery and Sciter have full set of selector methods needed in practice, but the Selector API just scratched the surface as you see below.

Let’s take a look on what this API gives us and compare with similar features available in Sciter/HTMLayout and jQuery.

function W3C Selectors Sciter jQuery
find first matching element in a document document.querySelector("selector")
: Element
self.select("selector")
: Element
$("selector").first()
: $Obj
find all matching elements in a document document.querySelectorAll("selector")
: staticNodeList
self.selectAll("selector")
: array (of Elements)
$("selector")
: $Obj
find first matching sub-element of an element
using global selector
element.querySelector("selector")
: Element
(See below) (See below)
find all matching sub-elements of an element
using global selector
element.querySelectorAll("selector")
: staticNodeList
(See below) (See below)
find first matching sub-element of an element
using local selector
N/A element.select("selector")
: Element
$obj.find("selector").first()
: $Obj
find all matching sub-elements of an element
using local selector
N/A element.selectAll("selector")
: array (of Elements)
$obj.find("selector")
: $Obj
find first matching sub-element of an element
using rooted local selector
N/A element.select(":root > cont1 > cont2")
: Element
$obj.find("> cont1 > cont2").first()
: $Obj
find all matching sub-elements of an element
using rooted local selector
N/A element.selectAll(":root > cont1 > cont2")
: array (of Elements)
$obj.find("> cont1 > cont2")
: $Obj
find first parent matching the selector N/A element.selectParent("selector")
: Element
$obj.first().closest("selector")
: $Obj
find all parents matching the selector N/A element.selectAllParents("selector")
: array (of Elements)
$obj.first().parents("selector")
: $Obj
check if the element satisfies given selector N/A element.match("selector")
: true | false
$obj.first().is("selector")
: true | false

Where:

  • global selector – selector that uses document root as a selector root.
  • local selector – selector that uses the element itself as a selector root.
  • rooted local selector – selector that contains explicit reference of the element itself as first component.
    For example, in Sciter, this call: ul.selectAll(":root>li") will find all <li> elements that are direct children of the ul element.

The element.querySelector[All]() method defined in the Selector API is just a variation of document.querySelector[All]() but on subset of descendants of the element. Consider this HTML fragment:

<ul>
  <section id=test>
    <ol>
      <li>one</li>
      <li>one</li>
    </ol>
  </section>
</ul>

With the use of the Selector API this code:

var section = document.getElementById("test");
var nListItems = section.querySelectorAll("ul li");

will give you two [items].

But the same thing with jQuery (or Sciter):

var nListItems = $("#test").find("ul li");

will give you zero items. jQuery and Sciter use local selectors (rooted or not).

So methods provided by the Selectors API cannot be used by jQuery to implement its all selector look up methods natively. Only one of them – global look-up can use this API, All local look up methods shall still use home brewed selector implementation in script.

I haven’t seen anyone requesting such strange element.querySelectorAll method and have no clue why it was included in the spec. If someone really needs such local look up using global selectors then it is a matter of writing something like this (in Sciter or jQuery):

section.selectAll("*").filter( :child: child.match("ul li") );

But I don’t know why someone will ever need such method…

The Selectors API has mark "Level 1" so I hope rest of methods will be added soon in Level 2.

So far the mountain has brought forth a mouse. And yet it took 6 years to do so, eh?

Use of CSS constants in script.

In Sciter you can define CSS constants using @const declarations like this:

<style>
  @const TEST_STR:"test";
  @const TEST_COLOR: rgb(128,0,0);
  @const TEST_NUMBER: 128;
</style>

and use them not only in CSS ( as @TEST_COLOR for example ) but also in script using accessor like this:

var test_str = self.style.constant("TEST_STR");

If you think that self.style.constant is too narrative then you can define short “stringizer” function for it:

  function $const( name ) { return self.style.constant(name) || ""; }

and later use it as:

var t1 = $const(TEST_STR); // "test" string
var t2 = $const(TEST_COLOR); // object of type Color, color(128,0,0)
var t3 = $const(TEST_NUMBER); // integer, 128