Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / modules / big_pipe / js / big_pipe.es6.js
1 /**
2  * @file
3  * Renders BigPipe placeholders using Drupal's Ajax system.
4  */
5
6 (function($, Drupal, drupalSettings) {
7   /**
8    * Maps textContent of <script type="application/vnd.drupal-ajax"> to an AJAX response.
9    *
10    * @param {string} content
11    *   The text content of a <script type="application/vnd.drupal-ajax"> DOM node.
12    * @return {Array|boolean}
13    *   The parsed Ajax response containing an array of Ajax commands, or false in
14    *   case the DOM node hasn't fully arrived yet.
15    */
16   function mapTextContentToAjaxResponse(content) {
17     if (content === '') {
18       return false;
19     }
20
21     try {
22       return JSON.parse(content);
23     } catch (e) {
24       return false;
25     }
26   }
27
28   /**
29    * Executes Ajax commands in <script type="application/vnd.drupal-ajax"> tag.
30    *
31    * These Ajax commands replace placeholders with HTML and load missing CSS/JS.
32    *
33    * @param {number} index
34    *   Current index.
35    * @param {HTMLScriptElement} placeholderReplacement
36    *   Script tag created by BigPipe.
37    */
38   function bigPipeProcessPlaceholderReplacement(index, placeholderReplacement) {
39     const placeholderId = placeholderReplacement.getAttribute(
40       'data-big-pipe-replacement-for-placeholder-with-id',
41     );
42     const content = this.textContent.trim();
43     // Ignore any placeholders that are not in the known placeholder list. Used
44     // to avoid someone trying to XSS the site via the placeholdering mechanism.
45     if (
46       typeof drupalSettings.bigPipePlaceholderIds[placeholderId] !== 'undefined'
47     ) {
48       const response = mapTextContentToAjaxResponse(content);
49       // If we try to parse the content too early (when the JSON containing Ajax
50       // commands is still arriving), textContent will be empty or incomplete.
51       if (response === false) {
52         /**
53          * Mark as unprocessed so this will be retried later.
54          * @see bigPipeProcessDocument()
55          */
56         $(this).removeOnce('big-pipe');
57       } else {
58         // Create a Drupal.Ajax object without associating an element, a
59         // progress indicator or a URL.
60         const ajaxObject = Drupal.ajax({
61           url: '',
62           base: false,
63           element: false,
64           progress: false,
65         });
66         // Then, simulate an AJAX response having arrived, and let the Ajax
67         // system handle it.
68         ajaxObject.success(response, 'success');
69       }
70     }
71   }
72
73   // The frequency with which to check for newly arrived BigPipe placeholders.
74   // Hence 50 ms means we check 20 times per second. Setting this to 100 ms or
75   // more would cause the user to see content appear noticeably slower.
76   const interval = drupalSettings.bigPipeInterval || 50;
77
78   // The internal ID to contain the watcher service.
79   let timeoutID;
80
81   /**
82    * Processes a streamed HTML document receiving placeholder replacements.
83    *
84    * @param {HTMLDocument} context
85    *   The HTML document containing <script type="application/vnd.drupal-ajax">
86    *   tags generated by BigPipe.
87    *
88    * @return {bool}
89    *   Returns true when processing has been finished and a stop signal has been
90    *   found.
91    */
92   function bigPipeProcessDocument(context) {
93     // Make sure we have BigPipe-related scripts before processing further.
94     if (!context.querySelector('script[data-big-pipe-event="start"]')) {
95       return false;
96     }
97
98     $(context)
99       .find('script[data-big-pipe-replacement-for-placeholder-with-id]')
100       .once('big-pipe')
101       .each(bigPipeProcessPlaceholderReplacement);
102
103     // If we see the stop signal, clear the timeout: all placeholder
104     // replacements are guaranteed to be received and processed.
105     if (context.querySelector('script[data-big-pipe-event="stop"]')) {
106       if (timeoutID) {
107         clearTimeout(timeoutID);
108       }
109       return true;
110     }
111
112     return false;
113   }
114
115   function bigPipeProcess() {
116     timeoutID = setTimeout(() => {
117       if (!bigPipeProcessDocument(document)) {
118         bigPipeProcess();
119       }
120     }, interval);
121   }
122
123   bigPipeProcess();
124
125   // If something goes wrong, make sure everything is cleaned up and has had a
126   // chance to be processed with everything loaded.
127   $(window).on('load', () => {
128     if (timeoutID) {
129       clearTimeout(timeoutID);
130     }
131     bigPipeProcessDocument(document);
132   });
133 })(jQuery, Drupal, drupalSettings);