Suggested by @sun in #1174634-36: Add new HTML5 FAPI element: telephone:

I'm not sure... would it make sense to properly fix/change that #autocomplete processing into a proper #process or #after_build in a separate issue first? This kind of manual invocation of form_add_autocomplete() in a theme function doesn't really look sustainable or clean to me. Obviously only concerned about this, as we're basically about to repeat this pattern for ~10+ other new form element types.

I agree with this entirely. This is the code we have now:

function theme_textfield($variables) {
  $element = $variables['element'];
  $element['#attributes']['type'] = 'text';
  element_set_attributes($element, array('id', 'name', 'value', 'size', 'maxlength'));
  _form_set_class($element, array('form-text'));

  $extra = '';
  if ($element['#autocomplete_path'] && drupal_valid_path($element['#autocomplete_path'])) {
    drupal_add_library('system', 'drupal.autocomplete');
    $element['#attributes']['class'][] = 'form-autocomplete';

    $attributes = array();
    $attributes['type'] = 'hidden';
    $attributes['id'] = $element['#attributes']['id'] . '-autocomplete';
    $attributes['value'] = url($element['#autocomplete_path'], array('absolute' => TRUE));
    $attributes['disabled'] = 'disabled';
    $attributes['class'][] = 'autocomplete';
    $extra = '<input' . drupal_attributes($attributes) . ' />';
  }

  $output = '<input' . drupal_attributes($element['#attributes']) . ' />';

  return $output . $extra;
}

Drupal 7 backport: #2267857: Support caching of forms with autocomplete

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

ericduran’s picture

Sub.... I'm kidding :-p

I'm working on this patch now. I'm doing it as a process fyi.

ericduran’s picture

Assigned: Unassigned » ericduran
catch’s picture

Category: bug » task
Priority: Normal » Major

Bumping to major task, it makes zero sense doing this in the theme layer. I'm sure there's an older issue for this, but can't find it now.

sun’s picture

Title: Stop processing autocomplete functionality in theme_textfield() » Process #autocomplete_path for all form elements; remove custom/duplicated code from theme_textfield()
Assigned: ericduran » sun
Status: Active » Needs review
FileSize
4.38 KB

This is not particularly easy to do, as the autocomplete "sub-widget" needs a special location - right after the actual input element, but before the form element description.

We don't have a clean way to squeeze something in there, other than #field_suffix, but everything in #field_suffix is not only wrapped in a SPAN, but also has a dedicated/unique purpose (e.g., suffixing the input with " minutes").

Attached patch moves the code more or less as-is from theme_textfield() into theme_form_element(), which seems to be the most simple resolution for now.

---
The only alternative I could see to this is would be to add a dedicated form_process_autocomplete() #process callback to the element info, and make that callback inject a new #type 'autocomplete' child element below the processed element, and lastly make theme_textfield() & co append the rendered $element['#children'] right after the markup they are producing.

sun’s picture

Here's the alternative approach mentioned in #4.

I kinda like this a lot more, because it formalizes the "autocomplete widget" (and thus makes it swappable/pluggable on its own), but it has and clarifies one larger issue we have in the current render/theme system: #theme functions do not render any child elements. To have the injected 'autocomplete' child element rendered, the #theme needs to be turned into a #theme_wrappers callback.

That particular issue should actually be one major discussion topic for #1382350: [discussion] Theme/render system problems...

ericduran’s picture

Yea, I attempted to fix this but I failed miserably were sun succeeded

sun’s picture

Status: Needs review » Needs work

So the question is whether this particular change is acceptable:

