Problem/Motivation
Seems to be some issue with the form cache interaction with the media library widget, and possibly other complex widgets. Not sure where the issue is exactly though. The problem is that after clicking the "remove" button in the media library widget to remove an already-selected item, the form builder doesn't know that the remove button was clicked, and it instead assumes the first button in the form was clicked, which could be anything. On a simple node form with just a media library widget, the button it clicks is the "add media" button so the media library selection modal opens up incorrectly.
Steps to reproduce
- Use Firefox
- Clean install of Drupal with the Media Library module enabled
- Create a content type with a media reference field with all default settings
- Create a node of that type, select a media item (upload one), and save the node
- Edit the node and click the "remove" button in the media library widget. Observe the correct behavior of the item being removed and the widget reverting to its original empty state
- Don't save the node, reload the form in your browser
- Again, click the "remove" button in the media library widget. Observe that instead of removing the item and reverting the widget to its original state, the media library selection modal opens up incorrectly.
Here's a video demonstrating the steps above. I started with a fresh form load (no form cache set in key value).
If you have a more complex node form, like one with a paragraphs field on it, what might end up happening instead of the media library modal opening is it that the entire media library widget gets replaced with a paragraph form for a paragraph item!
The wrong behavior is because of this code in FormBuilder:
// If a form contains a single textfield, and the ENTER key is pressed
// within it, Internet Explorer submits the form with no POST data
// identifying any submit button. Other browsers submit POST data as
// though the user clicked the first button. Therefore, to be as
// consistent as we can be across browsers, if no 'triggering_element' has
// been identified yet, default it to the first button.
$buttons = $form_state->getButtons();
if (!$form_state->isProgrammed() && !$form_state->getTriggeringElement() && !empty($buttons)) {
$form_state->setTriggeringElement($buttons[0]);
}
The wrong element is set as the triggering element for the form submission. Why? Because the form object that's being acted on is used a cached version of the form (cached after step #4 above) which is missing the "remove" button for the media library widget. When the form is being processed, and input elements in the form are checked to see if they were pressed and were the triggering element, the "remove" button doesn't exist in the form so it never sets itself as the triggering element, so it falls back to that logic pasted in above which just picks the first button.