-
-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathpseudo-selectors.lisp
139 lines (108 loc) · 4.91 KB
/
pseudo-selectors.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
(in-package #:org.shirakumo.clss)
(define-pseudo-selector root (node)
(root-p node))
(defun match-nth (i n)
(cond ((string-equal n "odd") (oddp i))
((string-equal n "even") (evenp i))
((find #\n n)
(let* ((npos (position #\n n))
(mult (cond ((= 0 npos) 1)
((and (= 1 npos) (char= #\- (char n 0))) -1)
(T (parse-integer n :end npos))))
(off (if (< (1+ npos) (length n))
(parse-integer n :start (1+ npos))
0)))
(multiple-value-bind (quot rem) (floor (- i off) mult)
(and (= 0 rem) (<= 0 quot)))))
(T (= (parse-integer n) i))))
(define-pseudo-selector nth-child (node n)
(match-nth (1+ (element-position node)) n))
(define-pseudo-selector nth-last-child (node n)
(match-nth (- (length (sibling-elements node))
(element-position node)) n))
(define-pseudo-selector nth-of-type (node n)
(match-nth (loop with count = 0
for sibling across (family node)
when (and (element-p sibling)
(string-equal (tag-name sibling) (tag-name node)))
do (incf count)
until (eq sibling node)
finally (return count)) n))
(define-pseudo-selector nth-last-of-type (node n)
(match-nth (loop with count = 0
for i downfrom (1- (length (family node))) to 0
for sibling = (aref (family node) i)
when (and (element-p sibling)
(string-equal (tag-name sibling) (tag-name node)))
do (incf count)
until (eq sibling node)
finally (return count)) n))
(define-pseudo-selector first-child (node)
(= (element-position node) 0))
(define-pseudo-selector last-child (node)
(loop for i downfrom (1- (length (family node))) to 0
for sibling = (aref (family node) i)
when (element-p sibling)
do (return (eq sibling node))))
(define-pseudo-selector first-of-type (node)
(loop for sibling across (family node)
when (and (element-p sibling)
(string-equal (tag-name sibling) (tag-name node)))
do (return (eq sibling node))))
(define-pseudo-selector last-of-type (node)
(loop for i downfrom (1- (length (family node))) to 0
for sibling = (aref (family node) i)
when (and (element-p sibling)
(string-equal (tag-name sibling) (tag-name node)))
do (return (eq sibling node))))
(define-pseudo-selector only-child (node)
(loop for sibling across (family node)
always (or (eq sibling node)
(not (element-p sibling)))))
(define-pseudo-selector only-of-type (node)
(loop for sibling across (family node)
always (or (eq sibling node)
(not (element-p sibling))
(not (string-equal (tag-name sibling) (tag-name node))))))
(define-pseudo-selector empty (node)
(= (length (children node)) 0))
(define-pseudo-selector link (node)
(error 'pseudo-selector-not-available :name "LINK"))
(define-pseudo-selector visited (node)
(error 'pseudo-selector-not-available :name "VISITED"))
(define-pseudo-selector active (node)
(error 'pseudo-selector-not-available :name "ACTIVE"))
(define-pseudo-selector hover (node)
(error 'pseudo-selector-not-available :name "HOVER"))
(define-pseudo-selector focus (node)
(error 'pseudo-selector-not-available :name "FOCUS"))
(define-pseudo-selector target (node)
(error 'pseudo-selector-not-available :name "TARGET"))
(define-pseudo-selector lang (node language)
(let ((languages (or (attribute node "lang")
(attribute node "xml:lang"))))
(when (and languages (find-substring language languages #\-))
language)))
(define-pseudo-selector enabled (node)
(has-attribute node "enabled"))
(define-pseudo-selector disabled (node)
(has-attribute node "disabled"))
(define-pseudo-selector checked (node)
(has-attribute node "checked"))
(define-pseudo-selector first-line (node)
(error 'pseudo-selector-not-available :name "FIRST-LINE"))
(define-pseudo-selector first-letter (node)
(error 'pseudo-selector-not-available :name "FIRST-LETTER"))
(define-pseudo-selector before (node)
(error 'pseudo-selector-not-available :name "BEFORE"))
(define-pseudo-selector after (node)
(error 'pseudo-selector-not-available :name "AFTER"))
(define-pseudo-selector warning (node)
(let ((classes (attribute node "class")))
(when (and classes (find-substring "warning" classes #\Space))
"warning")))
(define-pseudo-selector not (node selector)
(not (match-matcher (third (second (parse-selector selector))) node)))
;;; Extra extensions specific to CLSS
(define-pseudo-selector first-only (node)
(signal 'complete-match-pair :value (make-array 1 :initial-element node :adjustable T :fill-pointer T)))