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 2015-10-28 03:50:22.000000000 +0000 +++ new-Oh, Ducks!/notes 2015-10-28 03:50:23.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 2015-10-28 03:50:22.000000000 +0000 +++ new-Oh, Ducks!/selectors.lisp 2015-10-28 03:50:23.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 "#")) (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 2015-10-28 03:50:22.000000000 +0000 +++ new-Oh, Ducks!/tests.lisp 2015-10-28 03:50:23.000000000 +0000 @@ -47,6 +47,12 @@ "
I do not like cheese.
I like cheese.
") (values i span)) +(match (#T(html (:model dom) + ("div:first-child" . ?div) + ("i:nth-child(1)" . ?i)) + "
I do not like cheese.
I like cheese.
") + (values div i)) + #+LATER (match (#t(html ("div::content" . #t(regexp+ "^f(o+)" (?o)))) "
barbaz
fooooooobar
")