MDL-23450 moving mod/hotpot to contrib for now, because it is not ready for Moodle 2.0 yet

This commit is contained in:
Petr Skoda
2010-07-24 17:15:54 +00:00
parent 245491b062
commit 91b9560bd6
66 changed files with 0 additions and 21108 deletions
-87
View File
@@ -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.
-582
View File
@@ -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;
}
-347
View File
@@ -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);
}
-79
View File
@@ -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
)
)
);
-17
View File
@@ -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
}
-122
View File
@@ -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>
-30
View File
@@ -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;
}
-29
View File
@@ -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

-76
View File
@@ -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();
-402
View File
@@ -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("'"=>"\'", '"'=>'&quot;');
// 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> &nbsp; </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.'&amp;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.'&amp;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 = "&nbsp;";
$bestscore = "&nbsp;";
} 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 = "&nbsp;";
}
}
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 = '&nbsp;';
} 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();
-224
View File
@@ -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 &quot;SJIS&quot; 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 &quot;{$a}&quot;';
$string['error_couldnotopensourcefile'] = 'Could not open the source file "{$a}"';
$string['error_couldnotopentemplate'] = 'Could not open template for &quot;{$a}&quot; 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'] = '&quot;{$a}&quot; 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 &quot;Give Up&quot; 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 &quot;{$a}&quot;?';
$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
View File
File diff suppressed because it is too large Load Diff
-251
View File
@@ -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&nbsp;<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>&nbsp;';
$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&nbsp;<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>&nbsp;';
$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;
}
-48
View File
@@ -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');
//]]>
//-->
-338
View File
@@ -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

