feat: attribute selection
parent
c923159d7a
commit
79d6a8f77d
34
css.lua
34
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
|
||||
|
|
76
html.lua
76
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 = {}
|
||||
|
||||
|
|
Loading…
Reference in New Issue