1
0
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:
Jonas Fonseca 2005-12-25 03:48:53 +01:00 committed by Jonas Fonseca
parent 1347678988
commit fc35d9ee33

View File

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