-667
View File
@@ -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] : '&nbsp;';
$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];
}
-542
View File
@@ -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 ? '&nbsp;' : "";
// 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.'&amp;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.'&amp;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
-851
View File
@@ -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++;
}
}
-449
View File
@@ -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 ? '&nbsp;' : "";
$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.'&amp;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.'&amp;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 ? '&nbsp;' : "";
$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
;
}
-172
View File
@@ -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 ? '&nbsp;' : ' ';
$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.'&amp;course='.$course->id.'">'.$name.'</a>';
}
$grade = isset($user->grade) && $user->grade<>'&nbsp;' ? $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.'&amp;attempt='.$attempt->id.'">'.$attemptnumber.'</a>';
$starttime = '<a href="review.php?hp='.$hotpot->id.'&amp;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").'" />&nbsp;'."\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
-203
View File
@@ -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 ? '' : '&nbsp;');
$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[] = '&nbsp;';
$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.'&amp;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
-537
View File
@@ -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")." &quot;".format_string($record->name,true)."&quot;</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";
}
-251
View File
@@ -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();
}
-11
View File
@@ -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'), '') );
}
-75
View File
@@ -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"> &nbsp; <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();
?>
-111
View File
@@ -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('&#x003C;' => '<', '&#x003E;' => '>'));
// 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
-128
View File
@@ -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">&nbsp;<span id="TimerText">&nbsp;&nbsp;</span>&nbsp;</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()">&nbsp;[strCheckCaption]&nbsp;</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;">&nbsp;[strOKCaption]&nbsp;</button>
</div>
<!-- BeginBottomNavButtons -->
<!-- EndBottomNavButtons -->
<!-- BeginSubmissionForm -->
<!-- EndSubmissionForm -->
</body>
</html>
-369
View File
@@ -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]
-136
View File
@@ -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">&nbsp;<span id="TimerText">&nbsp;&nbsp;</span>&nbsp;</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)">&nbsp;[strCheckCaption]&nbsp;</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()">&nbsp;[strRestartCaption]&nbsp;</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)">&nbsp;[strHintCaption]&nbsp;</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">&nbsp;<br />&nbsp;</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;">&nbsp;[strOKCaption]&nbsp;</button>
</div>
<!-- BeginBottomNavButtons -->
<!-- EndBottomNavButtons -->
<!-- BeginSubmissionForm -->
<!-- EndSubmissionForm -->
</body>
</html>
-576
View File
@@ -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]
-105
View File
@@ -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>
-131
View File
@@ -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]
}
-8
View File
@@ -1,8 +0,0 @@
[inclReadingTitle]
<h3 class="ExerciseSubtitle">[strReadingTitle]</h3>
[/inclReadingTitle]
<div class="ReadingText">
[strReadingText]
</div>
-605
View File
@@ -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]);
//}
-42
View File
@@ -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();
}
}
}
-152
View File
@@ -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]
-18
View File
@@ -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();
}
}
-15
View File
@@ -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>
-18
View File
@@ -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]
-42
View File
@@ -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>
-53
View File
@@ -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();
}
-85
View File
@@ -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();
}
}
-33
View File
@@ -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--;
}
-248
View File
@@ -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, '&quot;')
}
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'));
}
}
}
-169
View File
@@ -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">&nbsp;&nbsp;</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()">&nbsp;[strCheckCaption]&nbsp;</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()">&nbsp;[strHintCaption]&nbsp;</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()">&nbsp;[strCheckCaption]&nbsp;</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()">&nbsp;[strHintCaption]&nbsp;</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;">&nbsp;[strOKCaption]&nbsp;</button>
</div>
<!-- BeginBottomNavButtons -->
[inclNavButtons]
[strBottomNavBar]
[/inclNavButtons]
<!-- EndBottomNavButtons -->
<!-- BeginSubmissionForm -->
<!-- EndSubmissionForm -->
</body>
</html>
-390
View File
@@ -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]
-191
View File
@@ -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">&nbsp;&nbsp;</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()">&nbsp;[strCheckCaption]&nbsp;</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()">&nbsp;[strCheckCaption]&nbsp;</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;">&nbsp;[strOKCaption]&nbsp;</button>
</div>
<!-- BeginBottomNavButtons -->
[inclNavButtons]
[strBottomNavBar]
[/inclNavButtons]
<!-- EndBottomNavButtons -->
<!-- BeginSubmissionForm -->
<!-- EndSubmissionForm -->
</body>
</html>
-373
View File
@@ -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]
-182
View File
@@ -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">&nbsp;</td>
[EndBlankCell]
[StartLetterOnlyCell]
<td class="LetterOnlyCell">&nbsp;<span class="Letter">[Letter]</span></td>
[EndLetterOnlyCell]
[StartNumLetterCell]
<td class="NumLetterCell"><span class="Num">[ClueNum]</span>&nbsp;<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>
-148
View File
@@ -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">&nbsp;&nbsp;</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()">&nbsp;[strCheckCaption]&nbsp;</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()">&nbsp;[strCheckCaption]&nbsp;</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;">&nbsp;[strOKCaption]&nbsp;</button>
</div>
<!-- BeginBottomNavButtons -->
[inclNavButtons]
[strBottomNavBar]
[/inclNavButtons]
<!-- EndBottomNavButtons -->
<!-- BeginSubmissionForm -->
<!-- EndSubmissionForm -->
</body>
</html>
-310
View File
@@ -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]
-155
View File
@@ -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">&nbsp;&nbsp;</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)">&nbsp;[strCheckCaption]&nbsp;</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()">&nbsp;[strUndoCaption]&nbsp;</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()">&nbsp;[strRestartCaption]&nbsp;</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)">&nbsp;[strHintCaption]&nbsp;</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;">&nbsp;[strOKCaption]&nbsp;</button>
</div>
<!-- BeginBottomNavButtons -->
[inclNavButtons]
[strBottomNavBar]
[/inclNavButtons]
<!-- EndBottomNavButtons -->
<!-- BeginSubmissionForm -->
<!-- EndSubmissionForm -->
</body>
</html>
-409
View File
@@ -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 = '&nbsp; &nbsp;<a class="ExSegment" href="javascript:void(0)" onclick="AddSegment([SegmentNumber])" title="[strClickToAdd]">[CurrentSegment]</a>&nbsp; &nbsp;';
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] + '&nbsp; &nbsp;&nbsp;';
}
}
//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]
-163
View File
@@ -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">&nbsp;&nbsp;</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">&nbsp;</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;">&nbsp;[strOKCaption]&nbsp;</button>
</div>
<!-- BeginBottomNavButtons -->
[inclNavButtons]
[strBottomNavBar]
[/inclNavButtons]
<!-- EndBottomNavButtons -->
<!-- BeginSubmissionForm -->
<!-- EndSubmissionForm -->
</body>
</html>
-668
View File
@@ -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]
-94
View File
@@ -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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li>[EndIndexItem]
</ul>
</div>
</div>
</body></html>
-29
View File
@@ -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>
-16
View File
@@ -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
-528
View File
@@ -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.'&amp;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&amp;framename=top\">\n";
print "<frame title=\"$txtmaintitle\" src=\"view.php?id=$cm->id&amp;framename=main\">\n";
print "<noframes>\n";
print "<p>$txtframesetinfo</p>\n";
print "<ul><li><a href=\"view.php?id=$cm->id&amp;framename=top\">$txttoptitle</a></li>\n";
print "<li><a href=\"view.php?id=$cm->id&amp;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.'&amp;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;
}