From 6d90b457c3314703b4c511f507fab8aa06f07ef6 Mon Sep 17 00:00:00 2001 From: Lars Bonczek Date: Wed, 20 Nov 2024 18:19:28 +0100 Subject: [PATCH] resize iframe when content height changes --- renderer.php | 105 ++++++++++++++++++++++-------- styles.css | 15 ++++- templates/iframe_content.mustache | 3 +- 3 files changed, 95 insertions(+), 28 deletions(-) diff --git a/renderer.php b/renderer.php index 21740ff..d97bf77 100644 --- a/renderer.php +++ b/renderer.php @@ -22,6 +22,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +use qtype_questionpy\api\attempt_ui; use qtype_questionpy\question_ui_renderer; /** @@ -66,48 +67,100 @@ public function formulation_and_controls(question_attempt $qa, question_display_ global $PAGE, $OUTPUT; $oldpage = $PAGE; - $oldoutput = $OUTPUT; // Class moodle_page also modifies global $OUTPUT variable. + $oldoutput = $OUTPUT; + // Initialize output buffer. + // We do this to ensure that any echo, var_dump, etc. statements are included in the iframe contents. + ob_start(); try { - $PAGE = new moodle_page(); + $classname = get_class($oldpage); // $PAGE class may be customized using $CFG->moodlepageclass. + /** @var moodle_page $PAGE */ + $PAGE = new $classname(); + /** @var \core\output\core_renderer $OUTPUT */ + $OUTPUT = new bootstrap_renderer(); // bootstrap_renderer will initialize $OUTPUT on first use. + $PAGE->set_context($options->context); $PAGE->set_pagelayout('embedded'); $PAGE->set_pagetype($oldpage->pagetype); $PAGE->set_url($oldpage->url); + $PAGE->add_body_class('questionpy-iframe-body'); - $qformulation = new question_ui_renderer($question->ui->formulation, $question->ui->placeholders, $options, - $qa); - $feedback = html_writer::nonempty_tag('div', $this->feedback_in_iframe($qa, $options), - ['class' => 'outcome clearfix']); - - $editor = editors_get_preferred_editor(FORMAT_HTML); // Only for testing purposes! - $editor->use_editor('mytextareaid', [ - 'context' => $options->context, - 'enable_filemanagement' => true, - 'maxfiles' => EDITOR_UNLIMITED_FILES, - ], question_utils::get_filepicker_options($options->context, 0)); - - $questionsrc = $this->output->render_from_template('qtype_questionpy/iframe_content', [ - 'question' => $qformulation->render(), - 'feedback' => $feedback, - 'filepicker' => $this->get_file_picker_test($options->context), - ]); + // Get a new instance of this renderer for the new $PAGE object to render the iframe contents. + // This is necessary so that any JS/CSS requirements get added to the new page's page_requirements_manager. + /** @var self $qpyrenderer */ + $qpyrenderer = $PAGE->get_renderer('qtype_questionpy'); - $outputrenderer = $PAGE->get_renderer('core', null); - $iframesrc = $outputrenderer->header(); - $iframesrc .= $questionsrc; - $iframesrc .= $outputrenderer->footer(); - return ''; + // Render iframe contents before the header is printed to allow CSS to be added to the page header. + $iframecontents = $qpyrenderer->formulation_and_controls_in_iframe($qa, $question->ui, $options); + + // Write iframe source into the output buffer. + echo $OUTPUT->header(); + echo ""; + echo $iframecontents; + echo $OUTPUT->footer(); } finally { $PAGE = $oldpage; $OUTPUT = $oldoutput; + $iframesrc = ob_get_clean(); } - return ''; + if ($iframesrc) { + // TODO srcdoc or src? + return ''; + } else { + return ''; + } } - protected function get_file_picker_test($context) { + /** + * @throws \core\exception\moodle_exception + * @throws coding_exception + */ + protected function formulation_and_controls_in_iframe(question_attempt $qa, attempt_ui $ui, question_display_options $options): string { + $qformulation = new question_ui_renderer($ui->formulation, $ui->placeholders, $options, + $qa); + $feedback = html_writer::nonempty_tag('div', $this->feedback_in_iframe($qa, $options), + ['class' => 'outcome clearfix']); + + $editor = editors_get_preferred_editor(FORMAT_HTML); // Only for testing purposes! + $editor->use_editor('mytextareaid', [ + 'context' => $options->context, + 'enable_filemanagement' => true, + 'maxfiles' => EDITOR_UNLIMITED_FILES, + ], question_utils::get_filepicker_options($options->context, 0)); + + return $this->render_from_template('qtype_questionpy/iframe_content', [ + 'question' => $qformulation->render(), + 'feedback' => $feedback, + 'filepicker' => $this->get_file_picker_test($options->context), + ]); + } + + /** + * @throws \core\exception\coding_exception + */ + protected function get_file_picker_test($context): string { global $CFG, $PAGE; require_once($CFG->dirroot . '/lib/form/filemanager.php'); diff --git a/styles.css b/styles.css index 3e9b440..282e115 100644 --- a/styles.css +++ b/styles.css @@ -41,7 +41,20 @@ height: 500px; } -.que .questionpy-iframe-content.content { +/* Make iframe body grow and shrink with page content. */ +body.questionpy-iframe-body { + height: auto; +} + +.questionpy-iframe-body .que { + margin: 0; +} + +.questionpy-iframe-body .que .content { + margin: 0; +} + +.questionpy-iframe-body .que .formulation { margin: 0; } diff --git a/templates/iframe_content.mustache b/templates/iframe_content.mustache index f637eec..bbd6b35 100644 --- a/templates/iframe_content.mustache +++ b/templates/iframe_content.mustache @@ -18,7 +18,7 @@ @template qtype_questionpy/iframe_content }}
-
+
{{{ question }}} @@ -38,6 +38,7 @@ dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
+ https://example.com
{{{ feedback }}}