2c2
< index 3e67737..6f32c6c 100644
---
> index 3e67737..e7f5377 100644
5,6c5,17
< @@ -339,6 +339,9 @@ protected function sendPlaceholders(array $placeholders, array $placeholder_orde
< return;
---
> @@ -508,7 +508,9 @@ protected function renderPlaceholder($placeholder, array $placeholder_render_arr
> *
> * @return array
> * Indexed array; the order in which the BigPipe placeholders must be sent.
> - * Values are the BigPipe placeholder IDs.
> + * Values are the BigPipe placeholder IDs. Note that only unique
> + * placeholders are kept: if the same placeholder occurs multiple times, we
> + * only keep the first occurrence.
> */
> protected function getPlaceholderOrder($html) {
> $fragments = explode('
';
> + $raw_content = $this->getRawContent();
> + $this->assertTrue(substr_count($raw_content, $expected_placeholder_replacement) == 1, 'Only one placeholder replacement was found for the duplicate #lazy_builder arrays.');
> + }
12,31c54,79
< // Send the start signal.
< print "\n";
< print static::START_SIGNAL;
< @@ -382,7 +385,17 @@ protected function sendPlaceholders(array $placeholders, array $placeholder_orde
< // placeholder ID (which has HTML entities encoded since we use it to find
< // the placeholders).
< $big_pipe_js_placeholder_id = Html::decodeEntities($placeholder_id);
< - $ajax_response->addCommand(new ReplaceCommand(sprintf('[data-big-pipe-placeholder-id="%s"]', $big_pipe_js_placeholder_id), $elements['#markup']));
< +
< + // If there are identical placeholders, only add the ReplaceCommand once,
< + // because all of the placeholders will be replaced the first time the
< + // ReplaceCommand runs. Otherwise, Drupal.detachBehaviors() and
< + // Drupal.attachBehaviors() will run on the context of the entire
< + // document for subsequent ReplaceCommand instances, because all
< + // placeholders with the identical ID will have been removed from the DOM
< + // and their context will no longer be available to JavaScript.
< + if (!in_array($big_pipe_js_placeholder_id, $sent_placeholders)) {
< + $ajax_response->addCommand(new ReplaceCommand(sprintf('[data-big-pipe-placeholder-id="%s"]', $big_pipe_js_placeholder_id), $elements['#markup']));
< + }
< $ajax_response->setAttachments($elements['#attached']);
---
> protected function assertBigPipeResponseHeadersPresent() {
> $this->pass('Verifying BigPipe response headers…', 'Debug');
> $this->assertTrue(FALSE !== strpos($this->drupalGetHeader('Cache-Control'), 'private'), 'Cache-Control header set to "private".');
> diff --git a/core/modules/big_pipe/tests/modules/big_pipe_test/big_pipe_test.routing.yml b/core/modules/big_pipe/tests/modules/big_pipe_test/big_pipe_test.routing.yml
> index 4979406..e60481c 100644
> --- a/core/modules/big_pipe/tests/modules/big_pipe_test/big_pipe_test.routing.yml
> +++ b/core/modules/big_pipe/tests/modules/big_pipe_test/big_pipe_test.routing.yml
> @@ -15,3 +15,12 @@ no_big_pipe:
> _no_big_pipe: TRUE
> requirements:
> _access: 'TRUE'
> +
> +big_pipe_duplicate_placeholders:
> + path: '/big_pipe_duplicate_placeholders'
> + defaults:
> + _controller: '\Drupal\big_pipe_test\BigPipeTestController::duplicates'
> + _title: 'BigPipe with duplicate placeholders test'
> + requirements:
> + _access: 'TRUE'
> +
> diff --git a/core/modules/big_pipe/tests/modules/big_pipe_test/src/BigPipeTestController.php b/core/modules/big_pipe/tests/modules/big_pipe_test/src/BigPipeTestController.php
> index 450a464..1327f37 100644
> --- a/core/modules/big_pipe/tests/modules/big_pipe_test/src/BigPipeTestController.php
> +++ b/core/modules/big_pipe/tests/modules/big_pipe_test/src/BigPipeTestController.php
> @@ -53,6 +53,30 @@ public static function nope() {
> }
33,36c81,111
< // Push a fake request with the asset libraries loaded so far and dispatch
< @@ -418,6 +431,9 @@ protected function sendPlaceholders(array $placeholders, array $placeholder_orde
< print $output;
< flush();
---
> /**
> + * Returns a render array with duplicate lazy_builder placeholders to test
> + * BigPipe handling of duplicates.
> + *
> + * @return array
> + */
> + public function duplicates() {
> + $adjective = 'awesome';
> + return [
> + 'item1' => [
> + '#lazy_builder' => [static::class . '::placeholderContent', [$adjective]],
> + '#create_placeholder' => TRUE,
> + ],
> + 'item2' => [
> + '#lazy_builder' => [static::class . '::placeholderContent', [$adjective]],
> + '#create_placeholder' => TRUE,
> + ],
> + 'item3' => [
> + '#lazy_builder' => [static::class . '::placeholderContent', [$adjective]],
> + '#create_placeholder' => TRUE,
> + ],
> + ];
> + }
> +
> + /**
> * #lazy_builder callback; builds