Verified Commit ac36d01e authored by Théodore Biadala's avatar Théodore Biadala
Browse files

Issue #3532159 by fathershawn, nicxvan, smustgrave: HTMX behavior attachment...

Issue #3532159 by fathershawn, nicxvan, smustgrave: HTMX behavior attachment fails with some swap strategies

(cherry picked from commit 7cf60930)
parent 2732a4f2
Loading
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -166,7 +166,8 @@
  // @see https://htmx.org/events/#htmx:afterSettle
  htmx.on('htmx:afterSettle', ({ detail }) => {
    requestAssetsLoaded.get(detail.xhr).then(() => {
      htmx.trigger(detail.elt, 'htmx:drupal:load');
      // Some HTMX swaps put the incoming element before or after detail.elt.
      htmx.trigger(detail.elt.parentNode, 'htmx:drupal:load');
      // This should be automatic but don't wait for the garbage collector.
      requestAssetsLoaded.delete(detail.xhr);
    });
+34 −1
Original line number Diff line number Diff line
@@ -22,6 +22,26 @@ public function page(): array {
    return self::generateHtmxButton();
  }

  /**
   * Builds a response with a `beforebegin` swap.
   *
   * @return mixed[]
   *   A render array.
   */
  public function before(): array {
    return self::generateHtmxButton('beforebegin');
  }

  /**
   * Builds a response with an `afterend` swap..
   *
   * @return mixed[]
   *   A render array.
   */
  public function after(): array {
    return self::generateHtmxButton('afterend');
  }

  /**
   * Builds the HTMX response.
   *
@@ -43,13 +63,23 @@ public function replace(): array {
    return $build;
  }

  /**
   * We need a static callback that ignores callback parameters.
   *
   * @return array
   *   The render array.
   */
  public static function replaceWithAjax(): array {
    return static::generateHtmxButton();
  }

  /**
   * Static helper to for reusable render array.
   *
   * @return array
   *   The render array.
   */
  public static function generateHtmxButton(): array {
  public static function generateHtmxButton(string $swap = ''): array {
    $url = Url::fromRoute('test_htmx.attachments.replace');
    $build['replace'] = [
      '#type' => 'html_tag',
@@ -68,6 +98,9 @@ public static function generateHtmxButton(): array {
        ],
      ],
    ];
    if ($swap !== '') {
      $build['replace']['#attributes']['data-hx-swap'] = $swap;
    }

    $build['content'] = [
      '#type' => 'container',
+1 −1
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ public function buildForm(array $form, FormStateInterface $form_state): array {
        '#ajax' => [
          'callback' => [
            HtmxTestAttachmentsController::class,
            'generateHtmxButton',
            'replaceWithAjax',
          ],
          'wrapper' => 'ajax-test-container',
        ],
+16 −0
Original line number Diff line number Diff line
@@ -6,6 +6,22 @@ test_htmx.attachments.page:
  requirements:
    _permission: 'access content'

test_htmx.attachments.before:
  path: '/htmx-test-attachments/before'
  defaults:
    _title: 'Page'
    _controller: '\Drupal\test_htmx\Controller\HtmxTestAttachmentsController::before'
  requirements:
    _permission: 'access content'

test_htmx.attachments.after:
  path: '/htmx-test-attachments/after'
  defaults:
    _title: 'Page'
    _controller: '\Drupal\test_htmx\Controller\HtmxTestAttachmentsController::after'
  requirements:
    _permission: 'access content'

test_htmx.attachments.replace:
  path: '/htmx-test-attachments/replace'
  defaults:
+50 −4
Original line number Diff line number Diff line
@@ -41,8 +41,54 @@ module.exports = {
      .assert.not.elementPresent(cssSelector)
      .waitForElementVisible('[name="replace"]', 1000)
      .click('[name="replace"]')
      .waitForElementVisible(elementSelector, 6000)
      .waitForElementVisible(elementInitSelector, 6000)
      .waitForElementVisible(elementSelector, 1100)
      .waitForElementVisible(elementInitSelector, 1100)
      .assert.elementPresent(scriptSelector)
      .assert.elementPresent(cssSelector);
  },

  'Swap Before': (browser) => {
    // Load the route htmx will use for the request on click and confirm the
    // markup we will be looking for is present in the source markup.
    browser
      .drupalRelativeURL('/htmx-test-attachments/replace')
      .waitForElementVisible('body', 1000)
      .assert.elementPresent(elementInitSelector);
    // Now load the page with the htmx enhanced button and verify the absence
    // of the markup to be inserted. Click the button
    // and check for inserted javascript and markup.
    browser
      .drupalRelativeURL('/htmx-test-attachments/before')
      .waitForElementVisible('body', 1000)
      .assert.not.elementPresent(scriptSelector)
      .assert.not.elementPresent(cssSelector)
      .waitForElementVisible('[name="replace"]', 1000)
      .click('[name="replace"]')
      .waitForElementVisible(elementSelector, 1100)
      .waitForElementVisible(elementInitSelector, 1100)
      .assert.elementPresent(scriptSelector)
      .assert.elementPresent(cssSelector);
  },

  'Swap After': (browser) => {
    // Load the route htmx will use for the request on click and confirm the
    // markup we will be looking for is present in the source markup.
    browser
      .drupalRelativeURL('/htmx-test-attachments/replace')
      .waitForElementVisible('body', 1000)
      .assert.elementPresent(elementInitSelector);
    // Now load the page with the htmx enhanced button and verify the absence
    // of the markup to be inserted. Click the button
    // and check for inserted javascript and markup.
    browser
      .drupalRelativeURL('/htmx-test-attachments/after')
      .waitForElementVisible('body', 1000)
      .assert.not.elementPresent(scriptSelector)
      .assert.not.elementPresent(cssSelector)
      .waitForElementVisible('[name="replace"]', 1000)
      .click('[name="replace"]')
      .waitForElementVisible(elementSelector, 1100)
      .waitForElementVisible(elementInitSelector, 1100)
      .assert.elementPresent(scriptSelector)
      .assert.elementPresent(cssSelector);
  },
@@ -69,8 +115,8 @@ module.exports = {
      .waitForElementVisible('[name="replace"]', 1000)
      .pause(1000)
      .click('[name="replace"]')
      .waitForElementVisible(elementSelector, 6000)
      .waitForElementVisible(elementInitSelector, 6000)
      .waitForElementVisible(elementSelector, 1100)
      .waitForElementVisible(elementInitSelector, 1100)
      .assert.elementPresent(scriptSelector)
      .assert.elementPresent(cssSelector);
  },