In field_conditional_state_element_process() you are you wrapping every field with an extra DIV. This can cause serious issues in theming... we must use the existing field ID here. It's already unique.

    $element['#prefix'] = '<div ' . drupal_attributes(array('id' => $ids[$original_id])) . '>';
    $element['#suffix'] = "</div>";

Comments

hass’s picture

Issue summary: View changes
Tobias Xy’s picture

To avoid too much pain we could be more specific in field_conditional_state_field_widget_form_alter.
Then it should be save to just use $element['#id'] in field_conditional_state_element_process (at least I hope so...).

But there is also a drawback: We possibly have to list a lot of widget types explicitly within field_conditional_state_field_widget_form_alter. At least I didn't find a proper way how to determine the actual input element (and not one of its wrappers) there.

But in the end we could remove a lot of confusing code within the process and pre_render callback.

Tobias Xy’s picture

Priority: Critical » Major

It's not exactly a critical issue.
"Critical bugs either render a system unusable (not being able to create content or upgrade between versions, blocks not displaying, and the like), cause loss of data, or expose security vulnerabilities."

hass’s picture

Critical also means a release blocker. This is something that cannot changed after release as it is changing html and therby theming. We really need to solve this before release.

Do we really have so many widget types? The list should be short. It may give us a lot more control what really happens without many unexpected side effects.

Tobias Xy’s picture

It's very annoying, that every widget has another array structure (hook_field_widget_form doesn't enforce any standards) and I have no clue how to handle that, without creating a lot of bad code, getting gray hair and having nightmares...

Maybe I have to do more research on how widgets are handled in Drupal, but I fear that there isn't a nice way to get the information we need...

Because of this I think we should add the process handler within the widget_form_alter hook just to the top level of the given element.
And then we should "search" for the actual input element within the process callback.

If anyone has a better solution please let me know...

hass’s picture

I'm not sure what you are talking about. Id and classes of a field widget should be in the same place all times. Otherwise theming wouldbe impossible. A have themed all my form elements abd added classes. It was not that difficult... But I may not understand something. Can you write up your action plan and what you are trying? Maybe I get a better idea of the problems you expect. Currently i do not understany why you are not using the element id as reference. That's all. We need, isn't it?

Maybe we need to hook into form theme functions.

Tobias Xy’s picture

Its not about the actual HTML output. The problem is, that during the form building process the widgets are differently wrapped.

For example:
Create a content type with a checkbox, a text field, a file field, a select list and a URL field (it's not in core but there are a lot of sites using it).
Then add a

dpm($element);

in field_conditional_state_element_process (devel needed) and go to node/add/helloworld
The differences between these widget types (especially $element['#id']):

  • Text field: The id set in $element['#id'] is not appearing in HTML!! The actual input element can be found in $element['value'], but $element['value']['#id'] doesn't exist. In this case the id in HTML is just $element['#id'] . "-value", but it's not that easy all the time, I fear.
  • File field: At the top level #entity_type and #bundle aren't set (it won't pass the initial if statement in field_conditional_state_element_process). Instead we have to go to $element[0] to find these information. But the #id is at the top level again and won't appear in HTML as well.
  • URL field: The top level #id finally appears in HTML, but it is a wrapper fieldset of the input element (located in $element['value']).
  • Checkbox / select list: The #id from the top level of the element array is applied to the checkbox / select list (<= the "good guys").

So we actually have to handle all the widget types differently, right?

hass’s picture

Well, I need to repro this first as I cannot fully follow.

Maybe we can use hook_form_alter() or some form preprocess functions and add the state api stuff there. Have you considered this already?

Tobias Xy’s picture

I don't think hook_form_alter (or any other form level hook) will do a better job there. We would still have to "find" the correct ID but starting from a higher level within the page array.
hook_field_widget_form_alter at least is called per field, so this should be less pain, than hook_form_alter.

Tobias Xy’s picture

Status: Active » Needs review
StatusFileSize
new7.76 KB

I created a patch. The extra div is now not longer needed. The main changes are:

1.) Now we use a #after_build callback instead of a #process callback, because during #process the element isn't completely build.
2.) _field_conditional_state_get_element_parents returns the path to the actual input element within the $element array and additionally the path to the field information like #entity_type, #bundle, #field_name if they aren't set on the actual element.
Currently all core widget types and the url_external widget type should be supported (except of "Check boxes/radio buttons"). Field collections (or actual any kind of form where one field exists twice or more) are not supported currently.
3.) field_conditional_state_element_after_build only adds the #pre_render callback to the actual input element as defined by _field_conditional_state_get_element_parents and maps the combination of entity type, bundle and field name to the actual used HTML ID ($element['#id']).

