diff --git a/css.lua b/css.lua index 54cf2c7..c94d9d0 100644 --- a/css.lua +++ b/css.lua @@ -66,7 +66,8 @@ local function parse_compound_selector( tokeniser ) tag_name = nil, id = nil, class = {}, - attributes = {}, + attributes_values = {}, + attributes_present = {}, } --local selectors = {} @@ -106,6 +107,37 @@ local function parse_compound_selector( tokeniser ) end --table.insert(selectors, {type = "id", value = name}) selector.id = name + elseif char == "[" then + tokeniser.next() -- consume leading [ + + local name = tokeniser.read_identifier() + + if tokeniser.peek() == "=" then + tokeniser.next() + + if tokeniser.peek() ~= "\"" then + error("Expected opening quote \" at pos " .. tokeniser.pos() ) + end + tokeniser.next() -- consume leading " + + local value = "" + while tokeniser.peek() ~= "\"" do + value = value .. tokeniser.peek() + tokeniser.next() + end + + tokeniser.next() -- consume trailing " + + selector.attributes_values[name] = value + else + table.insert( selector.attributes_present, name ) + end + + if tokeniser.peek() ~= "]" then + error("Expected closing bracket (']') at " .. tokeniser.pos()) + end + + tokeniser.next() -- consume trailing ] else break end diff --git a/html.lua b/html.lua index 5915bf6..57d022f 100644 --- a/html.lua +++ b/html.lua @@ -386,45 +386,59 @@ end function M.check_simple_selector(element, selector) - -- Skip text nodes - if element.tag_name == ":text" then + -- Skip text nodes + if element.tag_name == ":text" then + return false + end + + -- Check tag name if specified + if selector.tag_name and element.tag_name ~= selector.tag_name then + return false + end + + -- Check ID if specified + if selector.id and element.attributes.id ~= selector.id then + return false + end + + -- Check classes if specified + if selector.class and #selector.class > 0 then + local element_classes = element.attributes.class + if not element_classes then return false end - -- Check tag name if specified - if selector.tag_name and element.tag_name ~= selector.tag_name then - return false - end - - -- Check ID if specified - if selector.id and element.attributes.id ~= selector.id then - return false - end - - -- Check classes if specified - if selector.class and #selector.class > 0 then - local element_classes = element.attributes.class - if not element_classes then + for _, class in ipairs(selector.class) do + local found = false + for _, elem_class in ipairs(element_classes) do + if elem_class == class then + found = true + break + end + end + if not found then return false end - - for _, class in ipairs(selector.class) do - local found = false - for _, elem_class in ipairs(element_classes) do - if elem_class == class then - found = true - break - end - end - if not found then - return false - end - end end - - return true end + for attr_name, attr_value in pairs(selector.attributes_values) do + local elem_attr_value = element.attributes[attr_name] + if elem_attr_value ~= attr_value then + return false + end + end + + -- Check attribute presence selectors + for _, attr_name in ipairs(selector.attributes_present) do + if not element.attributes[attr_name] then + return false + end + end + + return true +end + function M.query_simple_selector(document, selector) local matches = {}