feat: attribute selection

main
Guilian 2025-01-20 17:05:29 +01:00
parent c923159d7a
commit 79d6a8f77d
Signed by: Guilian
GPG Key ID: B86CC9678982ED8C
2 changed files with 78 additions and 32 deletions

34
css.lua
View File

@ -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

View File

@ -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 = {}