Edit: With this patch #2185759: Select list control fields aren't working would be fixed too and #2200361: Incompatible with #type => text_format (ie. long text fields with formatting) at least partially.

Tobias Xy’s picture

StatusFileSize
new8.18 KB

Removed useless code in _field_conditional_state_add_states.

Tobias Xy’s picture

I don't expect any reviews, so I will commit the patch at the weekend, because it will probably fix a lot of problems.

hass’s picture

There are some code style issues. I cannot test before the weekend, too. Have you also checked pre_render hook?

Tobias Xy’s picture

StatusFileSize
new10.36 KB

Fixed a lot of coding style issues here.
The #pre_render hook should work as expected (at least it does when I tested the patch).

Tobias Xy’s picture

StatusFileSize
new10.36 KB

Small change in field_conditional_state_element_after_build.

Tobias Xy’s picture

Status: Needs review » Needs work

Actually visibility states have to be applied to the topmost level and enabled/required states to the actual input element. Will do that later today.

Tobias Xy’s picture

StatusFileSize
new12.34 KB

Now we have two different pre_render callbacks.

One to add the states visible and invisible and one to add all the other states.

field_conditional_state_element_after_build checks what kind of states are active for the current element and sets the appropriate pre_render callbacks (only if needed).

We have to handle this differently, because the states visible/invisible should show/hide the whole widget and not just the input element. There is not always a difference, but sometimes unfortunately there are (visible) wrappers around the element (URL field for example). So the state must be applied to the topmost level of $element passed to field_conditional_state_element_after_build.
The other states (enabled, disabled, required and optional) only affect the actual input element, so adding them to the topmost level won't work sometimes (URL field and some core widgets for example).

The whole thing is a little bit complex, but I think it's the most stable way of doing this.

Tobias Xy’s picture

Status: Needs work » Needs review
hass’s picture

Status: Needs review » Needs work

If I create a new node with fields inside having states I get tons of these notices at node/add/foo

Notice: Undefined index: #entity_type in field_conditional_state_element_after_build() (Zeile 123 von sites\all\modules\contrib\field_conditional_state\field_conditional_state.module).
Notice: Undefined index: #bundle in field_conditional_state_element_after_build() (Zeile 123 von sites\all\modules\contrib\field_conditional_state\field_conditional_state.module).
Notice: Undefined index: #field_name in field_conditional_state_element_after_build() (Zeile 123 von sites\all\modules\contrib\field_conditional_state\field_conditional_state.module).

Looks like entityreference_autocomplete fields are missing these keys... or better to say - they are inside ['target_id'] subarray.

Tobias Xy’s picture

I'll add a check for these keys tomorrow, but these notices should currently only appear for some of the not supported widget types.

Which widget types are you using on this form?
Autocomplete fields aren't supported at the moment. Going to add them tomorrow too (they have to be added to _field_conditional_state_get_element_parents).

hass’s picture

That sounds like it can fail on more field types. We should add a whitelist here. I guess we cannot support all custom field types.

Tobias Xy’s picture

It will fail on all widgets (not equal to field types!) where the entity_type, bundle and field_name information are not on the top level of the $elements array in field_conditional_state_element_after_build AND which are not explicitly handled by _field_conditional_state_get_element_parents.

Can we create our own documentation pages for FCS? I could write a table of supported widgets then.

hass’s picture

I do not like to see notices... The documentation of supported field types is a different thing. I think a table on project home fit, but everyone can create doc pages on d.o.

Tobias Xy’s picture

You mean a coded whitelist of widgets that are allowed to be control fields?
Sounds like a good idea.

hass’s picture

Yes. If somethink is known to work... Add/show it - otherwise it is not available. We will get the request to support missing fields... I'm sure :-)

Tobias Xy’s picture

Title: Remove the extra DIV added in field_conditional_state_element_process() » Rewrite of state handling using a whitelist of supported widgets
Status: Needs work » Needs review
StatusFileSize
new13.86 KB

I introduced a whitelist in the new patch. It doesn't really change the behavior of the fcs settings form, because thats not even easy. I created a new issue for that: #2218339: Restrict control field selection to supported control fields.
Unsupported fields are neither usable as control fields nor as controled field.

Tobias Xy’s picture

Status: Needs review » Fixed
StatusFileSize
new13.88 KB

I fixed a few coding style issues and committed it (patch is attached). Please create new issues for follow ups.

Status: Fixed » Closed (fixed)

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