Mon Nov 30 04:09:10 UTC 2009 pix@kepibu.org * Add :nth-child selector diff -rN -u old-Oh, Ducks!/notes new-Oh, Ducks!/notes --- old-Oh, Ducks!/notes 2013-11-17 08:13:14.000000000 +0000 +++ new-Oh, Ducks!/notes 2013-11-17 08:13:14.000000000 +0000 @@ -115,9 +115,9 @@ * [ ] selectors involving descendants ** write documentation ** improve selector support -*** positional selectors [2/12] +*** positional selectors [3/12] * [X] :nth-child(n) - * [ ] :nth-child(xn+y) + * [X] :nth-child(xn+y) * [ ] :nth-last-child * [X] :first-child * [ ] :last-child diff -rN -u old-Oh, Ducks!/selectors.lisp new-Oh, Ducks!/selectors.lisp --- old-Oh, Ducks!/selectors.lisp 2013-11-17 08:13:14.000000000 +0000 +++ new-Oh, Ducks!/selectors.lisp 2013-11-17 08:13:14.000000000 +0000 @@ -34,6 +34,7 @@ (defclass id-selector (simple-selector) ()) (defclass class-selector (simple-selector) ()) (defclass nth-child-selector (simple-selector) ()) +(defclass nth-last-child-selector (nth-child-selector) ()) (defmethod print-object ((selector universal-selector) stream) (format stream "#")) @@ -53,10 +54,25 @@ (#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))) + ;; FIXME: fix cl-unification so it can handle non-matching groups, + ;; so we can merge all these nth-child-selector variants + ;; into one or two + (#T(regexp$ ":nth-child\\([ ]*([+-]?[0-9]+)n[ ]*([+-]?[0-9]+)[ ]*\\)" (?a ?b)) + (cons (make-instance 'nth-child-selector :arg (cons (parse-integer a) (parse-integer b))) (parse-selector &rest))) + (#T(regexp$ ":nth-child\\([ ]*([+-]?[0-9]+)n[ ]*\\)" (?a)) + (cons (make-instance 'nth-child-selector :arg (cons (parse-integer a) 0)) (parse-selector &rest))) + (#T(regexp$ ":nth-child\\([ ]*n[ ]*([+-]?[0-9]+)[ ]*\\)" (?b)) + (cons (make-instance 'nth-child-selector :arg (cons 1 (parse-integer b))) (parse-selector &rest))) + (#T(regexp$ ":nth-child\\([ ]*-n[ ]*([+-]?[0-9]+)[ ]*\\)" (?b)) + (cons (make-instance 'nth-child-selector :arg (cons -1 (parse-integer b))) (parse-selector &rest))) + (#T(regexp$ ":nth-child\\([ ]*([+-]?[0-9]+)[ ]*\\)" (?b)) + (cons (make-instance 'nth-child-selector :arg (cons 0 (parse-integer b))) (parse-selector &rest))) + (#T(regexp$ ":nth-child\\([ ]*odd[ ]*\\)" ()) + (cons (make-instance 'nth-child-selector :arg (cons 2 1)) (parse-selector &rest))) + (#T(regexp$ ":nth-child\\([ ]*even[ ]*\\)" ()) + (cons (make-instance 'nth-child-selector :arg (cons 2 0)) (parse-selector &rest))) (#T(regexp$ ":first-child" ()) - (cons (make-instance 'nth-child-selector :arg 1) (parse-selector &rest))) + (cons (make-instance 'nth-child-selector :arg (cons 0 1)) (parse-selector &rest))) (#T(regexp$ "[#](\\w+)" (?id)) (cons (make-instance 'id-selector :arg id) (parse-selector &rest))) (#T(regexp$ "[\\.](\\w+)" (?class)) @@ -88,8 +104,20 @@ (defmethod element-matches-p (element (selector nth-child-selector)) (when-let* ((parent (element-parent element)) - (pos (position element (element-children parent) :test #'eq))) - (= (selector-arg selector) (1+ pos)))) + (pos (position element (funcall (typecase selector + (nth-last-child-selector #'reverse) + (nth-child-selector #'identity)) + (element-children parent)) :test #'eq))) + (let ((pos (1+ pos)) + (a (car (selector-arg selector))) + (b (cdr (selector-arg selector)))) + ;; pos = An + B + (cond + ;; pos = 0n + B + ((= 0 a) (= b pos)) + ;; (pos - B)/A = n + (t (and (zerop (mod (- pos b) a)) + (not (minusp (/ (- pos b) a))))))))) (defmethod element-matches-p (element (selector class-selector)) (member (selector-arg selector)