diff --git a/core/modules/big_pipe/js/big_pipe.js b/core/modules/big_pipe/js/big_pipe.js index 489a5f5..e21df03 100644 --- a/core/modules/big_pipe/js/big_pipe.js +++ b/core/modules/big_pipe/js/big_pipe.js @@ -3,88 +3,90 @@ * Provides Ajax page updating via BigPipe. */ -(function ($, window, Drupal, drupalSettings) { +(function ($, Drupal, drupalSettings) { - "use strict"; + 'use strict'; - var interval = 100; // Check every 100 ms. - var maxWait = 10; // Wait for a maximum of 10 seconds. - - // The internal ID to contain the watcher service. - var intervalID; - - function BigPipeClearInterval() { - if (intervalID) { - clearInterval(intervalID); - intervalID = undefined; + /** + * Execute Ajax commands included in the script tag. + * + * @param {number} index + * Current index. + * @param {HTMLScriptElement} placeholder + * Script tag created by bigPipe. + */ + function bigPipeProcessPlaceholder(index, placeholder) { + var placeholderName = this.getAttribute('data-big-pipe-placeholder'); + var content = this.textContent.trim(); + // Ignore any placeholders that are not in the known placeholder list. + // This is used to avoid someone trying to XSS the site via the + // placeholdering mechanism.; + if (typeof drupalSettings.bigPipePlaceholders[placeholderName] !== 'undefined') { + // If we try to parse the content too early textContent will be empty, + // making JSON.parse fail. Remove once so that it can be processed again + // later. + if (content === '') { + $(this).removeOnce('big-pipe'); + } + else { + var response = JSON.parse(content); + // Use a dummy url. + var ajaxObject = Drupal.ajax({url: 'big-pipe/placeholder.json'}); + ajaxObject.success(response); + } } } - function BigPipeProcessPlaceholders(context) { - var $container = jQuery('[data-big-pipe-container=1]', context); - - if (!$container.length) { - return; + /** + * + * @param {HTMLDocument} context + * Main + * + * @return {bool} + * Returns true when processing has been finished and a stop tag has been + * found. + */ + function bigPipeProcessContainer(context) { + // Make sure we have bigPipe related scripts before processing further. + if (!context.querySelector('script[data-big-pipe-event="start"]')) { + return false; } - // Process BigPipe inlined ajax responses. - $container.find('script[data-drupal-ajax-processor="big_pipe"]').each(function() { - var placeholder = $(this).data('big-pipe-placeholder'); + $(context).find('script[data-drupal-ajax-processor="big_pipe"]').once('big-pipe') + .each(bigPipeProcessPlaceholder); - // Ignore any placeholders that are not in the known placeholder list. - // This is used to avoid someone trying to XSS the site via the - // placeholdering mechanism. - if (typeof(drupalSettings.bigPipePlaceholders[placeholder]) !== 'undefined') { - var response = JSON.parse(this.textContent); - // Use a dummy url. - var ajaxObject = Drupal.ajax({url: 'big-pipe/placeholder.json'}); - ajaxObject.success(response); + // If we see a stop element always clear the timeout. + if (context.querySelector('script[data-big-pipe-event="stop"]')) { + if (timeoutID) { + clearTimeout(timeoutID); } - $(this).remove(); - }); - - // Check for start signal to attachBehaviors. - $container.find('script[data-big-pipe-start="1"]').each(function() { - $(this).remove(); - Drupal.attachBehaviors(); - }); + return true; + } - // Check for stop signal to stop checking. - $container.find('script[data-big-pipe-stop="1"]').each(function() { - $(this).remove(); - BigPipeClearInterval(); - }); + return false; } - $('body').each(function() { - if ($(this).data('big-pipe-processed') == true) { - return; - } - - $(this).data('big-pipe-processed', true); + function bigPipeProcess() { + timeoutID = setTimeout(function () { + if (!bigPipeProcessContainer(document)) { + bigPipeProcess(); + } + }, interval); + } - // Check for new BigPipe elements until we get the stop signal or the timeout occurs. - intervalID = setInterval(function() { - BigPipeProcessPlaceholders(document); - }, 100); + var interval = 200; + // The internal ID to contain the watcher service. + var timeoutID; - // Wait for a maxium of maxWait seconds. - setTimeout(BigPipeClearInterval, maxWait * 1000); - }); + bigPipeProcess(); - /** - * Defines the BigPipe behavior. - * - * @type {Drupal~behavior} - */ - Drupal.behaviors.BigPipe = { - attach: function (context, settings) { - if (!intervalID) { - // If we timeout before all data is loaded, try again once - // the regular ready() event fires. - BigPipeProcessPlaceholders(context); - } + // If something goes wrong, make sure everything is cleaned up and has had a + // chance to be processed with everything loaded. + $(window).on('load', function () { + if (timeoutID) { + clearTimeout(timeoutID); } - }; + bigPipeProcessContainer(document); + }); -})(jQuery, this, Drupal, drupalSettings); +})(jQuery, Drupal, drupalSettings); diff --git a/core/modules/big_pipe/src/Render/BigPipe.php b/core/modules/big_pipe/src/Render/BigPipe.php index 73e9d69..7cecb2f 100644 --- a/core/modules/big_pipe/src/Render/BigPipe.php +++ b/core/modules/big_pipe/src/Render/BigPipe.php @@ -147,8 +147,7 @@ public function sendContent($content, $attachments, array $placeholders) { // Print a container and the start signal. print "\n"; - print '
' . "\n"; - print ' ' . "\n"; + print '' . "\n"; flush(); @@ -206,8 +205,7 @@ public function sendContent($content, $attachments, array $placeholders) { } // Send the stop signal. - print ' ' . "\n"; - print '
' . "\n"; + print '' . "\n"; print ''; print $page_parts[1];