Skip to content

Commit 70f4e8f

Browse files
committed
feat: render a read-only view of response editor content
1 parent 92b0806 commit 70f4e8f

File tree

3 files changed

+104
-3
lines changed

3 files changed

+104
-3
lines changed

classes/local/attempt_ui/qpy_rich_text_editor.php

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,18 @@
1919
use core\context;
2020
use core\di;
2121
use core\exception\coding_exception;
22+
use DOMDocumentFragment;
2223
use DOMElement;
2324
use DOMNode;
2425
use file_exception;
2526
use moodle_exception;
2627
use moodle_url;
2728
use MoodleQuickForm_editor;
29+
use qtype_questionpy\constants;
2830
use qtype_questionpy\local\files\response_file_service;
2931
use qtype_questionpy\local\files\validatable_upload_limits;
3032
use qtype_questionpy\utils;
33+
use qtype_questionpy_renderer;
3134
use question_attempt;
3235
use stored_file_creation_exception;
3336

@@ -140,7 +143,43 @@ public static function from_element(DOMElement $element): ?static {
140143
* @throws stored_file_creation_exception
141144
*/
142145
public function render(question_attempt $qa, question_ui_renderer $renderer): DOMNode {
143-
// TODO: Maybe separate readonly view?
146+
if ($renderer->options->readonly) {
147+
global $PAGE;
148+
/** @var qtype_questionpy_renderer $qpyrenderer */
149+
$qpyrenderer = $PAGE->get_renderer('qtype_questionpy');
150+
151+
$responsestep = $qa->get_last_step_with_qt_var(constants::QT_VAR_RESPONSE);
152+
$editorsdata = utils::get_qpy_editors_data($responsestep->get_qt_data());
153+
$editordata = $editorsdata[$this->name] ?? null;
154+
155+
$html = $qpyrenderer->render_readonly_editor_content(
156+
$editordata,
157+
qubaid: $qa->get_usage_id(),
158+
slot: $qa->get_slot(),
159+
stepid: $responsestep->get_id(),
160+
fieldname: $this->name,
161+
options: $renderer->options,
162+
rows: $this->rows,
163+
cols: $this->cols
164+
);
165+
return dom_utils::html_to_fragment($this->element->ownerDocument, $html);
166+
} {
167+
return $this->render_writable($renderer, $qa);
168+
}
169+
}
170+
171+
/**
172+
* Renders an editor using the usual Moodle APIs.
173+
*
174+
* @param question_ui_renderer $renderer
175+
* @param question_attempt $qa
176+
* @return DOMDocumentFragment|false|void
177+
* @throws coding_exception
178+
* @throws file_exception
179+
* @throws moodle_exception
180+
* @throws stored_file_creation_exception
181+
*/
182+
public function render_writable(question_ui_renderer $renderer, question_attempt $qa) {
144183
$limits = $this->get_limits_in($renderer->options->context);
145184

146185
$alleditorsdata = utils::get_qpy_editors_data($qa);

classes/local/files/response_file_service.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,17 @@ public function prepare_split_draft_area(
217217
*/
218218
public static function mangle_filename(string $fieldname, string $filename): string {
219219
// URL-encoding the fieldname ensures that our separator is the first occurrence of the separator.
220-
return urlencode($fieldname) . static::MANGLE_SEPARATOR . $filename;
220+
return self::mangled_prefix_for($fieldname) . $filename;
221+
}
222+
223+
/**
224+
* Returns the prefix used to mangle filenames belonging to the given field.
225+
*
226+
* @param string $fieldname The upload field name the file(s) belongs to.
227+
* @return string
228+
*/
229+
public static function mangled_prefix_for(string $fieldname): string {
230+
return urlencode($fieldname) . static::MANGLE_SEPARATOR;
221231
}
222232

223233
/**

renderer.php

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ protected function get_iframe_document(context $context, qtype_questionpy_questi
277277
* @throws coding_exception
278278
*/
279279
protected function formulation_controls_feedback_in_iframe(
280-
question_attempt $qa, attempt_ui $ui, question_ui_renderer $renderer,
280+
question_attempt $qa, attempt_ui $ui, question_ui_renderer $renderer,
281281
question_display_options $options, string $responseinputid, string $editorsinputid
282282
): string {
283283
global $CFG;
@@ -616,4 +616,56 @@ public function render_readonly_file_view(question_attempt $qa, string $fieldnam
616616

617617
return $result;
618618
}
619+
620+
/**
621+
* Renders a read-only view of content entered into a {@see qpy_rich_text_editor} field.
622+
*
623+
* @param object|null $editordata
624+
* @param int $qubaid
625+
* @param int $slot
626+
* @param int $stepid
627+
* @param string $fieldname
628+
* @param question_display_options $options
629+
* @param int $rows
630+
* @param int $cols
631+
* @return string
632+
* @throws coding_exception
633+
*/
634+
public function render_readonly_editor_content(
635+
?object $editordata,
636+
int $qubaid,
637+
int $slot,
638+
int $stepid,
639+
string $fieldname,
640+
question_display_options $options,
641+
int $rows,
642+
int $cols
643+
): string {
644+
// Loosely based on qtype_essay_format_editor_renderer::response_area_read_only.
645+
646+
$content = '';
647+
if ($editordata) {
648+
// Replace the @@PLUGINFILE@@ placeholders with the correct pluginfile-URL prefix.
649+
// TODO: We use the standard question attempt file serving here, which saves us from having to do access control
650+
// ourselves, but also prevents us from using the actual (unmangled) filename when serving.
651+
$prefix = moodle_url::make_pluginfile_url(
652+
contextid: $options->context->id,
653+
component: 'question',
654+
area: constants::FILEAREA_RESPONSE_FILES,
655+
itemid: null,
656+
pathname: "/$qubaid/$slot/$stepid/",
657+
filename: response_file_service::mangled_prefix_for($fieldname)
658+
);
659+
$text = str_replace('@@PLUGINFILE@@/', $prefix, $editordata->text);
660+
661+
$content = format_text($text, $editordata->format, options: ['para' => false]);
662+
}
663+
664+
return html_writer::tag('div', $content, [
665+
'role' => 'textbox',
666+
'aria-readonly' => 'true',
667+
'class' => 'readonly',
668+
'style' => 'min-height: ' . ($rows * 1.5) . 'em;',
669+
]);
670+
}
619671
}

0 commit comments

Comments
 (0)