:first-child and :nth-child(n) selectors
Mon Nov 23 11:33:15 UTC 2009 pix@kepibu.org
* :first-child and :nth-child(n) selectors
diff -rN -u old-Oh, Ducks!/notes new-Oh, Ducks!/notes
--- old-Oh, Ducks!/notes 2013-11-22 19:48:46.000000000 +0000
+++ new-Oh, Ducks!/notes 2013-11-22 19:48:46.000000000 +0000
@@ -5,10 +5,11 @@
* [ ] selectors involving descendants
** write documentation
** improve selector support
-*** positional selectors
- * [ ] :nth-child
+*** positional selectors [2/12]
+ * [X] :nth-child(n)
+ * [ ] :nth-child(xn+y)
* [ ] :nth-last-child
- * [ ] :first-child
+ * [X] :first-child
* [ ] :last-child
* [ ] :nth-of-type
* [ ] :nth-last-of-type
@@ -17,7 +18,7 @@
* [ ] :only-child
* [ ] :only-of-type
* [ ] :empty
-*** attribute selectors
+*** attribute selectors [0/7]
* [ ] attribute-present [att]
* [ ] attribute-equal [att=val]
* [ ] attribute-member [att~=val]
diff -rN -u old-Oh, Ducks!/selectors.lisp new-Oh, Ducks!/selectors.lisp
--- old-Oh, Ducks!/selectors.lisp 2013-11-22 19:48:46.000000000 +0000
+++ new-Oh, Ducks!/selectors.lisp 2013-11-22 19:48:46.000000000 +0000
@@ -33,6 +33,10 @@
(defclass type-selector (simple-selector) ())
(defclass id-selector (simple-selector) ())
(defclass class-selector (simple-selector) ())
+(defclass nth-child-selector (simple-selector) ())
+
+(defmethod print-object ((selector universal-selector) stream)
+ (format stream "#<universal-selector>"))
(defmethod initialize-instance :after ((template combinator) &key)
(unless (slot-boundp template 'matcher)
@@ -44,13 +48,23 @@
;; combinators
#+TODO (#T(regexp$ "[ ]*[~][ ]*" ()) (list (make-instance 'sibling-combinator :matcher (parse-selector &rest))))
#+TODO (#T(regexp$ "[ ]*[+][ ]*" ()) (list (make-instance 'adjacent-combinator :matcher (parse-selector &rest))))
- (#T(regexp$ "[ ]*[>][ ]*" ()) (list (make-instance 'child-combinator :matcher (parse-selector &rest))))
- (#T(regexp$ "[ ]+" ()) (list (make-instance 'descendant-combinator :matcher (parse-selector &rest))))
- ;; simple selector
- (#T(regexp$ "[#](\\w+)" (?id)) (cons (make-instance 'id-selector :arg id) (parse-selector &rest)))
- (#T(regexp$ "[\\.](\\w+)" (?class)) (cons (make-instance 'class-selector :arg class) (parse-selector &rest)))
- (#T(regexp$ "(\\w+)" (?type)) (cons (make-instance 'type-selector :arg type) (parse-selector &rest)))
- (#T(regexp$ "\\*" ()) (cons (make-instance 'universal-selector) (parse-selector &rest)))))
+ (#T(regexp$ "[ ]*[>][ ]*" ())
+ (list (make-instance 'child-combinator :matcher (parse-selector &rest))))
+ (#T(regexp$ "[ ]+" ())
+ (list (make-instance 'descendant-combinator :matcher (parse-selector &rest))))
+ ;; simple selectors
+ (#T(regexp$ ":nth-child\\([ ]*([0-9]+)[ ]*\\)" (?n))
+ (cons (make-instance 'nth-child-selector :arg (parse-integer n)) (parse-selector &rest)))
+ (#T(regexp$ ":first-child" ())
+ (cons (make-instance 'nth-child-selector :arg 1) (parse-selector &rest)))
+ (#T(regexp$ "[#](\\w+)" (?id))
+ (cons (make-instance 'id-selector :arg id) (parse-selector &rest)))
+ (#T(regexp$ "[\\.](\\w+)" (?class))
+ (cons (make-instance 'class-selector :arg class) (parse-selector &rest)))
+ (#T(regexp$ "(\\w+)" (?type))
+ (cons (make-instance 'type-selector :arg type) (parse-selector &rest)))
+ (#T(regexp$ "\\*" ())
+ (cons (make-instance 'universal-selector) (parse-selector &rest)))))
(defgeneric find-matching-elements (selector element)
(:method (selector (element t))
@@ -70,6 +84,11 @@
(defmethod element-matches-p (element (selector id-selector))
(string= (element-id element) (selector-arg selector)))
+(defmethod element-matches-p (element (selector nth-child-selector))
+ (alexandria:when-let* ((parent (element-parent element))
+ (pos (position element (element-children parent) :test #'eq)))
+ (= (selector-arg selector) (1+ pos))))
+
(defmethod element-matches-p (element (selector class-selector))
(member (selector-arg selector)
(element-classes element)
diff -rN -u old-Oh, Ducks!/tests.lisp new-Oh, Ducks!/tests.lisp
--- old-Oh, Ducks!/tests.lisp 2013-11-22 19:48:46.000000000 +0000
+++ new-Oh, Ducks!/tests.lisp 2013-11-22 19:48:46.000000000 +0000
@@ -47,6 +47,12 @@
"<div>I do <i>not</i> like cheese.</div><div><span>I like <i>cheese</i>.</span></div>")
(values i span))
+(match (#T(html (:model dom)
+ ("div:first-child" . ?div)
+ ("i:nth-child(1)" . ?i))
+ "<div>I do <i>not</i> <i>like</i> cheese.</div><div><span>I like <i>cheese</i>.</span></div>")
+ (values div i))
+
#+LATER
(match (#t(html ("div::content" . #t(regexp+ "^f(o+)" (?o))))
"<div>barbaz</div><div>fooooooobar</div>")