Skip to content

Commit

Permalink
MDL-79276 core: Auto close streaming elements in shutdown handler
Browse files Browse the repository at this point in the history
  • Loading branch information
brendanheywood committed Oct 2, 2023
1 parent 21b5ad1 commit 08780b4
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 12 deletions.
3 changes: 3 additions & 0 deletions lib/classes/shutdown_manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,9 @@ protected static function request_shutdown() {
}
}

// 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;
Expand Down
42 changes: 30 additions & 12 deletions lib/outputrenderers.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -5228,36 +5234,46 @@ public function addblockbutton($region = ''): string {
*
* @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;
}

Expand All @@ -5274,6 +5290,7 @@ public function select_element_for_append(string $selector = '#region-main [role
* @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) {

Expand All @@ -5286,6 +5303,7 @@ public function select_element_for_replace(string $selector, string $html, bool
$html = addslashes_js($html);
$property = $outer ? 'outerHTML' : 'innerHTML';
$output = html_writer::tag('script', "document.querySelector('$selector').$property = '$html';");
$output .= "\n";
return $output;
}
}
Expand Down

0 comments on commit 08780b4

Please sign in to comment.