mirror of
https://github.com/moodle/moodle.git
synced 2025-06-01 05:35:55 +02:00
MDL-44630: Several additions to Common Cartridge Import/Export
Changes provided by Darko Miletic and Sam Chaffee. * Fix problem with CC import not detecting a CC package. (Sam) * Fixed Common Cartridge not importing FIB answers. (Sam) * Fix to CC export so that short answer pattern matching question in a quiz does not prevent the entire quiz from exporting. (Sam) * Fix notice about missing index when there is no answer-specific feedback in short answer question during CC export. (Sam) * Fixed Japanese characters being incorrectly encoded (garbled) on Common Cartridge import. (Sam) * Changed import of CC discussions to create 'Standard General' forums in Moodle. (Sam) * Fix problem with question name being replaced with question text on CC import of exported Moodle questions. (Sam) * Fix CC 1.1 multiple choice question import having no correct answers. (Sam) * Fixed problem with multiple choice, multiple answers allowed questions not exporting correct answers to CC. (Sam) * Removed duplicate method. (Darko) * Implemented fix that skips quiz export if it contains non-exportable question. (Darko) * Fixed: Common cartridge export is extremely slow when dealing with lot of more than 200 files. (Darko) * Added support for basic roles support in common cartridge. (Darko) * Implemented folder resource export. (Darko) * Minor fixes to adjust to the standard. (Darko) * Added support for exporting simple fill in the blank (shortanswer without wildcards in Moodle). (Darko) * Added support for exporting essay question. (Darko) * Added support for true/false export. (Darko) * Added support for exporting multiple response questions, added also category information into question metadata during export (Darko) * Added support for correctly importing multiple response questions. (Darko)
This commit is contained in:
parent
0a489777fc
commit
c3d245cff3
@ -40,4 +40,5 @@ require_once($CFG->dirroot .'/backup/cc/cc_lib/cc_converter_resource.php');
|
||||
require_once($CFG->dirroot .'/backup/cc/cc_lib/cc_converter_quiz.php');
|
||||
require_once($CFG->dirroot .'/backup/cc/cc_lib/cc_converter_page.php');
|
||||
require_once($CFG->dirroot .'/backup/cc/cc_lib/cc_converter_label.php');
|
||||
require_once($CFG->dirroot .'/backup/cc/cc_lib/cc_converter_folder.php');
|
||||
require_once($CFG->dirroot .'/backup/cc/cc_lib/cc_convert_moodle2.php');
|
||||
|
69
backup/cc/cc_lib/cc_assesment_essay.php
Normal file
69
backup/cc/cc_lib/cc_assesment_essay.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
/**
|
||||
* @package backup-convert
|
||||
* @copyright 2012 Darko Miletic <dmiletic@moodlerooms.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') or die('Direct access to this script is forbidden.');
|
||||
|
||||
class cc_assesment_question_essay extends cc_assesment_question_proc_base {
|
||||
public function __construct($quiz, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir) {
|
||||
parent::__construct($quiz, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
|
||||
$this->qtype = cc_qti_profiletype::essay;
|
||||
$maximum_quiz_grade = (int)$this->quiz->nodeValue('/activity/quiz/grade');
|
||||
$this->total_grade_value = ($maximum_quiz_grade + 1).'.0000000';
|
||||
}
|
||||
|
||||
public function on_generate_metadata() {
|
||||
parent::on_generate_metadata();
|
||||
//Mark essay for manual grading
|
||||
$this->qmetadata->enable_scoringpermitted();
|
||||
$this->qmetadata->enable_computerscored(false);
|
||||
}
|
||||
|
||||
public function on_generate_presentation() {
|
||||
parent::on_generate_presentation();
|
||||
$response_str = new cc_assesment_response_strtype();
|
||||
$response_fib = new cc_assesment_render_fibtype();
|
||||
$row_value = (int)$this->questions->nodeValue('plugin_qtype_essay_question//responsefieldlines', $this->question_node);
|
||||
$response_fib->set_rows($row_value);
|
||||
$response_str->set_render_fib($response_fib);
|
||||
$this->qpresentation->set_response_str($response_str);
|
||||
}
|
||||
|
||||
public function on_generate_response_processing() {
|
||||
parent::on_generate_response_processing();
|
||||
|
||||
//respconditions
|
||||
if (!empty($this->general_feedback)) {
|
||||
$qrespcondition = new cc_assesment_respconditiontype();
|
||||
$qrespcondition->set_title('General feedback');
|
||||
$this->qresprocessing->add_respcondition($qrespcondition);
|
||||
//define the condition for success
|
||||
$qconditionvar = new cc_assignment_conditionvar();
|
||||
$qrespcondition->set_conditionvar($qconditionvar);
|
||||
$qother = new cc_assignment_conditionvar_othertype();
|
||||
$qconditionvar->set_other($qother);
|
||||
$qdisplayfeedback = new cc_assignment_displayfeedbacktype();
|
||||
$qrespcondition->add_displayfeedback($qdisplayfeedback);
|
||||
$qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
|
||||
$qdisplayfeedback->set_linkrefid('general_fb');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
183
backup/cc/cc_lib/cc_assesment_sfib.php
Normal file
183
backup/cc/cc_lib/cc_assesment_sfib.php
Normal file
@ -0,0 +1,183 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
/**
|
||||
* @package backup-convert
|
||||
* @copyright 2012 Darko Miletic <dmiletic@moodlerooms.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') or die('Direct access to this script is forbidden.');
|
||||
|
||||
require_once 'cc_asssesment.php';
|
||||
|
||||
class cc_assesment_question_sfib extends cc_assesment_question_proc_base {
|
||||
public function __construct($quiz, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir) {
|
||||
parent::__construct($quiz, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
|
||||
$this->qtype = cc_qti_profiletype::field_entry;
|
||||
$this->correct_answer_node_id = $this->questions->nodeValue('plugin_qtype_truefalse_question/truefalse/trueanswer', $this->question_node);
|
||||
$maximum_quiz_grade = (int)$this->quiz->nodeValue('/activity/quiz/grade');
|
||||
$this->total_grade_value = ($maximum_quiz_grade + 1).'.0000000';
|
||||
}
|
||||
|
||||
public function on_generate_metadata() {
|
||||
parent::on_generate_metadata();
|
||||
|
||||
$category = $this->questions->nodeValue('../../name', $this->question_node);
|
||||
if (!empty($category)) {
|
||||
$this->qmetadata->set_category($category);
|
||||
}
|
||||
}
|
||||
|
||||
public function on_generate_presentation() {
|
||||
parent::on_generate_presentation();
|
||||
$response_str = new cc_assesment_response_strtype();
|
||||
$response_fib = new cc_assesment_render_fibtype();
|
||||
/**
|
||||
* The standard requires that only rows attribute must be set
|
||||
* The rest may or may not be configured. For the sake of brevity we leave it empty.
|
||||
*/
|
||||
$response_fib->set_rows(1);
|
||||
$response_str->set_render_fib($response_fib);
|
||||
$this->qpresentation->set_response_str($response_str);
|
||||
}
|
||||
|
||||
public function on_generate_feedbacks() {
|
||||
parent::on_generate_feedbacks();
|
||||
//Question combined feedbacks
|
||||
$responsenodes = $this->questions->nodeList('plugin_qtype_shortanswer_question//answer', $this->question_node);
|
||||
$count = 0;
|
||||
foreach ($responsenodes as $respnode) {
|
||||
$content = $this->questions->nodeValue('feedback', $respnode);
|
||||
if (empty($content)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$correct = (int)$this->questions->nodeValue('fraction', $respnode) == 1;
|
||||
$answerid = (int)$this->questions->nodeValue('@id', $respnode);
|
||||
|
||||
$result = cc_helpers::process_linked_files( $content,
|
||||
$this->manifest,
|
||||
$this->rootpath,
|
||||
$this->contextid,
|
||||
$this->outdir);
|
||||
$ident = $correct ? 'correct' : 'incorrect';
|
||||
$ident .= '_'.$count.'_fb';
|
||||
cc_assesment_helper::add_feedback( $this->qitem,
|
||||
$result[0],
|
||||
cc_qti_values::htmltype,
|
||||
$ident);
|
||||
|
||||
pkg_resource_dependencies::instance()->add($result[1]);
|
||||
|
||||
if ($correct) {
|
||||
$this->correct_feedbacks[$answerid] = $ident;
|
||||
} else {
|
||||
$this->incorrect_feedbacks[$answerid] = $ident;
|
||||
}
|
||||
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
|
||||
public function on_generate_response_processing() {
|
||||
parent::on_generate_response_processing();
|
||||
|
||||
//respconditions
|
||||
/**
|
||||
* General unconditional feedback must be added as a first respcondition
|
||||
* without any condition and just displayfeedback (if exists)
|
||||
*/
|
||||
if (!empty($this->general_feedback)) {
|
||||
$qrespcondition = new cc_assesment_respconditiontype();
|
||||
$qrespcondition->set_title('General feedback');
|
||||
$this->qresprocessing->add_respcondition($qrespcondition);
|
||||
$qrespcondition->enable_continue();
|
||||
//define the condition for success
|
||||
$qconditionvar = new cc_assignment_conditionvar();
|
||||
$qrespcondition->set_conditionvar($qconditionvar);
|
||||
$qother = new cc_assignment_conditionvar_othertype();
|
||||
$qconditionvar->set_other($qother);
|
||||
$qdisplayfeedback = new cc_assignment_displayfeedbacktype();
|
||||
$qrespcondition->add_displayfeedback($qdisplayfeedback);
|
||||
$qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
|
||||
$qdisplayfeedback->set_linkrefid('general_fb');
|
||||
}
|
||||
|
||||
//Answer separate conditions
|
||||
$correct_responses = $this->questions->nodeList('plugin_qtype_shortanswer_question//answer[fraction=1]', $this->question_node);
|
||||
$incorrect_responses = $this->questions->nodeList('plugin_qtype_shortanswer_question//answer[fraction<1]', $this->question_node);
|
||||
$items = array(array($correct_responses ,$this->correct_feedbacks), array($incorrect_responses, $this->incorrect_feedbacks));
|
||||
foreach ($items as $respfeed) {
|
||||
foreach ($respfeed[0] as $coresponse) {
|
||||
$qrespcondition = new cc_assesment_respconditiontype();
|
||||
$qrespcondition->enable_continue();
|
||||
$this->qresprocessing->add_respcondition($qrespcondition);
|
||||
$qconditionvar = new cc_assignment_conditionvar();
|
||||
$qrespcondition->set_conditionvar($qconditionvar);
|
||||
$respc = $this->questions->nodeValue('answertext', $coresponse);
|
||||
$resid = $this->questions->nodeValue('@id', $coresponse);
|
||||
$qvarequal = new cc_assignment_conditionvar_varequaltype($respc);
|
||||
$qconditionvar->set_varequal($qvarequal);
|
||||
$qvarequal->set_respident('response');
|
||||
$qvarequal->enable_case(false);
|
||||
if (!empty($respfeed[1][$resid])) {
|
||||
$qdisplayfeedback = new cc_assignment_displayfeedbacktype();
|
||||
$qrespcondition->add_displayfeedback($qdisplayfeedback);
|
||||
$qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
|
||||
$qdisplayfeedback->set_linkrefid($respfeed[1][$resid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
//success condition
|
||||
/**
|
||||
* For all question types outside of the Essay question, scoring is done in a
|
||||
* single <respcondition> with a continue flag set to No. The outcome is always
|
||||
* a variable named SCORE which value must be set to 100 in case of correct answer.
|
||||
* Partial scores (not 0 or 100) are not supported.
|
||||
*/
|
||||
$qrespcondition = new cc_assesment_respconditiontype();
|
||||
$qrespcondition->set_title('Correct');
|
||||
$this->qresprocessing->add_respcondition($qrespcondition);
|
||||
$qrespcondition->enable_continue(false);
|
||||
$qsetvar = new cc_assignment_setvartype(100);
|
||||
$qrespcondition->add_setvar($qsetvar);
|
||||
//define the condition for success
|
||||
$qconditionvar = new cc_assignment_conditionvar();
|
||||
$qrespcondition->set_conditionvar($qconditionvar);
|
||||
//No case sensitivity as stated in documentation
|
||||
//$case_sensitive = $this->questions->nodeValue('plugin_qtype_shortanswer_question//shortanswer/usecase', $this->question_node)==1;
|
||||
foreach ($correct_responses as $coresponse) {
|
||||
$respc = $this->questions->nodeValue('answertext', $coresponse);
|
||||
$qvarequal = new cc_assignment_conditionvar_varequaltype($respc);
|
||||
$qconditionvar->set_varequal($qvarequal);
|
||||
$qvarequal->set_respident('response');
|
||||
$qvarequal->enable_case(false);
|
||||
}
|
||||
|
||||
//Add incorrect handling
|
||||
$qrespcondition = new cc_assesment_respconditiontype();
|
||||
//$qrespcondition->set_title('General feedback');
|
||||
$this->qresprocessing->add_respcondition($qrespcondition);
|
||||
$qrespcondition->enable_continue(false);
|
||||
//define the condition for faliure
|
||||
$qconditionvar = new cc_assignment_conditionvar();
|
||||
$qrespcondition->set_conditionvar($qconditionvar);
|
||||
$qother = new cc_assignment_conditionvar_othertype();
|
||||
$qconditionvar->set_other($qother);
|
||||
$qsetvar = new cc_assignment_setvartype(0);
|
||||
$qrespcondition->add_setvar($qsetvar);
|
||||
}
|
||||
}
|
176
backup/cc/cc_lib/cc_assesment_truefalse.php
Normal file
176
backup/cc/cc_lib/cc_assesment_truefalse.php
Normal file
@ -0,0 +1,176 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
/**
|
||||
* @package backup-convert
|
||||
* @copyright 2012 Darko Miletic <dmiletic@moodlerooms.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') or die('Direct access to this script is forbidden.');
|
||||
|
||||
require_once 'cc_asssesment.php';
|
||||
|
||||
class cc_assesment_question_truefalse extends cc_assesment_question_proc_base {
|
||||
public function __construct($quiz, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir) {
|
||||
parent::__construct($quiz, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
|
||||
$this->qtype = cc_qti_profiletype::true_false;
|
||||
$this->correct_answer_node_id = $this->questions->nodeValue('plugin_qtype_truefalse_question/truefalse/trueanswer', $this->question_node);
|
||||
$maximum_quiz_grade = (int)$this->quiz->nodeValue('/activity/quiz/grade');
|
||||
$this->total_grade_value = ($maximum_quiz_grade + 1).'.0000000';
|
||||
}
|
||||
|
||||
public function on_generate_answers() {
|
||||
//add responses holder
|
||||
$qresponse_lid = new cc_response_lidtype();
|
||||
$this->qresponse_lid = $qresponse_lid;
|
||||
$this->qpresentation->set_response_lid($qresponse_lid);
|
||||
$qresponse_choice = new cc_assesment_render_choicetype();
|
||||
$qresponse_lid->set_render_choice($qresponse_choice);
|
||||
//Mark that question has only one correct answer -
|
||||
//which applies for multiple choice and yes/no questions
|
||||
$qresponse_lid->set_rcardinality(cc_qti_values::Single);
|
||||
//are we to shuffle the responses?
|
||||
$shuffle_answers = (int)$this->quiz->nodeValue('/activity/quiz/shuffleanswers') > 0;
|
||||
$qresponse_choice->enable_shuffle($shuffle_answers);
|
||||
$answerlist = array();
|
||||
$qa_responses = $this->questions->nodeList('plugin_qtype_truefalse_question/answers/answer', $this->question_node);
|
||||
foreach ($qa_responses as $node) {
|
||||
$answer_content = $this->questions->nodeValue('answertext', $node);
|
||||
$id = ((int)$this->questions->nodeValue('@id', $node) == $this->correct_answer_node_id);
|
||||
$qresponse_label = cc_assesment_helper::add_answer( $qresponse_choice,
|
||||
$answer_content,
|
||||
cc_qti_values::htmltype);
|
||||
$answer_ident = strtolower(trim($answer_content));
|
||||
$qresponse_label->set_ident($answer_ident);
|
||||
$feedback_ident = ($id) ? 'correct_fb' : 'incorrect_fb';
|
||||
if (empty($this->correct_answer_ident) && $id) {
|
||||
$this->correct_answer_ident = $answer_ident;
|
||||
}
|
||||
//add answer specific feedbacks if not empty
|
||||
$content = $this->questions->nodeValue('feedback', $node);
|
||||
if (!empty($content)) {
|
||||
$result = cc_helpers::process_linked_files( $content,
|
||||
$this->manifest,
|
||||
$this->rootpath,
|
||||
$this->contextid,
|
||||
$this->outdir);
|
||||
|
||||
|
||||
cc_assesment_helper::add_feedback( $this->qitem,
|
||||
$result[0],
|
||||
cc_qti_values::htmltype,
|
||||
$feedback_ident);
|
||||
|
||||
pkg_resource_dependencies::instance()->add($result[1]);
|
||||
|
||||
$answerlist[$answer_ident] = $feedback_ident;
|
||||
}
|
||||
}
|
||||
|
||||
$this->answerlist = $answerlist;
|
||||
|
||||
}
|
||||
|
||||
public function on_generate_response_processing() {
|
||||
parent::on_generate_response_processing();
|
||||
|
||||
//respconditions
|
||||
/**
|
||||
* General unconditional feedback must be added as a first respcondition
|
||||
* without any condition and just displayfeedback (if exists)
|
||||
*/
|
||||
if (!empty($this->general_feedback)) {
|
||||
$qrespcondition = new cc_assesment_respconditiontype();
|
||||
$qrespcondition->set_title('General feedback');
|
||||
$this->qresprocessing->add_respcondition($qrespcondition);
|
||||
$qrespcondition->enable_continue();
|
||||
//define the condition for success
|
||||
$qconditionvar = new cc_assignment_conditionvar();
|
||||
$qrespcondition->set_conditionvar($qconditionvar);
|
||||
$qother = new cc_assignment_conditionvar_othertype();
|
||||
$qconditionvar->set_other($qother);
|
||||
$qdisplayfeedback = new cc_assignment_displayfeedbacktype();
|
||||
$qrespcondition->add_displayfeedback($qdisplayfeedback);
|
||||
$qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
|
||||
$qdisplayfeedback->set_linkrefid('general_fb');
|
||||
}
|
||||
|
||||
//success condition
|
||||
/**
|
||||
* For all question types outside of the Essay question, scoring is done in a
|
||||
* single <respcondition> with a continue flag set to No. The outcome is always
|
||||
* a variable named SCORE which value must be set to 100 in case of correct answer.
|
||||
* Partial scores (not 0 or 100) are not supported.
|
||||
*/
|
||||
$qrespcondition = new cc_assesment_respconditiontype();
|
||||
$qrespcondition->set_title('Correct');
|
||||
$this->qresprocessing->add_respcondition($qrespcondition);
|
||||
$qrespcondition->enable_continue(false);
|
||||
$qsetvar = new cc_assignment_setvartype(100);
|
||||
$qrespcondition->add_setvar($qsetvar);
|
||||
//define the condition for success
|
||||
$qconditionvar = new cc_assignment_conditionvar();
|
||||
$qrespcondition->set_conditionvar($qconditionvar);
|
||||
//TODO: recheck this
|
||||
$qvarequal = new cc_assignment_conditionvar_varequaltype($this->correct_answer_ident);
|
||||
$qconditionvar->set_varequal($qvarequal);
|
||||
$qvarequal->set_respident($this->qresponse_lid->get_ident());
|
||||
|
||||
if (array_key_exists($this->correct_answer_ident, $this->answerlist)) {
|
||||
$qdisplayfeedback = new cc_assignment_displayfeedbacktype();
|
||||
$qrespcondition->add_displayfeedback($qdisplayfeedback);
|
||||
$qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
|
||||
$qdisplayfeedback->set_linkrefid($this->answerlist[$this->correct_answer_ident]);
|
||||
}
|
||||
|
||||
foreach ($this->correct_feedbacks as $ident) {
|
||||
$qdisplayfeedback = new cc_assignment_displayfeedbacktype();
|
||||
$qrespcondition->add_displayfeedback($qdisplayfeedback);
|
||||
$qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
|
||||
$qdisplayfeedback->set_linkrefid($ident);
|
||||
}
|
||||
|
||||
//rest of the conditions
|
||||
foreach ($this->answerlist as $ident => $refid) {
|
||||
if ($ident == $this->correct_answer_ident) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$qrespcondition = new cc_assesment_respconditiontype();
|
||||
$this->qresprocessing->add_respcondition($qrespcondition);
|
||||
$qsetvar = new cc_assignment_setvartype(0);
|
||||
$qrespcondition->add_setvar($qsetvar);
|
||||
//define the condition for fail
|
||||
$qconditionvar = new cc_assignment_conditionvar();
|
||||
$qrespcondition->set_conditionvar($qconditionvar);
|
||||
$qvarequal = new cc_assignment_conditionvar_varequaltype($ident);
|
||||
$qconditionvar->set_varequal($qvarequal);
|
||||
$qvarequal->set_respident($this->qresponse_lid->get_ident());
|
||||
|
||||
$qdisplayfeedback = new cc_assignment_displayfeedbacktype();
|
||||
$qrespcondition->add_displayfeedback($qdisplayfeedback);
|
||||
$qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
|
||||
$qdisplayfeedback->set_linkrefid($refid);
|
||||
|
||||
foreach ($this->incorrect_feedbacks as $ident) {
|
||||
$qdisplayfeedback = new cc_assignment_displayfeedbacktype();
|
||||
$qrespcondition->add_displayfeedback($qdisplayfeedback);
|
||||
$qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
|
||||
$qdisplayfeedback->set_linkrefid($ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -698,26 +698,30 @@ class cc_assignment_conditionvar_varsubstringtype extends cc_assignment_conditio
|
||||
|
||||
|
||||
class cc_assignment_conditionvar_andtype extends cc_question_metadata_base {
|
||||
protected $not = null;
|
||||
protected $varequal = null;
|
||||
protected $nots = array();
|
||||
protected $varequals = array();
|
||||
|
||||
public function set_not(cc_assignment_conditionvar_varequaltype $object) {
|
||||
$this->not = $object;
|
||||
$this->nots[] = $object;
|
||||
}
|
||||
|
||||
public function set_varequal(cc_assignment_conditionvar_varequaltype $object) {
|
||||
$this->varequal = $object;
|
||||
$this->varequals[] = $object;
|
||||
}
|
||||
|
||||
public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
|
||||
$node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::and_);
|
||||
if (!empty($this->not)) {
|
||||
$not = $doc->append_new_element_ns($node, $namespace, cc_qti_tags::not_);
|
||||
$this->not->generate($doc, $not, $namespace);
|
||||
if (!empty($this->nots)) {
|
||||
foreach ($this->nots as $notv) {
|
||||
$not = $doc->append_new_element_ns($node, $namespace, cc_qti_tags::not_);
|
||||
$notv->generate($doc, $not, $namespace);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->varequal)) {
|
||||
$this->varequal->generate($doc, $node, $namespace);
|
||||
if (!empty($this->varequals)) {
|
||||
foreach ($this->varequals as $varequal) {
|
||||
$varequal->generate($doc, $node, $namespace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -733,9 +737,9 @@ class cc_assignment_conditionvar extends cc_question_metadata_base {
|
||||
*/
|
||||
protected $other = null;
|
||||
/**
|
||||
* @var cc_assignment_conditionvar_varequaltype
|
||||
* @var array
|
||||
*/
|
||||
protected $varequal = null;
|
||||
protected $varequal = array();
|
||||
/**
|
||||
* @var cc_assignment_conditionvar_varsubstringtype
|
||||
*/
|
||||
@ -750,7 +754,7 @@ class cc_assignment_conditionvar extends cc_question_metadata_base {
|
||||
}
|
||||
|
||||
public function set_varequal(cc_assignment_conditionvar_varequaltype $object) {
|
||||
$this->varequal = $object;
|
||||
$this->varequal[] = $object;
|
||||
}
|
||||
|
||||
public function set_varsubstring(cc_assignment_conditionvar_varsubstringtype $object) {
|
||||
@ -769,7 +773,9 @@ class cc_assignment_conditionvar extends cc_question_metadata_base {
|
||||
}
|
||||
|
||||
if (!empty($this->varequal)) {
|
||||
$this->varequal->generate($doc, $node, $namespace);
|
||||
foreach ($this->varequal as $varequal) {
|
||||
$varequal->generate($doc, $node, $namespace);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->varsubstring)) {
|
||||
@ -1895,8 +1901,20 @@ abstract class cc_assesment_helper {
|
||||
return $qresponse_label;
|
||||
}
|
||||
|
||||
public static function add_response_condition() {
|
||||
|
||||
public static function add_response_condition($node, $title, $ident, $feedback_refid, $respident) {
|
||||
$qrespcondition = new cc_assesment_respconditiontype();
|
||||
$node->add_respcondition($qrespcondition);
|
||||
//define rest of the conditions
|
||||
$qconditionvar = new cc_assignment_conditionvar();
|
||||
$qrespcondition->set_conditionvar($qconditionvar);
|
||||
$qvarequal = new cc_assignment_conditionvar_varequaltype($ident);
|
||||
$qvarequal->enable_case();
|
||||
$qconditionvar->set_varequal($qvarequal);
|
||||
$qvarequal->set_respident($respident);
|
||||
$qdisplayfeedback = new cc_assignment_displayfeedbacktype();
|
||||
$qrespcondition->add_displayfeedback($qdisplayfeedback);
|
||||
$qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
|
||||
$qdisplayfeedback->set_linkrefid($feedback_refid);
|
||||
}
|
||||
|
||||
public static function add_assesment_description($rt, $content, $contenttype) {
|
||||
@ -1913,6 +1931,27 @@ abstract class cc_assesment_helper {
|
||||
$rt->set_rubric($activity_rubric);
|
||||
}
|
||||
|
||||
public static function add_respcondition($node, $title, $feedback_refid, $grade_value = null, $continue = false ) {
|
||||
$qrespcondition = new cc_assesment_respconditiontype();
|
||||
$qrespcondition->set_title($title);
|
||||
$node->add_respcondition($qrespcondition);
|
||||
$qrespcondition->enable_continue($continue);
|
||||
//Add setvar if grade present
|
||||
if ($grade_value !== null) {
|
||||
$qsetvar = new cc_assignment_setvartype($grade_value);
|
||||
$qrespcondition->add_setvar($qsetvar);
|
||||
}
|
||||
//define the condition for success
|
||||
$qconditionvar = new cc_assignment_conditionvar();
|
||||
$qrespcondition->set_conditionvar($qconditionvar);
|
||||
$qother = new cc_assignment_conditionvar_othertype();
|
||||
$qconditionvar->set_other($qother);
|
||||
$qdisplayfeedback = new cc_assignment_displayfeedbacktype();
|
||||
$qrespcondition->add_displayfeedback($qdisplayfeedback);
|
||||
$qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
|
||||
$qdisplayfeedback->set_linkrefid($feedback_refid);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Enter description here ...
|
||||
@ -1932,7 +1971,8 @@ abstract class cc_assesment_helper {
|
||||
}
|
||||
|
||||
pkg_resource_dependencies::instance()->reset();
|
||||
|
||||
$questioncount = 0;
|
||||
$questionforexport = 0;
|
||||
$qids = explode(',', $qdoc->nodeValue('/activity/quiz/questions'));
|
||||
foreach ($qids as $value) {
|
||||
if (intval($value) == 0) {
|
||||
@ -1942,6 +1982,7 @@ abstract class cc_assesment_helper {
|
||||
if (empty($question_node)) {
|
||||
continue;
|
||||
}
|
||||
++$questionforexport;
|
||||
//process question
|
||||
//question type
|
||||
$qtype = $questions->nodeValue('qtype', $question_node);
|
||||
@ -1949,15 +1990,43 @@ abstract class cc_assesment_helper {
|
||||
switch ($qtype) {
|
||||
case 'multichoice':
|
||||
$single_correct_answer = (int)$questions->nodeValue('plugin_qtype_multichoice_question/multichoice/single', $question_node) > 0;
|
||||
//TODO: Add checking for the nunmber of valid responses
|
||||
//If question is marked as multi response but contains only one valid answer it
|
||||
//should be handle as single response - classic multichoice
|
||||
if ($single_correct_answer) {
|
||||
$question_processor = new cc_assesment_question_multichoice($qdoc, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
|
||||
$question_processor->generate();
|
||||
} else {
|
||||
//TODO: implement
|
||||
$question_processor = new cc_assesment_question_multichoice_multiresponse($qdoc, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
|
||||
}
|
||||
$question_processor->generate();
|
||||
++$questioncount;
|
||||
break;
|
||||
case 'truefalse':
|
||||
$question_processor = new cc_assesment_question_truefalse($qdoc, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
|
||||
$question_processor->generate();
|
||||
++$questioncount;
|
||||
break;
|
||||
case 'essay':
|
||||
$question_processor = new cc_assesment_question_essay($qdoc, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
|
||||
$question_processor->generate();
|
||||
++$questioncount;
|
||||
break;
|
||||
case 'shortanswer':
|
||||
//This is rather ambiguos since shortanswer supports partial pattern match
|
||||
//In order to detect pattern match we need to scan for all the responses
|
||||
//if at least one of the responses uses wildcards it should be treated as
|
||||
//pattern match, otherwise it should be simple fill in the blank
|
||||
if (self::has_matching_element($questions, $question_node)) {
|
||||
//$question_processor = new cc_assesment_question_patternmatch($qdoc, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
|
||||
$questionforexport--;
|
||||
} else {
|
||||
$question_processor = new cc_assesment_question_sfib($qdoc, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
|
||||
}
|
||||
if (!empty($question_processor)) {
|
||||
$question_processor->generate();
|
||||
++$questioncount;
|
||||
}
|
||||
;
|
||||
break;
|
||||
|
||||
default:
|
||||
;
|
||||
break;
|
||||
@ -1966,7 +2035,28 @@ abstract class cc_assesment_helper {
|
||||
}
|
||||
|
||||
//return dependencies
|
||||
return pkg_resource_dependencies::instance()->get_deps();
|
||||
return ($questioncount == 0) || ($questioncount != $questionforexport)?
|
||||
false: pkg_resource_dependencies::instance()->get_deps();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Checks if question has matching element
|
||||
* @param XMLGenericDocument $questions
|
||||
* @param object $question_node
|
||||
* @return bool
|
||||
*/
|
||||
public static function has_matching_element(XMLGenericDocument $questions, $question_node) {
|
||||
$answers = $questions->nodeList('plugin_qtype_shortanswer_question//answertext', $question_node);
|
||||
$result = false;
|
||||
foreach ($answers as $answer) {
|
||||
$prepare = str_replace('\*', '\#', $answer->nodeValue);
|
||||
$result = (strpos($prepare, '*') !== false);
|
||||
if ($result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
@ -2085,6 +2175,11 @@ class cc_assesment_question_proc_base {
|
||||
if ($weighting_value > 1) {
|
||||
$this->qmetadata->set_weighting($weighting_value);
|
||||
}
|
||||
//Get category
|
||||
$question_category = $this->questions->nodeValue('../../name', $this->question_node);
|
||||
if (!empty($question_category)) {
|
||||
$this->qmetadata->set_category($question_category);
|
||||
}
|
||||
$rts = new cc_assesment_itemmetadata();
|
||||
$rts->add_metadata($this->qmetadata);
|
||||
$this->qitem->set_itemmetadata($rts);
|
||||
@ -2169,14 +2264,14 @@ class cc_assesment_question_multichoice extends cc_assesment_question_proc_base
|
||||
$this->qtype = cc_qti_profiletype::multiple_choice;
|
||||
|
||||
/**
|
||||
*
|
||||
* What is needed is a maximum grade value taken from the answer fraction
|
||||
* It is supposed to always be between 1 and 0 in decimal representation,
|
||||
* however that is not always the case so a change in test was needed
|
||||
* but since we support here one correct answer type
|
||||
* correct answer would always have to be 1
|
||||
*/
|
||||
$correct_answer_node = $this->questions->node("plugin_qtype_multichoice_question/answers/answer[fraction!=0.0000000]", $this->question_node);
|
||||
*
|
||||
* What is needed is a maximum grade value taken from the answer fraction
|
||||
* It is supposed to always be between 1 and 0 in decimal representation,
|
||||
* however that is not always the case so a change in test was needed
|
||||
* but since we support here one correct answer type
|
||||
* correct answer would always have to be 1
|
||||
*/
|
||||
$correct_answer_node = $this->questions->node("plugin_qtype_multichoice_question/answers/answer[fraction > 0]", $this->question_node);
|
||||
if (empty($correct_answer_node)) {
|
||||
throw new RuntimeException('No correct answer!');
|
||||
}
|
||||
@ -2362,3 +2457,193 @@ class cc_assesment_question_multichoice extends cc_assesment_question_proc_base
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class cc_assesment_question_multichoice_multiresponse extends cc_assesment_question_proc_base {
|
||||
/**
|
||||
* @var DOMNodeList
|
||||
*/
|
||||
protected $correct_answers = null;
|
||||
|
||||
public function __construct($quiz, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir) {
|
||||
parent::__construct($quiz, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
|
||||
$this->qtype = cc_qti_profiletype::multiple_response;
|
||||
|
||||
$correct_answer_nodes = $this->questions->nodeList("plugin_qtype_multichoice_question/answers/answer[fraction > 0]", $this->question_node);
|
||||
if ($correct_answer_nodes->length == 0) {
|
||||
throw new RuntimeException('No correct answer!');
|
||||
}
|
||||
$this->correct_answers = $correct_answer_nodes;
|
||||
//$this->correct_answer_node_id = $this->questions->nodeValue('@id', $correct_answer_node);
|
||||
$maximum_quiz_grade = (int)$this->quiz->nodeValue('/activity/quiz/grade');
|
||||
$this->total_grade_value = ($maximum_quiz_grade + 1).'.0000000';
|
||||
}
|
||||
|
||||
public function on_generate_answers() {
|
||||
//add responses holder
|
||||
$qresponse_lid = new cc_response_lidtype();
|
||||
$this->qresponse_lid = $qresponse_lid;
|
||||
$this->qpresentation->set_response_lid($qresponse_lid);
|
||||
$qresponse_choice = new cc_assesment_render_choicetype();
|
||||
$qresponse_lid->set_render_choice($qresponse_choice);
|
||||
//Mark that question has more than one correct answer
|
||||
$qresponse_lid->set_rcardinality(cc_qti_values::Multiple);
|
||||
//are we to shuffle the responses?
|
||||
$shuffle_answers = (int)$this->quiz->nodeValue('/activity/quiz/shuffleanswers') > 0;
|
||||
$qresponse_choice->enable_shuffle($shuffle_answers);
|
||||
$answerlist = array();
|
||||
$qa_responses = $this->questions->nodeList('plugin_qtype_multichoice_question/answers/answer', $this->question_node);
|
||||
foreach ($qa_responses as $node) {
|
||||
$answer_content = $this->questions->nodeValue('answertext', $node);
|
||||
$answer_grade_fraction = (float)$this->questions->nodeValue('fraction', $node);
|
||||
$result = cc_helpers::process_linked_files( $answer_content,
|
||||
$this->manifest,
|
||||
$this->rootpath,
|
||||
$this->contextid,
|
||||
$this->outdir);
|
||||
$qresponse_label = cc_assesment_helper::add_answer( $qresponse_choice,
|
||||
$result[0],
|
||||
cc_qti_values::htmltype);
|
||||
pkg_resource_dependencies::instance()->add($result[1]);
|
||||
$answer_ident = $qresponse_label->get_ident();
|
||||
$feedback_ident = $answer_ident.'_fb';
|
||||
//add answer specific feedbacks if not empty
|
||||
$content = $this->questions->nodeValue('feedback', $node);
|
||||
if (!empty($content)) {
|
||||
$result = cc_helpers::process_linked_files( $content,
|
||||
$this->manifest,
|
||||
$this->rootpath,
|
||||
$this->contextid,
|
||||
$this->outdir);
|
||||
|
||||
|
||||
cc_assesment_helper::add_feedback( $this->qitem,
|
||||
$result[0],
|
||||
cc_qti_values::htmltype,
|
||||
$feedback_ident);
|
||||
|
||||
pkg_resource_dependencies::instance()->add($result[1]);
|
||||
|
||||
}
|
||||
$answerlist[$answer_ident] = array($feedback_ident, ($answer_grade_fraction > 0));
|
||||
}
|
||||
|
||||
$this->answerlist = $answerlist;
|
||||
|
||||
}
|
||||
|
||||
public function on_generate_feedbacks() {
|
||||
parent::on_generate_feedbacks();
|
||||
//Question combined feedbacks
|
||||
$correct_question_fb = $this->questions->nodeValue('plugin_qtype_multichoice_question/multichoice/correctfeedback', $this->question_node);
|
||||
$incorrect_question_fb = $this->questions->nodeValue('plugin_qtype_multichoice_question/multichoice/incorrectfeedback', $this->question_node);
|
||||
if (empty($correct_question_fb)) {
|
||||
//Hardcode some text for now
|
||||
$correct_question_fb = 'Well done!';
|
||||
}
|
||||
if (empty($incorrect_question_fb)) {
|
||||
//Hardcode some text for now
|
||||
$incorrect_question_fb = 'Better luck next time!';
|
||||
}
|
||||
|
||||
$proc = array('correct_fb' => $correct_question_fb, 'incorrect_fb' => $incorrect_question_fb);
|
||||
foreach ($proc as $ident => $content) {
|
||||
if (empty($content)) {
|
||||
continue;
|
||||
}
|
||||
$result = cc_helpers::process_linked_files( $content,
|
||||
$this->manifest,
|
||||
$this->rootpath,
|
||||
$this->contextid,
|
||||
$this->outdir);
|
||||
|
||||
cc_assesment_helper::add_feedback( $this->qitem,
|
||||
$result[0],
|
||||
cc_qti_values::htmltype,
|
||||
$ident);
|
||||
|
||||
pkg_resource_dependencies::instance()->add($result[1]);
|
||||
if ($ident == 'correct_fb') {
|
||||
$this->correct_feedbacks[$ident] = $ident;
|
||||
} else {
|
||||
$this->incorrect_feedbacks[$ident] = $ident;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function on_generate_response_processing() {
|
||||
parent::on_generate_response_processing();
|
||||
|
||||
//respconditions
|
||||
/**
|
||||
* General unconditional feedback must be added as a first respcondition
|
||||
* without any condition and just displayfeedback (if exists)
|
||||
*/
|
||||
cc_assesment_helper::add_respcondition( $this->qresprocessing,
|
||||
'General feedback',
|
||||
$this->general_feedback,
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
//success condition
|
||||
/**
|
||||
* For all question types outside of the Essay question, scoring is done in a
|
||||
* single <respcondition> with a continue flag set to No. The outcome is always
|
||||
* a variable named SCORE which value must be set to 100 in case of correct answer.
|
||||
* Partial scores (not 0 or 100) are not supported.
|
||||
*/
|
||||
$qrespcondition = new cc_assesment_respconditiontype();
|
||||
$qrespcondition->set_title('Correct');
|
||||
$this->qresprocessing->add_respcondition($qrespcondition);
|
||||
$qrespcondition->enable_continue(false);
|
||||
$qsetvar = new cc_assignment_setvartype(100);
|
||||
$qrespcondition->add_setvar($qsetvar);
|
||||
//define the condition for success
|
||||
$qconditionvar = new cc_assignment_conditionvar();
|
||||
$qrespcondition->set_conditionvar($qconditionvar);
|
||||
//create root and condition
|
||||
$qandcondition = new cc_assignment_conditionvar_andtype();
|
||||
$qconditionvar->set_and($qandcondition);
|
||||
foreach ($this->answerlist as $ident => $refid) {
|
||||
$qvarequal = new cc_assignment_conditionvar_varequaltype($ident);
|
||||
$qvarequal->enable_case();
|
||||
if ($refid[1]) {
|
||||
$qandcondition->set_varequal($qvarequal);
|
||||
} else {
|
||||
$qandcondition->set_not($qvarequal);
|
||||
}
|
||||
$qvarequal->set_respident($this->qresponse_lid->get_ident());
|
||||
}
|
||||
|
||||
$qdisplayfeedback = new cc_assignment_displayfeedbacktype();
|
||||
$qrespcondition->add_displayfeedback($qdisplayfeedback);
|
||||
$qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
|
||||
//TODO: this needs to be fixed
|
||||
reset($this->correct_feedbacks);
|
||||
$ident = key($this->correct_feedbacks);
|
||||
$qdisplayfeedback->set_linkrefid($ident);
|
||||
|
||||
|
||||
//rest of the conditions
|
||||
foreach ($this->answerlist as $ident => $refid) {
|
||||
cc_assesment_helper::add_response_condition( $this->qresprocessing,
|
||||
'Incorrect feedback',
|
||||
$refid[0],
|
||||
$this->general_feedback,
|
||||
$this->qresponse_lid->get_ident()
|
||||
);
|
||||
}
|
||||
|
||||
//Final element for incorrect feedback
|
||||
reset($this->incorrect_feedbacks);
|
||||
$ident = key($this->incorrect_feedbacks);
|
||||
cc_assesment_helper::add_respcondition( $this->qresprocessing,
|
||||
'Incorrect feedback',
|
||||
$ident,
|
||||
0
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
48
backup/cc/cc_lib/cc_converter_folder.php
Normal file
48
backup/cc/cc_lib/cc_converter_folder.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
/**
|
||||
* @package backup-convert
|
||||
* @subpackage cc-library
|
||||
* @copyright 2012 Darko Miletic <dmiletic@moodlerooms.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once 'cc_converters.php';
|
||||
require_once 'cc_general.php';
|
||||
|
||||
class cc_converter_folder extends cc_converter {
|
||||
|
||||
public function __construct(cc_i_item &$item, cc_i_manifest &$manifest, $rootpath, $path){
|
||||
$this->defaultfile = 'folder.xml';
|
||||
parent::__construct($item, $manifest, $rootpath, $path);
|
||||
}
|
||||
|
||||
public function convert($outdir) {
|
||||
$resitem = new cc_item();
|
||||
$resitem->title = $this->doc->nodeValue('/activity/folder/name');
|
||||
$this->item->add_child_item($resitem);
|
||||
|
||||
$contextid = $this->doc->nodeValue('/activity/@contextid');
|
||||
cc_helpers::handle_static_content($this->manifest,
|
||||
$this->rootpath,
|
||||
$contextid,
|
||||
$outdir);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,9 @@
|
||||
require_once 'cc_converters.php';
|
||||
require_once 'cc_general.php';
|
||||
require_once 'cc_asssesment.php';
|
||||
require_once 'cc_assesment_truefalse.php';
|
||||
require_once 'cc_assesment_essay.php';
|
||||
require_once 'cc_assesment_sfib.php';
|
||||
|
||||
class cc_converter_quiz extends cc_converter {
|
||||
|
||||
@ -59,6 +62,11 @@ class cc_converter_quiz extends cc_converter {
|
||||
$this->rootpath,
|
||||
$contextid,
|
||||
$outdir);
|
||||
if ($ndeps === false) {
|
||||
//No exportable questions in quizz or quizz has no questions
|
||||
//so just skip it
|
||||
return true;
|
||||
}
|
||||
//store any additional dependencies
|
||||
$deps = array_merge($result[1], $ndeps);
|
||||
|
||||
|
@ -52,6 +52,9 @@ class cc_converter_resource extends cc_converter {
|
||||
$resitem->title = $title;
|
||||
$this->item->add_child_item($resitem);
|
||||
|
||||
//checking the visibility
|
||||
$this->manifest->update_instructoronly($resvalue, !$this->is_visible());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -110,6 +110,21 @@ abstract class cc_converter {
|
||||
*/
|
||||
abstract public function convert($outdir);
|
||||
|
||||
/**
|
||||
*
|
||||
* Is the element visible in the course?
|
||||
* @throws RuntimeException
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_visible() {
|
||||
$tdoc = new XMLGenericDocument();
|
||||
if (!$tdoc->load($this->path . DIRECTORY_SEPARATOR . 'module.xml')) {
|
||||
throw new RuntimeException('File does not exist!');
|
||||
}
|
||||
$visible = (int)$tdoc->nodeValue('/module/visible');
|
||||
return ($visible > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Stores any files that need to be stored
|
||||
@ -120,6 +135,7 @@ abstract class cc_converter {
|
||||
if ( $doc->saveTo($rtp) ) {
|
||||
$resource = new cc_resource($rdir->rootdir(), $this->defaultname, $rdir->dirname(true));
|
||||
$resource->dependency = empty($deps) ? array() : $deps;
|
||||
$resource->instructoronly = !$this->is_visible();
|
||||
$res = $this->manifest->add_resource($resource, null, $this->cc_type);
|
||||
$resitem = new cc_item();
|
||||
$resitem->attach_resource($res[0]);
|
||||
|
@ -118,11 +118,9 @@ class cc_manifest extends XMLGenericDocument implements cc_i_manifest {
|
||||
"[@identifier='".
|
||||
$identifier.
|
||||
"']/imscc:file");
|
||||
$dnode = $this->doc->createElementNS($this->ccnamespaces['imscc'], "metadata");
|
||||
|
||||
$metanode->insertBefore($dnode,$metanode2);
|
||||
|
||||
$this->activemanifest->create_metadata_resource_node($met,$this->doc,$dnode);
|
||||
$nspaces = $this->activemanifest->get_cc_namespaces();
|
||||
$dnode = $this->append_new_element_ns($metanode2, $nspaces['imscc'], 'metadata');
|
||||
$this->activemanifest->create_metadata_resource_node($met, $this->doc, $dnode);
|
||||
}
|
||||
|
||||
|
||||
@ -147,7 +145,8 @@ class cc_manifest extends XMLGenericDocument implements cc_i_manifest {
|
||||
$filename.
|
||||
"']");
|
||||
|
||||
$dnode = $this->doc->createElementNS($this->ccnamespaces['imscc'], "metadata");
|
||||
$nspaces = $this->activemanifest->get_cc_namespaces();
|
||||
$dnode = $this->doc->createElementNS($nspaces['imscc'], "metadata");
|
||||
|
||||
$metanode->appendChild($dnode);
|
||||
|
||||
@ -240,24 +239,15 @@ class cc_manifest extends XMLGenericDocument implements cc_i_manifest {
|
||||
throw new Exception("Type invalid...");
|
||||
}
|
||||
|
||||
if (is_null($res)){
|
||||
if ($res == null){
|
||||
throw new Exception('Invalid Resource or dont give it');
|
||||
}
|
||||
$rst = null;
|
||||
|
||||
if (is_string($res)){
|
||||
$rst = new cc_resource($this->filePath(), $res);
|
||||
if (is_string($identifier)){
|
||||
$rst->identifier = $identifier;
|
||||
}
|
||||
} else {
|
||||
$rst = $res;
|
||||
}
|
||||
$rst = $res;
|
||||
|
||||
//TODO: This has to be reviewed since it does not handle properly mutiple file
|
||||
// dependencies
|
||||
if (is_object($identifier)) {
|
||||
$this->activemanifest->create_resource_node($rst,$this->doc,$identifier);
|
||||
$this->activemanifest->create_resource_node($rst, $this->doc, $identifier);
|
||||
} else {
|
||||
$nresnode = null;
|
||||
|
||||
@ -265,50 +255,32 @@ class cc_manifest extends XMLGenericDocument implements cc_i_manifest {
|
||||
if (!cc_helpers::is_html($rst->filename)) {
|
||||
$rst->href = null;
|
||||
}
|
||||
$this->activemanifest->create_resource_node($rst,$this->doc,$nresnode);
|
||||
|
||||
|
||||
for ($i = 1 ; $i < count ($rst->files); $i++){
|
||||
$ident = $this->get_identifier_by_filename($rst->files[$i]);
|
||||
if(empty($ident)){
|
||||
$newres = new cc_resource($rst->manifestroot,$rst->files[$i],false);
|
||||
if (!empty($newres)) {
|
||||
if (!cc_helpers::is_html($rst->files[$i])) {
|
||||
$newres->href = null;
|
||||
}
|
||||
$newres->type = 'webcontent';
|
||||
$this->activemanifest->create_resource_node($newres,$this->doc,$nresnode);
|
||||
$this->activemanifest->create_resource_node($rst, $this->doc, $nresnode);
|
||||
foreach ($rst->files as $file) {
|
||||
$ident = $this->get_identifier_by_filename($file);
|
||||
if($ident == null){
|
||||
$newres = new cc_resource($rst->manifestroot, $file);
|
||||
if (!cc_helpers::is_html($file)) {
|
||||
$newres->href = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
foreach ($this->activemanifest->resources as $k => $v){
|
||||
($k);
|
||||
$depen = $this->check_if_exist_in_other($v->files[0]);
|
||||
if (!empty($depen)){
|
||||
$this->replace_file_x_dependency($depen,$v->files[0]);
|
||||
// coloca aca como type = webcontent porque son archivos dependientes
|
||||
// quizas aqui habria q ver de que type es el que vino y segun eso, ponerlo
|
||||
// en associatedcontent o en webcontent
|
||||
$v->type = 'webcontent';
|
||||
$newres->type = 'webcontent';
|
||||
$this->activemanifest->create_resource_node($newres, $this->doc, $nresnode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$tmparray = array($rst->identifier,$rst->files[0]);
|
||||
$tmparray = array($rst->identifier, $rst->files[0]);
|
||||
return $tmparray;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function check_if_exist_in_other($name){
|
||||
private function check_if_exist_in_other($name, $identifier){
|
||||
$status = array();
|
||||
foreach ($this->activemanifest->resources as $key => $value){
|
||||
($key);
|
||||
for ($i=1; $i< count($value->files); $i++){
|
||||
if ($name == $value->files[$i]){
|
||||
array_push($status,$value->identifier);
|
||||
}
|
||||
foreach ($this->activemanifest->resources as $value){
|
||||
if (($value->identifier != $identifier) && isset($value->files[$name])) {
|
||||
$status[] = $value->identifier;
|
||||
}
|
||||
}
|
||||
return $status;
|
||||
@ -332,11 +304,8 @@ class cc_manifest extends XMLGenericDocument implements cc_i_manifest {
|
||||
|
||||
private function get_identifier_by_filename($name){
|
||||
$result = null;
|
||||
foreach ($this->activemanifest->resources as $key => $value) {
|
||||
if ($name == $value->files[0]){
|
||||
$result = $key;
|
||||
break;
|
||||
}
|
||||
if (isset($this->activemanifest->resources_ind[$name])) {
|
||||
$result = $this->activemanifest->resources_ind[$name];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
@ -353,6 +322,12 @@ class cc_manifest extends XMLGenericDocument implements cc_i_manifest {
|
||||
|
||||
}
|
||||
|
||||
public function update_instructoronly($identifier, $value = false) {
|
||||
if (isset($this->activemanifest->resources[$identifier])) {
|
||||
$resource = $this->activemanifest->resources[$identifier];
|
||||
$resource->instructoronly = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the resources nodes in the Manifest
|
||||
@ -365,12 +340,31 @@ class cc_manifest extends XMLGenericDocument implements cc_i_manifest {
|
||||
"']/imscc:resources";
|
||||
$resnode = $this->node($resnodestr);
|
||||
|
||||
foreach ($this->activemanifest->resources as $key => $node) {
|
||||
($key);
|
||||
$resnode->appendChild($this->activemanifest->create_resource_node($node,$this->doc,null));
|
||||
foreach ($this->activemanifest->resources as $k => $v){
|
||||
($k);
|
||||
$depen = $this->check_if_exist_in_other($v->files[0], $v->identifier);
|
||||
if (!empty($depen)){
|
||||
$this->replace_file_x_dependency($depen,$v->files[0]);
|
||||
// coloca aca como type = webcontent porque son archivos dependientes
|
||||
// quizas aqui habria q ver de que type es el que vino y segun eso, ponerlo
|
||||
// en associatedcontent o en webcontent
|
||||
$v->type = 'webcontent';
|
||||
}
|
||||
}
|
||||
return $resnode;
|
||||
|
||||
foreach ($this->activemanifest->resources as $node) {
|
||||
$rnode = $this->activemanifest->create_resource_node($node, $this->doc, null);
|
||||
$resnode->appendChild($rnode);
|
||||
if ($node->instructoronly) {
|
||||
$metafileceduc = new cc_metadata_resouce_educational();
|
||||
$metafileceduc->set_value(intended_user_role::INSTRUCTOR);
|
||||
$metafile = new cc_metadata_resouce();
|
||||
$metafile->add_metadata_resource_educational($metafileceduc);
|
||||
$this->activemanifest->create_metadata_educational($metafile, $this->doc, $rnode);
|
||||
}
|
||||
}
|
||||
|
||||
return $resnode;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ class page11_resurce_file extends general_cc_file {
|
||||
protected $intro = null;
|
||||
|
||||
public function set_content($value) {
|
||||
//we are not cleaning up this one on purporse.
|
||||
$this->content = $value;
|
||||
}
|
||||
|
||||
|
@ -94,6 +94,7 @@ class cc_resource implements cc_i_resource {
|
||||
public $isempty = null;
|
||||
public $manifestroot = null;
|
||||
public $folder = null;
|
||||
public $instructoronly = false;
|
||||
|
||||
private $throwonerror = true;
|
||||
|
||||
|
@ -271,7 +271,7 @@ abstract class cc_helpers {
|
||||
$outdir);
|
||||
$replaceprefix = $webcontent ? '' : '$IMS-CC-FILEBASE$';
|
||||
foreach ($lfiles as $lfile) {
|
||||
if (array_key_exists($lfile, $files)) {
|
||||
if (isset($files[$lfile])) {
|
||||
$filename = str_replace('%2F', '/',rawurlencode($lfile));
|
||||
$content = str_replace('@@PLUGINFILE@@'.$filename,
|
||||
$replaceprefix.'../'.$files[$lfile][1],
|
||||
@ -413,11 +413,7 @@ class pkg_static_resources {
|
||||
}
|
||||
|
||||
public function get_identifier($location) {
|
||||
$result = false;
|
||||
if (array_key_exists($location, $this->values)) {
|
||||
$result = $this->values[$location];
|
||||
}
|
||||
return $result;
|
||||
return isset($this->values[$location]) ? $this->values[$location] : false;
|
||||
}
|
||||
|
||||
public function reset() {
|
||||
|
@ -96,10 +96,8 @@ class cc_version1 extends cc_version_base {
|
||||
|
||||
//add all namespaces
|
||||
foreach ($this->ccnamespaces as $key => $value) {
|
||||
if ($key != 'lom' ){
|
||||
$dummy_attr = $key.":dummy";
|
||||
$doc->createAttributeNS($value,$dummy_attr);
|
||||
}
|
||||
$dummy_attr = $key.":dummy";
|
||||
$doc->createAttributeNS($value,$dummy_attr);
|
||||
}
|
||||
|
||||
// add location of schemas
|
||||
@ -237,6 +235,7 @@ class cc_version1 extends cc_version_base {
|
||||
$dnode->appendChild($nd);
|
||||
}
|
||||
$this->resources[$res->identifier] = $res;
|
||||
$this->resources_ind[$res->files[0]] = $res->identifier;
|
||||
|
||||
foreach ($res->dependency as $dependency){
|
||||
$nd = $doc->createElementNS($this->ccnamespaces['imscc'],'dependency');
|
||||
@ -543,7 +542,7 @@ class cc_version1 extends cc_version_base {
|
||||
* @param object $xmlnode
|
||||
* @return DOMNode
|
||||
*/
|
||||
protected function create_metadata_educational ($met,DOMDocument &$doc, $xmlnode){
|
||||
public function create_metadata_educational ($met,DOMDocument &$doc, $xmlnode){
|
||||
$nd = $doc->createElementNS($this->ccnamespaces['lom'],'educational');
|
||||
$nd2 = $doc->createElementNS($this->ccnamespaces['lom'],'intendedEndUserRole');
|
||||
$nd3 = $doc->createElementNS($this->ccnamespaces['voc'],'vocabulary');
|
||||
|
@ -90,4 +90,33 @@ class cc_version11 extends cc_version1 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Education Metadata (How To)
|
||||
*
|
||||
* @param object $met
|
||||
* @param DOMDocument $doc
|
||||
* @param object $xmlnode
|
||||
* @return DOMNode
|
||||
*/
|
||||
public function create_metadata_educational ($met, DOMDocument &$doc, $xmlnode){
|
||||
$metadata = $doc->createElementNS($this->ccnamespaces['imscc'] ,'metadata');
|
||||
$xmlnode->insertBefore($metadata, $xmlnode->firstChild);
|
||||
$lom = $doc->createElementNS($this->ccnamespaces['lom'] ,'lom');
|
||||
$metadata->appendChild($lom);
|
||||
$educational = $doc->createElementNS($this->ccnamespaces['lom'] ,'educational');
|
||||
$lom->appendChild($educational);
|
||||
|
||||
foreach ($met->arrayeducational as $name => $value) {
|
||||
!is_array($value)?$value =array($value):null;
|
||||
foreach ($value as $v){
|
||||
$userrole = $doc->createElementNS($this->ccnamespaces['lom'],'intendedEndUserRole');
|
||||
$educational->appendChild($userrole);
|
||||
$nd4 = $doc->createElementNS($this->ccnamespaces['lom'], 'source', 'IMSGLC_CC_Rolesv1p1');
|
||||
$nd5 = $doc->createElementNS($this->ccnamespaces['lom'], 'value', $v[0]);
|
||||
$userrole->appendChild($nd4);
|
||||
$userrole->appendChild($nd5);
|
||||
}
|
||||
}
|
||||
return $metadata;
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ abstract class cc_version_base {
|
||||
protected $manifestID = null;
|
||||
protected $organizationid = null;
|
||||
public $resources = null;
|
||||
public $resources_ind = null;
|
||||
protected $metadata = null;
|
||||
public $organizations = null;
|
||||
protected $base = null;
|
||||
|
@ -51,62 +51,25 @@ function is_url($url) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
function GetDepFiles($manifestroot, $fname,$folder,&$filenames) {
|
||||
$extension = pathinfo($fname, PATHINFO_EXTENSION);
|
||||
$filenames = array();
|
||||
$dcx = new XMLGenericDocument();
|
||||
$result = true;
|
||||
|
||||
switch ($extension){
|
||||
case 'xml':
|
||||
$result = @$dcx->loadXMLFile($manifestroot.$folder.$fname);
|
||||
if (!$result) {
|
||||
$result = @$dcx->loadXMLFile($manifestroot.DIRECTORY_SEPARATOR.$folder.DIRECTORY_SEPARATOR.$fname);
|
||||
}
|
||||
GetDepFilesXML($manifestroot, $fname,$filenames,$dcx, $folder);
|
||||
break;
|
||||
case 'html':
|
||||
case 'htm':
|
||||
$result = @$dcx->loadHTMLFile($manifestroot.$folder.$fname);
|
||||
if (!$result) {
|
||||
$result = @$dcx->loadHTMLFile($manifestroot.DIRECTORY_SEPARATOR.$folder.DIRECTORY_SEPARATOR.$fname);
|
||||
}
|
||||
GetDepFilesHTML($manifestroot, $fname,$filenames,$dcx, $folder);
|
||||
break;
|
||||
function GetDepFiles($manifestroot, $fname, $folder, &$filenames) {
|
||||
static $types = array('xhtml' => true, 'html' => true, 'htm' => true);
|
||||
$extension = strtolower(trim(pathinfo($fname, PATHINFO_EXTENSION)));
|
||||
$filenames = array();
|
||||
if (isset($types[$extension])) {
|
||||
$dcx = new XMLGenericDocument();
|
||||
$filename = $manifestroot.$folder.$fname;
|
||||
if (!file_exists($filename)) {
|
||||
$filename = $manifestroot.DIRECTORY_SEPARATOR.$folder.DIRECTORY_SEPARATOR.$fname;
|
||||
}
|
||||
if (file_exists($filename)) {
|
||||
$res = $dcx->loadHTMLFile($filename);
|
||||
if ($res) {
|
||||
GetDepFilesHTML($manifestroot, $fname, $filenames, $dcx, $folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function GetDepFilesXML ($manifestroot, $fname,&$filenames,&$dcx, $folder){
|
||||
$nlist = $dcx->nodeList("//img/@src | //attachments/attachment/@href | //link/@href | //script/@src");
|
||||
$css_obj_array = array();
|
||||
foreach ($nlist as $nl) {
|
||||
$item = $folder.$nl->nodeValue;
|
||||
$path_parts = pathinfo($item);
|
||||
$fname = $path_parts['basename'];
|
||||
$ext = array_key_exists('extension',$path_parts) ? $path_parts['extension'] : '';
|
||||
if (!is_url($nl->nodeValue)) {
|
||||
//$file = $folder.$nl->nodeValue; // DEPENDERA SI SE QUIERE Q SEA RELATIVO O ABSOLUTO
|
||||
$file = $nl->nodeValue;
|
||||
toNativePath($file);
|
||||
$filenames[]=$file;
|
||||
}
|
||||
}
|
||||
$dcx->registerNS('qti','http://www.imsglobal.org/xsd/imscc/ims_qtiasiv1p2.xsd');
|
||||
$dcx->resetXpath();
|
||||
$nlist = $dcx->nodeList("//qti:mattext | //text");
|
||||
$dcx2 = new XMLGenericDocument();
|
||||
foreach ($nlist as $nl) {
|
||||
if ($dcx2->loadString($nl->nodeValue)){
|
||||
GetDepFilesHTML($manifestroot,$fname,$filenames,$dcx2,$folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function GetDepFilesHTML ($manifestroot, $fname, &$filenames, &$dcx, $folder){
|
||||
$dcx->resetXpath();
|
||||
$nlist = $dcx->nodeList("//img/@src | //link/@href | //script/@src | //a[not(starts-with(@href,'#'))]/@href");
|
||||
@ -121,7 +84,7 @@ function GetDepFilesHTML ($manifestroot, $fname, &$filenames, &$dcx, $folder){
|
||||
$file = fullPath($path,"/");
|
||||
toNativePath($file);
|
||||
if (file_exists($manifestroot.DIRECTORY_SEPARATOR.$file)) {
|
||||
$filenames[]= $file;
|
||||
$filenames[$file]= $file;
|
||||
}
|
||||
}
|
||||
if ($ext == 'css') {
|
||||
@ -138,10 +101,12 @@ function GetDepFilesHTML ($manifestroot, $fname, &$filenames, &$dcx, $folder){
|
||||
$limg = $cssobj->Get($item,"list-style-image");
|
||||
$npath = pathinfo($csskey);
|
||||
if ((!empty($bimg))&& ($bimg != 'none')) {
|
||||
$filenames[] = stripUrl($bimg,$npath['dirname'].'/');
|
||||
$value = stripUrl($bimg,$npath['dirname'].'/');
|
||||
$filenames[$value] = $value;
|
||||
} else
|
||||
if ((!empty($limg))&& ($limg != 'none')) {
|
||||
$filenames[] = stripUrl($limg,$npath['dirname'].'/');
|
||||
$value = stripUrl($limg,$npath['dirname'].'/');
|
||||
$filenames[$value] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -157,10 +122,12 @@ function GetDepFilesHTML ($manifestroot, $fname, &$filenames, &$dcx, $folder){
|
||||
$sbl = $cssobj->Get($elem,"list-style-image");
|
||||
$npath = pathinfo($csskey);
|
||||
if ((!empty($sb)) && ($sb != 'none')) {
|
||||
$filenames[] = stripUrl($sb,$npath['dirname'].'/');
|
||||
$value = stripUrl($sb,$npath['dirname'].'/');
|
||||
$filenames[$value] = $value;
|
||||
} else
|
||||
if ((!empty($sbl)) && ($sbl != 'none')) {
|
||||
$filenames[] = stripUrl($sbl,$npath['dirname'].'/');
|
||||
$value = stripUrl($sbl,$npath['dirname'].'/');
|
||||
$filenames[$value] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ class XMLGenericDocument {
|
||||
private $arrayPrefixNS = array();
|
||||
private $is_html = false;
|
||||
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @return string
|
||||
|
@ -83,9 +83,7 @@ class entities {
|
||||
|
||||
public function update_sources ($html, $root_path = '') {
|
||||
|
||||
$document = new DOMDocument();
|
||||
|
||||
@$document->loadHTML($html);
|
||||
$document = $this->load_html($html);
|
||||
|
||||
$tags = array('img' => 'src' , 'a' => 'href');
|
||||
|
||||
@ -108,7 +106,7 @@ class entities {
|
||||
}
|
||||
}
|
||||
|
||||
$html = $this->clear_doctype($document->saveHTML());
|
||||
$html = $this->html_insidebody($document);
|
||||
|
||||
return $html;
|
||||
}
|
||||
@ -159,8 +157,7 @@ class entities {
|
||||
|
||||
public function include_titles ($html) {
|
||||
|
||||
$document = new DOMDocument();
|
||||
@$document->loadHTML($html);
|
||||
$document = $this->load_html($html);
|
||||
|
||||
$images = $document->getElementsByTagName('img');
|
||||
|
||||
@ -180,7 +177,7 @@ class entities {
|
||||
$image->setAttribute('title', $title);
|
||||
}
|
||||
|
||||
$html = $this->clear_doctype($document->saveHTML());
|
||||
$html = $this->html_insidebody($document);
|
||||
|
||||
return $html;
|
||||
}
|
||||
@ -289,13 +286,36 @@ class entities {
|
||||
|
||||
}
|
||||
|
||||
private function clear_doctype ($html) {
|
||||
/**
|
||||
* @param string $html
|
||||
* @return DOMDocument
|
||||
*/
|
||||
private function load_html($html) {
|
||||
// Need to make sure that the html passed has charset meta tag.
|
||||
$metatag = '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
|
||||
if (strpos($html, $metatag) === false) {
|
||||
$html = '<html><head>'.$metatag.'</head><body>'.$html.'</body></html>';
|
||||
}
|
||||
|
||||
return preg_replace('/^<!DOCTYPE.+?>/',
|
||||
'',
|
||||
str_replace(array('<html>' , '</html>' , '<body>' , '</body>'),
|
||||
array('' , '' , '' , ''),
|
||||
$html));
|
||||
$document = new DOMDocument();
|
||||
@$document->loadHTML($html);
|
||||
|
||||
return $document;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMDocument $domdocument
|
||||
* @return string
|
||||
*/
|
||||
private function html_insidebody($domdocument) {
|
||||
$html = '';
|
||||
$bodyitems = $domdocument->getElementsByTagName('body');
|
||||
if ($bodyitems->length > 0) {
|
||||
$body = $bodyitems->item(0);
|
||||
$html = str_ireplace(array('<body>', '</body>'), '', $body->C14N());
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public function generate_random_string ($length = 6) {
|
||||
|
@ -653,8 +653,9 @@ class cc_quiz extends entities {
|
||||
|
||||
$question_cc_type = $this->get_question_type($identifier, $assessment);
|
||||
$question_cc_type = $question_cc_type['cc'];
|
||||
$is_multiresponse = ($question_cc_type == CC_QUIZ_MULTIPLE_RESPONSE);
|
||||
|
||||
if ($question_cc_type == CC_QUIZ_MULTIPLE_CHOICE || $question_cc_type == CC_QUIZ_MULTIPLE_RESPONSE || $question_cc_type == CC_QUIZ_TRUE_FALSE) {
|
||||
if ($question_cc_type == CC_QUIZ_MULTIPLE_CHOICE || $is_multiresponse || $question_cc_type == CC_QUIZ_TRUE_FALSE) {
|
||||
|
||||
$query_answers = '//xmlns:item[@ident="' . $identifier . '"]/xmlns:presentation/xmlns:response_lid/xmlns:render_choice/xmlns:response_label';
|
||||
$query_answers_with_flow = '//xmlns:item[@ident="' . $identifier . '"]/xmlns:presentation/xmlns:flow/xmlns:response_lid/xmlns:render_choice/xmlns:response_label';
|
||||
@ -704,7 +705,19 @@ class cc_quiz extends entities {
|
||||
}
|
||||
|
||||
if (!empty($response_items)) {
|
||||
|
||||
if ($is_multiresponse) {
|
||||
$correct_answer_score = 0;
|
||||
//get the correct answers count
|
||||
$canswers_query = "//xmlns:item[@ident='{$identifier}']//xmlns:setvar[@varname='SCORE'][.=100]/../xmlns:conditionvar//xmlns:varequal[@case='Yes'][not(parent::xmlns:not)]";
|
||||
$canswers = $xpath->query($canswers_query);
|
||||
if ($canswers->length > 0) {
|
||||
$correct_answer_score = round(1.0 / (float)$canswers->length, 7); //weird
|
||||
$correct_answers_ident = array();
|
||||
foreach ($canswers as $cnode) {
|
||||
$correct_answers_ident[$cnode->nodeValue] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($response_items as $response_item) {
|
||||
|
||||
$last_answer_id++;
|
||||
@ -719,6 +732,10 @@ class cc_quiz extends entities {
|
||||
|
||||
$answer_score = $this->get_score($assessment, $answer_identifier, $identifier);
|
||||
|
||||
if ($is_multiresponse && isset($correct_answers_ident[$answer_identifier])) {
|
||||
$answer_score = $correct_answer_score;
|
||||
}
|
||||
|
||||
$answers[] = array('id' => $last_answer_id,
|
||||
'title' => $answer_title,
|
||||
'score' => $answer_score,
|
||||
@ -757,7 +774,7 @@ class cc_quiz extends entities {
|
||||
}
|
||||
}
|
||||
|
||||
$score = empty($score) ? 0 : $score;
|
||||
$score = empty($score) ? 0 : sprintf("%.7F", $score);
|
||||
|
||||
return $score;
|
||||
}
|
||||
|
@ -304,8 +304,9 @@ class cc11_quiz extends entities11 {
|
||||
$question_type_node = ($question_moodle_type == MOODLE_QUIZ_ESSAY) ? $this->create_node_course_question_categories_question_category_question_eesay($question) : $question_type_node;
|
||||
$question_type_node = ($question_moodle_type == MOODLE_QUIZ_SHORTANSWER) ? $this->create_node_course_question_categories_question_category_question_shortanswer($question) : $question_type_node;
|
||||
|
||||
$questionname = !empty($question['name']) ? self::safexml($question['name']) : self::safexml($this->truncate_text($question['title'], 255, true));
|
||||
$replace_values = array($question['id'],
|
||||
self::safexml($this->truncate_text($question['title'], 255, true)),
|
||||
$questionname,
|
||||
self::safexml($question['title']),
|
||||
$question_moodle_type,
|
||||
self::safexml($question['feedback']),
|
||||
@ -365,7 +366,12 @@ class cc11_quiz extends entities11 {
|
||||
$question_title = $this->update_sources($question_title, $root_path);
|
||||
$question_title = !empty($question_title) ? str_replace("%24", "\$", $this->include_titles($question_title)) : '';
|
||||
|
||||
// This attribute is not IMSCC spec, but it is included in Moodle 2.x export of IMS1.1
|
||||
$questionname = $xpath->query('@title', $question_item);
|
||||
$questionname = !empty($questionname->item(0)->nodeValue) ? $questionname->item(0)->nodeValue : '';
|
||||
|
||||
$questions[$question_identifier]['title'] = $question_title;
|
||||
$questions[$question_identifier]['name'] = $questionname;
|
||||
$questions[$question_identifier]['identifier'] = $question_identifier;
|
||||
$questions[$question_identifier]['moodle_type'] = $question_type['moodle'];
|
||||
$questions[$question_identifier]['cc_type'] = $question_type['cc'];
|
||||
@ -507,63 +513,90 @@ class cc11_quiz extends entities11 {
|
||||
|
||||
$xpath = cc112moodle::newx_path($assessment, cc112moodle::getquizns());
|
||||
|
||||
$answers_fib = array();
|
||||
$correctanswersfib = array();
|
||||
$incorrectanswersfib = array();
|
||||
|
||||
$response_items = $xpath->query('//xmlns:item[@ident="' . $question_identifier . '"]/xmlns:resprocessing/xmlns:respcondition');
|
||||
|
||||
$correctrespcond = $xpath->query('//xmlns:item[@ident="' . $question_identifier . '"]/xmlns:resprocessing/xmlns:respcondition/xmlns:setvar[text()="100"]/..');
|
||||
$correctanswers = $xpath->query('xmlns:conditionvar/xmlns:varequal', $correctrespcond->item(0));
|
||||
|
||||
// Correct answers.
|
||||
foreach ($correctanswers as $correctans) {
|
||||
$answertitle = !empty($correctans->nodeValue) ? $correctans->nodeValue : '';
|
||||
if (empty($answertitle)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$last_answer_id++;
|
||||
|
||||
$correctanswersfib[$answertitle] = array(
|
||||
'id' => $last_answer_id,
|
||||
'title' => $answertitle,
|
||||
'score' => 1,
|
||||
'feedback' => '',
|
||||
'case' => 0);
|
||||
}
|
||||
|
||||
// Handle incorrect answers and feedback for all items.
|
||||
foreach ($response_items as $response_item) {
|
||||
|
||||
$setvar = $xpath->query('xmlns:setvar', $response_item);
|
||||
$setvar = is_object($setvar->item(0)) ? $setvar->item(0)->nodeValue : '';
|
||||
if (!empty($setvar->length) && $setvar->item(0)->nodeValue == '100') {
|
||||
// Skip the correct answer responsecondition.
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($setvar != '') {
|
||||
$varequal = $xpath->query('xmlns:conditionvar/xmlns:varequal', $response_item);
|
||||
if (empty($varequal->length)) {
|
||||
// Skip respcondition elements that don't have varequal containing an answer
|
||||
continue;
|
||||
}
|
||||
$answer_title = !empty($varequal->item(0)->nodeValue) ? $varequal->item(0)->nodeValue : '';
|
||||
|
||||
$display_feedback = $xpath->query('xmlns:displayfeedback', $response_item);
|
||||
|
||||
unset($feedbacks_identifiers);
|
||||
|
||||
if (!empty($display_feedback)) {
|
||||
|
||||
foreach ($display_feedback as $feedback) {
|
||||
|
||||
$feedback_identifier = $feedback->getAttributeNode('linkrefid');
|
||||
$feedback_identifier = !empty($feedback_identifier->nodeValue) ? $feedback_identifier->nodeValue : '';
|
||||
|
||||
if (!empty($feedback_identifier)) {
|
||||
$feedbacks_identifiers[] = $feedback_identifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$feedback = '';
|
||||
$feedbacks_identifiers = empty($feedbacks_identifiers) ? '' : $feedbacks_identifiers;
|
||||
|
||||
if (!empty($feedbacks_identifiers)) {
|
||||
foreach ($feedbacks_identifiers as $feedback_identifier) {
|
||||
$feedbacks = $xpath->query('//xmlns:item[@ident="' . $question_identifier . '"]/xmlns:itemfeedback[@ident="' . $feedback_identifier . '"]/xmlns:flow_mat/xmlns:material/xmlns:mattext');
|
||||
$feedback .= !empty($feedbacks->item(0)->nodeValue) ? $feedbacks->item(0)->nodeValue . ' ' : '';
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists($answer_title, $correctanswersfib)) {
|
||||
// Already a correct answer, just need the feedback for the correct answer.
|
||||
$correctanswerfib[$answer_title]['feedback'] = $feedback;
|
||||
} else {
|
||||
// Need to add an incorrect answer.
|
||||
$last_answer_id++;
|
||||
|
||||
$answer_title = $xpath->query('xmlns:conditionvar/xmlns:varequal[@respident="' . $identifier . '"]', $response_item);
|
||||
$answer_title = !empty($answer_title->item(0)->nodeValue) ? $answer_title->item(0)->nodeValue : '';
|
||||
|
||||
$case = $xpath->query('xmlns:conditionvar/xmlns:varequal/@case', $response_item);
|
||||
$case = is_object($case->item(0)) ? $case->item(0)->nodeValue : 'no'
|
||||
;
|
||||
$case = strtolower($case) == 'yes' ? 1 :
|
||||
0;
|
||||
|
||||
$display_feedback = $xpath->query('xmlns:displayfeedback', $response_item);
|
||||
|
||||
unset($feedbacks_identifiers);
|
||||
|
||||
if (!empty($display_feedback)) {
|
||||
|
||||
foreach ($display_feedback as $feedback) {
|
||||
|
||||
$feedback_identifier = $feedback->getAttributeNode('linkrefid');
|
||||
$feedback_identifier = !empty($feedback_identifier->nodeValue) ? $feedback_identifier->nodeValue : '';
|
||||
|
||||
if (!empty($feedback_identifier)) {
|
||||
$feedbacks_identifiers[] = $feedback_identifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$feedback = '';
|
||||
$feedbacks_identifiers = empty($feedbacks_identifiers) ? '' : $feedbacks_identifiers;
|
||||
|
||||
if (!empty($feedbacks_identifiers)) {
|
||||
foreach ($feedbacks_identifiers as $feedback_identifier) {
|
||||
$feedbacks = $xpath->query('//xmlns:item[@ident="' . $question_identifier . '"]/xmlns:itemfeedback[@ident="' . $feedback_identifier . '"]/xmlns:flow_mat/xmlns:material/xmlns:mattext');
|
||||
$feedback .= !empty($feedbacks->item(0)->nodeValue) ? $feedbacks->item(0)->nodeValue . ' ' : '';
|
||||
}
|
||||
}
|
||||
|
||||
$answers_fib[] = array('id' => $last_answer_id,
|
||||
'title' => $answer_title,
|
||||
'score' => $setvar,
|
||||
'feedback' => $feedback,
|
||||
'case' => $case);
|
||||
$incorrectanswersfib[] = array(
|
||||
'id' => $last_answer_id,
|
||||
'title' => $answer_title,
|
||||
'score' => 0,
|
||||
'feedback' => $feedback,
|
||||
'case' => 0);
|
||||
}
|
||||
}
|
||||
|
||||
$answers_fib = array_merge($correctanswersfib, $incorrectanswersfib);
|
||||
$answers_fib = empty($answers_fib) ? '' : $answers_fib;
|
||||
|
||||
return $answers_fib;
|
||||
@ -653,8 +686,9 @@ class cc11_quiz extends entities11 {
|
||||
|
||||
$question_cc_type = $this->get_question_type($identifier, $assessment);
|
||||
$question_cc_type = $question_cc_type['cc'];
|
||||
$is_multiresponse = ($question_cc_type == CC_QUIZ_MULTIPLE_RESPONSE);
|
||||
|
||||
if ($question_cc_type == CC_QUIZ_MULTIPLE_CHOICE || $question_cc_type == CC_QUIZ_MULTIPLE_RESPONSE || $question_cc_type == CC_QUIZ_TRUE_FALSE) {
|
||||
if ($question_cc_type == CC_QUIZ_MULTIPLE_CHOICE || $is_multiresponse || $question_cc_type == CC_QUIZ_TRUE_FALSE) {
|
||||
|
||||
$query_answers = '//xmlns:item[@ident="' . $identifier . '"]/xmlns:presentation/xmlns:response_lid/xmlns:render_choice/xmlns:response_label';
|
||||
$query_answers_with_flow = '//xmlns:item[@ident="' . $identifier . '"]/xmlns:presentation/xmlns:flow/xmlns:response_lid/xmlns:render_choice/xmlns:response_label';
|
||||
@ -705,6 +739,20 @@ class cc11_quiz extends entities11 {
|
||||
|
||||
if (!empty($response_items)) {
|
||||
|
||||
if ($is_multiresponse) {
|
||||
$correct_answer_score = 0;
|
||||
//get the correct answers count
|
||||
$canswers_query = "//xmlns:item[@ident='{$identifier}']//xmlns:setvar[@varname='SCORE'][.=100]/../xmlns:conditionvar//xmlns:varequal[@case='Yes'][not(parent::xmlns:not)]";
|
||||
$canswers = $xpath->query($canswers_query);
|
||||
if ($canswers->length > 0) {
|
||||
$correct_answer_score = round(1.0 / (float)$canswers->length, 7); //weird
|
||||
$correct_answers_ident = array();
|
||||
foreach ($canswers as $cnode) {
|
||||
$correct_answers_ident[$cnode->nodeValue] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($response_items as $response_item) {
|
||||
|
||||
$last_answer_id++;
|
||||
@ -719,6 +767,10 @@ class cc11_quiz extends entities11 {
|
||||
|
||||
$answer_score = $this->get_score($assessment, $answer_identifier, $identifier);
|
||||
|
||||
if ($is_multiresponse && isset($correct_answers_ident[$answer_identifier])) {
|
||||
$answer_score = $correct_answer_score;
|
||||
}
|
||||
|
||||
$answers[] = array('id' => $last_answer_id,
|
||||
'title' => $answer_title,
|
||||
'score' => $answer_score,
|
||||
@ -757,7 +809,8 @@ class cc11_quiz extends entities11 {
|
||||
}
|
||||
}
|
||||
|
||||
$score = empty($score) ? 0 : $score;
|
||||
// This method (get_score) is only used by T/F & M/C questions in CC, therefore it's either 0 or 1 in Moodle.
|
||||
$score = empty($score) ? "0.0000000" : '1.0000000';
|
||||
|
||||
return $score;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<MOD>
|
||||
<ID>[#mod_instance#]</ID>
|
||||
<MODTYPE>forum</MODTYPE>
|
||||
<TYPE>news</TYPE>
|
||||
<TYPE>general</TYPE>
|
||||
<NAME>[#mod_forum_title#]</NAME>
|
||||
<INTRO>[#mod_forum_intro#]</INTRO>
|
||||
<ASSESSED>0</ASSESSED>
|
||||
|
@ -44,7 +44,7 @@ class imscc1_converter extends base_converter {
|
||||
if (!empty($manifest)) {
|
||||
// looks promising, lets load some information
|
||||
$handle = fopen($manifest, 'r');
|
||||
$xml_snippet = fread($handle, 500);
|
||||
$xml_snippet = fread($handle, 1024);
|
||||
fclose($handle);
|
||||
|
||||
// check if it has the required strings
|
||||
|
@ -45,7 +45,7 @@ class imscc11_converter extends base_converter {
|
||||
if (file_exists($manifest)) {
|
||||
// looks promising, lets load some information
|
||||
$handle = fopen($manifest, 'r');
|
||||
$xml_snippet = fread($handle, 500);
|
||||
$xml_snippet = fread($handle, 1024);
|
||||
fclose($handle);
|
||||
|
||||
// check if it has the required strings
|
||||
|
Loading…
x
Reference in New Issue
Block a user