mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
Implement matching of element relations for DOM selection
It requires searching the select_data stack for all matches of the parent selector and check the properties of matched nodes.
This commit is contained in:
parent
1347678988
commit
fc35d9ee33
@ -455,19 +455,19 @@ parse_dom_select(struct dom_select *select, struct dom_stack *stack,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '>':
|
case '>':
|
||||||
if (get_element_relation(&sel))
|
if (get_element_relation(&sel) != DOM_SELECT_RELATION_DESCENDANT)
|
||||||
return DOM_ERR_SYNTAX;
|
return DOM_ERR_SYNTAX;
|
||||||
sel.match.element |= DOM_SELECT_RELATION_DIRECT_CHILD;
|
sel.match.element |= DOM_SELECT_RELATION_DIRECT_CHILD;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '+':
|
case '+':
|
||||||
if (get_element_relation(&sel))
|
if (get_element_relation(&sel) != DOM_SELECT_RELATION_DESCENDANT)
|
||||||
return DOM_ERR_SYNTAX;
|
return DOM_ERR_SYNTAX;
|
||||||
sel.match.element |= DOM_SELECT_RELATION_DIRECT_ADJACENT;
|
sel.match.element |= DOM_SELECT_RELATION_DIRECT_ADJACENT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '~':
|
case '~':
|
||||||
if (get_element_relation(&sel))
|
if (get_element_relation(&sel) != DOM_SELECT_RELATION_DESCENDANT)
|
||||||
return DOM_ERR_SYNTAX;
|
return DOM_ERR_SYNTAX;
|
||||||
sel.match.element |= DOM_SELECT_RELATION_INDIRECT_ADJACENT;
|
sel.match.element |= DOM_SELECT_RELATION_INDIRECT_ADJACENT;
|
||||||
break;
|
break;
|
||||||
@ -706,11 +706,87 @@ match_attribute_selectors(struct dom_select_node *base, struct dom_node *node)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* XXX: Assume the first context is the one! */
|
||||||
|
#define get_dom_select_state(stack, state) \
|
||||||
|
((struct dom_select_state *) get_dom_stack_state_data((stack)->contexts, state))
|
||||||
|
|
||||||
|
static int
|
||||||
|
match_element_relation(struct dom_select_node *selector, struct dom_node *node,
|
||||||
|
struct dom_stack *stack)
|
||||||
|
{
|
||||||
|
struct dom_stack_state *state;
|
||||||
|
enum dom_select_element_match relation = get_element_relation(selector);
|
||||||
|
int i, index;
|
||||||
|
|
||||||
|
assert(relation);
|
||||||
|
|
||||||
|
/* When matching any relation there must be a parent, either so that
|
||||||
|
* the node is a descendant or it is possible to check for siblings. */
|
||||||
|
if (!node->parent)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (relation != DOM_SELECT_RELATION_DIRECT_CHILD) {
|
||||||
|
/* When looking for preceeding siblings of the current node,
|
||||||
|
* the current node cannot be first or not in the list (-1). */
|
||||||
|
index = get_dom_node_list_index(node->parent, node);
|
||||||
|
if (index < 1)
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find states which hold the parent of the current selector
|
||||||
|
* and check if the parent selector's node is the parent of the
|
||||||
|
* current node. */
|
||||||
|
foreachback_dom_stack_state(stack, state, i) {
|
||||||
|
struct dom_node *selnode;
|
||||||
|
|
||||||
|
/* We are only interested in states which hold the parent of
|
||||||
|
* the current selector. */
|
||||||
|
if (state->node != selector->node.parent)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
selnode = get_dom_select_state(stack, state)->node;
|
||||||
|
|
||||||
|
if (relation == DOM_SELECT_RELATION_DIRECT_CHILD) {
|
||||||
|
/* Check if the parent selector's node is the parent of
|
||||||
|
* the current node. */
|
||||||
|
if (selnode == node->parent)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
int sibindex;
|
||||||
|
|
||||||
|
/* Check if they are siblings. */
|
||||||
|
if (selnode->parent != node->parent)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sibindex = get_dom_node_list_index(node->parent, selnode);
|
||||||
|
|
||||||
|
if (relation == DOM_SELECT_RELATION_DIRECT_ADJACENT) {
|
||||||
|
/* Check if the sibling node immediately
|
||||||
|
* preceeds the current node. */
|
||||||
|
if (sibindex + 1 == index)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
} else { /* DOM_SELECT_RELATION_INDIRECT_ADJACENT */
|
||||||
|
/* Check if the sibling node preceeds the
|
||||||
|
* current node. */
|
||||||
|
if (sibindex < index)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#define has_element_match(selector, name) \
|
#define has_element_match(selector, name) \
|
||||||
((selector)->match.element & (name))
|
((selector)->match.element & (name))
|
||||||
|
|
||||||
static int
|
static int
|
||||||
match_element_selector(struct dom_select_node *selector, struct dom_node *node)
|
match_element_selector(struct dom_select_node *selector, struct dom_node *node,
|
||||||
|
struct dom_stack *stack)
|
||||||
{
|
{
|
||||||
assert(node && node->type == DOM_NODE_ELEMENT);
|
assert(node && node->type == DOM_NODE_ELEMENT);
|
||||||
|
|
||||||
@ -718,25 +794,9 @@ match_element_selector(struct dom_select_node *selector, struct dom_node *node)
|
|||||||
&& dom_node_casecmp(&selector->node, node))
|
&& dom_node_casecmp(&selector->node, node))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
switch (get_element_relation(selector)) {
|
if (get_element_relation(selector) != DOM_SELECT_RELATION_DESCENDANT
|
||||||
case DOM_SELECT_RELATION_DIRECT_CHILD: /* E > F */
|
&& !match_element_relation(selector, node, stack))
|
||||||
/* node->parent */
|
return 0;
|
||||||
/* Check all states to see if node->parent is there
|
|
||||||
* and for the right reasons. */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DOM_SELECT_RELATION_DIRECT_ADJACENT: /* E + F */
|
|
||||||
/* Get preceding node to see if it is on the stack. */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DOM_SELECT_RELATION_INDIRECT_ADJACENT: /* E ~ F */
|
|
||||||
/* Check all states with same depth? */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DOM_SELECT_RELATION_DESCENDANT: /* E F */
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Root nodes either have no parents or are the single child of the
|
/* Root nodes either have no parents or are the single child of the
|
||||||
* document node. */
|
* document node. */
|
||||||
@ -790,7 +850,7 @@ dom_select_push_element(struct dom_stack *stack, struct dom_node *node, void *da
|
|||||||
* on the select_data->stack, cache what select nodes was
|
* on the select_data->stack, cache what select nodes was
|
||||||
* matches so that it is only checked once. */
|
* matches so that it is only checked once. */
|
||||||
|
|
||||||
if (!match_element_selector(selector, node))
|
if (!match_element_selector(selector, node, &select_data->stack))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
WDBG("Matched element: %.*s.", node->string.length, node->string.string);
|
WDBG("Matched element: %.*s.", node->string.length, node->string.string);
|
||||||
|
Loading…
Reference in New Issue
Block a user