MDL-79276 core: Auto close streaming elements in shutdown handler

This commit is contained in:
Brendan Heywood
2023-10-02 21:11:44 +10:00
parent 21b5ad1555
commit 08780b449f
2 changed files with 33 additions and 12 deletions
+3
View File
@@ -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;
+30 -12
View File
@@ -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;
}
}