Directly render preview, don't simulate click

Created on 25 March 2023, over 1 year ago
Updated 9 June 2023, about 1 year ago

Problem/Motivation

In I ran into issues where the checkbox wouldn't refresh the preview because it was looking for a preview button it couldn't find. While this fix, "fixes" the preview refresh I need a little more time to study if there's anything that the Node's preview button is doing that we're missing.

Steps to reproduce

1. Open a page that has a preview, this pushes the preview into tempstore
2. Inspect the iframe generated and copy the uuid to your clipboard.
3. Navigate to https:///en/node/preview_pane/
/full

Now you're the route we created for the preview wrapped with our new form controls.

4. Click the refresh button.

It will fail, informing you that it can't execute the click event on null.

What's null here is that the Node's hidden preview button that is provided by PreviewNodeForm isn't present. That's because we've coupled the our PreviewControlsForm to it. We should allow the PreviewControlsForm to work on it's own by directly executing the samePagePreviewRenderPreview method from same-page-preview.js (and clean up a todo we've put there)

Proposed resolution

Remaining tasks

See if that breaks anything else

User interface changes

API changes

Data model changes

πŸ› Bug report
Status

Postponed

Version

1.0

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States cosmicdreams Minneapolis/St. Paul

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @cosmicdreams
  • πŸ‡ΊπŸ‡ΈUnited States cosmicdreams Minneapolis/St. Paul

    This issue has led to a study of how $node->in_preview works. One key place where in_preview is used in the node module's NodeForm::form method. This logic attempts to reload the entity by using the uuid that was previously stored in the temp store.

    // Try to restore from temp store, this must be done before calling
        // parent::form().
        $store = $this->tempStoreFactory->get('node_preview');
    
        // Attempt to load from preview when the uuid is present unless we are
        // rebuilding the form.
        $request_uuid = \Drupal::request()->query->get('uuid');
        if (!$form_state->isRebuilding() && $request_uuid && $preview = $store->get($request_uuid)) {
          /** @var \Drupal\Core\Form\FormStateInterface $preview */
    
          $form_state->setStorage($preview->getStorage());
          $form_state->setUserInput($preview->getUserInput());
    
          // Rebuild the form.
          $form_state->setRebuild();
    
          // The combination of having user input and rebuilding the form means
          // that it will attempt to cache the form state which will fail if it is
          // a GET request.
          $form_state->setRequestMethod('POST');
    
          $this->entity = $preview->getFormObject()->getEntity();
          $this->entity->in_preview = NULL;
    
          $form_state->set('has_been_previewed', TRUE);
        }
    
  • πŸ‡ΊπŸ‡ΈUnited States cosmicdreams Minneapolis/St. Paul

    While work has progressed in πŸ“Œ On by default, make off-by-default an opt-in setting Closed: duplicate , we were able to get there by delegating all the work to the existing button-driven method of creating the openOffCanvasDialog method we've used throughout Phase 1. It would be really great to understand what the gap is between our effort to handle all of this without that button (the "easy" way). That would allow us to not need to simulate clicks.

    In regard to the "preview" button. We have learned more about why we rely on clicking that button. I create a flowchart explaining that whole thing. In short, the preview button does a lot of heavy lifting for us that we might just want to delegate to CORE to handle for us at the end of the day. I think we can stop pursuing an alternative there.

    But the "toggle Preview" button we have added is still a good option to takeover. I'll continue pursuing a solution by pulling bits from πŸ“Œ On by default, make off-by-default an opt-in setting Closed: duplicate . That issue can be reduced in scope so it can be merged.

  • Status changed to Needs work about 1 year ago
  • πŸ‡ΊπŸ‡ΈUnited States cosmicdreams Minneapolis/St. Paul
  • πŸ‡¨πŸ‡¦Canada mandclu

    I recently came across some code in core that is relevant to this issue, within EntityDisplayFormBase.php:

        // In overviews involving nested rows from contributed modules (i.e
        // field_group), the 'plugin type' selects can trigger a series of changes
        // in child rows. The #ajax behavior is therefore not attached directly to
        // the selects, but triggered by the client-side script through a hidden
        // #ajax 'Refresh' button. A hidden 'refresh_rows' input tracks the name of
        // affected rows.
        $form['refresh_rows'] = ['#type' => 'hidden'];
        $form['refresh'] = [
          '#type' => 'submit',
          '#value' => $this->t('Refresh'),
          '#op' => 'refresh_table',
          '#submit' => ['::multistepSubmit'],
          '#ajax' => [
            'callback' => '::multistepAjax',
            'wrapper' => 'field-display-overview-wrapper',
            'effect' => 'fade',
            // The button stays hidden, so we hide the Ajax spinner too. Ad-hoc
            // spinners will be added manually by the client-side script.
            'progress' => 'none',
          ],
          '#attributes' => ['class' => ['visually-hidden']],
        ];
    

    I thought it was interesting that using hidden elements to trigger AJAX behaviors is already in core.

  • Status changed to Postponed about 1 year ago
  • πŸ‡ΊπŸ‡ΈUnited States brianperry

    Marking as postponed as I don't think we have current plans to refactor this. But wondering if this one should be wontfix. We're pretty deep into making use of hidden elements...

Production build 0.69.0 2024