+++ b/core/modules/system/system.module
@@ -384,10 +390,13 @@ function system_element_info() {
-    '#theme' => 'textfield',
-    '#theme_wrappers' => array('form_element'),
+    '#theme_wrappers' => array(
+      // Signify the primary #theme function.
+      'theme' => 'textfield',
+      'form_element',
+    ),

...at least, for the time being...

catch’s picture

Status: Needs work » Needs review

I think that's fine as a workaround for now, especially considering the duplicate code we're adding on a much bigger scale in #1174620: Add new HTML5 FAPI element: email and other issues. Moving back to CNR.

effulgentsia’s picture

I discussed this with sun, and suggested using the drupal_render_children() function instead of changing #theme to #theme_wrappers. Here's the patch for that. Otherwise, this looks good to me. I'd RTBC it, except my changes need review.

effulgentsia’s picture

+++ b/core/includes/form.inc
@@ -3631,6 +3631,52 @@ function theme_vertical_tabs($variables) {
+    $element['#tree'] = TRUE;

Do we need to do this for any reason other than to set the child autocomplete element's id? If not, I'd rather we not mess with #tree here, as that will have other side-effects if the element has any other children, and just set $element['autocomplete']['#id'] = $element['#id'] . '-autocomplete';

sun’s picture

I'd be OK with leaving out #tree there. That said, this reminds me of #759222: #tree does not default to TRUE, fails to meet developer expectations, which we could look into changing for D8.

Furthermore:

+++ b/core/includes/form.inc
@@ -3631,6 +3631,52 @@ function theme_vertical_tabs($variables) {
+function form_process_autocomplete($element, &$form_state) {
...
+    $element['autocomplete'] = array(
+      '#type' => 'autocomplete',
...
+function theme_autocomplete($variables) {
...
+  $element['#attributes']['type'] = 'hidden';

+++ b/core/modules/system/system.module
@@ -506,6 +506,10 @@ function system_element_info() {
+  $types['autocomplete'] = array(
+    '#process' => array('ajax_process_form'),
+    '#theme' => 'autocomplete',
+  );

Do we actually need a theme_autocomplete() function then? It themes a hidden input element, for which we have a theme function already. Hence, just set #type autocomplete's #theme to 'hidden'...?

If you'd have an alternative implementation, then that could alter the #theme property of the #type instead of overriding the theme function.

sun’s picture

#1174620: Add new HTML5 FAPI element: email went in, so we additionally need to convert that.

Jacine’s picture

Issue tags: +sprint

Adding this to the next sprint.

effulgentsia’s picture

With #10-#12 incorporated.

sun’s picture

Thanks!

+++ b/core/includes/form.inc
@@ -3632,6 +3632,34 @@ function theme_vertical_tabs($variables) {
+      '#value' => url($element['#autocomplete_path'], array('absolute' => TRUE)),

The original #autocomplete_path value is no longer known to the element. Would it make sense to copy the raw #autocomplete_path into a custom #path property on the 'autocomplete' element in this #process callback?

+++ b/core/includes/form.inc
@@ -3632,6 +3632,34 @@ function theme_vertical_tabs($variables) {
+      '#attached' => array(
+        'library' => array(array('system', 'drupal.autocomplete')),
+      ),

I wonder whether it would make sense to specify this in hook_element_info() instead?

+++ b/core/includes/form.inc
@@ -3703,14 +3731,14 @@ function theme_image_button($variables) {
 function theme_hidden($variables) {
...
-  element_set_attributes($element, array('name', 'value'));
+  element_set_attributes($element, array('id', 'name', 'value'));

ahh. That's the detail of the idea I didn't think of :-/

We intentionally removed the HTML IDs for hidden input elements in #168722: Hidden input elements contain invalid characters in ID attributes

So we'd have two ways out:

1) set the hard-coded ID in #attributes instead and revert this change to theme_hidden().

2) go back to a separate theme_autocomplete() as in earlier patches.

effulgentsia’s picture

To be honest, I don't understand why autocomplete.js requires a hidden element in the markup to begin with. If it needs a hidden element at all (and I'm not sure it does), why can't it make it instead of requiring the document to be polluted. Anyway, not fixing that here, but given that, what do you think of this?

aspilicious’s picture

Status: Needs review » Needs work

#174630: Use watchdog to log user login went in :), we need to get this in as soon as possible

catch’s picture

Status: Needs work » Needs review

I'm fine with this patch converting what it already does, and then a follow-up for anything remaining once it's committed - that's likely to be a quicker route than re-rolling for each new HTML5 element.

Moving back to CNR.

effulgentsia’s picture

Here's an up to date one anyway, mostly as an excuse to trigger another email alert to sun :)

Jacine’s picture

Can we please get some reviews here? This one should be pretty simple. Thanks :)

ericduran’s picture

Ok I just this manually. Everything seems to be looking good.

I used the taxonomy term reference to test this. Everything works well, the hidden field isn't visible and the results list show up correctly.

I would mark this RTBC, but I'll leave it to sun.

Niklas Fiekas’s picture

Status: Needs review » Needs work

#1174628: Add new HTML5 FAPI element: search got in, adding more duplicate code to be removed.

catch’s picture

Status: Needs work » Needs review

We don't need a re-roll for that, just a follow-up once this is in.

sun’s picture

Status: Needs review » Reviewed & tested by the community

Thanks! Still very similar to my original patch, but leveraging drupal_render_children() instead.

I agree we can convert/fix the additional theme functions in a follow-up patch (in this issue).

Regarding the @todo, note that there's already at least one issue for investigating different autocomplete implementations (e.g., jQuery UI's), and this dedicated form element #process function will definitely help us to adjust or switch the implementation.

Dries’s picture

Status: Reviewed & tested by the community » Needs work

Great job. Committed to 8.x. Marking this needs work because more refactoring is possible due to #1174628: Add new HTML5 FAPI element: search (see comment #22 above).

aspilicious’s picture

Status: Needs work » Needs review
FileSize
2.07 KB
Niklas Fiekas’s picture

Status: Needs review » Needs work

Thank you. Looks excellent, except that the other patches have:

- *     #placeholder, #required, #attributes, #autocomplete_path.
+ *     #placeholder, #required, #attributes.
aspilicious’s picture

Status: Needs work » Needs review
FileSize
2.45 KB
Niklas Fiekas’s picture

Status: Needs review » Reviewed & tested by the community

Ok. We're done after that one - search is the last element.
Do we need a change notification?

catch’s picture

Title: Process #autocomplete_path for all form elements; remove custom/duplicated code from theme_textfield() » Change notification for: Process #autocomplete_path for all form elements; remove custom/duplicated code from theme_textfield()
Priority: Major » Critical
Status: Reviewed & tested by the community » Active

Nice! Committed/pushed to 8.x, I think we should add a change notification for this since it's an API addition and something contrib form elements can make use of/be refactored for.

Niklas Fiekas’s picture

Title: Change notification for: Process #autocomplete_path for all form elements; remove custom/duplicated code from theme_textfield() » Process #autocomplete_path for all form elements; remove custom/duplicated code from theme_textfield()
Priority: Critical » Major
Status: Active » Fixed

Created a change notification: http://drupal.org/node/1536426.

Automatically closed -- issue fixed for 2 weeks with no activity.

Bevan’s picture

Issue summary: View changes