diff --git a/lib/classes/shutdown_manager.php b/lib/classes/shutdown_manager.php index be23192781e..08ddcefb65a 100644 --- a/lib/classes/shutdown_manager.php +++ b/lib/classes/shutdown_manager.php @@ -240,6 +240,9 @@ class core_shutdown_manager { } } + // Close the current streaming element if any. + echo $OUTPUT->close_element_for_append(); + // Print any closing buffered tags. if (!empty($CFG->closingtags)) { echo $CFG->closingtags; diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php index d580eff853d..776d9a70c06 100644 --- a/lib/outputrenderers.php +++ b/lib/outputrenderers.php @@ -600,6 +600,12 @@ class core_renderer extends renderer_base { /** @var custom_menu_item language The language menu if created */ protected $language = null; + /** @var string The current selector for an element being streamed into */ + protected $currentselector = ''; + + /** @var string The current element tag which is being streamed into */ + protected $currentelement = ''; + /** * Constructor * @@ -5228,36 +5234,46 @@ EOD; * * @param string $selector where new content should be appended * @param string $element which contains the streamed content + * @return string html to be written */ public function select_element_for_append(string $selector = '#region-main [role=main]', string $element = 'div') { - static $currentselector = ''; - static $currentelement = ''; - if (!CLI_SCRIPT && !NO_OUTPUT_BUFFERING) { throw new coding_exception('select_element_for_append used in a non-CLI script without setting NO_OUTPUT_BUFFERING.', DEBUG_DEVELOPER); } // We are already streaming into this element so don't change anything. - if ($currentselector === $selector && $currentelement === $element) { + if ($this->currentselector === $selector && $this->currentelement === $element) { return; } - $html = ''; + // If we have a streaming element close it before starting a new one. + $html = $this->close_element_for_append(); - // We have a streaming element so close it before starting a new one. - if ($currentselector !== '') { - $html .= html_writer::end_tag($currentelement); - } - - $currentselector = $selector; - $currentelement = $element; + $this->currentselector = $selector; + $this->currentelement = $element; // Create an unclosed element for the streamed content to append into. $id = uniqid(); $html .= html_writer::start_tag($element, ['id' => $id]); $html .= html_writer::tag('script', "document.querySelector('$selector').append(document.getElementById('$id'))"); + $html .= "\n"; + return $html; + } + + /** + * This closes any opened stream elements + * + * @return string html to be written + */ + public function close_element_for_append() { + $html = ''; + if ($this->currentselector !== '') { + $html .= html_writer::end_tag($this->currentelement); + $html .= "\n"; + $this->currentelement = ''; + } return $html; } @@ -5274,6 +5290,7 @@ EOD; * @param string $selector where new content should be replaced * @param string $html A chunk of well formed html * @param bool $outer Wether it replaces the innerHTML or the outerHTML + * @return string html to be written */ public function select_element_for_replace(string $selector, string $html, bool $outer = false) { @@ -5286,6 +5303,7 @@ EOD; $html = addslashes_js($html); $property = $outer ? 'outerHTML' : 'innerHTML'; $output = html_writer::tag('script', "document.querySelector('$selector').$property = '$html';"); + $output .= "\n"; return $output; } }