123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- /**
- * @file
- * Renders BigPipe placeholders using Drupal's Ajax system.
- */
- (function($, Drupal, drupalSettings) {
- /**
- * Maps textContent of <script type="application/vnd.drupal-ajax"> to an AJAX response.
- *
- * @param {string} content
- * The text content of a <script type="application/vnd.drupal-ajax"> DOM node.
- * @return {Array|boolean}
- * The parsed Ajax response containing an array of Ajax commands, or false in
- * case the DOM node hasn't fully arrived yet.
- */
- function mapTextContentToAjaxResponse(content) {
- if (content === '') {
- return false;
- }
- try {
- return JSON.parse(content);
- } catch (e) {
- return false;
- }
- }
- /**
- * Executes Ajax commands in <script type="application/vnd.drupal-ajax"> tag.
- *
- * These Ajax commands replace placeholders with HTML and load missing CSS/JS.
- *
- * @param {number} index
- * Current index.
- * @param {HTMLScriptElement} placeholderReplacement
- * Script tag created by BigPipe.
- */
- function bigPipeProcessPlaceholderReplacement(index, placeholderReplacement) {
- const placeholderId = placeholderReplacement.getAttribute(
- 'data-big-pipe-replacement-for-placeholder-with-id',
- );
- const content = this.textContent.trim();
- // Ignore any placeholders that are not in the known placeholder list. Used
- // to avoid someone trying to XSS the site via the placeholdering mechanism.
- if (
- typeof drupalSettings.bigPipePlaceholderIds[placeholderId] !== 'undefined'
- ) {
- const response = mapTextContentToAjaxResponse(content);
- // If we try to parse the content too early (when the JSON containing Ajax
- // commands is still arriving), textContent will be empty or incomplete.
- if (response === false) {
- /**
- * Mark as unprocessed so this will be retried later.
- * @see bigPipeProcessDocument()
- */
- $(this).removeOnce('big-pipe');
- } else {
- // Create a Drupal.Ajax object without associating an element, a
- // progress indicator or a URL.
- const ajaxObject = Drupal.ajax({
- url: '',
- base: false,
- element: false,
- progress: false,
- });
- // Then, simulate an AJAX response having arrived, and let the Ajax
- // system handle it.
- ajaxObject.success(response, 'success');
- }
- }
- }
- // The frequency with which to check for newly arrived BigPipe placeholders.
- // Hence 50 ms means we check 20 times per second. Setting this to 100 ms or
- // more would cause the user to see content appear noticeably slower.
- const interval = drupalSettings.bigPipeInterval || 50;
- // The internal ID to contain the watcher service.
- let timeoutID;
- /**
- * Processes a streamed HTML document receiving placeholder replacements.
- *
- * @param {HTMLDocument} context
- * The HTML document containing <script type="application/vnd.drupal-ajax">
- * tags generated by BigPipe.
- *
- * @return {bool}
- * Returns true when processing has been finished and a stop signal has been
- * found.
- */
- function bigPipeProcessDocument(context) {
- // Make sure we have BigPipe-related scripts before processing further.
- if (!context.querySelector('script[data-big-pipe-event="start"]')) {
- return false;
- }
- $(context)
- .find('script[data-big-pipe-replacement-for-placeholder-with-id]')
- .once('big-pipe')
- .each(bigPipeProcessPlaceholderReplacement);
- // If we see the stop signal, clear the timeout: all placeholder
- // replacements are guaranteed to be received and processed.
- if (context.querySelector('script[data-big-pipe-event="stop"]')) {
- if (timeoutID) {
- clearTimeout(timeoutID);
- }
- return true;
- }
- return false;
- }
- function bigPipeProcess() {
- timeoutID = setTimeout(() => {
- if (!bigPipeProcessDocument(document)) {
- bigPipeProcess();
- }
- }, interval);
- }
- bigPipeProcess();
- // If something goes wrong, make sure everything is cleaned up and has had a
- // chance to be processed with everything loaded.
- $(window).on('load', () => {
- if (timeoutID) {
- clearTimeout(timeoutID);
- }
- bigPipeProcessDocument(document);
- });
- })(jQuery, Drupal, drupalSettings);
|