@@ 1,13 1,13 @@
# Functional psuedoclasses
These would mostly need to be added to the interpretor.
-* [ ] :not()
+* [x] :not() -- TODO apply specificity
* [x] :dir()
-* [ ] :is()
+* [x] :is() -- TODO apply specificity
* [x] :lang()
* [ ] :nth-child()
* [ ] :nth-last-child()
* [ ] :nth-of-type()
* [ ] :nth-last-child()
-* [ ] :where()
+* [x] :where()
* etc
@@ 11,12 11,16 @@ import Data.CSS.Style.Common
import Data.Text (unpack)
import Data.List
import Data.Maybe
+import Data.Bits (xor)
+
+-- For pseudoclasses
+import Data.CSS.Syntax.Selector (parseSelectors)
-- | A compiled(?) CSS selector.
type SelectorFunc = Element -> Bool
type AttrsFunc = [Attribute] -> Bool
-- Mostly here for the sake of pseudoclasses.
-data IL = Tagname Text | Fail
+data IL = Tagname Text | Fail | Recursive Bool [Selector]
-- | Converts a parsed CSS selector into a callable function.
compile :: Selector -> SelectorFunc
@@ 31,6 35,8 @@ compileInner sel = compileInner' $ lowerInner sel
compileInner' :: ([IL], [(Text, String -> Bool)]) -> SelectorFunc
compileInner' ((Tagname tag:tests), attrs) = testTag tag $ compileInner' (tests, attrs)
compileInner' ((Fail:_), _) = \_ -> False
+compileInner' ((Recursive negate' sels:tests), attrs) =
+ recursiveSelect negate' (map compile sels) $ compileInner' (tests, attrs)
compileInner' ([], attrs) = testAttrs (compileAttrs $ sortAttrs attrs) matched
compileAttrs :: [(Text, String -> Bool)] -> AttrsFunc
compileAttrs ((tag, test):attrs) = testAttr tag test $ compileAttrs attrs
@@ 43,6 49,11 @@ lowerInner (Class c:s) = (tests, ("class", hasWord $ unpack c):attrs) where (tes
lowerInner (Property prop test:s) = (tests, (prop, compileAttrTest test):attrs)
where (tests, attrs) = lowerInner s
-- psuedos, TODO handle argumented psuedoclasses.
+lowerInner (Psuedoclass c args:s)
+ | c `elem` ["is", "where"], (sels, []) <- parseSelectors args =
+ (Recursive False sels:tests, attrs) where (tests, attrs) = lowerInner s
+lowerInner (Psuedoclass "not" args:s) | (sels, []) <- parseSelectors args =
+ (Recursive True sels:tests, attrs) where (tests, attrs) = lowerInner s
lowerInner (Psuedoclass c []:s) =
(tests, ("", hasWord $ unpack c):attrs) where (tests, attrs) = lowerInner s
lowerInner (Psuedoclass _ _:_) = ([Fail], [])
@@ 93,6 104,11 @@ hasWord expected value = expected `elem` words value
hasLang :: [Char] -> [Char] -> Bool
hasLang expected value = expected == value || isPrefixOf (expected ++ "-") value
+--- Pseudoclasses
+recursiveSelect :: Bool -> [SelectorFunc] -> SelectorFunc -> SelectorFunc
+recursiveSelect negate' sels success el | negate' `xor` any ($ el) sels = success el
+ | otherwise = False
+
--------
---- RuleStore wrapper
--------