MDL-23450 moving mod/hotpot to contrib for now, because it is not ready for Moodle 2.0 yet
This commit is contained in:
@@ -1,87 +0,0 @@
|
||||
==================================================
|
||||
This is v2.4.2 of the HotPot module for Moodle 1.9
|
||||
==================================================
|
||||
|
||||
This module allows teachers to administer Hot Potatoes and TexToys quizzes via Moodle.
|
||||
It has been tested on:
|
||||
- Hot Potatoes 6
|
||||
- Moodle 1.9
|
||||
- PHP 4.1 thru 5.2
|
||||
- MySQL 4.x thru 5.0
|
||||
- PostgreSQL 7.3 thru 8.2
|
||||
|
||||
This module may be distributed under the terms of the General Public License
|
||||
(see http://www.gnu.org/licenses/gpl.txt for details)
|
||||
|
||||
This software is provided "AS IS" without a warranty of any kind.
|
||||
|
||||
Sponsors who have generously contributed to the development of this software:
|
||||
- Agencia de Gestio d'Ajuts Universitaris i de Recerca (AGAUR),
|
||||
Autonomous Government of Catalonia, Spain
|
||||
(via Josep M. Fontana, Universitat Pompeu Fabra)
|
||||
- Rikkyo Univeristy, Japan (via Paul Allum)
|
||||
- Universite de Franche-Comte, France (via Glenys Hanson)
|
||||
|
||||
|
||||
================
|
||||
IMPORTANT NOTICE
|
||||
================
|
||||
* Please be sure to use Hot Potatoes according to the conditions of use which are listed at the end of this file. If you restrict use via a required Moodle login, you most likely can still meet the 'freely available' condition if you make the same material on a separate URL that permits free access. Otherwise, please purchase a license.
|
||||
|
||||
|
||||
======================================
|
||||
TO INSTALL OR UPDATE THE HOTPOT MODULE
|
||||
======================================
|
||||
|
||||
You should install only this module by installing a complete Moodle 1.9 package.
|
||||
|
||||
Similarly, the recommended way to upgrade this module is to upgrade to a complete Moodle 1.8 package.
|
||||
|
||||
However, it is possible to download and unzip a complete Moodle 1.9 package and extract the "mod/hotpot" folder for use on your live Moodle 1.8 site.
|
||||
|
||||
========================
|
||||
TO USE THE HOTPOT MODULE
|
||||
========================
|
||||
|
||||
1. If you haven't already done so, download and install the Hot Potatoes software from http://www.halfbakedsoftware.com onto your PC
|
||||
|
||||
2. Create any type of Hot Potatoes quiz on your PC using the Hot Potatoes software
|
||||
|
||||
3. Upload the quiz's source file (".jcl", ".jcw", ".jmt", ".jmx", ".jqz") or ".html" file from your PC to the "Files" area of a course on your Moodle site.
|
||||
|
||||
4. Also upload any graphics, sound files, stylesheets or javascripts that the quiz uses
|
||||
|
||||
5. On the main page for the Moodle course, confirm editing is turned on (click the "Turn editing on" button), then, in the section where you want to add the HotPot activity, select "Hot Potatoes Quiz" on the "Add an activity" drop-down menu .
|
||||
|
||||
If "Hot Potatoes Quiz" does not appear on the "Add an activity" menu, you may need to enable the HotPot module as follows:
|
||||
|
||||
a) from the site's front page select "Admin" then "Modules"
|
||||
b) click the "closed eye" icon for the "Hot Potatoes Quiz" module
|
||||
|
||||
If there is no "Hot Potatoes Quiz" on the "Modules" page, you probably have not put the hotpot.php messages file in the right place. Please refer to step 2, "Install the messages and help files", of the installation procedure (see previous section)
|
||||
|
||||
6. The "Adding a new Hot Potatoes Quiz" page appears. Click the "Choose or Upload a file ..." button and select the desired Hot Potaotes quiz file.
|
||||
|
||||
7. Review the other settings for the quiz and click "Save Changes" when you are ready
|
||||
|
||||
8. You can view reports of the results via the "Hot Potatoes Quizzes" link on the "Activities menu". Students will see links to all the quizzes. Administrators and teachers will additionally see links to the statistical reports for each quiz.
|
||||
|
||||
9. You can also import the questions from the Hot Potatoes source file to the Moodle Quiz database, if you completed step 4, "enable import from Hot Potatoes XML files", of the installation procedure (see previous section)
|
||||
|
||||
|
||||
==============================
|
||||
HOT POTATOES CONDITIONS OF USE
|
||||
==============================
|
||||
** Reproduced from the Hot Potatoes site **
|
||||
|
||||
Hot Potatoes is offered free to the educational community by the University of Victoria Humanities Computing and Media Centre (formerly the Language Centre), under certain conditions. Hot Potatoes is free for use by state educational institutions which are non-profit making, on the condition that the material produced using the program is freely available to anyone via the WWW. However, you need to purchase a licence under any of the following conditions:
|
||||
* You do not work for a public sector educational establishment.
|
||||
* You charge money for access to the material you make with Hot Potatoes.
|
||||
* You restrict access to the material in some way. (The only exception here is if you have an account on www.hotpot.net, where you ARE allowed to use password restrictions.)
|
||||
* You want to use the Masher program included with the Hot Potatoes suite.
|
||||
|
||||
For more information on licences, and details on how to purchase one, check out our Website at:
|
||||
http://www.halfbakedsoftware.com/hotpot/
|
||||
|
||||
If you intend using the programs to generate more than a handful of exercises, please make sure you register. This costs you nothing -- see How to register for details.
|
||||
Martin Holmes, Half-Baked Software and the University of Victoria HCMC, 1998-2004.
|
||||
@@ -1,582 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once("../../config.php");
|
||||
require_once("lib.php");
|
||||
|
||||
$attemptid = required_param('attemptid', PARAM_INT);
|
||||
|
||||
$PAGE->set_url('/mod/hotpot/attempt.php', array('attemptid'=>$attemptid));
|
||||
|
||||
// get attempt, hotpot, course and course_module records
|
||||
if (! $attempt = $DB->get_record("hotpot_attempts", array("id"=>$attemptid))) {
|
||||
print_error('invalidattemptid', 'hotpot');
|
||||
}
|
||||
if ($attempt->userid != $USER->id) {
|
||||
print_error("invaliduserid");
|
||||
}
|
||||
if (! $hotpot = $DB->get_record("hotpot", array("id"=>$attempt->hotpot))) {
|
||||
print_error('invalidhotpotid', 'hotpot');
|
||||
}
|
||||
if (! $course = $DB->get_record("course", array("id"=>$hotpot->course))) {
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
if (! $cm = get_coursemodule_from_instance("hotpot", $hotpot->id, $course->id)) {
|
||||
print_error("invalidcoursemodule");
|
||||
}
|
||||
|
||||
// make sure this user is enrolled in this course
|
||||
require_login($course, true, $cm);
|
||||
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
|
||||
require_capability('mod/hotpot:attempt', $context, $USER->id);
|
||||
|
||||
$next_url = "$CFG->wwwroot/course/view.php?id=$course->id";
|
||||
$time = time();
|
||||
|
||||
// update attempt record fields using incoming data
|
||||
$attempt->score = optional_param('mark', NULL, PARAM_INT);
|
||||
$attempt->status = optional_param('status', NULL, PARAM_INT);
|
||||
$attempt->details = optional_param('detail', NULL, PARAM_RAW);
|
||||
$attempt->endtime = optional_param('endtime', NULL, PARAM_ALPHA);
|
||||
$attempt->starttime = optional_param('starttime', NULL, PARAM_ALPHA);
|
||||
$attempt->timefinish = $time;
|
||||
|
||||
// convert times, if necessary
|
||||
if (empty($attempt->starttime)) {
|
||||
$attempt->starttime = 0;
|
||||
} else {
|
||||
$attempt->starttime = strtotime($attempt->starttime);
|
||||
}
|
||||
if (empty($attempt->endtime)) {
|
||||
$attempt->endtime = 0;
|
||||
} else {
|
||||
$attempt->endtime = strtotime($attempt->endtime);
|
||||
}
|
||||
|
||||
// set clickreportid, (for click reporting)
|
||||
$attempt->clickreportid = $attempt->id;
|
||||
|
||||
$quiztype = optional_param('quiztype', 0, PARAM_INT);
|
||||
|
||||
if (empty($attempt->details)) {
|
||||
hotpot_set_attempt_details($attempt);
|
||||
$javascript_is_off = true;
|
||||
} else {
|
||||
$javascript_is_off = false;
|
||||
}
|
||||
|
||||
if (empty($attempt->status)) {
|
||||
if (empty($attempt->endtime)) {
|
||||
$attempt->status = HOTPOT_STATUS_INPROGRESS;
|
||||
} else {
|
||||
$attempt->status = HOTPOT_STATUS_COMPLETED;
|
||||
}
|
||||
}
|
||||
|
||||
// check if this is the second (or subsequent) click
|
||||
if ($DB->get_field("hotpot_attempts", "timefinish", array("id"=>$attempt->id))) {
|
||||
|
||||
if ($hotpot->clickreporting==HOTPOT_YES) {
|
||||
// add attempt record for each form submission
|
||||
// records are linked via the "clickreportid" field
|
||||
|
||||
// update status in previous records in this group
|
||||
$DB->set_field("hotpot_attempts", "status", $attempt->status, array("clickreportid"=>$attempt->clickreportid));
|
||||
|
||||
// add new attempt record
|
||||
unset ($attempt->id);
|
||||
$attempt->id = $DB->insert_record("hotpot_attempts", $attempt);
|
||||
|
||||
// add attempt details record, if necessary
|
||||
if (!empty($attempt->details)) {
|
||||
$details = new object();
|
||||
$details->attempt = $attempt->id;
|
||||
$details->details = $attempt->details;
|
||||
$DB->insert_record("hotpot_details", $details, false);
|
||||
}
|
||||
} else {
|
||||
// remove previous responses for this attempt, if required
|
||||
// (N.B. this does NOT remove the attempt record, just the responses)
|
||||
$DB->delete_records("hotpot_responses", array("attempt"=>$attempt->id));
|
||||
}
|
||||
}
|
||||
|
||||
// remove slashes added by lib/setup.php
|
||||
$attempt->details = $attempt->details;
|
||||
|
||||
// add details of this attempt
|
||||
hotpot_add_attempt_details($attempt);
|
||||
|
||||
// add slashes again, so the details can be added to the database
|
||||
$attempt->details = $attempt->details;
|
||||
|
||||
// update the attempt record
|
||||
$DB->update_record("hotpot_attempts", $attempt);
|
||||
|
||||
// update grades for this user
|
||||
hotpot_update_grades($hotpot, $attempt->userid);
|
||||
|
||||
// get previous attempt details record, if any
|
||||
$details_exist = $DB->record_exists("hotpot_details", array("attempt"=>$attempt->id));
|
||||
|
||||
// delete/update/add the attempt details record
|
||||
if (empty($attempt->details)) {
|
||||
if ($details_exist) {
|
||||
$DB->delete_records("hotpot_details", array("attempt"=>$attempt->id));
|
||||
}
|
||||
} else {
|
||||
if ($details_exist) {
|
||||
$DB->set_field("hotpot_details", "details", $attempt->details, array("attempt"=>$attempt->id));
|
||||
} else {
|
||||
$details = new object();
|
||||
$details->attempt = $attempt->id;
|
||||
$details->details = $attempt->details;
|
||||
$DB->insert_record("hotpot_details", $details);
|
||||
}
|
||||
}
|
||||
|
||||
if ($attempt->status==HOTPOT_STATUS_INPROGRESS) {
|
||||
if ($javascript_is_off) {
|
||||
// regenerate HTML page
|
||||
define('HOTPOT_FIRST_ATTEMPT', false);
|
||||
include ("$CFG->hotpotroot/view.php");
|
||||
} else {
|
||||
// continue without reloading the page
|
||||
header("Status: 204");
|
||||
header("HTTP/1.0 204 No Response");
|
||||
}
|
||||
|
||||
} else { // quiz is finished
|
||||
|
||||
add_to_log($course->id, "hotpot", "submit", "review.php?id=$cm->id&attempt=$attempt->id", "$hotpot->id", "$cm->id");
|
||||
|
||||
if ($hotpot->shownextquiz==HOTPOT_YES) {
|
||||
if (is_numeric($next_cm = hotpot_get_next_cm($cm))) {
|
||||
$next_url = "$CFG->wwwroot/mod/hotpot/view.php?id=$next_cm";
|
||||
}
|
||||
}
|
||||
|
||||
// redirect to the next quiz or the course page
|
||||
redirect($next_url, get_string('resultssaved', 'hotpot'));
|
||||
}
|
||||
|
||||
// =================
|
||||
// functions
|
||||
// =================
|
||||
|
||||
function hotpot_get_next_cm(&$cm) {
|
||||
// gets the next module in this section of the course
|
||||
// that is the same type of module as the current module
|
||||
global $DB;
|
||||
|
||||
$next_mod = false;
|
||||
|
||||
// get a list of $ids of modules in this section
|
||||
if ($ids = $DB->get_field('course_sections', 'sequence', array('id'=>$cm->section))) {
|
||||
|
||||
$found = false;
|
||||
$ids = explode(',', $ids);
|
||||
foreach ($ids as $id) {
|
||||
if ($found && ($cm->module==$DB->get_field('course_modules', 'module', array('id'=>$id)))) {
|
||||
$next_mod = $id;
|
||||
break;
|
||||
} else if ($cm->id==$id) {
|
||||
$found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $next_mod;
|
||||
}
|
||||
function hotpot_set_attempt_details(&$attempt) {
|
||||
global $CFG, $HOTPOT_QUIZTYPE, $DB;
|
||||
|
||||
// optional_param('showallquestions', 0, PARAM_INT);
|
||||
|
||||
$attempt->details = '';
|
||||
$attempt->score = 0;
|
||||
$attempt->status = HOTPOT_STATUS_COMPLETED;
|
||||
|
||||
$buttons = array('clues', 'hints', 'checks');
|
||||
$textfields = array('correct', 'wrong', 'ignored');
|
||||
|
||||
$ok = false;
|
||||
$quiztype = optional_param('quiztype', 0, PARAM_ALPHANUM);
|
||||
if ($quiztype) {
|
||||
if (is_numeric($quiztype)) {
|
||||
$ok = array_key_exists($quiztype, $HOTPOT_QUIZTYPE);
|
||||
} else {
|
||||
$quiztype = array_search($quiztype, $HOTPOT_QUIZTYPE);
|
||||
$ok = is_numeric($quiztype);
|
||||
}
|
||||
}
|
||||
if (!$ok) {
|
||||
return;
|
||||
// print_error('QuizTypeIsMissingOrInvalid');
|
||||
// print_error('error_invalidquiztype', 'hotpot');
|
||||
//
|
||||
// script finishes here if quiztype is invalid
|
||||
//
|
||||
}
|
||||
|
||||
// special flag to detect jquiz multiselect
|
||||
$is_jquiz_multiselect = false;
|
||||
|
||||
// set maximum question number
|
||||
$q_max = 0;;
|
||||
do {
|
||||
switch ($quiztype) {
|
||||
case HOTPOT_JCLOZE:
|
||||
case HOTPOT_JQUIZ:
|
||||
$field="q{$q_max}_a0_text";
|
||||
break;
|
||||
case HOTPOT_JCB:
|
||||
case HOTPOT_JCROSS:
|
||||
case HOTPOT_JMATCH:
|
||||
case HOTPOT_JMIX:
|
||||
default:
|
||||
$field = '';
|
||||
}
|
||||
} while ($field && isset($_POST[$field]) && ($q_max = $q_max+1));
|
||||
|
||||
// check JQuiz navigation buttons
|
||||
switch (true) {
|
||||
case isset($_POST['ShowAllQuestionsButton']):
|
||||
$_POST['ShowAllQuestions'] = 1;
|
||||
break;
|
||||
case isset($_POST['ShowOneByOneButton']):
|
||||
$_POST['ShowAllQuestions'] = 0;
|
||||
break;
|
||||
case isset($_POST['PrevQButton']):
|
||||
$_POST['ThisQuestion']--;
|
||||
break;
|
||||
case isset($_POST['NextQButton']):
|
||||
$_POST['ThisQuestion']++;
|
||||
break;
|
||||
}
|
||||
|
||||
$q = 0;
|
||||
while ($q<$q_max) {
|
||||
$responsefield="q{$q}";
|
||||
|
||||
$questiontype = optional_param("{$responsefield}_questiontype", 0, PARAM_INT);
|
||||
$is_jquiz_multiselect = ($quiztype==HOTPOT_JQUIZ && $questiontype==HOTPOT_JQUIZ_MULTISELECT);
|
||||
|
||||
if (isset($_POST[$responsefield]) && is_array($_POST[$responsefield])) {
|
||||
$responsevalue = array();
|
||||
foreach ($_POST[$responsefield] as $key=>$value) {
|
||||
$responsevalue[$key] = clean_param($value, PARAM_CLEAN);
|
||||
}
|
||||
} else {
|
||||
$responsevalue = optional_param($responsefield, '', PARAM_CLEAN);
|
||||
}
|
||||
if (is_array($responsevalue)) {
|
||||
// incomplete jquiz multi-select
|
||||
$responsevalues = $responsevalue;
|
||||
$responsevalue = implode('+', $responsevalue);
|
||||
} else {
|
||||
$responsevalues = explode('+', $responsevalue);
|
||||
}
|
||||
|
||||
// initialize $response object
|
||||
$response = new stdClass();
|
||||
$response->correct = array();
|
||||
$response->wrong = array();
|
||||
$response->ignored = array();
|
||||
$response->clues = 0;
|
||||
$response->hints = 0;
|
||||
$response->checks = 0;
|
||||
$response->score = 0;
|
||||
$response->weighting = 0;
|
||||
|
||||
// create another empty object to hold all previous responses (from database)
|
||||
$oldresponse = new stdClass();
|
||||
$vars = get_object_vars($response);
|
||||
foreach($vars as $name=>$value) {
|
||||
$oldresponse->$name = $value;
|
||||
}
|
||||
|
||||
foreach ($buttons as $button) {
|
||||
if (($field = "q{$q}_{$button}_button") && isset($_POST[$field])) {
|
||||
$value = optional_param($field, '', PARAM_RAW);
|
||||
if (!empty($value)) {
|
||||
$response->$button++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loop through possible answers to this question
|
||||
$firstcorrectvalue = '';
|
||||
$percents = array();
|
||||
$a = 0;
|
||||
while (($valuefield="q{$q}_a{$a}_text") && isset($_POST[$valuefield])) {
|
||||
$value = optional_param($valuefield, '', PARAM_RAW);
|
||||
|
||||
if (($percentfield="q{$q}_a{$a}_percent") && isset($_POST[$percentfield])) {
|
||||
$percent = optional_param($percentfield, 0, PARAM_INT);
|
||||
if ($percent) {
|
||||
$percents[$value] = $percent;
|
||||
}
|
||||
}
|
||||
|
||||
if (($correctfield="q{$q}_a{$a}_correct") && isset($_POST[$correctfield])) {
|
||||
$correct = optional_param($correctfield, 0, PARAM_INT);
|
||||
} else {
|
||||
$correct = false;
|
||||
}
|
||||
|
||||
if ($correct && empty($firstcorrectvalue)) {
|
||||
$firstcorrectvalue = $value;
|
||||
}
|
||||
|
||||
if ($is_jquiz_multiselect) {
|
||||
$selected = in_array($value, $responsevalues);
|
||||
if ($correct) {
|
||||
$response->correct[] = $value;
|
||||
if (empty($selected)) {
|
||||
$response->wrong[] = true;
|
||||
}
|
||||
} else {
|
||||
if ($selected) {
|
||||
$response->wrong[] = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// single answer only required
|
||||
if ($responsevalue==$value) {
|
||||
if ($correct) {
|
||||
$response->correct[] = $value;
|
||||
} else {
|
||||
$response->wrong[] = $value;
|
||||
}
|
||||
} else {
|
||||
$response->ignored[] = $value;
|
||||
}
|
||||
}
|
||||
$a++;
|
||||
}
|
||||
|
||||
// number of answers for this question
|
||||
$a_max = $a;
|
||||
|
||||
if ($is_jquiz_multiselect) {
|
||||
if (empty($response->wrong) && count($responsevalues)==count($response->correct)) {
|
||||
$response->wrong = array();
|
||||
$response->correct = array($responsevalue);
|
||||
} else {
|
||||
$response->correct = array();
|
||||
$response->wrong = array($responsevalue);
|
||||
}
|
||||
} else {
|
||||
// if response did not match any answer, then this response is wrong
|
||||
if (empty($response->correct) && empty($response->wrong)) {
|
||||
$response->wrong[] = $responsevalue;
|
||||
}
|
||||
}
|
||||
|
||||
// if this question has not been answered correctly, quiz is still in progress
|
||||
if (empty($response->correct)) {
|
||||
|
||||
if (isset($_POST["q{$q}_ShowAnswers_button"])) {
|
||||
$_POST[$responsefield] = $firstcorrectvalue;
|
||||
} else {
|
||||
$attempt->status = HOTPOT_STATUS_INPROGRESS;
|
||||
|
||||
if (isset($_POST["q{$q}_Hint_button"])) {
|
||||
// a particular hint button in JQuiz shortanswer
|
||||
$_POST['HintButton'] = true;
|
||||
}
|
||||
|
||||
// give a hint, if necessary
|
||||
if (isset($_POST['HintButton']) && $firstcorrectvalue) {
|
||||
|
||||
// make sure we only come through here once
|
||||
unset($_POST['HintButton']);
|
||||
|
||||
$correctlen = strlen($firstcorrectvalue);
|
||||
$responselen = strlen($responsevalue);
|
||||
|
||||
// check how many letters are the same
|
||||
$i = 0;
|
||||
while ($i<$responselen && $i<$correctlen && $responsevalue{$i}==$firstcorrectvalue{$i}) {
|
||||
$i++;
|
||||
}
|
||||
|
||||
if ($i<$responselen) {
|
||||
// remove incorrect characters on the end of the response
|
||||
$responsevalue = substr($responsevalue, 0, $i);
|
||||
}
|
||||
if ($i<$correctlen) {
|
||||
// append next correct letter
|
||||
$responsevalue .= $firstcorrectvalue{$i};
|
||||
}
|
||||
$_POST[$responsefield] = $responsevalue;
|
||||
$response->hints++;
|
||||
} // end if hint
|
||||
}
|
||||
} // end if not correct
|
||||
|
||||
// get clue text, if any
|
||||
if (($field="q{$q}_clue") && isset($_POST[$field])) {
|
||||
$response->clue_text = optional_param($field, '', PARAM_RAW);
|
||||
}
|
||||
|
||||
// get question name
|
||||
$qq = sprintf('%02d', $q); // (a padded, two-digit version of $q)
|
||||
if (($field="q{$q}_name") && isset($_POST[$field])) {
|
||||
$questionname = optional_param($field, '', PARAM_RAW);
|
||||
$questionname = strip_tags($questionname);
|
||||
} else {
|
||||
$questionname = $qq;
|
||||
}
|
||||
|
||||
// get previous responses to this question (if any)
|
||||
$records = $DB->get_records_sql("
|
||||
SELECT
|
||||
r.*
|
||||
FROM
|
||||
{hotpot_attempts} a,
|
||||
{hotpot_questions} q,
|
||||
{hotpot_responses} r
|
||||
WHERE
|
||||
a.clickreportid = ? AND
|
||||
a.id = r.attempt AND
|
||||
r.question = q.id AND
|
||||
q.name = ? AND
|
||||
q.hotpot = ?
|
||||
ORDER BY
|
||||
a.timefinish
|
||||
", array($attempt->clickreportid, $questionname, $attempt->hotpot));
|
||||
|
||||
if ($records) {
|
||||
foreach ($records as $record) {
|
||||
foreach ($buttons as $button) {
|
||||
$oldresponse->$button = max($oldresponse->$button, $record->$button);
|
||||
}
|
||||
foreach ($textfields as $field) {
|
||||
if ($record->$field && ($field=='correct' || $field=='wrong')) {
|
||||
$values = explode(',', hotpot_strings($record->$field));
|
||||
$oldresponse->$field = array_merge($oldresponse->$field, $values);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove "correct" and "wrong" values from "ignored" values
|
||||
$response->ignored = array_diff($response->ignored,
|
||||
$response->correct, $response->wrong, $oldresponse->correct, $oldresponse->wrong
|
||||
);
|
||||
|
||||
foreach ($buttons as $button) {
|
||||
$response->$button += $oldresponse->$button;
|
||||
}
|
||||
|
||||
$value_has_changed = false;
|
||||
foreach ($textfields as $field) {
|
||||
$response->$field = array_merge($oldresponse->$field, $response->$field);
|
||||
$response->$field = array_unique($response->$field);
|
||||
$response->$field = implode(',', $response->$field);
|
||||
|
||||
if ($field=='correct' || $field=='wrong') {
|
||||
$array = $oldresponse->$field;
|
||||
$array = array_unique($array);
|
||||
$oldresponse->$field = implode(',', $array);
|
||||
if ($response->$field<>$oldresponse->$field) {
|
||||
$value_has_changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($value_has_changed) {
|
||||
$response->checks++;
|
||||
}
|
||||
|
||||
// $response now holds amalgamation of all responses so far to this question
|
||||
|
||||
// set question score and weighting
|
||||
if ($response->correct) {
|
||||
switch ($quiztype) {
|
||||
case HOTPOT_JCB:
|
||||
break;
|
||||
case HOTPOT_JCLOZE:
|
||||
$strlen = strlen($response->correct);
|
||||
$response->score = 100*($strlen-($response->checks-1))/$strlen;
|
||||
$attempt->score += $response->score;
|
||||
break;
|
||||
case HOTPOT_JCROSS:
|
||||
break;
|
||||
case HOTPOT_JMATCH:
|
||||
break;
|
||||
case HOTPOT_JMIX:
|
||||
break;
|
||||
case HOTPOT_JQUIZ:
|
||||
switch ($questiontype) {
|
||||
case HOTPOT_JQUIZ_MULTICHOICE:
|
||||
$wrong = explode(',', $response->wrong);
|
||||
foreach ($wrong as $value) {
|
||||
if (isset($percents[$value])) {
|
||||
$percent = $percents[$value];
|
||||
} else {
|
||||
$percent = 0;
|
||||
}
|
||||
}
|
||||
case HOTPOT_JQUIZ_SHORTANSWER:
|
||||
$strlen = strlen($response->correct);
|
||||
$response->score = 100*($strlen-($response->checks-1))/$strlen;
|
||||
break;
|
||||
case HOTPOT_JQUIZ_MULTISELECT:
|
||||
if (isset($percents[$response->correct])) {
|
||||
$percent = $percents[$response->correct];
|
||||
} else {
|
||||
$percent = 0;
|
||||
}
|
||||
if ($a_max>0 && $response->checks>0 && $a_max>$response->checks) {
|
||||
$response->score = $percent*($a_max-($response->checks-1))/$a_max;
|
||||
}
|
||||
break;
|
||||
}
|
||||
$attempt->score += $response->score;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$fieldname = $HOTPOT_QUIZTYPE[$quiztype]."_q{$qq}_name";
|
||||
$attempt->details .= "<field><fieldname>$fieldname</fieldname><fielddata>$questionname</fielddata></field>";
|
||||
|
||||
// encode $response fields as XML
|
||||
$vars = get_object_vars($response);
|
||||
foreach($vars as $name=>$value) {
|
||||
if (!empty($value)) {
|
||||
$fieldname = $HOTPOT_QUIZTYPE[$quiztype]."_q{$qq}_{$name}";
|
||||
$attempt->details .= "<field><fieldname>$fieldname</fieldname><fielddata>$value</fielddata></field>";
|
||||
}
|
||||
}
|
||||
|
||||
$q++;
|
||||
} // end main loop through $q(uestions)
|
||||
|
||||
// set attempt score
|
||||
if ($q>0) {
|
||||
switch ($quiztype) {
|
||||
case HOTPOT_JCB:
|
||||
break;
|
||||
case HOTPOT_JCLOZE:
|
||||
$attempt->score = floor($attempt->score / $q);
|
||||
break;
|
||||
case HOTPOT_JCROSS:
|
||||
break;
|
||||
case HOTPOT_JMATCH:
|
||||
break;
|
||||
case HOTPOT_JMIX:
|
||||
break;
|
||||
case HOTPOT_JQUIZ:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($attempt->details) {
|
||||
$attempt->details = '<?xml version="1.0"?><hpjsresult><fields>'.$attempt->details.'</fields></hpjsresult>';
|
||||
}
|
||||
|
||||
// print "forcing status to in progress ..<br/>\n";
|
||||
// $attempt->status = HOTPOT_STATUS_INPROGRESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,347 +0,0 @@
|
||||
<?php
|
||||
//This php script contains all the stuff to backup/restore
|
||||
//quiz mods
|
||||
//-----------------------------------------------------------
|
||||
// This is the "graphical" structure of the hotpot mod:
|
||||
//-----------------------------------------------------------
|
||||
//
|
||||
// hotpot
|
||||
// (CL, pk->id,
|
||||
// fk->course, files)
|
||||
// |
|
||||
// +--------------+---------------+
|
||||
// | |
|
||||
// hotpot_attempts hotpot_questions
|
||||
// (UL, pk->id, (UL, pk->id,
|
||||
// fk->hotpot) fk->hotpot, text)
|
||||
// | | |
|
||||
// +-------------------+----------+ |
|
||||
// | | |
|
||||
// hotpot_details hotpot_responses |
|
||||
// (UL, pk->id, (UL, pk->id, |
|
||||
// fk->attempt) fk->attempt, question, |
|
||||
// correct, wrong, ignored) |
|
||||
// | |
|
||||
// +-------+-------+
|
||||
// |
|
||||
// hotpot_strings
|
||||
// (UL, pk->id)
|
||||
//
|
||||
// Meaning: pk->primary key field of the table
|
||||
// fk->foreign key to link with parent
|
||||
// nt->nested field (recursive data)
|
||||
// CL->course level info
|
||||
// UL->user level info
|
||||
// files->table may have files
|
||||
//
|
||||
//-----------------------------------------------------------
|
||||
function hotpot_backup_mods($bf, $preferences) {
|
||||
global $DB;
|
||||
|
||||
$status = true;
|
||||
|
||||
//Iterate over hotpot table
|
||||
$hotpots = $DB->get_records ("hotpot", array("course"=>$preferences->backup_course), "id");
|
||||
if ($hotpots) {
|
||||
foreach ($hotpots as $hotpot) {
|
||||
if (function_exists('backup_mod_selected')) {
|
||||
// Moodle >= 1.6
|
||||
$backup_mod_selected = backup_mod_selected($preferences, 'hotpot', $hotpot->id);
|
||||
} else {
|
||||
// Moodle <= 1.5
|
||||
$backup_mod_selected = true;
|
||||
}
|
||||
if ($backup_mod_selected) {
|
||||
$status = hotpot_backup_one_mod($bf, $preferences, $hotpot->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
||||
function hotpot_backup_one_mod($bf, $preferences, $instance=0) {
|
||||
// $bf : resource id for b(ackup) f(ile)
|
||||
// $preferences : object containing switches and settings for this backup
|
||||
$level = 3;
|
||||
$status = true;
|
||||
$table = 'hotpot';
|
||||
$select = "course=? AND id=?";
|
||||
$params = array($preferences->backup_course, $instance);
|
||||
$records_tag = '';
|
||||
$records_tags = array();
|
||||
$record_tag = 'MOD';
|
||||
$record_tags = array('MODTYPE'=>'hotpot');
|
||||
$excluded_tags = array();
|
||||
$more_backup = '';
|
||||
if (function_exists('backup_userdata_selected')) {
|
||||
// Moodle >= 1.6
|
||||
$backup_userdata_selected = backup_userdata_selected($preferences, 'hotpot', $instance);
|
||||
} else {
|
||||
// Moodle <= 1.5
|
||||
$backup_userdata_selected = $preferences->mods['hotpot']->userinfo;
|
||||
}
|
||||
if ($backup_userdata_selected) {
|
||||
$more_backup .= '$GLOBALS["hotpot_backup_string_ids"] = array();';
|
||||
$more_backup .= '$status = hotpot_backup_attempts($bf, $record, $level, $status);';
|
||||
$more_backup .= '$status = hotpot_backup_questions($bf, $record, $level, $status);';
|
||||
$more_backup .= '$status = hotpot_backup_strings($bf, $record, $level, $status);';
|
||||
$more_backup .= 'unset($GLOBALS["hotpot_backup_string_ids"]);'; // tidy up
|
||||
}
|
||||
return hotpot_backup_records(
|
||||
$bf, $status, $level,
|
||||
$table, $select, $params,
|
||||
$records_tag, $records_tags,
|
||||
$record_tag, $record_tags,
|
||||
$excluded_tags, $more_backup
|
||||
);
|
||||
}
|
||||
function hotpot_backup_attempts($bf, &$parent, $level, $status) {
|
||||
// $parent is a reference to a hotpot record
|
||||
$table = 'hotpot_attempts';
|
||||
$select = "hotpot=?";
|
||||
$params = array($parent->id);
|
||||
$records_tag = 'ATTEMPT_DATA';
|
||||
$records_tags = array();
|
||||
$record_tag = 'ATTEMPT';
|
||||
$record_tags = array();
|
||||
$more_backup = '';
|
||||
$more_backup .= 'hotpot_backup_details($bf, $record, $level, $status);';
|
||||
$more_backup .= 'hotpot_backup_responses($bf, $record, $level, $status);';
|
||||
$excluded_tags = array('hotpot');
|
||||
return hotpot_backup_records(
|
||||
$bf, $status, $level,
|
||||
$table, $select, $params,
|
||||
$records_tag, $records_tags,
|
||||
$record_tag, $record_tags,
|
||||
$excluded_tags, $more_backup
|
||||
);
|
||||
}
|
||||
function hotpot_backup_details($bf, &$parent, $level, $status) {
|
||||
// $parent is a reference to an attempt record
|
||||
$table = 'hotpot_details';
|
||||
$select = "attempt=?";
|
||||
$params = array($parent->id);
|
||||
$records_tag = '';
|
||||
$records_tags = array();
|
||||
$record_tag = '';
|
||||
$record_tags = array();
|
||||
$more_backup = '';
|
||||
$excluded_tags = array('id','attempt');
|
||||
return hotpot_backup_records(
|
||||
$bf, $status, $level,
|
||||
$table, $select, $params,
|
||||
$records_tag, $records_tags,
|
||||
$record_tag, $record_tags,
|
||||
$excluded_tags, $more_backup
|
||||
);
|
||||
}
|
||||
function hotpot_backup_responses($bf, &$parent, $level, $status) {
|
||||
// $parent is a reference to an attempt record
|
||||
$table = 'hotpot_responses';
|
||||
$select = "attempt=?";
|
||||
$params = array($parent->id);
|
||||
$records_tag = 'RESPONSE_DATA';
|
||||
$records_tags = array();
|
||||
$record_tag = 'RESPONSE';
|
||||
$record_tags = array();
|
||||
$more_backup = 'hotpot_backup_string_ids($record, array("correct","wrong","ignored"));';
|
||||
$excluded_tags = array('id','attempt');
|
||||
return hotpot_backup_records(
|
||||
$bf, $status, $level,
|
||||
$table, $select, $params,
|
||||
$records_tag, $records_tags,
|
||||
$record_tag, $record_tags,
|
||||
$excluded_tags, $more_backup
|
||||
);
|
||||
}
|
||||
function hotpot_backup_questions($bf, &$parent, $level, $status) {
|
||||
// $parent is a reference to an hotpot record
|
||||
$table = 'hotpot_questions';
|
||||
$select = "hotpot=?";
|
||||
$params = array($parent->id);
|
||||
$records_tag = 'QUESTION_DATA';
|
||||
$records_tags = array();
|
||||
$record_tag = 'QUESTION';
|
||||
$record_tags = array();
|
||||
$more_backup = 'hotpot_backup_string_ids($record, array("text"));';
|
||||
$excluded_tags = array('hotpot');
|
||||
return hotpot_backup_records(
|
||||
$bf, $status, $level,
|
||||
$table, $select,
|
||||
$records_tag, $records_tags,
|
||||
$record_tag, $record_tags,
|
||||
$excluded_tags, $more_backup
|
||||
);
|
||||
}
|
||||
function hotpot_backup_string_ids(&$record, $fields) {
|
||||
// as the questions and responses tables are backed up
|
||||
// this function is called to store the ids of strings.
|
||||
// The string ids are used later by "hotpot_backup_strings"
|
||||
// $GLOBALS['hotpot_backup_string_ids'] was initialized in "hotpot_backup_mods"
|
||||
// store the ids of strings used in this $record's $fields
|
||||
foreach ($fields as $field) {
|
||||
if (empty($record->$field)) {
|
||||
// do nothing
|
||||
} else {
|
||||
$value = $record->$field;
|
||||
$ids = explode(',', "$value");
|
||||
foreach ($ids as $id) {
|
||||
if (empty($id)) {
|
||||
// do nothing
|
||||
} else {
|
||||
$GLOBALS['hotpot_backup_string_ids'][$id] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function hotpot_backup_strings($bf, $record, $level, $status) {
|
||||
// This functions backups the strings used
|
||||
// in the question and responses for a single hotpot activity
|
||||
// The ids of the strings were stored by "hotpot_backup_string_ids"
|
||||
// $GLOBALS['hotpot_backup_string_ids'] was initialized in "hotpot_backup_mods"
|
||||
// retrieve $ids of strings to be backed up
|
||||
$ids = array_keys($GLOBALS['hotpot_backup_string_ids']);
|
||||
if (empty($ids)) {
|
||||
// no strings to backup
|
||||
} else {
|
||||
sort($ids);
|
||||
$ids = implode(',', $ids);
|
||||
$table = 'hotpot_strings';
|
||||
$select = "id IN ($ids)";
|
||||
$params = array();
|
||||
$records_tag = 'STRING_DATA';
|
||||
$records_tags = array();
|
||||
$record_tag = 'STRING';
|
||||
$record_tags = array();
|
||||
$more_backup = '';
|
||||
$excluded_tags = array('');
|
||||
$status = hotpot_backup_records(
|
||||
$bf, $status, $level,
|
||||
$table, $select, $params,
|
||||
$records_tag, $records_tags,
|
||||
$record_tag, $record_tags,
|
||||
$excluded_tags, $more_backup
|
||||
);
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
function hotpot_backup_records(&$bf, $status, $level, $table, $select, $params, $records_tag, $records_tags, $record_tag, $record_tags, $excluded_tags, $more_backup) {
|
||||
// general purpose backup function
|
||||
// $bf : resource id of backup file
|
||||
// $status : current status of backup (true or false)
|
||||
// $level : current depth level in the backup XML tree
|
||||
// $table : table from which records will be selected and backed up
|
||||
// $select : SQL selection string
|
||||
// $records_tag : optional XML tag which starts a group of records (and descends a level)
|
||||
// $records_tags : optional XML tags to be inserted at the start of a group of records
|
||||
// $record_tag : optional XML tag which starts a record (and descends a level)
|
||||
// $record_tags : optional XML tags to be inserted at the start of a record
|
||||
// $excluded_tags : fields which will NOT be backed up from the records
|
||||
// $more_backup : optional PHP code to be eval(uated) for each record
|
||||
// If any of the "fwrite" statements fail,
|
||||
// no further "fwrite"s will be attempted
|
||||
// and the function returns "false".
|
||||
// Otherwise, the function returns "true".
|
||||
global $DB;
|
||||
|
||||
if ($status && ($records = $DB->get_records_select($table, $select, $params, 'id'))) {
|
||||
// start a group of records
|
||||
if ($records_tag) {
|
||||
$status = $status && fwrite($bf, start_tag($records_tag, $level, true));
|
||||
$level++;
|
||||
foreach ($records_tags as $tag) {
|
||||
$status = $status && fwrite($bf, full_tag($tag, $level, false, $value));
|
||||
}
|
||||
}
|
||||
foreach ($records as $record) {
|
||||
// start a single record
|
||||
if ($record_tag) {
|
||||
$status = $status && fwrite($bf, start_tag($record_tag, $level, true));
|
||||
$level++;
|
||||
foreach ($record_tags as $tag=>$value) {
|
||||
$status = $status && fwrite($bf, full_tag($tag, $level, false, $value));
|
||||
}
|
||||
}
|
||||
// backup fields in this record
|
||||
$tags = get_object_vars($record);
|
||||
foreach ($tags as $tag=>$value) {
|
||||
if (!is_numeric($tag) && !in_array($tag, $excluded_tags)) {
|
||||
$status = $status && fwrite($bf, full_tag($tag, $level, false, $value));
|
||||
}
|
||||
}
|
||||
// backup related records, if required
|
||||
if ($more_backup) {
|
||||
eval($more_backup);
|
||||
}
|
||||
// end a single record
|
||||
if ($record_tag) {
|
||||
$level--;
|
||||
$status = $status && fwrite($bf, end_tag($record_tag, $level, true));
|
||||
}
|
||||
}
|
||||
// end a group of records
|
||||
if ($records_tag) {
|
||||
$level--;
|
||||
$status = $status && fwrite($bf, end_tag($records_tag, $level, true));
|
||||
}
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
////Return an array of info (name, value)
|
||||
function hotpot_check_backup_mods($course, $user_data=false, $backup_unique_code, $instances=null) {
|
||||
global $CFG, $DB;
|
||||
$info = array();
|
||||
if (isset($instances) && is_array($instances) && count($instances)) {
|
||||
foreach ($instances as $id => $instance) {
|
||||
$info += hotpot_check_backup_mods_instances($instance,$backup_unique_code);
|
||||
}
|
||||
} else {
|
||||
// the course data
|
||||
$info[0][0] = get_string('modulenameplural','hotpot');
|
||||
$info[0][1] = $DB->count_records('hotpot', array('course'=>$course));
|
||||
|
||||
// the user_data, if requested
|
||||
if ($user_data) {
|
||||
$table = "{hotpot} h, {hotpot_attempts} a";
|
||||
$select = "h.course = ? AND h.id = a.hotpot";
|
||||
$params = array($course);
|
||||
|
||||
$info[1][0] = get_string('attempts', 'quiz');
|
||||
$info[1][1] = $DB->count_records_sql("SELECT COUNT(*) FROM $table WHERE $select", $params);
|
||||
}
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
////Return an array of info (name, value)
|
||||
function hotpot_check_backup_mods_instances($instance,$backup_unique_code) {
|
||||
global $CFG, $DB;
|
||||
$info = array();
|
||||
|
||||
// the course data
|
||||
$info[$instance->id.'0'][0] = '<b>'.$instance->name.'</b>';
|
||||
$info[$instance->id.'0'][1] = '';
|
||||
|
||||
// the user_data, if requested
|
||||
if (!empty($instance->userdata)) {
|
||||
$table = "{hotpot_attempts} a";
|
||||
$select = "a.hotpot = ?";
|
||||
$params = array($instance->id);
|
||||
|
||||
$info[$instance->id.'1'][0] = get_string('attempts', 'quiz');
|
||||
$info[$instance->id.'1'][1] = $DB->count_records_sql("SELECT COUNT(*) FROM $table WHERE $select", $params);
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
// Return content encoded to support interactivities linking.
|
||||
// Called by "backup_encode_absolute_links()" in backup/backuplib.php
|
||||
// Content will be decoded by "hotpot_decode_content_links()"
|
||||
function hotpot_encode_content_links ($content, $preferences) {
|
||||
global $CFG;
|
||||
$base = preg_quote("$CFG->wwwroot/mod/hotpot/", '/');
|
||||
$search = "/($base)([a-z]+).php\?([a-z]+)\=([0-9]+)/";
|
||||
return preg_replace($search, '$@HOTPOT*$2*$3*$4@$', $content);
|
||||
}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
<?php
|
||||
//
|
||||
// Capability definitions for the hotpot module.
|
||||
//
|
||||
// The capabilities are loaded into the database table when the module is
|
||||
// installed or updated. Whenever the capability definitions are updated,
|
||||
// the module version number should be bumped up.
|
||||
//
|
||||
// The system has four possible values for a capability:
|
||||
// CAP_ALLOW, CAP_PREVENT, CAP_PROHIBIT, and inherit (not set).
|
||||
//
|
||||
//
|
||||
// CAPABILITY NAMING CONVENTION
|
||||
//
|
||||
// It is important that capability names are unique. The naming convention
|
||||
// for capabilities that are specific to modules and blocks is as follows:
|
||||
// [mod/block]/<plugin_name>:<capabilityname>
|
||||
//
|
||||
// component_name should be the same as the directory name of the mod or block.
|
||||
//
|
||||
// Core moodle capabilities are defined thus:
|
||||
// moodle/<capabilityclass>:<capabilityname>
|
||||
//
|
||||
// Examples: mod/forum:viewpost
|
||||
// block/recent_activity:view
|
||||
// moodle/site:deleteuser
|
||||
//
|
||||
// The variable name for the capability definitions array is $capabilities
|
||||
|
||||
|
||||
$capabilities = array(
|
||||
|
||||
'mod/hotpot:attempt' => array(
|
||||
|
||||
'captype' => 'read',
|
||||
'contextlevel' => CONTEXT_MODULE,
|
||||
'archetypes' => array(
|
||||
'student' => CAP_ALLOW,
|
||||
'teacher' => CAP_ALLOW,
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'manager' => CAP_ALLOW
|
||||
)
|
||||
),
|
||||
|
||||
'mod/hotpot:viewreport' => array(
|
||||
|
||||
'captype' => 'read',
|
||||
'contextlevel' => CONTEXT_MODULE,
|
||||
'archetypes' => array(
|
||||
'teacher' => CAP_ALLOW,
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'manager' => CAP_ALLOW
|
||||
)
|
||||
),
|
||||
|
||||
'mod/hotpot:grade' => array(
|
||||
|
||||
'captype' => 'read',
|
||||
'contextlevel' => CONTEXT_MODULE,
|
||||
'archetypes' => array(
|
||||
'teacher' => CAP_ALLOW,
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'manager' => CAP_ALLOW
|
||||
)
|
||||
),
|
||||
|
||||
'mod/hotpot:deleteattempt' => array(
|
||||
|
||||
'captype' => 'read',
|
||||
'contextlevel' => CONTEXT_MODULE,
|
||||
'archetypes' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'manager' => CAP_ALLOW
|
||||
)
|
||||
)
|
||||
|
||||
);
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
// This file replaces:
|
||||
// * STATEMENTS section in db/install.xml
|
||||
// * lib.php/modulename_install() post installation hook
|
||||
// * partially defaults.php
|
||||
|
||||
function xmldb_hotpot_install() {
|
||||
global $DB;
|
||||
|
||||
/// Disable it by default
|
||||
$DB->set_field('modules', 'visible', 0, array('name'=>'hotpot'));
|
||||
|
||||
/// Install logging support here
|
||||
|
||||
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="mod/hotpot/db" VERSION="20060901" COMMENT="XMLDB file for Moodle mod/hotpot"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
<TABLES>
|
||||
<TABLE NAME="hotpot" COMMENT="details about Hot Potatoes quizzes" NEXT="hotpot_attempts">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="course"/>
|
||||
<FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="name"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="course" NEXT="summary"/>
|
||||
<FIELD NAME="summary" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="timeopen"/>
|
||||
<FIELD NAME="timeopen" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="summary" NEXT="timeclose"/>
|
||||
<FIELD NAME="timeclose" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timeopen" NEXT="location"/>
|
||||
<FIELD NAME="location" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timeclose" NEXT="reference"/>
|
||||
<FIELD NAME="reference" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="location" NEXT="outputformat"/>
|
||||
<FIELD NAME="outputformat" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="1" SEQUENCE="false" PREVIOUS="reference" NEXT="navigation"/>
|
||||
<FIELD NAME="navigation" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="1" SEQUENCE="false" PREVIOUS="outputformat" NEXT="studentfeedback"/>
|
||||
<FIELD NAME="studentfeedback" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="navigation" NEXT="studentfeedbackurl"/>
|
||||
<FIELD NAME="studentfeedbackurl" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="studentfeedback" NEXT="forceplugins"/>
|
||||
<FIELD NAME="forceplugins" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="studentfeedbackurl" NEXT="shownextquiz"/>
|
||||
<FIELD NAME="shownextquiz" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="forceplugins" NEXT="review"/>
|
||||
<FIELD NAME="review" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="shownextquiz" NEXT="grade"/>
|
||||
<FIELD NAME="grade" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="review" NEXT="grademethod"/>
|
||||
<FIELD NAME="grademethod" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" PREVIOUS="grade" NEXT="attempts"/>
|
||||
<FIELD NAME="attempts" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="grademethod" NEXT="password"/>
|
||||
<FIELD NAME="password" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="attempts" NEXT="subnet"/>
|
||||
<FIELD NAME="subnet" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="password" NEXT="clickreporting"/>
|
||||
<FIELD NAME="clickreporting" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="subnet" NEXT="timecreated"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="clickreporting" NEXT="timemodified"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timecreated"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" />
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="hotpot_attempts" COMMENT="details about Hot Potatoes quiz attempts" PREVIOUS="hotpot" NEXT="hotpot_details">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="hotpot"/>
|
||||
<FIELD NAME="hotpot" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="userid"/>
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="hotpot" NEXT="starttime"/>
|
||||
<FIELD NAME="starttime" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="userid" NEXT="endtime"/>
|
||||
<FIELD NAME="endtime" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="starttime" NEXT="score"/>
|
||||
<FIELD NAME="score" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="endtime" NEXT="penalties"/>
|
||||
<FIELD NAME="penalties" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="score" NEXT="attempt"/>
|
||||
<FIELD NAME="attempt" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="penalties" NEXT="timestart"/>
|
||||
<FIELD NAME="timestart" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="attempt" NEXT="timefinish"/>
|
||||
<FIELD NAME="timefinish" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timestart" NEXT="status"/>
|
||||
<FIELD NAME="status" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="1" SEQUENCE="false" PREVIOUS="timefinish" NEXT="clickreportid"/>
|
||||
<FIELD NAME="clickreportid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="status"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="hotpot"/>
|
||||
<KEY NAME="hotpot" TYPE="foreign" FIELDS="hotpot" REFTABLE="hotpot" REFFIELDS="id" PREVIOUS="primary"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="userid" UNIQUE="false" FIELDS="userid"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="hotpot_details" COMMENT="raw details (as XML) of Hot Potatoes quiz attempts" PREVIOUS="hotpot_attempts" NEXT="hotpot_questions">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="attempt"/>
|
||||
<FIELD NAME="attempt" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="details"/>
|
||||
<FIELD NAME="details" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="attempt"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="attempt"/>
|
||||
<KEY NAME="attempt" TYPE="foreign" FIELDS="attempt" REFTABLE="hotpot_attempts" REFFIELDS="id" PREVIOUS="primary"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="hotpot_questions" COMMENT="details about questions in Hot Potatoes quiz attempts" PREVIOUS="hotpot_details" NEXT="hotpot_responses">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="name"/>
|
||||
<FIELD NAME="name" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="type"/>
|
||||
<FIELD NAME="type" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="name" NEXT="text"/>
|
||||
<FIELD NAME="text" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="type" NEXT="hotpot"/>
|
||||
<FIELD NAME="hotpot" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="text" NEXT="md5key"/>
|
||||
<FIELD NAME="md5key" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" PREVIOUS="hotpot"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="hotpot"/>
|
||||
<KEY NAME="hotpot" TYPE="foreign" FIELDS="hotpot" REFTABLE="hotpot" REFFIELDS="id" PREVIOUS="primary"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="md5key" UNIQUE="false" FIELDS="md5key"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="hotpot_responses" COMMENT="details about responses in Hot Potatoes quiz attempts" PREVIOUS="hotpot_questions" NEXT="hotpot_strings">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="attempt"/>
|
||||
<FIELD NAME="attempt" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="question"/>
|
||||
<FIELD NAME="question" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="attempt" NEXT="score"/>
|
||||
<FIELD NAME="score" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="question" NEXT="weighting"/>
|
||||
<FIELD NAME="weighting" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="score" NEXT="correct"/>
|
||||
<FIELD NAME="correct" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="weighting" NEXT="wrong"/>
|
||||
<FIELD NAME="wrong" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="correct" NEXT="ignored"/>
|
||||
<FIELD NAME="ignored" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="wrong" NEXT="hints"/>
|
||||
<FIELD NAME="hints" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="ignored" NEXT="clues"/>
|
||||
<FIELD NAME="clues" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="hints" NEXT="checks"/>
|
||||
<FIELD NAME="checks" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="clues"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="attempt"/>
|
||||
<KEY NAME="attempt" TYPE="foreign" FIELDS="attempt" REFTABLE="hotpot_attempts" REFFIELDS="id" PREVIOUS="primary" NEXT="question"/>
|
||||
<KEY NAME="question" TYPE="foreign" FIELDS="question" REFTABLE="hotpot_questions" REFFIELDS="id" PREVIOUS="attempt"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="hotpot_strings" COMMENT="strings used in Hot Potatoes questions and responses" PREVIOUS="hotpot_responses">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="string"/>
|
||||
<FIELD NAME="string" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="md5key"/>
|
||||
<FIELD NAME="md5key" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" PREVIOUS="string"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" />
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="md5key" UNIQUE="false" FIELDS="md5key"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
</TABLES>
|
||||
</XMLDB>
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
// This file keeps track of upgrades to the hotpot module
|
||||
//
|
||||
// Please do not forget to use upgrade_set_timeout()
|
||||
// before any action that may take longer time to finish.
|
||||
|
||||
function xmldb_hotpot_upgrade($oldversion) {
|
||||
global $CFG, $DB;
|
||||
|
||||
$dbman = $DB->get_manager();
|
||||
|
||||
//===== 1.9.0 upgrade line ======//
|
||||
|
||||
// update hotpot grades from sites earlier than Moodle 1.9, 27th March 2008
|
||||
if ($oldversion < 2007101511) {
|
||||
// ensure "hotpot_upgrade_grades" function is available
|
||||
require_once $CFG->dirroot.'/mod/hotpot/lib.php';
|
||||
hotpot_upgrade_grades();
|
||||
upgrade_mod_savepoint(true, 2007101511, 'hotpot');
|
||||
}
|
||||
|
||||
if ($oldversion < 2008011200) {
|
||||
// remove not used setting
|
||||
unset_config('hotpot_initialdisable');
|
||||
upgrade_mod_savepoint(true, 2008011200, 'hotpot');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once("../../config.php");
|
||||
|
||||
$id = required_param('id', PARAM_INT); // Course module ID
|
||||
|
||||
$PAGE->set_url('/mod/hotpot/grade.php', array('id'=>$id));
|
||||
|
||||
if (! $cm = get_coursemodule_from_id('hotpot', $id)) {
|
||||
print_error('invalidcoursemodule');
|
||||
}
|
||||
|
||||
if (! $hotpot = $DB->get_record("hotpot", array("id"=>$cm->instance))) {
|
||||
print_error('invalidhotpotid', 'hotpot');
|
||||
}
|
||||
|
||||
if (! $course = $DB->get_record("course", array("id"=>$hotpot->course))) {
|
||||
print_error("invalidcourse");
|
||||
}
|
||||
|
||||
require_login($course->id, false, $cm);
|
||||
|
||||
if (has_capability('mod/hotpot:grade', get_context_instance(CONTEXT_MODULE, $cm->id))) {
|
||||
redirect('report.php?id='.$cm->id);
|
||||
} else {
|
||||
redirect('view.php?id='.$cm->id);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 415 B |
@@ -1,76 +0,0 @@
|
||||
function domSniffer() {
|
||||
var t = true;
|
||||
var s = navigator.userAgent;
|
||||
if (s.indexOf("Mac") >=0) this.mac = t;
|
||||
if (s.indexOf("Opera") >=0) this.opera = t;
|
||||
var d = document;
|
||||
if (d.layers) this.n4 = t;
|
||||
if (d.childNodes) this.dom = t;
|
||||
if (d.all && d.plugins) this.ie = t;
|
||||
}
|
||||
function getContentH(lyr) {
|
||||
return (is.n4) ? lyr.document.height : (is.ie) ? (is.mac ? lyr.offsetHeight : lyr.scrollHeight) : (is.opera) ? lyr.style.pixelHeight : (is.dom) ? lyr.offsetHeight : 0;
|
||||
}
|
||||
function px(i) {
|
||||
return i + "px";
|
||||
}
|
||||
function setSize(obj, w, h) {
|
||||
if (is.n4) {
|
||||
if (w) obj.width = w;
|
||||
if (h) obj.height = h;
|
||||
} else if (is.opera) {
|
||||
// opera 5 needs pixelWidth/Height
|
||||
if (w) obj.style.pixelWidth = w;
|
||||
if (h) obj.style.pixelHeight = h;
|
||||
} else {
|
||||
if (w) obj.style.width = px(w);
|
||||
if (h) obj.style.height = px(h);
|
||||
}
|
||||
}
|
||||
function getElement(id, lyr) {
|
||||
var d = (document.layers && lyr) ? lyr.document : document;
|
||||
var obj = (document.layers) ? eval("d."+id) : (d.all) ? d.all[id] : (d.getElementById) ? d.getElementById(id) : null;
|
||||
return obj;
|
||||
}
|
||||
function set_embed_object_height(evt, embed_object) {
|
||||
if (typeof(embed_object)=='undefined') {
|
||||
if (evt) {
|
||||
// we are being called by the onload event handler
|
||||
if (evt.target) { // most browsers
|
||||
embed_object = evt.target;
|
||||
} else if (evt.srcElement) { // IE
|
||||
embed_object = evt.srcElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
var obj = null;
|
||||
if (embed_object) {
|
||||
if (document.frames) { // IE
|
||||
switch (embed_object.tagName) {
|
||||
case 'IFRAME':
|
||||
obj = document.frames[embed_object.name].document;
|
||||
break;
|
||||
case 'OBJECT':
|
||||
obj = embed_object; // already an HTML document element
|
||||
break;
|
||||
}
|
||||
} else { // Firefox, Safari, Opera, Chrome
|
||||
obj = embed_object.document || embed_object.contentDocument || null;
|
||||
}
|
||||
}
|
||||
if (obj) {
|
||||
if (obj.body) {
|
||||
obj = obj.body;
|
||||
}
|
||||
var h = getContentH(obj);
|
||||
if (h) {
|
||||
setSize(embed_object, 0, h + 65);
|
||||
}
|
||||
// at some point the next two lines were important, but now it doesn't seeme to matter ?!
|
||||
// if (document.all) {
|
||||
// embed_object.allowTransparency = true;
|
||||
// obj.style.backgroundColor = 'transparent';
|
||||
// }
|
||||
}
|
||||
}
|
||||
is = new domSniffer();
|
||||
@@ -1,402 +0,0 @@
|
||||
<?PHP
|
||||
|
||||
// This page lists all the instances of hotpot in a particular course
|
||||
|
||||
require_once("../../config.php");
|
||||
require_once("../../course/lib.php");
|
||||
require_once("lib.php");
|
||||
|
||||
$id = required_param('id', PARAM_INT); // course
|
||||
|
||||
$PAGE->set_url('/mod/hotpot/index.php', array('id'=>$id));
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course->id);
|
||||
$PAGE->set_pagelayout('incourse');
|
||||
|
||||
$coursecontext = get_context_instance(CONTEXT_COURSE, $id);
|
||||
$sitecontext = get_context_instance(CONTEXT_SYSTEM);
|
||||
|
||||
add_to_log($course->id, "hotpot", "view all", "index.php?id=$course->id", "");
|
||||
|
||||
$sesskey = '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
|
||||
|
||||
// get message strings for titles
|
||||
$strmodulenameplural = get_string("modulenameplural", "hotpot");
|
||||
$strmodulename = get_string("modulename", "hotpot");
|
||||
$strsectionname = get_string('sectionname', 'format_'.$course->format);
|
||||
|
||||
// string translation array for single and double quotes
|
||||
$quotes = array("'"=>"\'", '"'=>'"');
|
||||
|
||||
// Print the header
|
||||
$PAGE->navbar->add($strmodulenameplural);
|
||||
$PAGE->set_title(format_string($course->shortname) . ": $strmodulenameplural");
|
||||
$PAGE->set_heading($course->fullname);
|
||||
echo $OUTPUT->header();
|
||||
|
||||
$next_url = "$CFG->wwwroot/course/view.php?id=$course->id";
|
||||
|
||||
// get display section, if any
|
||||
$section = optional_param('section', 0, PARAM_ALPHANUM);
|
||||
if ($section=='all') {
|
||||
// do nothing
|
||||
} else {
|
||||
$section = intval($section);
|
||||
}
|
||||
if ($section) {
|
||||
$displaysection = course_set_display($course->id, $section);
|
||||
} else {
|
||||
if (isset($USER->display[$course->id])) {
|
||||
$displaysection = $USER->display[$course->id];
|
||||
} else {
|
||||
$displaysection = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Get all hotpot instances in this course
|
||||
$hotpots = array();
|
||||
if ($hotpot_instances = hotpot_get_all_instances_in_course('hotpot', $course)) {
|
||||
foreach ($hotpot_instances as $hotpot_instance) {
|
||||
if ($displaysection>0 && $hotpot_instance->section>0 && $displaysection<>$hotpot_instance->section) {
|
||||
// do nothing (user is not diplaying this section)
|
||||
} else {
|
||||
$hotpots[$hotpot_instance->id] = $hotpot_instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (empty($hotpots)) {
|
||||
notice(get_string('thereareno', 'moodle', $strmodulenameplural), $next_url);
|
||||
exit;
|
||||
}
|
||||
$hotpotids = implode(',', array_keys($hotpots));
|
||||
|
||||
$usesections = course_format_uses_sections($course->format);
|
||||
if ($usesections) {
|
||||
$sections = get_all_sections($course->id);
|
||||
}
|
||||
|
||||
if (has_capability('mod/hotpot:grade', $sitecontext)) {
|
||||
|
||||
// array of hotpots to be regraded
|
||||
$regrade_hotpots = array();
|
||||
|
||||
// do we need to regrade any or all of the hotpots?
|
||||
$regrade = optional_param('regrade', 0, PARAM_SEQUENCE);
|
||||
if ($regrade) {
|
||||
// add valid hotpot ids to the regrade array
|
||||
$regrade = explode(',', $regrade);
|
||||
foreach ($regrade as $id) {
|
||||
if (isset($hotpots[$id])) {
|
||||
$regrade_hotpots[$id] = &$hotpots[$id];
|
||||
}
|
||||
}
|
||||
$regrade = implode(',', array_keys($regrade_hotpots));
|
||||
}
|
||||
if ($regrade) {
|
||||
|
||||
$confirm = optional_param('confirm', 0, PARAM_BOOL);
|
||||
if (!$confirm) {
|
||||
|
||||
echo $OUTPUT->box_start("generalbox boxaligncenter boxwidthnormal errorboxcontent");
|
||||
|
||||
if (count($regrade_hotpots)==1) {
|
||||
echo $OUTPUT->heading(get_string('regradecheck', 'hotpot', $regrade_hotpots[$regrade]->name));
|
||||
} else {
|
||||
echo $OUTPUT->heading(get_string('regradecheck', 'hotpot', ''));
|
||||
print '<ul>';
|
||||
foreach ($regrade_hotpots as $hotpot) {
|
||||
print "<li>$hotpot->name</li>";
|
||||
}
|
||||
print '</ul>';
|
||||
}
|
||||
print ''
|
||||
. '<div class="mdl-align"><table border="0"><tr><td>'
|
||||
. '<form target="_parent" method="post" action="index.php">'
|
||||
. '<input type="hidden" name="id" value="'.$course->id.'" />'
|
||||
. '<input type="hidden" name="regrade" value="'.$regrade.'" />'
|
||||
. '<input type="hidden" name="confirm" value="1" />'
|
||||
. $sesskey
|
||||
. '<input type="submit" value="'.get_string("yes").'" />'
|
||||
. '</form>'
|
||||
. '</td><td> </td><td>'
|
||||
. '<form target="_parent" method="post" action="index.php">'
|
||||
. '<input type="hidden" name="id" value="'.$course->id.'" />'
|
||||
. $sesskey
|
||||
. '<input type="submit" value="'.get_string("no").'" />'
|
||||
. '</form>'
|
||||
. '</td></tr></table></div>'
|
||||
;
|
||||
|
||||
echo $OUTPUT->box_end();
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
|
||||
} else { // regrade has been confirmed, so proceed
|
||||
|
||||
// start hotpot counter and timer
|
||||
$hotpotstart = microtime();
|
||||
$hotpotcount = 0;
|
||||
|
||||
// regrade attempts for these hotpots
|
||||
foreach ($regrade_hotpots as $hotpot) {
|
||||
echo $OUTPUT->notification("<b>$hotpot->name</b>");
|
||||
|
||||
// delete questions and responses for this hotpot
|
||||
if ($records = $DB->get_records('hotpot_questions', array('hotpot'=>$hotpot->id), '', 'id,hotpot')) {
|
||||
$questionids = implode(',', array_keys($records));
|
||||
hotpot_delete_and_notify('hotpot_questions', "id IN ($questionids)", array(), get_string('question', 'quiz'));
|
||||
hotpot_delete_and_notify('hotpot_responses', "question IN ($questionids)", array(), get_string('answer', 'quiz'));
|
||||
}
|
||||
|
||||
// start attempt counter and timer
|
||||
$attemptstart = microtime();
|
||||
$attemptcount = 0;
|
||||
|
||||
// regrade attempts, if any, for this hotpot
|
||||
if ($attempts = $DB->get_records('hotpot_attempts', array('hotpot'=>$hotpot->id))) {
|
||||
foreach ($attempts as $attempt) {
|
||||
$attempt->details = $DB->get_field('hotpot_details', 'details', array('attempt'=>$attempt->id));
|
||||
if ($attempt->details) {
|
||||
hotpot_add_attempt_details($attempt);
|
||||
$DB->update_record('hotpot_attempts', $attempt);
|
||||
}
|
||||
$attemptcount++;
|
||||
}
|
||||
}
|
||||
if ($attemptcount) {
|
||||
$msg = get_string('added', 'moodle', "$attemptcount x ".get_string('attempts', 'quiz'));
|
||||
if (!empty($CFG->hotpot_showtimes)) {
|
||||
$msg .= ' ('.format_time(sprintf("%0.2f", microtime_diff($attemptstart, microtime()))).')';
|
||||
}
|
||||
echo $OUTPUT->notification($msg);
|
||||
}
|
||||
$hotpotcount++;
|
||||
} // end foreach $hotpots
|
||||
if ($hotpotcount) {
|
||||
$msg = get_string('regrade', 'quiz').": $hotpotcount x ".get_string('modulenameplural', 'hotpot');
|
||||
if (!empty($CFG->hotpot_showtimes)) {
|
||||
$msg .= ' ('.format_time(sprintf("%0.2f", microtime_diff($hotpotstart, microtime()))).')';
|
||||
}
|
||||
echo $OUTPUT->notification($msg);
|
||||
}
|
||||
echo $OUTPUT->notification(get_string('regradecomplete', 'quiz'));
|
||||
} // end if $confirm
|
||||
} // end regrade
|
||||
|
||||
// get duplicate hotpot-name questions
|
||||
// - JMatch LHS is longer than 255 bytes
|
||||
// - JQuiz question text is longer than 255 bytes
|
||||
// - other unidentified situations ?!
|
||||
|
||||
$regrade_hotpots = array();
|
||||
$concat_field = $DB->sql_concat('hotpot', "'_'", 'name');
|
||||
if ($concat_field) {
|
||||
$records = $DB->get_records_sql("
|
||||
SELECT $concat_field, COUNT(*), hotpot, name
|
||||
FROM {hotpot_questions}
|
||||
WHERE hotpot IN ($hotpotids)
|
||||
GROUP BY hotpot, name
|
||||
HAVING COUNT(*) >1
|
||||
");
|
||||
if ($records) {
|
||||
foreach ($records as $record) {
|
||||
$regrade_hotpots[$record->hotpot] = 1;
|
||||
}
|
||||
ksort($regrade_hotpots);
|
||||
$regrade_hotpots = array_keys($regrade_hotpots);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// start timer
|
||||
$start = microtime();
|
||||
|
||||
// get total number of attempts, users and details for these hotpots
|
||||
$params = array();
|
||||
$tables = "{hotpot_attempts} a";
|
||||
$fields = "
|
||||
a.hotpot AS hotpot,
|
||||
COUNT(DISTINCT a.clickreportid) AS attemptcount,
|
||||
COUNT(DISTINCT a.userid) AS usercount,
|
||||
MAX(a.score) AS maxscore
|
||||
";
|
||||
$select = "a.hotpot IN ($hotpotids)";
|
||||
if (has_capability('mod/hotpot:viewreport', $coursecontext)) {
|
||||
// do nothing (=get all users)
|
||||
} else {
|
||||
// restrict results to this user only
|
||||
$select .= " AND a.userid=:userid";
|
||||
$params['userid'] = $USER->id;
|
||||
}
|
||||
$usejoin = 0;
|
||||
if (has_capability('mod/hotpot:grade', get_context_instance(CONTEXT_SYSTEM)) && $usejoin) {
|
||||
// join attempts table and details table
|
||||
$tables .= ",{hotpot_details} d";
|
||||
$fields .= ',COUNT(DISTINCT d.id) AS detailcount';
|
||||
$select .= " AND a.id=d.attempt";
|
||||
|
||||
// this may take about twice as long as getting the gradecounts separately :-(
|
||||
// so this operation could be done after getting the $totals from the attempts table
|
||||
}
|
||||
$totals = $DB->get_records_sql("SELECT $fields FROM $tables WHERE $select GROUP BY a.hotpot", $params);
|
||||
|
||||
if (has_capability('mod/hotpot:grade', get_context_instance(CONTEXT_SYSTEM)) && empty($usejoin)) {
|
||||
foreach ($hotpots as $hotpot) {
|
||||
$totals[$hotpot->id]->detailcount = 0;
|
||||
if ($ids = $DB->get_records('hotpot_attempts', array('hotpot'=>$hotpot->id))) {
|
||||
$ids = join(',', array_keys($ids));
|
||||
$totals[$hotpot->id]->detailcount = $DB->count_records_select('hotpot_details', "attempt IN ($ids)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// message strings for main table
|
||||
$strusers = get_string('users');
|
||||
$strupdate = get_string('update');
|
||||
$strregrade = get_string('regrade', 'hotpot');
|
||||
$strneverclosed = get_string('neverclosed', 'hotpot');
|
||||
$strregraderequired = get_string('regraderequired', 'hotpot');
|
||||
|
||||
// column headings and attributes
|
||||
$table = new html_table();
|
||||
$table->head = array();
|
||||
$table->align = array();
|
||||
|
||||
if (!empty($CFG->hotpot_showtimes)) {
|
||||
print '<H3>'.sprintf("%0.3f", microtime_diff($start, microtime())).' secs'."</H3>\n";
|
||||
}
|
||||
|
||||
$title = $strsectionname;
|
||||
if ($title) {
|
||||
array_push($table->head, $title);
|
||||
array_push($table->align, "center");
|
||||
}
|
||||
if (has_capability('moodle/course:manageactivities', $coursecontext)) {
|
||||
array_push($table->head, $strupdate);
|
||||
array_push($table->align, "center");
|
||||
}
|
||||
array_push($table->head,
|
||||
get_string("name"),
|
||||
get_string("quizcloses", "quiz"),
|
||||
get_string("bestgrade", "quiz"),
|
||||
get_string("attempts", "quiz")
|
||||
);
|
||||
array_push($table->align,
|
||||
"left", "left", "center", "left"
|
||||
);
|
||||
if (has_capability('mod/hotpot:grade', $coursecontext)) {
|
||||
array_push($table->head, $strregrade);
|
||||
array_push($table->align, "center");
|
||||
}
|
||||
|
||||
$currentsection = -1;
|
||||
foreach ($hotpots as $hotpot) {
|
||||
|
||||
$printsection = "";
|
||||
if ($hotpot->section != $currentsection) {
|
||||
if ($hotpot->section) {
|
||||
if ($usesections) {
|
||||
$printsection = get_section_name($course, $sections[$hotpot->section]);
|
||||
// Show the zoom boxes
|
||||
if ($displaysection==$hotpot->section) {
|
||||
$strshowall = get_string('showall'.$course->format);
|
||||
$printsection .= '<br /><a href="index.php?id='.$course->id.'&section=all" title="'.$strshowall.'"><img src="'.$OUTPUT->pix_url('i/all') . '" style="height:25px; width:16px; border:0px" alt="'.$strshowall.'" /></a><br />';
|
||||
} else {
|
||||
$strshowone = get_string('showonly'.preg_replace('|s$|', '', $course->format, 1), '', $hotpot->section);
|
||||
$printsection .= '<br /><a href="index.php?id='.$course->id.'&section='.$hotpot->section.'" title="'.$strshowone.'"><img src="'.$OUTPUT->pix_url('i/one') . '" class="icon" alt="'.$strshowone.'" /></a><br />';
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($currentsection>=0) {
|
||||
$table->data[] = 'hr';
|
||||
}
|
||||
$currentsection = $hotpot->section;
|
||||
}
|
||||
|
||||
$class = ($hotpot->visible) ? '' : 'class="dimmed" ';
|
||||
$quizname = '<a '.$class.'href="view.php?id='.$hotpot->coursemodule.'">'.$hotpot->name.'</a>';
|
||||
$quizclose = empty($hotpot->timeclose) ? $strneverclosed : userdate($hotpot->timeclose);
|
||||
|
||||
// are there any totals for this hotpot?
|
||||
if (empty($totals[$hotpot->id]->attemptcount)) {
|
||||
$report = " ";
|
||||
$bestscore = " ";
|
||||
|
||||
} else {
|
||||
|
||||
$cm = get_coursemodule_from_instance('hotpot', $hotpot->id);
|
||||
// report number of attempts and users
|
||||
$report = get_string("viewallreports","quiz", $totals[$hotpot->id]->attemptcount);
|
||||
if (has_capability('mod/hotpot:viewreport', get_context_instance(CONTEXT_MODULE, $cm->id))) {
|
||||
$report .= " (".$totals[$hotpot->id]->usercount." $strusers)";
|
||||
}
|
||||
$report = '<a href="report.php?hp='.$hotpot->id.'">'.$report.'</a>';
|
||||
|
||||
// get best score
|
||||
if (is_numeric($totals[$hotpot->id]->maxscore)) {
|
||||
$weighting = $hotpot->grade / 100;
|
||||
$precision = hotpot_get_precision($hotpot);
|
||||
$bestscore = round($totals[$hotpot->id]->maxscore * $weighting, $precision)." / $hotpot->grade";
|
||||
} else {
|
||||
$bestscore = " ";
|
||||
}
|
||||
}
|
||||
|
||||
if (has_capability('mod/hotpot:grade', $sitecontext)) {
|
||||
if (in_array($hotpot->id, $regrade_hotpots)) {
|
||||
$report .= ' <font color="red">'.$strregraderequired.'</font>';
|
||||
}
|
||||
}
|
||||
|
||||
$data = array ();
|
||||
|
||||
if ($usesections) {
|
||||
array_push($data, $printsection);
|
||||
}
|
||||
|
||||
if (has_capability('moodle/course:manageactivities', $coursecontext)) {
|
||||
$updatebutton = ''
|
||||
. '<form method="get" action="'.$CFG->wwwroot.'/course/mod.php">'
|
||||
. '<input type="hidden" name="update" value="'.$hotpot->coursemodule.'" />'
|
||||
. $sesskey
|
||||
. '<input type="submit" value="'.$strupdate.'" />'
|
||||
. '</form>'
|
||||
;
|
||||
array_push($data, $updatebutton);
|
||||
}
|
||||
|
||||
array_push($data, $quizname, $quizclose, $bestscore, $report);
|
||||
|
||||
if (has_capability('mod/hotpot:grade', $sitecontext)) {
|
||||
if (empty($totals[$hotpot->id]->detailcount)) {
|
||||
// no details records for this hotpot, so disable regrade
|
||||
$regradebutton = ' ';
|
||||
} else {
|
||||
$strregradecheck = get_string('regradecheck', 'hotpot', strtr($hotpot->name, $quotes));
|
||||
$regradebutton = ''
|
||||
. '<form target="_parent" method="post" action="index.php" onsubmit="var x=window.confirm('."'$strregradecheck'".');this.confirm.value=x;return x;">'
|
||||
. '<input type="hidden" name="id" value="'.$course->id.'" />'
|
||||
. '<input type="hidden" name="regrade" value="'.$hotpot->id.'" />'
|
||||
. '<input type="hidden" name="confirm" value="" />'
|
||||
. $sesskey
|
||||
. '<input type="submit" value="'.$strregrade.'" />'
|
||||
. '</form>'
|
||||
;
|
||||
}
|
||||
array_push($data, $regradebutton);
|
||||
}
|
||||
|
||||
$table->data[] = $data;
|
||||
}
|
||||
|
||||
echo "<br />";
|
||||
|
||||
echo html_writer::table($table);
|
||||
|
||||
// Finish the page
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
@@ -1,224 +0,0 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'hotpot', language 'en', branch 'MOODLE_20_STABLE'
|
||||
*
|
||||
* @package hotpot
|
||||
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['abandoned'] = 'Abandoned';
|
||||
$string['addquizchain'] = 'Add quiz chain';
|
||||
$string['allmycourses'] = 'All my courses';
|
||||
$string['allowreview'] = 'Allow review';
|
||||
$string['allowreview_help'] = 'If enabled, students may review their quiz attempts after the quiz is closed.';
|
||||
$string['allusers'] = 'All users';
|
||||
$string['alwaysopen'] = 'Always open';
|
||||
$string['attemptsall'] = 'All attempts';
|
||||
$string['attemptsbest'] = 'Best attempt';
|
||||
$string['attemptsfirst'] = 'First attempt';
|
||||
$string['attemptslast'] = 'Last attempt';
|
||||
$string['average'] = 'Average';
|
||||
$string['cannotfindmethod'] = 'Template block expand method not found: ({$a})';
|
||||
$string['clickreporting'] = 'Enable click reporting';
|
||||
$string['clickreporting_help'] = 'If enabled, a separate record is kept each time a "hint", "clue" or "check" button is clicked. This allows the teacher to see a very detailed report showing the state of the quiz at each click. Otherwise, only one record per attempt at a quiz is kept.';
|
||||
$string['clues'] = 'Clues';
|
||||
$string['completed'] = 'Completed';
|
||||
$string['configexcelencodings'] = 'A list of encodings, separated by commas, that can be used to force report values into a specific encoding for spreadsheet programs. For example, Microsoft Excel requires the "SJIS" encoding for Japanese';
|
||||
$string['configshowtimes'] = 'Should the time taken to process records be displayed in listings and reports? This is only really necessary if you are trying to find out why your server is running slowly.';
|
||||
$string['copiedtoclipboard'] = 'The contents of this page have been copied to the clipboard';
|
||||
$string['copytoclipboard'] = 'Copy to Clipboard';
|
||||
$string['correct'] = 'Correct';
|
||||
$string['deleteabandoned'] = 'Delete abandoned';
|
||||
$string['deleteabandonedcheck'] = 'Do you really want to delete all {$a} abandoned attempts?';
|
||||
$string['deleteallattempts'] = 'Delete all attempts';
|
||||
$string['displaycoursenext'] = 'Display Course page next';
|
||||
$string['displayhotpotnext'] = 'Display Hot Potatoes quiz next';
|
||||
$string['displayindexnext'] = 'Display HotPot index next';
|
||||
$string['enterafilename'] = 'Please enter a file name';
|
||||
$string['error_couldnotopenfolder'] = 'Could not access the folder "{$a}"';
|
||||
$string['error_couldnotopensourcefile'] = 'Could not open the source file "{$a}"';
|
||||
$string['error_couldnotopentemplate'] = 'Could not open template for "{$a}" format';
|
||||
$string['error_invalidquiztype'] = 'Quiz type is missing or invalid';
|
||||
$string['error_nocourseorfilename'] = 'Could not create XML tree: missing course or file name';
|
||||
$string['error_nofeedbackurlformmail'] = 'Please enter a URL for the form processing script';
|
||||
$string['error_nofeedbackurlwebpage'] = 'Please enter a URL for the webpage';
|
||||
$string['error_nofilename'] = 'Please enter a file name';
|
||||
$string['error_noquizzesfound'] = 'No Hot Potatoes quizzes found';
|
||||
$string['error_notfileorfolder'] = '"{$a}" is not file or folder';
|
||||
$string['excelencodings'] = 'Excel encodings';
|
||||
$string['feedbackformmail'] = 'Feedback form';
|
||||
$string['feedbackmoodleforum'] = 'Moodle forum';
|
||||
$string['feedbackmoodlemessaging'] = 'Moodle messaging';
|
||||
$string['feedbacknone'] = 'None';
|
||||
$string['feedbackwebpage'] = 'Web page';
|
||||
$string['filetype'] = 'File type';
|
||||
$string['forceplugins'] = 'Force media plugins';
|
||||
$string['forceplugins_help'] = 'If enabled, Moodle-compatible media players will play files such as avi, mpeg, mpg, mp3, mov and wmv. Otherwise, Moodle will not change the settings of any media players in the quiz.';
|
||||
$string['forceplugins_link'] = 'mod/hotpot/mod';
|
||||
$string['giveup'] = 'Give Up';
|
||||
$string['hints'] = 'Hints';
|
||||
$string['hotpotadministration'] = 'Hot Potatoes quiz administration';
|
||||
$string['hotpot:attempt'] = 'Attempt a quiz';
|
||||
$string['hotpotcloses'] = 'Hot Potatoes quiz closes';
|
||||
$string['hotpot:deleteattempt'] = 'Delete quiz attempts';
|
||||
$string['hotpot:grade'] = 'Modify grades';
|
||||
$string['hotpotopens'] = 'Hot Potatoes quiz opens';
|
||||
$string['hotpot:view'] = 'Use quiz';
|
||||
$string['hotpot:viewreport'] = 'View reports';
|
||||
$string['checks'] = 'Checks';
|
||||
$string['ignored'] = 'Ignored';
|
||||
$string['inprogress'] = 'In progress';
|
||||
$string['invalidattemptid'] = 'Attempt ID was incorrect';
|
||||
$string['invalidhotpotid'] = 'hotpot ID was incorrect';
|
||||
$string['location'] = 'File location';
|
||||
$string['maxgrade'] = 'Maximum grade';
|
||||
$string['maxgrade_help'] = 'This setting specifies the grade that all scores are scaled to. For example, if the quiz is worth 20% of the whole course, the maximum grade would be set to 20.';
|
||||
$string['modulename'] = 'Hot Potatoes Quiz';
|
||||
$string['modulename_help'] = 'The HotPot module enables the teacher to include Hot Potatoes quizzes in the course. Each attempt is automatically marked, and reports are available which show how individual questions were answered and some statistical trends in the scores.';
|
||||
$string['modulename_link'] = 'hotpot';
|
||||
$string['modulenameplural'] = 'Hot Potatoes Quizzes';
|
||||
$string['navigation'] = 'Navigation';
|
||||
$string['navigation_help'] = 'This setting determines the navigation used in the quiz:
|
||||
|
||||
* Moodle navigation bar - The Moodle navigation bar will be displayed in the same window as the quiz at the top of the page
|
||||
* Moodle navigation frame - The Moodle navigation bar will be displayed in a separate frame at the top of the quiz
|
||||
* Embedded IFRAME - The Moodle navigation bar will be displayed in the same window as the quiz and the quiz will be embedded in an IFRAME
|
||||
* Hot Potatoes quiz buttons - The quiz will be displayed with the navigation buttons, if any, defined in the quiz
|
||||
* A single "Give Up" button - The quiz will be displayed with a single "Give Up" button at the top of the page
|
||||
* None - The quiz will be displayed with no navigation aids, so when all questions have been answered correctly, depending on the "Show next quiz?" setting, Moodle will either return to the course page or display the next quiz';
|
||||
$string['navigation_bar'] = 'Moodle navigation bar';
|
||||
$string['navigation_buttons'] = 'Hot Potatoes quiz buttons';
|
||||
$string['navigation_frame'] = 'Moodle navigation frame';
|
||||
$string['navigation_give_up'] = 'A single "Give Up" button';
|
||||
$string['navigation_iframe'] = 'Embedded IFRAME';
|
||||
$string['navigation_none'] = 'None';
|
||||
$string['neverclosed'] = 'Never closed';
|
||||
$string['noactivity'] = 'No activity';
|
||||
$string['noresponses'] = 'No information about individual questions and responses was found.';
|
||||
$string['notyourattempt'] = 'This is not your attempt!';
|
||||
$string['outputformat'] = 'Output format';
|
||||
$string['outputformat_help'] = 'This setting specifies the format to display the quiz.
|
||||
|
||||
* Best - The best format for the browser
|
||||
* v6+ - Drag and drop format for v6+ browsers
|
||||
* v6 - Format for v6 browsers';
|
||||
$string['outputformat_best'] = 'best';
|
||||
$string['outputformat_flash'] = 'Flash';
|
||||
$string['outputformat_mobile'] = 'mobile';
|
||||
$string['outputformat_v3'] = 'v3';
|
||||
$string['outputformat_v4'] = 'v4';
|
||||
$string['outputformat_v5'] = 'v5';
|
||||
$string['outputformat_v5_plus'] = 'v5+';
|
||||
$string['outputformat_v6'] = 'v6';
|
||||
$string['outputformat_v6_plus'] = 'v6+';
|
||||
$string['penalties'] = 'Penalties';
|
||||
$string['pluginname'] = 'Hot Potatoes Quiz';
|
||||
$string['questionshort'] = 'Q-{$a}';
|
||||
$string['quiztype'] = 'Quiz type';
|
||||
$string['quizunavailable'] = 'Quiz is unavailable at the moment';
|
||||
$string['rawdetails'] = 'Raw attempt details';
|
||||
$string['regrade'] = 'Regrade';
|
||||
$string['regradecheck'] = 'Do you really want to regrade "{$a}"?';
|
||||
$string['regraderequired'] = 'Regrade required';
|
||||
$string['removegradeitem'] = 'Remove grade item';
|
||||
$string['reportanswers'] = 'Answers';
|
||||
$string['reportattemptfinish'] = 'Att. finish';
|
||||
$string['reportattemptnumber'] = 'Attempt';
|
||||
$string['reportattemptstart'] = 'Att. start';
|
||||
$string['reportbutton'] = 'Generate report';
|
||||
$string['reportclick'] = 'Click trail report';
|
||||
$string['reportclicknumber'] = 'Click';
|
||||
$string['reportclicktime'] = 'Click time';
|
||||
$string['reportclicktype'] = 'Click type';
|
||||
$string['reportclues'] = 'Clues';
|
||||
$string['reportcontent'] = 'Content';
|
||||
$string['reportcontent_help'] = 'There are 4 report types:
|
||||
|
||||
* Overview - A list of all attempts
|
||||
* Simple statistics - A list of all attempts with average scores for individual questions and for the complete quiz
|
||||
* Detailed statistics - Full details of all attempts together with a responses table and an item analysis table
|
||||
* Click trail report (only available if click reporting is enabled) - Full details of every click by every student in all attempts';
|
||||
$string['reportcontent_link'] = 'mod/hotpot/report';
|
||||
$string['reportcorrectsymbol'] = 'O';
|
||||
$string['reportcoursename'] = 'Course name';
|
||||
$string['reportencoding'] = 'Encoding';
|
||||
$string['reportevents'] = 'Events';
|
||||
$string['reportexercisename'] = 'Ex. name';
|
||||
$string['reportexercisenumber'] = 'Exercise';
|
||||
$string['reportexercisetype'] = 'Ex. type';
|
||||
$string['reportformat'] = 'Format';
|
||||
$string['reportformat_help'] = 'Reports are available in HTML, Excel or text formats with the option to wrap data (to fit into table cells) and to have questions and answers represented by letters together with a legend showing which letters represent which questions or answers.';
|
||||
$string['reportformatexcel'] = 'Excel';
|
||||
$string['reportformathtml'] = 'HTML';
|
||||
$string['reportformattext'] = 'Text';
|
||||
$string['reporthints'] = 'Hints';
|
||||
$string['reporthotpotscore'] = 'Hotpot score';
|
||||
$string['reportchanges'] = 'Changes';
|
||||
$string['reportchecks'] = 'Checks';
|
||||
$string['reportlegend'] = 'Legend';
|
||||
$string['reportlogindate'] = 'Login date';
|
||||
$string['reportlogintime'] = 'Login time';
|
||||
$string['reportlogofftime'] = 'Logoff time';
|
||||
$string['reportmaxscore'] = 'Max score';
|
||||
$string['reportnottried'] = 'Not tried';
|
||||
$string['reportnottriedsymbol'] = '-';
|
||||
$string['reportnumberofquestions'] = 'No. of q\'s';
|
||||
$string['reportpercentscore'] = '% Score';
|
||||
$string['reportquestionstried'] = 'Q\'s tried';
|
||||
$string['reportrawscore'] = 'Raw score';
|
||||
$string['reportright'] = 'Right';
|
||||
$string['reportsectionnumber'] = 'Section';
|
||||
$string['reportshowanswer'] = 'Show answers';
|
||||
$string['reportshowlegend'] = 'Show legend';
|
||||
$string['reportsofar'] = '{$a} so far';
|
||||
$string['reportstatus'] = 'Status';
|
||||
$string['reportstudentid'] = 'Student id';
|
||||
$string['reportthisclick'] = '{$a} this click';
|
||||
$string['reporttimerecorded'] = 'Responses recorded';
|
||||
$string['reportwrapdata'] = 'Wrap data';
|
||||
$string['reportwrong'] = 'Wrong';
|
||||
$string['reportwrongsymbol'] = 'X';
|
||||
$string['resultssaved'] = 'Quiz results were saved';
|
||||
$string['score'] = 'Score';
|
||||
$string['showhtmlsource'] = 'Show HTML source';
|
||||
$string['shownextquiz'] = 'Show next quiz';
|
||||
$string['shownextquiz_help'] = 'This setting determines whether, on finishing a quiz, Moodle will return to the course page or display the next quiz (if there is one).';
|
||||
$string['showtimes'] = 'Show processing times';
|
||||
$string['showxmlsource'] = 'Show XML source';
|
||||
$string['showxmltree'] = 'Show XML tree';
|
||||
$string['specifictime'] = 'Specific time';
|
||||
$string['studentfeedback'] = 'Student feedback';
|
||||
$string['studentfeedback_help'] = 'If enabled, a link to a pop-up feedback window will be displayed whenever the student clicks on the "Check" button. The feedback window allows students to send feedback to the teacher in 4 possible ways:
|
||||
|
||||
* Web page (requires URL of the web page, for example http://myserver.com/feedbackform.html)
|
||||
* Feedback form (requires URL of the form script, for example http://myserver.com/cgi-bin/formmail.pl)
|
||||
* Moodle forum - The forum index for the course will be displayed
|
||||
* Moodle messaging - The Moodle instant messaging window will be displayed. If the course has several teachers, the student will be prompted to select a teacher before the messaging window appears.';
|
||||
$string['textsourcefilename'] = 'Use file name';
|
||||
$string['textsourcefilepath'] = 'Use file path';
|
||||
$string['textsourcequiz'] = 'Get from quiz';
|
||||
$string['textsourcespecific'] = 'Specific text';
|
||||
$string['thiscourse'] = 'This course';
|
||||
$string['timedout'] = 'Timed out';
|
||||
$string['unknownreport'] = 'Report not known ({$a})';
|
||||
$string['updatequizchain'] = 'Update quiz chain';
|
||||
$string['updatequizchain_help'] = 'If enabled, if this quiz is part of a chain of Hot Potatoes quizzes, then all quizzes in the chain will be assigned identical settings to the current quiz. Otherwise, only the current quiz will be updated.';
|
||||
$string['weighting'] = 'Weighting';
|
||||
$string['wrong'] = 'Wrong';
|
||||
-2996
File diff suppressed because it is too large
Load Diff
@@ -1,251 +0,0 @@
|
||||
<?php
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Media plugin filtering
|
||||
//
|
||||
// This filter will replace any links to a media file with
|
||||
// a media plugin that plays that media inline
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
/// This is the filtering function itself. It accepts the
|
||||
/// courseid and the text to be filtered (in HTML form).
|
||||
|
||||
function hotpot_mediaplayer_moodle(&$hotpot, $text) {
|
||||
global $CFG, $OUTPUT;
|
||||
|
||||
if ($CFG->filter_mediaplugin_enable_mp3) {
|
||||
static $c;
|
||||
|
||||
if (empty($c)) {
|
||||
$c = $OUTPUT->filter_mediaplugin_colors(); // You can set this up in your theme/xxx/config.php
|
||||
}
|
||||
// $c = htmlentities($c); // Commented out pending bug 5223
|
||||
$search = '/<a(.*?)href=\"([^<]+)\.mp3\"([^>]*)>(.*?)<\/a>/is';
|
||||
|
||||
$replace = '\\0 <object class="mediaplugin mp3" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"';
|
||||
$replace .= ' codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0" ';
|
||||
$replace .= ' width="90" height="15" id="mp3player">';
|
||||
$replace .= " <param name=\"movie\" value=\"$CFG->wwwroot/filter/mediaplugin/mp3player.swf?src=\\2.mp3\" />";
|
||||
$replace .= ' <param name="quality" value="high" />';
|
||||
$replace .= ' <param name="bgcolor" value="#333333" />';
|
||||
$replace .= ' <param name="flashvars" value="'.$c.'" />';
|
||||
$replace .= " <embed src=\"$CFG->wwwroot/filter/mediaplugin/mp3player.swf?src=\\2.mp3\" ";
|
||||
$replace .= " quality=\"high\" bgcolor=\"#333333\" width=\"90\" height=\"15\" name=\"mp3player\" ";
|
||||
$replace .= ' type="application/x-shockwave-flash" ';
|
||||
$replace .= ' flashvars="'.$c.'" ';
|
||||
$replace .= ' pluginspage="http://www.macromedia.com/go/getflashplayer">';
|
||||
$replace .= '</embed>';
|
||||
$replace .= '</object> ';
|
||||
|
||||
$text = preg_replace($search, $replace, $text);
|
||||
}
|
||||
|
||||
if ($CFG->filter_mediaplugin_enable_swf) {
|
||||
$search = array(
|
||||
'/<a(.*?)href=\"([^<]+)\.swf\?d=([\d]{1,3}%?)x([\d]{1,3}%?)\"([^>]*)>(.*?)<\/a>/is',
|
||||
'/<a(.*?)href=\"([^<]+)\.swf\"([^>]*)>(.*?)<\/a>/is'
|
||||
);
|
||||
|
||||
$replace = array();
|
||||
|
||||
$replace[0] = '\\0<p class="mediaplugin swf"><object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"';
|
||||
$replace[0] .= ' codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0" ';
|
||||
$replace[0] .= ' width="\\3" height="\\4" id="mp3player">';
|
||||
$replace[0] .= " <param name=\"movie\" value=\"\\2.swf\" />";
|
||||
$replace[0] .= ' <param name="quality" value="high" />';
|
||||
$replace[0] .= ' <param name="AllowScriptAccess" value="never" />';
|
||||
$replace[0] .= " <embed src=\"\\2.swf\" ";
|
||||
$replace[0] .= ' quality="high" width="\\3" height="\\4" name="flashfilter" AllowScriptAccess="never" ';
|
||||
$replace[0] .= ' type="application/x-shockwave-flash" ';
|
||||
$replace[0] .= ' pluginspage="http://www.macromedia.com/go/getflashplayer">';
|
||||
$replace[0] .= '</embed>';
|
||||
$replace[0] .= '</object></p>';
|
||||
|
||||
$replace[1] = '\\0<p class="mediaplugin swf"><object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"';
|
||||
$replace[1] .= ' codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0" ';
|
||||
$replace[1] .= ' width="400" height="300" id="mp3player">';
|
||||
$replace[1] .= " <param name=\"movie\" value=\"\\2.swf\" />";
|
||||
$replace[1] .= ' <param name="quality" value="high" />';
|
||||
$replace[1] .= ' <param name="AllowScriptAccess" value="never" />';
|
||||
$replace[1] .= " <embed src=\"\\2.swf\" ";
|
||||
$replace[1] .= ' quality="high" width="400" height="300" name="flashfilter" AllowScriptAccess="never" ';
|
||||
$replace[1] .= ' type="application/x-shockwave-flash" ';
|
||||
$replace[1] .= ' pluginspage="http://www.macromedia.com/go/getflashplayer">';
|
||||
$replace[1] .= '</embed>';
|
||||
$replace[1] .= '</object></p>';
|
||||
|
||||
$text = preg_replace($search, $replace, $text);
|
||||
|
||||
}
|
||||
|
||||
if ($CFG->filter_mediaplugin_enable_flv) {
|
||||
$search = '/<a(.*?)href=\"([^<]+)\.flv\"([^>]*)>(.*?)<\/a>/is';
|
||||
|
||||
$replace = '\\0 <object class="mediaplugin flv" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"';
|
||||
$replace .= ' codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0" ';
|
||||
$replace .= ' width="480" height="360" id="flvplayer">';
|
||||
$replace .= " <param name=\"movie\" value=\"$CFG->wwwroot/filter/mediaplugin/flvplayer.swf?file=\\2.flv\" />";
|
||||
$replace .= ' <param name="quality" value="high" />';
|
||||
$replace .= ' <param name="bgcolor" value="#FFFFFF" />';
|
||||
$replace .= " <embed src=\"$CFG->wwwroot/filter/mediaplugin/flvplayer.swf?file=\\2.flv\" ";
|
||||
$replace .= " quality=\"high\" bgcolor=\"#FFFFFF\" width=\"480\" height=\"360\" name=\"flvplayer\" ";
|
||||
$replace .= ' type="application/x-shockwave-flash" ';
|
||||
$replace .= ' pluginspage="http://www.macromedia.com/go/getflashplayer">';
|
||||
$replace .= '</embed>';
|
||||
$replace .= '</object> ';
|
||||
|
||||
$text = preg_replace($search, $replace, $text);
|
||||
}
|
||||
|
||||
if ($CFG->filter_mediaplugin_enable_mov) {
|
||||
$search = '/<a(.*?)href=\"([^<]+)\.mov\"([^>]*)>(.*?)<\/a>/is';
|
||||
|
||||
$replace = '\\0<p class="mediaplugin mov"><object classid="CLSID:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"';
|
||||
$replace .= ' codebase="http://www.apple.com/qtactivex/qtplugin.cab" ';
|
||||
$replace .= ' height="300" width="400"';
|
||||
$replace .= ' id="quicktime" type="application/x-oleobject">';
|
||||
$replace .= "<param name=\"src\" value=\"\\2.mov\" />";
|
||||
$replace .= '<param name="autoplay" value="false" />';
|
||||
$replace .= '<param name="loop" value="true" />';
|
||||
$replace .= '<param name="controller" value="true" />';
|
||||
$replace .= '<param name="scale" value="aspect" />';
|
||||
$replace .= "\n<embed src=\"\\2.mov\" name=\"quicktime\" type=\"video/quicktime\" ";
|
||||
$replace .= ' height="300" width="400" scale="aspect" ';
|
||||
$replace .= ' autoplay="false" controller="true" loop="true" ';
|
||||
$replace .= ' pluginspage="http://quicktime.apple.com/">';
|
||||
$replace .= '</embed>';
|
||||
$replace .= '</object></p>';
|
||||
|
||||
$text = preg_replace($search, $replace, $text);
|
||||
}
|
||||
|
||||
if ($CFG->filter_mediaplugin_enable_wmv) {
|
||||
$search = '/<a(.*?)href=\"([^<]+)\.wmv\"([^>]*)>(.*?)<\/a>/is';
|
||||
|
||||
$replace = '\\0<p class="mediaplugin wmv"><object classid="CLSID:22D6f312-B0F6-11D0-94AB-0080C74C7E95"';
|
||||
$replace .= ' codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701" ';
|
||||
$replace .= ' standby="Loading Microsoft� Windows� Media Player components..." ';
|
||||
$replace .= ' id="msplayer" type="application/x-oleobject">';
|
||||
$replace .= "<param name=\"Filename\" value=\"\\2.wmv\" />";
|
||||
$replace .= '<param name="ShowControls" value="true" />';
|
||||
$replace .= '<param name="AutoRewind" value="true" />';
|
||||
$replace .= '<param name="AutoStart" value="false" />';
|
||||
$replace .= '<param name="Autosize" value="true" />';
|
||||
$replace .= '<param name="EnableContextMenu" value="true" />';
|
||||
$replace .= '<param name="TransparentAtStart" value="false" />';
|
||||
$replace .= '<param name="AnimationAtStart" value="false" />';
|
||||
$replace .= '<param name="ShowGotoBar" value="false" />';
|
||||
$replace .= '<param name="EnableFullScreenControls" value="true" />';
|
||||
$replace .= "\n<embed src=\"\\2.wmv\" name=\"msplayer\" type=\"video/x-ms\" ";
|
||||
$replace .= ' ShowControls="1" AutoRewind="1" AutoStart="0" Autosize="0" EnableContextMenu="1"';
|
||||
$replace .= ' TransparentAtStart="0" AnimationAtStart="0" ShowGotoBar="0" EnableFullScreenControls="1"';
|
||||
$replace .= ' pluginspage="http://www.microsoft.com/Windows/Downloads/Contents/Products/MediaPlayer/">';
|
||||
$replace .= '</embed>';
|
||||
$replace .= '</object></p>';
|
||||
|
||||
$text = preg_replace($search, $replace, $text);
|
||||
}
|
||||
|
||||
if ($CFG->filter_mediaplugin_enable_mpg) {
|
||||
$search = '/<a(.*?)href=\"([^<]+)\.(mpe?g)\"([^>]*)>(.*?)<\/a>/is';
|
||||
|
||||
$replace = '\\0<p class="mediaplugin mpg"><object width="240" height="180">';
|
||||
$replace .= '<param name="src" value="\\2.\\3" />';
|
||||
$replace .= '<param name="controller" value="true" />';
|
||||
$replace .= '<param name="autoplay" value="false" />';
|
||||
$replace .= '<embed src="\\2.\\3" width="240" height="180" controller="true" autoplay="false"> </embed>';
|
||||
$replace .= '</object></p>';
|
||||
|
||||
$text = preg_replace($search, $replace, $text);
|
||||
}
|
||||
|
||||
if ($CFG->filter_mediaplugin_enable_avi) {
|
||||
$search = '/<a(.*?)href=\"([^<]+)\.avi\"([^>]*)>(.*?)<\/a>/is';
|
||||
|
||||
$replace = '\\0<p class="mediaplugin avi"><object width="240" height="180">';
|
||||
$replace .= '<param name="src" value="\\2.avi" />';
|
||||
$replace .= '<param name="controller" value="true" />';
|
||||
$replace .= '<param name="autoplay" value="false" />';
|
||||
$replace .= '<embed src="\\2.avi" width="240" height="180" controller="true" autoplay="false"> </embed>';
|
||||
$replace .= '</object></p>';
|
||||
|
||||
$text = preg_replace($search, $replace, $text);
|
||||
}
|
||||
|
||||
if ($CFG->filter_mediaplugin_enable_ram) {
|
||||
$search = '/<a(.*?)href=\"([^<]+)\.ram\"([^>]*)>(.*?)<\/a>/is';
|
||||
|
||||
$replace = '\\0<p class="mediaplugin ram"><object width="240" height="180">';
|
||||
$replace .= '<param name="src" value="\\2.ram" />';
|
||||
$replace .= '<param name="autostart" value="true" />';
|
||||
$replace .= '<param name="controls" value="imagewindow" />';
|
||||
$replace .= '<param name="console" value="video" />';
|
||||
$replace .= '<param name="loop" value="true" />';
|
||||
$replace .= '<embed src="\\2.ram" width=240" height="180" loop="true" type="audio/x-pn-realaudio-plugin" controls="imagewindow" console="video" autostart="true">';
|
||||
$replace .= '</embed>';
|
||||
$replace .= '</object><br />';
|
||||
|
||||
$replace .= '<object width="320" height="30">';
|
||||
$replace .= '<param name="src" value="\\2.ram" />';
|
||||
$replace .= '<param name="autostart" value="true" />';
|
||||
$replace .= '<param name="controls" value="ControlPanel" />';
|
||||
$replace .= '<param name="console" value="video" />';
|
||||
$replace .= '<embed src="\\2.ram" width="240" height="30" controls="ControlPanel" type="audio/x-pn-realaudio-plugin" console="video" autostart="true">';
|
||||
$replace .= '</embed>';
|
||||
$replace .= '</object></p>';
|
||||
|
||||
$text = preg_replace($search, $replace, $text);
|
||||
}
|
||||
|
||||
if ($CFG->filter_mediaplugin_enable_rpm) {
|
||||
$search = '/<a(.*?)href=\"([^<]+)\.rpm\"([^>]*)>(.*?)<\/a>/is';
|
||||
|
||||
$replace = '\\0<p class="mediaplugin rpm"><object width="240" height="180">';
|
||||
$replace .= '<param name="src" value="\\2.rpm" />';
|
||||
$replace .= '<param name="autostart" value="true" />';
|
||||
$replace .= '<param name="controls" value="imagewindow" />';
|
||||
$replace .= '<param name="console" value="video" />';
|
||||
$replace .= '<param name="loop" value="true" />';
|
||||
$replace .= '<embed src="\\2.rpm" width=240" height="180" loop="true" type="audio/x-pn-realaudio-plugin" controls="imagewindow" console="video" autostart="true">';
|
||||
$replace .= '</embed>';
|
||||
$replace .= '</object><br />';
|
||||
|
||||
$replace .= '<object width="320" height="30">';
|
||||
$replace .= '<param name="src" value="\\2.rpm" />';
|
||||
$replace .= '<param name="autostart" value="true" />';
|
||||
$replace .= '<param name="controls" value="ControlPanel" />';
|
||||
$replace .= '<param name="console" value="video" />';
|
||||
$replace .= '<embed src="\\2.rpm" width="240" height="30" controls="ControlPanel" type="audio/x-pn-realaudio-plugin" console="video" autostart="true">';
|
||||
$replace .= '</embed>';
|
||||
$replace .= '</object></p>';
|
||||
|
||||
$text = preg_replace($search, $replace, $text);
|
||||
}
|
||||
|
||||
if ($CFG->filter_mediaplugin_enable_rm) {
|
||||
$search = '/<a(.*?)href=\"([^<]+)\.rm\"([^>]*)>(.*?)<\/a>/is';
|
||||
|
||||
$replace = '\\0<p class="mediaplugin rm"><object width="240" height="180">';
|
||||
$replace .= '<param name="src" value="\\2.rm" />';
|
||||
$replace .= '<param name="autostart" value="true" />';
|
||||
$replace .= '<param name="controls" value="imagewindow" />';
|
||||
$replace .= '<param name="console" value="video" />';
|
||||
$replace .= '<param name="loop" value="true" />';
|
||||
$replace .= '<embed src="\\2.rm" width=240" height="180" loop="true" type="audio/x-pn-realaudio-plugin" controls="imagewindow" console="video" autostart="true">';
|
||||
$replace .= '</embed>';
|
||||
$replace .= '</object><br />';
|
||||
|
||||
$replace .= '<object width="320" height="30">';
|
||||
$replace .= '<param name="src" value="\\2.rm" />';
|
||||
$replace .= '<param name="autostart" value="true" />';
|
||||
$replace .= '<param name="controls" value="ControlPanel" />';
|
||||
$replace .= '<param name="console" value="video" />';
|
||||
$replace .= '<embed src="\\2.rm" width="240" height="30" controls="ControlPanel" type="audio/x-pn-realaudio-plugin" console="video" autostart="true">';
|
||||
$replace .= '</embed>';
|
||||
$replace .= '</object></p>';
|
||||
|
||||
$text = preg_replace($search, $replace, $text);
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
//<!--
|
||||
//<![CDATA[
|
||||
|
||||
function getObjValue(obj) {
|
||||
var v = ''; // the value
|
||||
var t = (obj && obj.type) ? obj.type : "";
|
||||
if (t=="text" || t=="textarea" || t=="hidden") {
|
||||
v = obj.value;
|
||||
} else if (t=="select-one" || t=="select-multiple") {
|
||||
var l = obj.options.length;
|
||||
for (var i=0; i<l; i++) {
|
||||
if (obj.options[i].selected) {
|
||||
v += (v=="" ? "" : ",") + obj.options[i].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
function getDir(s) {
|
||||
if (s.substring(0,7)=='http://' || s.substring(0,8)=='https://') {
|
||||
return '';
|
||||
}
|
||||
if (s.charAt(0) != '/') {
|
||||
s = '/' + s;
|
||||
}
|
||||
return s.substring(0, s.lastIndexOf('/'));
|
||||
}
|
||||
function AddWhiteSpace(BeforeOrAfter, id) {
|
||||
if (document.getElementById) {
|
||||
// locate the DIV object (class="fitem") containing the target element
|
||||
var obj = document.getElementById(id);
|
||||
while (obj && !(obj.className && (obj.className=='fitem' || obj.className.substring(0,6)=='fitem '))) {
|
||||
obj = obj.parentNode;
|
||||
}
|
||||
if (obj) {
|
||||
switch (BeforeOrAfter) {
|
||||
case 'before': obj.style.marginTop = '1.8em'; break;
|
||||
case 'after': obj.style.marginBottom = '0.8em'; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AddWhiteSpace('after', 'id_name');
|
||||
AddWhiteSpace('before', 'id_quizchain');
|
||||
AddWhiteSpace('before', 'id_password');
|
||||
AddWhiteSpace('before', 'id_review');
|
||||
//]]>
|
||||
//-->
|
||||
@@ -1,338 +0,0 @@
|
||||
<?php
|
||||
if (!defined('MOODLE_INTERNAL')) {
|
||||
die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
|
||||
}
|
||||
|
||||
require_once ($CFG->dirroot.'/course/moodleform_mod.php');
|
||||
require_once ($CFG->dirroot.'/mod/hotpot/lib.php');
|
||||
|
||||
$HOTPOT_TEXTSOURCE = array(
|
||||
HOTPOT_TEXTSOURCE_QUIZ => get_string('textsourcequiz', 'hotpot'),
|
||||
HOTPOT_TEXTSOURCE_FILENAME => get_string('textsourcefilename', 'hotpot'),
|
||||
HOTPOT_TEXTSOURCE_FILEPATH => get_string('textsourcefilepath', 'hotpot'),
|
||||
HOTPOT_TEXTSOURCE_SPECIFIC => get_string('textsourcespecific', 'hotpot')
|
||||
);
|
||||
|
||||
class mod_hotpot_mod_form extends moodleform_mod {
|
||||
// documentation on formslib.php here:
|
||||
// http://docs.moodle.org/en/Development:lib/formslib.php_Form_Definition
|
||||
|
||||
function definition() {
|
||||
// TO DO
|
||||
// =====
|
||||
// $mform->setType('name', PARAM_xxx);
|
||||
// $mform->setDefault('name', array('elementhelpfilename', get_string('helpicontitlestring', 'hotpot'), 'hotpot'));
|
||||
|
||||
global $CFG, $COURSE, $OUTPUT;
|
||||
global $HOTPOT_FEEDBACK, $HOTPOT_GRADEMETHOD, $HOTPOT_LOCATION;
|
||||
global $HOTPOT_NAVIGATION, $HOTPOT_OUTPUTFORMAT, $HOTPOT_TEXTSOURCE;
|
||||
|
||||
$mform =&$this->_form;
|
||||
|
||||
// initialize values for $hours, $minutes and $seconds
|
||||
$hours = array();
|
||||
$minutes = array();
|
||||
$seconds = array();
|
||||
for ($i=0; $i<60; $i++) {
|
||||
$str = sprintf('%02d', $i);
|
||||
if ($i<24) {
|
||||
$hours[$i] = $str;
|
||||
}
|
||||
$minutes[$i] = $str;
|
||||
$seconds[$i] = $str;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
$mform->addElement('header', 'general', get_string('general', 'form'));
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
|
||||
// Name
|
||||
global $form;
|
||||
if (isset($form->add)) {
|
||||
// new HotPot
|
||||
$elements = array();
|
||||
$elements[] = &$mform->createElement('select', 'namesource', '', $HOTPOT_TEXTSOURCE);
|
||||
$elements[] = &$mform->createElement('text', 'name', '', array('size' => '40'));
|
||||
$mform->addGroup($elements, 'name_elements', get_string('name'), array(' '), false);
|
||||
$mform->disabledIf('name_elements', 'namesource', 'ne', HOTPOT_TEXTSOURCE_SPECIFIC);
|
||||
// $mform->setAdvanced('name_elements');
|
||||
} else {
|
||||
// existing HotPot
|
||||
$mform->addElement('hidden', 'namesource', HOTPOT_TEXTSOURCE_SPECIFIC);
|
||||
$mform->setType('namesource', PARAM_RAW);
|
||||
$mform->addElement('text', 'name', get_string('name'), array('size' => '40'));
|
||||
}
|
||||
$mform->setType('namesource', PARAM_INT);
|
||||
if (!empty($CFG->formatstringstriptags)) {
|
||||
$mform->setType('name', PARAM_TEXT);
|
||||
} else {
|
||||
$mform->setType('name', PARAM_CLEAN);
|
||||
}
|
||||
|
||||
// Location
|
||||
$sitecontext = get_context_instance(CONTEXT_SYSTEM);
|
||||
if (has_capability('moodle/course:managefiles', $sitecontext)) {
|
||||
$site = get_site();
|
||||
if ($COURSE->id==$site->id) {
|
||||
$id = $site->id;
|
||||
$location = HOTPOT_LOCATION_SITEFILES;
|
||||
} else {
|
||||
$id = "'+(getObjValue(this.form.location)==".HOTPOT_LOCATION_SITEFILES."?".$site->id.":".$COURSE->id.")+'";
|
||||
$location = '';
|
||||
}
|
||||
} else { // ordinary teacher or content creator
|
||||
$id = $COURSE->id;
|
||||
$location = HOTPOT_LOCATION_COURSEFILES;
|
||||
}
|
||||
if (array_key_exists($location, $HOTPOT_LOCATION)) {
|
||||
$mform->addElement('hidden', 'location', $location);
|
||||
$mform->setType('location', PARAM_RAW);
|
||||
} else { // admin can select from "site" or "course" files
|
||||
$mform->addElement('select', 'location', get_string('location', 'hotpot'), $HOTPOT_LOCATION);
|
||||
}
|
||||
$mform->setType('location', PARAM_INT);
|
||||
|
||||
// Reference
|
||||
// create "Choose file" button
|
||||
$choosefile_button = $mform->createElement('button', 'popup', get_string('chooseafile', 'resource') .' ...');
|
||||
|
||||
// create a 'reference' group of form elements, comprising text box + buttons
|
||||
$elements = array();
|
||||
$elements[] = $mform->createElement('text', 'reference', '', array('size'=>'60'));
|
||||
$elements[] = &$choosefile_button;
|
||||
$mform->addGroup($elements, 'reference_elements', get_string('filename', 'resource'), ' ' , false);
|
||||
|
||||
// set attributes on the button
|
||||
if ($choosefile_button) {
|
||||
$wdir = "'+getDir(this.form.reference.value)+'";
|
||||
$url="/files/index.php?id=$id&wdir=$wdir&choose=id_reference";
|
||||
$attributes = array(
|
||||
'title'=>get_string('chooseafile', 'resource')
|
||||
);
|
||||
$choosefile_button->updateAttributes($attributes);
|
||||
|
||||
//attach the onclick event
|
||||
$action = new popup_action('click', $url, $choosefile_button->getName(), array('title'=>$choosefile_button->getName(),'width'=>750,'height'=>500));
|
||||
$OUTPUT->add_action_handler($action, $choosefile_button->id);
|
||||
}
|
||||
$mform->setType('reference', PARAM_TEXT);
|
||||
|
||||
// Summary
|
||||
if (isset($form->add)) {
|
||||
// new HotPot
|
||||
$elements = array();
|
||||
$elements[] = &$mform->createElement('select', 'summarysource', '', $HOTPOT_TEXTSOURCE);
|
||||
$elements[] = &$mform->createElement('htmleditor', 'summary', '');
|
||||
$mform->addGroup($elements, 'summary_elements', get_string('summary'), array(' '), false);
|
||||
$mform->setAdvanced('summary_elements');
|
||||
} else {
|
||||
// existing HotPot
|
||||
$mform->addElement('hidden', 'summarysource', HOTPOT_TEXTSOURCE_SPECIFIC);
|
||||
$mform->setType('summarysource', PARAM_RAW);
|
||||
$mform->addElement('htmleditor', 'summary', get_string('summary'));
|
||||
$mform->setType('summary', PARAM_RAW);
|
||||
$mform->setAdvanced('summary');
|
||||
}
|
||||
$mform->setType('summarysource', PARAM_INT);
|
||||
$mform->setType('summary', PARAM_RAW);
|
||||
|
||||
// Add/Update quiz chain?
|
||||
if (isset($form->add)) {
|
||||
$quizchain = 'addquizchain';
|
||||
} else {
|
||||
$quizchain = 'updatequizchain';
|
||||
}
|
||||
$mform->addElement('selectyesno', 'quizchain', get_string($quizchain, 'hotpot'));
|
||||
$mform->setDefault('quizchain', get_user_preferences("hotpot_$quizchain", HOTPOT_NO));
|
||||
$mform->setHelpButton('quizchain', array($quizchain, get_string($quizchain, 'hotpot'), 'hotpot'));
|
||||
// $mform->setAdvanced('quizchain');
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
$mform->addElement('header', 'displayhdr', get_string('display', 'form'));
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
|
||||
// Output format
|
||||
$mform->addElement('select', 'outputformat', get_string('outputformat', 'hotpot'), $HOTPOT_OUTPUTFORMAT);
|
||||
$mform->setDefault('outputformat', get_user_preferences('hotpot_outputformat', HOTPOT_OUTPUTFORMAT_BEST));
|
||||
$mform->setHelpButton('outputformat', array('outputformat', get_string('outputformat', 'hotpot'), 'hotpot'));
|
||||
|
||||
// Navigation
|
||||
$mform->addElement('select', 'navigation', get_string('navigation', 'hotpot'), $HOTPOT_NAVIGATION);
|
||||
$mform->setDefault('navigation', get_user_preferences('hotpot_navigation', HOTPOT_NAVIGATION_BAR));
|
||||
$mform->setHelpButton('navigation', array('navigation', get_string('navigation', 'hotpot'), 'hotpot'));
|
||||
|
||||
// Use Moode player ?
|
||||
$mform->addElement('selectyesno', 'forceplugins', get_string('forceplugins', 'hotpot'));
|
||||
$mform->setDefault('forceplugins', get_user_preferences('hotpot_forceplugins', HOTPOT_NO));
|
||||
$mform->setHelpButton('forceplugins', array('forceplugins', get_string('forceplugins', 'hotpot'), 'hotpot'));
|
||||
// $mform->setAdvanced('forceplugins');
|
||||
|
||||
// Student feedback
|
||||
$elements = array();
|
||||
$elements[] = &$mform->createElement('select', 'studentfeedback', '', $HOTPOT_FEEDBACK);
|
||||
$elements[] = &$mform->createElement('text', 'studentfeedbackurl', '', array('size'=>'50'));
|
||||
$mform->addGroup($elements, 'studentfeedback_elements', get_string('studentfeedback', 'hotpot'), array(' '), false);
|
||||
$mform->setHelpButton('studentfeedback_elements', array('studentfeedback', get_string('studentfeedback', 'hotpot'), 'hotpot'));
|
||||
$mform->disabledIf('studentfeedback_elements', 'studentfeedback', 'eq', HOTPOT_FEEDBACK_NONE);
|
||||
$mform->disabledIf('studentfeedback_elements', 'studentfeedback', 'eq', HOTPOT_FEEDBACK_MOODLEFORUM);
|
||||
$mform->disabledIf('studentfeedback_elements', 'studentfeedback', 'eq', HOTPOT_FEEDBACK_MOODLEMESSAGING);
|
||||
// $mform->setAdvanced('studentfeedback_elements');
|
||||
$mform->setType('studentfeedbackurl', PARAM_URL);
|
||||
|
||||
// Show next quiz ?
|
||||
$mform->addElement('selectyesno', 'shownextquiz', get_string('shownextquiz', 'hotpot'));
|
||||
$mform->setDefault('shownextquiz', get_user_preferences('hotpot_shownextquiz', HOTPOT_NO));
|
||||
$mform->setHelpButton('shownextquiz', array('shownextquiz', get_string('shownextquiz', 'hotpot'), 'hotpot'));
|
||||
// $mform->setAdvanced('forceplugins');
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
$mform->addElement('header', 'accesscontrolhdr', get_string('accesscontrol', 'lesson'));
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
|
||||
// Open time
|
||||
$mform->addElement('date_time_selector', 'timeopen', get_string('quizopen', 'quiz'), array('optional'=>true));
|
||||
$mform->setHelpButton('timeopen', array('timeopen', get_string('quizopen', 'quiz'), 'quiz'));
|
||||
|
||||
// Close time
|
||||
$mform->addElement('date_time_selector', 'timeclose', get_string('quizclose', 'quiz'), array('optional'=>true));
|
||||
$mform->setHelpButton('timeclose', array('timeopen', get_string('quizclose', 'quiz'), 'quiz'));
|
||||
|
||||
// Password
|
||||
$mform->addElement('text', 'password', get_string('requirepassword', 'quiz'));
|
||||
$mform->setType('password', PARAM_TEXT);
|
||||
$mform->setHelpButton('password', array('requirepassword', get_string('requirepassword', 'quiz'), 'quiz'));
|
||||
// $mform->setAdvanced('password');
|
||||
|
||||
// Subnet
|
||||
$mform->addElement('text', 'subnet', get_string('requiresubnet', 'quiz'));
|
||||
$mform->setType('subnet', PARAM_TEXT);
|
||||
$mform->setHelpButton('subnet', array('requiresubnet', get_string('requiresubnet', 'quiz'), 'quiz'));
|
||||
$mform->setDefault('subnet', get_user_preferences('hotpot_subnet'));
|
||||
// $mform->setAdvanced('subnet');
|
||||
|
||||
// Allow review?
|
||||
$mform->addElement('selectyesno', 'review', get_string('allowreview', 'quiz'));
|
||||
$mform->setDefault('review', get_user_preferences('hotpot_review', HOTPOT_YES));
|
||||
$mform->setHelpButton('review', array('review', get_string('allowreview', 'quiz'), 'quiz'));
|
||||
// $mform->setAdvanced('forceplugins');
|
||||
|
||||
// Maximum number of attempts
|
||||
$options = array(
|
||||
0 => get_string("attemptsunlimited", "quiz"),
|
||||
1 => '1 '.strtolower(get_string("attempt", "quiz"))
|
||||
);
|
||||
for ($i=2; $i<=10; $i++) {
|
||||
$options[$i] = "$i ".strtolower(get_string("attempts", "quiz"));
|
||||
}
|
||||
$mform->addElement('select', 'attempts', get_string('attemptsallowed', 'quiz'), $options);
|
||||
$mform->setDefault('attempts', get_user_preferences('hotpot_attempts', 0)); // 0=unlimited
|
||||
$mform->setHelpButton('attempts', array('attempts', get_string('attemptsallowed', 'quiz'), 'quiz'));
|
||||
// $mform->setAdvanced('forceplugins');
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
$mform->addElement('header', 'gradeshdr', get_string('grades', 'grades'));
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
|
||||
// Maximum grade
|
||||
$options = array();
|
||||
for ($i=100; $i>=1; $i--) {
|
||||
$options[$i] = $i;
|
||||
}
|
||||
$options[0] = get_string("nograde");
|
||||
$mform->addElement('select', 'grade', get_string('maximumgrade'), $options);
|
||||
$mform->setDefault('grade', get_user_preferences('hotpot_grade', 100));
|
||||
$mform->setHelpButton('grade', array('maxgrade', get_string('maximumgrade'), 'quiz'));
|
||||
// $mform->setAdvanced('forceplugins');
|
||||
|
||||
// Maximum grading method
|
||||
$mform->addElement('select', 'grademethod', get_string('grademethod', 'quiz'), $HOTPOT_GRADEMETHOD);
|
||||
$mform->setDefault('grademethod', get_user_preferences('hotpot_grademethod', HOTPOT_GRADEMETHOD_HIGHEST));
|
||||
$mform->setHelpButton('grademethod', array('grademethod', get_string('grademethod', 'quiz'), 'quiz'));
|
||||
// $mform->setAdvanced('forceplugins');
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
$mform->addElement('header', 'reportshdr', get_string('reports'));
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
|
||||
// Enable click reporting?
|
||||
$mform->addElement('selectyesno', 'clickreporting', get_string('clickreporting', 'hotpot'));
|
||||
$mform->setDefault('clickreporting', get_user_preferences('hotpot_clickreporting', HOTPOT_NO));
|
||||
$mform->setHelpButton('clickreporting', array('clickreporting', get_string('clickreporting', 'hotpot'), 'hotpot'));
|
||||
// $mform->setAdvanced('forceplugins');
|
||||
|
||||
//----------------------------------------------
|
||||
$features = new stdClass;
|
||||
$features->groups = true;
|
||||
$features->groupings = true;
|
||||
$features->groupmembersonly = true;
|
||||
$this->standard_coursemodule_elements($features);
|
||||
//----------------------------------------------
|
||||
|
||||
$this->add_action_buttons();
|
||||
|
||||
$js = '<script type="text/javascript" src="'.$CFG->wwwroot.'/mod/hotpot/mod_form.js"></script>';
|
||||
$mform->addElement('static', 'hotpot_mod_form_js', '', $js);
|
||||
}
|
||||
|
||||
function data_preprocessing(&$defaults){
|
||||
}
|
||||
|
||||
function validation($data, $files) {
|
||||
global $CFG, $USER, $DB, $COURSE;
|
||||
|
||||
$errors = parent::validation($data, $files);
|
||||
|
||||
// location
|
||||
if (empty($data['location'])) {
|
||||
// this shouldn't happen
|
||||
$data['location'] = $COURSE->id;
|
||||
} else {
|
||||
if ($data['location']==$COURSE->id) {
|
||||
// this is normal
|
||||
} else if ($data['location']==SITEID && has_capability('moodle/course:managefiles', get_context_instance(CONTEXT_SYSTEM))) {
|
||||
// admin can access site files
|
||||
} else {
|
||||
// location is invalid or missing, so set to default
|
||||
$data['location'] = $COURSE->id;
|
||||
}
|
||||
}
|
||||
|
||||
// reference
|
||||
if (isset($data['reference'])) {
|
||||
$data['reference'] = trim($data['reference']);
|
||||
}
|
||||
if (empty($data['reference'])) {
|
||||
$errors['reference_elements'] = get_string('error_nofilename', 'hotpot');
|
||||
} else {
|
||||
if (preg_match('|^https?://|', $data['reference'])) {
|
||||
// URL
|
||||
$errors['reference_elements'] = 'Sorry, handling of URLs is not implemented yet';
|
||||
} else {
|
||||
// course files
|
||||
$filepath = $CFG->dataroot.'/'.$data['location'].'/'.$data['reference'];
|
||||
if (! file_exists($filepath)) {
|
||||
$errors['reference_elements'] = get_string('error_pathdoesnotexist', 'hotpot', $filepath);
|
||||
} else if (! $data['quizchain'] && ! is_file($filepath)) {
|
||||
$errors['reference_elements'] = get_string('error_folderwithoutquizchain', 'hotpot');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// studentfeedbackurl
|
||||
if (empty($data['studentfeedbackurl']) || $data['studentfeedbackurl']=='http://') {
|
||||
$data['studentfeedbackurl'] = '';
|
||||
$error = false;
|
||||
if ($data['studentfeedback']==HOTPOT_FEEDBACK_WEBPAGE) {
|
||||
$error = true;
|
||||
}
|
||||
if ($data['studentfeedback']==HOTPOT_FEEDBACK_FORMMAIL) {
|
||||
$error = true;
|
||||
}
|
||||
if ($error) {
|
||||
$errors['studentfeedback_elements']= get_string('error_nofeedbackurlformmail', 'hotpot');
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 415 B |
@@ -1,667 +0,0 @@
|
||||
<?php
|
||||
|
||||
// This script uses installed report plugins to print quiz reports
|
||||
|
||||
require_once("../../config.php");
|
||||
require_once("lib.php");
|
||||
|
||||
$id = optional_param('id', 0, PARAM_INT); // Course Module ID, or
|
||||
$hp = optional_param('hp', 0, PARAM_INT); // hotpot ID
|
||||
|
||||
if ($id) {
|
||||
$PAGE->set_url('/mod/hotpot/report.php', array('id'=>$id));
|
||||
if (! $cm = get_coursemodule_from_id('hotpot', $id)) {
|
||||
print_error('invalidcoursemodule');
|
||||
}
|
||||
if (! $course = $DB->get_record("course", array("id"=>$cm->course))) {
|
||||
print_error('coursemisconf');
|
||||
}
|
||||
if (! $hotpot = $DB->get_record("hotpot", array("id"=>$cm->instance))) {
|
||||
print_error('invalidhotpotid', 'hotpot');
|
||||
}
|
||||
|
||||
} else {
|
||||
$PAGE->set_url('/mod/hotpot/report.php', array('hp'=>$hp));
|
||||
if (! $hotpot = $DB->get_record("hotpot", array("id"=>$hp))) {
|
||||
print_error('invalidhotpotid', 'hotpot');
|
||||
}
|
||||
if (! $course = $DB->get_record("course", array("id"=>$hotpot->course))) {
|
||||
print_error('coursemisconf');
|
||||
}
|
||||
if (! $cm = get_coursemodule_from_instance("hotpot", $hotpot->id, $course->id)) {
|
||||
print_error('invalidcoursemodule');
|
||||
}
|
||||
}
|
||||
|
||||
// get the roles context for this course
|
||||
$sitecontext = get_context_instance(CONTEXT_SYSTEM);
|
||||
$modulecontext = get_context_instance(CONTEXT_MODULE, $cm->id);
|
||||
|
||||
// set homeurl of couse (for error messages)
|
||||
$course_homeurl = "$CFG->wwwroot/course/view.php?id=$course->id";
|
||||
|
||||
require_login($course, true, $cm);
|
||||
|
||||
// get report mode
|
||||
if (has_capability('mod/hotpot:viewreport',$modulecontext)) {
|
||||
$mode = optional_param('mode', 'overview', PARAM_ALPHA);
|
||||
} else {
|
||||
// ordinary students have no choice
|
||||
$mode = 'overview';
|
||||
}
|
||||
|
||||
// assemble array of form data
|
||||
$formdata = array(
|
||||
'mode' => $mode,
|
||||
'reportusers' => has_capability('mod/hotpot:viewreport',$modulecontext) ? optional_param('reportusers', get_user_preferences('hotpot_reportusers', 'allusers'), PARAM_ALPHANUM) : 'this',
|
||||
'reportattempts' => optional_param('reportattempts', get_user_preferences('hotpot_reportattempts', 'all'), PARAM_ALPHA),
|
||||
'reportformat' => optional_param('reportformat', 'htm', PARAM_ALPHA),
|
||||
'reportshowlegend' => optional_param('reportshowlegend', get_user_preferences('hotpot_reportshowlegend', '0'), PARAM_INT),
|
||||
'reportencoding' => optional_param('reportencoding', get_user_preferences('hotpot_reportencoding', ''), PARAM_ALPHANUM),
|
||||
'reportwrapdata' => optional_param('reportwrapdata', get_user_preferences('hotpot_reportwrapdata', '1'), PARAM_INT),
|
||||
);
|
||||
|
||||
foreach ($formdata as $name=>$value) {
|
||||
set_user_preference("hotpot_$name", $value);
|
||||
}
|
||||
|
||||
/// Start the report
|
||||
|
||||
add_to_log($course->id, "hotpot", "report", "report.php?id=$cm->id&mode=$mode", "$hotpot->id", "$cm->id");
|
||||
|
||||
// print page header. if required
|
||||
if ($formdata['reportformat']=='htm') {
|
||||
hotpot_print_report_heading($course, $cm, $hotpot, $mode);
|
||||
if (has_capability('mod/hotpot:viewreport',$modulecontext)) {
|
||||
hotpot_print_report_selector($course, $hotpot, $formdata);
|
||||
}
|
||||
}
|
||||
|
||||
// delete selected attempts, if any
|
||||
if (has_capability('mod/hotpot:deleteattempt',$modulecontext)) {
|
||||
$del = optional_param('del', '', PARAM_ALPHA);
|
||||
hotpot_delete_selected_attempts($hotpot, $del);
|
||||
}
|
||||
|
||||
// check for groups
|
||||
if (preg_match('/^group(\d*)$/', $formdata['reportusers'], $matches)) {
|
||||
$formdata['reportusers'] = 'group';
|
||||
$formdata['reportgroupid'] = 0;
|
||||
// validate groupid
|
||||
if ($groups = groups_get_all_groups($course->id)) {
|
||||
if (isset($groups[$matches[1]])) {
|
||||
$formdata['reportgroupid'] = $matches[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$user_ids = '';
|
||||
$users = array();
|
||||
|
||||
switch ($formdata['reportusers']) {
|
||||
|
||||
case 'allusers':
|
||||
// anyone who has ever attempted this hotpot
|
||||
if ($records = $DB->get_records('hotpot_attempts', array('hotpot'=>$hotpot->id), '', 'id,userid')) {
|
||||
foreach ($records as $record) {
|
||||
$users[$record->userid] = 0; // "0" means user is NOT currently allowed to attempt this HotPot
|
||||
}
|
||||
unset($records);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'group':
|
||||
// group members
|
||||
if ($members = groups_get_members($formdata['reportgroupid'])) {
|
||||
foreach ($members as $memberid=>$unused) {
|
||||
$users[$memberid] = 1; // "1" signifies currently recognized participant
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'allparticipants':
|
||||
// anyone currently allowed to attempt this HotPot
|
||||
if ($records = hotpot_get_users_by_capability($modulecontext, 'mod/hotpot:attempt')) {
|
||||
foreach ($records as $record) {
|
||||
$users[$record->id] = 1; // "1" means user is allowed to do this HotPot
|
||||
}
|
||||
unset($records);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'existingstudents':
|
||||
// anyone currently allowed to attempt this HotPot who is not a teacher
|
||||
$teachers = hotpot_get_users_by_capability($modulecontext, 'mod/hotpot:viewreport');
|
||||
if ($records = hotpot_get_users_by_capability($modulecontext, 'mod/hotpot:attempt')) {
|
||||
foreach ($records as $record) {
|
||||
if (empty($teachers[$record->id])) {
|
||||
$users[$record->id] = 1;
|
||||
}
|
||||
}
|
||||
unset($records);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'this': // current user only
|
||||
$user_ids = $USER->id;
|
||||
break;
|
||||
|
||||
default: // specific user selected by teacher
|
||||
if (is_numeric($formdata['reportusers'])) {
|
||||
$user_ids = $formdata['reportusers'];
|
||||
}
|
||||
}
|
||||
if (empty($user_ids) && count($users)) {
|
||||
ksort($users);
|
||||
$user_ids = join(',', array_keys($users));
|
||||
}
|
||||
if (empty($user_ids)) {
|
||||
echo $OUTPUT->heading(get_string('nousersyet'));
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
}
|
||||
|
||||
// database table and selection conditions
|
||||
$table = "{hotpot_attempts} a";
|
||||
$select = "a.hotpot=:hotpotid AND a.userid IN ($user_ids)";
|
||||
if ($mode!='overview') {
|
||||
$select .= ' AND a.status<>'.HOTPOT_STATUS_INPROGRESS;
|
||||
}
|
||||
$params = array('hotpotid'=>$hotpot->id);
|
||||
|
||||
// confine attempts if necessary
|
||||
switch ($formdata['reportattempts']) {
|
||||
case 'best':
|
||||
$function = 'MAX';
|
||||
$fieldnames = array('score', 'id', 'clickreportid');
|
||||
$defaultvalue = 0;
|
||||
break;
|
||||
case 'first':
|
||||
$function = 'MIN';
|
||||
$fieldnames = array('timefinish', 'id', 'clickreportid');
|
||||
$default_value = time();
|
||||
break;
|
||||
case 'last':
|
||||
$function = 'MAX';
|
||||
$fieldnames = array('timefinish', 'id', 'clickreportid');
|
||||
$defaultvalue = time();
|
||||
break;
|
||||
default: // 'all' and any others
|
||||
$function = '';
|
||||
$fieldnames = array();
|
||||
$defaultvalue = '';
|
||||
break;
|
||||
}
|
||||
if (empty($function) || empty($fieldnames)) {
|
||||
// do nothing (i.e. get ALL attempts)
|
||||
} else {
|
||||
$groupby = 'userid';
|
||||
$records = hotpot_get_records_groupby($function, $fieldnames, $table, $select, $params, $groupby);
|
||||
|
||||
$select = '';
|
||||
$params = array();
|
||||
if ($records) {
|
||||
$ids = array();
|
||||
foreach ($records as $record) {
|
||||
$ids[] = $record->clickreportid;
|
||||
}
|
||||
if (count($ids)) {
|
||||
$select = "a.clickreportid IN (".join(',', $ids).")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pick out last attempt in each clickreport series
|
||||
if ($select) {
|
||||
$cr_attempts = hotpot_get_records_groupby('MAX', array('timefinish', 'id'), $table, $select, $params, 'clickreportid');
|
||||
} else {
|
||||
$cr_attempts = array();
|
||||
}
|
||||
|
||||
$fields = 'a.*, u.firstname, u.lastname, u.picture';
|
||||
if ($mode=='click') {
|
||||
$fields .= ', u.idnumber';
|
||||
} else {
|
||||
// overview, simple and detailed reports
|
||||
// get last attempt record in clickreport series
|
||||
$ids = array();
|
||||
foreach ($cr_attempts as $cr_attempt) {
|
||||
$ids[] = $cr_attempt->id;
|
||||
}
|
||||
if (empty($ids)) {
|
||||
$select = "";
|
||||
} else {
|
||||
$ids = array_unique($ids);
|
||||
sort($ids);
|
||||
$select = "a.id IN (".join(',', $ids).")";
|
||||
}
|
||||
$params = array();
|
||||
}
|
||||
|
||||
$attempts = array();
|
||||
|
||||
if ($select) {
|
||||
// add user information to SQL query
|
||||
$select .= ' AND a.userid = u.id';
|
||||
$table .= ", {user} u";
|
||||
$order = "u.lastname, a.attempt, a.timefinish";
|
||||
// get the attempts (at last!)
|
||||
$attempts = $DB->get_records_sql("SELECT $fields FROM $table WHERE $select ORDER BY $order", $params);
|
||||
}
|
||||
|
||||
// stop now if no attempts were found
|
||||
if (empty($attempts)) {
|
||||
echo $OUTPUT->heading(get_string('noattemptstoshow','quiz'));
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
}
|
||||
|
||||
// get the questions
|
||||
if (!$questions = $DB->get_records('hotpot_questions', array('hotpot'=>$hotpot->id))) {
|
||||
$questions = array();
|
||||
}
|
||||
|
||||
// get grades
|
||||
$grades = hotpot_get_grades($hotpot, $user_ids);
|
||||
|
||||
// get list of attempts by user and set reference to last attempt in clickreport series
|
||||
$users = array();
|
||||
foreach ($attempts as $id=>$attempt) {
|
||||
|
||||
$userid = $attempt->userid;
|
||||
|
||||
if (!isset($users[$userid])) {
|
||||
$users[$userid]->grade = isset($grades[$userid]) ? $grades[$userid] : ' ';
|
||||
$users[$userid]->attempts = array();
|
||||
}
|
||||
|
||||
$users[$userid]->attempts[] = &$attempts[$id];
|
||||
|
||||
if ($mode=='click') {
|
||||
// shortcut to clickreportid (=the id of the FIRST attempt in this clickreport series)
|
||||
$clickreportid = $attempt->clickreportid;
|
||||
if (isset($cr_attempts[$clickreportid])) {
|
||||
// store id and finish time of LAST attempt in this clickreport series
|
||||
$attempts[$id]->cr_lastclick = $cr_attempts[$clickreportid]->id;
|
||||
$attempts[$id]->cr_timefinish = $cr_attempts[$clickreportid]->timefinish;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($mode!='overview') {
|
||||
|
||||
// initialise details of responses to questions in these attempts
|
||||
foreach ($attempts as $a=>$attempt) {
|
||||
$attempts[$a]->responses = array();
|
||||
}
|
||||
foreach ($questions as $q=>$question) {
|
||||
$questions[$q]->attempts = array();
|
||||
}
|
||||
|
||||
// get reponses to these attempts
|
||||
$attempt_ids = join(',',array_keys($attempts));
|
||||
if (!$responses = $DB->get_records_sql("SELECT * FROM {hotpot_responses} WHERE attempt IN ($attempt_ids)")) {
|
||||
$responses = array();
|
||||
}
|
||||
|
||||
// ids of questions used in these responses
|
||||
$questionids = array();
|
||||
|
||||
foreach ($responses as $response) {
|
||||
// shortcuts to the attempt and question ids
|
||||
$a = $response->attempt;
|
||||
$q = $response->question;
|
||||
|
||||
// check the attempt and question objects exist
|
||||
// (if they don't exist, something is very wrong!)
|
||||
if (isset($attempts[$a]) || isset($questions[$q])) {
|
||||
|
||||
// add the response for this attempt
|
||||
$attempts[$a]->responses[$q] = $response;
|
||||
|
||||
// add a reference from the question to the attempt which includes this question
|
||||
$questions[$q]->attempts[] = &$attempts[$a];
|
||||
|
||||
// flag this id as being used
|
||||
$questionids[$q] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// remove unused questions
|
||||
$questionids = array_keys($questionids);
|
||||
foreach ($questions as $id=>$question) {
|
||||
if (!in_array($id, $questionids)) {
|
||||
unset($questions[$id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Open the selected hotpot report and display it
|
||||
|
||||
if (! is_readable("report/$mode/report.php")) {
|
||||
print_error('unknownreport', 'hotpot', $course_homeurl, clean_text($mode));
|
||||
}
|
||||
|
||||
include("report/default.php"); // Parent class
|
||||
include("report/$mode/report.php");
|
||||
|
||||
$report = new hotpot_report();
|
||||
|
||||
if (! $report->display($hotpot, $cm, $course, $users, $attempts, $questions, $formdata)) {
|
||||
print_error('error_processreport', 'hotpot', $course_homeurl);
|
||||
}
|
||||
|
||||
if ($formdata['reportformat']=='htm') {
|
||||
echo $OUTPUT->footer();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
/// functions to delete attempts and responses
|
||||
|
||||
function hotpot_grade_heading($hotpot, $formdata) {
|
||||
|
||||
global $HOTPOT_GRADEMETHOD;
|
||||
$grademethod = $HOTPOT_GRADEMETHOD[$hotpot->grademethod];
|
||||
|
||||
if ($hotpot->grade!=100) {
|
||||
$grademethod = "$hotpot->grade x $grademethod/100";
|
||||
}
|
||||
if ($formdata['reportformat']=='htm') {
|
||||
$grademethod = '<font size="1">'.$grademethod.'</font>';
|
||||
}
|
||||
$nl = $formdata['reportformat']=='htm' ? '<br />' : "\n";
|
||||
return get_string('grade')."$nl($grademethod)";
|
||||
}
|
||||
function hotpot_delete_selected_attempts(&$hotpot, $del) {
|
||||
global $DB;
|
||||
|
||||
$select = '';
|
||||
$params = array('hotpotid'=>$hotpot->id);
|
||||
switch ($del) {
|
||||
case 'all' :
|
||||
$select = "hotpot=:hotpotid";
|
||||
break;
|
||||
case 'abandoned':
|
||||
$select = "hotpot=:hotpotid AND status=".HOTPOT_STATUS_ABANDONED;
|
||||
break;
|
||||
case 'selection':
|
||||
$ids = array();
|
||||
$data = (array)data_submitted();
|
||||
foreach ($data as $name => $value) {
|
||||
if (preg_match('/^box\d+$/', $name)) {
|
||||
$ids[] = intval($value);
|
||||
}
|
||||
}
|
||||
if (count($ids)) {
|
||||
list($ids, $idparams) = $DB->get_in_or_equal($ids, SQL_PARAMS_NAMED, 'crid0');
|
||||
$params = array_merge($params, $idparams);
|
||||
$select = "hotpot=:hotpotid AND clickreportid $ids";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// delete attempts using $select, if it is set
|
||||
if ($select) {
|
||||
|
||||
$table = 'hotpot_attempts';
|
||||
if ($attempts = $DB->get_records_select($table, $select, $params)) {
|
||||
|
||||
hotpot_delete_and_notify($table, $select, $params, get_string('attempts', 'quiz'));
|
||||
|
||||
$select = 'attempt IN ('.implode(',', array_keys($attempts)).')';
|
||||
$params = array();
|
||||
hotpot_delete_and_notify('hotpot_details', $select, $params, get_string('rawdetails', 'hotpot'));
|
||||
hotpot_delete_and_notify('hotpot_responses', $select, $params, get_string('answer', 'quiz'));
|
||||
|
||||
// update grades for all users for this hotpot
|
||||
hotpot_update_grades($hotpot);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
/// functions to print the report headings and
|
||||
/// report selector menus
|
||||
|
||||
function hotpot_print_report_heading(&$course, &$cm, &$hotpot, &$mode) {
|
||||
global $OUTPUT;
|
||||
$strmodulenameplural = get_string("modulenameplural", "hotpot");
|
||||
$strmodulename = get_string("modulename", "hotpot");
|
||||
|
||||
$modulecontext = get_context_instance(CONTEXT_MODULE, $cm->id);
|
||||
if (has_capability('mod/hotpot:viewreport',$modulecontext)) {
|
||||
if ($mode=='overview' || $mode=='simplestat' || $mode=='fullstat') {
|
||||
$module = "quiz";
|
||||
} else {
|
||||
$module = "hotpot";
|
||||
}
|
||||
|
||||
$PAGE->navbar->add(get_string("report$mode", $module));
|
||||
} else {
|
||||
$PAGE->navbar->add(get_string("report", "quiz"));
|
||||
}
|
||||
|
||||
$PAGE->set_title(format_string($course->shortname) . ": $hotpot->name");
|
||||
$PAGE->set_heading($course->fullname);
|
||||
echo $OUTPUT->header();
|
||||
|
||||
$course_context = get_context_instance(CONTEXT_COURSE, $course->id);
|
||||
if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) {
|
||||
echo '<div class="allcoursegrades"><a href="' . $CFG->wwwroot . '/grade/report/grader/index.php?id=' . $course->id . '">'
|
||||
. get_string('seeallcoursegrades', 'grades') . '</a></div>';
|
||||
}
|
||||
echo $OUTPUT->heading($hotpot->name);
|
||||
}
|
||||
function hotpot_print_report_selector(&$course, &$hotpot, &$formdata) {
|
||||
global $CFG, $DB, $OUTPUT;
|
||||
|
||||
$reports = hotpot_get_report_names('overview,simplestat,fullstat');
|
||||
|
||||
print '<form method="post" action="'."$CFG->wwwroot/mod/hotpot/report.php?hp=$hotpot->id".'">';
|
||||
print '<table cellpadding="2" align="center">';
|
||||
|
||||
$menus = array();
|
||||
|
||||
$menus['mode'] = array();
|
||||
foreach ($reports as $name) {
|
||||
if ($name=='overview' || $name=='simplestat' || $name=='fullstat') {
|
||||
$module = "quiz"; // standard reports
|
||||
} else if ($name=='click' && empty($hotpot->clickreporting)) {
|
||||
$module = ""; // clickreporting is disabled
|
||||
} else {
|
||||
$module = "hotpot"; // custom reports
|
||||
}
|
||||
if ($module) {
|
||||
$menus['mode'][$name] = get_string("report$name", $module);
|
||||
}
|
||||
}
|
||||
|
||||
$menus['reportusers'] = array(
|
||||
'allusers' => get_string('allusers', 'hotpot'),
|
||||
'allparticipants' => get_string('allparticipants')
|
||||
);
|
||||
|
||||
// groups
|
||||
if ($groups = groups_get_all_groups($course->id)) {
|
||||
foreach ($groups as $gid => $group) {
|
||||
$menus['reportusers']["group$gid"] = get_string('group').': '.format_string($group->name);
|
||||
}
|
||||
}
|
||||
|
||||
// get users who have ever atetmpted this HotPot
|
||||
$users = $DB->get_records_sql("
|
||||
SELECT
|
||||
u.id, u.firstname, u.lastname
|
||||
FROM
|
||||
{user} u,
|
||||
{hotpot_attempts} ha
|
||||
WHERE
|
||||
u.id = ha.userid AND ha.hotpot=?
|
||||
ORDER BY
|
||||
u.lastname
|
||||
", array($hotpot->id));
|
||||
|
||||
if (!empty($users)) {
|
||||
// get context
|
||||
$cm = get_coursemodule_from_instance('hotpot', $hotpot->id);
|
||||
$modulecontext = get_context_instance(CONTEXT_MODULE, $cm->id);
|
||||
|
||||
$teachers = hotpot_get_users_by_capability($modulecontext, 'mod/hotpot:viewreport');
|
||||
$students = hotpot_get_users_by_capability($modulecontext, 'mod/hotpot:attempt');
|
||||
|
||||
// current students
|
||||
if (!empty($students)) {
|
||||
$firsttime = true;
|
||||
foreach ($users as $user) {
|
||||
if (array_key_exists($user->id, $teachers)) {
|
||||
continue; // skip teachers
|
||||
}
|
||||
if (array_key_exists($user->id, $students)) {
|
||||
if ($firsttime) {
|
||||
$firsttime = false; // so we only do this once
|
||||
$menus['reportusers']['existingstudents'] = get_string('existingstudents');
|
||||
$menus['reportusers'][] = '------';
|
||||
}
|
||||
$menus['reportusers']["$user->id"] = fullname($user);
|
||||
unset($users[$user->id]);
|
||||
}
|
||||
}
|
||||
unset($students);
|
||||
}
|
||||
// others (former students, teachers, admins, course creators)
|
||||
$firsttime = true;
|
||||
foreach ($users as $user) {
|
||||
if ($firsttime) {
|
||||
$firsttime = false; // so we only do this once
|
||||
$menus['reportusers'][] = '======';
|
||||
}
|
||||
$menus['reportusers']["$user->id"] = fullname($user);
|
||||
}
|
||||
}
|
||||
|
||||
$menus['reportattempts'] = array(
|
||||
'all' => get_string('attemptsall', 'hotpot'),
|
||||
'best' => get_string('attemptsbest', 'hotpot'),
|
||||
'first' => get_string('attemptsfirst', 'hotpot'),
|
||||
'last' => get_string('attemptslast', 'hotpot')
|
||||
);
|
||||
|
||||
print '<tr><td>';
|
||||
echo $OUTPUT->old_help_icon('reportcontent', get_string('reportcontent', 'hotpot'), 'hotpot');
|
||||
print '</td><th align="right" scope="col">'.get_string('reportcontent', 'hotpot').':</th><td colspan="7">';
|
||||
foreach ($menus as $name => $options) {
|
||||
$value = $formdata[$name];
|
||||
print html_writer::select($options, $name, $value, false);
|
||||
};
|
||||
print '<input type="submit" value="'.get_string('reportbutton', 'hotpot').'" /></td></tr>';
|
||||
|
||||
$menus = array();
|
||||
|
||||
$menus['reportformat'] = array();
|
||||
$menus['reportformat']['htm'] = get_string('reportformathtml', 'hotpot');
|
||||
if (file_exists("$CFG->libdir/excel") || file_exists("$CFG->libdir/excellib.class.php")) {
|
||||
$menus['reportformat']['xls'] = get_string('reportformatexcel', 'hotpot');
|
||||
}
|
||||
$menus['reportformat']['txt'] = get_string('reportformattext', 'hotpot');
|
||||
|
||||
if (trim($CFG->hotpot_excelencodings)) {
|
||||
$menus['reportencoding'] = array(get_string('none')=>'');
|
||||
|
||||
$encodings = explode(',', $CFG->hotpot_excelencodings);
|
||||
foreach ($encodings as $encoding) {
|
||||
|
||||
$encoding = trim($encoding);
|
||||
if ($encoding) {
|
||||
$menus['reportencoding'][$encoding] = $encoding;
|
||||
}
|
||||
}
|
||||
}
|
||||
$menus['reportwrapdata'] = array(
|
||||
'1' => get_string('yes'),
|
||||
'0' => get_string('no'),
|
||||
);
|
||||
$menus['reportshowlegend'] = array(
|
||||
'1' => get_string('yes'),
|
||||
'0' => get_string('no'),
|
||||
);
|
||||
|
||||
print '<tr><td>';
|
||||
echo $OUTPUT->old_help_icon('reportformat', get_string('reportformat', 'hotpot'), 'hotpot');
|
||||
print '</td>';
|
||||
foreach ($menus as $name => $options) {
|
||||
$value = $formdata[$name];
|
||||
print '<th align="right" scope="col">'.get_string($name, 'hotpot').':</th><td>'.html_writer::select($options, $name, $value, false).'</td>';
|
||||
}
|
||||
print '</tr>';
|
||||
|
||||
print '</table>';
|
||||
|
||||
print '<hr size="1" noshade="noshade" />';
|
||||
print '</form>'."\n";
|
||||
}
|
||||
function hotpot_get_report_names($names='') {
|
||||
// $names : optional list showing required order reports names
|
||||
|
||||
$reports = array();
|
||||
|
||||
// convert $names to an array, if necessary (usually is)
|
||||
if (!is_array($names)) {
|
||||
$names = explode(',', $names);
|
||||
}
|
||||
|
||||
$plugins = get_list_of_plugins('mod/hotpot/report');
|
||||
foreach($names as $name) {
|
||||
if (is_numeric($i = array_search($name, $plugins))) {
|
||||
$reports[] = $name;
|
||||
unset($plugins[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
// append remaining plugins
|
||||
$reports = array_merge($reports, $plugins);
|
||||
|
||||
return $reports;
|
||||
}
|
||||
|
||||
function hotpot_get_records_groupby($function, $fieldnames, $table, $select, $params, $groupby) {
|
||||
// $function is an SQL aggregate function (MAX or MIN)
|
||||
global $DB;
|
||||
|
||||
$fields = $DB->sql_concat_join("'_'", $fieldnames);
|
||||
$fields = "$groupby, $function($fields) AS joinedvalues";
|
||||
|
||||
if ($fields) {
|
||||
$records = $DB->get_records_sql("SELECT $fields FROM $table WHERE $select GROUP BY $groupby", $params);
|
||||
}
|
||||
|
||||
if (empty($fields) || empty($records)) {
|
||||
$records = array();
|
||||
}
|
||||
|
||||
$fieldcount = count($fieldnames);
|
||||
|
||||
foreach ($records as $id=>$record) {
|
||||
if (empty($record->joinedvalues)) {
|
||||
unset($records[$id]);
|
||||
} else {
|
||||
$values = explode('_', $record->joinedvalues);
|
||||
|
||||
for ($i=0; $i<$fieldcount; $i++) {
|
||||
$fieldname = $fieldnames[$i];
|
||||
$records[$id]->$fieldname = $values[$i];
|
||||
}
|
||||
}
|
||||
unset($record->joinedvalues);
|
||||
}
|
||||
|
||||
return $records;
|
||||
}
|
||||
function hotpot_get_users_by_capability(&$modulecontext, $capability) {
|
||||
static $users = array();
|
||||
if (! array_key_exists($capability, $users)) {
|
||||
$users[$capability] = get_users_by_capability($modulecontext, $capability, 'u.id,u.id', 'u.id');
|
||||
}
|
||||
return $users[$capability];
|
||||
}
|
||||
|
||||
@@ -1,542 +0,0 @@
|
||||
<?php
|
||||
/// Overview report just displays a big table of all the attempts
|
||||
class hotpot_report extends hotpot_default_report {
|
||||
function display(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options) {
|
||||
global $CFG;
|
||||
// create the tables
|
||||
$tables = array();
|
||||
$this->create_clickreport_table($hotpot, $cm, $course, $users, $attempts, $questions, $options, $tables);
|
||||
// print the tables
|
||||
$this->print_report($course, $hotpot, $tables, $options);
|
||||
return true;
|
||||
}
|
||||
function create_clickreport_table(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options, &$tables) {
|
||||
global $CFG;
|
||||
$is_html = ($options['reportformat']=='htm');
|
||||
// time and date format strings // date format strings
|
||||
$strftimetime = '%H:%M:%S';
|
||||
$strftimedate = get_string('strftimedate');
|
||||
// get the current time and max execution time
|
||||
$start_report_time = microtime();
|
||||
$max_execution_time = ini_get('max_execution_time');
|
||||
$correct = get_string('reportcorrectsymbol', 'hotpot');
|
||||
$wrong = get_string('reportwrongsymbol', 'hotpot');
|
||||
$nottried = get_string('reportnottriedsymbol', 'hotpot');
|
||||
// shortcuts for font tags
|
||||
$blank = $is_html ? ' ' : "";
|
||||
// store question count
|
||||
$questioncount = count($questions);
|
||||
// array to map columns onto question ids ($col => $id)
|
||||
$questionids = array_keys($questions);
|
||||
// store exercise type
|
||||
$exercisetype = $this->get_exercisetype($questions, $questionids, $blank);
|
||||
// initialize details ('events' must go last)
|
||||
$details = array('checks', 'status', 'answers', 'changes', 'hints', 'clues', 'events');
|
||||
// initialize $table
|
||||
unset($table);
|
||||
$table->border = 1;
|
||||
$table->width = '100%';
|
||||
// initialize legend, if necessary
|
||||
if (!empty($options['reportshowlegend'])) {
|
||||
$table->legend = array();
|
||||
}
|
||||
// start $table headings
|
||||
$this->set_head($options, $table, 'exercise');
|
||||
$this->set_head($options, $table, 'user');
|
||||
$this->set_head($options, $table, 'attempt');
|
||||
$this->set_head($options, $table, 'click');
|
||||
// store clicktype column number
|
||||
$clicktype_col = count($table->head)-1;
|
||||
// finish $table headings
|
||||
$this->set_head($options, $table, 'details', $exercisetype, $details, $questioncount);
|
||||
$this->set_head($options, $table, 'totals', $exercisetype);
|
||||
// set align and wrap
|
||||
$this->set_align_and_wrap($table);
|
||||
// is link to review allowed?
|
||||
$allow_review = ($is_html && (has_capability('mod/hotpot:viewreport',get_context_instance(CONTEXT_COURSE, $course->id)) || $hotpot->review));
|
||||
// initialize array of data values
|
||||
$this->data = array();
|
||||
// set exercise data values
|
||||
$this->set_data_exercise($cm, $course, $hotpot, $questions, $questionids, $questioncount, $blank);
|
||||
// add details of users' responses
|
||||
foreach ($users as $user) {
|
||||
$this->set_data_user($options, $course, $user);
|
||||
unset($clickreportid);
|
||||
foreach ($user->attempts as $attempt) {
|
||||
// initialize totals for
|
||||
$click = array(
|
||||
'qnumber' => array(),
|
||||
'correct' => array(),
|
||||
'wrong' => array(),
|
||||
'answers' => array(),
|
||||
'hints' => array(),
|
||||
'clues' => array(),
|
||||
'changes' => array(),
|
||||
'checks' => array(),
|
||||
'events' => array(),
|
||||
'score' => array(),
|
||||
'weighting' => array()
|
||||
);
|
||||
$clicktypes = array();
|
||||
// is the start of a new attempt?
|
||||
// (clicks in the same attempt have the same clickreportid)
|
||||
if (!isset($clickreportid) || $clickreportid != $attempt->clickreportid) {
|
||||
$clickcount = 1;
|
||||
$clickreportid = $attempt->clickreportid;
|
||||
// initialize totals for all clicks in this attempt
|
||||
$clicks = $click; // $click has just been initialized
|
||||
$this->set_data_attempt($attempt, $strftimedate, $strftimetime, $blank);
|
||||
}
|
||||
$cells = array();
|
||||
$this->set_data($cells, 'exercise');
|
||||
$this->set_data($cells, 'user');
|
||||
$this->set_data($cells, 'attempt');
|
||||
// get responses to questions in this attempt
|
||||
foreach ($attempt->responses as $response) {
|
||||
// set $q(uestion number)
|
||||
$q = array_search($response->question, $questionids);
|
||||
$click['qnumber'][$q] = true;
|
||||
// was this question answered correctly?
|
||||
if ($answer = hotpot_strings($response->correct)) {
|
||||
// mark the question as correctly answered
|
||||
if (empty($clicks['correct'][$q])) {
|
||||
$click['correct'][$q] = true;
|
||||
$clicks['correct'][$q] = true;
|
||||
}
|
||||
// unset 'wrong' flags, if necessary
|
||||
if (isset($click['wrong'][$q])) {
|
||||
unset($click['wrong'][$q]);
|
||||
}
|
||||
if (isset($clicks['wrong'][$q])) {
|
||||
unset($clicks['wrong'][$q]);
|
||||
}
|
||||
// otherwise, was the question answered wrongly?
|
||||
} else if ($answer = hotpot_strings($response->wrong)) {
|
||||
// mark the question as wrongly answered
|
||||
$click['wrong'][$q] = true;
|
||||
$clicks['wrong'][$q] = true;
|
||||
} else { // not correct or wrong (curious?!)
|
||||
unset($answer);
|
||||
}
|
||||
if (!empty($click['correct'][$q]) || !empty($click['wrong'][$q])) {
|
||||
$click['score'][$q] = $response->score;
|
||||
$clicks['score'][$q] = $response->score;
|
||||
$weighting = isset($response->weighting) ? $response->weighting : 100;
|
||||
$click['weighting'][$q] = $weighting;
|
||||
$clicks['weighting'][$q] =$weighting;
|
||||
}
|
||||
foreach($details as $detail) {
|
||||
switch ($detail) {
|
||||
case 'answers':
|
||||
if (isset($answer) && is_string($answer) && !empty($answer)) {
|
||||
$click[$detail][$q] = $answer;
|
||||
}
|
||||
break;
|
||||
case 'hints':
|
||||
case 'clues':
|
||||
case 'checks':
|
||||
if (isset($response->$detail) && is_numeric($response->$detail) && $response->$detail>0) {
|
||||
if (!isset($click[$detail][$q]) || $click[$detail][$q] < $response->$detail) {
|
||||
$click[$detail][$q] = $response->$detail;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} // end foreach $detail
|
||||
} // end foreach $response
|
||||
$click['types'] = array();
|
||||
$this->data['details'] = array();
|
||||
foreach($details as $detail) {
|
||||
for ($q=0; $q<$questioncount; $q++) {
|
||||
switch ($detail) {
|
||||
case 'status':
|
||||
if (isset($clicks['correct'][$q])) {
|
||||
$this->data['details'][] = $correct;
|
||||
} else if (isset($clicks['wrong'][$q])) {
|
||||
$this->data['details'][] = $wrong;
|
||||
} else if (isset($click['qnumber'][$q])) {
|
||||
$this->data['details'][] = $nottried;
|
||||
} else { // this question did not appear in this attempt
|
||||
$this->data['details'][] = $blank;
|
||||
}
|
||||
break;
|
||||
case 'answers':
|
||||
case 'hints':
|
||||
case 'clues':
|
||||
case 'checks':
|
||||
if (!isset($clicks[$detail][$q])) {
|
||||
if (!isset($click[$detail][$q])) {
|
||||
$this->data['details'][] = $blank;
|
||||
} else {
|
||||
$clicks[$detail][$q] = $click[$detail][$q];
|
||||
if ($detail=='answers') {
|
||||
$this->set_legend($table, $q, $click[$detail][$q], $questions[$questionids[$q]]);
|
||||
}
|
||||
$this->data['details'][] = $click[$detail][$q];
|
||||
$this->update_event_count($click, $detail, $q);
|
||||
}
|
||||
} else {
|
||||
if (!isset($click[$detail][$q])) {
|
||||
$this->data['details'][] = $blank;
|
||||
} else {
|
||||
$difference = '';
|
||||
if ($detail=='answers') {
|
||||
if ($click[$detail][$q] != $clicks[$detail][$q]) {
|
||||
$pattern = '/^'.preg_quote($clicks[$detail][$q], '/').',/';
|
||||
$difference = preg_replace($pattern, '', $click[$detail][$q], 1);
|
||||
}
|
||||
} else { // hints, clues, checks
|
||||
if ($click[$detail][$q] > $clicks[$detail][$q]) {
|
||||
$difference = $click[$detail][$q] - $clicks[$detail][$q];
|
||||
}
|
||||
}
|
||||
if ($difference) {
|
||||
$clicks[$detail][$q] = $click[$detail][$q];
|
||||
$click[$detail][$q] = $difference;
|
||||
if ($detail=='answers') {
|
||||
$this->set_legend($table, $q, $difference, $questions[$questionids[$q]]);
|
||||
}
|
||||
$this->data['details'][] = $difference;
|
||||
$this->update_event_count($click, $detail, $q);
|
||||
} else {
|
||||
unset($click[$detail][$q]);
|
||||
$this->data['details'][] = $blank;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'changes':
|
||||
case 'events':
|
||||
if (empty($click[$detail][$q])) {
|
||||
$this->data['details'][] = $blank;
|
||||
} else {
|
||||
$this->data['details'][] = $click[$detail][$q];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// do nothing
|
||||
break;
|
||||
} // end switch
|
||||
} // for $q
|
||||
} // foreach $detail
|
||||
// set data cell values for
|
||||
$this->set_data_click(
|
||||
$allow_review ? '<a href="review.php?hp='.$hotpot->id.'&attempt='.$attempt->id.'">'.$clickcount.'</a>' : $clickcount,
|
||||
trim(userdate($attempt->timefinish, $strftimetime)),
|
||||
$exercisetype,
|
||||
$click
|
||||
);
|
||||
$this->set_data($cells, 'click');
|
||||
$this->set_data($cells, 'details');
|
||||
$this->set_data_totals($click, $clicks, $questioncount, $blank, $attempt);
|
||||
$this->set_data($cells, 'totals');
|
||||
$table->data[] = $cells;
|
||||
$clickcount++;
|
||||
} // end foreach $attempt
|
||||
// insert 'tabledivider' between users
|
||||
$table->data[] = 'hr';
|
||||
} // end foreach $user
|
||||
// remove final 'hr' from data rows
|
||||
array_pop($table->data);
|
||||
if ($is_html && $CFG->hotpot_showtimes) {
|
||||
$count = count($users);
|
||||
$duration = sprintf("%0.3f", microtime_diff($start_report_time, microtime()));
|
||||
print "$count users processed in $duration seconds (".sprintf("%0.3f", $duration/$count).' secs/user)<hr size="1" noshade="noshade" />'."\n";
|
||||
}
|
||||
$tables[] = &$table;
|
||||
$this->create_legend_table($tables, $table);
|
||||
} // end function
|
||||
function get_exercisetype(&$questions, &$questionids, &$blank) {
|
||||
if (empty($questions)) {
|
||||
$type = $blank;
|
||||
} else {
|
||||
switch ($questions[$questionids[0]]->type) {
|
||||
case HOTPOT_JCB:
|
||||
$type = "JCB";
|
||||
break;
|
||||
case HOTPOT_JCLOZE :
|
||||
$type = "JCloze";
|
||||
break;
|
||||
case HOTPOT_JCROSS :
|
||||
$type = "JCross";
|
||||
break;
|
||||
case HOTPOT_JMATCH :
|
||||
$type = "JMatch";
|
||||
break;
|
||||
case HOTPOT_JMIX :
|
||||
$type = "JMix";
|
||||
break;
|
||||
case HOTPOT_JQUIZ :
|
||||
$type = "JQuiz";
|
||||
break;
|
||||
case HOTPOT_TEXTOYS_RHUBARB :
|
||||
$type = "Rhubarb";
|
||||
break;
|
||||
case HOTPOT_TEXTOYS_SEQUITUR :
|
||||
$type = "Sequitur";
|
||||
break;
|
||||
default:
|
||||
$type = $blank;
|
||||
}
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
function set_head(&$options, &$table, $zone, $exercisetype='', $details=array(), $questioncount=0) {
|
||||
if (empty($table->head)) {
|
||||
$table->head = array();
|
||||
}
|
||||
switch ($zone) {
|
||||
case 'exercise':
|
||||
array_push($table->head,
|
||||
get_string('reportcoursename', 'hotpot'),
|
||||
get_string('reportsectionnumber', 'hotpot'),
|
||||
get_string('reportexercisenumber', 'hotpot'),
|
||||
get_string('reportexercisename', 'hotpot'),
|
||||
get_string('reportexercisetype', 'hotpot'),
|
||||
get_string('reportnumberofquestions', 'hotpot')
|
||||
);
|
||||
break;
|
||||
case 'user':
|
||||
array_push($table->head,
|
||||
get_string('reportstudentid', 'hotpot'),
|
||||
get_string('reportlogindate', 'hotpot'),
|
||||
get_string('reportlogintime', 'hotpot'),
|
||||
get_string('reportlogofftime', 'hotpot')
|
||||
);
|
||||
break;
|
||||
case 'attempt':
|
||||
array_push($table->head,
|
||||
get_string('reportattemptnumber', 'hotpot'),
|
||||
get_string('reportattemptstart', 'hotpot'),
|
||||
get_string('reportattemptfinish', 'hotpot')
|
||||
);
|
||||
break;
|
||||
case 'click':
|
||||
array_push($table->head,
|
||||
get_string('reportclicknumber', 'hotpot'),
|
||||
get_string('reportclicktime', 'hotpot'),
|
||||
get_string('reportclicktype', 'hotpot')
|
||||
);
|
||||
break;
|
||||
case 'details':
|
||||
foreach($details as $detail) {
|
||||
if ($exercisetype=='JQuiz' && $detail=='clues') {
|
||||
$detail = 'showanswer';
|
||||
}
|
||||
$detail = get_string("report$detail", 'hotpot');
|
||||
for ($i=0; $i<$questioncount; $i++) {
|
||||
$str = get_string('questionshort', 'hotpot', $i+1);
|
||||
if ($i==0 || $options['reportformat']!='htm') {
|
||||
$str = "$detail $str";
|
||||
}
|
||||
$table->head[] = $str;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'totals':
|
||||
$reportpercentscore =get_string('reportpercentscore', 'hotpot');
|
||||
if (!function_exists('clean_getstring_data')) { // Moodle 1.4 (and less)
|
||||
$reportpercentscore = str_replace('%', '%%', $reportpercentscore);
|
||||
}
|
||||
array_push($table->head,
|
||||
get_string('reportthisclick', 'hotpot', get_string('reportquestionstried', 'hotpot')),
|
||||
get_string('reportsofar', 'hotpot', get_string('reportquestionstried', 'hotpot')),
|
||||
get_string('reportthisclick', 'hotpot', get_string('reportright', 'hotpot')),
|
||||
get_string('reportthisclick', 'hotpot', get_string('reportwrong', 'hotpot')),
|
||||
get_string('reportthisclick', 'hotpot', get_string('reportnottried', 'hotpot')),
|
||||
get_string('reportsofar', 'hotpot', get_string('reportright', 'hotpot')),
|
||||
get_string('reportsofar', 'hotpot', get_string('reportwrong', 'hotpot')),
|
||||
get_string('reportsofar', 'hotpot', get_string('reportnottried', 'hotpot')),
|
||||
get_string('reportthisclick', 'hotpot', get_string('reportanswers', 'hotpot')),
|
||||
get_string('reportthisclick', 'hotpot', get_string('reporthints', 'hotpot')),
|
||||
get_string('reportthisclick', 'hotpot', get_string($exercisetype=='JQuiz' ? 'reportshowanswer' : 'reportclues', 'hotpot')),
|
||||
get_string('reportthisclick', 'hotpot', get_string('reportevents', 'hotpot')),
|
||||
get_string('reportsofar', 'hotpot', get_string('reporthints', 'hotpot')),
|
||||
get_string('reportsofar', 'hotpot', get_string($exercisetype=='JQuiz' ? 'reportshowanswer' : 'reportclues', 'hotpot')),
|
||||
get_string('reportthisclick', 'hotpot', get_string('reportrawscore', 'hotpot')),
|
||||
get_string('reportthisclick', 'hotpot', get_string('reportmaxscore', 'hotpot')),
|
||||
get_string('reportthisclick', 'hotpot', $reportpercentscore),
|
||||
get_string('reportsofar', 'hotpot', get_string('reportrawscore', 'hotpot')),
|
||||
get_string('reportsofar', 'hotpot', get_string('reportmaxscore', 'hotpot')),
|
||||
get_string('reportsofar', 'hotpot', $reportpercentscore),
|
||||
get_string('reporthotpotscore', 'hotpot')
|
||||
);
|
||||
break;
|
||||
} // end switch
|
||||
}
|
||||
function set_align_and_wrap(&$table) {
|
||||
$count = count($table->head);
|
||||
for ($i=0; $i<$count; $i++) {
|
||||
if ($i==0 || $i==1 || $i==2 || $i==4 || $i==5 || $i>=7) {
|
||||
// numeric (and short text) columns
|
||||
$table->align[] = 'center';
|
||||
$table->wrap[] = '';
|
||||
} else {
|
||||
// text columns
|
||||
$table->align[] = 'left';
|
||||
$table->wrap[] = 'nowrap';
|
||||
}
|
||||
}
|
||||
}
|
||||
function set_data_exercise(&$cm, &$course, &$hotpot, &$questions, &$questionids, &$questioncount, &$blank) {
|
||||
global $DB;
|
||||
|
||||
// get exercise details (course name, section number, activity number, quiztype and question count)
|
||||
$record = $DB->get_record("course_sections", array("id"=>$cm->section));
|
||||
$this->data['exercise'] = array(
|
||||
'course' => $course->shortname,
|
||||
'section' => empty($record) ? $blank : $record->section+1,
|
||||
'number' => empty($record) ? $blank : array_search($cm->id, explode(',', $record->sequence))+1,
|
||||
'name' => $hotpot->name,
|
||||
'type' => $this->get_exercisetype($questions, $questionids, $blank),
|
||||
'questioncount' => $questioncount
|
||||
);
|
||||
}
|
||||
function set_data_user(&$options, &$course, &$user) {
|
||||
global $CFG;
|
||||
// shortcut to first attempt record (which also hold user info)
|
||||
$attempt = &$user->attempts[0];
|
||||
$idnumber = $attempt->idnumber;
|
||||
if (empty($idnumber)) {
|
||||
$idnumber = fullname($attempt);
|
||||
}
|
||||
if ($options['reportformat']=='htm') {
|
||||
$idnumber = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$attempt->userid.'&course='.$course->id.'">'.$idnumber.'</a>';
|
||||
}
|
||||
$this->data['user'] = array(
|
||||
'idnumber' => $idnumber,
|
||||
);
|
||||
}
|
||||
function set_data_attempt(&$attempt, &$strftimedate, &$strftimetime, &$blank) {
|
||||
global $CFG, $DB;
|
||||
$records = $DB->get_records_sql_menu("
|
||||
SELECT userid, MAX(time) AS logintime
|
||||
FROM {log}
|
||||
WHERE userid=? AND action='login' AND time<?
|
||||
GROUP BY userid
|
||||
", array($attempt->userid, $attempt->timestart));
|
||||
if (empty($records)) {
|
||||
$logindate = $blank;
|
||||
$logintime = $blank;
|
||||
} else {
|
||||
$logintime = $records[$attempt->userid];
|
||||
$logindate = trim(userdate($logintime, $strftimedate));
|
||||
$logintime = trim(userdate($logintime, $strftimetime));
|
||||
}
|
||||
$records = $DB->get_records_sql_menu("
|
||||
SELECT userid, MIN(time) AS logouttime
|
||||
FROM {log}
|
||||
WHERE userid=? AND action='logout' AND time>?
|
||||
GROUP BY userid
|
||||
", array($attempt->userid, $attempt->cr_timefinish));
|
||||
if (empty($records)) {
|
||||
$logouttime = $blank;
|
||||
} else {
|
||||
$logouttime = $records[$attempt->userid];
|
||||
$logouttime = trim(userdate($logouttime, $strftimetime));
|
||||
}
|
||||
$this->data['attempt'] = array(
|
||||
'logindate' => $logindate,
|
||||
'logintime' => $logintime,
|
||||
'logouttime' => $logouttime,
|
||||
'number' => $attempt->attempt,
|
||||
'start' => trim(userdate($attempt->timestart, $strftimetime)),
|
||||
'finish' => trim(userdate($attempt->cr_timefinish, $strftimetime)),
|
||||
);
|
||||
}
|
||||
function set_data_click($number, $time, $exercisetype, $click) {
|
||||
$types = array();
|
||||
foreach (array_keys($click['types']) as $type) {
|
||||
if ($exercisetype=='JQuiz' && $type=='clues') {
|
||||
$type = 'showanswer';
|
||||
} else {
|
||||
// remove final 's'
|
||||
$type = substr($type, 0, strlen($type)-1);
|
||||
}
|
||||
// $types[] = get_string($type, 'hotpot');
|
||||
$types[] = $type;
|
||||
}
|
||||
$this->data['click'] = array(
|
||||
'number' => $number,
|
||||
'time' => $time,
|
||||
'type' => empty($types) ? '??' : implode(',', $types)
|
||||
);
|
||||
}
|
||||
function set_data_totals(&$click, &$clicks, &$questioncount, &$blank, &$attempt) {
|
||||
$count= array(
|
||||
'click' => array(
|
||||
'correct' => count($click['correct']),
|
||||
'wrong' => count($click['wrong']),
|
||||
'answers' => count($click['answers']),
|
||||
'hints' => array_sum($click['hints']),
|
||||
'clues' => array_sum($click['clues']),
|
||||
'events' => array_sum($click['events']),
|
||||
'score' => array_sum($click['score']),
|
||||
'maxscore' => array_sum($click['weighting']),
|
||||
),
|
||||
'clicks' => array(
|
||||
'correct' => count($clicks['correct']),
|
||||
'wrong' => count($clicks['wrong']),
|
||||
'answers' => count($clicks['answers']),
|
||||
'hints' => array_sum($clicks['hints']),
|
||||
'clues' => array_sum($clicks['clues']),
|
||||
'score' => array_sum($clicks['score']),
|
||||
'maxscore' => array_sum($clicks['weighting']),
|
||||
)
|
||||
);
|
||||
foreach ($count as $period=>$values) {
|
||||
$count[$period]['nottried'] = $questioncount - ($values['correct'] + $values['wrong']);
|
||||
$count[$period]['percent'] = empty($values['maxscore']) ? $blank : round(100 * $values['score'] / $values['maxscore'], 0);
|
||||
// blank out zero click values
|
||||
if ($period=='click') {
|
||||
foreach ($values as $detail=>$value) {
|
||||
if ($detail=='answers' || $detail=='hints' || $detail=='clues' || $detail=='events') {
|
||||
if (empty($value)) {
|
||||
$count[$period][$detail] = $blank;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->data['totals'] = array(
|
||||
$count['click']['answers'], // "q's tried"
|
||||
$count['clicks']['answers'], // "q's tried so far"
|
||||
$count['click']['correct'], // "right"
|
||||
$count['click']['wrong'], // "wrong"
|
||||
$count['click']['nottried'], // "not tried"
|
||||
$count['clicks']['correct'], // "right so far"
|
||||
$count['clicks']['wrong'], // "wrong so far"
|
||||
$count['clicks']['nottried'], // "not tried so far"
|
||||
$count['click']['answers'], // "answers",
|
||||
$count['click']['hints'], // "hints",
|
||||
$count['click']['clues'], // "clues",
|
||||
$count['click']['events'], // "answers",
|
||||
$count['clicks']['hints'], // "hints so far",
|
||||
$count['clicks']['clues'], // "clues so far",
|
||||
$count['click']['score'], // 'raw score',
|
||||
$count['click']['maxscore'], // 'max score',
|
||||
$count['click']['percent'], // '% score'
|
||||
$count['clicks']['score'], // 'raw score,
|
||||
$count['clicks']['maxscore'], // 'max score,
|
||||
$count['clicks']['percent'], // '% score
|
||||
$attempt->score // 'hotpot score'
|
||||
);
|
||||
}
|
||||
function update_event_count(&$click, $detail, $q) {
|
||||
if ($detail=='checks' || $detail=='hints' || $detail=='clues') {
|
||||
$click['types'][$detail] = true;
|
||||
}
|
||||
if ($detail=='answers' || $detail=='hints' || $detail=='clues') {
|
||||
$click['events'][$q] = isset($click['events'][$q]) ? $click['events'][$q]+1 : 1;
|
||||
}
|
||||
if ($detail=='answers') {
|
||||
$click['changes'][$q] = isset($click['changes'][$q]) ? $click['changes'][$q]+1 : 1;
|
||||
}
|
||||
}
|
||||
function set_data(&$cells, $zone) {
|
||||
foreach ($this->data[$zone] as $name=>$value) {
|
||||
$cells[] = $value;
|
||||
}
|
||||
}
|
||||
} // end class
|
||||
|
||||
@@ -1,851 +0,0 @@
|
||||
<?PHP
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
/// Default class for report plugins
|
||||
///
|
||||
/// Doesn't do anything on it's own -- it needs to be extended.
|
||||
/// This class displays quiz reports. Because it is called from
|
||||
/// within /mod/quiz/report.php you can assume that the page header
|
||||
/// and footer are taken care of.
|
||||
///
|
||||
/// This file can refer to itself as report.php to pass variables
|
||||
/// to itself - all these will also be globally available. You must
|
||||
/// pass "id=$cm->id" or q=$quiz->id", and "mode=reportname".
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Included by ../report.php
|
||||
|
||||
class hotpot_default_report {
|
||||
|
||||
function display($hotpot, $cm, $course, $users, $attempts, $questions, $options) {
|
||||
/// This function just displays the report
|
||||
// it is replaced by the "display" functions in the scripts in the "report" folder
|
||||
return true;
|
||||
}
|
||||
|
||||
function add_question_headings(&$questions, &$table, $align='center', $size=50, $wrap=false, $fontsize=0) {
|
||||
$count = count($questions);
|
||||
for ($i=0; $i<$count; $i++) {
|
||||
$table->head[] = get_string('questionshort', 'hotpot', $i+1);
|
||||
if (isset($table->align)) {
|
||||
$table->align[] = $align;
|
||||
}
|
||||
if (isset($table->size)) {
|
||||
$table->size[] = $size;
|
||||
}
|
||||
if (isset($table->wrap)) {
|
||||
$table->wrap[] = $wrap;
|
||||
}
|
||||
if (isset($table->fontsize)) {
|
||||
$table->fontsize[] = $fontsize;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function set_legend(&$table, &$q, &$value, &$question) {
|
||||
// $q is the question number
|
||||
// $value is the value (=text) of the answer
|
||||
|
||||
// check the legend is required
|
||||
if (isset($table->legend) && isset($value)) {
|
||||
|
||||
// create question details array, if necessary
|
||||
if (empty($table->legend[$q])) {
|
||||
$table->legend[$q] = array(
|
||||
'name' => hotpot_get_question_name($question),
|
||||
'answers' => array()
|
||||
);
|
||||
}
|
||||
|
||||
// search for this $value in answers array for this $q(uestion)
|
||||
$i_max = count($table->legend[$q]['answers']);
|
||||
for ($i=0; $i<$i_max; $i++) {
|
||||
if ($table->legend[$q]['answers'][$i]==$value) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// add $value to answers array, if it was not there
|
||||
if ($i==$i_max) {
|
||||
$table->legend[$q]['answers'][$i] = $value;
|
||||
}
|
||||
|
||||
// convert $value to alphabetic index (A, B ... AA, AB ...)
|
||||
$value = $this->dec_to_ALPHA($i);
|
||||
}
|
||||
}
|
||||
function create_legend_table(&$tables, &$table) {
|
||||
|
||||
if (isset($table->legend)) {
|
||||
|
||||
$legend->width = '*';
|
||||
$legend->tablealign = '*';
|
||||
$legend->border = isset($table->border) ? $table->border : NULL;
|
||||
$legend->cellpadding = isset($table->cellpadding) ? $table->cellpadding : NULL;
|
||||
$legend->cellspacing = isset($table->cellspacing) ? $table->cellspacing : NULL;
|
||||
$legend->tableclass = isset($table->tableclass) ? $table->tableclass : NULL;
|
||||
|
||||
$legend->caption = get_string('reportlegend', 'hotpot');
|
||||
$legend->align = array('right', 'left');
|
||||
$legend->statheadercols = array(0);
|
||||
|
||||
$legend->stat = array();
|
||||
|
||||
// put the questions in order
|
||||
ksort($table->legend);
|
||||
|
||||
foreach($table->legend as $q=>$question) {
|
||||
|
||||
$legend->stat[] = array(
|
||||
get_string('questionshort', 'hotpot', $q+1),
|
||||
$question['name']
|
||||
);
|
||||
foreach($question['answers'] as $a=>$answer) {
|
||||
$legend->stat[] = array(
|
||||
$this->dec_to_ALPHA($a),
|
||||
$answer
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
unset($table->legend);
|
||||
$tables[] = $legend;
|
||||
}
|
||||
}
|
||||
function dec_to_ALPHA($dec) {
|
||||
if ($dec < 26) {
|
||||
return chr(ord('A') + $dec);
|
||||
} else {
|
||||
return $this->dec_to_ALPHA(intval($dec/26)-1).$this->dec_to_ALPHA($dec % 26);
|
||||
}
|
||||
}
|
||||
function remove_column(&$table, $target_col) {
|
||||
|
||||
if (is_array($table)) {
|
||||
unset($table[$target_col]);
|
||||
$table = array_values($table);
|
||||
|
||||
} else if (is_object($table)) {
|
||||
$vars = get_object_vars($table);
|
||||
foreach ($vars as $name=>$value) {
|
||||
switch ($name) {
|
||||
case 'data' :
|
||||
case 'stat' :
|
||||
case 'foot' :
|
||||
$skipcol = array();
|
||||
$cells = &$table->$name;
|
||||
|
||||
$row_max = count($cells);
|
||||
for ($row=0; $row<$row_max; $row++) {
|
||||
|
||||
$col = 0;
|
||||
$col_max = count($cells[$row]);
|
||||
|
||||
$current_col = 0;
|
||||
while ($current_col<$target_col && $col<$col_max) {
|
||||
|
||||
if (empty($skipcol[$current_col])) {
|
||||
|
||||
$cell = $cells[$row][$col++];
|
||||
if (is_object($cell)) {
|
||||
if (isset($cell->rowspan) && is_numeric($cell->rowspan) && ($cell->rowspan>0)) {
|
||||
// skip cells below this one
|
||||
$skipcol[$current_col] = $cell->rowspan-1;
|
||||
}
|
||||
if (isset($cell->colspan) && is_numeric($cell->colspan) && ($cell->colspan>0)) {
|
||||
// skip cells to the right of this one
|
||||
for ($c=1; $c<$cell->colspan; $c++) {
|
||||
if (empty($skipcol[$current_col+$c])) {
|
||||
$skipcol[$current_col+$c] = 1;
|
||||
} else {
|
||||
$skipcol[$current_col+$c] ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$skipcol[$current_col]--;
|
||||
}
|
||||
$current_col++;
|
||||
}
|
||||
if ($current_col==$target_col && $col<$col_max) {
|
||||
$this->remove_column($cells[$row], $col);
|
||||
}
|
||||
} // end for $row
|
||||
break;
|
||||
case 'head' :
|
||||
case 'align' :
|
||||
case 'class' :
|
||||
case 'fontsize' :
|
||||
case 'size' :
|
||||
case 'wrap' :
|
||||
$this->remove_column($table->$name, $target_col);
|
||||
break;
|
||||
case 'statheadercols' :
|
||||
$array = &$table->$name;
|
||||
$count = count($array);
|
||||
for ($i=0; $i<$count; $i++) {
|
||||
if ($array[$i]>=$target_col) {
|
||||
$array[$i] --;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} // end switch
|
||||
} // end foreach
|
||||
} // end if
|
||||
} // end function
|
||||
|
||||
|
||||
function expand_spans(&$table, $zone) {
|
||||
// expand multi-column and multi-row cells in a specified $zone of a $table
|
||||
|
||||
// do nothing if this $zone is empty
|
||||
if (empty($table->$zone)) return;
|
||||
|
||||
// shortcut to rows in this $table $zone
|
||||
$rows = &$table->{$zone};
|
||||
|
||||
// loop through the rows
|
||||
foreach ($rows as $row=>$cells) {
|
||||
|
||||
// check this is an array
|
||||
if (is_array($cells)) {
|
||||
|
||||
// loop through the cells in this row
|
||||
foreach ($cells as $col=>$cell) {
|
||||
|
||||
if (is_object($cell)) {
|
||||
if (isset($cell->rowspan) && is_numeric($cell->rowspan) && ($cell->rowspan>1)) {
|
||||
// fill in cells below this one
|
||||
$new_cell = array($cell->text);
|
||||
for ($r=1; $r<$cell->rowspan; $r++) {
|
||||
array_splice($rows[$row+$r], $col, 0, $new_cell);
|
||||
}
|
||||
}
|
||||
if (isset($cell->colspan) && is_numeric($cell->colspan) && ($cell->colspan>1)) {
|
||||
// fill in cells to the right of this one
|
||||
$new_cells = array();
|
||||
for ($c=1; $c<$cell->colspan; $c++) {
|
||||
$new_cells[] = $cell->text;
|
||||
}
|
||||
array_splice($rows[$row], $col, 0, $new_cells);
|
||||
}
|
||||
// replace $cell object with plain text
|
||||
$rows[$row][$col] = $cell->text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
/// print a report in html, text or Excel format
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
// the stuff to print is contained in $table
|
||||
// which has the following properties:
|
||||
|
||||
// $table->border border width for the table
|
||||
// $table->cellpadding padding on each cell
|
||||
// $table->cellspacing spacing between cells
|
||||
// $table->tableclass class for table
|
||||
// $table->width table width
|
||||
|
||||
// $table->align is an array of column alignments
|
||||
// $table->class is an array of column classes
|
||||
// $table->size is an array of column sizes
|
||||
// $table->wrap is an array of column wrap/nowrap switches
|
||||
// $table->fontsize is an array of fontsizes
|
||||
|
||||
// $table->caption is a caption (=title) for the report
|
||||
// $table->head is an array of headings (all TH cells)
|
||||
// $table->data[] is an array of arrays containing the data (all TD cells)
|
||||
// if a row is given as "hr", a "tabledivider" is inserted
|
||||
// if a cell is a string, it is assumed to be the cell content
|
||||
// a cell can also be an object, thus:
|
||||
// $cell->text : the content of the cell
|
||||
// $cell->rowspan : the row span of this cell
|
||||
// $cell->colspan : the column span of this cell
|
||||
// if rowspan or colspan are specified, neighboring cells are shifted accordingly
|
||||
// $table->stat[] is an array of arrays containing the statistics rows (TD and TH cells)
|
||||
// $table->foot[] is an array of arrays containing the footer rows (all TH cells)
|
||||
|
||||
// $table->statheadercols is an array of column numbers which are headers
|
||||
|
||||
|
||||
//////////////////////////////////////////
|
||||
/// print a report
|
||||
|
||||
function print_report(&$course, &$hotpot, &$tables, &$options) {
|
||||
switch ($options['reportformat']) {
|
||||
case 'txt':
|
||||
$this->print_text_report($course, $hotpot, $tables, $options);
|
||||
break;
|
||||
case 'xls':
|
||||
$this->print_excel_report($course, $hotpot, $tables, $options);
|
||||
break;
|
||||
default: // 'htm' (and anything else)
|
||||
$this->print_html_report($tables);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function print_report_start(&$course, &$hotpot, &$options, &$table) {
|
||||
switch ($options['reportformat']) {
|
||||
case 'txt':
|
||||
$this->print_text_start($course, $hotpot, $options);
|
||||
break;
|
||||
case 'xls':
|
||||
$this->print_excel_start($course, $hotpot, $options);
|
||||
break;
|
||||
|
||||
case 'htm':
|
||||
$this->print_html_start($course, $hotpot, $options);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function print_report_cells(&$table, &$options, $zone) {
|
||||
switch ($options['reportformat']) {
|
||||
case 'txt':
|
||||
$fmt = 'text';
|
||||
break;
|
||||
case 'xls':
|
||||
$fmt = 'excel';
|
||||
break;
|
||||
default: // 'htm' (and anything else)
|
||||
$fmt = 'html';
|
||||
break;
|
||||
}
|
||||
$fn = "print_{$fmt}_{$zone}";
|
||||
$this->$fn($table, $options);
|
||||
}
|
||||
|
||||
function print_report_finish(&$course, &$hotpot, &$options) {
|
||||
switch ($options['reportformat']) {
|
||||
case 'txt' :
|
||||
// do nothing
|
||||
break;
|
||||
case 'xls':
|
||||
$this->print_excel_finish($course, $hotpot, $options);
|
||||
break;
|
||||
case 'htm':
|
||||
$this->print_html_finish($course, $hotpot, $options);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
/// print an html report
|
||||
|
||||
function print_html_report(&$tables) {
|
||||
global $OUTPUT;
|
||||
$count = count($tables);
|
||||
foreach($tables as $i=>$table) {
|
||||
|
||||
$this->print_html_start($table);
|
||||
$this->print_html_head($table);
|
||||
$this->print_html_data($table);
|
||||
$this->print_html_stat($table);
|
||||
$this->print_html_foot($table);
|
||||
$this->print_html_finish($table);
|
||||
|
||||
if (($i+1)<$count) {
|
||||
echo $OUTPUT->spacer(array('height'=>30, 'width'=>10, 'br'=>true)); // should be done with CSS instead
|
||||
}
|
||||
}
|
||||
}
|
||||
function print_html_start(&$table) {
|
||||
global $OUTPUT;
|
||||
// default class for the table
|
||||
if (empty($table->tableclass)) {
|
||||
$table->tableclass = 'generaltable';
|
||||
}
|
||||
|
||||
// default classes for TD and TH
|
||||
$d = $table->tableclass.'cell';
|
||||
$h = $table->tableclass.'header';
|
||||
|
||||
$table->th_side = '<th valign="top" align="right" class="'.$h.'" scope="col">';
|
||||
|
||||
$table->td = array();
|
||||
$table->th_top = array();
|
||||
|
||||
if (empty($table->colspan)) {
|
||||
if (isset($table->head)) {
|
||||
$table->colspan = count($table->head);
|
||||
} else if (isset($table->data)) {
|
||||
$table->colspan = count($table->data[0]);
|
||||
} else if (isset($table->stat)) {
|
||||
$table->colspan = count($table->stat);
|
||||
} else if (isset($table->foot)) {
|
||||
$table->colspan = count($table->foot);
|
||||
} else {
|
||||
$table->colspan = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for ($i=0; $i<$table->colspan; $i++) {
|
||||
|
||||
$align = empty($table->align[$i]) ? '' : ' align="'.$table->align[$i].'"';
|
||||
$class = empty($table->class[$i]) ? $d : ' class="'.$table->class[$i].'"';
|
||||
$class = ' class="'.(empty($table->class[$i]) ? $d : $table->class[$i]).'"';
|
||||
$size = empty($table->size[$i]) ? '' : ' width="'.$table->size[$i].'"';
|
||||
$wrap = empty($table->wrap[$i]) ? '' : ' nowrap="nowrap"';
|
||||
|
||||
$table->th_top[$i] = '<th align="center"'.$size.' class="'.$h.'" nowrap="nowrap" scope="col">';
|
||||
|
||||
$table->td[$i] = '<td valign="top"'.$align.$class.$wrap.'>';
|
||||
|
||||
if (!empty($table->fontsize[$i])) {
|
||||
$table->td[$i] .= '<font size="'.$table->fontsize[$i].'">';
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($table->border)) {
|
||||
$table->border = 0;
|
||||
}
|
||||
if (empty($table->cellpadding)) {
|
||||
$table->cellpadding = 5;
|
||||
}
|
||||
if (empty($table->cellspacing)) {
|
||||
$table->cellspacing = 1;
|
||||
}
|
||||
if (empty($table->width)) {
|
||||
$table->width = "80%"; // actually the width of the "simple box"
|
||||
}
|
||||
if (empty($table->tablealign)) {
|
||||
$table->tablealign = "center";
|
||||
}
|
||||
|
||||
if (isset($table->start)) {
|
||||
print $table->start."\n";
|
||||
}
|
||||
|
||||
echo $OUTPUT->box_start("generalbox boxalign$table->tablealign");
|
||||
print '<table width="100%" border="'.$table->border.'" valign="top" align="center" cellpadding="'.$table->cellpadding.'" cellspacing="'.$table->cellspacing.'" class="'.$table->tableclass.'">'."\n";
|
||||
|
||||
if (isset($table->caption)) {
|
||||
print '<tr><td colspan="'.$table->colspan.'" class="'.$table->tableclass.'header"><b>'.$table->caption.'</b></td></tr>'."\n";
|
||||
}
|
||||
|
||||
}
|
||||
function print_html_head(&$table) {
|
||||
if (isset($table->head)) {
|
||||
print "<tr>\n";
|
||||
foreach ($table->head as $i=>$cell) {
|
||||
$th = $table->th_top[$i];
|
||||
print $th.$cell."</th>\n";
|
||||
}
|
||||
print "</tr>\n";
|
||||
}
|
||||
}
|
||||
function print_html_data(&$table) {
|
||||
if (isset($table->data)) {
|
||||
$skipcol = array();
|
||||
foreach ($table->data as $cells) {
|
||||
print "<tr>\n";
|
||||
if (is_array($cells)) {
|
||||
$i = 0; // index on $cells
|
||||
$col = 0; // column index
|
||||
while ($col<$table->colspan && isset($cells[$i])) {
|
||||
if (empty($skipcol[$col])) {
|
||||
$cell = &$cells[$i++];
|
||||
$td = $table->td[$col];
|
||||
if (is_object($cell)) {
|
||||
$text = $cell->text;
|
||||
if (isset($cell->rowspan) && is_numeric($cell->rowspan) && ($cell->rowspan>0)) {
|
||||
$td = '<td rowspan="'.$cell->rowspan.'"'.substr($td, 3);
|
||||
// skip cells below this one
|
||||
$skipcol[$col] = $cell->rowspan-1;
|
||||
}
|
||||
if (isset($cell->colspan) && is_numeric($cell->colspan) && ($cell->colspan>0)) {
|
||||
$td = '<td colspan="'.$cell->colspan.'"'.substr($td, 3);
|
||||
// skip cells to the right of this one
|
||||
for ($c=1; $c<$cell->colspan; $c++) {
|
||||
if (empty($skipcol[$col+$c])) {
|
||||
$skipcol[$col+$c] = 1;
|
||||
} else {
|
||||
$skipcol[$col+$c] ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // $cell is a string
|
||||
$text = $cell;
|
||||
}
|
||||
print $td.$text.(empty($table->fontsize[$col]) ? '' : '</font>')."</td>\n";
|
||||
} else {
|
||||
$skipcol[$col]--;
|
||||
}
|
||||
$col++;
|
||||
} // end while
|
||||
} else if ($cells=='hr') {
|
||||
print '<td colspan="'.$table->colspan.'"><div class="tabledivider"></div></td>'."\n";
|
||||
}
|
||||
print "</tr>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
function print_html_stat(&$table) {
|
||||
if (isset($table->stat)) {
|
||||
if (empty($table->statheadercols)) {
|
||||
$table->statheadercols = array();
|
||||
}
|
||||
foreach ($table->stat as $cells) {
|
||||
print '<tr>';
|
||||
foreach ($cells as $i => $cell) {
|
||||
if (in_array($i, $table->statheadercols)) {
|
||||
$th = $table->th_side;
|
||||
print $th.$cell."</th>\n";
|
||||
} else {
|
||||
$td = $table->td[$i];
|
||||
print $td.$cell."</td>\n";
|
||||
}
|
||||
}
|
||||
print "</tr>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
function print_html_foot(&$table) {
|
||||
if (isset($table->foot)) {
|
||||
foreach ($table->foot as $cells) {
|
||||
print "<tr>\n";
|
||||
foreach ($cells as $i => $cell) {
|
||||
if ($i==0) {
|
||||
$th = $table->th_side;
|
||||
print $th.$cell."</th>\n";
|
||||
} else {
|
||||
$th = $table->th_top[$i];
|
||||
print $th.$cell."</th>\n";
|
||||
}
|
||||
}
|
||||
print "</tr>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
function print_html_finish(&$table) {
|
||||
global $OUTPUT;
|
||||
print "</table>\n";
|
||||
echo $OUTPUT->box_end();
|
||||
|
||||
if (isset($table->finish)) {
|
||||
print $table->finish."\n";
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
/// print a text report
|
||||
|
||||
function print_text_report(&$course, &$hotpot, &$tables, &$options) {
|
||||
$this->print_text_start($course, $hotpot, $options);
|
||||
foreach ($tables as $table) {
|
||||
$this->print_text_head($table, $options);
|
||||
$this->print_text_data($table, $options);
|
||||
$this->print_text_stat($table, $options);
|
||||
$this->print_text_foot($table, $options);
|
||||
}
|
||||
}
|
||||
function print_text_start(&$course, &$hotpot, &$options) {
|
||||
$downloadfilename = clean_filename("$course->shortname $hotpot->name.txt");
|
||||
header("Content-Type: application/download\n");
|
||||
header("Content-Disposition: attachment; filename=$downloadfilename");
|
||||
header("Expires: 0");
|
||||
header("Cache-Control: must-revalidate, post-check=0,pre-check=0");
|
||||
header("Pragma: public");
|
||||
}
|
||||
function print_text_head(&$table, &$options) {
|
||||
if (isset($table->caption)) {
|
||||
$i = strlen($table->caption);
|
||||
$data = array(
|
||||
array(str_repeat('=', $i)),
|
||||
array($table->caption),
|
||||
array(str_repeat('=', $i)),
|
||||
);
|
||||
foreach($data as $cells) {
|
||||
$this->print_text_cells($cells, $options);
|
||||
}
|
||||
}
|
||||
if (isset($table->head)) {
|
||||
$this->expand_spans($table, 'head');
|
||||
$this->print_text_cells($table->head, $options);
|
||||
}
|
||||
}
|
||||
function print_text_data(&$table, &$options) {
|
||||
if (isset($table->data)) {
|
||||
$this->expand_spans($table, 'data');
|
||||
foreach ($table->data as $cells) {
|
||||
$this->print_text_cells($cells, $options);
|
||||
}
|
||||
}
|
||||
}
|
||||
function print_text_stat(&$table, &$options) {
|
||||
if (isset($table->stat)) {
|
||||
$this->expand_spans($table, 'stat');
|
||||
foreach ($table->stat as $cells) {
|
||||
$this->print_text_cells($cells, $options);
|
||||
}
|
||||
}
|
||||
}
|
||||
function print_text_foot(&$table, &$options) {
|
||||
if (isset($table->foot)) {
|
||||
$this->expand_spans($table, 'foot');
|
||||
foreach ($table->foot as $cells) {
|
||||
$this->print_text_cells($cells, $options);
|
||||
}
|
||||
}
|
||||
}
|
||||
function print_text_cells(&$cells, &$options) {
|
||||
|
||||
// do nothing if there are no cells
|
||||
if (empty($cells) || is_string($cells)) return;
|
||||
|
||||
// convert to tab-delimted string
|
||||
$str = implode("\t", $cells);
|
||||
|
||||
// replace newlines in string
|
||||
$str = preg_replace("/\n/", ",", $str);
|
||||
|
||||
// set best newline for this browser (if it hasn't been done already)
|
||||
if (empty($this->nl)) {
|
||||
$s = &$_SERVER['HTTP_USER_AGENT'];
|
||||
$win = is_numeric(strpos($s, 'Win'));
|
||||
$mac = is_numeric(strpos($s, 'Mac')) && !is_numeric(strpos($s, 'OS X'));
|
||||
$this->nl = $win ? "\r\n" : ($mac ? "\r" : "\n");
|
||||
}
|
||||
|
||||
print $str.$this->nl;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
/// print an Excel report
|
||||
|
||||
function print_excel_report(&$course, &$hotpot, &$tables, &$options) {
|
||||
global $CFG;
|
||||
|
||||
// create Excel workbook
|
||||
if (file_exists("$CFG->libdir/excellib.class.php")) {
|
||||
// Moodle >= 1.6
|
||||
require_once("$CFG->libdir/excellib.class.php");
|
||||
$wb = new MoodleExcelWorkbook("-");
|
||||
$wsnamelimit = 0; // no limit
|
||||
} else {
|
||||
// Moodle <= 1.5
|
||||
require_once("$CFG->libdir/excel/Worksheet.php");
|
||||
require_once("$CFG->libdir/excel/Workbook.php");
|
||||
$wb = new Workbook("-");
|
||||
$wsnamelimit = 31; // max length in chars
|
||||
}
|
||||
|
||||
// send HTTP headers
|
||||
$this->print_excel_headers($wb, $course, $hotpot);
|
||||
|
||||
// create one worksheet for each table
|
||||
foreach($tables as $table) {
|
||||
unset($ws);
|
||||
if (empty($table->caption)) {
|
||||
$wsname = '';
|
||||
} else {
|
||||
$wsname = strip_tags($table->caption);
|
||||
if ($wsnamelimit && strlen($wsname) > $wsnamelimit) {
|
||||
$wsname = substr($wsname, -$wsnamelimit); // end of string
|
||||
// $wsname = substr($wsname, 0, $wsnamelimit); // start of string
|
||||
}
|
||||
}
|
||||
$ws = &$wb->add_worksheet($wsname);
|
||||
|
||||
$row = 0;
|
||||
$this->print_excel_head($wb, $ws, $table, $row, $options);
|
||||
$this->print_excel_data($wb, $ws, $table, $row, $options);
|
||||
$this->print_excel_stat($wb, $ws, $table, $row, $options);
|
||||
$this->print_excel_foot($wb, $ws, $table, $row, $options);
|
||||
}
|
||||
|
||||
// close the workbook (and send it to the browser)
|
||||
$wb->close();
|
||||
}
|
||||
function print_excel_headers(&$wb, &$course, &$hotpot) {
|
||||
$downloadfilename = clean_filename("$course->shortname $hotpot->name.xls");
|
||||
if (method_exists($wb, 'send')) {
|
||||
// Moodle >=1.6
|
||||
$wb->send($downloadfilename);
|
||||
} else {
|
||||
// Moodle <=1.5
|
||||
header("Content-type: application/vnd.ms-excel");
|
||||
header("Content-Disposition: attachment; filename=$downloadfilename" );
|
||||
header("Expires: 0");
|
||||
header("Cache-Control: must-revalidate, post-check=0,pre-check=0");
|
||||
header("Pragma: public");
|
||||
}
|
||||
}
|
||||
function print_excel_head(&$wb, &$ws, &$table, &$row, &$options) {
|
||||
// define format properties
|
||||
$properties = array(
|
||||
'bold'=>1,
|
||||
'align'=>'center',
|
||||
'v_align'=>'bottom',
|
||||
'text_wrap'=>1
|
||||
);
|
||||
|
||||
// expand multi-column and multi-row cells
|
||||
$this->expand_spans($table, 'head');
|
||||
|
||||
// print the headings
|
||||
$this->print_excel_cells($wb, $ws, $table, $row, $properties, $table->head, $options);
|
||||
}
|
||||
function print_excel_data(&$wb, &$ws, &$table, &$row, &$options) {
|
||||
// do nothing if there are no cells
|
||||
if (empty($table->data)) return;
|
||||
|
||||
// define format properties
|
||||
$properties = array('text_wrap' => (empty($options['reportwrapdata']) ? 0 : 1));
|
||||
|
||||
// expand multi-column and multi-row cells
|
||||
$this->expand_spans($table, 'data');
|
||||
|
||||
// print rows
|
||||
foreach ($table->data as $cells) {
|
||||
$this->print_excel_cells($wb, $ws, $table, $row, $properties, $cells, $options);
|
||||
}
|
||||
}
|
||||
function print_excel_stat(&$wb, &$ws, &$table, &$row, &$options) {
|
||||
// do nothing if there are no cells
|
||||
if (empty($table->stat)) return;
|
||||
|
||||
// define format properties
|
||||
$properties = array('align'=>'right');
|
||||
|
||||
// expand multi-column and multi-row cells
|
||||
$this->expand_spans($table, 'stat');
|
||||
|
||||
// print rows
|
||||
$i_count = count($table->stat);
|
||||
foreach ($table->stat as $i => $cells) {
|
||||
|
||||
// set border on top and bottom row
|
||||
$properties['top'] = ($i==0) ? 1 : 0;
|
||||
$properties['bottom'] = ($i==($i_count-1)) ? 1 : 0;
|
||||
|
||||
// print this row
|
||||
$this->print_excel_cells($wb, $ws, $table, $row, $properties, $cells, $options, $table->statheadercols);
|
||||
}
|
||||
}
|
||||
function print_excel_foot(&$wb, &$ws, &$table, &$row, &$options) {
|
||||
// do nothing if there are no cells
|
||||
if (empty($table->foot)) return;
|
||||
|
||||
// define format properties
|
||||
$properties = array('bold'=>1, 'align'=>'center');
|
||||
|
||||
// expand multi-column and multi-row cells
|
||||
$this->expand_spans($table, 'foot');
|
||||
|
||||
// print rows
|
||||
$i_count = count($table->foot);
|
||||
foreach ($table->foot as $i => $cells) {
|
||||
|
||||
// set border on top and bottom row
|
||||
$properties['top'] = ($i==0) ? 1 : 0;
|
||||
$properties['bottom'] = ($i==($i_count-1)) ? 1 : 0;
|
||||
|
||||
// print this footer row
|
||||
$this->print_excel_cells($wb, $ws, $table, $row, $properties, $cells, $options);
|
||||
}
|
||||
}
|
||||
|
||||
function print_excel_cells(&$wb, &$ws, &$table, &$row, &$properties, &$cells, &$options, $statheadercols=NULL) {
|
||||
// do nothing if there are no cells
|
||||
if (empty($cells) || is_string($cells)) return;
|
||||
|
||||
// print cells
|
||||
foreach($cells as $col => $cell) {
|
||||
|
||||
unset($fmt_properties);
|
||||
$fmt_properties = $properties;
|
||||
|
||||
if (empty($fmt_properties['text_wrap'])) {
|
||||
if (strlen("$cell")>=9) {
|
||||
// long cell value
|
||||
$fmt_properties['align'] = 'left';
|
||||
}
|
||||
} else {
|
||||
if (strlen("$cell")<9 && strpos("$cell", "\n")===false) {
|
||||
// short cell value (wrapping not required)
|
||||
$fmt_properties['text_wrap'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// set bold, if required (for stat)
|
||||
if (isset($statheadercols)) {
|
||||
$fmt_properties['bold'] = in_array($col, $statheadercols) ? 1 : 0;
|
||||
$fmt_properties['align'] = in_array($col, $statheadercols) ? 'right' : $table->align[$col];
|
||||
}
|
||||
|
||||
// set align, if required
|
||||
if (isset($table->align[$col]) && empty($fmt_properties['align'])) {
|
||||
$fmt_properties['align'] = $table->align[$col];
|
||||
}
|
||||
|
||||
// check to see that an identical format object has not already been created
|
||||
unset($fmt);
|
||||
|
||||
if (isset($wb->pear_excel_workbook)) {
|
||||
// Moodle >=1.6
|
||||
$fmt_properties_obj = (object)$fmt_properties;
|
||||
foreach ($wb->pear_excel_workbook->_formats as $id=>$format) {
|
||||
if ($format==$fmt_properties_obj) {
|
||||
$fmt = &$wb->pear_excel_workbook->_formats[$id];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Moodle <=1.5
|
||||
foreach ($wb->formats as $id=>$format) {
|
||||
if (isset($format->properties) && $format->properties==$fmt_properties) {
|
||||
$fmt = &$wb->formats[$id];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_numeric($cell) || empty($options['reportencoding'])) {
|
||||
// do nothing
|
||||
} else {
|
||||
$in_charset = '';
|
||||
if (function_exists('mb_convert_encoding')) {
|
||||
$in_charset = mb_detect_encoding($cell, 'auto');
|
||||
}
|
||||
if (empty($in_charset)) {
|
||||
$in_charset = 'UTF-8';
|
||||
}
|
||||
if ($in_charset != 'ASCII' && function_exists('mb_convert_encoding')) {
|
||||
$cell = mb_convert_encoding($cell, $options['reportencoding'], $in_charset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create new format object, if necessary (to avoid "too many cell formats" error)
|
||||
if (!isset($fmt)) {
|
||||
$fmt = &$wb->add_format($fmt_properties);
|
||||
$fmt->properties = &$fmt_properties;
|
||||
|
||||
// set vertical alignment
|
||||
if (isset($fmt->properties['v_align'])) {
|
||||
$fmt->set_align($fmt->properties['v_align']);
|
||||
} else {
|
||||
$fmt->set_align('top'); // default
|
||||
}
|
||||
}
|
||||
|
||||
// write cell
|
||||
if (is_numeric($cell) && !preg_match("/^0./", $cell)) {
|
||||
$ws->write_number($row, $col, $cell, $fmt);
|
||||
} else {
|
||||
$ws->write_string($row, $col, $cell, $fmt);
|
||||
}
|
||||
} // end foreach $col
|
||||
|
||||
// increment $row
|
||||
$row++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,449 +0,0 @@
|
||||
<?php
|
||||
/// Overview report just displays a big table of all the attempts
|
||||
class hotpot_report extends hotpot_default_report {
|
||||
function display(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options) {
|
||||
global $CFG;
|
||||
// create the tables
|
||||
$tables = array();
|
||||
$this->create_responses_table($hotpot, $course, $users, $attempts, $questions, $options, $tables);
|
||||
$this->create_analysis_table($users, $attempts, $questions, $options, $tables);
|
||||
// print report
|
||||
$this->print_report($course, $hotpot, $tables, $options);
|
||||
return true;
|
||||
}
|
||||
function create_responses_table(&$hotpot, &$course, &$users, &$attempts, &$questions, &$options, &$tables) {
|
||||
global $CFG, $OUTPUT;
|
||||
$is_html = ($options['reportformat']=='htm');
|
||||
// shortcuts for font tags
|
||||
$br = $is_html ? "<br />\n" : "\n";
|
||||
$blank = $is_html ? ' ' : "";
|
||||
$font_end = $is_html ? '</font>' : '';
|
||||
$font_red = $is_html ? '<font color="red">' : '';
|
||||
$font_blue = $is_html ? '<font color="blue">' : '';
|
||||
$font_brown = $is_html ? '<font color="brown">' : '';
|
||||
$font_green = $is_html ? '<font color="green">' : '';
|
||||
$font_small = $is_html ? '<font size="-2">' : '';
|
||||
$nobr_start = $is_html ? '<nobr>' : '';
|
||||
$nobr_end = $is_html ? '</nobr>' : '';
|
||||
// is review allowed? (do this once here, to save time later)
|
||||
$allow_review = ($is_html && (has_capability('mod/hotpot:viewreport',get_context_instance(CONTEXT_COURSE, $course->id)) || $hotpot->review));
|
||||
// assume penalties column is NOT required
|
||||
$show_penalties = false;
|
||||
// initialize $table
|
||||
unset($table);
|
||||
$table->border = 1;
|
||||
$table->width = '100%';
|
||||
// initialize legend, if necessary
|
||||
if (!empty($options['reportshowlegend'])) {
|
||||
$table->legend = array();
|
||||
}
|
||||
// headings for name, attempt number, score/grade and penalties
|
||||
$table->head = array(
|
||||
get_string("name"),
|
||||
hotpot_grade_heading($hotpot, $options),
|
||||
get_string('attempt', 'quiz'),
|
||||
);
|
||||
$table->align = array('left', 'center', 'center');
|
||||
$table->size = array(150, 80, 10);
|
||||
$table->wrap = array(0, 0, 0);
|
||||
$table->fontsize = array(0, 0, 0);
|
||||
// question headings
|
||||
$this->add_question_headings($questions, $table, 'left', 0, false, 2);
|
||||
// penalties (not always needed) and raw score
|
||||
array_push($table->head,
|
||||
get_string('penalties', 'hotpot'),
|
||||
get_string('score', 'quiz')
|
||||
);
|
||||
array_push($table->align, 'center', 'center');
|
||||
array_push($table->size, 50, 50);
|
||||
array_push($table->wrap, 0, 0);
|
||||
array_push($table->fontsize, 0, 0);
|
||||
// message strings
|
||||
$strnoresponse = get_string('noresponse', 'quiz');
|
||||
// array to map columns onto question ids ($col => $id)
|
||||
$questionids = array_keys($questions);
|
||||
// add details of users' responses
|
||||
foreach ($users as $user) {
|
||||
// shortcut to user info held in first attempt record
|
||||
$u = &$user->attempts[0];
|
||||
if (function_exists("fullname")) {
|
||||
$name = fullname($u);
|
||||
} else {
|
||||
$name = "$u->firstname $u->lastname";
|
||||
}
|
||||
if ($is_html) {
|
||||
$name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$u->userid.'&course='.$course->id.'">'.$name.'</a>';
|
||||
}
|
||||
$grade = isset($user->grade) ? $user->grade : $blank;
|
||||
foreach ($user->attempts as $attempt) {
|
||||
$attemptnumber = $attempt->attempt;
|
||||
if ($allow_review) {
|
||||
$attemptnumber = ' <a href="review.php?hp='.$hotpot->id.'&attempt='.$attempt->id.'">'.$attemptnumber.'</a>';
|
||||
}
|
||||
$cells = array ($name, $grade, $attemptnumber);
|
||||
// $name and $grade are only printed on first line per user
|
||||
$name = $blank;
|
||||
$grade = $blank;
|
||||
$start_col = count($cells);
|
||||
foreach ($questionids as $col => $id) {
|
||||
$cells[$start_col + $col] = "$font_brown($strnoresponse)$font_end";
|
||||
}
|
||||
if (isset($attempt->penalties)) {
|
||||
$show_penalties = true;
|
||||
$penalties = $attempt->penalties;
|
||||
} else {
|
||||
$penalties = $blank;
|
||||
}
|
||||
array_push($cells, $penalties, hotpot_format_score($attempt));
|
||||
// get responses to questions in this attempt
|
||||
foreach ($attempt->responses as $response) {
|
||||
// check this question id is OK (should be)
|
||||
$col = array_search($response->question, $questionids);
|
||||
if (is_numeric($col)) {
|
||||
// correct
|
||||
if ($value = hotpot_strings($response->correct)) {
|
||||
$this->set_legend($table, $col, $value, $questions[$response->question]);
|
||||
} else {
|
||||
$value = "($strnoresponse)";
|
||||
}
|
||||
$cell = $font_red.$value.$font_end;
|
||||
// wrong
|
||||
if ($value = hotpot_strings($response->wrong)) {
|
||||
if (isset($table->legend)) {
|
||||
$values = array();
|
||||
foreach (explode(',', $value) as $v) {
|
||||
$this->set_legend($table, $col, $v, $questions[$response->question]);
|
||||
$values[] = $v;
|
||||
}
|
||||
$value = implode(',', $values);
|
||||
}
|
||||
$cell .= $br.$font_blue.$value.$font_end;
|
||||
}
|
||||
// ignored
|
||||
if ($value = hotpot_strings($response->ignored)) {
|
||||
if (isset($table->legend)) {
|
||||
$values = array();
|
||||
foreach (explode(',', $value) as $v) {
|
||||
$this->set_legend($table, $col, $v, $questions[$response->question]);
|
||||
$values[] = $v;
|
||||
}
|
||||
$value = implode(',', $values);
|
||||
}
|
||||
$cell .= $br.$font_brown.$value.$font_end;
|
||||
}
|
||||
// numeric
|
||||
if (is_numeric($response->score)) {
|
||||
if (empty($table->caption)) {
|
||||
$table->caption = get_string('indivresp', 'quiz');
|
||||
if ($is_html) {
|
||||
$table->caption .= $OUTPUT->old_help_icon('responsestable', $table->caption, 'hotpot');
|
||||
}
|
||||
}
|
||||
$hints = empty($response->hints) ? 0 : $response->hints;
|
||||
$clues = empty($response->clues) ? 0 : $response->clues;
|
||||
$checks = empty($response->checks) ? 0 : $response->checks;
|
||||
$numeric = $response->score.'% '.$blank.' ('.$hints.','.$clues.','.$checks.')';
|
||||
$cell .= $br.$nobr_start.$font_green.$numeric.$font_end.$nobr_end;
|
||||
}
|
||||
$cells[$start_col + $col] = $cell;
|
||||
}
|
||||
}
|
||||
$table->data[] = $cells;
|
||||
}
|
||||
// insert 'tabledivider' between users
|
||||
$table->data[] = 'hr';
|
||||
} // end foreach $users
|
||||
// remove final 'hr' from data rows
|
||||
array_pop($table->data);
|
||||
if (!$show_penalties) {
|
||||
$col = 3 + count($questionids);
|
||||
$this->remove_column($table, $col);
|
||||
}
|
||||
$tables[] = &$table;
|
||||
}
|
||||
function create_analysis_table(&$users, &$attempts, &$questions, &$options, &$tables) {
|
||||
global $OUTPUT;
|
||||
$is_html = ($options['reportformat']=='htm');
|
||||
// the fields we are interested in, in the order we want them
|
||||
$fields = array('correct', 'wrong', 'ignored', 'hints', 'clues', 'checks', 'weighting');
|
||||
$string_fields = array('correct', 'wrong', 'ignored');
|
||||
$q = array(); // statistics about the $q(uestions)
|
||||
$f = array(); // statistics about the $f(ields)
|
||||
////////////////////////////////////////////
|
||||
// compile the statistics about the questions
|
||||
////////////////////////////////////////////
|
||||
foreach ($questions as $id=>$question) {
|
||||
// extract scores for attempts at this question
|
||||
$scores = array();
|
||||
foreach ($question->attempts as $attempt) {
|
||||
$scores[] = $attempt->score;
|
||||
}
|
||||
// sort scores values (in ascending order)
|
||||
asort($scores);
|
||||
// get the borderline high and low scores
|
||||
$count = count($scores);
|
||||
switch ($count) {
|
||||
case 0:
|
||||
$lo_score = 0;
|
||||
$hi_score = 0;
|
||||
break;
|
||||
case 1:
|
||||
$lo_score = 0;
|
||||
$hi_score = $scores[0];
|
||||
break;
|
||||
default:
|
||||
$lo_score = $scores[round($count*1/3)];
|
||||
$hi_score = $scores[round($count*2/3)];
|
||||
break;
|
||||
}
|
||||
// get statistics for each attempt which includes this question
|
||||
foreach ($question->attempts as $attempt) {
|
||||
$is_hi_score = ($attempt->score >= $hi_score);
|
||||
$is_lo_score = ($attempt->score < $lo_score);
|
||||
// reference to the response to the current question
|
||||
$response = &$attempt->responses[$id];
|
||||
// update statistics for fields in this response
|
||||
foreach($fields as $field) {
|
||||
if (!isset($q[$id])) {
|
||||
$q[$id] = array();
|
||||
}
|
||||
if (!isset($f[$field])) {
|
||||
$f[$field] = array('count' => 0);
|
||||
}
|
||||
if (!isset($q[$id][$field])) {
|
||||
$q[$id][$field] = array('count' => 0);
|
||||
}
|
||||
$values = explode(',', $response->$field);
|
||||
$values = array_unique($values);
|
||||
foreach($values as $value) {
|
||||
// $value should be an integer (string_id or count)
|
||||
if (is_numeric($value)) {
|
||||
$f[$field]['count']++;
|
||||
if (!isset($q[$id][$field][$value])) {
|
||||
$q[$id][$field][$value] = 0;
|
||||
}
|
||||
$q[$id][$field]['count']++;
|
||||
$q[$id][$field][$value]++;
|
||||
}
|
||||
}
|
||||
} // end foreach $field
|
||||
// initialize counters for this question, if necessary
|
||||
if (!isset($q[$id]['count'])) {
|
||||
$q[$id]['count'] = array('hi'=>0, 'lo'=>0, 'correct'=>0, 'total'=>0, 'sum'=>0);
|
||||
}
|
||||
// increment counters
|
||||
$q[$id]['count']['sum'] += $response->score;
|
||||
$q[$id]['count']['total']++;
|
||||
if ($response->score==100) {
|
||||
$q[$id]['count']['correct']++;
|
||||
if ($is_hi_score) {
|
||||
$q[$id]['count']['hi']++;
|
||||
} else if ($is_lo_score) {
|
||||
$q[$id]['count']['lo']++;
|
||||
}
|
||||
}
|
||||
} // end foreach attempt
|
||||
} // end foreach question
|
||||
// check we have some details
|
||||
if (count($q)) {
|
||||
$showhideid = 'showhide';
|
||||
// shortcuts for html tags
|
||||
$bold_start = $is_html ? '<strong>' : "";
|
||||
$bold_end = $is_html ? '</strong>' : "";
|
||||
$div_start = $is_html ? '<div id="'.$showhideid.'">' : "";
|
||||
$div_end = $is_html ? '</div>' : "";
|
||||
$font_red = $is_html ? '<font color="red" size="-2">' : '';
|
||||
$font_blue = $is_html ? '<font color="blue" size="-2">' : '';
|
||||
$font_green = $is_html ? '<font color="green" size="-2">' : '';
|
||||
$font_brown = $is_html ? '<font color="brown" size="-2">' : '';
|
||||
$font_end = $is_html ? '</font>'."\n" : '';
|
||||
$br = $is_html ? '<br />' : "\n";
|
||||
$space = $is_html ? ' ' : "";
|
||||
$no_value = $is_html ? '--' : "";
|
||||
$help_button = $is_html ? $OUTPUT->old_help_icon("discrimination", get_string('discrimination', 'quiz'), "quiz") : "";
|
||||
// table properties
|
||||
unset($table);
|
||||
$table->border = 1;
|
||||
$table->width = '100%';
|
||||
$table->caption = get_string('itemanal', 'quiz');
|
||||
if ($is_html) {
|
||||
$table->caption .= $OUTPUT->old_help_icon('analysistable', $table->caption, 'hotpot');
|
||||
}
|
||||
// initialize legend, if necessary
|
||||
if (!empty($options['reportshowlegend'])) {
|
||||
if (empty($tables) || empty($tables[0]->legend)) {
|
||||
$table->legend = array();
|
||||
} else {
|
||||
$table->legend = $tables[0]->legend;
|
||||
unset($tables[0]->legend);
|
||||
}
|
||||
}
|
||||
// headings for name, attempt number and score/grade
|
||||
$table->head = array($space);
|
||||
$table->align = array('right');
|
||||
$table->size = array(80);
|
||||
// question headings
|
||||
$this->add_question_headings($questions, $table, 'left', 0);
|
||||
// initialize statistics
|
||||
$table->stat = array();
|
||||
$table->statheadercols = array(0);
|
||||
// add headings for the $foot of the $table
|
||||
$table->foot = array();
|
||||
$table->foot[0] = array(get_string('average', 'hotpot'));
|
||||
$table->foot[1] = array(get_string('percentcorrect', 'quiz'));
|
||||
$table->foot[2] = array(get_string('discrimination', 'quiz').$help_button);
|
||||
// maximum discrimination index (also default the default value)
|
||||
$max_d_index = 10;
|
||||
////////////////////////////////////////////
|
||||
// format the statistics into the $table
|
||||
////////////////////////////////////////////
|
||||
// add $stat(istics) and $foot of $table
|
||||
$questionids = array_keys($q);
|
||||
foreach ($questionids as $col => $id) {
|
||||
$row = 0;
|
||||
// print the question text if there is no legend
|
||||
if (empty($table->legend)) {
|
||||
// add button to show/hide question text
|
||||
if (!isset($table->stat[0])) {
|
||||
$button = $is_html ? hotpot_showhide_button($showhideid) : "";
|
||||
$table->stat[0] = array(get_string('question', 'quiz').$button);
|
||||
}
|
||||
// add the question name/text
|
||||
$name = hotpot_get_question_name($questions[$id]);
|
||||
$table->stat[$row++][$col+1] = $div_start.$bold_start.$name.$bold_end.$div_end.$space;
|
||||
}
|
||||
// add details about each field
|
||||
foreach ($fields as $field) {
|
||||
// check this row is required
|
||||
if ($f[$field]['count']) {
|
||||
$values = array();
|
||||
$string_type = array_search($field, $string_fields);
|
||||
// get the value of each response to this field
|
||||
// and the count of that value
|
||||
foreach ($q[$id][$field] as $value => $count) {
|
||||
if (is_numeric($value) && $count) {
|
||||
if (is_numeric($string_type)) {
|
||||
$value = hotpot_string($value);
|
||||
$this->set_legend($table, $col, $value, $questions[$id]);
|
||||
switch ($string_type) {
|
||||
case 0: // correct
|
||||
$font_start = $font_red;
|
||||
break;
|
||||
case 1: // wrong
|
||||
$font_start = $font_blue;
|
||||
break;
|
||||
case 2: // ignored
|
||||
$font_start = $font_brown;
|
||||
break;
|
||||
}
|
||||
} else { // numeric field
|
||||
$font_start = $font_green;
|
||||
}
|
||||
$values[] = $font_start.round(100*$count/$q[$id]['count']['total']).'%'.$font_end.' '.$value;
|
||||
}
|
||||
} // end foreach $value => $count
|
||||
// initialize stat(istics) row for this field, if required
|
||||
if (!isset($table->stat[$row])) {
|
||||
$table->stat[$row] = array(get_string($field, 'hotpot'));
|
||||
}
|
||||
// sort the values by frequency (using user-defined function)
|
||||
usort($values, "hotpot_sort_stat_values");
|
||||
// add stat(istics) values for this field
|
||||
$table->stat[$row++][$col+1] = count($values) ? implode($br, $values) : $space;
|
||||
}
|
||||
} // end foreach field
|
||||
// default percent correct and discrimination index for this question
|
||||
$average = $no_value;
|
||||
$percent = $no_value;
|
||||
$d_index = $no_value;
|
||||
if (isset($q[$id]['count'])) {
|
||||
// average and percent correct
|
||||
if ($q[$id]['count']['total']) {
|
||||
$average = round($q[$id]['count']['sum'] / $q[$id]['count']['total']).'%';
|
||||
$percent = round(100*$q[$id]['count']['correct'] / $q[$id]['count']['total']).'%';
|
||||
$percent .= ' ('.$q[$id]['count']['correct'].'/'.$q[$id]['count']['total'].')';
|
||||
}
|
||||
// discrimination index
|
||||
if ($q[$id]['count']['lo']) {
|
||||
$d_index = min($max_d_index, round($q[$id]['count']['hi'] / $q[$id]['count']['lo'], 1));
|
||||
} else {
|
||||
$d_index = $q[$id]['count']['hi'] ? $max_d_index : 0;
|
||||
}
|
||||
$d_index .= ' ('.$q[$id]['count']['hi'].'/'.$q[$id]['count']['lo'].')';
|
||||
}
|
||||
$table->foot[0][$col+1] = $average;
|
||||
$table->foot[1][$col+1] = $percent;
|
||||
$table->foot[2][$col+1] = $d_index;
|
||||
} // end foreach $question ($col)
|
||||
// add javascript to show/hide question text
|
||||
if (isset($table->stat[0]) && $is_html && empty($table->legend)) {
|
||||
$i = count($table->stat[0]);
|
||||
$table->stat[0][$i-1] .= hotpot_showhide_set($showhideid);
|
||||
}
|
||||
$tables[] = &$table;
|
||||
$this->create_legend_table($tables, $table);
|
||||
} // end if (empty($q)
|
||||
} // end function
|
||||
} // end class
|
||||
function hotpot_sort_stat_values($a, $b) {
|
||||
// sorts in descending order
|
||||
// assumes first chars in $a and $b are a percentage
|
||||
$a_val = intval(strip_tags($a));
|
||||
$b_val = intval(strip_tags($b));
|
||||
return ($a_val<$b_val) ? 1 : ($a_val==$b_val ? 0 : -1);
|
||||
}
|
||||
function hotpot_showhide_button($id) {
|
||||
$show = get_string('show');
|
||||
$hide = get_string('hide');
|
||||
$pref = '1';
|
||||
$text = ($pref=='1' ? $hide : $show);
|
||||
return <<<SHOWHIDE_BUTTON
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
function showhide (id, toggle) {
|
||||
var show = true;
|
||||
obj = document.getElementById(id+'pref');
|
||||
if (obj) {
|
||||
show = (obj.value=='1');
|
||||
if (toggle) {
|
||||
show = !show;
|
||||
obj.value = (show ? '1' : '0');
|
||||
}
|
||||
}
|
||||
obj = document.getElementById(id+'button');
|
||||
if (obj) {
|
||||
obj.value = (show ? '$hide' : '$show');
|
||||
}
|
||||
obj = document.getElementsByName(id);
|
||||
var i_max = obj.length;
|
||||
for (var i=0; i<i_max; i++) {
|
||||
obj[i].style.display = (show ? 'block' : 'none');
|
||||
}
|
||||
}
|
||||
var showhide_allowed = (document.getElementById && document.getElementsByName);
|
||||
if (showhide_allowed) {
|
||||
var html = '';
|
||||
html += '<form onsubmit="return false">';
|
||||
html += '<input type="button" value="$text" id="{$id}button" onClick="javascript: return showhide(\\'$id\\', true);" />';
|
||||
html += '<input type="hidden" name="{$id}pref" id="{$id}pref" value="$pref" />';
|
||||
html += '</form>';
|
||||
document.writeln(html);
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
SHOWHIDE_BUTTON
|
||||
;
|
||||
}
|
||||
function hotpot_showhide_set($id) {
|
||||
return <<<SHOWHIDE_SET
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
if (showhide_allowed) {
|
||||
showhide('$id');
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
SHOWHIDE_SET
|
||||
;
|
||||
}
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
<?php
|
||||
/// Overview report just displays a big table of all the attempts
|
||||
class hotpot_report extends hotpot_default_report {
|
||||
|
||||
function display(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options) {
|
||||
$tables = array();
|
||||
$this->create_overview_table($hotpot, $cm, $course, $users, $attempts, $questions, $options, $tables);
|
||||
$this->print_report($course, $hotpot, $tables, $options);
|
||||
return true;
|
||||
}
|
||||
function create_overview_table(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options, &$tables) {
|
||||
global $CFG, $OUTPUT;
|
||||
$strtimeformat = get_string('strftimedatetime');
|
||||
$is_html = ($options['reportformat']=='htm');
|
||||
$spacer = $is_html ? ' ' : ' ';
|
||||
$br = $is_html ? "<br />\n" : "\n";
|
||||
// initialize $table
|
||||
unset($table);
|
||||
$table->border = 1;
|
||||
$table->width = 10;
|
||||
$table->head = array();
|
||||
$table->align = array();
|
||||
$table->size = array();
|
||||
$table->wrap = array();
|
||||
// picture column, if required
|
||||
if ($is_html) {
|
||||
$table->head[] = $spacer;
|
||||
$table->align[] = 'center';
|
||||
$table->size[] = 10;
|
||||
$table->wrap[] = "nowrap";
|
||||
}
|
||||
array_push($table->head,
|
||||
get_string("name"),
|
||||
hotpot_grade_heading($hotpot, $options),
|
||||
get_string("attempt", "quiz"),
|
||||
get_string("time", "quiz"),
|
||||
get_string("reportstatus", "hotpot"),
|
||||
get_string("timetaken", "quiz"),
|
||||
get_string("score", "quiz")
|
||||
);
|
||||
array_push($table->align, "left", "center", "center", "left", "center", "center", "center");
|
||||
array_push($table->wrap, "nowrap", "nowrap", "nowrap", "nowrap", "nowrap", "nowrap", "nowrap");
|
||||
array_push($table->size, "*", "*", "*", "*", "*", "*", "*");
|
||||
$abandoned = 0;
|
||||
foreach ($users as $user) {
|
||||
// shortcut to user info held in first attempt record
|
||||
$u = &$user->attempts[0];
|
||||
$picture = '';
|
||||
$name = fullname($u);
|
||||
if ($is_html) {
|
||||
//grrrr
|
||||
$usr = clone($u);
|
||||
$u->id = $u->userid;
|
||||
$picture = $OUTPUT->user_picture($usr, array('courseid'=>$course->id));
|
||||
$name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$u->userid.'&course='.$course->id.'">'.$name.'</a>';
|
||||
}
|
||||
$grade = isset($user->grade) && $user->grade<>' ' ? $user->grade : $spacer;
|
||||
$attemptcount = count($user->attempts);
|
||||
if ($attemptcount>1) {
|
||||
$text = $name;
|
||||
$name = NULL;
|
||||
$name->text = $text;
|
||||
$name->rowspan = $attemptcount;
|
||||
$text = $grade;
|
||||
$grade = NULL;
|
||||
$grade->text = $text;
|
||||
$grade->rowspan = $attemptcount;
|
||||
}
|
||||
$data = array();
|
||||
if ($is_html) {
|
||||
if ($attemptcount>1) {
|
||||
$text = $picture;
|
||||
$picture = NULL;
|
||||
$picture->text = $text;
|
||||
$picture->rowspan = $attemptcount;
|
||||
}
|
||||
$data[] = $picture;
|
||||
}
|
||||
array_push($data, $name, $grade);
|
||||
foreach ($user->attempts as $attempt) {
|
||||
// increment count of abandoned attempts
|
||||
// if attempt is marked as finished but has no score
|
||||
if ($attempt->status==HOTPOT_STATUS_ABANDONED) {
|
||||
$abandoned++;
|
||||
}
|
||||
$attemptnumber = $attempt->attempt;
|
||||
$starttime = trim(userdate($attempt->timestart, $strtimeformat));
|
||||
if ($is_html && isset($attempt->score) && (has_capability('mod/hotpot:viewreport',get_context_instance(CONTEXT_COURSE, $course->id)) || $hotpot->review)) {
|
||||
$attemptnumber = '<a href="review.php?hp='.$hotpot->id.'&attempt='.$attempt->id.'">'.$attemptnumber.'</a>';
|
||||
$starttime = '<a href="review.php?hp='.$hotpot->id.'&attempt='.$attempt->id.'">'.$starttime.'</a>';
|
||||
}
|
||||
if ($is_html && has_capability('mod/hotpot:viewreport',get_context_instance(CONTEXT_COURSE, $course->id))) {
|
||||
$checkbox = '<input type="checkbox" name="box'.$attempt->clickreportid.'" value="'.$attempt->clickreportid.'" />'.$spacer;
|
||||
} else {
|
||||
$checkbox = '';
|
||||
}
|
||||
$timetaken = empty($attempt->timefinish) ? $spacer : format_time($attempt->timefinish - $attempt->timestart);
|
||||
$score = hotpot_format_score($attempt);
|
||||
if ($is_html && is_numeric($score) && $score==$user->grade) { // best grade
|
||||
$score = '<span class="highlight">'.$score.'</span>';
|
||||
}
|
||||
array_push($data,
|
||||
$attemptnumber,
|
||||
$checkbox.$starttime,
|
||||
hotpot_format_status($attempt),
|
||||
$timetaken,
|
||||
$score
|
||||
);
|
||||
$table->data[] = $data;
|
||||
$data = array();
|
||||
} // end foreach $attempt
|
||||
$table->data[] = 'hr';
|
||||
} // end foreach $user
|
||||
// remove final 'hr' from data rows
|
||||
array_pop($table->data);
|
||||
// add the "delete" form to the table
|
||||
if ($options['reportformat']=='htm' && has_capability('mod/hotpot:viewreport',get_context_instance(CONTEXT_COURSE, $course->id))) {
|
||||
$strdeletecheck = get_string('deleteattemptcheck','quiz');
|
||||
$table->start = $this->deleteform_javascript();
|
||||
$table->start .= '<form method="post" action="report.php" id="deleteform" onsubmit="'."return deletecheck('".$strdeletecheck."', 'selection')".'">'."\n";
|
||||
$table->start .= '<input type="hidden" name="del" value="selection" />'."\n";
|
||||
$table->start .= '<input type="hidden" name="id" value="'.$cm->id.'" />'."\n";
|
||||
$table->finish = '<center>'."\n";
|
||||
$table->finish .= '<input type="submit" value="'.get_string("deleteselected").'" /> '."\n";
|
||||
if ($abandoned) {
|
||||
$table->finish .= '<input type="button" value="'.get_string('deleteabandoned', 'hotpot').'" onClick="if(deletecheck('."'".addslashes_js(get_string('deleteabandonedcheck', 'hotpot', $abandoned))."', 'abandoned', true".')) document.getElementById(\'deleteform\').submit();" />'."\n";
|
||||
}
|
||||
$table->finish .= '<input type="button" value="'.get_string("deleteall").'" onClick="if(deletecheck('."'".addslashes_js($strdeletecheck)."', 'all', true".'))document.getElementById(\'deleteform\').submit();" />'."\n";
|
||||
$table->finish .= '</center>'."\n";
|
||||
$table->finish .= '</form>'."\n";
|
||||
}
|
||||
$tables[] = &$table;
|
||||
}
|
||||
function deleteform_javascript() {
|
||||
$strselectattempt = addslashes_js(get_string('selectattempt','hotpot'));
|
||||
return <<<END_OF_JAVASCRIPT
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
function deletecheck(p, v, x) {
|
||||
var r = false; // result
|
||||
// get length of form elements
|
||||
var f = document.getElementById('deleteform');
|
||||
var l = f ? f.elements.length : 0;
|
||||
// count selected items, if necessary
|
||||
if (!x) {
|
||||
x = 0;
|
||||
for (var i=0; i<l; i++) {
|
||||
var obj = f.elements[i];
|
||||
if (obj.type && obj.type=='checkbox' && obj.checked) {
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// confirm deletion
|
||||
var n = navigator;
|
||||
if (x || (n.appName=='Netscape' && parseInt(n.appVersion)==2)) {
|
||||
r = confirm(p);
|
||||
if (r) {
|
||||
f.del.value = v;
|
||||
}
|
||||
} else {
|
||||
alert('$strselectattempt');
|
||||
}
|
||||
return r;
|
||||
}
|
||||
//-->
|
||||
</script>
|
||||
END_OF_JAVASCRIPT
|
||||
;
|
||||
} // end function
|
||||
} // end class
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
<?php
|
||||
/// Overview report: displays a big table of all the attempts
|
||||
class hotpot_report extends hotpot_default_report {
|
||||
function display(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options) {
|
||||
global $CFG;
|
||||
// create the table
|
||||
$tables = array();
|
||||
$this->create_scores_table($hotpot, $course, $users, $attempts, $questions, $options, $tables);
|
||||
$this->print_report($course, $hotpot, $tables, $options);
|
||||
return true;
|
||||
}
|
||||
function create_scores_table(&$hotpot, &$course, &$users, &$attempts, &$questions, &$options, &$tables) {
|
||||
global $CFG, $OUTPUT;
|
||||
$download = ($options['reportformat']=='htm') ? false : true;
|
||||
$is_html = ($options['reportformat']=='htm');
|
||||
$blank = ($download ? '' : ' ');
|
||||
$no_value = ($download ? '' : '-');
|
||||
$allow_review = true;
|
||||
// start the table
|
||||
unset($table);
|
||||
$table->border = 1;
|
||||
$table->head = array();
|
||||
$table->align = array();
|
||||
$table->size = array();
|
||||
// picture column, if required
|
||||
if ($is_html) {
|
||||
$table->head[] = ' ';
|
||||
$table->align[] = 'center';
|
||||
$table->size[] = 10;
|
||||
}
|
||||
// name, grade and attempt number
|
||||
array_push($table->head,
|
||||
get_string("name"),
|
||||
hotpot_grade_heading($hotpot, $options),
|
||||
get_string("attempt", "quiz")
|
||||
);
|
||||
array_push($table->align, "left", "center", "center");
|
||||
array_push($table->size, '', '', '');
|
||||
// question headings
|
||||
$this->add_question_headings($questions, $table);
|
||||
// penalties and raw score
|
||||
array_push($table->head,
|
||||
get_string('penalties', 'hotpot'),
|
||||
get_string('score', 'quiz')
|
||||
);
|
||||
array_push($table->align, "center", "center");
|
||||
array_push($table->size, '', '');
|
||||
$table->data = array();
|
||||
$q = array(
|
||||
'grade' => array('count'=>0, 'total'=>0),
|
||||
'penalties' => array('count'=>0, 'total'=>0),
|
||||
'score' => array('count'=>0, 'total'=>0),
|
||||
);
|
||||
foreach ($users as $user) {
|
||||
// shortcut to user info held in first attempt record
|
||||
$u = &$user->attempts[0];
|
||||
$picture = '';
|
||||
$name = fullname($u);
|
||||
if ($is_html) {
|
||||
$picture = $OUTPUT->user_picture($u, array('courseid'=>$course->id));
|
||||
$name = html_writer::link($CFG->wwwroot.'/user/view.php?id='.$u->userid.'&course='.$course->id, $name);
|
||||
}
|
||||
if (isset($user->grade)) {
|
||||
$grade = $user->grade;
|
||||
$q['grade']['count'] ++;
|
||||
if (is_numeric($grade)) {
|
||||
$q['grade']['total'] += $grade;
|
||||
}
|
||||
} else {
|
||||
$grade = $no_value;
|
||||
}
|
||||
$attemptcount = count($user->attempts);
|
||||
if ($attemptcount>1) {
|
||||
$text = $name;
|
||||
$name = NULL;
|
||||
$name->text = $text;
|
||||
$name->rowspan = $attemptcount;
|
||||
$text = $grade;
|
||||
$grade = NULL;
|
||||
$grade->text = $text;
|
||||
$grade->rowspan = $attemptcount;
|
||||
}
|
||||
$data = array();
|
||||
if ($is_html) {
|
||||
if ($attemptcount>1) {
|
||||
$text = $picture;
|
||||
$picture = NULL;
|
||||
$picture->text = $text;
|
||||
$picture->rowspan = $attemptcount;
|
||||
}
|
||||
$data[] = $picture;
|
||||
}
|
||||
array_push($data, $name, $grade);
|
||||
foreach ($user->attempts as $attempt) {
|
||||
// set flag if this is best grade
|
||||
$is_best_grade = ($is_html && $attempt->score==$user->grade);
|
||||
// get attempt number
|
||||
$attemptnumber= $attempt->attempt;
|
||||
if ($is_html && $allow_review) {
|
||||
$attemptnumber = '<a href="review.php?hp='.$hotpot->id.'&attempt='.$attempt->id.'">'.$attemptnumber.'</a>';
|
||||
}
|
||||
if ($is_best_grade) {
|
||||
$score = '<span class="highlight">'.$attemptnumber.'</span>';
|
||||
}
|
||||
$data[] = $attemptnumber;
|
||||
// get responses to questions in this attempt by this user
|
||||
foreach ($questions as $id=>$question) {
|
||||
if (!isset($q[$id])) {
|
||||
$q[$id] = array('count'=>0, 'total'=>0);
|
||||
}
|
||||
if (isset($attempt->responses[$id])) {
|
||||
$score = $attempt->responses[$id]->score;
|
||||
if (is_numeric($score)) {
|
||||
$q[$id]['count'] ++;
|
||||
$q[$id]['total'] += $score;
|
||||
if ($is_best_grade) {
|
||||
$score = '<span class="highlight">'.$score.'</span>';
|
||||
}
|
||||
} else if (empty($score)) {
|
||||
$score = $no_value;
|
||||
}
|
||||
} else {
|
||||
$score = $no_value;
|
||||
}
|
||||
$data[] = $score;
|
||||
} // foreach $questions
|
||||
if (isset($attempt->penalties)) {
|
||||
$penalties = $attempt->penalties;
|
||||
if (is_numeric($penalties)) {
|
||||
$q['penalties']['count'] ++;
|
||||
$q['penalties']['total'] += $penalties;
|
||||
}
|
||||
if ($is_best_grade) {
|
||||
$penalties = '<span class="highlight">'.$penalties.'</span>';
|
||||
}
|
||||
} else {
|
||||
$penalties = $no_value;
|
||||
}
|
||||
$data[] = $penalties;
|
||||
if (isset($attempt->score)) {
|
||||
$score = $attempt->score;
|
||||
if (is_numeric($score)) {
|
||||
$q['score']['total'] += $score;
|
||||
$q['score']['count'] ++;
|
||||
}
|
||||
if ($is_best_grade) {
|
||||
$score = '<span class="highlight">'.$score.'</span>';
|
||||
}
|
||||
} else {
|
||||
$score = $no_value;
|
||||
}
|
||||
$data[] = $score;
|
||||
// append data for this attempt
|
||||
$table->data[] = $data;
|
||||
// reset data array for next attempt, if any
|
||||
$data = array();
|
||||
} // end foreach $attempt
|
||||
$table->data[] = 'hr';
|
||||
} // end foreach $user
|
||||
// remove final 'hr' from data rows
|
||||
array_pop($table->data);
|
||||
// add averages to foot of table
|
||||
$averages = array();
|
||||
if ($is_html) {
|
||||
$averages[] = $blank;
|
||||
}
|
||||
array_push($averages, get_string('average', 'hotpot'));
|
||||
$col = count($averages);
|
||||
if (empty($q['grade']['count'])) {
|
||||
// remove score $col from $table
|
||||
$this->remove_column($table, $col);
|
||||
} else {
|
||||
$precision = ($hotpot->grademethod==HOTPOT_GRADEMETHOD_AVERAGE || $hotpot->grade<100) ? 1 : 0;
|
||||
$averages[] = round($q['grade']['total'] / $q['grade']['count'], $precision);
|
||||
$col++;
|
||||
}
|
||||
// skip the attempt number column
|
||||
$averages[$col++] = $blank;
|
||||
foreach ($questions as $id=>$question) {
|
||||
if (empty($q[$id]['count'])) {
|
||||
// remove this question $col from $table
|
||||
$this->remove_column($table, $col);
|
||||
} else {
|
||||
$averages[$col++] = round($q[$id]['total'] / $q[$id]['count']);
|
||||
}
|
||||
}
|
||||
if (empty($q['penalties']['count'])) {
|
||||
// remove penalties $col from $table
|
||||
$this->remove_column($table, $col);
|
||||
} else {
|
||||
$averages[$col++] = round($q['penalties']['total'] / $q['penalties']['count']);
|
||||
}
|
||||
if (empty($q['score']['count'])) {
|
||||
// remove score $col from $table
|
||||
$this->remove_column($table, $col);
|
||||
} else {
|
||||
$averages[$col++] = round($q['score']['total'] / $q['score']['count']);
|
||||
}
|
||||
$table->foot = array($averages);
|
||||
$tables[] = &$table;
|
||||
}
|
||||
} // end class
|
||||
|
||||
@@ -1,537 +0,0 @@
|
||||
<?php
|
||||
//This php script contains all the stuff to restore hotpot mods
|
||||
//-----------------------------------------------------------
|
||||
// This is the "graphical" structure of the hotpot mod:
|
||||
//-----------------------------------------------------------
|
||||
//
|
||||
// hotpot
|
||||
// (CL, pk->id,
|
||||
// fk->course, files)
|
||||
// |
|
||||
// +--------------+---------------+
|
||||
// | |
|
||||
// hotpot_attempts hotpot_questions
|
||||
// (UL, pk->id, (UL, pk->id,
|
||||
// fk->hotpot) fk->hotpot, text)
|
||||
// | | |
|
||||
// +-------------------+----------+ |
|
||||
// | | |
|
||||
// hotpot_details hotpot_responses |
|
||||
// (UL, pk->id, (UL, pk->id, |
|
||||
// fk->attempt) fk->attempt, question, |
|
||||
// correct, wrong, ignored) |
|
||||
// | |
|
||||
// +-------+-------+
|
||||
// |
|
||||
// hotpot_strings
|
||||
// (UL, pk->id)
|
||||
//
|
||||
// Meaning: pk->primary key field of the table
|
||||
// fk->foreign key to link with parent
|
||||
// nt->nested field (recursive data)
|
||||
// CL->course level info
|
||||
// UL->user level info
|
||||
// files->table may have files
|
||||
//
|
||||
//-----------------------------------------------------------
|
||||
|
||||
require_once ("$CFG->dirroot/mod/hotpot/lib.php");
|
||||
|
||||
function hotpot_restore_mods($mod, $restore) {
|
||||
//This function restores a single hotpot activity
|
||||
|
||||
// This function is called by "restore_create_modules" (in "backup/restorelib.php")
|
||||
// which is called by "backup/restore_execute.html" (included by "backup/restore.php")
|
||||
// $mod is an object
|
||||
// id : id field in 'modtype' table
|
||||
// modtype : 'hotpot'
|
||||
// $restore is an object
|
||||
// backup_unique_code : xxxxxxxxxx
|
||||
// file : '/full/path/to/backupfile.zip'
|
||||
// mods : an array of $modinfo's (see below)
|
||||
// restoreto : See RESTORETO_XXX constants in backup/lib.php
|
||||
// users : 0=all, 1=course, 2=none
|
||||
// logs : 0=no, 1=yes
|
||||
// user_files : 0=no, 1=yes
|
||||
// course_files : 0=no, 1=yes
|
||||
// course_id : id of course into which data is to be restored
|
||||
// deleting : true if 'restoreto'==RESTORETO_NEW_COURSE, otherwise false
|
||||
// original_wwwroot : 'http://your.server.com/moodle'
|
||||
// $modinfo is an array
|
||||
// 'modname' : array( 'restore'=> 0=no 1=yes, 'userinfo' => 0=no 1=yes)
|
||||
|
||||
global $CFG;
|
||||
$status = true;
|
||||
|
||||
// get course module data this hotpot activity
|
||||
$data = backup_getid($restore->backup_unique_code, 'hotpot', $mod->id);
|
||||
if ($data) {
|
||||
// $data is an object
|
||||
// backup_code => xxxxxxxxxx,
|
||||
// table_name => 'hotpot',
|
||||
// old_id => xxx,
|
||||
// new_id => NULL,
|
||||
// info => xml tree array of info backed up for this hotpot activity
|
||||
$xml = &$data->info['MOD']['#'];
|
||||
$table = 'hotpot';
|
||||
$foreign_keys = array('course' => $restore->course_id);
|
||||
$more_restore = '';
|
||||
// print a message after each hotpot is backed up
|
||||
if (!defined('RESTORE_SILENTLY')) {
|
||||
$more_restore .= 'print "<li>".get_string("modulename", "hotpot")." "".format_string($record->name,true).""</li>";';
|
||||
}
|
||||
$more_restore .= 'backup_flush(300);';
|
||||
if (function_exists('restore_userdata_selected')) {
|
||||
// Moodle >= 1.6
|
||||
$restore_userdata_selected = restore_userdata_selected($restore, 'hotpot', $mod->id);
|
||||
} else {
|
||||
// Moodle <= 1.5
|
||||
$restore_userdata_selected = $restore->mods['hotpot']->userinfo;
|
||||
}
|
||||
if ($restore_userdata_selected) {
|
||||
$has_details = false;
|
||||
if (isset($xml["ATTEMPT_DATA"]["0"]["#"]["ATTEMPT"]["0"]["#"]["DETAILS"]["0"]["#"])) {
|
||||
$details = trim($xml["ATTEMPT_DATA"]["0"]["#"]["ATTEMPT"]["0"]["#"]["DETAILS"]["0"]["#"]);
|
||||
if ($details<>'' && $details<>'<?xml version="1.0"?><hpjsresult><fields></fields></hpjsresult>') {
|
||||
$has_details = true;
|
||||
}
|
||||
}
|
||||
if ($has_details && empty($xml["STRING_DATA"]) && empty($xml["QUESTION_DATA"])) {
|
||||
// HotPot v2.0.x (regenerate questions, responses and strings from attempt details)
|
||||
$more_restore .= '$status = hotpot_restore_attempts($restore, $status, $xml, $record, true);';
|
||||
} else {
|
||||
// HotPot v2.1+
|
||||
$more_restore .= '$status = hotpot_restore_strings($restore, $status, $xml, $record);';
|
||||
$more_restore .= '$status = hotpot_restore_questions($restore, $status, $xml, $record);';
|
||||
$more_restore .= '$status = hotpot_restore_attempts($restore, $status, $xml, $record);';
|
||||
}
|
||||
}
|
||||
|
||||
// if necessary, adjust HotPot date/time fields and write to restorelog
|
||||
if ($restore->course_startdateoffset) {
|
||||
restore_log_date_changes('Hotpot', $restore, $xml, array('TIMEOPEN', 'TIMECLOSE', 'TIMECREATED', 'TIMEMODIFIED'));
|
||||
}
|
||||
|
||||
$status = hotpot_restore_records(
|
||||
$restore, $status, $xml, $table, $foreign_keys, $more_restore
|
||||
);
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
function hotpot_restore_strings(&$restore, $status, &$xml, &$record) {
|
||||
// $xml is an XML tree for a hotpot record
|
||||
// $record is the newly added hotpot record
|
||||
return hotpot_restore_records(
|
||||
$restore, $status, $xml, 'hotpot_strings', array(), '', 'STRING_DATA', 'STRING', 'md5key'
|
||||
);
|
||||
}
|
||||
function hotpot_restore_questions(&$restore, $status, &$xml, &$record) {
|
||||
// $xml is an XML tree for a hotpot record
|
||||
// $record is the newly added hotpot record
|
||||
$foreignkeys = array(
|
||||
'hotpot'=>$record->id,
|
||||
'text'=>'hotpot_strings'
|
||||
);
|
||||
return hotpot_restore_records(
|
||||
$restore, $status, $xml, 'hotpot_questions', $foreignkeys, '', 'QUESTION_DATA', 'QUESTION'
|
||||
);
|
||||
}
|
||||
function hotpot_restore_attempts(&$restore, $status, &$xml, &$record, $hotpot_v20=false) {
|
||||
// $xml is an XML tree for a hotpot record
|
||||
// $record is the newly added hotpot record
|
||||
global $DB;
|
||||
$foreignkeys = array(
|
||||
'userid'=>'user',
|
||||
'hotpot'=>$record->id,
|
||||
);
|
||||
$more_restore = '';
|
||||
$more_restore .= 'hotpot_restore_details($restore, $status, $xml, $record);';
|
||||
if ($hotpot_v20) {
|
||||
// HotPot v2.0.x (regenerate questions and responses from details)
|
||||
$more_restore .= 'hotpot_add_attempt_details($record);'; // see "hotpot/lib.php"
|
||||
} else {
|
||||
// HotPot v2.1+
|
||||
$more_restore .= '$status = hotpot_restore_responses($restore, $status, $xml, $record);';
|
||||
// save clickreportid (to be updated it later)
|
||||
$more_restore .= 'if (!empty($record->clickreportid)) {';
|
||||
$more_restore .= '$GLOBALS["hotpot_backup_clickreportids"][$record->id]=$record->clickreportid;';
|
||||
$more_restore .= '}';
|
||||
// initialize global array to store clickreportids
|
||||
$GLOBALS["hotpot_backup_clickreportids"] = array();
|
||||
}
|
||||
$status = hotpot_restore_records(
|
||||
$restore, $status, $xml, 'hotpot_attempts', $foreignkeys, $more_restore, 'ATTEMPT_DATA', 'ATTEMPT'
|
||||
);
|
||||
if ($hotpot_v20) {
|
||||
if ($status) {
|
||||
global $CFG;
|
||||
// based on code in "mod/hotpot/db/update_to_v2.php"
|
||||
$params = array($record->id);
|
||||
$DB->execute("UPDATE {hotpot_attempts} SET status=1 WHERE hotpot=? AND timefinish=0 AND score IS NULL", $params);
|
||||
$DB->execute("UPDATE {hotpot_attempts} SET status=3 WHERE hotpot=? AND timefinish>0 AND score IS NULL", $params);
|
||||
$DB->execute("UPDATE {hotpot_attempts} SET status=4 WHERE hotpot=? AND timefinish>0 AND score IS NOT NULL", $params);
|
||||
$DB->execute("UPDATE {hotpot_attempts} SET clickreportid=id WHERE hotpot=? AND clickreportid IS NULL", $params);
|
||||
}
|
||||
} else {
|
||||
$status = hotpot_restore_clickreportids($restore, $status);
|
||||
unset($GLOBALS["hotpot_backup_clickreportids"]); // tidy up
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
function hotpot_restore_clickreportids(&$restore, $status) {
|
||||
// update clickreport ids, if any
|
||||
global $CFG, $DB;
|
||||
foreach ($GLOBALS["hotpot_backup_clickreportids"] as $id=>$clickreportid) {
|
||||
if ($status) {
|
||||
$attempt_record = backup_getid($restore->backup_unique_code, 'hotpot_attempts', $clickreportid);
|
||||
if ($attempt_record) {
|
||||
$new_clickreportid = $attempt_record->new_id;
|
||||
$status = $DB->execute("UPDATE {hotpot_attempts} SET clickreportid=? WHERE id=?", array($new_clickreportid, $id));
|
||||
} else {
|
||||
// New clickreport id could not be found
|
||||
if (!defined('RESTORE_SILENTLY')) {
|
||||
print "<ul><li>New clickreportid could not be found: attempt id=$id, clickreportid=$clickreportid</li></ul>";
|
||||
}
|
||||
$status = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
function hotpot_restore_responses(&$restore, $status, &$xml, &$record) {
|
||||
// $xml is an XML tree for an attempt record
|
||||
// $record is the newly added attempt record
|
||||
$foreignkeys = array(
|
||||
'attempt'=>$record->id,
|
||||
'question'=>'hotpot_questions',
|
||||
'correct'=>'hotpot_strings',
|
||||
'wrong'=>'hotpot_strings',
|
||||
'ignored'=>'hotpot_strings'
|
||||
);
|
||||
return hotpot_restore_records(
|
||||
$restore, $status, $xml, 'hotpot_responses', $foreignkeys, '', 'RESPONSE_DATA', 'RESPONSE'
|
||||
);
|
||||
}
|
||||
function hotpot_restore_details(&$restore, $status, &$xml, &$record) {
|
||||
global $DB;
|
||||
// $xml is an XML tree for an attempt record
|
||||
// $record is the newly added attempt record
|
||||
if (empty($record->details)) {
|
||||
$status = true;
|
||||
} else {
|
||||
$details = new stdClass();
|
||||
$details->attempt = $record->id;
|
||||
$details->details = $record->details;
|
||||
if ($DB->insert_record('hotpot_details', $details)) {
|
||||
$status = true;
|
||||
} else {
|
||||
if (!defined('RESTORE_SILENTLY')) {
|
||||
print "<ul><li>Details record could not be updated: attempt=$record->attempt</li></ul>";
|
||||
}
|
||||
$status = false;
|
||||
}
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
function hotpot_restore_records(&$restore, $status, &$xml, $table, $foreign_keys, $more_restore='', $records_TAG='', $record_TAG='', $secondary_key='') {
|
||||
// general purpose function to restore a group of records
|
||||
// $restore : (see "hotpot_restore_mods" above)
|
||||
// $xml : an XML tree (or sub-tree)
|
||||
// $records_TAG : (optional) the name of an XML tag which starts a block of records
|
||||
// If no $records_TAG is specified, $xml is assumed to be a block of records
|
||||
// $record_TAG : (optional) the name of an XML tag which starts a single record
|
||||
// If no $record_TAG is specified, the block of records is assumed to be a single record
|
||||
// other parameters are explained in "hotpot_restore_record" below
|
||||
|
||||
$i = 0; // index for $records_TAG
|
||||
do {
|
||||
unset($xml_records);
|
||||
if ($records_TAG) {
|
||||
if (isset($xml[$records_TAG][$i]['#'])) {
|
||||
$xml_records = &$xml[$records_TAG][$i]['#'];
|
||||
}
|
||||
} else {
|
||||
if ($i==0) {
|
||||
$xml_records = &$xml;
|
||||
}
|
||||
}
|
||||
if (isset($xml_records)) {
|
||||
$ii = 0; // index for $record_TAG
|
||||
do {
|
||||
unset($xml_record);
|
||||
if ($record_TAG) {
|
||||
if (isset($xml_records[$record_TAG][$ii]['#'])) {
|
||||
$xml_record = &$xml_records[$record_TAG][$ii]['#'];
|
||||
}
|
||||
} else {
|
||||
if ($ii==0) {
|
||||
$xml_record = &$xml_records;
|
||||
}
|
||||
}
|
||||
if (isset($xml_record)) {
|
||||
$status = hotpot_restore_record(
|
||||
$restore, $status, $xml_record, $table, $foreign_keys, $more_restore, $secondary_key
|
||||
);
|
||||
}
|
||||
$ii++;
|
||||
} while ($status && isset($xml_record));
|
||||
}
|
||||
$i++;
|
||||
} while ($status && isset($xml_records));
|
||||
return $status;
|
||||
}
|
||||
function hotpot_restore_record(&$restore, $status, &$xml, $table, $foreign_keys, $more_restore, $secondary_key) {
|
||||
// general purpose function to restore a single record
|
||||
// $restore : (see "hotpot_restore_mods" above)
|
||||
// $status : current status of backup (true or false)
|
||||
// $xml : XML tree of current record
|
||||
// $table : name of Moodle database table to restore to
|
||||
// $foreign_keys : array of foreign keys, if any, specifed as $key=>$value
|
||||
// $key : the name of a field in the current $record
|
||||
// $value : if $value is numeric, then $record->$key is set to $value.
|
||||
// Otherwise $value is assumed to be a table name and $record->$key
|
||||
// is treated as a comma separated list of ids in that table
|
||||
// $more_restore : optional PHP code to be eval(uated) for each record
|
||||
// $secondary_key :
|
||||
// the name of the secondary key field, if any, in the current $record.
|
||||
// If this field is specified, then the current record will only be added
|
||||
// if the $record->$secondarykey value does not already exist in $table
|
||||
|
||||
// maintain a cache of info on table columns
|
||||
global $DB;
|
||||
|
||||
static $table_columns = array();
|
||||
if (empty($table_columns[$table])) {
|
||||
global $CFG, $DB;
|
||||
$table_columns[$table] = $DB->get_columns($table);
|
||||
}
|
||||
|
||||
// get values for fields in this record
|
||||
$record = new stdClass();
|
||||
$TAGS = array_keys($xml);
|
||||
foreach ($TAGS as $TAG) {
|
||||
$value = $xml[$TAG][0]['#'];
|
||||
if (is_string($value)) {
|
||||
$tag = strtolower($TAG);
|
||||
$record->$tag = backup_todb($value);
|
||||
}
|
||||
}
|
||||
|
||||
// update foreign keys, if any
|
||||
$ok = true;
|
||||
foreach ($foreign_keys as $key=>$value) {
|
||||
if (is_numeric($value)) {
|
||||
$record->$key = $value;
|
||||
} else {
|
||||
$key_table = $value;
|
||||
$new_ids = array();
|
||||
if (isset($record->$key)) {
|
||||
$old_ids = explode(',', $record->$key);
|
||||
foreach ($old_ids as $old_id) {
|
||||
if (empty($old_id)) {
|
||||
// do nothing
|
||||
} else {
|
||||
$key_record = backup_getid($restore->backup_unique_code, $key_table, $old_id);
|
||||
if ($key_record) {
|
||||
$new_ids[] = $key_record->new_id;
|
||||
} else {
|
||||
// foreign key could not be updated
|
||||
if (!defined('RESTORE_SILENTLY')) {
|
||||
print "<ul><li><b>Warning:</b><br/>Foreign key could not be updated:<br/>";
|
||||
print "'$key_table' record (old id=$old_id) is missing from backup data<br/>";
|
||||
print "'$table' record ";
|
||||
if (isset($record->id)) {
|
||||
print "(old id=$record->id) ";
|
||||
}
|
||||
print "was not restored</li></ul>";
|
||||
}
|
||||
$ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$record->$key = implode(',', $new_ids);
|
||||
}
|
||||
}
|
||||
|
||||
// set md5 keys if necessary (restoring from Moodle<1.6)
|
||||
if ($table=='hotpot_questions' && empty($record->md5key)) {
|
||||
$record->md5key = md5($record->name);
|
||||
}
|
||||
if ($table=='hotpot_strings' && empty($record->md5key)) {
|
||||
$record->md5key = md5($record->string);
|
||||
}
|
||||
|
||||
// check all "not null" fields have been set
|
||||
foreach ($table_columns[$table] as $column) {
|
||||
if ($column->not_null) {
|
||||
$name = $column->name;
|
||||
if ($name=='id' || (isset($record->$name) && ! is_null($record->$name))) {
|
||||
// do nothing
|
||||
} else if (isset($column->default_value)) {
|
||||
$record->$name = $column->default_value;
|
||||
} else if (preg_match('/[INTD]/', $column->meta_type)) {
|
||||
$record->$name = 0;
|
||||
} else {
|
||||
$record->$name = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check everything is OK so far
|
||||
if ($ok) {
|
||||
// store old record id, if necessary
|
||||
if (isset($record->id)) {
|
||||
$record->old_id = $record->id;
|
||||
unset($record->id);
|
||||
}
|
||||
// if there is a secondary key field ...
|
||||
if ($secondary_key) {
|
||||
// check to see if a record with the same value already exists
|
||||
$key_records = $DB->get_records($table, array($secondary_key=>$record->$secondary_key));
|
||||
if ($key_records) {
|
||||
// set new record id from already existing record
|
||||
$key_record = reset($key_records);
|
||||
$record->id = $key_record->id;
|
||||
}
|
||||
}
|
||||
if (empty($record->id)) {
|
||||
// add the $record (and get new id)
|
||||
$record->id = $DB->insert_record($table, $record);
|
||||
}
|
||||
// check $record was added (or found)
|
||||
if (is_numeric($record->id)) {
|
||||
// if there was an old id, save a mapping to the new id
|
||||
if (isset($record->old_id)) {
|
||||
backup_putid($restore->backup_unique_code, $table, $record->old_id, $record->id);
|
||||
}
|
||||
} else {
|
||||
// failed to add (or find) $record
|
||||
if (!defined('RESTORE_SILENTLY')) {
|
||||
print "<ul><li>Record could not be added: table=$table</li></ul>";
|
||||
}
|
||||
$status = false;
|
||||
}
|
||||
// restore related records, if required
|
||||
if ($more_restore) {
|
||||
eval($more_restore);
|
||||
}
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
//This function returns a log record with all the necessay transformations
|
||||
//done. It's used by restore_log_module() to restore modules log.
|
||||
function hotpot_restore_logs($restore, $log) {
|
||||
// assume the worst
|
||||
$status = false;
|
||||
switch ($log->action) {
|
||||
case "add":
|
||||
case "update":
|
||||
case "view":
|
||||
if ($log->cmid) {
|
||||
//Get the new_id of the module (to recode the info field)
|
||||
$mod = backup_getid($restore->backup_unique_code, $log->module, $log->info);
|
||||
if ($mod) {
|
||||
$log->url = "view.php?id=".$log->cmid;
|
||||
$log->info = $mod->new_id;
|
||||
$status = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "view all":
|
||||
$log->url = "index.php?id=".$log->course;
|
||||
$status = true;
|
||||
break;
|
||||
case "report":
|
||||
if ($log->cmid) {
|
||||
//Get the new_id of the module (to recode the info field)
|
||||
$mod = backup_getid($restore->backup_unique_code,$log->module,$log->info);
|
||||
if ($mod) {
|
||||
$log->url = "report.php?id=".$log->cmid;
|
||||
$log->info = $mod->new_id;
|
||||
$status = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "attempt":
|
||||
case "submit":
|
||||
case "review":
|
||||
if ($log->cmid) {
|
||||
//Get the new_id of the module (to recode the info field)
|
||||
$mod = backup_getid($restore->backup_unique_code,$log->module,$log->info);
|
||||
if ($mod) {
|
||||
//Extract the attempt id from the url field
|
||||
$attemptid = substr(strrchr($log->url,"="),1);
|
||||
//Get the new_id of the attempt (to recode the url field)
|
||||
$attempt = backup_getid($restore->backup_unique_code,"hotpot_attempts",$attemptid);
|
||||
if ($attempt) {
|
||||
$log->url = "review.php?id=".$log->cmid."&attempt=".$attempt->new_id;
|
||||
$log->info = $mod->new_id;
|
||||
$status = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Oops, unknown $log->action
|
||||
if (!defined('RESTORE_SILENTLY')) {
|
||||
print "<p>action (".$log->module."-".$log->action.") unknown. Not restored</p>";
|
||||
}
|
||||
break;
|
||||
} // end switch
|
||||
return $status ? $log : false;
|
||||
}
|
||||
|
||||
function hotpot_decode_content_links($content, $restore) {
|
||||
$search = '/\$@(HOTPOT)\*([a-z]+)\*([a-z]+)\*([0-9]+)@\$/is';
|
||||
if (preg_match_all($search, $content, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
$i_max = count($matches[0]) - 1;
|
||||
for ($i=$i_max; $i>=0; $i--) {
|
||||
$start = $matches[0][$i][1];
|
||||
$length = strlen($matches[0][$i][0]);
|
||||
$replace = hotpot_decode_content_link(
|
||||
// $scriptname, $paramname, $paramvalue, $restore
|
||||
$matches[2][$i][0], $matches[3][$i][0], $matches[4][$i][0], $restore
|
||||
);
|
||||
$content = substr_replace($content, $replace, $start, $length);
|
||||
}
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
function hotpot_decode_content_link($scriptname, $paramname, $paramvalue, &$restore) {
|
||||
global $CFG;
|
||||
|
||||
$table = '';
|
||||
switch ($paramname) {
|
||||
case 'id':
|
||||
switch ($scriptname) {
|
||||
case 'index':
|
||||
$table = 'course';
|
||||
break;
|
||||
case 'report':
|
||||
case 'review':
|
||||
case 'view':
|
||||
$table = 'course_modules';
|
||||
break;
|
||||
case 'attempt':
|
||||
$table = 'hotpot_attempts';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'hp':
|
||||
case 'hotpotid':
|
||||
$table = 'hotpot';
|
||||
break;
|
||||
}
|
||||
|
||||
$new_id = 0;
|
||||
if ($table) {
|
||||
if ($rec = backup_getid($restore->backup_unique_code, $table, $paramvalue)) {
|
||||
$new_id = $rec->new_id;
|
||||
}
|
||||
}
|
||||
|
||||
return "$CFG->wwwroot/mod/hotpot/$scriptname.php?$paramname=$new_id";
|
||||
}
|
||||
|
||||
@@ -1,251 +0,0 @@
|
||||
<?PHP
|
||||
|
||||
// This page prints a review of a particular quiz attempt
|
||||
require_once("../../config.php");
|
||||
require_once("lib.php");
|
||||
|
||||
$id = optional_param('id', 0, PARAM_INT); // Course Module ID, or
|
||||
$hp = optional_param('hp', 0, PARAM_INT); // hotpot ID
|
||||
$attempt = required_param('attempt', PARAM_INT); // A particular attempt ID for review
|
||||
|
||||
if ($id) {
|
||||
$PAGE->set_url('/mod/hotpot/review.php', array('id'=>$id,'attempt'=>$attempt));
|
||||
if (! $cm = get_coursemodule_from_id('hotpot', $id)) {
|
||||
print_error('invalidcoursemodule');
|
||||
}
|
||||
if (! $course = $DB->get_record("course", array("id"=>$cm->course))) {
|
||||
print_error('coursemisconf');
|
||||
}
|
||||
if (! $hotpot = $DB->get_record("hotpot", array("id"=>$cm->instance))) {
|
||||
print_error('invalidcoursemodule');
|
||||
}
|
||||
} else {
|
||||
$PAGE->set_url('/mod/hotpot/review.php', array('hp'=>$hp,'attempt'=>$attempt));
|
||||
if (! $hotpot = $DB->get_record("hotpot", array("id"=>$hp))) {
|
||||
print_error('invalidcoursemodule');
|
||||
}
|
||||
if (! $course = $DB->get_record("course", array("id"=>$hotpot->course))) {
|
||||
print_error('coursemisconf');
|
||||
}
|
||||
if (! $cm = get_coursemodule_from_instance("hotpot", $hotpot->id, $course->id)) {
|
||||
print_error('invalidcoursemodule');
|
||||
}
|
||||
}
|
||||
if (! $attempt = $DB->get_record("hotpot_attempts", array("id"=>$attempt))) {
|
||||
print_error('invalidattemptid', 'hotpot');
|
||||
}
|
||||
|
||||
require_login($course, true, $cm);
|
||||
|
||||
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
|
||||
if (!has_capability('mod/hotpot:viewreport',$context)) {
|
||||
if (!$hotpot->review) {
|
||||
print_error("noreview", "quiz");
|
||||
}
|
||||
//if (time() < $hotpot->timeclose) {
|
||||
// print_error("noreviewuntil", "quiz", '', userdate($hotpot->timeclose));
|
||||
//}
|
||||
if ($attempt->userid != $USER->id) {
|
||||
print_error('notyourattempt', 'hotpot');
|
||||
}
|
||||
}
|
||||
add_to_log($course->id, "hotpot", "review", "review.php?id=$cm->id&attempt=$attempt->id", "$hotpot->id", "$cm->id");
|
||||
// Print the page header
|
||||
$strmodulenameplural = get_string("modulenameplural", "hotpot");
|
||||
$strmodulename = get_string("modulename", "hotpot");
|
||||
// print header
|
||||
|
||||
$PAGE->requires->js('/lib/overlib/overlib.js', true);
|
||||
$PAGE->requires->js('/lib/overlib/overlib_cssstyle.js', true);
|
||||
$PAGE->set_title(format_string($course->shortname) . ": $hotpot->name");
|
||||
$PAGE->set_heading($course->fullname);
|
||||
echo $OUTPUT->header();
|
||||
print '<div id="overDiv" style="position:absolute; visibility:hidden; z-index:1000;"></div>'; // for overlib
|
||||
echo $OUTPUT->heading($hotpot->name);
|
||||
hotpot_print_attempt_summary($hotpot, $attempt);
|
||||
hotpot_print_review_buttons($course, $hotpot, $attempt, $context);
|
||||
$action = has_capability('mod/hotpot:viewreport',$context) ? optional_param('action', '', PARAM_ALPHA) : '';
|
||||
if ($action) {
|
||||
$xml = $DB->get_field('hotpot_details', 'details', array('attempt'=>$attempt->id));
|
||||
print '<hr>';
|
||||
switch ($action) {
|
||||
case 'showxmltree':
|
||||
print '<pre id="contents">';
|
||||
$xml_tree = new hotpot_xml_tree($xml, "['hpjsresult']['#']");
|
||||
print_r ($xml_tree->xml_value('fields'));
|
||||
print '</pre>';
|
||||
break;
|
||||
case 'showxmlsource':
|
||||
print htmlspecialchars($xml);
|
||||
break;
|
||||
default:
|
||||
print "Action '$action' not recognized";
|
||||
}
|
||||
print '<hr>';
|
||||
} else {
|
||||
hotpot_print_attempt_details($hotpot, $attempt);
|
||||
}
|
||||
hotpot_print_review_buttons($course, $hotpot, $attempt, $context);
|
||||
echo $OUTPUT->footer();
|
||||
///////////////////////////
|
||||
// functions
|
||||
///////////////////////////
|
||||
function hotpot_print_attempt_summary(&$hotpot, &$attempt) {
|
||||
// start table
|
||||
global $OUTPUT;
|
||||
echo $OUTPUT->box_start("generalbox boxaligncenter boxwidthwide");
|
||||
print '<table width="100%" border="1" valign="top" align="center" cellpadding="2" cellspacing="2" class="generaltable">'."\n";
|
||||
// add attempt properties
|
||||
$fields = array('attempt', 'score', 'penalties', 'status', 'timetaken', 'timerecorded');
|
||||
foreach ($fields as $field) {
|
||||
switch ($field) {
|
||||
case 'score':
|
||||
$value = hotpot_format_score($attempt);
|
||||
break;
|
||||
case 'status':
|
||||
$value = hotpot_format_status($attempt);
|
||||
break;
|
||||
case 'timerecorded':
|
||||
$value = empty($attempt->timefinish) ? '-' : userdate($attempt->timefinish);
|
||||
break;
|
||||
case 'timetaken':
|
||||
$value = empty($attempt->timefinish) ? '-' : format_time($attempt->timefinish - $attempt->timestart);
|
||||
break;
|
||||
default:
|
||||
$value = isset($attempt->$field) ? $attempt->$field : NULL;
|
||||
}
|
||||
if (isset($value)) {
|
||||
switch ($field) {
|
||||
case 'status':
|
||||
case 'timerecorded':
|
||||
$name = get_string('report'.$field, 'hotpot');
|
||||
break;
|
||||
case 'penalties':
|
||||
$name = get_string('penalties', 'hotpot');
|
||||
break;
|
||||
default:
|
||||
$name = get_string($field, 'quiz');
|
||||
}
|
||||
print '<tr><th align="right" width="100" class="generaltableheader" scope="row">'.$name.':</th><td class="generaltablecell">'.$value.'</td></tr>';
|
||||
}
|
||||
}
|
||||
// finish table
|
||||
print '</table>';
|
||||
echo $OUTPUT->box_end();
|
||||
}
|
||||
function hotpot_print_review_buttons(&$course, &$hotpot, &$attempt, $context) {
|
||||
global $DB, $OUTPUT;
|
||||
|
||||
print "\n".'<table border="0" align="center" cellpadding="2" cellspacing="2" class="generaltable">';
|
||||
print "\n<tr>\n".'<td align="center">';
|
||||
echo $OUTPUT->single_button(new moodle_url("report.php", array('hp'=>$hotpot->id)), get_string('continue'));
|
||||
if (has_capability('mod/hotpot:viewreport',$context) && $DB->record_exists('hotpot_details', array('attempt'=>$attempt->id))) {
|
||||
print "</td>\n".'<td align="center">';
|
||||
echo $OUTPUT->single_button(new moodle_url("review.php", array('hp'=>$hotpot->id, 'attempt'=>$attempt->id, 'action'=>'showxmlsource')), get_string('showxmlsource', 'hotpot'));
|
||||
print "</td>\n".'<td align="center">';
|
||||
echo $OUTPUT->single_button(new moodle_url("review.php", array('hp'=>$hotpot->id,'attempt'=>$attempt->id, 'action'=>'showxmltree')), get_string('showxmltree', 'hotpot'));
|
||||
$colspan = 3;
|
||||
} else {
|
||||
$colspan = 1;
|
||||
}
|
||||
print "</td>\n</tr>\n";
|
||||
print '<tr><td colspan="'.$colspan.'">';
|
||||
echo $OUTPUT->spacer(array('height'=>4, 'width'=>1)); // should be done with CSS instead
|
||||
print "</td></tr>\n";
|
||||
print "</table>\n";
|
||||
}
|
||||
function hotpot_print_attempt_details(&$hotpot, &$attempt) {
|
||||
global $DB, $OUTPUT;
|
||||
|
||||
// define fields to print
|
||||
$textfields = array('correct', 'ignored', 'wrong');
|
||||
$numfields = array('score', 'weighting', 'hints', 'clues', 'checks');
|
||||
$fields = array_merge($textfields, $numfields);
|
||||
$q = array(); // questions
|
||||
$f = array(); // fields
|
||||
foreach ($fields as $field) {
|
||||
$name = get_string($field, 'hotpot');
|
||||
$f[$field] = array('count'=>0, 'name'=>$name);
|
||||
}
|
||||
// get questions and responses for this attempt
|
||||
$questions = $DB->get_records('hotpot_questions', array('hotpot'=>$hotpot->id), 'id');
|
||||
$responses = $DB->get_records('hotpot_responses', array('attempt'=>$attempt->id), 'id');
|
||||
if ($questions && $responses) {
|
||||
foreach ($responses as $response) {
|
||||
$id = $response->question;
|
||||
foreach ($fields as $field) {
|
||||
if (!isset($f[$field])) {
|
||||
$name = get_string($field, 'hotpot');
|
||||
$f[$field] = array('count'=>0, 'name'=>$name);
|
||||
}
|
||||
if (isset($response->$field)) {
|
||||
$f[$field]['count']++;
|
||||
if (!isset($q[$id])) {
|
||||
$name = hotpot_get_question_name($questions[$id]);
|
||||
$q[$id] = array('name'=>$name);
|
||||
}
|
||||
$q[$id][$field] = $response->$field;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// count the number of columns required in the table
|
||||
$colspan = 0;
|
||||
foreach ($numfields as $field) {
|
||||
if ($f[$field]['count']) {
|
||||
$colspan += 2;
|
||||
}
|
||||
}
|
||||
$colspan = max(2, $colspan);
|
||||
// start table of questions and responses
|
||||
echo $OUTPUT->box_start("generalbox boxaligncenter boxwidthwide");
|
||||
print '<table width="100%" border="1" valign="top" align="center" cellpadding="2" cellspacing="2" class="generaltable">'."\n";
|
||||
if (empty($q)) {
|
||||
print '<tr><td align="center" class="generaltablecell"><b>'.get_string("noresponses", "hotpot")."</b></td></tr>\n";
|
||||
} else {
|
||||
// flag to ensure separators are only printed before the 2nd and subsequent questions
|
||||
$printseparator = false;
|
||||
foreach ($q as $i=>$question) {
|
||||
// flag to ensure questions are only printed when there is at least one response
|
||||
$printedquestion = false;
|
||||
// add rows of text fields
|
||||
foreach ($textfields as $field) {
|
||||
if (isset($question[$field])) {
|
||||
$text = hotpot_strings($question[$field]);
|
||||
if (trim($text)) {
|
||||
// print question if necessary
|
||||
if (!$printedquestion) {
|
||||
if ($printseparator) {
|
||||
print '<tr><td colspan="'.$colspan.'"><div class="tabledivider"></div></td></tr>'."\n";
|
||||
}
|
||||
$printseparator = true;
|
||||
print '<tr><td colspan="'.$colspan.'" class="generaltablecell"><b>'.$question['name'].'</b></td></tr>'."\n";
|
||||
$printedquestion = true;
|
||||
}
|
||||
// print response
|
||||
print '<tr><th align="right" width="100" class="generaltableheader" scope="row">'.$f[$field]['name'].':</th><td colspan="'.($colspan-1).'" class="generaltablecell">'.$text.'</td></tr>'."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
// add row of numeric fields
|
||||
print '<tr>';
|
||||
foreach ($numfields as $field) {
|
||||
if ($f[$field]['count']) {
|
||||
// print question if necessary
|
||||
if (!$printedquestion) {
|
||||
print '<td colspan="'.$colspan.'" class="generaltablecell"><b>'.$question['name']."</b></td></tr>\n<tr>";
|
||||
$printedquestion = true;
|
||||
}
|
||||
// print numeric response
|
||||
$value = isset($question[$field]) ? $question[$field] : '-';
|
||||
print '<th align="right" width="100" class="generaltableheader" scope="row">'.$f[$field]['name'].':</th><td class="generaltablecell">'.$value.'</td>';
|
||||
}
|
||||
}
|
||||
print "</tr>\n";
|
||||
} // foreach $q
|
||||
}
|
||||
// finish table
|
||||
print "</table>\n";
|
||||
echo $OUTPUT->box_end();
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
if ($ADMIN->fulltree) {
|
||||
$settings->add(new admin_setting_configcheckbox('hotpot_showtimes', get_string('showtimes', 'hotpot'),
|
||||
get_string('configshowtimes', 'hotpot'), 0) );
|
||||
|
||||
$settings->add(new admin_setting_configtext('hotpot_excelencodings', get_string('excelencodings', 'hotpot'),
|
||||
get_string('configexcelencodings', 'hotpot'), '') );
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once("../../config.php");
|
||||
require_once("lib.php");
|
||||
|
||||
$params = new stdClass();
|
||||
$params->action = required_param('action', PARAM_ALPHA);
|
||||
$params->course = required_param('course', PARAM_INT);
|
||||
$params->reference = required_param('reference', PARAM_PATH);
|
||||
|
||||
$PAGE->set_url('/mod/hotpot/show.php', array('action'=>$params->action, 'course'=>$params->course, 'reference'=>$params->reference));
|
||||
|
||||
require_login($params->course);
|
||||
|
||||
if (!has_capability('mod/hotpot:viewreport',get_context_instance(CONTEXT_COURSE, $params->course))) {
|
||||
print_error('nopermissiontoviewpage');
|
||||
}
|
||||
if (has_capability('mod/hotpot:viewreport', get_context_instance(CONTEXT_SYSTEM))) {
|
||||
$params->location = optional_param('location', HOTPOT_LOCATION_COURSEFILES, PARAM_INT);
|
||||
} else {
|
||||
$params->location = HOTPOT_LOCATION_COURSEFILES;
|
||||
}
|
||||
$title = get_string($params->action, 'hotpot').': '.$params->reference;
|
||||
$PAGE->set_title($title);
|
||||
$PAGE->set_heading($title);
|
||||
echo $OUTPUT->header();
|
||||
hotpot_print_show_links($params->course, $params->location, $params->reference);
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
// http://www.krikkit.net/howto_javascript_copy_clipboard.html
|
||||
function copy_contents(id) {
|
||||
if (id==null) {
|
||||
id = 'contents';
|
||||
}
|
||||
var obj = null;
|
||||
if (document.getElementById) {
|
||||
obj = document.getElementById(id);
|
||||
}
|
||||
if (obj && window.clipboardData) {
|
||||
window.clipboardData.setData("Text", obj.innerText);
|
||||
alert('<?php print_string('copiedtoclipboard', 'hotpot') ?>');
|
||||
}
|
||||
}
|
||||
document.write('<span class="helplink"> <a href="javascript:copy_contents()"><?php print_string('copytoclipboard', 'hotpot') ?></A></span>');
|
||||
//]]>
|
||||
</script>
|
||||
<?php
|
||||
echo $OUTPUT->box_start("generalbox boxaligncenter boxwidthwide");
|
||||
if($hp = new hotpot_xml_quiz($params)) {
|
||||
print '<pre id="contents">';
|
||||
switch ($params->action) {
|
||||
case 'showxmlsource':
|
||||
print htmlspecialchars($hp->source);
|
||||
break;
|
||||
case 'showxmltree':
|
||||
if (isset($hp->xml)) {
|
||||
print_r($hp->xml);
|
||||
}
|
||||
break;
|
||||
case 'showhtmlsource':
|
||||
print htmlspecialchars($hp->html);
|
||||
break;
|
||||
case 'showhtmlquiz':
|
||||
print $hp->html;
|
||||
break;
|
||||
}
|
||||
print '</pre>';
|
||||
} else {
|
||||
echo $OUTPUT->box("Could not open Hot Potatoes XML file", "errorboxcontent generalbox");
|
||||
}
|
||||
echo $OUTPUT->box_end();
|
||||
print '<br />';
|
||||
echo $OUTPUT->close_window_button();
|
||||
?>
|
||||
@@ -1,111 +0,0 @@
|
||||
<?PHP
|
||||
class hotpot_xml_template_default {
|
||||
function read_template($filename, $tag='temporary') {
|
||||
// create the file path to the template
|
||||
$filepath = $this->parent->template_dirpath.DIRECTORY_SEPARATOR.$filename;
|
||||
// try and open the template file
|
||||
if (!file_exists($filepath) || !is_readable($filepath)) {
|
||||
print_error('cannotopentemplate', '', $this->parent->course_homeurl, $filepath);
|
||||
}
|
||||
// read in the template and close the file
|
||||
$this->$tag = file_get_contents($filepath);
|
||||
// expand the blocks and strings in the template
|
||||
$this->expand_blocks($tag);
|
||||
$this->expand_strings($tag);
|
||||
if ($tag=='temporary') {
|
||||
$template = $this->$tag;
|
||||
$this->$tag = '';
|
||||
return $template;
|
||||
}
|
||||
}
|
||||
function expand_blocks($tag) {
|
||||
// get block $names
|
||||
// [1] the full block name (including optional leading 'str' or 'incl')
|
||||
// [2] leading 'incl' or 'str', if any
|
||||
// [3] the real block name ([1] without [2])
|
||||
$search = '/\[\/((incl|str)?((?:\w|\.)+))\]/';
|
||||
preg_match_all($search, $this->$tag, $names);
|
||||
$i_max = count($names[0]);
|
||||
for ($i=0; $i<$i_max; $i++) {
|
||||
$method = $this->parent->template_dir.'_expand_'.str_replace('.', '', $names[3][$i]);
|
||||
if (method_exists($this, $method)) {
|
||||
eval('$value=$this->'.$method.'();');
|
||||
$search = '/\['.$names[1][$i].'\](.*?)\[\/'.$names[1][$i].'\]/s';
|
||||
preg_match_all($search, $this->$tag, $blocks);
|
||||
$ii_max = count($blocks[0]);
|
||||
for ($ii=0; $ii<$ii_max; $ii++) {
|
||||
$replace = empty($value) ? '' : $blocks[1][$ii];
|
||||
$this->$tag = str_replace($blocks[0][$ii], $replace, $this->$tag);
|
||||
}
|
||||
} else {
|
||||
print_error('cannotfindmethod', 'hotpot', $this->parent->course_homeurl, $method);
|
||||
}
|
||||
}
|
||||
}
|
||||
function expand_strings($tag, $search='') {
|
||||
if (empty($search)) {
|
||||
// default $search $pattern
|
||||
$search = '/\[(?:bool|int|str)(\\w+)\]/';
|
||||
}
|
||||
preg_match_all($search, $this->$tag, $matches);
|
||||
$i_max = count($matches[0]);
|
||||
for ($i=0; $i<$i_max; $i++) {
|
||||
$method = $this->parent->template_dir.'_expand_'.$matches[1][$i];
|
||||
if (method_exists($this, $method)) {
|
||||
eval('$replace=$this->'.$method.'();');
|
||||
$this->$tag = str_replace($matches[0][$i], $replace, $this->$tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
function bool_value($tags, $more_tags="[0]['#']") {
|
||||
$value = $this->parent->xml_value($tags, $more_tags);
|
||||
return empty($value) ? 'false' : 'true';
|
||||
}
|
||||
function int_value($tags, $more_tags="[0]['#']") {
|
||||
return intval($this->parent->xml_value($tags, $more_tags));
|
||||
}
|
||||
function js_value($tags, $more_tags="[0]['#']", $convert_to_unicode=false) {
|
||||
return $this->js_safe($this->parent->xml_value($tags, $more_tags), $convert_to_unicode);
|
||||
}
|
||||
function js_safe($str, $convert_to_unicode=false) {
|
||||
// encode a string for javascript
|
||||
// decode "<" and ">" - not necesary as it was done by xml_value()
|
||||
// $str = strtr($str, array('<' => '<', '>' => '>'));
|
||||
// escape single quotes and backslashes
|
||||
$str = strtr($str, array("'"=>"\\'", '\\'=>'\\\\'));
|
||||
// convert newlines (win = "\r\n", mac="\r", linix/unix="\n")
|
||||
$nl = '\\n'; // javascript newline
|
||||
$str = strtr($str, array("\r\n"=>$nl, "\r"=>$nl, "\n"=>$nl));
|
||||
// convert (hex and decimal) html entities to unicode, if required
|
||||
if ($convert_to_unicode) {
|
||||
$str = preg_replace('/&#x([0-9A-F]+);/i', '\\u\\1', $str);
|
||||
$str = preg_replace_callback('/&#(\d+);/', array(&$this, 'js_safe_callback'), $str);
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
function js_safe_callback(&$matches) {
|
||||
return '\\u'.sprintf('%04X', $matches[1]);
|
||||
}
|
||||
function get_halfway_color($x, $y) {
|
||||
// returns the $color that is half way between $x and $y
|
||||
$color = $x; // default
|
||||
$rgb = '/^\#?([0-9a-f])([0-9a-f])([0-9a-f])$/i';
|
||||
$rrggbb = '/^\#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i';
|
||||
if ((
|
||||
preg_match($rgb, $x, $x_matches) ||
|
||||
preg_match($rrggbb, $x, $x_matches)
|
||||
) && (
|
||||
preg_match($rgb, $y, $y_matches) ||
|
||||
preg_match($rrggbb, $y, $y_matches)
|
||||
)) {
|
||||
$color = '#';
|
||||
for ($i=1; $i<=3; $i++) {
|
||||
$x_dec = hexdec($x_matches[$i]);
|
||||
$y_dec = hexdec($y_matches[$i]);
|
||||
$color .= sprintf('%02x', min($x_dec, $y_dec) + abs($x_dec-$y_dec)/2);
|
||||
}
|
||||
}
|
||||
return $color;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,128 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xml:lang="en"><head>
|
||||
|
||||
[strDublinCoreMetadata]
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
|
||||
<title>
|
||||
[strPlainTitle]
|
||||
</title>
|
||||
|
||||
<!-- Made with executable version [strFullVersionInfo] -->
|
||||
|
||||
<!-- The following insertion allows you to add your own code directly to this head tag from the configuration screen -->
|
||||
|
||||
[strHeaderCode]
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
[strStyleSheet]
|
||||
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
//<![CDATA[
|
||||
|
||||
<!--
|
||||
|
||||
[inclScorm1.2]
|
||||
[strJSScorm_1_2]
|
||||
[/inclScorm1.2]
|
||||
|
||||
[strJSBrowserCheck]
|
||||
|
||||
[strJSButtons]
|
||||
|
||||
[strJSShowMessage]
|
||||
|
||||
[strJSUtilities]
|
||||
|
||||
[strJSHotPotNet]
|
||||
|
||||
[strJSCard]
|
||||
|
||||
[strJSDJMatch6]
|
||||
|
||||
[inclTimer]
|
||||
[strJSTimer]
|
||||
[/inclTimer]
|
||||
|
||||
[inclSendResults]
|
||||
[strJSSendResults]
|
||||
[/inclSendResults]
|
||||
|
||||
//-->
|
||||
|
||||
//]]>
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="TimerStartUp()" id="TheBody" [inclScorm1.2]onunload="CheckLMSFinish()"[/inclScorm1.2]>
|
||||
<!-- BeginTopNavButtons -->
|
||||
|
||||
[inclNavButtons]
|
||||
[strTopNavBar]
|
||||
[/inclNavButtons]
|
||||
|
||||
<!-- EndTopNavButtons -->
|
||||
|
||||
<div class="Titles">
|
||||
<h2 class="ExerciseTitle">[strExerciseTitle]</h2>
|
||||
[inclExerciseSubtitle]
|
||||
<h3 class="ExerciseSubtitle">[strExerciseSubtitle]</h3>
|
||||
[/inclExerciseSubtitle]
|
||||
[inclTimer]
|
||||
<div id="Timer"> <span id="TimerText"> </span> </div>
|
||||
[/inclTimer]
|
||||
|
||||
</div>
|
||||
|
||||
<div id="InstructionsDiv" class="StdDiv">
|
||||
<div id="Instructions">[strInstructions]</div>
|
||||
</div>
|
||||
|
||||
<div class="StdDiv" id="CheckButtonDiv">
|
||||
<button id="CheckButton1" class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="CheckAnswers()"> [strCheckCaption] </button>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
//<![CDATA[
|
||||
|
||||
<!--
|
||||
|
||||
|
||||
for (var i=0; i<F.length; i++){
|
||||
document.write('<div id="F' + i + '" class="CardStyle"></div>');
|
||||
}
|
||||
|
||||
for (var i=0; i<D.length; i++){
|
||||
document.write('<div id="D' + i + '" class="CardStyle" onmousedown="beginDrag(event, ' + i + ')"></div>');
|
||||
}
|
||||
|
||||
//-->
|
||||
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<div class="Feedback" id="FeedbackDiv">
|
||||
<div class="FeedbackText" id="FeedbackContent"></div>
|
||||
<button id="FeedbackOKButton" class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="HideFeedback(); return false;"> [strOKCaption] </button>
|
||||
</div>
|
||||
|
||||
<!-- BeginBottomNavButtons -->
|
||||
|
||||
<!-- EndBottomNavButtons -->
|
||||
|
||||
<!-- BeginSubmissionForm -->
|
||||
|
||||
<!-- EndSubmissionForm -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,369 +0,0 @@
|
||||
|
||||
[inclScorm1.2]
|
||||
//JMATCH-SPECIFIC SCORM-RELATED JAVASCRIPT CODE
|
||||
|
||||
function SetScormScore(){
|
||||
//Reports the current score and any other information back to the LMS
|
||||
if (API != null){
|
||||
API.LMSSetValue('cmi.core.score.raw', Score);
|
||||
|
||||
|
||||
//Now send a detailed reports on the item
|
||||
var ItemLabel = 'Matching';
|
||||
API.LMSSetValue('cmi.objectives.0.id', 'obj'+ItemLabel);
|
||||
API.LMSSetValue('cmi.interactions.0.id', 'int'+ItemLabel);
|
||||
API.LMSSetValue('cmi.objectives.0.status', API.LMSGetValue('cmi.core.lesson_status'));
|
||||
API.LMSSetValue('cmi.objectives.0.score.min', '0');
|
||||
API.LMSSetValue('cmi.objectives.0.score.max', '100');
|
||||
API.LMSSetValue('cmi.objectives.0.score.raw', Score);
|
||||
//We can only use the performance type, because we're storing multiple responses of various types.
|
||||
API.LMSSetValue('cmi.interactions.0.type', 'performance');
|
||||
API.LMSSetValue('cmi.interactions.0.student_response', AnswersTried);
|
||||
|
||||
API.LMSCommit('');
|
||||
}
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
|
||||
//JMATCH-SPECIFIC CORE JAVASCRIPT CODE
|
||||
|
||||
var CorrectResponse = '[strGuessCorrect]';
|
||||
var IncorrectResponse = '[strGuessIncorrect]';
|
||||
var YourScoreIs = '[strYourScoreIs]';
|
||||
var DivWidth = 600; //default value
|
||||
var FeedbackWidth = 200; //default
|
||||
var ExBGColor = '[strExBGColor]';
|
||||
var PageBGColor = '[strPageBGColor]';
|
||||
var TextColor = '[strTextColor]';
|
||||
var TitleColor = '[strTitleColor]';
|
||||
var Penalties = 0;
|
||||
var Score = 0;
|
||||
var TimeOver = false;
|
||||
var Locked = false;
|
||||
var ShuffleQs = [boolShuffleQs];
|
||||
var QsToShow = [QsToShow];
|
||||
|
||||
var DragWidth = 200;
|
||||
var LeftColPos = 100;
|
||||
var RightColPos = 500;
|
||||
var DragTop = 120;
|
||||
var Finished = false;
|
||||
var AnswersTried = '';
|
||||
|
||||
//Fixed and draggable card arrays
|
||||
FC = new Array();
|
||||
DC = new Array();
|
||||
|
||||
function onEndDrag(){
|
||||
//Is it dropped on any of the fixed cards?
|
||||
var Docked = false;
|
||||
var DropTarget = DroppedOnFixed(CurrDrag);
|
||||
if (DropTarget > -1){
|
||||
//If so, send home any card that is currently docked there
|
||||
for (var i=0; i<DC.length; i++){
|
||||
if (DC[i].tag == DropTarget+1){
|
||||
DC[i].GoHome();
|
||||
DC[i].tag = 0;
|
||||
D[i][2] = 0;
|
||||
}
|
||||
}
|
||||
//Dock the dropped card
|
||||
DC[CurrDrag].DockToR(FC[DropTarget]);
|
||||
D[CurrDrag][2] = F[DropTarget][1];
|
||||
DC[CurrDrag].tag = DropTarget+1;
|
||||
Docked = true;
|
||||
}
|
||||
|
||||
if (Docked == false){
|
||||
DC[CurrDrag].GoHome();
|
||||
DC[CurrDrag].tag = 0;
|
||||
D[CurrDrag][2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function DroppedOnFixed(DNum){
|
||||
var Result = -1;
|
||||
var OverlapArea = 0;
|
||||
var Temp = 0;
|
||||
for (var i=0; i<FC.length; i++){
|
||||
Temp = DC[DNum].Overlap(FC[i]);
|
||||
if (Temp > OverlapArea){
|
||||
OverlapArea = Temp;
|
||||
Result = i;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
function StartUp(){
|
||||
|
||||
[inclScorm1.2]
|
||||
ScormStartUp();
|
||||
[/inclScorm1.2]
|
||||
|
||||
[inclSendResults]
|
||||
GetUserName();
|
||||
[/inclSendResults]
|
||||
|
||||
[inclPreloadImages]
|
||||
PreloadImages([PreloadImageList]);
|
||||
[/inclPreloadImages]
|
||||
|
||||
//Calculate page dimensions and positions
|
||||
pg = new PageDim();
|
||||
DivWidth = Math.floor((pg.W*4)/5);
|
||||
DragWidth = Math.floor((DivWidth*3)/10);
|
||||
LeftColPos = Math.floor(pg.W/15);
|
||||
RightColPos = pg.W - (DragWidth + LeftColPos);
|
||||
DragTop = parseInt(document.getElementById('CheckButtonDiv').offsetHeight) + parseInt(document.getElementById('CheckButtonDiv').offsetTop) + 10;
|
||||
|
||||
if (C.ie){
|
||||
DragTop += 15;
|
||||
}
|
||||
|
||||
//Reduce array if required
|
||||
if (QsToShow < F.length){
|
||||
ReduceItems2();
|
||||
}
|
||||
|
||||
//Shuffle the left items if required
|
||||
if (ShuffleQs == true){
|
||||
F = Shuffle(F);
|
||||
}
|
||||
|
||||
//Shuffle the items on the right
|
||||
D = Shuffle(D);
|
||||
|
||||
var CurrTop = DragTop;
|
||||
var TempInt = 0;
|
||||
var DropHome = 0;
|
||||
var Widest = 0;
|
||||
var CardContent = '';
|
||||
for (var i=0; i<F.length; i++){
|
||||
CardContent = F[i][0];
|
||||
FC[i] = new Card('F' + i, 10);
|
||||
FC[i].elm.innerHTML = CardContent;
|
||||
if (FC[i].GetW() > Widest){
|
||||
Widest = FC[i].GetW();
|
||||
}
|
||||
}
|
||||
|
||||
if (Widest > DragWidth){Widest = DragWidth;}
|
||||
|
||||
CurrTop = DragTop;
|
||||
|
||||
DragWidth = Math.floor((DivWidth-Widest)/2) - 24;
|
||||
RightColPos = DivWidth + LeftColPos - (DragWidth + 14);
|
||||
var Highest = 0;
|
||||
var WidestRight = 0;
|
||||
|
||||
for (i=0; i<D.length; i++){
|
||||
DC[i] = new Card('D' + i, 10);
|
||||
CardContent = D[i][0];
|
||||
// if (CardContent.indexOf('<img ') > -1){CardContent += '<br clear="all" />';} //used to be required for Navigator rendering bug with images
|
||||
DC[i].elm.innerHTML = CardContent;
|
||||
if (DC[i].GetW() > DragWidth){DC[i].SetW(DragWidth);}
|
||||
DC[i].css.cursor = 'move';
|
||||
DC[i].css.backgroundColor = '[strExBGColor]';
|
||||
DC[i].css.color = '[strTextColor]';
|
||||
TempInt = DC[i].GetH();
|
||||
if (TempInt > Highest){Highest = TempInt;}
|
||||
TempInt = DC[i].GetW();
|
||||
if (TempInt > WidestRight){WidestRight = TempInt;}
|
||||
}
|
||||
|
||||
//Fix for 6.2: the reduction by 12 seems to be required -- no idea why!
|
||||
var HeightToSet = Highest-12;
|
||||
var WidthToSet = WidestRight-12;
|
||||
|
||||
for (i=0; i<D.length; i++){
|
||||
DC[i].SetT(CurrTop);
|
||||
DC[i].SetL(RightColPos);
|
||||
if (DC[i].GetH() < Highest){
|
||||
DC[i].SetH(HeightToSet);
|
||||
}
|
||||
if (DC[i].GetW() < WidestRight){
|
||||
DC[i].SetW(WidthToSet);
|
||||
}
|
||||
DC[i].SetHome();
|
||||
DC[i].tag = -1;
|
||||
CurrTop = CurrTop + DC[i].GetH() + 5;
|
||||
}
|
||||
|
||||
CurrTop = DragTop;
|
||||
|
||||
for (var i=0; i<F.length; i++){
|
||||
FC[i].SetW(Widest);
|
||||
if (FC[i].GetH() < Highest){
|
||||
FC[i].SetH(HeightToSet);
|
||||
}
|
||||
FC[i].SetT(CurrTop);
|
||||
FC[i].SetL(LeftColPos);
|
||||
FC[i].SetHome();
|
||||
TempInt = FC[i].GetH();
|
||||
CurrTop = CurrTop + TempInt + 5;
|
||||
}
|
||||
|
||||
[inclSlide]
|
||||
//Slide any elements that should be in position over
|
||||
for (i=0; i<D.length; i++){
|
||||
if (D[i][2] > 0){
|
||||
DC[i].tag = D[i][1];
|
||||
D[i][2] = D[i][1];
|
||||
var TopChange = 0;
|
||||
//Find the right target element
|
||||
var TargItem = -1;
|
||||
for (var j=0; j<F.length; j++){
|
||||
if (F[j][1] == D[i][1]){
|
||||
TargItem = j;
|
||||
}
|
||||
}
|
||||
var TargetLeft = FC[TargItem].GetR() + 5;
|
||||
var TargetTop = FC[TargItem].GetT();
|
||||
|
||||
if (TargetTop < DC[i].GetT()){
|
||||
TopChange = -1;
|
||||
}
|
||||
else {
|
||||
if (TargetTop > DC[i].GetT()){
|
||||
TopChange = 1;
|
||||
}
|
||||
}
|
||||
Slide(i, TargetLeft, TargetTop, TopChange);
|
||||
D[i][2] = F[TargItem][1];
|
||||
DC[i].tag = TargItem+1;
|
||||
}
|
||||
}
|
||||
[/inclSlide]
|
||||
[inclTimer]
|
||||
StartTimer();
|
||||
[/inclTimer]
|
||||
}
|
||||
|
||||
[inclSlide]
|
||||
function Slide(MoverNum, TargL, TargT, TopChange){
|
||||
var TempInt = DC[MoverNum].GetL();
|
||||
if (TempInt > TargL){
|
||||
DC[MoverNum].SetL(TempInt - 5);
|
||||
}
|
||||
TempInt = DC[MoverNum].GetT();
|
||||
if (TempInt != TargT){
|
||||
DC[MoverNum].SetT(TempInt + TopChange);
|
||||
}
|
||||
if ((DC[MoverNum].GetL() > TargL)||(DC[MoverNum].GetT() != TargT)){
|
||||
setTimeout('Slide('+MoverNum+','+TargL+','+TargT+','+TopChange+')', 1);
|
||||
}
|
||||
else{
|
||||
DC[MoverNum].SetL(TargL);
|
||||
}
|
||||
}
|
||||
[/inclSlide]
|
||||
|
||||
F = new Array();
|
||||
[FixedArray]
|
||||
|
||||
D = new Array();
|
||||
[DragArray]
|
||||
|
||||
function ReduceItems2(){
|
||||
var ItemToDump=0;
|
||||
var j=0;
|
||||
while (F.length > QsToShow){
|
||||
ItemToDump = Math.floor(F.length*Math.random());
|
||||
for (j=ItemToDump; j<(F.length-1); j++){
|
||||
F[j] = F[j+1];
|
||||
}
|
||||
for (j=ItemToDump; j<(D.length-1); j++){
|
||||
D[j] = D[j+1];
|
||||
}
|
||||
F.length = F.length-1;
|
||||
D.length = D.length-1;
|
||||
}
|
||||
}
|
||||
|
||||
function TimerStartUp(){
|
||||
setTimeout('StartUp()', 300);
|
||||
}
|
||||
|
||||
function CheckAnswers(){
|
||||
if (Locked == true){return;}
|
||||
//Set the default score and response
|
||||
var TotalCorrect = 0;
|
||||
Score = 0;
|
||||
var Feedback = '';
|
||||
|
||||
//for each fixed, check to see if the tag value for the draggable is the same as the fixed
|
||||
if (AnswersTried.length > 0){AnswersTried += ' | ';}
|
||||
var i, j;
|
||||
for (i=0; i<D.length; i++){
|
||||
if (i>0){AnswersTried += ',';}
|
||||
AnswersTried += D[i][1] + '.' + D[i][2] + '';
|
||||
if ((D[i][2] == D[i][1])&&(D[i][2] > 0)){
|
||||
TotalCorrect++;
|
||||
}
|
||||
else{
|
||||
//Change made for version 6.0.3.41: don't send wrong items home,
|
||||
//show them in a more conspicuous way.
|
||||
// DC[i].GoHome();
|
||||
DC[i].SetL(DC[i].GetL() + 10);
|
||||
DC[i].Highlight();
|
||||
}
|
||||
}
|
||||
|
||||
Score = Math.floor((100*(TotalCorrect-Penalties))/F.length);
|
||||
|
||||
var AllDone = false;
|
||||
|
||||
if (TotalCorrect == F.length) {
|
||||
AllDone = true;
|
||||
}
|
||||
|
||||
if (AllDone == true){
|
||||
Feedback = YourScoreIs + ' ' + Score + '%.';
|
||||
ShowMessage(Feedback + '<br />' + CorrectResponse);
|
||||
}
|
||||
else {
|
||||
Feedback = IncorrectResponse + '<br />' + YourScoreIs + ' ' + Score + '%.';
|
||||
ShowMessage(Feedback);
|
||||
Penalties++; // Penalty for inaccurate check
|
||||
}
|
||||
//If the exercise is over, deal with that
|
||||
if ((AllDone == true)||(TimeOver == true)){
|
||||
[inclSendResults]
|
||||
setTimeout('SendResults(' + Score + ')', 50);
|
||||
[/inclSendResults]
|
||||
[inclTimer]
|
||||
window.clearInterval(Interval);
|
||||
[/inclTimer]
|
||||
TimeOver = true;
|
||||
Locked = true;
|
||||
Finished = true;
|
||||
setTimeout('Finish()', SubmissionTimeout);
|
||||
WriteToInstructions(Feedback);
|
||||
}
|
||||
[inclScorm1.2]
|
||||
if (AllDone == true){
|
||||
SetScormComplete();
|
||||
}
|
||||
else{
|
||||
SetScormIncomplete();
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
}
|
||||
|
||||
[inclTimer]
|
||||
function TimesUp() {
|
||||
document.getElementById('Timer').innerHTML = '[strTimesUp]';
|
||||
[inclPreloadImages]
|
||||
RefreshImages();
|
||||
[/inclPreloadImages]
|
||||
TimeOver = true;
|
||||
CheckAnswers();
|
||||
Locked = true;
|
||||
[inclScorm1.2]
|
||||
SetScormTimedOut();
|
||||
[/inclScorm1.2]
|
||||
}
|
||||
[/inclTimer]
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xml:lang="en"><head>
|
||||
|
||||
[strDublinCoreMetadata]
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
|
||||
<title>
|
||||
[strPlainTitle]
|
||||
</title>
|
||||
|
||||
<!-- Made with executable version [strFullVersionInfo] -->
|
||||
|
||||
<!-- The following insertion allows you to add your own code directly to this head tag from the configuration screen -->
|
||||
|
||||
[strHeaderCode]
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
[strStyleSheet]
|
||||
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
//<![CDATA[
|
||||
|
||||
<!--
|
||||
|
||||
[inclScorm1.2]
|
||||
[strJSScorm_1_2]
|
||||
[/inclScorm1.2]
|
||||
|
||||
[strJSBrowserCheck]
|
||||
|
||||
[strJSButtons]
|
||||
|
||||
[strJSShowMessage]
|
||||
|
||||
[strJSUtilities]
|
||||
|
||||
[strJSHotPotNet]
|
||||
|
||||
[strJSCard]
|
||||
|
||||
[strJSDJMix6]
|
||||
|
||||
[inclTimer]
|
||||
[strJSTimer]
|
||||
[/inclTimer]
|
||||
|
||||
[inclSendResults]
|
||||
[strJSSendResults]
|
||||
[/inclSendResults]
|
||||
|
||||
//-->
|
||||
|
||||
//]]>
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="TimerStartUp()" id="TheBody" [inclScorm1.2]onunload="CheckLMSFinish()"[/inclScorm1.2]>
|
||||
<!-- BeginTopNavButtons -->
|
||||
|
||||
[inclNavButtons]
|
||||
[strTopNavBar]
|
||||
[/inclNavButtons]
|
||||
|
||||
<!-- EndTopNavButtons -->
|
||||
|
||||
<div class="Titles">
|
||||
<h2 class="ExerciseTitle">[strExerciseTitle]</h2>
|
||||
[inclExerciseSubtitle]
|
||||
<h3 class="ExerciseSubtitle">[strExerciseSubtitle]</h3>
|
||||
[/inclExerciseSubtitle]
|
||||
[inclTimer]
|
||||
<div id="Timer"> <span id="TimerText"> </span> </div>
|
||||
[/inclTimer]
|
||||
|
||||
</div>
|
||||
|
||||
<div id="InstructionsDiv" class="StdDiv">
|
||||
<div id="Instructions">[strInstructions]</div>
|
||||
</div>
|
||||
|
||||
<div class="StdDiv" id="CheckButtonDiv">
|
||||
<button id="CheckButton1" class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="CheckResults(0)"> [strCheckCaption] </button>
|
||||
|
||||
[inclRestart]
|
||||
<button class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="location.reload()"> [strRestartCaption] </button>
|
||||
[/inclRestart]
|
||||
|
||||
[inclHint]
|
||||
<button class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="CheckResults(1)"> [strHintCaption] </button>
|
||||
[/inclHint]
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
//<![CDATA[
|
||||
|
||||
<!--
|
||||
|
||||
|
||||
for (var i=0; i<DropTotal; i++){
|
||||
document.write('<div id="Drop' + i + '" class="DropLine" align="center"> <br /> </div>');
|
||||
}
|
||||
|
||||
for (var i=0; i<Segments.length; i++){
|
||||
document.write('<div id="D' + i + '" class="CardStyle" onmousedown="beginDrag(event, ' + i + ')"></div>');
|
||||
}
|
||||
|
||||
//-->
|
||||
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<div class="Feedback" id="FeedbackDiv">
|
||||
<div class="FeedbackText" id="FeedbackContent"></div>
|
||||
<button id="FeedbackOKButton" class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="HideFeedback(); return false;"> [strOKCaption] </button>
|
||||
</div>
|
||||
|
||||
<!-- BeginBottomNavButtons -->
|
||||
|
||||
<!-- EndBottomNavButtons -->
|
||||
|
||||
<!-- BeginSubmissionForm -->
|
||||
|
||||
<!-- EndSubmissionForm -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,576 +0,0 @@
|
||||
[inclScorm1.2]
|
||||
//JMMIX-SPECIFIC SCORM-RELATED JAVASCRIPT CODE
|
||||
|
||||
function SetScormScore(){
|
||||
//Reports the current score and any other information back to the LMS
|
||||
if (API != null){
|
||||
API.LMSSetValue('cmi.core.score.raw', Score);
|
||||
|
||||
//Now send a detailed reports on the item
|
||||
var ItemLabel = 'Item_1';
|
||||
API.LMSSetValue('cmi.objectives.0.id', 'obj'+ItemLabel);
|
||||
API.LMSSetValue('cmi.interactions.0.id', 'int'+ItemLabel);
|
||||
if (Finished == true){
|
||||
API.LMSSetValue('cmi.objectives.0.status', 'completed');
|
||||
}
|
||||
else{
|
||||
API.LMSSetValue('cmi.objectives.0.status', 'incomplete');
|
||||
}
|
||||
|
||||
API.LMSSetValue('cmi.objectives.0.score.min', '0');
|
||||
API.LMSSetValue('cmi.objectives.0.score.max', '100');
|
||||
API.LMSSetValue('cmi.objectives.0.score.raw', Score);
|
||||
//We can only use the performance type, because we're storing multiple responses of various types.
|
||||
API.LMSSetValue('cmi.interactions.0.type', 'performance');
|
||||
API.LMSSetValue('cmi.interactions.0.student_response', AnswersTried);
|
||||
|
||||
|
||||
API.LMSCommit('');
|
||||
}
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
|
||||
//JMIX DRAG-DROP OUTPUT FORMAT CODE
|
||||
|
||||
var Punctuation = '[strPunctuation]';
|
||||
|
||||
var Openers = '[strOpenPunctuation]';
|
||||
var CorrectResponse = '[strGuessCorrect]';
|
||||
var IncorrectResponse = '[strGuessIncorrect]';
|
||||
var ThisMuchCorrect = '[strThisMuch]';
|
||||
var TheseAnswersToo = '[strTheseAnswersToo]';
|
||||
var YourScoreIs = '[strYourScoreIs]';
|
||||
var NextCorrect = '[strNextCorrect]';
|
||||
var FeedbackWidth = 200; //default
|
||||
var ExBGColor = '[strExBGColor]';
|
||||
var PageBGColor = '[strPageBGColor]';
|
||||
var TextColor = '[strTextColor]';
|
||||
var TitleColor = '[strTitleColor]';
|
||||
var DropTotal = 3; // number of lines that will be available for dropping on
|
||||
var Gap = 4; //Gap between two segments when they're next to each other on a line
|
||||
var DropHeight = 30;
|
||||
var CapitalizeFirst = [boolCapitalizeFirst];
|
||||
var CompiledOutput = '';
|
||||
var TempSegment = '';
|
||||
var FirstSegment = -1;
|
||||
var FirstDiv = -1;
|
||||
var Penalties = 0;
|
||||
var Score = 0;
|
||||
var TimeOver = false;
|
||||
|
||||
var CurrDrag = -1;
|
||||
var topZ = 100;
|
||||
var Cds = new Array();
|
||||
var L = new Array();
|
||||
var Finished = false;
|
||||
|
||||
var Locked = false;
|
||||
var DivWidth = 600;
|
||||
var LeftColPos = 100;
|
||||
var DragTop = 120;
|
||||
var DragNumber = -1;
|
||||
var AnswersTried = '';
|
||||
|
||||
Lines = new Array();
|
||||
|
||||
function CapFirst(InString){
|
||||
var i = 0;
|
||||
if ((Openers.indexOf(InString.charAt(i))>-1)||(InString.charAt(i) == ' ')){
|
||||
i++;
|
||||
}
|
||||
if ((Openers.indexOf(InString.charAt(i))>-1)||(InString.charAt(i) == ' ')){
|
||||
i++;
|
||||
}
|
||||
var Temp = InString.charAt(i);
|
||||
Temp = Temp.toUpperCase();
|
||||
InString = InString.substring(0, i) + Temp + InString.substring(i+1, InString.length);
|
||||
return InString;
|
||||
}
|
||||
|
||||
function CheckResults(ChkType){
|
||||
//Get sequence student has chosen
|
||||
GetGuessSequence();
|
||||
|
||||
//Compile the answer
|
||||
CompiledOutput = CompileString(GuessSequence);
|
||||
|
||||
//Check the answer
|
||||
CheckAnswer(ChkType);
|
||||
}
|
||||
|
||||
function GetGuessSequence(){
|
||||
//Put pointers to draggables in arrays based on the lines they're sitting on
|
||||
var Drops = new Array();
|
||||
for (var i=0; i<L.length; i++){
|
||||
Drops[i] = new Array();
|
||||
}
|
||||
|
||||
var CardPos = 0;
|
||||
|
||||
for (i=0; i<Cds.length; i++){
|
||||
for (var j=0; j<L.length; j++){
|
||||
//Slight modification for 6.0.4: allow some leeway for 1px inaccuracy in card placing by browser.
|
||||
CardPos = L[j].GetB() - (Cds[i].GetH()+2);
|
||||
if (((Cds[i].GetT() - CardPos) < 4)&&((Cds[i].GetT() - CardPos) > -4)){
|
||||
Drops[j][Drops[j].length] = Cds[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Sort the drop arrays based on the Left of each div
|
||||
for (i=0; i<Drops.length; i++){
|
||||
Drops[i].sort(CompDrags);
|
||||
}
|
||||
|
||||
//Put the tags into the GuessSequence array
|
||||
GuessSequence.length = 0;
|
||||
for (i=0; i<Drops.length; i++){
|
||||
for (j=0; j<Drops[i].length; j++){
|
||||
GuessSequence[GuessSequence.length] = Drops[i][j].tag;
|
||||
}
|
||||
}
|
||||
|
||||
//Set the variable recording which div is first
|
||||
var NewFirstDiv = -1;
|
||||
for (i=0; i<Drops.length; i++){
|
||||
if (Drops[i].length > 0){
|
||||
NewFirstDiv = Drops[i][0].index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NewFirstDiv;
|
||||
}
|
||||
|
||||
function CompDrags(a,b){
|
||||
return a.GetL() - b.GetL();
|
||||
}
|
||||
|
||||
function FindSegment(SegID){
|
||||
var Seg = '';
|
||||
for (var i=0; i<Segments.length; i++){
|
||||
if (Segments[i][1] == SegID){
|
||||
Seg = Segments[i][0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Seg;
|
||||
}
|
||||
|
||||
function CompileString(InArray){
|
||||
var OutString = '';
|
||||
var i = 0;
|
||||
OutArray = new Array();
|
||||
|
||||
for (i=0; i<InArray.length; i++){
|
||||
OutArray[OutArray.length] = FindSegment(InArray[i]);
|
||||
}
|
||||
|
||||
if (OutArray.length > 0){
|
||||
OutString = OutArray[0];
|
||||
}
|
||||
else{
|
||||
OutString = '';
|
||||
}
|
||||
var Spacer = '';
|
||||
|
||||
for (i=1; i<OutArray.length; i++){
|
||||
Spacer = ' ';
|
||||
if ((Openers.indexOf(OutString.charAt(OutString.length-1)) > -1)||(Punctuation.indexOf(OutArray[i].charAt(0)) > -1)){
|
||||
Spacer = '';
|
||||
}
|
||||
OutString = OutString + Spacer + OutArray[i];
|
||||
}
|
||||
|
||||
//Capitalize the first letter if necessary
|
||||
if (CapitalizeFirst == true){
|
||||
OutString = CapFirst(OutString);
|
||||
}
|
||||
return OutString;
|
||||
}
|
||||
|
||||
function CheckAnswer(CheckType){
|
||||
if (Locked == true){return;}
|
||||
if (GuessSequence.length < 1){
|
||||
if (CheckType == 1){
|
||||
Penalties++;
|
||||
ShowMessage(NextCorrect + '<br /><br />' + FindSegment(Answers[0][0]));
|
||||
}
|
||||
return;
|
||||
}
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
var k = 0;
|
||||
var WellDone = '';
|
||||
var WhichCorrect = -1;
|
||||
var TryAgain = '';
|
||||
var LongestCorrectBit = '';
|
||||
TempCorrect = new Array();
|
||||
LongestCorrect = new Array();
|
||||
var TempHint = '';
|
||||
var HintToReturn = 1;
|
||||
var OtherAnswers = '';
|
||||
var AllDone = false;
|
||||
|
||||
for (i=0; i<Answers.length; i++){
|
||||
TempCorrect.length = 0;
|
||||
for (j=0; j<Answers[i].length; j++){
|
||||
if (Answers[i][j] == GuessSequence[j]){
|
||||
TempCorrect[j] = GuessSequence[j];
|
||||
}
|
||||
else{
|
||||
TempHint = Answers[i][j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((TempCorrect.length == GuessSequence.length)&&(TempCorrect.length == Answers[i].length)){
|
||||
WhichCorrect = i;
|
||||
break;
|
||||
}
|
||||
else{
|
||||
if (TempCorrect.length > LongestCorrect.length){
|
||||
LongestCorrect.length = 0;
|
||||
for (k=0; k<TempCorrect.length; k++){
|
||||
LongestCorrect[k] = TempCorrect[k];
|
||||
}
|
||||
HintToReturn = TempHint;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (WhichCorrect > -1){
|
||||
AllDone = true;
|
||||
for (i=0; i<Answers.length; i++){
|
||||
if (i!=WhichCorrect){
|
||||
OtherAnswers += '<br />' + CompileString(Answers[i]);
|
||||
}
|
||||
}
|
||||
WellDone = '<span class="CorrectAnswer">' + CompiledOutput + '</span><br /><br />' + CorrectResponse + '<br />';
|
||||
|
||||
if (AnswersTried.length > 0){AnswersTried += ' | ';}
|
||||
AnswersTried += CompiledOutput;
|
||||
|
||||
//Do score calculation here
|
||||
Score = Math.floor(((Segments.length-Penalties) * 100)/Segments.length);
|
||||
WellDone += YourScoreIs + ' ' + Score + '%.<br />';
|
||||
|
||||
[inclAlsoCorrect]
|
||||
if (OtherAnswers.length > 0){
|
||||
WellDone += TheseAnswersToo + '<span class="CorrectAnswer">' + OtherAnswers + '</span>';
|
||||
}
|
||||
[/inclAlsoCorrect]
|
||||
|
||||
ShowMessage(WellDone);
|
||||
WriteToInstructions(YourScoreIs + ' ' + Score + '%.');
|
||||
}
|
||||
|
||||
else{
|
||||
var WrongGuess = CompileString(GuessSequence);
|
||||
if (AnswersTried.length > 0){AnswersTried += ' | ';}
|
||||
AnswersTried += WrongGuess;
|
||||
TryAgain = '<span class="Guess">' + WrongGuess + '</span><br /><br />';
|
||||
if ((CheckType == 0)||(LongestCorrect.length==0)){
|
||||
TryAgain += IncorrectResponse + '<br />';
|
||||
}
|
||||
|
||||
if (LongestCorrect.length > 0){
|
||||
LongestCorrectBit = CompileString(LongestCorrect);
|
||||
GuessSequence.length = LongestCorrect.length;
|
||||
TryAgain += '<br />' + ThisMuchCorrect + '<br /><span class="Guess">' + LongestCorrectBit + '</span><br />';
|
||||
}
|
||||
|
||||
if (CheckType == 1){
|
||||
TryAgain += '<br />' + NextCorrect + '<br />' + FindSegment(HintToReturn);
|
||||
}
|
||||
|
||||
[inclTimer]
|
||||
if (TimeOver == true){
|
||||
Score = Math.floor(((LongestCorrect.length-Penalties) * 100)/Segments.length);
|
||||
if (Score < 0){Score = 0;}
|
||||
TryAgain += YourScoreIs + ' ' + Score + '%.<br />';
|
||||
}
|
||||
[/inclTimer]
|
||||
Penalties++; //Penalty for inaccurate check
|
||||
ShowMessage(TryAgain);
|
||||
}
|
||||
|
||||
//If the exercise is over, deal with that
|
||||
if ((AllDone == true)||(TimeOver == true)){
|
||||
[inclSendResults]
|
||||
setTimeout('SendResults(' + Score + ')', 50);
|
||||
[/inclSendResults]
|
||||
[inclTimer]
|
||||
window.clearInterval(Interval);
|
||||
[/inclTimer]
|
||||
TimeOver = true;
|
||||
Locked = true;
|
||||
Finished = true;
|
||||
setTimeout('Finish()', SubmissionTimeout);
|
||||
WriteToInstructions(YourScoreIs + ' ' + Score + '%.');
|
||||
}
|
||||
|
||||
[inclScorm1.2]
|
||||
if (AllDone == true){
|
||||
SetScormComplete();
|
||||
}
|
||||
else{
|
||||
SetScormIncomplete();
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
}
|
||||
|
||||
|
||||
var Segments = new Array();
|
||||
[SegmentArray]
|
||||
|
||||
var GuessSequence = new Array();
|
||||
|
||||
var Answers = new Array();
|
||||
[AnswerArray]
|
||||
|
||||
function doDrag(e) {
|
||||
if (CurrDrag == -1) {return};
|
||||
if (C.ie){var Ev = window.event}else{var Ev = e}
|
||||
var difX = Ev.clientX-window.lastX;
|
||||
var difY = Ev.clientY-window.lastY;
|
||||
var newX = Cds[CurrDrag].GetL()+difX;
|
||||
var newY = Cds[CurrDrag].GetT()+difY;
|
||||
Cds[CurrDrag].SetL(newX);
|
||||
Cds[CurrDrag].SetT(newY);
|
||||
window.lastX = Ev.clientX;
|
||||
window.lastY = Ev.clientY;
|
||||
return false;
|
||||
}
|
||||
|
||||
function beginDrag(e, DragNum) {
|
||||
CurrDrag = DragNum;
|
||||
if (C.ie){
|
||||
var Ev = window.event;
|
||||
document.onmousemove=doDrag;
|
||||
document.onmouseup=endDrag;
|
||||
}
|
||||
else{
|
||||
var Ev = e;
|
||||
window.onmousemove=doDrag;
|
||||
window.onmouseup=endDrag;
|
||||
}
|
||||
Cds[CurrDrag].SwapColours();
|
||||
topZ++;
|
||||
Cds[CurrDrag].css.zIndex = topZ;
|
||||
window.lastX=Ev.clientX;
|
||||
window.lastY=Ev.clientY;
|
||||
return true;
|
||||
}
|
||||
|
||||
function endDrag(e) {
|
||||
if (CurrDrag == -1) {return};
|
||||
Cds[CurrDrag].SwapColours();
|
||||
if (C.ie){document.onmousemove=null}else{window.onmousemove=null;}
|
||||
onEndDrag();
|
||||
CurrDrag = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
function onEndDrag(){
|
||||
//Snap to lines
|
||||
var i = 0;
|
||||
var SnapLine = Cds[CurrDrag].GetT();
|
||||
var BiggestOverlap = -1;
|
||||
var OverlapRect = 0;
|
||||
for (i=0; i<L.length; i++){
|
||||
if (Cds[CurrDrag].Overlap(L[i]) > OverlapRect){
|
||||
OverlapRect = Cds[CurrDrag].Overlap(L[i]);
|
||||
BiggestOverlap = i;
|
||||
}
|
||||
}
|
||||
if (BiggestOverlap > -1){
|
||||
SnapLine = L[BiggestOverlap].GetB() - (Cds[CurrDrag].GetH() + 2);
|
||||
Cds[CurrDrag].SetT(SnapLine);
|
||||
CheckOver(-1);
|
||||
}
|
||||
if (CapitalizeFirst==true){
|
||||
setTimeout('DoCapitalization()', 50);
|
||||
}
|
||||
}
|
||||
|
||||
function DoCapitalization(){
|
||||
//Capitalize first segment if necessary
|
||||
var FD = GetGuessSequence();
|
||||
if ((FD == -1)&&(FirstDiv > -1)){
|
||||
Cds[FirstDiv].elm.innerHTML = Segments[FirstDiv][0];
|
||||
}
|
||||
if (((FD != FirstDiv)&&(CapitalizeFirst == true))&&(FD > -1)){
|
||||
if (FirstDiv > -1){
|
||||
Cds[FirstDiv].elm.innerHTML = Segments[FirstDiv][0];
|
||||
}
|
||||
}
|
||||
if ((FD > -1)&&(CapitalizeFirst == true)){
|
||||
var Temp = CapFirst(Segments[FD][0]);
|
||||
Cds[FD].elm.innerHTML = Temp;
|
||||
FirstDiv = FD;
|
||||
}
|
||||
}
|
||||
|
||||
function CheckOver(NoMove){
|
||||
//This recursive function spreads out the Cards on a line if two of them are overlapping;
|
||||
//if the spread operation moves one beyond the end of a line, it wraps it to the next line.
|
||||
for (var i=0; i<Cds.length; i++){
|
||||
for (var j=0; j<Cds.length; j++){
|
||||
if (i!=j){
|
||||
if (Cds[i].Overlap(Cds[j]) > 0){
|
||||
if ((i==NoMove)||(Cds[i].GetL() < Cds[j].GetL())){
|
||||
Cds[j].DockToR(Cds[i]);
|
||||
if (Cds[j].GetR() > (LeftColPos + DivWidth)){
|
||||
Cds[j].SetL(LeftColPos);
|
||||
Cds[j].SetT(Cds[j].GetT() + DropHeight);
|
||||
}
|
||||
CheckOver(j);
|
||||
}
|
||||
else{
|
||||
Cds[i].DockToR(Cds[j]);
|
||||
if (Cds[i].GetR() > (LeftColPos + DivWidth)){
|
||||
Cds[i].SetL(LeftColPos);
|
||||
Cds[i].SetT(Cds[i].GetT() + DropHeight);
|
||||
}
|
||||
CheckOver(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function StartUp(){
|
||||
|
||||
[inclSendResults]
|
||||
GetUserName();
|
||||
[/inclSendResults]
|
||||
|
||||
[inclScorm1.2]
|
||||
ScormStartUp();
|
||||
[/inclScorm1.2]
|
||||
|
||||
[inclPreloadImages]
|
||||
PreloadImages([PreloadImageList]);
|
||||
[/inclPreloadImages]
|
||||
|
||||
Segments = Shuffle(Segments);
|
||||
|
||||
//Calculate page dimensions and positions
|
||||
pg = new PageDim();
|
||||
DivWidth = Math.floor((pg.W*4)/5);
|
||||
LeftColPos = Math.floor(pg.W/10);
|
||||
DragTop = parseInt(document.getElementById('CheckButtonDiv').offsetHeight) + parseInt(document.getElementById('CheckButtonDiv').offsetTop) + 10;
|
||||
|
||||
var CurrTop = DragTop + 10;
|
||||
|
||||
//Position the drop divs
|
||||
for (var i=0; i<DropTotal; i++){
|
||||
L[i] = new Card('Drop' + i, 0);
|
||||
L[i].SetT(CurrTop)
|
||||
L[i].tag = CurrTop-5;
|
||||
L[i].SetL(LeftColPos);
|
||||
L[i].css.backgroundColor = '[strPageBGColor]';
|
||||
CurrTop += L[i].GetH();
|
||||
topZ++;
|
||||
L[i].css.zIndex = topZ;
|
||||
}
|
||||
DropHeight = L[0].GetH();
|
||||
|
||||
CurrTop = DragTop;
|
||||
var TempInt = 0;
|
||||
var DropHome = 0;
|
||||
|
||||
for (i=0; i<Segments.length; i++){
|
||||
//Create a new pointer in the C array to ref the card div
|
||||
Cds[i] = new Card('D'+i, 0);
|
||||
Cds[i].elm.innerHTML = Segments[i][0];
|
||||
Cds[i].SetT(CurrTop);
|
||||
Cds[i].SetL(LeftColPos);
|
||||
Cds[i].css.cursor = 'move';
|
||||
TempInt = Cds[i].GetH();
|
||||
CurrTop = CurrTop + TempInt + 5;
|
||||
Cds[i].css.backgroundColor = '[strExBGColor]';
|
||||
Cds[i].css.color = '[strTextColor]';
|
||||
topZ++;
|
||||
Cds[i].css.zIndex = topZ;
|
||||
Cds[i].tag = Segments[i][1];
|
||||
Cds[i].index = i;
|
||||
}
|
||||
//Place them at the bottom of the page
|
||||
SetInitialPositions();
|
||||
|
||||
[inclTimer]
|
||||
StartTimer();
|
||||
[/inclTimer]
|
||||
}
|
||||
|
||||
function SetInitialPositions(){
|
||||
//Places all the divs at the bottom of the page in centred rows
|
||||
//First, get the vertical position of the first row
|
||||
var RTop = L[L.length-1].GetB() + 10;
|
||||
|
||||
//Create an array to hold the numbers of Cards for each row
|
||||
CRows = new Array();
|
||||
CRows[0] = new Array();
|
||||
Widths = new Array();
|
||||
var i=0;
|
||||
var r=0;
|
||||
var RowWidth=0;
|
||||
//Sort the Cards into rows, storing their numbers in the array
|
||||
|
||||
while (i<Cds.length){
|
||||
//if it fits on this row, add it
|
||||
if ((RowWidth + Cds[i].GetW() + 5) < DivWidth){
|
||||
CRows[r][CRows[r].length] = i;
|
||||
RowWidth += Cds[i].GetW() + 5;
|
||||
//Store the width in the Widths array for later
|
||||
Widths[r] = RowWidth;
|
||||
}
|
||||
//if not, increment the row number, and add it to the next row
|
||||
else{
|
||||
r++;
|
||||
CRows[r] = new Array();
|
||||
CRows[r][CRows[r].length] = i;
|
||||
RowWidth = Cds[i].GetW() + 5;
|
||||
//Store the width in the Widths array for later
|
||||
Widths[r] = RowWidth;
|
||||
}
|
||||
//move to the next Card
|
||||
i++;
|
||||
}
|
||||
//Now we have the numbers in rows, set out each row
|
||||
r=0;
|
||||
var Indent=0;
|
||||
for (r=0; r<CRows.length; r++){
|
||||
//Get the required indent for this row
|
||||
Indent = Math.floor((DivWidth-Widths[r])/2);
|
||||
//Set the first card in position
|
||||
Cds[CRows[r][0]].SetL(Indent + LeftColPos);
|
||||
Cds[CRows[r][0]].SetT(RTop);
|
||||
Cds[CRows[r][0]].SetHome();
|
||||
for (i=1; i<CRows[r].length; i++){
|
||||
Cds[CRows[r][i]].DockToR(Cds[CRows[r][i-1]]);
|
||||
Cds[CRows[r][i]].SetHome();
|
||||
}
|
||||
//Increment the row height
|
||||
RTop += Cds[0].GetH() + 5;
|
||||
}
|
||||
}
|
||||
|
||||
function TimerStartUp(){
|
||||
setTimeout('StartUp()', 300);
|
||||
}
|
||||
|
||||
[inclTimer]
|
||||
function TimesUp() {
|
||||
document.getElementById('Timer').innerHTML = '[strTimesUp]';
|
||||
[inclPreloadImages]
|
||||
RefreshImages();
|
||||
[/inclPreloadImages]
|
||||
TimeOver = true;
|
||||
CheckAnswer(0);
|
||||
Locked = true;
|
||||
[inclScorm1.2]
|
||||
SetScormTimedOut();
|
||||
[/inclScorm1.2]
|
||||
}
|
||||
[/inclTimer]
|
||||
@@ -1,105 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xml:lang="en"><head>
|
||||
|
||||
[strDublinCoreMetadata]
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
|
||||
<title>
|
||||
[strPlainTitle]
|
||||
</title>
|
||||
|
||||
<!-- Made with executable version [strFullVersionInfo] -->
|
||||
|
||||
<!-- The following insertion allows you to add your own code directly to this head tag from the configuration screen -->
|
||||
|
||||
[strHeaderCode]
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
[strStyleSheet]
|
||||
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
//<![CDATA[
|
||||
|
||||
<!--
|
||||
|
||||
[inclScorm1.2]
|
||||
[strJSScorm_1_2]
|
||||
[/inclScorm1.2]
|
||||
|
||||
[strJSBrowserCheck]
|
||||
|
||||
[strJSButtons]
|
||||
|
||||
[strJSUtilities]
|
||||
|
||||
[strJSFJMatch6]
|
||||
|
||||
//-->
|
||||
|
||||
//]]>
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</head>
|
||||
<!--<body>Fool those dumb ad-inserting ISPs</body>-->
|
||||
|
||||
<body onload="StartUp()" id="TheBody" [inclScorm1.2]onunload="SetScormBrowseTime(); CheckLMSFinish()"[/inclScorm1.2]>
|
||||
|
||||
<!-- BeginTopNavButtons -->
|
||||
|
||||
[inclNavButtons]
|
||||
[strTopNavBar]
|
||||
[/inclNavButtons]
|
||||
|
||||
<!-- EndTopNavButtons -->
|
||||
|
||||
<div class="Titles">
|
||||
<h2 class="ExerciseTitle">[strExerciseTitle]</h2>
|
||||
[inclExerciseSubtitle]
|
||||
<h3 class="ExerciseSubtitle">[strExerciseSubtitle]</h3>
|
||||
[/inclExerciseSubtitle]
|
||||
</div>
|
||||
|
||||
<div id="InstructionsDiv" class="StdDiv">
|
||||
<div id="Instructions">[strInstructions]</div>
|
||||
</div>
|
||||
|
||||
<div id="MainDiv" class="StdDiv">
|
||||
|
||||
<button class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="ShowItem()">[strNextCaption]</button>
|
||||
|
||||
<button class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="DeleteItem()">[strDeleteCaption]</button>
|
||||
|
||||
</div>
|
||||
|
||||
<table class="FlashcardTable" border="0" cellspacing="0">
|
||||
<tbody id="Questions">
|
||||
|
||||
[strTRows]
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- BeginBottomNavButtons -->
|
||||
|
||||
[inclNavButtons]
|
||||
[strBottomNavBar]
|
||||
[/inclNavButtons]
|
||||
|
||||
<!-- EndBottomNavButtons -->
|
||||
|
||||
<!-- BeginSubmissionForm -->
|
||||
|
||||
<!-- EndSubmissionForm -->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,131 +0,0 @@
|
||||
|
||||
[inclScorm1.2]
|
||||
//JMATCH-SPECIFIC SCORM-RELATED JAVASCRIPT CODE
|
||||
|
||||
function SetScormBrowseTime(){
|
||||
if (API != null){
|
||||
API.LMSSetValue('cmi.core.session_time', MillisecondsToTime((new Date()).getTime() - ScormStartTime));
|
||||
API.LMSCommit('');
|
||||
}
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
|
||||
//JMATCH-SPECIFIC CORE JAVASCRIPT CODE
|
||||
|
||||
var CurrItem = null;
|
||||
var Stage = 2;
|
||||
var QList = new Array();
|
||||
var ShuffleQs = [boolShuffleQs];
|
||||
|
||||
function SetUpItems(){
|
||||
|
||||
var i;
|
||||
var Row = null;
|
||||
|
||||
//Remove all the table rows and put them in an array for processing
|
||||
var Qs = document.getElementById('Questions');
|
||||
|
||||
//Remove the table rows to an array
|
||||
while (Qs.getElementsByTagName('tr').length > 0){
|
||||
Row = Qs.getElementsByTagName('tr')[0];
|
||||
Row.getElementsByTagName('td')[0].className = 'Hidden';
|
||||
Row.getElementsByTagName('td')[1].className = 'Hidden';
|
||||
QList.push(Qs.removeChild(Row));
|
||||
}
|
||||
|
||||
//Shuffle the rows
|
||||
if (ShuffleQs == true){
|
||||
QList = Shuffle(QList);
|
||||
}
|
||||
|
||||
//Write the rows back to the table body
|
||||
for (i=0; i<QList.length; i++){
|
||||
Qs.appendChild(QList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function StartUp(){
|
||||
|
||||
SetUpItems();
|
||||
|
||||
[inclScorm1.2]
|
||||
initAPI(window);
|
||||
if (API != null){
|
||||
API.LMSInitialize('');
|
||||
API.LMSSetValue('cmi.core.lesson_status', 'browsed');
|
||||
API.LMSSetValue('cmi.comments', 'This exercise has no checking or scoring features.');
|
||||
API.LMSCommit('');
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
|
||||
|
||||
[inclPreloadImages]
|
||||
PreloadImages([PreloadImageList]);
|
||||
[/inclPreloadImages]
|
||||
|
||||
[inclPreloadImages]
|
||||
RefreshImages();
|
||||
[/inclPreloadImages]
|
||||
}
|
||||
|
||||
var Started = false;
|
||||
|
||||
function DeleteItem(){
|
||||
if ((CurrItem == null)||(document.getElementById('Questions').getElementsByTagName('tr').length < 1)){return;}
|
||||
|
||||
//Delete the current item
|
||||
var DelItem = CurrItem;
|
||||
Stage = 2;
|
||||
ShowItem();
|
||||
document.getElementById('Questions').removeChild(DelItem);
|
||||
}
|
||||
|
||||
function ShowItem(){
|
||||
var Qs = document.getElementById('Questions');
|
||||
|
||||
var Len = Qs.getElementsByTagName('tr').length;
|
||||
|
||||
//Bail if no more items
|
||||
if (Len < 1){
|
||||
return;
|
||||
}
|
||||
|
||||
//if no current item, get the last item so we roll forward
|
||||
if (CurrItem == null){
|
||||
CurrItem = Qs.getElementsByTagName('tr')[Len-1];
|
||||
if (CurrItem == null){
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//if CurrItem has been fully shown, move to the next one
|
||||
if (Stage == 2){
|
||||
CurrItem.getElementsByTagName('td')[0].className = 'Hidden';
|
||||
CurrItem.getElementsByTagName('td')[1].className = 'Hidden';
|
||||
if (CurrItem.nextSibling != null){
|
||||
CurrItem = CurrItem.nextSibling;
|
||||
}
|
||||
else{
|
||||
CurrItem = Qs.getElementsByTagName('tr')[0];
|
||||
}
|
||||
}
|
||||
|
||||
//Show the appropriate bits
|
||||
if (Stage == 2){
|
||||
//Show the first item and hide the second
|
||||
CurrItem.getElementsByTagName('td')[0].className = 'Showing';
|
||||
CurrItem.getElementsByTagName('td')[1].className = 'Hidden';
|
||||
Stage = 1;
|
||||
}
|
||||
else{
|
||||
//Show both items
|
||||
CurrItem.getElementsByTagName('td')[0].className = 'Showing';
|
||||
CurrItem.getElementsByTagName('td')[1].className = 'Showing';
|
||||
Stage = 2;
|
||||
}
|
||||
|
||||
[inclPreloadImages]
|
||||
RefreshImages();
|
||||
[/inclPreloadImages]
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
[inclReadingTitle]
|
||||
<h3 class="ExerciseSubtitle">[strReadingTitle]</h3>
|
||||
[/inclReadingTitle]
|
||||
<div class="ReadingText">
|
||||
[strReadingText]
|
||||
</div>
|
||||
|
||||
@@ -1,605 +0,0 @@
|
||||
|
||||
/* This is the CSS stylesheet used in the exercise. */
|
||||
/* Elements in square brackets are replaced by data based on configuration settings when the exercise is built. */
|
||||
|
||||
/* BeginCorePageCSS */
|
||||
|
||||
/* Made with executable version [strFullVersionInfo] */
|
||||
|
||||
|
||||
/* Hack to hide a nested Quicktime player from IE, which can't handle it. */
|
||||
* html object.MediaPlayerNotForIE {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body{
|
||||
font-family: [strFontFace];
|
||||
[inclPageBGColor] background-color: [strPageBGColor];[/inclPageBGColor]
|
||||
color: [strTextColor];
|
||||
[inclGraphicURL] background-image: url([strGraphicURL]);[/inclGraphicURL]
|
||||
margin-right: 5%;
|
||||
margin-left: 5%;
|
||||
font-size: [strFontSize];
|
||||
}
|
||||
|
||||
p{
|
||||
text-align: left;
|
||||
margin: 0px;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
table,div,span,td{
|
||||
font-size: 100%;
|
||||
color: [strTextColor];
|
||||
}
|
||||
|
||||
div.Titles{
|
||||
padding: 0.5em;;
|
||||
text-align: center;
|
||||
color: [strTitleColor];
|
||||
}
|
||||
|
||||
button{
|
||||
font-family: [strFontFace];
|
||||
font-size: 100%;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.ExerciseTitle{
|
||||
font-size: 140%;
|
||||
color: [strTitleColor];
|
||||
}
|
||||
|
||||
.ExerciseSubtitle{
|
||||
font-size: 120%;
|
||||
color: [strTitleColor];
|
||||
}
|
||||
|
||||
div.StdDiv{
|
||||
[inclExBGColor] background-color: [strExBGColor];[/inclExBGColor]
|
||||
text-align: center;
|
||||
font-size: 100%;
|
||||
color: [strTextColor];
|
||||
padding: 0.5em;
|
||||
border-style: solid;
|
||||
border-width: 1px 1px 1px 1px;
|
||||
border-color: [strTextColor];
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
|
||||
/* EndCorePageCSS */
|
||||
|
||||
.RTLText{
|
||||
text-align: right;
|
||||
font-size: 150%;
|
||||
direction: rtl;
|
||||
font-family: "Simplified Arabic", "Traditional Arabic", "Times New Roman", [strFontFace];
|
||||
}
|
||||
|
||||
.CentredRTLText{
|
||||
text-align: center;
|
||||
font-size: 150%;
|
||||
direction: rtl;
|
||||
font-family: "Simplified Arabic", "Traditional Arabic", "Times New Roman", [strFontFace];
|
||||
}
|
||||
|
||||
button p.RTLText{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.RTLGapBox{
|
||||
text-align: right;
|
||||
font-size: 150%;
|
||||
direction: rtl;
|
||||
font-family: "Times New Roman", [strFontFace];
|
||||
}
|
||||
|
||||
.Guess{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.CorrectAnswer{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div#Timer{
|
||||
padding: 0.25em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
text-align: center;
|
||||
color: [strTitleColor];
|
||||
}
|
||||
|
||||
span#TimerText{
|
||||
padding: 0.25em;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
font-weight: bold;
|
||||
display: none;
|
||||
color: [strTitleColor];
|
||||
}
|
||||
|
||||
span.Instructions{
|
||||
|
||||
}
|
||||
|
||||
div.ExerciseText{
|
||||
|
||||
}
|
||||
|
||||
.FeedbackText, .FeedbackText span.CorrectAnswer, .FeedbackText span.Guess, .FeedbackText span.Answer{
|
||||
color: [strTitleColor];
|
||||
}
|
||||
|
||||
.LeftItem{
|
||||
font-size: 100%;
|
||||
color: [strTextColor];
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.RightItem{
|
||||
font-weight: bold;
|
||||
font-size: 100%;
|
||||
color: [strTextColor];
|
||||
}
|
||||
|
||||
span.CorrectMark{
|
||||
|
||||
}
|
||||
|
||||
input, textarea{
|
||||
font-family: [strFontFace];
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
select{
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
div.Feedback {
|
||||
[inclPageBGColor] background-color: [strPageBGColor];[/inclPageBGColor]
|
||||
left: 33%;
|
||||
width: 34%;
|
||||
top: 33%;
|
||||
z-index: 1;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
color: [strTitleColor];
|
||||
position: absolute;
|
||||
display: none;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
|
||||
[inclReading]
|
||||
div.LeftContainer{
|
||||
border-style: none;
|
||||
padding: 2px 0px 2px 0px;
|
||||
float: left;
|
||||
width: 49.8%;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
div.RightContainer{
|
||||
border-style: none;
|
||||
padding: 2px 0px 2px 0px;
|
||||
float: right;
|
||||
width: 49.8%;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.ReadingText{
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#ReadingDiv h3.ExerciseSubtitle{
|
||||
color: [strTextColor];
|
||||
}
|
||||
|
||||
[/inclReading]
|
||||
|
||||
div.ExerciseDiv{
|
||||
color: [strTextColor];
|
||||
}
|
||||
|
||||
/* JMatch flashcard styles */
|
||||
table.FlashcardTable{
|
||||
background-color: transparent;
|
||||
color: [strTextColor];
|
||||
border-color: [strTextColor];
|
||||
margin-left: 5%;
|
||||
margin-right: 5%;
|
||||
margin-top: 2em;
|
||||
margin-bottom: 2em;
|
||||
width: 90%;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
table.FlashcardTable tr{
|
||||
border-style: none;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
[inclExBGColor] background-color: [strExBGColor];[/inclExBGColor]
|
||||
}
|
||||
|
||||
table.FlashcardTable td.Showing{
|
||||
font-size: 140%;
|
||||
text-align: center;
|
||||
width: 50%;
|
||||
display: table-cell;
|
||||
padding: 2em;
|
||||
margin: 0px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
color: [strTextColor];
|
||||
[inclExBGColor] background-color: [strExBGColor];[/inclExBGColor]
|
||||
}
|
||||
|
||||
table.FlashcardTable td.Hidden{
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* JMix styles */
|
||||
div#SegmentDiv{
|
||||
margin-top: 2em;
|
||||
margin-bottom: 2em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
a.ExSegment{
|
||||
font-size: 120%;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: [strTextColor];
|
||||
}
|
||||
|
||||
span.RemainingWordList{
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
div.DropLine {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-color: [strTitleColor];
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
/* JCloze styles */
|
||||
|
||||
.ClozeWordList{
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.ClozeBody{
|
||||
text-align: left;
|
||||
margin-top: 2em;
|
||||
margin-bottom: 2em;
|
||||
line-height: 2.0
|
||||
}
|
||||
|
||||
span.GapSpan{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* JCross styles */
|
||||
|
||||
table.CrosswordGrid{
|
||||
margin: auto auto 1em auto;
|
||||
border-collapse: collapse;
|
||||
padding: 0px;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
table.CrosswordGrid tbody tr td{
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
font-size: 140%;
|
||||
padding: 1px;
|
||||
margin: 0px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #000000;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
table.CrosswordGrid span{
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
table.CrosswordGrid td.BlankCell{
|
||||
background-color: #000000;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
table.CrosswordGrid td.LetterOnlyCell{
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table.CrosswordGrid td.NumLetterCell{
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
padding: 1px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.NumLetterCellText{
|
||||
cursor: pointer;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.GridNum{
|
||||
vertical-align: super;
|
||||
font-size: 66%;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.GridNum:hover, .GridNum:visited{
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
table#Clues{
|
||||
margin: auto;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table#Clues td{
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table.ClueList{
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
td.ClueNum{
|
||||
text-align: right;
|
||||
font-weight: bold;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
td.Clue{
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div#ClueEntry{
|
||||
text-align: left;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
/* Keypad styles */
|
||||
|
||||
div.Keypad{
|
||||
text-align: center;
|
||||
display: none; /* initially hidden, shown if needed */
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
div.Keypad button{
|
||||
font-family: [strFontFace];
|
||||
font-size: 120%;
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
width: 2em;
|
||||
}
|
||||
|
||||
/* JQuiz styles */
|
||||
|
||||
div.QuestionNavigation{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.QNum{
|
||||
margin: 0em 1em 0.5em 1em;
|
||||
font-weight: bold;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
textarea{
|
||||
font-family: [strFontFace];
|
||||
}
|
||||
|
||||
.QuestionText{
|
||||
text-align: left;
|
||||
margin: 0px;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.Answer{
|
||||
font-size: 120%;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
|
||||
.PartialAnswer{
|
||||
font-size: 120%;
|
||||
letter-spacing: 0.1em;
|
||||
color: [strTitleColor];
|
||||
}
|
||||
|
||||
.Highlight{
|
||||
color: #000000;
|
||||
background-color: #ffff00;
|
||||
font-weight: bold;
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
ol.QuizQuestions{
|
||||
text-align: left;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
li.QuizQuestion{
|
||||
padding: 1em;
|
||||
border-style: solid;
|
||||
border-width: 0px 0px 1px 0px;
|
||||
}
|
||||
|
||||
ol.MCAnswers{
|
||||
text-align: left;
|
||||
list-style-type: upper-alpha;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
ol.MCAnswers li{
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
ol.MSelAnswers{
|
||||
text-align: left;
|
||||
list-style-type: lower-alpha;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
div.ShortAnswer{
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.FuncButton {
|
||||
text-align: center;
|
||||
border-style: solid;
|
||||
[inclExBGColor]
|
||||
border-left-color: [strFuncLightColor];
|
||||
border-top-color: [strFuncLightColor];
|
||||
border-right-color: [strFuncShadeColor];
|
||||
border-bottom-color: [strFuncShadeColor];
|
||||
color: [strTextColor];
|
||||
background-color: [strExBGColor];
|
||||
[/inclExBGColor]
|
||||
border-width: 2px;
|
||||
padding: 3px 6px 3px 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.FuncButtonUp {
|
||||
color: [strExBGColor];
|
||||
text-align: center;
|
||||
border-style: solid;
|
||||
[inclExBGColor]
|
||||
border-left-color: [strFuncLightColor];
|
||||
border-top-color: [strFuncLightColor];
|
||||
border-right-color: [strFuncShadeColor];
|
||||
border-bottom-color: [strFuncShadeColor];
|
||||
[/inclExBGColor]
|
||||
background-color: [strTextColor];
|
||||
color: [strExBGColor];
|
||||
border-width: 2px;
|
||||
padding: 3px 6px 3px 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.FuncButtonDown {
|
||||
color: [strExBGColor];
|
||||
text-align: center;
|
||||
border-style: solid;
|
||||
[inclExBGColor]
|
||||
border-left-color: [strFuncShadeColor];
|
||||
border-top-color: [strFuncShadeColor];
|
||||
border-right-color: [strFuncLightColor];
|
||||
border-bottom-color: [strFuncLightColor];
|
||||
background-color: [strTextColor];
|
||||
color: [strExBGColor];
|
||||
[/inclExBGColor]
|
||||
border-width: 2px;
|
||||
padding: 3px 6px 3px 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*BeginNavBarStyle*/
|
||||
|
||||
div.NavButtonBar{
|
||||
[inclNavBarColor] background-color: [strNavBarColor];[/inclNavBarColor]
|
||||
text-align: center;
|
||||
margin: 2px 0px 2px 0px;
|
||||
clear: both;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.NavButton {
|
||||
border-style: solid;
|
||||
[inclNavBarColor]
|
||||
border-left-color: [strNavLightColor];
|
||||
border-top-color: [strNavLightColor];
|
||||
border-right-color: [strNavShadeColor];
|
||||
border-bottom-color: [strNavShadeColor];
|
||||
background-color: [strNavBarColor];
|
||||
color: [strNavTextColor];
|
||||
[/inclNavBarColor]
|
||||
border-width: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.NavButtonUp {
|
||||
border-style: solid;
|
||||
[inclNavBarColor]
|
||||
border-left-color: [strNavLightColor];
|
||||
border-top-color: [strNavLightColor];
|
||||
border-right-color: [strNavShadeColor];
|
||||
border-bottom-color: [strNavShadeColor];
|
||||
color: [strNavBarColor];
|
||||
background-color: [strNavTextColor];
|
||||
[/inclNavBarColor]
|
||||
border-width: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.NavButtonDown {
|
||||
border-style: solid;
|
||||
[inclNavBarColor]
|
||||
border-left-color: [strNavShadeColor];
|
||||
border-top-color: [strNavShadeColor];
|
||||
border-right-color: [strNavLightColor];
|
||||
border-bottom-color: [strNavLightColor];
|
||||
color: [strNavBarColor];
|
||||
background-color: [strNavTextColor];
|
||||
[/inclNavBarColor]
|
||||
border-width: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*EndNavBarStyle*/
|
||||
|
||||
a{
|
||||
color: [strLinkColor];
|
||||
}
|
||||
|
||||
a:visited{
|
||||
color: [strVLinkColor];
|
||||
}
|
||||
|
||||
a:hover{
|
||||
color: [strLinkColor];
|
||||
}
|
||||
|
||||
div.CardStyle {
|
||||
position: absolute;
|
||||
font-family: [strFontFace];
|
||||
font-size: 100%;
|
||||
padding: 5px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
color: [strTextColor];
|
||||
[inclExBGColor] background-color: [strExBGColor];[/inclExBGColor]
|
||||
left: -50px;
|
||||
top: -50px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.rtl{
|
||||
text-align: right;
|
||||
font-size: 140%;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
|
||||
function Client(){
|
||||
//if not a DOM browser, hopeless
|
||||
this.min = false; if (document.getElementById){this.min = true;};
|
||||
|
||||
this.ua = navigator.userAgent;
|
||||
this.name = navigator.appName;
|
||||
this.ver = navigator.appVersion;
|
||||
|
||||
//Get data about the browser
|
||||
this.mac = (this.ver.indexOf('Mac') != -1);
|
||||
this.win = (this.ver.indexOf('Windows') != -1);
|
||||
|
||||
//Look for Gecko
|
||||
this.gecko = (this.ua.indexOf('Gecko') > 1);
|
||||
if (this.gecko){
|
||||
this.geckoVer = parseInt(this.ua.substring(this.ua.indexOf('Gecko')+6, this.ua.length));
|
||||
if (this.geckoVer < 20020000){this.min = false;}
|
||||
}
|
||||
|
||||
//Look for Firebird
|
||||
this.firebird = (this.ua.indexOf('Firebird') > 1);
|
||||
|
||||
//Look for Safari
|
||||
this.safari = (this.ua.indexOf('Safari') > 1);
|
||||
if (this.safari){
|
||||
this.gecko = false;
|
||||
}
|
||||
|
||||
//Look for IE
|
||||
this.ie = (this.ua.indexOf('MSIE') > 0);
|
||||
if (this.ie){
|
||||
this.ieVer = parseFloat(this.ua.substring(this.ua.indexOf('MSIE')+5, this.ua.length));
|
||||
if (this.ieVer < 5.5){this.min = false;}
|
||||
}
|
||||
|
||||
//Look for Opera
|
||||
this.opera = (this.ua.indexOf('Opera') > 0);
|
||||
if (this.opera){
|
||||
this.operaVer = parseFloat(this.ua.substring(this.ua.indexOf('Opera')+6, this.ua.length));
|
||||
if (this.operaVer < 7.04){this.min = false;}
|
||||
}
|
||||
if (this.min == false){
|
||||
alert('Your browser may not be able to handle this page.');
|
||||
}
|
||||
|
||||
//Special case for the horrible ie5mac
|
||||
this.ie5mac = (this.ie&&this.mac&&(this.ieVer<6));
|
||||
}
|
||||
|
||||
var C = new Client();
|
||||
|
||||
//for (prop in C){
|
||||
// alert(prop + ': ' + C[prop]);
|
||||
//}
|
||||
@@ -1,42 +0,0 @@
|
||||
|
||||
//CODE FOR HANDLING NAV BUTTONS AND FUNCTION BUTTONS
|
||||
|
||||
//[strNavBarJS]
|
||||
function NavBtnOver(Btn){
|
||||
if (Btn.className != 'NavButtonDown'){Btn.className = 'NavButtonUp';}
|
||||
}
|
||||
|
||||
function NavBtnOut(Btn){
|
||||
Btn.className = 'NavButton';
|
||||
}
|
||||
|
||||
function NavBtnDown(Btn){
|
||||
Btn.className = 'NavButtonDown';
|
||||
}
|
||||
//[/strNavBarJS]
|
||||
|
||||
function FuncBtnOver(Btn){
|
||||
if (Btn.className != 'FuncButtonDown'){Btn.className = 'FuncButtonUp';}
|
||||
}
|
||||
|
||||
function FuncBtnOut(Btn){
|
||||
Btn.className = 'FuncButton';
|
||||
}
|
||||
|
||||
function FuncBtnDown(Btn){
|
||||
Btn.className = 'FuncButtonDown';
|
||||
}
|
||||
|
||||
function FocusAButton(){
|
||||
if (document.getElementById('CheckButton1') != null){
|
||||
document.getElementById('CheckButton1').focus();
|
||||
}
|
||||
else{
|
||||
if (document.getElementById('CheckButton2') != null){
|
||||
document.getElementById('CheckButton2').focus();
|
||||
}
|
||||
else{
|
||||
document.getElementsByTagName('button')[0].focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
|
||||
function Card(ID, OverlapTolerance){
|
||||
this.elm=document.getElementById(ID);
|
||||
this.name=ID;
|
||||
this.css=this.elm.style;
|
||||
this.elm.style.left = 0 +'px';
|
||||
this.elm.style.top = 0 +'px';
|
||||
this.HomeL = 0;
|
||||
this.HomeT = 0;
|
||||
this.tag=-1;
|
||||
this.index=-1;
|
||||
this.OverlapTolerance = OverlapTolerance;
|
||||
}
|
||||
|
||||
function CardGetL(){return parseInt(this.css.left)}
|
||||
Card.prototype.GetL=CardGetL;
|
||||
|
||||
function CardGetT(){return parseInt(this.css.top)}
|
||||
Card.prototype.GetT=CardGetT;
|
||||
|
||||
function CardGetW(){return parseInt(this.elm.offsetWidth)}
|
||||
Card.prototype.GetW=CardGetW;
|
||||
|
||||
function CardGetH(){return parseInt(this.elm.offsetHeight)}
|
||||
Card.prototype.GetH=CardGetH;
|
||||
|
||||
function CardGetB(){return this.GetT()+this.GetH()}
|
||||
Card.prototype.GetB=CardGetB;
|
||||
|
||||
function CardGetR(){return this.GetL()+this.GetW()}
|
||||
Card.prototype.GetR=CardGetR;
|
||||
|
||||
function CardSetL(NewL){this.css.left = NewL+'px'}
|
||||
Card.prototype.SetL=CardSetL;
|
||||
|
||||
function CardSetT(NewT){this.css.top = NewT+'px'}
|
||||
Card.prototype.SetT=CardSetT;
|
||||
|
||||
function CardSetW(NewW){this.css.width = NewW+'px'}
|
||||
Card.prototype.SetW=CardSetW;
|
||||
|
||||
function CardSetH(NewH){this.css.height = NewH+'px'}
|
||||
Card.prototype.SetH=CardSetH;
|
||||
|
||||
function CardInside(X,Y){
|
||||
var Result=false;
|
||||
if(X>=this.GetL()){if(X<=this.GetR()){if(Y>=this.GetT()){if(Y<=this.GetB()){Result=true;}}}}
|
||||
return Result;
|
||||
}
|
||||
Card.prototype.Inside=CardInside;
|
||||
|
||||
function CardSwapColours(){
|
||||
var c=this.css.backgroundColor;
|
||||
this.css.backgroundColor=this.css.color;
|
||||
this.css.color=c;
|
||||
}
|
||||
Card.prototype.SwapColours=CardSwapColours;
|
||||
|
||||
function CardHighlight(){
|
||||
this.css.backgroundColor='[strTextColor]';
|
||||
this.css.color='[strExBGColor]';
|
||||
}
|
||||
Card.prototype.Highlight=CardHighlight;
|
||||
|
||||
function CardUnhighlight(){
|
||||
this.css.backgroundColor='[strExBGColor]';
|
||||
this.css.color='[strTextColor]';
|
||||
}
|
||||
Card.prototype.Unhighlight=CardUnhighlight;
|
||||
|
||||
function CardOverlap(OtherCard){
|
||||
var smR=(this.GetR()<(OtherCard.GetR()+this.OverlapTolerance))? this.GetR(): (OtherCard.GetR()+this.OverlapTolerance);
|
||||
var lgL=(this.GetL()>OtherCard.GetL())? this.GetL(): OtherCard.GetL();
|
||||
var HDim=smR-lgL;
|
||||
if (HDim<1){return 0;}
|
||||
var smB=(this.GetB()<OtherCard.GetB())? this.GetB(): OtherCard.GetB();
|
||||
var lgT=(this.GetT()>OtherCard.GetT())? this.GetT(): OtherCard.GetT();
|
||||
var VDim=smB-lgT;
|
||||
if (VDim<1){return 0;}
|
||||
return (HDim*VDim);
|
||||
}
|
||||
Card.prototype.Overlap=CardOverlap;
|
||||
|
||||
function CardDockToR(OtherCard){
|
||||
this.SetL(OtherCard.GetR() + 5);
|
||||
this.SetT(OtherCard.GetT());
|
||||
}
|
||||
|
||||
Card.prototype.DockToR=CardDockToR;
|
||||
|
||||
function CardSetHome(){
|
||||
this.HomeL=this.GetL();
|
||||
this.HomeT=this.GetT();
|
||||
}
|
||||
Card.prototype.SetHome=CardSetHome;
|
||||
|
||||
function CardGoHome(){
|
||||
this.SetL(this.HomeL);
|
||||
this.SetT(this.HomeT);
|
||||
}
|
||||
|
||||
Card.prototype.GoHome=CardGoHome;
|
||||
|
||||
|
||||
function doDrag(e) {
|
||||
if (CurrDrag == -1) {return};
|
||||
if (C.ie){var Ev = window.event}else{var Ev = e}
|
||||
var difX = Ev.clientX-window.lastX;
|
||||
var difY = Ev.clientY-window.lastY;
|
||||
var newX = DC[CurrDrag].GetL()+difX;
|
||||
var newY = DC[CurrDrag].GetT()+difY;
|
||||
DC[CurrDrag].SetL(newX);
|
||||
DC[CurrDrag].SetT(newY);
|
||||
window.lastX = Ev.clientX;
|
||||
window.lastY = Ev.clientY;
|
||||
return false;
|
||||
}
|
||||
|
||||
function beginDrag(e, DragNum) {
|
||||
CurrDrag = DragNum;
|
||||
if (C.ie){
|
||||
var Ev = window.event;
|
||||
document.onmousemove=doDrag;
|
||||
document.onmouseup=endDrag;
|
||||
}
|
||||
else{
|
||||
var Ev = e;
|
||||
window.onmousemove=doDrag;
|
||||
window.onmouseup=endDrag;
|
||||
}
|
||||
DC[CurrDrag].Highlight();
|
||||
topZ++;
|
||||
DC[CurrDrag].css.zIndex = topZ;
|
||||
window.lastX=Ev.clientX;
|
||||
window.lastY=Ev.clientY;
|
||||
return false;
|
||||
}
|
||||
|
||||
function endDrag(e) {
|
||||
if (CurrDrag == -1) {return};
|
||||
DC[CurrDrag].Unhighlight();
|
||||
if (C.ie){document.onmousemove=null}else{window.onmousemove=null;}
|
||||
onEndDrag();
|
||||
CurrDrag = -1;
|
||||
//Need a bugfix for Opera focus problem here
|
||||
if (C.opera){FocusAButton();}
|
||||
return true;
|
||||
}
|
||||
|
||||
var CurrDrag = -1;
|
||||
var topZ = 100;
|
||||
|
||||
@@ -1,405 +0,0 @@
|
||||
//CORE CODE FOR CHECKING SHORT ANSWER GUESSES AGAINST ANSWER ARRAYS
|
||||
|
||||
var CaseSensitive = [boolCaseSensitive];
|
||||
var ShowAlsoCorrect = [boolShowAlsoCorrect];
|
||||
var PleaseEnter = '[strPleaseEnter]';
|
||||
var HybridTries = [intHybridTries];
|
||||
var PartlyIncorrect = '[strPartlyIncorrect]';
|
||||
var CorrectList = '[strCorrectList]';
|
||||
var NextCorrect = '[strNextCorrect]';
|
||||
var CurrBox = null;
|
||||
|
||||
function TrackFocus(BoxID){
|
||||
InTextBox = true;
|
||||
CurrBox = document.getElementById(BoxID);
|
||||
}
|
||||
|
||||
function LeaveGap(){
|
||||
InTextBox = false;
|
||||
}
|
||||
|
||||
function TypeChars(Chars){
|
||||
if (CurrBox != null){
|
||||
//Following check added for 6.0.4.4 to avoid error message in IE6
|
||||
if (CurrBox.style.display != 'none'){
|
||||
CurrBox.value += Chars;
|
||||
CurrBox.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function CheckGuess(Guess, Answer, CaseSensitive, PercentCorrect, Feedback){
|
||||
this.Guess = Guess;
|
||||
this.Answer = Answer;
|
||||
this.PercentCorrect = PercentCorrect;
|
||||
this.Feedback = Feedback;
|
||||
if (CaseSensitive == false){
|
||||
this.WorkingGuess = Guess.toLowerCase();
|
||||
this.WorkingAnswer = Answer.toLowerCase();
|
||||
}
|
||||
else{
|
||||
this.WorkingGuess = Guess;
|
||||
this.WorkingAnswer = Answer;
|
||||
}
|
||||
this.Hint = '';
|
||||
this.HintPenalty = 1/Answer.length;
|
||||
this.CorrectStart = '';
|
||||
this.WrongMiddle = '';
|
||||
this.CorrectEnd = '';
|
||||
this.PercentMatch = 0;
|
||||
this.DoCheck();
|
||||
}
|
||||
|
||||
function CheckGuess_DoCheck(){
|
||||
//Check if it's an exact match
|
||||
if (this.WorkingAnswer == this.WorkingGuess){
|
||||
this.PercentMatch = 100;
|
||||
this.CorrectStart = this.Guess;
|
||||
return;
|
||||
}
|
||||
//Figure out how much of the beginning is correct
|
||||
var i = 0;
|
||||
var CorrectChars = 0;
|
||||
while (this.WorkingAnswer.charAt(i) == this.WorkingGuess.charAt(i)){
|
||||
i++;
|
||||
CorrectChars++;
|
||||
}
|
||||
//Stash the hint
|
||||
this.Hint = this.Answer.charAt(i);
|
||||
|
||||
this.CorrectStart = this.Guess.substring(0, i);
|
||||
|
||||
//If there's more to the answer, look at the rest of it
|
||||
if (i<this.Guess.length){
|
||||
|
||||
//Figure out how much of the end is correct
|
||||
var j = this.WorkingGuess.length-1;
|
||||
var k = this.WorkingAnswer.length-1;
|
||||
while ((j>=i)&&((this.WorkingAnswer.charAt(k) == this.WorkingGuess.charAt(j))&&(CorrectChars < this.Answer.length))){
|
||||
CorrectChars++;
|
||||
j--;
|
||||
k--;
|
||||
}
|
||||
this.CorrectEnd = this.Guess.substring(j+1, this.Guess.length);
|
||||
this.WrongMiddle = this.Guess.substring(i, j+1);
|
||||
}
|
||||
if (TrimString(this.WrongMiddle).length < 1){this.WrongMiddle = '_';}
|
||||
//Calculate match score based on how much of the guess is correct
|
||||
if (CorrectChars < this.Answer.length){
|
||||
this.PercentMatch = Math.floor(100*CorrectChars)/this.Answer.length;
|
||||
}
|
||||
else{
|
||||
this.PercentMatch = Math.floor((100 * CorrectChars)/this.Guess.length);
|
||||
}
|
||||
}
|
||||
|
||||
CheckGuess.prototype.DoCheck = CheckGuess_DoCheck;
|
||||
|
||||
function CheckAnswerArray(CaseSensitive){
|
||||
this.CaseSensitive = CaseSensitive;
|
||||
this.Answers = new Array();
|
||||
this.Score = 0;
|
||||
this.Feedback = '';
|
||||
this.Hint = '';
|
||||
this.HintPenalty = 0;
|
||||
this.MatchedAnswerLength = 1;
|
||||
this.CompleteMatch = false;
|
||||
this.MatchNum = -1;
|
||||
}
|
||||
|
||||
function CheckAnswerArray_AddAnswer(Guess, Answer, PercentCorrect, Feedback){
|
||||
this.Answers.push(new CheckGuess(Guess, Answer, this.CaseSensitive, PercentCorrect, Feedback));
|
||||
}
|
||||
|
||||
CheckAnswerArray.prototype.AddAnswer = CheckAnswerArray_AddAnswer;
|
||||
|
||||
function CheckAnswerArray_ClearAll(){
|
||||
this.Answers.length = 0;
|
||||
}
|
||||
|
||||
CheckAnswerArray.prototype.ClearAll = CheckAnswerArray_ClearAll;
|
||||
|
||||
function CheckAnswerArray_GetBestMatch(){
|
||||
//First check for a 100% match
|
||||
for (var i=0; i<this.Answers.length; i++){
|
||||
if (this.Answers[i].PercentMatch == 100){
|
||||
this.Feedback = this.Answers[i].Feedback;
|
||||
this.Score = this.Answers[i].PercentCorrect;
|
||||
this.CompleteMatch = true;
|
||||
this.MatchNum = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
//Now check for the best alternative match
|
||||
var PercentMatch = 0;
|
||||
var BestMatch = -1;
|
||||
for (i=0; i<this.Answers.length; i++){
|
||||
if ((this.Answers[i].PercentMatch > PercentMatch)&&(this.Answers[i].PercentCorrect == 100)){
|
||||
BestMatch = i;
|
||||
PercentMatch = this.Answers[i].PercentMatch;
|
||||
}
|
||||
}
|
||||
if (BestMatch > -1){
|
||||
this.Score = this.Answers[BestMatch].PercentMatch;
|
||||
this.Feedback = PartlyIncorrect + ' ';
|
||||
this.Feedback += '<span class="PartialAnswer">' + this.Answers[BestMatch].CorrectStart;
|
||||
this.Feedback += '<span class="Highlight">' + this.Answers[BestMatch].WrongMiddle + '</span>';
|
||||
this.Feedback += this.Answers[BestMatch].CorrectEnd + '</span>';
|
||||
this.Hint = '<span class="PartialAnswer">' + this.Answers[BestMatch].CorrectStart;
|
||||
this.Hint += '<span class="Highlight">' + this.Answers[BestMatch].Hint + '</span></span>';
|
||||
this.HintPenalty = this.Answers[BestMatch].HintPenalty;
|
||||
}
|
||||
else{
|
||||
this.Score = 0;
|
||||
this.Feedback = '';
|
||||
}
|
||||
}
|
||||
|
||||
CheckAnswerArray.prototype.GetBestMatch = CheckAnswerArray_GetBestMatch;
|
||||
|
||||
function CheckShortAnswer(QNum){
|
||||
//bail if question doesn't exist or exercise finished
|
||||
if ((State[QNum].length < 1)||(Finished == true)){return;}
|
||||
|
||||
//bail if question already complete
|
||||
if (State[QNum][0] > -1){return;}
|
||||
|
||||
//Get the guess (TrimString added to fix bug for 6.0.4.3)
|
||||
var G = TrimString(document.getElementById('Q_' + QNum + '_Guess').value);
|
||||
|
||||
//If no guess, bail with message; no penalty
|
||||
if (G.length < 1){
|
||||
ShowMessage(PleaseEnter);
|
||||
return;
|
||||
}
|
||||
|
||||
//Increment tries
|
||||
State[QNum][2]++;
|
||||
|
||||
//Create a check object
|
||||
var CA = new CheckAnswerArray(CaseSensitive);
|
||||
|
||||
CA.ClearAll();
|
||||
for (var ANum=0; ANum<I[QNum][3].length; ANum++){
|
||||
CA.AddAnswer(G, I[QNum][3][ANum][0], I[QNum][3][ANum][3], I[QNum][3][ANum][1]);
|
||||
}
|
||||
CA.GetBestMatch();
|
||||
|
||||
//Store any match in the state tracking field
|
||||
if (State[QNum][5].length > 0){State[QNum][5] += ' | ';}
|
||||
if (CA.MatchNum > -1){
|
||||
State[QNum][5] += String.fromCharCode(65+CA.MatchNum);
|
||||
}
|
||||
//Else store the student's answer
|
||||
else{
|
||||
State[QNum][5] += G;
|
||||
}
|
||||
|
||||
//Add the percent correct value for this answer to the Q State (works for all
|
||||
//situations, wrong or right)
|
||||
State[QNum][3] += CA.Score;
|
||||
|
||||
//Now branch, based on the nature of the match
|
||||
//Is it a complete match?
|
||||
if (CA.CompleteMatch == true){
|
||||
|
||||
//Is it with a wrong answer, or a right answer?
|
||||
if (CA.Score == 100){
|
||||
//It's right
|
||||
CalculateShortAnsQuestionScore(QNum);
|
||||
//Get correct answer list if required, assuming there are any other correct alternatives
|
||||
if (ShowAlsoCorrect == true){
|
||||
var AlsoCorrectList = GetCorrectList(QNum, G, false);
|
||||
if (AlsoCorrectList.length > 0){
|
||||
CA.Feedback += '<br />' + CorrectList + '<br />' + AlsoCorrectList;
|
||||
}
|
||||
}
|
||||
|
||||
//Get the overall score and add it to the feedback
|
||||
if (ContinuousScoring == true){
|
||||
CalculateOverallScore();
|
||||
CA.Feedback += '<br />' + YourScoreIs + ' ' + Score + '%.';
|
||||
WriteToInstructions(YourScoreIs + ' ' + Score + '%.');
|
||||
}
|
||||
ShowMessage(CA.Feedback);
|
||||
//Put the answer in
|
||||
ReplaceGuessBox(QNum, G);
|
||||
CheckFinished();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Otherwise, it's a match to a predicted wrong/partially correct, or a partial
|
||||
//match to a right answer
|
||||
if (CA.Feedback.length < 1){CA.Feedback = DefaultWrong;}
|
||||
//Remove any previous score unless exercise is finished (6.0.3.8+)
|
||||
if (Finished == false){
|
||||
WriteToInstructions(strInstructions);
|
||||
}
|
||||
ShowMessage(CA.Feedback);
|
||||
|
||||
//If necessary, switch a hybrid question to m/c
|
||||
if (State[QNum][2] >= HybridTries){
|
||||
SwitchHybridDisplay(QNum);
|
||||
}
|
||||
}
|
||||
|
||||
function CalculateShortAnsQuestionScore(QNum){
|
||||
var Tries = State[QNum][2] + State[QNum][4]; //include tries and hint penalties;
|
||||
var PercentCorrect = State[QNum][3];
|
||||
var HintPenalties = State[QNum][4];
|
||||
|
||||
//Make sure it's not already complete
|
||||
if (State[QNum][0] < 0){
|
||||
if (HintPenalties >= 1){
|
||||
State[QNum][0] = 0;
|
||||
}
|
||||
else{
|
||||
State[QNum][0] = (PercentCorrect/(100*Tries));
|
||||
}
|
||||
if (State[QNum][0] < 0){
|
||||
State[QNum][0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function SwitchHybridDisplay(QNum){
|
||||
if (document.getElementById('Q_' + QNum + '_Hybrid_MC') != null){
|
||||
document.getElementById('Q_' + QNum + '_Hybrid_MC').style.display = '';
|
||||
if (document.getElementById('Q_' + QNum + '_SA') != null){
|
||||
document.getElementById('Q_' + QNum + '_SA').style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function GetCorrectArray(QNum){
|
||||
var Result = new Array();
|
||||
for (var ANum=0; ANum<I[QNum][3].length; ANum++){
|
||||
if (I[QNum][3][ANum][2] == 1){ //This is an acceptable correct answer
|
||||
Result.push(I[QNum][3][ANum][0]);
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
function GetCorrectList(QNum, Answer, IncludeAnswer){
|
||||
var As = GetCorrectArray(QNum);
|
||||
var Result = '';
|
||||
for (var ANum=0; ANum<As.length; ANum++){
|
||||
if ((IncludeAnswer == true)||(As[ANum] != Answer)){
|
||||
Result += As[ANum] + '<br />';
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
function GetFirstCorrectAnswer(QNum){
|
||||
var As = GetCorrectArray(QNum);
|
||||
if (As.length > 0){
|
||||
return As[0];
|
||||
}
|
||||
else{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function ReplaceGuessBox(QNum, Ans){
|
||||
if (document.getElementById('Q_' + QNum + '_SA') != null){
|
||||
var El = document.getElementById('Q_' + QNum + '_SA');
|
||||
while (El.childNodes.length > 0){
|
||||
El.removeChild(El.childNodes[0]);
|
||||
}
|
||||
var A = document.createElement('span');
|
||||
A.setAttribute('class', 'Answer');
|
||||
var T = document.createTextNode(Ans);
|
||||
A.appendChild(T);
|
||||
El.appendChild(A);
|
||||
}
|
||||
}
|
||||
|
||||
[inclShowAnswer]
|
||||
|
||||
function ShowAnswers(QNum){
|
||||
//bail if question doesn't exist or exercise finished
|
||||
if ((State[QNum].length < 1)||(Finished == true)){return;}
|
||||
|
||||
//Get the answer list to display
|
||||
var Ans = GetCorrectList(QNum, '', false);
|
||||
Ans = CorrectList + '<br />' + Ans;
|
||||
|
||||
//Display feedback
|
||||
ShowMessage(Ans);
|
||||
|
||||
//Set the score for this question to 0 if no
|
||||
if (State[QNum][0] < 1){
|
||||
State[QNum][0] = 0;
|
||||
}
|
||||
|
||||
//Get the first correct answer
|
||||
var FirstAns = GetFirstCorrectAnswer(QNum);
|
||||
|
||||
//Replace the textbox
|
||||
ReplaceGuessBox(QNum, FirstAns);
|
||||
|
||||
//Remove any current score
|
||||
WriteToInstructions(strInstructions);
|
||||
|
||||
//This may be the last, so check finished status
|
||||
CheckFinished();
|
||||
}
|
||||
|
||||
[/inclShowAnswer]
|
||||
|
||||
[inclHint]
|
||||
|
||||
function ShowHint(QNum){
|
||||
//bail if question doesn't exist or exercise finished
|
||||
if ((State[QNum].length < 1)||(Finished == true)){return;}
|
||||
|
||||
//bail if question already complete
|
||||
if (State[QNum][0] > -1){return;}
|
||||
|
||||
//Get the guess
|
||||
var G = document.getElementById('Q_' + QNum + '_Guess').value;
|
||||
|
||||
//If no guess, give the first correct bit
|
||||
if (G.length < 1){
|
||||
var Ans = GetFirstCorrectAnswer(QNum);
|
||||
var Hint = Ans.charAt(0);
|
||||
ShowMessage(NextCorrect + '<br />' + Hint);
|
||||
//Penalty for hint
|
||||
State[QNum][4] += (1/Ans.length);
|
||||
return;
|
||||
}
|
||||
|
||||
//Increment tries
|
||||
State[QNum][2]++;
|
||||
|
||||
//Create a check object
|
||||
var CA = new CheckAnswerArray(CaseSensitive);
|
||||
|
||||
CA.ClearAll();
|
||||
for (var ANum=0; ANum<I[QNum][3].length; ANum++){
|
||||
//Use only correct answers
|
||||
if (I[QNum][3][ANum][2] == 1){
|
||||
CA.AddAnswer(G, I[QNum][3][ANum][0], I[QNum][3][ANum][3], I[QNum][3][ANum][1]);
|
||||
}
|
||||
}
|
||||
CA.GetBestMatch();
|
||||
if (CA.CompleteMatch == true){
|
||||
//It's right!
|
||||
CheckShortAnswer(QNum);
|
||||
return;
|
||||
}
|
||||
else{
|
||||
if (CA.Hint.length > 0){
|
||||
ShowMessage(NextCorrect + '<br />' + CA.Hint);
|
||||
State[QNum][4] += CA.HintPenalty;
|
||||
}
|
||||
else{
|
||||
ShowMessage(DefaultWrong + '<br />' + NextCorrect + '<br />' + GetFirstCorrectAnswer(QNum).charAt(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[/inclHint]
|
||||
@@ -1,18 +0,0 @@
|
||||
|
||||
//HOTPOTNET-RELATED CODE
|
||||
|
||||
var HPNStartTime = (new Date()).getTime();
|
||||
var SubmissionTimeout = 30000;
|
||||
var Detail = ''; //Global that is used to submit tracking data
|
||||
|
||||
function Finish(){
|
||||
//If there's a form, fill it out and submit it
|
||||
if (document.store != null){
|
||||
Frm = document.store;
|
||||
Frm.starttime.value = HPNStartTime;
|
||||
Frm.endtime.value = (new Date()).getTime();
|
||||
Frm.mark.value = Score;
|
||||
Frm.detail.value = Detail;
|
||||
Frm.submit();
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<div class="NavButtonBar" id="[strNavBarID]">
|
||||
|
||||
[inclBack]
|
||||
<button class="NavButton" onfocus="NavBtnOver(this)" onblur="NavBtnOut(this)" onmouseover="NavBtnOver(this)" onmouseout="NavBtnOut(this)" onmousedown="NavBtnDown(this)" onmouseup="NavBtnOut(this)" onclick="history.back(); return false;">[strBackCaption]</button>
|
||||
[/inclBack]
|
||||
|
||||
[inclContents]
|
||||
<button class="NavButton" onfocus="NavBtnOver(this)" onblur="NavBtnOut(this)" onmouseover="NavBtnOver(this)" onmouseout="NavBtnOut(this)" onmousedown="NavBtnDown(this)" onmouseup="NavBtnOut(this)" onclick="location='[strContentsURL]'; return false;"> [strContentsCaption] </button>
|
||||
[/inclContents]
|
||||
|
||||
[inclNextEx]
|
||||
<button class="NavButton" onfocus="NavBtnOver(this)" onblur="NavBtnOut(this)" onmouseover="NavBtnOver(this)" onmouseout="NavBtnOut(this)" onmousedown="NavBtnDown(this)" onmouseup="NavBtnOut(this)" onclick="location='[strNextExURL]'; return false;">[strNextExCaption]</button>
|
||||
[/inclNextEx]
|
||||
|
||||
</div>
|
||||
@@ -1,18 +0,0 @@
|
||||
|
||||
[QuickTime Player]<object classid="clsid:02bf25d5-8c17-4b23-bc80-d3488abddc6b" data="[strFilePath]" width="[strWidth]" height="[strHeight]" type="audio/quicktime"><param name="src" value="[strFilePath]" /> <param name="autoplay" value="false" /> <param name="controller" value="true" /> <object class="MediaPlayerNotForIE" type="video/quicktime" data="[strFilePath]" width="[strWidth]" height="[strHeight]"> <param name="src" value="[strFilePath]" /> <param name="autoplay" value="false" /> <param name="controller" value="true" /> [strContent]</object> </object>[/QuickTime Player]
|
||||
|
||||
[Windows Media Player]<object classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6" width="[strWidth]" height="[strHeight]">
|
||||
<param name="url" value="[strFilePath]" />
|
||||
<param name="autostart" value="false" />
|
||||
<param name="showcontrols" value="true" />[strContent]</object>
|
||||
[/Windows Media Player]
|
||||
|
||||
[Real Player]
|
||||
<object type="audio/x-pn-realaudio-plugin" classid="CLSID:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA" width="[strWidth]" height="[strHeight]">
|
||||
<param name="type" value="audio/x-pn-realaudio-plugin" />
|
||||
<param name="src" value="[strFilePath]" />
|
||||
<param name="autostart" value="false" />
|
||||
<param name="controls" value="[inclVideo]ImageWindow,[/inclVideo]ControlPanel" />
|
||||
[strContent]</object>[/Real Player]
|
||||
|
||||
[Flash Player]<object codebase="[strFilePath]" type="application/x-shockwave-flash" width="[strWidth]" height="[strHeight]" data="[strFilePath]"> <param name="movie" value="[strFilePath]" />[strContent]</object>[/Flash Player]
|
||||
@@ -1,42 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xml:lang="en"><head>
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
|
||||
<title>
|
||||
Page Title
|
||||
</title>
|
||||
|
||||
<!-- Made with executable version [strFullVersionInfo] -->
|
||||
|
||||
<!-- The following insertion allows you to add your own code directly to this head tag from the configuration screen -->
|
||||
|
||||
[strHeaderCode]
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
[strStyleSheet]
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body id="TheBody">
|
||||
|
||||
<div class="Titles">
|
||||
<h2 class="ExerciseTitle">Page Title</h2>
|
||||
<h3 class="ExerciseSubtitle">Page Subtitle</h3>
|
||||
</div>
|
||||
|
||||
<div id="MainDiv" class="StdDiv">
|
||||
|
||||
<p>Page content...</p>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,53 +0,0 @@
|
||||
|
||||
|
||||
//CODE FOR HANDLING SENDING OF RESULTS
|
||||
|
||||
var UserName = '';
|
||||
var StartTime = (new Date()).toLocaleString();
|
||||
|
||||
var ResultForm = '<html><body><form name="Results" action="[strFormMailURL]" method="post" enctype="x-www-form-encoded">';
|
||||
ResultForm += '<input type="hidden" name="recipient" value="[strEMail]"></input>';
|
||||
ResultForm += '<input type="hidden" name="subject" value="[strEscapedExerciseTitle]"></input>';
|
||||
ResultForm += '<input type="hidden" name="Exercise" value="[strEscapedExerciseTitle]"></input>';
|
||||
ResultForm += '<input type="hidden" name="realname" value=""></input>';
|
||||
ResultForm += '<input type="hidden" name="Score" value=""></input>';
|
||||
ResultForm += '<input type="hidden" name="Start_Time" value=""></input>';
|
||||
ResultForm += '<input type="hidden" name="End_Time" value=""></input>';
|
||||
ResultForm += '<input type="hidden" name="title" value="Thanks!"></input>';
|
||||
[inclPageBGColor]ResultForm += '<input type="hidden" name="bgcolor" value="[strPageBGColor]"></input>';[/inclPageBGColor]
|
||||
ResultForm += '<input type="hidden" name="text_color" value="[strTitleColor]"></input>';
|
||||
ResultForm += '<input type="hidden" name="sort" value="order:realname,Exercise,Score,Start_Time,End_Time"></input>';
|
||||
ResultForm += '</form></body></html>';
|
||||
|
||||
function GetUserName(){
|
||||
UserName = prompt('[strNamePlease]','');
|
||||
UserName += '';
|
||||
if ((UserName.substring(0,4) == 'null')||(UserName.length < 1)){
|
||||
UserName = prompt('[strNamePlease]','');
|
||||
UserName += '';
|
||||
if ((UserName.substring(0,4) == 'null')||(UserName.length < 1)){
|
||||
history.back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function SendResults(Score){
|
||||
var today = new Date;
|
||||
var NewName = '' + today.getTime();
|
||||
var NewWin = window.open('', NewName, 'toolbar=no,location=no,directories=no,status=no, menubar=no,scrollbars=yes,resizable=no,,width=400,height=300');
|
||||
|
||||
//If user has prevented popups, no way to proceed -- exit
|
||||
if (NewWin == null){
|
||||
return;
|
||||
}
|
||||
|
||||
NewWin.document.clear();
|
||||
NewWin.document.open();
|
||||
NewWin.document.write(ResultForm);
|
||||
NewWin.document.close();
|
||||
NewWin.document.Results.Score.value = Score + '%';
|
||||
NewWin.document.Results.realname.value = UserName;
|
||||
NewWin.document.Results.End_Time.value = (new Date()).toLocaleString();
|
||||
NewWin.document.Results.Start_Time.value = StartTime;
|
||||
NewWin.document.Results.submit();
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
|
||||
|
||||
//CODE FOR HANDLING DISPLAY OF POPUP FEEDBACK BOX
|
||||
|
||||
var topZ = 1000;
|
||||
|
||||
function ShowMessage(Feedback){
|
||||
var Output = Feedback + '<br /><br />';
|
||||
document.getElementById('FeedbackContent').innerHTML = Output;
|
||||
var FDiv = document.getElementById('FeedbackDiv');
|
||||
topZ++;
|
||||
FDiv.style.zIndex = topZ;
|
||||
FDiv.style.top = TopSettingWithScrollOffset(30) + 'px';
|
||||
|
||||
FDiv.style.display = 'block';
|
||||
|
||||
ShowElements(false, 'input');
|
||||
ShowElements(false, 'select');
|
||||
ShowElements(false, 'object');
|
||||
ShowElements(true, 'object', 'FeedbackContent');
|
||||
|
||||
//Focus the OK button
|
||||
setTimeout("document.getElementById('FeedbackOKButton').focus()", 50);
|
||||
|
||||
//[inclPreloadImages]
|
||||
// RefreshImages();
|
||||
//[/inclPreloadImages]
|
||||
}
|
||||
|
||||
function ShowElements(Show, TagName, ContainerToReverse){
|
||||
// added third argument to allow objects in the feedback box to appear
|
||||
//IE bug -- hide all the form elements that will show through the popup
|
||||
//FF on Mac bug : doesn't redisplay objects whose visibility is set to visible
|
||||
//unless the object's display property is changed
|
||||
|
||||
//get container object (by Id passed in, or use document otherwise)
|
||||
TopNode = document.getElementById(ContainerToReverse);
|
||||
var Els;
|
||||
if (TopNode != null) {
|
||||
Els = TopNode.getElementsByTagName(TagName);
|
||||
} else {
|
||||
Els = document.getElementsByTagName(TagName);
|
||||
}
|
||||
|
||||
for (var i=0; i<Els.length; i++){
|
||||
if (TagName == "object") {
|
||||
//manipulate object elements in all browsers
|
||||
if (Show == true){
|
||||
Els[i].style.visibility = 'visible';
|
||||
//get Mac FireFox to manipulate display, to force screen redraw
|
||||
if (C.mac && C.gecko) {Els[i].style.display = '';}
|
||||
}
|
||||
else{
|
||||
Els[i].style.visibility = 'hidden';
|
||||
if (C.mac && C.gecko) {Els[i].style.display = 'none';}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// tagName is either input or select (that is, Form Elements)
|
||||
// ie6 has a problem with Form elements, so manipulate those
|
||||
if (C.ie) {
|
||||
if (C.ieVer < 7) {
|
||||
if (Show == true){
|
||||
Els[i].style.visibility = 'visible';
|
||||
}
|
||||
else{
|
||||
Els[i].style.visibility = 'hidden';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function HideFeedback(){
|
||||
document.getElementById('FeedbackDiv').style.display = 'none';
|
||||
ShowElements(true, 'input');
|
||||
ShowElements(true, 'select');
|
||||
ShowElements(true, 'object');
|
||||
if (Finished == true){
|
||||
Finish();
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
|
||||
|
||||
//CODE FOR HANDLING TIMER
|
||||
//Timer code
|
||||
var Seconds = [intSeconds];
|
||||
var Interval = null;
|
||||
|
||||
function StartTimer(){
|
||||
Interval = window.setInterval('DownTime()',1000);
|
||||
document.getElementById('TimerText').style.display = 'inline';
|
||||
}
|
||||
|
||||
function DownTime(){
|
||||
var ss = Seconds % 60;
|
||||
if (ss<10){
|
||||
ss='0' + ss + '';
|
||||
}
|
||||
|
||||
var mm = Math.floor(Seconds / 60);
|
||||
|
||||
if (document.getElementById('Timer') == null){
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('TimerText').innerHTML = mm + ':' + ss;
|
||||
if (Seconds < 1){
|
||||
window.clearInterval(Interval);
|
||||
TimeOver = true;
|
||||
TimesUp();
|
||||
}
|
||||
Seconds--;
|
||||
}
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
//GENERAL UTILITY FUNCTIONS AND VARIABLES
|
||||
|
||||
//PAGE DIMENSION FUNCTIONS
|
||||
function PageDim(){
|
||||
//Get the page width and height
|
||||
this.W = 600;
|
||||
this.H = 400;
|
||||
this.W = document.getElementsByTagName('body')[0].clientWidth;
|
||||
this.H = document.getElementsByTagName('body')[0].clientHeight;
|
||||
}
|
||||
|
||||
var pg = null;
|
||||
|
||||
function GetPageXY(El) {
|
||||
var XY = {x: 0, y: 0};
|
||||
while(El){
|
||||
XY.x += El.offsetLeft;
|
||||
XY.y += El.offsetTop;
|
||||
El = El.offsetParent;
|
||||
}
|
||||
return XY;
|
||||
}
|
||||
|
||||
function GetScrollTop(){
|
||||
if (typeof(window.pageYOffset) == 'number'){
|
||||
return window.pageYOffset;
|
||||
}
|
||||
else{
|
||||
if ((document.body)&&(document.body.scrollTop)){
|
||||
return document.body.scrollTop;
|
||||
}
|
||||
else{
|
||||
if ((document.documentElement)&&(document.documentElement.scrollTop)){
|
||||
return document.documentElement.scrollTop;
|
||||
}
|
||||
else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function GetViewportHeight(){
|
||||
if (typeof window.innerHeight != 'undefined'){
|
||||
return window.innerHeight;
|
||||
}
|
||||
else{
|
||||
if (((typeof document.documentElement != 'undefined')&&(typeof document.documentElement.clientHeight !=
|
||||
'undefined'))&&(document.documentElement.clientHeight != 0)){
|
||||
return document.documentElement.clientHeight;
|
||||
}
|
||||
else{
|
||||
return document.getElementsByTagName('body')[0].clientHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function TopSettingWithScrollOffset(TopPercent){
|
||||
var T = Math.floor(GetViewportHeight() * (TopPercent/100));
|
||||
return GetScrollTop() + T;
|
||||
}
|
||||
|
||||
//CODE FOR AVOIDING LOSS OF DATA WHEN BACKSPACE KEY INVOKES history.back()
|
||||
var InTextBox = false;
|
||||
|
||||
function SuppressBackspace(e){
|
||||
if (InTextBox == true){return;}
|
||||
if (C.ie) {
|
||||
thisKey = window.event.keyCode;
|
||||
}
|
||||
else {
|
||||
thisKey = e.keyCode;
|
||||
}
|
||||
|
||||
var Suppress = false;
|
||||
|
||||
if (thisKey == 8) {
|
||||
Suppress = true;
|
||||
}
|
||||
|
||||
if (Suppress == true){
|
||||
if (C.ie){
|
||||
window.event.returnValue = false;
|
||||
window.event.cancelBubble = true;
|
||||
}
|
||||
else{
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (C.ie){
|
||||
document.attachEvent('onkeydown',SuppressBackspace);
|
||||
window.attachEvent('onkeydown',SuppressBackspace);
|
||||
}
|
||||
else{
|
||||
if (window.addEventListener){
|
||||
window.addEventListener('keypress',SuppressBackspace,false);
|
||||
}
|
||||
}
|
||||
|
||||
function ReduceItems(InArray, ReduceToSize){
|
||||
var ItemToDump=0;
|
||||
var j=0;
|
||||
while (InArray.length > ReduceToSize){
|
||||
ItemToDump = Math.floor(InArray.length*Math.random());
|
||||
InArray.splice(ItemToDump, 1);
|
||||
}
|
||||
}
|
||||
|
||||
function Shuffle(InArray){
|
||||
var Num;
|
||||
var Temp = new Array();
|
||||
var Len = InArray.length;
|
||||
|
||||
var j = Len;
|
||||
|
||||
for (var i=0; i<Len; i++){
|
||||
Temp[i] = InArray[i];
|
||||
}
|
||||
|
||||
for (i=0; i<Len; i++){
|
||||
Num = Math.floor(j * Math.random());
|
||||
InArray[i] = Temp[Num];
|
||||
|
||||
for (var k=Num; k < (j-1); k++) {
|
||||
Temp[k] = Temp[k+1];
|
||||
}
|
||||
j--;
|
||||
}
|
||||
return InArray;
|
||||
}
|
||||
|
||||
function WriteToInstructions(Feedback) {
|
||||
document.getElementById('InstructionsDiv').innerHTML = Feedback;
|
||||
[inclPreloadImages]
|
||||
RefreshImages();
|
||||
[/inclPreloadImages]
|
||||
}
|
||||
|
||||
|
||||
[inclPreloadImages]
|
||||
Imgs = new Array();
|
||||
|
||||
function PreloadImages(){
|
||||
var a = PreloadImages.arguments;
|
||||
for (var i=0; i<a.length; i++){
|
||||
Imgs[i] = new Image();
|
||||
Imgs[i].src = a[i];
|
||||
}
|
||||
}
|
||||
|
||||
function RefreshImages(){
|
||||
for (var i=0; i<document.images.length; i++){
|
||||
if (document.images[i].name.substring(0,6) != 'NavBar'){
|
||||
document.images[i].src = document.images[i].src;
|
||||
}
|
||||
}
|
||||
}
|
||||
[/inclPreloadImages]
|
||||
|
||||
function EscapeDoubleQuotes(InString){
|
||||
return InString.replace(/"/g, '"')
|
||||
}
|
||||
|
||||
function TrimString(InString){
|
||||
var x = 0;
|
||||
|
||||
if (InString.length != 0) {
|
||||
while ((InString.charAt(InString.length - 1) == '\u0020') || (InString.charAt(InString.length - 1) == '\u000A') || (InString.charAt(InString.length - 1) == '\u000D')){
|
||||
InString = InString.substring(0, InString.length - 1)
|
||||
}
|
||||
|
||||
while ((InString.charAt(0) == '\u0020') || (InString.charAt(0) == '\u000A') || (InString.charAt(0) == '\u000D')){
|
||||
InString = InString.substring(1, InString.length)
|
||||
}
|
||||
|
||||
while (InString.indexOf(' ') != -1) {
|
||||
x = InString.indexOf(' ')
|
||||
InString = InString.substring(0, x) + InString.substring(x+1, InString.length)
|
||||
}
|
||||
|
||||
return InString;
|
||||
}
|
||||
|
||||
else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function FindLongest(InArray){
|
||||
if (InArray.length < 1){return -1;}
|
||||
|
||||
var Longest = 0;
|
||||
for (var i=1; i<InArray.length; i++){
|
||||
if (InArray[i].length > InArray[Longest].length){
|
||||
Longest = i;
|
||||
}
|
||||
}
|
||||
return Longest;
|
||||
}
|
||||
|
||||
//UNICODE CHARACTER FUNCTIONS
|
||||
function IsCombiningDiacritic(CharNum){
|
||||
var Result = (((CharNum >= 0x0300)&&(CharNum <= 0x370))||((CharNum >= 0x20d0)&&(CharNum <= 0x20ff)));
|
||||
Result = Result || (((CharNum >= 0x3099)&&(CharNum <= 0x309a))||((CharNum >= 0xfe20)&&(CharNum <= 0xfe23)));
|
||||
return Result;
|
||||
}
|
||||
|
||||
function IsCJK(CharNum){
|
||||
return ((CharNum >= 0x3000)&&(CharNum < 0xd800));
|
||||
}
|
||||
|
||||
//SETUP FUNCTIONS
|
||||
//BROWSER WILL REFILL TEXT BOXES FROM CACHE IF NOT PREVENTED
|
||||
function ClearTextBoxes(){
|
||||
var NList = document.getElementsByTagName('input');
|
||||
for (var i=0; i<NList.length; i++){
|
||||
if ((NList[i].id.indexOf('Guess') > -1)||(NList[i].id.indexOf('Gap') > -1)){
|
||||
NList[i].value = '';
|
||||
}
|
||||
if (NList[i].id.indexOf('Chk') > -1){
|
||||
NList[i].checked = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//EXTENSION TO ARRAY OBJECT
|
||||
function Array_IndexOf(Input){
|
||||
var Result = -1;
|
||||
for (var i=0; i<this.length; i++){
|
||||
if (this[i] == Input){
|
||||
Result = i;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
Array.prototype.indexOf = Array_IndexOf;
|
||||
|
||||
//IE HAS RENDERING BUG WITH BOTTOM NAVBAR
|
||||
function RemoveBottomNavBarForIE(){
|
||||
if ((C.ie)&&(document.getElementById('Reading') != null)){
|
||||
if (document.getElementById('BottomNavBar') != null){
|
||||
document.getElementById('TheBody').removeChild(document.getElementById('BottomNavBar'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xml:lang="en"><head>
|
||||
|
||||
[strDublinCoreMetadata]
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
|
||||
<title>
|
||||
[strPlainTitle]
|
||||
</title>
|
||||
|
||||
<!-- Made with executable version [strFullVersionInfo] -->
|
||||
|
||||
<!-- The following insertion allows you to add your own code directly to this head tag from the configuration screen -->
|
||||
|
||||
[strHeaderCode]
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
[strStyleSheet]
|
||||
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
//<![CDATA[
|
||||
|
||||
<!--
|
||||
|
||||
[inclScorm1.2]
|
||||
[strJSScorm_1_2]
|
||||
[/inclScorm1.2]
|
||||
|
||||
[strJSBrowserCheck]
|
||||
|
||||
[strJSButtons]
|
||||
|
||||
[strJSShowMessage]
|
||||
|
||||
[strJSUtilities]
|
||||
|
||||
[strJSHotPotNet]
|
||||
|
||||
[strJSJCloze6]
|
||||
|
||||
[inclTimer]
|
||||
[strJSTimer]
|
||||
[/inclTimer]
|
||||
|
||||
[inclSendResults]
|
||||
[strJSSendResults]
|
||||
[/inclSendResults]
|
||||
|
||||
//-->
|
||||
|
||||
//]]>
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="StartUp()" id="TheBody" [inclScorm1.2]onunload="CheckLMSFinish()"[/inclScorm1.2]>
|
||||
|
||||
<!-- BeginTopNavButtons -->
|
||||
|
||||
[inclNavButtons]
|
||||
[strTopNavBar]
|
||||
[/inclNavButtons]
|
||||
|
||||
<!-- EndTopNavButtons -->
|
||||
|
||||
<div class="Titles">
|
||||
<h2 class="ExerciseTitle">[strExerciseTitle]</h2>
|
||||
[inclExerciseSubtitle]
|
||||
<h3 class="ExerciseSubtitle">[strExerciseSubtitle]</h3>
|
||||
[/inclExerciseSubtitle]
|
||||
[inclTimer]
|
||||
<div id="Timer"><span id="TimerText"> </span></div>
|
||||
[/inclTimer]
|
||||
|
||||
</div>
|
||||
|
||||
<div id="InstructionsDiv" class="StdDiv">
|
||||
<div id="Instructions">[strInstructions]</div>
|
||||
</div>
|
||||
|
||||
[inclReading]
|
||||
<div class="LeftContainer">
|
||||
|
||||
<div id="Reading" class="StdDiv">
|
||||
|
||||
<div id="ReadingDiv">
|
||||
[strReadingText]
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="RightContainer">
|
||||
[/inclReading]
|
||||
|
||||
[inclWordList]
|
||||
<div id="WordsDiv" class="StdDiv">
|
||||
<span id="WordList" class="ClozeWordList">[strWordList]</span>
|
||||
</div>
|
||||
[/inclWordList]
|
||||
|
||||
<div id="MainDiv" class="StdDiv">
|
||||
|
||||
<!-- These top buttons hidden; reveal if required -->
|
||||
<!--
|
||||
<button id="CheckButton1" class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="CheckAnswers()"> [strCheckCaption] </button>
|
||||
|
||||
[inclHint]
|
||||
<button class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="ShowHint()"> [strHintCaption] </button>
|
||||
[/inclHint]
|
||||
|
||||
-->
|
||||
|
||||
<div id="ClozeDiv">
|
||||
<form id="Cloze" method="post" action="" onsubmit="return false;">
|
||||
<div class="ClozeBody">
|
||||
[strClozeBody]
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
[inclKeypad]
|
||||
<div class="Keypad" id="CharacterKeypad">
|
||||
[strKeypad]
|
||||
</div>
|
||||
[/inclKeypad]
|
||||
|
||||
<button id="CheckButton2" class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="CheckAnswers()"> [strCheckCaption] </button>
|
||||
|
||||
[inclHint]
|
||||
<button class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="ShowHint()"> [strHintCaption] </button>
|
||||
[/inclHint]
|
||||
|
||||
</div>
|
||||
|
||||
[inclReading]
|
||||
</div>
|
||||
[/inclReading]
|
||||
|
||||
<div class="Feedback" id="FeedbackDiv">
|
||||
<div class="FeedbackText" id="FeedbackContent"></div>
|
||||
<button id="FeedbackOKButton" class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="HideFeedback(); return false;"> [strOKCaption] </button>
|
||||
</div>
|
||||
|
||||
<!-- BeginBottomNavButtons -->
|
||||
|
||||
[inclNavButtons]
|
||||
[strBottomNavBar]
|
||||
[/inclNavButtons]
|
||||
|
||||
<!-- EndBottomNavButtons -->
|
||||
|
||||
<!-- BeginSubmissionForm -->
|
||||
|
||||
<!-- EndSubmissionForm -->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,390 +0,0 @@
|
||||
|
||||
[inclScorm1.2]
|
||||
//JCLOZE-SPECIFIC SCORM-RELATED JAVASCRIPT CODE
|
||||
|
||||
function SetScormScore(){
|
||||
//Reports the current score and any other information back to the LMS
|
||||
if (API != null){
|
||||
API.LMSSetValue('cmi.core.score.raw', Score);
|
||||
//Now send detailed reports about each item
|
||||
for (var i=0; i<State.length; i++){
|
||||
var ThisItemGuesses = '';
|
||||
var GapLabel = 'Gap_' + (i+1).toString();
|
||||
var ThisItemScore = Math.floor(State[i].ItemScore * 100) + '';
|
||||
API.LMSSetValue('cmi.objectives.' + i + '.id', 'obj'+GapLabel);
|
||||
API.LMSSetValue('cmi.interactions.' + i + '.id', 'int'+GapLabel);
|
||||
API.LMSSetValue('cmi.objectives.' + i + '.score.raw', ThisItemScore);
|
||||
API.LMSSetValue('cmi.objectives.' + i + '.score.min', '0');
|
||||
API.LMSSetValue('cmi.objectives.' + i + '.score.max', '100');
|
||||
if (State[i].AnsweredCorrectly == true){
|
||||
API.LMSSetValue('cmi.objectives.' + i + '.status', 'completed');
|
||||
}
|
||||
else{
|
||||
API.LMSSetValue('cmi.objectives.' + i + '.status', 'incomplete');
|
||||
}
|
||||
for (var j=0; j<State[i].Guesses.length; j++){
|
||||
if (j>0){ThisItemGuesses += ' | ';}
|
||||
ThisItemGuesses += State[i].Guesses[j];
|
||||
}
|
||||
API.LMSSetValue('cmi.interactions.' + i + '.type', 'fill-in');
|
||||
API.LMSSetValue('cmi.interactions.' + i + '.student_response', ThisItemGuesses);
|
||||
}
|
||||
API.LMSCommit('');
|
||||
}
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
|
||||
//JCLOZE CORE JAVASCRIPT CODE
|
||||
|
||||
function ItemState(){
|
||||
this.ClueGiven = false;
|
||||
this.HintsAndChecks = 0;
|
||||
this.MatchedAnswerLength = 0;
|
||||
this.ItemScore = 0;
|
||||
this.AnsweredCorrectly = false;
|
||||
this.Guesses = new Array();
|
||||
return this;
|
||||
}
|
||||
|
||||
var Feedback = '';
|
||||
var Correct = '[strCorrect]';
|
||||
var Incorrect = '[strIncorrect]';
|
||||
var GiveHint = '[strGiveHint]';
|
||||
var CaseSensitive = [boolCaseSensitive];
|
||||
var YourScoreIs = '[strYourScoreIs]';
|
||||
var Finished = false;
|
||||
var Locked = false;
|
||||
var Score = 0;
|
||||
var CurrentWord = 0;
|
||||
var Guesses = '';
|
||||
var TimeOver = false;
|
||||
|
||||
I = new Array();
|
||||
[strItemArray]
|
||||
|
||||
State = new Array();
|
||||
|
||||
function StartUp(){
|
||||
RemoveBottomNavBarForIE();
|
||||
//Show a keypad if there is one (added bugfix for 6.0.4.12)
|
||||
if (document.getElementById('CharacterKeypad') != null){
|
||||
document.getElementById('CharacterKeypad').style.display = 'block';
|
||||
}
|
||||
|
||||
[inclScorm1.2]
|
||||
ScormStartUp();
|
||||
[/inclScorm1.2]
|
||||
|
||||
[inclSendResults]
|
||||
GetUserName();
|
||||
[/inclSendResults]
|
||||
|
||||
[inclPreloadImages]
|
||||
PreloadImages([PreloadImageList]);
|
||||
[/inclPreloadImages]
|
||||
|
||||
var i = 0;
|
||||
|
||||
State.length = 0;
|
||||
for (i=0; i<I.length; i++){
|
||||
State[i] = new ItemState();
|
||||
}
|
||||
|
||||
ClearTextBoxes();
|
||||
|
||||
[inclTimer]
|
||||
StartTimer();
|
||||
[/inclTimer]
|
||||
|
||||
}
|
||||
|
||||
function ShowClue(ItemNum){
|
||||
if (Locked == true){return;}
|
||||
State[ItemNum].ClueGiven = true;
|
||||
ShowMessage(I[ItemNum][2]);
|
||||
}
|
||||
|
||||
function SaveCurrentAnswers(){
|
||||
var Ans = '';
|
||||
for (var i=0; i<I.length; i++){
|
||||
Ans = GetGapValue(i);
|
||||
if ((Ans.length > 0)&&(Ans != State[i].Guesses[State[i].Guesses.length-1])){
|
||||
State[i].Guesses[State[i].Guesses.length] = Ans;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function CompileGuesses(){
|
||||
var F = document.getElementById('store');
|
||||
if (F != null){
|
||||
var Temp = '<?xml version="1.0"?><hpnetresult><fields>';
|
||||
var GapLabel = '';
|
||||
for (var i=0; i<State.length; i++){
|
||||
GapLabel = 'Gap ' + (i+1).toString();
|
||||
Temp += '<field><fieldname>' + GapLabel + '</fieldname>';
|
||||
Temp += '<fieldtype>student-responses</fieldtype><fieldlabel>' + GapLabel + '</fieldlabel>';
|
||||
Temp += '<fieldlabelid>JClozeStudentResponses</fieldlabelid><fielddata>';
|
||||
for (var j=0; j<State[i].Guesses.length; j++){
|
||||
if (j>0){Temp += '| ';}
|
||||
Temp += State[i].Guesses[j] + ' ';
|
||||
}
|
||||
Temp += '</fielddata></field>';
|
||||
}
|
||||
Temp += '</fields></hpnetresult>';
|
||||
Detail = Temp;
|
||||
}
|
||||
}
|
||||
|
||||
function CheckAnswers(){
|
||||
if (Locked == true){return;}
|
||||
SaveCurrentAnswers();
|
||||
var AllCorrect = true;
|
||||
|
||||
//Check each answer
|
||||
for (var i = 0; i<I.length; i++){
|
||||
|
||||
if (State[i].AnsweredCorrectly == false){
|
||||
//If it's right, calculate its score
|
||||
if (CheckAnswer(i, true) > -1){
|
||||
var TotalChars = GetGapValue(i).length;
|
||||
State[i].ItemScore = (TotalChars-State[i].HintsAndChecks)/TotalChars;
|
||||
if (State[i].ClueGiven == true){State[i].ItemScore /= 2;}
|
||||
if (State[i].ItemScore <0 ){State[i].ItemScore = 0;}
|
||||
State[i].AnsweredCorrectly = true;
|
||||
//Drop the correct answer into the page, replacing the text box
|
||||
SetCorrectAnswer(i, GetGapValue(i));
|
||||
}
|
||||
else{
|
||||
//Otherwise, increment the hints for this item, as a penalty
|
||||
State[i].HintsAndChecks++;
|
||||
|
||||
//then set the flag
|
||||
AllCorrect = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Calculate the total score
|
||||
var TotalScore = 0;
|
||||
for (i=0; i<State.length; i++){
|
||||
TotalScore += State[i].ItemScore;
|
||||
}
|
||||
TotalScore = Math.floor((TotalScore * 100)/I.length);
|
||||
|
||||
//Compile the output
|
||||
Output = '';
|
||||
|
||||
if (AllCorrect == true){
|
||||
Output = Correct + '<br />';
|
||||
}
|
||||
|
||||
Output += YourScoreIs + ' ' + TotalScore + '%.<br />';
|
||||
if (AllCorrect == false){
|
||||
Output += '<br />' + Incorrect;
|
||||
}
|
||||
ShowMessage(Output);
|
||||
setTimeout('WriteToInstructions(Output)', 50);
|
||||
|
||||
Score = TotalScore;
|
||||
CompileGuesses();
|
||||
|
||||
if ((AllCorrect == true)||(Finished == true)){
|
||||
|
||||
[inclSendResults]
|
||||
setTimeout('SendResults(' + TotalScore + ')', 50);
|
||||
[/inclSendResults]
|
||||
[inclTimer]
|
||||
window.clearInterval(Interval);
|
||||
[/inclTimer]
|
||||
TimeOver = true;
|
||||
Locked = true;
|
||||
Finished = true;
|
||||
setTimeout('Finish()', SubmissionTimeout);
|
||||
}
|
||||
[inclScorm1.2]
|
||||
if (AllCorrect == true){
|
||||
SetScormComplete();
|
||||
}
|
||||
else{
|
||||
SetScormIncomplete();
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
}
|
||||
|
||||
function TrackFocus(BoxNumber){
|
||||
CurrentWord = BoxNumber;
|
||||
InTextBox = true;
|
||||
}
|
||||
|
||||
function LeaveGap(){
|
||||
InTextBox = false;
|
||||
}
|
||||
|
||||
function CheckBeginning(Guess, Answer){
|
||||
var OutString = '';
|
||||
var i = 0;
|
||||
var UpperGuess = '';
|
||||
var UpperAnswer = '';
|
||||
|
||||
if (CaseSensitive == false) {
|
||||
UpperGuess = Guess.toUpperCase();
|
||||
UpperAnswer = Answer.toUpperCase();
|
||||
}
|
||||
else {
|
||||
UpperGuess = Guess;
|
||||
UpperAnswer = Answer;
|
||||
}
|
||||
|
||||
while (UpperGuess.charAt(i) == UpperAnswer.charAt(i)) {
|
||||
OutString += Guess.charAt(i);
|
||||
i++;
|
||||
}
|
||||
OutString += Answer.charAt(i);
|
||||
return OutString;
|
||||
}
|
||||
|
||||
function GetGapValue(GNum){
|
||||
var RetVal = '';
|
||||
if ((GNum<0)||(GNum>=I.length)){return RetVal;}
|
||||
if (document.getElementById('Gap' + GNum) != null){
|
||||
RetVal = document.getElementById('Gap' + GNum).value;
|
||||
RetVal = TrimString(RetVal);
|
||||
}
|
||||
else{
|
||||
RetVal = State[GNum].Guesses[State[GNum].Guesses.length-1];
|
||||
}
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
function SetGapValue(GNum, Val){
|
||||
if ((GNum<0)||(GNum>=I.length)){return;}
|
||||
if (document.getElementById('Gap' + GNum) != null){
|
||||
document.getElementById('Gap' + GNum).value = Val;
|
||||
document.getElementById('Gap' + GNum).focus();
|
||||
}
|
||||
}
|
||||
|
||||
function SetCorrectAnswer(GNum, Val){
|
||||
if ((GNum<0)||(GNum>=I.length)){return;}
|
||||
if (document.getElementById('GapSpan' + GNum) != null){
|
||||
document.getElementById('GapSpan' + GNum).innerHTML = Val;
|
||||
}
|
||||
}
|
||||
|
||||
function FindCurrent() {
|
||||
var x = 0;
|
||||
FoundCurrent = -1;
|
||||
|
||||
//Test the current word:
|
||||
//If its state is not set to already correct, check the word.
|
||||
if (State[CurrentWord].AnsweredCorrectly == false){
|
||||
if (CheckAnswer(CurrentWord, false) < 0){
|
||||
return CurrentWord;
|
||||
}
|
||||
}
|
||||
|
||||
x=CurrentWord + 1;
|
||||
while (x<I.length){
|
||||
if (State[x].AnsweredCorrectly == false){
|
||||
if (CheckAnswer(x, false) < 0){
|
||||
return x;
|
||||
}
|
||||
}
|
||||
x++;
|
||||
}
|
||||
|
||||
x = 0;
|
||||
while (x<CurrentWord){
|
||||
if (State[x].AnsweredCorrectly == false){
|
||||
if (CheckAnswer(x, false) < 0){
|
||||
return x;
|
||||
}
|
||||
}
|
||||
x++;
|
||||
}
|
||||
return FoundCurrent;
|
||||
}
|
||||
|
||||
function CheckAnswer(GapNum, MarkAnswer){
|
||||
var Guess = GetGapValue(GapNum);
|
||||
var UpperGuess = '';
|
||||
var UpperAnswer = '';
|
||||
if (CaseSensitive == false){
|
||||
UpperGuess = Guess.toUpperCase();
|
||||
}
|
||||
else{
|
||||
UpperGuess = Guess;
|
||||
}
|
||||
var Match = -1;
|
||||
for (var i = 0; i<I[GapNum][1].length; i++){
|
||||
if (CaseSensitive == false){
|
||||
UpperAnswer = I[GapNum][1][i][0].toUpperCase();
|
||||
}
|
||||
else{
|
||||
UpperAnswer = I[GapNum][1][i][0];
|
||||
}
|
||||
if (TrimString(UpperGuess) == UpperAnswer){
|
||||
Match = i;
|
||||
if (MarkAnswer == true){
|
||||
State[GapNum].AnsweredCorrectly = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Match;
|
||||
}
|
||||
|
||||
function GetHint(GapNum){
|
||||
Guess = GetGapValue(GapNum);
|
||||
|
||||
if (CheckAnswer(GapNum, false) > -1){return ''}
|
||||
RightBits = new Array();
|
||||
for (var i=0; i<I[GapNum][1].length; i++){
|
||||
RightBits[i] = CheckBeginning(Guess, I[GapNum][1][i][0]);
|
||||
}
|
||||
var RightOne = FindLongest(RightBits);
|
||||
var Result = I[GapNum][1][RightOne][0].substring(0,RightBits[RightOne].length);
|
||||
//Add another char if the last one is a space
|
||||
if (Result.charAt(Result.length-1) == ' '){
|
||||
Result = I[GapNum][1][RightOne][0].substring(0,RightBits[RightOne].length+1);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
function ShowHint(){
|
||||
if (document.getElementById('FeedbackDiv').style.display == 'block'){return;}
|
||||
if (Locked == true){return;}
|
||||
var CurrGap = FindCurrent();
|
||||
if (CurrGap < 0){return;}
|
||||
|
||||
var HintString = GetHint(CurrGap);
|
||||
|
||||
if (HintString.length > 0){
|
||||
SetGapValue(CurrGap, HintString);
|
||||
State[CurrGap].HintsAndChecks += 1;
|
||||
}
|
||||
ShowMessage(GiveHint);
|
||||
}
|
||||
|
||||
function TypeChars(Chars){
|
||||
var CurrGap = FindCurrent();
|
||||
if (CurrGap < 0){return;}
|
||||
if (document.getElementById('Gap' + CurrGap) != null){
|
||||
SetGapValue(CurrGap, document.getElementById('Gap' + CurrGap).value + Chars);
|
||||
}
|
||||
}
|
||||
|
||||
[inclTimer]
|
||||
function TimesUp() {
|
||||
document.getElementById('Timer').innerHTML = '[strTimesUp]';
|
||||
[inclPreloadImages]
|
||||
RefreshImages();
|
||||
[/inclPreloadImages]
|
||||
TimeOver = true;
|
||||
Finished = true;
|
||||
CheckAnswers();
|
||||
Locked = true;
|
||||
[inclScorm1.2]
|
||||
SetScormTimedOut();
|
||||
[/inclScorm1.2]
|
||||
}
|
||||
[/inclTimer]
|
||||
@@ -1,191 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xml:lang="en"><head>
|
||||
|
||||
[strDublinCoreMetadata]
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
|
||||
<title>
|
||||
[strPlainTitle]
|
||||
</title>
|
||||
|
||||
<!-- Made with executable version [strFullVersionInfo] -->
|
||||
|
||||
<!-- The following insertion allows you to add your own code directly to this head tag from the configuration screen -->
|
||||
|
||||
[strHeaderCode]
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
[strStyleSheet]
|
||||
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
//<![CDATA[
|
||||
|
||||
<!--
|
||||
|
||||
[inclScorm1.2]
|
||||
[strJSScorm_1_2]
|
||||
[/inclScorm1.2]
|
||||
|
||||
[strJSBrowserCheck]
|
||||
|
||||
[strJSButtons]
|
||||
|
||||
[strJSShowMessage]
|
||||
|
||||
[strJSUtilities]
|
||||
|
||||
[strJSHotPotNet]
|
||||
|
||||
[strJSJCross6]
|
||||
|
||||
[inclTimer]
|
||||
[strJSTimer]
|
||||
[/inclTimer]
|
||||
|
||||
[inclSendResults]
|
||||
[strJSSendResults]
|
||||
[/inclSendResults]
|
||||
|
||||
//-->
|
||||
|
||||
//]]>
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="StartUp()" id="TheBody" [inclScorm1.2]onunload="CheckLMSFinish()"[/inclScorm1.2]>
|
||||
|
||||
<!-- BeginTopNavButtons -->
|
||||
|
||||
[inclNavButtons]
|
||||
[strTopNavBar]
|
||||
[/inclNavButtons]
|
||||
|
||||
<!-- EndTopNavButtons -->
|
||||
|
||||
<div class="Titles">
|
||||
<h2 class="ExerciseTitle">[strExerciseTitle]</h2>
|
||||
[inclExerciseSubtitle]
|
||||
<h3 class="ExerciseSubtitle">[strExerciseSubtitle]</h3>
|
||||
[/inclExerciseSubtitle]
|
||||
[inclTimer]
|
||||
<div id="Timer"><span id="TimerText"> </span></div>
|
||||
[/inclTimer]
|
||||
|
||||
</div>
|
||||
|
||||
<div id="InstructionsDiv" class="StdDiv">
|
||||
<div id="Instructions">[strInstructions]</div>
|
||||
</div>
|
||||
|
||||
[inclReading]
|
||||
<div class="LeftContainer">
|
||||
|
||||
<div id="Reading" class="StdDiv">
|
||||
|
||||
<div id="ReadingDiv">
|
||||
[strReadingText]
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="RightContainer">
|
||||
[/inclReading]
|
||||
|
||||
<div id="MainDiv" class="StdDiv">
|
||||
|
||||
[inclKeypad]
|
||||
<div class="Keypad" id="CharacterKeypad" style="float: left;">
|
||||
[strKeypad]
|
||||
</div>
|
||||
[/inclKeypad]
|
||||
|
||||
<div id="ClueEntry">
|
||||
|
||||
</div>
|
||||
|
||||
<!-- This top button is hidden; uncomment it to reveal it. -->
|
||||
<!--
|
||||
<button id="CheckButton1" class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="CheckAnswers()"> [strCheckCaption] </button>
|
||||
|
||||
-->
|
||||
|
||||
<table class="CrosswordGrid">
|
||||
<tbody>
|
||||
|
||||
[strGridBody]
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<button id="CheckButton2" class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="CheckAnswers()"> [strCheckCaption] </button>
|
||||
|
||||
<table id="Clues"[ShowHideClueList]>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<table class="ClueList">
|
||||
<tbody id="CluesAcross">
|
||||
<tr><td colspan="2"><h3 class="ExerciseSubtitle" id="CluesAcrossLabel">[strCluesAcrossLabel]</h3></td></tr>
|
||||
|
||||
[strCluesAcross]
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
|
||||
<td>
|
||||
|
||||
<table class="ClueList">
|
||||
<tbody id="CluesDown">
|
||||
<tr><td colspan="2"><h3 class="ExerciseSubtitle" id="CluesDownLabel">[strCluesDownLabel]</h3></td></tr>
|
||||
|
||||
[strCluesDown]
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
[inclReading]
|
||||
</div>
|
||||
[/inclReading]
|
||||
|
||||
<div class="Feedback" id="FeedbackDiv">
|
||||
<div class="FeedbackText" id="FeedbackContent"></div>
|
||||
<button id="FeedbackOKButton" class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="HideFeedback(); return false;"> [strOKCaption] </button>
|
||||
</div>
|
||||
|
||||
<!-- BeginBottomNavButtons -->
|
||||
|
||||
[inclNavButtons]
|
||||
[strBottomNavBar]
|
||||
[/inclNavButtons]
|
||||
|
||||
<!-- EndBottomNavButtons -->
|
||||
|
||||
<!-- BeginSubmissionForm -->
|
||||
|
||||
<!-- EndSubmissionForm -->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,373 +0,0 @@
|
||||
[inclScorm1.2]
|
||||
//JCROSS-SPECIFIC SCORM-RELATED JAVASCRIPT CODE
|
||||
|
||||
function SetScormScore(){
|
||||
//Reports the current score and any other information back to the LMS
|
||||
if (API != null){
|
||||
API.LMSSetValue('cmi.core.score.raw', Score);
|
||||
|
||||
//Now send a detailed reports on the item
|
||||
var ItemLabel = 'Crossword';
|
||||
API.LMSSetValue('cmi.objectives.0.id', 'obj'+ItemLabel);
|
||||
API.LMSSetValue('cmi.interactions.0.id', 'int'+ItemLabel);
|
||||
if (Finished == true){
|
||||
API.LMSSetValue('cmi.objectives.0.status', 'completed');
|
||||
}
|
||||
else{
|
||||
API.LMSSetValue('cmi.objectives.0.status', 'incomplete');
|
||||
}
|
||||
API.LMSSetValue('cmi.objectives.0.score.min', '0');
|
||||
API.LMSSetValue('cmi.objectives.0.score.max', '100');
|
||||
API.LMSSetValue('cmi.objectives.0.score.raw', Score);
|
||||
//We're not sending any student response data, so we can set this to a non-standard value
|
||||
API.LMSSetValue('cmi.interactions.0.type', 'crossword');
|
||||
|
||||
API.LMSCommit('');
|
||||
}
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
|
||||
//JCROSS CORE JAVASCRIPT CODE
|
||||
|
||||
var InGap = false;
|
||||
var CurrentBox = null;
|
||||
var Feedback = '';
|
||||
var AcrossCaption = '';
|
||||
var DownCaption = '';
|
||||
var Correct = '[strCorrect]';
|
||||
var Incorrect = '[strIncorrect]';
|
||||
var GiveHint = '[strGiveHint]';
|
||||
var YourScoreIs = '[strYourScoreIs]';
|
||||
var BuiltGrid = '';
|
||||
var BuiltExercise = '';
|
||||
var Penalties = 0;
|
||||
var Score = 0;
|
||||
var InTextBox = false;
|
||||
var Locked = false;
|
||||
var TimeOver = false;
|
||||
var CaseSensitive = [boolCaseSensitive];
|
||||
|
||||
var InputStuff = '<form method="post" action="" onsubmit="return false;"><span class="ClueNum">[strClueNum]: </span>';
|
||||
InputStuff += '[strClue] <input onfocus="CurrentBox=this;InTextBox=true;" onblur="InTextBox=false;" id="[strBoxId]" type="edit" size="[strEditSize]" maxlength="[strMaxLength]"></input>';
|
||||
InputStuff += '<button class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="EnterGuess([strParams])">[strEnterCaption]</button>';
|
||||
InputStuff += '[inclHint]<button class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="ShowHint([strParams])">[strHintCaption]</button>[/inclHint]';
|
||||
InputStuff += '</form>';
|
||||
|
||||
var CurrBoxElement = null;
|
||||
var Finished = false;
|
||||
|
||||
function StartUp(){
|
||||
RemoveBottomNavBarForIE();
|
||||
//Show a keypad if there is one (added bugfix for 6.0.4.12)
|
||||
if (document.getElementById('CharacterKeypad') != null){
|
||||
document.getElementById('CharacterKeypad').style.display = 'block';
|
||||
}
|
||||
[inclScorm1.2]
|
||||
ScormStartUp();
|
||||
[/inclScorm1.2]
|
||||
|
||||
AcrossCaption = document.getElementById('CluesAcrossLabel').innerHTML;
|
||||
DownCaption = document.getElementById('CluesDownLabel').innerHTML;
|
||||
[inclSendResults]
|
||||
GetUserName();
|
||||
[/inclSendResults]
|
||||
|
||||
[inclPreloadImages]
|
||||
PreloadImages([PreloadImageList]);
|
||||
[/inclPreloadImages]
|
||||
|
||||
[inclTimer]
|
||||
StartTimer();
|
||||
[/inclTimer]
|
||||
|
||||
}
|
||||
|
||||
function GetAnswerLength(Across,x,y){
|
||||
Result = 0;
|
||||
if (Across == false){
|
||||
while ((x<L.length)&&(L[x][y].length > 0)){
|
||||
Result += L[x][y].length;
|
||||
x++;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
else{
|
||||
while ((y<L[x].length)&&(L[x][y].length > 0)){
|
||||
Result += L[x][y].length;
|
||||
y++;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
|
||||
function GetEditSize(Across,x,y){
|
||||
var Len = GetAnswerLength(Across,x,y);
|
||||
if (IsCJK(L[x][y].charCodeAt(0))){
|
||||
Len *= 2;
|
||||
}
|
||||
return Len;
|
||||
}
|
||||
|
||||
function ShowClue(ClueNum,x,y){
|
||||
var Result = '';
|
||||
var Temp;
|
||||
var strParams;
|
||||
var Clue = document.getElementById('Clue_A_' + ClueNum);
|
||||
if (Clue != null){
|
||||
Temp = InputStuff.replace(/\[ClueNum\]/g, ClueNum);
|
||||
Temp = Temp.replace(/\[strClueNum\]/g, AcrossCaption + ' ' + ClueNum);
|
||||
strParams = 'true,' + ClueNum + ',' + x + ',' + y + ',\'[strBoxId]\'';
|
||||
Temp = Temp.replace(/\[strParams\]/g, strParams);
|
||||
Temp = Temp.replace(/\[strBoxId\]/g, 'GA_' + ClueNum + '_' + x + '_' + y);
|
||||
Temp = Temp.replace(/\[strEditSize\]/g, GetEditSize(true,x,y));
|
||||
Temp = Temp.replace(/\[strMaxLength\]/g, GetAnswerLength(true,x,y));
|
||||
Temp = Temp.replace(/\[strClue\]/g, Clue.innerHTML, Temp);
|
||||
Result += Temp;
|
||||
}
|
||||
Clue = document.getElementById('Clue_D_' + ClueNum);
|
||||
if (Clue != null){
|
||||
Temp = InputStuff.replace(/\[ClueNum\]/g, ClueNum);
|
||||
Temp = Temp.replace(/\[strClueNum\]/g, DownCaption + ' ' + ClueNum);
|
||||
strParams = 'false,' + ClueNum + ',' + x + ',' + y + ',\'[strBoxId]\'';
|
||||
Temp = Temp.replace(/\[strParams\]/g, strParams);
|
||||
Temp = Temp.replace(/\[strBoxId\]/g, 'GD_' + ClueNum + '_' + x + '_' + y);
|
||||
Temp = Temp.replace(/\[strEditSize\]/g, GetAnswerLength(false,x,y));
|
||||
Temp = Temp.replace(/\[strClue\]/g, Clue.innerHTML, Temp);
|
||||
Result += Temp;
|
||||
}
|
||||
document.getElementById('ClueEntry').innerHTML = Result;
|
||||
}
|
||||
|
||||
function EnterGuess(Across,ClueNum,x,y,BoxId){
|
||||
if (document.getElementById(BoxId) != null){
|
||||
var Guess = document.getElementById(BoxId).value;
|
||||
var AnsLength = GetAnswerLength(Across,x,y);
|
||||
EnterAnswer(Guess,Across,AnsLength,x,y);
|
||||
}
|
||||
}
|
||||
|
||||
function SplitStringToPerceivedChars(InString, PC){
|
||||
var Temp = InString.charAt(0);
|
||||
if (InString.length > 1){
|
||||
for (var i=1; i<InString.length; i++){
|
||||
if (IsCombiningDiacritic(InString.charCodeAt(i)) == true){
|
||||
Temp += InString.charAt(i);
|
||||
}
|
||||
else{
|
||||
PC.push(Temp);
|
||||
Temp = InString.charAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
PC.push(Temp);
|
||||
}
|
||||
|
||||
function EnterAnswer(Guess,Across,AnsLength,x,y){
|
||||
var PC = new Array();
|
||||
SplitStringToPerceivedChars(Guess, PC);
|
||||
|
||||
var i=x;
|
||||
var j=y;
|
||||
var Letter = 0;
|
||||
while (Letter < AnsLength){
|
||||
if (Letter < PC.length){
|
||||
G[i][j] = PC[Letter];
|
||||
if (document.getElementById('L_' + i + '_' + j) != null){
|
||||
document.getElementById('L_' + i + '_' + j).innerHTML = PC[Letter];
|
||||
}
|
||||
}
|
||||
if (Across == true){
|
||||
j++;
|
||||
}
|
||||
else{
|
||||
i++;
|
||||
}
|
||||
Letter++;
|
||||
}
|
||||
}
|
||||
|
||||
function SetGridSquareValue(x,y,Val){
|
||||
var GridId = 'L_' + x + '_' + y;
|
||||
if (document.getElementById(GridId) != null){
|
||||
document.getElementById(GridId).innerHTML = Val;
|
||||
}
|
||||
}
|
||||
|
||||
function ShowHint(Across,ClueNum,x,y,BoxId){
|
||||
var i=x;
|
||||
var j=y;
|
||||
var LetterFromGuess = '';
|
||||
var LetterFromKey = '';
|
||||
var OutString = '';
|
||||
if (Across==true){
|
||||
while (j<L[i].length){
|
||||
if (L[i][j] != ''){
|
||||
OutString += L[i][j];
|
||||
if (CaseSensitive == true){
|
||||
LetterFromKey = L[i][j];
|
||||
LetterFromGuess = G[i][j];
|
||||
}
|
||||
else {
|
||||
LetterFromKey = L[i][j].toUpperCase();
|
||||
LetterFromGuess = G[i][j].toUpperCase();
|
||||
}
|
||||
if (LetterFromGuess != LetterFromKey){
|
||||
// if (G[i][j] != L[i][j]){
|
||||
G[i][j] = L[i][j];
|
||||
Penalties++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else{
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
else{
|
||||
while (i<L.length){
|
||||
if (L[i][j] != ''){
|
||||
OutString += L[i][j];
|
||||
if (CaseSensitive == true){
|
||||
LetterFromKey = L[i][j];
|
||||
LetterFromGuess = G[i][j];
|
||||
}
|
||||
else {
|
||||
LetterFromKey = L[i][j].toUpperCase();
|
||||
LetterFromGuess = G[i][j].toUpperCase();
|
||||
}
|
||||
if (LetterFromGuess != LetterFromKey){
|
||||
// if (G[i][j] != L[i][j]){
|
||||
G[i][j] = L[i][j];
|
||||
Penalties++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else{
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (document.getElementById(BoxId) != null){
|
||||
document.getElementById(BoxId).value = OutString;
|
||||
}
|
||||
}
|
||||
|
||||
L = new Array();
|
||||
[strLetterArray]
|
||||
|
||||
CL = new Array();
|
||||
[strClueNumArray]
|
||||
|
||||
G = new Array();
|
||||
[strGuessArray]
|
||||
|
||||
function CheckAnswers(){
|
||||
if (Locked == true){return;}
|
||||
|
||||
var AllCorrect = true;
|
||||
var TotLetters = 0;
|
||||
var CorrectLetters = 0;
|
||||
var LetterFromKey = '';
|
||||
var LetterFromGuess = '';
|
||||
|
||||
//Check each letter
|
||||
for (var i=0; i<L.length; i++){
|
||||
for (var j=0; j<L[i].length; j++){
|
||||
if (L[i][j] != ''){
|
||||
TotLetters++;
|
||||
if (CaseSensitive == true) {
|
||||
LetterFromKey = L[i][j];
|
||||
LetterFromGuess = G[i][j];
|
||||
}
|
||||
else {
|
||||
LetterFromKey = L[i][j].toUpperCase();
|
||||
LetterFromGuess = G[i][j].toUpperCase();
|
||||
}
|
||||
if (LetterFromGuess != LetterFromKey){
|
||||
G[i][j] = '';
|
||||
//Blank that square in the grid
|
||||
SetGridSquareValue(i,j,'');
|
||||
AllCorrect = false;
|
||||
}
|
||||
else{
|
||||
CorrectLetters++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Score = Math.floor(((CorrectLetters-Penalties) * 100)/TotLetters);
|
||||
if (Score < 0){Score = 0;}
|
||||
|
||||
//Compile the output
|
||||
var Output = '';
|
||||
|
||||
if (AllCorrect == true){
|
||||
Output = Correct + '<br />';
|
||||
}
|
||||
|
||||
Output += YourScoreIs + ' ' + Score + '%.<br />';
|
||||
if (AllCorrect == false){
|
||||
Output += Incorrect;
|
||||
Penalties++;
|
||||
}
|
||||
|
||||
ShowMessage(Output);
|
||||
WriteToInstructions(Output);
|
||||
|
||||
if ((AllCorrect == true)||(TimeOver == true)){
|
||||
[inclSendResults]
|
||||
setTimeout('SendResults(' + Score + ')', 50);
|
||||
[/inclSendResults]
|
||||
[inclTimer]
|
||||
window.clearInterval(Interval);
|
||||
[/inclTimer]
|
||||
TimeOver = true;
|
||||
Locked = true;
|
||||
Finished = true;
|
||||
setTimeout('Finish()', SubmissionTimeout);
|
||||
}
|
||||
[inclScorm1.2]
|
||||
if (AllCorrect == true){
|
||||
SetScormComplete();
|
||||
}
|
||||
else{
|
||||
SetScormIncomplete();
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
}
|
||||
|
||||
function Finish(){
|
||||
//If there's a form, fill it out and submit it
|
||||
if (document.store != null){
|
||||
Frm = document.store;
|
||||
Frm.starttime.value = HPNStartTime;
|
||||
Frm.endtime.value = (new Date()).getTime();
|
||||
Frm.mark.value = Score;
|
||||
Frm.submit();
|
||||
}
|
||||
}
|
||||
|
||||
function TypeChars(Chars){
|
||||
if (CurrentBox != null){
|
||||
CurrentBox.value += Chars;
|
||||
}
|
||||
}
|
||||
|
||||
[inclTimer]
|
||||
function TimesUp() {
|
||||
document.getElementById('Timer').innerHTML = '[strTimesUp]';
|
||||
[inclPreloadImages]
|
||||
RefreshImages();
|
||||
[/inclPreloadImages]
|
||||
TimeOver = true;
|
||||
Finished = true;
|
||||
CheckAnswers();
|
||||
Locked = true;
|
||||
[inclScorm1.2]
|
||||
SetScormTimedOut();
|
||||
[/inclScorm1.2]
|
||||
}
|
||||
[/inclTimer]
|
||||
@@ -1,182 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xml:lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
|
||||
<title></title>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
//<![CDATA[
|
||||
|
||||
<!--
|
||||
|
||||
var strPrintExplanation = '[strPrintExplanation]';
|
||||
|
||||
function ShowMessage(){
|
||||
alert(strPrintExplanation);
|
||||
}
|
||||
|
||||
function ShowKey(){
|
||||
var NList = document.getElementsByTagName('span');
|
||||
for (var i=0; i<NList.length; i++){
|
||||
if (NList[i].className == 'Letter'){
|
||||
if (NList[i].style.display == 'inline'){
|
||||
NList[i].style.display = 'none';
|
||||
}
|
||||
else{
|
||||
NList[i].style.display = 'inline';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-->
|
||||
|
||||
//]]>
|
||||
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
<!--
|
||||
|
||||
body{
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
font-family: [strFontFace];
|
||||
font-size: [strFontSize];
|
||||
}
|
||||
|
||||
div.Titles{
|
||||
padding: 0.5em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table{
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
table#Grid td{
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
font-size: 140%;
|
||||
}
|
||||
|
||||
table#Grid td.BlankCell{
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
padding: 0px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
background-color: #000000;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
table#Grid td.LetterOnlyCell{
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
table#Grid td.NumLetterCell{
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
span.Num{
|
||||
vertical-align: super;
|
||||
font-size: 100%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span.Letter{
|
||||
font-weight: bold;
|
||||
font-size: 140%;
|
||||
display: none;
|
||||
}
|
||||
|
||||
table.ClueTable{
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.ClueNum{
|
||||
font-weight: bold;
|
||||
font-size: 140%;
|
||||
padding: 0px 1em 0px 0px;
|
||||
}
|
||||
|
||||
.Clue{
|
||||
|
||||
}
|
||||
|
||||
-->
|
||||
</style>
|
||||
|
||||
|
||||
</head>
|
||||
<body onload="ShowMessage()">
|
||||
|
||||
<div class="Titles">
|
||||
<h2 style="cursor: pointer;" onclick="ShowKey()">[strExerciseTitle]</h2>
|
||||
[inclExerciseSubtitle]
|
||||
<h3 class="ExerciseSubtitle">[strExerciseSubtitle]</h3>
|
||||
[/inclExerciseSubtitle]
|
||||
</div>
|
||||
|
||||
<table id="Grid" border="1" cellspacing="0" cellpadding="0">
|
||||
|
||||
[StartBlankCell]
|
||||
<td class="BlankCell"> </td>
|
||||
[EndBlankCell]
|
||||
|
||||
[StartLetterOnlyCell]
|
||||
<td class="LetterOnlyCell"> <span class="Letter">[Letter]</span></td>
|
||||
[EndLetterOnlyCell]
|
||||
|
||||
[StartNumLetterCell]
|
||||
<td class="NumLetterCell"><span class="Num">[ClueNum]</span> <span class="Letter">[Letter]</span></td>
|
||||
[EndNumLetterCell]
|
||||
|
||||
</table>
|
||||
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<table border="0" class="ClueTable">
|
||||
<tr><td colspan="2"><h3>[strCluesAcrossLabel]</h3></td></tr>
|
||||
|
||||
[StartCluesAcrossLoop]
|
||||
<tr><td class="ClueNum">[ClueNum]</td>
|
||||
<td class="Clue">[Clue]</td></tr>
|
||||
[EndCluesAcrossLoop]
|
||||
|
||||
</table>
|
||||
|
||||
</td>
|
||||
|
||||
<td valign="top">
|
||||
|
||||
<table border="0" class="ClueTable">
|
||||
<tr><td colspan="2"><h3>[strCluesDownLabel]</h3></td></tr>
|
||||
|
||||
[StartCluesDownLoop]
|
||||
<tr><td class="ClueNum">[ClueNum]</td>
|
||||
<td class="Clue">[Clue]</td></tr>
|
||||
[EndCluesDownLoop]
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr></table>
|
||||
|
||||
</body></html>
|
||||
@@ -1,148 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xml:lang="en"><head>
|
||||
|
||||
[strDublinCoreMetadata]
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
|
||||
<title>
|
||||
[strPlainTitle]
|
||||
</title>
|
||||
|
||||
<!-- Made with executable version [strFullVersionInfo] -->
|
||||
|
||||
<!-- The following insertion allows you to add your own code directly to this head tag from the configuration screen -->
|
||||
|
||||
[strHeaderCode]
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
[strStyleSheet]
|
||||
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
//<![CDATA[
|
||||
|
||||
<!--
|
||||
|
||||
[inclScorm1.2]
|
||||
[strJSScorm_1_2]
|
||||
[/inclScorm1.2]
|
||||
|
||||
[strJSBrowserCheck]
|
||||
|
||||
[strJSButtons]
|
||||
|
||||
[strJSShowMessage]
|
||||
|
||||
[strJSUtilities]
|
||||
|
||||
[strJSHotPotNet]
|
||||
|
||||
[strJSJMatch6]
|
||||
|
||||
[inclTimer]
|
||||
[strJSTimer]
|
||||
[/inclTimer]
|
||||
|
||||
[inclSendResults]
|
||||
[strJSSendResults]
|
||||
[/inclSendResults]
|
||||
|
||||
//-->
|
||||
|
||||
//]]>
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="StartUp()" id="TheBody" [inclScorm1.2]onunload="CheckLMSFinish()"[/inclScorm1.2]>
|
||||
|
||||
<!-- BeginTopNavButtons -->
|
||||
|
||||
[inclNavButtons]
|
||||
[strTopNavBar]
|
||||
[/inclNavButtons]
|
||||
|
||||
<!-- EndTopNavButtons -->
|
||||
|
||||
<div class="Titles">
|
||||
<h2 class="ExerciseTitle">[strExerciseTitle]</h2>
|
||||
[inclExerciseSubtitle]
|
||||
<h3 class="ExerciseSubtitle">[strExerciseSubtitle]</h3>
|
||||
[/inclExerciseSubtitle]
|
||||
[inclTimer]
|
||||
<div id="Timer"><span id="TimerText"> </span></div>
|
||||
[/inclTimer]
|
||||
|
||||
</div>
|
||||
|
||||
<div id="InstructionsDiv" class="StdDiv">
|
||||
<div id="Instructions">[strInstructions]</div>
|
||||
</div>
|
||||
|
||||
[inclReading]
|
||||
<div class="LeftContainer">
|
||||
|
||||
<div id="Reading" class="StdDiv">
|
||||
|
||||
<div id="ReadingDiv">
|
||||
[strReadingText]
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="RightContainer">
|
||||
[/inclReading]
|
||||
|
||||
<div id="MainDiv" class="StdDiv">
|
||||
|
||||
<button id="CheckButton1" class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="CheckAnswers()"> [strCheckCaption] </button>
|
||||
|
||||
<div id="MatchDiv" style="text-align: center;">
|
||||
|
||||
<form id="QForm" method="post" action="" onsubmit="return false;">
|
||||
<table border="0" style="margin: 2em auto 2em auto;"><tbody id="Questions">
|
||||
|
||||
[strMatchDivItems]
|
||||
|
||||
</tbody></table>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<button id="CheckButton2" class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="CheckAnswers()"> [strCheckCaption] </button>
|
||||
|
||||
</div>
|
||||
|
||||
[inclReading]
|
||||
</div>
|
||||
[/inclReading]
|
||||
|
||||
<div class="Feedback" id="FeedbackDiv">
|
||||
<div class="FeedbackText" id="FeedbackContent"></div>
|
||||
<button id="FeedbackOKButton" class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="HideFeedback(); return false;"> [strOKCaption] </button>
|
||||
</div>
|
||||
|
||||
<!-- BeginBottomNavButtons -->
|
||||
|
||||
[inclNavButtons]
|
||||
[strBottomNavBar]
|
||||
[/inclNavButtons]
|
||||
|
||||
<!-- EndBottomNavButtons -->
|
||||
|
||||
<!-- BeginSubmissionForm -->
|
||||
|
||||
<!-- EndSubmissionForm -->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,310 +0,0 @@
|
||||
|
||||
[inclScorm1.2]
|
||||
//JMATCH-SPECIFIC SCORM-RELATED JAVASCRIPT CODE
|
||||
|
||||
function SetScormScore(){
|
||||
//Reports the current score and any other information back to the LMS
|
||||
if (API != null){
|
||||
API.LMSSetValue('cmi.core.score.raw', Score);
|
||||
|
||||
//Now send a detailed reports on the item
|
||||
var ItemLabel = 'Matching';
|
||||
API.LMSSetValue('cmi.objectives.0.id', 'obj'+ItemLabel);
|
||||
API.LMSSetValue('cmi.interactions.0.id', 'int'+ItemLabel);
|
||||
API.LMSSetValue('cmi.objectives.0.status', API.LMSGetValue('cmi.core.lesson_status'));
|
||||
API.LMSSetValue('cmi.objectives.0.score.min', '0');
|
||||
API.LMSSetValue('cmi.objectives.0.score.max', '100');
|
||||
API.LMSSetValue('cmi.objectives.0.score.raw', Score);
|
||||
//We can only use the performance type, because we're storing multiple responses of various types.
|
||||
API.LMSSetValue('cmi.interactions.0.type', 'performance');
|
||||
|
||||
var AnswersTried = '';
|
||||
for (var i=0; i<Status[0][3].length; i++){
|
||||
if (i>0){AnswersTried += ' | ';}
|
||||
for (var j=0; j<Status.length; j++){
|
||||
if (j>0){AnswersTried += ',';}
|
||||
AnswersTried += j + '.' + Status[j][3][i];
|
||||
}
|
||||
}
|
||||
API.LMSSetValue('cmi.interactions.0.student_response', AnswersTried);
|
||||
API.LMSCommit('');
|
||||
}
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
|
||||
//JMATCH CORE JAVASCRIPT CODE
|
||||
|
||||
var CorrectIndicator = '[strCorrectIndicator]';
|
||||
var IncorrectIndicator = '[strIncorrectIndicator]';
|
||||
var YourScoreIs = '[strYourScoreIs]';
|
||||
var CorrectResponse = '[strGuessCorrect]';
|
||||
var IncorrectResponse = '[strGuessIncorrect]';
|
||||
var TotalUnfixedLeftItems = 0;
|
||||
var TotCorrectChoices = 0;
|
||||
var Penalties = 0;
|
||||
var Finished = false;
|
||||
var TimeOver = false;
|
||||
|
||||
var Score = 0;
|
||||
var Locked = false;
|
||||
var ShuffleQs = [boolShuffleQs];
|
||||
var QsToShow = [QsToShow];
|
||||
|
||||
|
||||
function StartUp(){
|
||||
RemoveBottomNavBarForIE();
|
||||
|
||||
[inclScorm1.2]
|
||||
ScormStartUp();
|
||||
[/inclScorm1.2]
|
||||
|
||||
[inclSendResults]
|
||||
GetUserName();
|
||||
[/inclSendResults]
|
||||
|
||||
[inclPreloadImages]
|
||||
PreloadImages([PreloadImageList]);
|
||||
[/inclPreloadImages]
|
||||
|
||||
SetUpItems(ShuffleQs,QsToShow);
|
||||
|
||||
TotalUnfixedLeftItems = document.getElementById('MatchDiv').getElementsByTagName('select').length;
|
||||
|
||||
//Create arrays
|
||||
CreateStatusArrays();
|
||||
|
||||
[inclTimer]
|
||||
StartTimer();
|
||||
[/inclTimer]
|
||||
}
|
||||
|
||||
Status = new Array();
|
||||
|
||||
|
||||
function CreateStatusArrays(){
|
||||
var Selects = document.getElementById('Questions').getElementsByTagName('select');
|
||||
for (var x=0; x<Selects.length; x++){
|
||||
Status[x] = new Array();
|
||||
Status[x][0] = 0; // Item not matched correctly yet
|
||||
Status[x][1] = 0; //Tries at this item so far
|
||||
Status[x][2] = Selects[x].id; //Store a ref to the original drop-down
|
||||
Status[x][3] = new Array(); //Sequence of guesses for this item
|
||||
}
|
||||
}
|
||||
|
||||
function GetKeyFromSelectContainer(Container){
|
||||
var Result = -1;
|
||||
if (Container.getElementsByTagName('select').length > 0){
|
||||
var Select = Container.getElementsByTagName('select')[0];
|
||||
if (Select != null){
|
||||
Result = parseInt(Select.id.substring(1, Select.id.length));
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
function GetKeyFromSelect(Select){
|
||||
var Result = -1;
|
||||
if (Select != null){
|
||||
Result = parseInt(Select.id.substring(1, Select.id.length));
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
var OriginalKeys = new Array();
|
||||
var ReducedKeys = new Array();
|
||||
|
||||
function GetUniqueKeys(Container, TargetArray){
|
||||
TargetArray.length = 0;
|
||||
var x = -1;
|
||||
var SList = Container.getElementsByTagName('select');
|
||||
if (SList.length > 0){
|
||||
for (var i=0; i<SList.length; i++){
|
||||
x = GetKeyFromSelect(SList[i]);
|
||||
if (TargetArray.indexOf(x) < 0){
|
||||
TargetArray.push(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function SetUpItems(ShuffleQs, ReduceTo){
|
||||
var QList = new Array();
|
||||
var i, j, k, Selects, Options;
|
||||
|
||||
//Remove all the table rows and put them in an array for processing
|
||||
var Qs = document.getElementById('Questions');
|
||||
|
||||
//First, get a list of keys
|
||||
GetUniqueKeys(Qs, OriginalKeys);
|
||||
|
||||
//Remove the table rows to an array
|
||||
while (Qs.getElementsByTagName('tr').length > 0){
|
||||
QList.push(Qs.removeChild(Qs.getElementsByTagName('tr')[0]));
|
||||
}
|
||||
|
||||
var Reducing = (QList.length > ReduceTo);
|
||||
|
||||
//If required, select random rows to delete
|
||||
if (Reducing == true){
|
||||
var DumpItem = 0;
|
||||
while (ReduceTo < QList.length){
|
||||
|
||||
//Get a number to delete from the array
|
||||
DumpItem = Math.floor(QList.length*Math.random());
|
||||
for (i=DumpItem; i<(QList.length-1); i++){
|
||||
QList[i] = QList[i+1];
|
||||
}
|
||||
QList.length = QList.length-1;
|
||||
}
|
||||
}
|
||||
//Shuffle the rows if necessary
|
||||
if (ShuffleQs == true){
|
||||
QList = Shuffle(QList);
|
||||
}
|
||||
|
||||
TotalUnfixedLeftItems = QList.length;
|
||||
|
||||
//Write the rows back to the table body
|
||||
for (i=0; i<QList.length; i++){
|
||||
Qs.appendChild(QList[i]);
|
||||
}
|
||||
|
||||
//Now we need to remove any drop-down options that no longer have associated select items
|
||||
if (Reducing == true){
|
||||
GetUniqueKeys(Qs, ReducedKeys);
|
||||
|
||||
Selects = Qs.getElementsByTagName('select');
|
||||
for (i=0; i<Selects.length; i++){
|
||||
Options = Selects[i].getElementsByTagName('option');
|
||||
for (j=Options.length-1; j>=0; j--){
|
||||
if (OptionRequired(Options[j].value) == false){
|
||||
Selects[i].removeChild(Options[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function OptionRequired(Key){
|
||||
if (ReducedKeys.indexOf(Key) > -1){
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
if (OriginalKeys.indexOf(Key) > -1){
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function CheckAnswers(){
|
||||
if (Locked == true){return;}
|
||||
var Select = null;
|
||||
var Key = -1;
|
||||
var Parent = null;
|
||||
var Answer = null;
|
||||
var AnsText = '';
|
||||
var AllDone = true;
|
||||
TotCorrectChoices = 0;
|
||||
|
||||
//for each item not fixed or a distractor
|
||||
for (var i=0; i<Status.length; i++){
|
||||
|
||||
//if it hasn't been answered correctly yet
|
||||
if (Status[i][0] < 1){
|
||||
|
||||
//Add one to the number of tries for this item
|
||||
Status[i][1]++;
|
||||
|
||||
//Get a pointer to the drop-down
|
||||
Select = document.getElementById(Status[i][2]);
|
||||
Key = GetKeyFromSelect(Select);
|
||||
//Save the answer given
|
||||
Status[i][3].push(Select.options[Select.selectedIndex].value);
|
||||
|
||||
//Check the answer
|
||||
if (Select.options[Select.selectedIndex].value == Key){
|
||||
Status[i][0] = 1;
|
||||
AnsText = Select.options[Select.selectedIndex].innerHTML;
|
||||
Parent = Select.parentNode;
|
||||
Parent.removeChild(Select);
|
||||
Parent.innerHTML = AnsText;
|
||||
Parent.nextSibling.innerHTML = CorrectIndicator;
|
||||
}
|
||||
else{
|
||||
AllDone = false;
|
||||
Parent = Select.parentNode;
|
||||
Parent.nextSibling.innerHTML = IncorrectIndicator;
|
||||
}
|
||||
}
|
||||
else{
|
||||
//Add a copy of the last (correct) answer.
|
||||
Status[i][3].push(Status[i][3][Status[i][3].length-1]);
|
||||
}
|
||||
//If it's correct, count it
|
||||
if (Status[i][0] == 1){
|
||||
TotCorrectChoices++;
|
||||
}
|
||||
}
|
||||
//Calculate the score
|
||||
Score = Math.floor(((TotCorrectChoices-Penalties)/TotalUnfixedLeftItems)*100);
|
||||
if (Score<0){Score = 0;}
|
||||
var Feedback = '';
|
||||
|
||||
//Build the feedback
|
||||
if (AllDone == true){
|
||||
Feedback = CorrectResponse + '<br />' + YourScoreIs + Score + '%.';
|
||||
}
|
||||
else{
|
||||
Feedback = IncorrectResponse + '<br />' + YourScoreIs + Score + '%.';
|
||||
//Penalty for incorrect check
|
||||
Penalties++;
|
||||
}
|
||||
|
||||
//If the exercise is over, deal with that
|
||||
if ((AllDone == true)||(TimeOver == true)){
|
||||
[inclSendResults]
|
||||
setTimeout('SendResults(' + Score + ')', 50);
|
||||
[/inclSendResults]
|
||||
[inclTimer]
|
||||
window.clearInterval(Interval);
|
||||
[/inclTimer]
|
||||
TimeOver = true;
|
||||
Locked = true;
|
||||
Finished = true;
|
||||
setTimeout('Finish()', SubmissionTimeout);
|
||||
WriteToInstructions(Feedback);
|
||||
}
|
||||
|
||||
//Show the feedback
|
||||
ShowMessage(Feedback);
|
||||
|
||||
[inclScorm1.2]
|
||||
if (AllDone == true){
|
||||
SetScormComplete();
|
||||
}
|
||||
else{
|
||||
SetScormIncomplete();
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
}
|
||||
|
||||
[inclTimer]
|
||||
function TimesUp() {
|
||||
document.getElementById('Timer').innerHTML = '[strTimesUp]';
|
||||
[inclPreloadImages]
|
||||
RefreshImages();
|
||||
[/inclPreloadImages]
|
||||
TimeOver = true;
|
||||
Finished = true;
|
||||
CheckAnswers();
|
||||
Locked = true;
|
||||
[inclScorm1.2]
|
||||
SetScormTimedOut();
|
||||
[/inclScorm1.2]
|
||||
}
|
||||
[/inclTimer]
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xml:lang="en"><head>
|
||||
|
||||
[strDublinCoreMetadata]
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
|
||||
<title>
|
||||
[strPlainTitle]
|
||||
</title>
|
||||
|
||||
<!-- Made with executable version [strFullVersionInfo] -->
|
||||
|
||||
<!-- The following insertion allows you to add your own code directly to this head tag from the configuration screen -->
|
||||
|
||||
[strHeaderCode]
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
[strStyleSheet]
|
||||
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
//<![CDATA[
|
||||
|
||||
<!--
|
||||
|
||||
[inclScorm1.2]
|
||||
[strJSScorm_1_2]
|
||||
[/inclScorm1.2]
|
||||
|
||||
[strJSBrowserCheck]
|
||||
|
||||
[strJSButtons]
|
||||
|
||||
[strJSShowMessage]
|
||||
|
||||
[strJSUtilities]
|
||||
|
||||
[strJSHotPotNet]
|
||||
|
||||
[strJSJMix6]
|
||||
|
||||
[inclTimer]
|
||||
[strJSTimer]
|
||||
[/inclTimer]
|
||||
|
||||
[inclSendResults]
|
||||
[strJSSendResults]
|
||||
[/inclSendResults]
|
||||
|
||||
//-->
|
||||
|
||||
//]]>
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="StartUp()" id="TheBody" [inclScorm1.2]onunload="CheckLMSFinish()"[/inclScorm1.2]>
|
||||
|
||||
<!-- BeginTopNavButtons -->
|
||||
|
||||
[inclNavButtons]
|
||||
[strTopNavBar]
|
||||
[/inclNavButtons]
|
||||
|
||||
<!-- EndTopNavButtons -->
|
||||
|
||||
<div class="Titles">
|
||||
<h2 class="ExerciseTitle">[strExerciseTitle]</h2>
|
||||
[inclExerciseSubtitle]
|
||||
<h3 class="ExerciseSubtitle">[strExerciseSubtitle]</h3>
|
||||
[/inclExerciseSubtitle]
|
||||
[inclTimer]
|
||||
<div id="Timer"><span id="TimerText"> </span></div>
|
||||
[/inclTimer]
|
||||
|
||||
</div>
|
||||
|
||||
<div id="InstructionsDiv" class="StdDiv">
|
||||
<div id="Instructions">[strInstructions]</div>
|
||||
</div>
|
||||
|
||||
[inclReading]
|
||||
<div class="LeftContainer">
|
||||
|
||||
<div id="Reading" class="StdDiv">
|
||||
|
||||
<div id="ReadingDiv">
|
||||
[strReadingText]
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="RightContainer">
|
||||
[/inclReading]
|
||||
|
||||
<div id="GuessDiv" class="StdDiv">
|
||||
|
||||
</div>
|
||||
|
||||
<div id="MainDiv" class="StdDiv">
|
||||
|
||||
<button id="CheckButton1" class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="CheckAnswer(0)"> [strCheckCaption] </button>
|
||||
|
||||
[inclUndo]
|
||||
<button class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="Undo()"> [strUndoCaption] </button>
|
||||
[/inclUndo]
|
||||
|
||||
[inclRestart]
|
||||
<button class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="location.reload()"> [strRestartCaption] </button>
|
||||
[/inclRestart]
|
||||
|
||||
[inclHint]
|
||||
<button class="FuncButton" onmouseover="FuncBtnOver(this)" onfocus="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onblur="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="CheckAnswer(1)"> [strHintCaption] </button>
|
||||
[/inclHint]
|
||||
|
||||
<div id="SegmentDiv">
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
[inclReading]
|
||||
</div>
|
||||
[/inclReading]
|
||||
|
||||
<div class="Feedback" id="FeedbackDiv">
|
||||
<div class="FeedbackText" id="FeedbackContent"></div>
|
||||
<button id="FeedbackOKButton" class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="HideFeedback(); return false;"> [strOKCaption] </button>
|
||||
</div>
|
||||
|
||||
<!-- BeginBottomNavButtons -->
|
||||
|
||||
[inclNavButtons]
|
||||
[strBottomNavBar]
|
||||
[/inclNavButtons]
|
||||
|
||||
<!-- EndBottomNavButtons -->
|
||||
|
||||
<!-- BeginSubmissionForm -->
|
||||
|
||||
<!-- EndSubmissionForm -->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,409 +0,0 @@
|
||||
[inclScorm1.2]
|
||||
//JMIX-SPECIFIC SCORM-RELATED JAVASCRIPT CODE
|
||||
|
||||
function SetScormScore(){
|
||||
//Reports the current score and any other information back to the LMS
|
||||
if (API != null){
|
||||
API.LMSSetValue('cmi.core.score.raw', Score);
|
||||
|
||||
//Now send a detailed reports on the item
|
||||
var ItemLabel = 'Item_1';
|
||||
API.LMSSetValue('cmi.objectives.0.id', 'obj'+ItemLabel);
|
||||
API.LMSSetValue('cmi.interactions.0.id', 'int'+ItemLabel);
|
||||
if (Finished == true){
|
||||
API.LMSSetValue('cmi.objectives.0.status', 'completed');
|
||||
}
|
||||
else{
|
||||
API.LMSSetValue('cmi.objectives.0.status', 'incomplete');
|
||||
}
|
||||
|
||||
API.LMSSetValue('cmi.objectives.0.score.min', '0');
|
||||
API.LMSSetValue('cmi.objectives.0.score.max', '100');
|
||||
API.LMSSetValue('cmi.objectives.0.score.raw', Score);
|
||||
//We can only use the performance type, because we're storing multiple responses of various types.
|
||||
API.LMSSetValue('cmi.interactions.0.type', 'performance');
|
||||
API.LMSSetValue('cmi.interactions.0.student_response', AnswersTried);
|
||||
|
||||
API.LMSCommit('');
|
||||
}
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
|
||||
//JMIX STANDARD OUTPUT FORMAT CODE
|
||||
|
||||
var CorrectResponse = '[strGuessCorrect]';
|
||||
var IncorrectResponse = '[strGuessIncorrect]';
|
||||
var TheseAnswersToo = '[strTheseAnswersToo]';
|
||||
var ThisMuchCorrect = '[strThisMuch]';
|
||||
var NextCorrect = '[strNextCorrect]';
|
||||
var YourScoreIs = '[strYourScoreIs]';
|
||||
var CapitalizeFirst = [boolCapitalizeFirst];
|
||||
var Penalties = 0;
|
||||
var Finished = false;
|
||||
var TimeOver = false;
|
||||
var Score = 0;
|
||||
var strInstructions = '';
|
||||
var AnswersTried = '';
|
||||
|
||||
|
||||
var SegmentTemplate = ' <a class="ExSegment" href="javascript:void(0)" onclick="AddSegment([SegmentNumber])" title="[strClickToAdd]">[CurrentSegment]</a> ';
|
||||
|
||||
var Exercise = '';
|
||||
|
||||
var Punctuation = '[strPunctuation]';
|
||||
|
||||
var Openers = '[strOpenPunctuation]';
|
||||
|
||||
var Guesses = new Array();
|
||||
var Remaining = new Array();
|
||||
var CorrectParts = new Array();
|
||||
|
||||
var ClosestMatch = 0;
|
||||
|
||||
var LowerString='';
|
||||
var UpperString='';
|
||||
|
||||
var Output = '';
|
||||
|
||||
var Segments = new Array();
|
||||
[SegmentArray]
|
||||
|
||||
var GuessSequence = new Array();
|
||||
|
||||
var Answers = new Array();
|
||||
[AnswerArray]
|
||||
|
||||
function WriteToGuess(Feedback) {
|
||||
document.getElementById('GuessDiv').innerHTML = Feedback;
|
||||
[inclPreloadImages]
|
||||
RefreshImages();
|
||||
[/inclPreloadImages]
|
||||
}
|
||||
|
||||
function Undo(){
|
||||
if (GuessSequence.length < 1){
|
||||
return;
|
||||
}
|
||||
GuessSequence.length = GuessSequence.length - 1;
|
||||
BuildCurrGuess();
|
||||
BuildExercise();
|
||||
DisplayExercise(Exercise);
|
||||
//Following line modified for 6.0.4.44 -- "remaining words" message removed, no longer needed
|
||||
WriteToGuess('<span class="Answer">' + Output + '</span>');
|
||||
}
|
||||
|
||||
function AddSegment(SegNum){
|
||||
[inclTimer]
|
||||
if (TimeOver == true){return;}
|
||||
[/inclTimer]
|
||||
GuessSequence[GuessSequence.length] = SegNum;
|
||||
BuildCurrGuess();
|
||||
WriteToGuess('<span class="Answer">' + Output + '</span>');
|
||||
BuildExercise();
|
||||
DisplayExercise(Exercise);
|
||||
}
|
||||
|
||||
function BuildCurrGuess(){
|
||||
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
var NewSeg = '';
|
||||
|
||||
//first, create arrays of all the segments guessed so far and those not yet used
|
||||
GuessSegs = new Array();
|
||||
GuessSegs.length = 0;
|
||||
|
||||
//set the "used" markers all to 0
|
||||
for (i=0; i<Segments.length; i++){
|
||||
Segments[i][2] = 0;
|
||||
}
|
||||
|
||||
for (i=0; i<GuessSequence.length; i++){
|
||||
for (j=0; j<Segments.length; j++){
|
||||
if ((Segments[j][1] == GuessSequence[i])&&(Segments[j][2] == 0)){
|
||||
GuessSegs[GuessSegs.length] = Segments[j][0];
|
||||
Segments[j][2] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Create the list of unused segments
|
||||
RemainingList = '';
|
||||
for (i=0; i<Segments.length; i++){
|
||||
if (Segments[i][2] == 0){
|
||||
RemainingList += Segments[i][0] + ' ';
|
||||
}
|
||||
}
|
||||
|
||||
//now concatenate the segments, adding spaces where appropriate;
|
||||
Output = CompileString(GuessSequence);
|
||||
}
|
||||
|
||||
function CompileString(InArray){
|
||||
var OutString = '';
|
||||
var i = 0;
|
||||
OutArray = new Array();
|
||||
|
||||
for (i=0; i<InArray.length; i++){
|
||||
OutArray[OutArray.length] = FindSegment(InArray[i]);
|
||||
}
|
||||
|
||||
if (OutArray.length > 0){
|
||||
OutString = OutArray[0];
|
||||
}
|
||||
else{
|
||||
OutString = '';
|
||||
}
|
||||
var Spacer = '';
|
||||
|
||||
for (i=1; i<OutArray.length; i++){
|
||||
Spacer = ' ';
|
||||
if ((Openers.indexOf(OutString.charAt(OutString.length-1)) > -1)||(Punctuation.indexOf(OutArray[i].charAt(0)) > -1)){
|
||||
Spacer = '';
|
||||
}
|
||||
OutString = OutString + Spacer + OutArray[i];
|
||||
}
|
||||
|
||||
//Capitalize the first letter if necessary
|
||||
if (CapitalizeFirst == true){
|
||||
i = 0;
|
||||
if ((Openers.indexOf(OutString.charAt(i))>-1)||(OutString.charAt(i) == ' ')){
|
||||
i++;
|
||||
}
|
||||
if ((Openers.indexOf(OutString.charAt(i))>-1)||(OutString.charAt(i) == ' ')){
|
||||
i++;
|
||||
}
|
||||
var Temp = OutString.charAt(i);
|
||||
Temp = Temp.toUpperCase();
|
||||
OutString = OutString.substring(0, i) + Temp + OutString.substring(i+1, OutString.length);
|
||||
}
|
||||
return OutString;
|
||||
}
|
||||
function CheckAnswer(CheckType){
|
||||
|
||||
if (GuessSequence.length < 1){
|
||||
if (CheckType == 1){
|
||||
ShowMessage(NextCorrect + '<br /><span class="Answer">' + FindSegment(Answers[0][0]) + '</span>');
|
||||
Penalties++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
var k = 0;
|
||||
var WellDone = '';
|
||||
var WhichCorrect = -1;
|
||||
var TryAgain = '';
|
||||
var LongestCorrectBit = '';
|
||||
TempCorrect = new Array();
|
||||
LongestCorrect = new Array();
|
||||
var TempHint = '';
|
||||
var HintToReturn = 1;
|
||||
var OtherAnswers = '';
|
||||
var AllDone = false;
|
||||
|
||||
for (i=0; i<Answers.length; i++){
|
||||
TempCorrect.length = 0;
|
||||
for (j=0; j<Answers[i].length; j++){
|
||||
if (Answers[i][j] == GuessSequence[j]){
|
||||
TempCorrect[j] = GuessSequence[j];
|
||||
}
|
||||
else{
|
||||
TempHint = Answers[i][j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((TempCorrect.length == GuessSequence.length)&&(TempCorrect.length == Answers[i].length)){
|
||||
|
||||
WhichCorrect = i;
|
||||
break;
|
||||
}
|
||||
else{
|
||||
if (TempCorrect.length > LongestCorrect.length){
|
||||
LongestCorrect.length = 0;
|
||||
for (k=0; k<TempCorrect.length; k++){
|
||||
LongestCorrect[k] = TempCorrect[k];
|
||||
}
|
||||
HintToReturn = TempHint;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (WhichCorrect > -1){
|
||||
AllDone = true;
|
||||
for (i=0; i<Answers.length; i++){
|
||||
if (i!=WhichCorrect){
|
||||
OtherAnswers += '<br />' + CompileString(Answers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
WellDone = '<span class="Answer">' + Output + '</span><br /><br />' + CorrectResponse + '<br />';
|
||||
|
||||
if (AnswersTried.length > 0){AnswersTried += ' | ';}
|
||||
AnswersTried += Output;
|
||||
|
||||
//Do score calculation here
|
||||
Score = Math.floor(((Segments.length-Penalties) * 100)/Segments.length);
|
||||
WellDone += YourScoreIs + ' ' + Score + '%.<br />';
|
||||
|
||||
[inclAlsoCorrect]
|
||||
if (OtherAnswers.length > 0){
|
||||
WellDone += TheseAnswersToo + '<span class="Answer">' + OtherAnswers + '</span>';
|
||||
}
|
||||
[/inclAlsoCorrect]
|
||||
|
||||
WriteToGuess(WellDone);
|
||||
ShowMessage(WellDone);
|
||||
}
|
||||
|
||||
else{
|
||||
var WrongGuess = CompileString(GuessSequence);
|
||||
if (AnswersTried.length > 0){AnswersTried += ' | ';}
|
||||
AnswersTried += WrongGuess;
|
||||
TryAgain = '<span class="Answer">' + WrongGuess + '</span><br /><br />';
|
||||
if (CheckType == 0){
|
||||
TryAgain += IncorrectResponse + '<br />';
|
||||
}
|
||||
|
||||
if (LongestCorrect.length > 0){
|
||||
|
||||
LongestCorrectBit = CompileString(LongestCorrect);
|
||||
GuessSequence.length = LongestCorrect.length;
|
||||
TryAgain += ThisMuchCorrect + '<br /><span class="Answer">' + LongestCorrectBit + '</span><br />';
|
||||
|
||||
//These lines added for 6.0.3.44
|
||||
WriteToGuess('<span class="Answer">' + LongestCorrectBit + '</span>');
|
||||
}
|
||||
else{
|
||||
GuessSequence.length = 0;
|
||||
WriteToGuess('');
|
||||
}
|
||||
|
||||
if (CheckType == 1){
|
||||
TryAgain += NextCorrect + '<br /><span class="Answer">' + FindSegment(HintToReturn) + '</span>';
|
||||
}
|
||||
|
||||
BuildCurrGuess();
|
||||
BuildExercise();
|
||||
DisplayExercise(Exercise);
|
||||
ShowMessage(TryAgain);
|
||||
Penalties++; //Penalty for inaccurate check
|
||||
|
||||
[inclTimer]
|
||||
if (TimeOver == true){
|
||||
Score = Math.floor(((LongestCorrect.length-Penalties) * 100)/Segments.length);
|
||||
if (Score < 0){Score = 0;}
|
||||
ShowMessage(YourScoreIs + ' ' + Score + '%.<br />');
|
||||
}
|
||||
[/inclTimer]
|
||||
|
||||
}
|
||||
//If the exercise is over, deal with that
|
||||
if ((AllDone == true)||(TimeOver == true)){
|
||||
[inclSendResults]
|
||||
setTimeout('SendResults(' + Score + ')', 50);
|
||||
[/inclSendResults]
|
||||
[inclTimer]
|
||||
window.clearInterval(Interval);
|
||||
[/inclTimer]
|
||||
TimeOver = true;
|
||||
Locked = true;
|
||||
Finished = true;
|
||||
setTimeout('Finish()', SubmissionTimeout);
|
||||
WriteToInstructions(YourScoreIs + ' ' + Score + '%.');
|
||||
}
|
||||
[inclScorm1.2]
|
||||
if (AllDone == true){
|
||||
SetScormComplete();
|
||||
}
|
||||
else{
|
||||
SetScormIncomplete();
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
}
|
||||
|
||||
function FindSegment(SegID){
|
||||
var Seg = '';
|
||||
for (var i=0; i<Segments.length; i++){
|
||||
if (Segments[i][1] == SegID){
|
||||
Seg = Segments[i][0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Seg;
|
||||
}
|
||||
|
||||
function StartUp(){
|
||||
RemoveBottomNavBarForIE();
|
||||
|
||||
//Stash the instructions so they can be redisplayed
|
||||
strInstructions = document.getElementById('InstructionsDiv').innerHTML;
|
||||
|
||||
[inclSendResults]
|
||||
GetUserName();
|
||||
[/inclSendResults]
|
||||
|
||||
[inclScorm1.2]
|
||||
ScormStartUp();
|
||||
[/inclScorm1.2]
|
||||
|
||||
[inclPreloadImages]
|
||||
PreloadImages([PreloadImageList]);
|
||||
[/inclPreloadImages]
|
||||
|
||||
Segments = Shuffle(Segments);
|
||||
|
||||
//Build and show the exercise
|
||||
BuildExercise();
|
||||
DisplayExercise(Exercise);
|
||||
|
||||
[inclTimer]
|
||||
StartTimer();
|
||||
[/inclTimer]
|
||||
}
|
||||
|
||||
|
||||
function BuildExercise(){
|
||||
Exercise = '';
|
||||
|
||||
var SegRow = '';
|
||||
var TempRow = '';
|
||||
|
||||
for (var i=0; i<Segments.length; i++){
|
||||
//if the segment hasn't been used yet
|
||||
if (Segments[i][2] == 0){
|
||||
TempRow = SegmentTemplate;
|
||||
TempRow = TempRow.replace(/\[SegmentNumber\]/g, Segments[i][1]);
|
||||
TempRow = TempRow.replace(/\[CurrentSegment\]/g, Segments[i][0]);
|
||||
SegRow += TempRow;
|
||||
}
|
||||
}
|
||||
|
||||
//Make it into a table
|
||||
Exercise = SegRow;
|
||||
}
|
||||
|
||||
function DisplayExercise(StuffToDisplay){
|
||||
document.getElementById('SegmentDiv').innerHTML = StuffToDisplay;
|
||||
FocusAButton();
|
||||
[inclPreloadImages]
|
||||
RefreshImages();
|
||||
[/inclPreloadImages]
|
||||
}
|
||||
|
||||
[inclTimer]
|
||||
function TimesUp() {
|
||||
document.getElementById('Timer').innerHTML = '[strTimesUp]';
|
||||
[inclPreloadImages]
|
||||
RefreshImages();
|
||||
[/inclPreloadImages]
|
||||
TimeOver = true;
|
||||
Finished = true;
|
||||
CheckAnswer(0);
|
||||
Locked = true;
|
||||
[inclScorm1.2]
|
||||
SetScormTimedOut();
|
||||
[/inclScorm1.2]
|
||||
}
|
||||
[/inclTimer]
|
||||
@@ -1,163 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xml:lang="en"><head>
|
||||
|
||||
[strDublinCoreMetadata]
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
|
||||
<title>
|
||||
[strPlainTitle]
|
||||
</title>
|
||||
|
||||
<!-- Made with executable version [strFullVersionInfo] -->
|
||||
|
||||
<!-- The following insertion allows you to add your own code directly to this head tag from the configuration screen -->
|
||||
|
||||
[strHeaderCode]
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
[strStyleSheet]
|
||||
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
//<![CDATA[
|
||||
|
||||
<!--
|
||||
|
||||
[inclScorm1.2]
|
||||
[strJSScorm_1_2]
|
||||
[/inclScorm1.2]
|
||||
|
||||
[strJSBrowserCheck]
|
||||
|
||||
[strJSButtons]
|
||||
|
||||
[strJSShowMessage]
|
||||
|
||||
[strJSUtilities]
|
||||
|
||||
[strJSHotPotNet]
|
||||
|
||||
[strJSJQuiz6]
|
||||
|
||||
[inclShortAnswer]
|
||||
[strJSCheckShortAnswer]
|
||||
[/inclShortAnswer]
|
||||
|
||||
[inclTimer]
|
||||
[strJSTimer]
|
||||
[/inclTimer]
|
||||
|
||||
[inclSendResults]
|
||||
[strJSSendResults]
|
||||
[/inclSendResults]
|
||||
|
||||
//-->
|
||||
|
||||
//]]>
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="StartUp()" id="TheBody" [inclScorm1.2]onunload="CheckLMSFinish()"[/inclScorm1.2]>
|
||||
|
||||
<!-- BeginTopNavButtons -->
|
||||
|
||||
[inclNavButtons]
|
||||
[strTopNavBar]
|
||||
[/inclNavButtons]
|
||||
|
||||
<!-- EndTopNavButtons -->
|
||||
|
||||
<div class="Titles">
|
||||
<h2 class="ExerciseTitle">[strExerciseTitle]</h2>
|
||||
[inclExerciseSubtitle]
|
||||
<h3 class="ExerciseSubtitle">[strExerciseSubtitle]</h3>
|
||||
[/inclExerciseSubtitle]
|
||||
[inclTimer]
|
||||
<div id="Timer"><span id="TimerText"> </span></div>
|
||||
[/inclTimer]
|
||||
|
||||
</div>
|
||||
|
||||
<div id="InstructionsDiv" class="StdDiv">
|
||||
<div id="Instructions">[strInstructions]</div>
|
||||
</div>
|
||||
|
||||
[inclReading]
|
||||
<div class="LeftContainer">
|
||||
|
||||
<div id="Reading" class="StdDiv">
|
||||
|
||||
<div id="ReadingDiv">
|
||||
[strReadingText]
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="RightContainer">
|
||||
[/inclReading]
|
||||
|
||||
|
||||
<div id="MainDiv" class="StdDiv">
|
||||
|
||||
<div id="QNav" class="QuestionNavigation">
|
||||
|
||||
<p style="text-align: right;">
|
||||
<button id="ShowMethodButton" class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOver(this)" onclick="ShowHideQuestions(); return false;">[strShowAllQuestionsCaption]</button>
|
||||
</p>
|
||||
|
||||
<div id="OneByOneReadout">
|
||||
<button id="PrevQButton" class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOver(this)" onclick="ChangeQ(-1); return false;">[strLastQCaption]</button>
|
||||
|
||||
<span id="QNumReadout" class="QNum"> </span>
|
||||
|
||||
<button id="NextQButton" class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOver(this)" onclick="ChangeQ(1); return false;">[strNextQCaption]</button>
|
||||
<br />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
[strQuestionOutput]
|
||||
|
||||
[inclKeypad]
|
||||
<div id="CharacterKeypad" class="Keypad">
|
||||
[strKeypad]
|
||||
</div>
|
||||
[/inclKeypad]
|
||||
|
||||
</div>
|
||||
|
||||
[inclReading]
|
||||
</div>
|
||||
[/inclReading]
|
||||
|
||||
<div class="Feedback" id="FeedbackDiv">
|
||||
<div class="FeedbackText" id="FeedbackContent"></div>
|
||||
<button id="FeedbackOKButton" class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="HideFeedback(); return false;"> [strOKCaption] </button>
|
||||
</div>
|
||||
|
||||
<!-- BeginBottomNavButtons -->
|
||||
|
||||
[inclNavButtons]
|
||||
[strBottomNavBar]
|
||||
[/inclNavButtons]
|
||||
|
||||
<!-- EndBottomNavButtons -->
|
||||
|
||||
<!-- BeginSubmissionForm -->
|
||||
|
||||
<!-- EndSubmissionForm -->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,668 +0,0 @@
|
||||
|
||||
[inclScorm1.2]
|
||||
//JQUIZ-SPECIFIC SCORM-RELATED JAVASCRIPT CODE
|
||||
|
||||
function SetScormScore(){
|
||||
//Reports the current score and any other information back to the LMS
|
||||
if (API != null){
|
||||
API.LMSSetValue('cmi.core.score.raw', Score);
|
||||
//Now send detailed reports about each item
|
||||
for (var i=0; i<State.length; i++){
|
||||
if (State[i] != null){
|
||||
var ItemLabel = 'Item_' + (i+1).toString();
|
||||
var ThisItemScore = '';
|
||||
var ThisItemStatus = '';
|
||||
API.LMSSetValue('cmi.objectives.' + i + '.id', 'obj'+ItemLabel);
|
||||
API.LMSSetValue('cmi.interactions.' + i + '.id', 'int'+ItemLabel);
|
||||
API.LMSSetValue('cmi.objectives.' + i + '.score.min', '0');
|
||||
API.LMSSetValue('cmi.objectives.' + i + '.score.max', '100');
|
||||
if (State[i][2] > 0){
|
||||
ThisItemScore = Math.floor(State[i][0] * 100) + '';
|
||||
ThisItemStatus = 'completed';
|
||||
}
|
||||
else{
|
||||
ThisItemScore = '0';
|
||||
ThisItemStatus = 'incomplete';
|
||||
}
|
||||
API.LMSSetValue('cmi.objectives.' + i + '.score.raw', ThisItemScore);
|
||||
API.LMSSetValue('cmi.objectives.' + i + '.status', ThisItemStatus);
|
||||
API.LMSSetValue('cmi.interactions.' + i + '.weighting', I[i][0]);
|
||||
//We can only use the performance type, because we're storing multiple responses of various types.
|
||||
API.LMSSetValue('cmi.interactions.' + i + '.type', 'performance');
|
||||
API.LMSSetValue('cmi.interactions.' + i + '.student_response', State[i][5]);
|
||||
}
|
||||
}
|
||||
|
||||
API.LMSCommit('');
|
||||
}
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
|
||||
//JQUIZ CORE JAVASCRIPT CODE
|
||||
|
||||
var CurrQNum = 0;
|
||||
var CorrectIndicator = '[strCorrectIndicator]';
|
||||
var IncorrectIndicator = '[strIncorrectIndicator]';
|
||||
var YourScoreIs = '[strYourScoreIs]';
|
||||
var ContinuousScoring = [boolContinuousScoring];
|
||||
var CorrectFirstTime = '[strCorrectFirstTime]';
|
||||
var ShowCorrectFirstTime = [boolShowCorrectFirstTime];
|
||||
var ShuffleQs = [boolShuffleQs];
|
||||
var ShuffleAs = [boolShuffleAs];
|
||||
var DefaultRight = '[strDefaultRight]';
|
||||
var DefaultWrong = '[strDefaultWrong]';
|
||||
var QsToShow = [QsToShow];
|
||||
var Score = 0;
|
||||
var Finished = false;
|
||||
var Qs = null;
|
||||
var QArray = new Array();
|
||||
var ShowingAllQuestions = false;
|
||||
var ShowAllQuestionsCaption = '[strShowAllQuestionsCaptionJS]';
|
||||
var ShowOneByOneCaption = '[strShowOneByOneCaptionJS]';
|
||||
var State = new Array();
|
||||
var Feedback = '';
|
||||
var TimeOver = false;
|
||||
var strInstructions = '';
|
||||
var Locked = false;
|
||||
|
||||
//The following variable can be used to add a message explaining that
|
||||
//the question is finished, so no further marking will take place.
|
||||
var strQuestionFinished = '';
|
||||
|
||||
function CompleteEmptyFeedback(){
|
||||
var QNum, ANum;
|
||||
for (QNum=0; QNum<I.length; QNum++){
|
||||
//Only do this if not multi-select
|
||||
if (I[QNum][2] != '3'){
|
||||
for (ANum = 0; ANum<I[QNum][3].length; ANum++){
|
||||
if (I[QNum][3][ANum][1].length < 1){
|
||||
if (I[QNum][3][ANum][2] > 0){
|
||||
I[QNum][3][ANum][1] = DefaultRight;
|
||||
}
|
||||
else{
|
||||
I[QNum][3][ANum][1] = DefaultWrong;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function SetUpQuestions(){
|
||||
var AList = new Array();
|
||||
var QList = new Array();
|
||||
var i, j;
|
||||
Qs = document.getElementById('Questions');
|
||||
while (Qs.getElementsByTagName('li').length > 0){
|
||||
QList.push(Qs.removeChild(Qs.getElementsByTagName('li')[0]));
|
||||
}
|
||||
var DumpItem = 0;
|
||||
if (QsToShow > QList.length){
|
||||
QsToShow = QList.length;
|
||||
}
|
||||
while (QsToShow < QList.length){
|
||||
DumpItem = Math.floor(QList.length*Math.random());
|
||||
for (j=DumpItem; j<(QList.length-1); j++){
|
||||
QList[j] = QList[j+1];
|
||||
}
|
||||
QList.length = QList.length-1;
|
||||
}
|
||||
if (ShuffleQs == true){
|
||||
QList = Shuffle(QList);
|
||||
}
|
||||
if (ShuffleAs == true){
|
||||
var As;
|
||||
for (var i=0; i<QList.length; i++){
|
||||
As = QList[i].getElementsByTagName('ol')[0];
|
||||
if (As != null){
|
||||
AList.length = 0;
|
||||
while (As.getElementsByTagName('li').length > 0){
|
||||
AList.push(As.removeChild(As.getElementsByTagName('li')[0]));
|
||||
}
|
||||
AList = Shuffle(AList);
|
||||
for (j=0; j<AList.length; j++){
|
||||
As.appendChild(AList[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<QList.length; i++){
|
||||
Qs.appendChild(QList[i]);
|
||||
QArray[QArray.length] = QList[i];
|
||||
}
|
||||
|
||||
//Show the first item
|
||||
QArray[0].style.display = '';
|
||||
|
||||
//Now hide all except the first item
|
||||
for (i=1; i<QArray.length; i++){
|
||||
QArray[i].style.display = 'none';
|
||||
}
|
||||
SetQNumReadout();
|
||||
|
||||
SetFocusToTextbox();
|
||||
}
|
||||
|
||||
function SetFocusToTextbox(){
|
||||
//if there's a textbox, set the focus in it
|
||||
if (QArray[CurrQNum].getElementsByTagName('input')[0] != null){
|
||||
QArray[CurrQNum].getElementsByTagName('input')[0].focus();
|
||||
//and show a keypad if there is one
|
||||
if (document.getElementById('CharacterKeypad') != null){
|
||||
document.getElementById('CharacterKeypad').style.display = 'block';
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (QArray[CurrQNum].getElementsByTagName('textarea')[0] != null){
|
||||
QArray[CurrQNum].getElementsByTagName('textarea')[0].focus();
|
||||
//and show a keypad if there is one
|
||||
if (document.getElementById('CharacterKeypad') != null){
|
||||
document.getElementById('CharacterKeypad').style.display = 'block';
|
||||
}
|
||||
}
|
||||
//This added for 6.0.4.11: hide accented character buttons if no textbox
|
||||
else{
|
||||
if (document.getElementById('CharacterKeypad') != null){
|
||||
document.getElementById('CharacterKeypad').style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ChangeQ(ChangeBy){
|
||||
//The following line prevents moving to another question until the current
|
||||
//question is answered correctly. Uncomment it to enable this behaviour.
|
||||
// if (State[CurrQNum][0] == -1){return;}
|
||||
if (((CurrQNum + ChangeBy) < 0)||((CurrQNum + ChangeBy) >= QArray.length)){return;}
|
||||
QArray[CurrQNum].style.display = 'none';
|
||||
CurrQNum += ChangeBy;
|
||||
QArray[CurrQNum].style.display = '';
|
||||
//Undocumented function added 10/12/2004
|
||||
ShowSpecialReadingForQuestion();
|
||||
SetQNumReadout();
|
||||
SetFocusToTextbox();
|
||||
}
|
||||
|
||||
var HiddenReadingShown = false;
|
||||
function ShowSpecialReadingForQuestion(){
|
||||
//Undocumented function for showing specific reading text elements which change with each question
|
||||
//Added on 10/12/2004
|
||||
if (document.getElementById('ReadingDiv') != null){
|
||||
if (HiddenReadingShown == true){
|
||||
document.getElementById('ReadingDiv').innerHTML = '';
|
||||
}
|
||||
if (QArray[CurrQNum] != null){
|
||||
//Fix for 6.0.4.25
|
||||
var Children = QArray[CurrQNum].getElementsByTagName('div');
|
||||
for (var i=0; i<Children.length; i++){
|
||||
if (Children[i].className=="HiddenReading"){
|
||||
document.getElementById('ReadingDiv').innerHTML = Children[i].innerHTML;
|
||||
HiddenReadingShown = true;
|
||||
//Hide the ShowAllQuestions button to avoid confusion
|
||||
if (document.getElementById('ShowMethodButton') != null){
|
||||
document.getElementById('ShowMethodButton').style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function SetQNumReadout(){
|
||||
document.getElementById('QNumReadout').innerHTML = (CurrQNum+1) + ' / ' + QArray.length;
|
||||
if ((CurrQNum+1) >= QArray.length){
|
||||
if (document.getElementById('NextQButton') != null){
|
||||
document.getElementById('NextQButton').style.visibility = 'hidden';
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (document.getElementById('NextQButton') != null){
|
||||
document.getElementById('NextQButton').style.visibility = 'visible';
|
||||
}
|
||||
}
|
||||
if (CurrQNum <= 0){
|
||||
if (document.getElementById('PrevQButton') != null){
|
||||
document.getElementById('PrevQButton').style.visibility = 'hidden';
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (document.getElementById('PrevQButton') != null){
|
||||
document.getElementById('PrevQButton').style.visibility = 'visible';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[strItemArray]
|
||||
|
||||
function StartUp(){
|
||||
RemoveBottomNavBarForIE();
|
||||
|
||||
//If there's only one question, no need for question navigation controls
|
||||
if (QsToShow < 2){
|
||||
document.getElementById('QNav').style.display = 'none';
|
||||
}
|
||||
|
||||
//Stash the instructions so they can be redisplayed
|
||||
strInstructions = document.getElementById('InstructionsDiv').innerHTML;
|
||||
|
||||
[inclScorm1.2]
|
||||
ScormStartUp();
|
||||
[/inclScorm1.2]
|
||||
|
||||
[inclSendResults]
|
||||
GetUserName();
|
||||
[/inclSendResults]
|
||||
|
||||
[inclPreloadImages]
|
||||
PreloadImages([PreloadImageList]);
|
||||
[/inclPreloadImages]
|
||||
|
||||
CompleteEmptyFeedback();
|
||||
|
||||
SetUpQuestions();
|
||||
ClearTextBoxes();
|
||||
CreateStatusArray();
|
||||
|
||||
[inclTimer]
|
||||
setTimeout('StartTimer()', 50);
|
||||
[/inclTimer]
|
||||
|
||||
//Check search string for q parameter
|
||||
if (document.location.search.length > 0){
|
||||
if (ShuffleQs == false){
|
||||
var JumpTo = parseInt(document.location.search.substring(1,document.location.search.length))-1;
|
||||
if (JumpTo <= QsToShow){
|
||||
ChangeQ(JumpTo);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Undocumented function added 10/12/2004
|
||||
ShowSpecialReadingForQuestion();
|
||||
}
|
||||
|
||||
function ShowHideQuestions(){
|
||||
FuncBtnOut(document.getElementById('ShowMethodButton'));
|
||||
document.getElementById('ShowMethodButton').style.display = 'none';
|
||||
if (ShowingAllQuestions == false){
|
||||
for (var i=0; i<QArray.length; i++){
|
||||
QArray[i].style.display = '';
|
||||
}
|
||||
document.getElementById('Questions').style.listStyleType = 'decimal';
|
||||
document.getElementById('OneByOneReadout').style.display = 'none';
|
||||
document.getElementById('ShowMethodButton').innerHTML = ShowOneByOneCaption;
|
||||
ShowingAllQuestions = true;
|
||||
}
|
||||
else{
|
||||
for (var i=0; i<QArray.length; i++){
|
||||
if (i != CurrQNum){
|
||||
QArray[i].style.display = 'none';
|
||||
}
|
||||
}
|
||||
document.getElementById('Questions').style.listStyleType = 'none';
|
||||
document.getElementById('OneByOneReadout').style.display = '';
|
||||
document.getElementById('ShowMethodButton').innerHTML = ShowAllQuestionsCaption;
|
||||
ShowingAllQuestions = false;
|
||||
}
|
||||
document.getElementById('ShowMethodButton').style.display = 'inline';
|
||||
}
|
||||
|
||||
function CreateStatusArray(){
|
||||
var QNum, ANum;
|
||||
//For each item in the item array
|
||||
for (QNum=0; QNum<I.length; QNum++){
|
||||
//Check if the question still exists (hasn't been nuked by showing a random selection)
|
||||
if (document.getElementById('Q_' + QNum) != null){
|
||||
State[QNum] = new Array();
|
||||
State[QNum][0] = -1; //Score for this q; -1 shows question not done yet
|
||||
State[QNum][1] = new Array(); //answers
|
||||
for (ANum = 0; ANum<I[QNum][3].length; ANum++){
|
||||
State[QNum][1][ANum] = 0; //answer not chosen yet; when chosen, will store its position in the series of choices
|
||||
}
|
||||
State[QNum][2] = 0; //tries at this q so far
|
||||
State[QNum][3] = 0; //incrementing percent-correct values of selected answers
|
||||
State[QNum][4] = 0; //penalties incurred for hints
|
||||
State[QNum][5] = ''; //Sequence of answers chosen by number
|
||||
}
|
||||
else{
|
||||
State[QNum] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[inclMultiChoice]
|
||||
|
||||
function CheckMCAnswer(QNum, ANum, Btn){
|
||||
//if question doesn't exist, bail
|
||||
if (State[QNum].length < 1){return;}
|
||||
|
||||
//Get the feedback
|
||||
Feedback = I[QNum][3][ANum][1];
|
||||
|
||||
//Now show feedback and bail if question already complete
|
||||
if (State[QNum][0] > -1){
|
||||
//Add an extra message explaining that the question
|
||||
// is finished if defined by the user
|
||||
if (strQuestionFinished.length > 0){Feedback += '<br />' + strQuestionFinished;}
|
||||
//Show the feedback
|
||||
ShowMessage(Feedback);
|
||||
return;
|
||||
}
|
||||
|
||||
//Hide the button while processing
|
||||
Btn.style.display = 'none';
|
||||
|
||||
//Increment the number of tries
|
||||
State[QNum][2]++;
|
||||
|
||||
//Add the percent-correct value of this answer
|
||||
State[QNum][3] += I[QNum][3][ANum][3];
|
||||
|
||||
//Store the try number in the answer part of the State array, for tracking purposes
|
||||
State[QNum][1][ANum] = State[QNum][2];
|
||||
if (State[QNum][5].length > 0){State[QNum][5] += ' | ';}
|
||||
State[QNum][5] += String.fromCharCode(65+ANum);
|
||||
|
||||
//Should this answer be accepted as correct?
|
||||
if (I[QNum][3][ANum][2] < 1){
|
||||
//It's wrong
|
||||
|
||||
//Mark the answer
|
||||
Btn.innerHTML = IncorrectIndicator;
|
||||
|
||||
//Remove any previous score unless exercise is finished (6.0.3.8+)
|
||||
if (Finished == false){
|
||||
WriteToInstructions(strInstructions);
|
||||
}
|
||||
|
||||
//Check whether this leaves just one MC answer unselected, in which case the Q is terminated
|
||||
var RemainingAnswer = FinalAnswer(QNum);
|
||||
if (RemainingAnswer > -1){
|
||||
//Behave as if the last answer had been selected, but give no credit for it
|
||||
//Increment the number of tries
|
||||
State[QNum][2]++;
|
||||
|
||||
//Calculate the score for this question
|
||||
CalculateMCQuestionScore(QNum);
|
||||
|
||||
//Get the overall score and add it to the feedback
|
||||
CalculateOverallScore();
|
||||
if ((ContinuousScoring == true)||(Finished == true)){
|
||||
Feedback += '<br />' + YourScoreIs + ' ' + Score + '%.';
|
||||
WriteToInstructions(YourScoreIs + ' ' + Score + '%.');
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
//It's right
|
||||
//Mark the answer
|
||||
Btn.innerHTML = CorrectIndicator;
|
||||
|
||||
//Calculate the score for this question
|
||||
CalculateMCQuestionScore(QNum);
|
||||
|
||||
//Get the overall score and add it to the feedback
|
||||
if (ContinuousScoring == true){
|
||||
CalculateOverallScore();
|
||||
if ((ContinuousScoring == true)||(Finished == true)){
|
||||
Feedback += '<br />' + YourScoreIs + ' ' + Score + '%.';
|
||||
WriteToInstructions(YourScoreIs + ' ' + Score + '%.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Show the button again
|
||||
Btn.style.display = 'inline';
|
||||
|
||||
//Finally, show the feedback
|
||||
ShowMessage(Feedback);
|
||||
|
||||
//Check whether all questions are now done
|
||||
CheckFinished();
|
||||
}
|
||||
|
||||
function CalculateMCQuestionScore(QNum){
|
||||
var Tries = State[QNum][2] + State[QNum][4]; //include tries and hint penalties
|
||||
var PercentCorrect = State[QNum][3];
|
||||
var TotAns = GetTotalMCAnswers(QNum);
|
||||
var HintPenalties = State[QNum][4];
|
||||
|
||||
//Make sure it's not already complete
|
||||
|
||||
if (State[QNum][0] < 0){
|
||||
//Allow for Hybrids
|
||||
if (HintPenalties >= 1){
|
||||
State[QNum][0] = 0;
|
||||
}
|
||||
else{
|
||||
//This line calculates the score for this question
|
||||
if (TotAns == 1){
|
||||
State[QNum][0] = 1;
|
||||
}
|
||||
else{
|
||||
State[QNum][0] = ((TotAns-((Tries*100)/State[QNum][3]))/(TotAns-1));
|
||||
}
|
||||
}
|
||||
//Fix for Safari bug added for version 6.0.3.42 (negative infinity problem)
|
||||
if ((State[QNum][0] < 0)||(State[QNum][0] == Number.NEGATIVE_INFINITY)){
|
||||
State[QNum][0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function GetTotalMCAnswers(QNum){
|
||||
var Result = 0;
|
||||
for (var ANum=0; ANum<I[QNum][3].length; ANum++){
|
||||
if (I[QNum][3][ANum][4] == 1){ //This is an MC answer
|
||||
Result++;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
function FinalAnswer(QNum){
|
||||
var UnchosenAnswers = 0;
|
||||
var FinalAnswer = -1;
|
||||
for (var ANum=0; ANum<I[QNum][3].length; ANum++){
|
||||
if (I[QNum][3][ANum][4] == 1){ //This is an MC answer
|
||||
if (State[QNum][1][ANum] < 1){ //This answer hasn't been chosen yet
|
||||
UnchosenAnswers++;
|
||||
FinalAnswer = ANum;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (UnchosenAnswers == 1){
|
||||
return FinalAnswer;
|
||||
}
|
||||
else{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
[/inclMultiChoice]
|
||||
|
||||
[inclMultiSelect]
|
||||
|
||||
function CheckMultiSelAnswer(QNum){
|
||||
//bail if question doesn't exist or exercise finished
|
||||
if ((State[QNum].length < 1)||(Finished == true)){return;}
|
||||
|
||||
//Increment the tries for this question
|
||||
State[QNum][2]++;
|
||||
|
||||
var ShouldBeChecked;
|
||||
var Matches = 0;
|
||||
if (State[QNum][5].length > 0){State[QNum][5] += ' | ';}
|
||||
|
||||
//Check if there are any mismatches
|
||||
Feedback = '';
|
||||
var CheckBox = null;
|
||||
for (var ANum=0; ANum<I[QNum][3].length; ANum++){
|
||||
CheckBox = document.getElementById('Q_' + QNum + '_' + ANum + '_Chk');
|
||||
if (CheckBox.checked == true){
|
||||
State[QNum][5] += 'Y';
|
||||
}
|
||||
else{
|
||||
State[QNum][5] += 'N';
|
||||
}
|
||||
ShouldBeChecked = (I[QNum][3][ANum][2] == 1);
|
||||
if (ShouldBeChecked == CheckBox.checked){
|
||||
Matches++;
|
||||
}
|
||||
else{
|
||||
Feedback = I[QNum][3][ANum][1];
|
||||
}
|
||||
}
|
||||
//Add the hit readout
|
||||
Feedback = Matches + ' / ' + I[QNum][3].length + '<br />' + Feedback;
|
||||
if (Matches == I[QNum][3].length){
|
||||
//It's right
|
||||
CalculateMultiSelQuestionScore(QNum);
|
||||
if (ContinuousScoring == true){
|
||||
CalculateOverallScore();
|
||||
if ((ContinuousScoring == true)||(Finished == true)){
|
||||
Feedback += '<br />' + YourScoreIs + ' ' + Score + '%.';
|
||||
WriteToInstructions(YourScoreIs + ' ' + Score + '%.');
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
//It's wrong -- Remove any previous score unless exercise is finished (6.0.3.8+)
|
||||
if (Finished == false){
|
||||
WriteToInstructions(strInstructions);
|
||||
}
|
||||
}
|
||||
|
||||
//Show the feedback
|
||||
ShowMessage(Feedback);
|
||||
|
||||
//Check whether all questions are now done
|
||||
CheckFinished();
|
||||
}
|
||||
|
||||
function CalculateMultiSelQuestionScore(QNum){
|
||||
var Tries = State[QNum][2];
|
||||
var TotAns = State[QNum][1].length;
|
||||
|
||||
//Make sure it's not already complete
|
||||
if (State[QNum][0] < 0){
|
||||
State[QNum][0] = (TotAns - (Tries-1)) / TotAns;
|
||||
if (State[QNum][0] < 0){
|
||||
State[QNum][0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[/inclMultiSelect]
|
||||
|
||||
function CalculateOverallScore(){
|
||||
var TotalWeighting = 0;
|
||||
var TotalScore = 0;
|
||||
|
||||
for (var QNum=0; QNum<State.length; QNum++){
|
||||
if (State[QNum] != null){
|
||||
if (State[QNum][0] > -1){
|
||||
TotalWeighting += I[QNum][0];
|
||||
TotalScore += (I[QNum][0] * State[QNum][0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TotalWeighting > 0){
|
||||
Score = Math.floor((TotalScore/TotalWeighting)*100);
|
||||
}
|
||||
else{
|
||||
//if TotalWeighting is 0, no questions so far have any value, so
|
||||
//no penalty should be shown.
|
||||
Score = 100;
|
||||
}
|
||||
}
|
||||
|
||||
function CheckFinished(){
|
||||
var FB = '';
|
||||
var AllDone = true;
|
||||
for (var QNum=0; QNum<State.length; QNum++){
|
||||
if (State[QNum] != null){
|
||||
if (State[QNum][0] < 0){
|
||||
AllDone = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (AllDone == true){
|
||||
|
||||
//Report final score and submit if necessary
|
||||
CalculateOverallScore();
|
||||
FB = YourScoreIs + ' ' + Score + '%.';
|
||||
if (ShowCorrectFirstTime == true){
|
||||
var CFT = 0;
|
||||
for (QNum=0; QNum<State.length; QNum++){
|
||||
if (State[QNum] != null){
|
||||
if (State[QNum][0] >= 1){
|
||||
CFT++;
|
||||
}
|
||||
}
|
||||
}
|
||||
FB += '<br />' + CorrectFirstTime + ' ' + CFT + '/' + QsToShow;
|
||||
}
|
||||
WriteToInstructions(FB);
|
||||
|
||||
Finished == true;
|
||||
[inclTimer]
|
||||
window.clearInterval(Interval);
|
||||
[/inclTimer]
|
||||
|
||||
[inclScorm1.2]
|
||||
if (TimeOver == true){
|
||||
SetScormTimedOut();
|
||||
}
|
||||
else{
|
||||
SetScormComplete();
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
|
||||
TimeOver = true;
|
||||
Locked = true;
|
||||
|
||||
[inclSendResults]
|
||||
setTimeout('SendResults(' + Score + ')', 50);
|
||||
[/inclSendResults]
|
||||
|
||||
Finished = true;
|
||||
Detail = '<?xml version="1.0"?><hpnetresult><fields>';
|
||||
for (QNum=0; QNum<State.length; QNum++){
|
||||
if (State[QNum] != null){
|
||||
if (State[QNum][5].length > 0){
|
||||
Detail += '<field><fieldname>Question #' + (QNum+1) + '</fieldname><fieldtype>question-tracking</fieldtype><fieldlabel>Q ' + (QNum+1) + '</fieldlabel><fieldlabelid>QuestionTrackingField</fieldlabelid><fielddata>' + State[QNum][5] + '</fielddata></field>';
|
||||
}
|
||||
}
|
||||
}
|
||||
Detail += '</fields></hpnetresult>';
|
||||
setTimeout('Finish()', SubmissionTimeout);
|
||||
}
|
||||
[inclScorm1.2]
|
||||
else{
|
||||
SetScormIncomplete();
|
||||
}
|
||||
[/inclScorm1.2]
|
||||
}
|
||||
|
||||
[inclTimer]
|
||||
function TimesUp(){
|
||||
document.getElementById('Timer').innerHTML = '[strTimesUp]';
|
||||
[inclPreloadImages]
|
||||
RefreshImages();
|
||||
[/inclPreloadImages]
|
||||
TimeOver = true;
|
||||
Finished = true;
|
||||
ShowMessage('[strTimesUp]');
|
||||
|
||||
//Set all remaining scores to 0
|
||||
for (var QNum=0; QNum<State.length; QNum++){
|
||||
if (State[QNum] != null){
|
||||
if (State[QNum][0] < 0){
|
||||
State[QNum][0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
CheckFinished();
|
||||
}
|
||||
[/inclTimer]
|
||||
@@ -1,94 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xml:lang="en"><head>
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
|
||||
<title>
|
||||
[strPlainIndexTitle]
|
||||
</title>
|
||||
|
||||
<!-- Made with executable version [strFullVersionInfo] -->
|
||||
|
||||
<!-- The following insertion allows you to add your own code directly to this head tag from the configuration screen -->
|
||||
|
||||
[strHeaderCode]
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
body{
|
||||
font-family: [strFontFace];
|
||||
[inclPageBGColor] background-color: [strPageBGColor];[/inclPageBGColor]
|
||||
color: [strTextColor];
|
||||
[inclGraphicURL] background-image: url([strGraphicURL]);[/inclGraphicURL]
|
||||
padding-left: 5%;
|
||||
padding-right: 5%;
|
||||
font-size: [strFontSize];
|
||||
}
|
||||
|
||||
div.Titles{
|
||||
padding: 0.5em;;
|
||||
text-align: center;
|
||||
color: [strTitleColor];
|
||||
}
|
||||
|
||||
.ExerciseTitle{
|
||||
font-size: 140%;
|
||||
color: [strTitleColor];
|
||||
}
|
||||
|
||||
.ExerciseSubtitle{
|
||||
font-size: 120%;
|
||||
color: [strTitleColor];
|
||||
}
|
||||
|
||||
div.IndexDiv{
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 2em;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
text-align: center;
|
||||
width: 40%;
|
||||
background-color: [strExBGColor];
|
||||
color: [strTextColor];
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.Index{
|
||||
text-align: left;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
a{
|
||||
color: [strLinkColor];
|
||||
}
|
||||
|
||||
a:visited{
|
||||
color: [strVLinkColor];
|
||||
}
|
||||
|
||||
a:hover{
|
||||
color: [strLinkColor];
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="Titles">
|
||||
<h2 class="ExerciseTitle">[strIndexTitle]</h2>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center;">
|
||||
<div class="IndexDiv">
|
||||
<ul class="Index">
|
||||
|
||||
[BeginIndexItem]<li><a href="[strIndexItemURL]">[strIndexItemTitle]</a> </li>[EndIndexItem]
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body></html>
|
||||
@@ -1,29 +0,0 @@
|
||||
|
||||
<!-- BeginMasherV6NavBar -->
|
||||
|
||||
<!-- BeginNavBarHeaderCodeInsertedByMasher -->
|
||||
<style type="text/css">
|
||||
|
||||
[strNavBarStyle]
|
||||
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
<!--
|
||||
|
||||
[strNavBarJS]
|
||||
|
||||
//-->
|
||||
//]]>
|
||||
</script>
|
||||
<!-- EndNavBarHeaderCodeInsertedByMasher -->
|
||||
|
||||
<!-- BeginNavBarInsertedByMasher -->
|
||||
|
||||
<!-- BeginRepeatCode -->
|
||||
[strTopNavBar]
|
||||
<!-- EndRepeatCode -->
|
||||
|
||||
<!-- EndNavBarInsertedByMasher -->
|
||||
<!-- EndMasherV6NavBar -->
|
||||
@@ -1,35 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xml:lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
|
||||
<title>
|
||||
Testing browser check code
|
||||
</title>
|
||||
<style type="text/css">
|
||||
|
||||
</style>
|
||||
|
||||
<script type="text/javascript" src="hp6browsercheck.js_"></script>
|
||||
|
||||
<base href="http://hotpot.uvic.ca/" />
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
for (var i in C){
|
||||
document.write('C.' + i + '=' + C[i].toString() + '<br />');
|
||||
}
|
||||
//var BH = document.getElementsByTagName('base')[0].getAttribute('href');
|
||||
//alert(BH);
|
||||
//-->
|
||||
</script>
|
||||
|
||||
<a href="index.htm">Go</a>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
/// Code fragment to define the version of hotpot
|
||||
/// This fragment is called by moodle_needs_upgrading() and /admin/index.php
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
$module->version = 2008011200; // release date of this version (see note below)
|
||||
$module->release = 'v2.4.2'; // human-friendly version name (used in mod/hotpot/lib.php)
|
||||
$module->requires = 2007101509; // Requires this Moodle version
|
||||
$module->cron = 0; // period for cron to check this module (secs)
|
||||
// interpretation of YYYYMMDDXY version numbers
|
||||
// YYYY : year
|
||||
// MM : month
|
||||
// DD : day
|
||||
// X : point release version 1,2,3 etc
|
||||
// Y : increment between point releases
|
||||
|
||||
@@ -1,528 +0,0 @@
|
||||
<?PHP
|
||||
|
||||
/// This page prints a hotpot quiz
|
||||
if (defined('HOTPOT_FIRST_ATTEMPT') && HOTPOT_FIRST_ATTEMPT==false) {
|
||||
// this script is being included (by attempt.php)
|
||||
} else {
|
||||
// this script is being called directly from the browser
|
||||
define('HOTPOT_FIRST_ATTEMPT', true);
|
||||
require_once("../../config.php");
|
||||
require_once("lib.php");
|
||||
|
||||
$id = optional_param('id', 0, PARAM_INT); // Course Module ID, or
|
||||
$hp = optional_param('hp', 0, PARAM_INT); // hotpot ID
|
||||
|
||||
if ($id) {
|
||||
$PAGE->set_url('/mod/hotpot/report.php', array('id'=>$id));
|
||||
if (! $cm = get_coursemodule_from_id('hotpot', $id)) {
|
||||
print_error('invalidcoursemodule');
|
||||
}
|
||||
if (! $course = $DB->get_record("course", array("id"=>$cm->course))) {
|
||||
print_error('coursemisconf');
|
||||
}
|
||||
if (! $hotpot = $DB->get_record("hotpot", array("id"=>$cm->instance))) {
|
||||
print_error('invalidcoursemodule');
|
||||
}
|
||||
|
||||
} else {
|
||||
$PAGE->set_url('/mod/hotpot/report.php', array('hp'=>$hp));
|
||||
if (! $hotpot = $DB->get_record("hotpot", array("id"=>$hp))) {
|
||||
print_error('invalidhotpotid', 'hotpot');
|
||||
}
|
||||
if (! $course = $DB->get_record("course", array("id"=>$hotpot->course))) {
|
||||
print_error('coursemisconf');
|
||||
}
|
||||
if (! $cm = get_coursemodule_from_instance("hotpot", $hotpot->id, $course->id)) {
|
||||
print_error('invalidcoursemodule');
|
||||
}
|
||||
|
||||
}
|
||||
require_login($course, true, $cm);
|
||||
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
|
||||
require_capability('mod/hotpot:attempt', $context, $USER->id);
|
||||
}
|
||||
// set nextpage (for error messages)
|
||||
$nextpage = "$CFG->wwwroot/course/view.php?id=$course->id";
|
||||
// header strings
|
||||
$title = format_string($course->shortname.': '.$hotpot->name, true);
|
||||
$heading = $course->fullname;
|
||||
|
||||
$button = update_module_button($cm->id, $course->id, get_string("modulename", "hotpot"));
|
||||
$button = '<div style="font-size:0.75em;">'.$button.'</div>';
|
||||
|
||||
$PAGE->set_title($title);
|
||||
$PAGE->set_heading($heading);
|
||||
$PAGE->set_button($button);
|
||||
|
||||
$time = time();
|
||||
$hppassword = optional_param('hppassword', '', PARAM_RAW);
|
||||
if (HOTPOT_FIRST_ATTEMPT && !has_capability('mod/hotpot:grade', $context)) {
|
||||
// check this quiz is available to this student
|
||||
// error message, if quiz is unavailable
|
||||
$error = '';
|
||||
// check quiz is visible
|
||||
if (!hotpot_is_visible($cm)) {
|
||||
$error = get_string("activityiscurrentlyhidden");
|
||||
// check network address
|
||||
} else if ($hotpot->subnet && !address_in_subnet(getremoteaddr(), $hotpot->subnet)) {
|
||||
$error = get_string("subneterror", "quiz");
|
||||
// check number of attempts
|
||||
} else if ($hotpot->attempts && $hotpot->attempts <= $DB->count_records_select('hotpot_attempts', 'hotpot=? AND userid=?', array($hotpot->id, $USER->id), 'COUNT(DISTINCT clickreportid)')) {
|
||||
$error = get_string("nomoreattempts", "quiz");
|
||||
// get password
|
||||
} else if ($hotpot->password && empty($hppassword)) {
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($hotpot->name);
|
||||
$boxalign = 'center';
|
||||
$boxwidth = 500;
|
||||
if (trim(strip_tags($hotpot->summary))) {
|
||||
echo $OUTPUT->box_start("generalbox boxalign$boxalign");
|
||||
print '<div class="mdl-align">'.format_text($hotpot->summary)."</div>\n";
|
||||
echo $OUTPUT->box_end();
|
||||
print "<br />\n";
|
||||
}
|
||||
print '<form id="passwordform" method="post" action="view.php?id='.$cm->id.'">'."\n";
|
||||
echo $OUTPUT->box_start("generalbox boxalign$boxalign");
|
||||
print '<div class="mdl-align">';
|
||||
print get_string('requirepasswordmessage', 'quiz').'<br /><br />';
|
||||
print '<b>'.get_string('password').':</b> ';
|
||||
print '<input name="hppassword" type="password" value="" /> ';
|
||||
print '<input type="submit" value="'.get_string("ok").'" /> ';
|
||||
print "</div>\n";
|
||||
echo $OUTPUT->box_end();
|
||||
print "</form>\n";
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
// check password
|
||||
} else if ($hotpot->password && strcmp($hotpot->password, $hppassword)) {
|
||||
$error = get_string("passworderror", "quiz");
|
||||
$nextpage = "view.php?id=$cm->id";
|
||||
// check quiz is open
|
||||
} else if ($hotpot->timeopen && $hotpot->timeopen > $time) {
|
||||
$error = get_string("quiznotavailable", "quiz", userdate($hotpot->timeopen))."<br />\n";
|
||||
// check quiz is not closed
|
||||
} else if ($hotpot->timeclose && $hotpot->timeclose < $time) {
|
||||
$error = get_string("quizclosed", "quiz", userdate($hotpot->timeclose))."<br />\n";
|
||||
}
|
||||
if ($error) {
|
||||
echo $OUTPUT->header();
|
||||
notice($error, $nextpage);
|
||||
//
|
||||
// script stops here, if quiz is unavailable to student
|
||||
//
|
||||
}
|
||||
}
|
||||
$available_msg = '';
|
||||
if (!empty($hotpot->timeclose) && $hotpot->timeclose > $time) {
|
||||
// quiz is available until 'timeclose'
|
||||
$available_msg = get_string("quizavailable", "quiz", userdate($hotpot->timeclose))."<br />\n";
|
||||
}
|
||||
// open and parse the source file
|
||||
if(!$hp = new hotpot_xml_quiz($hotpot)) {
|
||||
print_error('quizunavailable', 'hotpot');
|
||||
}
|
||||
$get_js = optional_param('js', '', PARAM_ALPHA);
|
||||
$get_css = optional_param('css', '', PARAM_ALPHA);
|
||||
$framename = optional_param('framename', '', PARAM_ALPHA);
|
||||
// look for <frameset> (HP5 v5)
|
||||
$frameset = '';
|
||||
$frameset_tags = '';
|
||||
if (preg_match_all('|<frameset([^>]*)>(.*?)</frameset>|is', $hp->html, $matches)) {
|
||||
$last = count($matches[0])-1;
|
||||
$frameset = $matches[2][$last];
|
||||
$frameset_tags = $matches[1][$last];
|
||||
}
|
||||
// if HTML is being requested ...
|
||||
if (empty($get_js) && empty($get_css)) {
|
||||
if (empty($frameset)) {
|
||||
// HP v6
|
||||
if ($hotpot->navigation==HOTPOT_NAVIGATION_FRAME || $hotpot->navigation==HOTPOT_NAVIGATION_IFRAME) {
|
||||
$get_html = ($framename=='main') ? true : false;
|
||||
} else {
|
||||
$get_html = true;
|
||||
}
|
||||
} else {
|
||||
// HP5 v5
|
||||
$get_html = empty($framename) ? true : false;
|
||||
}
|
||||
if ($get_html) {
|
||||
|
||||
if (HOTPOT_FIRST_ATTEMPT) {
|
||||
add_to_log($course->id, "hotpot", "view", "view.php?id=$cm->id", "$hotpot->id", "$cm->id");
|
||||
|
||||
$attemptid = hotpot_add_attempt($hotpot->id);
|
||||
}
|
||||
$hp->adjust_media_urls();
|
||||
if (empty($frameset)) {
|
||||
// HP6 v6
|
||||
$targetframe = '';
|
||||
switch ($hotpot->navigation) {
|
||||
case HOTPOT_NAVIGATION_BUTTONS:
|
||||
// do nothing (i.e. leave buttons as they are)
|
||||
break;
|
||||
case HOTPOT_NAVIGATION_GIVEUP:
|
||||
$hp->insert_giveup_form($attemptid, '<!-- BeginTopNavButtons -->', '<!-- EndTopNavButtons -->');
|
||||
break;
|
||||
case HOTPOT_NAVIGATION_FRAME:
|
||||
case HOTPOT_NAVIGATION_IFRAME:
|
||||
if (empty($CFG->framename)) {
|
||||
$targetframe = '_top';
|
||||
} else {
|
||||
$targetframe = $CFG->framename;
|
||||
}
|
||||
if ($pos = strpos($hp->html, '</body>')) {
|
||||
$insert = ''
|
||||
.'<script type="text/javascript">'."\n"
|
||||
.'//<![CDATA['."\n"
|
||||
."var obj = document.getElementsByTagName('a');\n"
|
||||
."if (obj) {\n"
|
||||
." var i_max = obj.length;\n"
|
||||
." for (var i=0; i<i_max; i++) {\n"
|
||||
." if (obj[i].href && ! obj[i].target) {\n"
|
||||
." obj[i].target = '$targetframe';\n"
|
||||
." }\n"
|
||||
." }\n"
|
||||
." var obj = null;\n"
|
||||
."}\n"
|
||||
."var obj = document.getElementsByTagName('form');\n"
|
||||
."if (obj) {\n"
|
||||
." var i_max = obj.length;\n"
|
||||
." for (var i=0; i<i_max; i++) {\n"
|
||||
." if (obj[i].action && ! obj[i].target) {\n"
|
||||
." obj[i].target = '$targetframe';\n"
|
||||
." }\n"
|
||||
." }\n"
|
||||
." var obj = null;\n"
|
||||
."}\n"
|
||||
.'//]]>'."\n"
|
||||
.'</script>'."\n"
|
||||
;
|
||||
$hp->html = substr_replace($hp->html, $insert, $pos, 0);
|
||||
}
|
||||
$hp->remove_nav_buttons();
|
||||
break;
|
||||
default:
|
||||
$hp->remove_nav_buttons();
|
||||
}
|
||||
if (isset($hp->real_outputformat) && $hp->real_outputformat==HOTPOT_OUTPUTFORMAT_MOBILE) {
|
||||
$hp->insert_submission_form($attemptid, '<!-- BeginSubmissionForm -->', '<!-- EndSubmissionForm -->', true);
|
||||
} else {
|
||||
$hp->insert_submission_form($attemptid, '<!-- BeginSubmissionForm -->', '<!-- EndSubmissionForm -->', false, $targetframe);
|
||||
}
|
||||
} else {
|
||||
// HP5 v5
|
||||
switch ($hotpot->navigation) {
|
||||
case HOTPOT_NAVIGATION_BUTTONS:
|
||||
// convert URLs in nav buttons
|
||||
break;
|
||||
case HOTPOT_NAVIGATION_GIVEUP:
|
||||
// $hp->insert_giveup_form($attemptid, '<!-- BeginTopNavButtons -->', '<!-- EndTopNavButtons -->');
|
||||
break;
|
||||
default:
|
||||
// remove navigation buttons
|
||||
$hp->html = preg_replace('#NavBar\+=(.*);#', '', $hp->html);
|
||||
}
|
||||
$hp->insert_submission_form($attemptid, "var NavBar='", "';");
|
||||
}
|
||||
}
|
||||
}
|
||||
//FEEDBACK = new Array();
|
||||
//FEEDBACK[0] = ''; // url of feedback page/script
|
||||
//FEEDBACK[1] = ''; // array of array('teachername', 'value');
|
||||
//FEEDBACK[2] = ''; // 'student name' [formmail only]
|
||||
//FEEDBACK[3] = ''; // 'student email' [formmail only]
|
||||
//FEEDBACK[4] = ''; // window width
|
||||
//FEEDBACK[5] = ''; // window height
|
||||
//FEEDBACK[6] = ''; // 'Send a message to teacher' [prompt/button text]
|
||||
//FEEDBACK[7] = ''; // 'Title'
|
||||
//FEEDBACK[8] = ''; // 'Teacher'
|
||||
//FEEDBACK[9] = ''; // 'Message'
|
||||
//FEEDBACK[10] = ''; // 'Close this window'
|
||||
$feedback = array();
|
||||
switch ($hotpot->studentfeedback) {
|
||||
case HOTPOT_FEEDBACK_NONE:
|
||||
// do nothing
|
||||
break;
|
||||
case HOTPOT_FEEDBACK_WEBPAGE:
|
||||
if (empty($hotpot->studentfeedbackurl)) {
|
||||
$hotpot->studentfeedback = HOTPOT_FEEDBACK_NONE;
|
||||
} else {
|
||||
$feedback[0] = "'$hotpot->studentfeedbackurl'";
|
||||
}
|
||||
break;
|
||||
case HOTPOT_FEEDBACK_FORMMAIL:
|
||||
$teachers = hotpot_feedback_teachers($course, $hotpot);
|
||||
if (empty($teachers) || empty($hotpot->studentfeedbackurl)) {
|
||||
$hotpot->studentfeedback = HOTPOT_FEEDBACK_NONE;
|
||||
} else {
|
||||
$feedback[0] = "'$hotpot->studentfeedbackurl'";
|
||||
$feedback[1] = $teachers;
|
||||
$feedback[2] = "'".fullname($USER)."'";
|
||||
$feedback[3] = "'".$USER->email."'";
|
||||
$feedback[4] = 500; // width
|
||||
$feedback[5] = 300; // height
|
||||
}
|
||||
break;
|
||||
case HOTPOT_FEEDBACK_MOODLEFORUM:
|
||||
$module = $DB->get_record('modules', array('name'=>'forum'));
|
||||
$forums = $DB->get_records('forum', array('course'=>$course->id));
|
||||
if (empty($module) || empty($module->visible) || empty($forums)) {
|
||||
$hotpot->studentfeedback = HOTPOT_FEEDBACK_NONE;
|
||||
} else {
|
||||
$feedback[0] = "'$CFG->wwwroot/mod/forum/index.php?id=$course->id'";
|
||||
}
|
||||
break;
|
||||
case HOTPOT_FEEDBACK_MOODLEMESSAGING:
|
||||
$teachers = hotpot_feedback_teachers($course, $hotpot);
|
||||
if (empty($CFG->messaging) || empty($teachers)) {
|
||||
$hotpot->studentfeedback = HOTPOT_FEEDBACK_NONE;
|
||||
} else {
|
||||
$feedback[0] = "'$CFG->wwwroot/message/discussion.php?id='";
|
||||
$feedback[1] = $teachers;
|
||||
$feedback[4] = 400; // width
|
||||
$feedback[5] = 500; // height
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// do nothing
|
||||
}
|
||||
if ($hotpot->studentfeedback != HOTPOT_FEEDBACK_NONE) {
|
||||
$feedback[6] = "'Send a message to teacher'";
|
||||
$feedback[7] = "'Title'";
|
||||
$feedback[8] = "'Teacher'";
|
||||
$feedback[9] = "'Message'";
|
||||
$feedback[10] = "'Close this window'";
|
||||
$js = '';
|
||||
foreach ($feedback as $i=>$str) {
|
||||
$js .= 'FEEDBACK['.$i."] = $str;\n";
|
||||
}
|
||||
$js = '<script type="text/javascript">'."\n//<![CDATA[\n"."FEEDBACK = new Array();\n".$js."//]]>\n</script>\n";
|
||||
$hp->html = preg_replace('|</head>|i', "$js</head>", $hp->html, 1);
|
||||
}
|
||||
// insert hot-potatoes.js
|
||||
$hp->insert_script(HOTPOT_JS);
|
||||
// get Moodle pageid and pageclass
|
||||
$pageid = $PAGE->pagetype;
|
||||
|
||||
// extract first <head> tag
|
||||
$head = '';
|
||||
$pattern = '|<head([^>]*)>(.*?)</head>|is';
|
||||
if (preg_match($pattern, $hp->html, $matches)) {
|
||||
$head = $matches[2];
|
||||
// remove <title>
|
||||
$head = preg_replace('|<title[^>]*>(.*?)</title>|is', '', $head);
|
||||
}
|
||||
// extract <style> tags (and remove from $head)
|
||||
$styles = '';
|
||||
$pattern = '|<style([^>]*)>(.*?)</style>|is';
|
||||
if (preg_match_all($pattern, $head, $matches)) {
|
||||
$count = count($matches[0]);
|
||||
for ($i=0; $i<$count; $i++) {
|
||||
if ($pageid) {
|
||||
$styles .= str_replace('TheBody', $pageid, $matches[0][$i])."\n";
|
||||
}
|
||||
$head = str_replace($matches[0][$i], '', $head);
|
||||
}
|
||||
}
|
||||
// extract <script> tags (and remove from $head)
|
||||
$scripts = '';
|
||||
$pattern = '|<script([^>]*)>(.*?)</script>|is';
|
||||
if (preg_match_all($pattern, $head, $matches)) {
|
||||
$count = count($matches[0]);
|
||||
for ($i=0; $i<$count; $i++) {
|
||||
if ($pageid) {
|
||||
$scripts .= str_replace('TheBody', $pageid, $matches[0][$i])."\n";
|
||||
}
|
||||
$head = str_replace($matches[0][$i], '', $head);
|
||||
}
|
||||
}
|
||||
// extract <body> tags
|
||||
$body = '';
|
||||
$body_tags = '';
|
||||
$footer = '</html>';
|
||||
// HP6 and some HP5 (v6 and v4)
|
||||
if (preg_match('|<body'.'([^>]*'.'onLoad=(["\'])(.*?)(\\2)'.'[^>]*)'.'>(.*)</body>|is', $hp->html, $matches)) {
|
||||
$body = $matches[5]; // contents of first <body onload="StartUp()">...</body> block
|
||||
if ($pageid) {
|
||||
$body_tags = str_replace(' id="TheBody"', '', $matches[1]);
|
||||
}
|
||||
// workaround to ensure javascript onload routine for quiz is always executed
|
||||
// $body_tags will only be inserted into the <body ...> tag
|
||||
// if it is included in the theme/$CFG->theme/header.html,
|
||||
// so some old or modified themes may not insert $body_tags
|
||||
$body .= ""
|
||||
. '<script type="text/javascript">'."\n"
|
||||
. "//<![CDATA[\n"
|
||||
. " var s = (typeof(window.onload)=='function') ? onload.toString() : '';\n"
|
||||
. " if (s.indexOf('".$matches[3]."')<0) {\n"
|
||||
. " if (s=='') {\n" // no previous onload
|
||||
. " window.onload = new Function('".$matches[3]."');\n"
|
||||
. " } else {\n"
|
||||
. " window.onload_hotpot = onload;\n"
|
||||
. " window.onload = new Function('window.onload_hotpot();'+'".$matches[3]."');\n"
|
||||
. " }\n"
|
||||
. " }\n"
|
||||
. "//]]>\n"
|
||||
. "</script>\n"
|
||||
;
|
||||
$footer = '</body>'.$footer;
|
||||
} else if ($frameset) { // HP5 v5
|
||||
switch ($framename) {
|
||||
case 'top':
|
||||
echo $OUTPUT->header();
|
||||
print $footer;
|
||||
break;
|
||||
default:
|
||||
// add a HotPot navigation frame at the top of the page
|
||||
//$rows = empty($CFG->resource_framesize) ? 85 : $CFG->resource_framesize;
|
||||
//$frameset = "\n\t".'<frame src="view.php?id='.$cm->id.'&framename=top" frameborder="0" name="top"></frame>'.$frameset;
|
||||
//$frameset_tags = preg_replace('|rows="(.*?)"|', 'rows="'.$rows.',\\1"', $frameset_tags);
|
||||
// put navigation into var NavBar='';
|
||||
// add form to TopFrame in "WriteFeedback" function
|
||||
// OR add form to BottomFrame in "DisplayExercise" function
|
||||
// submission form: '<!-- BeginSubmissionForm -->', '<!-- EndSubmissionForm -->'
|
||||
// give up form: '<!-- BeginTopNavButtons -->', '<!-- EndTopNavButtons -->'
|
||||
print "<html>\n";
|
||||
print "<head>\n<title>$title</title>\n$styles\n$scripts</head>\n";
|
||||
print "<frameset$frameset_tags>$frameset</frameset>\n";
|
||||
print "</html>\n";
|
||||
break;
|
||||
} // end switch $framename
|
||||
exit;
|
||||
// other files (maybe not even a HotPots)
|
||||
} else if (preg_match('|<body'.'([^>]*)'.'>(.*)</body>|is', $hp->html, $matches)) {
|
||||
$body = $matches[2];
|
||||
$body_tags = $matches[1];
|
||||
}
|
||||
// print the quiz to the browser
|
||||
if ($get_js) {
|
||||
print($scripts);
|
||||
exit;
|
||||
}
|
||||
if ($get_css) {
|
||||
print($styles);
|
||||
exit;
|
||||
}
|
||||
// closing tags for "page" and "content" divs
|
||||
$footer = '</div></div>'.$footer;
|
||||
switch ($hotpot->navigation) {
|
||||
case HOTPOT_NAVIGATION_BAR:
|
||||
$PAGE->set_title($title);
|
||||
$PAGE->set_heading($heading);
|
||||
$PAGE->set_button($button);
|
||||
echo $OUTPUT->header();
|
||||
if (!empty($available_msg)) {
|
||||
echo $OUTPUT->notification($available_msg);
|
||||
}
|
||||
print $body.$footer;
|
||||
break;
|
||||
case HOTPOT_NAVIGATION_FRAME:
|
||||
switch ($framename) {
|
||||
case 'top':
|
||||
echo $OUTPUT->header();
|
||||
print $footer;
|
||||
break;
|
||||
case 'main':
|
||||
if (!empty($available_msg)) {
|
||||
$hp->insert_message('<!-- BeginTopNavButtons -->', $available_msg);
|
||||
}
|
||||
print $hp->html;
|
||||
break;
|
||||
default:
|
||||
$txtframesetinfo = get_string('framesetinfo');
|
||||
$txttoptitle = get_string('navigation', 'hotpot');
|
||||
$txtmaintitle = get_string('modulename', 'hotpot');
|
||||
|
||||
$rows = empty($CFG->resource_framesize) ? 85 : $CFG->resource_framesize;
|
||||
|
||||
@header('Content-Type: text/html; charset=utf-8');
|
||||
print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Frameset//EN\" \"http://www.w3.org/TR/html4/frameset.dtd\">\n";
|
||||
print "<html>\n";
|
||||
print "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n";
|
||||
print "<head><title>$title</title></head>\n";
|
||||
print "<frameset rows=$rows,*>\n";
|
||||
print "<frame title=\"$txttoptitle\" src=\"view.php?id=$cm->id&framename=top\">\n";
|
||||
print "<frame title=\"$txtmaintitle\" src=\"view.php?id=$cm->id&framename=main\">\n";
|
||||
print "<noframes>\n";
|
||||
print "<p>$txtframesetinfo</p>\n";
|
||||
print "<ul><li><a href=\"view.php?id=$cm->id&framename=top\">$txttoptitle</a></li>\n";
|
||||
print "<li><a href=\"view.php?id=$cm->id&framename=main\">$txtmaintitle</a></li></ul>\n";
|
||||
print "</noframes>\n";
|
||||
print "</frameset>\n";
|
||||
print "</html>\n";
|
||||
break;
|
||||
} // end switch $framename
|
||||
break;
|
||||
case HOTPOT_NAVIGATION_IFRAME:
|
||||
switch ($framename) {
|
||||
case 'main':
|
||||
print $hp->html;
|
||||
break;
|
||||
default:
|
||||
// set iframe attributes
|
||||
$iframe_id = 'hotpot_embed_object';
|
||||
$iframe_src = 'view.php?id='.$cm->id.'&framename=main';
|
||||
|
||||
$PAGE->requires->js('/mod/hotpot/iframe.js');
|
||||
$PAGE->requires->js_function_call('set_embed_object_height', array($iframe_id), true);
|
||||
|
||||
echo $OUTPUT->header();
|
||||
if (!empty($available_msg)) {
|
||||
echo $OUTPUT->notification($available_msg);
|
||||
}
|
||||
|
||||
// for XHTML 1.0 Strict compatability, the embedded page should be implemented
|
||||
// using an <object> not an <iframe>. However, IE <object>'s are problematic
|
||||
// (links and forms cannot escape), so we use conditional comments to display
|
||||
// an <iframe> in IE and an <object> in other browsers
|
||||
|
||||
// print the html element to hold the embedded html page
|
||||
// Note: the iframe in IE needs a "name" attribute for the resizing to work
|
||||
print '<!--[if IE]>'."\n";
|
||||
print '<iframe id="'.$iframe_id.'" name="'.$iframe_id.'_name" src="'.$iframe_src.'" width="100%" height="100%"></iframe>'."\n";
|
||||
print '<![endif]-->'."\n";
|
||||
print '<!--[if !IE]> <-->'."\n";
|
||||
print '<object id="'.$iframe_id.'" type="text/html" data="'.$iframe_src.'" width="100%" height="100%"></object>'."\n";
|
||||
print '<!--> <![endif]-->'."\n";
|
||||
|
||||
print $footer;
|
||||
} // end switch $framename
|
||||
break;
|
||||
case HOTPOT_NAVIGATION_GIVEUP:
|
||||
// replace charset , if necessary
|
||||
// HotPots are plain ascii (iso-8859-1) with unicode chars encoded as HTML entities
|
||||
$hp->html = preg_replace(
|
||||
'|<meta[^>]*charset=iso-8859-1[^>]*>|is',
|
||||
'<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />',
|
||||
$hp->html
|
||||
);
|
||||
// no break (continue to print html to browser)
|
||||
default:
|
||||
// HOTPOT_NAVIGATION_BUTTONS
|
||||
// HOTPOT_NAVIGATION_NONE
|
||||
if (!empty($available_msg)) {
|
||||
$hp->insert_message('<!-- BeginTopNavButtons -->', $available_msg);
|
||||
}
|
||||
print($hp->html);
|
||||
}
|
||||
///////////////////////////////////
|
||||
/// functions
|
||||
///////////////////////////////////
|
||||
function hotpot_feedback_teachers(&$course, &$hotpot) {
|
||||
global $CFG;
|
||||
$teachers = get_users_by_capability(get_context_instance(CONTEXT_COURSE, $course->id), 'mod/hotpot:grade');
|
||||
$teacherdetails = '';
|
||||
if (!empty($teachers)) {
|
||||
$details = array();
|
||||
foreach ($teachers as $teacher) {
|
||||
if ($hotpot->studentfeedback==HOTPOT_FEEDBACK_MOODLEMESSAGING) {
|
||||
$detail = $teacher->id;
|
||||
} else {
|
||||
$detail =$teacher->email;
|
||||
}
|
||||
$details[] = "new Array('".fullname($teacher)."', '$detail')";
|
||||
}
|
||||
$teacherdetails = 'new Array('.implode(',', $details).");\n";
|
||||
}
|
||||
return $teacherdetails;
|
||||
}
|
||||
Reference in New Issue
Block a user