protected function nthOfTypeChild($groupSize, $elementInGroup, $lastChild)
{
// EXPERIMENTAL: New in Quark. This should be substantially faster
// than the old (jQuery-ish) version. It still has E_STRICT violations
// though.
$parents = new \SplObjectStorage();
$matches = new \SplObjectStorage();
$i = 0;
foreach ($this->matches as $item) {
$parent = $item->parentNode;
// Build up an array of all of children of this parent, and store the
// index of each element for reference later. We only need to do this
// once per parent, though.
if (!$parents->contains($parent)) {
$c = 0;
foreach ($parent->childNodes as $child) {
// This doesn't totally make sense, since the CSS 3 spec does not require that
// this pseudo-class be adjoined to an element (e.g. ' :nth-of-type' is allowed).
if ($child->nodeType == XML_ELEMENT_NODE && $child->tagName == $item->tagName) {
// This may break E_STRICT.
$child->nodeIndex = ++$c;
}
}
// This may break E_STRICT.
$parent->numElements = $c;
$parents->attach($parent);
}
// If we are looking for the last child, we count from the end of a list.
// Note that we add 1 because CSS indices begin at 1, not 0.
if ($lastChild) {
$indexToMatch = $item->parentNode->numElements - $item->nodeIndex + 1;
} else {
$indexToMatch = $item->nodeIndex;
}
// If group size is 0, then we return element at the right index.
if ($groupSize == 0) {
if ($indexToMatch == $elementInGroup) {
$matches->attach($item);
}
} else {
if (($indexToMatch - $elementInGroup) % $groupSize == 0 && ($indexToMatch - $elementInGroup) / $groupSize >= 0) {
$matches->attach($item);
}
}
// Iterate.
++$i;
}
$this->matches = $matches;
}