From 855288c8184b0844b87d73e02c696bde312b19a6 Mon Sep 17 00:00:00 2001 From: Stefaan Lippens <soxofaan@41478.no-reply.drupal.org> Date: Sat, 19 Nov 2011 23:37:54 +0100 Subject: [PATCH] Improved CAPTCHA placement detection, using D7's "actions" form element group. --- captcha.inc | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/captcha.inc b/captcha.inc index 3776fd24..818dd90f 100644 --- a/captcha.inc +++ b/captcha.inc @@ -242,22 +242,12 @@ function _captcha_get_captcha_placement($form_id, $form) { if ($placement_map === NULL) { // If second level cache missed: start from a fresh placement map. $placement_map = array(); - // Prefill with some hard coded default entries. - // The comment form can have a 'Preview' button, or both a 'Submit' and 'Preview' button, - // which is tricky for automatic placement detection. Luckily, Drupal core sets their - // weight (19 and 20), so we just have to specify a slightly smaller weight. - // There's a different comment form for each node type, so we need to set the placement - // for each and every comment form. - $node_types = array_keys(node_type_get_types()); - foreach($node_types as $node_type) { - $placement_map['comment_node_' . $node_type . '_form'] = array('path' => array(), 'key' => NULL, 'weight' => 18.9); - } - // Additional note: the node forms also have the posibility to only show a 'Preview' button. - // However, the 'Submit' button is always present, but is just not rendered ('#access' = FALSE) - // in those cases. The the automatic button detection should be sufficient for node forms. + // This is the place to (pre)fill the placement map with some hard coded default entries. + // However, probably all Drupal core forms are correctly handled with the best effort + // guess based on the 'actions' element (see below). So not much to here at the moment. - // $placement_map['user_login'] = array('path' => array(), 'key' => NULL, 'weight' => 1.9); + // TODO: provide a hook here so other modules can inject placements here? // TODO: also make the placement 'overridable' from the admin UI? } } @@ -266,21 +256,32 @@ function _captcha_get_captcha_placement($form_id, $form) { if (array_key_exists($form_id, $placement_map)) { $placement = $placement_map[$form_id]; } - // If no placement info is available in placement map: - // search the form for buttons and guess placement from it. + // If no placement info is available in placement map: make a best effort guess. else { - $buttons = _captcha_search_buttons($form); - if (count($buttons)) { - // Pick first button. - // TODO: make this more sofisticated? Use cases needed. - $placement = $buttons[0]; + // If there is an "actions" button group, a good placement is just before that. + if (isset($form['actions']) && isset($form['actions']['#type']) && $form['actions']['#type'] === 'actions') { + $placement = array( + 'path' => array(), + 'key' => 'actions', + // #type 'actions' defaults to 100. + 'weight' => (isset($form['actions']['#weight']) ? $form['actions']['#weight'] - 1 : 99), + ); } else { - // Use NULL when no buttons were found. - $placement = NULL; + // Search the form for buttons and guess placement from it. + $buttons = _captcha_search_buttons($form); + if (count($buttons)) { + // Pick first button. + // TODO: make this more sofisticated? Use cases needed. + $placement = $buttons[0]; + } + else { + // Use NULL when no buttons were found. + $placement = NULL; + } } - // Store calculated placement in caches. + // Store calculated placement in cache. $placement_map[$form_id] = $placement; variable_set('captcha_placement_map_cache', $placement_map); } -- GitLab