/** * Renders hint button. Could be used by behaviour or question renderer to avoid code duplication while rendering it. * @param hintobj object an object of a child of qtype_specific_hint class */ public function render_hint_button(question_attempt $qa, question_display_options $options, $hintobj) { $question = $qa->get_question(); $hintkey = $hintobj->hint_key(); // Render button. $attributes = array('type' => 'submit', 'id' => $qa->get_behaviour_field_name($hintkey . 'btn'), 'name' => $qa->get_behaviour_field_name($hintkey . 'btn'), 'value' => get_string('hintbtn', 'qbehaviour_adaptivehints', $hintobj->hint_description()), 'class' => 'submit btn'); if ($options->readonly) { $attributes['disabled'] = 'disabled'; } $output = html_writer::empty_tag('input', $attributes); // Cost message. if ($hintobj->penalty_response_based()) { // If penalty is response-based. // Try to get last response. $response = $qa->get_last_qt_data(); if (empty($response)) { $response = null; } $penalty = $hintobj->penalty_for_specific_hint($response); if ($penalty != 0) { $output .= $this->button_cost('withpenaltyapprox', $penalty, $options); // Note that reported penalty is approximation since user could change response in adaptive. } } else { $penalty = $hintobj->penalty_for_specific_hint(null); if ($penalty != 0) { $output .= $this->button_cost('withpenalty', $penalty, $options); } } if (!$options->readonly) { $this->page->requires->js_init_call('M.core_question_engine.init_submit_button', array($attributes['id'], $qa->get_slot())); } return $output; }
public function feedback(question_attempt $qa, question_display_options $options) { if (!$qa->get_state()->is_active() || !$options->readonly) { return ''; } $attributes = array('type' => 'submit', 'id' => $qa->get_behaviour_field_name('tryagain'), 'name' => $qa->get_behaviour_field_name('tryagain'), 'value' => get_string('tryagain', 'qbehaviour_interactive'), 'class' => 'submit btn'); if ($options->readonly !== qbehaviour_interactive::READONLY_EXCEPT_TRY_AGAIN) { $attributes['disabled'] = 'disabled'; } $output = html_writer::empty_tag('input', $attributes); if (empty($attributes['disabled'])) { $this->page->requires->js_init_call('M.core_question_engine.init_submit_button', array($attributes['id'], $qa->get_slot())); } return $output; }
/** * Construct the HTML for the optional 'precheck' button, which triggers * a partial submit in which no penalties are imposed but only the * 'Use as example' test cases are run. * This code is identical to the 'submit_button' code in * qbehaviour_renderer::submit_button except for the id and name of the * button. */ protected function precheck_button(question_attempt $qa, question_display_options $options) { if (!$qa->get_state()->is_active()) { return ''; // Not sure if this can happen, but the submit button does it. } $attributes = array('type' => 'submit', 'id' => $qa->get_behaviour_field_name('precheck'), 'name' => $qa->get_behaviour_field_name('precheck'), 'value' => get_string('precheck', 'qbehaviour_adaptive_adapted_for_coderunner'), 'class' => 'submit btn'); if ($options->readonly) { $attributes['disabled'] = 'disabled'; } $output = html_writer::empty_tag('input', $attributes); if (!$options->readonly) { $this->page->requires->js_init_call('M.core_question_engine.init_submit_button', array($attributes['id'], $qa->get_slot())); } return $output; }
protected function require_js($toreplaceid, question_attempt $qa, $readonly, $correctness) { global $PAGE; $jsmodule = array('name' => 'qtype_jme', 'fullpath' => '/question/type/jme/module.js', 'requires' => array(), 'strings' => array(array('enablejavascript', 'qtype_jme'))); $topnode = 'div.que.jme#q' . $qa->get_slot(); $appleturl = new moodle_url('/question/type/jme/jme/JME.jar'); $question = $qa->get_question(); // They will be converted to strings later. $width = $question->width; $height = $question->height; $appletoptions = $question->jmeoptions; if ($correctness) { $feedbackimage = $this->feedback_image($this->fraction_for_last_response($qa)); } else { $feedbackimage = ''; } $name = 'JME' . $qa->get_slot(); $appletid = 'jme' . $qa->get_slot(); $PAGE->requires->js_init_call('M.qtype_jme.insert_applet', array($toreplaceid, $name, $appletid, $topnode, $appleturl->out(), $feedbackimage, $readonly, "{$width}", "{$height}", $appletoptions), false, $jsmodule); }
/** * Generate the display of the response history part of the question. This * is the table showing all the steps the question has been through. * * @param question_attempt $qa the question attempt to display. * @param qbehaviour_renderer $behaviouroutput the renderer to output the behaviour * specific parts. * @param qtype_renderer $qtoutput the renderer to output the question type * specific parts. * @param question_display_options $options controls what should and should not be displayed. * @return HTML fragment. */ protected function response_history(question_attempt $qa, qbehaviour_renderer $behaviouroutput, qtype_renderer $qtoutput, question_display_options $options) { if (!$options->history) { return ''; } $table = new html_table(); $table->head = array(get_string('step', 'question'), get_string('time'), get_string('action', 'question'), get_string('state', 'question')); if ($options->marks >= question_display_options::MARK_AND_MAX) { $table->head[] = get_string('marks', 'question'); } foreach ($qa->get_full_step_iterator() as $i => $step) { $stepno = $i + 1; $rowclass = ''; if ($stepno == $qa->get_num_steps()) { $rowclass = 'current'; } else { if (!empty($options->questionreviewlink)) { $url = new moodle_url($options->questionreviewlink, array('slot' => $qa->get_slot(), 'step' => $i)); $stepno = $this->output->action_link($url, $stepno, new popup_action('click', $url, 'reviewquestion', array('width' => 450, 'height' => 650)), array('title' => get_string('reviewresponse', 'question'))); } } $restrictedqa = new question_attempt_with_restricted_history($qa, $i, null); $user = new stdClass(); $user->id = $step->get_user_id(); $row = array($stepno, userdate($step->get_timecreated(), get_string('strftimedatetimeshort')), s($qa->summarise_action($step)), $restrictedqa->get_state_string($options->correctness)); if ($options->marks >= question_display_options::MARK_AND_MAX) { $row[] = $qa->format_fraction_as_mark($step->get_fraction(), $options->markdp); } $table->rowclasses[] = $rowclass; $table->data[] = $row; } return html_writer::tag('h4', get_string('responsehistory', 'question'), array('class' => 'responsehistoryheader')) . $options->extrahistorycontent . html_writer::tag('div', html_writer::table($table, true), array('class' => 'responsehistoryheader')); }
protected function require_js($toreplaceid, question_attempt $qa, $readonly, $correctness, $uniqid) { global $PAGE, $CFG; $marvinjsconfig = get_config('qtype_easyonamejs_options'); $protocol = (empty($_SERVER['HTTPS']) or $_SERVER['HTTPS'] == 'off') ? 'http://' : 'https://'; $marvinjspath = $protocol . $_SERVER['HTTP_HOST'] . $marvinjsconfig->path; $topnode = 'div.que.easyonamejs#q' . $qa->get_slot(); $feedbackimage = ''; if ($correctness) { $feedbackimage = $this->feedback_image($this->fraction_for_last_response($qa)); } $name = 'EASYONAMEJS' . $uniqid; $appletid = 'easyonamejs' . $uniqid; $strippedanswerid = "stripped_answer" . $uniqid; $PAGE->requires->js_init_call('M.qtype_easyonamejs.insert_easyonamejs_applet', array($toreplaceid, $name, $appletid, $topnode, $feedbackimage, $readonly, $strippedanswerid, $CFG->wwwroot, $marvinjspath), false); }
public function notify_step_deleted(question_attempt_step $step, question_attempt $qa) { if (array_key_exists($qa->get_slot(), $this->attemptsadded)) { return; } if (($key = $this->is_step_added($step)) !== false) { unset($this->stepsadded[$key]); return; } if (($key = $this->is_step_modified($step)) !== false) { unset($this->stepsmodified[$key]); } $stepid = $step->get_id(); if (empty($stepid)) { return; // Was never in the database. } $this->stepsdeleted[$stepid] = $step; }
/** * Get the postdata that needs to be sent to question/toggleflag.php to change the flag state. * You need to append &newstate=0/1 to this. * @return the post data to send. */ public static function get_postdata(question_attempt $qa) { $qaid = $qa->get_database_id(); $qubaid = $qa->get_usage_id(); $qid = $qa->get_question()->id; $slot = $qa->get_slot(); $checksum = self::get_toggle_checksum($qubaid, $qid, $qaid, $slot); return "qaid={$qaid}&qubaid={$qubaid}&qid={$qid}&slot={$slot}&checksum={$checksum}&sesskey=" . sesskey() . '&newstate='; }
public function notify_step_added(question_attempt_step $step, question_attempt $qa, $seq) { if (array_key_exists($qa->get_slot(), $this->attemptsadded)) { return; } $this->stepsadded[] = array($step, $qa->get_database_id(), $seq); }
public function notify_metadata_modified(question_attempt $qa, $name) { if (array_key_exists($qa->get_slot(), $this->attemptsadded)) { return; } if ($this->is_step_added($qa->get_step(0)) !== false) { return; } if (isset($this->metadataadded[$qa->get_slot()][$name])) { return; } if (isset($this->metadatamodified[$qa->get_slot()][$name])) { return; } $this->metadatamodified[$qa->get_slot()][$name] = $qa; }
/** * Several behaviours need a submit button, so put the common code here. * The button is disabled if the question is displayed read-only. * @param question_display_options $options controls what should and should not be displayed. * @return string HTML fragment. */ protected function submit_button(question_attempt $qa, question_display_options $options) { $attributes = array('type' => 'submit', 'id' => $qa->get_behaviour_field_name('submit'), 'name' => $qa->get_behaviour_field_name('submit'), 'value' => get_string('check', 'question'), 'class' => 'submit btn'); if ($options->readonly) { $attributes['disabled'] = 'disabled'; } $output = html_writer::empty_tag('input', $attributes); if (!$options->readonly) { $this->page->requires->js_init_call('M.core_question_engine.init_submit_button', array($attributes['id'], $qa->get_slot())); } return $output; }
/** * Returns the URL for an image * * @param object $qa Question attempt object * @param string $filearea File area descriptor * @param int $itemid Item id to get * @return string Output url, or null if not found */ protected static function get_url_for_image(question_attempt $qa, $filearea, $itemid = 0) { $question = $qa->get_question(); $qubaid = $qa->get_usage_id(); $slot = $qa->get_slot(); $fs = get_file_storage(); if ($filearea == 'bgimage') { $itemid = $question->id; } $componentname = $question->qtype->plugin_name(); $draftfiles = $fs->get_area_files($question->contextid, $componentname, $filearea, $itemid, 'id'); if ($draftfiles) { foreach ($draftfiles as $file) { if ($file->is_directory()) { continue; } $url = moodle_url::make_pluginfile_url($question->contextid, $componentname, $filearea, "{$qubaid}/{$slot}/{$itemid}", '/', $file->get_filename()); return $url->out(); } } return null; }